Merge "Sync media/OWNERS" am: b5d34b3e03  -s ours am: b3f2ee1b96  -s ours
am: 01c96a41b1  -s ours

Change-Id: Ib98b79ea303c8b96ddb5cd4f00490695630ac31b
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 0771fc8..07d4e7e 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -140,5 +140,7 @@
 
     void prepare2(int maxCount, int streamId);
 
+    void updateOutputConfiguration(int streamId, in OutputConfiguration outputConfiguration);
+
     void finalizeOutputConfigurations(int streamId, in OutputConfiguration outputConfiguration);
 }
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 468a1eb..813d6c9 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -160,12 +160,12 @@
 }
 
 OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
-        int surfaceSetID) {
+        int surfaceSetID, bool isShared) {
     mGbps.push_back(gbp);
     mRotation = rotation;
     mSurfaceSetID = surfaceSetID;
     mIsDeferred = false;
-    mIsShared = false;
+    mIsShared = isShared;
 }
 
 status_t OutputConfiguration::writeToParcel(android::Parcel* parcel) const {
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index 8e641c7..3599604 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -64,7 +64,7 @@
     OutputConfiguration(const android::Parcel& parcel);
 
     OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
-            int surfaceSetID = INVALID_SET_ID);
+            int surfaceSetID = INVALID_SET_ID, bool isShared = false);
 
     bool operator == (const OutputConfiguration& other) const {
         return ( mRotation == other.mRotation &&
@@ -110,6 +110,7 @@
 
     bool gbpsEqual(const OutputConfiguration& other) const;
     bool gbpsLessThan(const OutputConfiguration& other) const;
+    void addGraphicProducer(sp<IGraphicBufferProducer> gbp) {mGbps.push_back(gbp);}
 private:
     std::vector<sp<IGraphicBufferProducer>> mGbps;
     int                        mRotation;
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index 2a6b182..fd95296 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -135,3 +135,19 @@
     }
     return session->abortCaptures();
 }
+
+EXPORT
+camera_status_t ACameraCaptureSession_updateSharedOutput(ACameraCaptureSession* session,
+        ACaptureSessionOutput* output) {
+    ATRACE_CALL();
+    if (session == nullptr) {
+        ALOGE("%s: Error: session is null", __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    if (session->isClosed()) {
+        ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+    return session->updateOutputConfiguration(output);
+}
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
index 9f6d1f7..ac4beea 100644
--- a/camera/ndk/NdkCameraDevice.cpp
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -103,11 +103,74 @@
                 __FUNCTION__, window, out);
         return ACAMERA_ERROR_INVALID_PARAMETER;
     }
-    *out = new ACaptureSessionOutput(window);
+    *out = new ACaptureSessionOutput(window, false);
     return ACAMERA_OK;
 }
 
 EXPORT
+camera_status_t ACaptureSessionSharedOutput_create(
+        ANativeWindow* window, /*out*/ACaptureSessionOutput** out) {
+    ATRACE_CALL();
+    if (window == nullptr || out == nullptr) {
+        ALOGE("%s: Error: bad argument. window %p, out %p",
+                __FUNCTION__, window, out);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    *out = new ACaptureSessionOutput(window, true);
+    return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *out,
+        ANativeWindow* window) {
+    ATRACE_CALL();
+    if ((window == nullptr) || (out == nullptr)) {
+        ALOGE("%s: Error: bad argument. window %p, out %p",
+                __FUNCTION__, window, out);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    if (!out->mIsShared) {
+        ALOGE("%s: Error trying to insert a new window in non-shared output configuration",
+                __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_OPERATION;
+    }
+    if (out->mWindow == window) {
+        ALOGE("%s: Error trying to add the same window associated with the output configuration",
+                __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    auto insert = out->mSharedWindows.insert(window);
+    camera_status_t ret = (insert.second) ? ACAMERA_OK : ACAMERA_ERROR_INVALID_PARAMETER;
+    return ret;
+}
+
+EXPORT
+camera_status_t ACaptureSessionSharedOutput_remove(ACaptureSessionOutput *out,
+        ANativeWindow* window) {
+    ATRACE_CALL();
+    if ((window == nullptr) || (out == nullptr)) {
+        ALOGE("%s: Error: bad argument. window %p, out %p",
+                __FUNCTION__, window, out);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    if (!out->mIsShared) {
+        ALOGE("%s: Error trying to remove a  window in non-shared output configuration",
+                __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_OPERATION;
+    }
+    if (out->mWindow == window) {
+        ALOGE("%s: Error trying to remove the same window associated with the output configuration",
+                __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    auto remove = out->mSharedWindows.erase(window);
+    camera_status_t ret = (remove) ? ACAMERA_OK : ACAMERA_ERROR_INVALID_PARAMETER;
+    return ret;
+}
+
+EXPORT
 void ACaptureSessionOutput_free(ACaptureSessionOutput* output) {
     ATRACE_CALL();
     if (output != nullptr) {
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
index b9c159d..6d1d5ce 100644
--- a/camera/ndk/impl/ACameraCaptureSession.cpp
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -148,6 +148,23 @@
     return ret;
 }
 
+camera_status_t ACameraCaptureSession::updateOutputConfiguration(ACaptureSessionOutput *output) {
+    sp<CameraDevice> dev = getDeviceSp();
+    if (dev == nullptr) {
+        ALOGE("Error: Device associated with session %p has been closed!", this);
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+
+    camera_status_t ret;
+    dev->lockDeviceForSessionOps();
+    {
+        Mutex::Autolock _l(mSessionLock);
+        ret = dev->updateOutputConfiguration(output);
+    }
+    dev->unlockDevice();
+    return ret;
+}
+
 ACameraDevice*
 ACameraCaptureSession::getDevice() {
     Mutex::Autolock _l(mSessionLock);
diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h
index 339c665..a2068e7 100644
--- a/camera/ndk/impl/ACameraCaptureSession.h
+++ b/camera/ndk/impl/ACameraCaptureSession.h
@@ -24,7 +24,8 @@
 using namespace android;
 
 struct ACaptureSessionOutput {
-    explicit ACaptureSessionOutput(ANativeWindow* window) : mWindow(window) {};
+    explicit ACaptureSessionOutput(ANativeWindow* window, bool isShared = false) :
+            mWindow(window), mIsShared(isShared) {};
 
     bool operator == (const ACaptureSessionOutput& other) const {
         return mWindow == other.mWindow;
@@ -40,6 +41,8 @@
     }
 
     ANativeWindow* mWindow;
+    std::set<ANativeWindow *> mSharedWindows;
+    bool           mIsShared;
     int            mRotation = CAMERA3_STREAM_ROTATION_0;
 };
 
@@ -89,6 +92,8 @@
             int numRequests, ACaptureRequest** requests,
             /*optional*/int* captureSequenceId);
 
+    camera_status_t updateOutputConfiguration(ACaptureSessionOutput *output);
+
     ACameraDevice* getDevice();
 
   private:
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 907802c..9ce0ac8 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -289,6 +289,82 @@
     return ACAMERA_OK;
 }
 
+camera_status_t CameraDevice::updateOutputConfiguration(ACaptureSessionOutput *output) {
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        return ret;
+    }
+
+    if (output == nullptr) {
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    if (!output->mIsShared) {
+        ALOGE("Error output configuration is not shared");
+        return ACAMERA_ERROR_INVALID_OPERATION;
+    }
+
+    int32_t streamId = -1;
+    for (auto& kvPair : mConfiguredOutputs) {
+        if (kvPair.second.first == output->mWindow) {
+            streamId = kvPair.first;
+            break;
+        }
+    }
+    if (streamId < 0) {
+        ALOGE("Error: Invalid output configuration");
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    sp<IGraphicBufferProducer> iGBP(nullptr);
+    ret = getIGBPfromAnw(output->mWindow, iGBP);
+    if (ret != ACAMERA_OK) {
+        ALOGE("Camera device %s failed to extract graphic producer from native window",
+                getId());
+        return ret;
+    }
+
+    OutputConfiguration outConfig(iGBP, output->mRotation, OutputConfiguration::INVALID_SET_ID,
+            true);
+
+    for (auto& anw : output->mSharedWindows) {
+        ret = getIGBPfromAnw(anw, iGBP);
+        if (ret != ACAMERA_OK) {
+            ALOGE("Camera device %s failed to extract graphic producer from native window",
+                    getId());
+            return ret;
+        }
+        outConfig.addGraphicProducer(iGBP);
+    }
+
+    auto remoteRet = mRemote->updateOutputConfiguration(streamId, outConfig);
+    if (!remoteRet.isOk()) {
+        switch (remoteRet.serviceSpecificErrorCode()) {
+            case hardware::ICameraService::ERROR_INVALID_OPERATION:
+                ALOGE("Camera device %s invalid operation: %s", getId(),
+                        remoteRet.toString8().string());
+                return ACAMERA_ERROR_INVALID_OPERATION;
+                break;
+            case hardware::ICameraService::ERROR_ALREADY_EXISTS:
+                ALOGE("Camera device %s output surface already exists: %s", getId(),
+                        remoteRet.toString8().string());
+                return ACAMERA_ERROR_INVALID_PARAMETER;
+                break;
+            case hardware::ICameraService::ERROR_ILLEGAL_ARGUMENT:
+                ALOGE("Camera device %s invalid input argument: %s", getId(),
+                        remoteRet.toString8().string());
+                return ACAMERA_ERROR_INVALID_PARAMETER;
+                break;
+            default:
+                ALOGE("Camera device %s failed to add shared output: %s", getId(),
+                        remoteRet.toString8().string());
+                return ACAMERA_ERROR_UNKNOWN;
+        }
+    }
+
+    return ACAMERA_OK;
+}
+
 camera_status_t
 CameraDevice::allocateCaptureRequest(
         const ACaptureRequest* request, /*out*/sp<CaptureRequest>& outReq) {
@@ -540,7 +616,8 @@
             return ret;
         }
         outputSet.insert(std::make_pair(
-                anw, OutputConfiguration(iGBP, outConfig.mRotation)));
+                anw, OutputConfiguration(iGBP, outConfig.mRotation,
+                        OutputConfiguration::INVALID_SET_ID, outConfig.mIsShared)));
     }
     auto addSet = outputSet;
     std::vector<int> deleteList;
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 6ed3881..23cc1a1 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -36,7 +36,8 @@
 #include <camera/camera2/OutputConfiguration.h>
 #include <camera/camera2/CaptureRequest.h>
 
-#include <camera/NdkCameraDevice.h>
+#include <camera/NdkCameraManager.h>
+#include <camera/NdkCameraCaptureSession.h>
 #include "ACameraMetadata.h"
 
 namespace android {
@@ -122,6 +123,8 @@
             /*out*/int* captureSequenceId,
             bool isRepeating);
 
+    camera_status_t updateOutputConfiguration(ACaptureSessionOutput *output);
+
     static camera_status_t allocateCaptureRequest(
             const ACaptureRequest* request, sp<CaptureRequest>& outReq);
 
diff --git a/camera/ndk/include/camera/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h
index d96f538..67003c1 100644
--- a/camera/ndk/include/camera/NdkCameraCaptureSession.h
+++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h
@@ -591,6 +591,54 @@
 
 #endif /* __ANDROID_API__ >= 24 */
 
+#if __ANDROID_API__ >= 28
+
+typedef struct ACaptureSessionOutput ACaptureSessionOutput;
+
+/**
+ * Update shared ACaptureSessionOutput.
+ *
+ * <p>A shared ACaptureSessionOutput (see {@link ACaptureSessionSharedOutput_create}) that
+ * was modified via calls to {@link ACaptureSessionSharedOutput_add} or
+ * {@link ACaptureSessionSharedOutput_remove} must be updated by calling this method before its
+ * changes take effect. After the update call returns  with {@link ACAMERA_OK}, any newly added
+ * native windows can be used as a target in subsequent capture requests.</p>
+ *
+ * <p>Native windows that get removed must not be part of any active repeating or single/burst
+ * request or have any pending results. Consider updating repeating requests via
+ * {@link ACaptureSessionOutput_setRepeatingRequest} and then wait for the last frame number
+ * when the sequence completes
+ * {@link ACameraCaptureSession_captureCallback#onCaptureSequenceCompleted}.</p>
+ *
+ * <p>Native windows that get added must not be part of any other registered ACaptureSessionOutput
+ * and must be compatible. Compatible windows must have matching format, rotation and
+ * consumer usage.</p>
+ *
+ * <p>A shared ACameraCaptureSession can support up to 4 additional native windows.</p>
+ *
+ * @param session the capture session of interest
+ * @param output the modified output configuration
+ *
+ * @return <ul><li>
+ *             {@link ACAMERA_OK} if the method succeeds.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if session or output is NULL; or output
+ *             contains invalid native windows; or if an attempt was made to add
+ *             a native window to a different output configuration; or new native window is not
+ *             compatible; or any removed native window still has pending requests;</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_OPERATION} if output configuration is not shared (see
+ *             {@link ACaptureSessionSharedOutput_create};  or the number of additional
+ *             native windows goes beyond the supported limit.</li>
+ *         <li>{@link ACAMERA_ERROR_SESSION_CLOSED} if the capture session has been closed</li>
+ *         <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if the camera device is closed</li>
+ *         <li>{@link ACAMERA_ERROR_CAMERA_DEVICE} if the camera device encounters fatal error</li>
+ *         <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal
+ *             error</li>
+ *         <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons</li></ul>
+ */
+camera_status_t ACameraCaptureSession_updateSharedOutput(ACameraCaptureSession* session,
+        ACaptureSessionOutput* output);
+#endif /* __ANDROID_API__ >= 28 */
+
 __END_DECLS
 
 #endif /* _NDK_CAMERA_CAPTURE_SESSION_H */
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index 6c9e85a..3a6f3ef 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -661,6 +661,67 @@
 
 #endif /* __ANDROID_API__ >= 24 */
 
+#if __ANDROID_API__ >= 28
+
+/**
+ * Create a shared ACaptureSessionOutput object.
+ *
+ * <p>The ACaptureSessionOutput is used in {@link ACaptureSessionOutputContainer_add} method to add
+ * an output {@link ANativeWindow} to ACaptureSessionOutputContainer. Use
+ * {@link ACaptureSessionOutput_free} to free the object and its memory after application no longer
+ * needs the {@link ACaptureSessionOutput}. A shared ACaptureSessionOutput can be further modified
+ * via {@link ACaptureSessionSharedOutput_add} or {@link ACaptureSessionSharedOutput_remove} and
+ * must be updated via {@link ACameraCaptureSession_updateSharedOutput}.</p>
+ *
+ * @param anw the {@link ANativeWindow} to be associated with the {@link ACaptureSessionOutput}
+ * @param output the output {@link ACaptureSessionOutput} will be stored here if the
+ *                  method call succeeds.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds. The created container will be
+ *                                filled in the output argument.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if anw or output is NULL.</li></ul>
+ *
+ * @see ACaptureSessionOutputContainer_add
+ */
+camera_status_t ACaptureSessionSharedOutput_create(
+        ANativeWindow* anw, /*out*/ACaptureSessionOutput** output);
+
+/**
+ * Add a native window to shared ACaptureSessionOutput.
+ *
+ * The ACaptureSessionOutput must be created via {@link ACaptureSessionSharedOutput_create}.
+ *
+ * @param output  the shared ACaptureSessionOutput to be extended.
+ * @param anw The new native window.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if anw or output is NULL; or output is not
+ *             shared see {@link ACaptureSessionSharedOutput_create}; or anw matches with the native
+ *             window associated with ACaptureSessionOutput; or anw is already present inside
+ *             ACaptureSessionOutput.</li></ul>
+ */
+camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *output, ANativeWindow *anw);
+
+/**
+ * Remove a native window from shared ACaptureSessionOutput.
+ *
+ * @param output the {@link ACaptureSessionOutput} to be modified.
+ * @param anw The native window to be removed.
+ *
+ * @return <ul>
+ *         <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ *         <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if anw or output is NULL; or output is not
+ *             shared see {@link ACaptureSessionSharedOutput_create}; or anw matches with the native
+ *             window associated with ACaptureSessionOutput; or anw is not present inside
+ *             ACaptureSessionOutput.</li></ul>
+ */
+camera_status_t ACaptureSessionSharedOutput_remove(ACaptureSessionOutput *output,
+        ANativeWindow* anw);
+
+#endif /* __ANDROID_API__ >= 28 */
+
 __END_DECLS
 
 #endif /* _NDK_CAMERA_DEVICE_H */
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 629d75a..1793877 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -471,10 +471,6 @@
      * Otherwise will always be present.</p>
      * <p>The maximum number of regions supported by the device is determined by the value
      * of android.control.maxRegionsAe.</p>
-     * <p>The data representation is int[5 * area_count].
-     * Every five elements represent a metering region of (xmin, ymin, xmax, ymax, weight).
-     * The rectangle is defined to be inclusive on xmin and ymin, but exclusive on xmax and
-     * ymax.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * (ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE.width - 1,
@@ -495,6 +491,10 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata.  If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
+     * <p>The data representation is <code>int[5 * area_count]</code>.
+     * Every five elements represent a metering region of <code>(xmin, ymin, xmax, ymax, weight)</code>.
+     * The rectangle is defined to be inclusive on xmin and ymin, but exclusive on xmax and
+     * ymax.</p>
      *
      * @see ACAMERA_SCALER_CROP_REGION
      * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -633,10 +633,6 @@
      * Otherwise will always be present.</p>
      * <p>The maximum number of focus areas supported by the device is determined by the value
      * of android.control.maxRegionsAf.</p>
-     * <p>The data representation is int[5 * area_count].
-     * Every five elements represent a metering region of (xmin, ymin, xmax, ymax, weight).
-     * The rectangle is defined to be inclusive on xmin and ymin, but exclusive on xmax and
-     * ymax.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * (ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE.width - 1,
@@ -657,6 +653,10 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata. If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
+     * <p>The data representation is <code>int[5 * area_count]</code>.
+     * Every five elements represent a metering region of <code>(xmin, ymin, xmax, ymax, weight)</code>.
+     * The rectangle is defined to be inclusive on xmin and ymin, but exclusive on xmax and
+     * ymax.</p>
      *
      * @see ACAMERA_SCALER_CROP_REGION
      * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -791,10 +791,6 @@
      * Otherwise will always be present.</p>
      * <p>The maximum number of regions supported by the device is determined by the value
      * of android.control.maxRegionsAwb.</p>
-     * <p>The data representation is int[5 * area_count].
-     * Every five elements represent a metering region of (xmin, ymin, xmax, ymax, weight).
-     * The rectangle is defined to be inclusive on xmin and ymin, but exclusive on xmax and
-     * ymax.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * (ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE.width - 1,
@@ -815,6 +811,10 @@
      * region and output only the intersection rectangle as the metering region in the result
      * metadata.  If the region is entirely outside the crop region, it will be ignored and
      * not reported in the result metadata.</p>
+     * <p>The data representation is <code>int[5 * area_count]</code>.
+     * Every five elements represent a metering region of <code>(xmin, ymin, xmax, ymax, weight)</code>.
+     * The rectangle is defined to be inclusive on xmin and ymin, but exclusive on xmax and
+     * ymax.</p>
      *
      * @see ACAMERA_SCALER_CROP_REGION
      * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -885,11 +885,10 @@
      * <p>When set to AUTO, the individual algorithm controls in
      * ACAMERA_CONTROL_* are in effect, such as ACAMERA_CONTROL_AF_MODE.</p>
      * <p>When set to USE_SCENE_MODE, the individual controls in
-     * ACAMERA_CONTROL_* are mostly disabled, and the camera device implements
-     * one of the scene mode settings (such as ACTION, SUNSET, or PARTY)
-     * as it wishes. The camera device scene mode 3A settings are provided by
-     * capture results {@link ACameraMetadata} from
-     * {@link ACameraCaptureSession_captureCallback_result}.</p>
+     * ACAMERA_CONTROL_* are mostly disabled, and the camera device
+     * implements one of the scene mode settings (such as ACTION,
+     * SUNSET, or PARTY) as it wishes. The camera device scene mode
+     * 3A settings are provided by {@link ACameraCaptureSession_captureCallback_result capture results}.</p>
      * <p>When set to OFF_KEEP_STATE, it is similar to OFF mode, the only difference
      * is that this frame will not be used by camera device background 3A statistics
      * update, as if this frame is never captured. This mode can be used in the scenario
@@ -1043,20 +1042,18 @@
      * <p>For constant-framerate recording, for each normal
      * <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a>, that is, a
      * <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a> that has
-     * <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#quality">quality</a>
-     * in the range [
-     * <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#QUALITY_LOW">QUALITY_LOW</a>,
-     * <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#QUALITY_2160P">QUALITY_2160P</a>],
-     * if the profile is supported by the device and has
-     * <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#videoFrameRate">videoFrameRate</a>
-     * <code>x</code>, this list will always include (<code>x</code>,<code>x</code>).</p>
+     * <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#quality">quality</a> in
+     * the range [<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#QUALITY_LOW">QUALITY_LOW</a>,
+     * <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#QUALITY_2160P">QUALITY_2160P</a>], if the profile is
+     * supported by the device and has
+     * <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#videoFrameRate">videoFrameRate</a> <code>x</code>, this list will
+     * always include (<code>x</code>,<code>x</code>).</p>
      * </li>
      * <li>
      * <p>Also, a camera device must either not support any
      * <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a>,
      * or support at least one
-     * normal <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a>
-     * that has
+     * normal <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a> that has
      * <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#videoFrameRate">videoFrameRate</a> <code>x</code> &gt;= 24.</p>
      * </li>
      * </ul>
@@ -1619,13 +1616,13 @@
      * compared to previous regular requests. enableZsl does not affect requests with other
      * capture intents.</p>
      * <p>For example, when requests are submitted in the following order:
-     *   Request A: enableZsl is <code>true</code>, ACAMERA_CONTROL_CAPTURE_INTENT is PREVIEW
-     *   Request B: enableZsl is <code>true</code>, ACAMERA_CONTROL_CAPTURE_INTENT is STILL_CAPTURE</p>
+     *   Request A: enableZsl is ON, ACAMERA_CONTROL_CAPTURE_INTENT is PREVIEW
+     *   Request B: enableZsl is ON, ACAMERA_CONTROL_CAPTURE_INTENT is STILL_CAPTURE</p>
      * <p>The output images for request B may have contents captured before the output images for
      * request A, and the result metadata for request B may be older than the result metadata for
      * request A.</p>
-     * <p>Note that when enableZsl is <code>true</code>, it is not guaranteed to get output images captured in the
-     * past for requests with STILL_CAPTURE capture intent.</p>
+     * <p>Note that when enableZsl is <code>true</code>, it is not guaranteed to get output images captured in
+     * the past for requests with STILL_CAPTURE capture intent.</p>
      * <p>For applications targeting SDK versions O and newer, the value of enableZsl in
      * TEMPLATE_STILL_CAPTURE template may be <code>true</code>. The value in other templates is always
      * <code>false</code> if present.</p>
@@ -1959,14 +1956,14 @@
      * <p>When an ACAMERA_JPEG_ORIENTATION of non-zero degree is requested,
      * the camera device will handle thumbnail rotation in one of the following ways:</p>
      * <ul>
-     * <li>Set the
-     *   <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>
+     * <li>Set the <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>
      *   and keep jpeg and thumbnail image data unrotated.</li>
      * <li>Rotate the jpeg and thumbnail image data and not set
-     *   <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>.
-     *   In this case, LIMITED or FULL hardware level devices will report rotated thumnail size
-     *   in capture result, so the width and height will be interchanged if 90 or 270 degree
-     *   orientation is requested. LEGACY device will always report unrotated thumbnail size.</li>
+     *   <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>. In this
+     *   case, LIMITED or FULL hardware level devices will report rotated thumnail size in
+     *   capture result, so the width and height will be interchanged if 90 or 270 degree
+     *   orientation is requested. LEGACY device will always report unrotated thumbnail
+     *   size.</li>
      * </ul>
      *
      * @see ACAMERA_JPEG_ORIENTATION
@@ -2218,9 +2215,8 @@
      * <p>The position of the camera device's lens optical center,
      * as a three-dimensional vector <code>(x,y,z)</code>, relative to the
      * optical center of the largest camera device facing in the
-     * same direction as this camera, in the
-     * <a href="https://developer.android.com/reference/android/hardware/SensorEvent.html">Android sensor coordinate axes</a>.
-     * Note that only the axis definitions are shared with
+     * same direction as this camera, in the <a href="https://developer.android.com/reference/android/hardware/SensorEvent.html">Android sensor coordinate
+     * axes</a>. Note that only the axis definitions are shared with
      * the sensor coordinate system, but not the origin.</p>
      * <p>If this device is the largest or only camera device with a
      * given facing, then this position will be <code>(0, 0, 0)</code>; a
@@ -2662,11 +2658,12 @@
      * into the 3 stream types as below:</p>
      * <ul>
      * <li>Processed (but stalling): any non-RAW format with a stallDurations &gt; 0.
-     *   Typically {@link AIMAGE_FORMAT_JPEG} format.</li>
-     * <li>Raw formats: {@link AIMAGE_FORMAT_RAW16}, {@link AIMAGE_FORMAT_RAW10}, or
-     *   {@link AIMAGE_FORMAT_RAW12}.</li>
-     * <li>Processed (but not-stalling): any non-RAW format without a stall duration.
-     *   Typically {@link AIMAGE_FORMAT_YUV_420_888}.</li>
+     *   Typically {@link AIMAGE_FORMAT_JPEG JPEG format}.</li>
+     * <li>Raw formats: {@link AIMAGE_FORMAT_RAW16 RAW_SENSOR}, {@link AIMAGE_FORMAT_RAW10 RAW10}, or
+     *   {@link AIMAGE_FORMAT_RAW12 RAW12}.</li>
+     * <li>Processed (but not-stalling): any non-RAW format without a stall duration.  Typically
+     *   {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888},
+     *   <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a>, or <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a>.</li>
      * </ul>
      *
      * @see ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
@@ -2787,7 +2784,7 @@
             ACAMERA_REQUEST_START + 12,
     /**
      * <p>A list of all keys that the camera device has available
-     * to use with {@link ACaptureRequest}.</p>
+     * to use with {@link ACaptureRequest }.</p>
      *
      * <p>Type: int32[n]</p>
      *
@@ -2809,9 +2806,7 @@
     ACAMERA_REQUEST_AVAILABLE_REQUEST_KEYS =                    // int32[n]
             ACAMERA_REQUEST_START + 13,
     /**
-     * <p>A list of all keys that the camera device has available
-     * to query with {@link ACameraMetadata} from
-     * {@link ACameraCaptureSession_captureCallback_result}.</p>
+     * <p>A list of all keys that the camera device has available to use with {@link ACameraCaptureSession_captureCallback_result }.</p>
      *
      * <p>Type: int32[n]</p>
      *
@@ -2842,9 +2837,7 @@
     ACAMERA_REQUEST_AVAILABLE_RESULT_KEYS =                     // int32[n]
             ACAMERA_REQUEST_START + 14,
     /**
-     * <p>A list of all keys that the camera device has available
-     * to query with {@link ACameraMetadata} from
-     * {@link ACameraManager_getCameraCharacteristics}.</p>
+     * <p>A list of all keys that the camera device has available to use with {@link ACameraManager_getCameraCharacteristics }.</p>
      *
      * <p>Type: int32[n]</p>
      *
@@ -2876,7 +2869,6 @@
      * </ul></p>
      *
      * <p>This control can be used to implement digital zoom.</p>
-     * <p>The data representation is int[4], which maps to (left, top, width, height).</p>
      * <p>The crop region coordinate system is based off
      * ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE, with <code>(0, 0)</code> being the
      * top-left corner of the sensor active array.</p>
@@ -2906,6 +2898,7 @@
      * for rounding and other hardware requirements; the final
      * crop region used will be included in the output capture
      * result.</p>
+     * <p>The data representation is int[4], which maps to (left, top, width, height).</p>
      *
      * @see ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
      * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -3061,13 +3054,14 @@
      * ignored).</p>
      * <p>The following formats may always have a stall duration:</p>
      * <ul>
-     * <li>{@link AIMAGE_FORMAT_JPEG}</li>
-     * <li>{@link AIMAGE_FORMAT_RAW16}</li>
+     * <li>{@link AIMAGE_FORMAT_JPEG }</li>
+     * <li>{@link AIMAGE_FORMAT_RAW16 }</li>
      * </ul>
      * <p>The following formats will never have a stall duration:</p>
      * <ul>
-     * <li>{@link AIMAGE_FORMAT_YUV_420_888}</li>
-     * <li>{@link AIMAGE_FORMAT_RAW10}</li>
+     * <li>{@link AIMAGE_FORMAT_YUV_420_888 }</li>
+     * <li>{@link AIMAGE_FORMAT_RAW10 }</li>
+     * <li>{@link AIMAGE_FORMAT_RAW12 }</li>
      * </ul>
      * <p>All other formats may or may not have an allowed stall duration on
      * a per-capability basis; refer to ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
@@ -3177,39 +3171,29 @@
      * can run concurrently to the rest of the camera pipeline, but
      * cannot process more than 1 capture at a time.</li>
      * </ul>
-     * <p>The necessary information for the application, given the model above,
-     * is provided via
-     * {@link ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS}.
-     * These are used to determine the maximum frame rate / minimum frame
-     * duration that is possible for a given stream configuration.</p>
+     * <p>The necessary information for the application, given the model above, is provided via
+     * {@link ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS }.
+     * These are used to determine the maximum frame rate / minimum frame duration that is
+     * possible for a given stream configuration.</p>
      * <p>Specifically, the application can use the following rules to
      * determine the minimum frame duration it can request from the camera
      * device:</p>
      * <ol>
-     * <li>Let the set of currently configured input/output streams
-     * be called <code>S</code>.</li>
-     * <li>Find the minimum frame durations for each stream in <code>S</code>, by looking
-     * it up in {@link ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS}
-     * (with its respective size/format). Let this set of frame durations be
-     * called <code>F</code>.</li>
-     * <li>For any given request <code>R</code>, the minimum frame duration allowed
-     * for <code>R</code> is the maximum out of all values in <code>F</code>. Let the streams
-     * used in <code>R</code> be called <code>S_r</code>.</li>
+     * <li>Let the set of currently configured input/output streams be called <code>S</code>.</li>
+     * <li>Find the minimum frame durations for each stream in <code>S</code>, by looking it up in {@link ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS }
+     * (with its respective size/format). Let this set of frame durations be called <code>F</code>.</li>
+     * <li>For any given request <code>R</code>, the minimum frame duration allowed for <code>R</code> is the maximum
+     * out of all values in <code>F</code>. Let the streams used in <code>R</code> be called <code>S_r</code>.</li>
      * </ol>
-     * <p>If none of the streams in <code>S_r</code> have a stall time (listed in {@link
-     * ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS}
-     * using its respective size/format), then the frame duration in <code>F</code>
-     * determines the steady state frame rate that the application will get
-     * if it uses <code>R</code> as a repeating request. Let this special kind of
-     * request be called <code>Rsimple</code>.</p>
-     * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
-     * by a single capture of a new request <code>Rstall</code> (which has at least
-     * one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
-     * same minimum frame duration this will not cause a frame rate loss
-     * if all buffers from the previous <code>Rstall</code> have already been
-     * delivered.</p>
-     * <p>For more details about stalling, see
-     * {@link ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS}.</p>
+     * <p>If none of the streams in <code>S_r</code> have a stall time (listed in {@link ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS }
+     * using its respective size/format), then the frame duration in <code>F</code> determines the steady
+     * state frame rate that the application will get if it uses <code>R</code> as a repeating request. Let
+     * this special kind of request be called <code>Rsimple</code>.</p>
+     * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved by a single capture of a
+     * new request <code>Rstall</code> (which has at least one in-use stream with a non-0 stall time) and if
+     * <code>Rstall</code> has the same minimum frame duration this will not cause a frame rate loss if all
+     * buffers from the previous <code>Rstall</code> have already been delivered.</p>
+     * <p>For more details about stalling, see {@link ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS }.</p>
      * <p>This control is only effective if ACAMERA_CONTROL_AE_MODE or ACAMERA_CONTROL_MODE is set to
      * OFF; otherwise the auto-exposure algorithm will override this value.</p>
      *
@@ -3567,14 +3551,12 @@
      * timestamps for other captures from the same camera device, but are
      * not guaranteed to be comparable to any other time source.</p>
      * <p>When ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE <code>==</code> REALTIME, the
-     * timestamps measure time in the same timebase as
-     * <a href="https://developer.android.com/reference/android/os/SystemClock.html#elapsedRealtimeNanos">elapsedRealtimeNanos</a>
-     * (or CLOCK_BOOTTIME), and they can
+     * timestamps measure time in the same timebase as <a href="https://developer.android.com/reference/android/os/SystemClock.html#elapsedRealtimeNanos">SystemClock#elapsedRealtimeNanos</a>, and they can
      * be compared to other timestamps from other subsystems that
      * are using that base.</p>
      * <p>For reprocessing, the timestamp will match the start of exposure of
-     * the input image, i.e. {@link CaptureResult#SENSOR_TIMESTAMP the
-     * timestamp} in the TotalCaptureResult that was used to create the
+     * the input image, i.e. <a href="https://developer.android.com/reference/CaptureResult.html#SENSOR_TIMESTAMP">the
+     * timestamp</a> in the TotalCaptureResult that was used to create the
      * reprocess capture request.</p>
      *
      * @see ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE
@@ -3775,7 +3757,6 @@
      * optically shielded pixel areas. By blocking light, these pixels
      * provides a reliable black reference for black level compensation
      * in active array region.</p>
-     * <p>The data representation is int[4], which maps to (left, top, width, height).</p>
      * <p>This key provides a list of disjoint rectangles specifying the
      * regions of optically shielded (with metal shield) black pixel
      * regions if the camera device is capable of reading out these black
@@ -3785,6 +3766,7 @@
      * black level of each captured raw images.</p>
      * <p>When this key is reported, the ACAMERA_SENSOR_DYNAMIC_BLACK_LEVEL and
      * ACAMERA_SENSOR_DYNAMIC_WHITE_LEVEL will also be reported.</p>
+     * <p>The data representation is <code>int[4]</code>, which maps to <code>(left, top, width, height)</code>.</p>
      *
      * @see ACAMERA_SENSOR_BLACK_LEVEL_PATTERN
      * @see ACAMERA_SENSOR_DYNAMIC_BLACK_LEVEL
@@ -3825,9 +3807,8 @@
      * layout key (see ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT), i.e. the
      * nth value given corresponds to the black level offset for the nth
      * color channel listed in the CFA.</p>
-     * <p>This key will be available if ACAMERA_SENSOR_OPTICAL_BLACK_REGIONS is
-     * available or the camera device advertises this key via
-     * {@link ACAMERA_REQUEST_AVAILABLE_RESULT_KEYS}.</p>
+     * <p>This key will be available if ACAMERA_SENSOR_OPTICAL_BLACK_REGIONS is available or the
+     * camera device advertises this key via {@link ACAMERA_REQUEST_AVAILABLE_RESULT_KEYS }.</p>
      *
      * @see ACAMERA_SENSOR_BLACK_LEVEL_PATTERN
      * @see ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
@@ -3853,7 +3834,7 @@
      * estimated white level for each frame.</p>
      * <p>This key will be available if ACAMERA_SENSOR_OPTICAL_BLACK_REGIONS is
      * available or the camera device advertises this key via
-     * {@link ACAMERA_REQUEST_AVAILABLE_RESULT_KEYS}.</p>
+     * {@link ACAMERA_REQUEST_AVAILABLE_RESULT_KEYS }.</p>
      *
      * @see ACAMERA_SENSOR_BLACK_LEVEL_PATTERN
      * @see ACAMERA_SENSOR_INFO_WHITE_LEVEL
@@ -3882,13 +3863,13 @@
      * <p>This rectangle is defined relative to the full pixel array; (0,0) is the top-left of
      * the full pixel array, and the size of the full pixel array is given by
      * ACAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE.</p>
-     * <p>The data representation is int[4], which maps to (left, top, width, height).</p>
      * <p>The coordinate system for most other keys that list pixel coordinates, including
      * ACAMERA_SCALER_CROP_REGION, is defined relative to the active array rectangle given in
      * this field, with <code>(0, 0)</code> being the top-left of this rectangle.</p>
      * <p>The active array may be smaller than the full pixel array, since the full array may
      * include black calibration pixels or other inactive regions, and geometric correction
      * resulting in scaling or cropping may have been applied.</p>
+     * <p>The data representation is <code>int[4]</code>, which maps to <code>(left, top, width, height)</code>.</p>
      *
      * @see ACAMERA_SCALER_CROP_REGION
      * @see ACAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE
@@ -3960,8 +3941,7 @@
      * <p>Attempting to use frame durations beyond the maximum will result in the frame
      * duration being clipped to the maximum. See that control for a full definition of frame
      * durations.</p>
-     * <p>Refer to {@link
-     * ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS}
+     * <p>Refer to {@link ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS }
      * for the minimum frame duration values.</p>
      */
     ACAMERA_SENSOR_INFO_MAX_FRAME_DURATION =                    // int64
@@ -4000,9 +3980,9 @@
      * the raw buffers produced by this sensor.</p>
      * <p>If a camera device supports raw sensor formats, either this or
      * ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE is the maximum dimensions for the raw
-     * output formats listed in ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS (this depends on
-     * whether or not the image sensor returns buffers containing pixels that are not
-     * part of the active array region for blacklevel calibration or other purposes).</p>
+     * output formats listed in {@link ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS }
+     * (this depends on whether or not the image sensor returns buffers containing pixels that
+     * are not part of the active array region for blacklevel calibration or other purposes).</p>
      * <p>Some parts of the full pixel array may not receive light from the scene,
      * or be otherwise inactive.  The ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE key
      * defines the rectangle of active pixels that will be included in processed image
@@ -4092,7 +4072,6 @@
      *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
      * </ul></p>
      *
-     * <p>The data representation is int[4], which maps to (left, top, width, height).</p>
      * <p>This is the rectangle representing the size of the active region of the sensor (i.e.
      * the region that actually receives light from the scene) before any geometric correction
      * has been applied, and should be treated as the active region rectangle for any of the
@@ -4143,6 +4122,7 @@
      * ACAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE.</p>
      * <p>The pre-correction active array may be smaller than the full pixel array, since the
      * full array may include black calibration pixels or other inactive regions.</p>
+     * <p>The data representation is <code>int[4]</code>, which maps to <code>(left, top, width, height)</code>.</p>
      *
      * @see ACAMERA_LENS_RADIAL_DISTORTION
      * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -4302,10 +4282,10 @@
      *   <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
      * </ul></p>
      *
-     * <p>The data representation is int[4], which maps to (left, top, width, height).</p>
      * <p>The coordinate system is that of ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE, with
      * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
-     * <p>Only available if ACAMERA_STATISTICS_FACE_DETECT_MODE != OFF</p>
+     * <p>Only available if ACAMERA_STATISTICS_FACE_DETECT_MODE != OFF
+     * The data representation is <code>int[4]</code>, which maps to <code>(left, top, width, height)</code>.</p>
      *
      * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
      * @see ACAMERA_STATISTICS_FACE_DETECT_MODE
@@ -4832,7 +4812,7 @@
      * <p>See the individual level enums for full descriptions of the supported capabilities.  The
      * ACAMERA_REQUEST_AVAILABLE_CAPABILITIES entry describes the device's capabilities at a
      * finer-grain level, if needed. In addition, many controls have their available settings or
-     * ranges defined in individual metadata tag entries in this document.</p>
+     * ranges defined in individual entries from {@link ACameraManager_getCameraCharacteristics }.</p>
      * <p>Some features are not part of any particular hardware level or capability and must be
      * queried separately. These include:</p>
      * <ul>
@@ -6157,13 +6137,13 @@
     ACAMERA_EDGE_MODE_HIGH_QUALITY                                   = 2,
 
     /**
-     * <p>Edge enhancement is applied at different levels for different output streams,
-     * based on resolution. Streams at maximum recording resolution (see {@link
-     * ACameraDevice_createCaptureSession}) or below have
-     * edge enhancement applied, while higher-resolution streams have no edge enhancement
-     * applied. The level of edge enhancement for low-resolution streams is tuned so that
-     * frame rate is not impacted, and the quality is equal to or better than FAST (since it
-     * is only applied to lower-resolution outputs, quality may improve from FAST).</p>
+     * <p>Edge enhancement is applied at different
+     * levels for different output streams, based on resolution. Streams at maximum recording
+     * resolution (see {@link ACameraDevice_createCaptureSession })
+     * or below have edge enhancement applied, while higher-resolution streams have no edge
+     * enhancement applied. The level of edge enhancement for low-resolution streams is tuned
+     * so that frame rate is not impacted, and the quality is equal to or better than FAST
+     * (since it is only applied to lower-resolution outputs, quality may improve from FAST).</p>
      * <p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
      * with YUV or PRIVATE reprocessing, where the application continuously captures
      * high-resolution intermediate buffers into a circular buffer, from which a final image is
@@ -6412,13 +6392,12 @@
 
     /**
      * <p>Noise reduction is applied at different levels for different output streams,
-     * based on resolution. Streams at maximum recording resolution (see {@link
-     * ACameraDevice_createCaptureSession}) or below have noise
-     * reduction applied, while higher-resolution streams have MINIMAL (if supported) or no
-     * noise reduction applied (if MINIMAL is not supported.) The degree of noise reduction
-     * for low-resolution streams is tuned so that frame rate is not impacted, and the quality
-     * is equal to or better than FAST (since it is only applied to lower-resolution outputs,
-     * quality may improve from FAST).</p>
+     * based on resolution. Streams at maximum recording resolution (see {@link ACameraDevice_createCaptureSession })
+     * or below have noise reduction applied, while higher-resolution streams have MINIMAL (if
+     * supported) or no noise reduction applied (if MINIMAL is not supported.) The degree of
+     * noise reduction for low-resolution streams is tuned so that frame rate is not impacted,
+     * and the quality is equal to or better than FAST (since it is only applied to
+     * lower-resolution outputs, quality may improve from FAST).</p>
      * <p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
      * with YUV or PRIVATE reprocessing, where the application continuously captures
      * high-resolution intermediate buffers into a circular buffer, from which a final image is
@@ -6635,18 +6614,16 @@
      * to FAST. Additionally, maximum-resolution images can be captured at &gt;= 10 frames
      * per second.  Here, 'high resolution' means at least 8 megapixels, or the maximum
      * resolution of the device, whichever is smaller.</p>
-     * <p>More specifically, this means that at least one output {@link
-     * AIMAGE_FORMAT_YUV_420_888} size listed in
-     * {@link ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS} is larger or equal to the
-     * 'high resolution' defined above, and can be captured at at least 20 fps.
-     * For the largest {@link AIMAGE_FORMAT_YUV_420_888} size listed in
-     * {@link ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS}, camera device can capture this
-     * size for at least 10 frames per second.
-     * Also the ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES entry lists at least one FPS range
-     * where the minimum FPS is &gt;= 1 / minimumFrameDuration for the largest YUV_420_888 size.</p>
-     * <p>If the device supports the {@link AIMAGE_FORMAT_RAW10}, {@link
-     * AIMAGE_FORMAT_RAW12}, then those can also be captured at the same rate
-     * as the maximum-size YUV_420_888 resolution is.</p>
+     * <p>More specifically, this means that at least one output {@link AIMAGE_FORMAT_YUV_420_888 } size listed in
+     * {@link ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS }
+     * is larger or equal to the 'high resolution' defined above, and can be captured at at
+     * least 20 fps.  For the largest {@link AIMAGE_FORMAT_YUV_420_888 } size listed in
+     * {@link ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS },
+     * camera device can capture this size for at least 10 frames per second.  Also the
+     * ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES entry lists at least one FPS range where
+     * the minimum FPS is &gt;= 1 / minimumFrameDuration for the largest YUV_420_888 size.</p>
+     * <p>If the device supports the {@link AIMAGE_FORMAT_RAW10 }, {@link AIMAGE_FORMAT_RAW12 }, then those can also be
+     * captured at the same rate as the maximum-size YUV_420_888 resolution is.</p>
      * <p>In addition, the ACAMERA_SYNC_MAX_LATENCY field is guaranted to have a value between 0
      * and 4, inclusive. ACAMERA_CONTROL_AE_LOCK_AVAILABLE and ACAMERA_CONTROL_AWB_LOCK_AVAILABLE
      * are also guaranteed to be <code>true</code> so burst capture with these two locks ON yields
@@ -6663,13 +6640,13 @@
      * <p>The camera device can produce depth measurements from its field of view.</p>
      * <p>This capability requires the camera device to support the following:</p>
      * <ul>
-     * <li>{@link AIMAGE_FORMAT_DEPTH16} is supported as an output format.</li>
-     * <li>{@link AIMAGE_FORMAT_DEPTH_POINT_CLOUD} is optionally supported as an
-     *   output format.</li>
-     * <li>This camera device, and all camera devices with the same ACAMERA_LENS_FACING,
-     *   will list the following calibration entries in {@link ACameraMetadata} from both
-     *   {@link ACameraManager_getCameraCharacteristics} and
-     *   {@link ACameraCaptureSession_captureCallback_result}:<ul>
+     * <li>{@link AIMAGE_FORMAT_DEPTH16 } is supported as
+     *   an output format.</li>
+     * <li>{@link AIMAGE_FORMAT_DEPTH_POINT_CLOUD } is
+     *   optionally supported as an output format.</li>
+     * <li>This camera device, and all camera devices with the same ACAMERA_LENS_FACING, will
+     *   list the following calibration metadata entries in both {@link ACameraManager_getCameraCharacteristics }
+     *   and {@link ACameraCaptureSession_captureCallback_result }:<ul>
      * <li>ACAMERA_LENS_POSE_TRANSLATION</li>
      * <li>ACAMERA_LENS_POSE_ROTATION</li>
      * <li>ACAMERA_LENS_INTRINSIC_CALIBRATION</li>
@@ -6683,8 +6660,7 @@
      * </ul>
      * <p>Generally, depth output operates at a slower frame rate than standard color capture,
      * so the DEPTH16 and DEPTH_POINT_CLOUD formats will commonly have a stall duration that
-     * should be accounted for (see
-     * {@link ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS}).
+     * should be accounted for (see {@link ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS }).
      * On a device that supports both depth and color-based output, to enable smooth preview,
      * using a repeating burst is recommended, where a depth-output target is only included
      * once every N frames, where N is the ratio between preview output rate and depth output
@@ -6918,8 +6894,8 @@
 
     /**
      * <p>Timestamps from ACAMERA_SENSOR_TIMESTAMP are in the same timebase as
-     * <a href="https://developer.android.com/reference/android/os/SystemClock.html#elapsedRealtimeNanos">elapsedRealtimeNanos</a>
-     * (or CLOCK_BOOTTIME), and they can be compared to other timestamps using that base.</p>
+     * <a href="https://developer.android.com/reference/android/os/SystemClock.html#elapsedRealtimeNanos">SystemClock#elapsedRealtimeNanos</a>,
+     * and they can be compared to other timestamps using that base.</p>
      *
      * @see ACAMERA_SENSOR_TIMESTAMP
      */
@@ -7104,7 +7080,7 @@
      * <p>This camera device does not have enough capabilities to qualify as a <code>FULL</code> device or
      * better.</p>
      * <p>Only the stream configurations listed in the <code>LEGACY</code> and <code>LIMITED</code> tables in the
-     * {@link ACameraDevice_createCaptureSession} documentation are guaranteed to be supported.</p>
+     * {@link ACameraDevice_createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
      * <p>All <code>LIMITED</code> devices support the <code>BACKWARDS_COMPATIBLE</code> capability, indicating basic
      * support for color image capture. The only exception is that the device may
      * alternatively support only the <code>DEPTH_OUTPUT</code> capability, if it can only output depth
@@ -7130,7 +7106,7 @@
     /**
      * <p>This camera device is capable of supporting advanced imaging applications.</p>
      * <p>The stream configurations listed in the <code>FULL</code>, <code>LEGACY</code> and <code>LIMITED</code> tables in the
-     * {@link ACameraDevice_createCaptureSession} documentation are guaranteed to be supported.</p>
+     * {@link ACameraDevice_createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
      * <p>A <code>FULL</code> device will support below capabilities:</p>
      * <ul>
      * <li><code>BURST_CAPTURE</code> capability (ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
@@ -7157,8 +7133,7 @@
 
     /**
      * <p>This camera device is running in backward compatibility mode.</p>
-     * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the {@link
-     * ACameraDevice_createCaptureSession} documentation are supported.</p>
+     * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the {@link ACameraDevice_createCaptureSession createCaptureSession} documentation are supported.</p>
      * <p>A <code>LEGACY</code> device does not support per-frame control, manual sensor control, manual
      * post-processing, arbitrary cropping regions, and has relaxed performance constraints.
      * No additional capabilities beyond <code>BACKWARD_COMPATIBLE</code> will ever be listed by a
@@ -7179,9 +7154,7 @@
      * <p>This camera device is capable of YUV reprocessing and RAW data capture, in addition to
      * FULL-level capabilities.</p>
      * <p>The stream configurations listed in the <code>LEVEL_3</code>, <code>RAW</code>, <code>FULL</code>, <code>LEGACY</code> and
-     * <code>LIMITED</code> tables in the {@link
-     * ACameraDevice_createCaptureSession}
-     * documentation are guaranteed to be supported.</p>
+     * <code>LIMITED</code> tables in the {@link ACameraDevice_createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
      * <p>The following additional capabilities are guaranteed to be supported:</p>
      * <ul>
      * <li><code>YUV_REPROCESSING</code> capability (ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index 41bb22b..0a8a6e9 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -6,6 +6,7 @@
     ACameraCaptureSession_getDevice;
     ACameraCaptureSession_setRepeatingRequest;
     ACameraCaptureSession_stopRepeating;
+    ACameraCaptureSession_updateSharedOutput;
     ACameraDevice_close;
     ACameraDevice_createCaptureRequest;
     ACameraDevice_createCaptureSession;
@@ -40,6 +41,9 @@
     ACaptureSessionOutputContainer_free;
     ACaptureSessionOutputContainer_remove;
     ACaptureSessionOutput_create;
+    ACaptureSessionSharedOutput_create;
+    ACaptureSessionSharedOutput_add;
+    ACaptureSessionSharedOutput_remove;
     ACaptureSessionOutput_free;
   local:
     *;
diff --git a/camera/tests/CameraZSLTests.cpp b/camera/tests/CameraZSLTests.cpp
index ecca354..02c6e2a 100644
--- a/camera/tests/CameraZSLTests.cpp
+++ b/camera/tests/CameraZSLTests.cpp
@@ -256,10 +256,10 @@
         ASSERT_TRUE(nullptr != surfaceControl.get());
         ASSERT_TRUE(surfaceControl->isValid());
 
-        SurfaceComposerClient::openGlobalTransaction();
-        ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(0x7fffffff));
-        ASSERT_EQ(NO_ERROR, surfaceControl->show());
-        SurfaceComposerClient::closeGlobalTransaction();
+        SurfaceComposerClient::Transaction{}
+                .setLayer(surfaceControl, 0x7fffffff)
+                .show(surfaceControl)
+                .apply();
 
         previewSurface = surfaceControl->getSurface();
         ASSERT_TRUE(previewSurface != NULL);
diff --git a/cmds/screenrecord/Android.mk b/cmds/screenrecord/Android.mk
index 7aa684a..5e83ed6 100644
--- a/cmds/screenrecord/Android.mk
+++ b/cmds/screenrecord/Android.mk
@@ -25,8 +25,8 @@
 	Program.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libmedia libutils libbinder libstagefright_foundation \
-	libjpeg libgui libcutils liblog libEGL libGLESv2
+	libstagefright libmedia libmedia_omx libutils libbinder libstagefright_foundation \
+	libjpeg libui libgui libcutils liblog libEGL libGLESv2
 
 LOCAL_C_INCLUDES := \
 	frameworks/av/media/libstagefright \
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index bc32bbe..f9e4639 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -213,7 +213,9 @@
  * Sets the display projection, based on the display dimensions, video size,
  * and device orientation.
  */
-static status_t setDisplayProjection(const sp<IBinder>& dpy,
+static status_t setDisplayProjection(
+        SurfaceComposerClient::Transaction& t,
+        const sp<IBinder>& dpy,
         const DisplayInfo& mainDpyInfo) {
 
     // Set the region of the layer stack we're interested in, which in our
@@ -279,7 +281,7 @@
         }
     }
 
-    SurfaceComposerClient::setDisplayProjection(dpy,
+    t.setDisplayProjection(dpy,
             gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0,
             layerStackRect, displayRect);
     return NO_ERROR;
@@ -295,11 +297,11 @@
     sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
             String8("ScreenRecorder"), false /*secure*/);
 
-    SurfaceComposerClient::openGlobalTransaction();
-    SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer);
-    setDisplayProjection(dpy, mainDpyInfo);
-    SurfaceComposerClient::setDisplayLayerStack(dpy, 0);    // default stack
-    SurfaceComposerClient::closeGlobalTransaction();
+    SurfaceComposerClient::Transaction t;
+    t.setDisplaySurface(dpy, bufferProducer);
+    setDisplayProjection(t, dpy, mainDpyInfo);
+    t.setDisplayLayerStack(dpy, 0);    // default stack
+    t.apply();
 
     *pDisplayHandle = dpy;
 
@@ -379,9 +381,9 @@
                         ALOGW("getDisplayInfo(main) failed: %d", err);
                     } else if (orientation != mainDpyInfo.orientation) {
                         ALOGD("orientation changed, now %d", mainDpyInfo.orientation);
-                        SurfaceComposerClient::openGlobalTransaction();
-                        setDisplayProjection(virtualDpy, mainDpyInfo);
-                        SurfaceComposerClient::closeGlobalTransaction();
+                        SurfaceComposerClient::Transaction t;
+                        setDisplayProjection(t, virtualDpy, mainDpyInfo);
+                        t.apply();
                         orientation = mainDpyInfo.orientation;
                     }
                 }
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index f647ffd..c62833d 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -8,9 +8,9 @@
         SineSource.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libmedia libutils libbinder libstagefright_foundation \
-        libjpeg libgui libcutils liblog \
-        libhidlmemory \
+        libstagefright libmedia libmedia_omx libmediaextractor libutils libbinder \
+        libstagefright_foundation libjpeg libui libgui libcutils liblog \
+        libhidlbase \
         android.hardware.media.omx@1.0 \
 
 LOCAL_C_INCLUDES:= \
@@ -36,7 +36,8 @@
         record.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libmedia liblog libutils libbinder libstagefright_foundation
+        libstagefright libmedia libmediaextractor liblog libutils libbinder \
+        libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
@@ -60,7 +61,8 @@
         recordvideo.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libmedia liblog libutils libbinder libstagefright_foundation
+        libstagefright libmedia libmediaextractor liblog libutils libbinder \
+        libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
@@ -85,7 +87,8 @@
         audioloop.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright libmedia liblog libutils libbinder libstagefright_foundation
+        libstagefright libmedia libmediaextractor liblog libutils libbinder \
+        libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
@@ -107,7 +110,7 @@
         stream.cpp    \
 
 LOCAL_SHARED_LIBRARIES := \
-        libstagefright liblog libutils libbinder libgui \
+        libstagefright liblog libutils libbinder libui libgui \
         libstagefright_foundation libmedia libcutils
 
 LOCAL_C_INCLUDES:= \
@@ -132,7 +135,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
         libstagefright liblog libutils libbinder libstagefright_foundation \
-        libmedia libaudioclient libgui libcutils
+        libmedia libmedia_omx libaudioclient libui libgui libcutils
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
@@ -163,6 +166,8 @@
         libbinder \
         libstagefright_foundation \
         libmedia \
+        libmedia_omx \
+        libui \
         libgui \
         libcutils \
         libRScpp \
diff --git a/cmds/stagefright/SineSource.h b/cmds/stagefright/SineSource.h
index be05661..f1fb96d 100644
--- a/cmds/stagefright/SineSource.h
+++ b/cmds/stagefright/SineSource.h
@@ -2,7 +2,7 @@
 
 #define SINE_SOURCE_H_
 
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <utils/Compat.h>
 
 namespace android {
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index ed44b4d..67017eb 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -112,7 +112,7 @@
     looper->setName("audioloop");
     looper->start();
 
-    sp<IMediaSource> encoder = MediaCodecSource::Create(looper, meta, source);
+    sp<MediaSource> encoder = MediaCodecSource::Create(looper, meta, source);
 
     if (fileOut != NULL) {
         // target file specified, write encoded AMR output
@@ -128,7 +128,7 @@
         writer->stop();
     } else {
         // otherwise decode to speaker
-        sp<IMediaSource> decoder = SimpleDecodingSource::Create(encoder);
+        sp<MediaSource> decoder = SimpleDecodingSource::Create(encoder);
 
         if (playToSpeaker) {
             AudioPlayer *player = new AudioPlayer(NULL);
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index 3108a67..6a58467 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -430,10 +430,10 @@
         CHECK(control != NULL);
         CHECK(control->isValid());
 
-        SurfaceComposerClient::openGlobalTransaction();
-        CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
-        CHECK_EQ(control->show(), (status_t)OK);
-        SurfaceComposerClient::closeGlobalTransaction();
+        SurfaceComposerClient::Transaction{}
+                 .setLayer(control, INT_MAX)
+                 .show(control)
+                 .apply();
 
         surface = control->getSurface();
         CHECK(surface != NULL);
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
index f219e69..f24d2dd 100644
--- a/cmds/stagefright/mediafilter.cpp
+++ b/cmds/stagefright/mediafilter.cpp
@@ -764,10 +764,10 @@
         CHECK(control != NULL);
         CHECK(control->isValid());
 
-        SurfaceComposerClient::openGlobalTransaction();
-        CHECK_EQ((status_t)OK, control->setLayer(INT_MAX));
-        CHECK_EQ((status_t)OK, control->show());
-        SurfaceComposerClient::closeGlobalTransaction();
+        SurfaceComposerClient::Transaction{}
+                .setLayer(control, INT_MAX)
+                .show(control)
+                .apply();
 
         surface = control->getSurface();
         CHECK(surface != NULL);
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 94c2e96..073ee6b 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -17,6 +17,7 @@
 #include "SineSource.h"
 
 #include <binder/ProcessState.h>
+#include <media/MediaExtractor.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -27,7 +28,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaCodecSource.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/SimpleDecodingSource.h>
 #include <media/MediaPlayerInterface.h>
@@ -120,7 +121,7 @@
     sp<MediaSource> source;
 
     sp<MediaExtractor> extractor =
-        MediaExtractor::Create(new FileSource(filename));
+        MediaExtractorFactory::Create(new FileSource(filename));
     if (extractor == NULL) {
         return NULL;
     }
@@ -320,7 +321,7 @@
     looper->setName("record");
     looper->start();
 
-    sp<IMediaSource> encoder =
+    sp<MediaSource> encoder =
         MediaCodecSource::Create(looper, encMeta, audioSource);
 
     encoder->start();
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index 7a3c842..af39d46 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -303,7 +303,7 @@
     looper->setName("recordvideo");
     looper->start();
 
-    sp<IMediaSource> encoder =
+    sp<MediaSource> encoder =
         MediaCodecSource::Create(
                 looper, enc_meta, source, NULL /* consumer */,
                 preferSoftwareCodec ? MediaCodecSource::FLAG_PREFER_SOFTWARE_CODEC : 0);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index d70282b..ddc4b16 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -31,9 +31,11 @@
 
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
 #include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
-#include <media/IMediaCodecService.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -41,14 +43,14 @@
 #include <media/stagefright/foundation/AUtils.h>
 #include "include/NuCachedSource2.h"
 #include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
 #include <media/stagefright/JPEGSource.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/SimpleDecodingSource.h>
 #include <media/stagefright/Utils.h>
@@ -65,7 +67,6 @@
 #include <gui/SurfaceComposerClient.h>
 
 #include <android/hardware/media/omx/1.0/IOmx.h>
-#include <media/omx/1.0/WOmx.h>
 
 using namespace android;
 
@@ -141,7 +142,7 @@
     }
 }
 
-static void dumpSource(const sp<IMediaSource> &source, const String8 &filename) {
+static void dumpSource(const sp<MediaSource> &source, const String8 &filename) {
     FILE *out = fopen(filename.string(), "wb");
 
     CHECK_EQ((status_t)OK, source->start());
@@ -174,13 +175,13 @@
     out = NULL;
 }
 
-static void playSource(sp<IMediaSource> &source) {
+static void playSource(sp<MediaSource> &source) {
     sp<MetaData> meta = source->getFormat();
 
     const char *mime;
     CHECK(meta->findCString(kKeyMIMEType, &mime));
 
-    sp<IMediaSource> rawSource;
+    sp<MediaSource> rawSource;
     if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) {
         rawSource = source;
     } else {
@@ -404,7 +405,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 struct DetectSyncSource : public MediaSource {
-    explicit DetectSyncSource(const sp<IMediaSource> &source);
+    explicit DetectSyncSource(const sp<MediaSource> &source);
 
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
@@ -421,14 +422,14 @@
         OTHER,
     };
 
-    sp<IMediaSource> mSource;
+    sp<MediaSource> mSource;
     StreamType mStreamType;
     bool mSawFirstIDRFrame;
 
     DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource);
 };
 
-DetectSyncSource::DetectSyncSource(const sp<IMediaSource> &source)
+DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source)
     : mSource(source),
       mStreamType(OTHER),
       mSawFirstIDRFrame(false) {
@@ -510,7 +511,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 static void writeSourcesToMP4(
-        Vector<sp<IMediaSource> > &sources, bool syncInfoPresent) {
+        Vector<sp<MediaSource> > &sources, bool syncInfoPresent) {
 #if 0
     sp<MPEG4Writer> writer =
         new MPEG4Writer(gWriteMP4Filename.string());
@@ -528,7 +529,7 @@
     writer->setMaxFileDuration(60000000ll);
 
     for (size_t i = 0; i < sources.size(); ++i) {
-        sp<IMediaSource> source = sources.editItemAt(i);
+        sp<MediaSource> source = sources.editItemAt(i);
 
         CHECK_EQ(writer->addSource(
                     syncInfoPresent ? source : new DetectSyncSource(source)),
@@ -545,7 +546,7 @@
     writer->stop();
 }
 
-static void performSeekTest(const sp<IMediaSource> &source) {
+static void performSeekTest(const sp<MediaSource> &source) {
     CHECK_EQ((status_t)OK, source->start());
 
     int64_t durationUs;
@@ -909,37 +910,24 @@
     }
 
     if (listComponents) {
-        sp<IOMX> omx;
-        if (property_get_bool("persist.media.treble_omx", true)) {
-            using namespace ::android::hardware::media::omx::V1_0;
-            sp<IOmx> tOmx = IOmx::getService();
+        using ::android::hardware::hidl_vec;
+        using ::android::hardware::hidl_string;
+        using namespace ::android::hardware::media::omx::V1_0;
+        sp<IOmx> omx = IOmx::getService();
+        CHECK(omx.get() != nullptr);
 
-            CHECK(tOmx.get() != NULL);
-
-            omx = new utils::LWOmx(tOmx);
-        } else {
-            sp<IServiceManager> sm = defaultServiceManager();
-            sp<IBinder> binder = sm->getService(String16("media.codec"));
-            sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
-
-            CHECK(service.get() != NULL);
-
-            omx = service->getOMX();
-        }
-        CHECK(omx.get() != NULL);
-
-        List<IOMX::ComponentInfo> list;
-        omx->listNodes(&list);
-
-        for (List<IOMX::ComponentInfo>::iterator it = list.begin();
-             it != list.end(); ++it) {
-            printf("%s\t Roles: ", (*it).mName.string());
-            for (List<String8>::iterator itRoles = (*it).mRoles.begin() ;
-                    itRoles != (*it).mRoles.end() ; ++itRoles) {
-                printf("%s\t", (*itRoles).string());
-            }
-            printf("\n");
-        }
+        hidl_vec<IOmx::ComponentInfo> nodeList;
+        auto transStatus = omx->listNodes([](
+                const auto& status, const auto& nodeList) {
+                    CHECK(status == Status::OK);
+                    for (const auto& info : nodeList) {
+                        printf("%s\t Roles: ", info.mName.c_str());
+                        for (const auto& role : info.mRoles) {
+                            printf("%s\t", role.c_str());
+                        }
+                    }
+                });
+        CHECK(transStatus.isOk());
     }
 
     sp<SurfaceComposerClient> composerClient;
@@ -960,10 +948,10 @@
             CHECK(control != NULL);
             CHECK(control->isValid());
 
-            SurfaceComposerClient::openGlobalTransaction();
-            CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
-            CHECK_EQ(control->show(), (status_t)OK);
-            SurfaceComposerClient::closeGlobalTransaction();
+            SurfaceComposerClient::Transaction{}
+                    .setLayer(control, INT_MAX)
+                    .show(control)
+                    .apply();
 
             gSurface = control->getSurface();
             CHECK(gSurface != NULL);
@@ -988,7 +976,7 @@
         const char *filename = argv[k];
 
         sp<DataSource> dataSource =
-            DataSource::CreateFromURI(NULL /* httpService */, filename);
+            DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
 
         if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
             fprintf(stderr, "Unable to create data source.\n");
@@ -1002,8 +990,8 @@
             isJPEG = true;
         }
 
-        Vector<sp<IMediaSource> > mediaSources;
-        sp<IMediaSource> mediaSource;
+        Vector<sp<MediaSource> > mediaSources;
+        sp<MediaSource> mediaSource;
 
         if (isJPEG) {
             mediaSource = new JPEGSource(dataSource);
@@ -1022,7 +1010,7 @@
                 mediaSources.push(mediaSource);
             }
         } else {
-            sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
+            sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
 
             if (extractor == NULL) {
                 fprintf(stderr, "could not create extractor.\n");
@@ -1049,7 +1037,8 @@
                 bool haveAudio = false;
                 bool haveVideo = false;
                 for (size_t i = 0; i < numTracks; ++i) {
-                    sp<IMediaSource> source = extractor->getTrack(i);
+                    sp<MediaSource> source = CreateMediaSourceFromIMediaSource(
+                            extractor->getTrack(i));
                     if (source == nullptr) {
                         fprintf(stderr, "skip NULL track %zu, track count %zu.\n", i, numTracks);
                         continue;
@@ -1115,7 +1104,7 @@
                            thumbTimeUs, thumbTimeUs / 1E6);
                 }
 
-                mediaSource = extractor->getTrack(i);
+                mediaSource = CreateMediaSourceFromIMediaSource(extractor->getTrack(i));
                 if (mediaSource == nullptr) {
                     fprintf(stderr, "skip NULL track %zu, total tracks %zu.\n", i, numTracks);
                     return -1;
@@ -1128,7 +1117,7 @@
         } else if (dumpStream) {
             dumpSource(mediaSource, dumpStreamFilename);
         } else if (dumpPCMStream) {
-            sp<IMediaSource> decSource = SimpleDecodingSource::Create(mediaSource);
+            sp<MediaSource> decSource = SimpleDecodingSource::Create(mediaSource);
             dumpSource(decSource, dumpStreamFilename);
         } else if (seekTest) {
             performSeekTest(mediaSource);
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 2e1d240..b0199d8 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -21,15 +21,18 @@
 #include <binder/ProcessState.h>
 #include <cutils/properties.h> // for property_get
 
+#include <media/DataSource.h>
 #include <media/IMediaHTTPService.h>
 #include <media/IStreamSource.h>
+#include <media/MediaExtractor.h>
 #include <media/mediaplayer.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MPEG2TSWriter.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 
 #include <binder/IServiceManager.h>
@@ -161,11 +164,11 @@
     : mCurrentBufferIndex(-1),
       mCurrentBufferOffset(0) {
     sp<DataSource> dataSource =
-        DataSource::CreateFromURI(NULL /* httpService */, filename);
+        DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
 
     CHECK(dataSource != NULL);
 
-    sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
+    sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
     CHECK(extractor != NULL);
 
     mWriter = new MPEG2TSWriter(
@@ -182,7 +185,7 @@
             continue;
         }
 
-        sp<IMediaSource> track = extractor->getTrack(i);
+        sp<MediaSource> track = CreateMediaSourceFromIMediaSource(extractor->getTrack(i));
         if (track == nullptr) {
             fprintf(stderr, "skip NULL track %zu, total tracks %zu\n", i, numTracks);
             continue;
@@ -335,10 +338,10 @@
     CHECK(control != NULL);
     CHECK(control->isValid());
 
-    SurfaceComposerClient::openGlobalTransaction();
-    CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
-    CHECK_EQ(control->show(), (status_t)OK);
-    SurfaceComposerClient::closeGlobalTransaction();
+    SurfaceComposerClient::Transaction{}
+            .setLayer(control, INT_MAX)
+            .show(control)
+            .apply();
 
     sp<Surface> surface = control->getSurface();
     CHECK(surface != NULL);
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp b/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp
index cb69f91..eaa3390 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp
@@ -89,7 +89,7 @@
     // asset_id change. If it sends an EcmContainer with 2 Ecms with different
     // asset_ids (old and new) then it might be best to prefetch the Emm.
     if ((asset_.id() != 0) && (*asset_id != asset_.id())) {
-        ALOGW("Asset_id change from %" PRIu64 " to %" PRIu64, asset_.id(), *asset_id);
+        ALOGW("Asset_id change from %llu to %" PRIu64, asset_.id(), *asset_id);
         asset_.Clear();
     }
 
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.cpp b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
index 18cd9a4..500208b 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.cpp
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
@@ -146,7 +146,7 @@
     if (session == NULL) {
         return BAD_VALUE;
     }
-    ALOGV("ECM: size=%d", ecm.size());
+    ALOGV("ECM: size=%zu", ecm.size());
     ALOGV("ECM: data=%s", arrayToString(ecm).string());
 
     return OK;
@@ -156,7 +156,7 @@
     ALOGV("processEmm");
     Mutex::Autolock lock(mLock);
 
-    ALOGV("EMM: size=%d", emm.size());
+    ALOGV("EMM: size=%zu", emm.size());
     ALOGV("EMM: data=%s", arrayToString(emm).string());
 
     return OK;
diff --git a/drm/mediadrm/plugins/clearkey/Android.bp b/drm/mediadrm/plugins/clearkey/Android.bp
index 385815c..4b7a63c 100644
--- a/drm/mediadrm/plugins/clearkey/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/Android.bp
@@ -53,6 +53,10 @@
 
     export_include_dirs: ["."],
     export_static_lib_headers: ["libjsmn"],
+
+    sanitize: {
+        integer_overflow: true,
+    },
 }
 
 //########################################################################
diff --git a/include/OWNERS b/include/OWNERS
index 3cb6d9c..d6bd998 100644
--- a/include/OWNERS
+++ b/include/OWNERS
@@ -1,5 +1,5 @@
 elaurent@google.com
-gkasten@android.com
+gkasten@google.com
 hunga@google.com
 jtinker@google.com
 lajos@google.com
diff --git a/include/common_time/OWNERS b/include/common_time/OWNERS
new file mode 100644
index 0000000..f9cb567
--- /dev/null
+++ b/include/common_time/OWNERS
@@ -0,0 +1 @@
+gkasten@google.com
diff --git a/include/media/AudioClient.h b/include/media/AudioClient.h
deleted file mode 100644
index 9efd76d..0000000
--- a/include/media/AudioClient.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#ifndef ANDROID_AUDIO_CLIENT_H
-#define ANDROID_AUDIO_CLIENT_H
-
-#include <system/audio.h>
-#include <utils/String16.h>
-
-namespace android {
-
-class AudioClient {
- public:
-    AudioClient() :
-        clientUid(-1), clientPid(-1), packageName("") {}
-
-    uid_t clientUid;
-    pid_t clientPid;
-    String16 packageName;
-};
-
-}; // namespace android
-
-#endif  // ANDROID_AUDIO_CLIENT_H
diff --git a/include/media/AudioClient.h b/include/media/AudioClient.h
new file mode 120000
index 0000000..feac9b9
--- /dev/null
+++ b/include/media/AudioClient.h
@@ -0,0 +1 @@
+media/libaudioclient/include/media/AudioClient.h
\ No newline at end of file
diff --git a/include/media/DataSource.h b/include/media/DataSource.h
new file mode 120000
index 0000000..905bec1
--- /dev/null
+++ b/include/media/DataSource.h
@@ -0,0 +1 @@
+../../media/libmediaextractor/include/media/DataSource.h
\ No newline at end of file
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
deleted file mode 120000
index 7fbf8f2..0000000
--- a/include/media/IAudioRecord.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioRecord.h
\ No newline at end of file
diff --git a/include/media/IHDCP.h b/include/media/IHDCP.h
deleted file mode 120000
index 9d4568e..0000000
--- a/include/media/IHDCP.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IHDCP.h
\ No newline at end of file
diff --git a/include/media/MediaExtractor.h b/include/media/MediaExtractor.h
new file mode 120000
index 0000000..4b35fe1
--- /dev/null
+++ b/include/media/MediaExtractor.h
@@ -0,0 +1 @@
+../../media/libmediaextractor/include/media/MediaExtractor.h
\ No newline at end of file
diff --git a/include/media/MediaSource.h b/include/media/MediaSource.h
new file mode 120000
index 0000000..2e147c4
--- /dev/null
+++ b/include/media/MediaSource.h
@@ -0,0 +1 @@
+../../media/libmediaextractor/include/media/MediaSource.h
\ No newline at end of file
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
index 302641f..a3aaece 100644
--- a/include/media/VolumeShaper.h
+++ b/include/media/VolumeShaper.h
@@ -37,6 +37,8 @@
 
 namespace android {
 
+namespace media {
+
 // The native VolumeShaper class mirrors the java VolumeShaper class;
 // in addition, the native class contains implementation for actual operation.
 //
@@ -101,7 +103,7 @@
      * See "frameworks/base/media/java/android/media/VolumeShaper.java" for
      * details on the Java implementation.
      */
-    class Configuration : public Interpolator<S, T>, public RefBase {
+    class Configuration : public Interpolator<S, T>, public RefBase, public Parcelable {
     public:
         // Must match with VolumeShaper.java in frameworks/base.
         enum Type : int32_t {
@@ -283,7 +285,7 @@
         }
 
         // The parcel layout must match VolumeShaper.java
-        status_t writeToParcel(Parcel *parcel) const {
+        status_t writeToParcel(Parcel *parcel) const override {
             if (parcel == nullptr) return BAD_VALUE;
             return parcel->writeInt32((int32_t)mType)
                     ?: parcel->writeInt32(mId)
@@ -294,17 +296,17 @@
                             ?: Interpolator<S, T>::writeToParcel(parcel);
         }
 
-        status_t readFromParcel(const Parcel &parcel) {
+        status_t readFromParcel(const Parcel *parcel) override {
             int32_t type, optionFlags;
-            return parcel.readInt32(&type)
+            return parcel->readInt32(&type)
                     ?: setType((Type)type)
-                    ?: parcel.readInt32(&mId)
+                    ?: parcel->readInt32(&mId)
                     ?: mType == TYPE_ID
                         ? NO_ERROR
-                        : parcel.readInt32(&optionFlags)
+                        : parcel->readInt32(&optionFlags)
                             ?: setOptionFlags((OptionFlag)optionFlags)
-                            ?: parcel.readDouble(&mDurationMs)
-                            ?: Interpolator<S, T>::readFromParcel(parcel)
+                            ?: parcel->readDouble(&mDurationMs)
+                            ?: Interpolator<S, T>::readFromParcel(*parcel)
                             ?: checkCurve();
         }
 
@@ -336,7 +338,7 @@
      * See "frameworks/base/media/java/android/media/VolumeShaper.java" for
      * details on the Java implementation.
      */
-    class Operation : public RefBase {
+    class Operation : public RefBase, public Parcelable {
     public:
         // Must match with VolumeShaper.java.
         enum Flag : int32_t {
@@ -418,18 +420,18 @@
             return NO_ERROR;
         }
 
-        status_t writeToParcel(Parcel *parcel) const {
+        status_t writeToParcel(Parcel *parcel) const override {
             if (parcel == nullptr) return BAD_VALUE;
             return parcel->writeInt32((int32_t)mFlags)
                     ?: parcel->writeInt32(mReplaceId)
                     ?: parcel->writeFloat(mXOffset);
         }
 
-        status_t readFromParcel(const Parcel &parcel) {
+        status_t readFromParcel(const Parcel *parcel) override {
             int32_t flags;
-            return parcel.readInt32(&flags)
-                    ?: parcel.readInt32(&mReplaceId)
-                    ?: parcel.readFloat(&mXOffset)
+            return parcel->readInt32(&flags)
+                    ?: parcel->readInt32(&mReplaceId)
+                    ?: parcel->readFloat(&mXOffset)
                     ?: setFlags((Flag)flags);
         }
 
@@ -455,7 +457,7 @@
      * See "frameworks/base/media/java/android/media/VolumeShaper.java" for
      * details on the Java implementation.
      */
-    class State : public RefBase {
+    class State : public RefBase, public Parcelable {
     public:
         State(T volume, S xOffset)
             : mVolume(volume)
@@ -481,15 +483,15 @@
             mXOffset = xOffset;
         }
 
-        status_t writeToParcel(Parcel *parcel) const {
+        status_t writeToParcel(Parcel *parcel) const override {
             if (parcel == nullptr) return BAD_VALUE;
             return parcel->writeFloat(mVolume)
                     ?: parcel->writeFloat(mXOffset);
         }
 
-        status_t readFromParcel(const Parcel &parcel) {
-            return parcel.readFloat(&mVolume)
-                     ?: parcel.readFloat(&mXOffset);
+        status_t readFromParcel(const Parcel *parcel) override {
+            return parcel->readFloat(&mVolume)
+                     ?: parcel->readFloat(&mXOffset);
         }
 
         std::string toString() const {
@@ -1020,6 +1022,8 @@
     std::list<VolumeShaper> mVolumeShapers; // list provides stable iterators on erase
 }; // VolumeHandler
 
+} // namespace media
+
 } // namespace android
 
 #pragma pop_macro("LOG_TAG")
diff --git a/include/media/nbaio/NBLog.h b/include/media/nbaio/NBLog.h
deleted file mode 120000
index c35401e..0000000
--- a/include/media/nbaio/NBLog.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/NBLog.h
\ No newline at end of file
diff --git a/include/media/nbaio/PerformanceAnalysis.h b/include/media/nbaio/PerformanceAnalysis.h
deleted file mode 120000
index 7acfc90..0000000
--- a/include/media/nbaio/PerformanceAnalysis.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
\ No newline at end of file
diff --git a/include/media/nblog/NBLog.h b/include/media/nblog/NBLog.h
new file mode 120000
index 0000000..3cc366c
--- /dev/null
+++ b/include/media/nblog/NBLog.h
@@ -0,0 +1 @@
+../../../media/libnblog/include/media/nblog/NBLog.h
\ No newline at end of file
diff --git a/include/media/nblog/PerformanceAnalysis.h b/include/media/nblog/PerformanceAnalysis.h
new file mode 120000
index 0000000..6ead3bc
--- /dev/null
+++ b/include/media/nblog/PerformanceAnalysis.h
@@ -0,0 +1 @@
+../../../media/libnblog/include/media/nblog/PerformanceAnalysis.h
\ No newline at end of file
diff --git a/include/media/nblog/ReportPerformance.h b/include/media/nblog/ReportPerformance.h
new file mode 120000
index 0000000..e9b8e80
--- /dev/null
+++ b/include/media/nblog/ReportPerformance.h
@@ -0,0 +1 @@
+../../../media/libnblog/include/media/nblog/ReportPerformance.h
\ No newline at end of file
diff --git a/include/private/media/OWNERS b/include/private/media/OWNERS
new file mode 100644
index 0000000..21723ba
--- /dev/null
+++ b/include/private/media/OWNERS
@@ -0,0 +1,3 @@
+elaurent@google.com
+gkasten@google.com
+hunga@google.com
diff --git a/include/soundtrigger/OWNERS b/include/soundtrigger/OWNERS
new file mode 100644
index 0000000..e83f6b9
--- /dev/null
+++ b/include/soundtrigger/OWNERS
@@ -0,0 +1,2 @@
+elaurent@google.com
+thorntonc@google.com
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index 3ee7494..ee87751 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -3,7 +3,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
-	main_audioserver.cpp
+	main_audioserver.cpp \
+	../libaudioclient/aidl/android/media/IAudioRecord.aidl
 
 LOCAL_SHARED_LIBRARIES := \
 	libaaudioservice \
@@ -12,11 +13,12 @@
 	libbinder \
 	libcutils \
 	liblog \
+	libhidltransport \
+	libhwbinder \
 	libmedialogservice \
 	libnbaio \
 	libsoundtriggerservice \
-	libutils \
-	libhwbinder
+	libutils
 
 # TODO oboeservice is the old folder name for aaudioservice. It will be changed.
 LOCAL_C_INCLUDES := \
@@ -36,6 +38,9 @@
 	$(call include-path-for, audio-utils) \
 	external/sonic \
 
+LOCAL_AIDL_INCLUDES := \
+        frameworks/av/media/libaudioclient/aidl
+
 # If AUDIOSERVER_MULTILIB in device.mk is non-empty then it is used to control
 # the LOCAL_MULTILIB for all audioserver exclusive libraries.
 # This is relevant for 64 bit architectures where either or both
diff --git a/media/audioserver/OWNERS b/media/audioserver/OWNERS
new file mode 100644
index 0000000..f9cb567
--- /dev/null
+++ b/media/audioserver/OWNERS
@@ -0,0 +1 @@
+gkasten@google.com
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index 9d42bce..75675a9 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -1,10 +1,13 @@
 service audioserver /system/bin/audioserver
-    class main
+    class core
     user audioserver
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
     group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
     ioprio rt 4
     writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    onrestart restart vendor.audio-hal-2-0
+    # Keep the original service name for backward compatibility when upgrading
+    # O-MR1 devices with framework-only.
     onrestart restart audio-hal-2-0
 
 on property:vts.native_server.on=1
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
index 474ef97..5a9d1bb 100644
--- a/media/audioserver/main_audioserver.cpp
+++ b/media/audioserver/main_audioserver.cpp
@@ -25,12 +25,9 @@
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
+#include <hidl/HidlTransportSupport.h>
 #include <utils/Log.h>
 
-// FIXME: remove when BUG 31748996 is fixed
-#include <hwbinder/IPCThreadState.h>
-#include <hwbinder/ProcessState.h>
-
 // from LOCAL_C_INCLUDES
 #include "aaudio/AAudioTesting.h"
 #include "AudioFlinger.h"
@@ -128,6 +125,7 @@
             prctl(PR_SET_PDEATHSIG, SIGKILL);   // if parent media.log dies before me, kill me also
             setpgid(0, 0);                      // but if I die first, don't kill my parent
         }
+        android::hardware::configureRpcThreadpool(4, false /*callerWillJoin*/);
         sp<ProcessState> proc(ProcessState::self());
         sp<IServiceManager> sm = defaultServiceManager();
         ALOGI("ServiceManager: %p", sm.get());
@@ -145,10 +143,6 @@
 
         SoundTriggerHwService::instantiate();
         ProcessState::self()->startThreadPool();
-
-// FIXME: remove when BUG 31748996 is fixed
-        android::hardware::ProcessState::self()->startThreadPool();
-
         IPCThreadState::self()->joinThreadPool();
     }
 }
diff --git a/media/common_time/OWNERS b/media/common_time/OWNERS
new file mode 100644
index 0000000..f9cb567
--- /dev/null
+++ b/media/common_time/OWNERS
@@ -0,0 +1 @@
+gkasten@google.com
diff --git a/media/extractors/Android.bp b/media/extractors/Android.bp
new file mode 100644
index 0000000..e8176cf
--- /dev/null
+++ b/media/extractors/Android.bp
@@ -0,0 +1,3 @@
+subdirs = [
+    "*",
+]
diff --git a/media/libstagefright/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
similarity index 90%
rename from media/libstagefright/AACExtractor.cpp
rename to media/extractors/aac/AACExtractor.cpp
index 7449aa7..716fe31 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -18,17 +18,16 @@
 #define LOG_TAG "AACExtractor"
 #include <utils/Log.h>
 
-#include "include/AACExtractor.h"
-#include "include/avc_utils.h"
-
+#include "AACExtractor.h"
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 
@@ -140,13 +139,8 @@
     sp<AMessage> meta = _meta;
 
     if (meta == NULL) {
-        String8 mimeType;
-        float confidence;
-        sp<AMessage> _meta;
-
-        if (!SniffAAC(mDataSource, &mimeType, &confidence, &meta)) {
-            return;
-        }
+        ALOGE("no metadata specified");
+        return;
     }
 
     int64_t offset;
@@ -213,7 +207,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-sp<IMediaSource> AACExtractor::getTrack(size_t index) {
+sp<MediaSource> AACExtractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -333,7 +327,13 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool SniffAAC(
+static MediaExtractor* CreateExtractor(
+        const sp<DataSource> &source,
+        const sp<AMessage>& meta) {
+    return new AACExtractor(source, meta);
+}
+
+static MediaExtractor::CreatorFunc Sniff(
         const sp<DataSource> &source, String8 *mimeType, float *confidence,
         sp<AMessage> *meta) {
     off64_t pos = 0;
@@ -342,7 +342,7 @@
         uint8_t id3header[10];
         if (source->readAt(pos, id3header, sizeof(id3header))
                 < (ssize_t)sizeof(id3header)) {
-            return false;
+            return NULL;
         }
 
         if (memcmp("ID3", id3header, 3)) {
@@ -368,7 +368,7 @@
     uint8_t header[2];
 
     if (source->readAt(pos, &header, 2) != 2) {
-        return false;
+        return NULL;
     }
 
     // ADTS syncword
@@ -379,10 +379,26 @@
         *meta = new AMessage;
         (*meta)->setInt64("offset", pos);
 
-        return true;
+        return CreateExtractor;
     }
 
-    return false;
+    return NULL;
 }
 
-}  // namespace android
+
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("4fd80eae-03d2-4d72-9eb9-48fa6bb54613"),
+        1, // version
+        "AAC Extractor",
+        Sniff
+    };
+}
+
+} // extern "C"
+
+} // namespace android
diff --git a/media/libstagefright/include/AACExtractor.h b/media/extractors/aac/AACExtractor.h
similarity index 93%
rename from media/libstagefright/include/AACExtractor.h
rename to media/extractors/aac/AACExtractor.h
index bd4c41c..aede185 100644
--- a/media/libstagefright/include/AACExtractor.h
+++ b/media/extractors/aac/AACExtractor.h
@@ -18,7 +18,7 @@
 
 #define AAC_EXTRACTOR_H_
 
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 #include <utils/Vector.h>
 
@@ -32,7 +32,7 @@
     AACExtractor(const sp<DataSource> &source, const sp<AMessage> &meta);
 
     virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
+    virtual sp<MediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/extractors/aac/Android.bp b/media/extractors/aac/Android.bp
new file mode 100644
index 0000000..65f9b96
--- /dev/null
+++ b/media/extractors/aac/Android.bp
@@ -0,0 +1,38 @@
+cc_library_shared {
+
+    srcs: ["AACExtractor.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libmediaextractor",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    name: "libaacextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/aac/MODULE_LICENSE_APACHE2
similarity index 100%
rename from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
rename to media/extractors/aac/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/aac/NOTICE
similarity index 100%
rename from media/libstagefright/matroska/NOTICE
rename to media/extractors/aac/NOTICE
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
similarity index 89%
rename from media/libstagefright/AMRExtractor.cpp
rename to media/extractors/amr/AMRExtractor.cpp
index 2892520..b8967bd 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -18,14 +18,14 @@
 #define LOG_TAG "AMRExtractor"
 #include <utils/Log.h>
 
-#include "include/AMRExtractor.h"
+#include "AMRExtractor.h"
 
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 
@@ -186,7 +186,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-sp<IMediaSource> AMRExtractor::getTrack(size_t index) {
+sp<MediaSource> AMRExtractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -362,4 +362,31 @@
     return false;
 }
 
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("c86639c9-2f31-40ac-a715-fa01b4493aaf"),
+        1,
+        "AMR Extractor",
+        [](
+                const sp<DataSource> &source,
+                String8 *mimeType,
+                float *confidence,
+                sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
+            if (SniffAMR(source, mimeType, confidence, meta)) {
+                return [](
+                        const sp<DataSource> &source,
+                        const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                    return new AMRExtractor(source);};
+            }
+            return NULL;
+        }
+    };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/include/AMRExtractor.h b/media/extractors/amr/AMRExtractor.h
similarity index 93%
rename from media/libstagefright/include/AMRExtractor.h
rename to media/extractors/amr/AMRExtractor.h
index 8abcb12..79b22d6 100644
--- a/media/libstagefright/include/AMRExtractor.h
+++ b/media/extractors/amr/AMRExtractor.h
@@ -19,7 +19,7 @@
 #define AMR_EXTRACTOR_H_
 
 #include <utils/Errors.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 namespace android {
 
@@ -32,7 +32,7 @@
     explicit AMRExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
+    virtual sp<MediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/extractors/amr/Android.bp b/media/extractors/amr/Android.bp
new file mode 100644
index 0000000..01bbfa2
--- /dev/null
+++ b/media/extractors/amr/Android.bp
@@ -0,0 +1,38 @@
+cc_library_shared {
+
+    srcs: ["AMRExtractor.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libmediaextractor",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    name: "libamrextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/amr/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/amr/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/amr/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/amr/NOTICE
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
new file mode 100644
index 0000000..80a4125
--- /dev/null
+++ b/media/extractors/flac/Android.bp
@@ -0,0 +1,43 @@
+cc_library_shared {
+
+    srcs: ["FLACExtractor.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "external/flac/include",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libmediaextractor",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libFLAC",
+    ],
+
+    name: "libflacextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
similarity index 84%
rename from media/libstagefright/FLACExtractor.cpp
rename to media/extractors/flac/FLACExtractor.cpp
index 1b88e5d..0c88246 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -18,22 +18,147 @@
 #define LOG_TAG "FLACExtractor"
 #include <utils/Log.h>
 
-#include "include/FLACExtractor.h"
-// Vorbis comments
-#include "include/OggExtractor.h"
+#include "FLACExtractor.h"
 // libFLAC parser
 #include "FLAC/stream_decoder.h"
 
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
+#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/foundation/base64.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
 
 namespace android {
 
+// also exists in OggExtractor, candidate for moving to utility/support library?
+static void extractAlbumArt(
+        const sp<MetaData> &fileMeta, const void *data, size_t size) {
+    ALOGV("extractAlbumArt from '%s'", (const char *)data);
+
+    sp<ABuffer> flacBuffer = decodeBase64(AString((const char *)data, size));
+    if (flacBuffer == NULL) {
+        ALOGE("malformed base64 encoded data.");
+        return;
+    }
+
+    size_t flacSize = flacBuffer->size();
+    uint8_t *flac = flacBuffer->data();
+    ALOGV("got flac of size %zu", flacSize);
+
+    uint32_t picType;
+    uint32_t typeLen;
+    uint32_t descLen;
+    uint32_t dataLen;
+    char type[128];
+
+    if (flacSize < 8) {
+        return;
+    }
+
+    picType = U32_AT(flac);
+
+    if (picType != 3) {
+        // This is not a front cover.
+        return;
+    }
+
+    typeLen = U32_AT(&flac[4]);
+    if (typeLen > sizeof(type) - 1) {
+        return;
+    }
+
+    // we've already checked above that flacSize >= 8
+    if (flacSize - 8 < typeLen) {
+        return;
+    }
+
+    memcpy(type, &flac[8], typeLen);
+    type[typeLen] = '\0';
+
+    ALOGV("picType = %d, type = '%s'", picType, type);
+
+    if (!strcmp(type, "-->")) {
+        // This is not inline cover art, but an external url instead.
+        return;
+    }
+
+    if (flacSize < 32 || flacSize - 32 < typeLen) {
+        return;
+    }
+
+    descLen = U32_AT(&flac[8 + typeLen]);
+    if (flacSize - 32 - typeLen < descLen) {
+        return;
+    }
+
+    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
+
+    // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
+    if (flacSize - 32 - typeLen - descLen < dataLen) {
+        return;
+    }
+
+    ALOGV("got image data, %zu trailing bytes",
+         flacSize - 32 - typeLen - descLen - dataLen);
+
+    fileMeta->setData(
+            kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
+
+    fileMeta->setCString(kKeyAlbumArtMIME, type);
+}
+
+// also exists in OggExtractor, candidate for moving to utility/support library?
+static void parseVorbisComment(
+        const sp<MetaData> &fileMeta, const char *comment, size_t commentLength)
+{
+    struct {
+        const char *const mTag;
+        uint32_t mKey;
+    } kMap[] = {
+        { "TITLE", kKeyTitle },
+        { "ARTIST", kKeyArtist },
+        { "ALBUMARTIST", kKeyAlbumArtist },
+        { "ALBUM ARTIST", kKeyAlbumArtist },
+        { "COMPILATION", kKeyCompilation },
+        { "ALBUM", kKeyAlbum },
+        { "COMPOSER", kKeyComposer },
+        { "GENRE", kKeyGenre },
+        { "AUTHOR", kKeyAuthor },
+        { "TRACKNUMBER", kKeyCDTrackNumber },
+        { "DISCNUMBER", kKeyDiscNumber },
+        { "DATE", kKeyDate },
+        { "YEAR", kKeyYear },
+        { "LYRICIST", kKeyWriter },
+        { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
+        { "ANDROID_LOOP", kKeyAutoLoop },
+    };
+
+        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
+            size_t tagLen = strlen(kMap[j].mTag);
+            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
+                    && comment[tagLen] == '=') {
+                if (kMap[j].mKey == kKeyAlbumArt) {
+                    extractAlbumArt(
+                            fileMeta,
+                            &comment[tagLen + 1],
+                            commentLength - tagLen - 1);
+                } else if (kMap[j].mKey == kKeyAutoLoop) {
+                    if (!strcasecmp(&comment[tagLen + 1], "true")) {
+                        fileMeta->setInt32(kKeyAutoLoop, true);
+                    }
+                } else {
+                    fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
+                }
+            }
+        }
+
+}
+
 class FLACParser;
 
 class FLACSource : public MediaSource {
@@ -811,7 +936,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-sp<IMediaSource> FLACExtractor::getTrack(size_t index)
+sp<MediaSource> FLACExtractor::getTrack(size_t index)
 {
     if (mInitCheck != OK || index > 0) {
         return NULL;
@@ -864,4 +989,32 @@
     return true;
 }
 
+
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+            UUID("1364b048-cc45-4fda-9934-327d0ebf9829"),
+            1,
+            "FLAC Extractor",
+            [](
+                    const sp<DataSource> &source,
+                    String8 *mimeType,
+                    float *confidence,
+                    sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
+                if (SniffFLAC(source, mimeType, confidence, meta)) {
+                    return [](
+                            const sp<DataSource> &source,
+                            const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                        return new FLACExtractor(source);};
+                }
+                return NULL;
+            }
+     };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/include/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
similarity index 91%
rename from media/libstagefright/include/FLACExtractor.h
rename to media/extractors/flac/FLACExtractor.h
index 51bc139..6907ceb 100644
--- a/media/libstagefright/include/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -17,8 +17,8 @@
 #ifndef FLAC_EXTRACTOR_H_
 #define FLAC_EXTRACTOR_H_
 
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
 #include <utils/String8.h>
 
 namespace android {
@@ -32,7 +32,7 @@
     explicit FLACExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
+    virtual sp<MediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/flac/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/flac/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/flac/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/flac/NOTICE
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
new file mode 100644
index 0000000..68f8766
--- /dev/null
+++ b/media/extractors/midi/Android.bp
@@ -0,0 +1,42 @@
+cc_library_shared {
+
+    srcs: ["MidiExtractor.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libmediaextractor",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libmedia_midiiowrapper",
+        "libsonivox",
+    ],
+    name: "libmidiextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/midi/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/midi/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
similarity index 89%
rename from media/libstagefright/MidiExtractor.cpp
rename to media/extractors/midi/MidiExtractor.cpp
index 7930bbb..a8509fc 100644
--- a/media/libstagefright/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -18,14 +18,14 @@
 #define LOG_TAG "MidiExtractor"
 #include <utils/Log.h>
 
-#include "include/MidiExtractor.h"
+#include "MidiExtractor.h"
 
 #include <media/MidiIoWrapper.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <libsonivox/eas_reverb.h>
 
 namespace android {
@@ -282,7 +282,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-sp<IMediaSource> MidiExtractor::getTrack(size_t index)
+sp<MediaSource> MidiExtractor::getTrack(size_t index)
 {
     if (mInitCheck != OK || index > 0) {
         return NULL;
@@ -323,4 +323,31 @@
 
 }
 
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("ef6cca0a-f8a2-43e6-ba5f-dfcd7c9a7ef2"),
+        1,
+        "MIDI Extractor",
+        [](
+                const sp<DataSource> &source,
+                String8 *mimeType,
+                float *confidence,
+                sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
+            if (SniffMidi(source, mimeType, confidence, meta)) {
+                return [](
+                        const sp<DataSource> &source,
+                        const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                    return new MidiExtractor(source);};
+            }
+            return NULL;
+        }
+    };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/include/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
similarity index 94%
rename from media/libstagefright/include/MidiExtractor.h
rename to media/extractors/midi/MidiExtractor.h
index 94d2d08..0fae94a 100644
--- a/media/libstagefright/include/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -17,8 +17,8 @@
 #ifndef MIDI_EXTRACTOR_H_
 #define MIDI_EXTRACTOR_H_
 
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/MidiIoWrapper.h>
@@ -56,7 +56,7 @@
     explicit MidiExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
+    virtual sp<MediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/midi/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/midi/NOTICE
diff --git a/media/libstagefright/matroska/Android.bp b/media/extractors/mkv/Android.bp
similarity index 61%
rename from media/libstagefright/matroska/Android.bp
rename to media/extractors/mkv/Android.bp
index ec2fb4b..350c6fe 100644
--- a/media/libstagefright/matroska/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -1,35 +1,46 @@
-cc_library_static {
-    name: "libstagefright_matroska",
+cc_library_shared {
 
     srcs: ["MatroskaExtractor.cpp"],
 
     include_dirs: [
         "external/flac/include",
         "external/libvpx/libwebm",
-        "frameworks/native/include/media/openmax",
         "frameworks/av/media/libstagefright/flac/dec",
         "frameworks/av/media/libstagefright/include",
     ],
 
+    shared_libs: [
+        "liblog",
+        "libmediaextractor",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libstagefright_flacdec",
+        "libwebm",
+    ],
+
+    name: "libmkvextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
     cflags: [
-        "-Wno-multichar",
         "-Werror",
         "-Wall",
+        "-fvisibility=hidden",
     ],
 
     sanitize: {
-        misc_undefined: [
-            "signed-integer-overflow",
-            "unsigned-integer-overflow",
-        ],
         cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
         diag: {
             cfi: true,
         },
     },
 
-    shared_libs: [
-        "libmedia",
-        "libstagefright_flacdec"
-    ],
 }
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/mkv/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/mkv/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
similarity index 94%
rename from media/libstagefright/matroska/MatroskaExtractor.cpp
rename to media/extractors/mkv/MatroskaExtractor.cpp
index 462eff6..e199f03 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -20,20 +20,20 @@
 
 #include "FLACDecoder.h"
 #include "MatroskaExtractor.h"
-#include "avc_utils.h"
 
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/ColorUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
 #include <utils/String8.h>
 
 #include <inttypes.h>
@@ -542,6 +542,31 @@
     return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
 }
 
+static AString uriDebugString(const AString &uri) {
+    // find scheme
+    AString scheme;
+    const char *chars = uri.c_str();
+    for (size_t i = 0; i < uri.size(); i++) {
+        const char c = chars[i];
+        if (!isascii(c)) {
+            break;
+        } else if (isalpha(c)) {
+            continue;
+        } else if (i == 0) {
+            // first character must be a letter
+            break;
+        } else if (isdigit(c) || c == '+' || c == '.' || c =='-') {
+            continue;
+        } else if (c != ':') {
+            break;
+        }
+        scheme = AString(uri, 0, i);
+        scheme.append("://<suppressed>");
+        return scheme;
+    }
+    return AString("<no-scheme URI suppressed>");
+}
+
 void MatroskaSource::clearPendingFrames() {
     while (!mPendingFrames.empty()) {
         MediaBuffer *frame = *mPendingFrames.begin();
@@ -678,18 +703,22 @@
 
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
-    if (options && options->getSeekTo(&seekTimeUs, &mode)
-            && !mExtractor->isLiveStreaming()) {
-        clearPendingFrames();
+    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+        if (mode == ReadOptions::SEEK_FRAME_INDEX) {
+            return ERROR_UNSUPPORTED;
+        }
 
-        // The audio we want is located by using the Cues to seek the video
-        // stream to find the target Cluster then iterating to finalize for
-        // audio.
-        int64_t actualFrameTimeUs;
-        mBlockIter.seek(seekTimeUs, mIsAudio, &actualFrameTimeUs);
+        if (!mExtractor->isLiveStreaming()) {
+            clearPendingFrames();
 
-        if (mode == ReadOptions::SEEK_CLOSEST) {
-            targetSampleTimeUs = actualFrameTimeUs;
+            // The audio we want is located by using the Cues to seek the video
+            // stream to find the target Cluster then iterating to finalize for
+            // audio.
+            int64_t actualFrameTimeUs;
+            mBlockIter.seek(seekTimeUs, mIsAudio, &actualFrameTimeUs);
+            if (mode == ReadOptions::SEEK_CLOSEST) {
+                targetSampleTimeUs = actualFrameTimeUs;
+            }
         }
     }
 
@@ -899,7 +928,7 @@
     return mTracks.size();
 }
 
-sp<IMediaSource> MatroskaExtractor::getTrack(size_t index) {
+sp<MediaSource> MatroskaExtractor::getTrack(size_t index) {
     if (index >= mTracks.size()) {
         return NULL;
     }
@@ -1535,4 +1564,32 @@
     return true;
 }
 
+
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("abbedd92-38c4-4904-a4c1-b3f45f899980"),
+        1,
+        "Matroska Extractor",
+        [](
+                const sp<DataSource> &source,
+                String8 *mimeType,
+                float *confidence,
+                sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
+            if (SniffMatroska(source, mimeType, confidence, meta)) {
+                return [](
+                        const sp<DataSource> &source,
+                        const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                    return new MatroskaExtractor(source);};
+            }
+            return NULL;
+        }
+    };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
similarity index 96%
rename from media/libstagefright/matroska/MatroskaExtractor.h
rename to media/extractors/mkv/MatroskaExtractor.h
index 19775ce..26f8d19 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -20,7 +20,7 @@
 
 #include "mkvparser/mkvparser.h"
 
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 #include <utils/Vector.h>
 #include <utils/threads.h>
 
@@ -38,7 +38,7 @@
 
     virtual size_t countTracks();
 
-    virtual sp<IMediaSource> getTrack(size_t index);
+    virtual sp<MediaSource> getTrack(size_t index);
 
     virtual sp<MetaData> getTrackMetaData(
             size_t index, uint32_t flags);
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/mkv/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/mkv/NOTICE
diff --git a/media/extractors/mp3/Android.bp b/media/extractors/mp3/Android.bp
new file mode 100644
index 0000000..6912ef1
--- /dev/null
+++ b/media/extractors/mp3/Android.bp
@@ -0,0 +1,46 @@
+cc_library_shared {
+
+    srcs: [
+            "MP3Extractor.cpp",
+            "VBRISeeker.cpp",
+            "XINGSeeker.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libmediaextractor",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libstagefright_id3",
+    ],
+
+    name: "libmp3extractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
similarity index 93%
rename from media/libstagefright/MP3Extractor.cpp
rename to media/extractors/mp3/MP3Extractor.cpp
index 22df522..f26ed25 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -18,23 +18,23 @@
 #define LOG_TAG "MP3Extractor"
 #include <utils/Log.h>
 
-#include "include/MP3Extractor.h"
+#include "MP3Extractor.h"
 
-#include "include/avc_utils.h"
-#include "include/ID3.h"
-#include "include/VBRISeeker.h"
-#include "include/XINGSeeker.h"
+#include "ID3.h"
+#include "VBRISeeker.h"
+#include "XINGSeeker.h"
 
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
 #include <utils/String8.h>
 
 namespace android {
@@ -407,7 +407,7 @@
     return mInitCheck != OK ? 0 : 1;
 }
 
-sp<IMediaSource> MP3Extractor::getTrack(size_t index) {
+sp<MediaSource> MP3Extractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -666,14 +666,29 @@
     return meta;
 }
 
-bool SniffMP3(
+static MediaExtractor* CreateExtractor(
+        const sp<DataSource> &source,
+        const sp<AMessage>& meta) {
+    return new MP3Extractor(source, meta);
+}
+
+static MediaExtractor::CreatorFunc Sniff(
         const sp<DataSource> &source, String8 *mimeType,
         float *confidence, sp<AMessage> *meta) {
     off64_t pos = 0;
     off64_t post_id3_pos;
     uint32_t header;
+    uint8_t mpeg_header[5];
+    if (source->readAt(0, mpeg_header, sizeof(mpeg_header)) < (ssize_t)sizeof(mpeg_header)) {
+        return NULL;
+    }
+
+    if (!memcmp("\x00\x00\x01\xba", mpeg_header, 4) && (mpeg_header[4] >> 4) == 2) {
+        ALOGV("MPEG1PS container is not supported!");
+        return NULL;
+    }
     if (!Resync(source, 0, &pos, &post_id3_pos, &header)) {
-        return false;
+        return NULL;
     }
 
     *meta = new AMessage;
@@ -684,7 +699,22 @@
     *mimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
     *confidence = 0.2f;
 
-    return true;
+    return CreateExtractor;
 }
 
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("812a3f6c-c8cf-46de-b529-3774b14103d4"),
+        1, // version
+        "MP3 Extractor",
+        Sniff
+    };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/include/MP3Extractor.h b/media/extractors/mp3/MP3Extractor.h
similarity index 93%
rename from media/libstagefright/include/MP3Extractor.h
rename to media/extractors/mp3/MP3Extractor.h
index 2fd04f2..f0ab6b0 100644
--- a/media/libstagefright/include/MP3Extractor.h
+++ b/media/extractors/mp3/MP3Extractor.h
@@ -19,7 +19,7 @@
 #define MP3_EXTRACTOR_H_
 
 #include <utils/Errors.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 namespace android {
 
@@ -34,7 +34,7 @@
     MP3Extractor(const sp<DataSource> &source, const sp<AMessage> &meta);
 
     virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
+    virtual sp<MediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/MP3Seeker.h b/media/extractors/mp3/MP3Seeker.h
similarity index 100%
rename from media/libstagefright/include/MP3Seeker.h
rename to media/extractors/mp3/MP3Seeker.h
diff --git a/media/libstagefright/VBRISeeker.cpp b/media/extractors/mp3/VBRISeeker.cpp
similarity index 96%
rename from media/libstagefright/VBRISeeker.cpp
rename to media/extractors/mp3/VBRISeeker.cpp
index 5b8f23a..e7db6fd 100644
--- a/media/libstagefright/VBRISeeker.cpp
+++ b/media/extractors/mp3/VBRISeeker.cpp
@@ -21,14 +21,13 @@
 
 #include <utils/Log.h>
 
-#include "include/VBRISeeker.h"
+#include "VBRISeeker.h"
 
-#include "include/avc_utils.h"
-#include "include/MP3Extractor.h"
+#include <media/stagefright/foundation/avc_utils.h>
 
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/DataSource.h>
 
 namespace android {
 
diff --git a/media/libstagefright/include/VBRISeeker.h b/media/extractors/mp3/VBRISeeker.h
similarity index 97%
rename from media/libstagefright/include/VBRISeeker.h
rename to media/extractors/mp3/VBRISeeker.h
index c57d571..87258b0 100644
--- a/media/libstagefright/include/VBRISeeker.h
+++ b/media/extractors/mp3/VBRISeeker.h
@@ -18,7 +18,7 @@
 
 #define VBRI_SEEKER_H_
 
-#include "include/MP3Seeker.h"
+#include "MP3Seeker.h"
 
 #include <utils/Vector.h>
 
diff --git a/media/libstagefright/XINGSeeker.cpp b/media/extractors/mp3/XINGSeeker.cpp
similarity index 96%
rename from media/libstagefright/XINGSeeker.cpp
rename to media/extractors/mp3/XINGSeeker.cpp
index 81ed9c6..fa59701 100644
--- a/media/libstagefright/XINGSeeker.cpp
+++ b/media/extractors/mp3/XINGSeeker.cpp
@@ -17,11 +17,11 @@
 #define LOG_TAG "XINGSEEKER"
 #include <utils/Log.h>
 
-#include "include/XINGSeeker.h"
-#include "include/avc_utils.h"
+#include "XINGSeeker.h"
+#include <media/stagefright/foundation/avc_utils.h>
 
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/DataSource.h>
 
 namespace android {
 
diff --git a/media/libstagefright/include/XINGSeeker.h b/media/extractors/mp3/XINGSeeker.h
similarity index 97%
rename from media/libstagefright/include/XINGSeeker.h
rename to media/extractors/mp3/XINGSeeker.h
index cce04f0..37077c4 100644
--- a/media/libstagefright/include/XINGSeeker.h
+++ b/media/extractors/mp3/XINGSeeker.h
@@ -18,7 +18,7 @@
 
 #define XING_SEEKER_H_
 
-#include "include/MP3Seeker.h"
+#include "MP3Seeker.h"
 
 namespace android {
 
diff --git a/media/extractors/mp4/Android.bp b/media/extractors/mp4/Android.bp
new file mode 100644
index 0000000..49a3714
--- /dev/null
+++ b/media/extractors/mp4/Android.bp
@@ -0,0 +1,48 @@
+cc_library_shared {
+
+    srcs: [
+        "ItemTable.cpp",
+        "MPEG4Extractor.cpp",
+        "SampleIterator.cpp",
+        "SampleTable.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libmediaextractor",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libstagefright_esds",
+        "libstagefright_id3",
+    ],
+
+    name: "libmp4extractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
similarity index 83%
rename from media/libstagefright/ItemTable.cpp
rename to media/extractors/mp4/ItemTable.cpp
index 7bc4f3c..85c66b2 100644
--- a/media/libstagefright/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -17,14 +17,14 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ItemTable"
 
-#include <include/ItemTable.h>
-#include <media/MediaDefs.h>
-#include <media/stagefright/DataSource.h>
+#include <ItemTable.h>
+#include <media/DataSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
 #include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 #include <utils/Log.h>
 
 namespace android {
@@ -40,8 +40,9 @@
     friend struct ItemReference;
     friend struct ItemProperty;
 
-    ImageItem() : ImageItem(0) {}
-    ImageItem(uint32_t _type) : type(_type),
+    ImageItem() : ImageItem(0, 0, false) {}
+    ImageItem(uint32_t _type, uint32_t _id, bool _hidden) :
+            type(_type), itemId(_id), hidden(_hidden),
             rows(0), columns(0), width(0), height(0), rotation(0),
             offset(0), size(0), nextTileIndex(0) {}
 
@@ -61,6 +62,8 @@
     }
 
     uint32_t type;
+    uint32_t itemId;
+    bool hidden;
     int32_t rows;
     int32_t columns;
     int32_t width;
@@ -470,41 +473,7 @@
 
     uint32_t itemId() { return mItemId; }
 
-    void apply(KeyedVector<uint32_t, ImageItem> &itemIdToImageMap) const {
-        ssize_t imageIndex = itemIdToImageMap.indexOfKey(mItemId);
-
-        // ignore non-image items
-        if (imageIndex < 0) {
-            return;
-        }
-
-        ALOGV("attach reference type 0x%x to item id %d)", type(), mItemId);
-
-        if (type() == FOURCC('d', 'i', 'm', 'g')) {
-            ImageItem &image = itemIdToImageMap.editValueAt(imageIndex);
-            if (!image.dimgRefs.empty()) {
-                ALOGW("dimgRefs if not clean!");
-            }
-            image.dimgRefs.appendVector(mRefs);
-        } else if (type() == FOURCC('t', 'h', 'm', 'b')) {
-            for (size_t i = 0; i < mRefs.size(); i++) {
-                imageIndex = itemIdToImageMap.indexOfKey(mRefs[i]);
-
-                // ignore non-image items
-                if (imageIndex < 0) {
-                    continue;
-                }
-                ALOGV("Image item id %d uses thumbnail item id %d", mRefs[i], mItemId);
-                ImageItem &image = itemIdToImageMap.editValueAt(imageIndex);
-                if (!image.thumbnails.empty()) {
-                    ALOGW("already has thumbnails!");
-                }
-                image.thumbnails.push_back(mItemId);
-            }
-        } else {
-            ALOGW("ignoring unsupported ref type 0x%x", type());
-        }
-    }
+    void apply(KeyedVector<uint32_t, ImageItem> &itemIdToItemMap) const;
 
 private:
     uint32_t mItemId;
@@ -514,6 +483,64 @@
     DISALLOW_EVIL_CONSTRUCTORS(ItemReference);
 };
 
+void ItemReference::apply(KeyedVector<uint32_t, ImageItem> &itemIdToItemMap) const {
+    ssize_t itemIndex = itemIdToItemMap.indexOfKey(mItemId);
+
+    // ignore non-image items
+    if (itemIndex < 0) {
+        return;
+    }
+
+    ALOGV("attach reference type 0x%x to item id %d)", type(), mItemId);
+
+    if (type() == FOURCC('d', 'i', 'm', 'g')) {
+        ImageItem &derivedImage = itemIdToItemMap.editValueAt(itemIndex);
+        if (!derivedImage.dimgRefs.empty()) {
+            ALOGW("dimgRefs if not clean!");
+        }
+        derivedImage.dimgRefs.appendVector(mRefs);
+
+        for (size_t i = 0; i < mRefs.size(); i++) {
+            itemIndex = itemIdToItemMap.indexOfKey(mRefs[i]);
+
+            // ignore non-image items
+            if (itemIndex < 0) {
+                continue;
+            }
+            ImageItem &sourceImage = itemIdToItemMap.editValueAt(itemIndex);
+
+            // mark the source image of the derivation as hidden
+            sourceImage.hidden = true;
+        }
+    } else if (type() == FOURCC('t', 'h', 'm', 'b')) {
+        // mark thumbnail image as hidden, these can be retrieved if the client
+        // request thumbnail explicitly, but won't be exposed as displayables.
+        ImageItem &thumbImage = itemIdToItemMap.editValueAt(itemIndex);
+        thumbImage.hidden = true;
+
+        for (size_t i = 0; i < mRefs.size(); i++) {
+            itemIndex = itemIdToItemMap.indexOfKey(mRefs[i]);
+
+            // ignore non-image items
+            if (itemIndex < 0) {
+                continue;
+            }
+            ALOGV("Image item id %d uses thumbnail item id %d", mRefs[i], mItemId);
+            ImageItem &masterImage = itemIdToItemMap.editValueAt(itemIndex);
+            if (!masterImage.thumbnails.empty()) {
+                ALOGW("already has thumbnails!");
+            }
+            masterImage.thumbnails.push_back(mItemId);
+        }
+    } else if (type() == FOURCC('a', 'u', 'x', 'l')) {
+        // mark auxiliary image as hidden
+        ImageItem &auxImage = itemIdToItemMap.editValueAt(itemIndex);
+        auxImage.hidden = true;
+    } else {
+        ALOGW("ignoring unsupported ref type 0x%x", type());
+    }
+}
+
 status_t ItemReference::parse(off64_t offset, size_t size) {
     if (size < mRefIdSize + 2) {
         return ERROR_MALFORMED;
@@ -940,6 +967,7 @@
 struct ItemInfo {
     uint32_t itemId;
     uint32_t itemType;
+    bool hidden;
 };
 
 struct InfeBox : public FullBox {
@@ -985,45 +1013,7 @@
     }
 
     if (version() == 0 || version() == 1) {
-        if (size < 4) {
-            return ERROR_MALFORMED;
-        }
-        uint16_t item_id;
-        if (!source()->getUInt16(offset, &item_id)) {
-            return ERROR_IO;
-        }
-        ALOGV("item_id %d", item_id);
-        uint16_t item_protection_index;
-        if (!source()->getUInt16(offset + 2, &item_protection_index)) {
-            return ERROR_IO;
-        }
-        offset += 4;
-        size -= 4;
-
-        String8 item_name;
-        if (!parseNullTerminatedString(&offset, &size, &item_name)) {
-            return ERROR_MALFORMED;
-        }
-
-        String8 content_type;
-        if (!parseNullTerminatedString(&offset, &size, &content_type)) {
-            return ERROR_MALFORMED;
-        }
-
-        String8 content_encoding;
-        if (!parseNullTerminatedString(&offset, &size, &content_encoding)) {
-            return ERROR_MALFORMED;
-        }
-
-        if (version() == 1) {
-            uint32_t extension_type;
-            if (!source()->getUInt32(offset, &extension_type)) {
-                return ERROR_IO;
-            }
-            offset++;
-            size--;
-            // TODO: handle this case
-        }
+        return ERROR_UNSUPPORTED;
     } else { // version >= 2
         uint32_t item_id;
         size_t itemIdSize = (version() == 2) ? 2 : 4;
@@ -1048,6 +1038,9 @@
 
         itemInfo->itemId = item_id;
         itemInfo->itemType = item_type;
+        // According to HEIF spec, (flags & 1) indicates the image is hidden
+        // and not supposed to be displayed.
+        itemInfo->hidden = (flags() & 1);
 
         char itemTypeString[5];
         MakeFourCCString(item_type, itemTypeString);
@@ -1140,12 +1133,13 @@
     InfeBox infeBox(source());
     ItemInfo itemInfo;
     status_t err = infeBox.parse(offset, size, &itemInfo);
-    if (err != OK) {
-        return err;
+    if (err == OK) {
+        mItemInfos->push_back(itemInfo);
+        mHasGrids |= (itemInfo.itemType == FOURCC('g', 'r', 'i', 'd'));
     }
-    mItemInfos->push_back(itemInfo);
-    mHasGrids |= (itemInfo.itemType == FOURCC('g', 'r', 'i', 'd'));
-    return OK;
+    // InfeBox parse returns ERROR_UNSUPPORTED if the box if an unsupported
+    // version. Ignore this error as it's not fatal.
+    return (err == ERROR_UNSUPPORTED) ? OK : err;
 }
 
 //////////////////////////////////////////////////////////////////
@@ -1156,7 +1150,7 @@
       mIdatOffset(0),
       mIdatSize(0),
       mImageItemsValid(false),
-      mCurrentImageIndex(0) {
+      mCurrentItemIndex(0) {
     mRequiredBoxes.insert('iprp');
     mRequiredBoxes.insert('iloc');
     mRequiredBoxes.insert('pitm');
@@ -1311,8 +1305,8 @@
             continue;
         }
 
-        ssize_t imageIndex = mItemIdToImageMap.indexOfKey(info.itemId);
-        if (imageIndex >= 0) {
+        ssize_t itemIndex = mItemIdToItemMap.indexOfKey(info.itemId);
+        if (itemIndex >= 0) {
             ALOGW("ignoring duplicate image item id %d", info.itemId);
             continue;
         }
@@ -1330,7 +1324,7 @@
             return ERROR_MALFORMED;
         }
 
-        ImageItem image(info.itemType);
+        ImageItem image(info.itemType, info.itemId, info.hidden);
 
         ALOGV("adding %s: itemId %d", image.isGrid() ? "grid" : "image", info.itemId);
 
@@ -1351,7 +1345,7 @@
             image.offset = offset;
             image.size = size;
         }
-        mItemIdToImageMap.add(info.itemId, image);
+        mItemIdToItemMap.add(info.itemId, image);
     }
 
     for (size_t i = 0; i < mAssociations.size(); i++) {
@@ -1359,7 +1353,30 @@
     }
 
     for (size_t i = 0; i < mItemReferences.size(); i++) {
-        mItemReferences[i]->apply(mItemIdToImageMap);
+        mItemReferences[i]->apply(mItemIdToItemMap);
+    }
+
+    bool foundPrimary = false;
+    for (size_t i = 0; i < mItemIdToItemMap.size(); i++) {
+        // add all non-hidden images, also add the primary even if it's marked
+        // hidden, in case the primary is set to a thumbnail
+        bool isPrimary = (mItemIdToItemMap[i].itemId == mPrimaryItemId);
+        if (!mItemIdToItemMap[i].hidden || isPrimary) {
+            mDisplayables.push_back(i);
+        }
+        foundPrimary |= isPrimary;
+    }
+
+    ALOGV("found %zu displayables", mDisplayables.size());
+
+    // fail if no displayables are found
+    if (mDisplayables.empty()) {
+        return ERROR_MALFORMED;
+    }
+
+    // if the primary item id is invalid, set primary to the first displayable
+    if (!foundPrimary) {
+        mPrimaryItemId = mItemIdToItemMap[mDisplayables[0]].itemId;
     }
 
     mImageItemsValid = true;
@@ -1367,10 +1384,10 @@
 }
 
 void ItemTable::attachProperty(const AssociationEntry &association) {
-    ssize_t imageIndex = mItemIdToImageMap.indexOfKey(association.itemId);
+    ssize_t itemIndex = mItemIdToItemMap.indexOfKey(association.itemId);
 
     // ignore non-image items
-    if (imageIndex < 0) {
+    if (itemIndex < 0) {
         return;
     }
 
@@ -1383,29 +1400,36 @@
     ALOGV("attach property %d to item id %d)",
             propertyIndex, association.itemId);
 
-    mItemProperties[propertyIndex]->attachTo(
-            mItemIdToImageMap.editValueAt(imageIndex));
+    mItemProperties[propertyIndex]->attachTo(mItemIdToItemMap.editValueAt(itemIndex));
 }
 
-sp<MetaData> ItemTable::getImageMeta() {
+uint32_t ItemTable::countImages() const {
+    return mImageItemsValid ? mDisplayables.size() : 0;
+}
+
+sp<MetaData> ItemTable::getImageMeta(const uint32_t imageIndex) {
     if (!mImageItemsValid) {
         return NULL;
     }
 
-    ssize_t imageIndex = mItemIdToImageMap.indexOfKey(mPrimaryItemId);
-    if (imageIndex < 0) {
-        ALOGE("Primary item id %d not found!", mPrimaryItemId);
+    if (imageIndex >= mDisplayables.size()) {
+        ALOGE("%s: invalid image index %u", __FUNCTION__, imageIndex);
         return NULL;
     }
+    const uint32_t itemIndex = mDisplayables[imageIndex];
+    ALOGV("image[%u]: item index %u", imageIndex, itemIndex);
 
-    ALOGV("primary image index %zu", imageIndex);
-
-    const ImageItem *image = &mItemIdToImageMap[imageIndex];
+    const ImageItem *image = &mItemIdToItemMap[itemIndex];
 
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
 
-    ALOGV("setting image size %dx%d", image->width, image->height);
+    if (image->itemId == mPrimaryItemId) {
+        meta->setInt32(kKeyTrackIsDefault, 1);
+    }
+
+    ALOGV("image[%u]: size %dx%d", imageIndex, image->width, image->height);
+
     meta->setInt32(kKeyWidth, image->width);
     meta->setInt32(kKeyHeight, image->height);
     if (image->rotation != 0) {
@@ -1421,43 +1445,38 @@
     meta->setInt32(kKeyMaxInputSize, image->width * image->height * 1.5);
 
     if (!image->thumbnails.empty()) {
-        ssize_t thumbnailIndex = mItemIdToImageMap.indexOfKey(image->thumbnails[0]);
-        if (thumbnailIndex >= 0) {
-            const ImageItem &thumbnail = mItemIdToImageMap[thumbnailIndex];
+        ssize_t thumbItemIndex = mItemIdToItemMap.indexOfKey(image->thumbnails[0]);
+        if (thumbItemIndex >= 0) {
+            const ImageItem &thumbnail = mItemIdToItemMap[thumbItemIndex];
 
             meta->setInt32(kKeyThumbnailWidth, thumbnail.width);
             meta->setInt32(kKeyThumbnailHeight, thumbnail.height);
             meta->setData(kKeyThumbnailHVCC, kTypeHVCC,
                     thumbnail.hvcc->data(), thumbnail.hvcc->size());
-            ALOGV("thumbnail meta: %dx%d, index %zd",
-                    thumbnail.width, thumbnail.height, thumbnailIndex);
+            ALOGV("image[%u]: thumbnail: size %dx%d, item index %zd",
+                    imageIndex, thumbnail.width, thumbnail.height, thumbItemIndex);
         } else {
-            ALOGW("Referenced thumbnail does not exist!");
+            ALOGW("%s: Referenced thumbnail does not exist!", __FUNCTION__);
         }
     }
 
     if (image->isGrid()) {
-        ssize_t tileIndex = mItemIdToImageMap.indexOfKey(image->dimgRefs[0]);
-        if (tileIndex < 0) {
+        ssize_t tileItemIndex = mItemIdToItemMap.indexOfKey(image->dimgRefs[0]);
+        if (tileItemIndex < 0) {
             return NULL;
         }
-        // when there are tiles, (kKeyWidth, kKeyHeight) is the full tiled area,
-        // and (kKeyDisplayWidth, kKeyDisplayHeight) may be smaller than that.
-        meta->setInt32(kKeyDisplayWidth, image->width);
-        meta->setInt32(kKeyDisplayHeight, image->height);
-        int32_t gridRows = image->rows, gridCols = image->columns;
+        meta->setInt32(kKeyGridRows, image->rows);
+        meta->setInt32(kKeyGridCols, image->columns);
 
         // point image to the first tile for grid size and HVCC
-        image = &mItemIdToImageMap.editValueAt(tileIndex);
-        meta->setInt32(kKeyWidth, image->width * gridCols);
-        meta->setInt32(kKeyHeight, image->height * gridRows);
+        image = &mItemIdToItemMap.editValueAt(tileItemIndex);
         meta->setInt32(kKeyGridWidth, image->width);
         meta->setInt32(kKeyGridHeight, image->height);
         meta->setInt32(kKeyMaxInputSize, image->width * image->height * 1.5);
     }
 
     if (image->hvcc == NULL) {
-        ALOGE("hvcc is missing!");
+        ALOGE("%s: hvcc is missing for image[%u]!", __FUNCTION__, imageIndex);
         return NULL;
     }
     meta->setData(kKeyHVCC, kTypeHVCC, image->hvcc->data(), image->hvcc->size());
@@ -1468,88 +1487,87 @@
     return meta;
 }
 
-uint32_t ItemTable::countImages() const {
-    return mImageItemsValid ? mItemIdToImageMap.size() : 0;
-}
-
-status_t ItemTable::findPrimaryImage(uint32_t *imageIndex) {
+status_t ItemTable::findImageItem(const uint32_t imageIndex, uint32_t *itemIndex) {
     if (!mImageItemsValid) {
         return INVALID_OPERATION;
     }
 
-    ssize_t index = mItemIdToImageMap.indexOfKey(mPrimaryItemId);
-    if (index < 0) {
-        return ERROR_MALFORMED;
+    if (imageIndex >= mDisplayables.size()) {
+        ALOGE("%s: invalid image index %d", __FUNCTION__, imageIndex);
+        return BAD_VALUE;
     }
 
-    *imageIndex = index;
+    *itemIndex = mDisplayables[imageIndex];
+
+    ALOGV("image[%u]: item index %u", imageIndex, *itemIndex);
     return OK;
 }
 
-status_t ItemTable::findThumbnail(uint32_t *imageIndex) {
+status_t ItemTable::findThumbnailItem(const uint32_t imageIndex, uint32_t *itemIndex) {
     if (!mImageItemsValid) {
         return INVALID_OPERATION;
     }
 
-    ssize_t primaryIndex = mItemIdToImageMap.indexOfKey(mPrimaryItemId);
-    if (primaryIndex < 0) {
-        ALOGE("Primary item id %d not found!", mPrimaryItemId);
-        return ERROR_MALFORMED;
+    if (imageIndex >= mDisplayables.size()) {
+        ALOGE("%s: invalid image index %d", __FUNCTION__, imageIndex);
+        return BAD_VALUE;
     }
 
-    const ImageItem &primaryImage = mItemIdToImageMap[primaryIndex];
-    if (primaryImage.thumbnails.empty()) {
-        ALOGW("Using primary in place of thumbnail.");
-        *imageIndex = primaryIndex;
+    uint32_t masterItemIndex = mDisplayables[imageIndex];
+
+    const ImageItem &masterImage = mItemIdToItemMap[masterItemIndex];
+    if (masterImage.thumbnails.empty()) {
+        *itemIndex = masterItemIndex;
         return OK;
     }
 
-    ssize_t thumbnailIndex = mItemIdToImageMap.indexOfKey(
-            primaryImage.thumbnails[0]);
-    if (thumbnailIndex < 0) {
-        ALOGE("Thumbnail item id %d not found!", primaryImage.thumbnails[0]);
-        return ERROR_MALFORMED;
+    ssize_t thumbItemIndex = mItemIdToItemMap.indexOfKey(masterImage.thumbnails[0]);
+    if (thumbItemIndex < 0) {
+        ALOGW("%s: Thumbnail item id %d not found, use master instead",
+                __FUNCTION__, masterImage.thumbnails[0]);
+        *itemIndex = masterItemIndex;
+        return OK;
     }
 
-    *imageIndex = thumbnailIndex;
+    *itemIndex = thumbItemIndex;
     return OK;
 }
 
 status_t ItemTable::getImageOffsetAndSize(
-        uint32_t *imageIndex, off64_t *offset, size_t *size) {
+        uint32_t *itemIndex, off64_t *offset, size_t *size) {
     if (!mImageItemsValid) {
         return INVALID_OPERATION;
     }
 
-    if (imageIndex != NULL) {
-        if (*imageIndex >= mItemIdToImageMap.size()) {
-            ALOGE("Bad image index!");
+    if (itemIndex != NULL) {
+        if (*itemIndex >= mItemIdToItemMap.size()) {
+            ALOGE("%s: Bad item index!", __FUNCTION__);
             return BAD_VALUE;
         }
-        mCurrentImageIndex = *imageIndex;
+        mCurrentItemIndex = *itemIndex;
     }
 
-    ImageItem &image = mItemIdToImageMap.editValueAt(mCurrentImageIndex);
+    ImageItem &image = mItemIdToItemMap.editValueAt(mCurrentItemIndex);
     if (image.isGrid()) {
         uint32_t tileItemId;
-        status_t err = image.getNextTileItemId(&tileItemId, imageIndex != NULL);
+        status_t err = image.getNextTileItemId(&tileItemId, itemIndex != NULL);
         if (err != OK) {
             return err;
         }
-        ssize_t tileImageIndex = mItemIdToImageMap.indexOfKey(tileItemId);
-        if (tileImageIndex < 0) {
+        ssize_t tileItemIndex = mItemIdToItemMap.indexOfKey(tileItemId);
+        if (tileItemIndex < 0) {
             return ERROR_END_OF_STREAM;
         }
-        *offset = mItemIdToImageMap[tileImageIndex].offset;
-        *size = mItemIdToImageMap[tileImageIndex].size;
+        *offset = mItemIdToItemMap[tileItemIndex].offset;
+        *size = mItemIdToItemMap[tileItemIndex].size;
     } else {
-        if (imageIndex == NULL) {
+        if (itemIndex == NULL) {
             // For single images, we only allow it to be read once, after that
-            // it's EOS.  New image index must be requested each time.
+            // it's EOS.  New item index must be requested each time.
             return ERROR_END_OF_STREAM;
         }
-        *offset = mItemIdToImageMap[mCurrentImageIndex].offset;
-        *size = mItemIdToImageMap[mCurrentImageIndex].size;
+        *offset = mItemIdToItemMap[mCurrentItemIndex].offset;
+        *size = mItemIdToItemMap[mCurrentItemIndex].size;
     }
 
     return OK;
diff --git a/media/libstagefright/include/ItemTable.h b/media/extractors/mp4/ItemTable.h
similarity index 85%
rename from media/libstagefright/include/ItemTable.h
rename to media/extractors/mp4/ItemTable.h
index 5a6af5e..3d2e2ae 100644
--- a/media/libstagefright/include/ItemTable.h
+++ b/media/extractors/mp4/ItemTable.h
@@ -49,12 +49,12 @@
     status_t parse(uint32_t type, off64_t offset, size_t size);
 
     bool isValid() { return mImageItemsValid; }
-    sp<MetaData> getImageMeta();
     uint32_t countImages() const;
-    status_t findPrimaryImage(uint32_t *imageIndex);
-    status_t findThumbnail(uint32_t *thumbnailIndex);
+    sp<MetaData> getImageMeta(const uint32_t imageIndex);
+    status_t findImageItem(const uint32_t imageIndex, uint32_t *itemIndex);
+    status_t findThumbnailItem(const uint32_t imageIndex, uint32_t *itemIndex);
     status_t getImageOffsetAndSize(
-            uint32_t *imageIndex, off64_t *offset, size_t *size);
+            uint32_t *itemIndex, off64_t *offset, size_t *size);
 
 protected:
     ~ItemTable();
@@ -76,8 +76,9 @@
     std::set<uint32_t> mBoxesSeen;
 
     bool mImageItemsValid;
-    uint32_t mCurrentImageIndex;
-    KeyedVector<uint32_t, ImageItem> mItemIdToImageMap;
+    uint32_t mCurrentItemIndex;
+    KeyedVector<uint32_t, ImageItem> mItemIdToItemMap;
+    Vector<uint32_t> mDisplayables;
 
     status_t parseIlocBox(off64_t offset, size_t size);
     status_t parseIinfBox(off64_t offset, size_t size);
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/mp4/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/mp4/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
similarity index 96%
rename from media/libstagefright/MPEG4Extractor.cpp
rename to media/extractors/mp4/MPEG4Extractor.cpp
index 104b324..b411125 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -26,28 +26,29 @@
 
 #include <utils/Log.h>
 
-#include "include/MPEG4Extractor.h"
-#include "include/SampleTable.h"
-#include "include/ItemTable.h"
+#include "MPEG4Extractor.h"
+#include "SampleTable.h"
+#include "ItemTable.h"
 #include "include/ESDS.h"
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/ColorUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 
 #include <byteswap.h>
 #include "include/ID3.h"
-#include "include/avc_utils.h"
 
 #ifndef UINT32_MAX
 #define UINT32_MAX       (4294967295U)
@@ -137,7 +138,7 @@
 
     uint8_t *mSrcBuffer;
 
-    bool mIsHEIF;
+    bool mIsHeif;
     sp<ItemTable> mItemTable;
 
     size_t parseNALSize(const uint8_t *data) const;
@@ -337,7 +338,7 @@
     return false;
 }
 
-MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
+MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source, const char *mime)
     : mMoofOffset(0),
       mMoofFound(false),
       mMdatFound(false),
@@ -345,12 +346,15 @@
       mInitCheck(NO_INIT),
       mHeaderTimescale(0),
       mIsQT(false),
-      mIsHEIF(false),
+      mIsHeif(false),
+      mHasMoovBox(false),
+      mPreferHeif(mime != NULL && !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_HEIF)),
       mFirstTrack(NULL),
       mLastTrack(NULL),
       mFileMetaData(new MetaData),
       mFirstSINF(NULL),
       mIsDrm(false) {
+    ALOGV("mime=%s, mPreferHeif=%d", mime, mPreferHeif);
 }
 
 MPEG4Extractor::~MPEG4Extractor() {
@@ -559,8 +563,9 @@
     status_t err;
     bool sawMoovOrSidx = false;
 
-    while (!((sawMoovOrSidx && (mMdatFound || mMoofFound)) ||
-            (mIsHEIF && (mItemTable != NULL) && mItemTable->isValid()))) {
+    while (!((mHasMoovBox && sawMoovOrSidx && (mMdatFound || mMoofFound)) ||
+             (mIsHeif && (mPreferHeif || !mHasMoovBox) &&
+                     (mItemTable != NULL) && mItemTable->isValid()))) {
         off64_t orig_offset = offset;
         err = parseChunk(&offset, 0);
 
@@ -577,12 +582,43 @@
         }
     }
 
+    if (mIsHeif && (mItemTable != NULL) && (mItemTable->countImages() > 0)) {
+        for (uint32_t imageIndex = 0;
+                imageIndex < mItemTable->countImages(); imageIndex++) {
+            sp<MetaData> meta = mItemTable->getImageMeta(imageIndex);
+            if (meta == NULL) {
+                ALOGE("heif image %u has no meta!", imageIndex);
+                continue;
+            }
+
+            ALOGV("adding HEIF image track %u", imageIndex);
+            Track *track = new Track;
+            track->next = NULL;
+            if (mLastTrack != NULL) {
+                mLastTrack->next = track;
+            } else {
+                mFirstTrack = track;
+            }
+            mLastTrack = track;
+
+            track->meta = meta;
+            track->meta->setInt32(kKeyTrackID, imageIndex);
+            track->includes_expensive_metadata = false;
+            track->skipTrack = false;
+            track->timescale = 0;
+        }
+    }
+
     if (mInitCheck == OK) {
         if (findTrackByMimePrefix("video/") != NULL) {
             mFileMetaData->setCString(
                     kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG4);
         } else if (findTrackByMimePrefix("audio/") != NULL) {
             mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
+        } else if (findTrackByMimePrefix(
+                MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC) != NULL) {
+            mFileMetaData->setCString(
+                    kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_HEIF);
         } else {
             mFileMetaData->setCString(kKeyMIMEType, "application/octet-stream");
         }
@@ -613,28 +649,6 @@
         free(buf);
     }
 
-    if (mIsHEIF) {
-        sp<MetaData> meta = mItemTable->getImageMeta();
-        if (meta == NULL) {
-            return ERROR_MALFORMED;
-        }
-
-        Track *track = mLastTrack;
-        if (track != NULL) {
-            ALOGW("track is set before metadata is fully processed");
-        } else {
-            track = new Track;
-            track->next = NULL;
-            mFirstTrack = mLastTrack = track;
-        }
-
-        track->meta = meta;
-        track->meta->setInt32(kKeyTrackID, 0);
-        track->includes_expensive_metadata = false;
-        track->skipTrack = false;
-        track->timescale = 0;
-    }
-
     return mInitCheck;
 }
 
@@ -1036,6 +1050,7 @@
                 }
                 isTrack = true;
 
+                ALOGV("adding new track");
                 Track *track = new Track;
                 track->next = NULL;
                 if (mLastTrack) {
@@ -1083,6 +1098,7 @@
                 }
 
                 if (mLastTrack->skipTrack) {
+                    ALOGV("skipping this track...");
                     Track *cur = mFirstTrack;
 
                     if (cur == mLastTrack) {
@@ -1259,6 +1275,25 @@
             break;
         }
 
+        case FOURCC('t', 'r', 'e', 'f'):
+        {
+            *offset += chunk_size;
+
+            if (mLastTrack == NULL) {
+                return ERROR_MALFORMED;
+            }
+
+            // Skip thumbnail track for now since we don't have an
+            // API to retrieve it yet.
+            // The thumbnail track can't be accessed by negative index or time,
+            // because each timed sample has its own corresponding thumbnail
+            // in the thumbnail track. We'll need a dedicated API to retrieve
+            // thumbnail at time instead.
+            mLastTrack->skipTrack = true;
+
+            break;
+        }
+
         case FOURCC('p', 's', 's', 'h'):
         {
             *offset += chunk_size;
@@ -1757,6 +1792,8 @@
                             mLastTrack->meta->setInt32(kKeyFrameRate, frameRate);
                         }
                     }
+                    ALOGV("setting frame count %zu", nSamples);
+                    mLastTrack->meta->setInt32(kKeyFrameCount, nSamples);
                 }
             }
 
@@ -2088,7 +2125,7 @@
         case FOURCC('i', 'r', 'e', 'f'):
         case FOURCC('i', 'p', 'r', 'o'):
         {
-            if (mIsHEIF) {
+            if (mIsHeif) {
                 if (mItemTable == NULL) {
                     mItemTable = new ItemTable(mDataSource);
                 }
@@ -2468,10 +2505,22 @@
 
             if (brandSet.count(FOURCC('q', 't', ' ', ' ')) > 0) {
                 mIsQT = true;
-            } else if (brandSet.count(FOURCC('m', 'i', 'f', '1')) > 0
-                    && brandSet.count(FOURCC('h', 'e', 'i', 'c')) > 0) {
-                mIsHEIF = true;
-                ALOGV("identified HEIF image");
+            } else {
+                if (brandSet.count(FOURCC('m', 'i', 'f', '1')) > 0
+                 && brandSet.count(FOURCC('h', 'e', 'i', 'c')) > 0) {
+                    ALOGV("identified HEIF image");
+
+                    mIsHeif = true;
+                    brandSet.erase(FOURCC('m', 'i', 'f', '1'));
+                    brandSet.erase(FOURCC('h', 'e', 'i', 'c'));
+                }
+
+                if (!brandSet.empty()) {
+                    // This means that the file should have moov box.
+                    // It could be any iso files (mp4, heifs, etc.)
+                    mHasMoovBox = true;
+                    ALOGV("identified HEIF image with other tracks");
+                }
             }
 
             *offset = stop_offset;
@@ -3347,7 +3396,7 @@
     }
 }
 
-sp<IMediaSource> MPEG4Extractor::getTrack(size_t index) {
+sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
     status_t err;
     if ((err = readMetaData()) != OK) {
         return NULL;
@@ -3390,6 +3439,7 @@
         return NULL;
     }
 
+    sp<ItemTable> itemTable;
     if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
         uint32_t type;
         const void *data;
@@ -3403,7 +3453,8 @@
         if (size < 7 || ptr[0] != 1) {  // configurationVersion == 1
             return NULL;
         }
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)
+            || !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
         uint32_t type;
         const void *data;
         size_t size;
@@ -3416,11 +3467,14 @@
         if (size < 22 || ptr[0] != 1) {  // configurationVersion == 1
             return NULL;
         }
+        if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
+            itemTable = mItemTable;
+        }
     }
 
     sp<MPEG4Source> source =  new MPEG4Source(this,
             track->meta, mDataSource, track->timescale, track->sampleTable,
-            mSidxEntries, trex, mMoofOffset, mItemTable);
+            mSidxEntries, trex, mMoofOffset, itemTable);
     if (source->init() != OK) {
         return NULL;
     }
@@ -3848,7 +3902,7 @@
       mBuffer(NULL),
       mWantsNALFragments(false),
       mSrcBuffer(NULL),
-      mIsHEIF(itemTable != NULL),
+      mIsHeif(itemTable != NULL),
       mItemTable(itemTable) {
 
     memset(&mTrackFragmentHeaderInfo, 0, sizeof(mTrackFragmentHeaderInfo));
@@ -3870,7 +3924,8 @@
     CHECK(success);
 
     mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
-    mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+    mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
+              !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
 
     if (mIsAVC) {
         uint32_t type;
@@ -4624,15 +4679,19 @@
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
-        if (mIsHEIF) {
+        if (mIsHeif) {
             CHECK(mSampleTable == NULL);
             CHECK(mItemTable != NULL);
+            int32_t imageIndex;
+            if (!mFormat->findInt32(kKeyTrackID, &imageIndex)) {
+                return ERROR_MALFORMED;
+            }
 
             status_t err;
             if (seekTimeUs >= 0) {
-                err = mItemTable->findPrimaryImage(&mCurrentSampleIndex);
+                err = mItemTable->findImageItem(imageIndex, &mCurrentSampleIndex);
             } else {
-                err = mItemTable->findThumbnail(&mCurrentSampleIndex);
+                err = mItemTable->findThumbnailItem(imageIndex, &mCurrentSampleIndex);
             }
             if (err != OK) {
                 return err;
@@ -4650,6 +4709,9 @@
                 case ReadOptions::SEEK_CLOSEST:
                     findFlags = SampleTable::kFlagClosest;
                     break;
+                case ReadOptions::SEEK_FRAME_INDEX:
+                    findFlags = SampleTable::kFlagFrameIndex;
+                    break;
                 default:
                     CHECK(!"Should not be here.");
                     break;
@@ -4660,7 +4722,8 @@
                     seekTimeUs, 1000000, mTimescale,
                     &sampleIndex, findFlags);
 
-            if (mode == ReadOptions::SEEK_CLOSEST) {
+            if (mode == ReadOptions::SEEK_CLOSEST
+                    || mode == ReadOptions::SEEK_FRAME_INDEX) {
                 // We found the closest sample already, now we want the sync
                 // sample preceding it (or the sample itself of course), even
                 // if the subsequent sync sample is closer.
@@ -4692,7 +4755,8 @@
                 return err;
             }
 
-            if (mode == ReadOptions::SEEK_CLOSEST) {
+            if (mode == ReadOptions::SEEK_CLOSEST
+                || mode == ReadOptions::SEEK_FRAME_INDEX) {
                 targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale;
             }
 
@@ -4728,7 +4792,7 @@
         newBuffer = true;
 
         status_t err;
-        if (!mIsHEIF) {
+        if (!mIsHeif) {
             err = mSampleTable->getMetaDataForSample(
                     mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample, &stts);
         } else {
@@ -5315,7 +5379,8 @@
         || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)
         || !memcmp(header, "ftypM4A ", 8) || !memcmp(header, "ftypf4v ", 8)
         || !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)
-        || !memcmp(header, "ftypmif1", 8) || !memcmp(header, "ftypheic", 8)) {
+        || !memcmp(header, "ftypmif1", 8) || !memcmp(header, "ftypheic", 8)
+        || !memcmp(header, "ftypmsf1", 8) || !memcmp(header, "ftyphevc", 8)) {
         *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
         *confidence = 0.4;
 
@@ -5346,6 +5411,8 @@
         FOURCC('3', 'g', '2', 'b'),
         FOURCC('m', 'i', 'f', '1'),  // HEIF image
         FOURCC('h', 'e', 'i', 'c'),  // HEIF image
+        FOURCC('m', 's', 'f', '1'),  // HEIF image sequence
+        FOURCC('h', 'e', 'v', 'c'),  // HEIF image sequence
     };
 
     for (size_t i = 0;
@@ -5481,19 +5548,42 @@
     return true;
 }
 
-bool SniffMPEG4(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+static MediaExtractor* CreateExtractor(
+        const sp<DataSource> &source,
+        const sp<AMessage>& meta __unused) {
+    return new MPEG4Extractor(source);
+}
+
+static MediaExtractor::CreatorFunc Sniff(
+        const sp<DataSource> &source,
+        String8 *mimeType,
+        float *confidence,
         sp<AMessage> *meta) {
     if (BetterSniffMPEG4(source, mimeType, confidence, meta)) {
-        return true;
+        return CreateExtractor;
     }
 
     if (LegacySniffMPEG4(source, mimeType, confidence)) {
         ALOGW("Identified supported mpeg4 through LegacySniffMPEG4.");
-        return true;
+        return CreateExtractor;
     }
 
-    return false;
+    return NULL;
 }
 
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("27575c67-4417-4c54-8d3d-8e626985a164"),
+        1, // version
+        "MP4 Extractor",
+        Sniff
+    };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
similarity index 93%
rename from media/libstagefright/include/MPEG4Extractor.h
rename to media/extractors/mp4/MPEG4Extractor.h
index 214a3de..76b549d 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -20,9 +20,8 @@
 
 #include <arpa/inet.h>
 
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/Utils.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
 #include <utils/List.h>
 #include <utils/Vector.h>
 #include <utils/String8.h>
@@ -53,10 +52,10 @@
 class MPEG4Extractor : public MediaExtractor {
 public:
     // Extractor assumes ownership of "source".
-    explicit MPEG4Extractor(const sp<DataSource> &source);
+    explicit MPEG4Extractor(const sp<DataSource> &source, const char *mime = NULL);
 
     virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
+    virtual sp<MediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
@@ -104,7 +103,9 @@
     status_t mInitCheck;
     uint32_t mHeaderTimescale;
     bool mIsQT;
-    bool mIsHEIF;
+    bool mIsHeif;
+    bool mHasMoovBox;
+    bool mPreferHeif;
 
     Track *mFirstTrack, *mLastTrack;
 
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/mp4/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/mp4/NOTICE
diff --git a/media/libstagefright/SampleIterator.cpp b/media/extractors/mp4/SampleIterator.cpp
similarity index 98%
rename from media/libstagefright/SampleIterator.cpp
rename to media/extractors/mp4/SampleIterator.cpp
index 75f744d..78cc691 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/extractors/mp4/SampleIterator.cpp
@@ -18,15 +18,15 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
-#include "include/SampleIterator.h"
+#include "SampleIterator.h"
 
 #include <arpa/inet.h>
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 
-#include "include/SampleTable.h"
+#include "SampleTable.h"
 
 namespace android {
 
diff --git a/media/libstagefright/include/SampleIterator.h b/media/extractors/mp4/SampleIterator.h
similarity index 100%
rename from media/libstagefright/include/SampleIterator.h
rename to media/extractors/mp4/SampleIterator.h
diff --git a/media/libstagefright/SampleTable.cpp b/media/extractors/mp4/SampleTable.cpp
similarity index 98%
rename from media/libstagefright/SampleTable.cpp
rename to media/extractors/mp4/SampleTable.cpp
index 1d2a931..378d63a 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/extractors/mp4/SampleTable.cpp
@@ -20,14 +20,14 @@
 
 #include <limits>
 
-#include "include/SampleTable.h"
-#include "include/SampleIterator.h"
+#include "SampleTable.h"
+#include "SampleIterator.h"
 
 #include <arpa/inet.h>
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 
 /* TODO: remove after being merged into other branches */
 #ifndef UINT32_MAX
@@ -724,6 +724,14 @@
         return ERROR_OUT_OF_RANGE;
     }
 
+    if (flags == kFlagFrameIndex) {
+        if (req_time >= mNumSampleSizes) {
+            return ERROR_OUT_OF_RANGE;
+        }
+        *sample_index = mSampleTimeEntries[req_time].mSampleIndex;
+        return OK;
+    }
+
     uint32_t left = 0;
     uint32_t right_plus_one = mNumSampleSizes;
     while (left < right_plus_one) {
diff --git a/media/libstagefright/include/SampleTable.h b/media/extractors/mp4/SampleTable.h
similarity index 98%
rename from media/libstagefright/include/SampleTable.h
rename to media/extractors/mp4/SampleTable.h
index eb1a674..466e26b 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/extractors/mp4/SampleTable.h
@@ -72,7 +72,8 @@
     enum {
         kFlagBefore,
         kFlagAfter,
-        kFlagClosest
+        kFlagClosest,
+        kFlagFrameIndex,
     };
     status_t findSampleAtTime(
             uint64_t req_time, uint64_t scale_num, uint64_t scale_den,
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
new file mode 100644
index 0000000..50f740b
--- /dev/null
+++ b/media/extractors/mpeg2/Android.bp
@@ -0,0 +1,56 @@
+cc_library_shared {
+
+    srcs: [
+        "ExtractorBundle.cpp",
+        "MPEG2PSExtractor.cpp",
+        "MPEG2TSExtractor.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    shared_libs: [
+        "android.hardware.cas@1.0",
+        "android.hardware.cas.native@1.0",
+        "android.hidl.token@1.0-utils",
+        "libbinder",
+        "libcrypto",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libmedia",  // Needed for IStreamListener
+        "libmediaextractor",
+        "libstagefright",  // Needed for AnotherPacketSource and more
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libstagefright_mpeg2support",
+    ],
+
+    name: "libmpeg2extractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/extractors/mpeg2/ExtractorBundle.cpp b/media/extractors/mpeg2/ExtractorBundle.cpp
new file mode 100644
index 0000000..d5682e9
--- /dev/null
+++ b/media/extractors/mpeg2/ExtractorBundle.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MPEG2ExtractorBundle"
+#include <utils/Log.h>
+
+#include <media/MediaExtractor.h>
+#include "MPEG2PSExtractor.h"
+#include "MPEG2TSExtractor.h"
+
+namespace android {
+
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("3d1dcfeb-e40a-436d-a574-c2438a555e5f"),
+        1,
+        "MPEG2-PS/TS Extractor",
+        [](
+                const sp<DataSource> &source,
+                String8 *mimeType,
+                float *confidence,
+                sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
+            if (SniffMPEG2TS(source, mimeType, confidence, meta)) {
+                return [](
+                        const sp<DataSource> &source,
+                        const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                    return new MPEG2TSExtractor(source);};
+            } else if (SniffMPEG2PS(source, mimeType, confidence, meta)) {
+                        return [](
+                                const sp<DataSource> &source,
+                                const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                            return new MPEG2PSExtractor(source);};
+            }
+            return NULL;
+        }
+    };
+}
+
+} // extern "C"
+
+} // namespace android
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/mpeg2/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/mpeg2/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
similarity index 98%
rename from media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
rename to media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 078a5f0..c519caf 100644
--- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -18,22 +18,22 @@
 #define LOG_TAG "MPEG2PSExtractor"
 #include <utils/Log.h>
 
-#include "include/MPEG2PSExtractor.h"
+#include "MPEG2PSExtractor.h"
 
-#include "AnotherPacketSource.h"
-#include "ESQueue.h"
+#include "mpeg2ts/AnotherPacketSource.h"
+#include "mpeg2ts/ESQueue.h"
 
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
 #include <utils/String8.h>
 
 #include <inttypes.h>
@@ -125,7 +125,7 @@
     return mTracks.size();
 }
 
-sp<IMediaSource> MPEG2PSExtractor::getTrack(size_t index) {
+sp<MediaSource> MPEG2PSExtractor::getTrack(size_t index) {
     if (index >= mTracks.size()) {
         return NULL;
     }
diff --git a/media/libstagefright/include/MPEG2PSExtractor.h b/media/extractors/mpeg2/MPEG2PSExtractor.h
similarity index 94%
rename from media/libstagefright/include/MPEG2PSExtractor.h
rename to media/extractors/mpeg2/MPEG2PSExtractor.h
index f5471b3..ab3ab05 100644
--- a/media/libstagefright/include/MPEG2PSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.h
@@ -19,7 +19,7 @@
 #define MPEG2_PS_EXTRACTOR_H_
 
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
 
@@ -34,7 +34,7 @@
     explicit MPEG2PSExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
+    virtual sp<MediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
similarity index 98%
rename from media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
rename to media/extractors/mpeg2/MPEG2TSExtractor.cpp
index 9d684e0..4f61e16 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -20,23 +20,22 @@
 #include <inttypes.h>
 #include <utils/Log.h>
 
-#include "include/MPEG2TSExtractor.h"
-#include "include/NuCachedSource2.h"
+#include "MPEG2TSExtractor.h"
 
+#include <media/DataSource.h>
+#include <media/IStreamSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
-#include <media/IStreamSource.h>
 #include <utils/String8.h>
 
-#include "AnotherPacketSource.h"
-#include "ATSParser.h"
+#include "mpeg2ts/AnotherPacketSource.h"
+#include "mpeg2ts/ATSParser.h"
 
 #include <hidl/HybridInterface.h>
 #include <android/hardware/cas/1.0/ICas.h>
@@ -129,7 +128,7 @@
     return mSourceImpls.size();
 }
 
-sp<IMediaSource> MPEG2TSExtractor::getTrack(size_t index) {
+sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) {
     if (index >= mSourceImpls.size()) {
         return NULL;
     }
@@ -513,6 +512,8 @@
                 --index;
             }
             break;
+        default:
+            return ERROR_UNSUPPORTED;
     }
     if (!shouldSeekBeyond || mOffset <= mSeekSyncPoints->valueAt(index)) {
         int64_t actualSeekTimeUs = mSeekSyncPoints->keyAt(index);
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/extractors/mpeg2/MPEG2TSExtractor.h
similarity index 95%
rename from media/libstagefright/include/MPEG2TSExtractor.h
rename to media/extractors/mpeg2/MPEG2TSExtractor.h
index ac93b5e..55356bf 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.h
@@ -19,8 +19,8 @@
 #define MPEG2_TS_EXTRACTOR_H_
 
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
@@ -40,7 +40,7 @@
     explicit MPEG2TSExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
+    virtual sp<MediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/mpeg2/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/mpeg2/NOTICE
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
new file mode 100644
index 0000000..6bd8025
--- /dev/null
+++ b/media/extractors/ogg/Android.bp
@@ -0,0 +1,43 @@
+cc_library_shared {
+
+    srcs: ["OggExtractor.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "external/tremolo",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libmediaextractor",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libvorbisidec",
+    ],
+
+    name: "liboggextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/ogg/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/ogg/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/ogg/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/ogg/NOTICE
diff --git a/media/libstagefright/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
similarity index 96%
rename from media/libstagefright/OggExtractor.cpp
rename to media/extractors/ogg/OggExtractor.cpp
index 766230a..f42a6a8 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -18,20 +18,20 @@
 #define LOG_TAG "OggExtractor"
 #include <utils/Log.h>
 
-#include "include/OggExtractor.h"
+#include "OggExtractor.h"
 
 #include <cutils/properties.h>
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/base64.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
 #include <utils/String8.h>
 
 extern "C" {
@@ -1176,19 +1176,8 @@
     return (mVi.bitrate_lower + mVi.bitrate_upper) / 2;
 }
 
-void MyOggExtractor::parseFileMetaData() {
-    mFileMeta = new MetaData;
-    mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
-
-    for (int i = 0; i < mVc.comments; ++i) {
-        const char *comment = mVc.user_comments[i];
-        size_t commentLength = mVc.comment_lengths[i];
-        parseVorbisComment(mFileMeta, comment, commentLength);
-        //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
-    }
-}
-
-void parseVorbisComment(
+// also exists in FLACExtractor, candidate for moving to utility/support library?
+static void parseVorbisComment(
         const sp<MetaData> &fileMeta, const char *comment, size_t commentLength)
 {
     struct {
@@ -1234,6 +1223,7 @@
 
 }
 
+// also exists in FLACExtractor, candidate for moving to utility/support library?
 static void extractAlbumArt(
         const sp<MetaData> &fileMeta, const void *data, size_t size) {
     ALOGV("extractAlbumArt from '%s'", (const char *)data);
@@ -1310,6 +1300,19 @@
     fileMeta->setCString(kKeyAlbumArtMIME, type);
 }
 
+void MyOggExtractor::parseFileMetaData() {
+    mFileMeta = new MetaData;
+    mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
+
+    for (int i = 0; i < mVc.comments; ++i) {
+        const char *comment = mVc.user_comments[i];
+        size_t commentLength = mVc.comment_lengths[i];
+        parseVorbisComment(mFileMeta, comment, commentLength);
+        //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
+    }
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 
 OggExtractor::OggExtractor(const sp<DataSource> &source)
@@ -1345,7 +1348,7 @@
     return mInitCheck != OK ? 0 : 1;
 }
 
-sp<IMediaSource> OggExtractor::getTrack(size_t index) {
+sp<MediaSource> OggExtractor::getTrack(size_t index) {
     if (index >= 1) {
         return NULL;
     }
@@ -1366,18 +1369,41 @@
     return mImpl->getFileMetaData();
 }
 
-bool SniffOgg(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+static MediaExtractor* CreateExtractor(
+        const sp<DataSource> &source,
+        const sp<AMessage>& meta __unused) {
+    return new OggExtractor(source);
+}
+
+static MediaExtractor::CreatorFunc Sniff(
+        const sp<DataSource> &source,
+        String8 *mimeType,
+        float *confidence,
         sp<AMessage> *) {
     char tmp[4];
     if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
-        return false;
+        return NULL;
     }
 
     mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG);
     *confidence = 0.2f;
 
-    return true;
+    return CreateExtractor;
 }
 
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("8cc5cd06-f772-495e-8a62-cba9649374e9"),
+        1, // version
+        "Ogg Extractor",
+        Sniff
+    };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/include/OggExtractor.h b/media/extractors/ogg/OggExtractor.h
similarity index 87%
rename from media/libstagefright/include/OggExtractor.h
rename to media/extractors/ogg/OggExtractor.h
index 55aafed..0f7fe5f 100644
--- a/media/libstagefright/include/OggExtractor.h
+++ b/media/extractors/ogg/OggExtractor.h
@@ -19,7 +19,7 @@
 #define OGG_EXTRACTOR_H_
 
 #include <utils/Errors.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 namespace android {
 
@@ -34,7 +34,7 @@
     explicit OggExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
+    virtual sp<MediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
@@ -59,9 +59,6 @@
         const sp<DataSource> &source, String8 *mimeType, float *confidence,
         sp<AMessage> *);
 
-void parseVorbisComment(
-        const sp<MetaData> &fileMeta, const char *comment, size_t commentLength);
-
 }  // namespace android
 
 #endif  // OGG_EXTRACTOR_H_
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
new file mode 100644
index 0000000..f310892
--- /dev/null
+++ b/media/extractors/wav/Android.bp
@@ -0,0 +1,42 @@
+cc_library_shared {
+
+    srcs: ["WAVExtractor.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libmediaextractor",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libfifo",
+    ],
+
+    name: "libwavextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/wav/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/wav/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/wav/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/wav/NOTICE
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
similarity index 94%
rename from media/libstagefright/WAVExtractor.cpp
rename to media/extractors/wav/WAVExtractor.cpp
index 780b746..6c5f893 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -18,15 +18,15 @@
 #define LOG_TAG "WAVExtractor"
 #include <utils/Log.h>
 
-#include "include/WAVExtractor.h"
+#include "WAVExtractor.h"
 
 #include <audio_utils/primitives.h>
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 #include <cutils/bitops.h>
@@ -120,7 +120,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-sp<IMediaSource> WAVExtractor::getTrack(size_t index) {
+sp<MediaSource> WAVExtractor::getTrack(size_t index) {
     if (mInitCheck != OK || index > 0) {
         return NULL;
     }
@@ -544,27 +544,50 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool SniffWAV(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+static MediaExtractor* CreateExtractor(
+        const sp<DataSource> &source,
+        const sp<AMessage>& meta __unused) {
+    return new WAVExtractor(source);
+}
+
+static MediaExtractor::CreatorFunc Sniff(
+        const sp<DataSource> &source,
+        String8 *mimeType,
+        float *confidence,
         sp<AMessage> *) {
     char header[12];
     if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
-        return false;
+        return NULL;
     }
 
     if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) {
-        return false;
+        return NULL;
     }
 
     sp<MediaExtractor> extractor = new WAVExtractor(source);
     if (extractor->countTracks() == 0) {
-        return false;
+        return NULL;
     }
 
     *mimeType = MEDIA_MIMETYPE_CONTAINER_WAV;
     *confidence = 0.3f;
 
-    return true;
+    return CreateExtractor;
 }
 
-}  // namespace android
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("7d613858-5837-4a38-84c5-332d1cddee27"),
+        1, // version
+        "WAV Extractor",
+        Sniff
+    };
+}
+
+} // extern "C"
+
+} // namespace android
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/extractors/wav/WAVExtractor.h
similarity index 88%
rename from media/libstagefright/include/WAVExtractor.h
rename to media/extractors/wav/WAVExtractor.h
index 12ad441..98a2dfa 100644
--- a/media/libstagefright/include/WAVExtractor.h
+++ b/media/extractors/wav/WAVExtractor.h
@@ -19,7 +19,7 @@
 #define WAV_EXTRACTOR_H_
 
 #include <utils/Errors.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 namespace android {
 
@@ -33,7 +33,7 @@
     explicit WAVExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
+    virtual sp<MediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
@@ -61,10 +61,6 @@
     WAVExtractor &operator=(const WAVExtractor &);
 };
 
-bool SniffWAV(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *);
-
 }  // namespace android
 
 #endif  // WAV_EXTRACTOR_H_
diff --git a/media/libaaudio/examples/Android.bp b/media/libaaudio/examples/Android.bp
index f2e00a7..639fab2 100644
--- a/media/libaaudio/examples/Android.bp
+++ b/media/libaaudio/examples/Android.bp
@@ -1,4 +1,6 @@
+subdirs = ["*"]
+
 cc_library_headers {
     name: "libaaudio_example_utils",
-    export_include_dirs: ["."],
+    export_include_dirs: ["utils"],
 }
diff --git a/media/libaaudio/examples/input_monitor/Android.bp b/media/libaaudio/examples/input_monitor/Android.bp
new file mode 100644
index 0000000..2c3418d
--- /dev/null
+++ b/media/libaaudio/examples/input_monitor/Android.bp
@@ -0,0 +1,15 @@
+cc_test {
+    name: "input_monitor",
+    gtest: false,
+    srcs: ["src/input_monitor.cpp"],
+    shared_libs: ["libaaudio"],
+    header_libs: ["libaaudio_example_utils"],
+}
+
+cc_test {
+    name: "input_monitor_callback",
+    gtest: false,
+    srcs: ["src/input_monitor_callback.cpp"],
+    shared_libs: ["libaaudio"],
+    header_libs: ["libaaudio_example_utils"],
+}
diff --git a/media/libaaudio/examples/loopback/Android.bp b/media/libaaudio/examples/loopback/Android.bp
new file mode 100644
index 0000000..2b624a8
--- /dev/null
+++ b/media/libaaudio/examples/loopback/Android.bp
@@ -0,0 +1,7 @@
+cc_test {
+    name: "aaudio_loopback",
+    gtest: false,
+    srcs: ["src/loopback.cpp"],
+    shared_libs: ["libaaudio"],
+    header_libs: ["libaaudio_example_utils"],
+}
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index b678d8a..ac6024e 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -159,21 +159,27 @@
 }
 
 static void usage() {
-    printf("loopback: -n{numBursts} -p{outPerf} -P{inPerf} -t{test} -g{gain} -f{freq}\n");
-    printf("          -c{inputChannels}\n");
-    printf("          -f{freq}  sine frequency\n");
-    printf("          -g{gain}  recirculating loopback gain\n");
-    printf("          -m enable MMAP mode\n");
-    printf("          -n{numBursts} buffer size, for example 2 for double buffered\n");
-    printf("          -p{outPerf}  set output AAUDIO_PERFORMANCE_MODE*\n");
-    printf("          -P{inPerf}   set input AAUDIO_PERFORMANCE_MODE*\n");
+    printf("Usage: aaudio_loopback [OPTION]...\n\n");
+    printf("          -c{channels}      number of output channels\n");
+    printf("          -C{channels}      number of input channels\n");
+    printf("          -g{gain}          recirculating loopback gain\n");
+    printf("          -m{0|1|2|3}       set MMAP policy\n");
+    printf("              0 = _UNSPECIFIED\n");
+    printf("              1 = _NEVER\n");
+    printf("              2 = _AUTO, also if -m is used with no number\n");
+    printf("              3 = _ALWAYS\n");
+    printf("          -n{numBursts}     buffer size, for example 2 for double buffered\n");
+    printf("          -p{outPerf}       set output AAUDIO_PERFORMANCE_MODE*\n");
+    printf("          -P{inPerf}        set input AAUDIO_PERFORMANCE_MODE*\n");
     printf("              n for _NONE\n");
     printf("              l for _LATENCY\n");
-    printf("              p for _POWER_SAVING;\n");
-    printf("          -t{test}   select test mode\n");
+    printf("              p for _POWER_SAVING\n");
+    printf("          -t{test}          select test mode\n");
     printf("              m for sine magnitude\n");
-    printf("              e for echo latency (default)\n");
-    printf("For example:  loopback -b2 -pl -Pn\n");
+    printf("              e for echo latency (default)\n\n");
+    printf("          -x                use EXCLUSIVE mode for output\n");
+    printf("          -X                use EXCLUSIVE mode for input\n");
+    printf("Example:  aaudio_loopback -n2 -pl -Pl -x\n");
 }
 
 static aaudio_performance_mode_t parsePerformanceMode(char c) {
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index ada37e2..142b295 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -17,6 +17,8 @@
 #ifndef AAUDIO_EXAMPLE_ARGS_PARSER_H
 #define AAUDIO_EXAMPLE_ARGS_PARSER_H
 
+#define MAX_CHANNELS                     8
+
 #include <cctype>
 #include <unistd.h>
 #include <stdio.h>
@@ -39,6 +41,10 @@
     }
 
     void setChannelCount(int32_t channelCount) {
+        if (channelCount > MAX_CHANNELS) {
+            printf("Sorry, MAX of %d channels!\n", MAX_CHANNELS);
+            channelCount = MAX_CHANNELS;
+        }
         mChannelCount = channelCount;
     }
 
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 606c4ba..3fafecf 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -19,11 +19,10 @@
 #ifndef AAUDIO_SIMPLE_PLAYER_H
 #define AAUDIO_SIMPLE_PLAYER_H
 
-#include <unistd.h>
 #include <sched.h>
+#include <unistd.h>
 
 #include <aaudio/AAudio.h>
-#include <atomic>
 #include "AAudioArgsParser.h"
 #include "SineGenerator.h"
 
@@ -31,12 +30,12 @@
 #define SHARING_MODE  AAUDIO_SHARING_MODE_SHARED
 #define PERFORMANCE_MODE AAUDIO_PERFORMANCE_MODE_NONE
 
-// Arbitrary period for glitches, once per second at 48000 Hz.
-#define FORCED_UNDERRUN_PERIOD_FRAMES    48000
+// Arbitrary period for glitches
+#define FORCED_UNDERRUN_PERIOD_FRAMES    (2 * 48000)
 // How long to sleep in a callback to cause an intentional glitch. For testing.
 #define FORCED_UNDERRUN_SLEEP_MICROS     (10 * 1000)
 
-#define MAX_TIMESTAMPS   16
+#define MAX_TIMESTAMPS                   16
 
 typedef struct Timestamp {
     int64_t position;
@@ -70,13 +69,6 @@
     }
 
     // TODO Extract a common base class for record and playback.
-    /**
-     * Also known as "sample rate"
-     * Only call this after open() has been called.
-     */
-    int32_t getFramesPerSecond() const {
-        return getSampleRate(); // alias
-    }
 
     /**
      * Only call this after open() has been called.
@@ -172,6 +164,7 @@
         result = AAudioStreamBuilder_openStream(builder, &mStream);
 
         AAudioStreamBuilder_delete(builder);
+
         return result;
     }
 
@@ -212,13 +205,35 @@
         aaudio_result_t result = AAudioStream_requestStop(mStream);
         if (result != AAUDIO_OK) {
             printf("ERROR - AAudioStream_requestStop() returned %d %s\n",
-                    result, AAudio_convertResultToText(result));
+                   result, AAudio_convertResultToText(result));
         }
         int32_t xRunCount = AAudioStream_getXRunCount(mStream);
         printf("AAudioStream_getXRunCount %d\n", xRunCount);
         return result;
     }
 
+    // Pause the stream. AAudio will stop calling your callback function.
+    aaudio_result_t pause() {
+        aaudio_result_t result = AAudioStream_requestPause(mStream);
+        if (result != AAUDIO_OK) {
+            printf("ERROR - AAudioStream_requestPause() returned %d %s\n",
+                   result, AAudio_convertResultToText(result));
+        }
+        int32_t xRunCount = AAudioStream_getXRunCount(mStream);
+        printf("AAudioStream_getXRunCount %d\n", xRunCount);
+        return result;
+    }
+
+    // Flush the stream. AAudio will stop calling your callback function.
+    aaudio_result_t flush() {
+        aaudio_result_t result = AAudioStream_requestFlush(mStream);
+        if (result != AAUDIO_OK) {
+            printf("ERROR - AAudioStream_requestFlush() returned %d %s\n",
+                   result, AAudio_convertResultToText(result));
+        }
+        return result;
+    }
+
     AAudioStream *getStream() const {
         return mStream;
     }
@@ -232,23 +247,49 @@
 
 typedef struct SineThreadedData_s {
 
-    SineGenerator  sineOsc1;
-    SineGenerator  sineOsc2;
-    Timestamp      timestamps[MAX_TIMESTAMPS];
-    int64_t        framesTotal = 0;
-    int64_t        nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
-    int32_t        minNumFrames = INT32_MAX;
-    int32_t        maxNumFrames = 0;
-    int32_t        timestampCount = 0; // in timestamps
+    SineGenerator      sineOscillators[MAX_CHANNELS];
+    Timestamp          timestamps[MAX_TIMESTAMPS];
+    int64_t            framesTotal = 0;
+    int64_t            nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
+    int32_t            minNumFrames = INT32_MAX;
+    int32_t            maxNumFrames = 0;
+    int32_t            timestampCount = 0; // in timestamps
+    int32_t            sampleRate = 48000;
+    int32_t            prefixToneFrames = 0;
+    bool               sweepSetup = false;
 
-    int            scheduler = 0;
-    bool           schedulerChecked = false;
-    bool           forceUnderruns = false;
+    int                scheduler = 0;
+    bool               schedulerChecked = false;
+    bool               forceUnderruns = false;
 
     AAudioSimplePlayer simplePlayer;
     int32_t            callbackCount = 0;
     WakeUp             waker{AAUDIO_OK};
 
+    /**
+     * Set sampleRate first.
+     */
+    void setupSineBlip() {
+        for (int i = 0; i < MAX_CHANNELS; ++i) {
+            double centerFrequency = 880.0 * (i + 2);
+            sineOscillators[i].setup(centerFrequency, sampleRate);
+            sineOscillators[i].setSweep(centerFrequency, centerFrequency, 0.0);
+        }
+    }
+
+    void setupSineSweeps() {
+        for (int i = 0; i < MAX_CHANNELS; ++i) {
+            double centerFrequency = 220.0 * (i + 2);
+            sineOscillators[i].setup(centerFrequency, sampleRate);
+            double minFrequency = centerFrequency * 2.0 / 3.0;
+            // Change range slightly so they will go out of phase.
+            double maxFrequency = centerFrequency * 3.0 / 2.0;
+            double sweepSeconds = 5.0 + i;
+            sineOscillators[i].setSweep(minFrequency, maxFrequency, sweepSeconds);
+        }
+        sweepSetup = true;
+    }
+
 } SineThreadedData_t;
 
 // Callback function that fills the audio output buffer.
@@ -265,9 +306,11 @@
         return AAUDIO_CALLBACK_RESULT_STOP;
     }
     SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
-    sineData->callbackCount++;
 
-    sineData->framesTotal += numFrames;
+    // Play an initial high tone so we can tell whether the beginning was truncated.
+    if (!sineData->sweepSetup && sineData->framesTotal >= sineData->prefixToneFrames) {
+        sineData->setupSineSweeps();
+    }
 
     if (sineData->forceUnderruns) {
         if (sineData->framesTotal > sineData->nextFrameToGlitch) {
@@ -301,33 +344,32 @@
     }
 
     int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
-    // This code only plays on the first one or two channels.
-    // TODO Support arbitrary number of channels.
+
+
+    int numActiveOscilators = (samplesPerFrame > MAX_CHANNELS) ? MAX_CHANNELS : samplesPerFrame;
     switch (AAudioStream_getFormat(stream)) {
         case AAUDIO_FORMAT_PCM_I16: {
             int16_t *audioBuffer = (int16_t *) audioData;
-            // Render sine waves as shorts to first channel.
-            sineData->sineOsc1.render(&audioBuffer[0], samplesPerFrame, numFrames);
-            // Render sine waves to second channel if there is one.
-            if (samplesPerFrame > 1) {
-                sineData->sineOsc2.render(&audioBuffer[1], samplesPerFrame, numFrames);
+            for (int i = 0; i < numActiveOscilators; ++i) {
+                sineData->sineOscillators[i].render(&audioBuffer[i], samplesPerFrame,
+                                                    numFrames);
             }
         }
-        break;
+            break;
         case AAUDIO_FORMAT_PCM_FLOAT: {
             float *audioBuffer = (float *) audioData;
-            // Render sine waves as floats to first channel.
-            sineData->sineOsc1.render(&audioBuffer[0], samplesPerFrame, numFrames);
-            // Render sine waves to second channel if there is one.
-            if (samplesPerFrame > 1) {
-                sineData->sineOsc2.render(&audioBuffer[1], samplesPerFrame, numFrames);
+            for (int i = 0; i < numActiveOscilators; ++i) {
+                sineData->sineOscillators[i].render(&audioBuffer[i], samplesPerFrame,
+                                                    numFrames);
             }
         }
-        break;
+            break;
         default:
             return AAUDIO_CALLBACK_RESULT_STOP;
     }
 
+    sineData->callbackCount++;
+    sineData->framesTotal += numFrames;
     return AAUDIO_CALLBACK_RESULT_CONTINUE;
 }
 
diff --git a/media/libaaudio/examples/utils/SineGenerator.h b/media/libaaudio/examples/utils/SineGenerator.h
index a755582..9e6d46d 100644
--- a/media/libaaudio/examples/utils/SineGenerator.h
+++ b/media/libaaudio/examples/utils/SineGenerator.h
@@ -31,20 +31,20 @@
     }
 
     void setSweep(double frequencyLow, double frequencyHigh, double seconds) {
-        mPhaseIncrementLow = frequencyLow * M_PI * 2 / mFrameRate;
-        mPhaseIncrementHigh = frequencyHigh * M_PI * 2 / mFrameRate;
-
-        double numFrames = seconds * mFrameRate;
-        mUpScaler = pow((frequencyHigh / frequencyLow), (1.0 / numFrames));
-        mDownScaler = 1.0 / mUpScaler;
-        mGoingUp = true;
-        mSweeping = true;
+        mSweeping = seconds > 0.0;
+        if (mSweeping) {
+            mPhaseIncrementLow = frequencyLow * M_PI * 2 / mFrameRate;
+            mPhaseIncrementHigh = frequencyHigh * M_PI * 2 / mFrameRate;
+            double numFrames = seconds * mFrameRate;
+            mUpScaler = pow((frequencyHigh / frequencyLow), (1.0 / numFrames));
+            mDownScaler = 1.0 / mUpScaler;
+        }
     }
 
     void render(int16_t *buffer, int32_t channelStride, int32_t numFrames) {
         int sampleIndex = 0;
         for (int i = 0; i < numFrames; i++) {
-            buffer[sampleIndex] = (int16_t) (32767 * sin(mPhase) * mAmplitude);
+            buffer[sampleIndex] = (int16_t) (INT16_MAX * sin(mPhase) * mAmplitude);
             sampleIndex += channelStride;
             advancePhase();
         }
@@ -61,6 +61,7 @@
     void setAmplitude(double amplitude) {
         mAmplitude = amplitude;
     }
+
     double getAmplitude() const {
         return mAmplitude;
     }
diff --git a/media/libaaudio/examples/write_sine/Android.bp b/media/libaaudio/examples/write_sine/Android.bp
new file mode 100644
index 0000000..f162e85
--- /dev/null
+++ b/media/libaaudio/examples/write_sine/Android.bp
@@ -0,0 +1,13 @@
+cc_test {
+    name: "write_sine",
+    srcs: ["src/write_sine.cpp"],
+    shared_libs: ["libaaudio"],
+    header_libs: ["libaaudio_example_utils"],
+}
+
+cc_test {
+    name: "write_sine_callback",
+    srcs: ["src/write_sine_callback.cpp"],
+    shared_libs: ["libaaudio"],
+    header_libs: ["libaaudio_example_utils"],
+}
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index 8c6f783..38e1e4c 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -47,6 +47,7 @@
     int32_t  framesToPlay = 0;
     int32_t  framesLeft = 0;
     int32_t  xRunCount = 0;
+    int      numActiveOscilators = 0;
     float   *floatData = nullptr;
     int16_t *shortData = nullptr;
 
@@ -76,8 +77,8 @@
     actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
     actualDataFormat = AAudioStream_getFormat(aaudioStream);
 
-    myData.sineOsc1.setup(440.0, actualSampleRate);
-    myData.sineOsc2.setup(660.0, actualSampleRate);
+    myData.sampleRate = actualSampleRate;
+    myData.setupSineSweeps();
 
     // Some DMA might use very short bursts of 16 frames. We don't need to write such small
     // buffers. But it helps to use a multiple of the burst size for predictable scheduling.
@@ -116,19 +117,18 @@
     // Play for a while.
     framesToPlay = actualSampleRate * argParser.getDurationSeconds();
     framesLeft = framesToPlay;
+    numActiveOscilators = (actualChannelCount > MAX_CHANNELS) ? MAX_CHANNELS : actualChannelCount;
     while (framesLeft > 0) {
-
+        // Render as FLOAT or PCM
         if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
-            // Render sine waves to left and right channels.
-            myData.sineOsc1.render(&floatData[0], actualChannelCount, framesPerWrite);
-            if (actualChannelCount > 1) {
-                myData.sineOsc2.render(&floatData[1], actualChannelCount, framesPerWrite);
+            for (int i = 0; i < numActiveOscilators; ++i) {
+                myData.sineOscillators[i].render(&floatData[i], actualChannelCount,
+                                                  framesPerWrite);
             }
         } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
-            // Render sine waves to left and right channels.
-            myData.sineOsc1.render(&shortData[0], actualChannelCount, framesPerWrite);
-            if (actualChannelCount > 1) {
-                myData.sineOsc2.render(&shortData[1], actualChannelCount, framesPerWrite);
+            for (int i = 0; i < numActiveOscilators; ++i) {
+                myData.sineOscillators[i].render(&shortData[i], actualChannelCount,
+                                                  framesPerWrite);
             }
         }
 
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index 4f9cde6..5d41fd0 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -28,7 +28,7 @@
 #include <aaudio/AAudio.h>
 #include "AAudioExampleUtils.h"
 #include "AAudioSimplePlayer.h"
-#include "../../utils/AAudioSimplePlayer.h"
+#include "AAudioArgsParser.h"
 
 /**
  * Open stream, play some sine waves, then close the stream.
@@ -36,37 +36,39 @@
  * @param argParser
  * @return AAUDIO_OK or negative error code
  */
-static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser)
+static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser,
+                                         int32_t loopCount,
+                                         int32_t prefixToneMsec,
+                                         bool forceUnderruns)
 {
     SineThreadedData_t myData;
     AAudioSimplePlayer &player = myData.simplePlayer;
     aaudio_result_t    result = AAUDIO_OK;
     bool               disconnected = false;
+    bool               bailOut = false;
     int64_t            startedAtNanos;
 
     printf("----------------------- run complete test --------------------------\n");
     myData.schedulerChecked = false;
     myData.callbackCount = 0;
-    myData.forceUnderruns = false; // set true to test AAudioStream_getXRunCount()
+    myData.forceUnderruns = forceUnderruns; // test AAudioStream_getXRunCount()
 
     result = player.open(argParser,
                          SimplePlayerDataCallbackProc, SimplePlayerErrorCallbackProc, &myData);
     if (result != AAUDIO_OK) {
-        fprintf(stderr, "ERROR -  player.open() returned %d\n", result);
+        fprintf(stderr, "ERROR -  player.open() returned %s\n",
+                AAudio_convertResultToText(result));
         goto error;
     }
 
     argParser.compareWithStream(player.getStream());
 
-    // Setup sine wave generators.
-    {
-        int32_t actualSampleRate = player.getSampleRate();
-        myData.sineOsc1.setup(440.0, actualSampleRate);
-        myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
-        myData.sineOsc1.setAmplitude(0.2);
-        myData.sineOsc2.setup(660.0, actualSampleRate);
-        myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
-        myData.sineOsc2.setAmplitude(0.2);
+    myData.sampleRate = player.getSampleRate();
+    myData.prefixToneFrames = prefixToneMsec * myData.sampleRate / 1000;
+    if (myData.prefixToneFrames > 0) {
+        myData.setupSineBlip();
+    } else {
+        myData.setupSineSweeps();
     }
 
 #if 0
@@ -78,42 +80,93 @@
     }
 #endif
 
-    result = player.start();
-    if (result != AAUDIO_OK) {
-        fprintf(stderr, "ERROR - player.start() returned %d\n", result);
-        goto error;
-    }
+    for (int loopIndex = 0; loopIndex < loopCount; loopIndex++) {
+        // Only play data on every other loop so we can hear if there is stale data.
+        double amplitude;
+        int32_t durationSeconds;
+        if ((loopIndex & 1) == 0) {
+            printf("--------------- SINE ------\n");
+            amplitude = 0.2;
+            durationSeconds = argParser.getDurationSeconds();
+        } else {
+            printf("--------------- QUIET -----\n");
+            amplitude = 0.0;
+            durationSeconds = 2; // just wait briefly when quiet
+        }
+        for (int i = 0; i < MAX_CHANNELS; ++i) {
+            myData.sineOscillators[i].setAmplitude(amplitude);
+        }
 
-    // Play a sine wave in the background.
-    printf("Sleep for %d seconds while audio plays in a callback thread.\n",
-           argParser.getDurationSeconds());
-    startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
-    for (int second = 0; second < argParser.getDurationSeconds(); second++)
-    {
-        // Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
-        long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
-        int64_t millis = (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
-        result = myData.waker.get();
-        printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
-               ", second = %d, framesWritten = %8d, underruns = %d\n",
-               ret, result, (int) millis,
-               second,
-               (int) AAudioStream_getFramesWritten(player.getStream()),
-               (int) AAudioStream_getXRunCount(player.getStream()));
+        result = player.start();
         if (result != AAUDIO_OK) {
-            if (result == AAUDIO_ERROR_DISCONNECTED) {
-                disconnected = true;
+            fprintf(stderr, "ERROR - player.start() returned %d\n", result);
+            goto error;
+        }
+
+        // Play a sine wave in the background.
+        printf("Sleep for %d seconds while audio plays in a callback thread. %d of %d\n",
+               argParser.getDurationSeconds(), (loopIndex + 1), loopCount);
+        startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
+        for (int second = 0; second < durationSeconds; second++) {
+            // Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
+            long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
+            int64_t millis =
+                    (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
+            result = myData.waker.get();
+            printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
+                           ", second = %3d, framesWritten = %8d, underruns = %d\n",
+                   ret, result, (int) millis,
+                   second,
+                   (int) AAudioStream_getFramesWritten(player.getStream()),
+                   (int) AAudioStream_getXRunCount(player.getStream()));
+            if (result != AAUDIO_OK) {
+                disconnected = (result == AAUDIO_ERROR_DISCONNECTED);
+                bailOut = true;
+                break;
             }
+        }
+        printf("AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
+
+        // Alternate between using stop or pause for each sine/quiet pair.
+        // Repeat this pattern: {sine-stop-quiet-stop-sine-pause-quiet-pause}
+        if ((loopIndex & 2) == 0) {
+            printf("STOP, callback # = %d\n", myData.callbackCount);
+            result = player.stop();
+        } else {
+            printf("PAUSE/FLUSH, callback # = %d\n", myData.callbackCount);
+            result = player.pause();
+            if (result != AAUDIO_OK) {
+                goto error;
+            }
+            result = player.flush();
+        }
+        if (result != AAUDIO_OK) {
+            goto error;
+        }
+
+        if (bailOut) {
             break;
         }
-    }
-    printf("AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
 
-    printf("call stop() callback # = %d\n", myData.callbackCount);
-    result = player.stop();
-    if (result != AAUDIO_OK) {
-        goto error;
+        {
+            aaudio_stream_state_t state = AAudioStream_getState(player.getStream());
+            aaudio_stream_state_t finalState = AAUDIO_STREAM_STATE_UNINITIALIZED;
+            int64_t timeoutNanos = 2000 * NANOS_PER_MILLISECOND;
+            result = AAudioStream_waitForStateChange(player.getStream(), state,
+                                                     &finalState, timeoutNanos);
+            printf("waitForStateChange returns %s, state = %s\n",
+                   AAudio_convertResultToText(result),
+                   AAudio_convertStreamStateToText(finalState));
+            int64_t written = AAudioStream_getFramesWritten(player.getStream());
+            int64_t read = AAudioStream_getFramesRead(player.getStream());
+            printf("   framesWritten = %lld, framesRead = %lld, diff = %d\n",
+                   (long long) written,
+                   (long long) read,
+                   (int) (written - read));
+        }
+
     }
+
     printf("call close()\n");
     result = player.close();
     if (result != AAUDIO_OK) {
@@ -147,23 +200,59 @@
     return disconnected ? AAUDIO_ERROR_DISCONNECTED : result;
 }
 
+static void usage() {
+    AAudioArgsParser::usage();
+    printf("      -l{count} loopCount start/stop, every other one is silent\n");
+    printf("      -t{msec}  play a high pitched tone at the beginning\n");
+    printf("      -u        force periodic Underruns by sleeping in callback\n");
+}
+
 int main(int argc, const char **argv)
 {
     AAudioArgsParser   argParser;
     aaudio_result_t    result;
+    int32_t            loopCount = 1;
+    int32_t            prefixToneMsec = 0;
+    bool               forceUnderruns = false;
 
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
 
-    printf("%s - Play a sine sweep using an AAudio callback V0.1.2\n", argv[0]);
+    printf("%s - Play a sine sweep using an AAudio callback V0.1.3\n", argv[0]);
 
-    if (argParser.parseArgs(argc, argv)) {
-        return EXIT_FAILURE;
+    for (int i = 1; i < argc; i++) {
+        const char *arg = argv[i];
+        if (argParser.parseArg(arg)) {
+            // Handle options that are not handled by the ArgParser
+            if (arg[0] == '-') {
+                char option = arg[1];
+                switch (option) {
+                    case 'l':
+                        loopCount = atoi(&arg[2]);
+                        break;
+                    case 't':
+                        prefixToneMsec = atoi(&arg[2]);
+                        break;
+                    case 'u':
+                        forceUnderruns = true;
+                        break;
+                    default:
+                        usage();
+                        exit(EXIT_FAILURE);
+                        break;
+                }
+            } else {
+                usage();
+                exit(EXIT_FAILURE);
+                break;
+            }
+        }
     }
 
     // Keep looping until we can complete the test without disconnecting.
-    while((result = testOpenPlayClose(argParser)) == AAUDIO_ERROR_DISCONNECTED);
+    while((result = testOpenPlayClose(argParser, loopCount, prefixToneMsec, forceUnderruns))
+            == AAUDIO_ERROR_DISCONNECTED);
 
     return (result) ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index 07ee2de..dd620e3 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -15,7 +15,7 @@
  */
 
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioBinderClient"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -61,11 +61,11 @@
         , Singleton<AAudioBinderClient>() {
     gKeepBinderClient = this; // so this singleton won't get deleted
     mAAudioClient = new AAudioClient(this);
-    ALOGV("AAudioBinderClient() this = %p, created mAAudioClient = %p", this, mAAudioClient.get());
+    ALOGV("%s - this = %p, created mAAudioClient = %p", __func__, this, mAAudioClient.get());
 }
 
 AAudioBinderClient::~AAudioBinderClient() {
-    ALOGV("AAudioBinderClient()::~AAudioBinderClient() destroying %p", this);
+    ALOGV("%s - destroying %p", __func__, this);
     Mutex::Autolock _l(mServiceLock);
     if (mAAudioService != 0) {
         IInterface::asBinder(mAAudioService)->unlinkToDeath(mAAudioClient);
@@ -137,7 +137,7 @@
         stream = service->openStream(request, configurationOutput);
 
         if (stream == AAUDIO_ERROR_NO_SERVICE) {
-            ALOGE("AAudioBinderClient::openStream lost connection to AAudioService.");
+            ALOGE("openStream lost connection to AAudioService.");
             dropAAudioService(); // force a reconnect
         } else {
             break;
diff --git a/media/libaaudio/src/binding/AAudioServiceMessage.h b/media/libaaudio/src/binding/AAudioServiceMessage.h
index 54e8001..9779f24 100644
--- a/media/libaaudio/src/binding/AAudioServiceMessage.h
+++ b/media/libaaudio/src/binding/AAudioServiceMessage.h
@@ -38,13 +38,16 @@
     AAUDIO_SERVICE_EVENT_FLUSHED,
     AAUDIO_SERVICE_EVENT_CLOSED,
     AAUDIO_SERVICE_EVENT_DISCONNECTED,
-    AAUDIO_SERVICE_EVENT_VOLUME
+    AAUDIO_SERVICE_EVENT_VOLUME,
+    AAUDIO_SERVICE_EVENT_XRUN
 } aaudio_service_event_t;
 
 struct AAudioMessageEvent {
     aaudio_service_event_t event;
-    double                 dataDouble;
-    int64_t                dataLong;
+    union {
+        double  dataDouble;
+        int64_t dataLong;
+    };
 };
 
 typedef struct AAudioServiceMessage_s {
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index 1200ab2..c30c5b9 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioStreamRequest"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -58,7 +58,7 @@
     return NO_ERROR;
 
 error:
-    ALOGE("AAudioStreamRequest.writeToParcel(): write failed = %d", status);
+    ALOGE("writeToParcel(): write failed = %d", status);
     return status;
 }
 
@@ -80,7 +80,7 @@
     return NO_ERROR;
 
 error:
-    ALOGE("AAudioStreamRequest.readFromParcel(): read failed = %d", status);
+    ALOGE("readFromParcel(): read failed = %d", status);
     return status;
 }
 
@@ -89,9 +89,9 @@
 }
 
 void AAudioStreamRequest::dump() const {
-    ALOGD("AAudioStreamRequest mUserId    = %d", mUserId);
-    ALOGD("AAudioStreamRequest mProcessId = %d", mProcessId);
-    ALOGD("AAudioStreamRequest mSharingModeMatchRequired = %d", mSharingModeMatchRequired);
-    ALOGD("AAudioStreamRequest mInService = %d", mInService);
+    ALOGD("mUserId    = %d", mUserId);
+    ALOGD("mProcessId = %d", mProcessId);
+    ALOGD("mSharingModeMatchRequired = %d", mSharingModeMatchRequired);
+    ALOGD("mInService = %d", mInService);
     mConfiguration.dump();
 }
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
index 1a97555..9eed96d 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioEndpointParcelable"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -112,49 +112,49 @@
 aaudio_result_t AudioEndpointParcelable::validate() {
     aaudio_result_t result;
     if (mNumSharedMemories < 0 || mNumSharedMemories >= MAX_SHARED_MEMORIES) {
-        ALOGE("AudioEndpointParcelable invalid mNumSharedMemories = %d", mNumSharedMemories);
+        ALOGE("invalid mNumSharedMemories = %d", mNumSharedMemories);
         return AAUDIO_ERROR_INTERNAL;
     }
     for (int i = 0; i < mNumSharedMemories; i++) {
         result = mSharedMemories[i].validate();
         if (result != AAUDIO_OK) {
-            ALOGE("AudioEndpointParcelable invalid mSharedMemories[%d] = %d", i, result);
+            ALOGE("invalid mSharedMemories[%d] = %d", i, result);
             return result;
         }
     }
     if ((result = mUpMessageQueueParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("AudioEndpointParcelable invalid mUpMessageQueueParcelable = %d", result);
+        ALOGE("invalid mUpMessageQueueParcelable = %d", result);
         return result;
     }
     if ((result = mDownMessageQueueParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("AudioEndpointParcelable invalid mDownMessageQueueParcelable = %d", result);
+        ALOGE("invalid mDownMessageQueueParcelable = %d", result);
         return result;
     }
     if ((result = mUpDataQueueParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("AudioEndpointParcelable invalid mUpDataQueueParcelable = %d", result);
+        ALOGE("invalid mUpDataQueueParcelable = %d", result);
         return result;
     }
     if ((result = mDownDataQueueParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("AudioEndpointParcelable invalid mDownDataQueueParcelable = %d", result);
+        ALOGE("invalid mDownDataQueueParcelable = %d", result);
         return result;
     }
     return AAUDIO_OK;
 }
 
 void AudioEndpointParcelable::dump() {
-    ALOGD("AudioEndpointParcelable ======================================= BEGIN");
-    ALOGD("AudioEndpointParcelable mNumSharedMemories = %d", mNumSharedMemories);
+    ALOGD("======================================= BEGIN");
+    ALOGD("mNumSharedMemories = %d", mNumSharedMemories);
     for (int i = 0; i < mNumSharedMemories; i++) {
         mSharedMemories[i].dump();
     }
-    ALOGD("AudioEndpointParcelable mUpMessageQueueParcelable =========");
+    ALOGD("mUpMessageQueueParcelable =========");
     mUpMessageQueueParcelable.dump();
-    ALOGD("AudioEndpointParcelable mDownMessageQueueParcelable =======");
+    ALOGD("mDownMessageQueueParcelable =======");
     mDownMessageQueueParcelable.dump();
-    ALOGD("AudioEndpointParcelable mUpDataQueueParcelable ============");
+    ALOGD("mUpDataQueueParcelable ============");
     mUpDataQueueParcelable.dump();
-    ALOGD("AudioEndpointParcelable mDownDataQueueParcelable ==========");
+    ALOGD("mDownDataQueueParcelable ==========");
     mDownDataQueueParcelable.dump();
-    ALOGD("AudioEndpointParcelable ======================================= END");
+    ALOGD("======================================= END");
 }
 
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.cpp b/media/libaaudio/src/binding/RingBufferParcelable.cpp
index 6b74b21..2babbff 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.cpp
+++ b/media/libaaudio/src/binding/RingBufferParcelable.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "RingBufferParcelable"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -97,7 +97,7 @@
     }
     return NO_ERROR;
 error:
-    ALOGE("RingBufferParcelable::writeToParcel() error = %d", status);
+    ALOGE("writeToParcel() error = %d", status);
     return status;
 }
 
@@ -120,7 +120,7 @@
     }
     return NO_ERROR;
 error:
-    ALOGE("RingBufferParcelable::readFromParcel() error = %d", status);
+    ALOGE("readFromParcel() error = %d", status);
     return status;
 }
 
@@ -154,27 +154,27 @@
 aaudio_result_t RingBufferParcelable::validate() {
     aaudio_result_t result;
     if (mCapacityInFrames < 0 || mCapacityInFrames >= 32 * 1024) {
-        ALOGE("RingBufferParcelable invalid mCapacityInFrames = %d", mCapacityInFrames);
+        ALOGE("invalid mCapacityInFrames = %d", mCapacityInFrames);
         return AAUDIO_ERROR_INTERNAL;
     }
     if (mBytesPerFrame < 0 || mBytesPerFrame >= 256) {
-        ALOGE("RingBufferParcelable invalid mBytesPerFrame = %d", mBytesPerFrame);
+        ALOGE("invalid mBytesPerFrame = %d", mBytesPerFrame);
         return AAUDIO_ERROR_INTERNAL;
     }
     if (mFramesPerBurst < 0 || mFramesPerBurst >= 16 * 1024) {
-        ALOGE("RingBufferParcelable invalid mFramesPerBurst = %d", mFramesPerBurst);
+        ALOGE("invalid mFramesPerBurst = %d", mFramesPerBurst);
         return AAUDIO_ERROR_INTERNAL;
     }
     if ((result = mReadCounterParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("RingBufferParcelable invalid mReadCounterParcelable = %d", result);
+        ALOGE("invalid mReadCounterParcelable = %d", result);
         return result;
     }
     if ((result = mWriteCounterParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("RingBufferParcelable invalid mWriteCounterParcelable = %d", result);
+        ALOGE("invalid mWriteCounterParcelable = %d", result);
         return result;
     }
     if ((result = mDataParcelable.validate()) != AAUDIO_OK) {
-        ALOGE("RingBufferParcelable invalid mDataParcelable = %d", result);
+        ALOGE("invalid mDataParcelable = %d", result);
         return result;
     }
     return AAUDIO_OK;
@@ -182,11 +182,11 @@
 
 
 void RingBufferParcelable::dump() {
-    ALOGD("RingBufferParcelable mCapacityInFrames = %d ---------", mCapacityInFrames);
+    ALOGD("mCapacityInFrames = %d ---------", mCapacityInFrames);
     if (mCapacityInFrames > 0) {
-        ALOGD("RingBufferParcelable mBytesPerFrame = %d", mBytesPerFrame);
-        ALOGD("RingBufferParcelable mFramesPerBurst = %d", mFramesPerBurst);
-        ALOGD("RingBufferParcelable mFlags = %u", mFlags);
+        ALOGD("mBytesPerFrame = %d", mBytesPerFrame);
+        ALOGD("mFramesPerBurst = %d", mFramesPerBurst);
+        ALOGD("mFlags = %u", mFlags);
         mReadCounterParcelable.dump();
         mWriteCounterParcelable.dump();
         mDataParcelable.dump();
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 90217ab..4e3e5d1 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "SharedMemoryParcelable"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -43,8 +43,7 @@
 
 void SharedMemoryParcelable::setup(const unique_fd& fd, int32_t sizeInBytes) {
     mFd.reset(dup(fd.get())); // store a duplicate fd
-    ALOGV("SharedMemoryParcelable::setup(%d -> %d, %d) this = %p\n",
-          fd.get(), mFd.get(), sizeInBytes, this);
+    ALOGV("setup(%d -> %d, %d) this = %p\n", fd.get(), mFd.get(), sizeInBytes, this);
     mSizeInBytes = sizeInBytes;
 }
 
@@ -52,7 +51,7 @@
     status_t status = parcel->writeInt32(mSizeInBytes);
     if (status != NO_ERROR) return status;
     if (mSizeInBytes > 0) {
-        ALOGV("SharedMemoryParcelable::writeToParcel() mFd = %d, this = %p\n", mFd.get(), this);
+        ALOGV("writeToParcel() mFd = %d, this = %p\n", mFd.get(), this);
         status = parcel->writeUniqueFileDescriptor(mFd);
         ALOGE_IF(status != NO_ERROR, "SharedMemoryParcelable writeDupFileDescriptor failed : %d",
                  status);
@@ -70,8 +69,7 @@
         unique_fd mmapFd;
         status = parcel->readUniqueFileDescriptor(&mmapFd);
         if (status != NO_ERROR) {
-            ALOGE("SharedMemoryParcelable::readFromParcel() readUniqueFileDescriptor() failed : %d",
-                  status);
+            ALOGE("readFromParcel() readUniqueFileDescriptor() failed : %d", status);
         } else {
             // Resolve the memory now while we still have the FD from the Parcel.
             // Closing the FD will not affect the shared memory once mmap() has been called.
@@ -85,7 +83,7 @@
     if (mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
         int err = munmap(mResolvedAddress, mSizeInBytes);
         if (err < 0) {
-            ALOGE("SharedMemoryParcelable::close() munmap() failed %d", err);
+            ALOGE("close() munmap() failed %d", err);
             return AAudioConvert_androidToAAudioResult(err);
         }
         mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
@@ -97,8 +95,7 @@
     mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ | PROT_WRITE,
                                         MAP_SHARED, fd.get(), 0);
     if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
-        ALOGE("SharedMemoryParcelable mmap() failed for fd = %d, errno = %s",
-              fd.get(), strerror(errno));
+        ALOGE("mmap() failed for fd = %d, errno = %s", fd.get(), strerror(errno));
         return AAUDIO_ERROR_INTERNAL;
     }
     return AAUDIO_OK;
@@ -107,10 +104,10 @@
 aaudio_result_t SharedMemoryParcelable::resolve(int32_t offsetInBytes, int32_t sizeInBytes,
                                               void **regionAddressPtr) {
     if (offsetInBytes < 0) {
-        ALOGE("SharedMemoryParcelable illegal offsetInBytes = %d", offsetInBytes);
+        ALOGE("illegal offsetInBytes = %d", offsetInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     } else if ((offsetInBytes + sizeInBytes) > mSizeInBytes) {
-        ALOGE("SharedMemoryParcelable out of range, offsetInBytes = %d, "
+        ALOGE("out of range, offsetInBytes = %d, "
                       "sizeInBytes = %d, mSizeInBytes = %d",
               offsetInBytes, sizeInBytes, mSizeInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
@@ -122,16 +119,15 @@
         if (mFd.get() != -1) {
             result = resolveSharedMemory(mFd);
         } else {
-            ALOGE("SharedMemoryParcelable has no file descriptor for shared memory.");
+            ALOGE("has no file descriptor for shared memory.");
             result = AAUDIO_ERROR_INTERNAL;
         }
     }
 
     if (result == AAUDIO_OK && mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
         *regionAddressPtr = mResolvedAddress + offsetInBytes;
-        ALOGV("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
-        ALOGV("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p",
-              offsetInBytes, *regionAddressPtr);
+        ALOGV("mResolvedAddress = %p", mResolvedAddress);
+        ALOGV("offset by %d, *regionAddressPtr = %p", offsetInBytes, *regionAddressPtr);
     }
     return result;
 }
@@ -142,14 +138,14 @@
 
 aaudio_result_t SharedMemoryParcelable::validate() {
     if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
-        ALOGE("SharedMemoryParcelable invalid mSizeInBytes = %d", mSizeInBytes);
+        ALOGE("invalid mSizeInBytes = %d", mSizeInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
     return AAUDIO_OK;
 }
 
 void SharedMemoryParcelable::dump() {
-    ALOGD("SharedMemoryParcelable mFd = %d", mFd.get());
-    ALOGD("SharedMemoryParcelable mSizeInBytes = %d", mSizeInBytes);
-    ALOGD("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
+    ALOGD("mFd = %d", mFd.get());
+    ALOGD("mSizeInBytes = %d", mSizeInBytes);
+    ALOGD("mResolvedAddress = %p", mResolvedAddress);
 }
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.cpp b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
index 7381dcb..7aa80bf 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "SharedRegionParcelable"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -71,7 +71,7 @@
         return AAUDIO_OK;
     }
     if (mSharedMemoryIndex < 0) {
-        ALOGE("SharedRegionParcelable invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
+        ALOGE("invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
         return AAUDIO_ERROR_INTERNAL;
     }
     SharedMemoryParcelable *memoryParcel = &memoryParcels[mSharedMemoryIndex];
@@ -80,16 +80,16 @@
 
 aaudio_result_t SharedRegionParcelable::validate() {
     if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
-        ALOGE("SharedRegionParcelable invalid mSizeInBytes = %d", mSizeInBytes);
+        ALOGE("invalid mSizeInBytes = %d", mSizeInBytes);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
     if (mSizeInBytes > 0) {
         if (mOffsetInBytes < 0 || mOffsetInBytes >= MAX_MMAP_OFFSET_BYTES) {
-            ALOGE("SharedRegionParcelable invalid mOffsetInBytes = %d", mOffsetInBytes);
+            ALOGE("invalid mOffsetInBytes = %d", mOffsetInBytes);
             return AAUDIO_ERROR_OUT_OF_RANGE;
         }
         if (mSharedMemoryIndex < 0 || mSharedMemoryIndex >= MAX_SHARED_MEMORIES) {
-            ALOGE("SharedRegionParcelable invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
+            ALOGE("invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
             return AAUDIO_ERROR_INTERNAL;
         }
     }
@@ -97,9 +97,9 @@
 }
 
 void SharedRegionParcelable::dump() {
-    ALOGD("SharedRegionParcelable mSizeInBytes = %d -----", mSizeInBytes);
+    ALOGD("mSizeInBytes = %d -----", mSizeInBytes);
     if (mSizeInBytes > 0) {
-        ALOGD("SharedRegionParcelable mSharedMemoryIndex = %d", mSharedMemoryIndex);
-        ALOGD("SharedRegionParcelable mOffsetInBytes = %d", mOffsetInBytes);
+        ALOGD("mSharedMemoryIndex = %d", mSharedMemoryIndex);
+        ALOGD("mOffsetInBytes = %d", mOffsetInBytes);
     }
 }
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 604eed5..f8e34d1 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioEndpoint"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -45,6 +45,7 @@
     delete mUpCommandQueue;
 }
 
+// TODO Consider moving to a method in RingBufferDescriptor
 static aaudio_result_t AudioEndpoint_validateQueueDescriptor(const char *type,
                                                   const RingBufferDescriptor *descriptor) {
     if (descriptor == nullptr) {
@@ -127,19 +128,19 @@
     // ============================ up message queue =============================
     const RingBufferDescriptor *descriptor = &pEndpointDescriptor->upMessageQueueDescriptor;
     if(descriptor->bytesPerFrame != sizeof(AAudioServiceMessage)) {
-        ALOGE("AudioEndpoint.configure() bytesPerFrame != sizeof(AAudioServiceMessage) = %d",
+        ALOGE("configure() bytesPerFrame != sizeof(AAudioServiceMessage) = %d",
               descriptor->bytesPerFrame);
         return AAUDIO_ERROR_INTERNAL;
     }
 
     if(descriptor->readCounterAddress == nullptr || descriptor->writeCounterAddress == nullptr) {
-        ALOGE("AudioEndpoint.configure() NULL counter address");
+        ALOGE("configure() NULL counter address");
         return AAUDIO_ERROR_NULL;
     }
 
     // Prevent memory leak and reuse.
     if(mUpCommandQueue != nullptr || mDataQueue != nullptr) {
-        ALOGE("AudioEndpoint.configure() endpoint already used");
+        ALOGE("configure() endpoint already used");
         return AAUDIO_ERROR_INTERNAL;
     }
 
@@ -153,8 +154,8 @@
 
     // ============================ data queue =============================
     descriptor = &pEndpointDescriptor->dataQueueDescriptor;
-    ALOGV("AudioEndpoint.configure() data framesPerBurst = %d", descriptor->framesPerBurst);
-    ALOGV("AudioEndpoint.configure() data readCounterAddress = %p",
+    ALOGV("configure() data framesPerBurst = %d", descriptor->framesPerBurst);
+    ALOGV("configure() data readCounterAddress = %p",
           descriptor->readCounterAddress);
 
     // An example of free running is when the other side is read or written by hardware DMA
@@ -163,7 +164,7 @@
                              ? descriptor->readCounterAddress // read by other side
                              : descriptor->writeCounterAddress; // written by other side
     mFreeRunning = (remoteCounter == nullptr);
-    ALOGV("AudioEndpoint.configure() mFreeRunning = %d", mFreeRunning ? 1 : 0);
+    ALOGV("configure() mFreeRunning = %d", mFreeRunning ? 1 : 0);
 
     int64_t *readCounterAddress = (descriptor->readCounterAddress == nullptr)
                                   ? &mDataReadCounter
@@ -258,8 +259,8 @@
 }
 
 void AudioEndpoint::dump() const {
-    ALOGD("AudioEndpoint: data readCounter  = %lld", (long long) mDataQueue->getReadCounter());
-    ALOGD("AudioEndpoint: data writeCounter = %lld", (long long) mDataQueue->getWriteCounter());
+    ALOGD("data readCounter  = %lld", (long long) mDataQueue->getReadCounter());
+    ALOGD("data writeCounter = %lld", (long long) mDataQueue->getWriteCounter());
 }
 
 void AudioEndpoint::eraseDataMemory() {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 2fdbfaf..b7b4b5c 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -61,15 +61,14 @@
         , mClockModel()
         , mAudioEndpoint()
         , mServiceStreamHandle(AAUDIO_HANDLE_INVALID)
-        , mFramesPerBurst(16)
         , mInService(inService)
         , mServiceInterface(serviceInterface)
         , mAtomicTimestamp()
         , mWakeupDelayNanos(AAudioProperty_getWakeupDelayMicros() * AAUDIO_NANOS_PER_MICROSECOND)
         , mMinimumSleepNanos(AAudioProperty_getMinimumSleepMicros() * AAUDIO_NANOS_PER_MICROSECOND)
         {
-    ALOGD("AudioStreamInternal(): mWakeupDelayNanos = %d, mMinimumSleepNanos = %d",
-          mWakeupDelayNanos, mMinimumSleepNanos);
+    ALOGD("%s - mWakeupDelayNanos = %d, mMinimumSleepNanos = %d",
+          __func__, mWakeupDelayNanos, mMinimumSleepNanos);
 }
 
 AudioStreamInternal::~AudioStreamInternal() {
@@ -79,11 +78,12 @@
 
     aaudio_result_t result = AAUDIO_OK;
     int32_t capacity;
+    int32_t framesPerBurst;
     AAudioStreamRequest request;
     AAudioStreamConfiguration configurationOutput;
 
     if (getState() != AAUDIO_STREAM_STATE_UNINITIALIZED) {
-        ALOGE("AudioStreamInternal::open(): already open! state = %d", getState());
+        ALOGE("%s - already open! state = %d", __func__, getState());
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
@@ -117,7 +117,7 @@
     mServiceStreamHandle = mServiceInterface.openStream(request, configurationOutput);
     if (mServiceStreamHandle < 0) {
         result = mServiceStreamHandle;
-        ALOGE("AudioStreamInternal::open(): openStream() returned %d", result);
+        ALOGE("%s - openStream() returned %d", __func__, result);
         return result;
     }
 
@@ -151,17 +151,19 @@
         goto error;
     }
 
-    mFramesPerBurst = mEndpointDescriptor.dataQueueDescriptor.framesPerBurst;
-    capacity = mEndpointDescriptor.dataQueueDescriptor.capacityInFrames;
 
     // Validate result from server.
-    if (mFramesPerBurst < 16 || mFramesPerBurst > 16 * 1024) {
-        ALOGE("AudioStreamInternal::open(): framesPerBurst out of range = %d", mFramesPerBurst);
+    framesPerBurst = mEndpointDescriptor.dataQueueDescriptor.framesPerBurst;
+    if (framesPerBurst < MIN_FRAMES_PER_BURST || framesPerBurst > MAX_FRAMES_PER_BURST) {
+        ALOGE("%s - framesPerBurst out of range = %d", __func__, framesPerBurst);
         result = AAUDIO_ERROR_OUT_OF_RANGE;
         goto error;
     }
-    if (capacity < mFramesPerBurst || capacity > 32 * 1024) {
-        ALOGE("AudioStreamInternal::open(): bufferCapacity out of range = %d", capacity);
+    mFramesPerBurst = framesPerBurst; // only save good value
+
+    capacity = mEndpointDescriptor.dataQueueDescriptor.capacityInFrames;
+    if (capacity < mFramesPerBurst || capacity > MAX_BUFFER_CAPACITY_IN_FRAMES) {
+        ALOGE("%s - bufferCapacity out of range = %d", __func__, capacity);
         result = AAUDIO_ERROR_OUT_OF_RANGE;
         goto error;
     }
@@ -172,13 +174,13 @@
     if (getDataCallbackProc()) {
         mCallbackFrames = builder.getFramesPerDataCallback();
         if (mCallbackFrames > getBufferCapacity() / 2) {
-            ALOGE("AudioStreamInternal::open(): framesPerCallback too big = %d, capacity = %d",
-                  mCallbackFrames, getBufferCapacity());
+            ALOGE("%s - framesPerCallback too big = %d, capacity = %d",
+                  __func__, mCallbackFrames, getBufferCapacity());
             result = AAUDIO_ERROR_OUT_OF_RANGE;
             goto error;
 
         } else if (mCallbackFrames < 0) {
-            ALOGE("AudioStreamInternal::open(): framesPerCallback negative");
+            ALOGE("%s - framesPerCallback negative", __func__);
             result = AAUDIO_ERROR_OUT_OF_RANGE;
             goto error;
 
@@ -240,7 +242,7 @@
 static void *aaudio_callback_thread_proc(void *context)
 {
     AudioStreamInternal *stream = (AudioStreamInternal *)context;
-    //LOGD("AudioStreamInternal(): oboe_callback_thread, stream = %p", stream);
+    //LOGD("oboe_callback_thread, stream = %p", stream);
     if (stream != NULL) {
         return stream->callbackLoop();
     } else {
@@ -448,32 +450,32 @@
     aaudio_result_t result = AAUDIO_OK;
     switch (message->event.event) {
         case AAUDIO_SERVICE_EVENT_STARTED:
-            ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_STARTED");
+            ALOGD("%s - got AAUDIO_SERVICE_EVENT_STARTED", __func__);
             if (getState() == AAUDIO_STREAM_STATE_STARTING) {
                 setState(AAUDIO_STREAM_STATE_STARTED);
             }
             break;
         case AAUDIO_SERVICE_EVENT_PAUSED:
-            ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_PAUSED");
+            ALOGD("%s - got AAUDIO_SERVICE_EVENT_PAUSED", __func__);
             if (getState() == AAUDIO_STREAM_STATE_PAUSING) {
                 setState(AAUDIO_STREAM_STATE_PAUSED);
             }
             break;
         case AAUDIO_SERVICE_EVENT_STOPPED:
-            ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_STOPPED");
+            ALOGD("%s - got AAUDIO_SERVICE_EVENT_STOPPED", __func__);
             if (getState() == AAUDIO_STREAM_STATE_STOPPING) {
                 setState(AAUDIO_STREAM_STATE_STOPPED);
             }
             break;
         case AAUDIO_SERVICE_EVENT_FLUSHED:
-            ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_FLUSHED");
+            ALOGD("%s - got AAUDIO_SERVICE_EVENT_FLUSHED", __func__);
             if (getState() == AAUDIO_STREAM_STATE_FLUSHING) {
                 setState(AAUDIO_STREAM_STATE_FLUSHED);
                 onFlushFromServer();
             }
             break;
         case AAUDIO_SERVICE_EVENT_CLOSED:
-            ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_CLOSED");
+            ALOGD("%s - got AAUDIO_SERVICE_EVENT_CLOSED", __func__);
             setState(AAUDIO_STREAM_STATE_CLOSED);
             break;
         case AAUDIO_SERVICE_EVENT_DISCONNECTED:
@@ -483,18 +485,18 @@
             }
             result = AAUDIO_ERROR_DISCONNECTED;
             setState(AAUDIO_STREAM_STATE_DISCONNECTED);
-            ALOGW("WARNING - AudioStreamInternal::onEventFromServer()"
-                          " AAUDIO_SERVICE_EVENT_DISCONNECTED - FIFO cleared");
+            ALOGW("%s - AAUDIO_SERVICE_EVENT_DISCONNECTED - FIFO cleared", __func__);
             break;
         case AAUDIO_SERVICE_EVENT_VOLUME:
             mStreamVolume = (float)message->event.dataDouble;
             doSetVolume();
-            ALOGD("AudioStreamInternal::onEventFromServer() AAUDIO_SERVICE_EVENT_VOLUME %lf",
-                     message->event.dataDouble);
+            ALOGD("%s - AAUDIO_SERVICE_EVENT_VOLUME %lf", __func__, message->event.dataDouble);
+            break;
+        case AAUDIO_SERVICE_EVENT_XRUN:
+            mXRunCount = static_cast<int32_t>(message->event.dataLong);
             break;
         default:
-            ALOGW("WARNING - AudioStreamInternal::onEventFromServer() Unrecognized event = %d",
-                 (int) message->event.event);
+            ALOGE("%s - Unrecognized event = %d", __func__, (int) message->event.event);
             break;
     }
     return result;
@@ -519,8 +521,7 @@
                 break;
 
             default:
-                ALOGE("WARNING - drainTimestampsFromService() Unrecognized what = %d",
-                      (int) message.what);
+                ALOGE("%s - unrecognized message.what = %d", __func__, (int) message.what);
                 result = AAUDIO_ERROR_INTERNAL;
                 break;
         }
@@ -533,7 +534,6 @@
     aaudio_result_t result = AAUDIO_OK;
 
     while (result == AAUDIO_OK) {
-        //ALOGD("AudioStreamInternal::processCommands() - looping, %d", result);
         AAudioServiceMessage message;
         if (mAudioEndpoint.readUpCommand(&message) != 1) {
             break; // no command this time, no problem
@@ -552,8 +552,7 @@
             break;
 
         default:
-            ALOGE("WARNING - processCommands() Unrecognized what = %d",
-                 (int) message.what);
+            ALOGE("%s - unrecognized message.what = %d", __func__, (int) message.what);
             result = AAUDIO_ERROR_INTERNAL;
             break;
         }
@@ -614,13 +613,13 @@
             if (wakeTimeNanos > deadlineNanos) {
                 // If we time out, just return the framesWritten so far.
                 // TODO remove after we fix the deadline bug
-                ALOGW("AudioStreamInternal::processData(): entered at %lld nanos, currently %lld",
+                ALOGW("processData(): entered at %lld nanos, currently %lld",
                       (long long) entryTimeNanos, (long long) currentTimeNanos);
-                ALOGW("AudioStreamInternal::processData(): TIMEOUT after %lld nanos",
+                ALOGW("processData(): TIMEOUT after %lld nanos",
                       (long long) timeoutNanoseconds);
-                ALOGW("AudioStreamInternal::processData(): wakeTime = %lld, deadline = %lld nanos",
+                ALOGW("processData(): wakeTime = %lld, deadline = %lld nanos",
                       (long long) wakeTimeNanos, (long long) deadlineNanos);
-                ALOGW("AudioStreamInternal::processData(): past deadline by %d micros",
+                ALOGW("processData(): past deadline by %d micros",
                       (int)((wakeTimeNanos - deadlineNanos) / AAUDIO_NANOS_PER_MICROSECOND));
                 mClockModel.dump();
                 mAudioEndpoint.dump();
@@ -655,14 +654,29 @@
 }
 
 aaudio_result_t AudioStreamInternal::setBufferSize(int32_t requestedFrames) {
+    int32_t adjustedFrames = requestedFrames;
     int32_t actualFrames = 0;
-    // Round to the next highest burst size.
-    if (getFramesPerBurst() > 0) {
-        int32_t numBursts = (requestedFrames + getFramesPerBurst() - 1) / getFramesPerBurst();
-        requestedFrames = numBursts * getFramesPerBurst();
+    int32_t maximumSize = getBufferCapacity();
+
+    // Clip to minimum size so that rounding up will work better.
+    if (adjustedFrames < 1) {
+        adjustedFrames = 1;
     }
 
-    aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(requestedFrames, &actualFrames);
+    if (adjustedFrames > maximumSize) {
+        // Clip to maximum size.
+        adjustedFrames = maximumSize;
+    } else {
+        // Round to the next highest burst size.
+        int32_t numBursts = (adjustedFrames + mFramesPerBurst - 1) / mFramesPerBurst;
+        adjustedFrames = numBursts * mFramesPerBurst;
+        // Rounding may have gone above maximum.
+        if (adjustedFrames > maximumSize) {
+            adjustedFrames = maximumSize;
+        }
+    }
+
+    aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(adjustedFrames, &actualFrames);
     ALOGD("setBufferSize() req = %d => %d", requestedFrames, actualFrames);
     if (result < 0) {
         return result;
@@ -680,7 +694,7 @@
 }
 
 int32_t AudioStreamInternal::getFramesPerBurst() const {
-    return mEndpointDescriptor.dataQueueDescriptor.framesPerBurst;
+    return mFramesPerBurst;
 }
 
 aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 47024c0..117756d 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -34,6 +34,12 @@
 
 namespace aaudio {
 
+    // These are intended to be outside the range of what is normally encountered.
+    // TODO MAXes should probably be much bigger.
+    constexpr int32_t MIN_FRAMES_PER_BURST = 16; // arbitrary
+    constexpr int32_t MAX_FRAMES_PER_BURST = 16 * 1024;  // arbitrary
+    constexpr int32_t MAX_BUFFER_CAPACITY_IN_FRAMES = 32 * 1024;  // arbitrary
+
 // A stream that talks to the AAudioService or directly to a HAL.
 class AudioStreamInternal : public AudioStream {
 
@@ -141,7 +147,7 @@
     AudioEndpoint            mAudioEndpoint;   // source for reads or sink for writes
     aaudio_handle_t          mServiceStreamHandle; // opaque handle returned from service
 
-    int32_t                  mFramesPerBurst;     // frames per HAL transfer
+    int32_t                  mFramesPerBurst = MIN_FRAMES_PER_BURST; // frames per HAL transfer
     int32_t                  mXRunCount = 0;      // how many underrun events?
 
     // Offset from underlying frame position.
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index b792ecd..3e82a88 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG (mInService ? "AAudioService" : "AAudio")
+#define LOG_TAG (mInService ? "AudioStreamInternalCapture_Service" \
+                          : "AudioStreamInternalCapture_Client")
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -101,7 +102,8 @@
     }
 
     // If the write index passed the read index then consider it an overrun.
-    if (mAudioEndpoint.getEmptyFramesAvailable() < 0) {
+    // For shared streams, the xRunCount is passed up from the service.
+    if (mAudioEndpoint.isFreeRunning() && mAudioEndpoint.getEmptyFramesAvailable() < 0) {
         mXRunCount++;
         if (ATRACE_ENABLED()) {
             ATRACE_INT("aaOverRuns", mXRunCount);
@@ -152,7 +154,7 @@
 
 aaudio_result_t AudioStreamInternalCapture::readNowWithConversion(void *buffer,
                                                                 int32_t numFrames) {
-    // ALOGD("AudioStreamInternalCapture::readNowWithConversion(%p, %d)",
+    // ALOGD("readNowWithConversion(%p, %d)",
     //              buffer, numFrames);
     WrappingBuffer wrappingBuffer;
     uint8_t *destination = (uint8_t *) buffer;
@@ -201,7 +203,7 @@
     int32_t framesProcessed = numFrames - framesLeft;
     mAudioEndpoint.advanceReadIndex(framesProcessed);
 
-    //ALOGD("AudioStreamInternalCapture::readNowWithConversion() returns %d", framesProcessed);
+    //ALOGD("readNowWithConversion() returns %d", framesProcessed);
     return framesProcessed;
 }
 
@@ -215,14 +217,14 @@
     // Prevent retrograde motion.
     mLastFramesWritten = std::max(mLastFramesWritten,
                                   framesWrittenHardware + mFramesOffsetFromService);
-    //ALOGD("AudioStreamInternalCapture::getFramesWritten() returns %lld",
+    //ALOGD("getFramesWritten() returns %lld",
     //      (long long)mLastFramesWritten);
     return mLastFramesWritten;
 }
 
 int64_t AudioStreamInternalCapture::getFramesRead() {
     int64_t frames = mAudioEndpoint.getDataReadCounter() + mFramesOffsetFromService;
-    //ALOGD("AudioStreamInternalCapture::getFramesRead() returns %lld", (long long)frames);
+    //ALOGD("getFramesRead() returns %lld", (long long)frames);
     return frames;
 }
 
@@ -242,7 +244,7 @@
         // This is a BLOCKING READ!
         result = read(mCallbackBuffer, mCallbackFrames, timeoutNanos);
         if ((result != mCallbackFrames)) {
-            ALOGE("AudioStreamInternalCapture(): callbackLoop: read() returned %d", result);
+            ALOGE("callbackLoop: read() returned %d", result);
             if (result >= 0) {
                 // Only read some of the frames requested. Must have timed out.
                 result = AAUDIO_ERROR_TIMEOUT;
@@ -265,12 +267,12 @@
                 mCallbackFrames);
 
         if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
-            ALOGD("AudioStreamInternalCapture(): callback returned AAUDIO_CALLBACK_RESULT_STOP");
+            ALOGD("callback returned AAUDIO_CALLBACK_RESULT_STOP");
             break;
         }
     }
 
-    ALOGD("AudioStreamInternalCapture(): callbackLoop() exiting, result = %d, isActive() = %d",
+    ALOGD("callbackLoop() exiting, result = %d, isActive() = %d",
           result, (int) isActive());
     return NULL;
 }
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 1e02eee..b49e08c 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG (mInService ? "AAudioService" : "AAudio")
+#define LOG_TAG (mInService ? "AudioStreamInternalPlay_Service" \
+                          : "AudioStreamInternalPlay_Client")
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -139,7 +140,8 @@
     }
 
     // If the read index passed the write index then consider it an underrun.
-    if (mAudioEndpoint.getFullFramesAvailable() < 0) {
+    // For shared streams, the xRunCount is passed up from the service.
+    if (mAudioEndpoint.isFreeRunning() && mAudioEndpoint.getFullFramesAvailable() < 0) {
         mXRunCount++;
         if (ATRACE_ENABLED()) {
             ATRACE_INT("aaUnderRuns", mXRunCount);
@@ -218,8 +220,7 @@
             // Data conversion.
             float levelFrom;
             float levelTo;
-            bool ramping = mVolumeRamp.nextSegment(framesToWrite * getSamplesPerFrame(),
-                                                   &levelFrom, &levelTo);
+            bool ramping = mVolumeRamp.nextSegment(framesToWrite, &levelFrom, &levelTo);
             // The formats are validated when the stream is opened so we do not have to
             // check for illegal combinations here.
             // TODO factor this out into a utility function
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index bac69f1..95b52be 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "IsochronousClockModel"
 //#define LOG_NDEBUG 0
 #include <log/log.h>
 
@@ -41,20 +41,20 @@
 }
 
 void IsochronousClockModel::setPositionAndTime(int64_t framePosition, int64_t nanoTime) {
-    ALOGV("IsochronousClockModel::setPositionAndTime(%lld, %lld)",
+    ALOGV("setPositionAndTime(%lld, %lld)",
           (long long) framePosition, (long long) nanoTime);
     mMarkerFramePosition = framePosition;
     mMarkerNanoTime = nanoTime;
 }
 
 void IsochronousClockModel::start(int64_t nanoTime) {
-    ALOGV("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime);
+    ALOGV("start(nanos = %lld)\n", (long long) nanoTime);
     mMarkerNanoTime = nanoTime;
     mState = STATE_STARTING;
 }
 
 void IsochronousClockModel::stop(int64_t nanoTime) {
-    ALOGV("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime);
+    ALOGV("stop(nanos = %lld)\n", (long long) nanoTime);
     setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
     // TODO should we set position?
     mState = STATE_STOPPED;
@@ -156,7 +156,7 @@
     int64_t framesDelta = nextBurstPosition - mMarkerFramePosition;
     int64_t nanosDelta = convertDeltaPositionToTime(framesDelta);
     int64_t time = mMarkerNanoTime + nanosDelta;
-//    ALOGD("IsochronousClockModel::convertPositionToTime: pos = %llu --> time = %llu",
+//    ALOGD("convertPositionToTime: pos = %llu --> time = %llu",
 //         (unsigned long long)framePosition,
 //         (unsigned long long)time);
     return time;
@@ -171,19 +171,19 @@
     int64_t nextBurstPosition = mMarkerFramePosition + framesDelta;
     int64_t nextBurstIndex = nextBurstPosition / mFramesPerBurst;
     int64_t position = nextBurstIndex * mFramesPerBurst;
-//    ALOGD("IsochronousClockModel::convertTimeToPosition: time = %llu --> pos = %llu",
+//    ALOGD("convertTimeToPosition: time = %llu --> pos = %llu",
 //         (unsigned long long)nanoTime,
 //         (unsigned long long)position);
-//    ALOGD("IsochronousClockModel::convertTimeToPosition: framesDelta = %llu, mFramesPerBurst = %d",
+//    ALOGD("convertTimeToPosition: framesDelta = %llu, mFramesPerBurst = %d",
 //         (long long) framesDelta, mFramesPerBurst);
     return position;
 }
 
 void IsochronousClockModel::dump() const {
-    ALOGD("IsochronousClockModel::mMarkerFramePosition = %lld", (long long) mMarkerFramePosition);
-    ALOGD("IsochronousClockModel::mMarkerNanoTime      = %lld", (long long) mMarkerNanoTime);
-    ALOGD("IsochronousClockModel::mSampleRate          = %6d", mSampleRate);
-    ALOGD("IsochronousClockModel::mFramesPerBurst      = %6d", mFramesPerBurst);
-    ALOGD("IsochronousClockModel::mMaxLatenessInNanos  = %6d", mMaxLatenessInNanos);
-    ALOGD("IsochronousClockModel::mState               = %6d", mState);
+    ALOGD("mMarkerFramePosition = %lld", (long long) mMarkerFramePosition);
+    ALOGD("mMarkerNanoTime      = %lld", (long long) mMarkerNanoTime);
+    ALOGD("mSampleRate          = %6d", mSampleRate);
+    ALOGD("mFramesPerBurst      = %6d", mFramesPerBurst);
+    ALOGD("mMaxLatenessInNanos  = %6d", mMaxLatenessInNanos);
+    ALOGD("mState               = %6d", mState);
 }
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 82445e7..6400eb4 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -15,7 +15,7 @@
  */
 
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioStreamParameters"
 #include <utils/Log.h>
 #include <hardware/audio.h>
 
@@ -47,12 +47,12 @@
 aaudio_result_t AAudioStreamParameters::validate() const {
     if (mSamplesPerFrame != AAUDIO_UNSPECIFIED
         && (mSamplesPerFrame < SAMPLES_PER_FRAME_MIN || mSamplesPerFrame > SAMPLES_PER_FRAME_MAX)) {
-        ALOGE("AAudioStreamParameters: channelCount out of range = %d", mSamplesPerFrame);
+        ALOGE("channelCount out of range = %d", mSamplesPerFrame);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
 
     if (mDeviceId < 0) {
-        ALOGE("AAudioStreamParameters: deviceId out of range = %d", mDeviceId);
+        ALOGE("deviceId out of range = %d", mDeviceId);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
 
@@ -61,7 +61,7 @@
         case AAUDIO_SHARING_MODE_SHARED:
             break;
         default:
-            ALOGE("AAudioStreamParameters: illegal sharingMode = %d", mSharingMode);
+            ALOGE("illegal sharingMode = %d", mSharingMode);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             // break;
     }
@@ -72,19 +72,19 @@
         case AAUDIO_FORMAT_PCM_FLOAT:
             break; // valid
         default:
-            ALOGE("AAudioStreamParameters: audioFormat not valid = %d", mAudioFormat);
+            ALOGE("audioFormat not valid = %d", mAudioFormat);
             return AAUDIO_ERROR_INVALID_FORMAT;
             // break;
     }
 
     if (mSampleRate != AAUDIO_UNSPECIFIED
         && (mSampleRate < SAMPLE_RATE_HZ_MIN || mSampleRate > SAMPLE_RATE_HZ_MAX)) {
-        ALOGE("AAudioStreamParameters: sampleRate out of range = %d", mSampleRate);
+        ALOGE("sampleRate out of range = %d", mSampleRate);
         return AAUDIO_ERROR_INVALID_RATE;
     }
 
     if (mBufferCapacity < 0) {
-        ALOGE("AAudioStreamParameters: bufferCapacity out of range = %d", mBufferCapacity);
+        ALOGE("bufferCapacity out of range = %d", mBufferCapacity);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
 
@@ -93,7 +93,7 @@
         case AAUDIO_DIRECTION_OUTPUT:
             break; // valid
         default:
-            ALOGE("AAudioStreamParameters: direction not valid = %d", mDirection);
+            ALOGE("direction not valid = %d", mDirection);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             // break;
     }
@@ -102,12 +102,12 @@
 }
 
 void AAudioStreamParameters::dump() const {
-    ALOGD("AAudioStreamParameters mDeviceId        = %d", mDeviceId);
-    ALOGD("AAudioStreamParameters mSampleRate      = %d", mSampleRate);
-    ALOGD("AAudioStreamParameters mSamplesPerFrame = %d", mSamplesPerFrame);
-    ALOGD("AAudioStreamParameters mSharingMode     = %d", (int)mSharingMode);
-    ALOGD("AAudioStreamParameters mAudioFormat     = %d", (int)mAudioFormat);
-    ALOGD("AAudioStreamParameters mDirection       = %d", mDirection);
-    ALOGD("AAudioStreamParameters mBufferCapacity  = %d", mBufferCapacity);
+    ALOGD("mDeviceId        = %6d", mDeviceId);
+    ALOGD("mSampleRate      = %6d", mSampleRate);
+    ALOGD("mSamplesPerFrame = %6d", mSamplesPerFrame);
+    ALOGD("mSharingMode     = %6d", (int)mSharingMode);
+    ALOGD("mAudioFormat     = %6d", (int)mAudioFormat);
+    ALOGD("mDirection       = %6d", mDirection);
+    ALOGD("mBufferCapacity  = %6d", mBufferCapacity);
 }
 
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 8dcc37a..27c36e1 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -91,11 +91,11 @@
     mErrorCallbackUserData = builder.getErrorCallbackUserData();
 
     // This is very helpful for debugging in the future. Please leave it in.
-    ALOGI("AudioStream::open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
+    ALOGI("open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
           mSampleRate, mSamplesPerFrame, mFormat,
           AudioStream_convertSharingModeToShortText(mSharingMode),
           (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
-    ALOGI("AudioStream::open() device = %d, perfMode = %d, callback: %s with frames = %d",
+    ALOGI("open() device = %d, perfMode = %d, callback: %s with frames = %d",
           mDeviceId, mPerformanceMode,
           (mDataCallbackProc == nullptr ? "OFF" : "ON"),
           mFramesPerDataCallback);
@@ -163,7 +163,7 @@
                                      void* threadArg)
 {
     if (mHasThread) {
-        ALOGE("AudioStream::createThread() - mHasThread already true");
+        ALOGE("createThread() - mHasThread already true");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     if (threadProc == nullptr) {
@@ -185,7 +185,7 @@
 aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds)
 {
     if (!mHasThread) {
-        ALOGE("AudioStream::joinThread() - but has no thread");
+        ALOGE("joinThread() - but has no thread");
         return AAUDIO_ERROR_INVALID_STATE;
     }
 #if 0
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 09ebb3e..f7cb8d6 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioStreamBuilder"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -87,7 +87,7 @@
             break;
 
         default:
-            ALOGE("AudioStreamBuilder(): bad direction = %d", direction);
+            ALOGE("bad direction = %d", direction);
             result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
     }
     return result;
@@ -99,7 +99,7 @@
 aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
     AudioStream *audioStream = nullptr;
     if (streamPtr == nullptr) {
-        ALOGE("AudioStreamBuilder::build() streamPtr is null");
+        ALOGE("build() streamPtr is null");
         return AAUDIO_ERROR_NULL;
     }
     *streamPtr = nullptr;
@@ -124,13 +124,13 @@
     if (mapExclusivePolicy == AAUDIO_UNSPECIFIED) {
         mapExclusivePolicy = AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT;
     }
-    ALOGD("AudioStreamBuilder(): mmapPolicy = %d, mapExclusivePolicy = %d",
+    ALOGD("mmapPolicy = %d, mapExclusivePolicy = %d",
           mmapPolicy, mapExclusivePolicy);
 
     aaudio_sharing_mode_t sharingMode = getSharingMode();
     if ((sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE)
         && (mapExclusivePolicy == AAUDIO_POLICY_NEVER)) {
-        ALOGW("AudioStreamBuilder(): EXCLUSIVE sharing mode not supported. Use SHARED.");
+        ALOGW("EXCLUSIVE sharing mode not supported. Use SHARED.");
         sharingMode = AAUDIO_SHARING_MODE_SHARED;
         setSharingMode(sharingMode);
     }
@@ -156,7 +156,7 @@
             audioStream = nullptr;
 
             if (isMMap && allowLegacy) {
-                ALOGD("AudioStreamBuilder.build() MMAP stream did not open so try Legacy path");
+                ALOGD("build() MMAP stream did not open so try Legacy path");
                 // If MMAP stream failed to open then TRY using a legacy stream.
                 result = builder_createStream(getDirection(), sharingMode,
                                               false, &audioStream);
@@ -190,7 +190,7 @@
         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
             break;
         default:
-            ALOGE("AudioStreamBuilder: illegal performanceMode = %d", mPerformanceMode);
+            ALOGE("illegal performanceMode = %d", mPerformanceMode);
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             // break;
     }
@@ -199,7 +199,7 @@
     if (mFramesPerDataCallback != AAUDIO_UNSPECIFIED
         && (mFramesPerDataCallback < FRAMES_PER_DATA_CALLBACK_MIN
             || mFramesPerDataCallback > FRAMES_PER_DATA_CALLBACK_MAX)) {
-        ALOGE("AudioStreamBuilder: framesPerDataCallback out of range = %d",
+        ALOGE("framesPerDataCallback out of range = %d",
               mFramesPerDataCallback);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index a869886..e6e7c8e 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -43,7 +43,7 @@
     int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
     mStorage = new uint8_t[bytesPerBuffer];
     mStorageOwned = true;
-    ALOGD("FifoBuffer: capacityInFrames = %d, bytesPerFrame = %d",
+    ALOGD("capacityInFrames = %d, bytesPerFrame = %d",
           capacityInFrames, bytesPerFrame);
 }
 
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index bc6e60c..6d98ed3 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -96,7 +96,7 @@
     }
     mCallbackBufferSize = builder.getFramesPerDataCallback();
 
-    ALOGD("AudioStreamRecord::open(), request notificationFrames = %u, frameCount = %u",
+    ALOGD("open(), request notificationFrames = %u, frameCount = %u",
           notificationFrames, (uint)frameCount);
     mAudioRecord = new AudioRecord(
             mOpPackageName // const String16& opPackageName TODO does not compile
@@ -126,7 +126,7 @@
     status_t status = mAudioRecord->initCheck();
     if (status != OK) {
         close();
-        ALOGE("AudioStreamRecord::open(), initCheck() returned %d", status);
+        ALOGE("open(), initCheck() returned %d", status);
         return AAudioConvert_androidToAAudioResult(status);
     }
 
@@ -136,7 +136,7 @@
 
     int32_t actualSampleRate = mAudioRecord->getSampleRate();
     ALOGW_IF(actualSampleRate != getSampleRate(),
-             "AudioStreamRecord::open() sampleRate changed from %d to %d",
+             "open() sampleRate changed from %d to %d",
              getSampleRate(), actualSampleRate);
     setSampleRate(actualSampleRate);
 
@@ -164,10 +164,10 @@
 
     // Log warning if we did not get what we asked for.
     ALOGW_IF(actualFlags != flags,
-             "AudioStreamRecord::open() flags changed from 0x%08X to 0x%08X",
+             "open() flags changed from 0x%08X to 0x%08X",
              flags, actualFlags);
     ALOGW_IF(actualPerformanceMode != perfMode,
-             "AudioStreamRecord::open() perfMode changed from %d to %d",
+             "open() perfMode changed from %d to %d",
              perfMode, actualPerformanceMode);
 
     setState(AAUDIO_STREAM_STATE_OPEN);
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 0e9aaef..c2ce9a2 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -113,7 +113,7 @@
     }
     mCallbackBufferSize = builder.getFramesPerDataCallback();
 
-    ALOGD("AudioStreamTrack::open(), request notificationFrames = %d, frameCount = %u",
+    ALOGD("open(), request notificationFrames = %d, frameCount = %u",
           notificationFrames, (uint)frameCount);
     mAudioTrack = new AudioTrack(); // TODO review
     if (getDeviceId() != AAUDIO_UNSPECIFIED) {
@@ -139,7 +139,7 @@
     status_t status = mAudioTrack->initCheck();
     if (status != NO_ERROR) {
         close();
-        ALOGE("AudioStreamTrack::open(), initCheck() returned %d", status);
+        ALOGE("open(), initCheck() returned %d", status);
         return AAudioConvert_androidToAAudioResult(status);
     }
 
@@ -153,7 +153,7 @@
 
     int32_t actualSampleRate = mAudioTrack->getSampleRate();
     ALOGW_IF(actualSampleRate != getSampleRate(),
-             "AudioStreamTrack::open() sampleRate changed from %d to %d",
+             "open() sampleRate changed from %d to %d",
              getSampleRate(), actualSampleRate);
     setSampleRate(actualSampleRate);
 
@@ -186,10 +186,10 @@
 
     // Log warning if we did not get what we asked for.
     ALOGW_IF(actualFlags != flags,
-             "AudioStreamTrack::open() flags changed from 0x%08X to 0x%08X",
+             "open() flags changed from 0x%08X to 0x%08X",
              flags, actualFlags);
     ALOGW_IF(actualPerformanceMode != perfMode,
-             "AudioStreamTrack::open() perfMode changed from %d to %d",
+             "open() perfMode changed from %d to %d",
              perfMode, actualPerformanceMode);
 
     return AAUDIO_OK;
@@ -227,7 +227,7 @@
     std::lock_guard<std::mutex> lock(mStreamMutex);
 
     if (mAudioTrack.get() == nullptr) {
-        ALOGE("AudioStreamTrack::requestStart() no AudioTrack");
+        ALOGE("requestStart() no AudioTrack");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     // Get current position so we can detect when the track is playing.
@@ -273,10 +273,10 @@
     std::lock_guard<std::mutex> lock(mStreamMutex);
 
     if (mAudioTrack.get() == nullptr) {
-        ALOGE("AudioStreamTrack::requestFlush() no AudioTrack");
+        ALOGE("requestFlush() no AudioTrack");
         return AAUDIO_ERROR_INVALID_STATE;
     } else if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
-        ALOGE("AudioStreamTrack::requestFlush() not paused");
+        ALOGE("requestFlush() not paused");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     setState(AAUDIO_STREAM_STATE_FLUSHING);
@@ -291,7 +291,7 @@
     std::lock_guard<std::mutex> lock(mStreamMutex);
 
     if (mAudioTrack.get() == nullptr) {
-        ALOGE("AudioStreamTrack::requestStop() no AudioTrack");
+        ALOGE("requestStop() no AudioTrack");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     onStop();
diff --git a/media/libaaudio/src/utility/LinearRamp.h b/media/libaaudio/src/utility/LinearRamp.h
index ff09dce..2b1b8e0 100644
--- a/media/libaaudio/src/utility/LinearRamp.h
+++ b/media/libaaudio/src/utility/LinearRamp.h
@@ -87,7 +87,7 @@
 
     std::atomic<float>   mTarget;
 
-    int32_t mLengthInFrames  = 48000 / 50; // 20 msec at 48000 Hz
+    int32_t mLengthInFrames  = 48000 / 100; // 10 msec at 48000 Hz
     int32_t mRemaining       = 0;
     float   mLevelFrom       = 0.0f;
     float   mLevelTo         = 0.0f;
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 19c56d3..884a2b3 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -27,6 +27,7 @@
 
 cc_test {
     name: "test_timestamps",
+    defaults: ["libaaudio_tests_defaults"],
     srcs: ["test_timestamps.cpp"],
     header_libs: ["libaaudio_example_utils"],
     shared_libs: ["libaaudio"],
@@ -86,3 +87,27 @@
         "libutils",
     ],
 }
+
+cc_test {
+    name: "test_bad_disconnect",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_bad_disconnect.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+}
+
+cc_test {
+    name: "test_various",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_various.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+}
diff --git a/media/libaaudio/tests/test_bad_disconnect.cpp b/media/libaaudio/tests/test_bad_disconnect.cpp
new file mode 100644
index 0000000..435990d
--- /dev/null
+++ b/media/libaaudio/tests/test_bad_disconnect.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Handle a DISCONNECT by only opening and starting a new stream
+ * without stopping and closing the old one.
+ * This caused the new stream to use the old disconnected device.
+ */
+
+#include <stdio.h>
+#include <thread>
+#include <unistd.h>
+
+#include <aaudio/AAudio.h>
+
+#define DEFAULT_TIMEOUT_NANOS  ((int64_t)1000000000)
+
+static void s_myErrorCallbackProc(
+        AAudioStream *stream,
+        void *userData,
+        aaudio_result_t error);
+
+struct AudioEngine {
+    AAudioStreamBuilder *builder = nullptr;
+    AAudioStream *stream = nullptr;
+    std::thread *thread = nullptr;
+    int64_t framesRead = 0;
+};
+
+AudioEngine s_AudioEngine;
+
+// Callback function that fills the audio output buffer.
+static aaudio_data_callback_result_t s_myDataCallbackProc(
+        AAudioStream *stream,
+        void *userData,
+        void *audioData,
+        int32_t numFrames
+) {
+    (void) userData;
+    (void) audioData;
+    (void) numFrames;
+    s_AudioEngine.framesRead = AAudioStream_getFramesRead(stream);
+    return AAUDIO_CALLBACK_RESULT_CONTINUE;
+}
+
+static aaudio_result_t s_StartAudio() {
+    int32_t framesPerBurst = 0;
+    int32_t deviceId = 0;
+
+    // Use an AAudioStreamBuilder to contain requested parameters.
+    aaudio_result_t result = AAudio_createStreamBuilder(&s_AudioEngine.builder);
+    if (result != AAUDIO_OK) {
+        printf("AAudio_createStreamBuilder returned %s",
+               AAudio_convertResultToText(result));
+        return result;
+    }
+
+    // Request stream properties.
+    AAudioStreamBuilder_setFormat(s_AudioEngine.builder, AAUDIO_FORMAT_PCM_FLOAT);
+    AAudioStreamBuilder_setPerformanceMode(s_AudioEngine.builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+    AAudioStreamBuilder_setDataCallback(s_AudioEngine.builder, s_myDataCallbackProc, nullptr);
+    AAudioStreamBuilder_setErrorCallback(s_AudioEngine.builder, s_myErrorCallbackProc, nullptr);
+
+    // Create an AAudioStream using the Builder.
+    result = AAudioStreamBuilder_openStream(s_AudioEngine.builder, &s_AudioEngine.stream);
+    if (result != AAUDIO_OK) {
+        printf("AAudioStreamBuilder_openStream returned %s",
+               AAudio_convertResultToText(result));
+        return result;
+    }
+
+    result = AAudioStream_requestStart(s_AudioEngine.stream);
+    if (result != AAUDIO_OK) {
+        printf("AAudioStream_requestStart returned %s",
+               AAudio_convertResultToText(result));
+    }
+
+    // Check to see what kind of stream we actually got.
+    deviceId = AAudioStream_getDeviceId(s_AudioEngine.stream);
+    framesPerBurst = AAudioStream_getFramesPerBurst(s_AudioEngine.stream);
+
+    printf("-------- started: deviceId = %3d, framesPerBurst = %3d\n", deviceId, framesPerBurst);
+
+    return result;
+}
+
+static aaudio_result_t s_StopAudio() {
+    aaudio_result_t result = AAUDIO_OK;
+    if (s_AudioEngine.stream != nullptr) {
+        result = AAudioStream_requestStop(s_AudioEngine.stream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_requestStop returned %s\n",
+                   AAudio_convertResultToText(result));
+        }
+        result = AAudioStream_close(s_AudioEngine.stream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_close returned %s\n",
+                   AAudio_convertResultToText(result));
+        }
+        s_AudioEngine.stream = nullptr;
+        AAudioStreamBuilder_delete(s_AudioEngine.builder);
+        s_AudioEngine.builder = nullptr;
+    }
+    return result;
+}
+
+static void s_StartThreadProc() {
+    // A good app would call s_StopAudio here! This test simulates a bad app.
+    s_StartAudio();
+    s_AudioEngine.thread = nullptr;
+}
+
+static void s_myErrorCallbackProc(
+        AAudioStream *stream __unused,
+        void *userData __unused,
+        aaudio_result_t error) {
+    if (error == AAUDIO_ERROR_DISCONNECTED) {
+        // Handle stream restart on a separate thread
+        if (s_AudioEngine.thread == nullptr) {
+            s_AudioEngine.thread = new std::thread(s_StartThreadProc);
+        }
+    }
+}
+
+int main(int argc, char **argv) {
+    (void) argc;
+    (void) argv;
+
+    aaudio_result_t result = AAUDIO_OK;
+
+    // Make printf print immediately so that debug info is not stuck
+    // in a buffer if we hang or crash.
+    setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+    printf("Test Bad Disconnect V1.0\n");
+    printf("\n=========== Please PLUG and UNPLUG headphones! ==============\n\n");
+    printf("You should see the deviceID change on each plug event.\n");
+    printf("Headphones will generally get a new deviceId each time.\n");
+    printf("Speakers will have the same deviceId each time.\n");
+    printf("The framesRead should reset on each plug event then increase over time.\n");
+    printf("\n");
+
+    result = s_StartAudio();
+
+    if (result == AAUDIO_OK) {
+        for (int i = 20; i > 0; i--) {
+            sleep(1);
+            printf("playing silence #%d, framesRead = %d\n", i, (int) s_AudioEngine.framesRead);
+        }
+    }
+
+    s_StopAudio();
+
+    printf("result = %d = %s\n", result, AAudio_convertResultToText(result));
+}
diff --git a/media/libaaudio/tests/test_timestamps.cpp b/media/libaaudio/tests/test_timestamps.cpp
index b57f0a4..dfa7815 100644
--- a/media/libaaudio/tests/test_timestamps.cpp
+++ b/media/libaaudio/tests/test_timestamps.cpp
@@ -22,8 +22,7 @@
 
 #include <aaudio/AAudio.h>
 #include <aaudio/AAudioTesting.h>
-#include "utils/AAudioExampleUtils.h"
-#include "../examples/utils/AAudioExampleUtils.h"
+#include "AAudioExampleUtils.h"
 
 // Arbitrary period for glitches, once per second at 48000 Hz.
 #define FORCED_UNDERRUN_PERIOD_FRAMES    48000
diff --git a/media/libaaudio/tests/test_various.cpp b/media/libaaudio/tests/test_various.cpp
new file mode 100644
index 0000000..9e505d5
--- /dev/null
+++ b/media/libaaudio/tests/test_various.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Test various AAudio features including AAudioStream_setBufferSizeInFrames().
+
+#include <stdio.h>
+//#include <stdlib.h>
+//#include <math.h>
+
+#include <android-base/macros.h>
+#include <aaudio/AAudio.h>
+
+#include <gtest/gtest.h>
+
+// Callback function that does nothing.
+aaudio_data_callback_result_t MyDataCallbackProc(
+        AAudioStream *stream,
+        void *userData,
+        void *audioData,
+        int32_t numFrames
+) {
+    (void) stream;
+    (void) userData;
+    (void) audioData;
+    (void) numFrames;
+    return AAUDIO_CALLBACK_RESULT_CONTINUE;
+}
+
+// Test AAudioStream_setBufferSizeInFrames()
+
+//int main() { // To fix Android Studio formatting when editing.
+TEST(test_various, aaudio_set_buffer_size) {
+
+    aaudio_result_t result = AAUDIO_OK;
+    int32_t bufferCapacity;
+    int32_t framesPerBurst = 0;
+    int32_t actualSize = 0;
+
+    AAudioStreamBuilder *aaudioBuilder = nullptr;
+    AAudioStream *aaudioStream = nullptr;
+
+    // Use an AAudioStreamBuilder to contain requested parameters.
+    ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
+
+    // Request stream properties.
+    AAudioStreamBuilder_setDataCallback(aaudioBuilder, MyDataCallbackProc, nullptr);
+    AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+
+    // Create an AAudioStream using the Builder.
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
+
+    // This is the number of frames that are read in one chunk by a DMA controller
+    // or a DSP or a mixer.
+    framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
+    bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream);
+    printf("          bufferCapacity = %d, remainder = %d\n",
+           bufferCapacity, bufferCapacity % framesPerBurst);
+
+    actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, 0);
+    EXPECT_GT(actualSize, 0);
+    EXPECT_LE(actualSize, bufferCapacity);
+
+    actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, 2 * framesPerBurst);
+    EXPECT_GT(actualSize, framesPerBurst);
+    EXPECT_LE(actualSize, bufferCapacity);
+
+    actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, bufferCapacity - 1);
+    EXPECT_GT(actualSize, framesPerBurst);
+    EXPECT_LE(actualSize, bufferCapacity);
+
+    actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, bufferCapacity);
+    EXPECT_GT(actualSize, framesPerBurst);
+    EXPECT_LE(actualSize, bufferCapacity);
+
+    actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, bufferCapacity + 1);
+    EXPECT_GT(actualSize, framesPerBurst);
+    EXPECT_LE(actualSize, bufferCapacity);
+
+    actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, 1234567);
+    EXPECT_GT(actualSize, framesPerBurst);
+    EXPECT_LE(actualSize, bufferCapacity);
+
+    actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, INT32_MAX);
+    EXPECT_GT(actualSize, framesPerBurst);
+    EXPECT_LE(actualSize, bufferCapacity);
+
+    actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, INT32_MIN);
+    EXPECT_GT(actualSize, 0);
+    EXPECT_LE(actualSize, bufferCapacity);
+
+    AAudioStream_close(aaudioStream);
+    AAudioStreamBuilder_delete(aaudioBuilder);
+    printf("          result = %d = %s\n", result, AAudio_convertResultToText(result));
+}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 61c946c..98e8d95 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -6,7 +6,22 @@
 
 cc_library_shared {
     name: "libaudioclient",
+
+    aidl: {
+        export_aidl_headers: true,
+        local_include_dirs: ["aidl"],
+        include_dirs: [
+            "frameworks/av/media/libaudioclient/aidl",
+        ],
+    },
+
     srcs: [
+        // AIDL files for audioclient interfaces
+        // The headers for these interfaces will be available to any modules that
+        // include libaudioclient, at the path "aidl/package/path/BnFoo.h"
+        "aidl/android/media/IAudioRecord.aidl",
+        "aidl/android/media/IPlayer.aidl",
+
         "AudioEffect.cpp",
         "AudioPolicy.cpp",
         "AudioRecord.cpp",
@@ -17,7 +32,6 @@
         "IAudioFlingerClient.cpp",
         "IAudioPolicyService.cpp",
         "IAudioPolicyServiceClient.cpp",
-        "IAudioRecord.cpp",
         "IAudioTrack.cpp",
         "IEffect.cpp",
         "IEffectClient.cpp",
@@ -36,7 +50,7 @@
     ],
     export_shared_lib_headers: ["libbinder"],
 
-    local_include_dirs: ["include/media"],
+    local_include_dirs: ["include/media", "aidl"],
     header_libs: ["libaudioclient_headers"],
     export_header_lib_headers: ["libaudioclient_headers"],
 
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index ba4acc6..2432cac 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -89,7 +89,8 @@
         audio_input_flags_t flags,
         uid_t uid,
         pid_t pid,
-        const audio_attributes_t* pAttributes)
+        const audio_attributes_t* pAttributes,
+        audio_port_handle_t selectedDeviceId)
     : mActive(false),
       mStatus(NO_INIT),
       mOpPackageName(opPackageName),
@@ -97,12 +98,11 @@
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mProxy(NULL),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
       mPortId(AUDIO_PORT_HANDLE_NONE)
 {
     mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
             notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
-            uid, pid, pAttributes);
+            uid, pid, pAttributes, selectedDeviceId);
 }
 
 AudioRecord::~AudioRecord()
@@ -148,7 +148,8 @@
         audio_input_flags_t flags,
         uid_t uid,
         pid_t pid,
-        const audio_attributes_t* pAttributes)
+        const audio_attributes_t* pAttributes,
+        audio_port_handle_t selectedDeviceId)
 {
     ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
           "notificationFrames %u, sessionId %d, transferType %d, flags %#x, opPackageName %s "
@@ -156,6 +157,8 @@
           inputSource, sampleRate, format, channelMask, frameCount, notificationFrames,
           sessionId, transferType, flags, String8(mOpPackageName).string(), uid, pid);
 
+    mSelectedDeviceId = selectedDeviceId;
+
     switch (transferType) {
     case TRANSFER_DEFAULT:
         if (cbf == NULL || threadCanCallJava) {
@@ -323,7 +326,7 @@
 
     status_t status = NO_ERROR;
     if (!(flags & CBLK_INVALID)) {
-        status = mAudioRecord->start(event, triggerSession);
+        status = mAudioRecord->start(event, triggerSession).transactionError();
         if (status == DEAD_OBJECT) {
             flags |= CBLK_INVALID;
         }
@@ -489,6 +492,7 @@
                 mAudioRecord->stop();
             }
             android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+            mProxy->interrupt();
         }
     }
     return NO_ERROR;
@@ -656,22 +660,22 @@
 
     sp<IMemory> iMem;           // for cblk
     sp<IMemory> bufferMem;
-    sp<IAudioRecord> record = audioFlinger->openRecord(input,
-                                                       mSampleRate,
-                                                       mFormat,
-                                                       mChannelMask,
-                                                       opPackageName,
-                                                       &temp,
-                                                       &flags,
-                                                       mClientPid,
-                                                       tid,
-                                                       mClientUid,
-                                                       &mSessionId,
-                                                       &notificationFrames,
-                                                       iMem,
-                                                       bufferMem,
-                                                       &status,
-                                                       mPortId);
+    sp<media::IAudioRecord> record = audioFlinger->openRecord(input,
+                                                              mSampleRate,
+                                                              mFormat,
+                                                              mChannelMask,
+                                                              opPackageName,
+                                                              &temp,
+                                                              &flags,
+                                                              mClientPid,
+                                                              tid,
+                                                              mClientUid,
+                                                              &mSessionId,
+                                                              &notificationFrames,
+                                                              iMem,
+                                                              bufferMem,
+                                                              &status,
+                                                              mPortId);
     ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId,
             "session ID changed from %d to %d", originalSessionId, mSessionId);
 
@@ -1228,7 +1232,8 @@
         if (mActive) {
             // callback thread or sync event hasn't changed
             // FIXME this fails if we have a new AudioFlinger instance
-            result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, AUDIO_SESSION_NONE);
+            result = mAudioRecord->start(
+                AudioSystem::SYNC_EVENT_SAME, AUDIO_SESSION_NONE).transactionError();
         }
         mFramesReadServerOffset = mFramesRead; // server resets to zero so we need an offset.
     }
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index cdc75ac..c284f73 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -20,6 +20,7 @@
 #include <utils/Log.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
+#include <media/AudioResamplerPublic.h>
 #include <media/AudioSystem.h>
 #include <media/IAudioFlinger.h>
 #include <media/IAudioPolicyService.h>
@@ -253,6 +254,31 @@
     return volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0;
 }
 
+/* static */ size_t AudioSystem::calculateMinFrameCount(
+        uint32_t afLatencyMs, uint32_t afFrameCount, uint32_t afSampleRate,
+        uint32_t sampleRate, float speed /*, uint32_t notificationsPerBufferReq*/)
+{
+    // Ensure that buffer depth covers at least audio hardware latency
+    uint32_t minBufCount = afLatencyMs / ((1000 * afFrameCount) / afSampleRate);
+    if (minBufCount < 2) {
+        minBufCount = 2;
+    }
+#if 0
+    // The notificationsPerBufferReq parameter is not yet used for non-fast tracks,
+    // but keeping the code here to make it easier to add later.
+    if (minBufCount < notificationsPerBufferReq) {
+        minBufCount = notificationsPerBufferReq;
+    }
+#endif
+    ALOGV("calculateMinFrameCount afLatency %u  afFrameCount %u  afSampleRate %u  "
+            "sampleRate %u  speed %f  minBufCount: %u" /*"  notificationsPerBufferReq %u"*/,
+            afLatencyMs, afFrameCount, afSampleRate, sampleRate, speed, minBufCount
+            /*, notificationsPerBufferReq*/);
+    return minBufCount * sourceFramesNeededWithTimestretch(
+            sampleRate, afFrameCount, afSampleRate, speed);
+}
+
+
 status_t AudioSystem::getOutputSamplingRate(uint32_t* samplingRate, audio_stream_type_t streamType)
 {
     audio_io_handle_t output;
@@ -822,16 +848,11 @@
 }
 
 
-audio_io_handle_t AudioSystem::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 AudioSystem::getOutput(audio_stream_type_t stream)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return 0;
-    return aps->getOutput(stream, samplingRate, format, channelMask, flags, offloadInfo);
+    return aps->getOutput(stream);
 }
 
 status_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr,
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index c6622cd..30f97ac 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -39,6 +39,8 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
+using media::VolumeShaper;
+
 // TODO: Move to a separate .h
 
 template <typename T>
@@ -97,32 +99,6 @@
     return kFixPitch ? AUDIO_TIMESTRETCH_PITCH_NORMAL : pitch;
 }
 
-// Must match similar computation in createTrack_l in Threads.cpp.
-// TODO: Move to a common library
-static size_t calculateMinFrameCount(
-        uint32_t afLatencyMs, uint32_t afFrameCount, uint32_t afSampleRate,
-        uint32_t sampleRate, float speed /*, uint32_t notificationsPerBufferReq*/)
-{
-    // Ensure that buffer depth covers at least audio hardware latency
-    uint32_t minBufCount = afLatencyMs / ((1000 * afFrameCount) / afSampleRate);
-    if (minBufCount < 2) {
-        minBufCount = 2;
-    }
-#if 0
-    // The notificationsPerBufferReq parameter is not yet used for non-fast tracks,
-    // but keeping the code here to make it easier to add later.
-    if (minBufCount < notificationsPerBufferReq) {
-        minBufCount = notificationsPerBufferReq;
-    }
-#endif
-    ALOGV("calculateMinFrameCount afLatency %u  afFrameCount %u  afSampleRate %u  "
-            "sampleRate %u  speed %f  minBufCount: %u" /*"  notificationsPerBufferReq %u"*/,
-            afLatencyMs, afFrameCount, afSampleRate, sampleRate, speed, minBufCount
-            /*, notificationsPerBufferReq*/);
-    return minBufCount * sourceFramesNeededWithTimestretch(
-            sampleRate, afFrameCount, afSampleRate, speed);
-}
-
 // static
 status_t AudioTrack::getMinFrameCount(
         size_t* frameCount,
@@ -163,8 +139,8 @@
 
     // When called from createTrack, speed is 1.0f (normal speed).
     // This is rechecked again on setting playback rate (TODO: on setting sample rate, too).
-    *frameCount = calculateMinFrameCount(afLatency, afFrameCount, afSampleRate, sampleRate, 1.0f
-            /*, 0 notificationsPerBufferReq*/);
+    *frameCount = AudioSystem::calculateMinFrameCount(afLatency, afFrameCount, afSampleRate,
+                                              sampleRate, 1.0f /*, 0 notificationsPerBufferReq*/);
 
     // The formula above should always produce a non-zero value under normal circumstances:
     // AudioTrack.SAMPLE_RATE_HZ_MIN <= sampleRate <= AudioTrack.SAMPLE_RATE_HZ_MAX.
@@ -188,8 +164,7 @@
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
       mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mPortId(AUDIO_PORT_HANDLE_NONE)
+      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE)
 {
     mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
     mAttributes.usage = AUDIO_USAGE_UNKNOWN;
@@ -214,19 +189,18 @@
         pid_t pid,
         const audio_attributes_t* pAttributes,
         bool doNotReconnect,
-        float maxRequiredSpeed)
+        float maxRequiredSpeed,
+        audio_port_handle_t selectedDeviceId)
     : mStatus(NO_INIT),
       mState(STATE_STOPPED),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
-      mPausedPosition(0),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mPortId(AUDIO_PORT_HANDLE_NONE)
+      mPausedPosition(0)
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
             0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
-            offloadInfo, uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed);
+            offloadInfo, uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
 }
 
 AudioTrack::AudioTrack(
@@ -252,8 +226,7 @@
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mPortId(AUDIO_PORT_HANDLE_NONE)
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             0 /*frameCount*/, flags, cbf, user, notificationFrames,
@@ -308,7 +281,8 @@
         pid_t pid,
         const audio_attributes_t* pAttributes,
         bool doNotReconnect,
-        float maxRequiredSpeed)
+        float maxRequiredSpeed,
+        audio_port_handle_t selectedDeviceId)
 {
     ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
           "flags #%x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
@@ -316,6 +290,8 @@
           sessionId, transferType, uid, pid);
 
     mThreadCanCallJava = threadCanCallJava;
+    mSelectedDeviceId = selectedDeviceId;
+    mSessionId = sessionId;
 
     switch (transferType) {
     case TRANSFER_DEFAULT:
@@ -496,11 +472,6 @@
                 notificationFrames, minNotificationsPerBuffer, maxNotificationsPerBuffer);
     }
     mNotificationFramesAct = 0;
-    if (sessionId == AUDIO_SESSION_ALLOCATE) {
-        mSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
-    } else {
-        mSessionId = sessionId;
-    }
     int callingpid = IPCThreadState::self()->getCallingPid();
     int mypid = getpid();
     if (uid == AUDIO_UID_INVALID || (callingpid != mypid)) {
@@ -562,7 +533,7 @@
     mFramesWritten = 0;
     mFramesWrittenServerOffset = 0;
     mFramesWrittenAtRestore = -1; // -1 is a unique initializer.
-    mVolumeHandler = new VolumeHandler();
+    mVolumeHandler = new media::VolumeHandler();
     return NO_ERROR;
 }
 
@@ -1219,6 +1190,7 @@
         mSelectedDeviceId = deviceId;
         if (mStatus == NO_ERROR) {
             android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+            mProxy->interrupt();
         }
     }
     return NO_ERROR;
@@ -1312,70 +1284,12 @@
         return NO_INIT;
     }
 
-    audio_io_handle_t output;
-    audio_stream_type_t streamType = mStreamType;
-    audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL;
+    status_t status;
     bool callbackAdded = false;
 
+    {
     // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
     // After fast request is denied, we will request again if IAudioTrack is re-created.
-
-    status_t status;
-    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
-    config.sample_rate = mSampleRate;
-    config.channel_mask = mChannelMask;
-    config.format = mFormat;
-    config.offload_info = mOffloadInfoCopy;
-    mRoutedDeviceId = mSelectedDeviceId;
-    status = AudioSystem::getOutputForAttr(attr, &output,
-                                           mSessionId, &streamType, mClientUid,
-                                           &config,
-                                           mFlags, &mRoutedDeviceId, &mPortId);
-
-    if (status != NO_ERROR || output == AUDIO_IO_HANDLE_NONE) {
-        ALOGE("Could not get audio output for session %d, stream type %d, usage %d, sample rate %u,"
-              " format %#x, channel mask %#x, flags %#x",
-              mSessionId, streamType, mAttributes.usage, 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
-    status = AudioSystem::getLatency(output, &mAfLatency);
-    if (status != NO_ERROR) {
-        ALOGE("getLatency(%d) failed status %d", output, status);
-        goto release;
-    }
-    ALOGV("createTrack_l() output %d afLatency %u", output, mAfLatency);
-
-    status = AudioSystem::getFrameCount(output, &mAfFrameCount);
-    if (status != NO_ERROR) {
-        ALOGE("getFrameCount(output=%d) status %d", output, status);
-        goto release;
-    }
-
-    // TODO consider making this a member variable if there are other uses for it later
-    size_t afFrameCountHAL;
-    status = AudioSystem::getFrameCountHAL(output, &afFrameCountHAL);
-    if (status != NO_ERROR) {
-        ALOGE("getFrameCountHAL(output=%d) status %d", output, status);
-        goto release;
-    }
-    ALOG_ASSERT(afFrameCountHAL > 0);
-
-    status = AudioSystem::getSamplingRate(output, &mAfSampleRate);
-    if (status != NO_ERROR) {
-        ALOGE("getSamplingRate(output=%d) status %d", output, status);
-        goto release;
-    }
-    if (mSampleRate == 0) {
-        mSampleRate = mAfSampleRate;
-        mOriginalSampleRate = mAfSampleRate;
-    }
-
     // Client can only express a preference for FAST.  Server will perform additional tests.
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
         // either of these use cases:
@@ -1389,130 +1303,78 @@
             // use case 4: synchronous write
             ((mTransfer == TRANSFER_SYNC) && mThreadCanCallJava);
 
-        bool useCaseAllowed = sharedBuffer || transferAllowed;
-        if (!useCaseAllowed) {
+        bool fastAllowed = sharedBuffer || transferAllowed;
+        if (!fastAllowed) {
             ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client, not shared buffer and transfer = %s",
                   convertTransferToText(mTransfer));
-        }
-
-        // sample rates must also match
-        bool sampleRateAllowed = mSampleRate == mAfSampleRate;
-        if (!sampleRateAllowed) {
-            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client, sample rate %u Hz but HAL needs %u Hz",
-                  mSampleRate, mAfSampleRate);
-        }
-
-        bool fastAllowed = useCaseAllowed && sampleRateAllowed;
-        if (!fastAllowed) {
             mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
         }
     }
 
-    mNotificationFramesAct = mNotificationFramesReq;
-
-    size_t frameCount = mReqFrameCount;
-    if (!audio_has_proportional_frames(mFormat)) {
-
-        if (mSharedBuffer != 0) {
-            // Same comment as below about ignoring frameCount parameter for set()
-            frameCount = mSharedBuffer->size();
-        } else if (frameCount == 0) {
-            frameCount = mAfFrameCount;
-        }
-        if (mNotificationFramesAct != frameCount) {
-            mNotificationFramesAct = frameCount;
-        }
-    } else if (mSharedBuffer != 0) {
-        // FIXME: Ensure client side memory buffers need
-        // not have additional alignment beyond sample
-        // (e.g. 16 bit stereo accessed as 32 bit frame).
-        size_t alignment = audio_bytes_per_sample(mFormat);
-        if (alignment & 1) {
-            // for AUDIO_FORMAT_PCM_24_BIT_PACKED (not exposed through Java).
-            alignment = 1;
-        }
-        if (mChannelCount > 1) {
-            // More than 2 channels does not require stronger alignment than stereo
-            alignment <<= 1;
-        }
-        if (((uintptr_t)mSharedBuffer->pointer() & (alignment - 1)) != 0) {
-            ALOGE("Invalid buffer alignment: address %p, channel count %u",
-                    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 = mSharedBuffer->size() / mFrameSize;
+    IAudioFlinger::CreateTrackInput input;
+    if (mStreamType != AUDIO_STREAM_DEFAULT) {
+        stream_type_to_audio_attributes(mStreamType, &input.attr);
     } else {
-        size_t minFrameCount = 0;
-        // For fast tracks the frame count calculations and checks are mostly done by server,
-        // but we try to respect the application's request for notifications per buffer.
-        if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
-            if (mNotificationsPerBufferReq > 0) {
-                // Avoid possible arithmetic overflow during multiplication.
-                // mNotificationsPerBuffer is clamped to a small integer earlier, so it is unlikely.
-                if (mNotificationsPerBufferReq > SIZE_MAX / afFrameCountHAL) {
-                    ALOGE("Requested notificationPerBuffer=%u ignored for HAL frameCount=%zu",
-                            mNotificationsPerBufferReq, afFrameCountHAL);
-                } else {
-                    minFrameCount = afFrameCountHAL * mNotificationsPerBufferReq;
-                }
-            }
-        } else {
-            // for normal tracks precompute the frame count based on speed.
-            const float speed = !isPurePcmData_l() || isOffloadedOrDirect_l() ? 1.0f :
-                            max(mMaxRequiredSpeed, mPlaybackRate.mSpeed);
-            minFrameCount = calculateMinFrameCount(
-                    mAfLatency, mAfFrameCount, mAfSampleRate, mSampleRate,
-                    speed /*, 0 mNotificationsPerBufferReq*/);
-        }
-        if (frameCount < minFrameCount) {
-            frameCount = minFrameCount;
-        }
+        input.attr = mAttributes;
     }
-
-    audio_output_flags_t flags = mFlags;
-
-    pid_t tid = -1;
+    input.config = AUDIO_CONFIG_INITIALIZER;
+    input.config.sample_rate = mSampleRate;
+    input.config.channel_mask = mChannelMask;
+    input.config.format = mFormat;
+    input.config.offload_info = mOffloadInfoCopy;
+    input.clientInfo.clientUid = mClientUid;
+    input.clientInfo.clientPid = mClientPid;
+    input.clientInfo.clientTid = -1;
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
         // It is currently meaningless to request SCHED_FIFO for a Java thread.  Even if the
         // application-level code follows all non-blocking design rules, the language runtime
         // doesn't also follow those rules, so the thread will not benefit overall.
         if (mAudioTrackThread != 0 && !mThreadCanCallJava) {
-            tid = mAudioTrackThread->getTid();
+            input.clientInfo.clientTid = mAudioTrackThread->getTid();
         }
     }
+    input.sharedBuffer = mSharedBuffer;
+    input.notificationsPerBuffer = mNotificationsPerBufferReq;
+    input.speed = 1.0;
+    if (audio_has_proportional_frames(mFormat) && mSharedBuffer == 0 &&
+            (mFlags & AUDIO_OUTPUT_FLAG_FAST) == 0) {
+        input.speed  = !isPurePcmData_l() || isOffloadedOrDirect_l() ? 1.0f :
+                        max(mMaxRequiredSpeed, mPlaybackRate.mSpeed);
+    }
+    input.flags = mFlags;
+    input.frameCount = mReqFrameCount;
+    input.notificationFrameCount = mNotificationFramesReq;
+    input.selectedDeviceId = mSelectedDeviceId;
+    input.sessionId = mSessionId;
 
-    size_t temp = frameCount;   // temp may be replaced by a revised value of frameCount,
-                                // but we will still need the original value also
-    audio_session_t originalSessionId = mSessionId;
-    sp<IAudioTrack> track = audioFlinger->createTrack(streamType,
-                                                      mSampleRate,
-                                                      mFormat,
-                                                      mChannelMask,
-                                                      &temp,
-                                                      &flags,
-                                                      mSharedBuffer,
+    IAudioFlinger::CreateTrackOutput output;
+
+    sp<IAudioTrack> track = audioFlinger->createTrack(input,
                                                       output,
-                                                      mClientPid,
-                                                      tid,
-                                                      &mSessionId,
-                                                      mClientUid,
-                                                      &status,
-                                                      mPortId);
-    ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId,
-            "session ID changed from %d to %d", originalSessionId, mSessionId);
+                                                      &status);
 
-    if (status != NO_ERROR) {
-        ALOGE("AudioFlinger could not create track, status: %d", status);
-        goto release;
+    if (status != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
+        ALOGE("AudioFlinger could not create track, status: %d output %d", status, output.outputId);
+        goto error;
     }
     ALOG_ASSERT(track != 0);
 
+    mFrameCount = output.frameCount;
+    mNotificationFramesAct = (uint32_t)output.notificationFrameCount;
+    mRoutedDeviceId = output.selectedDeviceId;
+    mSessionId = output.sessionId;
+
+    mSampleRate = output.sampleRate;
+    if (mOriginalSampleRate == 0) {
+        mOriginalSampleRate = mSampleRate;
+    }
+
+    mAfFrameCount = output.afFrameCount;
+    mAfSampleRate = output.afSampleRate;
+    mAfLatency = output.afLatencyMs;
+
+    mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
+
     // AudioFlinger now owns the reference to the I/O handle,
     // so we are no longer responsible for releasing it.
 
@@ -1521,13 +1383,13 @@
     if (iMem == 0) {
         ALOGE("Could not get control block");
         status = NO_INIT;
-        goto release;
+        goto error;
     }
     void *iMemPointer = iMem->pointer();
     if (iMemPointer == NULL) {
         ALOGE("Could not get control block pointer");
         status = NO_INIT;
-        goto release;
+        goto error;
     }
     // invariant that mAudioTrack != 0 is true only after set() returns successfully
     if (mAudioTrack != 0) {
@@ -1540,75 +1402,33 @@
 
     audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
     mCblk = cblk;
-    // 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
-        // for fast track as it uses a special method of assigning frame count.
-        ALOGW("Requested frameCount %zu but received frameCount %zu", frameCount, temp);
-    }
-    frameCount = temp;
 
     mAwaitBoost = false;
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
-        if (flags & AUDIO_OUTPUT_FLAG_FAST) {
-            ALOGI("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu -> %zu", frameCount, temp);
+        if (output.flags & AUDIO_OUTPUT_FLAG_FAST) {
+            ALOGI("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu -> %zu",
+                  mReqFrameCount, mFrameCount);
             if (!mThreadCanCallJava) {
                 mAwaitBoost = true;
             }
         } else {
-            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu -> %zu", frameCount,
-                    temp);
+            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu -> %zu", mReqFrameCount,
+                  mFrameCount);
         }
     }
-    mFlags = flags;
-
-    // Make sure that application is notified with sufficient margin before underrun.
-    // The client can divide the AudioTrack buffer into sub-buffers,
-    // and expresses its desire to server as the notification frame count.
-    if (mSharedBuffer == 0 && audio_is_linear_pcm(mFormat)) {
-        size_t maxNotificationFrames;
-        if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
-            // notify every HAL buffer, regardless of the size of the track buffer
-            maxNotificationFrames = afFrameCountHAL;
-        } else {
-            // For normal tracks, use at least double-buffering if no sample rate conversion,
-            // or at least triple-buffering if there is sample rate conversion
-            const int nBuffering = mOriginalSampleRate == mAfSampleRate ? 2 : 3;
-            maxNotificationFrames = frameCount / nBuffering;
-            // If client requested a fast track but this was denied, then use the smaller maximum.
-            // FMS_20 is the minimum task wakeup period in ms for which CFS operates reliably.
-#define FMS_20 20   // FIXME share a common declaration with the same symbol in Threads.cpp
-            if (mOrigFlags & AUDIO_OUTPUT_FLAG_FAST) {
-                size_t maxNotificationFramesFastDenied = FMS_20 * mSampleRate / 1000;
-                if (maxNotificationFrames > maxNotificationFramesFastDenied) {
-                    maxNotificationFrames = maxNotificationFramesFastDenied;
-                }
-            }
-        }
-        if (mNotificationFramesAct == 0 || mNotificationFramesAct > maxNotificationFrames) {
-            if (mNotificationFramesAct == 0) {
-                ALOGD("Client defaulted notificationFrames to %zu for frameCount %zu",
-                    maxNotificationFrames, frameCount);
-            } else {
-                ALOGW("Client adjusted notificationFrames from %u to %zu for frameCount %zu",
-                    mNotificationFramesAct, maxNotificationFrames, frameCount);
-            }
-            mNotificationFramesAct = (uint32_t) maxNotificationFrames;
-        }
-    }
+    mFlags = output.flags;
 
     //mOutput != output includes the case where mOutput == AUDIO_IO_HANDLE_NONE for first creation
-    if (mDeviceCallback != 0 && mOutput != output) {
+    if (mDeviceCallback != 0 && mOutput != output.outputId) {
         if (mOutput != AUDIO_IO_HANDLE_NONE) {
             AudioSystem::removeAudioDeviceCallback(this, mOutput);
         }
-        AudioSystem::addAudioDeviceCallback(this, output);
+        AudioSystem::addAudioDeviceCallback(this, output.outputId);
         callbackAdded = true;
     }
 
     // We retain a copy of the I/O handle, but don't own the reference
-    mOutput = output;
+    mOutput = output.outputId;
     mRefreshRemaining = true;
 
     // Starting address of buffers in shared memory.  If there is a shared buffer, buffers
@@ -1623,18 +1443,16 @@
         if (buffers == NULL) {
             ALOGE("Could not get buffer pointer");
             status = NO_INIT;
-            goto release;
+            goto error;
         }
     }
 
     mAudioTrack->attachAuxEffect(mAuxEffectId);
-    mFrameCount = frameCount;
-    updateLatency_l();  // this refetches mAfLatency and sets mLatency
 
     // If IAudioTrack is re-created, don't let the requested frameCount
     // decrease.  This can confuse clients that cache frameCount().
-    if (frameCount > mReqFrameCount) {
-        mReqFrameCount = frameCount;
+    if (mFrameCount > mReqFrameCount) {
+        mReqFrameCount = mFrameCount;
     }
 
     // reset server position to 0 as we have new cblk.
@@ -1643,9 +1461,9 @@
     // update proxy
     if (mSharedBuffer == 0) {
         mStaticProxy.clear();
-        mProxy = new AudioTrackClientProxy(cblk, buffers, frameCount, mFrameSize);
+        mProxy = new AudioTrackClientProxy(cblk, buffers, mFrameCount, mFrameSize);
     } else {
-        mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSize);
+        mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, mFrameCount, mFrameSize);
         mProxy = mStaticProxy;
     }
 
@@ -1671,8 +1489,7 @@
     return NO_ERROR;
     }
 
-release:
-    AudioSystem::releaseOutput(output, streamType, mSessionId);
+error:
     if (callbackAdded) {
         // note: mOutput is always valid is callbackAdded is true
         AudioSystem::removeAudioDeviceCallback(this, mOutput);
@@ -1680,6 +1497,8 @@
     if (status == NO_ERROR) {
         status = NO_INIT;
     }
+
+    // sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
     return status;
 }
 
@@ -2415,8 +2234,8 @@
         return true; // static tracks do not have issues with buffer sizing.
     }
     const size_t minFrameCount =
-            calculateMinFrameCount(mAfLatency, mAfFrameCount, mAfSampleRate, sampleRate, speed
-                /*, 0 mNotificationsPerBufferReq*/);
+            AudioSystem::calculateMinFrameCount(mAfLatency, mAfFrameCount, mAfSampleRate,
+                                            sampleRate, speed /*, 0 mNotificationsPerBufferReq*/);
     const bool allowed = mFrameCount >= minFrameCount;
     ALOGD_IF(!allowed,
             "isSampleRateSpeedAllowed_l denied "
@@ -2832,23 +2651,28 @@
 
 status_t AudioTrack::dump(int fd, const Vector<String16>& args __unused) const
 {
-
-    const size_t SIZE = 256;
-    char buffer[SIZE];
     String8 result;
 
     result.append(" AudioTrack::dump\n");
-    snprintf(buffer, 255, "  stream type(%d), left - right volume(%f, %f)\n", mStreamType,
-            mVolume[AUDIO_INTERLEAVE_LEFT], mVolume[AUDIO_INTERLEAVE_RIGHT]);
-    result.append(buffer);
-    snprintf(buffer, 255, "  format(%d), channel count(%d), frame count(%zu)\n", mFormat,
-            mChannelCount, mFrameCount);
-    result.append(buffer);
-    snprintf(buffer, 255, "  sample rate(%u), speed(%f), status(%d)\n",
-            mSampleRate, mPlaybackRate.mSpeed, mStatus);
-    result.append(buffer);
-    snprintf(buffer, 255, "  state(%d), latency (%d)\n", mState, mLatency);
-    result.append(buffer);
+    result.appendFormat("  status(%d), state(%d), session Id(%d), flags(%x)\n",
+                        mStatus, mState, mSessionId, mFlags);
+    result.appendFormat("  stream type(%d), left - right volume(%f, %f)\n",
+                        (mStreamType == AUDIO_STREAM_DEFAULT) ?
+                                audio_attributes_to_stream_type(&mAttributes) : mStreamType,
+                        mVolume[AUDIO_INTERLEAVE_LEFT], mVolume[AUDIO_INTERLEAVE_RIGHT]);
+    result.appendFormat("  format(%x), channel mask(%x), channel count(%u)\n",
+                  mFormat, mChannelMask, mChannelCount);
+    result.appendFormat("  sample rate(%u), original sample rate(%u), speed(%f)\n",
+                  mSampleRate, mOriginalSampleRate, mPlaybackRate.mSpeed);
+    result.appendFormat("  frame count(%zu), req. frame count(%zu)\n",
+                  mFrameCount, mReqFrameCount);
+    result.appendFormat("  notif. frame count(%u), req. notif. frame count(%u),"
+            " req. notif. per buff(%u)\n",
+             mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq);
+    result.appendFormat("  latency (%d), selected device Id(%d), routed device Id(%d)\n",
+                        mLatency, mSelectedDeviceId, mRoutedDeviceId);
+    result.appendFormat("  output(%d) AF latency (%u) AF frame count(%zu) AF SampleRate(%u)\n",
+                        mOutput, mAfLatency, mAfFrameCount, mAfSampleRate);
     ::write(fd, result.string(), result.size());
     return NO_ERROR;
 }
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 14feada..5cf2bdb 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -95,87 +95,42 @@
     {
     }
 
-    virtual sp<IAudioTrack> createTrack(
-                                audio_stream_type_t streamType,
-                                uint32_t sampleRate,
-                                audio_format_t format,
-                                audio_channel_mask_t channelMask,
-                                size_t *pFrameCount,
-                                audio_output_flags_t *flags,
-                                const sp<IMemory>& sharedBuffer,
-                                audio_io_handle_t output,
-                                pid_t pid,
-                                pid_t tid,
-                                audio_session_t *sessionId,
-                                int clientUid,
-                                status_t *status,
-                                audio_port_handle_t portId)
+    virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
+                                        CreateTrackOutput& output,
+                                        status_t *status)
     {
         Parcel data, reply;
         sp<IAudioTrack> track;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32((int32_t) streamType);
-        data.writeInt32(sampleRate);
-        data.writeInt32(format);
-        data.writeInt32(channelMask);
-        size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0;
-        data.writeInt64(frameCount);
-        audio_output_flags_t lFlags = flags != NULL ? *flags : AUDIO_OUTPUT_FLAG_NONE;
-        data.writeInt32(lFlags);
-        // haveSharedBuffer
-        if (sharedBuffer != 0) {
-            data.writeInt32(true);
-            data.writeStrongBinder(IInterface::asBinder(sharedBuffer));
-        } else {
-            data.writeInt32(false);
+
+        if (status == nullptr) {
+            return track;
         }
-        data.writeInt32((int32_t) output);
-        data.writeInt32((int32_t) pid);
-        data.writeInt32((int32_t) tid);
-        audio_session_t lSessionId = AUDIO_SESSION_ALLOCATE;
-        if (sessionId != NULL) {
-            lSessionId = *sessionId;
-        }
-        data.writeInt32(lSessionId);
-        data.writeInt32(clientUid);
-        data.writeInt32(portId);
+
+        input.writeToParcel(&data);
+
         status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
         if (lStatus != NO_ERROR) {
-            ALOGE("createTrack error: %s", strerror(-lStatus));
-        } else {
-            frameCount = reply.readInt64();
-            if (pFrameCount != NULL) {
-                *pFrameCount = frameCount;
-            }
-            lFlags = (audio_output_flags_t)reply.readInt32();
-            if (flags != NULL) {
-                *flags = lFlags;
-            }
-            lSessionId = (audio_session_t) reply.readInt32();
-            if (sessionId != NULL) {
-                *sessionId = lSessionId;
-            }
-            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();
-                }
-            }
+            ALOGE("createTrack transaction error %d", lStatus);
+            *status = DEAD_OBJECT;
+            return track;
         }
-        if (status != NULL) {
-            *status = lStatus;
+        *status = reply.readInt32();
+        if (*status != NO_ERROR) {
+            ALOGE("createTrack returned error %d", *status);
+            return track;
         }
+        track = interface_cast<IAudioTrack>(reply.readStrongBinder());
+        if (track == 0) {
+            ALOGE("createTrack returned an NULL IAudioTrack with status OK");
+            *status = DEAD_OBJECT;
+            return track;
+        }
+        output.readFromParcel(&reply);
         return track;
     }
 
-    virtual sp<IAudioRecord> openRecord(
+    virtual sp<media::IAudioRecord> openRecord(
                                 audio_io_handle_t input,
                                 uint32_t sampleRate,
                                 audio_format_t format,
@@ -194,7 +149,7 @@
                                 audio_port_handle_t portId)
     {
         Parcel data, reply;
-        sp<IAudioRecord> record;
+        sp<media::IAudioRecord> record;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32((int32_t) input);
         data.writeInt32(sampleRate);
@@ -238,7 +193,7 @@
                 *notificationFrames = lNotificationFrames;
             }
             lStatus = reply.readInt32();
-            record = interface_cast<IAudioRecord>(reply.readStrongBinder());
+            record = interface_cast<media::IAudioRecord>(reply.readStrongBinder());
             cblk = interface_cast<IMemory>(reply.readStrongBinder());
             if (cblk != 0 && cblk->pointer() == NULL) {
                 cblk.clear();
@@ -970,41 +925,27 @@
     switch (code) {
         case CREATE_TRACK: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int streamType = data.readInt32();
-            uint32_t sampleRate = data.readInt32();
-            audio_format_t format = (audio_format_t) data.readInt32();
-            audio_channel_mask_t channelMask = data.readInt32();
-            size_t frameCount = data.readInt64();
-            audio_output_flags_t flags = (audio_output_flags_t) data.readInt32();
-            bool haveSharedBuffer = data.readInt32() != 0;
-            sp<IMemory> buffer;
-            if (haveSharedBuffer) {
-                buffer = interface_cast<IMemory>(data.readStrongBinder());
+
+            CreateTrackInput input;
+            if (input.readFromParcel((Parcel*)&data) != NO_ERROR) {
+                reply->writeInt32(DEAD_OBJECT);
+                return NO_ERROR;
             }
-            audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
-            pid_t pid = (pid_t) data.readInt32();
-            pid_t tid = (pid_t) data.readInt32();
-            audio_session_t sessionId = (audio_session_t) data.readInt32();
-            int clientUid = data.readInt32();
-            audio_port_handle_t portId = (audio_port_handle_t) data.readInt32();
-            status_t status = NO_ERROR;
-            sp<IAudioTrack> track;
-            if ((haveSharedBuffer && (buffer == 0)) ||
-                    ((buffer != 0) && (buffer->pointer() == NULL))) {
-                ALOGW("CREATE_TRACK: cannot retrieve shared memory");
-                status = DEAD_OBJECT;
-            } else {
-                track = createTrack(
-                        (audio_stream_type_t) streamType, sampleRate, format,
-                        channelMask, &frameCount, &flags, buffer, output, pid, tid,
-                        &sessionId, clientUid, &status, portId);
-                LOG_ALWAYS_FATAL_IF((track != 0) != (status == NO_ERROR));
-            }
-            reply->writeInt64(frameCount);
-            reply->writeInt32(flags);
-            reply->writeInt32(sessionId);
+
+            status_t status;
+            CreateTrackOutput output;
+
+            sp<IAudioTrack> track= createTrack(input,
+                                               output,
+                                               &status);
+
+            LOG_ALWAYS_FATAL_IF((track != 0) != (status == NO_ERROR));
             reply->writeInt32(status);
+            if (status != NO_ERROR) {
+                return NO_ERROR;
+            }
             reply->writeStrongBinder(IInterface::asBinder(track));
+            output.writeToParcel(reply);
             return NO_ERROR;
         } break;
         case OPEN_RECORD: {
@@ -1025,7 +966,7 @@
             sp<IMemory> cblk;
             sp<IMemory> buffers;
             status_t status = NO_ERROR;
-            sp<IAudioRecord> record = openRecord(input,
+            sp<media::IAudioRecord> record = openRecord(input,
                     sampleRate, format, channelMask, opPackageName, &frameCount, &flags,
                     pid, tid, clientUid, &sessionId, &notificationFrames, cblk, buffers,
                     &status, portId);
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index ceba211..0397eec 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -160,28 +160,11 @@
         return static_cast <audio_policy_forced_cfg_t> (reply.readInt32());
     }
 
-    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 audio_io_handle_t getOutput(audio_stream_type_t stream)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
         data.writeInt32(static_cast <uint32_t>(stream));
-        data.writeInt32(samplingRate);
-        data.writeInt32(static_cast <uint32_t>(format));
-        data.writeInt32(channelMask);
-        data.writeInt32(static_cast <uint32_t>(flags));
-        // hasOffloadInfo
-        if (offloadInfo == NULL) {
-            data.writeInt32(0);
-        } else {
-            data.writeInt32(1);
-            data.write(offloadInfo, sizeof(audio_offload_info_t));
-        }
         remote()->transact(GET_OUTPUT, data, &reply);
         return static_cast <audio_io_handle_t> (reply.readInt32());
     }
@@ -934,22 +917,7 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_stream_type_t stream =
                     static_cast <audio_stream_type_t>(data.readInt32());
-            uint32_t samplingRate = data.readInt32();
-            audio_format_t format = (audio_format_t) data.readInt32();
-            audio_channel_mask_t channelMask = data.readInt32();
-            audio_output_flags_t flags =
-                    static_cast <audio_output_flags_t>(data.readInt32());
-            bool hasOffloadInfo = data.readInt32() != 0;
-            audio_offload_info_t offloadInfo;
-            if (hasOffloadInfo) {
-                data.read(&offloadInfo, sizeof(audio_offload_info_t));
-            }
-            audio_io_handle_t output = getOutput(stream,
-                                                 samplingRate,
-                                                 format,
-                                                 channelMask,
-                                                 flags,
-                                                 hasOffloadInfo ? &offloadInfo : NULL);
+            audio_io_handle_t output = getOutput(stream);
             reply->writeInt32(static_cast <int>(output));
             return NO_ERROR;
         } break;
diff --git a/media/libaudioclient/IAudioRecord.cpp b/media/libaudioclient/IAudioRecord.cpp
deleted file mode 100644
index 1331c0d..0000000
--- a/media/libaudioclient/IAudioRecord.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "IAudioRecord"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include <media/IAudioRecord.h>
-
-namespace android {
-
-enum {
-    UNUSED_WAS_GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
-    START,
-    STOP
-};
-
-class BpAudioRecord : public BpInterface<IAudioRecord>
-{
-public:
-    explicit BpAudioRecord(const sp<IBinder>& impl)
-        : BpInterface<IAudioRecord>(impl)
-    {
-    }
-
-    virtual status_t start(int /*AudioSystem::sync_event_t*/ event, audio_session_t triggerSession)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
-        data.writeInt32(event);
-        data.writeInt32(triggerSession);
-        status_t status = remote()->transact(START, data, &reply);
-        if (status == NO_ERROR) {
-            status = reply.readInt32();
-        } else {
-            ALOGW("start() error: %s", strerror(-status));
-        }
-        return status;
-    }
-
-    virtual void stop()
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
-        remote()->transact(STOP, data, &reply);
-    }
-
-};
-
-IMPLEMENT_META_INTERFACE(AudioRecord, "android.media.IAudioRecord");
-
-// ----------------------------------------------------------------------
-
-status_t BnAudioRecord::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch (code) {
-        case START: {
-            CHECK_INTERFACE(IAudioRecord, data, reply);
-            int /*AudioSystem::sync_event_t*/ event = data.readInt32();
-            audio_session_t triggerSession = (audio_session_t) data.readInt32();
-            reply->writeInt32(start(event, triggerSession));
-            return NO_ERROR;
-        } break;
-        case STOP: {
-            CHECK_INTERFACE(IAudioRecord, data, reply);
-            stop();
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-} // namespace android
diff --git a/media/libaudioclient/IAudioTrack.cpp b/media/libaudioclient/IAudioTrack.cpp
index 79e864d..adff057 100644
--- a/media/libaudioclient/IAudioTrack.cpp
+++ b/media/libaudioclient/IAudioTrack.cpp
@@ -28,6 +28,8 @@
 
 namespace android {
 
+using media::VolumeShaper;
+
 enum {
     GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
     START,
@@ -185,7 +187,7 @@
             return nullptr;
         }
         sp<VolumeShaper::State> state = new VolumeShaper::State;
-        status = state->readFromParcel(reply);
+        status = state->readFromParcel(&reply);
         if (status != NO_ERROR) {
             return nullptr;
         }
@@ -263,12 +265,12 @@
             status_t status = data.readInt32(&present);
             if (status == NO_ERROR && present != 0) {
                 configuration = new VolumeShaper::Configuration();
-                status = configuration->readFromParcel(data);
+                status = configuration->readFromParcel(&data);
             }
             status = status ?: data.readInt32(&present);
             if (status == NO_ERROR && present != 0) {
                 operation = new VolumeShaper::Operation();
-                status = operation->readFromParcel(data);
+                status = operation->readFromParcel(&data);
             }
             if (status == NO_ERROR) {
                 status = (status_t)applyVolumeShaper(configuration, operation);
diff --git a/media/libaudioclient/PlayerBase.cpp b/media/libaudioclient/PlayerBase.cpp
index 7868318..b0c68e5 100644
--- a/media/libaudioclient/PlayerBase.cpp
+++ b/media/libaudioclient/PlayerBase.cpp
@@ -22,6 +22,8 @@
 
 namespace android {
 
+using media::VolumeShaper;
+
 //--------------------------------------------------------------------------------------------------
 PlayerBase::PlayerBase() : BnPlayer(),
         mPanMultiplierL(1.0f), mPanMultiplierR(1.0f),
@@ -117,23 +119,26 @@
 
 //------------------------------------------------------------------------------
 // Implementation of IPlayer
-void PlayerBase::start() {
+binder::Status PlayerBase::start() {
     ALOGD("PlayerBase::start() from IPlayer");
     (void)startWithStatus();
+    return binder::Status::ok();
 }
 
-void PlayerBase::pause() {
+binder::Status PlayerBase::pause() {
     ALOGD("PlayerBase::pause() from IPlayer");
     (void)pauseWithStatus();
+    return binder::Status::ok();
 }
 
 
-void PlayerBase::stop() {
+binder::Status PlayerBase::stop() {
     ALOGD("PlayerBase::stop() from IPlayer");
     (void)stopWithStatus();
+    return binder::Status::ok();
 }
 
-void PlayerBase::setVolume(float vol) {
+binder::Status PlayerBase::setVolume(float vol) {
     ALOGD("PlayerBase::setVolume() from IPlayer");
     {
         Mutex::Autolock _l(mSettingsLock);
@@ -144,9 +149,10 @@
     if (status != NO_ERROR) {
         ALOGW("PlayerBase::setVolume() error %d", status);
     }
+    return binder::Status::fromStatusT(status);
 }
 
-void PlayerBase::setPan(float pan) {
+binder::Status PlayerBase::setPan(float pan) {
     ALOGD("PlayerBase::setPan() from IPlayer");
     {
         Mutex::Autolock _l(mSettingsLock);
@@ -163,22 +169,19 @@
     if (status != NO_ERROR) {
         ALOGW("PlayerBase::setPan() error %d", status);
     }
+    return binder::Status::fromStatusT(status);
 }
 
-void PlayerBase::setStartDelayMs(int32_t delayMs __unused) {
+binder::Status PlayerBase::setStartDelayMs(int32_t delayMs __unused) {
     ALOGW("setStartDelay() is not supported");
+    return binder::Status::ok();
 }
 
-void PlayerBase::applyVolumeShaper(
-        const sp<VolumeShaper::Configuration>& configuration  __unused,
-        const sp<VolumeShaper::Operation>& operation __unused) {
+binder::Status PlayerBase::applyVolumeShaper(
+            const VolumeShaper::Configuration& configuration __unused,
+            const VolumeShaper::Operation& operation __unused) {
     ALOGW("applyVolumeShaper() is not supported");
-}
-
-status_t PlayerBase::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    return BnPlayer::onTransact(code, data, reply, flags);
+    return binder::Status::ok();
 }
 
 } // namespace android
diff --git a/media/libaudioclient/TrackPlayerBase.cpp b/media/libaudioclient/TrackPlayerBase.cpp
index 48cd803..0a914fc 100644
--- a/media/libaudioclient/TrackPlayerBase.cpp
+++ b/media/libaudioclient/TrackPlayerBase.cpp
@@ -18,6 +18,8 @@
 
 namespace android {
 
+using media::VolumeShaper;
+
 //--------------------------------------------------------------------------------------------------
 TrackPlayerBase::TrackPlayerBase() : PlayerBase(),
         mPlayerVolumeL(1.0f), mPlayerVolumeR(1.0f)
@@ -103,18 +105,24 @@
 }
 
 
-void TrackPlayerBase::applyVolumeShaper(
-        const sp<VolumeShaper::Configuration>& configuration,
-        const sp<VolumeShaper::Operation>& operation) {
+binder::Status TrackPlayerBase::applyVolumeShaper(
+        const VolumeShaper::Configuration& configuration,
+        const VolumeShaper::Operation& operation) {
+
+    sp<VolumeShaper::Configuration> spConfiguration = new VolumeShaper::Configuration(configuration);
+    sp<VolumeShaper::Operation> spOperation = new VolumeShaper::Operation(operation);
+
     if (mAudioTrack != 0) {
         ALOGD("TrackPlayerBase::applyVolumeShaper() from IPlayer");
-        VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(configuration, operation);
+        VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(spConfiguration, spOperation);
         if (status < 0) { // a non-negative value is the volume shaper id.
             ALOGE("TrackPlayerBase::applyVolumeShaper() failed with status %d", status);
         }
+        return binder::Status::fromStatusT(status);
     } else {
         ALOGD("TrackPlayerBase::applyVolumeShaper()"
-                " no AudioTrack for volume control from IPlayer");
+              " no AudioTrack for volume control from IPlayer");
+        return binder::Status::ok();
     }
 }
 
diff --git a/media/libaudioclient/aidl/android/media/IAudioRecord.aidl b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
new file mode 100644
index 0000000..50ce78f
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+interface IAudioRecord {
+
+  /* After it's created the track is not active. Call start() to
+   * make it active.
+   */
+  void start(int /*AudioSystem::sync_event_t*/ event,
+             int /*audio_session_t*/ triggerSession);
+
+  /* Stop a track. If set, the callback will cease being called and
+   * obtainBuffer will return an error. Buffers that are already released
+   * will be processed, unless flush() is called.
+   */
+  void stop();
+}
diff --git a/media/libaudioclient/aidl/android/media/IPlayer.aidl b/media/libaudioclient/aidl/android/media/IPlayer.aidl
new file mode 100644
index 0000000..a90fcdd
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/IPlayer.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.VolumeShaper.Configuration;
+import android.media.VolumeShaper.Operation;
+
+/**
+ * @hide
+ */
+interface IPlayer {
+    oneway void start();
+    oneway void pause();
+    oneway void stop();
+    oneway void setVolume(float vol);
+    oneway void setPan(float pan);
+    oneway void setStartDelayMs(int delayMs);
+    oneway void applyVolumeShaper(in Configuration configuration,
+                                  in Operation operation);
+}
diff --git a/media/libstagefright/MediaSource.cpp b/media/libaudioclient/aidl/android/media/VolumeShaper/Configuration.aidl
similarity index 72%
copy from media/libstagefright/MediaSource.cpp
copy to media/libaudioclient/aidl/android/media/VolumeShaper/Configuration.aidl
index a17757a..fd0e60f 100644
--- a/media/libstagefright/MediaSource.cpp
+++ b/media/libaudioclient/aidl/android/media/VolumeShaper/Configuration.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,12 +14,6 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/MediaSource.h>
+package android.media.VolumeShaper;
 
-namespace android {
-
-MediaSource::MediaSource() {}
-
-MediaSource::~MediaSource() {}
-
-}  // namespace android
+parcelable Configuration cpp_header "media/VolumeShaper.h";
diff --git a/media/libstagefright/MediaSource.cpp b/media/libaudioclient/aidl/android/media/VolumeShaper/Operation.aidl
similarity index 72%
copy from media/libstagefright/MediaSource.cpp
copy to media/libaudioclient/aidl/android/media/VolumeShaper/Operation.aidl
index a17757a..4290d9d 100644
--- a/media/libstagefright/MediaSource.cpp
+++ b/media/libaudioclient/aidl/android/media/VolumeShaper/Operation.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,12 +14,6 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/MediaSource.h>
+package android.media.VolumeShaper;
 
-namespace android {
-
-MediaSource::MediaSource() {}
-
-MediaSource::~MediaSource() {}
-
-}  // namespace android
+parcelable Operation cpp_header "media/VolumeShaper.h";
diff --git a/media/libstagefright/MediaSource.cpp b/media/libaudioclient/aidl/android/media/VolumeShaper/State.aidl
similarity index 72%
rename from media/libstagefright/MediaSource.cpp
rename to media/libaudioclient/aidl/android/media/VolumeShaper/State.aidl
index a17757a..f6a22b8 100644
--- a/media/libstagefright/MediaSource.cpp
+++ b/media/libaudioclient/aidl/android/media/VolumeShaper/State.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,12 +14,6 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/MediaSource.h>
+package android.media.VolumeShaper;
 
-namespace android {
-
-MediaSource::MediaSource() {}
-
-MediaSource::~MediaSource() {}
-
-}  // namespace android
+parcelable State cpp_header "media/VolumeShaper.h";
diff --git a/media/libaudioclient/include/media/AudioClient.h b/media/libaudioclient/include/media/AudioClient.h
index 9efd76d..108e326 100644
--- a/media/libaudioclient/include/media/AudioClient.h
+++ b/media/libaudioclient/include/media/AudioClient.h
@@ -18,6 +18,7 @@
 #ifndef ANDROID_AUDIO_CLIENT_H
 #define ANDROID_AUDIO_CLIENT_H
 
+#include <binder/Parcel.h>
 #include <system/audio.h>
 #include <utils/String16.h>
 
@@ -26,11 +27,28 @@
 class AudioClient {
  public:
     AudioClient() :
-        clientUid(-1), clientPid(-1), packageName("") {}
+        clientUid(-1), clientPid(-1), clientTid(-1), packageName("") {}
 
     uid_t clientUid;
     pid_t clientPid;
+    pid_t clientTid;
     String16 packageName;
+
+    status_t readFromParcel(Parcel *parcel) {
+        clientUid = parcel->readInt32();
+        clientPid = parcel->readInt32();
+        clientTid = parcel->readInt32();
+        packageName = parcel->readString16();
+        return NO_ERROR;
+    }
+
+    status_t writeToParcel(Parcel *parcel) const {
+        parcel->writeInt32(clientUid);
+        parcel->writeInt32(clientPid);
+        parcel->writeInt32(clientTid);
+        parcel->writeString16(packageName);
+        return NO_ERROR;
+    }
 };
 
 }; // namespace android
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index 2bd2d01..dcd4a5d 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -25,7 +25,7 @@
 #include <media/AudioResampler.h>
 #include <media/AudioResamplerPublic.h>
 #include <media/BufferProviders.h>
-#include <media/nbaio/NBLog.h>
+#include <media/nblog/NBLog.h>
 #include <system/audio.h>
 #include <utils/Compat.h>
 #include <utils/threads.h>
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index dd72170..51596a2 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -17,13 +17,16 @@
 #ifndef ANDROID_AUDIORECORD_H
 #define ANDROID_AUDIORECORD_H
 
+#include <binder/IMemory.h>
 #include <cutils/sched_policy.h>
 #include <media/AudioSystem.h>
 #include <media/AudioTimestamp.h>
-#include <media/IAudioRecord.h>
 #include <media/Modulo.h>
+#include <utils/RefBase.h>
 #include <utils/threads.h>
 
+#include "android/media/IAudioRecord.h"
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -182,7 +185,8 @@
                                     audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
                                     uid_t uid = AUDIO_UID_INVALID,
                                     pid_t pid = -1,
-                                    const audio_attributes_t* pAttributes = NULL);
+                                    const audio_attributes_t* pAttributes = NULL,
+                                    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
 
     /* Terminates the AudioRecord and unregisters it from AudioFlinger.
      * Also destroys all resources associated with the AudioRecord.
@@ -220,7 +224,8 @@
                             audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
                             uid_t uid = AUDIO_UID_INVALID,
                             pid_t pid = -1,
-                            const audio_attributes_t* pAttributes = NULL);
+                            const audio_attributes_t* pAttributes = NULL,
+                            audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
 
     /* Result of constructing the AudioRecord. This must be checked for successful initialization
      * before using any AudioRecord API (except for set()), because using
@@ -635,7 +640,7 @@
 
     // Next 5 fields may be changed if IAudioRecord is re-created, but always != 0
     // provided the initial set() was successful
-    sp<IAudioRecord>        mAudioRecord;
+    sp<media::IAudioRecord> mAudioRecord;
     sp<IMemory>             mCblkMemory;
     audio_track_cblk_t*     mCblk;              // re-load after mLock.unlock()
     sp<IMemory>             mBufferMemory;
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 5a81d83..66601da 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -106,6 +106,9 @@
 
     static float linearToLog(int volume);
     static int logToLinear(float volume);
+    static size_t calculateMinFrameCount(
+            uint32_t afLatencyMs, uint32_t afFrameCount, uint32_t afSampleRate,
+            uint32_t sampleRate, float speed /*, uint32_t notificationsPerBufferReq*/);
 
     // Returned samplingRate and frameCount output values are guaranteed
     // to be non-zero if status == NO_ERROR
@@ -209,14 +212,6 @@
     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 getOutputForAttr(const audio_attributes_t *attr,
                                      audio_io_handle_t *output,
                                      audio_session_t session,
@@ -450,6 +445,7 @@
         Vector <sp <AudioPortCallback> >    mAudioPortCallbacks;
     };
 
+    static audio_io_handle_t getOutput(audio_stream_type_t stream);
     static const sp<AudioFlingerClient> getAudioFlingerClient();
     static sp<AudioIoDescriptor> getIoDescriptor(audio_io_handle_t ioHandle);
 
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 47d87e9..9fbd04b 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -218,6 +218,8 @@
      *                     maxRequiredSpeed playback. Values less than 1.0f and greater than
      *                     AUDIO_TIMESTRETCH_SPEED_MAX will be clamped.  For non-PCM tracks
      *                     and direct or offloaded tracks, this parameter is ignored.
+     * selectedDeviceId:   Selected device id of the app which initially requested the AudioTrack
+     *                     to open with a specific device.
      * threadCanCallJava:  Not present in parameter list, and so is fixed at false.
      */
 
@@ -237,7 +239,8 @@
                                     pid_t pid = -1,
                                     const audio_attributes_t* pAttributes = NULL,
                                     bool doNotReconnect = false,
-                                    float maxRequiredSpeed = 1.0f);
+                                    float maxRequiredSpeed = 1.0f,
+                                    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
 
     /* Creates an audio track and registers it with AudioFlinger.
      * With this constructor, the track is configured for static buffer mode.
@@ -313,7 +316,8 @@
                             pid_t pid = -1,
                             const audio_attributes_t* pAttributes = NULL,
                             bool doNotReconnect = false,
-                            float maxRequiredSpeed = 1.0f);
+                            float maxRequiredSpeed = 1.0f,
+                            audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
 
     /* Result of constructing the AudioTrack. This must be checked for successful initialization
      * before using any AudioTrack API (except for set()), because using
@@ -748,12 +752,12 @@
             status_t    setParameters(const String8& keyValuePairs);
 
     /* Sets the volume shaper object */
-            VolumeShaper::Status applyVolumeShaper(
-                    const sp<VolumeShaper::Configuration>& configuration,
-                    const sp<VolumeShaper::Operation>& operation);
+            media::VolumeShaper::Status applyVolumeShaper(
+                    const sp<media::VolumeShaper::Configuration>& configuration,
+                    const sp<media::VolumeShaper::Operation>& operation);
 
     /* Gets the volume shaper state */
-            sp<VolumeShaper::State> getVolumeShaperState(int id);
+            sp<media::VolumeShaper::State> getVolumeShaperState(int id);
 
     /* Get parameters */
             String8     getParameters(const String8& keys);
@@ -990,7 +994,7 @@
     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()
+    audio_io_handle_t       mOutput;                // returned by AudioSystem::getOutputForAttr()
 
     sp<AudioTrackThread>    mAudioTrackThread;
     bool                    mThreadCanCallJava;
@@ -1160,7 +1164,7 @@
                                               // May not match the app selection depending on other
                                               // activity and connected devices.
 
-    sp<VolumeHandler>       mVolumeHandler;
+    sp<media::VolumeHandler>       mVolumeHandler;
 
 private:
     class DeathNotifier : public IBinder::DeathRecipient {
@@ -1178,7 +1182,6 @@
     pid_t                   mClientPid;
 
     wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
-    audio_port_handle_t     mPortId;  // unique ID allocated by audio policy
 };
 
 }; // namespace android
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 0ad4231..9061c26 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -24,8 +24,9 @@
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
 #include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <media/AudioClient.h>
 #include <media/IAudioTrack.h>
-#include <media/IAudioRecord.h>
 #include <media/IAudioFlingerClient.h>
 #include <system/audio.h>
 #include <system/audio_effect.h>
@@ -34,6 +35,8 @@
 #include <media/IEffectClient.h>
 #include <utils/String8.h>
 
+#include "android/media/IAudioRecord.h"
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -43,6 +46,135 @@
 public:
     DECLARE_META_INTERFACE(AudioFlinger);
 
+    /* CreateTrackInput contains all input arguments sent by AudioTrack to AudioFlinger
+     * when calling createTrack() including arguments that will be updated by AudioFlinger
+     * and returned in CreateTrackOutput object
+     */
+    class CreateTrackInput {
+    public:
+        status_t readFromParcel(Parcel *parcel) {
+            /* input arguments*/
+            memset(&attr, 0, sizeof(audio_attributes_t));
+            if (parcel->read(&attr, sizeof(audio_attributes_t)) != NO_ERROR) {
+                return DEAD_OBJECT;
+            }
+            attr.tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE -1] = '\0';
+            memset(&config, 0, sizeof(audio_config_t));
+            if (parcel->read(&config, sizeof(audio_config_t)) != NO_ERROR) {
+                return DEAD_OBJECT;
+            }
+            (void)clientInfo.readFromParcel(parcel);
+            if (parcel->readInt32() != 0) {
+                sharedBuffer = interface_cast<IMemory>(parcel->readStrongBinder());
+                if (sharedBuffer == 0 || sharedBuffer->pointer() == NULL) {
+                    return BAD_VALUE;
+                }
+            }
+            notificationsPerBuffer = parcel->readInt32();
+            speed = parcel->readFloat();
+
+            /* input/output arguments*/
+            (void)parcel->read(&flags, sizeof(audio_output_flags_t));
+            frameCount = parcel->readInt64();
+            notificationFrameCount = parcel->readInt64();
+            (void)parcel->read(&selectedDeviceId, sizeof(audio_port_handle_t));
+            (void)parcel->read(&sessionId, sizeof(audio_session_t));
+            return NO_ERROR;
+        }
+
+        status_t writeToParcel(Parcel *parcel) const {
+            /* input arguments*/
+            (void)parcel->write(&attr, sizeof(audio_attributes_t));
+            (void)parcel->write(&config, sizeof(audio_config_t));
+            (void)clientInfo.writeToParcel(parcel);
+            if (sharedBuffer != 0) {
+                (void)parcel->writeInt32(1);
+                (void)parcel->writeStrongBinder(IInterface::asBinder(sharedBuffer));
+            } else {
+                (void)parcel->writeInt32(0);
+            }
+            (void)parcel->writeInt32(notificationsPerBuffer);
+            (void)parcel->writeFloat(speed);
+
+            /* input/output arguments*/
+            (void)parcel->write(&flags, sizeof(audio_output_flags_t));
+            (void)parcel->writeInt64(frameCount);
+            (void)parcel->writeInt64(notificationFrameCount);
+            (void)parcel->write(&selectedDeviceId, sizeof(audio_port_handle_t));
+            (void)parcel->write(&sessionId, sizeof(audio_session_t));
+            return NO_ERROR;
+        }
+
+        /* input */
+        audio_attributes_t attr;
+        audio_config_t config;
+        AudioClient clientInfo;
+        sp<IMemory> sharedBuffer;
+        uint32_t notificationsPerBuffer;
+        float speed;
+
+        /* input/output */
+        audio_output_flags_t flags;
+        size_t frameCount;
+        size_t notificationFrameCount;
+        audio_port_handle_t selectedDeviceId;
+        audio_session_t sessionId;
+    };
+
+    /* CreateTrackOutput contains all output arguments returned by AudioFlinger to AudioTrack
+     * when calling createTrack() including arguments that were passed as I/O for update by
+     * CreateTrackInput.
+     */
+    class CreateTrackOutput {
+    public:
+        status_t readFromParcel(Parcel *parcel) {
+            /* input/output arguments*/
+            (void)parcel->read(&flags, sizeof(audio_output_flags_t));
+            frameCount = parcel->readInt64();
+            notificationFrameCount = parcel->readInt64();
+            (void)parcel->read(&selectedDeviceId, sizeof(audio_port_handle_t));
+            (void)parcel->read(&sessionId, sizeof(audio_session_t));
+
+            /* output arguments*/
+            sampleRate = parcel->readUint32();
+            afFrameCount = parcel->readInt64();
+            afSampleRate = parcel->readInt64();
+            afLatencyMs = parcel->readInt32();
+            (void)parcel->read(&outputId, sizeof(audio_io_handle_t));
+            return NO_ERROR;
+        }
+
+        status_t writeToParcel(Parcel *parcel) const {
+            /* input/output arguments*/
+            (void)parcel->write(&flags, sizeof(audio_output_flags_t));
+            (void)parcel->writeInt64(frameCount);
+            (void)parcel->writeInt64(notificationFrameCount);
+            (void)parcel->write(&selectedDeviceId, sizeof(audio_port_handle_t));
+            (void)parcel->write(&sessionId, sizeof(audio_session_t));
+
+            /* output arguments*/
+            (void)parcel->writeUint32(sampleRate);
+            (void)parcel->writeInt64(afFrameCount);
+            (void)parcel->writeInt64(afSampleRate);
+            (void)parcel->writeInt32(afLatencyMs);
+            (void)parcel->write(&outputId, sizeof(audio_io_handle_t));
+            return NO_ERROR;
+        }
+
+        /* input/output */
+        audio_output_flags_t flags;
+        size_t frameCount;
+        size_t notificationFrameCount;
+        audio_port_handle_t selectedDeviceId;
+        audio_session_t sessionId;
+
+        /* output */
+        uint32_t sampleRate;
+        size_t   afFrameCount;
+        uint32_t afSampleRate;
+        uint32_t afLatencyMs;
+        audio_io_handle_t outputId;
+    };
 
     // invariant on exit for all APIs that return an sp<>:
     //   (return value != 0) == (*status == NO_ERROR)
@@ -50,26 +182,11 @@
     /* create an audio track and registers it with AudioFlinger.
      * return null if the track cannot be created.
      */
-    virtual sp<IAudioTrack> createTrack(
-                                audio_stream_type_t streamType,
-                                uint32_t sampleRate,
-                                audio_format_t format,
-                                audio_channel_mask_t channelMask,
-                                size_t *pFrameCount,
-                                audio_output_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 pid,
-                                pid_t tid,  // -1 means unused, otherwise must be valid non-0
-                                audio_session_t *sessionId,
-                                int clientUid,
-                                status_t *status,
-                                audio_port_handle_t portId) = 0;
+    virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
+                                        CreateTrackOutput& output,
+                                        status_t *status) = 0;
 
-    virtual sp<IAudioRecord> openRecord(
+    virtual sp<media::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.
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 9b3e35e..7c88e57 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -55,12 +55,7 @@
     virtual status_t setForceUse(audio_policy_force_use_t usage,
                                     audio_policy_forced_cfg_t config) = 0;
     virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) = 0;
-    virtual 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 = 0,
-                                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
-                                        const audio_offload_info_t *offloadInfo = NULL) = 0;
+    virtual audio_io_handle_t getOutput(audio_stream_type_t stream) = 0;
     virtual status_t getOutputForAttr(const audio_attributes_t *attr,
                                       audio_io_handle_t *output,
                                       audio_session_t session,
diff --git a/media/libaudioclient/include/media/IAudioRecord.h b/media/libaudioclient/include/media/IAudioRecord.h
deleted file mode 100644
index 7768176..0000000
--- a/media/libaudioclient/include/media/IAudioRecord.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IAUDIORECORD_H_
-#define IAUDIORECORD_H_
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-#include <binder/IMemory.h>
-#include <system/audio.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class IAudioRecord : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(AudioRecord);
-
-    /* After it's created the track is not active. Call start() to
-     * make it active.
-     */
-    virtual status_t    start(int /*AudioSystem::sync_event_t*/ event,
-                              audio_session_t triggerSession) = 0;
-
-    /* Stop a track. If set, the callback will cease being called and
-     * obtainBuffer will return an error. Buffers that are already released
-     * will be processed, unless flush() is called.
-     */
-    virtual void        stop() = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnAudioRecord : public BnInterface<IAudioRecord>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif /*IAUDIORECORD_H_*/
diff --git a/media/libaudioclient/include/media/IAudioTrack.h b/media/libaudioclient/include/media/IAudioTrack.h
index 27a62d6..94afe3c 100644
--- a/media/libaudioclient/include/media/IAudioTrack.h
+++ b/media/libaudioclient/include/media/IAudioTrack.h
@@ -77,12 +77,12 @@
     virtual void        signal() = 0;
 
     /* Sets the volume shaper */
-    virtual VolumeShaper::Status applyVolumeShaper(
-            const sp<VolumeShaper::Configuration>& configuration,
-            const sp<VolumeShaper::Operation>& operation) = 0;
+    virtual media::VolumeShaper::Status applyVolumeShaper(
+            const sp<media::VolumeShaper::Configuration>& configuration,
+            const sp<media::VolumeShaper::Operation>& operation) = 0;
 
     /* gets the volume shaper state */
-    virtual sp<VolumeShaper::State> getVolumeShaperState(int id) = 0;
+    virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/libaudioclient/include/media/PlayerBase.h b/media/libaudioclient/include/media/PlayerBase.h
index e63090b..e7a8abc 100644
--- a/media/libaudioclient/include/media/PlayerBase.h
+++ b/media/libaudioclient/include/media/PlayerBase.h
@@ -17,35 +17,31 @@
 #ifndef __ANDROID_PLAYER_BASE_H__
 #define __ANDROID_PLAYER_BASE_H__
 
-#include <audiomanager/IPlayer.h>
 #include <audiomanager/AudioManager.h>
 #include <audiomanager/IAudioManager.h>
 
+#include "android/media/BnPlayer.h"
 
 namespace android {
 
-class PlayerBase : public BnPlayer
+class PlayerBase : public ::android::media::BnPlayer
 {
 public:
     explicit PlayerBase();
-    virtual ~PlayerBase();
+    virtual ~PlayerBase() override;
 
     virtual void destroy() = 0;
 
     //IPlayer implementation
-    virtual void start();
-    virtual void pause();
-    virtual void stop();
-    virtual void setVolume(float vol);
-    virtual void setPan(float pan);
-    virtual void setStartDelayMs(int32_t delayMs);
-    virtual void applyVolumeShaper(
-            const sp<VolumeShaper::Configuration>& configuration,
-            const sp<VolumeShaper::Operation>& operation) override;
-
-    virtual status_t onTransact(
-                uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
-
+    virtual binder::Status start() override;
+    virtual binder::Status pause() override;
+    virtual binder::Status stop() override;
+    virtual binder::Status setVolume(float vol) override;
+    virtual binder::Status setPan(float pan) override;
+    virtual binder::Status setStartDelayMs(int32_t delayMs) override;
+    virtual binder::Status applyVolumeShaper(
+            const media::VolumeShaper::Configuration& configuration,
+            const media::VolumeShaper::Operation& operation) override;
 
             status_t startWithStatus();
             status_t pauseWithStatus();
diff --git a/media/libaudioclient/include/media/TrackPlayerBase.h b/media/libaudioclient/include/media/TrackPlayerBase.h
index 2d113c0..66e9b3b 100644
--- a/media/libaudioclient/include/media/TrackPlayerBase.h
+++ b/media/libaudioclient/include/media/TrackPlayerBase.h
@@ -32,9 +32,9 @@
     virtual void destroy();
 
     //IPlayer implementation
-    virtual void applyVolumeShaper(
-            const sp<VolumeShaper::Configuration>& configuration,
-            const sp<VolumeShaper::Operation>& operation);
+    virtual binder::Status applyVolumeShaper(
+            const media::VolumeShaper::Configuration& configuration,
+            const media::VolumeShaper::Operation& operation);
 
     //FIXME move to protected field, so far made public to minimize changes to AudioTrack logic
     sp<AudioTrack> mAudioTrack;
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
new file mode 100644
index 0000000..700de8e
--- /dev/null
+++ b/media/libaudiohal/Android.bp
@@ -0,0 +1,47 @@
+cc_library_shared {
+    name: "libaudiohal",
+
+    srcs: [
+        "DeviceHalLocal.cpp",
+        "DevicesFactoryHalHybrid.cpp",
+        "DevicesFactoryHalLocal.cpp",
+        "StreamHalLocal.cpp",
+
+        "ConversionHelperHidl.cpp",
+        "HalDeathHandlerHidl.cpp",
+        "DeviceHalHidl.cpp",
+        "DevicesFactoryHalHidl.cpp",
+        "EffectBufferHalHidl.cpp",
+        "EffectHalHidl.cpp",
+        "EffectsFactoryHalHidl.cpp",
+        "StreamHalHidl.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    export_include_dirs: ["include"],
+
+    shared_libs: [
+        "libaudioutils",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libhardware",
+        "libbase",
+        "libfmq",
+        "libhwbinder",
+        "libhidlbase",
+        "libhidlmemory",
+        "libhidltransport",
+        "android.hardware.audio@2.0",
+        "android.hardware.audio.common@2.0",
+        "android.hardware.audio.common@2.0-util",
+        "android.hardware.audio.effect@2.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libmedia_helper",
+        "libmediautils",
+    ],
+}
diff --git a/media/libaudiohal/Android.mk b/media/libaudiohal/Android.mk
deleted file mode 100644
index 827908e..0000000
--- a/media/libaudiohal/Android.mk
+++ /dev/null
@@ -1,71 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SHARED_LIBRARIES := \
-    libaudioutils \
-    libcutils   \
-    liblog      \
-    libutils    \
-    libhardware
-
-LOCAL_SRC_FILES := \
-    DeviceHalLocal.cpp          \
-    DevicesFactoryHalHybrid.cpp \
-    DevicesFactoryHalLocal.cpp  \
-    StreamHalLocal.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-ifeq ($(USE_LEGACY_LOCAL_AUDIO_HAL), true)
-
-# Use audiohal directly w/o hwbinder middleware.
-# This is for performance comparison and debugging only.
-
-LOCAL_SRC_FILES += \
-    EffectBufferHalLocal.cpp    \
-    EffectsFactoryHalLocal.cpp  \
-    EffectHalLocal.cpp
-
-LOCAL_SHARED_LIBRARIES += \
-    libeffects
-
-LOCAL_CFLAGS += -DUSE_LEGACY_LOCAL_AUDIO_HAL
-
-else  # if !USE_LEGACY_LOCAL_AUDIO_HAL
-
-LOCAL_SRC_FILES += \
-    ConversionHelperHidl.cpp   \
-    HalDeathHandlerHidl.cpp    \
-    DeviceHalHidl.cpp          \
-    DevicesFactoryHalHidl.cpp  \
-    EffectBufferHalHidl.cpp    \
-    EffectHalHidl.cpp          \
-    EffectsFactoryHalHidl.cpp  \
-    StreamHalHidl.cpp
-
-LOCAL_SHARED_LIBRARIES += \
-    libbase          \
-    libfmq           \
-    libhwbinder      \
-    libhidlbase      \
-    libhidlmemory    \
-    libhidltransport \
-    android.hardware.audio@2.0             \
-    android.hardware.audio.common@2.0      \
-    android.hardware.audio.common@2.0-util \
-    android.hardware.audio.effect@2.0      \
-    android.hidl.allocator@1.0             \
-    android.hidl.memory@1.0                \
-    libmedia_helper  \
-    libmediautils
-
-endif  # USE_LEGACY_LOCAL_AUDIO_HAL
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-LOCAL_MODULE := libaudiohal
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libaudiohal/DevicesFactoryHalHidl.cpp b/media/libaudiohal/DevicesFactoryHalHidl.cpp
index 31da263..5b33592 100644
--- a/media/libaudiohal/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/DevicesFactoryHalHidl.cpp
@@ -43,6 +43,9 @@
         ALOGE("Failed to obtain IDevicesFactory service, terminating process.");
         exit(1);
     }
+    // The MSD factory is optional
+    mDevicesFactoryMsd = IDevicesFactory::getService(AUDIO_HAL_SERVICE_NAME_MSD);
+    // TODO: Register death handler, and add 'restart' directive to audioserver.rc
 }
 
 DevicesFactoryHalHidl::~DevicesFactoryHalHidl() {
diff --git a/media/libaudiohal/DevicesFactoryHalHidl.h b/media/libaudiohal/DevicesFactoryHalHidl.h
index e2f1ad1..0748849 100644
--- a/media/libaudiohal/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/DevicesFactoryHalHidl.h
@@ -39,6 +39,7 @@
     friend class DevicesFactoryHalHybrid;
 
     sp<IDevicesFactory> mDevicesFactory;
+    sp<IDevicesFactory> mDevicesFactoryMsd;
 
     static status_t nameFromHal(const char *name, IDevicesFactory::Device *device);
 
diff --git a/media/libaudiohal/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/DevicesFactoryHalHybrid.cpp
index 454b03b..8dc1434 100644
--- a/media/libaudiohal/DevicesFactoryHalHybrid.cpp
+++ b/media/libaudiohal/DevicesFactoryHalHybrid.cpp
@@ -19,9 +19,7 @@
 
 #include "DevicesFactoryHalHybrid.h"
 #include "DevicesFactoryHalLocal.h"
-#ifndef USE_LEGACY_LOCAL_AUDIO_HAL
 #include "DevicesFactoryHalHidl.h"
-#endif
 
 namespace android {
 
@@ -32,13 +30,7 @@
 
 DevicesFactoryHalHybrid::DevicesFactoryHalHybrid()
         : mLocalFactory(new DevicesFactoryHalLocal()),
-          mHidlFactory(
-#ifdef USE_LEGACY_LOCAL_AUDIO_HAL
-                  nullptr
-#else
-                  new DevicesFactoryHalHidl()
-#endif
-                       ) {
+          mHidlFactory(new DevicesFactoryHalHidl()) {
 }
 
 DevicesFactoryHalHybrid::~DevicesFactoryHalHybrid() {
diff --git a/media/libaudiohal/EffectBufferHalHidl.h b/media/libaudiohal/EffectBufferHalHidl.h
index 66a81c2..d7a43ae 100644
--- a/media/libaudiohal/EffectBufferHalHidl.h
+++ b/media/libaudiohal/EffectBufferHalHidl.h
@@ -35,6 +35,8 @@
     virtual audio_buffer_t* audioBuffer();
     virtual void* externalData() const;
 
+    virtual size_t getSize() const override { return mBufferSize; }
+
     virtual void setExternalData(void* external);
     virtual void setFrameCount(size_t frameCount);
     virtual bool checkFrameCountChange();
diff --git a/media/libaudiohal/EffectBufferHalLocal.cpp b/media/libaudiohal/EffectBufferHalLocal.cpp
deleted file mode 100644
index 7951c8e..0000000
--- a/media/libaudiohal/EffectBufferHalLocal.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "EffectBufferHalLocal"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-
-#include "EffectBufferHalLocal.h"
-
-namespace android {
-
-// static
-status_t EffectBufferHalInterface::allocate(
-        size_t size, sp<EffectBufferHalInterface>* buffer) {
-    *buffer = new EffectBufferHalLocal(size);
-    return OK;
-}
-
-// static
-status_t EffectBufferHalInterface::mirror(
-        void* external, size_t size, sp<EffectBufferHalInterface>* buffer) {
-    *buffer = new EffectBufferHalLocal(external, size);
-    return OK;
-}
-
-EffectBufferHalLocal::EffectBufferHalLocal(size_t size)
-        : mOwnBuffer(new uint8_t[size]),
-          mBufferSize(size), mFrameCountChanged(false),
-          mAudioBuffer{0, {mOwnBuffer.get()}} {
-}
-
-EffectBufferHalLocal::EffectBufferHalLocal(void* external, size_t size)
-        : mOwnBuffer(nullptr),
-          mBufferSize(size), mFrameCountChanged(false),
-          mAudioBuffer{0, {external}} {
-}
-
-EffectBufferHalLocal::~EffectBufferHalLocal() {
-}
-
-audio_buffer_t* EffectBufferHalLocal::audioBuffer() {
-    return &mAudioBuffer;
-}
-
-void* EffectBufferHalLocal::externalData() const {
-    return mAudioBuffer.raw;
-}
-
-void EffectBufferHalLocal::setFrameCount(size_t frameCount) {
-    mAudioBuffer.frameCount = frameCount;
-    mFrameCountChanged = true;
-}
-
-void EffectBufferHalLocal::setExternalData(void* external) {
-    ALOGE_IF(mOwnBuffer != nullptr, "Attempt to set external data for allocated buffer");
-    mAudioBuffer.raw = external;
-}
-
-bool EffectBufferHalLocal::checkFrameCountChange() {
-    bool result = mFrameCountChanged;
-    mFrameCountChanged = false;
-    return result;
-}
-
-void EffectBufferHalLocal::update() {
-}
-
-void EffectBufferHalLocal::commit() {
-}
-
-void EffectBufferHalLocal::update(size_t) {
-}
-
-void EffectBufferHalLocal::commit(size_t) {
-}
-
-} // namespace android
diff --git a/media/libaudiohal/EffectBufferHalLocal.h b/media/libaudiohal/EffectBufferHalLocal.h
deleted file mode 100644
index d2b624b..0000000
--- a/media/libaudiohal/EffectBufferHalLocal.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_EFFECT_BUFFER_HAL_LOCAL_H
-#define ANDROID_HARDWARE_EFFECT_BUFFER_HAL_LOCAL_H
-
-#include <memory>
-
-#include <media/audiohal/EffectBufferHalInterface.h>
-#include <system/audio_effect.h>
-
-namespace android {
-
-class EffectBufferHalLocal : public EffectBufferHalInterface
-{
-  public:
-    virtual audio_buffer_t* audioBuffer();
-    virtual void* externalData() const;
-
-    virtual void setExternalData(void* external);
-    virtual void setFrameCount(size_t frameCount);
-    virtual bool checkFrameCountChange();
-
-    virtual void update();
-    virtual void commit();
-    virtual void update(size_t size);
-    virtual void commit(size_t size);
-
-  private:
-    friend class EffectBufferHalInterface;
-
-    std::unique_ptr<uint8_t[]> mOwnBuffer;
-    const size_t mBufferSize;
-    bool mFrameCountChanged;
-    audio_buffer_t mAudioBuffer;
-
-    // Can not be constructed directly by clients.
-    explicit EffectBufferHalLocal(size_t size);
-    EffectBufferHalLocal(void* external, size_t size);
-
-    virtual ~EffectBufferHalLocal();
-
-    status_t init();
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_EFFECT_BUFFER_HAL_LOCAL_H
diff --git a/media/libaudiohal/EffectHalLocal.cpp b/media/libaudiohal/EffectHalLocal.cpp
deleted file mode 100644
index dd465c3..0000000
--- a/media/libaudiohal/EffectHalLocal.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "EffectHalLocal"
-//#define LOG_NDEBUG 0
-
-#include <media/EffectsFactoryApi.h>
-#include <utils/Log.h>
-
-#include "EffectHalLocal.h"
-
-namespace android {
-
-EffectHalLocal::EffectHalLocal(effect_handle_t handle)
-        : mHandle(handle) {
-}
-
-EffectHalLocal::~EffectHalLocal() {
-    int status = EffectRelease(mHandle);
-    ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
-    mHandle = 0;
-}
-
-status_t EffectHalLocal::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
-    mInBuffer = buffer;
-    return OK;
-}
-
-status_t EffectHalLocal::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
-    mOutBuffer = buffer;
-    return OK;
-}
-
-status_t EffectHalLocal::process() {
-    if (mInBuffer == nullptr || mOutBuffer == nullptr) {
-        ALOGE_IF(mInBuffer == nullptr, "Input buffer not set");
-        ALOGE_IF(mOutBuffer == nullptr, "Output buffer not set");
-        return NO_INIT;
-    }
-    return (*mHandle)->process(mHandle, mInBuffer->audioBuffer(), mOutBuffer->audioBuffer());
-}
-
-status_t EffectHalLocal::processReverse() {
-    if ((*mHandle)->process_reverse != NULL) {
-        if (mInBuffer == nullptr || mOutBuffer == nullptr) {
-            ALOGE_IF(mInBuffer == nullptr, "Input buffer not set");
-            ALOGE_IF(mOutBuffer == nullptr, "Output buffer not set");
-            return NO_INIT;
-        }
-        return (*mHandle)->process_reverse(
-                mHandle, mInBuffer->audioBuffer(), mOutBuffer->audioBuffer());
-    } else {
-        return INVALID_OPERATION;
-    }
-}
-
-status_t EffectHalLocal::command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
-        uint32_t *replySize, void *pReplyData) {
-    return (*mHandle)->command(mHandle, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
-}
-
-status_t EffectHalLocal::getDescriptor(effect_descriptor_t *pDescriptor) {
-    return (*mHandle)->get_descriptor(mHandle, pDescriptor);
-}
-
-status_t EffectHalLocal::close() {
-    return OK;
-}
-
-} // namespace android
diff --git a/media/libaudiohal/EffectHalLocal.h b/media/libaudiohal/EffectHalLocal.h
deleted file mode 100644
index 693fb50..0000000
--- a/media/libaudiohal/EffectHalLocal.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_EFFECT_HAL_LOCAL_H
-#define ANDROID_HARDWARE_EFFECT_HAL_LOCAL_H
-
-#include <hardware/audio_effect.h>
-#include <media/audiohal/EffectHalInterface.h>
-
-namespace android {
-
-class EffectHalLocal : public EffectHalInterface
-{
-  public:
-    // Set the input buffer.
-    virtual status_t setInBuffer(const sp<EffectBufferHalInterface>& buffer);
-
-    // Set the output buffer.
-    virtual status_t setOutBuffer(const sp<EffectBufferHalInterface>& buffer);
-
-    // Effect process function.
-    virtual status_t process();
-
-    // Process reverse stream function. This function is used to pass
-    // a reference stream to the effect engine.
-    virtual status_t processReverse();
-
-    // Send a command and receive a response to/from effect engine.
-    virtual status_t command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
-            uint32_t *replySize, void *pReplyData);
-
-    // Returns the effect descriptor.
-    virtual status_t getDescriptor(effect_descriptor_t *pDescriptor);
-
-    // Free resources on the remote side.
-    virtual status_t close();
-
-    // Whether it's a local implementation.
-    virtual bool isLocal() const { return true; }
-
-    effect_handle_t handle() const { return mHandle; }
-
-  private:
-    effect_handle_t mHandle;
-    sp<EffectBufferHalInterface> mInBuffer;
-    sp<EffectBufferHalInterface> mOutBuffer;
-
-    friend class EffectsFactoryHalLocal;
-
-    // Can not be constructed directly by clients.
-    explicit EffectHalLocal(effect_handle_t handle);
-
-    // The destructor automatically releases the effect.
-    virtual ~EffectHalLocal();
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_EFFECT_HAL_LOCAL_H
diff --git a/media/libaudiohal/EffectsFactoryHalLocal.cpp b/media/libaudiohal/EffectsFactoryHalLocal.cpp
deleted file mode 100644
index bbdef5d..0000000
--- a/media/libaudiohal/EffectsFactoryHalLocal.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <media/EffectsFactoryApi.h>
-
-#include "EffectHalLocal.h"
-#include "EffectsFactoryHalLocal.h"
-
-namespace android {
-
-// static
-sp<EffectsFactoryHalInterface> EffectsFactoryHalInterface::create() {
-    return new EffectsFactoryHalLocal();
-}
-
-// static
-bool EffectsFactoryHalInterface::isNullUuid(const effect_uuid_t *pEffectUuid) {
-    return EffectIsNullUuid(pEffectUuid);
-}
-
-status_t EffectsFactoryHalLocal::queryNumberEffects(uint32_t *pNumEffects) {
-    return EffectQueryNumberEffects(pNumEffects);
-}
-
-status_t EffectsFactoryHalLocal::getDescriptor(
-        uint32_t index, effect_descriptor_t *pDescriptor) {
-    return EffectQueryEffect(index, pDescriptor);
-}
-
-status_t EffectsFactoryHalLocal::getDescriptor(
-        const effect_uuid_t *pEffectUuid, effect_descriptor_t *pDescriptor) {
-    return EffectGetDescriptor(pEffectUuid, pDescriptor);
-}
-
-status_t EffectsFactoryHalLocal::createEffect(
-        const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t ioId,
-        sp<EffectHalInterface> *effect) {
-    effect_handle_t handle;
-    int result = EffectCreate(pEffectUuid, sessionId, ioId, &handle);
-    if (result == 0) {
-        *effect = new EffectHalLocal(handle);
-    }
-    return result;
-}
-
-status_t EffectsFactoryHalLocal::dumpEffects(int fd) {
-    return EffectDumpEffects(fd);
-}
-
-} // namespace android
diff --git a/media/libaudiohal/EffectsFactoryHalLocal.h b/media/libaudiohal/EffectsFactoryHalLocal.h
deleted file mode 100644
index d5b81be..0000000
--- a/media/libaudiohal/EffectsFactoryHalLocal.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_LOCAL_H
-#define ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_LOCAL_H
-
-#include <media/audiohal/EffectsFactoryHalInterface.h>
-
-namespace android {
-
-class EffectsFactoryHalLocal : public EffectsFactoryHalInterface
-{
-  public:
-    // Returns the number of different effects in all loaded libraries.
-    virtual status_t queryNumberEffects(uint32_t *pNumEffects);
-
-    // Returns a descriptor of the next available effect.
-    virtual status_t getDescriptor(uint32_t index,
-            effect_descriptor_t *pDescriptor);
-
-    virtual status_t getDescriptor(const effect_uuid_t *pEffectUuid,
-            effect_descriptor_t *pDescriptor);
-
-    // Creates an effect engine of the specified type.
-    // To release the effect engine, it is necessary to release references
-    // to the returned effect object.
-    virtual status_t createEffect(const effect_uuid_t *pEffectUuid,
-            int32_t sessionId, int32_t ioId,
-            sp<EffectHalInterface> *effect);
-
-    virtual status_t dumpEffects(int fd);
-
-  private:
-    friend class EffectsFactoryHalInterface;
-
-    // Can not be constructed directly by clients.
-    EffectsFactoryHalLocal() {}
-
-    virtual ~EffectsFactoryHalLocal() {}
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_LOCAL_H
diff --git a/media/libaudiohal/HalDeathHandlerHidl.cpp b/media/libaudiohal/HalDeathHandlerHidl.cpp
index a742671..1e3ab58 100644
--- a/media/libaudiohal/HalDeathHandlerHidl.cpp
+++ b/media/libaudiohal/HalDeathHandlerHidl.cpp
@@ -48,12 +48,13 @@
 
 void HalDeathHandler::serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) {
     // No matter which of the service objects has died,
-    // we need to run all the registered handlers and crash our process.
+    // we need to run all the registered handlers and exit.
     std::lock_guard<std::mutex> guard(mHandlersLock);
     for (const auto& handler : mHandlers) {
         handler.second();
     }
-    LOG_ALWAYS_FATAL("HAL server crashed, need to restart");
+    ALOGE("HAL server crashed, audio server is restarting");
+    exit(1);
 }
 
 } // namespace android
diff --git a/media/libaudiohal/StreamHalLocal.cpp b/media/libaudiohal/StreamHalLocal.cpp
index dc17f5c..8d61e24 100644
--- a/media/libaudiohal/StreamHalLocal.cpp
+++ b/media/libaudiohal/StreamHalLocal.cpp
@@ -21,7 +21,6 @@
 #include <utils/Log.h>
 
 #include "DeviceHalLocal.h"
-#include "EffectHalLocal.h"
 #include "StreamHalLocal.h"
 
 namespace android {
@@ -86,16 +85,14 @@
     return OK;
 }
 
-status_t StreamHalLocal::addEffect(sp<EffectHalInterface> effect) {
-    LOG_ALWAYS_FATAL_IF(!effect->isLocal(), "Only local effects can be added for a local stream");
-    return mStream->add_audio_effect(mStream,
-            static_cast<EffectHalLocal*>(effect.get())->handle());
+status_t StreamHalLocal::addEffect(sp<EffectHalInterface>) {
+    LOG_ALWAYS_FATAL("Local streams can not have effects");
+    return INVALID_OPERATION;
 }
 
-status_t StreamHalLocal::removeEffect(sp<EffectHalInterface> effect) {
-    LOG_ALWAYS_FATAL_IF(!effect->isLocal(), "Only local effects can be removed for a local stream");
-    return mStream->remove_audio_effect(mStream,
-            static_cast<EffectHalLocal*>(effect.get())->handle());
+status_t StreamHalLocal::removeEffect(sp<EffectHalInterface>) {
+    LOG_ALWAYS_FATAL("Local streams can not have effects");
+    return INVALID_OPERATION;
 }
 
 status_t StreamHalLocal::standby() {
diff --git a/media/libaudiohal/include/media/audiohal/EffectBufferHalInterface.h b/media/libaudiohal/include/media/audiohal/EffectBufferHalInterface.h
index e862f6e..1cae662 100644
--- a/media/libaudiohal/include/media/audiohal/EffectBufferHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/EffectBufferHalInterface.h
@@ -37,6 +37,8 @@
         return externalData() != nullptr ? externalData() : audioBuffer()->raw;
     }
 
+    virtual size_t getSize() const = 0;
+
     virtual void setExternalData(void* external) = 0;
     virtual void setFrameCount(size_t frameCount) = 0;
     virtual bool checkFrameCountChange() = 0;  // returns whether frame count has been updated
diff --git a/media/libaudioprocessing/Android.mk b/media/libaudioprocessing/Android.mk
index c850984..da1ecc2 100644
--- a/media/libaudioprocessing/Android.mk
+++ b/media/libaudioprocessing/Android.mk
@@ -24,6 +24,7 @@
     libcutils \
     liblog \
     libnbaio \
+    libnblog \
     libsonic \
     libutils \
 
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index 238925d..43b97a5 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -813,7 +813,7 @@
                 mMixerInFormat, sampleRate, playbackRate);
         reconfigureBufferProviders();
     } else {
-        reinterpret_cast<TimestretchBufferProvider*>(mTimestretchBufferProvider)
+        static_cast<TimestretchBufferProvider*>(mTimestretchBufferProvider)
                 ->setPlaybackRate(playbackRate);
     }
     return true;
@@ -1947,11 +1947,10 @@
     case AUDIO_FORMAT_PCM_16_BIT:
         switch (mixerOutFormat) {
         case AUDIO_FORMAT_PCM_FLOAT:
-            memcpy_to_float_from_q4_27((float*)out, (int32_t*)in, sampleCount);
+            memcpy_to_float_from_q4_27((float*)out, (const int32_t*)in, sampleCount);
             break;
         case AUDIO_FORMAT_PCM_16_BIT:
-            // two int16_t are produced per iteration
-            ditherAndClamp((int32_t*)out, (int32_t*)in, sampleCount >> 1);
+            memcpy_to_i16_from_q4_27((int16_t*)out, (const int32_t*)in, sampleCount);
             break;
         default:
             LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat);
diff --git a/media/libaudioprocessing/AudioResamplerDyn.cpp b/media/libaudioprocessing/AudioResamplerDyn.cpp
index 8f7b982..eeeecce 100644
--- a/media/libaudioprocessing/AudioResamplerDyn.cpp
+++ b/media/libaudioprocessing/AudioResamplerDyn.cpp
@@ -38,6 +38,9 @@
 
 //#define DEBUG_RESAMPLER
 
+// use this for our buffer alignment.  Should be at least 32 bytes.
+constexpr size_t CACHE_LINE_SIZE = 64;
+
 namespace android {
 
 /*
@@ -94,7 +97,10 @@
 
     // create new buffer
     TI* state = NULL;
-    (void)posix_memalign(reinterpret_cast<void**>(&state), 32, stateCount*sizeof(*state));
+    (void)posix_memalign(
+            reinterpret_cast<void **>(&state),
+            CACHE_LINE_SIZE /* alignment */,
+            stateCount * sizeof(*state));
     memset(state, 0, stateCount*sizeof(*state));
 
     // attempt to preserve state
@@ -185,6 +191,16 @@
     // setSampleRate() for 1:1. (May be removed if precalculated filters are used.)
     mInSampleRate = 0;
     mConstants.set(128, 8, mSampleRate, mSampleRate); // TODO: set better
+
+    // fetch property based resampling parameters
+    mPropertyEnableAtSampleRate = property_get_int32(
+            "ro.audio.resampler.psd.enable_at_samplerate", mPropertyEnableAtSampleRate);
+    mPropertyHalfFilterLength = property_get_int32(
+            "ro.audio.resampler.psd.halflength", mPropertyHalfFilterLength);
+    mPropertyStopbandAttenuation = property_get_int32(
+            "ro.audio.resampler.psd.stopband", mPropertyStopbandAttenuation);
+    mPropertyCutoffPercent = property_get_int32(
+            "ro.audio.resampler.psd.cutoff_percent", mPropertyCutoffPercent);
 }
 
 template<typename TC, typename TI, typename TO>
@@ -215,6 +231,8 @@
     }
 }
 
+// TODO: update to C++11
+
 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;}
@@ -223,37 +241,74 @@
 void AudioResamplerDyn<TC, TI, TO>::createKaiserFir(Constants &c,
         double stopBandAtten, int inSampleRate, int outSampleRate, double tbwCheat)
 {
-    TC* buf = NULL;
-    static const double atten = 0.9998;   // to avoid ripple overflow
-    double fcr;
-    double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
+    // compute the normalized transition bandwidth
+    const double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
+    const double halfbw = tbw / 2.;
 
-    (void)posix_memalign(reinterpret_cast<void**>(&buf), 32, (c.mL+1)*c.mHalfNumCoefs*sizeof(TC));
+    double fcr; // compute fcr, the 3 dB amplitude cut-off.
     if (inSampleRate < outSampleRate) { // upsample
-        fcr = max(0.5*tbwCheat - tbw/2, tbw/2);
+        fcr = max(0.5 * tbwCheat - halfbw, halfbw);
     } else { // downsample
-        fcr = max(0.5*tbwCheat*outSampleRate/inSampleRate - tbw/2, tbw/2);
+        fcr = max(0.5 * tbwCheat * outSampleRate / inSampleRate - halfbw, halfbw);
     }
-    // create and set filter
-    firKaiserGen(buf, c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten);
-    c.mFirCoefs = buf;
-    if (mCoefBuffer) {
-        free(mCoefBuffer);
-    }
-    mCoefBuffer = buf;
-#ifdef DEBUG_RESAMPLER
+    createKaiserFir(c, stopBandAtten, fcr);
+}
+
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::createKaiserFir(Constants &c,
+        double stopBandAtten, double fcr) {
+    // compute the normalized transition bandwidth
+    const double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
+    const int phases = c.mL;
+    const int halfLength = c.mHalfNumCoefs;
+
+    // create buffer
+    TC *coefs = nullptr;
+    int ret = posix_memalign(
+            reinterpret_cast<void **>(&coefs),
+            CACHE_LINE_SIZE /* alignment */,
+            (phases + 1) * halfLength * sizeof(TC));
+    LOG_ALWAYS_FATAL_IF(ret != 0, "Cannot allocate buffer memory, ret %d", ret);
+    c.mFirCoefs = coefs;
+    free(mCoefBuffer);
+    mCoefBuffer = coefs;
+
+    // square the computed minimum passband value (extra safety).
+    double attenuation =
+            computeWindowedSincMinimumPassbandValue(stopBandAtten);
+    attenuation *= attenuation;
+
+    // design filter
+    firKaiserGen(coefs, phases, halfLength, stopBandAtten, fcr, attenuation);
+
+    // update the design criteria
+    mNormalizedCutoffFrequency = fcr;
+    mNormalizedTransitionBandwidth = tbw;
+    mFilterAttenuation = attenuation;
+    mStopbandAttenuationDb = stopBandAtten;
+    mPassbandRippleDb = computeWindowedSincPassbandRippleDb(stopBandAtten);
+
+#if 0
+    // Keep this debug code in case an app causes resampler design issues.
+    const double halfbw = tbw / 2.;
     // 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;
+    ALOGD("L:%d  hnc:%d  stopBandAtten:%lf  fcr:%lf  atten:%lf  tbw:%lf\n",
+            c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, attenuation, tbw);
+
+    // test the filter and report results.
+    // Since this is a polyphase filter, normalized fp and fs must be scaled.
+    const double fp = (fcr - halfbw) / phases;
+    const double fs = (fcr + halfbw) / phases;
+
     double passMin, passMax, passRipple;
     double stopMax, stopRipple;
-    testFir(buf, c.mL, c.mHalfNumCoefs, fp, fs, /*passSteps*/ 1000, /*stopSteps*/ 100000,
+
+    const int32_t passSteps = 1000;
+
+    testFir(coefs, c.mL, c.mHalfNumCoefs, fp, fs, passSteps, passSteps * c.ML /*stopSteps*/,
             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);
+    ALOGD("passband(%lf, %lf): %.8lf %.8lf %.8lf\n", 0., fp, passMin, passMax, passRipple);
+    ALOGD("stopband(%lf, %lf): %.8lf %.3lf\n", fs, 0.5, stopMax, stopRipple);
 #endif
 }
 
@@ -304,6 +359,11 @@
         mFilterSampleRate = inSampleRate;
         mFilterQuality = getQuality();
 
+        double stopBandAtten;
+        double tbwCheat = 1.; // how much we "cheat" into aliasing
+        int halfLength;
+        double fcr = 0.;
+
         // Begin Kaiser Filter computation
         //
         // The quantization floor for S16 is about 96db - 10*log_10(#length) + 3dB.
@@ -313,52 +373,60 @@
         // 96-98dB
         //
 
-        double stopBandAtten;
-        double tbwCheat = 1.; // how much we "cheat" into aliasing
-        int halfLength;
-        if (mFilterQuality == DYN_HIGH_QUALITY) {
-            // 32b coefficients, 64 length
+        if (mPropertyEnableAtSampleRate >= 0 && mSampleRate >= mPropertyEnableAtSampleRate) {
+            // An alternative method which allows allows a greater fcr
+            // at the expense of potential aliasing.
+            halfLength = mPropertyHalfFilterLength;
+            stopBandAtten = mPropertyStopbandAttenuation;
             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;
+            fcr = mInSampleRate <= mSampleRate
+                    ? 0.5 : 0.5 * mSampleRate / mInSampleRate;
+            fcr *= mPropertyCutoffPercent / 100.;
+        } else {
+            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;
+                }
             }
         }
 
@@ -390,8 +458,12 @@
 
         // create the filter
         mConstants.set(phases, halfLength, inSampleRate, mSampleRate);
-        createKaiserFir(mConstants, stopBandAtten,
-                inSampleRate, mSampleRate, tbwCheat);
+        if (fcr > 0.) {
+            createKaiserFir(mConstants, stopBandAtten, fcr);
+        } else {
+            createKaiserFir(mConstants, stopBandAtten,
+                    inSampleRate, mSampleRate, tbwCheat);
+        }
     } // End Kaiser filter
 
     // update phase and state based on the new filter.
diff --git a/media/libaudioprocessing/AudioResamplerDyn.h b/media/libaudioprocessing/AudioResamplerDyn.h
index 1840fc7..92144d0 100644
--- a/media/libaudioprocessing/AudioResamplerDyn.h
+++ b/media/libaudioprocessing/AudioResamplerDyn.h
@@ -55,6 +55,39 @@
     virtual size_t resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider);
 
+    // Make available key design criteria for testing
+    int getHalfLength() const {
+        return mConstants.mHalfNumCoefs;
+    }
+
+    const TC *getFilterCoefs() const {
+        return mConstants.mFirCoefs;
+    }
+
+    int getPhases() const {
+        return mConstants.mL;
+    }
+
+    double getStopbandAttenuationDb() const {
+        return mStopbandAttenuationDb;
+    }
+
+    double getPassbandRippleDb() const {
+        return mPassbandRippleDb;
+    }
+
+    double getNormalizedTransitionBandwidth() const {
+        return mNormalizedTransitionBandwidth;
+    }
+
+    double getFilterAttenuation() const {
+        return mFilterAttenuation;
+    }
+
+    double getNormalizedCutoffFrequency() const {
+        return mNormalizedCutoffFrequency;
+    }
+
 private:
 
     class Constants { // stores the filter constants.
@@ -112,6 +145,8 @@
     void createKaiserFir(Constants &c, double stopBandAtten,
             int inSampleRate, int outSampleRate, double tbwCheat);
 
+    void createKaiserFir(Constants &c, double stopBandAtten, double fcr);
+
     template<int CHANNELS, bool LOCKED, int STRIDE>
     size_t resample(TO* out, size_t outFrameCount, AudioBufferProvider* provider);
 
@@ -127,6 +162,38 @@
             int32_t mFilterSampleRate; // designed filter sample rate.
         src_quality mFilterQuality;    // designed filter quality.
               void* mCoefBuffer;       // if a filter is created, this is not null
+
+    // Property selected design parameters.
+              // This will enable fixed high quality resampling.
+
+              // 32 char PROP_NAME_MAX limit enforced before Android O
+
+              // Use for sample rates greater than or equal to this value.
+              // Set to non-negative to enable, negative to disable.
+              int32_t mPropertyEnableAtSampleRate = 48000;
+                      // "ro.audio.resampler.psd.enable_at_samplerate"
+
+              // Specify HALF the resampling filter length.
+              // Set to a value which is a multiple of 4.
+              int32_t mPropertyHalfFilterLength = 32;
+                      // "ro.audio.resampler.psd.halflength"
+
+              // Specify the stopband attenuation in positive dB.
+              // Set to a value greater or equal to 20.
+              int32_t mPropertyStopbandAttenuation = 90;
+                      // "ro.audio.resampler.psd.stopband"
+
+              // Specify the cutoff frequency as a percentage of Nyquist.
+              // Set to a value between 50 and 100.
+              int32_t mPropertyCutoffPercent = 100;
+                      // "ro.audio.resampler.psd.cutoff_percent"
+
+    // Filter creation design parameters, see setSampleRate()
+             double mStopbandAttenuationDb = 0.;
+             double mPassbandRippleDb = 0.;
+             double mNormalizedTransitionBandwidth = 0.;
+             double mFilterAttenuation = 0.;
+             double mNormalizedCutoffFrequency = 0.;
 };
 
 } // namespace android
diff --git a/media/libaudioprocessing/AudioResamplerFirGen.h b/media/libaudioprocessing/AudioResamplerFirGen.h
index ad18965..39cafeb 100644
--- a/media/libaudioprocessing/AudioResamplerFirGen.h
+++ b/media/libaudioprocessing/AudioResamplerFirGen.h
@@ -546,8 +546,9 @@
         }
         wstart += wstep;
     }
-    // renormalize - this is only needed for integer filter types
-    double norm = 1./((1ULL<<(sizeof(T)*8-1))*L);
+    // renormalize - this is needed for integer filter types, use 1 for float or double.
+    constexpr int64_t integralShift = std::is_integral<T>::value ? (sizeof(T) * 8 - 1) : 0;
+    const double norm = 1. / (L << integralShift);
 
     firMin = fmin * norm;
     firMax = fmax * norm;
@@ -557,9 +558,12 @@
  * 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
+ * and is used to verify the design.
+ *
+ * For a polyphase filter (L > 1), typically 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.
+ * Similarly the stopSteps should be L * passSteps for equivalent accuracy.
  *
  * @param coef is the designed polyphase filter banks
  *
@@ -610,6 +614,74 @@
 }
 
 /*
+ * Estimate the windowed sinc minimum passband value.
+ *
+ * This is the minimum value for a windowed sinc filter in its passband,
+ * which is identical to the scaling required not to cause overflow of a 0dBFS signal.
+ * The actual value used to attenuate the filter amplitude should be slightly
+ * smaller than this (suggest squaring) as this is just an estimate.
+ *
+ * As a windowed sinc has a passband ripple commensurate to the stopband attenuation
+ * due to Gibb's phenomenon from truncating the sinc, we derive this value from
+ * the design stopbandAttenuationDb (a positive value).
+ */
+static inline double computeWindowedSincMinimumPassbandValue(
+        double stopBandAttenuationDb) {
+    return 1. - pow(10. /* base */, stopBandAttenuationDb * (-1. / 20.));
+}
+
+/*
+ * Compute the windowed sinc passband ripple from stopband attenuation.
+ *
+ * As a windowed sinc has an passband ripple commensurate to the stopband attenuation
+ * due to Gibb's phenomenon from truncating the sinc, we derive this value from
+ * the design stopbandAttenuationDb (a positive value).
+ */
+static inline double computeWindowedSincPassbandRippleDb(
+        double stopBandAttenuationDb) {
+    return -20. * log10(computeWindowedSincMinimumPassbandValue(stopBandAttenuationDb));
+}
+
+/*
+ * Kaiser window Beta value
+ *
+ * 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 positive 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
+ *
+ * For some values of stopBandAttenuationDb the function may be computed
+ * at compile time.
+ */
+static inline constexpr double computeBeta(double stopBandAttenuationDb) {
+    if (stopBandAttenuationDb > 50.) {
+        return 0.1102 * (stopBandAttenuationDb - 8.7);
+    }
+    const double offset = stopBandAttenuationDb - 21.;
+    if (offset > 0.) {
+        return 0.5842 * pow(offset, 0.4) + 0.07886 * offset;
+    }
+    return 0.;
+}
+
+/*
  * 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
@@ -642,31 +714,8 @@
 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 beta = computeBeta(stopBandAtten);
     const double xstep = (2. * M_PI) * fcr / L;
     const double xfrac = 1. / N;
     const double yscale = atten * L / (I0(beta) * M_PI);
@@ -696,9 +745,9 @@
                 sg.advance();
             }
 
-            if (is_same<T, int16_t>::value) { // int16_t needs noise shaping
+            if (std::is_same<T, int16_t>::value) { // int16_t needs noise shaping
                 *coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1), err));
-            } else if (is_same<T, int32_t>::value) {
+            } else if (std::is_same<T, int32_t>::value) {
                 *coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1)));
             } else { // assumed float or double
                 *coef++ = static_cast<T>(y);
diff --git a/media/libaudioprocessing/OWNERS b/media/libaudioprocessing/OWNERS
new file mode 100644
index 0000000..96d0ea0
--- /dev/null
+++ b/media/libaudioprocessing/OWNERS
@@ -0,0 +1,3 @@
+gkasten@google.com
+hunga@google.com
+rago@google.com
diff --git a/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh b/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh
index 704d095..efef417 100755
--- a/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh
+++ b/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh
@@ -14,8 +14,8 @@
 
 echo "waiting for device"
 adb root && adb wait-for-device remount
-adb push $OUT/system/lib/libaudioresampler.so /system/lib
-adb push $OUT/system/lib64/libaudioresampler.so /system/lib64
+adb push $OUT/system/lib/libaudioprocessing.so /system/lib
+adb push $OUT/system/lib64/libaudioprocessing.so /system/lib64
 adb push $OUT/data/nativetest/resampler_tests/resampler_tests /data/nativetest/resampler_tests/resampler_tests
 adb push $OUT/data/nativetest64/resampler_tests/resampler_tests /data/nativetest64/resampler_tests/resampler_tests
 
diff --git a/media/libaudioprocessing/tests/resampler_tests.cpp b/media/libaudioprocessing/tests/resampler_tests.cpp
index a23c000..e1623f7 100644
--- a/media/libaudioprocessing/tests/resampler_tests.cpp
+++ b/media/libaudioprocessing/tests/resampler_tests.cpp
@@ -29,6 +29,7 @@
 #include <unistd.h>
 
 #include <iostream>
+#include <memory>
 #include <utility>
 #include <vector>
 
@@ -37,6 +38,8 @@
 #include <media/AudioBufferProvider.h>
 
 #include <media/AudioResampler.h>
+#include "../AudioResamplerDyn.h"
+#include "../AudioResamplerFirGen.h"
 #include "test_utils.h"
 
 template <typename T>
@@ -242,6 +245,60 @@
     delete resampler;
 }
 
+void testFilterResponse(
+        size_t channels, unsigned inputFreq, unsigned outputFreq)
+{
+    // create resampler
+    using ResamplerType = android::AudioResamplerDyn<float, float, float>;
+    std::unique_ptr<ResamplerType> rdyn(
+            static_cast<ResamplerType *>(
+                    android::AudioResampler::create(
+                            AUDIO_FORMAT_PCM_FLOAT,
+                            channels,
+                            outputFreq,
+                            android::AudioResampler::DYN_HIGH_QUALITY)));
+    rdyn->setSampleRate(inputFreq);
+
+    // get design parameters
+    const int phases = rdyn->getPhases();
+    const int halfLength = rdyn->getHalfLength();
+    const float *coefs = rdyn->getFilterCoefs();
+    const double fcr = rdyn->getNormalizedCutoffFrequency();
+    const double tbw = rdyn->getNormalizedTransitionBandwidth();
+    const double attenuation = rdyn->getFilterAttenuation();
+    const double stopbandDb = rdyn->getStopbandAttenuationDb();
+    const double passbandDb = rdyn->getPassbandRippleDb();
+    const double fp = fcr - tbw / 2;
+    const double fs = fcr + tbw / 2;
+
+    printf("inputFreq:%d outputFreq:%d design"
+            " phases:%d halfLength:%d"
+            " fcr:%lf fp:%lf fs:%lf tbw:%lf"
+            " attenuation:%lf stopRipple:%.lf passRipple:%lf"
+            "\n",
+            inputFreq, outputFreq,
+            phases, halfLength,
+            fcr, fp, fs, tbw,
+            attenuation, stopbandDb, passbandDb);
+
+    // verify design parameters
+    constexpr int32_t passSteps = 1000;
+    double passMin, passMax, passRipple, stopMax, stopRipple;
+    android::testFir(coefs, phases, halfLength, fp / phases, fs / phases,
+            passSteps, phases * passSteps /* stopSteps */,
+            passMin, passMax, passRipple,
+            stopMax, stopRipple);
+    printf("inputFreq:%d outputFreq:%d verify"
+            " passMin:%lf passMax:%lf passRipple:%lf stopMax:%lf stopRipple:%lf"
+            "\n",
+            inputFreq, outputFreq,
+            passMin, passMax, passRipple, stopMax, stopRipple);
+
+    ASSERT_GT(stopRipple, 60.);  // enough stopband attenuation
+    ASSERT_LT(passRipple, 0.2);  // small passband ripple
+    ASSERT_GT(passMin, 0.99);    // we do not attenuate the signal (ideally 1.)
+}
+
 /* Buffer increment test
  *
  * We compare a reference output, where we consume and process the entire
@@ -484,3 +541,30 @@
     }
 }
 
+TEST(audioflinger_resampler, filterresponse) {
+    std::vector<int> inSampleRates{
+        8000,
+        11025,
+        12000,
+        16000,
+        22050,
+        24000,
+        32000,
+        44100,
+        48000,
+        88200,
+        96000,
+        176400,
+        192000,
+    };
+    std::vector<int> outSampleRates{
+        48000,
+        96000,
+    };
+
+    for (int outSampleRate : outSampleRates) {
+        for (int inSampleRate : inSampleRates) {
+            testFilterResponse(2 /* channels */, inSampleRate, outSampleRate);
+        }
+    }
+}
diff --git a/media/libaudioprocessing/tests/test-mixer.cpp b/media/libaudioprocessing/tests/test-mixer.cpp
index 75dbf91..b67810d 100644
--- a/media/libaudioprocessing/tests/test-mixer.cpp
+++ b/media/libaudioprocessing/tests/test-mixer.cpp
@@ -316,8 +316,7 @@
             outputSampleRate, outputChannels, outputFrames, useMixerFloat);
     if (auxFilename) {
         // Aux buffer is always in q4_27 format for now.
-        // memcpy_to_i16_from_q4_27(), but with stereo frame count (not sample count)
-        ditherAndClamp((int32_t*)auxAddr, (int32_t*)auxAddr, outputFrames >> 1);
+        memcpy_to_i16_from_q4_27((int16_t*)auxAddr, (const int32_t*)auxAddr, outputFrames);
         writeFile(auxFilename, auxAddr, outputSampleRate, 1, outputFrames, false);
     }
 
diff --git a/media/libcpustats/OWNERS b/media/libcpustats/OWNERS
new file mode 100644
index 0000000..f9cb567
--- /dev/null
+++ b/media/libcpustats/OWNERS
@@ -0,0 +1 @@
+gkasten@google.com
diff --git a/media/libeffects/OWNERS b/media/libeffects/OWNERS
index 7e3de13..7f9ae81 100644
--- a/media/libeffects/OWNERS
+++ b/media/libeffects/OWNERS
@@ -1,3 +1,4 @@
+hunga@google.com
 krocard@google.com
 mnaganov@google.com
 rago@google.com
diff --git a/media/libeffects/config/include/media/EffectsConfig.h b/media/libeffects/config/include/media/EffectsConfig.h
index 811730c..55b946f 100644
--- a/media/libeffects/config/include/media/EffectsConfig.h
+++ b/media/libeffects/config/include/media/EffectsConfig.h
@@ -32,8 +32,13 @@
 namespace android {
 namespace effectsConfig {
 
-/** Default path of effect configuration file. */
-constexpr char DEFAULT_PATH[] = "/vendor/etc/audio_effects.xml";
+/** Default path of effect configuration file. Relative to DEFAULT_LOCATIONS. */
+constexpr const char* DEFAULT_NAME = "audio_effects.xml";
+
+/** Default path of effect configuration file.
+ * The /vendor partition is the recommended one, the others are deprecated.
+ */
+constexpr const char* DEFAULT_LOCATIONS[] = {"/odm/etc", "/vendor/etc", "/system/etc"};
 
 /** Directories where the effect libraries will be search for. */
 constexpr const char* LD_EFFECT_LIBRARY_PATH[] =
@@ -91,13 +96,16 @@
     /** Parsed config, nullptr if the xml lib could not load the file */
     std::unique_ptr<Config> parsedConfig;
     size_t nbSkippedElement; //< Number of skipped invalid library, effect or processing chain
+    const char* configPath; //< Path to the loaded configuration
 };
 
 /** Parses the provided effect configuration.
  * Parsing do not stop of first invalid element, but continues to the next.
+ * @param[in] path of the configuration file do load
+ *                 if nullptr, look for DEFAULT_NAME in DEFAULT_LOCATIONS.
  * @see ParsingResult::nbSkippedElement
  */
-ParsingResult parse(const char* path = DEFAULT_PATH);
+ParsingResult parse(const char* path = nullptr);
 
 } // namespace effectsConfig
 } // namespace android
diff --git a/media/libeffects/config/src/EffectsConfig.cpp b/media/libeffects/config/src/EffectsConfig.cpp
index 97462f8..18c406d 100644
--- a/media/libeffects/config/src/EffectsConfig.cpp
+++ b/media/libeffects/config/src/EffectsConfig.cpp
@@ -20,6 +20,7 @@
 #include <cstdint>
 #include <functional>
 #include <string>
+#include <unistd.h>
 
 #include <tinyxml2.h>
 #include <log/log.h>
@@ -85,7 +86,7 @@
 constexpr std::enable_if<false, Enum> STREAM_NAME_MAP;
 
 /** All output stream types which support effects.
- * This need to be kept in sink with the xsd streamOutputType.
+ * This need to be kept in sync with the xsd streamOutputType.
  */
 template <>
 constexpr std::pair<audio_stream_type_t, const char*> STREAM_NAME_MAP<audio_stream_type_t>[] = {
@@ -102,7 +103,7 @@
 };
 
 /** All input stream types which support effects.
- * This need to be kept in sink with the xsd streamOutputType.
+ * This need to be kept in sync with the xsd streamOutputType.
  */
 template <>
 constexpr std::pair<audio_source_t, const char*> STREAM_NAME_MAP<audio_source_t>[] = {
@@ -142,7 +143,7 @@
 }
 
 /** Find an element in a collection by its name.
- * @return nullptr if not found, the ellements address if found.
+ * @return nullptr if not found, the element address if found.
  */
 template <class T>
 T* findByName(const char* name, std::vector<T>& collection) {
@@ -249,15 +250,14 @@
     return true;
 }
 
-}; // namespace
-
-ParsingResult parse(const char* path) {
+/** Internal version of the public parse(const char* path) with precondition `path != nullptr`. */
+ParsingResult parseWithPath(const char* path) {
     XMLDocument doc;
     doc.LoadFile(path);
     if (doc.Error()) {
         ALOGE("Failed to parse %s: Tinyxml2 error (%d): %s %s", path,
               doc.ErrorID(), doc.GetErrorStr1(), doc.GetErrorStr2());
-        return {nullptr, 0};
+        return {nullptr, 0, path};
     }
 
     auto config = std::make_unique<Config>();
@@ -295,7 +295,29 @@
             }
         }
     }
-    return {std::move(config), nbSkippedElements};
+    return {std::move(config), nbSkippedElements, path};
+}
+
+}; // namespace
+
+ParsingResult parse(const char* path) {
+    if (path != nullptr) {
+        return parseWithPath(path);
+    }
+
+    for (std::string location : DEFAULT_LOCATIONS) {
+        std::string defaultPath = location + '/' + DEFAULT_NAME;
+        if (access(defaultPath.c_str(), R_OK) != 0) {
+            continue;
+        }
+        auto result = parseWithPath(defaultPath.c_str());
+        if (result.parsedConfig != nullptr) {
+            return result;
+        }
+    }
+
+    ALOGE("Could not parse effect configuration in any of the default locations.");
+    return {nullptr, 0, nullptr};
 }
 
 } // namespace effectsConfig
diff --git a/media/libeffects/factory/EffectsXmlConfigLoader.cpp b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
index 438b787..7a7d431 100644
--- a/media/libeffects/factory/EffectsXmlConfigLoader.cpp
+++ b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
@@ -327,7 +327,7 @@
                                            &gSkippedEffects, &gSubEffectList);
 
     ALOGE_IF(result.nbSkippedElement != 0, "%zu errors during loading of configuration: %s",
-             result.nbSkippedElement, path ?: effectsConfig::DEFAULT_PATH);
+             result.nbSkippedElement, result.configPath ?: "No config file found");
 
     return result.nbSkippedElement;
 }
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Coeffs.h b/media/libeffects/lvm/lib/Bass/src/LVDBE_Coeffs.h
index f32ed30..4ecaf14 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Coeffs.h
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Coeffs.h
@@ -534,246 +534,246 @@
 
  /* Coefficients for centre frequency 55Hz */
 #define HPF_Fs8000_Fc55_A0                        0.958849f
-#define HPF_Fs8000_Fc55_A1                        -1.917698f
+#define HPF_Fs8000_Fc55_A1                        (-1.917698f)
 #define HPF_Fs8000_Fc55_A2                        0.958849f
-#define HPF_Fs8000_Fc55_B1                        -1.939001f
+#define HPF_Fs8000_Fc55_B1                        (-1.939001f)
 #define HPF_Fs8000_Fc55_B2                        0.940807f
 #define HPF_Fs11025_Fc55_A0                       0.966909f
-#define HPF_Fs11025_Fc55_A1                       -1.933818f
+#define HPF_Fs11025_Fc55_A1                       (-1.933818f)
 #define HPF_Fs11025_Fc55_A2                       0.966909f
-#define HPF_Fs11025_Fc55_B1                       -1.955732f
+#define HPF_Fs11025_Fc55_B1                       (-1.955732f)
 #define HPF_Fs11025_Fc55_B2                       0.956690f
 #define HPF_Fs12000_Fc55_A0                       0.968650f
-#define HPF_Fs12000_Fc55_A1                       -1.937300f
+#define HPF_Fs12000_Fc55_A1                       (-1.937300f)
 #define HPF_Fs12000_Fc55_A2                       0.968650f
-#define HPF_Fs12000_Fc55_B1                       -1.959327f
+#define HPF_Fs12000_Fc55_B1                       (-1.959327f)
 #define HPF_Fs12000_Fc55_B2                       0.960138f
 #define HPF_Fs16000_Fc55_A0                       0.973588f
-#define HPF_Fs16000_Fc55_A1                       -1.947176f
+#define HPF_Fs16000_Fc55_A1                       (-1.947176f)
 #define HPF_Fs16000_Fc55_A2                       0.973588f
-#define HPF_Fs16000_Fc55_B1                       -1.969494f
+#define HPF_Fs16000_Fc55_B1                       (-1.969494f)
 #define HPF_Fs16000_Fc55_B2                       0.969952f
 #define HPF_Fs22050_Fc55_A0                       0.977671f
-#define HPF_Fs22050_Fc55_A1                       -1.955343f
+#define HPF_Fs22050_Fc55_A1                       (-1.955343f)
 #define HPF_Fs22050_Fc55_A2                       0.977671f
-#define HPF_Fs22050_Fc55_B1                       -1.977863f
+#define HPF_Fs22050_Fc55_B1                       (-1.977863f)
 #define HPF_Fs22050_Fc55_B2                       0.978105f
 #define HPF_Fs24000_Fc55_A0                       0.978551f
-#define HPF_Fs24000_Fc55_A1                       -1.957102f
+#define HPF_Fs24000_Fc55_A1                       (-1.957102f)
 #define HPF_Fs24000_Fc55_A2                       0.978551f
-#define HPF_Fs24000_Fc55_B1                       -1.979662f
+#define HPF_Fs24000_Fc55_B1                       (-1.979662f)
 #define HPF_Fs24000_Fc55_B2                       0.979866f
 #define HPF_Fs32000_Fc55_A0                       0.981042f
-#define HPF_Fs32000_Fc55_A1                       -1.962084f
+#define HPF_Fs32000_Fc55_A1                       (-1.962084f)
 #define HPF_Fs32000_Fc55_A2                       0.981042f
-#define HPF_Fs32000_Fc55_B1                       -1.984746f
+#define HPF_Fs32000_Fc55_B1                       (-1.984746f)
 #define HPF_Fs32000_Fc55_B2                       0.984861f
 #define HPF_Fs44100_Fc55_A0                       0.983097f
-#define HPF_Fs44100_Fc55_A1                       -1.966194f
+#define HPF_Fs44100_Fc55_A1                       (-1.966194f)
 #define HPF_Fs44100_Fc55_A2                       0.983097f
-#define HPF_Fs44100_Fc55_B1                       -1.988931f
+#define HPF_Fs44100_Fc55_B1                       (-1.988931f)
 #define HPF_Fs44100_Fc55_B2                       0.988992f
 #define HPF_Fs48000_Fc55_A0                       0.983539f
-#define HPF_Fs48000_Fc55_A1                       -1.967079f
+#define HPF_Fs48000_Fc55_A1                       (-1.967079f)
 #define HPF_Fs48000_Fc55_A2                       0.983539f
-#define HPF_Fs48000_Fc55_B1                       -1.989831f
+#define HPF_Fs48000_Fc55_B1                       (-1.989831f)
 #define HPF_Fs48000_Fc55_B2                       0.989882f
 
 #ifdef HIGHER_FS
 #define HPF_Fs96000_Fc55_A0                       0.986040f
-#define HPF_Fs96000_Fc55_A1                       -1.972080f
+#define HPF_Fs96000_Fc55_A1                       (-1.972080f)
 #define HPF_Fs96000_Fc55_A2                       0.986040f
-#define HPF_Fs96000_Fc55_B1                       -1.994915f
+#define HPF_Fs96000_Fc55_B1                       (-1.994915f)
 #define HPF_Fs96000_Fc55_B2                       0.994928f
 
 #define HPF_Fs192000_Fc55_A0                      0.987294f
-#define HPF_Fs192000_Fc55_A1                      -1.974588f
+#define HPF_Fs192000_Fc55_A1                      (-1.974588f)
 #define HPF_Fs192000_Fc55_A2                      0.987294f
-#define HPF_Fs192000_Fc55_B1                      -1.997458f
+#define HPF_Fs192000_Fc55_B1                      (-1.997458f)
 #define HPF_Fs192000_Fc55_B2                      0.997461f
 #endif
 
 
  /* Coefficients for centre frequency 66Hz */
 #define HPF_Fs8000_Fc66_A0                        0.953016f
-#define HPF_Fs8000_Fc66_A1                        -1.906032f
+#define HPF_Fs8000_Fc66_A1                        (-1.906032f)
 #define HPF_Fs8000_Fc66_A2                        0.953016f
-#define HPF_Fs8000_Fc66_B1                        -1.926810f
+#define HPF_Fs8000_Fc66_B1                        (-1.926810f)
 #define HPF_Fs8000_Fc66_B2                        0.929396f
 #define HPF_Fs11025_Fc66_A0                       0.962638f
-#define HPF_Fs11025_Fc66_A1                       -1.925275f
+#define HPF_Fs11025_Fc66_A1                       (-1.925275f)
 #define HPF_Fs11025_Fc66_A2                       0.962638f
-#define HPF_Fs11025_Fc66_B1                       -1.946881f
+#define HPF_Fs11025_Fc66_B1                       (-1.946881f)
 #define HPF_Fs11025_Fc66_B2                       0.948256f
 #define HPF_Fs12000_Fc66_A0                       0.964718f
-#define HPF_Fs12000_Fc66_A1                       -1.929435f
+#define HPF_Fs12000_Fc66_A1                       (-1.929435f)
 #define HPF_Fs12000_Fc66_A2                       0.964718f
-#define HPF_Fs12000_Fc66_B1                       -1.951196f
+#define HPF_Fs12000_Fc66_B1                       (-1.951196f)
 #define HPF_Fs12000_Fc66_B2                       0.952359f
 #define HPF_Fs16000_Fc66_A0                       0.970622f
-#define HPF_Fs16000_Fc66_A1                       -1.941244f
+#define HPF_Fs16000_Fc66_A1                       (-1.941244f)
 #define HPF_Fs16000_Fc66_A2                       0.970622f
-#define HPF_Fs16000_Fc66_B1                       -1.963394f
+#define HPF_Fs16000_Fc66_B1                       (-1.963394f)
 #define HPF_Fs16000_Fc66_B2                       0.964052f
 #define HPF_Fs22050_Fc66_A0                       0.975509f
-#define HPF_Fs22050_Fc66_A1                       -1.951019f
+#define HPF_Fs22050_Fc66_A1                       (-1.951019f)
 #define HPF_Fs22050_Fc66_A2                       0.975509f
-#define HPF_Fs22050_Fc66_B1                       -1.973436f
+#define HPF_Fs22050_Fc66_B1                       (-1.973436f)
 #define HPF_Fs22050_Fc66_B2                       0.973784f
 #define HPF_Fs24000_Fc66_A0                       0.976563f
-#define HPF_Fs24000_Fc66_A1                       -1.953125f
+#define HPF_Fs24000_Fc66_A1                       (-1.953125f)
 #define HPF_Fs24000_Fc66_A2                       0.976563f
-#define HPF_Fs24000_Fc66_B1                       -1.975594f
+#define HPF_Fs24000_Fc66_B1                       (-1.975594f)
 #define HPF_Fs24000_Fc66_B2                       0.975889f
 #define HPF_Fs32000_Fc66_A0                       0.979547f
-#define HPF_Fs32000_Fc66_A1                       -1.959093f
+#define HPF_Fs32000_Fc66_A1                       (-1.959093f)
 #define HPF_Fs32000_Fc66_A2                       0.979547f
-#define HPF_Fs32000_Fc66_B1                       -1.981695f
+#define HPF_Fs32000_Fc66_B1                       (-1.981695f)
 #define HPF_Fs32000_Fc66_B2                       0.981861f
 #define HPF_Fs44100_Fc66_A0                       0.982010f
-#define HPF_Fs44100_Fc66_A1                       -1.964019f
+#define HPF_Fs44100_Fc66_A1                       (-1.964019f)
 #define HPF_Fs44100_Fc66_A2                       0.982010f
-#define HPF_Fs44100_Fc66_B1                       -1.986718f
+#define HPF_Fs44100_Fc66_B1                       (-1.986718f)
 #define HPF_Fs44100_Fc66_B2                       0.986805f
 #define HPF_Fs48000_Fc66_A0                       0.982540f
-#define HPF_Fs48000_Fc66_A1                       -1.965079f
+#define HPF_Fs48000_Fc66_A1                       (-1.965079f)
 #define HPF_Fs48000_Fc66_A2                       0.982540f
-#define HPF_Fs48000_Fc66_B1                       -1.987797f
+#define HPF_Fs48000_Fc66_B1                       (-1.987797f)
 #define HPF_Fs48000_Fc66_B2                       0.987871f
 
 #ifdef HIGHER_FS
 #define HPF_Fs96000_Fc66_A0                       0.985539f
-#define HPF_Fs96000_Fc66_A1                       -1.971077f
+#define HPF_Fs96000_Fc66_A1                       (-1.971077f)
 #define HPF_Fs96000_Fc66_A2                       0.985539f
-#define HPF_Fs96000_Fc66_B1                       -1.993898f
+#define HPF_Fs96000_Fc66_B1                       (-1.993898f)
 #define HPF_Fs96000_Fc66_B2                       0.993917f
 
 #define HPF_Fs192000_Fc66_A0                      0.987043f
-#define HPF_Fs192000_Fc66_A1                      -1.974086f
+#define HPF_Fs192000_Fc66_A1                      (-1.974086f)
 #define HPF_Fs192000_Fc66_A2                      0.987043f
-#define HPF_Fs192000_Fc66_B1                      -1.996949f
+#define HPF_Fs192000_Fc66_B1                      (-1.996949f)
 #define HPF_Fs192000_Fc66_B2                      0.996954f
 #endif
 
 /* Coefficients for centre frequency 78Hz */
 #define HPF_Fs8000_Fc78_A0                        0.946693f
-#define HPF_Fs8000_Fc78_A1                        -1.893387f
+#define HPF_Fs8000_Fc78_A1                        (-1.893387f)
 #define HPF_Fs8000_Fc78_A2                        0.946693f
-#define HPF_Fs8000_Fc78_B1                        -1.913517f
+#define HPF_Fs8000_Fc78_B1                        (-1.913517f)
 #define HPF_Fs8000_Fc78_B2                        0.917105f
 #define HPF_Fs11025_Fc78_A0                       0.957999f
-#define HPF_Fs11025_Fc78_A1                       -1.915998f
+#define HPF_Fs11025_Fc78_A1                       (-1.915998f)
 #define HPF_Fs11025_Fc78_A2                       0.957999f
-#define HPF_Fs11025_Fc78_B1                       -1.937229f
+#define HPF_Fs11025_Fc78_B1                       (-1.937229f)
 #define HPF_Fs11025_Fc78_B2                       0.939140f
 #define HPF_Fs12000_Fc78_A0                       0.960446f
-#define HPF_Fs12000_Fc78_A1                       -1.920892f
+#define HPF_Fs12000_Fc78_A1                       (-1.920892f)
 #define HPF_Fs12000_Fc78_A2                       0.960446f
-#define HPF_Fs12000_Fc78_B1                       -1.942326f
+#define HPF_Fs12000_Fc78_B1                       (-1.942326f)
 #define HPF_Fs12000_Fc78_B2                       0.943944f
 #define HPF_Fs16000_Fc78_A0                       0.967397f
-#define HPF_Fs16000_Fc78_A1                       -1.934794f
+#define HPF_Fs16000_Fc78_A1                       (-1.934794f)
 #define HPF_Fs16000_Fc78_A2                       0.967397f
-#define HPF_Fs16000_Fc78_B1                       -1.956740f
+#define HPF_Fs16000_Fc78_B1                       (-1.956740f)
 #define HPF_Fs16000_Fc78_B2                       0.957656f
 #define HPF_Fs22050_Fc78_A0                       0.973156f
-#define HPF_Fs22050_Fc78_A1                       -1.946313f
+#define HPF_Fs22050_Fc78_A1                       (-1.946313f)
 #define HPF_Fs22050_Fc78_A2                       0.973156f
-#define HPF_Fs22050_Fc78_B1                       -1.968607f
+#define HPF_Fs22050_Fc78_B1                       (-1.968607f)
 #define HPF_Fs22050_Fc78_B2                       0.969092f
 #define HPF_Fs24000_Fc78_A0                       0.974398f
-#define HPF_Fs24000_Fc78_A1                       -1.948797f
+#define HPF_Fs24000_Fc78_A1                       (-1.948797f)
 #define HPF_Fs24000_Fc78_A2                       0.974398f
-#define HPF_Fs24000_Fc78_B1                       -1.971157f
+#define HPF_Fs24000_Fc78_B1                       (-1.971157f)
 #define HPF_Fs24000_Fc78_B2                       0.971568f
 #define HPF_Fs32000_Fc78_A0                       0.977918f
-#define HPF_Fs32000_Fc78_A1                       -1.955836f
+#define HPF_Fs32000_Fc78_A1                       (-1.955836f)
 #define HPF_Fs32000_Fc78_A2                       0.977918f
-#define HPF_Fs32000_Fc78_B1                       -1.978367f
+#define HPF_Fs32000_Fc78_B1                       (-1.978367f)
 #define HPF_Fs32000_Fc78_B2                       0.978599f
 #define HPF_Fs44100_Fc78_A0                       0.980824f
-#define HPF_Fs44100_Fc78_A1                       -1.961649f
+#define HPF_Fs44100_Fc78_A1                       (-1.961649f)
 #define HPF_Fs44100_Fc78_A2                       0.980824f
-#define HPF_Fs44100_Fc78_B1                       -1.984303f
+#define HPF_Fs44100_Fc78_B1                       (-1.984303f)
 #define HPF_Fs44100_Fc78_B2                       0.984425f
 #define HPF_Fs48000_Fc78_A0                       0.981450f
-#define HPF_Fs48000_Fc78_A1                       -1.962900f
+#define HPF_Fs48000_Fc78_A1                       (-1.962900f)
 #define HPF_Fs48000_Fc78_A2                       0.981450f
-#define HPF_Fs48000_Fc78_B1                       -1.985578f
+#define HPF_Fs48000_Fc78_B1                       (-1.985578f)
 #define HPF_Fs48000_Fc78_B2                       0.985681f
 
 #ifdef HIGHER_FS
 #define HPF_Fs96000_Fc78_A0                       0.984992f
-#define HPF_Fs96000_Fc78_A1                       -1.969984f
+#define HPF_Fs96000_Fc78_A1                       (-1.969984f)
 #define HPF_Fs96000_Fc78_A2                       0.984992f
-#define HPF_Fs96000_Fc78_B1                       -1.992789f
+#define HPF_Fs96000_Fc78_B1                       (-1.992789f)
 #define HPF_Fs96000_Fc78_B2                       0.992815f
 
 #define HPF_Fs192000_Fc78_A0                      0.986769f
-#define HPF_Fs192000_Fc78_A1                      -1.973539f
+#define HPF_Fs192000_Fc78_A1                      (-1.973539f)
 #define HPF_Fs192000_Fc78_A2                      0.986769f
-#define HPF_Fs192000_Fc78_B1                      -1.996394f
+#define HPF_Fs192000_Fc78_B1                      (-1.996394f)
 #define HPF_Fs192000_Fc78_B2                      0.996401f
 #endif
 
 /* Coefficients for centre frequency 90Hz */
 #define HPF_Fs8000_Fc90_A0                       0.940412f
-#define HPF_Fs8000_Fc90_A1                       -1.880825f
+#define HPF_Fs8000_Fc90_A1                       (-1.880825f)
 #define HPF_Fs8000_Fc90_A2                       0.940412f
-#define HPF_Fs8000_Fc90_B1                       -1.900231f
+#define HPF_Fs8000_Fc90_B1                       (-1.900231f)
 #define HPF_Fs8000_Fc90_B2                       0.904977f
 #define HPF_Fs11025_Fc90_A0                      0.953383f
-#define HPF_Fs11025_Fc90_A1                      -1.906766f
+#define HPF_Fs11025_Fc90_A1                      (-1.906766f)
 #define HPF_Fs11025_Fc90_A2                      0.953383f
-#define HPF_Fs11025_Fc90_B1                      -1.927579f
+#define HPF_Fs11025_Fc90_B1                      (-1.927579f)
 #define HPF_Fs11025_Fc90_B2                      0.930111f
 #define HPF_Fs12000_Fc90_A0                      0.956193f
-#define HPF_Fs12000_Fc90_A1                      -1.912387f
+#define HPF_Fs12000_Fc90_A1                      (-1.912387f)
 #define HPF_Fs12000_Fc90_A2                      0.956193f
-#define HPF_Fs12000_Fc90_B1                      -1.933459f
+#define HPF_Fs12000_Fc90_B1                      (-1.933459f)
 #define HPF_Fs12000_Fc90_B2                      0.935603f
 #define HPF_Fs16000_Fc90_A0                      0.964183f
-#define HPF_Fs16000_Fc90_A1                      -1.928365f
+#define HPF_Fs16000_Fc90_A1                      (-1.928365f)
 #define HPF_Fs16000_Fc90_A2                      0.964183f
-#define HPF_Fs16000_Fc90_B1                      -1.950087f
+#define HPF_Fs16000_Fc90_B1                      (-1.950087f)
 #define HPF_Fs16000_Fc90_B2                      0.951303f
 #define HPF_Fs22050_Fc90_A0                      0.970809f
-#define HPF_Fs22050_Fc90_A1                      -1.941618f
+#define HPF_Fs22050_Fc90_A1                      (-1.941618f)
 #define HPF_Fs22050_Fc90_A2                      0.970809f
-#define HPF_Fs22050_Fc90_B1                      -1.963778f
+#define HPF_Fs22050_Fc90_B1                      (-1.963778f)
 #define HPF_Fs22050_Fc90_B2                      0.964423f
 #define HPF_Fs24000_Fc90_A0                      0.972239f
-#define HPF_Fs24000_Fc90_A1                      -1.944477f
+#define HPF_Fs24000_Fc90_A1                      (-1.944477f)
 #define HPF_Fs24000_Fc90_A2                      0.972239f
-#define HPF_Fs24000_Fc90_B1                      -1.966721f
+#define HPF_Fs24000_Fc90_B1                      (-1.966721f)
 #define HPF_Fs24000_Fc90_B2                      0.967266f
 #define HPF_Fs32000_Fc90_A0                      0.976292f
-#define HPF_Fs32000_Fc90_A1                      -1.952584f
+#define HPF_Fs32000_Fc90_A1                      (-1.952584f)
 #define HPF_Fs32000_Fc90_A2                      0.976292f
-#define HPF_Fs32000_Fc90_B1                      -1.975040f
+#define HPF_Fs32000_Fc90_B1                      (-1.975040f)
 #define HPF_Fs32000_Fc90_B2                      0.975347f
 #define HPF_Fs44100_Fc90_A0                      0.979641f
-#define HPF_Fs44100_Fc90_A1                      -1.959282f
+#define HPF_Fs44100_Fc90_A1                      (-1.959282f)
 #define HPF_Fs44100_Fc90_A2                      0.979641f
-#define HPF_Fs44100_Fc90_B1                      -1.981888f
+#define HPF_Fs44100_Fc90_B1                      (-1.981888f)
 #define HPF_Fs44100_Fc90_B2                      0.982050f
 #define HPF_Fs48000_Fc90_A0                      0.980362f
-#define HPF_Fs48000_Fc90_A1                      -1.960724f
+#define HPF_Fs48000_Fc90_A1                      (-1.960724f)
 #define HPF_Fs48000_Fc90_A2                      0.980362f
-#define HPF_Fs48000_Fc90_B1                      -1.983359f
+#define HPF_Fs48000_Fc90_B1                      (-1.983359f)
 #define HPF_Fs48000_Fc90_B2                      0.983497f
 
 #ifdef HIGHER_FS
 #define HPF_Fs96000_Fc90_A0                       0.984446f
-#define HPF_Fs96000_Fc90_A1                       -1.968892f
+#define HPF_Fs96000_Fc90_A1                       (-1.968892f)
 #define HPF_Fs96000_Fc90_A2                       0.984446f
-#define HPF_Fs96000_Fc90_B1                       -1.991680f
+#define HPF_Fs96000_Fc90_B1                       (-1.991680f)
 #define HPF_Fs96000_Fc90_B2                       0.991714f
 
 #define HPF_Fs192000_Fc90_A0                      0.986496f
-#define HPF_Fs192000_Fc90_A1                      -1.972992f
+#define HPF_Fs192000_Fc90_A1                      (-1.972992f)
 #define HPF_Fs192000_Fc90_A2                      0.986496f
-#define HPF_Fs192000_Fc90_B1                      -1.995840f
+#define HPF_Fs192000_Fc90_B1                      (-1.995840f)
 #define HPF_Fs192000_Fc90_B2                      0.995848f
 #endif
 
@@ -786,244 +786,244 @@
 /* Coefficients for centre frequency 55Hz */
 #define BPF_Fs8000_Fc55_A0                       0.009197f
 #define BPF_Fs8000_Fc55_A1                       0.000000f
-#define BPF_Fs8000_Fc55_A2                       -0.009197f
-#define BPF_Fs8000_Fc55_B1                       -1.979545f
+#define BPF_Fs8000_Fc55_A2                       (-0.009197f)
+#define BPF_Fs8000_Fc55_B1                       (-1.979545f)
 #define BPF_Fs8000_Fc55_B2                       0.981393f
 #define BPF_Fs11025_Fc55_A0                      0.006691f
 #define BPF_Fs11025_Fc55_A1                      0.000000f
-#define BPF_Fs11025_Fc55_A2                      -0.006691f
-#define BPF_Fs11025_Fc55_B1                      -1.985488f
+#define BPF_Fs11025_Fc55_A2                      (-0.006691f)
+#define BPF_Fs11025_Fc55_B1                      (-1.985488f)
 #define BPF_Fs11025_Fc55_B2                      0.986464f
 #define BPF_Fs12000_Fc55_A0                      0.006150f
 #define BPF_Fs12000_Fc55_A1                      0.000000f
-#define BPF_Fs12000_Fc55_A2                      -0.006150f
-#define BPF_Fs12000_Fc55_B1                      -1.986733f
+#define BPF_Fs12000_Fc55_A2                      (-0.006150f)
+#define BPF_Fs12000_Fc55_B1                      (-1.986733f)
 #define BPF_Fs12000_Fc55_B2                      0.987557f
 #define BPF_Fs16000_Fc55_A0                      0.004620f
 #define BPF_Fs16000_Fc55_A1                      0.000000f
-#define BPF_Fs16000_Fc55_A2                      -0.004620f
-#define BPF_Fs16000_Fc55_B1                      -1.990189f
+#define BPF_Fs16000_Fc55_A2                      (-0.004620f)
+#define BPF_Fs16000_Fc55_B1                      (-1.990189f)
 #define BPF_Fs16000_Fc55_B2                      0.990653f
 #define BPF_Fs22050_Fc55_A0                      0.003357f
 #define BPF_Fs22050_Fc55_A1                      0.000000f
-#define BPF_Fs22050_Fc55_A2                      -0.003357f
-#define BPF_Fs22050_Fc55_B1                      -1.992964f
+#define BPF_Fs22050_Fc55_A2                      (-0.003357f)
+#define BPF_Fs22050_Fc55_B1                      (-1.992964f)
 #define BPF_Fs22050_Fc55_B2                      0.993209f
 #define BPF_Fs24000_Fc55_A0                      0.003085f
 #define BPF_Fs24000_Fc55_A1                      0.000000f
-#define BPF_Fs24000_Fc55_A2                      -0.003085f
-#define BPF_Fs24000_Fc55_B1                      -1.993552f
+#define BPF_Fs24000_Fc55_A2                      (-0.003085f)
+#define BPF_Fs24000_Fc55_B1                      (-1.993552f)
 #define BPF_Fs24000_Fc55_B2                      0.993759f
 #define BPF_Fs32000_Fc55_A0                      0.002315f
 #define BPF_Fs32000_Fc55_A1                      0.000000f
-#define BPF_Fs32000_Fc55_A2                      -0.002315f
-#define BPF_Fs32000_Fc55_B1                      -1.995199f
+#define BPF_Fs32000_Fc55_A2                      (-0.002315f)
+#define BPF_Fs32000_Fc55_B1                      (-1.995199f)
 #define BPF_Fs32000_Fc55_B2                      0.995316f
 #define BPF_Fs44100_Fc55_A0                      0.001681f
 #define BPF_Fs44100_Fc55_A1                      0.000000f
-#define BPF_Fs44100_Fc55_A2                      -0.001681f
-#define BPF_Fs44100_Fc55_B1                      -1.996537f
+#define BPF_Fs44100_Fc55_A2                      (-0.001681f)
+#define BPF_Fs44100_Fc55_B1                      (-1.996537f)
 #define BPF_Fs44100_Fc55_B2                      0.996599f
 #define BPF_Fs48000_Fc55_A0                      0.001545f
 #define BPF_Fs48000_Fc55_A1                      0.000000f
-#define BPF_Fs48000_Fc55_A2                      -0.001545f
-#define BPF_Fs48000_Fc55_B1                      -1.996823f
+#define BPF_Fs48000_Fc55_A2                      (-0.001545f)
+#define BPF_Fs48000_Fc55_B1                      (-1.996823f)
 #define BPF_Fs48000_Fc55_B2                      0.996875f
 
 #ifdef HIGHER_FS
 #define BPF_Fs96000_Fc55_A0                      0.000762f
 #define BPF_Fs96000_Fc55_A1                      0.000000f
-#define BPF_Fs96000_Fc55_A2                      -0.000762f
-#define BPF_Fs96000_Fc55_B1                      -1.998461f
+#define BPF_Fs96000_Fc55_A2                      (-0.000762f)
+#define BPF_Fs96000_Fc55_B1                      (-1.998461f)
 #define BPF_Fs96000_Fc55_B2                      0.998477f
 
 #define BPF_Fs192000_Fc55_A0                     0.000381f
 #define BPF_Fs192000_Fc55_A1                     0.000000f
-#define BPF_Fs192000_Fc55_A2                     -0.000381f
-#define BPF_Fs192000_Fc55_B1                     -1.999234f
+#define BPF_Fs192000_Fc55_A2                     (-0.000381f)
+#define BPF_Fs192000_Fc55_B1                     (-1.999234f)
 #define BPF_Fs192000_Fc55_B2                     0.999238f
 #endif
 
 /* Coefficients for centre frequency 66Hz */
 #define BPF_Fs8000_Fc66_A0                      0.012648f
 #define BPF_Fs8000_Fc66_A1                      0.000000f
-#define BPF_Fs8000_Fc66_A2                      -0.012648f
-#define BPF_Fs8000_Fc66_B1                      -1.971760f
+#define BPF_Fs8000_Fc66_A2                      (-0.012648f)
+#define BPF_Fs8000_Fc66_B1                      (-1.971760f)
 #define BPF_Fs8000_Fc66_B2                      0.974412f
 #define BPF_Fs11025_Fc66_A0                     0.009209f
 #define BPF_Fs11025_Fc66_A1                     0.000000f
-#define BPF_Fs11025_Fc66_A2                     -0.009209f
-#define BPF_Fs11025_Fc66_B1                     -1.979966f
+#define BPF_Fs11025_Fc66_A2                     (-0.009209f)
+#define BPF_Fs11025_Fc66_B1                     (-1.979966f)
 #define BPF_Fs11025_Fc66_B2                     0.981368f
 #define BPF_Fs12000_Fc66_A0                     0.008468f
 #define BPF_Fs12000_Fc66_A1                     0.000000f
-#define BPF_Fs12000_Fc66_A2                     -0.008468f
-#define BPF_Fs12000_Fc66_B1                     -1.981685f
+#define BPF_Fs12000_Fc66_A2                     (-0.008468f)
+#define BPF_Fs12000_Fc66_B1                     (-1.981685f)
 #define BPF_Fs12000_Fc66_B2                     0.982869f
 #define BPF_Fs16000_Fc66_A0                     0.006364f
 #define BPF_Fs16000_Fc66_A1                     0.000000f
-#define BPF_Fs16000_Fc66_A2                     -0.006364f
-#define BPF_Fs16000_Fc66_B1                     -1.986457f
+#define BPF_Fs16000_Fc66_A2                     (-0.006364f)
+#define BPF_Fs16000_Fc66_B1                     (-1.986457f)
 #define BPF_Fs16000_Fc66_B2                     0.987124f
 #define BPF_Fs22050_Fc66_A0                     0.004626f
 #define BPF_Fs22050_Fc66_A1                     0.000000f
-#define BPF_Fs22050_Fc66_A2                     -0.004626f
-#define BPF_Fs22050_Fc66_B1                     -1.990288f
+#define BPF_Fs22050_Fc66_A2                     (-0.004626f)
+#define BPF_Fs22050_Fc66_B1                     (-1.990288f)
 #define BPF_Fs22050_Fc66_B2                     0.990641f
 #define BPF_Fs24000_Fc66_A0                     0.004252f
 #define BPF_Fs24000_Fc66_A1                     0.000000f
-#define BPF_Fs24000_Fc66_A2                     -0.004252f
-#define BPF_Fs24000_Fc66_B1                     -1.991100f
+#define BPF_Fs24000_Fc66_A2                     (-0.004252f)
+#define BPF_Fs24000_Fc66_B1                     (-1.991100f)
 #define BPF_Fs24000_Fc66_B2                     0.991398f
 #define BPF_Fs32000_Fc66_A0                     0.003192f
 #define BPF_Fs32000_Fc66_A1                     0.000000f
-#define BPF_Fs32000_Fc66_A2                     -0.003192f
-#define BPF_Fs32000_Fc66_B1                     -1.993374f
+#define BPF_Fs32000_Fc66_A2                     (-0.003192f)
+#define BPF_Fs32000_Fc66_B1                     (-1.993374f)
 #define BPF_Fs32000_Fc66_B2                     0.993541f
 #define BPF_Fs44100_Fc66_A0                     0.002318f
 #define BPF_Fs44100_Fc66_A1                     0.000000f
-#define BPF_Fs44100_Fc66_A2                     -0.002318f
-#define BPF_Fs44100_Fc66_B1                     -1.995221f
+#define BPF_Fs44100_Fc66_A2                     (-0.002318f)
+#define BPF_Fs44100_Fc66_B1                     (-1.995221f)
 #define BPF_Fs44100_Fc66_B2                     0.995309f
 #define BPF_Fs48000_Fc66_A0                     0.002131f
 #define BPF_Fs48000_Fc66_A1                     0.000000f
-#define BPF_Fs48000_Fc66_A2                     -0.002131f
-#define BPF_Fs48000_Fc66_B1                     -1.995615f
+#define BPF_Fs48000_Fc66_A2                     (-0.002131f)
+#define BPF_Fs48000_Fc66_B1                     (-1.995615f)
 #define BPF_Fs48000_Fc66_B2                     0.995690f
 
 #ifdef HIGHER_FS
 #define BPF_Fs96000_Fc66_A0                     0.001055f
 #define BPF_Fs96000_Fc66_A1                     0.000000f
-#define BPF_Fs96000_Fc66_A2                     -0.001055f
-#define BPF_Fs96000_Fc66_B1                     -1.997868f
+#define BPF_Fs96000_Fc66_A2                     (-0.001055f)
+#define BPF_Fs96000_Fc66_B1                     (-1.997868f)
 #define BPF_Fs96000_Fc66_B2                     0.997891f
 
 #define BPF_Fs192000_Fc66_A0                    0.000528f
 #define BPF_Fs192000_Fc66_A1                    0.000000f
-#define BPF_Fs192000_Fc66_A2                   -0.000528f
-#define BPF_Fs192000_Fc66_B1                   -1.998939f
+#define BPF_Fs192000_Fc66_A2                   (-0.000528f)
+#define BPF_Fs192000_Fc66_B1                   (-1.998939f)
 #define BPF_Fs192000_Fc66_B2                    0.998945f
 #endif
 
 /* Coefficients for centre frequency 78Hz */
 #define BPF_Fs8000_Fc78_A0                      0.018572f
 #define BPF_Fs8000_Fc78_A1                      0.000000f
-#define BPF_Fs8000_Fc78_A2                      -0.018572f
-#define BPF_Fs8000_Fc78_B1                      -1.958745f
+#define BPF_Fs8000_Fc78_A2                      (-0.018572f)
+#define BPF_Fs8000_Fc78_B1                      (-1.958745f)
 #define BPF_Fs8000_Fc78_B2                      0.962427f
 #define BPF_Fs11025_Fc78_A0                     0.013545f
 #define BPF_Fs11025_Fc78_A1                     0.000000f
-#define BPF_Fs11025_Fc78_A2                     -0.013545f
-#define BPF_Fs11025_Fc78_B1                     -1.970647f
+#define BPF_Fs11025_Fc78_A2                     (-0.013545f)
+#define BPF_Fs11025_Fc78_B1                     (-1.970647f)
 #define BPF_Fs11025_Fc78_B2                     0.972596f
 #define BPF_Fs12000_Fc78_A0                     0.012458f
 #define BPF_Fs12000_Fc78_A1                     0.000000f
-#define BPF_Fs12000_Fc78_A2                     -0.012458f
-#define BPF_Fs12000_Fc78_B1                     -1.973148f
+#define BPF_Fs12000_Fc78_A2                     (-0.012458f)
+#define BPF_Fs12000_Fc78_B1                     (-1.973148f)
 #define BPF_Fs12000_Fc78_B2                     0.974795f
 #define BPF_Fs16000_Fc78_A0                     0.009373f
 #define BPF_Fs16000_Fc78_A1                     0.000000f
-#define BPF_Fs16000_Fc78_A2                     -0.009373f
-#define BPF_Fs16000_Fc78_B1                     -1.980108f
+#define BPF_Fs16000_Fc78_A2                     (-0.009373f)
+#define BPF_Fs16000_Fc78_B1                     (-1.980108f)
 #define BPF_Fs16000_Fc78_B2                     0.981037f
 #define BPF_Fs22050_Fc78_A0                     0.006819f
 #define BPF_Fs22050_Fc78_A1                     0.000000f
-#define BPF_Fs22050_Fc78_A2                     -0.006819f
-#define BPF_Fs22050_Fc78_B1                     -1.985714f
+#define BPF_Fs22050_Fc78_A2                     (-0.006819f)
+#define BPF_Fs22050_Fc78_B1                     (-1.985714f)
 #define BPF_Fs22050_Fc78_B2                     0.986204f
 #define BPF_Fs24000_Fc78_A0                     0.006268f
 #define BPF_Fs24000_Fc78_A1                     0.000000f
-#define BPF_Fs24000_Fc78_A2                     -0.006268f
-#define BPF_Fs24000_Fc78_B1                     -1.986904f
+#define BPF_Fs24000_Fc78_A2                     (-0.006268f)
+#define BPF_Fs24000_Fc78_B1                     (-1.986904f)
 #define BPF_Fs24000_Fc78_B2                     0.987318f
 #define BPF_Fs32000_Fc78_A0                     0.004709f
 #define BPF_Fs32000_Fc78_A1                     0.000000f
-#define BPF_Fs32000_Fc78_A2                     -0.004709f
-#define BPF_Fs32000_Fc78_B1                     -1.990240f
+#define BPF_Fs32000_Fc78_A2                     (-0.004709f)
+#define BPF_Fs32000_Fc78_B1                     (-1.990240f)
 #define BPF_Fs32000_Fc78_B2                     0.990473f
 #define BPF_Fs44100_Fc78_A0                     0.003421f
 #define BPF_Fs44100_Fc78_A1                     0.000000f
-#define BPF_Fs44100_Fc78_A2                     -0.003421f
-#define BPF_Fs44100_Fc78_B1                     -1.992955f
+#define BPF_Fs44100_Fc78_A2                     (-0.003421f)
+#define BPF_Fs44100_Fc78_B1                     (-1.992955f)
 #define BPF_Fs44100_Fc78_B2                     0.993078f
 #define BPF_Fs48000_Fc78_A0                     0.003144f
 #define BPF_Fs48000_Fc78_A1                     0.000000f
-#define BPF_Fs48000_Fc78_A2                     -0.003144f
-#define BPF_Fs48000_Fc78_B1                     -1.993535f
+#define BPF_Fs48000_Fc78_A2                     (-0.003144f)
+#define BPF_Fs48000_Fc78_B1                     (-1.993535f)
 #define BPF_Fs48000_Fc78_B2                     0.993639f
 
 #ifdef HIGHER_FS
 #define BPF_Fs96000_Fc78_A0                     0.001555f
 #define BPF_Fs96000_Fc78_A1                     0.000000f
-#define BPF_Fs96000_Fc78_A2                    -0.0015555f
-#define BPF_Fs96000_Fc78_B1                    -1.996860f
+#define BPF_Fs96000_Fc78_A2                    (-0.0015555f)
+#define BPF_Fs96000_Fc78_B1                    (-1.996860f)
 #define BPF_Fs96000_Fc78_B2                     0.996891f
 
 #define BPF_Fs192000_Fc78_A0                    0.000778f
 #define BPF_Fs192000_Fc78_A1                    0.000000f
-#define BPF_Fs192000_Fc78_A2                   -0.000778f
-#define BPF_Fs192000_Fc78_B1                   -1.998437f
+#define BPF_Fs192000_Fc78_A2                   (-0.000778f)
+#define BPF_Fs192000_Fc78_B1                   (-1.998437f)
 #define BPF_Fs192000_Fc78_B2                    0.998444f
 #endif
 
 /* Coefficients for centre frequency 90Hz */
 #define BPF_Fs8000_Fc90_A0                       0.022760f
 #define BPF_Fs8000_Fc90_A1                       0.000000f
-#define BPF_Fs8000_Fc90_A2                       -0.022760f
-#define BPF_Fs8000_Fc90_B1                       -1.949073f
+#define BPF_Fs8000_Fc90_A2                       (-0.022760f)
+#define BPF_Fs8000_Fc90_B1                       (-1.949073f)
 #define BPF_Fs8000_Fc90_B2                       0.953953f
 #define BPF_Fs11025_Fc90_A0                      0.016619f
 #define BPF_Fs11025_Fc90_A1                      0.000000f
-#define BPF_Fs11025_Fc90_A2                      -0.016619f
-#define BPF_Fs11025_Fc90_B1                      -1.963791f
+#define BPF_Fs11025_Fc90_A2                      (-0.016619f)
+#define BPF_Fs11025_Fc90_B1                      (-1.963791f)
 #define BPF_Fs11025_Fc90_B2                      0.966377f
 #define BPF_Fs12000_Fc90_A0                      0.015289f
 #define BPF_Fs12000_Fc90_A1                      0.000000f
-#define BPF_Fs12000_Fc90_A2                      -0.015289f
-#define BPF_Fs12000_Fc90_B1                      -1.966882f
+#define BPF_Fs12000_Fc90_A2                      (-0.015289f)
+#define BPF_Fs12000_Fc90_B1                      (-1.966882f)
 #define BPF_Fs12000_Fc90_B2                      0.969067f
 #define BPF_Fs16000_Fc90_A0                      0.011511f
 #define BPF_Fs16000_Fc90_A1                      0.000000f
-#define BPF_Fs16000_Fc90_A2                      -0.011511f
-#define BPF_Fs16000_Fc90_B1                      -1.975477f
+#define BPF_Fs16000_Fc90_A2                      (-0.011511f)
+#define BPF_Fs16000_Fc90_B1                      (-1.975477f)
 #define BPF_Fs16000_Fc90_B2                      0.976711f
 #define BPF_Fs22050_Fc90_A0                      0.008379f
 #define BPF_Fs22050_Fc90_A1                      0.000000f
-#define BPF_Fs22050_Fc90_A2                      -0.008379f
-#define BPF_Fs22050_Fc90_B1                      -1.982395f
+#define BPF_Fs22050_Fc90_A2                      (-0.008379f)
+#define BPF_Fs22050_Fc90_B1                      (-1.982395f)
 #define BPF_Fs22050_Fc90_B2                      0.983047f
 #define BPF_Fs24000_Fc90_A0                      0.007704f
 #define BPF_Fs24000_Fc90_A1                      0.000000f
-#define BPF_Fs24000_Fc90_A2                      -0.007704f
-#define BPF_Fs24000_Fc90_B1                      -1.983863f
+#define BPF_Fs24000_Fc90_A2                      (-0.007704f)
+#define BPF_Fs24000_Fc90_B1                      (-1.983863f)
 #define BPF_Fs24000_Fc90_B2                      0.984414f
 #define BPF_Fs32000_Fc90_A0                      0.005789f
 #define BPF_Fs32000_Fc90_A1                      0.000000f
-#define BPF_Fs32000_Fc90_A2                      -0.005789f
-#define BPF_Fs32000_Fc90_B1                      -1.987977f
+#define BPF_Fs32000_Fc90_A2                      (-0.005789f)
+#define BPF_Fs32000_Fc90_B1                      (-1.987977f)
 #define BPF_Fs32000_Fc90_B2                      0.988288f
 #define BPF_Fs44100_Fc90_A0                      0.004207f
 #define BPF_Fs44100_Fc90_A1                      0.000000f
-#define BPF_Fs44100_Fc90_A2                      -0.004207f
-#define BPF_Fs44100_Fc90_B1                      -1.991324f
+#define BPF_Fs44100_Fc90_A2                      (-0.004207f)
+#define BPF_Fs44100_Fc90_B1                      (-1.991324f)
 #define BPF_Fs44100_Fc90_B2                      0.991488f
 #define BPF_Fs48000_Fc90_A0                      0.003867f
 #define BPF_Fs48000_Fc90_A1                      0.000000f
-#define BPF_Fs48000_Fc90_A2                      -0.003867f
-#define BPF_Fs48000_Fc90_B1                      -1.992038f
+#define BPF_Fs48000_Fc90_A2                      (-0.003867f)
+#define BPF_Fs48000_Fc90_B1                      (-1.992038f)
 #define BPF_Fs48000_Fc90_B2                      0.992177f
 
 #ifdef HIGHER_FS
 #define BPF_Fs96000_Fc90_A0                      0.001913f
 #define BPF_Fs96000_Fc90_A1                      0.000000f
-#define BPF_Fs96000_Fc90_A2                     -0.001913f
-#define BPF_Fs96000_Fc90_B1                     -1.996134f
+#define BPF_Fs96000_Fc90_A2                     (-0.001913f)
+#define BPF_Fs96000_Fc90_B1                     (-1.996134f)
 #define BPF_Fs96000_Fc90_B2                      0.996174f
 
 #define BPF_Fs192000_Fc90_A0                     0.000958f
 #define BPF_Fs192000_Fc90_A1                     0.000000f
-#define BPF_Fs192000_Fc90_A2                    -0.000958f
-#define BPF_Fs192000_Fc90_B1                    -1.998075f
+#define BPF_Fs192000_Fc90_A2                    (-0.000958f)
+#define BPF_Fs192000_Fc90_B1                    (-1.998075f)
 #define BPF_Fs192000_Fc90_B2                     0.998085f
 #endif
 
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Coeffs.h b/media/libeffects/lvm/lib/Bundle/src/LVM_Coeffs.h
index 353560c..8c04847 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Coeffs.h
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Coeffs.h
@@ -69,55 +69,55 @@
 #define HPF_Fs22050_Gain6_B2                            0.000000
                                                                     /* Gain =  7.000000 dB */
 #define HPF_Fs22050_Gain7_A0                            1.390177
-#define HPF_Fs22050_Gain7_A1                            -0.020144
+#define HPF_Fs22050_Gain7_A1                            (-0.020144)
 #define HPF_Fs22050_Gain7_A2                            0.000000
 #define HPF_Fs22050_Gain7_B1                            0.370033
 #define HPF_Fs22050_Gain7_B2                            0.000000
                                                                     /* Gain =  8.000000 dB */
 #define HPF_Fs22050_Gain8_A0                            1.476219
-#define HPF_Fs22050_Gain8_A1                            -0.106187
+#define HPF_Fs22050_Gain8_A1                            (-0.106187)
 #define HPF_Fs22050_Gain8_A2                            0.000000
 #define HPF_Fs22050_Gain8_B1                            0.370033
 #define HPF_Fs22050_Gain8_B2                            0.000000
                                                                     /* Gain =  9.000000 dB */
 #define HPF_Fs22050_Gain9_A0                            1.572761
-#define HPF_Fs22050_Gain9_A1                            -0.202728
+#define HPF_Fs22050_Gain9_A1                            (-0.202728)
 #define HPF_Fs22050_Gain9_A2                            0.000000
 #define HPF_Fs22050_Gain9_B1                            0.370033
 #define HPF_Fs22050_Gain9_B2                            0.000000
                                                                     /* Gain =  10.000000 dB */
 #define HPF_Fs22050_Gain10_A0                           1.681082
-#define HPF_Fs22050_Gain10_A1                           -0.311049
+#define HPF_Fs22050_Gain10_A1                           (-0.311049)
 #define HPF_Fs22050_Gain10_A2                           0.000000
 #define HPF_Fs22050_Gain10_B1                           0.370033
 #define HPF_Fs22050_Gain10_B2                           0.000000
                                                                     /* Gain =  11.000000 dB */
 #define HPF_Fs22050_Gain11_A0                           1.802620
-#define HPF_Fs22050_Gain11_A1                           -0.432588
+#define HPF_Fs22050_Gain11_A1                           (-0.432588)
 #define HPF_Fs22050_Gain11_A2                           0.000000
 #define HPF_Fs22050_Gain11_B1                           0.370033
 #define HPF_Fs22050_Gain11_B2                           0.000000
                                                                     /* Gain =  12.000000 dB */
 #define HPF_Fs22050_Gain12_A0                           1.938989
-#define HPF_Fs22050_Gain12_A1                           -0.568956
+#define HPF_Fs22050_Gain12_A1                           (-0.568956)
 #define HPF_Fs22050_Gain12_A2                           0.000000
 #define HPF_Fs22050_Gain12_B1                           0.370033
 #define HPF_Fs22050_Gain12_B2                           0.000000
                                                                     /* Gain =  13.000000 dB */
 #define HPF_Fs22050_Gain13_A0                           2.091997
-#define HPF_Fs22050_Gain13_A1                           -0.721964
+#define HPF_Fs22050_Gain13_A1                           (-0.721964)
 #define HPF_Fs22050_Gain13_A2                           0.000000
 #define HPF_Fs22050_Gain13_B1                           0.370033
 #define HPF_Fs22050_Gain13_B2                           0.000000
                                                                     /* Gain =  14.000000 dB */
 #define HPF_Fs22050_Gain14_A0                           2.263674
-#define HPF_Fs22050_Gain14_A1                           -0.893641
+#define HPF_Fs22050_Gain14_A1                           (-0.893641)
 #define HPF_Fs22050_Gain14_A2                           0.000000
 #define HPF_Fs22050_Gain14_B1                           0.370033
 #define HPF_Fs22050_Gain14_B2                           0.000000
                                                                     /* Gain =  15.000000 dB */
 #define HPF_Fs22050_Gain15_A0                           2.456300
-#define HPF_Fs22050_Gain15_A1                           -1.086267
+#define HPF_Fs22050_Gain15_A1                           (-1.086267)
 #define HPF_Fs22050_Gain15_A2                           0.000000
 #define HPF_Fs22050_Gain15_B1                           0.370033
 #define HPF_Fs22050_Gain15_B2                           0.000000
@@ -148,342 +148,342 @@
 #define HPF_Fs24000_Gain4_B2                            0.000000
                                                                     /* Gain =  5.000000 dB */
 #define HPF_Fs24000_Gain5_A0                            1.284870
-#define HPF_Fs24000_Gain5_A1                            -0.016921
+#define HPF_Fs24000_Gain5_A1                            (-0.016921)
 #define HPF_Fs24000_Gain5_A2                            0.000000
 #define HPF_Fs24000_Gain5_B1                            0.267949
 #define HPF_Fs24000_Gain5_B2                            0.000000
                                                                     /* Gain =  6.000000 dB */
 #define HPF_Fs24000_Gain6_A0                           1.364291
-#define HPF_Fs24000_Gain6_A1                           -0.096342
+#define HPF_Fs24000_Gain6_A1                           (-0.096342)
 #define HPF_Fs24000_Gain6_A2                           0.000000
 #define HPF_Fs24000_Gain6_B1                           0.267949
 #define HPF_Fs24000_Gain6_B2                           0.000000
                                                                     /* Gain =  7.000000 dB */
 #define HPF_Fs24000_Gain7_A0                            1.453403
-#define HPF_Fs24000_Gain7_A1                            -0.185454
+#define HPF_Fs24000_Gain7_A1                            (-0.185454)
 #define HPF_Fs24000_Gain7_A2                            0.000000
 #define HPF_Fs24000_Gain7_B1                            0.267949
 #define HPF_Fs24000_Gain7_B2                            0.000000
                                                                     /* Gain =  8.000000 dB */
 #define HPF_Fs24000_Gain8_A0                            1.553389
-#define HPF_Fs24000_Gain8_A1                            -0.285440
+#define HPF_Fs24000_Gain8_A1                            (-0.285440)
 #define HPF_Fs24000_Gain8_A2                            0.000000
 #define HPF_Fs24000_Gain8_B1                            0.267949
 #define HPF_Fs24000_Gain8_B2                            0.000000
                                                                     /* Gain =  9.000000 dB */
 #define HPF_Fs24000_Gain9_A0                            1.665574
-#define HPF_Fs24000_Gain9_A1                            -0.397625
+#define HPF_Fs24000_Gain9_A1                            (-0.397625)
 #define HPF_Fs24000_Gain9_A2                            0.000000
 #define HPF_Fs24000_Gain9_B1                            0.267949
 #define HPF_Fs24000_Gain9_B2                            0.000000
                                                                     /* Gain =  10.000000 dB */
 #define HPF_Fs24000_Gain10_A0                           1.791449
-#define HPF_Fs24000_Gain10_A1                           -0.523499
+#define HPF_Fs24000_Gain10_A1                           (-0.523499)
 #define HPF_Fs24000_Gain10_A2                           0.000000
 #define HPF_Fs24000_Gain10_B1                           0.267949
 #define HPF_Fs24000_Gain10_B2                           0.000000
                                                                     /* Gain =  11.000000 dB */
 #define HPF_Fs24000_Gain11_A0                           1.932682
-#define HPF_Fs24000_Gain11_A1                           -0.664733
+#define HPF_Fs24000_Gain11_A1                           (-0.664733)
 #define HPF_Fs24000_Gain11_A2                           0.000000
 #define HPF_Fs24000_Gain11_B1                           0.267949
 #define HPF_Fs24000_Gain11_B2                           0.000000
                                                                     /* Gain =  12.000000 dB */
 #define HPF_Fs24000_Gain12_A0                           2.091148
-#define HPF_Fs24000_Gain12_A1                           -0.823199
+#define HPF_Fs24000_Gain12_A1                           (-0.823199)
 #define HPF_Fs24000_Gain12_A2                           0.000000
 #define HPF_Fs24000_Gain12_B1                           0.267949
 #define HPF_Fs24000_Gain12_B2                           0.000000
                                                                     /* Gain =  13.000000 dB */
 #define HPF_Fs24000_Gain13_A0                           2.268950
-#define HPF_Fs24000_Gain13_A1                           -1.001001
+#define HPF_Fs24000_Gain13_A1                           (-1.001001)
 #define HPF_Fs24000_Gain13_A2                           0.000000
 #define HPF_Fs24000_Gain13_B1                           0.267949
 #define HPF_Fs24000_Gain13_B2                           0.000000
                                                                     /* Gain =  14.000000 dB */
 #define HPF_Fs24000_Gain14_A0                           2.468447
-#define HPF_Fs24000_Gain14_A1                           -1.200498
+#define HPF_Fs24000_Gain14_A1                           (-1.200498)
 #define HPF_Fs24000_Gain14_A2                           0.000000
 #define HPF_Fs24000_Gain14_B1                           0.267949
 #define HPF_Fs24000_Gain14_B2                           0.000000
                                                                     /* Gain =  15.000000 dB */
 #define HPF_Fs24000_Gain15_A0                           2.692287
-#define HPF_Fs24000_Gain15_A1                           -1.424338
+#define HPF_Fs24000_Gain15_A1                           (-1.424338)
 #define HPF_Fs24000_Gain15_A2                           0.000000
 #define HPF_Fs24000_Gain15_B1                           0.267949
 #define HPF_Fs24000_Gain15_B2                           0.000000
 /* Coefficients for sample rate 32000Hz */
                                                                     /* Gain =  1.000000 dB */
 #define HPF_Fs32000_Gain1_A0                            1.061009
-#define HPF_Fs32000_Gain1_A1                            -0.061009
+#define HPF_Fs32000_Gain1_A1                            (-0.061009)
 #define HPF_Fs32000_Gain1_A2                            0.000000
-#define HPF_Fs32000_Gain1_B1                            -0.000000
+#define HPF_Fs32000_Gain1_B1                            (-0.000000)
 #define HPF_Fs32000_Gain1_B2                            0.000000
                                                                     /* Gain =  2.000000 dB */
 #define HPF_Fs32000_Gain2_A0                             1.129463
-#define HPF_Fs32000_Gain2_A1                             -0.129463
+#define HPF_Fs32000_Gain2_A1                             (-0.129463)
 #define HPF_Fs32000_Gain2_A2                             0.000000
-#define HPF_Fs32000_Gain2_B1                             -0.000000
+#define HPF_Fs32000_Gain2_B1                             (-0.000000)
 #define HPF_Fs32000_Gain2_B2                             0.000000
                                                                     /* Gain =  3.000000 dB */
 #define HPF_Fs32000_Gain3_A0                             1.206267
-#define HPF_Fs32000_Gain3_A1                             -0.206267
+#define HPF_Fs32000_Gain3_A1                             (-0.206267)
 #define HPF_Fs32000_Gain3_A2                             0.000000
-#define HPF_Fs32000_Gain3_B1                             -0.000000
+#define HPF_Fs32000_Gain3_B1                             (-0.000000)
 #define HPF_Fs32000_Gain3_B2                             0.000000
                                                                     /* Gain =  4.000000 dB */
 #define HPF_Fs32000_Gain4_A0                            1.292447
-#define HPF_Fs32000_Gain4_A1                            -0.292447
+#define HPF_Fs32000_Gain4_A1                            (-0.292447)
 #define HPF_Fs32000_Gain4_A2                            0.000000
-#define HPF_Fs32000_Gain4_B1                            -0.000000
+#define HPF_Fs32000_Gain4_B1                            (-0.000000)
 #define HPF_Fs32000_Gain4_B2                            0.000000
                                                                     /* Gain =  5.000000 dB */
 #define HPF_Fs32000_Gain5_A0                            1.389140
-#define HPF_Fs32000_Gain5_A1                            -0.389140
+#define HPF_Fs32000_Gain5_A1                            (-0.389140)
 #define HPF_Fs32000_Gain5_A2                            0.000000
-#define HPF_Fs32000_Gain5_B1                            -0.000000
+#define HPF_Fs32000_Gain5_B1                            (-0.000000)
 #define HPF_Fs32000_Gain5_B2                            0.000000
                                                                     /* Gain =  6.000000 dB */
 #define HPF_Fs32000_Gain6_A0                             1.497631
-#define HPF_Fs32000_Gain6_A1                             -0.497631
+#define HPF_Fs32000_Gain6_A1                             (-0.497631)
 #define HPF_Fs32000_Gain6_A2                             0.000000
-#define HPF_Fs32000_Gain6_B1                             -0.000000
+#define HPF_Fs32000_Gain6_B1                             (-0.000000)
 #define HPF_Fs32000_Gain6_B2                             0.000000
                                                                     /* Gain =  7.000000 dB */
 #define HPF_Fs32000_Gain7_A0                             1.619361
-#define HPF_Fs32000_Gain7_A1                             -0.619361
+#define HPF_Fs32000_Gain7_A1                             (-0.619361)
 #define HPF_Fs32000_Gain7_A2                             0.000000
-#define HPF_Fs32000_Gain7_B1                             -0.000000
+#define HPF_Fs32000_Gain7_B1                             (-0.000000)
 #define HPF_Fs32000_Gain7_B2                             0.000000
                                                                     /* Gain =  8.000000 dB */
 #define HPF_Fs32000_Gain8_A0                             1.755943
-#define HPF_Fs32000_Gain8_A1                             -0.755943
+#define HPF_Fs32000_Gain8_A1                             (-0.755943)
 #define HPF_Fs32000_Gain8_A2                             0.000000
-#define HPF_Fs32000_Gain8_B1                             -0.000000
+#define HPF_Fs32000_Gain8_B1                             (-0.000000)
 #define HPF_Fs32000_Gain8_B2                             0.000000
                                                                     /* Gain =  9.000000 dB */
 #define HPF_Fs32000_Gain9_A0                             1.909191
-#define HPF_Fs32000_Gain9_A1                             -0.909191
+#define HPF_Fs32000_Gain9_A1                             (-0.909191)
 #define HPF_Fs32000_Gain9_A2                             0.000000
-#define HPF_Fs32000_Gain9_B1                             -0.000000
+#define HPF_Fs32000_Gain9_B1                             (-0.000000)
 #define HPF_Fs32000_Gain9_B2                             0.000000
                                                                     /* Gain =  10.000000 dB */
 #define HPF_Fs32000_Gain10_A0                            2.081139
-#define HPF_Fs32000_Gain10_A1                            -1.081139
+#define HPF_Fs32000_Gain10_A1                            (-1.081139)
 #define HPF_Fs32000_Gain10_A2                            0.000000
-#define HPF_Fs32000_Gain10_B1                            -0.000000
+#define HPF_Fs32000_Gain10_B1                            (-0.000000)
 #define HPF_Fs32000_Gain10_B2                            0.000000
                                                                     /* Gain =  11.000000 dB */
 #define HPF_Fs32000_Gain11_A0                           2.274067
-#define HPF_Fs32000_Gain11_A1                           -1.274067
+#define HPF_Fs32000_Gain11_A1                           (-1.274067)
 #define HPF_Fs32000_Gain11_A2                           0.000000
-#define HPF_Fs32000_Gain11_B1                           -0.000000
+#define HPF_Fs32000_Gain11_B1                           (-0.000000)
 #define HPF_Fs32000_Gain11_B2                           0.000000
                                                                     /* Gain =  12.000000 dB */
 #define HPF_Fs32000_Gain12_A0                          2.490536
-#define HPF_Fs32000_Gain12_A1                          -1.490536
+#define HPF_Fs32000_Gain12_A1                          (-1.490536)
 #define HPF_Fs32000_Gain12_A2                          0.000000
-#define HPF_Fs32000_Gain12_B1                          -0.000000
+#define HPF_Fs32000_Gain12_B1                          (-0.000000)
 #define HPF_Fs32000_Gain12_B2                          0.000000
                                                                     /* Gain =  13.000000 dB */
 #define HPF_Fs32000_Gain13_A0                           2.733418
-#define HPF_Fs32000_Gain13_A1                           -1.733418
+#define HPF_Fs32000_Gain13_A1                           (-1.733418)
 #define HPF_Fs32000_Gain13_A2                           0.000000
-#define HPF_Fs32000_Gain13_B1                           -0.000000
+#define HPF_Fs32000_Gain13_B1                           (-0.000000)
 #define HPF_Fs32000_Gain13_B2                           0.000000
                                                                     /* Gain =  14.000000 dB */
 #define HPF_Fs32000_Gain14_A0                           3.005936
-#define HPF_Fs32000_Gain14_A1                           -2.005936
+#define HPF_Fs32000_Gain14_A1                           (-2.005936)
 #define HPF_Fs32000_Gain14_A2                           0.000000
-#define HPF_Fs32000_Gain14_B1                           -0.000000
+#define HPF_Fs32000_Gain14_B1                           (-0.000000)
 #define HPF_Fs32000_Gain14_B2                           0.000000
                                                                     /* Gain =  15.000000 dB */
 #define HPF_Fs32000_Gain15_A0                          3.311707
-#define HPF_Fs32000_Gain15_A1                          -2.311707
+#define HPF_Fs32000_Gain15_A1                          (-2.311707)
 #define HPF_Fs32000_Gain15_A2                          0.000000
-#define HPF_Fs32000_Gain15_B1                          -0.000000
+#define HPF_Fs32000_Gain15_B1                          (-0.000000)
 #define HPF_Fs32000_Gain15_B2                          0.000000
 /* Coefficients for sample rate 44100Hz */
                                                                     /* Gain =  1.000000 dB */
 #define HPF_Fs44100_Gain1_A0                            1.074364
-#define HPF_Fs44100_Gain1_A1                            -0.293257
+#define HPF_Fs44100_Gain1_A1                            (-0.293257)
 #define HPF_Fs44100_Gain1_A2                            0.000000
-#define HPF_Fs44100_Gain1_B1                            -0.218894
+#define HPF_Fs44100_Gain1_B1                            (-0.218894)
 #define HPF_Fs44100_Gain1_B2                            0.000000
                                                                     /* Gain =  2.000000 dB */
 #define HPF_Fs44100_Gain2_A0                            1.157801
-#define HPF_Fs44100_Gain2_A1                            -0.376695
+#define HPF_Fs44100_Gain2_A1                            (-0.376695)
 #define HPF_Fs44100_Gain2_A2                            0.000000
-#define HPF_Fs44100_Gain2_B1                            -0.218894
+#define HPF_Fs44100_Gain2_B1                            (-0.218894)
 #define HPF_Fs44100_Gain2_B2                            0.000000
                                                                     /* Gain =  3.000000 dB */
 #define HPF_Fs44100_Gain3_A0                           1.251420
-#define HPF_Fs44100_Gain3_A1                           -0.470313
+#define HPF_Fs44100_Gain3_A1                           (-0.470313)
 #define HPF_Fs44100_Gain3_A2                           0.000000
-#define HPF_Fs44100_Gain3_B1                           -0.218894
+#define HPF_Fs44100_Gain3_B1                           (-0.218894)
 #define HPF_Fs44100_Gain3_B2                           0.000000
                                                                     /* Gain =  4.000000 dB */
 #define HPF_Fs44100_Gain4_A0                            1.356461
-#define HPF_Fs44100_Gain4_A1                            -0.575355
+#define HPF_Fs44100_Gain4_A1                            (-0.575355)
 #define HPF_Fs44100_Gain4_A2                            0.000000
-#define HPF_Fs44100_Gain4_B1                            -0.218894
+#define HPF_Fs44100_Gain4_B1                            (-0.218894)
 #define HPF_Fs44100_Gain4_B2                            0.000000
                                                                     /* Gain =  5.000000 dB */
 #define HPF_Fs44100_Gain5_A0                            1.474320
-#define HPF_Fs44100_Gain5_A1                            -0.693213
+#define HPF_Fs44100_Gain5_A1                            (-0.693213)
 #define HPF_Fs44100_Gain5_A2                            0.000000
-#define HPF_Fs44100_Gain5_B1                            -0.218894
+#define HPF_Fs44100_Gain5_B1                            (-0.218894)
 #define HPF_Fs44100_Gain5_B2                            0.000000
                                                                     /* Gain =  6.000000 dB */
 #define HPF_Fs44100_Gain6_A0                           1.606559
-#define HPF_Fs44100_Gain6_A1                           -0.825453
+#define HPF_Fs44100_Gain6_A1                           (-0.825453)
 #define HPF_Fs44100_Gain6_A2                           0.000000
-#define HPF_Fs44100_Gain6_B1                           -0.218894
+#define HPF_Fs44100_Gain6_B1                           (-0.218894)
 #define HPF_Fs44100_Gain6_B2                           0.000000
                                                                     /* Gain =  7.000000 dB */
 #define HPF_Fs44100_Gain7_A0                           1.754935
-#define HPF_Fs44100_Gain7_A1                           -0.973828
+#define HPF_Fs44100_Gain7_A1                           (-0.973828)
 #define HPF_Fs44100_Gain7_A2                           0.000000
-#define HPF_Fs44100_Gain7_B1                           -0.218894
+#define HPF_Fs44100_Gain7_B1                           (-0.218894)
 #define HPF_Fs44100_Gain7_B2                           0.000000
                                                                     /* Gain =  8.000000 dB */
 #define HPF_Fs44100_Gain8_A0                            1.921414
-#define HPF_Fs44100_Gain8_A1                            -1.140308
+#define HPF_Fs44100_Gain8_A1                            (-1.140308)
 #define HPF_Fs44100_Gain8_A2                            0.000000
-#define HPF_Fs44100_Gain8_B1                            -0.218894
+#define HPF_Fs44100_Gain8_B1                            (-0.218894)
 #define HPF_Fs44100_Gain8_B2                            0.000000
                                                                     /* Gain =  9.000000 dB */
 #define HPF_Fs44100_Gain9_A0                            2.108208
-#define HPF_Fs44100_Gain9_A1                            -1.327101
+#define HPF_Fs44100_Gain9_A1                            (-1.327101)
 #define HPF_Fs44100_Gain9_A2                            0.000000
-#define HPF_Fs44100_Gain9_B1                            -0.218894
+#define HPF_Fs44100_Gain9_B1                            (-0.218894)
 #define HPF_Fs44100_Gain9_B2                            0.000000
                                                                     /* Gain =  10.000000 dB */
 #define HPF_Fs44100_Gain10_A0                          2.317793
-#define HPF_Fs44100_Gain10_A1                          -1.536687
+#define HPF_Fs44100_Gain10_A1                          (-1.536687)
 #define HPF_Fs44100_Gain10_A2                          0.000000
-#define HPF_Fs44100_Gain10_B1                          -0.218894
+#define HPF_Fs44100_Gain10_B1                          (-0.218894)
 #define HPF_Fs44100_Gain10_B2                          0.000000
                                                                     /* Gain =  11.000000 dB */
 #define HPF_Fs44100_Gain11_A0                          2.552952
-#define HPF_Fs44100_Gain11_A1                          -1.771846
+#define HPF_Fs44100_Gain11_A1                          (-1.771846)
 #define HPF_Fs44100_Gain11_A2                          0.000000
-#define HPF_Fs44100_Gain11_B1                          -0.218894
+#define HPF_Fs44100_Gain11_B1                          (-0.218894)
 #define HPF_Fs44100_Gain11_B2                          0.000000
                                                                     /* Gain =  12.000000 dB */
 #define HPF_Fs44100_Gain12_A0                          2.816805
-#define HPF_Fs44100_Gain12_A1                          -2.035698
+#define HPF_Fs44100_Gain12_A1                          (-2.035698)
 #define HPF_Fs44100_Gain12_A2                          0.000000
-#define HPF_Fs44100_Gain12_B1                          -0.218894
+#define HPF_Fs44100_Gain12_B1                          (-0.218894)
 #define HPF_Fs44100_Gain12_B2                          0.000000
                                                                     /* Gain =  13.000000 dB */
 #define HPF_Fs44100_Gain13_A0                           3.112852
-#define HPF_Fs44100_Gain13_A1                           -2.331746
+#define HPF_Fs44100_Gain13_A1                           (-2.331746)
 #define HPF_Fs44100_Gain13_A2                           0.000000
-#define HPF_Fs44100_Gain13_B1                           -0.218894
+#define HPF_Fs44100_Gain13_B1                           (-0.218894)
 #define HPF_Fs44100_Gain13_B2                           0.000000
                                                                     /* Gain =  14.000000 dB */
 #define HPF_Fs44100_Gain14_A0                          3.445023
-#define HPF_Fs44100_Gain14_A1                          -2.663916
+#define HPF_Fs44100_Gain14_A1                          (-2.663916)
 #define HPF_Fs44100_Gain14_A2                          0.000000
-#define HPF_Fs44100_Gain14_B1                          -0.218894
+#define HPF_Fs44100_Gain14_B1                          (-0.218894)
 #define HPF_Fs44100_Gain14_B2                          0.000000
                                                                     /* Gain =  15.000000 dB */
 #define HPF_Fs44100_Gain15_A0                          3.817724
-#define HPF_Fs44100_Gain15_A1                          -3.036618
+#define HPF_Fs44100_Gain15_A1                          (-3.036618)
 #define HPF_Fs44100_Gain15_A2                          0.000000
-#define HPF_Fs44100_Gain15_B1                          -0.218894
+#define HPF_Fs44100_Gain15_B1                          (-0.218894)
 #define HPF_Fs44100_Gain15_B2                          0.000000
 /* Coefficients for sample rate 48000Hz */
                                                                     /* Gain =  1.000000 dB */
 #define HPF_Fs48000_Gain1_A0                          1.077357
-#define HPF_Fs48000_Gain1_A1                          -0.345306
+#define HPF_Fs48000_Gain1_A1                          (-0.345306)
 #define HPF_Fs48000_Gain1_A2                          0.000000
-#define HPF_Fs48000_Gain1_B1                          -0.267949
+#define HPF_Fs48000_Gain1_B1                          (-0.267949)
 #define HPF_Fs48000_Gain1_B2                          0.000000
                                                                     /* Gain =  2.000000 dB */
 #define HPF_Fs48000_Gain2_A0                          1.164152
-#define HPF_Fs48000_Gain2_A1                          -0.432101
+#define HPF_Fs48000_Gain2_A1                          (-0.432101)
 #define HPF_Fs48000_Gain2_A2                          0.000000
-#define HPF_Fs48000_Gain2_B1                          -0.267949
+#define HPF_Fs48000_Gain2_B1                          (-0.267949)
 #define HPF_Fs48000_Gain2_B2                          0.000000
                                                                     /* Gain =  3.000000 dB */
 #define HPF_Fs48000_Gain3_A0                          1.261538
-#define HPF_Fs48000_Gain3_A1                          -0.529488
+#define HPF_Fs48000_Gain3_A1                          (-0.529488)
 #define HPF_Fs48000_Gain3_A2                          0.000000
-#define HPF_Fs48000_Gain3_B1                          -0.267949
+#define HPF_Fs48000_Gain3_B1                          (-0.267949)
 #define HPF_Fs48000_Gain3_B2                          0.000000
                                                                     /* Gain =  4.000000 dB */
 #define HPF_Fs48000_Gain4_A0                           1.370807
-#define HPF_Fs48000_Gain4_A1                           -0.638757
+#define HPF_Fs48000_Gain4_A1                           (-0.638757)
 #define HPF_Fs48000_Gain4_A2                           0.000000
-#define HPF_Fs48000_Gain4_B1                           -0.267949
+#define HPF_Fs48000_Gain4_B1                           (-0.267949)
 #define HPF_Fs48000_Gain4_B2                           0.000000
                                                                     /* Gain =  5.000000 dB */
 #define HPF_Fs48000_Gain5_A0                           1.493409
-#define HPF_Fs48000_Gain5_A1                           -0.761359
+#define HPF_Fs48000_Gain5_A1                           (-0.761359)
 #define HPF_Fs48000_Gain5_A2                           0.000000
-#define HPF_Fs48000_Gain5_B1                           -0.267949
+#define HPF_Fs48000_Gain5_B1                           (-0.267949)
 #define HPF_Fs48000_Gain5_B2                           0.000000
                                                                     /* Gain =  6.000000 dB */
 #define HPF_Fs48000_Gain6_A0                            1.630971
-#define HPF_Fs48000_Gain6_A1                            -0.898920
+#define HPF_Fs48000_Gain6_A1                            (-0.898920)
 #define HPF_Fs48000_Gain6_A2                            0.000000
-#define HPF_Fs48000_Gain6_B1                            -0.267949
+#define HPF_Fs48000_Gain6_B1                            (-0.267949)
 #define HPF_Fs48000_Gain6_B2                            0.000000
                                                                     /* Gain =  7.000000 dB */
 #define HPF_Fs48000_Gain7_A0                            1.785318
-#define HPF_Fs48000_Gain7_A1                            -1.053267
+#define HPF_Fs48000_Gain7_A1                            (-1.053267)
 #define HPF_Fs48000_Gain7_A2                            0.000000
-#define HPF_Fs48000_Gain7_B1                            -0.267949
+#define HPF_Fs48000_Gain7_B1                            (-0.267949)
 #define HPF_Fs48000_Gain7_B2                            0.000000
                                                                     /* Gain =  8.000000 dB */
 #define HPF_Fs48000_Gain8_A0                           1.958498
-#define HPF_Fs48000_Gain8_A1                           -1.226447
+#define HPF_Fs48000_Gain8_A1                           (-1.226447)
 #define HPF_Fs48000_Gain8_A2                           0.000000
-#define HPF_Fs48000_Gain8_B1                           -0.267949
+#define HPF_Fs48000_Gain8_B1                           (-0.267949)
 #define HPF_Fs48000_Gain8_B2                           0.000000
                                                                     /* Gain =  9.000000 dB */
 #define HPF_Fs48000_Gain9_A0                          2.152809
-#define HPF_Fs48000_Gain9_A1                          -1.420758
+#define HPF_Fs48000_Gain9_A1                          (-1.420758)
 #define HPF_Fs48000_Gain9_A2                          0.000000
-#define HPF_Fs48000_Gain9_B1                          -0.267949
+#define HPF_Fs48000_Gain9_B1                          (-0.267949)
 #define HPF_Fs48000_Gain9_B2                          0.000000
                                                                     /* Gain =  10.000000 dB */
 #define HPF_Fs48000_Gain10_A0                         2.370829
-#define HPF_Fs48000_Gain10_A1                         -1.638778
+#define HPF_Fs48000_Gain10_A1                         (-1.638778)
 #define HPF_Fs48000_Gain10_A2                         0.000000
-#define HPF_Fs48000_Gain10_B1                         -0.267949
+#define HPF_Fs48000_Gain10_B1                         (-0.267949)
 #define HPF_Fs48000_Gain10_B2                         0.000000
                                                                     /* Gain =  11.000000 dB */
 #define HPF_Fs48000_Gain11_A0                          2.615452
-#define HPF_Fs48000_Gain11_A1                          -1.883401
+#define HPF_Fs48000_Gain11_A1                          (-1.883401)
 #define HPF_Fs48000_Gain11_A2                          0.000000
-#define HPF_Fs48000_Gain11_B1                          -0.267949
+#define HPF_Fs48000_Gain11_B1                          (-0.267949)
 #define HPF_Fs48000_Gain11_B2                          0.000000
                                                                     /* Gain =  12.000000 dB */
 #define HPF_Fs48000_Gain12_A0                          2.889924
-#define HPF_Fs48000_Gain12_A1                          -2.157873
+#define HPF_Fs48000_Gain12_A1                          (-2.157873)
 #define HPF_Fs48000_Gain12_A2                          0.000000
-#define HPF_Fs48000_Gain12_B1                          -0.267949
+#define HPF_Fs48000_Gain12_B1                          (-0.267949)
 #define HPF_Fs48000_Gain12_B2                          0.000000
                                                                     /* Gain =  13.000000 dB */
 #define HPF_Fs48000_Gain13_A0                           3.197886
-#define HPF_Fs48000_Gain13_A1                           -2.465835
+#define HPF_Fs48000_Gain13_A1                           (-2.465835)
 #define HPF_Fs48000_Gain13_A2                           0.000000
-#define HPF_Fs48000_Gain13_B1                           -0.267949
+#define HPF_Fs48000_Gain13_B1                           (-0.267949)
 #define HPF_Fs48000_Gain13_B2                           0.000000
                                                                     /* Gain =  14.000000 dB */
 #define HPF_Fs48000_Gain14_A0                          3.543425
-#define HPF_Fs48000_Gain14_A1                          -2.811374
+#define HPF_Fs48000_Gain14_A1                          (-2.811374)
 #define HPF_Fs48000_Gain14_A2                          0.000000
-#define HPF_Fs48000_Gain14_B1                          -0.267949
+#define HPF_Fs48000_Gain14_B1                          (-0.267949)
 #define HPF_Fs48000_Gain14_B2                          0.000000
                                                                     /* Gain =  15.000000 dB */
 #define HPF_Fs48000_Gain15_A0                         3.931127
-#define HPF_Fs48000_Gain15_A1                         -3.199076
+#define HPF_Fs48000_Gain15_A1                         (-3.199076)
 #define HPF_Fs48000_Gain15_A2                         0.000000
-#define HPF_Fs48000_Gain15_B1                         -0.267949
+#define HPF_Fs48000_Gain15_B1                         (-0.267949)
 #define HPF_Fs48000_Gain15_B2                         0.000000
 
 #ifdef HIGHER_FS
@@ -491,185 +491,185 @@
 /* Coefficients for sample rate 96000Hz */
                                                                  /* Gain =  1.000000 dB */
 #define HPF_Fs96000_Gain1_A0                          1.096233
-#define HPF_Fs96000_Gain1_A1                          -0.673583
+#define HPF_Fs96000_Gain1_A1                          (-0.673583)
 #define HPF_Fs96000_Gain1_A2                          0.000000
-#define HPF_Fs96000_Gain1_B1                          -0.577350
+#define HPF_Fs96000_Gain1_B1                          (-0.577350)
 #define HPF_Fs96000_Gain1_B2                          0.000000
                                                                  /* Gain =  2.000000 dB */
 #define HPF_Fs96000_Gain2_A0                          1.204208
-#define HPF_Fs96000_Gain2_A1                          -0.781558
+#define HPF_Fs96000_Gain2_A1                          (-0.781558)
 #define HPF_Fs96000_Gain2_A2                          0.000000
-#define HPF_Fs96000_Gain2_B1                          -0.577350
+#define HPF_Fs96000_Gain2_B1                          (-0.577350)
 #define HPF_Fs96000_Gain2_B2                          0.000000
                                                                  /* Gain =  3.000000 dB */
 #define HPF_Fs96000_Gain3_A0                          1.325358
-#define HPF_Fs96000_Gain3_A1                          -0.902708
+#define HPF_Fs96000_Gain3_A1                          (-0.902708)
 #define HPF_Fs96000_Gain3_A2                          0.000000
-#define HPF_Fs96000_Gain3_B1                          -0.577350
+#define HPF_Fs96000_Gain3_B1                          (-0.577350)
 #define HPF_Fs96000_Gain3_B2                          0.000000
                                                                  /* Gain =  4.000000 dB */
 #define HPF_Fs96000_Gain4_A0                           1.461291
-#define HPF_Fs96000_Gain4_A1                           -1.038641
+#define HPF_Fs96000_Gain4_A1                           (-1.038641)
 #define HPF_Fs96000_Gain4_A2                           0.000000
-#define HPF_Fs96000_Gain4_B1                           -0.577350
+#define HPF_Fs96000_Gain4_B1                           (-0.577350)
 #define HPF_Fs96000_Gain4_B2                           0.000000
                                                                  /* Gain =  5.000000 dB */
 #define HPF_Fs96000_Gain5_A0                           1.613810
-#define HPF_Fs96000_Gain5_A1                           -1.191160
+#define HPF_Fs96000_Gain5_A1                           (-1.191160)
 #define HPF_Fs96000_Gain5_A2                           0.000000
-#define HPF_Fs96000_Gain5_B1                           -0.577350
+#define HPF_Fs96000_Gain5_B1                           (-0.577350)
 #define HPF_Fs96000_Gain5_B2                           0.000000
                                                                  /* Gain =  6.000000 dB */
 #define HPF_Fs96000_Gain6_A0                            1.784939
-#define HPF_Fs96000_Gain6_A1                            -1.362289
+#define HPF_Fs96000_Gain6_A1                            (-1.362289)
 #define HPF_Fs96000_Gain6_A2                            0.000000
-#define HPF_Fs96000_Gain6_B1                            -0.577350
+#define HPF_Fs96000_Gain6_B1                            (-0.577350)
 #define HPF_Fs96000_Gain6_B2                            0.000000
                                                                 /* Gain =  7.000000 dB */
 #define HPF_Fs96000_Gain7_A0                            1.976949
-#define HPF_Fs96000_Gain7_A1                            -1.554299
+#define HPF_Fs96000_Gain7_A1                            (-1.554299)
 #define HPF_Fs96000_Gain7_A2                            0.000000
-#define HPF_Fs96000_Gain7_B1                            -0.577350
+#define HPF_Fs96000_Gain7_B1                            (-0.577350)
 #define HPF_Fs96000_Gain7_B2                            0.000000
                                                                  /* Gain =  8.000000 dB */
 #define HPF_Fs96000_Gain8_A0                           2.192387
-#define HPF_Fs96000_Gain8_A1                           -1.769738
+#define HPF_Fs96000_Gain8_A1                           (-1.769738)
 #define HPF_Fs96000_Gain8_A2                           0.000000
-#define HPF_Fs96000_Gain8_B1                           -0.577350
+#define HPF_Fs96000_Gain8_B1                           (-0.577350)
 #define HPF_Fs96000_Gain8_B2                           0.000000
                                                                 /* Gain =  9.000000 dB */
 #define HPF_Fs96000_Gain9_A0                          2.434113
-#define HPF_Fs96000_Gain9_A1                          -2.011464
+#define HPF_Fs96000_Gain9_A1                          (-2.011464)
 #define HPF_Fs96000_Gain9_A2                          0.000000
-#define HPF_Fs96000_Gain9_B1                          -0.577350
+#define HPF_Fs96000_Gain9_B1                          (-0.577350)
 #define HPF_Fs96000_Gain9_B2                          0.000000
                                                                /* Gain =  10.000000 dB */
 #define HPF_Fs96000_Gain10_A0                        2.705335
-#define HPF_Fs96000_Gain10_A1                        -2.282685
+#define HPF_Fs96000_Gain10_A1                        (-2.282685)
 #define HPF_Fs96000_Gain10_A2                         0.000000
-#define HPF_Fs96000_Gain10_B1                         -0.577350
+#define HPF_Fs96000_Gain10_B1                         (-0.577350)
 #define HPF_Fs96000_Gain10_B2                         0.000000
                                                               /* Gain =  11.000000 dB */
 #define HPF_Fs96000_Gain11_A0                          3.009650
-#define HPF_Fs96000_Gain11_A1                          -2.587000
+#define HPF_Fs96000_Gain11_A1                          (-2.587000)
 #define HPF_Fs96000_Gain11_A2                          0.000000
-#define HPF_Fs96000_Gain11_B1                          -0.577350
+#define HPF_Fs96000_Gain11_B1                          (-0.577350)
 #define HPF_Fs96000_Gain11_B2                          0.000000
                                                                   /* Gain =  12.000000 dB */
 #define HPF_Fs96000_Gain12_A0                          3.351097
-#define HPF_Fs96000_Gain12_A1                          -2.928447
+#define HPF_Fs96000_Gain12_A1                          (-2.928447)
 #define HPF_Fs96000_Gain12_A2                          0.000000
-#define HPF_Fs96000_Gain12_B1                          -0.577350
+#define HPF_Fs96000_Gain12_B1                          (-0.577350)
 #define HPF_Fs96000_Gain12_B2                          0.000000
                                                                 /* Gain =  13.000000 dB */
 #define HPF_Fs96000_Gain13_A0                           3.734207
-#define HPF_Fs96000_Gain13_A1                           -3.311558
+#define HPF_Fs96000_Gain13_A1                           (-3.311558)
 #define HPF_Fs96000_Gain13_A2                           0.000000
-#define HPF_Fs96000_Gain13_B1                           -0.577350
+#define HPF_Fs96000_Gain13_B1                           (-0.577350)
 #define HPF_Fs96000_Gain13_B2                           0.000000
                                                                  /* Gain =  14.000000 dB */
 #define HPF_Fs96000_Gain14_A0                         4.164064
-#define HPF_Fs96000_Gain14_A1                         -3.741414
+#define HPF_Fs96000_Gain14_A1                         (-3.741414)
 #define HPF_Fs96000_Gain14_A2                          0.000000
-#define HPF_Fs96000_Gain14_B1                          -0.577350
+#define HPF_Fs96000_Gain14_B1                          (-0.577350)
 #define HPF_Fs96000_Gain14_B2                          0.000000
                                                                  /* Gain =  15.000000 dB */
 #define HPF_Fs96000_Gain15_A0                         4.646371
-#define HPF_Fs96000_Gain15_A1                         -4.223721
+#define HPF_Fs96000_Gain15_A1                         (-4.223721)
 #define HPF_Fs96000_Gain15_A2                         0.000000
-#define HPF_Fs96000_Gain15_B1                         -0.577350
+#define HPF_Fs96000_Gain15_B1                         (-0.577350)
 #define HPF_Fs96000_Gain15_B2                         0.000000
 
 /* Coefficients for sample rate 192000Hz */
                                                                   /* Gain =  1.000000 dB */
 #define HPF_Fs192000_Gain1_A0                          1.107823
-#define HPF_Fs192000_Gain1_A1                          -0.875150
+#define HPF_Fs192000_Gain1_A1                          (-0.875150)
 #define HPF_Fs192000_Gain1_A2                          0.000000
-#define HPF_Fs192000_Gain1_B1                          -0.767327
+#define HPF_Fs192000_Gain1_B1                          (-0.767327)
 #define HPF_Fs192000_Gain1_B2                          0.000000
                                                                   /* Gain =  2.000000 dB */
 #define HPF_Fs192000_Gain2_A0                          1.228803
-#define HPF_Fs192000_Gain2_A1                          -0.996130
+#define HPF_Fs192000_Gain2_A1                          (-0.996130)
 #define HPF_Fs192000_Gain2_A2                          0.000000
-#define HPF_Fs192000_Gain2_B1                          -0.767327
+#define HPF_Fs192000_Gain2_B1                          (-0.767327)
 #define HPF_Fs192000_Gain2_B2                          0.000000
                                                                    /* Gain =  3.000000 dB */
 #define HPF_Fs192000_Gain3_A0                          1.364544
-#define HPF_Fs192000_Gain3_A1                          -1.131871
+#define HPF_Fs192000_Gain3_A1                          (-1.131871)
 #define HPF_Fs192000_Gain3_A2                          0.000000
-#define HPF_Fs192000_Gain3_B1                          -0.767327
+#define HPF_Fs192000_Gain3_B1                          (-0.767327)
 #define HPF_Fs192000_Gain3_B2                          0.000000
                                                                    /* Gain =  4.000000 dB */
 #define HPF_Fs192000_Gain4_A0                          1.516849
-#define HPF_Fs192000_Gain4_A1                          -1.284176
+#define HPF_Fs192000_Gain4_A1                          (-1.284176)
 #define HPF_Fs192000_Gain4_A2                           0.000000
-#define HPF_Fs192000_Gain4_B1                           -0.767327
+#define HPF_Fs192000_Gain4_B1                           (-0.767327)
 #define HPF_Fs192000_Gain4_B2                           0.000000
                                                                    /* Gain =  5.000000 dB */
 #define HPF_Fs192000_Gain5_A0                           1.687737
-#define HPF_Fs192000_Gain5_A1                           -1.455064
+#define HPF_Fs192000_Gain5_A1                           (-1.455064)
 #define HPF_Fs192000_Gain5_A2                           0.000000
-#define HPF_Fs192000_Gain5_B1                           -0.767327
+#define HPF_Fs192000_Gain5_B1                           (-0.767327)
 #define HPF_Fs192000_Gain5_B2                           0.000000
                                                                    /* Gain =  6.000000 dB */
 #define HPF_Fs192000_Gain6_A0                            1.879477
-#define HPF_Fs192000_Gain6_A1                            -1.646804
+#define HPF_Fs192000_Gain6_A1                            (-1.646804)
 #define HPF_Fs192000_Gain6_A2                            0.000000
-#define HPF_Fs192000_Gain6_B1                            -0.767327
+#define HPF_Fs192000_Gain6_B1                            (-0.767327)
 #define HPF_Fs192000_Gain6_B2                            0.000000
                                                                  /* Gain =  7.000000 dB */
 #define HPF_Fs192000_Gain7_A0                            2.094613
-#define HPF_Fs192000_Gain7_A1                            -1.861940
+#define HPF_Fs192000_Gain7_A1                            (-1.861940)
 #define HPF_Fs192000_Gain7_A2                            0.000000
-#define HPF_Fs192000_Gain7_B1                            -0.767327
+#define HPF_Fs192000_Gain7_B1                            (-0.767327)
 #define HPF_Fs192000_Gain7_B2                            0.000000
                                                                    /* Gain =  8.000000 dB */
 #define HPF_Fs192000_Gain8_A0                           2.335999
-#define HPF_Fs192000_Gain8_A1                           -2.103326
+#define HPF_Fs192000_Gain8_A1                           (-2.103326)
 #define HPF_Fs192000_Gain8_A2                           0.000000
-#define HPF_Fs192000_Gain8_B1                           -0.767327
+#define HPF_Fs192000_Gain8_B1                           (-0.767327)
 #define HPF_Fs192000_Gain8_B2                           0.000000
                                                                    /* Gain =  9.000000 dB */
 #define HPF_Fs192000_Gain9_A0                          2.606839
-#define HPF_Fs192000_Gain9_A1                          -2.374166
+#define HPF_Fs192000_Gain9_A1                          (-2.374166)
 #define HPF_Fs192000_Gain9_A2                          0.000000
-#define HPF_Fs192000_Gain9_B1                          -0.767327
+#define HPF_Fs192000_Gain9_B1                          (-0.767327)
 #define HPF_Fs192000_Gain9_B2                          0.000000
                                                                  /* Gain =  10.000000 dB */
 #define HPF_Fs192000_Gain10_A0                        2.910726
-#define HPF_Fs192000_Gain10_A1                        -2.678053
+#define HPF_Fs192000_Gain10_A1                        (-2.678053)
 #define HPF_Fs192000_Gain10_A2                         0.000000
-#define HPF_Fs192000_Gain10_B1                         -0.767327
+#define HPF_Fs192000_Gain10_B1                         (-0.767327)
 #define HPF_Fs192000_Gain10_B2                         0.000000
                                                                   /* Gain =  11.000000 dB */
 #define HPF_Fs192000_Gain11_A0                          3.251693
-#define HPF_Fs192000_Gain11_A1                          -3.019020
+#define HPF_Fs192000_Gain11_A1                          (-3.019020)
 #define HPF_Fs192000_Gain11_A2                          0.000000
-#define HPF_Fs192000_Gain11_B1                          -0.767327
+#define HPF_Fs192000_Gain11_B1                          (-0.767327)
 #define HPF_Fs192000_Gain11_B2                          0.000000
                                                                   /* Gain =  12.000000 dB */
 #define HPF_Fs192000_Gain12_A0                          3.634264
-#define HPF_Fs192000_Gain12_A1                          -3.401591
+#define HPF_Fs192000_Gain12_A1                          (-3.401591)
 #define HPF_Fs192000_Gain12_A2                          0.000000
-#define HPF_Fs192000_Gain12_B1                          -0.767327
+#define HPF_Fs192000_Gain12_B1                          (-0.767327)
 #define HPF_Fs192000_Gain12_B2                          0.000000
                                                                 /* Gain =  13.000000 dB */
 #define HPF_Fs192000_Gain13_A0                           4.063516
-#define HPF_Fs192000_Gain13_A1                           -3.830843
+#define HPF_Fs192000_Gain13_A1                           (-3.830843)
 #define HPF_Fs192000_Gain13_A2                           0.000000
-#define HPF_Fs192000_Gain13_B1                           -0.767327
+#define HPF_Fs192000_Gain13_B1                           (-0.767327)
 #define HPF_Fs192000_Gain13_B2                           0.000000
                                                                 /* Gain =  14.000000 dB */
 #define HPF_Fs192000_Gain14_A0                          4.545145
-#define HPF_Fs192000_Gain14_A1                          -4.312472
+#define HPF_Fs192000_Gain14_A1                          (-4.312472)
 #define HPF_Fs192000_Gain14_A2                          0.000000
-#define HPF_Fs192000_Gain14_B1                          -0.767327
+#define HPF_Fs192000_Gain14_B1                          (-0.767327)
 #define HPF_Fs192000_Gain14_B2                          0.000000
                                                                   /* Gain =  15.000000 dB */
 #define HPF_Fs192000_Gain15_A0                         5.085542
-#define HPF_Fs192000_Gain15_A1                         -4.852868
+#define HPF_Fs192000_Gain15_A1                         (-4.852868)
 #define HPF_Fs192000_Gain15_A2                         0.000000
-#define HPF_Fs192000_Gain15_B1                         -0.767327
+#define HPF_Fs192000_Gain15_B1                         (-0.767327)
 #define HPF_Fs192000_Gain15_B2                         0.000000
 
 #endif
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
index cb15b60..ea16072 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
@@ -44,9 +44,6 @@
 
 #define LVM_MAXINT_8            127                 /* Maximum positive integer size */
 #define LVM_MAXINT_16           32767
-#ifdef BUILD_FLOAT
-#define LVM_MAXFLOAT            1.0f
-#endif
 #define LVM_MAXINT_32           2147483647
 #define LVM_MAXENUM             2147483647
 
@@ -99,8 +96,32 @@
 typedef     uint32_t            LVM_UINT32;         /* Unsigned 32-bit word */
 
 #ifdef BUILD_FLOAT
-typedef     float               LVM_FLOAT;          /* single precission floating point*/
-#endif
+
+#define LVM_MAXFLOAT            1.f
+
+typedef     float               LVM_FLOAT;          /* single precision floating point */
+
+// If NATIVE_FLOAT_BUFFER is defined, we expose effects as floating point format;
+// otherwise we expose as integer 16 bit and translate to float for the effect libraries.
+// Hence, NATIVE_FLOAT_BUFFER should only be enabled under BUILD_FLOAT compilation.
+
+#define NATIVE_FLOAT_BUFFER
+
+#endif // BUILD_FLOAT
+
+// Select whether we expose int16_t or float buffers.
+#ifdef NATIVE_FLOAT_BUFFER
+
+#define    EFFECT_BUFFER_FORMAT AUDIO_FORMAT_PCM_FLOAT
+typedef     float               effect_buffer_t;
+
+#else // NATIVE_FLOAT_BUFFER
+
+#define    EFFECT_BUFFER_FORMAT AUDIO_FORMAT_PCM_16_BIT
+typedef     int16_t             effect_buffer_t;
+
+#endif // NATIVE_FLOAT_BUFFER
+
 /****************************************************************************************/
 /*                                                                                      */
 /*  Standard Enumerated types                                                           */
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Coeffs.h b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Coeffs.h
index f0deb6c..42ea46f 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Coeffs.h
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Coeffs.h
@@ -26,21 +26,21 @@
 /*                                                                                  */
 /************************************************************************************/
 #ifdef BUILD_FLOAT
-#define LVEQNB_Gain_Neg15_dB                             -0.822172f
-#define LVEQNB_Gain_Neg14_dB                             -0.800474f
-#define LVEQNB_Gain_Neg13_dB                             -0.776128f
-#define LVEQNB_Gain_Neg12_dB                             -0.748811f
-#define LVEQNB_Gain_Neg11_dB                             -0.718162f
-#define LVEQNB_Gain_Neg10_dB                             -0.683772f
-#define LVEQNB_Gain_Neg9_dB                              -0.645187f
-#define LVEQNB_Gain_Neg8_dB                              -0.601893f
-#define LVEQNB_Gain_Neg7_dB                              -0.553316f
-#define LVEQNB_Gain_Neg6_dB                              -0.498813f
-#define LVEQNB_Gain_Neg5_dB                              -0.437659f
-#define LVEQNB_Gain_Neg4_dB                              -0.369043f
-#define LVEQNB_Gain_Neg3_dB                              -0.292054f
-#define LVEQNB_Gain_Neg2_dB                              -0.205672f
-#define LVEQNB_Gain_Neg1_dB                              -0.108749f
+#define LVEQNB_Gain_Neg15_dB                             (-0.822172f)
+#define LVEQNB_Gain_Neg14_dB                             (-0.800474f)
+#define LVEQNB_Gain_Neg13_dB                             (-0.776128f)
+#define LVEQNB_Gain_Neg12_dB                             (-0.748811f)
+#define LVEQNB_Gain_Neg11_dB                             (-0.718162f)
+#define LVEQNB_Gain_Neg10_dB                             (-0.683772f)
+#define LVEQNB_Gain_Neg9_dB                              (-0.645187f)
+#define LVEQNB_Gain_Neg8_dB                              (-0.601893f)
+#define LVEQNB_Gain_Neg7_dB                              (-0.553316f)
+#define LVEQNB_Gain_Neg6_dB                              (-0.498813f)
+#define LVEQNB_Gain_Neg5_dB                              (-0.437659f)
+#define LVEQNB_Gain_Neg4_dB                              (-0.369043f)
+#define LVEQNB_Gain_Neg3_dB                              (-0.292054f)
+#define LVEQNB_Gain_Neg2_dB                              (-0.205672f)
+#define LVEQNB_Gain_Neg1_dB                              (-0.108749f)
 #define LVEQNB_Gain_0_dB                                  0.000000f
 #define LVEQNB_Gain_1_dB                                  0.122018f
 #define LVEQNB_Gain_2_dB                                  0.258925f
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Headphone_Coeffs.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Headphone_Coeffs.h
index 4f5221a..0c2fe53 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Headphone_Coeffs.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Headphone_Coeffs.h
@@ -27,127 +27,127 @@
 #ifdef BUILD_FLOAT
 /* Stereo Enhancer coefficients for 8000 Hz sample rate, scaled with 0.161258 */
 #define CS_MIDDLE_8000_A0                           0.227720
-#define CS_MIDDLE_8000_A1                          -0.215125
+#define CS_MIDDLE_8000_A1                          (-0.215125)
 #define CS_MIDDLE_8000_A2                           0.000000
-#define CS_MIDDLE_8000_B1                          -0.921899
+#define CS_MIDDLE_8000_B1                          (-0.921899)
 #define CS_MIDDLE_8000_B2                           0.000000
 #define CS_MIDDLE_8000_SCALE                        15
 #define CS_SIDE_8000_A0                             0.611441
-#define CS_SIDE_8000_A1                            -0.380344
-#define CS_SIDE_8000_A2                            -0.231097
-#define CS_SIDE_8000_B1                            -0.622470
-#define CS_SIDE_8000_B2                            -0.130759
+#define CS_SIDE_8000_A1                            (-0.380344)
+#define CS_SIDE_8000_A2                            (-0.231097)
+#define CS_SIDE_8000_B1                            (-0.622470)
+#define CS_SIDE_8000_B2                            (-0.130759)
 #define CS_SIDE_8000_SCALE                         15
 
 /* Stereo Enhancer coefficients for 11025Hz sample rate, scaled with 0.162943 */
 #define CS_MIDDLE_11025_A0                       0.230838
-#define CS_MIDDLE_11025_A1                      -0.221559
+#define CS_MIDDLE_11025_A1                      (-0.221559)
 #define CS_MIDDLE_11025_A2                       0.000000
-#define CS_MIDDLE_11025_B1                      -0.943056
+#define CS_MIDDLE_11025_B1                      (-0.943056)
 #define CS_MIDDLE_11025_B2                       0.000000
 #define CS_MIDDLE_11025_SCALE                    15
 #define CS_SIDE_11025_A0                         0.557372
-#define CS_SIDE_11025_A1                        -0.391490
-#define CS_SIDE_11025_A2                        -0.165881
-#define CS_SIDE_11025_B1                        -0.880608
+#define CS_SIDE_11025_A1                        (-0.391490)
+#define CS_SIDE_11025_A2                        (-0.165881)
+#define CS_SIDE_11025_B1                        (-0.880608)
 #define CS_SIDE_11025_B2                         0.032397
 #define CS_SIDE_11025_SCALE                      15
 
 /* Stereo Enhancer coefficients for 12000Hz sample rate, scaled with 0.162191 */
 #define CS_MIDDLE_12000_A0                        0.229932
-#define CS_MIDDLE_12000_A1                       -0.221436
+#define CS_MIDDLE_12000_A1                       (-0.221436)
 #define CS_MIDDLE_12000_A2                        0.000000
-#define CS_MIDDLE_12000_B1                       -0.947616
+#define CS_MIDDLE_12000_B1                       (-0.947616)
 #define CS_MIDDLE_12000_B2                        0.000000
 #define CS_MIDDLE_12000_SCALE                        15
 #define CS_SIDE_12000_A0                         0.558398
-#define CS_SIDE_12000_A1                        -0.392211
-#define CS_SIDE_12000_A2                        -0.166187
-#define CS_SIDE_12000_B1                        -0.892550
+#define CS_SIDE_12000_A1                        (-0.392211)
+#define CS_SIDE_12000_A2                        (-0.166187)
+#define CS_SIDE_12000_B1                        (-0.892550)
 #define CS_SIDE_12000_B2                         0.032856
 #define CS_SIDE_12000_SCALE                          15
 
 /* Stereo Enhancer coefficients for 16000Hz sample rate, scaled with 0.162371 */
 #define CS_MIDDLE_16000_A0                       0.230638
-#define CS_MIDDLE_16000_A1                      -0.224232
+#define CS_MIDDLE_16000_A1                      (-0.224232)
 #define CS_MIDDLE_16000_A2                       0.000000
-#define CS_MIDDLE_16000_B1                      -0.960550
+#define CS_MIDDLE_16000_B1                      (-0.960550)
 #define CS_MIDDLE_16000_B2                       0.000000
 #define CS_MIDDLE_16000_SCALE                        15
 #define CS_SIDE_16000_A0                         0.499695
-#define CS_SIDE_16000_A1                        -0.355543
-#define CS_SIDE_16000_A2                        -0.144152
-#define CS_SIDE_16000_B1                        -1.050788
+#define CS_SIDE_16000_A1                        (-0.355543)
+#define CS_SIDE_16000_A2                        (-0.144152)
+#define CS_SIDE_16000_B1                        (-1.050788)
 #define CS_SIDE_16000_B2                         0.144104
 #define CS_SIDE_16000_SCALE                          14
 
 /* Stereo Enhancer coefficients for 22050Hz sample rate, scaled with 0.160781 */
 #define CS_MIDDLE_22050_A0                       0.228749
-#define CS_MIDDLE_22050_A1                      -0.224128
+#define CS_MIDDLE_22050_A1                      (-0.224128)
 #define CS_MIDDLE_22050_A2                       0.000000
-#define CS_MIDDLE_22050_B1                      -0.971262
+#define CS_MIDDLE_22050_B1                      (-0.971262)
 #define CS_MIDDLE_22050_B2                       0.000000
 #define CS_MIDDLE_22050_SCALE                        15
 #define CS_SIDE_22050_A0                          0.440112
-#define CS_SIDE_22050_A1                         -0.261096
-#define CS_SIDE_22050_A2                         -0.179016
-#define CS_SIDE_22050_B1                         -1.116786
+#define CS_SIDE_22050_A1                         (-0.261096)
+#define CS_SIDE_22050_A2                         (-0.179016)
+#define CS_SIDE_22050_B1                         (-1.116786)
 #define CS_SIDE_22050_B2                          0.182507
 #define CS_SIDE_22050_SCALE                          14
 
 /* Stereo Enhancer coefficients for 24000Hz sample rate, scaled with 0.161882 */
 #define CS_MIDDLE_24000_A0                         0.230395
-#define CS_MIDDLE_24000_A1                        -0.226117
+#define CS_MIDDLE_24000_A1                        (-0.226117)
 #define CS_MIDDLE_24000_A2                         0.000000
-#define CS_MIDDLE_24000_B1                        -0.973573
+#define CS_MIDDLE_24000_B1                        (-0.973573)
 #define CS_MIDDLE_24000_B2                         0.000000
 #define CS_MIDDLE_24000_SCALE                        15
 #define CS_SIDE_24000_A0                           0.414770
-#define CS_SIDE_24000_A1                          -0.287182
-#define CS_SIDE_24000_A2                          -0.127588
-#define CS_SIDE_24000_B1                          -1.229648
+#define CS_SIDE_24000_A1                          (-0.287182)
+#define CS_SIDE_24000_A2                          (-0.127588)
+#define CS_SIDE_24000_B1                          (-1.229648)
 #define CS_SIDE_24000_B2                           0.282177
 #define CS_SIDE_24000_SCALE                          14
 
 /* Stereo Enhancer coefficients for 32000Hz sample rate, scaled with 0.160322 */
 #define CS_MIDDLE_32000_A0                          0.228400
-#define CS_MIDDLE_32000_A1                         -0.225214
+#define CS_MIDDLE_32000_A1                         (-0.225214)
 #define CS_MIDDLE_32000_A2                          0.000000
-#define CS_MIDDLE_32000_B1                         -0.980126
+#define CS_MIDDLE_32000_B1                         (-0.980126)
 #define CS_MIDDLE_32000_B2                          0.000000
 #define CS_MIDDLE_32000_SCALE                        15
 #define CS_SIDE_32000_A0                            0.364579
-#define CS_SIDE_32000_A1                           -0.207355
-#define CS_SIDE_32000_A2                           -0.157224
-#define CS_SIDE_32000_B1                           -1.274231
+#define CS_SIDE_32000_A1                           (-0.207355)
+#define CS_SIDE_32000_A2                           (-0.157224)
+#define CS_SIDE_32000_B1                           (-1.274231)
 #define CS_SIDE_32000_B2                            0.312495
 #define CS_SIDE_32000_SCALE                          14
 
 /* Stereo Enhancer coefficients for 44100Hz sample rate, scaled with 0.163834 */
 #define CS_MIDDLE_44100_A0                     0.233593
-#define CS_MIDDLE_44100_A1                    -0.231225
+#define CS_MIDDLE_44100_A1                    (-0.231225)
 #define CS_MIDDLE_44100_A2                     0.000000
-#define CS_MIDDLE_44100_B1                    -0.985545
+#define CS_MIDDLE_44100_B1                    (-0.985545)
 #define CS_MIDDLE_44100_B2                     0.000000
 #define CS_MIDDLE_44100_SCALE                        15
 #define CS_SIDE_44100_A0                       0.284573
-#define CS_SIDE_44100_A1                      -0.258910
-#define CS_SIDE_44100_A2                      -0.025662
-#define CS_SIDE_44100_B1                      -1.572248
+#define CS_SIDE_44100_A1                      (-0.258910)
+#define CS_SIDE_44100_A2                      (-0.025662)
+#define CS_SIDE_44100_B1                      (-1.572248)
 #define CS_SIDE_44100_B2                       0.588399
 #define CS_SIDE_44100_SCALE                  14
 
 /* Stereo Enhancer coefficients for 48000Hz sample rate, scaled with 0.164402 */
 #define CS_MIDDLE_48000_A0                     0.234445
-#define CS_MIDDLE_48000_A1                    -0.232261
+#define CS_MIDDLE_48000_A1                    (-0.232261)
 #define CS_MIDDLE_48000_A2                     0.000000
-#define CS_MIDDLE_48000_B1                    -0.986713
+#define CS_MIDDLE_48000_B1                    (-0.986713)
 #define CS_MIDDLE_48000_B2                     0.000000
 #define CS_MIDDLE_48000_SCALE                        15
 #define CS_SIDE_48000_A0                     0.272606
-#define CS_SIDE_48000_A1                    -0.266952
-#define CS_SIDE_48000_A2                    -0.005654
-#define CS_SIDE_48000_B1                    -1.617141
+#define CS_SIDE_48000_A1                    (-0.266952)
+#define CS_SIDE_48000_A2                    (-0.005654)
+#define CS_SIDE_48000_B1                    (-1.617141)
 #define CS_SIDE_48000_B2                     0.630405
 #define CS_SIDE_48000_SCALE                          14
 
@@ -155,31 +155,31 @@
 /* Stereo Enhancer coefficients for 96000Hz sample rate, scaled with  0.165*/
 /* high pass filter with cutoff frequency 102.18 Hz*/
 #define CS_MIDDLE_96000_A0                     0.235532
-#define CS_MIDDLE_96000_A1                    -0.234432
+#define CS_MIDDLE_96000_A1                    (-0.234432)
 #define CS_MIDDLE_96000_A2                     0.000000
-#define CS_MIDDLE_96000_B1                    -0.993334
+#define CS_MIDDLE_96000_B1                    (-0.993334)
 #define CS_MIDDLE_96000_B2                     0.000000
 #define CS_MIDDLE_96000_SCALE                        15
 /* bandpass filter with fc1 270 and fc2 3703, designed using 2nd order butterworth */
 #define CS_SIDE_96000_A0                     0.016727
 #define CS_SIDE_96000_A1                     0.000000
-#define CS_SIDE_96000_A2                    -0.016727
-#define CS_SIDE_96000_B1                    -1.793372
+#define CS_SIDE_96000_A2                    (-0.016727)
+#define CS_SIDE_96000_B1                    (-1.793372)
 #define CS_SIDE_96000_B2                     0.797236
 #define CS_SIDE_96000_SCALE                        14
 
 /* Stereo Enhancer coefficients for 192000Hz sample rate, scaled with  0.1689*/
 #define CS_MIDDLE_192000_A0                     0.241219
-#define CS_MIDDLE_192000_A1                    -0.240656
+#define CS_MIDDLE_192000_A1                    (-0.240656)
 #define CS_MIDDLE_192000_A2                     0.000000
-#define CS_MIDDLE_192000_B1                    -0.996661
+#define CS_MIDDLE_192000_B1                    (-0.996661)
 #define CS_MIDDLE_192000_B2                     0.000000
 #define CS_MIDDLE_192000_SCALE                        15
 /* bandpass filter with fc1 270 and fc2 3703, designed using 2nd order butterworth */
 #define CS_SIDE_192000_A0                     0.008991
-#define CS_SIDE_192000_A1                    -0.000000
-#define CS_SIDE_192000_A2                    -0.008991
-#define CS_SIDE_192000_B1                    -1.892509
+#define CS_SIDE_192000_A1                    (-0.000000)
+#define CS_SIDE_192000_A2                    (-0.008991)
+#define CS_SIDE_192000_B1                    (-1.892509)
 #define CS_SIDE_192000_B2                     0.893524
 #define CS_SIDE_192000_SCALE                       14
 #endif
@@ -203,74 +203,74 @@
 
 /* Reverb coefficients for 8000 Hz sample rate, scaled with 1.038030 */
 #define CS_REVERB_8000_A0                          0.667271
-#define CS_REVERB_8000_A1                         -0.667271
+#define CS_REVERB_8000_A1                         (-0.667271)
 #define CS_REVERB_8000_A2                          0.000000
-#define CS_REVERB_8000_B1                         -0.668179
+#define CS_REVERB_8000_B1                         (-0.668179)
 #define CS_REVERB_8000_B2                          0.000000
 #define CS_REVERB_8000_SCALE                         15
 
 /* Reverb coefficients for 11025Hz sample rate, scaled with 1.038030 */
 #define CS_REVERB_11025_A0                     0.699638
-#define CS_REVERB_11025_A1                    -0.699638
+#define CS_REVERB_11025_A1                    (-0.699638)
 #define CS_REVERB_11025_A2                     0.000000
-#define CS_REVERB_11025_B1                    -0.749096
+#define CS_REVERB_11025_B1                    (-0.749096)
 #define CS_REVERB_11025_B2                     0.000000
 #define CS_REVERB_11025_SCALE                  15
 
 /* Reverb coefficients for 12000Hz sample rate, scaled with 1.038030 */
 #define CS_REVERB_12000_A0                   0.706931
-#define CS_REVERB_12000_A1                  -0.706931
+#define CS_REVERB_12000_A1                  (-0.706931)
 #define CS_REVERB_12000_A2                   0.000000
-#define CS_REVERB_12000_B1                  -0.767327
+#define CS_REVERB_12000_B1                  (-0.767327)
 #define CS_REVERB_12000_B2                   0.000000
 #define CS_REVERB_12000_SCALE                15
 
 /* Reverb coefficients for 16000Hz sample rate, scaled with 1.038030 */
 #define CS_REVERB_16000_A0                      0.728272
-#define CS_REVERB_16000_A1                     -0.728272
+#define CS_REVERB_16000_A1                     (-0.728272)
 #define CS_REVERB_16000_A2                      0.000000
-#define CS_REVERB_16000_B1                     -0.820679
+#define CS_REVERB_16000_B1                     (-0.820679)
 #define CS_REVERB_16000_B2                      0.000000
 #define CS_REVERB_16000_SCALE                        15
 
 /* Reverb coefficients for 22050Hz sample rate, scaled with 1.038030 */
 #define CS_REVERB_22050_A0                     0.516396
 #define CS_REVERB_22050_A1                     0.000000
-#define CS_REVERB_22050_A2                    -0.516396
-#define CS_REVERB_22050_B1                    -0.518512
-#define CS_REVERB_22050_B2                    -0.290990
+#define CS_REVERB_22050_A2                    (-0.516396)
+#define CS_REVERB_22050_B1                    (-0.518512)
+#define CS_REVERB_22050_B2                    (-0.290990)
 #define CS_REVERB_22050_SCALE                        15
 
 
 /* Reverb coefficients for 24000Hz sample rate, scaled with 1.038030 */
 #define CS_REVERB_24000_A0                       0.479565
 #define CS_REVERB_24000_A1                       0.000000
-#define CS_REVERB_24000_A2                      -0.479565
-#define CS_REVERB_24000_B1                      -0.637745
-#define CS_REVERB_24000_B2                      -0.198912
+#define CS_REVERB_24000_A2                      (-0.479565)
+#define CS_REVERB_24000_B1                      (-0.637745)
+#define CS_REVERB_24000_B2                      (-0.198912)
 #define CS_REVERB_24000_SCALE                        15
 
 /* Reverb coefficients for 32000Hz sample rate, scaled with 1.038030 */
 #define CS_REVERB_32000_A0                      0.380349
 #define CS_REVERB_32000_A1                      0.000000
-#define CS_REVERB_32000_A2                     -0.380349
-#define CS_REVERB_32000_B1                     -0.950873
+#define CS_REVERB_32000_A2                     (-0.380349)
+#define CS_REVERB_32000_B1                     (-0.950873)
 #define CS_REVERB_32000_B2                      0.049127
 #define CS_REVERB_32000_SCALE                        15
 
 /* Reverb coefficients for 44100Hz sample rate, scaled with 1.038030 */
 #define CS_REVERB_44100_A0                         0.297389
 #define CS_REVERB_44100_A1                         0.000000
-#define CS_REVERB_44100_A2                        -0.297389
-#define CS_REVERB_44100_B1                        -1.200423
+#define CS_REVERB_44100_A2                        (-0.297389)
+#define CS_REVERB_44100_B1                        (-1.200423)
 #define CS_REVERB_44100_B2                         0.256529
 #define CS_REVERB_44100_SCALE                        14
 
 /* Reverb coefficients for 48000Hz sample rate, scaled with 1.038030 */
 #define CS_REVERB_48000_A0                       0.278661
 #define CS_REVERB_48000_A1                       0.000000
-#define CS_REVERB_48000_A2                      -0.278661
-#define CS_REVERB_48000_B1                      -1.254993
+#define CS_REVERB_48000_A2                      (-0.278661)
+#define CS_REVERB_48000_B1                      (-1.254993)
 #define CS_REVERB_48000_B2                       0.303347
 #define CS_REVERB_48000_SCALE                        14
 
@@ -279,8 +279,8 @@
 /* Band pass filter with fc1=500 and fc2=8000*/
 #define CS_REVERB_96000_A0                       0.1602488
 #define CS_REVERB_96000_A1                       0.000000
-#define CS_REVERB_96000_A2                      -0.1602488
-#define CS_REVERB_96000_B1                      -1.585413
+#define CS_REVERB_96000_A2                      (-0.1602488)
+#define CS_REVERB_96000_B1                      (-1.585413)
 #define CS_REVERB_96000_B2                       0.599377
 #define CS_REVERB_96000_SCALE                        14
 
@@ -288,8 +288,8 @@
 /* Band pass filter with fc1=500 and fc2=8000*/
 #define CS_REVERB_192000_A0                       0.0878369
 #define CS_REVERB_192000_A1                       0.000000
-#define CS_REVERB_192000_A2                      -0.0878369
-#define CS_REVERB_192000_B1                      -1.7765764
+#define CS_REVERB_192000_A2                      (-0.0878369)
+#define CS_REVERB_192000_B1                      (-1.7765764)
 #define CS_REVERB_192000_B2                       0.7804076
 #define CS_REVERB_192000_SCALE                        14
 
@@ -312,163 +312,163 @@
 /* Equaliser coefficients for 8000 Hz sample rate, \
    CS scaled with 1.038497 and CSEX scaled with 0.775480 */
 #define CS_EQUALISER_8000_A0                     1.263312
-#define CS_EQUALISER_8000_A1                    -0.601748
-#define CS_EQUALISER_8000_A2                    -0.280681
-#define CS_EQUALISER_8000_B1                    -0.475865
-#define CS_EQUALISER_8000_B2                    -0.408154
+#define CS_EQUALISER_8000_A1                    (-0.601748)
+#define CS_EQUALISER_8000_A2                    (-0.280681)
+#define CS_EQUALISER_8000_B1                    (-0.475865)
+#define CS_EQUALISER_8000_B2                    (-0.408154)
 #define CS_EQUALISER_8000_SCALE                      14
 #define CSEX_EQUALISER_8000_A0                    0.943357
-#define CSEX_EQUALISER_8000_A1                   -0.449345
-#define CSEX_EQUALISER_8000_A2                   -0.209594
-#define CSEX_EQUALISER_8000_B1                   -0.475865
-#define CSEX_EQUALISER_8000_B2                   -0.408154
+#define CSEX_EQUALISER_8000_A1                   (-0.449345)
+#define CSEX_EQUALISER_8000_A2                   (-0.209594)
+#define CSEX_EQUALISER_8000_B1                   (-0.475865)
+#define CSEX_EQUALISER_8000_B2                   (-0.408154)
 #define CSEX_EQUALISER_8000_SCALE                    15
 
 /* Equaliser coefficients for 11025Hz sample rate, \
    CS scaled with 1.027761 and CSEX scaled with 0.767463 */
 #define CS_EQUALISER_11025_A0                    1.101145
 #define CS_EQUALISER_11025_A1                    0.139020
-#define CS_EQUALISER_11025_A2                   -0.864423
+#define CS_EQUALISER_11025_A2                   (-0.864423)
 #define CS_EQUALISER_11025_B1                    0.024541
-#define CS_EQUALISER_11025_B2                   -0.908930
+#define CS_EQUALISER_11025_B2                   (-0.908930)
 #define CS_EQUALISER_11025_SCALE                     14
 #define CSEX_EQUALISER_11025_A0                    0.976058
-#define CSEX_EQUALISER_11025_A1                   -0.695326
-#define CSEX_EQUALISER_11025_A2                   -0.090809
-#define CSEX_EQUALISER_11025_B1                   -0.610594
-#define CSEX_EQUALISER_11025_B2                   -0.311149
+#define CSEX_EQUALISER_11025_A1                   (-0.695326)
+#define CSEX_EQUALISER_11025_A2                   (-0.090809)
+#define CSEX_EQUALISER_11025_B1                   (-0.610594)
+#define CSEX_EQUALISER_11025_B2                   (-0.311149)
 #define CSEX_EQUALISER_11025_SCALE                   15
 
 /* Equaliser coefficients for 12000Hz sample rate, \
    CS scaled with 1.032521 and CSEX scaled with 0.771017 */
 #define CS_EQUALISER_12000_A0                      1.276661
-#define CS_EQUALISER_12000_A1                     -1.017519
-#define CS_EQUALISER_12000_A2                     -0.044128
-#define CS_EQUALISER_12000_B1                     -0.729616
-#define CS_EQUALISER_12000_B2                     -0.204532
+#define CS_EQUALISER_12000_A1                     (-1.017519)
+#define CS_EQUALISER_12000_A2                     (-0.044128)
+#define CS_EQUALISER_12000_B1                     (-0.729616)
+#define CS_EQUALISER_12000_B2                     (-0.204532)
 #define CS_EQUALISER_12000_SCALE                     14
 #define CSEX_EQUALISER_12000_A0                 1.007095
-#define CSEX_EQUALISER_12000_A1                -0.871912
+#define CSEX_EQUALISER_12000_A1                (-0.871912)
 #define CSEX_EQUALISER_12000_A2                 0.023232
-#define CSEX_EQUALISER_12000_B1                -0.745857
-#define CSEX_EQUALISER_12000_B2                -0.189171
+#define CSEX_EQUALISER_12000_B1                (-0.745857)
+#define CSEX_EQUALISER_12000_B2                (-0.189171)
 #define CSEX_EQUALISER_12000_SCALE                   14
 
 /* Equaliser coefficients for 16000Hz sample rate, \
    CS scaled with 1.031378 and CSEX scaled with 0.770164 */
 #define CS_EQUALISER_16000_A0                     1.281629
-#define CS_EQUALISER_16000_A1                    -1.075872
-#define CS_EQUALISER_16000_A2                    -0.041365
-#define CS_EQUALISER_16000_B1                    -0.725239
-#define CS_EQUALISER_16000_B2                    -0.224358
+#define CS_EQUALISER_16000_A1                    (-1.075872)
+#define CS_EQUALISER_16000_A2                    (-0.041365)
+#define CS_EQUALISER_16000_B1                    (-0.725239)
+#define CS_EQUALISER_16000_B2                    (-0.224358)
 #define CS_EQUALISER_16000_SCALE                     14
 #define CSEX_EQUALISER_16000_A0                  1.081091
-#define CSEX_EQUALISER_16000_A1                 -0.867183
-#define CSEX_EQUALISER_16000_A2                 -0.070247
-#define CSEX_EQUALISER_16000_B1                 -0.515121
-#define CSEX_EQUALISER_16000_B2                 -0.425893
+#define CSEX_EQUALISER_16000_A1                 (-0.867183)
+#define CSEX_EQUALISER_16000_A2                 (-0.070247)
+#define CSEX_EQUALISER_16000_B1                 (-0.515121)
+#define CSEX_EQUALISER_16000_B2                 (-0.425893)
 #define CSEX_EQUALISER_16000_SCALE                   14
 
 /* Equaliser coefficients for 22050Hz sample rate, \
    CS scaled with 1.041576 and CSEX scaled with 0.777779 */
 #define CS_EQUALISER_22050_A0                   1.388605
-#define CS_EQUALISER_22050_A1                  -1.305799
+#define CS_EQUALISER_22050_A1                  (-1.305799)
 #define CS_EQUALISER_22050_A2                   0.039922
-#define CS_EQUALISER_22050_B1                  -0.719494
-#define CS_EQUALISER_22050_B2                  -0.243245
+#define CS_EQUALISER_22050_B1                  (-0.719494)
+#define CS_EQUALISER_22050_B2                  (-0.243245)
 #define CS_EQUALISER_22050_SCALE                     14
 #define CSEX_EQUALISER_22050_A0                   1.272910
-#define CSEX_EQUALISER_22050_A1                  -1.341014
+#define CSEX_EQUALISER_22050_A1                  (-1.341014)
 #define CSEX_EQUALISER_22050_A2                   0.167462
-#define CSEX_EQUALISER_22050_B1                  -0.614219
-#define CSEX_EQUALISER_22050_B2                  -0.345384
+#define CSEX_EQUALISER_22050_B1                  (-0.614219)
+#define CSEX_EQUALISER_22050_B2                  (-0.345384)
 #define CSEX_EQUALISER_22050_SCALE                   14
 
 /* Equaliser coefficients for 24000Hz sample rate, \
    CS scaled with 1.034495 and CSEX scaled with 0.772491 */
 #define CS_EQUALISER_24000_A0                    1.409832
-#define CS_EQUALISER_24000_A1                   -1.456506
+#define CS_EQUALISER_24000_A1                   (-1.456506)
 #define CS_EQUALISER_24000_A2                    0.151410
-#define CS_EQUALISER_24000_B1                   -0.804201
-#define CS_EQUALISER_24000_B2                   -0.163783
+#define CS_EQUALISER_24000_B1                   (-0.804201)
+#define CS_EQUALISER_24000_B2                   (-0.163783)
 #define CS_EQUALISER_24000_SCALE                     14
 #define CSEX_EQUALISER_24000_A0                  1.299198
-#define CSEX_EQUALISER_24000_A1                 -1.452447
+#define CSEX_EQUALISER_24000_A1                 (-1.452447)
 #define CSEX_EQUALISER_24000_A2                  0.240489
-#define CSEX_EQUALISER_24000_B1                 -0.669303
-#define CSEX_EQUALISER_24000_B2                 -0.294984
+#define CSEX_EQUALISER_24000_B1                 (-0.669303)
+#define CSEX_EQUALISER_24000_B2                 (-0.294984)
 #define CSEX_EQUALISER_24000_SCALE                   14
 
 /* Equaliser coefficients for 32000Hz sample rate, \
    CS scaled with 1.044559 and CSEX scaled with 0.780006 */
 #define CS_EQUALISER_32000_A0                     1.560988
-#define CS_EQUALISER_32000_A1                    -1.877724
+#define CS_EQUALISER_32000_A1                    (-1.877724)
 #define CS_EQUALISER_32000_A2                     0.389741
-#define CS_EQUALISER_32000_B1                    -0.907410
-#define CS_EQUALISER_32000_B2                    -0.070489
+#define CS_EQUALISER_32000_B1                    (-0.907410)
+#define CS_EQUALISER_32000_B2                    (-0.070489)
 #define CS_EQUALISER_32000_SCALE                     14
 #define CSEX_EQUALISER_32000_A0                  1.785049
-#define CSEX_EQUALISER_32000_A1                 -2.233497
+#define CSEX_EQUALISER_32000_A1                 (-2.233497)
 #define CSEX_EQUALISER_32000_A2                  0.526431
-#define CSEX_EQUALISER_32000_B1                 -0.445939
-#define CSEX_EQUALISER_32000_B2                 -0.522446
+#define CSEX_EQUALISER_32000_B1                 (-0.445939)
+#define CSEX_EQUALISER_32000_B2                 (-0.522446)
 #define CSEX_EQUALISER_32000_SCALE                   13
 
 /* Equaliser coefficients for 44100Hz sample rate, \
    CS scaled with 1.022170 and CSEX scaled with 0.763288 */
 #define CS_EQUALISER_44100_A0                  1.623993
-#define CS_EQUALISER_44100_A1                 -2.270743
+#define CS_EQUALISER_44100_A1                 (-2.270743)
 #define CS_EQUALISER_44100_A2                  0.688829
-#define CS_EQUALISER_44100_B1                 -1.117190
+#define CS_EQUALISER_44100_B1                 (-1.117190)
 #define CS_EQUALISER_44100_B2                  0.130208
 #define CS_EQUALISER_44100_SCALE                     13
 #define CSEX_EQUALISER_44100_A0                   2.028315
-#define CSEX_EQUALISER_44100_A1                  -2.882459
+#define CSEX_EQUALISER_44100_A1                  (-2.882459)
 #define CSEX_EQUALISER_44100_A2                   0.904535
-#define CSEX_EQUALISER_44100_B1                  -0.593308
-#define CSEX_EQUALISER_44100_B2                  -0.385816
+#define CSEX_EQUALISER_44100_B1                  (-0.593308)
+#define CSEX_EQUALISER_44100_B2                  (-0.385816)
 #define CSEX_EQUALISER_44100_SCALE                   13
 
 /* Equaliser coefficients for 48000Hz sample rate, \
    CS scaled with 1.018635 and CSEX scaled with 0.760648 */
 #define CS_EQUALISER_48000_A0                    1.641177
-#define CS_EQUALISER_48000_A1                   -2.364687
+#define CS_EQUALISER_48000_A1                   (-2.364687)
 #define CS_EQUALISER_48000_A2                    0.759910
-#define CS_EQUALISER_48000_B1                   -1.166774
+#define CS_EQUALISER_48000_B1                   (-1.166774)
 #define CS_EQUALISER_48000_B2                    0.178074
 #define CS_EQUALISER_48000_SCALE                     13
 #define CSEX_EQUALISER_48000_A0                  2.099655
-#define CSEX_EQUALISER_48000_A1                 -3.065220
+#define CSEX_EQUALISER_48000_A1                 (-3.065220)
 #define CSEX_EQUALISER_48000_A2                  1.010417
-#define CSEX_EQUALISER_48000_B1                 -0.634021
-#define CSEX_EQUALISER_48000_B2                 -0.347332
+#define CSEX_EQUALISER_48000_B1                 (-0.634021)
+#define CSEX_EQUALISER_48000_B2                 (-0.347332)
 #define CSEX_EQUALISER_48000_SCALE                   13
 
 
 #ifdef HIGHER_FS
 #define CS_EQUALISER_96000_A0                    1.784497
-#define CS_EQUALISER_96000_A1                   -3.001435
+#define CS_EQUALISER_96000_A1                   (-3.001435)
 #define CS_EQUALISER_96000_A2                    1.228422
-#define CS_EQUALISER_96000_B1                   -1.477804
+#define CS_EQUALISER_96000_B1                   (-1.477804)
 #define CS_EQUALISER_96000_B2                    0.481369
 #define CS_EQUALISER_96000_SCALE                     13
 #define CSEX_EQUALISER_96000_A0                  2.7573
-#define CSEX_EQUALISER_96000_A1                 -4.6721
+#define CSEX_EQUALISER_96000_A1                 (-4.6721)
 #define CSEX_EQUALISER_96000_A2                  1.9317
-#define CSEX_EQUALISER_96000_B1                 -0.971718
-#define CSEX_EQUALISER_96000_B2                 -0.021216
+#define CSEX_EQUALISER_96000_B1                 (-0.971718)
+#define CSEX_EQUALISER_96000_B2                 (-0.021216)
 #define CSEX_EQUALISER_96000_SCALE                   13
 
 #define CS_EQUALISER_192000_A0                    1.889582
-#define CS_EQUALISER_192000_A1                   -3.456140
+#define CS_EQUALISER_192000_A1                   (-3.456140)
 #define CS_EQUALISER_192000_A2                    1.569864
-#define CS_EQUALISER_192000_B1                   -1.700798
+#define CS_EQUALISER_192000_B1                   (-1.700798)
 #define CS_EQUALISER_192000_B2                    0.701824
 #define CS_EQUALISER_192000_SCALE                     13
 #define CSEX_EQUALISER_192000_A0                  3.4273
-#define CSEX_EQUALISER_192000_A1                 -6.2936
+#define CSEX_EQUALISER_192000_A1                 (-6.2936)
 #define CSEX_EQUALISER_192000_A2                  2.8720
-#define CSEX_EQUALISER_192000_B1                 -1.31074
+#define CSEX_EQUALISER_192000_B1                 (-1.31074)
 #define CSEX_EQUALISER_192000_B2                 0.31312
 #define CSEX_EQUALISER_192000_SCALE                   13
 #endif
diff --git a/media/libeffects/lvm/wrapper/Android.mk b/media/libeffects/lvm/wrapper/Android.mk
index f106aae..341dbc2 100644
--- a/media/libeffects/lvm/wrapper/Android.mk
+++ b/media/libeffects/lvm/wrapper/Android.mk
@@ -1,5 +1,8 @@
 LOCAL_PATH:= $(call my-dir)
 
+# The wrapper -DBUILD_FLOAT needs to match
+# the lvm library -DBUILD_FLOAT.
+
 # music bundle wrapper
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
@@ -20,15 +23,17 @@
 LOCAL_STATIC_LIBRARIES += libmusicbundle
 
 LOCAL_SHARED_LIBRARIES := \
-     liblog \
+     libaudioutils \
      libcutils \
-     libdl
+     libdl \
+     liblog \
 
 LOCAL_C_INCLUDES += \
 	$(LOCAL_PATH)/Bundle \
 	$(LOCAL_PATH)/../lib/Common/lib/ \
 	$(LOCAL_PATH)/../lib/Bundle/lib/ \
-	$(call include-path-for, audio-effects)
+	$(call include-path-for, audio-effects) \
+	$(call include-path-for, audio-utils) \
 
 LOCAL_HEADER_LIBRARIES += libhardware_headers
 include $(BUILD_SHARED_LIBRARY)
@@ -53,15 +58,20 @@
 LOCAL_STATIC_LIBRARIES += libreverb
 
 LOCAL_SHARED_LIBRARIES := \
-     liblog \
+     libaudioutils \
      libcutils \
-     libdl
+     libdl \
+     liblog \
 
 LOCAL_C_INCLUDES += \
     $(LOCAL_PATH)/Reverb \
     $(LOCAL_PATH)/../lib/Common/lib/ \
     $(LOCAL_PATH)/../lib/Reverb/lib/ \
-    $(call include-path-for, audio-effects)
+    $(call include-path-for, audio-effects) \
+    $(call include-path-for, audio-utils) \
 
 LOCAL_HEADER_LIBRARIES += libhardware_headers
+
+LOCAL_SANITIZE := integer_overflow
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index aae80b6..146e9e8 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <audio_utils/primitives.h>
 #include <log/log.h>
 
 #include "EffectBundle.h"
@@ -63,16 +64,6 @@
         }\
     }
 
-
-static inline int16_t clamp16(int32_t sample)
-{
-    // check overflow for both positive and negative values:
-    // all bits above short range must me equal to sign bit
-    if ((sample>>15) ^ (sample>>31))
-        sample = 0x7FFF ^ (sample>>31);
-    return sample;
-}
-
 // Namespaces
 namespace android {
 namespace {
@@ -299,7 +290,7 @@
         pContext->pBundledContext->SamplesToExitCountVirt   = 0;
         pContext->pBundledContext->SamplesToExitCountBb     = 0;
         pContext->pBundledContext->SamplesToExitCountEq     = 0;
-#ifdef BUILD_FLOAT
+#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
         pContext->pBundledContext->pInputBuffer             = NULL;
         pContext->pBundledContext->pOutputBuffer            = NULL;
 #endif
@@ -470,13 +461,9 @@
         if (pContext->pBundledContext->workBuffer != NULL) {
             free(pContext->pBundledContext->workBuffer);
         }
-#ifdef BUILD_FLOAT
-        if (pContext->pBundledContext->pInputBuffer != NULL) {
-            free(pContext->pBundledContext->pInputBuffer);
-        }
-        if (pContext->pBundledContext->pOutputBuffer != NULL) {
-            free(pContext->pBundledContext->pOutputBuffer);
-        }
+#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
+        free(pContext->pBundledContext->pInputBuffer);
+        free(pContext->pBundledContext->pOutputBuffer);
 #endif
         delete pContext->pBundledContext;
         pContext->pBundledContext = LVM_NULL;
@@ -549,7 +536,7 @@
 
     pContext->config.inputCfg.accessMode                    = EFFECT_BUFFER_ACCESS_READ;
     pContext->config.inputCfg.channels                      = AUDIO_CHANNEL_OUT_STEREO;
-    pContext->config.inputCfg.format                        = AUDIO_FORMAT_PCM_16_BIT;
+    pContext->config.inputCfg.format                        = EFFECT_BUFFER_FORMAT;
     pContext->config.inputCfg.samplingRate                  = 44100;
     pContext->config.inputCfg.bufferProvider.getBuffer      = NULL;
     pContext->config.inputCfg.bufferProvider.releaseBuffer  = NULL;
@@ -557,7 +544,7 @@
     pContext->config.inputCfg.mask                          = EFFECT_CONFIG_ALL;
     pContext->config.outputCfg.accessMode                   = EFFECT_BUFFER_ACCESS_ACCUMULATE;
     pContext->config.outputCfg.channels                     = AUDIO_CHANNEL_OUT_STEREO;
-    pContext->config.outputCfg.format                       = AUDIO_FORMAT_PCM_16_BIT;
+    pContext->config.outputCfg.format                       = EFFECT_BUFFER_FORMAT;
     pContext->config.outputCfg.samplingRate                 = 44100;
     pContext->config.outputCfg.bufferProvider.getBuffer     = NULL;
     pContext->config.outputCfg.bufferProvider.releaseBuffer = NULL;
@@ -734,47 +721,6 @@
     return 0;
 }   /* end LvmBundle_init */
 
-#ifdef BUILD_FLOAT
-/**********************************************************************************
-   FUNCTION INT16LTOFLOAT
-***********************************************************************************/
-// Todo: need to write function descriptor
-static void Int16ToFloat(const LVM_INT16 *src, LVM_FLOAT *dst, size_t n) {
-    size_t ii;
-    src += n-1;
-    dst += n-1;
-    for (ii = n; ii != 0; ii--) {
-        *dst = ((LVM_FLOAT)((LVM_INT16)*src)) / 32768.0f;
-        src--;
-        dst--;
-    }
-    return;
-}
-/**********************************************************************************
-   FUNCTION FLOATTOINT16_SAT
-***********************************************************************************/
-// Todo : Need to write function descriptor
-static void FloatToInt16_SAT(const LVM_FLOAT *src, LVM_INT16 *dst, size_t n) {
-    size_t ii;
-    LVM_INT32 temp;
-
-    src += n-1;
-    dst += n-1;
-    for (ii = n; ii != 0; ii--) {
-        temp = (LVM_INT32)((*src) * 32768.0f);
-        if (temp >= 32767) {
-            *dst = 32767;
-        } else if (temp <= -32768) {
-            *dst = -32768;
-        } else {
-            *dst = (LVM_INT16)temp;
-        }
-        src--;
-        dst--;
-    }
-    return;
-}
-#endif
 //----------------------------------------------------------------------------
 // LvmBundle_process()
 //----------------------------------------------------------------------------
@@ -782,8 +728,8 @@
 // Apply LVM Bundle effects
 //
 // Inputs:
-//  pIn:        pointer to stereo 16 bit input data
-//  pOut:       pointer to stereo 16 bit output data
+//  pIn:        pointer to stereo float or 16 bit input data
+//  pOut:       pointer to stereo float or 16 bit output data
 //  frameCount: Frames to process
 //  pContext:   effect engine context
 //  strength    strength to be applied
@@ -793,44 +739,37 @@
 //
 //----------------------------------------------------------------------------
 #ifdef BUILD_FLOAT
-int LvmBundle_process(LVM_INT16        *pIn,
-                      LVM_INT16        *pOut,
+int LvmBundle_process(effect_buffer_t  *pIn,
+                      effect_buffer_t  *pOut,
                       int              frameCount,
                       EffectContext    *pContext){
 
-
-    //LVM_ControlParams_t     ActiveParams;                           /* Current control Parameters */
     LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;                /* Function call status */
-    LVM_INT16               *pOutTmp;
-    LVM_FLOAT               *pInputBuff;
-    LVM_FLOAT               *pOutputBuff;
-
-    if (pContext->pBundledContext->pInputBuffer == NULL ||
+    effect_buffer_t         *pOutTmp;
+#ifndef NATIVE_FLOAT_BUFFER
+    if (pContext->pBundledContext->pInputBuffer == nullptr ||
             pContext->pBundledContext->frameCount < frameCount) {
-        if (pContext->pBundledContext->pInputBuffer != NULL) {
-            free(pContext->pBundledContext->pInputBuffer);
-        }
-        pContext->pBundledContext->pInputBuffer = (LVM_FLOAT *)malloc(frameCount * \
-                                                                      sizeof(LVM_FLOAT) * FCC_2);
+        free(pContext->pBundledContext->pInputBuffer);
+        pContext->pBundledContext->pInputBuffer =
+                (LVM_FLOAT *)calloc(frameCount, sizeof(LVM_FLOAT) * FCC_2);
     }
 
-    if (pContext->pBundledContext->pOutputBuffer == NULL ||
+    if (pContext->pBundledContext->pOutputBuffer == nullptr ||
             pContext->pBundledContext->frameCount < frameCount) {
-        if (pContext->pBundledContext->pOutputBuffer != NULL) {
-            free(pContext->pBundledContext->pOutputBuffer);
-        }
-        pContext->pBundledContext->pOutputBuffer = (LVM_FLOAT *)malloc(frameCount * \
-                                                                       sizeof(LVM_FLOAT) * FCC_2);
+        free(pContext->pBundledContext->pOutputBuffer);
+        pContext->pBundledContext->pOutputBuffer =
+                (LVM_FLOAT *)calloc(frameCount, sizeof(LVM_FLOAT) * FCC_2);
     }
 
-    if ((pContext->pBundledContext->pInputBuffer == NULL) ||
-                                    (pContext->pBundledContext->pOutputBuffer == NULL)) {
-        ALOGV("LVM_ERROR : LvmBundle_process memory allocation for float buffer's failed");
+    if (pContext->pBundledContext->pInputBuffer == nullptr ||
+            pContext->pBundledContext->pOutputBuffer == nullptr) {
+        ALOGE("LVM_ERROR : LvmBundle_process memory allocation for float buffer's failed");
         return -EINVAL;
     }
 
-    pInputBuff = pContext->pBundledContext->pInputBuffer;
-    pOutputBuff = pContext->pBundledContext->pOutputBuffer;
+    LVM_FLOAT * const pInputBuff = pContext->pBundledContext->pInputBuffer;
+    LVM_FLOAT * const pOutputBuff = pContext->pBundledContext->pOutputBuffer;
+#endif
 
     if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){
         pOutTmp = pOut;
@@ -840,7 +779,7 @@
                 free(pContext->pBundledContext->workBuffer);
             }
             pContext->pBundledContext->workBuffer =
-                    (LVM_INT16 *)calloc(frameCount, sizeof(LVM_INT16) * FCC_2);
+                    (effect_buffer_t *)calloc(frameCount, sizeof(effect_buffer_t) * FCC_2);
             if (pContext->pBundledContext->workBuffer == NULL) {
                 return -ENOMEM;
             }
@@ -852,43 +791,61 @@
         return -EINVAL;
     }
 
-    #ifdef LVM_PCM
-    fwrite(pIn, frameCount*sizeof(LVM_INT16) * FCC_2, 1, pContext->pBundledContext->PcmInPtr);
+#ifdef LVM_PCM
+    fwrite(pIn,
+            frameCount*sizeof(effect_buffer_t) * FCC_2, 1, pContext->pBundledContext->PcmInPtr);
     fflush(pContext->pBundledContext->PcmInPtr);
-    #endif
+#endif
 
+#ifndef NATIVE_FLOAT_BUFFER
     /* Converting input data from fixed point to float point */
-    Int16ToFloat(pIn, pInputBuff, frameCount * 2);
+    memcpy_to_float_from_i16(pInputBuff, pIn, frameCount * FCC_2);
 
     /* Process the samples */
     LvmStatus = LVM_Process(pContext->pBundledContext->hInstance, /* Instance handle */
                             pInputBuff,                           /* Input buffer */
                             pOutputBuff,                          /* Output buffer */
                             (LVM_UINT16)frameCount,               /* Number of samples to read */
-                            0);                                   /* Audo Time */
+                            0);                                   /* Audio Time */
 
+    /* Converting output data from float point to fixed point */
+    memcpy_to_i16_from_float(pOutTmp, pOutputBuff, frameCount * FCC_2);
+
+#else
+    /* Process the samples */
+    LvmStatus = LVM_Process(pContext->pBundledContext->hInstance, /* Instance handle */
+                            pIn,                                  /* Input buffer */
+                            pOutTmp,                              /* Output buffer */
+                            (LVM_UINT16)frameCount,               /* Number of samples to read */
+                            0);                                   /* Audio Time */
+#endif
     LVM_ERROR_CHECK(LvmStatus, "LVM_Process", "LvmBundle_process")
     if(LvmStatus != LVM_SUCCESS) return -EINVAL;
 
-    /* Converting output data from float point to fixed point */
-    FloatToInt16_SAT(pOutputBuff, pOutTmp, (LVM_UINT16)frameCount * 2);
-    #ifdef LVM_PCM
-    fwrite(pOutTmp, frameCount*sizeof(LVM_INT16) * FCC_2, 1, pContext->pBundledContext->PcmOutPtr);
+#ifdef LVM_PCM
+    fwrite(pOutTmp,
+            frameCount*sizeof(effect_buffer_t) * FCC_2, 1, pContext->pBundledContext->PcmOutPtr);
     fflush(pContext->pBundledContext->PcmOutPtr);
-    #endif
+#endif
 
     if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
-        for (int i = 0; i < frameCount * 2; i++){
+        for (int i = 0; i < frameCount * FCC_2; i++) {
+#ifndef NATIVE_FLOAT_BUFFER
             pOut[i] = clamp16((LVM_INT32)pOut[i] + (LVM_INT32)pOutTmp[i]);
+#else
+            pOut[i] = pOut[i] + pOutTmp[i];
+#endif
         }
     }
     return 0;
 }    /* end LvmBundle_process */
-#else
+
+#else // BUILD_FLOAT
+
 int LvmBundle_process(LVM_INT16        *pIn,
                       LVM_INT16        *pOut,
                       int              frameCount,
-                      EffectContext    *pContext){
+                      EffectContext    *pContext) {
 
     LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;                /* Function call status */
     LVM_INT16               *pOutTmp;
@@ -901,7 +858,7 @@
                 free(pContext->pBundledContext->workBuffer);
             }
             pContext->pBundledContext->workBuffer =
-                    (LVM_INT16 *)calloc(frameCount, sizeof(LVM_INT16) * 2);
+                    (effect_buffer_t *)calloc(frameCount, sizeof(effect_buffer_t) * FCC_2);
             if (pContext->pBundledContext->workBuffer == NULL) {
                 return -ENOMEM;
             }
@@ -913,10 +870,11 @@
         return -EINVAL;
     }
 
-    #ifdef LVM_PCM
-    fwrite(pIn, frameCount*sizeof(LVM_INT16)*2, 1, pContext->pBundledContext->PcmInPtr);
+#ifdef LVM_PCM
+    fwrite(pIn, frameCount * sizeof(*pIn) * FCC_2,
+            1 /* nmemb */, pContext->pBundledContext->PcmInPtr);
     fflush(pContext->pBundledContext->PcmInPtr);
-    #endif
+#endif
 
     //ALOGV("Calling LVM_Process");
 
@@ -925,15 +883,16 @@
                             pIn,                                  /* Input buffer */
                             pOutTmp,                              /* Output buffer */
                             (LVM_UINT16)frameCount,               /* Number of samples to read */
-                            0);                                   /* Audo Time */
+                            0);                                   /* Audio Time */
 
     LVM_ERROR_CHECK(LvmStatus, "LVM_Process", "LvmBundle_process")
     if(LvmStatus != LVM_SUCCESS) return -EINVAL;
 
-    #ifdef LVM_PCM
-    fwrite(pOutTmp, frameCount*sizeof(LVM_INT16)*2, 1, pContext->pBundledContext->PcmOutPtr);
+#ifdef LVM_PCM
+    fwrite(pOutTmp, frameCount * sizeof(*pOutTmp) * FCC_2,
+            1 /* nmemb */, pContext->pBundledContext->PcmOutPtr);
     fflush(pContext->pBundledContext->PcmOutPtr);
-    #endif
+#endif
 
     if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
         for (int i=0; i<frameCount*2; i++){
@@ -942,7 +901,8 @@
     }
     return 0;
 }    /* end LvmBundle_process */
-#endif
+
+#endif // BUILD_FLOAT
 
 //----------------------------------------------------------------------------
 // EqualizerUpdateActiveParams()
@@ -1276,8 +1236,7 @@
     CHECK_ARG(pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_STEREO);
     CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE
               || pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
-    CHECK_ARG(pConfig->inputCfg.format == AUDIO_FORMAT_PCM_16_BIT);
-
+    CHECK_ARG(pConfig->inputCfg.format == EFFECT_BUFFER_FORMAT);
     pContext->config = *pConfig;
 
     switch (pConfig->inputCfg.samplingRate) {
@@ -3349,10 +3308,17 @@
         pContext->pBundledContext->NumberEffectsCalled = 0;
         /* Process all the available frames, block processing is
            handled internalLY by the LVM bundle */
-        processStatus = android::LvmBundle_process(    (LVM_INT16 *)inBuffer->raw,
-                                                (LVM_INT16 *)outBuffer->raw,
-                                                outBuffer->frameCount,
-                                                pContext);
+#ifdef NATIVE_FLOAT_BUFFER
+        processStatus = android::LvmBundle_process(inBuffer->f32,
+                                                   outBuffer->f32,
+                                                   outBuffer->frameCount,
+                                                   pContext);
+#else
+        processStatus = android::LvmBundle_process(inBuffer->s16,
+                                                   outBuffer->s16,
+                                                   outBuffer->frameCount,
+                                                   pContext);
+#endif
         if (processStatus != 0){
             ALOGV("\tLVM_ERROR : LvmBundle_process returned error %d", processStatus);
             if (status == 0) {
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index 291383a..6bf045d 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -95,7 +95,7 @@
     int                             SamplesToExitCountEq;
     int                             SamplesToExitCountBb;
     int                             SamplesToExitCountVirt;
-    LVM_INT16                       *workBuffer;
+    effect_buffer_t                 *workBuffer;
     int                             frameCount;
     int32_t                         bandGaindB[FIVEBAND_NUMBANDS];
     int                             volume;
@@ -103,10 +103,10 @@
     FILE                            *PcmInPtr;
     FILE                            *PcmOutPtr;
     #endif
-    #ifdef BUILD_FLOAT
+#if defined(BUILD_FLOAT) && !defined(NATIVE_FLOAT_BUFFER)
     LVM_FLOAT                       *pInputBuffer;
     LVM_FLOAT                       *pOutputBuffer;
-    #endif
+#endif
 };
 
 /* SessionContext : One session */
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 3d8e982..0630285 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <audio_utils/primitives.h>
 #include <log/log.h>
 
 #include "EffectReverb.h"
@@ -135,6 +136,12 @@
         &gInsertPresetReverbDescriptor
 };
 
+#ifdef BUILD_FLOAT
+typedef     float               process_buffer_t; // process in float
+#else
+typedef     int32_t             process_buffer_t; // process in Q4_27
+#endif // BUILD_FLOAT
+
 struct ReverbContext{
     const struct effect_interface_s *itfe;
     effect_config_t                 config;
@@ -152,8 +159,8 @@
     FILE                            *PcmOutPtr;
     #endif
     LVM_Fs_en                       SampleRate;
-    LVM_INT32                       *InFrames32;
-    LVM_INT32                       *OutFrames32;
+    process_buffer_t                *InFrames;
+    process_buffer_t                *OutFrames;
     size_t                          bufferSizeIn;
     size_t                          bufferSizeOut;
     bool                            auxiliary;
@@ -262,7 +269,7 @@
 
     *pHandle = (effect_handle_t)pContext;
 
-    #ifdef LVM_PCM
+#ifdef LVM_PCM
     pContext->PcmInPtr = NULL;
     pContext->PcmOutPtr = NULL;
 
@@ -273,19 +280,15 @@
        (pContext->PcmOutPtr == NULL)){
        return -EINVAL;
     }
-    #endif
+#endif
 
+    int channels = audio_channel_count_from_out_mask(pContext->config.inputCfg.channels);
 
     // Allocate memory for reverb process (*2 is for STEREO)
-#ifdef BUILD_FLOAT
-    pContext->bufferSizeIn = LVREV_MAX_FRAME_SIZE * sizeof(float) * 2;
-    pContext->bufferSizeOut = pContext->bufferSizeIn;
-#else
-    pContext->bufferSizeIn = LVREV_MAX_FRAME_SIZE * sizeof(LVM_INT32) * 2;
-    pContext->bufferSizeOut = pContext->bufferSizeIn;
-#endif
-    pContext->InFrames32  = (LVM_INT32 *)malloc(pContext->bufferSizeIn);
-    pContext->OutFrames32 = (LVM_INT32 *)malloc(pContext->bufferSizeOut);
+    pContext->bufferSizeIn = LVREV_MAX_FRAME_SIZE * sizeof(process_buffer_t) * channels;
+    pContext->bufferSizeOut = LVREV_MAX_FRAME_SIZE * sizeof(process_buffer_t) * FCC_2;
+    pContext->InFrames  = (process_buffer_t *)calloc(pContext->bufferSizeIn, 1 /* size */);
+    pContext->OutFrames = (process_buffer_t *)calloc(pContext->bufferSizeOut, 1 /* size */);
 
     ALOGV("\tEffectCreate %p, size %zu", pContext, sizeof(ReverbContext));
     ALOGV("\tEffectCreate end\n");
@@ -305,8 +308,8 @@
     fclose(pContext->PcmInPtr);
     fclose(pContext->PcmOutPtr);
     #endif
-    free(pContext->InFrames32);
-    free(pContext->OutFrames32);
+    free(pContext->InFrames);
+    free(pContext->OutFrames);
     pContext->bufferSizeIn = 0;
     pContext->bufferSizeOut = 0;
     Reverb_free(pContext);
@@ -344,114 +347,6 @@
     }                                         \
 }
 
-#if 0
-//----------------------------------------------------------------------------
-// MonoTo2I_32()
-//----------------------------------------------------------------------------
-// Purpose:
-//  Convert MONO to STEREO
-//
-//----------------------------------------------------------------------------
-
-void MonoTo2I_32( const LVM_INT32  *src,
-                        LVM_INT32  *dst,
-                        LVM_INT16 n)
-{
-   LVM_INT16 ii;
-   src += (n-1);
-   dst += ((n*2)-1);
-
-   for (ii = n; ii != 0; ii--)
-   {
-       *dst = *src;
-       dst--;
-
-       *dst = *src;
-       dst--;
-       src--;
-   }
-
-   return;
-}
-
-//----------------------------------------------------------------------------
-// From2iToMono_32()
-//----------------------------------------------------------------------------
-// Purpose:
-//  Convert STEREO to MONO
-//
-//----------------------------------------------------------------------------
-
-void From2iToMono_32( const LVM_INT32 *src,
-                            LVM_INT32 *dst,
-                            LVM_INT16 n)
-{
-   LVM_INT16 ii;
-   LVM_INT32 Temp;
-
-   for (ii = n; ii != 0; ii--)
-   {
-       Temp = (*src>>1);
-       src++;
-
-       Temp +=(*src>>1);
-       src++;
-
-       *dst = Temp;
-       dst++;
-   }
-
-   return;
-}
-#endif
-
-#ifdef BUILD_FLOAT
-/**********************************************************************************
-   FUNCTION INT16LTOFLOAT
-***********************************************************************************/
-// Todo: need to write function descriptor
-static void Int16ToFloat(const LVM_INT16 *src, LVM_FLOAT *dst, size_t n) {
-    size_t ii;
-    src += n-1;
-    dst += n-1;
-    for (ii = n; ii != 0; ii--) {
-        *dst = ((LVM_FLOAT)((LVM_INT16)*src)) / 32768.0f;
-        src--;
-        dst--;
-    }
-    return;
-}
-/**********************************************************************************
-   FUNCTION FLOATTOINT16_SAT
-***********************************************************************************/
-// Todo : Need to write function descriptor
-static void FloatToInt16_SAT(const LVM_FLOAT *src, LVM_INT16 *dst, size_t n) {
-    size_t ii;
-    LVM_INT32 temp;
-
-    for (ii = 0; ii < n; ii++) {
-        temp = (LVM_INT32)((*src) * 32768.0f);
-        if (temp >= 32767) {
-            *dst = 32767;
-        } else if (temp <= -32768) {
-            *dst = -32768;
-        } else {
-            *dst = (LVM_INT16)temp;
-        }
-        src++;
-        dst++;
-    }
-    return;
-}
-#endif
-
-static inline int16_t clamp16(int32_t sample)
-{
-    if ((sample>>15) ^ (sample>>31))
-        sample = 0x7FFF ^ (sample>>31);
-    return sample;
-}
-
 //----------------------------------------------------------------------------
 // process()
 //----------------------------------------------------------------------------
@@ -459,8 +354,8 @@
 // Apply the Reverb
 //
 // Inputs:
-//  pIn:        pointer to stereo/mono 16 bit input data
-//  pOut:       pointer to stereo 16 bit output data
+//  pIn:        pointer to stereo/mono float or 16 bit input data
+//  pOut:       pointer to stereo float or 16 bit output data
 //  frameCount: Frames to process
 //  pContext:   effect engine context
 //  strength    strength to be applied
@@ -469,116 +364,107 @@
 //  pOut:       pointer to updated stereo 16 bit output data
 //
 //----------------------------------------------------------------------------
-
-int process( LVM_INT16     *pIn,
-             LVM_INT16     *pOut,
+int process( effect_buffer_t   *pIn,
+             effect_buffer_t   *pOut,
              int           frameCount,
              ReverbContext *pContext){
 
-    LVM_INT16               samplesPerFrame = 1;
+    int channels = audio_channel_count_from_out_mask(pContext->config.inputCfg.channels);
     LVREV_ReturnStatus_en   LvmStatus = LVREV_SUCCESS;              /* Function call status */
-    LVM_INT16 *OutFrames16;
-#ifdef BUILD_FLOAT
-    LVM_FLOAT               *pInputBuff;
-    LVM_FLOAT               *pOutputBuff;
-#endif
 
-#ifdef BUILD_FLOAT
-    if (pContext->InFrames32 == NULL ||
-            pContext->bufferSizeIn < frameCount * sizeof(float) * 2) {
-        if (pContext->InFrames32 != NULL) {
-            free(pContext->InFrames32);
-        }
-        pContext->bufferSizeIn = frameCount * sizeof(float) * 2;
-        pContext->InFrames32 = (LVM_INT32 *)malloc(pContext->bufferSizeIn);
-    }
-    if (pContext->OutFrames32 == NULL ||
-            pContext->bufferSizeOut < frameCount * sizeof(float) * 2) {
-        if (pContext->OutFrames32 != NULL) {
-            free(pContext->OutFrames32);
-        }
-        pContext->bufferSizeOut = frameCount * sizeof(float) * 2;
-        pContext->OutFrames32 = (LVM_INT32 *)malloc(pContext->bufferSizeOut);
-    }
-    pInputBuff = (float *)pContext->InFrames32;
-    pOutputBuff = (float *)pContext->OutFrames32;
-#endif
     // Check that the input is either mono or stereo
-    if (pContext->config.inputCfg.channels == AUDIO_CHANNEL_OUT_STEREO) {
-        samplesPerFrame = 2;
-    } else if (pContext->config.inputCfg.channels != AUDIO_CHANNEL_OUT_MONO) {
-        ALOGV("\tLVREV_ERROR : process invalid PCM format");
+    if (!(channels == 1 || channels == FCC_2) ) {
+        ALOGE("\tLVREV_ERROR : process invalid PCM format");
         return -EINVAL;
     }
 
-    OutFrames16 = (LVM_INT16 *)pContext->OutFrames32;
+#ifdef BUILD_FLOAT
+    size_t inSize = frameCount * sizeof(process_buffer_t) * channels;
+    size_t outSize = frameCount * sizeof(process_buffer_t) * FCC_2;
+    if (pContext->InFrames == NULL ||
+            pContext->bufferSizeIn < inSize) {
+        free(pContext->InFrames);
+        pContext->bufferSizeIn = inSize;
+        pContext->InFrames = (process_buffer_t *)calloc(1, pContext->bufferSizeIn);
+    }
+    if (pContext->OutFrames == NULL ||
+            pContext->bufferSizeOut < outSize) {
+        free(pContext->OutFrames);
+        pContext->bufferSizeOut = outSize;
+        pContext->OutFrames = (process_buffer_t *)calloc(1, pContext->bufferSizeOut);
+    }
+
+#ifndef NATIVE_FLOAT_BUFFER
+    effect_buffer_t * const OutFrames16 = (effect_buffer_t *)pContext->OutFrames;
+#endif
+#endif
 
     // Check for NULL pointers
-    if((pContext->InFrames32 == NULL)||(pContext->OutFrames32 == NULL)){
-        ALOGV("\tLVREV_ERROR : process failed to allocate memory for temporary buffers ");
+    if ((pContext->InFrames == NULL) || (pContext->OutFrames == NULL)) {
+        ALOGE("\tLVREV_ERROR : process failed to allocate memory for temporary buffers ");
         return -EINVAL;
     }
 
-    #ifdef LVM_PCM
-    fwrite(pIn, frameCount*sizeof(LVM_INT16)*samplesPerFrame, 1, pContext->PcmInPtr);
+#ifdef LVM_PCM
+    fwrite(pIn, frameCount * sizeof(*pIn) * channels, 1 /* nmemb */, pContext->PcmInPtr);
     fflush(pContext->PcmInPtr);
-    #endif
+#endif
 
     if (pContext->preset && pContext->nextPreset != pContext->curPreset) {
         Reverb_LoadPreset(pContext);
     }
 
-    // Convert to Input 32 bits
     if (pContext->auxiliary) {
 #ifdef BUILD_FLOAT
-        Int16ToFloat(pIn, pInputBuff, frameCount * samplesPerFrame);
+#ifdef NATIVE_FLOAT_BUFFER
+        static_assert(std::is_same<decltype(*pIn), decltype(*pContext->InFrames)>::value,
+                "pIn and InFrames must be same type");
+        memcpy(pContext->InFrames, pIn, frameCount * channels * sizeof(*pIn));
 #else
-        for(int i=0; i<frameCount*samplesPerFrame; i++){
-            pContext->InFrames32[i] = (LVM_INT32)pIn[i]<<8;
+        memcpy_to_float_from_i16(
+                pContext->InFrames, pIn, frameCount * channels);
+#endif
+#else //no BUILD_FLOAT
+        for (int i = 0; i < frameCount * channels; i++) {
+            pContext->InFrames[i] = (process_buffer_t)pIn[i]<<8;
         }
 #endif
         } else {
         // insert reverb input is always stereo
         for (int i = 0; i < frameCount; i++) {
-#ifndef BUILD_FLOAT
-            pContext->InFrames32[2*i] = (pIn[2*i] * REVERB_SEND_LEVEL) >> 4; // <<8 + >>12
-            pContext->InFrames32[2*i+1] = (pIn[2*i+1] * REVERB_SEND_LEVEL) >> 4; // <<8 + >>12
+#ifdef BUILD_FLOAT
+#ifdef NATIVE_FLOAT_BUFFER
+            pContext->InFrames[2 * i] = (process_buffer_t)pIn[2 * i] * REVERB_SEND_LEVEL;
+            pContext->InFrames[2 * i + 1] = (process_buffer_t)pIn[2 * i + 1] * REVERB_SEND_LEVEL;
 #else
-            pInputBuff[2 * i] = (LVM_FLOAT)pIn[2 * i] * REVERB_SEND_LEVEL / 32768.0f;
-            pInputBuff[2 * i + 1] = (LVM_FLOAT)pIn[2 * i + 1] * REVERB_SEND_LEVEL / 32768.0f;
+            pContext->InFrames[2 * i] =
+                    (process_buffer_t)pIn[2 * i] * REVERB_SEND_LEVEL / 32768.0f;
+            pContext->InFrames[2 * i + 1] =
+                    (process_buffer_t)pIn[2 * i + 1] * REVERB_SEND_LEVEL / 32768.0f;
+#endif
+#else
+            pContext->InFrames[2*i] = (pIn[2*i] * REVERB_SEND_LEVEL) >> 4; // <<8 + >>12
+            pContext->InFrames[2*i+1] = (pIn[2*i+1] * REVERB_SEND_LEVEL) >> 4; // <<8 + >>12
 #endif
         }
     }
 
     if (pContext->preset && pContext->curPreset == REVERB_PRESET_NONE) {
-#ifdef BUILD_FLOAT
-        memset(pOutputBuff, 0, frameCount * sizeof(LVM_FLOAT) * 2); //always stereo here
-#else
-        memset(pContext->OutFrames32, 0, frameCount * sizeof(LVM_INT32) * 2); //always stereo here
-#endif
+        memset(pContext->OutFrames, 0,
+                frameCount * sizeof(*pContext->OutFrames) * FCC_2); //always stereo here
     } else {
         if(pContext->bEnabled == LVM_FALSE && pContext->SamplesToExitCount > 0) {
-#ifdef BUILD_FLOAT
-            memset(pInputBuff, 0, frameCount * sizeof(LVM_FLOAT) * samplesPerFrame);
-#else
-            memset(pContext->InFrames32,0,frameCount * sizeof(LVM_INT32) * samplesPerFrame);
-#endif
-            ALOGV("\tZeroing %d samples per frame at the end of call", samplesPerFrame);
+            memset(pContext->InFrames, 0,
+                    frameCount * sizeof(*pContext->OutFrames) * channels);
+            ALOGV("\tZeroing %d samples per frame at the end of call", channels);
         }
 
         /* Process the samples, producing a stereo output */
-#ifdef BUILD_FLOAT
         LvmStatus = LVREV_Process(pContext->hInstance,      /* Instance handle */
-                                  pInputBuff,     /* Input buffer */
-                                  pOutputBuff,    /* Output buffer */
+                                  pContext->InFrames,     /* Input buffer */
+                                  pContext->OutFrames,    /* Output buffer */
                                   frameCount);              /* Number of samples to read */
-#else
-        LvmStatus = LVREV_Process(pContext->hInstance,      /* Instance handle */
-                                  pContext->InFrames32,     /* Input buffer */
-                                  pContext->OutFrames32,    /* Output buffer */
-                                  frameCount);              /* Number of samples to read */
-#endif
-        }
+    }
 
     LVM_ERROR_CHECK(LvmStatus, "LVREV_Process", "process")
     if(LvmStatus != LVREV_SUCCESS) return -EINVAL;
@@ -586,55 +472,87 @@
     // Convert to 16 bits
     if (pContext->auxiliary) {
 #ifdef BUILD_FLOAT
-        FloatToInt16_SAT(pOutputBuff, OutFrames16, (size_t)frameCount * 2);
-#else
-        for (int i=0; i < frameCount*2; i++) { //always stereo here
-            OutFrames16[i] = clamp16(pContext->OutFrames32[i]>>8);
-        }
+        // nothing to do here
+#ifndef NATIVE_FLOAT_BUFFER
+        // pContext->OutFrames and OutFrames16 point to the same buffer
+        // make sure the float to int conversion happens in the right order.
+        memcpy_to_i16_from_float(OutFrames16, pContext->OutFrames,
+                (size_t)frameCount * FCC_2);
 #endif
-        } else {
-#ifdef BUILD_FLOAT
-            for (int i = 0; i < frameCount * 2; i++) {//always stereo here
-                //pOutputBuff and OutFrames16 point to the same buffer, so better to
-                //accumulate in pInputBuff, which is available
-                pInputBuff[i] = pOutputBuff[i] + (LVM_FLOAT)pIn[i] / 32768.0f;
-            }
-
-            FloatToInt16_SAT(pInputBuff, OutFrames16, (size_t)frameCount * 2);
 #else
-            for (int i=0; i < frameCount*2; i++) { //always stereo here
-                OutFrames16[i] = clamp16((pContext->OutFrames32[i]>>8) + (LVM_INT32)pIn[i]);
-            }
+        memcpy_to_i16_from_q4_27(OutFrames16, pContext->OutFrames, (size_t)frameCount * FCC_2);
+#endif
+    } else {
+#ifdef BUILD_FLOAT
+#ifdef NATIVE_FLOAT_BUFFER
+        for (int i = 0; i < frameCount * FCC_2; i++) { // always stereo here
+            // Mix with dry input
+            pContext->OutFrames[i] += pIn[i];
+        }
+#else
+        for (int i = 0; i < frameCount * FCC_2; i++) { // always stereo here
+            // pOutputBuff and OutFrames16 point to the same buffer
+            // make sure the float to int conversion happens in the right order.
+            pContext->OutFrames[i] += (process_buffer_t)pIn[i] / 32768.0f;
+        }
+        memcpy_to_i16_from_float(OutFrames16, pContext->OutFrames,
+                (size_t)frameCount * FCC_2);
+#endif
+#else
+        for (int i=0; i < frameCount * FCC_2; i++) { // always stereo here
+            OutFrames16[i] = clamp16((pContext->OutFrames[i]>>8) + (process_buffer_t)pIn[i]);
+        }
 #endif
         // apply volume with ramp if needed
         if ((pContext->leftVolume != pContext->prevLeftVolume ||
                 pContext->rightVolume != pContext->prevRightVolume) &&
                 pContext->volumeMode == REVERB_VOLUME_RAMP) {
+#if defined (BUILD_FLOAT) && defined (NATIVE_FLOAT_BUFFER)
+            // FIXME: still using int16 volumes.
+            // For reference: REVERB_UNIT_VOLUME  (0x1000) // 1.0 in 4.12 format
+            float vl = (float)pContext->prevLeftVolume / 4096;
+            float incl = (((float)pContext->leftVolume / 4096) - vl) / frameCount;
+            float vr = (float)pContext->prevRightVolume / 4096;
+            float incr = (((float)pContext->rightVolume / 4096) - vr) / frameCount;
+
+            for (int i = 0; i < frameCount; i++) {
+                pContext->OutFrames[FCC_2 * i] *= vl;
+                pContext->OutFrames[FCC_2 * i + 1] *= vr;
+
+                vl += incl;
+                vr += incr;
+            }
+#else
             LVM_INT32 vl = (LVM_INT32)pContext->prevLeftVolume << 16;
             LVM_INT32 incl = (((LVM_INT32)pContext->leftVolume << 16) - vl) / frameCount;
             LVM_INT32 vr = (LVM_INT32)pContext->prevRightVolume << 16;
             LVM_INT32 incr = (((LVM_INT32)pContext->rightVolume << 16) - vr) / frameCount;
 
             for (int i = 0; i < frameCount; i++) {
-                OutFrames16[2*i] =
+                OutFrames16[FCC_2 * i] =
                         clamp16((LVM_INT32)((vl >> 16) * OutFrames16[2*i]) >> 12);
-                OutFrames16[2*i+1] =
+                OutFrames16[FCC_2 * i + 1] =
                         clamp16((LVM_INT32)((vr >> 16) * OutFrames16[2*i+1]) >> 12);
 
                 vl += incl;
                 vr += incr;
             }
-
+#endif
             pContext->prevLeftVolume = pContext->leftVolume;
             pContext->prevRightVolume = pContext->rightVolume;
         } else if (pContext->volumeMode != REVERB_VOLUME_OFF) {
             if (pContext->leftVolume != REVERB_UNIT_VOLUME ||
                 pContext->rightVolume != REVERB_UNIT_VOLUME) {
                 for (int i = 0; i < frameCount; i++) {
-                    OutFrames16[2*i] =
+#if defined(BUILD_FLOAT) && defined(NATIVE_FLOAT_BUFFER)
+                    pContext->OutFrames[FCC_2 * i] *= ((float)pContext->leftVolume / 4096);
+                    pContext->OutFrames[FCC_2 * i + 1] *= ((float)pContext->rightVolume / 4096);
+#else
+                    OutFrames16[FCC_2 * i] =
                             clamp16((LVM_INT32)(pContext->leftVolume * OutFrames16[2*i]) >> 12);
-                    OutFrames16[2*i+1] =
+                    OutFrames16[FCC_2 * i + 1] =
                             clamp16((LVM_INT32)(pContext->rightVolume * OutFrames16[2*i+1]) >> 12);
+#endif
                 }
             }
             pContext->prevLeftVolume = pContext->leftVolume;
@@ -643,20 +561,25 @@
         }
     }
 
-    #ifdef LVM_PCM
-    fwrite(OutFrames16, frameCount*sizeof(LVM_INT16)*2, 1, pContext->PcmOutPtr);
+#ifdef LVM_PCM
+    fwrite(pContext->OutFrames, frameCount * sizeof(*pContext->OutFrames) * FCC_2,
+            1 /* nmemb */, pContext->PcmOutPtr);
     fflush(pContext->PcmOutPtr);
-    #endif
+#endif
 
     // Accumulate if required
     if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
         //ALOGV("\tBuffer access is ACCUMULATE");
-        for (int i=0; i<frameCount*2; i++){ //always stereo here
+        for (int i = 0; i < frameCount * FCC_2; i++) { // always stereo here
+#ifndef NATIVE_FLOAT_BUFFER
             pOut[i] = clamp16((int32_t)pOut[i] + (int32_t)OutFrames16[i]);
+#else
+            pOut[i] += pContext->OutFrames[i];
+#endif
         }
     }else{
         //ALOGV("\tBuffer access is WRITE");
-        memcpy(pOut, OutFrames16, frameCount*sizeof(LVM_INT16)*2);
+        memcpy(pOut, pContext->OutFrames, frameCount * sizeof(*pOut) * FCC_2);
     }
 
     return 0;
@@ -733,8 +656,7 @@
     CHECK_ARG(pConfig->outputCfg.channels == AUDIO_CHANNEL_OUT_STEREO);
     CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE
               || pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
-    CHECK_ARG(pConfig->inputCfg.format == AUDIO_FORMAT_PCM_16_BIT);
-
+    CHECK_ARG(pConfig->inputCfg.format == EFFECT_BUFFER_FORMAT);
     //ALOGV("\tReverb_setConfig calling memcpy");
     pContext->config = *pConfig;
 
@@ -847,8 +769,7 @@
     } else {
         pContext->config.inputCfg.channels                  = AUDIO_CHANNEL_OUT_STEREO;
     }
-
-    pContext->config.inputCfg.format                        = AUDIO_FORMAT_PCM_16_BIT;
+    pContext->config.inputCfg.format                        = EFFECT_BUFFER_FORMAT;
     pContext->config.inputCfg.samplingRate                  = 44100;
     pContext->config.inputCfg.bufferProvider.getBuffer      = NULL;
     pContext->config.inputCfg.bufferProvider.releaseBuffer  = NULL;
@@ -856,7 +777,7 @@
     pContext->config.inputCfg.mask                          = EFFECT_CONFIG_ALL;
     pContext->config.outputCfg.accessMode                   = EFFECT_BUFFER_ACCESS_ACCUMULATE;
     pContext->config.outputCfg.channels                     = AUDIO_CHANNEL_OUT_STEREO;
-    pContext->config.outputCfg.format                       = AUDIO_FORMAT_PCM_16_BIT;
+    pContext->config.outputCfg.format                       = EFFECT_BUFFER_FORMAT;
     pContext->config.outputCfg.samplingRate                 = 44100;
     pContext->config.outputCfg.bufferProvider.getBuffer     = NULL;
     pContext->config.outputCfg.bufferProvider.releaseBuffer = NULL;
@@ -2031,10 +1952,17 @@
     }
     //ALOGV("\tReverb_process() Calling process with %d frames", outBuffer->frameCount);
     /* Process all the available frames, block processing is handled internalLY by the LVM bundle */
-    status = process(    (LVM_INT16 *)inBuffer->raw,
-                         (LVM_INT16 *)outBuffer->raw,
-                                      outBuffer->frameCount,
-                                      pContext);
+#if defined (BUILD_FLOAT) && defined (NATIVE_FLOAT_BUFFER)
+    status = process(    inBuffer->f32,
+                         outBuffer->f32,
+                         outBuffer->frameCount,
+                         pContext);
+#else
+    status = process(    inBuffer->s16,
+                         outBuffer->s16,
+                         outBuffer->frameCount,
+                         pContext);
+#endif
 
     if (pContext->bEnabled == LVM_FALSE) {
         if (pContext->SamplesToExitCount > 0) {
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index 4b131a7..a63a2df 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -25,8 +25,8 @@
 #include <drm/drm_framework_common.h>
 #include <media/IDataSource.h>
 #include <media/mediametadataretriever.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaSource.h>
 #include <private/media/VideoFrame.h>
 #include <utils/Log.h>
 #include <utils/RefBase.h>
@@ -270,7 +270,9 @@
     // it's not, default to HAL_PIXEL_FORMAT_RGB_565.
     mOutputColor(HAL_PIXEL_FORMAT_RGB_565),
     mCurScanline(0),
-    mFrameDecoded(false) {
+    mFrameDecoded(false),
+    mHasImage(false),
+    mHasVideo(false) {
 }
 
 HeifDecoderImpl::~HeifDecoderImpl() {
@@ -278,6 +280,8 @@
 
 bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) {
     mFrameDecoded = false;
+    mFrameMemory.clear();
+
     sp<HeifDataSource> dataSource = new HeifDataSource(stream);
     if (!dataSource->init()) {
         return false;
@@ -285,7 +289,7 @@
     mDataSource = dataSource;
 
     mRetriever = new MediaMetadataRetriever();
-    status_t err = mRetriever->setDataSource(mDataSource, "video/mp4");
+    status_t err = mRetriever->setDataSource(mDataSource, "image/heif");
     if (err != OK) {
         ALOGE("failed to set data source!");
 
@@ -295,15 +299,21 @@
     }
     ALOGV("successfully set data source.");
 
+    const char* hasImage = mRetriever->extractMetadata(METADATA_KEY_HAS_IMAGE);
     const char* hasVideo = mRetriever->extractMetadata(METADATA_KEY_HAS_VIDEO);
-    if (!hasVideo || strcasecmp(hasVideo, "yes")) {
-        ALOGE("no video: %s", hasVideo ? hasVideo : "null");
-        return false;
+
+    mHasImage = hasImage && !strcasecmp(hasImage, "yes");
+    mHasVideo = hasVideo && !strcasecmp(hasVideo, "yes");
+    if (mHasImage) {
+        // image index < 0 to retrieve primary image
+        mFrameMemory = mRetriever->getImageAtIndex(
+                -1, mOutputColor, true /*metaOnly*/);
+    } else if (mHasVideo) {
+        mFrameMemory = mRetriever->getFrameAtTime(0,
+                MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
+                mOutputColor, true /*metaOnly*/);
     }
 
-    mFrameMemory = mRetriever->getFrameAtTime(0,
-            IMediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
-            mOutputColor, true /*metaOnly*/);
     if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
         ALOGE("getFrameAtTime: videoFrame is a nullptr");
         return false;
@@ -368,8 +378,14 @@
         return true;
     }
 
-    mFrameMemory = mRetriever->getFrameAtTime(0,
-            IMediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
+    if (mHasImage) {
+        // image index < 0 to retrieve primary image
+        mFrameMemory = mRetriever->getImageAtIndex(-1, mOutputColor);
+    } else if (mHasVideo) {
+        mFrameMemory = mRetriever->getFrameAtTime(0,
+                MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
+    }
+
     if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
         ALOGE("getFrameAtTime: videoFrame is a nullptr");
         return false;
diff --git a/media/libheif/HeifDecoderImpl.h b/media/libheif/HeifDecoderImpl.h
index c2e4ff3..406c2c1 100644
--- a/media/libheif/HeifDecoderImpl.h
+++ b/media/libheif/HeifDecoderImpl.h
@@ -55,6 +55,8 @@
     android_pixel_format_t mOutputColor;
     size_t mCurScanline;
     bool mFrameDecoded;
+    bool mHasImage;
+    bool mHasVideo;
 };
 
 } // namespace android
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index a462f3a..1f4bd0a 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -24,7 +24,7 @@
         "-Wno-error=deprecated-declarations",
         "-Wall",
     ],
-    shared_libs: ["libutils", "liblog", "libgui"],
+    shared_libs: ["libutils", "liblog"],
     header_libs: [
         "libmedia_headers",
         "libaudioclient_headers",
@@ -33,22 +33,21 @@
     clang: true,
 }
 
-// TODO(b/35449087): merge back with libmedia when OMX implementatoins
-// no longer use aidl wrappers (or remove OMX component form libmedia)
-cc_defaults {
-    name: "libmedia_omx_defaults",
+cc_library_shared {
+    name: "libmedia_omx",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
 
     srcs: [
         "aidl/android/IGraphicBufferSource.aidl",
         "aidl/android/IOMXBufferSource.aidl",
 
         "IMediaCodecList.cpp",
-        "IMediaCodecService.cpp",
         "IOMX.cpp",
-        "IOMXStore.cpp",
         "MediaCodecBuffer.cpp",
         "MediaCodecInfo.cpp",
-        "MediaDefs.cpp",
         "OMXBuffer.cpp",
         "omx/1.0/WGraphicBufferSource.cpp",
         "omx/1.0/WOmx.cpp",
@@ -63,18 +62,13 @@
     },
 
     shared_libs: [
-        "android.hidl.memory@1.0",
         "android.hidl.token@1.0-utils",
         "android.hardware.media.omx@1.0",
-        "android.hardware.media@1.0",
-        "libbase",
         "libbinder",
         "libcutils",
         "libgui",
         "libhidlbase",
-        "libhidlmemory",
         "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libstagefright_foundation",
         "libui",
@@ -82,11 +76,8 @@
     ],
 
     export_shared_lib_headers: [
-        "android.hidl.memory@1.0",
         "android.hidl.token@1.0-utils",
         "android.hardware.media.omx@1.0",
-        "android.hardware.media@1.0",
-        "libhidlmemory",
         "libstagefright_foundation",
         "libui",
     ],
@@ -121,23 +112,38 @@
     },
 }
 
-cc_library_shared {
-    name: "libmedia_omx",
-    vendor_available: true,
-    vndk: {
-        enabled: true,
-    },
+cc_library_static {
+    name: "libmedia_midiiowrapper",
 
-    defaults: ["libmedia_omx_defaults"],
+    srcs: ["MidiIoWrapper.cpp"],
+
+    static_libs: [
+        "libsonivox",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
 }
 
 cc_library_shared {
     name: "libmedia",
-    defaults: ["libmedia_omx_defaults"],
 
     srcs: [
         "IDataSource.cpp",
-        "IHDCP.cpp",
         "BufferingSettings.cpp",
         "mediaplayer.cpp",
         "IMediaHTTPConnection.cpp",
@@ -161,7 +167,6 @@
         "IMediaMetadataRetriever.cpp",
         "mediametadataretriever.cpp",
         "MidiDeviceInfo.cpp",
-        "MidiIoWrapper.cpp",
         "JetPlayer.cpp",
         "MediaScanner.cpp",
         "MediaScannerClient.cpp",
@@ -186,36 +191,28 @@
         "libexpat",
         "libcamera_client",
         "libstagefright_foundation",
+        "libmediaextractor",
         "libgui",
         "libdl",
         "libaudioutils",
         "libaudioclient",
-        "libmedia_helper",
-        "libmediadrm",
-        "libmediametrics",
-        "libbase",
         "libhidlbase",
         "libhidltransport",
-        "libhwbinder",
-        "libhidlmemory",
-        "android.hidl.memory@1.0",
-        "android.hardware.graphics.common@1.0",
-        "android.hardware.graphics.bufferqueue@1.0",
+        "libmedia_omx",
     ],
 
     export_shared_lib_headers: [
+        "libaudioclient",
         "libbinder",
         "libicuuc",
         "libicui18n",
         "libsonivox",
-        "libmediadrm",
-        "libmedia_helper",
-        "android.hidl.memory@1.0",
+        "libmedia_omx",
     ],
 
-    // for memory heap analysis
     static_libs: [
-        "libc_malloc_debug_backtrace",
+        "libc_malloc_debug_backtrace",  // for memory heap analysis
+        "libmedia_midiiowrapper",
     ],
 
     export_include_dirs: [
diff --git a/media/libmedia/BufferingSettings.cpp b/media/libmedia/BufferingSettings.cpp
index a69497e..271a238 100644
--- a/media/libmedia/BufferingSettings.cpp
+++ b/media/libmedia/BufferingSettings.cpp
@@ -23,43 +23,16 @@
 
 namespace android {
 
-// static
-bool BufferingSettings::IsValidBufferingMode(int mode) {
-    return (mode >= BUFFERING_MODE_NONE && mode < BUFFERING_MODE_COUNT);
-}
-
-// static
-bool BufferingSettings::IsTimeBasedBufferingMode(int mode) {
-    return (mode == BUFFERING_MODE_TIME_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
-}
-
-// static
-bool BufferingSettings::IsSizeBasedBufferingMode(int mode) {
-    return (mode == BUFFERING_MODE_SIZE_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
-}
-
 BufferingSettings::BufferingSettings()
-        : mInitialBufferingMode(BUFFERING_MODE_NONE),
-          mRebufferingMode(BUFFERING_MODE_NONE),
-          mInitialWatermarkMs(kNoWatermark),
-          mInitialWatermarkKB(kNoWatermark),
-          mRebufferingWatermarkLowMs(kNoWatermark),
-          mRebufferingWatermarkHighMs(kNoWatermark),
-          mRebufferingWatermarkLowKB(kNoWatermark),
-          mRebufferingWatermarkHighKB(kNoWatermark) { }
+        : mInitialMarkMs(kNoMark),
+          mResumePlaybackMarkMs(kNoMark) { }
 
 status_t BufferingSettings::readFromParcel(const Parcel* parcel) {
     if (parcel == nullptr) {
         return BAD_VALUE;
     }
-    mInitialBufferingMode = (BufferingMode)parcel->readInt32();
-    mRebufferingMode = (BufferingMode)parcel->readInt32();
-    mInitialWatermarkMs = parcel->readInt32();
-    mInitialWatermarkKB = parcel->readInt32();
-    mRebufferingWatermarkLowMs = parcel->readInt32();
-    mRebufferingWatermarkHighMs = parcel->readInt32();
-    mRebufferingWatermarkLowKB = parcel->readInt32();
-    mRebufferingWatermarkHighKB = parcel->readInt32();
+    mInitialMarkMs = parcel->readInt32();
+    mResumePlaybackMarkMs = parcel->readInt32();
 
     return OK;
 }
@@ -68,26 +41,17 @@
     if (parcel == nullptr) {
         return BAD_VALUE;
     }
-    parcel->writeInt32(mInitialBufferingMode);
-    parcel->writeInt32(mRebufferingMode);
-    parcel->writeInt32(mInitialWatermarkMs);
-    parcel->writeInt32(mInitialWatermarkKB);
-    parcel->writeInt32(mRebufferingWatermarkLowMs);
-    parcel->writeInt32(mRebufferingWatermarkHighMs);
-    parcel->writeInt32(mRebufferingWatermarkLowKB);
-    parcel->writeInt32(mRebufferingWatermarkHighKB);
+    parcel->writeInt32(mInitialMarkMs);
+    parcel->writeInt32(mResumePlaybackMarkMs);
 
     return OK;
 }
 
 String8 BufferingSettings::toString() const {
     String8 s;
-    s.appendFormat("initialMode(%d), rebufferingMode(%d), "
-            "initialMarks(%d ms, %d KB), rebufferingMarks(%d, %d)ms, (%d, %d)KB",
-            mInitialBufferingMode, mRebufferingMode,
-            mInitialWatermarkMs, mInitialWatermarkKB,
-            mRebufferingWatermarkLowMs, mRebufferingWatermarkHighMs,
-            mRebufferingWatermarkLowKB, mRebufferingWatermarkHighKB);
+    s.appendFormat(
+            "initialMarks(%d ms), resumePlaybackMarks(%d ms)",
+            mInitialMarkMs, mResumePlaybackMarkMs);
     return s;
 }
 
diff --git a/media/libmedia/IHDCP.cpp b/media/libmedia/IHDCP.cpp
deleted file mode 100644
index a46017f..0000000
--- a/media/libmedia/IHDCP.cpp
+++ /dev/null
@@ -1,359 +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 "IHDCP"
-#include <utils/Log.h>
-
-#include <binder/Parcel.h>
-#include <media/IHDCP.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace android {
-
-enum {
-    OBSERVER_NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
-    HDCP_SET_OBSERVER,
-    HDCP_INIT_ASYNC,
-    HDCP_SHUTDOWN_ASYNC,
-    HDCP_GET_CAPS,
-    HDCP_ENCRYPT,
-    HDCP_ENCRYPT_NATIVE,
-    HDCP_DECRYPT,
-};
-
-struct BpHDCPObserver : public BpInterface<IHDCPObserver> {
-    explicit BpHDCPObserver(const sp<IBinder> &impl)
-        : BpInterface<IHDCPObserver>(impl) {
-    }
-
-    virtual void notify(
-            int msg, int ext1, int ext2, const Parcel *obj) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IHDCPObserver::getInterfaceDescriptor());
-        data.writeInt32(msg);
-        data.writeInt32(ext1);
-        data.writeInt32(ext2);
-        if (obj && obj->dataSize() > 0) {
-            data.appendFrom(const_cast<Parcel *>(obj), 0, obj->dataSize());
-        }
-        remote()->transact(OBSERVER_NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-};
-
-IMPLEMENT_META_INTERFACE(HDCPObserver, "android.hardware.IHDCPObserver");
-
-struct BpHDCP : public BpInterface<IHDCP> {
-    explicit BpHDCP(const sp<IBinder> &impl)
-        : BpInterface<IHDCP>(impl) {
-    }
-
-    virtual status_t setObserver(const sp<IHDCPObserver> &observer) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IHDCP::getInterfaceDescriptor());
-        data.writeStrongBinder(IInterface::asBinder(observer));
-        remote()->transact(HDCP_SET_OBSERVER, data, &reply);
-        return reply.readInt32();
-    }
-
-    virtual status_t initAsync(const char *host, unsigned port) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IHDCP::getInterfaceDescriptor());
-        data.writeCString(host);
-        data.writeInt32(port);
-        remote()->transact(HDCP_INIT_ASYNC, data, &reply);
-        return reply.readInt32();
-    }
-
-    virtual status_t shutdownAsync() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IHDCP::getInterfaceDescriptor());
-        remote()->transact(HDCP_SHUTDOWN_ASYNC, data, &reply);
-        return reply.readInt32();
-    }
-
-    virtual uint32_t getCaps() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IHDCP::getInterfaceDescriptor());
-        remote()->transact(HDCP_GET_CAPS, data, &reply);
-        return reply.readInt32();
-    }
-
-    virtual status_t encrypt(
-            const void *inData, size_t size, uint32_t streamCTR,
-            uint64_t *outInputCTR, void *outData) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IHDCP::getInterfaceDescriptor());
-        data.writeInt32(size);
-        data.write(inData, size);
-        data.writeInt32(streamCTR);
-        remote()->transact(HDCP_ENCRYPT, data, &reply);
-
-        status_t err = reply.readInt32();
-
-        if (err != OK) {
-            *outInputCTR = 0;
-
-            return err;
-        }
-
-        *outInputCTR = reply.readInt64();
-        reply.read(outData, size);
-
-        return err;
-    }
-
-    virtual status_t encryptNative(
-            const sp<GraphicBuffer> &graphicBuffer,
-            size_t offset, size_t size, uint32_t streamCTR,
-            uint64_t *outInputCTR, void *outData) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IHDCP::getInterfaceDescriptor());
-        data.write(*graphicBuffer);
-        data.writeInt32(offset);
-        data.writeInt32(size);
-        data.writeInt32(streamCTR);
-        remote()->transact(HDCP_ENCRYPT_NATIVE, data, &reply);
-
-        status_t err = reply.readInt32();
-
-        if (err != OK) {
-            *outInputCTR = 0;
-            return err;
-        }
-
-        *outInputCTR = reply.readInt64();
-        reply.read(outData, size);
-
-        return err;
-    }
-
-    virtual status_t decrypt(
-            const void *inData, size_t size,
-            uint32_t streamCTR, uint64_t inputCTR,
-            void *outData) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IHDCP::getInterfaceDescriptor());
-        data.writeInt32(size);
-        data.write(inData, size);
-        data.writeInt32(streamCTR);
-        data.writeInt64(inputCTR);
-        remote()->transact(HDCP_DECRYPT, data, &reply);
-
-        status_t err = reply.readInt32();
-
-        if (err != OK) {
-            return err;
-        }
-
-        reply.read(outData, size);
-
-        return err;
-    }
-};
-
-IMPLEMENT_META_INTERFACE(HDCP, "android.hardware.IHDCP");
-
-status_t BnHDCPObserver::onTransact(
-        uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
-    switch (code) {
-        case OBSERVER_NOTIFY:
-        {
-            CHECK_INTERFACE(IHDCPObserver, data, reply);
-
-            int msg = data.readInt32();
-            int ext1 = data.readInt32();
-            int ext2 = data.readInt32();
-
-            Parcel obj;
-            if (data.dataAvail() > 0) {
-                obj.appendFrom(
-                        const_cast<Parcel *>(&data),
-                        data.dataPosition(),
-                        data.dataAvail());
-            }
-
-            notify(msg, ext1, ext2, &obj);
-
-            return OK;
-        }
-
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-status_t BnHDCP::onTransact(
-        uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
-    switch (code) {
-        case HDCP_SET_OBSERVER:
-        {
-            CHECK_INTERFACE(IHDCP, data, reply);
-
-            sp<IHDCPObserver> observer =
-                interface_cast<IHDCPObserver>(data.readStrongBinder());
-
-            reply->writeInt32(setObserver(observer));
-            return OK;
-        }
-
-        case HDCP_INIT_ASYNC:
-        {
-            CHECK_INTERFACE(IHDCP, data, reply);
-
-            const char *host = data.readCString();
-            unsigned port = data.readInt32();
-
-            reply->writeInt32(initAsync(host, port));
-            return OK;
-        }
-
-        case HDCP_SHUTDOWN_ASYNC:
-        {
-            CHECK_INTERFACE(IHDCP, data, reply);
-
-            reply->writeInt32(shutdownAsync());
-            return OK;
-        }
-
-        case HDCP_GET_CAPS:
-        {
-            CHECK_INTERFACE(IHDCP, data, reply);
-
-            reply->writeInt32(getCaps());
-            return OK;
-        }
-
-        case HDCP_ENCRYPT:
-        {
-            CHECK_INTERFACE(IHDCP, data, reply);
-
-            size_t size = data.readInt32();
-            void *inData = NULL;
-            // watch out for overflow
-            if (size <= SIZE_MAX / 2) {
-                inData = malloc(2 * size);
-            }
-            if (inData == NULL) {
-                reply->writeInt32(ERROR_OUT_OF_RANGE);
-                return OK;
-            }
-
-            void *outData = (uint8_t *)inData + size;
-
-            status_t err = data.read(inData, size);
-            if (err != OK) {
-                free(inData);
-                reply->writeInt32(err);
-                return OK;
-            }
-
-            uint32_t streamCTR = data.readInt32();
-            uint64_t inputCTR;
-            err = encrypt(inData, size, streamCTR, &inputCTR, outData);
-
-            reply->writeInt32(err);
-
-            if (err == OK) {
-                reply->writeInt64(inputCTR);
-                reply->write(outData, size);
-            }
-
-            free(inData);
-            inData = outData = NULL;
-
-            return OK;
-        }
-
-        case HDCP_ENCRYPT_NATIVE:
-        {
-            CHECK_INTERFACE(IHDCP, data, reply);
-
-            sp<GraphicBuffer> graphicBuffer = new GraphicBuffer();
-            data.read(*graphicBuffer);
-            size_t offset = data.readInt32();
-            size_t size = data.readInt32();
-            uint32_t streamCTR = data.readInt32();
-            void *outData = NULL;
-            uint64_t inputCTR;
-
-            status_t err = ERROR_OUT_OF_RANGE;
-
-            outData = malloc(size);
-
-            if (outData != NULL) {
-                err = encryptNative(graphicBuffer, offset, size,
-                                             streamCTR, &inputCTR, outData);
-            }
-
-            reply->writeInt32(err);
-
-            if (err == OK) {
-                reply->writeInt64(inputCTR);
-                reply->write(outData, size);
-            }
-
-            free(outData);
-            outData = NULL;
-
-            return OK;
-        }
-
-        case HDCP_DECRYPT:
-        {
-            CHECK_INTERFACE(IHDCP, data, reply);
-
-            size_t size = data.readInt32();
-            size_t bufSize = 2 * size;
-
-            // watch out for overflow
-            void *inData = NULL;
-            if (bufSize > size) {
-                inData = malloc(bufSize);
-            }
-
-            if (inData == NULL) {
-                reply->writeInt32(ERROR_OUT_OF_RANGE);
-                return OK;
-            }
-
-            void *outData = (uint8_t *)inData + size;
-
-            data.read(inData, size);
-
-            uint32_t streamCTR = data.readInt32();
-            uint64_t inputCTR = data.readInt64();
-            status_t err = decrypt(inData, size, streamCTR, inputCTR, outData);
-
-            reply->writeInt32(err);
-
-            if (err == OK) {
-                reply->write(outData, size);
-            }
-
-            free(inData);
-            inData = outData = NULL;
-
-            return OK;
-        }
-
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-}  // namespace android
diff --git a/media/libmedia/IMediaCodecService.cpp b/media/libmedia/IMediaCodecService.cpp
deleted file mode 100644
index adfa93d..0000000
--- a/media/libmedia/IMediaCodecService.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "IMediaCodecService"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/Parcel.h>
-#include <media/IMediaCodecService.h>
-
-namespace android {
-
-enum {
-    GET_OMX = IBinder::FIRST_CALL_TRANSACTION,
-    GET_OMX_STORE
-};
-
-class BpMediaCodecService : public BpInterface<IMediaCodecService>
-{
-public:
-    explicit BpMediaCodecService(const sp<IBinder>& impl)
-        : BpInterface<IMediaCodecService>(impl)
-    {
-    }
-
-    virtual sp<IOMX> getOMX() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
-        remote()->transact(GET_OMX, data, &reply);
-        return interface_cast<IOMX>(reply.readStrongBinder());
-    }
-
-    virtual sp<IOMXStore> getOMXStore() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
-        remote()->transact(GET_OMX_STORE, data, &reply);
-        return interface_cast<IOMXStore>(reply.readStrongBinder());
-    }
-
-};
-
-IMPLEMENT_META_INTERFACE(MediaCodecService, "android.media.IMediaCodecService");
-
-// ----------------------------------------------------------------------
-
-status_t BnMediaCodecService::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch (code) {
-
-        case GET_OMX: {
-            CHECK_INTERFACE(IMediaCodecService, data, reply);
-            sp<IOMX> omx = getOMX();
-            reply->writeStrongBinder(IInterface::asBinder(omx));
-            return NO_ERROR;
-        }
-        case GET_OMX_STORE: {
-            CHECK_INTERFACE(IMediaCodecService, data, reply);
-            sp<IOMXStore> omxStore = getOMXStore();
-            reply->writeStrongBinder(IInterface::asBinder(omxStore));
-            return NO_ERROR;
-        }
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-} // namespace android
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
index 7c0d08d..d7533ca 100644
--- a/media/libmedia/IMediaExtractorService.cpp
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -23,7 +23,7 @@
 #include <sys/types.h>
 #include <binder/Parcel.h>
 #include <media/IMediaExtractorService.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
 
 namespace android {
 
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 5ea2e8b..f725c97 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -68,6 +68,8 @@
     SET_DATA_SOURCE_FD,
     SET_DATA_SOURCE_CALLBACK,
     GET_FRAME_AT_TIME,
+    GET_IMAGE_AT_INDEX,
+    GET_FRAME_AT_INDEX,
     EXTRACT_ALBUM_ART,
     EXTRACT_METADATA,
 };
@@ -164,6 +166,55 @@
         return interface_cast<IMemory>(reply.readStrongBinder());
     }
 
+    sp<IMemory> getImageAtIndex(int index, int colorFormat, bool metaOnly)
+    {
+        ALOGV("getImageAtIndex: index %d, colorFormat(%d) metaOnly(%d)",
+                index, colorFormat, metaOnly);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeInt32(index);
+        data.writeInt32(colorFormat);
+        data.writeInt32(metaOnly);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+        sendSchedPolicy(data);
+#endif
+        remote()->transact(GET_IMAGE_AT_INDEX, data, &reply);
+        status_t ret = reply.readInt32();
+        if (ret != NO_ERROR) {
+            return NULL;
+        }
+        return interface_cast<IMemory>(reply.readStrongBinder());
+    }
+
+    status_t getFrameAtIndex(std::vector<sp<IMemory> > *frames,
+            int frameIndex, int numFrames, int colorFormat, bool metaOnly)
+    {
+        ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d) metaOnly(%d)",
+                frameIndex, numFrames, colorFormat, metaOnly);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeInt32(frameIndex);
+        data.writeInt32(numFrames);
+        data.writeInt32(colorFormat);
+        data.writeInt32(metaOnly);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+        sendSchedPolicy(data);
+#endif
+        remote()->transact(GET_FRAME_AT_INDEX, data, &reply);
+        status_t ret = reply.readInt32();
+        if (ret != NO_ERROR) {
+            return ret;
+        }
+        int retNumFrames = reply.readInt32();
+        if (retNumFrames < numFrames) {
+            numFrames = retNumFrames;
+        }
+        for (int i = 0; i < numFrames; i++) {
+            frames->push_back(interface_cast<IMemory>(reply.readStrongBinder()));
+        }
+        return OK;
+    }
+
     sp<IMemory> extractAlbumArt()
     {
         Parcel data, reply;
@@ -300,6 +351,54 @@
 #endif
             return NO_ERROR;
         } break;
+        case GET_IMAGE_AT_INDEX: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            int index = data.readInt32();
+            int colorFormat = data.readInt32();
+            bool metaOnly = (data.readInt32() != 0);
+            ALOGV("getImageAtIndex: index(%d), colorFormat(%d), metaOnly(%d)",
+                    index, colorFormat, metaOnly);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+            setSchedPolicy(data);
+#endif
+            sp<IMemory> bitmap = getImageAtIndex(index, colorFormat, metaOnly);
+            if (bitmap != 0) {  // Don't send NULL across the binder interface
+                reply->writeInt32(NO_ERROR);
+                reply->writeStrongBinder(IInterface::asBinder(bitmap));
+            } else {
+                reply->writeInt32(UNKNOWN_ERROR);
+            }
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+            restoreSchedPolicy();
+#endif
+            return NO_ERROR;
+        } break;
+        case GET_FRAME_AT_INDEX: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            int frameIndex = data.readInt32();
+            int numFrames = data.readInt32();
+            int colorFormat = data.readInt32();
+            bool metaOnly = (data.readInt32() != 0);
+            ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d), metaOnly(%d)",
+                    frameIndex, numFrames, colorFormat, metaOnly);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+            setSchedPolicy(data);
+#endif
+            std::vector<sp<IMemory> > frames;
+            status_t err = getFrameAtIndex(
+                    &frames, frameIndex, numFrames, colorFormat, metaOnly);
+            reply->writeInt32(err);
+            if (OK == err) {
+                reply->writeInt32(frames.size());
+                for (size_t i = 0; i < frames.size(); i++) {
+                    reply->writeStrongBinder(IInterface::asBinder(frames[i]));
+                }
+            }
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+            restoreSchedPolicy();
+#endif
+            return NO_ERROR;
+        } break;
         case EXTRACT_ALBUM_ART: {
             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
 #ifndef DISABLE_GROUP_SCHEDULE_HACK
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 3996227..e2eccdd 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -35,6 +35,8 @@
 
 namespace android {
 
+using media::VolumeShaper;
+
 enum {
     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
     SET_DATA_SOURCE_URL,
@@ -42,7 +44,7 @@
     SET_DATA_SOURCE_STREAM,
     SET_DATA_SOURCE_CALLBACK,
     SET_BUFFERING_SETTINGS,
-    GET_DEFAULT_BUFFERING_SETTINGS,
+    GET_BUFFERING_SETTINGS,
     PREPARE_ASYNC,
     START,
     STOP,
@@ -56,6 +58,7 @@
     GET_CURRENT_POSITION,
     GET_DURATION,
     RESET,
+    NOTIFY_AT,
     SET_AUDIO_STREAM_TYPE,
     SET_LOOPING,
     SET_VOLUME,
@@ -75,6 +78,10 @@
     // Modular DRM
     PREPARE_DRM,
     RELEASE_DRM,
+    // AudioRouting
+    SET_OUTPUT_DEVICE,
+    GET_ROUTED_DEVICE_ID,
+    ENABLE_AUDIO_DEVICE_CALLBACK,
 };
 
 // ModDrm helpers
@@ -177,14 +184,14 @@
         return reply.readInt32();
     }
 
-    status_t getDefaultBufferingSettings(BufferingSettings* buffering /* nonnull */)
+    status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */)
     {
         if (buffering == nullptr) {
             return BAD_VALUE;
         }
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
-        remote()->transact(GET_DEFAULT_BUFFERING_SETTINGS, data, &reply);
+        remote()->transact(GET_BUFFERING_SETTINGS, data, &reply);
         status_t err = reply.readInt32();
         if (err == OK) {
             err = buffering->readFromParcel(&reply);
@@ -326,6 +333,15 @@
         return reply.readInt32();
     }
 
+    status_t notifyAt(int64_t mediaTimeUs)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeInt64(mediaTimeUs);
+        remote()->transact(NOTIFY_AT, data, &reply);
+        return reply.readInt32();
+    }
+
     status_t setAudioStreamType(audio_stream_type_t stream)
     {
         Parcel data, reply;
@@ -509,7 +525,7 @@
             return nullptr;
         }
         sp<VolumeShaper::State> state = new VolumeShaper::State();
-        status = state->readFromParcel(reply);
+        status = state->readFromParcel(&reply);
         if (status != NO_ERROR) {
             return nullptr;
         }
@@ -547,6 +563,59 @@
 
         return reply.readInt32();
     }
+
+    status_t setOutputDevice(audio_port_handle_t deviceId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        data.writeInt32(deviceId);
+
+        status_t status = remote()->transact(SET_OUTPUT_DEVICE, data, &reply);
+        if (status != OK) {
+            ALOGE("setOutputDevice: binder call failed: %d", status);
+            return status;
+        }
+
+        return reply.readInt32();
+    }
+
+    status_t getRoutedDeviceId(audio_port_handle_t* deviceId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        status_t status = remote()->transact(GET_ROUTED_DEVICE_ID, data, &reply);
+        if (status != OK) {
+            ALOGE("getRoutedDeviceid: binder call failed: %d", status);
+            *deviceId = AUDIO_PORT_HANDLE_NONE;
+            return status;
+        }
+
+        status = reply.readInt32();
+        if (status != NO_ERROR) {
+            *deviceId = AUDIO_PORT_HANDLE_NONE;
+        } else {
+            *deviceId = reply.readInt32();
+        }
+        return status;
+    }
+
+    status_t enableAudioDeviceCallback(bool enabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        data.writeBool(enabled);
+
+        status_t status = remote()->transact(ENABLE_AUDIO_DEVICE_CALLBACK, data, &reply);
+        if (status != OK) {
+            ALOGE("enableAudioDeviceCallback: binder call failed: %d, %d", enabled, status);
+            return status;
+        }
+
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -631,10 +700,10 @@
             reply->writeInt32(setBufferingSettings(buffering));
             return NO_ERROR;
         } break;
-        case GET_DEFAULT_BUFFERING_SETTINGS: {
+        case GET_BUFFERING_SETTINGS: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             BufferingSettings buffering;
-            status_t err = getDefaultBufferingSettings(&buffering);
+            status_t err = getBufferingSettings(&buffering);
             reply->writeInt32(err);
             if (err == OK) {
                 buffering.writeToParcel(reply);
@@ -744,6 +813,11 @@
             reply->writeInt32(reset());
             return NO_ERROR;
         } break;
+        case NOTIFY_AT: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(notifyAt(data.readInt64()));
+            return NO_ERROR;
+        } break;
         case SET_AUDIO_STREAM_TYPE: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             reply->writeInt32(setAudioStreamType((audio_stream_type_t) data.readInt32()));
@@ -851,14 +925,14 @@
             status_t status = data.readInt32(&present);
             if (status == NO_ERROR && present != 0) {
                 configuration = new VolumeShaper::Configuration();
-                status = configuration->readFromParcel(data);
+                status = configuration->readFromParcel(&data);
             }
             if (status == NO_ERROR) {
                 status = data.readInt32(&present);
             }
             if (status == NO_ERROR && present != 0) {
                 operation = new VolumeShaper::Operation();
-                status = operation->readFromParcel(data);
+                status = operation->readFromParcel(&data);
             }
             if (status == NO_ERROR) {
                 status = (status_t)applyVolumeShaper(configuration, operation);
@@ -899,6 +973,41 @@
             reply->writeInt32(result);
             return OK;
         }
+
+        // AudioRouting
+        case SET_OUTPUT_DEVICE: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            int deviceId;
+            status_t status = data.readInt32(&deviceId);
+            if (status == NO_ERROR) {
+                reply->writeInt32(setOutputDevice(deviceId));
+            } else {
+                reply->writeInt32(BAD_VALUE);
+            }
+            return NO_ERROR;
+        }
+        case GET_ROUTED_DEVICE_ID: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            audio_port_handle_t deviceId;
+            status_t ret = getRoutedDeviceId(&deviceId);
+            reply->writeInt32(ret);
+            if (ret == NO_ERROR) {
+                reply->writeInt32(deviceId);
+            }
+            return NO_ERROR;
+        } break;
+        case ENABLE_AUDIO_DEVICE_CALLBACK: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            bool enabled;
+            status_t status = data.readBool(&enabled);
+            if (status == NO_ERROR) {
+                reply->writeInt32(enableAudioDeviceCallback(enabled));
+            } else {
+                reply->writeInt32(BAD_VALUE);
+            }
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index a01852c..aca7ad9 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -20,7 +20,6 @@
 
 #include <binder/Parcel.h>
 #include <binder/IMemory.h>
-#include <media/IHDCP.h>
 #include <media/IMediaCodecList.h>
 #include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
@@ -39,8 +38,6 @@
     CREATE = IBinder::FIRST_CALL_TRANSACTION,
     CREATE_MEDIA_RECORDER,
     CREATE_METADATA_RETRIEVER,
-    GET_OMX,
-    MAKE_HDCP,
     ADD_BATTERY_DATA,
     PULL_BATTERY_DATA,
     LISTEN_FOR_REMOTE_DISPLAY,
@@ -83,21 +80,6 @@
         return interface_cast<IMediaRecorder>(reply.readStrongBinder());
     }
 
-    virtual sp<IOMX> getOMX() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
-        remote()->transact(GET_OMX, data, &reply);
-        return interface_cast<IOMX>(reply.readStrongBinder());
-    }
-
-    virtual sp<IHDCP> makeHDCP(bool createEncryptionModule) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
-        data.writeInt32(createEncryptionModule);
-        remote()->transact(MAKE_HDCP, data, &reply);
-        return interface_cast<IHDCP>(reply.readStrongBinder());
-    }
-
     virtual void addBatteryData(uint32_t params) {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
@@ -161,19 +143,6 @@
             reply->writeStrongBinder(IInterface::asBinder(retriever));
             return NO_ERROR;
         } break;
-        case GET_OMX: {
-            CHECK_INTERFACE(IMediaPlayerService, data, reply);
-            sp<IOMX> omx = getOMX();
-            reply->writeStrongBinder(IInterface::asBinder(omx));
-            return NO_ERROR;
-        } break;
-        case MAKE_HDCP: {
-            CHECK_INTERFACE(IMediaPlayerService, data, reply);
-            bool createEncryptionModule = data.readInt32();
-            sp<IHDCP> hdcp = makeHDCP(createEncryptionModule);
-            reply->writeStrongBinder(IInterface::asBinder(hdcp));
-            return NO_ERROR;
-        } break;
         case ADD_BATTERY_DATA: {
             CHECK_INTERFACE(IMediaPlayerService, data, reply);
             uint32_t params = data.readInt32();
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 5282352..72f5f58 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -61,6 +61,9 @@
     PAUSE,
     RESUME,
     GET_METRICS,
+    SET_INPUT_DEVICE,
+    GET_ROUTED_DEVICE_ID,
+    ENABLE_AUDIO_DEVICE_CALLBACK,
 
 };
 
@@ -337,6 +340,57 @@
         remote()->transact(RELEASE, data, &reply);
         return reply.readInt32();
     }
+
+    status_t setInputDevice(audio_port_handle_t deviceId)
+    {
+        ALOGV("setInputDevice");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(deviceId);
+
+        status_t status = remote()->transact(SET_INPUT_DEVICE, data, &reply);
+        if (status != OK) {
+            ALOGE("setInputDevice binder call failed: %d", status);
+            return status;
+        }
+        return reply.readInt32();;
+    }
+
+    audio_port_handle_t getRoutedDeviceId(audio_port_handle_t *deviceId)
+    {
+        ALOGV("getRoutedDeviceId");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+
+        status_t status = remote()->transact(GET_ROUTED_DEVICE_ID, data, &reply);
+        if (status != OK) {
+            ALOGE("getRoutedDeviceid binder call failed: %d", status);
+            *deviceId = AUDIO_PORT_HANDLE_NONE;
+            return status;
+        }
+
+        status = reply.readInt32();
+        if (status != NO_ERROR) {
+            *deviceId = AUDIO_PORT_HANDLE_NONE;
+        } else {
+            *deviceId = reply.readInt32();
+        }
+        return status;
+    }
+
+    status_t enableAudioDeviceCallback(bool enabled)
+    {
+        ALOGV("enableAudioDeviceCallback");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeBool(enabled);
+        status_t status = remote()->transact(ENABLE_AUDIO_DEVICE_CALLBACK, data, &reply);
+        if (status != OK) {
+            ALOGE("enableAudioDeviceCallback binder call failed: %d, %d", enabled, status);
+            return status;
+        }
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaRecorder, "android.media.IMediaRecorder");
@@ -543,6 +597,41 @@
             }
             return NO_ERROR;
         } break;
+        case SET_INPUT_DEVICE: {
+            ALOGV("SET_INPUT_DEVICE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            audio_port_handle_t deviceId;
+            status_t status = data.readInt32(&deviceId);
+            if (status == NO_ERROR) {
+                reply->writeInt32(setInputDevice(deviceId));
+            } else {
+                reply->writeInt32(BAD_VALUE);
+            }
+            return NO_ERROR;
+        } break;
+        case GET_ROUTED_DEVICE_ID: {
+            ALOGV("GET_ROUTED_DEVICE_ID");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            audio_port_handle_t deviceId;
+            status_t status = getRoutedDeviceId(&deviceId);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->writeInt32(deviceId);
+            }
+            return NO_ERROR;
+        } break;
+        case ENABLE_AUDIO_DEVICE_CALLBACK: {
+            ALOGV("ENABLE_AUDIO_DEVICE_CALLBACK");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            bool enabled;
+            status_t status = data.readBool(&enabled);
+            if (status == NO_ERROR) {
+                reply->writeInt32(enableAudioDeviceCallback(enabled));
+            } else {
+                reply->writeInt32(BAD_VALUE);
+            }
+            return NO_ERROR;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index 724b3a0..bc78892 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -26,7 +26,7 @@
 #include <media/IMediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 
 namespace android {
@@ -113,7 +113,8 @@
         return NULL;
     }
 
-    virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
+    virtual status_t read(MediaBuffer **buffer,
+            const MediaSource::ReadOptions *options) {
         Vector<MediaBuffer *> buffers;
         status_t ret = readMultiple(&buffers, 1 /* maxNumBuffers */, options);
         *buffer = buffers.size() == 0 ? nullptr : buffers[0];
@@ -123,7 +124,8 @@
     }
 
     virtual status_t readMultiple(
-            Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers, const ReadOptions *options) {
+            Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers,
+            const MediaSource::ReadOptions *options) {
         ALOGV("readMultiple");
         if (buffers == NULL || !buffers->isEmpty()) {
             return BAD_VALUE;
@@ -330,7 +332,7 @@
             }
 
             // Get read options, if any.
-            ReadOptions opts;
+            MediaSource::ReadOptions opts;
             uint32_t len;
             const bool useOptions =
                     data.readUint32(&len) == NO_ERROR
@@ -449,58 +451,5 @@
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-
-IMediaSource::ReadOptions::ReadOptions() {
-    reset();
-}
-
-void IMediaSource::ReadOptions::reset() {
-    mOptions = 0;
-    mSeekTimeUs = 0;
-    mLatenessUs = 0;
-    mNonBlocking = false;
-}
-
-void IMediaSource::ReadOptions::setNonBlocking() {
-    mNonBlocking = true;
-}
-
-void IMediaSource::ReadOptions::clearNonBlocking() {
-    mNonBlocking = false;
-}
-
-bool IMediaSource::ReadOptions::getNonBlocking() const {
-    return mNonBlocking;
-}
-
-void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
-    mOptions |= kSeekTo_Option;
-    mSeekTimeUs = time_us;
-    mSeekMode = mode;
-}
-
-void IMediaSource::ReadOptions::clearSeekTo() {
-    mOptions &= ~kSeekTo_Option;
-    mSeekTimeUs = 0;
-    mSeekMode = SEEK_CLOSEST_SYNC;
-}
-
-bool IMediaSource::ReadOptions::getSeekTo(
-        int64_t *time_us, SeekMode *mode) const {
-    *time_us = mSeekTimeUs;
-    *mode = mSeekMode;
-    return (mOptions & kSeekTo_Option) != 0;
-}
-
-void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
-    mLatenessUs = lateness_us;
-}
-
-int64_t IMediaSource::ReadOptions::getLateBy() const {
-    return mLatenessUs;
-}
-
-
 }  // namespace android
 
diff --git a/media/libmedia/IOMXStore.cpp b/media/libmedia/IOMXStore.cpp
deleted file mode 100644
index 4948f1a..0000000
--- a/media/libmedia/IOMXStore.cpp
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright (c) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "IOMXStore"
-
-#include <utils/Log.h>
-
-#include <media/IOMX.h>
-#include <media/IOMXStore.h>
-#include <android/hardware/media/omx/1.0/IOmxStore.h>
-
-#include <binder/IInterface.h>
-#include <binder/IBinder.h>
-#include <binder/Parcel.h>
-
-#include <vector>
-#include <string>
-
-namespace android {
-
-namespace {
-
-enum {
-    CONNECT = IBinder::FIRST_CALL_TRANSACTION,
-    LIST_SERVICE_ATTRIBUTES,
-    GET_NODE_PREFIX,
-    LIST_ROLES,
-    GET_OMX,
-};
-
-// Forward declarations of std::vector<T> <-> Parcel conversion funcitons that
-// depend on writeToParcel() and readToParcel() for T <-> Parcel.
-
-template <typename T>
-status_t writeToParcel(const std::vector<T>& v, Parcel* p);
-
-template <typename T>
-status_t readFromParcel(std::vector<T>* v, const Parcel& p);
-
-// std::string <-> Parcel
-
-status_t writeToParcel(const std::string& s, Parcel* p) {
-    if (s.size() > INT32_MAX) {
-        return BAD_VALUE;
-    }
-    return p->writeByteArray(
-            s.size(), reinterpret_cast<const uint8_t*>(s.c_str()));
-}
-
-status_t readFromParcel(std::string* s, const Parcel& p) {
-    int32_t len;
-    status_t status = p.readInt32(&len);
-    if (status != NO_ERROR) {
-        return status;
-    } else if ((len < 0) || (static_cast<uint64_t>(len) > SIZE_MAX)) {
-        return BAD_VALUE;
-    }
-    s->resize(len);
-    if (len == 0) {
-        return NO_ERROR;
-    }
-    return p.read(static_cast<void*>(&s->front()), static_cast<size_t>(len));
-}
-
-// IOMXStore::Attribute <-> Parcel
-
-status_t writeToParcel(const IOMXStore::Attribute& a, Parcel* p) {
-    status_t status = writeToParcel(a.key, p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    return writeToParcel(a.value, p);
-}
-
-status_t readFromParcel(IOMXStore::Attribute* a, const Parcel& p) {
-    status_t status = readFromParcel(&(a->key), p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    return readFromParcel(&(a->value), p);
-}
-
-// IOMXStore::NodeInfo <-> Parcel
-
-status_t writeToParcel(const IOMXStore::NodeInfo& n, Parcel* p) {
-    status_t status = writeToParcel(n.name, p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = writeToParcel(n.owner, p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    return writeToParcel(n.attributes, p);
-}
-
-status_t readFromParcel(IOMXStore::NodeInfo* n, const Parcel& p) {
-    status_t status = readFromParcel(&(n->name), p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = readFromParcel(&(n->owner), p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    return readFromParcel(&(n->attributes), p);
-}
-
-// IOMXStore::RoleInfo <-> Parcel
-
-status_t writeToParcel(const IOMXStore::RoleInfo& r, Parcel* p) {
-    status_t status = writeToParcel(r.role, p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = writeToParcel(r.type, p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = p->writeBool(r.isEncoder);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = p->writeBool(r.preferPlatformNodes);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    return writeToParcel(r.nodes, p);
-}
-
-status_t readFromParcel(IOMXStore::RoleInfo* r, const Parcel& p) {
-    status_t status = readFromParcel(&(r->role), p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = readFromParcel(&(r->type), p);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = p.readBool(&(r->isEncoder));
-    if (status != NO_ERROR) {
-        return status;
-    }
-    status = p.readBool(&(r->preferPlatformNodes));
-    if (status != NO_ERROR) {
-        return status;
-    }
-    return readFromParcel(&(r->nodes), p);
-}
-
-// std::vector<NodeInfo> <-> Parcel
-// std::vector<RoleInfo> <-> Parcel
-
-template <typename T>
-status_t writeToParcel(const std::vector<T>& v, Parcel* p) {
-    status_t status = p->writeVectorSize(v);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    for (const T& x : v) {
-        status = writeToParcel(x, p);
-        if (status != NO_ERROR) {
-            return status;
-        }
-    }
-    return NO_ERROR;
-}
-
-template <typename T>
-status_t readFromParcel(std::vector<T>* v, const Parcel& p) {
-    status_t status = p.resizeOutVector(v);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    for (T& x : *v) {
-        status = readFromParcel(&x, p);
-        if (status != NO_ERROR) {
-            return status;
-        }
-    }
-    return NO_ERROR;
-}
-
-} // unnamed namespace
-
-////////////////////////////////////////////////////////////////////////////////
-
-class BpOMXStore : public BpInterface<IOMXStore> {
-public:
-    explicit BpOMXStore(const sp<IBinder> &impl)
-        : BpInterface<IOMXStore>(impl) {
-    }
-
-    status_t listServiceAttributes(
-            std::vector<Attribute>* attributes) override {
-        Parcel data, reply;
-        status_t status;
-        status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
-        if (status != NO_ERROR) {
-            return status;
-        }
-        status = remote()->transact(LIST_SERVICE_ATTRIBUTES, data, &reply);
-        if (status != NO_ERROR) {
-            return status;
-        }
-        return readFromParcel(attributes, reply);
-    }
-
-    status_t getNodePrefix(std::string* prefix) override {
-        Parcel data, reply;
-        status_t status;
-        status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
-        if (status != NO_ERROR) {
-            return status;
-        }
-        status = remote()->transact(GET_NODE_PREFIX, data, &reply);
-        if (status != NO_ERROR) {
-            return status;
-        }
-        return readFromParcel(prefix, reply);
-    }
-
-    status_t listRoles(std::vector<RoleInfo>* roleList) override {
-        Parcel data, reply;
-        status_t status;
-        status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
-        if (status != NO_ERROR) {
-            return status;
-        }
-        status = remote()->transact(LIST_ROLES, data, &reply);
-        if (status != NO_ERROR) {
-            return status;
-        }
-        return readFromParcel(roleList, reply);
-    }
-
-    status_t getOmx(const std::string& name, sp<IOMX>* omx) override {
-        Parcel data, reply;
-        status_t status;
-        status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
-        if (status != NO_ERROR) {
-            return status;
-        }
-        status = writeToParcel(name, &data);
-        if (status != NO_ERROR) {
-            return status;
-        }
-        status = remote()->transact(GET_OMX, data, &reply);
-        if (status != NO_ERROR) {
-            return status;
-        }
-        return reply.readStrongBinder(omx);
-    }
-
-};
-
-IMPLEMENT_META_INTERFACE(OMXStore, "android.hardware.IOMXStore");
-
-////////////////////////////////////////////////////////////////////////////////
-
-#define CHECK_OMX_INTERFACE(interface, data, reply) \
-        do { if (!(data).enforceInterface(interface::getInterfaceDescriptor())) { \
-            ALOGW("Call incorrectly routed to " #interface); \
-            return PERMISSION_DENIED; \
-        } } while (0)
-
-status_t BnOMXStore::onTransact(
-    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
-    switch (code) {
-        case LIST_SERVICE_ATTRIBUTES: {
-            CHECK_OMX_INTERFACE(IOMXStore, data, reply);
-            status_t status;
-            std::vector<Attribute> attributes;
-
-            status = listServiceAttributes(&attributes);
-            if (status != NO_ERROR) {
-                ALOGE("listServiceAttributes() fails with status %d",
-                        static_cast<int>(status));
-                return NO_ERROR;
-            }
-            status = writeToParcel(attributes, reply);
-            if (status != NO_ERROR) {
-                ALOGE("listServiceAttributes() fails to send reply");
-                return NO_ERROR;
-            }
-            return NO_ERROR;
-        }
-        case GET_NODE_PREFIX: {
-            CHECK_OMX_INTERFACE(IOMXStore, data, reply);
-            status_t status;
-            std::string prefix;
-
-            status = getNodePrefix(&prefix);
-            if (status != NO_ERROR) {
-                ALOGE("getNodePrefix() fails with status %d",
-                        static_cast<int>(status));
-                return NO_ERROR;
-            }
-            status = writeToParcel(prefix, reply);
-            if (status != NO_ERROR) {
-                ALOGE("getNodePrefix() fails to send reply");
-                return NO_ERROR;
-            }
-            return NO_ERROR;
-        }
-        case LIST_ROLES: {
-            CHECK_OMX_INTERFACE(IOMXStore, data, reply);
-            status_t status;
-            std::vector<RoleInfo> roleList;
-
-            status = listRoles(&roleList);
-            if (status != NO_ERROR) {
-                ALOGE("listRoles() fails with status %d",
-                        static_cast<int>(status));
-                return NO_ERROR;
-            }
-            status = writeToParcel(roleList, reply);
-            if (status != NO_ERROR) {
-                ALOGE("listRoles() fails to send reply");
-                return NO_ERROR;
-            }
-            return NO_ERROR;
-        }
-        case GET_OMX: {
-            CHECK_OMX_INTERFACE(IOMXStore, data, reply);
-            status_t status;
-            std::string name;
-            sp<IOMX> omx;
-
-            status = readFromParcel(&name, data);
-            if (status != NO_ERROR) {
-                ALOGE("getOmx() fails to retrieve name");
-                return NO_ERROR;
-            }
-            status = getOmx(name, &omx);
-            if (status != NO_ERROR) {
-                ALOGE("getOmx() fails with status %d",
-                        static_cast<int>(status));
-                return NO_ERROR;
-            }
-            status = reply->writeStrongBinder(IInterface::asBinder(omx));
-            if (status != NO_ERROR) {
-                ALOGE("getOmx() fails to send reply");
-                return NO_ERROR;
-            }
-            return NO_ERROR;
-        }
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-}  // namespace android
diff --git a/media/libmedia/include/media/BufferingSettings.h b/media/libmedia/include/media/BufferingSettings.h
index e812d2a..d2a3e40 100644
--- a/media/libmedia/include/media/BufferingSettings.h
+++ b/media/libmedia/include/media/BufferingSettings.h
@@ -21,45 +21,14 @@
 
 namespace android {
 
-enum BufferingMode : int {
-    // Do not support buffering.
-    BUFFERING_MODE_NONE             = 0,
-    // Support only time based buffering.
-    BUFFERING_MODE_TIME_ONLY        = 1,
-    // Support only size based buffering.
-    BUFFERING_MODE_SIZE_ONLY        = 2,
-    // Support both time and size based buffering, time based calculation precedes size based.
-    // Size based calculation will be used only when time information is not available for
-    // the stream.
-    BUFFERING_MODE_TIME_THEN_SIZE   = 3,
-    // Number of modes.
-    BUFFERING_MODE_COUNT            = 4,
-};
-
 struct BufferingSettings : public Parcelable {
-    static const int kNoWatermark = -1;
+    static const int kNoMark = -1;
 
-    static bool IsValidBufferingMode(int mode);
-    static bool IsTimeBasedBufferingMode(int mode);
-    static bool IsSizeBasedBufferingMode(int mode);
+    int mInitialMarkMs;
 
-    BufferingMode mInitialBufferingMode;  // for prepare
-    BufferingMode mRebufferingMode;  // for playback
-
-    int mInitialWatermarkMs;  // time based
-    int mInitialWatermarkKB;  // size based
-
-    // When cached data is below this mark, playback will be paused for buffering
-    // till data reach |mRebufferingWatermarkHighMs| or end of stream.
-    int mRebufferingWatermarkLowMs;
-    // When cached data is above this mark, buffering will be paused.
-    int mRebufferingWatermarkHighMs;
-
-    // When cached data is below this mark, playback will be paused for buffering
-    // till data reach |mRebufferingWatermarkHighKB| or end of stream.
-    int mRebufferingWatermarkLowKB;
-    // When cached data is above this mark, buffering will be paused.
-    int mRebufferingWatermarkHighKB;
+    // When cached data is above this mark, playback will be resumed if it has been paused
+    // due to low cached data.
+    int mResumePlaybackMarkMs;
 
     BufferingSettings();
 
diff --git a/media/libmedia/include/media/IHDCP.h b/media/libmedia/include/media/IHDCP.h
deleted file mode 100644
index 352561e..0000000
--- a/media/libmedia/include/media/IHDCP.h
+++ /dev/null
@@ -1,120 +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 <binder/IInterface.h>
-#include <media/hardware/HDCPAPI.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <ui/GraphicBuffer.h>
-
-namespace android {
-
-struct IHDCPObserver : public IInterface {
-    DECLARE_META_INTERFACE(HDCPObserver);
-
-    virtual void notify(
-            int msg, int ext1, int ext2, const Parcel *obj) = 0;
-
-private:
-    DISALLOW_EVIL_CONSTRUCTORS(IHDCPObserver);
-};
-
-struct IHDCP : public IInterface {
-    DECLARE_META_INTERFACE(HDCP);
-
-    // Called to specify the observer that receives asynchronous notifications
-    // from the HDCP implementation to signal completion/failure of asynchronous
-    // operations (such as initialization) or out of band events.
-    virtual status_t setObserver(const sp<IHDCPObserver> &observer) = 0;
-
-    // Request to setup an HDCP session with the specified host listening
-    // on the specified port.
-    virtual status_t initAsync(const char *host, unsigned port) = 0;
-
-    // Request to shutdown the active HDCP session.
-    virtual status_t shutdownAsync() = 0;
-
-    // Returns the capability bitmask of this HDCP session.
-    // Possible return values (please refer to HDCAPAPI.h):
-    //   HDCP_CAPS_ENCRYPT: mandatory, meaning the HDCP module can encrypt
-    //   from an input byte-array buffer to an output byte-array buffer
-    //   HDCP_CAPS_ENCRYPT_NATIVE: the HDCP module supports encryption from
-    //   a native buffer to an output byte-array buffer. The format of the
-    //   input native buffer is specific to vendor's encoder implementation.
-    //   It is the same format as that used by the encoder when
-    //   "storeMetaDataInBuffers" extension is enabled on its output port.
-    virtual uint32_t getCaps() = 0;
-
-    // ENCRYPTION only:
-    // Encrypt data according to the HDCP spec. "size" bytes of data are
-    // available at "inData" (virtual address), "size" may not be a multiple
-    // of 128 bits (16 bytes). An equal number of encrypted bytes should be
-    // written to the buffer at "outData" (virtual address).
-    // This operation is to be synchronous, i.e. this call does not return
-    // until outData contains size bytes of encrypted data.
-    // streamCTR will be assigned by the caller (to 0 for the first PES stream,
-    // 1 for the second and so on)
-    // inputCTR _will_be_maintained_by_the_callee_ for each PES stream.
-    virtual status_t encrypt(
-            const void *inData, size_t size, uint32_t streamCTR,
-            uint64_t *outInputCTR, void *outData) = 0;
-
-    // Encrypt data according to the HDCP spec. "size" bytes of data starting
-    // at location "offset" are available in "buffer" (buffer handle). "size"
-    // may not be a multiple of 128 bits (16 bytes). An equal number of
-    // encrypted bytes should be written to the buffer at "outData" (virtual
-    // address). This operation is to be synchronous, i.e. this call does not
-    // return until outData contains size bytes of encrypted data.
-    // streamCTR will be assigned by the caller (to 0 for the first PES stream,
-    // 1 for the second and so on)
-    // inputCTR _will_be_maintained_by_the_callee_ for each PES stream.
-    virtual status_t encryptNative(
-            const sp<GraphicBuffer> &graphicBuffer,
-            size_t offset, size_t size, uint32_t streamCTR,
-            uint64_t *outInputCTR, void *outData) = 0;
-
-    // DECRYPTION only:
-    // Decrypt data according to the HDCP spec.
-    // "size" bytes of encrypted data are available at "inData"
-    // (virtual address), "size" may not be a multiple of 128 bits (16 bytes).
-    // An equal number of decrypted bytes should be written to the buffer
-    // at "outData" (virtual address).
-    // This operation is to be synchronous, i.e. this call does not return
-    // until outData contains size bytes of decrypted data.
-    // Both streamCTR and inputCTR will be provided by the caller.
-    virtual status_t decrypt(
-            const void *inData, size_t size,
-            uint32_t streamCTR, uint64_t inputCTR,
-            void *outData) = 0;
-
-private:
-    DISALLOW_EVIL_CONSTRUCTORS(IHDCP);
-};
-
-struct BnHDCPObserver : public BnInterface<IHDCPObserver> {
-    virtual status_t onTransact(
-            uint32_t code, const Parcel &data, Parcel *reply,
-            uint32_t flags = 0);
-};
-
-struct BnHDCP : public BnInterface<IHDCP> {
-    virtual status_t onTransact(
-            uint32_t code, const Parcel &data, Parcel *reply,
-            uint32_t flags = 0);
-};
-
-}  // namespace android
-
-
diff --git a/media/libmedia/include/media/IMediaCodecService.h b/media/libmedia/include/media/IMediaCodecService.h
deleted file mode 100644
index 59fb1c0..0000000
--- a/media/libmedia/include/media/IMediaCodecService.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IMEDIACODECSERVICE_H
-#define ANDROID_IMEDIACODECSERVICE_H
-
-#include <binder/IInterface.h>
-#include <binder/IMemory.h>
-#include <binder/Parcel.h>
-#include <media/IDataSource.h>
-#include <media/IOMX.h>
-#include <media/IOMXStore.h>
-
-namespace android {
-
-class IMediaCodecService: public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(MediaCodecService);
-
-    virtual sp<IOMX> getOMX() = 0;
-    virtual sp<IOMXStore> getOMXStore() = 0;
-};
-
-class BnMediaCodecService: public BnInterface<IMediaCodecService>
-{
-public:
-    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-                                uint32_t flags = 0);
-};
-
-}   // namespace android
-
-#endif  // ANDROID_IMEDIACODECSERVICE_H
diff --git a/media/libmedia/include/media/IMediaExtractor.h b/media/libmedia/include/media/IMediaExtractor.h
index 0ac7673..44f8c1d 100644
--- a/media/libmedia/include/media/IMediaExtractor.h
+++ b/media/libmedia/include/media/IMediaExtractor.h
@@ -18,8 +18,8 @@
 
 #define IMEDIA_EXTRACTOR_BASE_H_
 
+#include <media/DataSource.h>
 #include <media/IMediaSource.h>
-#include <media/stagefright/DataSource.h>
 #include <vector>
 
 namespace android {
diff --git a/media/libmedia/include/media/IMediaMetadataRetriever.h b/media/libmedia/include/media/IMediaMetadataRetriever.h
index ea95161..5491535 100644
--- a/media/libmedia/include/media/IMediaMetadataRetriever.h
+++ b/media/libmedia/include/media/IMediaMetadataRetriever.h
@@ -44,6 +44,11 @@
             const sp<IDataSource>& dataSource, const char *mime) = 0;
     virtual sp<IMemory>     getFrameAtTime(
             int64_t timeUs, int option, int colorFormat, bool metaOnly) = 0;
+    virtual sp<IMemory>     getImageAtIndex(
+            int index, int colorFormat, bool metaOnly) = 0;
+    virtual status_t        getFrameAtIndex(
+            std::vector<sp<IMemory> > *frames,
+            int frameIndex, int numFrames, int colorFormat, bool metaOnly) = 0;
     virtual sp<IMemory>     extractAlbumArt() = 0;
     virtual const char*     extractMetadata(int keyCode) = 0;
 };
diff --git a/media/libmedia/include/media/IMediaPlayer.h b/media/libmedia/include/media/IMediaPlayer.h
index e5a98dd..97a998e 100644
--- a/media/libmedia/include/media/IMediaPlayer.h
+++ b/media/libmedia/include/media/IMediaPlayer.h
@@ -23,7 +23,7 @@
 #include <utils/KeyedVector.h>
 #include <system/audio.h>
 
-#include <media/IMediaSource.h>
+#include <media/MediaSource.h>
 #include <media/VolumeShaper.h>
 
 // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
@@ -42,7 +42,7 @@
 struct AVSyncSettings;
 struct BufferingSettings;
 
-typedef IMediaSource::ReadOptions::SeekMode MediaPlayerSeekMode;
+typedef MediaSource::ReadOptions::SeekMode MediaPlayerSeekMode;
 
 class IMediaPlayer: public IInterface
 {
@@ -61,7 +61,7 @@
     virtual status_t        setDataSource(const sp<IDataSource>& source) = 0;
     virtual status_t        setVideoSurfaceTexture(
                                     const sp<IGraphicBufferProducer>& bufferProducer) = 0;
-    virtual status_t        getDefaultBufferingSettings(
+    virtual status_t        getBufferingSettings(
                                     BufferingSettings* buffering /* nonnull */) = 0;
     virtual status_t        setBufferingSettings(const BufferingSettings& buffering) = 0;
     virtual status_t        prepareAsync() = 0;
@@ -79,6 +79,7 @@
             MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) = 0;
     virtual status_t        getCurrentPosition(int* msec) = 0;
     virtual status_t        getDuration(int* msec) = 0;
+    virtual status_t        notifyAt(int64_t mediaTimeUs) = 0;
     virtual status_t        reset() = 0;
     virtual status_t        setAudioStreamType(audio_stream_type_t type) = 0;
     virtual status_t        setLooping(int loop) = 0;
@@ -91,10 +92,10 @@
     virtual status_t        getRetransmitEndpoint(struct sockaddr_in* endpoint) = 0;
     virtual status_t        setNextPlayer(const sp<IMediaPlayer>& next) = 0;
 
-    virtual VolumeShaper::Status applyVolumeShaper(
-                                    const sp<VolumeShaper::Configuration>& configuration,
-                                    const sp<VolumeShaper::Operation>& operation) = 0;
-    virtual sp<VolumeShaper::State> getVolumeShaperState(int id) = 0;
+    virtual media::VolumeShaper::Status applyVolumeShaper(
+                                    const sp<media::VolumeShaper::Configuration>& configuration,
+                                    const sp<media::VolumeShaper::Operation>& operation) = 0;
+    virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) = 0;
 
     // Modular DRM
     virtual status_t        prepareDrm(const uint8_t uuid[16],
@@ -130,6 +131,11 @@
     virtual status_t        getMetadata(bool update_only,
                                         bool apply_filter,
                                         Parcel *metadata) = 0;
+
+    // AudioRouting
+    virtual status_t        setOutputDevice(audio_port_handle_t deviceId) = 0;
+    virtual status_t        getRoutedDeviceId(audio_port_handle_t *deviceId) = 0;
+    virtual status_t        enableAudioDeviceCallback(bool enabled) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/libmedia/include/media/IMediaPlayerService.h b/media/libmedia/include/media/IMediaPlayerService.h
index f21bb3a..217de14 100644
--- a/media/libmedia/include/media/IMediaPlayerService.h
+++ b/media/libmedia/include/media/IMediaPlayerService.h
@@ -31,7 +31,6 @@
 
 namespace android {
 
-struct IHDCP;
 class IMediaCodecList;
 struct IMediaHTTPService;
 class IMediaRecorder;
@@ -49,8 +48,6 @@
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0;
     virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client,
             audio_session_t audioSessionId = AUDIO_SESSION_ALLOCATE) = 0;
-    virtual sp<IOMX>            getOMX() = 0;
-    virtual sp<IHDCP>           makeHDCP(bool createEncryptionModule) = 0;
     virtual sp<IMediaCodecList> getCodecList() const = 0;
 
     // Connects to a remote display.
diff --git a/media/libmedia/include/media/IMediaRecorder.h b/media/libmedia/include/media/IMediaRecorder.h
index 9d0341a..3cef329 100644
--- a/media/libmedia/include/media/IMediaRecorder.h
+++ b/media/libmedia/include/media/IMediaRecorder.h
@@ -19,6 +19,7 @@
 #define ANDROID_IMEDIARECORDER_H
 
 #include <binder/IInterface.h>
+#include <system/audio.h>
 
 namespace android {
 
@@ -64,6 +65,10 @@
     virtual status_t release() = 0;
     virtual status_t setInputSurface(const sp<PersistentSurface>& surface) = 0;
     virtual sp<IGraphicBufferProducer> querySurfaceMediaSource() = 0;
+
+    virtual status_t setInputDevice(audio_port_handle_t deviceId) = 0;
+    virtual status_t getRoutedDeviceId(audio_port_handle_t *deviceId) = 0;
+    virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/libmedia/include/media/IMediaSource.h b/media/libmedia/include/media/IMediaSource.h
index 2bde782..7aea90c 100644
--- a/media/libmedia/include/media/IMediaSource.h
+++ b/media/libmedia/include/media/IMediaSource.h
@@ -22,12 +22,12 @@
 
 #include <binder/IInterface.h>
 #include <binder/IMemory.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaErrors.h>
 
 namespace android {
 
-struct MediaSource;
 class MetaData;
 class MediaBufferGroup;
 
@@ -55,51 +55,6 @@
     // Returns the format of the data output by this media source.
     virtual sp<MetaData> getFormat() = 0;
 
-    // Options that modify read() behaviour. The default is to
-    // a) not request a seek
-    // b) not be late, i.e. lateness_us = 0
-    struct ReadOptions {
-        enum SeekMode : int32_t {
-            SEEK_PREVIOUS_SYNC,
-            SEEK_NEXT_SYNC,
-            SEEK_CLOSEST_SYNC,
-            SEEK_CLOSEST,
-        };
-
-        ReadOptions();
-
-        // Reset everything back to defaults.
-        void reset();
-
-        void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
-        void clearSeekTo();
-        bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
-
-        // TODO: remove this if unused.
-        void setLateBy(int64_t lateness_us);
-        int64_t getLateBy() const;
-
-        void setNonBlocking();
-        void clearNonBlocking();
-        bool getNonBlocking() const;
-
-        // Used to clear all non-persistent options for multiple buffer reads.
-        void clearNonPersistent() {
-            clearSeekTo();
-        }
-
-    private:
-        enum Options {
-            kSeekTo_Option      = 1,
-        };
-
-        uint32_t mOptions;
-        int64_t mSeekTimeUs;
-        SeekMode mSeekMode;
-        int64_t mLatenessUs;
-        bool mNonBlocking;
-    } __attribute__((packed)); // sent through Binder
-
     // Returns a new buffer of data. Call blocks until a
     // buffer is available, an error is encountered or the end of the stream
     // is reached.
@@ -110,7 +65,8 @@
     //
     // TODO: consider removing read() in favor of readMultiple().
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
+            MediaBuffer **buffer,
+            const MediaSource::ReadOptions *options = NULL) = 0;
 
     // Returns a vector of new buffers of data, where the new buffers are added
     // to the end of the vector.
@@ -126,7 +82,7 @@
     // non-persistent options (e.g. seek) apply only to the first read.
     virtual status_t readMultiple(
             Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1,
-            const ReadOptions *options = nullptr) = 0;
+            const MediaSource::ReadOptions *options = nullptr) = 0;
 
     // Returns true if |readMultiple| is supported, otherwise false.
     virtual bool supportReadMultiple() = 0;
@@ -168,7 +124,7 @@
     // TODO: Implement this for local media sources.
     virtual status_t readMultiple(
             Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */,
-            const ReadOptions * /* options = nullptr */) {
+            const MediaSource::ReadOptions * /* options = nullptr */) {
         return ERROR_UNSUPPORTED;
     }
 
diff --git a/media/libmedia/include/media/IOMXStore.h b/media/libmedia/include/media/IOMXStore.h
deleted file mode 100644
index 628db70..0000000
--- a/media/libmedia/include/media/IOMXStore.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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_IOMXSTORE_H_
-
-#define ANDROID_IOMXSTORE_H_
-
-#include <media/IOMX.h>
-#include <android/hardware/media/omx/1.0/IOmxStore.h>
-
-#include <binder/IInterface.h>
-#include <binder/IBinder.h>
-
-#include <vector>
-#include <string>
-
-namespace android {
-
-using hardware::media::omx::V1_0::IOmxStore;
-
-class IOMXStore : public IInterface {
-public:
-    DECLARE_META_INTERFACE(OMXStore);
-
-    struct Attribute {
-        std::string key;
-        std::string value;
-    };
-
-    struct NodeInfo {
-        std::string name;
-        std::string owner;
-        std::vector<Attribute> attributes;
-    };
-
-    struct RoleInfo {
-        std::string role;
-        std::string type;
-        bool isEncoder;
-        bool preferPlatformNodes;
-        std::vector<NodeInfo> nodes;
-    };
-
-    virtual status_t listServiceAttributes(
-            std::vector<Attribute>* attributes) = 0;
-
-    virtual status_t getNodePrefix(std::string* prefix) = 0;
-
-    virtual status_t listRoles(std::vector<RoleInfo>* roleList) = 0;
-
-    virtual status_t getOmx(const std::string& name, sp<IOMX>* omx) = 0;
-};
-
-
-////////////////////////////////////////////////////////////////////////////////
-
-class BnOMXStore : public BnInterface<IOMXStore> {
-public:
-    virtual status_t onTransact(
-            uint32_t code, const Parcel &data, Parcel *reply,
-            uint32_t flags = 0);
-};
-
-}  // namespace android
-
-#endif  // ANDROID_IOMX_H_
diff --git a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
index 257002d..fc9e53c 100644
--- a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
+++ b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
@@ -22,6 +22,7 @@
 #include <media/mediametadataretriever.h>
 #include <media/mediascanner.h>
 #include <private/media/VideoFrame.h>
+#include <media/stagefright/MediaErrors.h>
 
 namespace android {
 
@@ -41,9 +42,14 @@
             const KeyedVector<String8, String8> *headers = NULL) = 0;
 
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length) = 0;
-    virtual status_t setDataSource(const sp<DataSource>& source, const char *mime) = 0;
+    virtual status_t    setDataSource(const sp<DataSource>& source, const char *mime) = 0;
     virtual VideoFrame* getFrameAtTime(
             int64_t timeUs, int option, int colorFormat, bool metaOnly) = 0;
+    virtual VideoFrame* getImageAtIndex(
+            int index, int colorFormat, bool metaOnly) = 0;
+    virtual status_t getFrameAtIndex(
+            std::vector<VideoFrame*>* frames,
+            int frameIndex, int numFrames, int colorFormat, bool metaOnly);
     virtual MediaAlbumArt* extractAlbumArt() = 0;
     virtual const char* extractMetadata(int keyCode) = 0;
 };
@@ -58,6 +64,13 @@
     virtual VideoFrame* getFrameAtTime(
             int64_t /*timeUs*/, int /*option*/, int /*colorFormat*/, bool /*metaOnly*/)
     { return NULL; }
+    virtual VideoFrame* getImageAtIndex(
+            int /*index*/, int /*colorFormat*/, bool /*metaOnly*/)
+    { return NULL; }
+    virtual status_t getFrameAtIndex(
+            std::vector<VideoFrame*>* /*frames*/,
+            int /*frameIndex*/, int /*numFrames*/, int /*colorFormat*/, bool /*metaOnly*/)
+    { return ERROR_UNSUPPORTED; }
     virtual MediaAlbumArt* extractAlbumArt() { return NULL; }
     virtual const char* extractMetadata(int /*keyCode*/) { return NULL; }
 };
diff --git a/media/libmedia/include/media/MediaRecorderBase.h b/media/libmedia/include/media/MediaRecorderBase.h
index 40dd9f9..748153c 100644
--- a/media/libmedia/include/media/MediaRecorderBase.h
+++ b/media/libmedia/include/media/MediaRecorderBase.h
@@ -18,6 +18,7 @@
 
 #define MEDIA_RECORDER_BASE_H_
 
+#include <media/AudioSystem.h>
 #include <media/mediarecorder.h>
 
 #include <system/audio.h>
@@ -62,6 +63,10 @@
     virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
     virtual status_t setInputSurface(const sp<PersistentSurface>& surface) = 0;
     virtual sp<IGraphicBufferProducer> querySurfaceMediaSource() const = 0;
+    virtual status_t setInputDevice(audio_port_handle_t deviceId) = 0;
+    virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId) = 0;
+    virtual void setAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback) = 0;
+    virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
 
 
 protected:
diff --git a/media/libmedia/include/media/MidiIoWrapper.h b/media/libmedia/include/media/MidiIoWrapper.h
index e6f8cf7..2754b2c 100644
--- a/media/libmedia/include/media/MidiIoWrapper.h
+++ b/media/libmedia/include/media/MidiIoWrapper.h
@@ -19,7 +19,7 @@
 
 #include <libsonivox/eas_types.h>
 
-#include "media/stagefright/DataSource.h"
+#include <media/DataSource.h>
 
 namespace android {
 
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index 65c266b..3511253 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -59,6 +59,13 @@
     METADATA_KEY_LOCATION        = 23,
     METADATA_KEY_VIDEO_ROTATION  = 24,
     METADATA_KEY_CAPTURE_FRAMERATE = 25,
+    METADATA_KEY_HAS_IMAGE       = 26,
+    METADATA_KEY_IMAGE_COUNT     = 27,
+    METADATA_KEY_IMAGE_PRIMARY   = 28,
+    METADATA_KEY_IMAGE_WIDTH     = 29,
+    METADATA_KEY_IMAGE_HEIGHT    = 30,
+    METADATA_KEY_IMAGE_ROTATION  = 31,
+    METADATA_KEY_VIDEO_FRAME_COUNT  = 32,
 
     // Add more here...
 };
@@ -80,6 +87,11 @@
             const sp<IDataSource>& dataSource, const char *mime = NULL);
     sp<IMemory> getFrameAtTime(int64_t timeUs, int option,
             int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
+    sp<IMemory> getImageAtIndex(int index,
+            int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
+    status_t getFrameAtIndex(
+            std::vector<sp<IMemory> > *frames, int frameIndex, int numFrames = 1,
+            int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
     sp<IMemory> extractAlbumArt();
     const char* extractMetadata(int keyCode);
 
diff --git a/media/libmedia/include/media/mediaplayer.h b/media/libmedia/include/media/mediaplayer.h
index 623c374..dc3b3aa 100644
--- a/media/libmedia/include/media/mediaplayer.h
+++ b/media/libmedia/include/media/mediaplayer.h
@@ -50,12 +50,14 @@
     MEDIA_PAUSED            = 7,
     MEDIA_STOPPED           = 8,
     MEDIA_SKIPPED           = 9,
+    MEDIA_NOTIFY_TIME       = 98,
     MEDIA_TIMED_TEXT        = 99,
     MEDIA_ERROR             = 100,
     MEDIA_INFO              = 200,
     MEDIA_SUBTITLE_DATA     = 201,
     MEDIA_META_DATA         = 202,
     MEDIA_DRM_INFO          = 210,
+    MEDIA_AUDIO_ROUTING_CHANGED = 10000,
 };
 
 // Generic error codes for the media player framework.  Errors are fatal, the
@@ -225,7 +227,6 @@
             status_t        setVideoSurfaceTexture(
                                     const sp<IGraphicBufferProducer>& bufferProducer);
             status_t        setListener(const sp<MediaPlayerListener>& listener);
-            status_t        getDefaultBufferingSettings(BufferingSettings* buffering /* nonnull */);
             status_t        getBufferingSettings(BufferingSettings* buffering /* nonnull */);
             status_t        setBufferingSettings(const BufferingSettings& buffering);
             status_t        prepare();
@@ -245,6 +246,7 @@
             status_t        seekTo(
                     int msec,
                     MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC);
+            status_t        notifyAt(int64_t mediaTimeUs);
             status_t        getCurrentPosition(int *msec);
             status_t        getDuration(int *msec);
             status_t        reset();
@@ -266,13 +268,17 @@
             status_t        setRetransmitEndpoint(const char* addrString, uint16_t port);
             status_t        setNextMediaPlayer(const sp<MediaPlayer>& player);
 
-            VolumeShaper::Status applyVolumeShaper(
-                                    const sp<VolumeShaper::Configuration>& configuration,
-                                    const sp<VolumeShaper::Operation>& operation);
-            sp<VolumeShaper::State> getVolumeShaperState(int id);
+            media::VolumeShaper::Status applyVolumeShaper(
+                                    const sp<media::VolumeShaper::Configuration>& configuration,
+                                    const sp<media::VolumeShaper::Operation>& operation);
+            sp<media::VolumeShaper::State> getVolumeShaperState(int id);
             // Modular DRM
             status_t        prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
             status_t        releaseDrm();
+            // AudioRouting
+            status_t        setOutputDevice(audio_port_handle_t deviceId);
+            audio_port_handle_t getRoutedDeviceId();
+            status_t        enableAudioDeviceCallback(bool enabled);
 
 private:
             void            clear_l();
@@ -309,7 +315,6 @@
     float                       mSendLevel;
     struct sockaddr_in          mRetransmitEndpoint;
     bool                        mRetransmitEndpointValid;
-    BufferingSettings           mCurrentBufferingSettings;
 };
 
 }; // namespace android
diff --git a/media/libmedia/include/media/mediarecorder.h b/media/libmedia/include/media/mediarecorder.h
index 071e7a1..5f2a6fe 100644
--- a/media/libmedia/include/media/mediarecorder.h
+++ b/media/libmedia/include/media/mediarecorder.h
@@ -77,6 +77,9 @@
     /* VP8/VORBIS data in a WEBM container */
     OUTPUT_FORMAT_WEBM = 9,
 
+    /* HEIC data in a HEIF container */
+    OUTPUT_FORMAT_HEIF = 10,
+
     OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
 };
 
@@ -138,6 +141,8 @@
     MEDIA_RECORDER_TRACK_EVENT_ERROR              = 100,
     MEDIA_RECORDER_TRACK_EVENT_INFO               = 101,
     MEDIA_RECORDER_TRACK_EVENT_LIST_END           = 1000,
+
+    MEDIA_RECORDER_AUDIO_ROUTING_CHANGED          = 10000,
 };
 
 /*
@@ -250,6 +255,9 @@
     status_t    setInputSurface(const sp<PersistentSurface>& surface);
     sp<IGraphicBufferProducer>     querySurfaceMediaSourceFromMediaServer();
     status_t    getMetrics(Parcel *reply);
+    status_t    setInputDevice(audio_port_handle_t deviceId);
+    status_t    getRoutedDeviceId(audio_port_handle_t *deviceId);
+    status_t    enableAudioDeviceCallback(bool enabled);
 
 private:
     void                    doCleanUp();
diff --git a/media/libmedia/include/media/omx/1.0/Conversion.h b/media/libmedia/include/media/omx/1.0/Conversion.h
index 9816fe1..94f2e8d 100644
--- a/media/libmedia/include/media/omx/1.0/Conversion.h
+++ b/media/libmedia/include/media/omx/1.0/Conversion.h
@@ -24,7 +24,6 @@
 
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
-#include <hidlmemory/mapping.h>
 
 #include <binder/Binder.h>
 #include <binder/Status.h>
@@ -36,7 +35,6 @@
 #include <media/OMXBuffer.h>
 #include <media/hardware/VideoAPI.h>
 
-#include <android/hidl/memory/1.0/IMemory.h>
 #include <android/hardware/media/omx/1.0/types.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 7d27d57..6a4204b 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -154,6 +154,32 @@
     return mRetriever->getFrameAtTime(timeUs, option, colorFormat, metaOnly);
 }
 
+sp<IMemory> MediaMetadataRetriever::getImageAtIndex(
+        int index, int colorFormat, bool metaOnly) {
+    ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d)",
+            index, colorFormat, metaOnly);
+    Mutex::Autolock _l(mLock);
+    if (mRetriever == 0) {
+        ALOGE("retriever is not initialized");
+        return NULL;
+    }
+    return mRetriever->getImageAtIndex(index, colorFormat, metaOnly);
+}
+
+status_t MediaMetadataRetriever::getFrameAtIndex(
+        std::vector<sp<IMemory> > *frames,
+        int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
+    ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d) metaOnly(%d)",
+            frameIndex, numFrames, colorFormat, metaOnly);
+    Mutex::Autolock _l(mLock);
+    if (mRetriever == 0) {
+        ALOGE("retriever is not initialized");
+        return INVALID_OPERATION;
+    }
+    return mRetriever->getFrameAtIndex(
+            frames, frameIndex, numFrames, colorFormat, metaOnly);
+}
+
 const char* MediaMetadataRetriever::extractMetadata(int keyCode)
 {
     ALOGV("extractMetadata(%d)", keyCode);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index b976721..26908e5 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -48,6 +48,8 @@
 
 namespace android {
 
+using media::VolumeShaper;
+
 MediaPlayer::MediaPlayer()
 {
     ALOGV("constructor");
@@ -137,10 +139,8 @@
         mPlayer = player;
         if (player != 0) {
             mCurrentState = MEDIA_PLAYER_INITIALIZED;
-            player->getDefaultBufferingSettings(&mCurrentBufferingSettings);
             err = NO_ERROR;
         } else {
-            mCurrentBufferingSettings = BufferingSettings();
             ALOGE("Unable to create media player");
         }
     }
@@ -247,17 +247,6 @@
     return mPlayer->setVideoSurfaceTexture(bufferProducer);
 }
 
-status_t MediaPlayer::getDefaultBufferingSettings(BufferingSettings* buffering /* nonnull */)
-{
-    ALOGV("getDefaultBufferingSettings");
-
-    Mutex::Autolock _l(mLock);
-    if (mPlayer == 0) {
-        return NO_INIT;
-    }
-    return mPlayer->getDefaultBufferingSettings(buffering);
-}
-
 status_t MediaPlayer::getBufferingSettings(BufferingSettings* buffering /* nonnull */)
 {
     ALOGV("getBufferingSettings");
@@ -266,8 +255,7 @@
     if (mPlayer == 0) {
         return NO_INIT;
     }
-    *buffering = mCurrentBufferingSettings;
-    return NO_ERROR;
+    return mPlayer->getBufferingSettings(buffering);
 }
 
 status_t MediaPlayer::setBufferingSettings(const BufferingSettings& buffering)
@@ -278,11 +266,7 @@
     if (mPlayer == 0) {
         return NO_INIT;
     }
-    status_t err =  mPlayer->setBufferingSettings(buffering);
-    if (err == NO_ERROR) {
-        mCurrentBufferingSettings = buffering;
-    }
-    return err;
+    return mPlayer->setBufferingSettings(buffering);
 }
 
 // must call with lock held
@@ -608,6 +592,15 @@
     return result;
 }
 
+status_t MediaPlayer::notifyAt(int64_t mediaTimeUs)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer != 0) {
+        return mPlayer->notifyAt(mediaTimeUs);
+    }
+    return INVALID_OPERATION;
+}
+
 status_t MediaPlayer::reset_l()
 {
     mLoop = false;
@@ -625,7 +618,6 @@
         // setDataSource has to be called again to create a
         // new mediaplayer.
         mPlayer = 0;
-        mCurrentBufferingSettings = BufferingSettings();
         return ret;
     }
     clear_l();
@@ -649,8 +641,12 @@
 status_t MediaPlayer::reset()
 {
     ALOGV("reset");
+    mLockThreadId = getThreadId();
     Mutex::Autolock _l(mLock);
-    return reset_l();
+    status_t result = reset_l();
+    mLockThreadId = 0;
+
+    return result;
 }
 
 status_t MediaPlayer::setAudioStreamType(audio_stream_type_t type)
@@ -860,7 +856,7 @@
     // this will deadlock.
     //
     // The threadId hack below works around this for the care of prepare,
-    // seekTo and start within the same process.
+    // seekTo, start, and reset within the same process.
     // FIXME: Remember, this is a hack, it's not even a hack that is applied
     // consistently for all use-cases, this needs to be revisited.
     if (mLockThreadId != getThreadId()) {
@@ -944,6 +940,9 @@
         mVideoWidth = ext1;
         mVideoHeight = ext2;
         break;
+    case MEDIA_NOTIFY_TIME:
+        ALOGV("Received notify time message");
+        break;
     case MEDIA_TIMED_TEXT:
         ALOGV("Received timed text message");
         break;
@@ -1076,4 +1075,39 @@
     return status;
 }
 
+status_t MediaPlayer::setOutputDevice(audio_port_handle_t deviceId)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        ALOGV("setOutputDevice: player not init");
+        return NO_INIT;
+    }
+    return mPlayer->setOutputDevice(deviceId);
+}
+
+audio_port_handle_t MediaPlayer::getRoutedDeviceId()
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        ALOGV("getRoutedDeviceId: player not init");
+        return AUDIO_PORT_HANDLE_NONE;
+    }
+    audio_port_handle_t deviceId;
+    status_t status = mPlayer->getRoutedDeviceId(&deviceId);
+    if (status != NO_ERROR) {
+        return AUDIO_PORT_HANDLE_NONE;
+    }
+    return deviceId;
+}
+
+status_t MediaPlayer::enableAudioDeviceCallback(bool enabled)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        ALOGV("addAudioDeviceCallback: player not init");
+        return NO_INIT;
+    }
+    return mPlayer->enableAudioDeviceCallback(enabled);
+}
+
 } // namespace android
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 4405930..aab845b 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -792,4 +792,41 @@
     notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
 }
 
+status_t MediaRecorder::setInputDevice(audio_port_handle_t deviceId)
+{
+    ALOGV("setInputDevice");
+
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    return mMediaRecorder->setInputDevice(deviceId);
+}
+
+status_t MediaRecorder::getRoutedDeviceId(audio_port_handle_t* deviceId)
+{
+    ALOGV("getRoutedDeviceId");
+
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    status_t status = mMediaRecorder->getRoutedDeviceId(deviceId);
+    if (status != NO_ERROR) {
+        *deviceId = AUDIO_PORT_HANDLE_NONE;
+    }
+    return status;
+}
+
+status_t MediaRecorder::enableAudioDeviceCallback(bool enabled)
+{
+    ALOGV("enableAudioDeviceCallback");
+
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    return mMediaRecorder->enableAudioDeviceCallback(enabled);
+}
+
 } // namespace android
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
new file mode 100644
index 0000000..c57cd41
--- /dev/null
+++ b/media/libmediaextractor/Android.bp
@@ -0,0 +1,42 @@
+cc_library_shared {
+    name: "libmediaextractor",
+    include_dirs: [
+        "frameworks/av/include",
+        "frameworks/av/media/libmediaextractor/include",
+    ],
+
+    export_include_dirs: ["include"],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+    ],
+
+    shared_libs: [
+        "libmediametrics",
+        "libstagefright_foundation",
+        "libutils",
+        "libcutils",
+        "liblog",
+    ],
+
+    srcs: [
+        "DataSource.cpp",
+        "MediaSource.cpp",
+        "MediaExtractor.cpp",
+    ],
+
+    clang: true,
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+}
diff --git a/media/libmediaextractor/DataSource.cpp b/media/libmediaextractor/DataSource.cpp
new file mode 100644
index 0000000..c22e4cb
--- /dev/null
+++ b/media/libmediaextractor/DataSource.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DataSource"
+
+#include <media/DataSource.h>
+#include <media/IDataSource.h>
+#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/String8.h>
+
+namespace android {
+
+bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
+    *x = 0;
+
+    uint8_t byte[2];
+    if (readAt(offset, byte, 2) != 2) {
+        return false;
+    }
+
+    *x = (byte[0] << 8) | byte[1];
+
+    return true;
+}
+
+bool DataSource::getUInt24(off64_t offset, uint32_t *x) {
+    *x = 0;
+
+    uint8_t byte[3];
+    if (readAt(offset, byte, 3) != 3) {
+        return false;
+    }
+
+    *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
+
+    return true;
+}
+
+bool DataSource::getUInt32(off64_t offset, uint32_t *x) {
+    *x = 0;
+
+    uint32_t tmp;
+    if (readAt(offset, &tmp, 4) != 4) {
+        return false;
+    }
+
+    *x = ntohl(tmp);
+
+    return true;
+}
+
+bool DataSource::getUInt64(off64_t offset, uint64_t *x) {
+    *x = 0;
+
+    uint64_t tmp;
+    if (readAt(offset, &tmp, 8) != 8) {
+        return false;
+    }
+
+    *x = ntoh64(tmp);
+
+    return true;
+}
+
+bool DataSource::getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
+    if (size == 2) {
+        return getUInt16(offset, x);
+    }
+    if (size == 1) {
+        uint8_t tmp;
+        if (readAt(offset, &tmp, 1) == 1) {
+            *x = tmp;
+            return true;
+        }
+    }
+    return false;
+}
+
+bool DataSource::getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
+    if (size == 4) {
+        return getUInt32(offset, x);
+    }
+    if (size == 2) {
+        uint16_t tmp;
+        if (getUInt16(offset, &tmp)) {
+            *x = tmp;
+            return true;
+        }
+    }
+    return false;
+}
+
+bool DataSource::getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
+    if (size == 8) {
+        return getUInt64(offset, x);
+    }
+    if (size == 4) {
+        uint32_t tmp;
+        if (getUInt32(offset, &tmp)) {
+            *x = tmp;
+            return true;
+        }
+    }
+    return false;
+}
+
+status_t DataSource::getSize(off64_t *size) {
+    *size = 0;
+
+    return ERROR_UNSUPPORTED;
+}
+
+sp<IDataSource> DataSource::getIDataSource() const {
+    return nullptr;
+}
+
+String8 DataSource::getMIMEType() const {
+    return String8("application/octet-stream");
+}
+
+}  // namespace android
diff --git a/media/libmediaextractor/MediaExtractor.cpp b/media/libmediaextractor/MediaExtractor.cpp
new file mode 100644
index 0000000..6ba7c0e
--- /dev/null
+++ b/media/libmediaextractor/MediaExtractor.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaExtractor"
+#include <utils/Log.h>
+#include <pwd.h>
+
+#include <media/MediaAnalyticsItem.h>
+#include <media/MediaExtractor.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+// key for media statistics
+static const char *kKeyExtractor = "extractor";
+
+MediaExtractor::MediaExtractor() {
+    if (!LOG_NDEBUG) {
+        uid_t uid = getuid();
+        struct passwd *pw = getpwuid(uid);
+        ALOGV("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
+    }
+
+    mAnalyticsItem = NULL;
+    if (MEDIA_LOG) {
+        mAnalyticsItem = new MediaAnalyticsItem(kKeyExtractor);
+        (void) mAnalyticsItem->generateSessionID();
+    }
+}
+
+MediaExtractor::~MediaExtractor() {
+
+    // log the current record, provided it has some information worth recording
+    if (MEDIA_LOG) {
+        if (mAnalyticsItem != NULL) {
+            if (mAnalyticsItem->count() > 0) {
+                mAnalyticsItem->setFinalized(true);
+                mAnalyticsItem->selfrecord();
+            }
+        }
+    }
+    if (mAnalyticsItem != NULL) {
+        delete mAnalyticsItem;
+        mAnalyticsItem = NULL;
+    }
+}
+
+sp<MetaData> MediaExtractor::getMetaData() {
+    return new MetaData;
+}
+
+status_t MediaExtractor::getMetrics(Parcel *reply) {
+
+    if (mAnalyticsItem == NULL || reply == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    populateMetrics();
+    mAnalyticsItem->writeToParcel(reply);
+
+    return OK;
+}
+
+void MediaExtractor::populateMetrics() {
+    ALOGV("MediaExtractor::populateMetrics");
+    // normally overridden in subclasses
+}
+
+uint32_t MediaExtractor::flags() const {
+    return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
+}
+
+}  // namespace android
diff --git a/media/libmediaextractor/MediaSource.cpp b/media/libmediaextractor/MediaSource.cpp
new file mode 100644
index 0000000..8038a59
--- /dev/null
+++ b/media/libmediaextractor/MediaSource.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 <media/MediaSource.h>
+#include <media/IMediaSource.h>
+
+namespace android {
+
+MediaSource::MediaSource() {}
+
+MediaSource::~MediaSource() {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MediaSource::ReadOptions::ReadOptions() {
+    reset();
+}
+
+void MediaSource::ReadOptions::reset() {
+    mOptions = 0;
+    mSeekTimeUs = 0;
+    mLatenessUs = 0;
+    mNonBlocking = false;
+}
+
+void MediaSource::ReadOptions::setNonBlocking() {
+    mNonBlocking = true;
+}
+
+void MediaSource::ReadOptions::clearNonBlocking() {
+    mNonBlocking = false;
+}
+
+bool MediaSource::ReadOptions::getNonBlocking() const {
+    return mNonBlocking;
+}
+
+void MediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
+    mOptions |= kSeekTo_Option;
+    mSeekTimeUs = time_us;
+    mSeekMode = mode;
+}
+
+void MediaSource::ReadOptions::clearSeekTo() {
+    mOptions &= ~kSeekTo_Option;
+    mSeekTimeUs = 0;
+    mSeekMode = SEEK_CLOSEST_SYNC;
+}
+
+bool MediaSource::ReadOptions::getSeekTo(
+        int64_t *time_us, SeekMode *mode) const {
+    *time_us = mSeekTimeUs;
+    *mode = mSeekMode;
+    return (mOptions & kSeekTo_Option) != 0;
+}
+
+void MediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
+    mLatenessUs = lateness_us;
+}
+
+int64_t MediaSource::ReadOptions::getLateBy() const {
+    return mLatenessUs;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/include/media/stagefright/DataSource.h b/media/libmediaextractor/include/media/DataSource.h
similarity index 89%
rename from media/libstagefright/include/media/stagefright/DataSource.h
rename to media/libmediaextractor/include/media/DataSource.h
index bd863ba..e917f4e 100644
--- a/media/libstagefright/include/media/stagefright/DataSource.h
+++ b/media/libmediaextractor/include/media/DataSource.h
@@ -47,17 +47,6 @@
         kIsLocalFileSource     = 16,
     };
 
-    static sp<DataSource> CreateFromURI(
-            const sp<IMediaHTTPService> &httpService,
-            const char *uri,
-            const KeyedVector<String8, String8> *headers = NULL,
-            String8 *contentType = NULL,
-            HTTPBase *httpSource = NULL);
-
-    static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
-    static sp<DataSource> CreateFromIDataSource(const sp<IDataSource> &source);
-    static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
-
     DataSource() {}
 
     virtual status_t initCheck() const = 0;
@@ -123,9 +112,6 @@
 
     virtual void close() {};
 
-    // creates an IDataSource wrapper to the DataSource.
-    virtual sp<IDataSource> asIDataSource();
-
     // returns a pointer to IDataSource if it is wrapped.
     virtual sp<IDataSource> getIDataSource() const;
 
diff --git a/media/libmediaextractor/include/media/MediaExtractor.h b/media/libmediaextractor/include/media/MediaExtractor.h
new file mode 100644
index 0000000..2dcced3
--- /dev/null
+++ b/media/libmediaextractor/include/media/MediaExtractor.h
@@ -0,0 +1,200 @@
+/*
+ * 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 MEDIA_EXTRACTOR_H_
+
+#define MEDIA_EXTRACTOR_H_
+
+#include <stdio.h>
+#include <vector>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+// still doing some on/off toggling here.
+#define MEDIA_LOG       1
+
+namespace android {
+
+class DataSource;
+class IMediaSource;
+class MediaAnalyticsItem;
+class MediaExtractorFactory;
+class MetaData;
+class Parcel;
+class String8;
+struct AMessage;
+struct MediaSource;
+typedef std::vector<uint8_t> HInterfaceToken;
+
+class MediaExtractor : public RefBase {
+public:
+    virtual size_t countTracks() = 0;
+    virtual sp<MediaSource> getTrack(size_t index) = 0;
+
+    enum GetTrackMetaDataFlags {
+        kIncludeExtensiveMetaData = 1
+    };
+    virtual sp<MetaData> getTrackMetaData(
+            size_t index, uint32_t flags = 0) = 0;
+
+    // Return container specific meta-data. The default implementation
+    // returns an empty metadata object.
+    virtual sp<MetaData> getMetaData();
+
+    status_t getMetrics(Parcel *reply);
+
+    enum Flags {
+        CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button"
+        CAN_SEEK_FORWARD   = 2,  // the "seek 10secs forward button"
+        CAN_PAUSE          = 4,
+        CAN_SEEK           = 8,  // the "seek bar"
+    };
+
+    // If subclasses do _not_ override this, the default is
+    // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
+    virtual uint32_t flags() const;
+
+    // for DRM
+    virtual char* getDrmTrackInfo(size_t /*trackID*/, int * /*len*/) {
+        return NULL;
+    }
+    virtual void setUID(uid_t /*uid*/) {
+    }
+    virtual status_t setMediaCas(const HInterfaceToken &/*casToken*/) {
+        return INVALID_OPERATION;
+    }
+
+    virtual const char * name() { return "<unspecified>"; }
+
+    virtual void release() {}
+    typedef MediaExtractor* (*CreatorFunc)(
+            const sp<DataSource> &source, const sp<AMessage> &meta);
+
+    // The sniffer can optionally fill in "meta" with an AMessage containing
+    // a dictionary of values that helps the corresponding extractor initialize
+    // its state without duplicating effort already exerted by the sniffer.
+    typedef CreatorFunc (*SnifferFunc)(
+            const sp<DataSource> &source, String8 *mimeType,
+            float *confidence, sp<AMessage> *meta);
+
+    typedef struct {
+        const uint8_t b[16];
+    } uuid_t;
+
+    typedef struct {
+        // version number of this structure
+        const uint32_t def_version;
+
+        // A unique identifier for this extractor.
+        // See below for a convenience macro to create this from a string.
+        uuid_t extractor_uuid;
+
+        // Version number of this extractor. When two extractors with the same
+        // uuid are encountered, the one with the largest version number will
+        // be used.
+        const uint32_t extractor_version;
+
+        // a human readable name
+        const char *extractor_name;
+
+        // the sniffer function
+        const SnifferFunc sniff;
+    } ExtractorDef;
+
+    static const uint32_t EXTRACTORDEF_VERSION = 1;
+
+    typedef ExtractorDef (*GetExtractorDef)();
+
+protected:
+    MediaExtractor();
+    virtual ~MediaExtractor();
+
+    MediaAnalyticsItem *mAnalyticsItem;
+
+    virtual void populateMetrics();
+
+private:
+    MediaExtractor(const MediaExtractor &);
+    MediaExtractor &operator=(const MediaExtractor &);
+    friend class MediaExtractorFactory;
+};
+
+// purposely not defined anywhere so that this will fail to link if
+// expressions below are not evaluated at compile time
+int invalid_uuid_string(const char *);
+
+template <typename T, size_t N>
+constexpr uint8_t _digitAt_(const T (&s)[N], const size_t n) {
+    return s[n] >= '0' && s[n] <= '9' ? s[n] - '0'
+            : s[n] >= 'a' && s[n] <= 'f' ? s[n] - 'a' + 10
+                    : s[n] >= 'A' && s[n] <= 'F' ? s[n] - 'A' + 10
+                            : invalid_uuid_string("uuid: bad digits");
+}
+
+template <typename T, size_t N>
+constexpr uint8_t _hexByteAt_(const T (&s)[N], size_t n) {
+    return (_digitAt_(s, n) << 4) + _digitAt_(s, n + 1);
+}
+
+constexpr bool _assertIsDash_(char c) {
+    return c == '-' ? true : invalid_uuid_string("Wrong format");
+}
+
+template <size_t N>
+constexpr MediaExtractor::uuid_t constUUID(const char (&s) [N]) {
+    static_assert(N == 37, "uuid: wrong length");
+    return
+            _assertIsDash_(s[8]),
+            _assertIsDash_(s[13]),
+            _assertIsDash_(s[18]),
+            _assertIsDash_(s[23]),
+            MediaExtractor::uuid_t {{
+                _hexByteAt_(s, 0),
+                _hexByteAt_(s, 2),
+                _hexByteAt_(s, 4),
+                _hexByteAt_(s, 6),
+                _hexByteAt_(s, 9),
+                _hexByteAt_(s, 11),
+                _hexByteAt_(s, 14),
+                _hexByteAt_(s, 16),
+                _hexByteAt_(s, 19),
+                _hexByteAt_(s, 21),
+                _hexByteAt_(s, 24),
+                _hexByteAt_(s, 26),
+                _hexByteAt_(s, 28),
+                _hexByteAt_(s, 30),
+                _hexByteAt_(s, 32),
+                _hexByteAt_(s, 34),
+            }};
+}
+// Convenience macro to create a uuid_t from a string literal, which should
+// be formatted as "12345678-1234-1234-1234-123456789abc", as generated by
+// e.g. https://www.uuidgenerator.net/ or the 'uuidgen' linux command.
+// Hex digits may be upper or lower case.
+//
+// The macro call is otherwise equivalent to specifying the structure directly
+// (e.g. UUID("7d613858-5837-4a38-84c5-332d1cddee27") is the same as
+//       {{0x7d, 0x61, 0x38, 0x58, 0x58, 0x37, 0x4a, 0x38,
+//         0x84, 0xc5, 0x33, 0x2d, 0x1c, 0xdd, 0xee, 0x27}})
+
+#define UUID(str) []{ constexpr MediaExtractor::uuid_t uuid = constUUID(str); return uuid; }()
+
+
+
+}  // namespace android
+
+#endif  // MEDIA_EXTRACTOR_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaSource.h b/media/libmediaextractor/include/media/MediaSource.h
similarity index 74%
rename from media/libstagefright/include/media/stagefright/MediaSource.h
rename to media/libmediaextractor/include/media/MediaSource.h
index 14adb05..504653b 100644
--- a/media/libstagefright/include/media/stagefright/MediaSource.h
+++ b/media/libmediaextractor/include/media/MediaSource.h
@@ -20,8 +20,10 @@
 
 #include <sys/types.h>
 
-#include <media/IMediaSource.h>
+#include <binder/IMemory.h>
+#include <binder/MemoryDealer.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
 
@@ -29,8 +31,9 @@
 
 class MediaBuffer;
 class MetaData;
+class IMediaSource;
 
-struct MediaSource : public BnMediaSource {
+struct MediaSource : public virtual RefBase {
     MediaSource();
 
     // To be called before any other methods on this object, except
@@ -48,6 +51,52 @@
     // Returns the format of the data output by this media source.
     virtual sp<MetaData> getFormat() = 0;
 
+    // Options that modify read() behaviour. The default is to
+    // a) not request a seek
+    // b) not be late, i.e. lateness_us = 0
+    struct ReadOptions {
+        enum SeekMode : int32_t {
+            SEEK_PREVIOUS_SYNC,
+            SEEK_NEXT_SYNC,
+            SEEK_CLOSEST_SYNC,
+            SEEK_CLOSEST,
+            SEEK_FRAME_INDEX,
+        };
+
+        ReadOptions();
+
+        // Reset everything back to defaults.
+        void reset();
+
+        void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
+        void clearSeekTo();
+        bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
+
+        // TODO: remove this if unused.
+        void setLateBy(int64_t lateness_us);
+        int64_t getLateBy() const;
+
+        void setNonBlocking();
+        void clearNonBlocking();
+        bool getNonBlocking() const;
+
+        // Used to clear all non-persistent options for multiple buffer reads.
+        void clearNonPersistent() {
+            clearSeekTo();
+        }
+
+    private:
+        enum Options {
+            kSeekTo_Option      = 1,
+        };
+
+        uint32_t mOptions;
+        int64_t mSeekTimeUs;
+        SeekMode mSeekMode;
+        int64_t mLatenessUs;
+        bool mNonBlocking;
+    } __attribute__((packed)); // sent through Binder
+
     // Returns a new buffer of data. Call blocks until a
     // buffer is available, an error is encountered of the end of the stream
     // is reached.
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index f968c09..f7df2b4 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -279,8 +279,10 @@
         prop = &mProps[i];
     } else {
         if (i == mPropSize) {
-            growProps();
-            // XXX: verify success
+            if (growProps() == false) {
+                ALOGE("failed allocation for new props");
+                return NULL;
+            }
         }
         i = mPropCount++;
         prop = &mProps[i];
@@ -312,41 +314,54 @@
 // set the values
 void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
     Prop *prop = allocateProp(name);
-    prop->mType = kTypeInt32;
-    prop->u.int32Value = value;
+    if (prop != NULL) {
+        prop->mType = kTypeInt32;
+        prop->u.int32Value = value;
+    }
 }
 
 void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
     Prop *prop = allocateProp(name);
-    prop->mType = kTypeInt64;
-    prop->u.int64Value = value;
+    if (prop != NULL) {
+        prop->mType = kTypeInt64;
+        prop->u.int64Value = value;
+    }
 }
 
 void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
     Prop *prop = allocateProp(name);
-    prop->mType = kTypeDouble;
-    prop->u.doubleValue = value;
+    if (prop != NULL) {
+        prop->mType = kTypeDouble;
+        prop->u.doubleValue = value;
+    }
 }
 
 void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
 
     Prop *prop = allocateProp(name);
     // any old value will be gone
-    prop->mType = kTypeCString;
-    prop->u.CStringValue = strdup(value);
+    if (prop != NULL) {
+        prop->mType = kTypeCString;
+        prop->u.CStringValue = strdup(value);
+    }
 }
 
 void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
     Prop *prop = allocateProp(name);
-    prop->mType = kTypeRate;
-    prop->u.rate.count = count;
-    prop->u.rate.duration = duration;
+    if (prop != NULL) {
+        prop->mType = kTypeRate;
+        prop->u.rate.count = count;
+        prop->u.rate.duration = duration;
+    }
 }
 
 
 // find/add/set fused into a single operation
 void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
     Prop *prop = allocateProp(name);
+    if (prop == NULL) {
+        return;
+    }
     switch (prop->mType) {
         case kTypeInt32:
             prop->u.int32Value += value;
@@ -361,6 +376,9 @@
 
 void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
     Prop *prop = allocateProp(name);
+    if (prop == NULL) {
+        return;
+    }
     switch (prop->mType) {
         case kTypeInt64:
             prop->u.int64Value += value;
@@ -375,6 +393,9 @@
 
 void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
     Prop *prop = allocateProp(name);
+    if (prop == NULL) {
+        return;
+    }
     switch (prop->mType) {
         case kTypeRate:
             prop->u.rate.count += count;
@@ -391,6 +412,9 @@
 
 void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
     Prop *prop = allocateProp(name);
+    if (prop == NULL) {
+        return;
+    }
     switch (prop->mType) {
         case kTypeDouble:
             prop->u.doubleValue += value;
@@ -585,7 +609,7 @@
     }
 }
 
-void MediaAnalyticsItem::growProps(int increment)
+bool MediaAnalyticsItem::growProps(int increment)
 {
     if (increment <= 0) {
         increment = kGrowProps;
@@ -599,6 +623,10 @@
         }
         mProps = ni;
         mPropSize = nsize;
+        return true;
+    } else {
+        ALOGW("MediaAnalyticsItem::growProps fails");
+        return false;
     }
 }
 
@@ -963,32 +991,26 @@
     int nattr = incoming->mPropCount;
     for (int i = 0 ; i < nattr; i++ ) {
         Prop *iprop = &incoming->mProps[i];
-        Prop *oprop = findProp(iprop->mName);
         const char *p = iprop->mName;
         size_t len = strlen(p);
-        char semantic = p[len-1];
+
+        // should ignore a zero length name...
+        if (len == 0) {
+            continue;
+        }
+
+        Prop *oprop = findProp(iprop->mName);
 
         if (oprop == NULL) {
             // no oprop, so we insert the new one
             oprop = allocateProp(p);
-            copyProp(oprop, iprop);
-        } else {
-            // merge iprop into oprop
-            switch (semantic) {
-                case '<':       // first  aka keep old)
-                    /* nop */
-                    break;
-
-                default:        // default is 'last'
-                case '>':       // last (aka keep new)
-                    copyProp(oprop, iprop);
-                    break;
-
-                case '+':       /* sum */
-                    // XXX validate numeric types, sum in place
-                    break;
-
+            if (oprop != NULL) {
+                copyProp(oprop, iprop);
+            } else {
+                ALOGW("dropped property '%s'", iprop->mName);
             }
+        } else {
+            copyProp(oprop, iprop);
         }
     }
 
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index dd7452f..5f9b916 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -243,7 +243,7 @@
         enum {
             kGrowProps = 10
         };
-        void growProps(int increment = kGrowProps);
+        bool growProps(int increment = kGrowProps);
         size_t findPropIndex(const char *name, size_t len);
         Prop *findProp(const char *name);
         Prop *allocateProp(const char *name);
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
new file mode 100644
index 0000000..a37973b
--- /dev/null
+++ b/media/libmediaplayerservice/Android.bp
@@ -0,0 +1,78 @@
+cc_library_shared {
+
+    srcs: [
+        "ActivityManager.cpp",
+        "MediaPlayerFactory.cpp",
+        "MediaPlayerService.cpp",
+        "MediaRecorderClient.cpp",
+        "MetadataRetrieverClient.cpp",
+        "StagefrightRecorder.cpp",
+        "TestPlayerStub.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.media.omx@1.0",
+        "libaudioclient",
+        "libbinder",
+        "libcamera_client",
+        "libcrypto",
+        "libcutils",
+        "libdl",
+        "libgui",
+        "libhidlbase",
+        "libhidlmemory",
+        "liblog",
+        "libmedia",
+        "libmedia_omx",
+        "libmediaextractor",
+        "libmediadrm",
+        "libmediametrics",
+        "libmediautils",
+        "libmemunreachable",
+        "libpowermanager",
+        "libstagefright",
+        "libstagefright_foundation",
+        "libstagefright_httplive",
+        "libutils",
+    ],
+
+    header_libs: [
+        "media_plugin_headers",
+    ],
+
+    static_libs: [
+        "libstagefright_nuplayer",
+        "libstagefright_rtsp",
+        "libstagefright_timedtext",
+    ],
+
+    export_shared_lib_headers: ["libmedia"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/rtsp",
+        "frameworks/av/media/libstagefright/webm",
+    ],
+
+    local_include_dirs: ["include"],
+
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    name: "libmediaplayerservice",
+
+    compile_multilib: "32",
+
+    sanitize: {
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
+
+subdirs = ["*"]
+
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
deleted file mode 100644
index 1fc74a9..0000000
--- a/media/libmediaplayerservice/Android.mk
+++ /dev/null
@@ -1,73 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#
-# libmediaplayerservice
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=               \
-    ActivityManager.cpp         \
-    HDCP.cpp                    \
-    MediaPlayerFactory.cpp      \
-    MediaPlayerService.cpp      \
-    MediaRecorderClient.cpp     \
-    MetadataRetrieverClient.cpp \
-    RemoteDisplay.cpp           \
-    StagefrightRecorder.cpp     \
-    TestPlayerStub.cpp          \
-
-LOCAL_SHARED_LIBRARIES :=       \
-    libbinder                   \
-    libcrypto                   \
-    libcutils                   \
-    libdrmframework             \
-    liblog                      \
-    libdl                       \
-    libgui                      \
-    libaudioclient              \
-    libmedia                    \
-    libmediametrics             \
-    libmediadrm                 \
-    libmediautils               \
-    libmemunreachable           \
-    libstagefright              \
-    libstagefright_foundation   \
-    libstagefright_httplive     \
-    libstagefright_omx          \
-    libstagefright_wfd          \
-    libutils                    \
-    libnativewindow             \
-    libhidlbase                 \
-    android.hardware.media.omx@1.0 \
-
-LOCAL_STATIC_LIBRARIES :=       \
-    libstagefright_nuplayer     \
-    libstagefright_rtsp         \
-    libstagefright_timedtext    \
-
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libmedia
-
-LOCAL_C_INCLUDES :=                                                 \
-    frameworks/av/media/libstagefright/include               \
-    frameworks/av/media/libstagefright/rtsp                  \
-    frameworks/av/media/libstagefright/wifi-display          \
-    frameworks/av/media/libstagefright/webm                  \
-    $(LOCAL_PATH)/include/media                              \
-    frameworks/av/include/camera                             \
-    frameworks/native/include/media/openmax                  \
-    frameworks/native/include/media/hardware                 \
-    external/tremolo/Tremolo                                 \
-
-LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall
-
-LOCAL_MODULE:= libmediaplayerservice
-
-LOCAL_32_BIT_ONLY := true
-
-LOCAL_SANITIZE := cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libmediaplayerservice/HDCP.cpp b/media/libmediaplayerservice/HDCP.cpp
deleted file mode 100644
index afe3936..0000000
--- a/media/libmediaplayerservice/HDCP.cpp
+++ /dev/null
@@ -1,175 +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 "HDCP"
-#include <utils/Log.h>
-
-#include "HDCP.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-
-#include <dlfcn.h>
-
-namespace android {
-
-HDCP::HDCP(bool createEncryptionModule)
-    : mIsEncryptionModule(createEncryptionModule),
-      mLibHandle(NULL),
-      mHDCPModule(NULL) {
-    mLibHandle = dlopen("libstagefright_hdcp.so", RTLD_NOW);
-
-    if (mLibHandle == NULL) {
-        ALOGE("Unable to locate libstagefright_hdcp.so");
-        return;
-    }
-
-    typedef HDCPModule *(*CreateHDCPModuleFunc)(
-            void *, HDCPModule::ObserverFunc);
-
-    CreateHDCPModuleFunc createHDCPModule =
-        mIsEncryptionModule
-            ? (CreateHDCPModuleFunc)dlsym(mLibHandle, "createHDCPModule")
-            : (CreateHDCPModuleFunc)dlsym(
-                    mLibHandle, "createHDCPModuleForDecryption");
-
-    if (createHDCPModule == NULL) {
-        ALOGE("Unable to find symbol 'createHDCPModule'.");
-    } else if ((mHDCPModule = createHDCPModule(
-                    this, &HDCP::ObserveWrapper)) == NULL) {
-        ALOGE("createHDCPModule failed.");
-    }
-}
-
-HDCP::~HDCP() {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mHDCPModule != NULL) {
-        delete mHDCPModule;
-        mHDCPModule = NULL;
-    }
-
-    if (mLibHandle != NULL) {
-        dlclose(mLibHandle);
-        mLibHandle = NULL;
-    }
-}
-
-status_t HDCP::setObserver(const sp<IHDCPObserver> &observer) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mHDCPModule == NULL) {
-        return NO_INIT;
-    }
-
-    mObserver = observer;
-
-    return OK;
-}
-
-status_t HDCP::initAsync(const char *host, unsigned port) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mHDCPModule == NULL) {
-        return NO_INIT;
-    }
-
-    return mHDCPModule->initAsync(host, port);
-}
-
-status_t HDCP::shutdownAsync() {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mHDCPModule == NULL) {
-        return NO_INIT;
-    }
-
-    return mHDCPModule->shutdownAsync();
-}
-
-uint32_t HDCP::getCaps() {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mHDCPModule == NULL) {
-        return NO_INIT;
-    }
-
-    return mHDCPModule->getCaps();
-}
-
-status_t HDCP::encrypt(
-        const void *inData, size_t size, uint32_t streamCTR,
-        uint64_t *outInputCTR, void *outData) {
-    Mutex::Autolock autoLock(mLock);
-
-    CHECK(mIsEncryptionModule);
-
-    if (mHDCPModule == NULL) {
-        *outInputCTR = 0;
-
-        return NO_INIT;
-    }
-
-    return mHDCPModule->encrypt(inData, size, streamCTR, outInputCTR, outData);
-}
-
-status_t HDCP::encryptNative(
-        const sp<GraphicBuffer> &graphicBuffer,
-        size_t offset, size_t size, uint32_t streamCTR,
-        uint64_t *outInputCTR, void *outData) {
-    Mutex::Autolock autoLock(mLock);
-
-    CHECK(mIsEncryptionModule);
-
-    if (mHDCPModule == NULL) {
-        *outInputCTR = 0;
-
-        return NO_INIT;
-    }
-
-    return mHDCPModule->encryptNative(graphicBuffer->handle,
-                    offset, size, streamCTR, outInputCTR, outData);
-}
-
-status_t HDCP::decrypt(
-        const void *inData, size_t size,
-        uint32_t streamCTR, uint64_t outInputCTR, void *outData) {
-    Mutex::Autolock autoLock(mLock);
-
-    CHECK(!mIsEncryptionModule);
-
-    if (mHDCPModule == NULL) {
-        return NO_INIT;
-    }
-
-    return mHDCPModule->decrypt(inData, size, streamCTR, outInputCTR, outData);
-}
-
-// static
-void HDCP::ObserveWrapper(void *me, int msg, int ext1, int ext2) {
-    static_cast<HDCP *>(me)->observe(msg, ext1, ext2);
-}
-
-void HDCP::observe(int msg, int ext1, int ext2) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mObserver != NULL) {
-        mObserver->notify(msg, ext1, ext2, NULL /* obj */);
-    }
-}
-
-}  // namespace android
-
diff --git a/media/libmediaplayerservice/HDCP.h b/media/libmediaplayerservice/HDCP.h
deleted file mode 100644
index 83c61b5..0000000
--- a/media/libmediaplayerservice/HDCP.h
+++ /dev/null
@@ -1,66 +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 HDCP_H_
-
-#define HDCP_H_
-
-#include <media/IHDCP.h>
-#include <utils/Mutex.h>
-
-namespace android {
-
-struct HDCP : public BnHDCP {
-    explicit HDCP(bool createEncryptionModule);
-    virtual ~HDCP();
-
-    virtual status_t setObserver(const sp<IHDCPObserver> &observer);
-    virtual status_t initAsync(const char *host, unsigned port);
-    virtual status_t shutdownAsync();
-    virtual uint32_t getCaps();
-
-    virtual status_t encrypt(
-            const void *inData, size_t size, uint32_t streamCTR,
-            uint64_t *outInputCTR, void *outData);
-
-    virtual status_t encryptNative(
-            const sp<GraphicBuffer> &graphicBuffer,
-            size_t offset, size_t size, uint32_t streamCTR,
-            uint64_t *outInputCTR, void *outData);
-
-    virtual status_t decrypt(
-            const void *inData, size_t size,
-            uint32_t streamCTR, uint64_t outInputCTR, void *outData);
-
-private:
-    Mutex mLock;
-
-    bool mIsEncryptionModule;
-
-    void *mLibHandle;
-    HDCPModule *mHDCPModule;
-    sp<IHDCPObserver> mObserver;
-
-    static void ObserveWrapper(void *me, int msg, int ext1, int ext2);
-    void observe(int msg, int ext1, int ext2);
-
-    DISALLOW_EVIL_CONSTRUCTORS(HDCP);
-};
-
-}  // namespace android
-
-#endif  // HDCP_H_
-
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 6da1ec1..055d5ab 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -20,8 +20,8 @@
 #include <utils/Log.h>
 
 #include <cutils/properties.h>
+#include <media/DataSource.h>
 #include <media/IMediaPlayer.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <utils/Errors.h>
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 3f50684..495c418 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -55,6 +55,7 @@
 #include <media/Metadata.h>
 #include <media/AudioTrack.h>
 #include <media/MemoryLeakTrackUtil.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
@@ -77,11 +78,7 @@
 #include "TestPlayerStub.h"
 #include "nuplayer/NuPlayerDriver.h"
 
-#include <media/stagefright/omx/OMX.h>
-
-#include "HDCP.h"
 #include "HTTPBase.h"
-#include "RemoteDisplay.h"
 
 static const int kDumpLockRetries = 50;
 static const int kDumpLockSleepUs = 20000;
@@ -93,6 +90,7 @@
 using android::BAD_VALUE;
 using android::NOT_ENOUGH_DATA;
 using android::Parcel;
+using android::media::VolumeShaper;
 
 // Max number of entries in the filter.
 const int kMaxFilterSize = 64;  // I pulled that out of thin air.
@@ -337,29 +335,13 @@
     return MediaCodecList::getLocalInstance();
 }
 
-sp<IOMX> MediaPlayerService::getOMX() {
-    ALOGI("MediaPlayerService::getOMX");
-    Mutex::Autolock autoLock(mLock);
-
-    if (mOMX.get() == NULL) {
-        mOMX = new OMX;
-    }
-
-    return mOMX;
-}
-
-sp<IHDCP> MediaPlayerService::makeHDCP(bool createEncryptionModule) {
-    return new HDCP(createEncryptionModule);
-}
-
 sp<IRemoteDisplay> MediaPlayerService::listenForRemoteDisplay(
-        const String16 &opPackageName,
-        const sp<IRemoteDisplayClient>& client, const String8& iface) {
-    if (!checkPermission("android.permission.CONTROL_WIFI_DISPLAY")) {
-        return NULL;
-    }
+        const String16 &/*opPackageName*/,
+        const sp<IRemoteDisplayClient>& /*client*/,
+        const String8& /*iface*/) {
+    ALOGE("listenForRemoteDisplay is no longer supported!");
 
-    return new RemoteDisplay(opPackageName, client, iface.string());
+    return NULL;
 }
 
 status_t MediaPlayerService::AudioOutput::dump(int fd, const Vector<String16>& args) const
@@ -608,6 +590,7 @@
         free(mAudioAttributes);
     }
     clearDeathNotifiers_l();
+    mAudioDeviceUpdatedListener.clear();
 }
 
 void MediaPlayerService::Client::disconnect()
@@ -715,6 +698,17 @@
     }
 }
 
+void MediaPlayerService::Client::AudioDeviceUpdatedNotifier::onAudioDeviceUpdate(
+        audio_io_handle_t audioIo,
+        audio_port_handle_t deviceId) {
+    sp<MediaPlayerBase> listener = mListener.promote();
+    if (listener != NULL) {
+        listener->sendEvent(MEDIA_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
+    } else {
+        ALOGW("listener for process %d death is gone", MEDIA_AUDIO_ROUTING_CHANGED);
+    }
+}
+
 void MediaPlayerService::Client::clearDeathNotifiers_l() {
     if (mExtractorDeathListener != nullptr) {
         mExtractorDeathListener->unlinkToDeath();
@@ -747,36 +741,25 @@
             new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);
     binder->linkToDeath(extractorDeathListener);
 
-    sp<ServiceDeathNotifier> codecDeathListener;
-    if (property_get_bool("persist.media.treble_omx", true)) {
-        // Treble IOmx
-        sp<IOmx> omx = IOmx::getService();
-        if (omx == nullptr) {
-            ALOGE("Treble IOmx not available");
-            return NULL;
-        }
-        codecDeathListener = new ServiceDeathNotifier(omx, p, MEDIACODEC_PROCESS_DEATH);
-        omx->linkToDeath(codecDeathListener, 0);
-    } else {
-        // Legacy IOMX
-        binder = sm->getService(String16("media.codec"));
-        if (binder == NULL) {
-            ALOGE("codec service not available");
-            return NULL;
-        }
-        codecDeathListener = new ServiceDeathNotifier(binder, p, MEDIACODEC_PROCESS_DEATH);
-        binder->linkToDeath(codecDeathListener);
+    sp<IOmx> omx = IOmx::getService();
+    if (omx == nullptr) {
+        ALOGE("IOmx service is not available");
+        return NULL;
     }
+    sp<ServiceDeathNotifier> codecDeathListener =
+            new ServiceDeathNotifier(omx, p, MEDIACODEC_PROCESS_DEATH);
+    omx->linkToDeath(codecDeathListener, 0);
 
     Mutex::Autolock lock(mLock);
 
     clearDeathNotifiers_l();
     mExtractorDeathListener = extractorDeathListener;
     mCodecDeathListener = codecDeathListener;
+    mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
 
     if (!p->hardwareOutput()) {
         mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
-                mPid, mAudioAttributes);
+                mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
         static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
     }
 
@@ -906,7 +889,7 @@
 
 status_t MediaPlayerService::Client::setDataSource(
         const sp<IDataSource> &source) {
-    sp<DataSource> dataSource = DataSource::CreateFromIDataSource(source);
+    sp<DataSource> dataSource = CreateDataSourceFromIDataSource(source);
     player_type playerType = MediaPlayerFactory::getPlayerType(this, dataSource);
     sp<MediaPlayerBase> p = setDataSource_pre(playerType);
     if (p == NULL) {
@@ -1063,18 +1046,18 @@
     return p->setBufferingSettings(buffering);
 }
 
-status_t MediaPlayerService::Client::getDefaultBufferingSettings(
+status_t MediaPlayerService::Client::getBufferingSettings(
         BufferingSettings* buffering /* nonnull */)
 {
     sp<MediaPlayerBase> p = getPlayer();
     // TODO: create mPlayer on demand.
     if (p == 0) return UNKNOWN_ERROR;
-    status_t ret = p->getDefaultBufferingSettings(buffering);
+    status_t ret = p->getBufferingSettings(buffering);
     if (ret == NO_ERROR) {
-        ALOGV("[%d] getDefaultBufferingSettings{%s}",
+        ALOGV("[%d] getBufferingSettings{%s}",
                 mConnId, buffering->toString().string());
     } else {
-        ALOGV("[%d] getDefaultBufferingSettings returned %d", mConnId, ret);
+        ALOGE("[%d] getBufferingSettings returned %d", mConnId, ret);
     }
     return ret;
 }
@@ -1281,6 +1264,14 @@
     return p->reset();
 }
 
+status_t MediaPlayerService::Client::notifyAt(int64_t mediaTimeUs)
+{
+    ALOGV("[%d] notifyAt(%lld)", mConnId, (long long)mediaTimeUs);
+    sp<MediaPlayerBase> p = getPlayer();
+    if (p == 0) return UNKNOWN_ERROR;
+    return p->notifyAt(mediaTimeUs);
+}
+
 status_t MediaPlayerService::Client::setAudioStreamType(audio_stream_type_t type)
 {
     ALOGV("[%d] setAudioStreamType(%d)", mConnId, type);
@@ -1538,6 +1529,42 @@
     return ret;
 }
 
+status_t MediaPlayerService::Client::setOutputDevice(audio_port_handle_t deviceId)
+{
+    ALOGV("[%d] setOutputDevice", mConnId);
+    {
+        Mutex::Autolock l(mLock);
+        if (mAudioOutput.get() != nullptr) {
+            return mAudioOutput->setOutputDevice(deviceId);
+        }
+    }
+    return NO_INIT;
+}
+
+status_t MediaPlayerService::Client::getRoutedDeviceId(audio_port_handle_t* deviceId)
+{
+    ALOGV("[%d] getRoutedDeviceId", mConnId);
+    {
+        Mutex::Autolock l(mLock);
+        if (mAudioOutput.get() != nullptr) {
+            return mAudioOutput->getRoutedDeviceId(deviceId);
+        }
+    }
+    return NO_INIT;
+}
+
+status_t MediaPlayerService::Client::enableAudioDeviceCallback(bool enabled)
+{
+    ALOGV("[%d] enableAudioDeviceCallback, %d", mConnId, enabled);
+    {
+        Mutex::Autolock l(mLock);
+        if (mAudioOutput.get() != nullptr) {
+            return mAudioOutput->enableAudioDeviceCallback(enabled);
+        }
+    }
+    return NO_INIT;
+}
+
 #if CALLBACK_ANTAGONIZER
 const int Antagonizer::interval = 10000; // 10 msecs
 
@@ -1576,7 +1603,7 @@
 #undef LOG_TAG
 #define LOG_TAG "AudioSink"
 MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
-        const audio_attributes_t* attr)
+        const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
     : mCallback(NULL),
       mCallbackCookie(NULL),
       mCallbackData(NULL),
@@ -1593,7 +1620,11 @@
       mSendLevel(0.0),
       mAuxEffectId(0),
       mFlags(AUDIO_OUTPUT_FLAG_NONE),
-      mVolumeHandler(new VolumeHandler())
+      mVolumeHandler(new media::VolumeHandler()),
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mDeviceCallbackEnabled(false),
+      mDeviceCallback(deviceCallback)
 {
     ALOGV("AudioOutput(%d)", sessionId);
     if (attr != NULL) {
@@ -1979,7 +2010,9 @@
                     mUid,
                     mPid,
                     mAttributes,
-                    doNotReconnect);
+                    doNotReconnect,
+                    1.0f,  // default value for maxRequiredSpeed
+                    mSelectedDeviceId);
         } else {
             // TODO: Due to buffer memory concerns, we use a max target playback speed
             // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
@@ -2006,7 +2039,8 @@
                     mPid,
                     mAttributes,
                     doNotReconnect,
-                    targetSpeed);
+                    targetSpeed,
+                    mSelectedDeviceId);
         }
 
         if ((t == 0) || (t->initCheck() != NO_ERROR)) {
@@ -2100,6 +2134,10 @@
             res = mTrack->attachAuxEffect(mAuxEffectId);
         }
     }
+    mTrack->setOutputDevice(mSelectedDeviceId);
+    if (mDeviceCallbackEnabled) {
+        mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
+    }
     ALOGV("updateTrack() DONE status %d", res);
     return res;
 }
@@ -2315,6 +2353,45 @@
     return NO_ERROR;
 }
 
+status_t MediaPlayerService::AudioOutput::setOutputDevice(audio_port_handle_t deviceId)
+{
+    ALOGV("setOutputDevice(%d)", deviceId);
+    Mutex::Autolock lock(mLock);
+    mSelectedDeviceId = deviceId;
+    if (mTrack != 0) {
+        return mTrack->setOutputDevice(deviceId);
+    }
+    return NO_ERROR;
+}
+
+status_t MediaPlayerService::AudioOutput::getRoutedDeviceId(audio_port_handle_t* deviceId)
+{
+    ALOGV("getRoutedDeviceId");
+    Mutex::Autolock lock(mLock);
+    if (mTrack != 0) {
+        mRoutedDeviceId = mTrack->getRoutedDeviceId();
+    }
+    *deviceId = mRoutedDeviceId;
+    return NO_ERROR;
+}
+
+status_t MediaPlayerService::AudioOutput::enableAudioDeviceCallback(bool enabled)
+{
+    ALOGV("enableAudioDeviceCallback, %d", enabled);
+    Mutex::Autolock lock(mLock);
+    mDeviceCallbackEnabled = enabled;
+    if (mTrack != 0) {
+        status_t status;
+        if (enabled) {
+            status = mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
+        } else {
+            status = mTrack->removeAudioDeviceCallback(mDeviceCallback.promote());
+        }
+        return status;
+    }
+    return NO_ERROR;
+}
+
 VolumeShaper::Status MediaPlayerService::AudioOutput::applyVolumeShaper(
                 const sp<VolumeShaper::Configuration>& configuration,
                 const sp<VolumeShaper::Operation>& operation)
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index e35d098..eefdd7d 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -78,8 +78,12 @@
         class CallbackData;
 
      public:
-                                AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
-                                        const audio_attributes_t * attr);
+                                AudioOutput(
+                                        audio_session_t sessionId,
+                                        uid_t uid,
+                                        int pid,
+                                        const audio_attributes_t * attr,
+                                        const sp<AudioSystem::AudioDeviceCallback>& deviceCallback);
         virtual                 ~AudioOutput();
 
         virtual bool            ready() const { return mTrack != 0; }
@@ -132,10 +136,15 @@
         virtual status_t        setParameters(const String8& keyValuePairs);
         virtual String8         getParameters(const String8& keys);
 
-        virtual VolumeShaper::Status applyVolumeShaper(
-                                        const sp<VolumeShaper::Configuration>& configuration,
-                                        const sp<VolumeShaper::Operation>& operation) override;
-        virtual sp<VolumeShaper::State> getVolumeShaperState(int id) override;
+        virtual media::VolumeShaper::Status applyVolumeShaper(
+                                        const sp<media::VolumeShaper::Configuration>& configuration,
+                                        const sp<media::VolumeShaper::Operation>& operation) override;
+        virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) override;
+
+        // AudioRouting
+        virtual status_t        setOutputDevice(audio_port_handle_t deviceId);
+        virtual status_t        getRoutedDeviceId(audio_port_handle_t* deviceId);
+        virtual status_t        enableAudioDeviceCallback(bool enabled);
 
     private:
         static void             setMinBufferCount();
@@ -165,7 +174,11 @@
         float                   mSendLevel;
         int                     mAuxEffectId;
         audio_output_flags_t    mFlags;
-        sp<VolumeHandler>       mVolumeHandler;
+        sp<media::VolumeHandler>       mVolumeHandler;
+        audio_port_handle_t     mSelectedDeviceId;
+        audio_port_handle_t     mRoutedDeviceId;
+        bool                    mDeviceCallbackEnabled;
+        wp<AudioSystem::AudioDeviceCallback>        mDeviceCallback;
         mutable Mutex           mLock;
 
         // static variables below not protected by mutex
@@ -228,8 +241,6 @@
                                        audio_session_t audioSessionId);
 
     virtual sp<IMediaCodecList> getCodecList() const;
-    virtual sp<IOMX>            getOMX();
-    virtual sp<IHDCP>           makeHDCP(bool createEncryptionModule);
 
     virtual sp<IRemoteDisplay> listenForRemoteDisplay(const String16 &opPackageName,
             const sp<IRemoteDisplayClient>& client, const String8& iface);
@@ -309,7 +320,7 @@
         virtual status_t        setVideoSurfaceTexture(
                                         const sp<IGraphicBufferProducer>& bufferProducer);
         virtual status_t        setBufferingSettings(const BufferingSettings& buffering) override;
-        virtual status_t        getDefaultBufferingSettings(
+        virtual status_t        getBufferingSettings(
                                         BufferingSettings* buffering /* nonnull */) override;
         virtual status_t        prepareAsync();
         virtual status_t        start();
@@ -327,6 +338,7 @@
         virtual status_t        getCurrentPosition(int* msec);
         virtual status_t        getDuration(int* msec);
         virtual status_t        reset();
+        virtual status_t        notifyAt(int64_t mediaTimeUs);
         virtual status_t        setAudioStreamType(audio_stream_type_t type);
         virtual status_t        setLooping(int loop);
         virtual status_t        setVolume(float leftVolume, float rightVolume);
@@ -343,10 +355,10 @@
         virtual status_t        getRetransmitEndpoint(struct sockaddr_in* endpoint);
         virtual status_t        setNextPlayer(const sp<IMediaPlayer>& player);
 
-        virtual VolumeShaper::Status applyVolumeShaper(
-                                        const sp<VolumeShaper::Configuration>& configuration,
-                                        const sp<VolumeShaper::Operation>& operation) override;
-        virtual sp<VolumeShaper::State> getVolumeShaperState(int id) override;
+        virtual media::VolumeShaper::Status applyVolumeShaper(
+                                        const sp<media::VolumeShaper::Configuration>& configuration,
+                                        const sp<media::VolumeShaper::Operation>& operation) override;
+        virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) override;
 
         sp<MediaPlayerBase>     createPlayer(player_type playerType);
 
@@ -375,6 +387,10 @@
         // Modular DRM
         virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
         virtual status_t releaseDrm();
+        // AudioRouting
+        virtual status_t setOutputDevice(audio_port_handle_t deviceId);
+        virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
+        virtual status_t enableAudioDeviceCallback(bool enabled);
 
     private:
         class ServiceDeathNotifier:
@@ -404,6 +420,21 @@
             wp<MediaPlayerBase> mListener;
         };
 
+        class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback
+        {
+        public:
+            AudioDeviceUpdatedNotifier(const sp<MediaPlayerBase>& listener) {
+                mListener = listener;
+            }
+            ~AudioDeviceUpdatedNotifier() {}
+
+            virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                             audio_port_handle_t deviceId);
+
+        private:
+            wp<MediaPlayerBase> mListener;
+        };
+
         void clearDeathNotifiers_l();
 
         friend class MediaPlayerService;
@@ -467,6 +498,7 @@
 
         sp<ServiceDeathNotifier> mExtractorDeathListener;
         sp<ServiceDeathNotifier> mCodecDeathListener;
+        sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedListener;
 #if CALLBACK_ANTAGONIZER
                     Antagonizer*                mAntagonizer;
 #endif
@@ -481,7 +513,6 @@
                 SortedVector< wp<Client> >  mClients;
                 SortedVector< wp<MediaRecorderClient> > mMediaRecorderClients;
                 int32_t                     mNextConnId;
-                sp<IOMX>                    mOMX;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 9b9b3bb..dcd393b 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -411,6 +411,25 @@
     }
 }
 
+MediaRecorderClient::AudioDeviceUpdatedNotifier::AudioDeviceUpdatedNotifier(
+        const sp<IMediaRecorderClient>& listener) {
+    mListener = listener;
+}
+
+MediaRecorderClient::AudioDeviceUpdatedNotifier::~AudioDeviceUpdatedNotifier() {
+}
+
+void MediaRecorderClient::AudioDeviceUpdatedNotifier::onAudioDeviceUpdate(
+        audio_io_handle_t audioIo,
+        audio_port_handle_t deviceId) {
+    sp<IMediaRecorderClient> listener = mListener.promote();
+    if (listener != NULL) {
+        listener->notify(MEDIA_RECORDER_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
+    } else {
+        ALOGW("listener for process %d death is gone", MEDIA_RECORDER_AUDIO_ROUTING_CHANGED);
+    }
+}
+
 void MediaRecorderClient::clearDeathNotifiers_l() {
     if (mCameraDeathListener != nullptr) {
         mCameraDeathListener->unlinkToDeath();
@@ -450,27 +469,17 @@
     }
     sCameraChecked = true;
 
-    if (property_get_bool("persist.media.treble_omx", true)) {
-        // Treble IOmx
-        sp<IOmx> omx = IOmx::getService();
-        if (omx == nullptr) {
-            ALOGE("Treble IOmx not available");
-            return NO_INIT;
-        }
-        mCodecDeathListener = new ServiceDeathNotifier(omx, listener,
-                MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
-        omx->linkToDeath(mCodecDeathListener, 0);
-    } else {
-        // Legacy IOMX
-        binder = sm->getService(String16("media.codec"));
-        if (binder == NULL) {
-           ALOGE("Unable to connect to media codec service");
-           return NO_INIT;
-        }
-        mCodecDeathListener = new ServiceDeathNotifier(binder, listener,
-                MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
-        binder->linkToDeath(mCodecDeathListener);
+    sp<IOmx> omx = IOmx::getService();
+    if (omx == nullptr) {
+        ALOGE("IOmx service is not available");
+        return NO_INIT;
     }
+    mCodecDeathListener = new ServiceDeathNotifier(omx, listener,
+            MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
+    omx->linkToDeath(mCodecDeathListener, 0);
+
+    mAudioDeviceUpdatedNotifier = new AudioDeviceUpdatedNotifier(listener);
+    mRecorder->setAudioDeviceCallback(mAudioDeviceUpdatedNotifier);
 
     return OK;
 }
@@ -492,4 +501,30 @@
     return OK;
 }
 
+status_t MediaRecorderClient::setInputDevice(audio_port_handle_t deviceId) {
+    ALOGV("setInputDevice(%d)", deviceId);
+    Mutex::Autolock lock(mLock);
+    if (mRecorder != NULL) {
+        return mRecorder->setInputDevice(deviceId);
+    }
+    return NO_INIT;
+}
+
+status_t MediaRecorderClient::getRoutedDeviceId(audio_port_handle_t* deviceId) {
+    ALOGV("getRoutedDeviceId");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder != NULL) {
+        return mRecorder->getRoutedDeviceId(deviceId);
+    }
+    return NO_INIT;
+}
+
+status_t MediaRecorderClient::enableAudioDeviceCallback(bool enabled) {
+    ALOGV("enableDeviceCallback: %d", enabled);
+    Mutex::Autolock lock(mLock);
+    if (mRecorder != NULL) {
+        return mRecorder->enableAudioDeviceCallback(enabled);
+    }
+    return NO_INIT;
+}
 }; // namespace android
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 711db2c..538b461 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -18,6 +18,7 @@
 #ifndef ANDROID_MEDIARECORDERCLIENT_H
 #define ANDROID_MEDIARECORDERCLIENT_H
 
+#include <media/AudioSystem.h>
 #include <media/IMediaRecorder.h>
 
 #include <android/hardware/media/omx/1.0/IOmx.h>
@@ -58,6 +59,18 @@
         wp<IMediaRecorderClient> mListener;
     };
 
+    class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback
+    {
+    public:
+        AudioDeviceUpdatedNotifier(const sp<IMediaRecorderClient>& listener);
+        virtual ~AudioDeviceUpdatedNotifier();
+        virtual void onAudioDeviceUpdate(
+                audio_io_handle_t audioIo,
+                audio_port_handle_t deviceId);
+    private:
+        wp<IMediaRecorderClient> mListener;
+    };
+
     void clearDeathNotifiers_l();
 
 public:
@@ -91,6 +104,9 @@
     virtual     status_t   dump(int fd, const Vector<String16>& args);
     virtual     status_t   setInputSurface(const sp<PersistentSurface>& surface);
     virtual     sp<IGraphicBufferProducer> querySurfaceMediaSource();
+    virtual     status_t   setInputDevice(audio_port_handle_t deviceId);
+    virtual     status_t   getRoutedDeviceId(audio_port_handle_t* deviceId);
+    virtual     status_t   enableAudioDeviceCallback(bool enabled);
 
 private:
     friend class           MediaPlayerService;  // for accessing private constructor
@@ -103,6 +119,7 @@
 
     sp<ServiceDeathNotifier> mCameraDeathListener;
     sp<ServiceDeathNotifier> mCodecDeathListener;
+    sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedNotifier;
 
     pid_t                  mPid;
     Mutex                  mLock;
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 5a468f3..16ed530 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -31,10 +31,11 @@
 #include <binder/MemoryHeapBase.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <media/DataSource.h>
 #include <media/IMediaHTTPService.h>
 #include <media/MediaMetadataRetrieverInterface.h>
 #include <media/MediaPlayerInterface.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/Utils.h>
 #include <private/media/VideoFrame.h>
 #include "MetadataRetrieverClient.h"
@@ -180,7 +181,7 @@
     ALOGV("setDataSource(IDataSource)");
     Mutex::Autolock lock(mLock);
 
-    sp<DataSource> dataSource = DataSource::CreateFromIDataSource(source);
+    sp<DataSource> dataSource = CreateDataSourceFromIDataSource(source);
     player_type playerType =
         MediaPlayerFactory::getPlayerType(NULL /* client */, dataSource);
     ALOGV("player type = %d", playerType);
@@ -193,6 +194,25 @@
 
 Mutex MetadataRetrieverClient::sLock;
 
+static sp<IMemory> getThumbnail(VideoFrame* frame) {
+    std::unique_ptr<VideoFrame> frameDeleter(frame);
+
+    size_t size = frame->getFlattenedSize();
+    sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
+    if (heap == NULL) {
+        ALOGE("failed to create MemoryDealer");
+        return NULL;
+    }
+    sp<IMemory> thrumbnail = new MemoryBase(heap, 0, size);
+    if (thrumbnail == NULL) {
+        ALOGE("not enough memory for VideoFrame size=%zu", size);
+        return NULL;
+    }
+    VideoFrame *frameCopy = static_cast<VideoFrame *>(thrumbnail->pointer());
+    frameCopy->copyFlattened(*frame);
+    return thrumbnail;
+}
+
 sp<IMemory> MetadataRetrieverClient::getFrameAtTime(
         int64_t timeUs, int option, int colorFormat, bool metaOnly)
 {
@@ -205,29 +225,55 @@
         ALOGE("retriever is not initialized");
         return NULL;
     }
-    VideoFrame *frame = mRetriever->getFrameAtTime(
-            timeUs, option, colorFormat, metaOnly);
+    VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option, colorFormat, metaOnly);
     if (frame == NULL) {
         ALOGE("failed to capture a video frame");
         return NULL;
     }
-    size_t size = frame->getFlattenedSize();
-    sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
-    if (heap == NULL) {
-        ALOGE("failed to create MemoryDealer");
-        delete frame;
+    return getThumbnail(frame);
+}
+
+sp<IMemory> MetadataRetrieverClient::getImageAtIndex(
+        int index, int colorFormat, bool metaOnly) {
+    ALOGV("getFrameAtTime: index(%d) colorFormat(%d), metaOnly(%d)",
+            index, colorFormat, metaOnly);
+    Mutex::Autolock lock(mLock);
+    Mutex::Autolock glock(sLock);
+    mThumbnail.clear();
+    if (mRetriever == NULL) {
+        ALOGE("retriever is not initialized");
         return NULL;
     }
-    mThumbnail = new MemoryBase(heap, 0, size);
-    if (mThumbnail == NULL) {
-        ALOGE("not enough memory for VideoFrame size=%zu", size);
-        delete frame;
+    VideoFrame *frame = mRetriever->getImageAtIndex(index, colorFormat, metaOnly);
+    if (frame == NULL) {
+        ALOGE("failed to extract image");
         return NULL;
     }
-    VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
-    frameCopy->copyFlattened(*frame);
-    delete frame;  // Fix memory leakage
-    return mThumbnail;
+    return getThumbnail(frame);
+}
+
+status_t MetadataRetrieverClient::getFrameAtIndex(
+            std::vector<sp<IMemory> > *frames,
+            int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
+    ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d), metaOnly(%d)",
+            frameIndex, numFrames, colorFormat, metaOnly);
+    Mutex::Autolock lock(mLock);
+    Mutex::Autolock glock(sLock);
+    if (mRetriever == NULL) {
+        ALOGE("retriever is not initialized");
+        return INVALID_OPERATION;
+    }
+
+    std::vector<VideoFrame*> videoFrames;
+    status_t err = mRetriever->getFrameAtIndex(
+            &videoFrames, frameIndex, numFrames, colorFormat, metaOnly);
+    if (err != OK) {
+        return err;
+    }
+    for (size_t i = 0; i < videoFrames.size(); i++) {
+        frames->push_back(getThumbnail(videoFrames[i]));
+    }
+    return OK;
 }
 
 sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index c78cd4b..f71891a 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -52,6 +52,11 @@
     virtual status_t                setDataSource(const sp<IDataSource>& source, const char *mime);
     virtual sp<IMemory>             getFrameAtTime(
             int64_t timeUs, int option, int colorFormat, bool metaOnly);
+    virtual sp<IMemory>             getImageAtIndex(
+            int index, int colorFormat, bool metaOnly);
+    virtual status_t getFrameAtIndex(
+                std::vector<sp<IMemory> > *frames,
+                int frameIndex, int numFrames, int colorFormat, bool metaOnly);
     virtual sp<IMemory>             extractAlbumArt();
     virtual const char*             extractMetadata(int keyCode);
 
diff --git a/media/libmediaplayerservice/RemoteDisplay.cpp b/media/libmediaplayerservice/RemoteDisplay.cpp
deleted file mode 100644
index 0eb4b5d..0000000
--- a/media/libmediaplayerservice/RemoteDisplay.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 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 "RemoteDisplay.h"
-
-#include "source/WifiDisplaySource.h"
-
-#include <media/IRemoteDisplayClient.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/ANetworkSession.h>
-
-namespace android {
-
-RemoteDisplay::RemoteDisplay(
-        const String16 &opPackageName,
-        const sp<IRemoteDisplayClient> &client,
-        const char *iface)
-    : mLooper(new ALooper),
-      mNetSession(new ANetworkSession) {
-    mLooper->setName("wfd_looper");
-
-    mSource = new WifiDisplaySource(opPackageName, mNetSession, client);
-    mLooper->registerHandler(mSource);
-
-    mNetSession->start();
-    mLooper->start();
-
-    mSource->start(iface);
-}
-
-RemoteDisplay::~RemoteDisplay() {
-}
-
-status_t RemoteDisplay::pause() {
-    return mSource->pause();
-}
-
-status_t RemoteDisplay::resume() {
-    return mSource->resume();
-}
-
-status_t RemoteDisplay::dispose() {
-    mSource->stop();
-    mSource.clear();
-
-    mLooper->stop();
-    mNetSession->stop();
-
-    return OK;
-}
-
-}  // namespace android
diff --git a/media/libmediaplayerservice/RemoteDisplay.h b/media/libmediaplayerservice/RemoteDisplay.h
deleted file mode 100644
index d4573e9..0000000
--- a/media/libmediaplayerservice/RemoteDisplay.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 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 REMOTE_DISPLAY_H_
-
-#define REMOTE_DISPLAY_H_
-
-#include <media/IMediaPlayerService.h>
-#include <media/IRemoteDisplay.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-struct ALooper;
-struct ANetworkSession;
-class IRemoteDisplayClient;
-struct WifiDisplaySource;
-
-struct RemoteDisplay : public BnRemoteDisplay {
-    RemoteDisplay(
-            const String16 &opPackageName,
-            const sp<IRemoteDisplayClient> &client,
-            const char *iface);
-
-    virtual status_t pause();
-    virtual status_t resume();
-    virtual status_t dispose();
-
-protected:
-    virtual ~RemoteDisplay();
-
-private:
-    sp<ALooper> mNetLooper;
-    sp<ALooper> mLooper;
-    sp<ANetworkSession> mNetSession;
-    sp<WifiDisplaySource> mSource;
-
-    DISALLOW_EVIL_CONSTRUCTORS(RemoteDisplay);
-};
-
-}  // namespace android
-
-#endif  // REMOTE_DISPLAY_H_
-
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 89354d6..77eaefe 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -103,7 +103,9 @@
       mOutputFd(-1),
       mAudioSource(AUDIO_SOURCE_CNT),
       mVideoSource(VIDEO_SOURCE_LIST_END),
-      mStarted(false) {
+      mStarted(false),
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mDeviceCallbackEnabled(false) {
 
     ALOGV("Constructor");
 
@@ -204,7 +206,7 @@
     return OK;
 }
 
-// The client side of mediaserver asks it to creat a SurfaceMediaSource
+// The client side of mediaserver asks it to create a SurfaceMediaSource
 // and return a interface reference. The client side will use that
 // while encoding GL Frames
 sp<IGraphicBufferProducer> StagefrightRecorder::querySurfaceMediaSource() const {
@@ -1069,7 +1071,8 @@
                 mAudioChannels,
                 mSampleRate,
                 mClientUid,
-                mClientPid);
+                mClientPid,
+                mSelectedDeviceId);
 
     status_t err = audioSource->initCheck();
 
@@ -1120,6 +1123,10 @@
 
     sp<MediaCodecSource> audioEncoder =
             MediaCodecSource::Create(mLooper, format, audioSource);
+    sp<AudioSystem::AudioDeviceCallback> callback = mAudioDeviceCallback.promote();
+    if (mDeviceCallbackEnabled && callback != 0) {
+        audioSource->addAudioDeviceCallback(callback);
+    }
     mAudioSourceNode = audioSource;
 
     if (audioEncoder == NULL) {
@@ -2116,6 +2123,46 @@
     return OK;
 }
 
+status_t StagefrightRecorder::setInputDevice(audio_port_handle_t deviceId) {
+    ALOGV("setInputDevice");
+
+    if (mSelectedDeviceId != deviceId) {
+        mSelectedDeviceId = deviceId;
+        if (mAudioSourceNode != 0) {
+            return mAudioSourceNode->setInputDevice(deviceId);
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t StagefrightRecorder::getRoutedDeviceId(audio_port_handle_t* deviceId) {
+    ALOGV("getRoutedDeviceId");
+
+    if (mAudioSourceNode != 0) {
+        status_t status = mAudioSourceNode->getRoutedDeviceId(deviceId);
+        return status;
+    }
+    return NO_INIT;
+}
+
+void StagefrightRecorder::setAudioDeviceCallback(
+        const sp<AudioSystem::AudioDeviceCallback>& callback) {
+    mAudioDeviceCallback = callback;
+}
+
+status_t StagefrightRecorder::enableAudioDeviceCallback(bool enabled) {
+    mDeviceCallbackEnabled = enabled;
+    sp<AudioSystem::AudioDeviceCallback> callback = mAudioDeviceCallback.promote();
+    if (mAudioSourceNode != 0 && callback != 0) {
+        if (enabled) {
+            return mAudioSourceNode->addAudioDeviceCallback(callback);
+        } else {
+            return mAudioSourceNode->removeAudioDeviceCallback(callback);
+        }
+    }
+    return NO_ERROR;
+}
+
 status_t StagefrightRecorder::dump(
         int fd, const Vector<String16>& args) const {
     ALOGV("dump");
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 9a6c4da..ec7e8ed 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -25,7 +25,7 @@
 
 #include <system/audio.h>
 
-#include <MetadataBufferType.h>
+#include <media/hardware/MetadataBufferType.h>
 
 namespace android {
 
@@ -72,6 +72,10 @@
     virtual status_t dump(int fd, const Vector<String16> &args) const;
     // Querying a SurfaceMediaSourcer
     virtual sp<IGraphicBufferProducer> querySurfaceMediaSource() const;
+    virtual status_t setInputDevice(audio_port_handle_t deviceId);
+    virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
+    virtual void setAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+    virtual status_t enableAudioDeviceCallback(bool enabled);
 
 private:
     mutable Mutex mLock;
@@ -144,6 +148,10 @@
     sp<IGraphicBufferProducer> mGraphicBufferProducer;
     sp<ALooper> mLooper;
 
+    audio_port_handle_t mSelectedDeviceId;
+    bool mDeviceCallbackEnabled;
+    wp<AudioSystem::AudioDeviceCallback> mAudioDeviceCallback;
+
     static const int kMaxHighSpeedFps = 1000;
 
     status_t prepareInternal();
diff --git a/media/libmediaplayerservice/include/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h
index e8d59a7..a03884f 100644
--- a/media/libmediaplayerservice/include/MediaPlayerInterface.h
+++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h
@@ -146,10 +146,15 @@
         virtual status_t    setParameters(const String8& /* keyValuePairs */) { return NO_ERROR; }
         virtual String8     getParameters(const String8& /* keys */) { return String8::empty(); }
 
-        virtual VolumeShaper::Status applyVolumeShaper(
-                                    const sp<VolumeShaper::Configuration>& configuration,
-                                    const sp<VolumeShaper::Operation>& operation);
-        virtual sp<VolumeShaper::State> getVolumeShaperState(int id);
+        virtual media::VolumeShaper::Status applyVolumeShaper(
+                                    const sp<media::VolumeShaper::Configuration>& configuration,
+                                    const sp<media::VolumeShaper::Operation>& operation);
+        virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id);
+
+        // AudioRouting
+        virtual status_t    setOutputDevice(audio_port_handle_t deviceId);
+        virtual status_t    getRoutedDeviceId(audio_port_handle_t* deviceId);
+        virtual status_t    enableAudioDeviceCallback(bool enabled);
     };
 
                         MediaPlayerBase() : mCookie(0), mNotify(0) {}
@@ -180,7 +185,7 @@
     virtual status_t    setVideoSurfaceTexture(
                                 const sp<IGraphicBufferProducer>& bufferProducer) = 0;
 
-    virtual status_t    getDefaultBufferingSettings(
+    virtual status_t    getBufferingSettings(
                                 BufferingSettings* buffering /* nonnull */) {
         *buffering = BufferingSettings();
         return OK;
@@ -225,6 +230,9 @@
     virtual status_t    getCurrentPosition(int *msec) = 0;
     virtual status_t    getDuration(int *msec) = 0;
     virtual status_t    reset() = 0;
+    virtual status_t    notifyAt(int64_t /* mediaTimeUs */) {
+        return INVALID_OPERATION;
+    }
     virtual status_t    setLooping(int loop) = 0;
     virtual player_type playerType() = 0;
     virtual status_t    setParameter(int key, const Parcel &request) = 0;
diff --git a/media/libstagefright/foundation/AWakeLock.cpp b/media/libmediaplayerservice/nuplayer/AWakeLock.cpp
similarity index 98%
rename from media/libstagefright/foundation/AWakeLock.cpp
rename to media/libmediaplayerservice/nuplayer/AWakeLock.cpp
index d9277ac..684ba2e 100644
--- a/media/libstagefright/foundation/AWakeLock.cpp
+++ b/media/libmediaplayerservice/nuplayer/AWakeLock.cpp
@@ -18,11 +18,11 @@
 #define LOG_TAG "AWakeLock"
 #include <utils/Log.h>
 
-#include "ADebug.h"
 #include "AWakeLock.h"
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <powermanager/PowerManager.h>
 
 
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AWakeLock.h b/media/libmediaplayerservice/nuplayer/AWakeLock.h
similarity index 100%
rename from media/libstagefright/foundation/include/media/stagefright/foundation/AWakeLock.h
rename to media/libmediaplayerservice/nuplayer/AWakeLock.h
diff --git a/media/libmediaplayerservice/nuplayer/Android.bp b/media/libmediaplayerservice/nuplayer/Android.bp
new file mode 100644
index 0000000..645bb7a
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/Android.bp
@@ -0,0 +1,66 @@
+cc_library_static {
+
+    srcs: [
+        "AWakeLock.cpp",
+        "GenericSource.cpp",
+        "HTTPLiveSource.cpp",
+        "NuPlayer.cpp",
+        "NuPlayerCCDecoder.cpp",
+        "NuPlayerDecoder.cpp",
+        "NuPlayerDecoderBase.cpp",
+        "NuPlayerDecoderPassThrough.cpp",
+        "NuPlayerDriver.cpp",
+        "NuPlayerDrm.cpp",
+        "NuPlayerRenderer.cpp",
+        "NuPlayerStreamListener.cpp",
+        "RTSPSource.cpp",
+        "StreamingSource.cpp",
+    ],
+
+    header_libs: [
+        "media_plugin_headers",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/av/media/libstagefright/httplive",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/av/media/libstagefright/mpeg2ts",
+        "frameworks/av/media/libstagefright/rtsp",
+        "frameworks/av/media/libstagefright/timedtext",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    product_variables: {
+        debuggable: {
+            cflags: [
+                "-DENABLE_STAGEFRIGHT_EXPERIMENTS",
+            ],
+        }
+    },
+
+    shared_libs: [
+        "libbinder",
+        "libui",
+        "libgui",
+        "libmedia",
+        "libmediadrm",
+        "libpowermanager",
+    ],
+
+    name: "libstagefright_nuplayer",
+
+    tags: ["eng"],
+
+    sanitize: {
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
deleted file mode 100644
index c582631..0000000
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=                       \
-        GenericSource.cpp               \
-        HTTPLiveSource.cpp              \
-        NuPlayer.cpp                    \
-        NuPlayerCCDecoder.cpp           \
-        NuPlayerDecoder.cpp             \
-        NuPlayerDecoderBase.cpp         \
-        NuPlayerDecoderPassThrough.cpp  \
-        NuPlayerDriver.cpp              \
-        NuPlayerDrm.cpp                 \
-        NuPlayerRenderer.cpp            \
-        NuPlayerStreamListener.cpp      \
-        RTSPSource.cpp                  \
-        StreamingSource.cpp             \
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/media/libstagefright                     \
-	frameworks/av/media/libstagefright/httplive            \
-	frameworks/av/media/libstagefright/include             \
-	frameworks/av/media/libstagefright/mpeg2ts             \
-	frameworks/av/media/libstagefright/rtsp                \
-	frameworks/av/media/libstagefright/timedtext           \
-	frameworks/av/media/libmediaplayerservice              \
-	frameworks/native/include/media/openmax
-
-LOCAL_CFLAGS += -Werror -Wall
-
-# enable experiments only in userdebug and eng builds
-ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-LOCAL_CFLAGS += -DENABLE_STAGEFRIGHT_EXPERIMENTS
-endif
-
-LOCAL_SHARED_LIBRARIES :=       \
-    libbinder                   \
-    libui                       \
-    libgui                      \
-    libmedia                    \
-    libmediadrm                 \
-
-LOCAL_MODULE:= libstagefright_nuplayer
-
-LOCAL_MODULE_TAGS := eng
-
-LOCAL_SANITIZE := cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index aa21fff..a3f4efb 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -23,17 +23,21 @@
 #include "AnotherPacketSource.h"
 #include <binder/IServiceManager.h>
 #include <cutils/properties.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
 #include <media/IMediaExtractorService.h>
 #include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
 #include <media/stagefright/FileSource.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaClock.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 #include "../../libstagefright/include/NuCachedSource2.h"
@@ -41,22 +45,26 @@
 
 namespace android {
 
-static const int kLowWaterMarkMs          = 2000;  // 2secs
-static const int kHighWaterMarkMs         = 5000;  // 5secs
-static const int kHighWaterMarkRebufferMs = 15000;  // 15secs
+static const int kInitialMarkMs        = 5000;  // 5secs
 
-static const int kLowWaterMarkKB  = 40;
-static const int kHighWaterMarkKB = 200;
+//static const int kPausePlaybackMarkMs  = 2000;  // 2secs
+static const int kResumePlaybackMarkMs = 15000;  // 15secs
 
 NuPlayer::GenericSource::GenericSource(
         const sp<AMessage> &notify,
         bool uidValid,
-        uid_t uid)
+        uid_t uid,
+        const sp<MediaClock> &mediaClock)
     : Source(notify),
       mAudioTimeUs(0),
       mAudioLastDequeueTimeUs(0),
       mVideoTimeUs(0),
       mVideoLastDequeueTimeUs(0),
+      mPrevBufferPercentage(-1),
+      mPollBufferingGeneration(0),
+      mSentPauseOnBuffering(false),
+      mAudioDataGeneration(0),
+      mVideoDataGeneration(0),
       mFetchSubtitleDataGeneration(0),
       mFetchTimedTextDataGeneration(0),
       mDurationUs(-1ll),
@@ -65,12 +73,15 @@
       mIsStreaming(false),
       mUIDValid(uidValid),
       mUID(uid),
+      mMediaClock(mediaClock),
       mFd(-1),
       mBitrate(-1ll),
       mPendingReadBufferTypes(0) {
     ALOGV("GenericSource");
+    CHECK(mediaClock != NULL);
 
-    mBufferingMonitor = new BufferingMonitor(notify);
+    mBufferingSettings.mInitialMarkMs = kInitialMarkMs;
+    mBufferingSettings.mResumePlaybackMarkMs = kResumePlaybackMarkMs;
     resetDataSource();
 }
 
@@ -79,6 +90,7 @@
 
     mHTTPService.clear();
     mHttpSource.clear();
+    mDisconnected = false;
     mUri.clear();
     mUriHeaders.clear();
     if (mFd >= 0) {
@@ -88,14 +100,7 @@
     mOffset = 0;
     mLength = 0;
     mStarted = false;
-    mStopRead = true;
-
-    if (mBufferingMonitorLooper != NULL) {
-        mBufferingMonitorLooper->unregisterHandler(mBufferingMonitor->id());
-        mBufferingMonitorLooper->stop();
-        mBufferingMonitorLooper = NULL;
-    }
-    mBufferingMonitor->stop();
+    mPreparing = false;
 
     mIsDrmProtected = false;
     mIsDrmReleased = false;
@@ -107,6 +112,7 @@
         const sp<IMediaHTTPService> &httpService,
         const char *url,
         const KeyedVector<String8, String8> *headers) {
+    Mutex::Autolock _l(mLock);
     ALOGV("setDataSource url: %s", url);
 
     resetDataSource();
@@ -125,6 +131,7 @@
 
 status_t NuPlayer::GenericSource::setDataSource(
         int fd, int64_t offset, int64_t length) {
+    Mutex::Autolock _l(mLock);
     ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length);
 
     resetDataSource();
@@ -139,6 +146,7 @@
 }
 
 status_t NuPlayer::GenericSource::setDataSource(const sp<DataSource>& source) {
+    Mutex::Autolock _l(mLock);
     ALOGV("setDataSource (source: %p)", source.get());
 
     resetDataSource();
@@ -147,21 +155,34 @@
 }
 
 sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
+    Mutex::Autolock _l(mLock);
     return mFileMeta;
 }
 
 status_t NuPlayer::GenericSource::initFromDataSource() {
     sp<IMediaExtractor> extractor;
     CHECK(mDataSource != NULL);
+    sp<DataSource> dataSource = mDataSource;
 
-    extractor = MediaExtractor::Create(mDataSource, NULL);
+    mLock.unlock();
+    // This might take long time if data source is not reliable.
+    extractor = MediaExtractorFactory::Create(dataSource, NULL);
 
     if (extractor == NULL) {
         ALOGE("initFromDataSource, cannot create extractor!");
         return UNKNOWN_ERROR;
     }
 
-    mFileMeta = extractor->getMetaData();
+    sp<MetaData> fileMeta = extractor->getMetaData();
+
+    size_t numtracks = extractor->countTracks();
+    if (numtracks == 0) {
+        ALOGE("initFromDataSource, source has no track!");
+        return UNKNOWN_ERROR;
+    }
+
+    mLock.lock();
+    mFileMeta = fileMeta;
     if (mFileMeta != NULL) {
         int64_t duration;
         if (mFileMeta->findInt64(kKeyDuration, &duration)) {
@@ -171,12 +192,6 @@
 
     int32_t totalBitrate = 0;
 
-    size_t numtracks = extractor->countTracks();
-    if (numtracks == 0) {
-        ALOGE("initFromDataSource, source has no track!");
-        return UNKNOWN_ERROR;
-    }
-
     mMimes.clear();
 
     for (size_t i = 0; i < numtracks; ++i) {
@@ -259,14 +274,23 @@
     return OK;
 }
 
-status_t NuPlayer::GenericSource::getDefaultBufferingSettings(
+status_t NuPlayer::GenericSource::getBufferingSettings(
         BufferingSettings* buffering /* nonnull */) {
-    mBufferingMonitor->getDefaultBufferingSettings(buffering);
+    {
+        Mutex::Autolock _l(mLock);
+        *buffering = mBufferingSettings;
+    }
+
+    ALOGV("getBufferingSettings{%s}", buffering->toString().string());
     return OK;
 }
 
 status_t NuPlayer::GenericSource::setBufferingSettings(const BufferingSettings& buffering) {
-    return mBufferingMonitor->setBufferingSettings(buffering);
+    ALOGV("setBufferingSettings{%s}", buffering.toString().string());
+
+    Mutex::Autolock _l(mLock);
+    mBufferingSettings = buffering;
+    return OK;
 }
 
 status_t NuPlayer::GenericSource::startSources() {
@@ -302,6 +326,7 @@
 
 status_t NuPlayer::GenericSource::setBuffers(
         bool audio, Vector<MediaBuffer *> &buffers) {
+    Mutex::Autolock _l(mLock);
     if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
         return mVideoTrack.mSource->setBuffers(buffers);
     }
@@ -309,13 +334,10 @@
 }
 
 bool NuPlayer::GenericSource::isStreaming() const {
+    Mutex::Autolock _l(mLock);
     return mIsStreaming;
 }
 
-void NuPlayer::GenericSource::setOffloadAudio(bool offload) {
-    mBufferingMonitor->setOffloadAudio(offload);
-}
-
 NuPlayer::GenericSource::~GenericSource() {
     ALOGV("~GenericSource");
     if (mLooper != NULL) {
@@ -326,6 +348,7 @@
 }
 
 void NuPlayer::GenericSource::prepareAsync() {
+    Mutex::Autolock _l(mLock);
     ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
 
     if (mLooper == NULL) {
@@ -354,7 +377,7 @@
             String8 contentType;
 
             if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
-                mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
+                mHttpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService);
                 if (mHttpSource == NULL) {
                     ALOGE("Failed to create http source!");
                     notifyPreparedAndCleanup(UNKNOWN_ERROR);
@@ -362,9 +385,15 @@
                 }
             }
 
-            mDataSource = DataSource::CreateFromURI(
+            mLock.unlock();
+            // This might take long time if connection has some issue.
+            sp<DataSource> dataSource = DataSourceFactory::CreateFromURI(
                    mHTTPService, uri, &mUriHeaders, &contentType,
                    static_cast<HTTPBase *>(mHttpSource.get()));
+            mLock.lock();
+            if (!mDisconnected) {
+                mDataSource = dataSource;
+            }
         } else {
             if (property_get_bool("media.stagefright.extractremote", true) &&
                     !FileSource::requiresDrm(mFd, mOffset, mLength, nullptr /* mime */)) {
@@ -379,7 +408,7 @@
                     ALOGV("IDataSource(FileSource): %p %d %lld %lld",
                             source.get(), mFd, (long long)mOffset, (long long)mLength);
                     if (source.get() != nullptr) {
-                        mDataSource = DataSource::CreateFromIDataSource(source);
+                        mDataSource = CreateDataSourceFromIDataSource(source);
                         if (mDataSource != nullptr) {
                             // Close the local file descriptor as it is not needed anymore.
                             close(mFd);
@@ -397,7 +426,7 @@
                 mDataSource = new FileSource(mFd, mOffset, mLength);
             }
             // TODO: close should always be done on mFd, see the lines following
-            // DataSource::CreateFromIDataSource above,
+            // CreateDataSourceFromIDataSource above,
             // and the FileSource constructor should dup the mFd argument as needed.
             mFd = -1;
         }
@@ -427,7 +456,7 @@
     }
 
     if (mVideoTrack.mSource != NULL) {
-        sp<MetaData> meta = doGetFormatMeta(false /* audio */);
+        sp<MetaData> meta = getFormatMeta_l(false /* audio */);
         sp<AMessage> msg = new AMessage;
         err = convertMetaDataToMessage(meta, &msg);
         if(err != OK) {
@@ -461,47 +490,39 @@
     }
 
     if (mIsStreaming) {
-        if (mBufferingMonitorLooper == NULL) {
-            mBufferingMonitor->prepare(mCachedSource, mDurationUs, mBitrate,
-                    mIsStreaming);
-
-            mBufferingMonitorLooper = new ALooper;
-            mBufferingMonitorLooper->setName("GSBMonitor");
-            mBufferingMonitorLooper->start();
-            mBufferingMonitorLooper->registerHandler(mBufferingMonitor);
-        }
-
-        mBufferingMonitor->ensureCacheIsFetching();
-        mBufferingMonitor->restartPollBuffering();
+        mCachedSource->resumeFetchingIfNecessary();
+        mPreparing = true;
+        schedulePollBuffering();
     } else {
         notifyPrepared();
     }
+
+    if (mAudioTrack.mSource != NULL) {
+        postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
+    }
+
+    if (mVideoTrack.mSource != NULL) {
+        postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
+    }
 }
 
 void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
     if (err != OK) {
-        {
-            sp<DataSource> dataSource = mDataSource;
-            sp<NuCachedSource2> cachedSource = mCachedSource;
-            sp<DataSource> httpSource = mHttpSource;
-            {
-                Mutex::Autolock _l(mDisconnectLock);
-                mDataSource.clear();
-                mCachedSource.clear();
-                mHttpSource.clear();
-            }
-        }
-        mBitrate = -1;
+        mDataSource.clear();
+        mCachedSource.clear();
+        mHttpSource.clear();
 
-        mBufferingMonitor->cancelPollBuffering();
+        mBitrate = -1;
+        mPrevBufferPercentage = -1;
+        ++mPollBufferingGeneration;
     }
     notifyPrepared(err);
 }
 
 void NuPlayer::GenericSource::start() {
+    Mutex::Autolock _l(mLock);
     ALOGI("start");
 
-    mStopRead = false;
     if (mAudioTrack.mSource != NULL) {
         postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
     }
@@ -511,30 +532,30 @@
     }
 
     mStarted = true;
-
-    (new AMessage(kWhatStart, this))->post();
 }
 
 void NuPlayer::GenericSource::stop() {
+    Mutex::Autolock _l(mLock);
     mStarted = false;
 }
 
 void NuPlayer::GenericSource::pause() {
+    Mutex::Autolock _l(mLock);
     mStarted = false;
 }
 
 void NuPlayer::GenericSource::resume() {
+    Mutex::Autolock _l(mLock);
     mStarted = true;
-
-    (new AMessage(kWhatResume, this))->post();
 }
 
 void NuPlayer::GenericSource::disconnect() {
     sp<DataSource> dataSource, httpSource;
     {
-        Mutex::Autolock _l(mDisconnectLock);
+        Mutex::Autolock _l(mLock);
         dataSource = mDataSource;
         httpSource = mHttpSource;
+        mDisconnected = true;
     }
 
     if (dataSource != NULL) {
@@ -551,7 +572,24 @@
     return OK;
 }
 
+void NuPlayer::GenericSource::sendCacheStats() {
+    int32_t kbps = 0;
+    status_t err = UNKNOWN_ERROR;
+
+    if (mCachedSource != NULL) {
+        err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
+    }
+
+    if (err == OK) {
+        sp<AMessage> notify = dupNotify();
+        notify->setInt32("what", kWhatCacheStats);
+        notify->setInt32("bandwidth", kbps);
+        notify->post();
+    }
+}
+
 void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
+    Mutex::Autolock _l(mLock);
     switch (msg->what()) {
       case kWhatPrepareAsync:
       {
@@ -620,6 +658,8 @@
           track->mSource = source;
           track->mSource->start();
           track->mIndex = trackIndex;
+          ++mAudioDataGeneration;
+          ++mVideoDataGeneration;
 
           int64_t timeUs, actualTimeUs;
           const bool formatChange = true;
@@ -637,37 +677,6 @@
           break;
       }
 
-      case kWhatStart:
-      case kWhatResume:
-      {
-          mBufferingMonitor->restartPollBuffering();
-          break;
-      }
-
-      case kWhatGetFormat:
-      {
-          onGetFormatMeta(msg);
-          break;
-      }
-
-      case kWhatGetSelectedTrack:
-      {
-          onGetSelectedTrack(msg);
-          break;
-      }
-
-      case kWhatGetTrackInfo:
-      {
-          onGetTrackInfo(msg);
-          break;
-      }
-
-      case kWhatSelectTrack:
-      {
-          onSelectTrack(msg);
-          break;
-      }
-
       case kWhatSeek:
       {
           onSeek(msg);
@@ -680,25 +689,13 @@
           break;
       }
 
-      case kWhatPrepareDrm:
+      case kWhatPollBuffering:
       {
-          status_t status = onPrepareDrm(msg);
-          sp<AMessage> response = new AMessage;
-          response->setInt32("status", status);
-          sp<AReplyToken> replyID;
-          CHECK(msg->senderAwaitsResponse(&replyID));
-          response->postReply(replyID);
-          break;
-      }
-
-      case kWhatReleaseDrm:
-      {
-          status_t status = onReleaseDrm();
-          sp<AMessage> response = new AMessage;
-          response->setInt32("status", status);
-          sp<AReplyToken> replyID;
-          CHECK(msg->senderAwaitsResponse(&replyID));
-          response->postReply(replyID);
+          int32_t generation;
+          CHECK(msg->findInt32("generation", &generation));
+          if (generation == mPollBufferingGeneration) {
+              onPollBuffering();
+          }
           break;
       }
 
@@ -729,17 +726,20 @@
     int64_t timeUs;
     CHECK(msg->findInt64("timeUs", &timeUs));
 
-    int64_t subTimeUs;
+    int64_t subTimeUs = 0;
     readBuffer(type, timeUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, &subTimeUs);
 
-    int64_t delayUs = subTimeUs - timeUs;
+    status_t eosResult;
+    if (!packets->hasBufferAvailable(&eosResult)) {
+        return;
+    }
+
     if (msg->what() == kWhatFetchSubtitleData) {
-        const int64_t oneSecUs = 1000000ll;
-        delayUs -= oneSecUs;
+        subTimeUs -= 1000000ll;  // send subtile data one second earlier
     }
     sp<AMessage> msg2 = new AMessage(sendWhat, this);
     msg2->setInt32("generation", msgGeneration);
-    msg2->post(delayUs < 0 ? 0 : delayUs);
+    mMediaClock->addTimer(msg2, subTimeUs);
 }
 
 void NuPlayer::GenericSource::sendTextData(
@@ -771,8 +771,10 @@
         notify->setBuffer("buffer", buffer);
         notify->post();
 
-        const int64_t delayUs = nextSubTimeUs - subTimeUs;
-        msg->post(delayUs < 0 ? 0 : delayUs);
+        if (msg->what() == kWhatSendSubtitleData) {
+            nextSubTimeUs -= 1000000ll;  // send subtile data one second earlier
+        }
+        mMediaClock->addTimer(msg, nextSubTimeUs);
     }
 }
 
@@ -808,34 +810,11 @@
 }
 
 sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
-    sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
-    msg->setInt32("audio", audio);
-
-    sp<AMessage> response;
-    sp<RefBase> format;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findObject("format", &format));
-        return static_cast<MetaData*>(format.get());
-    } else {
-        return NULL;
-    }
+    Mutex::Autolock _l(mLock);
+    return getFormatMeta_l(audio);
 }
 
-void NuPlayer::GenericSource::onGetFormatMeta(const sp<AMessage>& msg) const {
-    int32_t audio;
-    CHECK(msg->findInt32("audio", &audio));
-
-    sp<AMessage> response = new AMessage;
-    sp<MetaData> format = doGetFormatMeta(audio);
-    response->setObject("format", format);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
+sp<MetaData> NuPlayer::GenericSource::getFormatMeta_l(bool audio) {
     sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
 
     if (source == NULL) {
@@ -847,10 +826,7 @@
 
 status_t NuPlayer::GenericSource::dequeueAccessUnit(
         bool audio, sp<ABuffer> *accessUnit) {
-    if (audio && !mStarted) {
-        return -EWOULDBLOCK;
-    }
-
+    Mutex::Autolock _l(mLock);
     // If has gone through stop/releaseDrm sequence, we no longer send down any buffer b/c
     // the codec's crypto object has gone away (b/37960096).
     // Note: This will be unnecessary when stop() changes behavior and releases codec (b/35248283).
@@ -876,10 +852,32 @@
 
     status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
 
-    // start pulling in more buffers if we only have one (or no) buffer left
+    // start pulling in more buffers if cache is running low
     // so that decoder has less chance of being starved
-    if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
-        postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+    if (!mIsStreaming) {
+        if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
+            postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+        }
+    } else {
+        int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
+        // TODO: maxRebufferingMarkMs could be larger than
+        // mBufferingSettings.mResumePlaybackMarkMs
+        int64_t restartBufferingMarkUs =
+             mBufferingSettings.mResumePlaybackMarkMs * 1000ll / 2;
+        if (finalResult == OK) {
+            if (durationUs < restartBufferingMarkUs) {
+                postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+            }
+            if (track->mPackets->getAvailableBufferCount(&finalResult) < 2
+                && !mSentPauseOnBuffering && !mPreparing) {
+                mCachedSource->resumeFetchingIfNecessary();
+                sendCacheStats();
+                mSentPauseOnBuffering = true;
+                sp<AMessage> notify = dupNotify();
+                notify->setInt32("what", kWhatPauseOnBufferingStart);
+                notify->post();
+            }
+        }
     }
 
     if (result != OK) {
@@ -899,7 +897,6 @@
     CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
     if (audio) {
         mAudioLastDequeueTimeUs = timeUs;
-        mBufferingMonitor->updateDequeuedBufferTime(timeUs);
     } else {
         mVideoLastDequeueTimeUs = timeUs;
     }
@@ -924,43 +921,18 @@
 }
 
 status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
+    Mutex::Autolock _l(mLock);
     *durationUs = mDurationUs;
     return OK;
 }
 
 size_t NuPlayer::GenericSource::getTrackCount() const {
+    Mutex::Autolock _l(mLock);
     return mSources.size();
 }
 
 sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
-    sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, this);
-    msg->setSize("trackIndex", trackIndex);
-
-    sp<AMessage> response;
-    sp<RefBase> format;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findObject("format", &format));
-        return static_cast<AMessage*>(format.get());
-    } else {
-        return NULL;
-    }
-}
-
-void NuPlayer::GenericSource::onGetTrackInfo(const sp<AMessage>& msg) const {
-    size_t trackIndex;
-    CHECK(msg->findSize("trackIndex", &trackIndex));
-
-    sp<AMessage> response = new AMessage;
-    sp<AMessage> format = doGetTrackInfo(trackIndex);
-    response->setObject("format", format);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-sp<AMessage> NuPlayer::GenericSource::doGetTrackInfo(size_t trackIndex) const {
+    Mutex::Autolock _l(mLock);
     size_t trackCount = mSources.size();
     if (trackIndex >= trackCount) {
         return NULL;
@@ -1010,35 +982,7 @@
 }
 
 ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
-    sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
-    msg->setInt32("type", type);
-
-    sp<AMessage> response;
-    int32_t index;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findInt32("index", &index));
-        return index;
-    } else {
-        return -1;
-    }
-}
-
-void NuPlayer::GenericSource::onGetSelectedTrack(const sp<AMessage>& msg) const {
-    int32_t tmpType;
-    CHECK(msg->findInt32("type", &tmpType));
-    media_track_type type = (media_track_type)tmpType;
-
-    sp<AMessage> response = new AMessage;
-    ssize_t index = doGetSelectedTrack(type);
-    response->setInt32("index", index);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
+    Mutex::Autolock _l(mLock);
     const Track *track = NULL;
     switch (type) {
     case MEDIA_TRACK_TYPE_VIDEO:
@@ -1065,38 +1009,9 @@
 }
 
 status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
+    Mutex::Autolock _l(mLock);
     ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
-    sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
-    msg->setInt32("trackIndex", trackIndex);
-    msg->setInt32("select", select);
-    msg->setInt64("timeUs", timeUs);
 
-    sp<AMessage> response;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findInt32("err", &err));
-    }
-
-    return err;
-}
-
-void NuPlayer::GenericSource::onSelectTrack(const sp<AMessage>& msg) {
-    int32_t trackIndex, select;
-    int64_t timeUs;
-    CHECK(msg->findInt32("trackIndex", &trackIndex));
-    CHECK(msg->findInt32("select", &select));
-    CHECK(msg->findInt64("timeUs", &timeUs));
-
-    sp<AMessage> response = new AMessage;
-    status_t err = doSelectTrack(trackIndex, select, timeUs);
-    response->setInt32("err", err);
-
-    sp<AReplyToken> replyID;
-    CHECK(msg->senderAwaitsResponse(&replyID));
-    response->postReply(replyID);
-}
-
-status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
     if (trackIndex >= mSources.size()) {
         return BAD_INDEX;
     }
@@ -1188,10 +1103,14 @@
 }
 
 status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
+    ALOGV("seekTo: %lld, %d", (long long)seekTimeUs, mode);
     sp<AMessage> msg = new AMessage(kWhatSeek, this);
     msg->setInt64("seekTimeUs", seekTimeUs);
     msg->setInt32("mode", mode);
 
+    // Need to call readBuffer on |mLooper| to ensure the calls to
+    // IMediaSource::read* are serialized. Note that IMediaSource::read*
+    // is called without |mLock| acquired and MediaSource is not thread safe.
     sp<AMessage> response;
     status_t err = msg->postAndAwaitResponse(&response);
     if (err == OK && response != NULL) {
@@ -1217,17 +1136,9 @@
 }
 
 status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
-    mBufferingMonitor->updateDequeuedBufferTime(-1ll);
-
-    // If the Widevine source is stopped, do not attempt to read any
-    // more buffers.
-    //
-    // TODO: revisit after widevine is removed.  May be able to
-    // combine mStopRead with mStarted.
-    if (mStopRead) {
-        return INVALID_OPERATION;
-    }
     if (mVideoTrack.mSource != NULL) {
+        ++mVideoDataGeneration;
+
         int64_t actualTimeUs;
         readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs);
 
@@ -1238,7 +1149,8 @@
     }
 
     if (mAudioTrack.mSource != NULL) {
-        readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
+        ++mAudioDataGeneration;
+        readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs, MediaPlayerSeekMode::SEEK_CLOSEST);
         mAudioLastDequeueTimeUs = seekTimeUs;
     }
 
@@ -1252,12 +1164,8 @@
         mFetchTimedTextDataGeneration++;
     }
 
-    // If currently buffering, post kWhatBufferingEnd first, so that
-    // NuPlayer resumes. Otherwise, if cache hits high watermark
-    // before new polling happens, no one will resume the playback.
-    mBufferingMonitor->stopBufferingIfNecessary();
-    mBufferingMonitor->restartPollBuffering();
-
+    ++mPollBufferingGeneration;
+    schedulePollBuffering();
     return OK;
 }
 
@@ -1360,9 +1268,29 @@
     return ab;
 }
 
-void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
-    Mutex::Autolock _l(mReadBufferLock);
+int32_t NuPlayer::GenericSource::getDataGeneration(media_track_type type) const {
+    int32_t generation = -1;
+    switch (type) {
+    case MEDIA_TRACK_TYPE_VIDEO:
+        generation = mVideoDataGeneration;
+        break;
+    case MEDIA_TRACK_TYPE_AUDIO:
+        generation = mAudioDataGeneration;
+        break;
+    case MEDIA_TRACK_TYPE_TIMEDTEXT:
+        generation = mFetchTimedTextDataGeneration;
+        break;
+    case MEDIA_TRACK_TYPE_SUBTITLE:
+        generation = mFetchSubtitleDataGeneration;
+        break;
+    default:
+        break;
+    }
 
+    return generation;
+}
+
+void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
     if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
         mPendingReadBufferTypes |= (1 << trackType);
         sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
@@ -1375,25 +1303,13 @@
     int32_t tmpType;
     CHECK(msg->findInt32("trackType", &tmpType));
     media_track_type trackType = (media_track_type)tmpType;
+    mPendingReadBufferTypes &= ~(1 << trackType);
     readBuffer(trackType);
-    {
-        // only protect the variable change, as readBuffer may
-        // take considerable time.
-        Mutex::Autolock _l(mReadBufferLock);
-        mPendingReadBufferTypes &= ~(1 << trackType);
-    }
 }
 
 void NuPlayer::GenericSource::readBuffer(
         media_track_type trackType, int64_t seekTimeUs, MediaPlayerSeekMode mode,
         int64_t *actualTimeUs, bool formatChange) {
-    // Do not read data if Widevine source is stopped
-    //
-    // TODO: revisit after widevine is removed.  May be able to
-    // combine mStopRead with mStarted.
-    if (mStopRead) {
-        return;
-    }
     Track *track;
     size_t maxBuffers = 1;
     switch (trackType) {
@@ -1437,25 +1353,38 @@
         options.setNonBlocking();
     }
 
+    int32_t generation = getDataGeneration(trackType);
     for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
         Vector<MediaBuffer *> mediaBuffers;
         status_t err = NO_ERROR;
 
+        sp<IMediaSource> source = track->mSource;
+        mLock.unlock();
         if (couldReadMultiple) {
-            err = track->mSource->readMultiple(
+            err = source->readMultiple(
                     &mediaBuffers, maxBuffers - numBuffers, &options);
         } else {
             MediaBuffer *mbuf = NULL;
-            err = track->mSource->read(&mbuf, &options);
+            err = source->read(&mbuf, &options);
             if (err == OK && mbuf != NULL) {
                 mediaBuffers.push_back(mbuf);
             }
         }
+        mLock.lock();
 
         options.clearNonPersistent();
 
         size_t id = 0;
         size_t count = mediaBuffers.size();
+
+        // in case track has been changed since we don't have lock for some time.
+        if (generation != getDataGeneration(trackType)) {
+            for (; id < count; ++id) {
+                mediaBuffers[id]->release();
+            }
+            break;
+        }
+
         for (; id < count; ++id) {
             int64_t timeUs;
             MediaBuffer *mbuf = mediaBuffers[id];
@@ -1466,10 +1395,8 @@
             }
             if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
                 mAudioTimeUs = timeUs;
-                mBufferingMonitor->updateQueuedTime(true /* isAudio */, timeUs);
             } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
                 mVideoTimeUs = timeUs;
-                mBufferingMonitor->updateQueuedTime(false /* isAudio */, timeUs);
             }
 
             queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
@@ -1516,6 +1443,41 @@
             break;
         }
     }
+
+    if (mIsStreaming
+        && (trackType == MEDIA_TRACK_TYPE_VIDEO || trackType == MEDIA_TRACK_TYPE_AUDIO)) {
+        status_t finalResult;
+        int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
+
+        // TODO: maxRebufferingMarkMs could be larger than
+        // mBufferingSettings.mResumePlaybackMarkMs
+        int64_t markUs = (mPreparing ? mBufferingSettings.mInitialMarkMs
+            : mBufferingSettings.mResumePlaybackMarkMs) * 1000ll;
+        if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
+            if (mPreparing || mSentPauseOnBuffering) {
+                Track *counterTrack =
+                    (trackType == MEDIA_TRACK_TYPE_VIDEO ? &mAudioTrack : &mVideoTrack);
+                if (counterTrack->mSource != NULL) {
+                    durationUs = counterTrack->mPackets->getBufferedDurationUs(&finalResult);
+                }
+                if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
+                    if (mPreparing) {
+                        notifyPrepared();
+                        mPreparing = false;
+                    } else {
+                        sendCacheStats();
+                        mSentPauseOnBuffering = false;
+                        sp<AMessage> notify = dupNotify();
+                        notify->setInt32("what", kWhatResumeOnBufferingEnd);
+                        notify->post();
+                    }
+                }
+            }
+            return;
+        }
+
+        postReadBuffer(trackType);
+    }
 }
 
 void NuPlayer::GenericSource::queueDiscontinuityIfNeeded(
@@ -1533,160 +1495,7 @@
     }
 }
 
-NuPlayer::GenericSource::BufferingMonitor::BufferingMonitor(const sp<AMessage> &notify)
-    : mNotify(notify),
-      mDurationUs(-1ll),
-      mBitrate(-1ll),
-      mIsStreaming(false),
-      mAudioTimeUs(0),
-      mVideoTimeUs(0),
-      mPollBufferingGeneration(0),
-      mPrepareBuffering(false),
-      mBuffering(false),
-      mPrevBufferPercentage(-1),
-      mOffloadAudio(false),
-      mFirstDequeuedBufferRealUs(-1ll),
-      mFirstDequeuedBufferMediaUs(-1ll),
-      mlastDequeuedBufferMediaUs(-1ll) {
-      getDefaultBufferingSettings(&mSettings);
-}
-
-NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() {
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::getDefaultBufferingSettings(
-        BufferingSettings *buffering /* nonnull */) {
-    buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
-    buffering->mRebufferingMode = BUFFERING_MODE_TIME_THEN_SIZE;
-    buffering->mInitialWatermarkMs = kHighWaterMarkMs;
-    buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs;
-    buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs;
-    buffering->mRebufferingWatermarkLowKB = kLowWaterMarkKB;
-    buffering->mRebufferingWatermarkHighKB = kHighWaterMarkKB;
-
-    ALOGV("BufferingMonitor::getDefaultBufferingSettings{%s}",
-            buffering->toString().string());
-}
-
-status_t NuPlayer::GenericSource::BufferingMonitor::setBufferingSettings(
-        const BufferingSettings &buffering) {
-    ALOGV("BufferingMonitor::setBufferingSettings{%s}",
-            buffering.toString().string());
-
-    Mutex::Autolock _l(mLock);
-    if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
-            || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
-                && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)
-            || (buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
-                && buffering.mRebufferingWatermarkLowKB > buffering.mRebufferingWatermarkHighKB)) {
-        return BAD_VALUE;
-    }
-    mSettings = buffering;
-    if (mSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
-        mSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
-    }
-    if (!mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
-        mSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
-        mSettings.mRebufferingWatermarkHighMs = INT32_MAX;
-    }
-    if (!mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
-        mSettings.mRebufferingWatermarkLowKB = BufferingSettings::kNoWatermark;
-        mSettings.mRebufferingWatermarkHighKB = INT32_MAX;
-    }
-    return OK;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::prepare(
-        const sp<NuCachedSource2> &cachedSource,
-        int64_t durationUs,
-        int64_t bitrate,
-        bool isStreaming) {
-    Mutex::Autolock _l(mLock);
-    prepare_l(cachedSource, durationUs, bitrate, isStreaming);
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stop() {
-    Mutex::Autolock _l(mLock);
-    prepare_l(NULL /* cachedSource */, -1 /* durationUs */,
-            -1 /* bitrate */, false /* isStreaming */);
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering() {
-    Mutex::Autolock _l(mLock);
-    cancelPollBuffering_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::restartPollBuffering() {
-    Mutex::Autolock _l(mLock);
-    if (mIsStreaming) {
-        cancelPollBuffering_l();
-        onPollBuffering_l();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary() {
-    Mutex::Autolock _l(mLock);
-    stopBufferingIfNecessary_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching() {
-    Mutex::Autolock _l(mLock);
-    ensureCacheIsFetching_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::updateQueuedTime(bool isAudio, int64_t timeUs) {
-    Mutex::Autolock _l(mLock);
-    if (isAudio) {
-        mAudioTimeUs = timeUs;
-    } else {
-        mVideoTimeUs = timeUs;
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::setOffloadAudio(bool offload) {
-    Mutex::Autolock _l(mLock);
-    mOffloadAudio = offload;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::updateDequeuedBufferTime(int64_t mediaUs) {
-    Mutex::Autolock _l(mLock);
-    if (mediaUs < 0) {
-        mFirstDequeuedBufferRealUs = -1ll;
-        mFirstDequeuedBufferMediaUs = -1ll;
-    } else if (mFirstDequeuedBufferRealUs < 0) {
-        mFirstDequeuedBufferRealUs = ALooper::GetNowUs();
-        mFirstDequeuedBufferMediaUs = mediaUs;
-    }
-    mlastDequeuedBufferMediaUs = mediaUs;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::prepare_l(
-        const sp<NuCachedSource2> &cachedSource,
-        int64_t durationUs,
-        int64_t bitrate,
-        bool isStreaming) {
-
-    mCachedSource = cachedSource;
-    mDurationUs = durationUs;
-    mBitrate = bitrate;
-    mIsStreaming = isStreaming;
-    mAudioTimeUs = 0;
-    mVideoTimeUs = 0;
-    mPrepareBuffering = (cachedSource != NULL);
-    cancelPollBuffering_l();
-    mOffloadAudio = false;
-    mFirstDequeuedBufferRealUs = -1ll;
-    mFirstDequeuedBufferMediaUs = -1ll;
-    mlastDequeuedBufferMediaUs = -1ll;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering_l() {
-    mBuffering = false;
-    ++mPollBufferingGeneration;
-    mPrevBufferPercentage = -1;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::notifyBufferingUpdate_l(int32_t percentage) {
+void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) {
     // Buffering percent could go backward as it's estimated from remaining
     // data and last access time. This could cause the buffering position
     // drawn on media control to jitter slightly. Remember previously reported
@@ -1699,106 +1508,28 @@
 
     mPrevBufferPercentage = percentage;
 
-    ALOGV("notifyBufferingUpdate_l: buffering %d%%", percentage);
+    ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
 
-    sp<AMessage> msg = mNotify->dup();
-    msg->setInt32("what", kWhatBufferingUpdate);
-    msg->setInt32("percentage", percentage);
-    msg->post();
+    sp<AMessage> notify = dupNotify();
+    notify->setInt32("what", kWhatBufferingUpdate);
+    notify->setInt32("percentage", percentage);
+    notify->post();
 }
 
-void NuPlayer::GenericSource::BufferingMonitor::startBufferingIfNecessary_l() {
-    if (mPrepareBuffering) {
-        return;
-    }
-
-    if (!mBuffering) {
-        ALOGD("startBufferingIfNecessary_l");
-
-        mBuffering = true;
-
-        ensureCacheIsFetching_l();
-        sendCacheStats_l();
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatPauseOnBufferingStart);
-        notify->post();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary_l() {
-    if (mPrepareBuffering) {
-        ALOGD("stopBufferingIfNecessary_l, mBuffering=%d", mBuffering);
-
-        mPrepareBuffering = false;
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatPrepared);
-        notify->setInt32("err", OK);
-        notify->post();
-
-        return;
-    }
-
-    if (mBuffering) {
-        ALOGD("stopBufferingIfNecessary_l");
-        mBuffering = false;
-
-        sendCacheStats_l();
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatResumeOnBufferingEnd);
-        notify->post();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::sendCacheStats_l() {
-    int32_t kbps = 0;
-    status_t err = UNKNOWN_ERROR;
-
-    if (mCachedSource != NULL) {
-        err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
-    }
-
-    if (err == OK) {
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatCacheStats);
-        notify->setInt32("bandwidth", kbps);
-        notify->post();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching_l() {
-    if (mCachedSource != NULL) {
-        mCachedSource->resumeFetchingIfNecessary();
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::schedulePollBuffering_l() {
+void NuPlayer::GenericSource::schedulePollBuffering() {
     sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
     msg->setInt32("generation", mPollBufferingGeneration);
     // Enquires buffering status every second.
     msg->post(1000000ll);
 }
 
-int64_t NuPlayer::GenericSource::BufferingMonitor::getLastReadPosition_l() {
-    if (mAudioTimeUs > 0) {
-        return mAudioTimeUs;
-    } else if (mVideoTimeUs > 0) {
-        return mVideoTimeUs;
-    } else {
-        return 0;
-    }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() {
+void NuPlayer::GenericSource::onPollBuffering() {
     status_t finalStatus = UNKNOWN_ERROR;
     int64_t cachedDurationUs = -1ll;
     ssize_t cachedDataRemaining = -1;
 
     if (mCachedSource != NULL) {
-        cachedDataRemaining =
-                mCachedSource->approxDataRemaining(&finalStatus);
+        cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
 
         if (finalStatus == OK) {
             off64_t size;
@@ -1816,157 +1547,49 @@
     }
 
     if (finalStatus != OK) {
-        ALOGV("onPollBuffering_l: EOS (finalStatus = %d)", finalStatus);
+        ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
 
         if (finalStatus == ERROR_END_OF_STREAM) {
-            notifyBufferingUpdate_l(100);
+            notifyBufferingUpdate(100);
         }
 
-        stopBufferingIfNecessary_l();
         return;
     }
 
     if (cachedDurationUs >= 0ll) {
         if (mDurationUs > 0ll) {
-            int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs;
+            int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
             int percentage = 100.0 * cachedPosUs / mDurationUs;
             if (percentage > 100) {
                 percentage = 100;
             }
 
-            notifyBufferingUpdate_l(percentage);
+            notifyBufferingUpdate(percentage);
         }
 
-        ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
-
-        if (mPrepareBuffering) {
-            if (cachedDurationUs > mSettings.mInitialWatermarkMs * 1000) {
-                stopBufferingIfNecessary_l();
-            }
-        } else if (mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
-            if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
-                // Take into account the data cached in downstream components to try to avoid
-                // unnecessary pause.
-                if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) {
-                    int64_t downStreamCacheUs =
-                        mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs
-                            - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs);
-                    if (downStreamCacheUs > 0) {
-                        cachedDurationUs += downStreamCacheUs;
-                    }
-                }
-
-                if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
-                    startBufferingIfNecessary_l();
-                }
-            } else if (cachedDurationUs > mSettings.mRebufferingWatermarkHighMs * 1000) {
-                stopBufferingIfNecessary_l();
-            }
-        }
-    } else if (cachedDataRemaining >= 0
-            && mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
-        ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes",
-                cachedDataRemaining);
-
-        if (cachedDataRemaining < (mSettings.mRebufferingWatermarkLowKB << 10)) {
-            startBufferingIfNecessary_l();
-        } else if (cachedDataRemaining > (mSettings.mRebufferingWatermarkHighKB << 10)) {
-            stopBufferingIfNecessary_l();
-        }
+        ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
     }
 
-    schedulePollBuffering_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-      case kWhatPollBuffering:
-      {
-          int32_t generation;
-          CHECK(msg->findInt32("generation", &generation));
-          Mutex::Autolock _l(mLock);
-          if (generation == mPollBufferingGeneration) {
-              onPollBuffering_l();
-          }
-          break;
-      }
-      default:
-          TRESPASS();
-          break;
-    }
+    schedulePollBuffering();
 }
 
 // Modular DRM
 status_t NuPlayer::GenericSource::prepareDrm(
-        const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto)
-{
+        const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *outCrypto) {
+    Mutex::Autolock _l(mLock);
     ALOGV("prepareDrm");
 
-    sp<AMessage> msg = new AMessage(kWhatPrepareDrm, this);
-    // synchronous call so just passing the address but with local copies of "const" args
-    uint8_t UUID[16];
-    memcpy(UUID, uuid, sizeof(UUID));
-    Vector<uint8_t> sessionId = drmSessionId;
-    msg->setPointer("uuid", (void*)UUID);
-    msg->setPointer("drmSessionId", (void*)&sessionId);
-    msg->setPointer("crypto", (void*)crypto);
-
-    sp<AMessage> response;
-    status_t status = msg->postAndAwaitResponse(&response);
-
-    if (status == OK && response != NULL) {
-        CHECK(response->findInt32("status", &status));
-        ALOGV_IF(status == OK, "prepareDrm: mCrypto: %p (%d)", crypto->get(),
-                (*crypto != NULL ? (*crypto)->getStrongCount() : 0));
-        ALOGD("prepareDrm ret: %d ", status);
-    } else {
-        ALOGE("prepareDrm err: %d", status);
-    }
-
-    return status;
-}
-
-status_t NuPlayer::GenericSource::releaseDrm()
-{
-    ALOGV("releaseDrm");
-
-    sp<AMessage> msg = new AMessage(kWhatReleaseDrm, this);
-
-    // synchronous call to update the source states before the player proceedes with crypto cleanup
-    sp<AMessage> response;
-    status_t status = msg->postAndAwaitResponse(&response);
-
-    if (status == OK && response != NULL) {
-        ALOGD("releaseDrm ret: OK ");
-    } else {
-        ALOGE("releaseDrm err: %d", status);
-    }
-
-    return status;
-}
-
-status_t NuPlayer::GenericSource::onPrepareDrm(const sp<AMessage> &msg)
-{
-    ALOGV("onPrepareDrm ");
-
     mIsDrmProtected = false;
     mIsDrmReleased = false;
     mIsSecure = false;
 
-    uint8_t *uuid;
-    Vector<uint8_t> *drmSessionId;
-    sp<ICrypto> *outCrypto;
-    CHECK(msg->findPointer("uuid", (void**)&uuid));
-    CHECK(msg->findPointer("drmSessionId", (void**)&drmSessionId));
-    CHECK(msg->findPointer("crypto", (void**)&outCrypto));
-
     status_t status = OK;
-    sp<ICrypto> crypto = NuPlayerDrm::createCryptoAndPlugin(uuid, *drmSessionId, status);
+    sp<ICrypto> crypto = NuPlayerDrm::createCryptoAndPlugin(uuid, drmSessionId, status);
     if (crypto == NULL) {
-        ALOGE("onPrepareDrm: createCrypto failed. status: %d", status);
+        ALOGE("prepareDrm: createCrypto failed. status: %d", status);
         return status;
     }
-    ALOGV("onPrepareDrm: createCryptoAndPlugin succeeded for uuid: %s",
+    ALOGV("prepareDrm: createCryptoAndPlugin succeeded for uuid: %s",
             DrmUUID::toHexString(uuid).string());
 
     *outCrypto = crypto;
@@ -1975,14 +1598,14 @@
 
     if (mMimes.size() == 0) {
         status = UNKNOWN_ERROR;
-        ALOGE("onPrepareDrm: Unexpected. Must have at least one track. status: %d", status);
+        ALOGE("prepareDrm: Unexpected. Must have at least one track. status: %d", status);
         return status;
     }
 
     // first mime in this list is either the video track, or the first audio track
     const char *mime = mMimes[0].string();
     mIsSecure = crypto->requiresSecureDecoderComponent(mime);
-    ALOGV("onPrepareDrm: requiresSecureDecoderComponent mime: %s  isSecure: %d",
+    ALOGV("prepareDrm: requiresSecureDecoderComponent mime: %s  isSecure: %d",
             mime, mIsSecure);
 
     // Checking the member flags while in the looper to send out the notification.
@@ -1996,18 +1619,27 @@
             FLAG_CAN_SEEK_FORWARD |
             FLAG_CAN_SEEK);
 
+    if (status == OK) {
+        ALOGV("prepareDrm: mCrypto: %p (%d)", outCrypto->get(),
+                (*outCrypto != NULL ? (*outCrypto)->getStrongCount() : 0));
+        ALOGD("prepareDrm ret: %d ", status);
+    } else {
+        ALOGE("prepareDrm err: %d", status);
+    }
     return status;
 }
 
-status_t NuPlayer::GenericSource::onReleaseDrm()
-{
+status_t NuPlayer::GenericSource::releaseDrm() {
+    Mutex::Autolock _l(mLock);
+    ALOGV("releaseDrm");
+
     if (mIsDrmProtected) {
         mIsDrmProtected = false;
         // to prevent returning any more buffer after stop/releaseDrm (b/37960096)
         mIsDrmReleased = true;
-        ALOGV("onReleaseDrm: mIsDrmProtected is reset.");
+        ALOGV("releaseDrm: mIsDrmProtected is reset.");
     } else {
-        ALOGE("onReleaseDrm: mIsDrmProtected is already false.");
+        ALOGE("releaseDrm: mIsDrmProtected is already false.");
     }
 
     return OK;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 4064133..cb9c27f 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -24,6 +24,7 @@
 #include "ATSParser.h"
 
 #include <media/mediaplayer.h>
+#include <media/stagefright/MediaBuffer.h>
 
 namespace android {
 
@@ -35,12 +36,14 @@
 struct IMediaHTTPService;
 struct MediaSource;
 class MediaBuffer;
+struct MediaClock;
 struct NuCachedSource2;
 
 struct NuPlayer::GenericSource : public NuPlayer::Source,
                                  public MediaBufferObserver // Modular DRM
 {
-    GenericSource(const sp<AMessage> &notify, bool uidValid, uid_t uid);
+    GenericSource(const sp<AMessage> &notify, bool uidValid, uid_t uid,
+                  const sp<MediaClock> &mediaClock);
 
     status_t setDataSource(
             const sp<IMediaHTTPService> &httpService,
@@ -51,7 +54,7 @@
 
     status_t setDataSource(const sp<DataSource>& dataSource);
 
-    virtual status_t getDefaultBufferingSettings(
+    virtual status_t getBufferingSettings(
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
@@ -83,13 +86,11 @@
 
     virtual bool isStreaming() const;
 
-    virtual void setOffloadAudio(bool offload);
-
     // Modular DRM
     virtual void signalBufferReturned(MediaBuffer *buffer);
 
     virtual status_t prepareDrm(
-            const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto);
+            const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *outCrypto);
 
     virtual status_t releaseDrm();
 
@@ -111,17 +112,11 @@
         kWhatSendTimedTextData,
         kWhatChangeAVSource,
         kWhatPollBuffering,
-        kWhatGetFormat,
-        kWhatGetSelectedTrack,
-        kWhatSelectTrack,
         kWhatSeek,
         kWhatReadBuffer,
         kWhatStart,
         kWhatResume,
         kWhatSecureDecodersInstantiated,
-        // Modular DRM
-        kWhatPrepareDrm,
-        kWhatReleaseDrm,
     };
 
     struct Track {
@@ -130,84 +125,6 @@
         sp<AnotherPacketSource> mPackets;
     };
 
-    // Helper to monitor buffering status. The polling happens every second.
-    // When necessary, it will send out buffering events to the player.
-    struct BufferingMonitor : public AHandler {
-    public:
-        explicit BufferingMonitor(const sp<AMessage> &notify);
-
-        void getDefaultBufferingSettings(BufferingSettings *buffering /* nonnull */);
-        status_t setBufferingSettings(const BufferingSettings &buffering);
-
-        // Set up state.
-        void prepare(const sp<NuCachedSource2> &cachedSource,
-                int64_t durationUs,
-                int64_t bitrate,
-                bool isStreaming);
-        // Stop and reset buffering monitor.
-        void stop();
-        // Cancel the current monitor task.
-        void cancelPollBuffering();
-        // Restart the monitor task.
-        void restartPollBuffering();
-        // Stop buffering task and send out corresponding events.
-        void stopBufferingIfNecessary();
-        // Make sure data source is getting data.
-        void ensureCacheIsFetching();
-        // Update media time of just extracted buffer from data source.
-        void updateQueuedTime(bool isAudio, int64_t timeUs);
-
-        // Set the offload mode.
-        void setOffloadAudio(bool offload);
-        // Update media time of last dequeued buffer which is sent to the decoder.
-        void updateDequeuedBufferTime(int64_t mediaUs);
-
-    protected:
-        virtual ~BufferingMonitor();
-        virtual void onMessageReceived(const sp<AMessage> &msg);
-
-    private:
-        enum {
-            kWhatPollBuffering,
-        };
-
-        sp<AMessage> mNotify;
-
-        sp<NuCachedSource2> mCachedSource;
-        int64_t mDurationUs;
-        int64_t mBitrate;
-        bool mIsStreaming;
-
-        int64_t mAudioTimeUs;
-        int64_t mVideoTimeUs;
-        int32_t mPollBufferingGeneration;
-        bool mPrepareBuffering;
-        bool mBuffering;
-        int32_t mPrevBufferPercentage;
-
-        mutable Mutex mLock;
-
-        BufferingSettings mSettings;
-        bool mOffloadAudio;
-        int64_t mFirstDequeuedBufferRealUs;
-        int64_t mFirstDequeuedBufferMediaUs;
-        int64_t mlastDequeuedBufferMediaUs;
-
-        void prepare_l(const sp<NuCachedSource2> &cachedSource,
-                int64_t durationUs,
-                int64_t bitrate,
-                bool isStreaming);
-        void cancelPollBuffering_l();
-        void notifyBufferingUpdate_l(int32_t percentage);
-        void startBufferingIfNecessary_l();
-        void stopBufferingIfNecessary_l();
-        void sendCacheStats_l();
-        void ensureCacheIsFetching_l();
-        int64_t getLastReadPosition_l();
-        void onPollBuffering_l();
-        void schedulePollBuffering_l();
-    };
-
     Vector<sp<IMediaSource> > mSources;
     Track mAudioTrack;
     int64_t mAudioTimeUs;
@@ -218,6 +135,13 @@
     Track mSubtitleTrack;
     Track mTimedTextTrack;
 
+    BufferingSettings mBufferingSettings;
+    int32_t mPrevBufferPercentage;
+    int32_t mPollBufferingGeneration;
+    bool mSentPauseOnBuffering;
+
+    int32_t mAudioDataGeneration;
+    int32_t mVideoDataGeneration;
     int32_t mFetchSubtitleDataGeneration;
     int32_t mFetchTimedTextDataGeneration;
     int64_t mDurationUs;
@@ -227,6 +151,7 @@
     bool mIsStreaming;
     bool mUIDValid;
     uid_t mUID;
+    const sp<MediaClock> mMediaClock;
     sp<IMediaHTTPService> mHTTPService;
     AString mUri;
     KeyedVector<String8, String8> mUriHeaders;
@@ -234,22 +159,20 @@
     int64_t mOffset;
     int64_t mLength;
 
+    bool mDisconnected;
     sp<DataSource> mDataSource;
     sp<NuCachedSource2> mCachedSource;
     sp<DataSource> mHttpSource;
     sp<MetaData> mFileMeta;
     bool mStarted;
-    bool mStopRead;
+    bool mPreparing;
     int64_t mBitrate;
-    sp<BufferingMonitor> mBufferingMonitor;
     uint32_t mPendingReadBufferTypes;
     sp<ABuffer> mGlobalTimedText;
 
-    mutable Mutex mReadBufferLock;
-    mutable Mutex mDisconnectLock;
+    mutable Mutex mLock;
 
     sp<ALooper> mLooper;
-    sp<ALooper> mBufferingMonitorLooper;
 
     void resetDataSource();
 
@@ -261,18 +184,6 @@
     void finishPrepareAsync();
     status_t startSources();
 
-    void onGetFormatMeta(const sp<AMessage>& msg) const;
-    sp<MetaData> doGetFormatMeta(bool audio) const;
-
-    void onGetTrackInfo(const sp<AMessage>& msg) const;
-    sp<AMessage> doGetTrackInfo(size_t trackIndex) const;
-
-    void onGetSelectedTrack(const sp<AMessage>& msg) const;
-    ssize_t doGetSelectedTrack(media_track_type type) const;
-
-    void onSelectTrack(const sp<AMessage>& msg);
-    status_t doSelectTrack(size_t trackIndex, bool select, int64_t timeUs);
-
     void onSeek(const sp<AMessage>& msg);
     status_t doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode);
 
@@ -310,6 +221,15 @@
     void queueDiscontinuityIfNeeded(
             bool seeking, bool formatChange, media_track_type trackType, Track *track);
 
+    void schedulePollBuffering();
+    void onPollBuffering();
+    void notifyBufferingUpdate(int32_t percentage);
+
+    void sendCacheStats();
+
+    sp<MetaData> getFormatMeta_l(bool audio);
+    int32_t getDataGeneration(media_track_type type) const;
+
     // Modular DRM
     // The source is DRM protected and is prepared for DRM.
     bool mIsDrmProtected;
@@ -318,8 +238,6 @@
     Vector<String8> mMimes;
 
     status_t checkDrmInfo();
-    status_t onPrepareDrm(const sp<AMessage> &msg);
-    status_t onReleaseDrm();
 
     DISALLOW_EVIL_CONSTRUCTORS(GenericSource);
 };
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index ad4c223..11f1bfd 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -35,7 +35,6 @@
 // default buffer prepare/ready/underflow marks
 static const int kReadyMarkMs     = 5000;  // 5 seconds
 static const int kPrepareMarkMs   = 1500;  // 1.5 seconds
-static const int kUnderflowMarkMs = 1000;  // 1 second
 
 namespace android {
 
@@ -54,7 +53,8 @@
       mFetchMetaDataGeneration(0),
       mHasMetadata(false),
       mMetadataSelected(false) {
-    getDefaultBufferingSettings(&mBufferingSettings);
+    mBufferingSettings.mInitialMarkMs = kPrepareMarkMs;
+    mBufferingSettings.mResumePlaybackMarkMs = kReadyMarkMs;
     if (headers) {
         mExtraHeaders = *headers;
 
@@ -82,35 +82,16 @@
     }
 }
 
-status_t NuPlayer::HTTPLiveSource::getDefaultBufferingSettings(
+status_t NuPlayer::HTTPLiveSource::getBufferingSettings(
             BufferingSettings* buffering /* nonnull */) {
-    buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
-    buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY;
-    buffering->mInitialWatermarkMs = kPrepareMarkMs;
-    buffering->mRebufferingWatermarkLowMs = kUnderflowMarkMs;
-    buffering->mRebufferingWatermarkHighMs = kReadyMarkMs;
+    *buffering = mBufferingSettings;
 
     return OK;
 }
 
 status_t NuPlayer::HTTPLiveSource::setBufferingSettings(const BufferingSettings& buffering) {
-    if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
-            || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
-            || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
-                && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)) {
-        return BAD_VALUE;
-    }
-
     mBufferingSettings = buffering;
 
-    if (mBufferingSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
-        mBufferingSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
-    }
-    if (mBufferingSettings.mRebufferingMode == BUFFERING_MODE_NONE) {
-        mBufferingSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
-        mBufferingSettings.mRebufferingWatermarkHighMs = INT32_MAX;
-    }
-
     if (mLiveSession != NULL) {
         mLiveSession->setBufferingSettings(mBufferingSettings);
     }
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 2866a6a..2d6c604 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -34,7 +34,7 @@
             const char *url,
             const KeyedVector<String8, String8> *headers);
 
-    virtual status_t getDefaultBufferingSettings(
+    virtual status_t getBufferingSettings(
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index df36046..d1e5d45 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -48,7 +48,9 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaClock.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -56,7 +58,6 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
 
-#include "avc_utils.h"
 
 #include "ESDS.h"
 #include <media/stagefright/Utils.h>
@@ -172,14 +173,16 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-NuPlayer::NuPlayer(pid_t pid)
+NuPlayer::NuPlayer(pid_t pid, const sp<MediaClock> &mediaClock)
     : mUIDValid(false),
       mPID(pid),
+      mMediaClock(mediaClock),
       mSourceFlags(0),
       mOffloadAudio(false),
       mAudioDecoderGeneration(0),
       mVideoDecoderGeneration(0),
       mRendererGeneration(0),
+      mLastStartedPlayingTimeNs(0),
       mPreviousSeekTimeUs(0),
       mAudioEOS(false),
       mVideoEOS(false),
@@ -204,6 +207,7 @@
       mPausedForBuffering(false),
       mIsDrmProtected(false),
       mDataSourceType(DATA_SOURCE_TYPE_NONE) {
+    CHECK(mediaClock != NULL);
     clearFlushComplete();
 }
 
@@ -278,7 +282,7 @@
         ALOGV("setDataSourceAsync GenericSource %s", url);
 
         sp<GenericSource> genericSource =
-                new GenericSource(notify, mUIDValid, mUID);
+                new GenericSource(notify, mUIDValid, mUID, mMediaClock);
 
         status_t err = genericSource->setDataSource(httpService, url, headers);
 
@@ -301,7 +305,7 @@
     sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
 
     sp<GenericSource> source =
-            new GenericSource(notify, mUIDValid, mUID);
+            new GenericSource(notify, mUIDValid, mUID, mMediaClock);
 
     ALOGV("setDataSourceAsync fd %d/%lld/%lld source: %p",
             fd, (long long)offset, (long long)length, source.get());
@@ -322,7 +326,7 @@
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
     sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
 
-    sp<GenericSource> source = new GenericSource(notify, mUIDValid, mUID);
+    sp<GenericSource> source = new GenericSource(notify, mUIDValid, mUID, mMediaClock);
     status_t err = source->setDataSource(dataSource);
 
     if (err != OK) {
@@ -335,9 +339,9 @@
     mDataSourceType = DATA_SOURCE_TYPE_MEDIA;
 }
 
-status_t NuPlayer::getDefaultBufferingSettings(
+status_t NuPlayer::getBufferingSettings(
         BufferingSettings *buffering /* nonnull */) {
-    sp<AMessage> msg = new AMessage(kWhatGetDefaultBufferingSettings, this);
+    sp<AMessage> msg = new AMessage(kWhatGetBufferingSettings, this);
     sp<AMessage> response;
     status_t err = msg->postAndAwaitResponse(&response);
     if (err == OK && response != NULL) {
@@ -470,6 +474,13 @@
     (new AMessage(kWhatReset, this))->post();
 }
 
+status_t NuPlayer::notifyAt(int64_t mediaTimeUs) {
+    sp<AMessage> notify = new AMessage(kWhatNotifyTime, this);
+    notify->setInt64("timerUs", mediaTimeUs);
+    mMediaClock->addTimer(notify, mediaTimeUs);
+    return OK;
+}
+
 void NuPlayer::seekToAsync(int64_t seekTimeUs, MediaPlayerSeekMode mode, bool needNotify) {
     sp<AMessage> msg = new AMessage(kWhatSeek, this);
     msg->setInt64("seekTimeUs", seekTimeUs);
@@ -556,16 +567,16 @@
             break;
         }
 
-        case kWhatGetDefaultBufferingSettings:
+        case kWhatGetBufferingSettings:
         {
             sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
-            ALOGV("kWhatGetDefaultBufferingSettings");
+            ALOGV("kWhatGetBufferingSettings");
             BufferingSettings buffering;
             status_t err = OK;
             if (mSource != NULL) {
-                err = mSource->getDefaultBufferingSettings(&buffering);
+                err = mSource->getBufferingSettings(&buffering);
             } else {
                 err = INVALID_OPERATION;
             }
@@ -1299,6 +1310,8 @@
             ALOGV("kWhatReset");
 
             mResetting = true;
+            stopPlaybackTimer("kWhatReset");
+            stopRebufferingTimer(true);
 
             mDeferredActions.push_back(
                     new FlushDecoderAction(
@@ -1312,6 +1325,16 @@
             break;
         }
 
+        case kWhatNotifyTime:
+        {
+            ALOGV("kWhatNotifyTime");
+            int64_t timerUs;
+            CHECK(msg->findInt64("timerUs", &timerUs));
+
+            notifyListener(MEDIA_NOTIFY_TIME, timerUs, 0);
+            break;
+        }
+
         case kWhatSeek:
         {
             int64_t seekTimeUs;
@@ -1429,7 +1452,7 @@
         ALOGW("resume called when renderer is gone or not set");
     }
 
-    mLastStartedPlayingTimeNs = systemTime();
+    startPlaybackTimer("onresume");
 }
 
 status_t NuPlayer::onInstantiateSecureDecoders() {
@@ -1523,7 +1546,7 @@
     sp<AMessage> notify = new AMessage(kWhatRendererNotify, this);
     ++mRendererGeneration;
     notify->setInt32("generation", mRendererGeneration);
-    mRenderer = new Renderer(mAudioSink, notify, flags);
+    mRenderer = new Renderer(mAudioSink, mMediaClock, notify, flags);
     mRendererLooper = new ALooper;
     mRendererLooper->setName("NuPlayerRenderer");
     mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
@@ -1549,12 +1572,74 @@
         mAudioDecoder->setRenderer(mRenderer);
     }
 
-    mLastStartedPlayingTimeNs = systemTime();
+    startPlaybackTimer("onstart");
 
     postScanSources();
 }
 
+void NuPlayer::startPlaybackTimer(const char *where) {
+    Mutex::Autolock autoLock(mPlayingTimeLock);
+    if (mLastStartedPlayingTimeNs == 0) {
+        mLastStartedPlayingTimeNs = systemTime();
+        ALOGV("startPlaybackTimer() time %20" PRId64 " (%s)",  mLastStartedPlayingTimeNs, where);
+    }
+}
+
+void NuPlayer::stopPlaybackTimer(const char *where) {
+    Mutex::Autolock autoLock(mPlayingTimeLock);
+
+    ALOGV("stopPlaybackTimer()  time %20" PRId64 " (%s)", mLastStartedPlayingTimeNs, where);
+
+    if (mLastStartedPlayingTimeNs != 0) {
+        sp<NuPlayerDriver> driver = mDriver.promote();
+        if (driver != NULL) {
+            int64_t now = systemTime();
+            int64_t played = now - mLastStartedPlayingTimeNs;
+            ALOGV("stopPlaybackTimer()  log  %20" PRId64 "", played);
+
+            if (played > 0) {
+                driver->notifyMorePlayingTimeUs((played+500)/1000);
+            }
+        }
+        mLastStartedPlayingTimeNs = 0;
+    }
+}
+
+void NuPlayer::startRebufferingTimer() {
+    Mutex::Autolock autoLock(mPlayingTimeLock);
+    if (mLastStartedRebufferingTimeNs == 0) {
+        mLastStartedRebufferingTimeNs = systemTime();
+        ALOGV("startRebufferingTimer() time %20" PRId64 "",  mLastStartedRebufferingTimeNs);
+    }
+}
+
+void NuPlayer::stopRebufferingTimer(bool exitingPlayback) {
+    Mutex::Autolock autoLock(mPlayingTimeLock);
+
+    ALOGV("stopRebufferTimer()  time %20" PRId64 " (exiting %d)", mLastStartedRebufferingTimeNs, exitingPlayback);
+
+    if (mLastStartedRebufferingTimeNs != 0) {
+        sp<NuPlayerDriver> driver = mDriver.promote();
+        if (driver != NULL) {
+            int64_t now = systemTime();
+            int64_t rebuffered = now - mLastStartedRebufferingTimeNs;
+            ALOGV("stopRebufferingTimer()  log  %20" PRId64 "", rebuffered);
+
+            if (rebuffered > 0) {
+                driver->notifyMoreRebufferingTimeUs((rebuffered+500)/1000);
+                if (exitingPlayback) {
+                    driver->notifyRebufferingWhenExit(true);
+                }
+            }
+        }
+        mLastStartedRebufferingTimeNs = 0;
+    }
+}
+
 void NuPlayer::onPause() {
+
+    stopPlaybackTimer("onPause");
+
     if (mPaused) {
         return;
     }
@@ -1570,13 +1655,6 @@
         ALOGW("pause called when renderer is gone or not set");
     }
 
-    sp<NuPlayerDriver> driver = mDriver.promote();
-    if (driver != NULL) {
-        int64_t now = systemTime();
-        int64_t played = now - mLastStartedPlayingTimeNs;
-
-        driver->notifyMorePlayingTimeUs((played+500)/1000);
-    }
 }
 
 bool NuPlayer::audioDecoderStillNeeded() {
@@ -2203,6 +2281,9 @@
     CHECK(mAudioDecoder == NULL);
     CHECK(mVideoDecoder == NULL);
 
+    stopPlaybackTimer("performReset");
+    stopRebufferingTimer(true);
+
     cancelPollDuration();
 
     ++mScanSourcesGeneration;
@@ -2455,6 +2536,7 @@
             if (mStarted) {
                 ALOGI("buffer low, pausing...");
 
+                startRebufferingTimer();
                 mPausedForBuffering = true;
                 onPause();
             }
@@ -2468,6 +2550,7 @@
             if (mStarted) {
                 ALOGI("buffer ready, resuming...");
 
+                stopRebufferingTimer(false);
                 mPausedForBuffering = false;
 
                 // do not resume yet if client didn't unpause
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index c69835f..fda69e8 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -30,11 +30,12 @@
 struct AudioPlaybackRate;
 struct AVSyncSettings;
 class IDataSource;
+struct MediaClock;
 class MetaData;
 struct NuPlayerDriver;
 
 struct NuPlayer : public AHandler {
-    explicit NuPlayer(pid_t pid);
+    explicit NuPlayer(pid_t pid, const sp<MediaClock> &mediaClock);
 
     void setUID(uid_t uid);
 
@@ -51,7 +52,7 @@
 
     void setDataSourceAsync(const sp<DataSource> &source);
 
-    status_t getDefaultBufferingSettings(BufferingSettings* buffering /* nonnull */);
+    status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */);
     status_t setBufferingSettings(const BufferingSettings& buffering);
 
     void prepareAsync();
@@ -72,6 +73,9 @@
     // Will notify the driver through "notifyResetComplete" once finished.
     void resetAsync();
 
+    // Request a notification when specified media time is reached.
+    status_t notifyAt(int64_t mediaTimeUs);
+
     // Will notify the driver through "notifySeekComplete" once finished
     // and needNotify is true.
     void seekToAsync(
@@ -139,6 +143,7 @@
         kWhatClosedCaptionNotify        = 'capN',
         kWhatRendererNotify             = 'renN',
         kWhatReset                      = 'rset',
+        kWhatNotifyTime                 = 'nfyT',
         kWhatSeek                       = 'seek',
         kWhatPause                      = 'paus',
         kWhatResume                     = 'rsme',
@@ -147,7 +152,7 @@
         kWhatGetTrackInfo               = 'gTrI',
         kWhatGetSelectedTrack           = 'gSel',
         kWhatSelectTrack                = 'selT',
-        kWhatGetDefaultBufferingSettings = 'gDBS',
+        kWhatGetBufferingSettings       = 'gBus',
         kWhatSetBufferingSettings       = 'sBuS',
         kWhatPrepareDrm                 = 'pDrm',
         kWhatReleaseDrm                 = 'rDrm',
@@ -157,6 +162,7 @@
     bool mUIDValid;
     uid_t mUID;
     pid_t mPID;
+    const sp<MediaClock> mMediaClock;
     Mutex mSourceLock;  // guard |mSource|.
     sp<Source> mSource;
     uint32_t mSourceFlags;
@@ -172,7 +178,14 @@
     int32_t mVideoDecoderGeneration;
     int32_t mRendererGeneration;
 
+    Mutex mPlayingTimeLock;
     int64_t mLastStartedPlayingTimeNs;
+    void stopPlaybackTimer(const char *where);
+    void startPlaybackTimer(const char *where);
+
+    int64_t mLastStartedRebufferingTimeNs;
+    void startRebufferingTimer();
+    void stopRebufferingTimer(bool exitingPlayback);
 
     int64_t mPreviousSeekTimeUs;
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
index 73b07bb..0a8b97f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
@@ -19,13 +19,13 @@
 #include <utils/Log.h>
 #include <inttypes.h>
 
-#include "avc_utils.h"
 #include "NuPlayerCCDecoder.h"
 
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaDefs.h>
 
 namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index ac187cc..a84d0e5 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -33,6 +33,7 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaDefs.h>
@@ -40,7 +41,6 @@
 #include <media/stagefright/SurfaceUtils.h>
 #include <gui/Surface.h>
 
-#include "avc_utils.h"
 #include "ATSParser.h"
 
 namespace android {
@@ -750,12 +750,20 @@
 
         buffer->meta()->setInt32("eos", true);
         reply->setInt32("eos", true);
-    } else if (mSkipRenderingUntilMediaTimeUs >= 0) {
+    }
+
+    if (mSkipRenderingUntilMediaTimeUs >= 0) {
         if (timeUs < mSkipRenderingUntilMediaTimeUs) {
             ALOGV("[%s] dropping buffer at time %lld as requested.",
                      mComponentName.c_str(), (long long)timeUs);
 
             reply->post();
+            if (eos) {
+                notifyResumeCompleteIfNecessary();
+                if (mRenderer != NULL && !isDiscontinuityPending()) {
+                    mRenderer->queueEOS(mIsAudio, ERROR_END_OF_STREAM);
+                }
+            }
             return true;
         }
 
@@ -937,7 +945,8 @@
                             mCurrentMaxVideoTemporalLayerId);
                 } else if (layerId > mCurrentMaxVideoTemporalLayerId) {
                     mCurrentMaxVideoTemporalLayerId = layerId;
-                } else if (layerId == 0 && mNumVideoTemporalLayerTotal > 1 && IsIDR(accessUnit)) {
+                } else if (layerId == 0 && mNumVideoTemporalLayerTotal > 1
+                        && IsIDR(accessUnit->data(), accessUnit->size())) {
                     mCurrentMaxVideoTemporalLayerId = mNumVideoTemporalLayerTotal - 1;
                 }
             }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index dc29761..ebf57c6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -28,6 +28,8 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/MediaClock.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
@@ -54,6 +56,10 @@
 static const char *kPlayerError = "android.media.mediaplayer.err";
 static const char *kPlayerErrorCode = "android.media.mediaplayer.errcode";
 static const char *kPlayerDataSourceType = "android.media.mediaplayer.dataSource";
+//
+static const char *kPlayerRebuffering = "android.media.mediaplayer.rebufferingMs";
+static const char *kPlayerRebufferingCount = "android.media.mediaplayer.rebuffers";
+static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit";
 
 
 NuPlayerDriver::NuPlayerDriver(pid_t pid)
@@ -65,8 +71,12 @@
       mPositionUs(-1),
       mSeekInProgress(false),
       mPlayingTimeUs(0),
+      mRebufferingTimeUs(0),
+      mRebufferingEvents(0),
+      mRebufferingAtExit(false),
       mLooper(new ALooper),
-      mPlayer(new NuPlayer(pid)),
+      mMediaClock(new MediaClock),
+      mPlayer(new NuPlayer(pid, mMediaClock)),
       mPlayerFlags(0),
       mAnalyticsItem(NULL),
       mClientUid(-1),
@@ -76,6 +86,8 @@
     ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
     mLooper->setName("NuPlayerDriver Looper");
 
+    mMediaClock->init();
+
     // set up an analytics record
     mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
     mAnalyticsItem->generateSessionID();
@@ -226,8 +238,8 @@
     return OK;
 }
 
-status_t NuPlayerDriver::getDefaultBufferingSettings(BufferingSettings* buffering) {
-    ALOGV("getDefaultBufferingSettings(%p)", this);
+status_t NuPlayerDriver::getBufferingSettings(BufferingSettings* buffering) {
+    ALOGV("getBufferingSettings(%p)", this);
     {
         Mutex::Autolock autoLock(mLock);
         if (mState == STATE_IDLE) {
@@ -235,7 +247,7 @@
         }
     }
 
-    return mPlayer->getDefaultBufferingSettings(buffering);
+    return mPlayer->getBufferingSettings(buffering);
 }
 
 status_t NuPlayerDriver::setBufferingSettings(const BufferingSettings& buffering) {
@@ -577,6 +589,12 @@
 
     mAnalyticsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
 
+    if (mRebufferingEvents != 0) {
+        mAnalyticsItem->setInt64(kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
+        mAnalyticsItem->setInt32(kPlayerRebufferingCount, mRebufferingEvents);
+        mAnalyticsItem->setInt32(kPlayerRebufferingAtExit, mRebufferingAtExit);
+    }
+
     mAnalyticsItem->setCString(kPlayerDataSourceType, mPlayer->getDataSourceType());
 }
 
@@ -656,10 +674,18 @@
     mPositionUs = -1;
     mLooping = false;
     mPlayingTimeUs = 0;
+    mRebufferingTimeUs = 0;
+    mRebufferingEvents = 0;
+    mRebufferingAtExit = false;
 
     return OK;
 }
 
+status_t NuPlayerDriver::notifyAt(int64_t mediaTimeUs) {
+    ALOGV("notifyAt(%p), time:%lld", this, (long long)mediaTimeUs);
+    return mPlayer->notifyAt(mediaTimeUs);
+}
+
 status_t NuPlayerDriver::setLooping(int loop) {
     mLooping = loop != 0;
     return OK;
@@ -801,6 +827,17 @@
     mPlayingTimeUs += playingUs;
 }
 
+void NuPlayerDriver::notifyMoreRebufferingTimeUs(int64_t rebufferingUs) {
+    Mutex::Autolock autoLock(mLock);
+    mRebufferingTimeUs += rebufferingUs;
+    mRebufferingEvents++;
+}
+
+void NuPlayerDriver::notifyRebufferingWhenExit(bool status) {
+    Mutex::Autolock autoLock(mLock);
+    mRebufferingAtExit = status;
+}
+
 void NuPlayerDriver::notifySeekComplete() {
     ALOGV("notifySeekComplete(%p)", this);
     Mutex::Autolock autoLock(mLock);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index d0cf1dd..13b46c3 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -22,6 +22,7 @@
 namespace android {
 
 struct ALooper;
+struct MediaClock;
 struct NuPlayer;
 
 struct NuPlayerDriver : public MediaPlayerInterface {
@@ -45,7 +46,7 @@
     virtual status_t setVideoSurfaceTexture(
             const sp<IGraphicBufferProducer> &bufferProducer);
 
-    virtual status_t getDefaultBufferingSettings(
+    virtual status_t getBufferingSettings(
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
@@ -64,6 +65,7 @@
     virtual status_t getCurrentPosition(int *msec);
     virtual status_t getDuration(int *msec);
     virtual status_t reset();
+    virtual status_t notifyAt(int64_t mediaTimeUs) override;
     virtual status_t setLooping(int loop);
     virtual player_type playerType();
     virtual status_t invoke(const Parcel &request, Parcel *reply);
@@ -82,6 +84,8 @@
     void notifySetSurfaceComplete();
     void notifyDuration(int64_t durationUs);
     void notifyMorePlayingTimeUs(int64_t timeUs);
+    void notifyMoreRebufferingTimeUs(int64_t timeUs);
+    void notifyRebufferingWhenExit(bool status);
     void notifySeekComplete();
     void notifySeekComplete_l();
     void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
@@ -124,9 +128,13 @@
     int64_t mPositionUs;
     bool mSeekInProgress;
     int64_t mPlayingTimeUs;
+    int64_t mRebufferingTimeUs;
+    int32_t mRebufferingEvents;
+    bool mRebufferingAtExit;
     // <<<
 
     sp<ALooper> mLooper;
+    const sp<MediaClock> mMediaClock;
     const sp<NuPlayer> mPlayer;
     sp<AudioSink> mAudioSink;
     uint32_t mPlayerFlags;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index bd866cb..cc7f688 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -18,13 +18,13 @@
 #define LOG_TAG "NuPlayerRenderer"
 #include <utils/Log.h>
 
+#include "AWakeLock.h"
 #include "NuPlayerRenderer.h"
 #include <algorithm>
 #include <cutils/properties.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/foundation/AWakeLock.h>
 #include <media/stagefright/MediaClock.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -89,6 +89,7 @@
 
 NuPlayer::Renderer::Renderer(
         const sp<MediaPlayerBase::AudioSink> &sink,
+        const sp<MediaClock> &mediaClock,
         const sp<AMessage> &notify,
         uint32_t flags)
     : mAudioSink(sink),
@@ -103,11 +104,13 @@
       mAudioDrainGeneration(0),
       mVideoDrainGeneration(0),
       mAudioEOSGeneration(0),
+      mMediaClock(mediaClock),
       mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
       mAudioFirstAnchorTimeMediaUs(-1),
       mAnchorTimeMediaUs(-1),
       mAnchorNumFramesWritten(-1),
       mVideoLateByUs(0ll),
+      mNextVideoTimeMediaUs(-1),
       mHasAudio(false),
       mHasVideo(false),
       mNotifyCompleteAudio(false),
@@ -130,7 +133,7 @@
       mLastAudioBufferDrained(0),
       mUseAudioCallback(false),
       mWakeLock(new AWakeLock()) {
-    mMediaClock = new MediaClock;
+    CHECK(mediaClock != NULL);
     mPlaybackRate = mPlaybackSettings.mSpeed;
     mMediaClock->setPlaybackRate(mPlaybackRate);
 }
@@ -149,7 +152,6 @@
         flushQueue(&mVideoQueue);
     }
     mWakeLock.clear();
-    mMediaClock.clear();
     mVideoScheduler.clear();
     mNotify.clear();
     mAudioSink.clear();
@@ -300,6 +302,7 @@
 
         mMediaClock->clearAnchor();
         mVideoLateByUs = 0;
+        mNextVideoTimeMediaUs = -1;
         mSyncQueues = false;
     }
 
@@ -548,8 +551,10 @@
                 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
                          (status_t)OK);
 
+                // Handle AudioTrack race when start is immediately called after flush.
                 uint32_t numFramesPendingPlayout =
-                    mNumFramesWritten - numFramesPlayed;
+                    (mNumFramesWritten > numFramesPlayed ?
+                        mNumFramesWritten - numFramesPlayed : 0);
 
                 // This is how long the audio sink will have data to
                 // play back.
@@ -1245,82 +1250,49 @@
         return;
     }
 
-    bool needRepostDrainVideoQueue = false;
-    int64_t delayUs;
     int64_t nowUs = ALooper::GetNowUs();
-    int64_t realTimeUs;
     if (mFlags & FLAG_REAL_TIME) {
-        int64_t mediaTimeUs;
-        CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
-        realTimeUs = mediaTimeUs;
-    } else {
-        int64_t mediaTimeUs;
-        CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
+        int64_t realTimeUs;
+        CHECK(entry.mBuffer->meta()->findInt64("timeUs", &realTimeUs));
 
-        {
-            Mutex::Autolock autoLock(mLock);
-            if (mAnchorTimeMediaUs < 0) {
-                mMediaClock->updateAnchor(mediaTimeUs, nowUs, mediaTimeUs);
-                mAnchorTimeMediaUs = mediaTimeUs;
-                realTimeUs = nowUs;
-            } else if (!mVideoSampleReceived) {
-                // Always render the first video frame.
-                realTimeUs = nowUs;
-            } else if (mAudioFirstAnchorTimeMediaUs < 0
-                || mMediaClock->getRealTimeFor(mediaTimeUs, &realTimeUs) == OK) {
-                realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
-            } else if (mediaTimeUs - mAudioFirstAnchorTimeMediaUs >= 0) {
-                needRepostDrainVideoQueue = true;
-                realTimeUs = nowUs;
-            } else {
-                realTimeUs = nowUs;
-            }
-        }
-        if (!mHasAudio) {
-            // smooth out videos >= 10fps
-            mMediaClock->updateMaxTimeMedia(mediaTimeUs + 100000);
-        }
+        realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
 
-        // Heuristics to handle situation when media time changed without a
-        // discontinuity. If we have not drained an audio buffer that was
-        // received after this buffer, repost in 10 msec. Otherwise repost
-        // in 500 msec.
-        delayUs = realTimeUs - nowUs;
-        int64_t postDelayUs = -1;
-        if (delayUs > 500000) {
-            postDelayUs = 500000;
-            if (mHasAudio && (mLastAudioBufferDrained - entry.mBufferOrdinal) <= 0) {
-                postDelayUs = 10000;
-            }
-        } else if (needRepostDrainVideoQueue) {
-            // CHECK(mPlaybackRate > 0);
-            // CHECK(mAudioFirstAnchorTimeMediaUs >= 0);
-            // CHECK(mediaTimeUs - mAudioFirstAnchorTimeMediaUs >= 0);
-            postDelayUs = mediaTimeUs - mAudioFirstAnchorTimeMediaUs;
-            postDelayUs /= mPlaybackRate;
-        }
+        int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000);
 
-        if (postDelayUs >= 0) {
-            msg->setWhat(kWhatPostDrainVideoQueue);
-            msg->post(postDelayUs);
-            mVideoScheduler->restart();
-            ALOGI("possible video time jump of %dms (%lld : %lld) or uninitialized media clock,"
-                    " retrying in %dms",
-                    (int)(delayUs / 1000), (long long)mediaTimeUs,
-                    (long long)mAudioFirstAnchorTimeMediaUs, (int)(postDelayUs / 1000));
-            mDrainVideoQueuePending = true;
-            return;
-        }
+        int64_t delayUs = realTimeUs - nowUs;
+
+        ALOGW_IF(delayUs > 500000, "unusually high delayUs: %lld", (long long)delayUs);
+        // post 2 display refreshes before rendering is due
+        msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0);
+
+        mDrainVideoQueuePending = true;
+        return;
     }
 
-    realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
-    int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000);
+    int64_t mediaTimeUs;
+    CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
 
-    delayUs = realTimeUs - nowUs;
+    {
+        Mutex::Autolock autoLock(mLock);
+        if (mAnchorTimeMediaUs < 0) {
+            mMediaClock->updateAnchor(mediaTimeUs, nowUs, mediaTimeUs);
+            mAnchorTimeMediaUs = mediaTimeUs;
+        }
+    }
+    mNextVideoTimeMediaUs = mediaTimeUs + 100000;
+    if (!mHasAudio) {
+        // smooth out videos >= 10fps
+        mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
+    }
 
-    ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs);
-    // post 2 display refreshes before rendering is due
-    msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0);
+    if (!mVideoSampleReceived || mediaTimeUs < mAudioFirstAnchorTimeMediaUs) {
+        msg->post();
+    } else {
+        int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000);
+
+        // post 2 display refreshes before rendering is due
+        mMediaClock->addTimer(msg, mediaTimeUs, -twoVsyncsUs);
+    }
 
     mDrainVideoQueuePending = true;
 }
@@ -1354,6 +1326,7 @@
 
         realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
     }
+    realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
 
     bool tooLate = false;
 
@@ -1440,6 +1413,14 @@
     if (audio) {
         // Video might outlive audio. Clear anchor to enable video only case.
         mAnchorTimeMediaUs = -1;
+        mHasAudio = false;
+        if (mNextVideoTimeMediaUs >= 0) {
+            int64_t mediaUs = 0;
+            mMediaClock->getMediaTime(ALooper::GetNowUs(), &mediaUs);
+            if (mNextVideoTimeMediaUs > mediaUs) {
+                mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
+            }
+        }
     }
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index f58b79c..a047975 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -36,6 +36,7 @@
         FLAG_OFFLOAD_AUDIO = 2,
     };
     Renderer(const sp<MediaPlayerBase::AudioSink> &sink,
+             const sp<MediaClock> &mediaClock,
              const sp<AMessage> &notify,
              uint32_t flags = 0);
 
@@ -165,7 +166,7 @@
     int32_t mVideoDrainGeneration;
     int32_t mAudioEOSGeneration;
 
-    sp<MediaClock> mMediaClock;
+    const sp<MediaClock> mMediaClock;
     float mPlaybackRate; // audio track rate
 
     AudioPlaybackRate mPlaybackSettings;
@@ -176,6 +177,7 @@
     int64_t mAnchorTimeMediaUs;
     int64_t mAnchorNumFramesWritten;
     int64_t mVideoLateByUs;
+    int64_t mNextVideoTimeMediaUs;
     bool mHasAudio;
     bool mHasVideo;
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 8ba9c0d..2df5e88 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -66,7 +66,7 @@
         : mNotify(notify) {
     }
 
-    virtual status_t getDefaultBufferingSettings(
+    virtual status_t getBufferingSettings(
             BufferingSettings* buffering /* nonnull */) = 0;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) = 0;
 
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 8b3d0dc..851217b 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -62,7 +62,8 @@
       mSeekGeneration(0),
       mEOSTimeoutAudio(0),
       mEOSTimeoutVideo(0) {
-    getDefaultBufferingSettings(&mBufferingSettings);
+    mBufferingSettings.mInitialMarkMs = kPrepareMarkMs;
+    mBufferingSettings.mResumePlaybackMarkMs = kOverflowMarkMs;
     if (headers) {
         mExtraHeaders = *headers;
 
@@ -84,32 +85,17 @@
     }
 }
 
-status_t NuPlayer::RTSPSource::getDefaultBufferingSettings(
+status_t NuPlayer::RTSPSource::getBufferingSettings(
             BufferingSettings* buffering /* nonnull */) {
-    buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
-    buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY;
-    buffering->mInitialWatermarkMs = kPrepareMarkMs;
-    buffering->mRebufferingWatermarkLowMs = kUnderflowMarkMs;
-    buffering->mRebufferingWatermarkHighMs = kOverflowMarkMs;
-
+    Mutex::Autolock _l(mBufferingSettingsLock);
+    *buffering = mBufferingSettings;
     return OK;
 }
 
 status_t NuPlayer::RTSPSource::setBufferingSettings(const BufferingSettings& buffering) {
-    if (mLooper == NULL) {
-        mBufferingSettings = buffering;
-        return OK;
-    }
-
-    sp<AMessage> msg = new AMessage(kWhatSetBufferingSettings, this);
-    writeToAMessage(msg, buffering);
-    sp<AMessage> response;
-    status_t err = msg->postAndAwaitResponse(&response);
-    if (err == OK && response != NULL) {
-        CHECK(response->findInt32("err", &err));
-    }
-
-    return err;
+    Mutex::Autolock _l(mBufferingSettingsLock);
+    mBufferingSettings = buffering;
+    return OK;
 }
 
 void NuPlayer::RTSPSource::prepareAsync() {
@@ -356,8 +342,17 @@
         }
         int64_t bufferedDurationUs = src->getBufferedDurationUs(&finalResult);
 
+        int64_t initialMarkUs;
+        int64_t maxRebufferingMarkUs;
+        {
+            Mutex::Autolock _l(mBufferingSettingsLock);
+            initialMarkUs = mBufferingSettings.mInitialMarkMs * 1000ll;
+            // TODO: maxRebufferingMarkUs could be larger than
+            // mBufferingSettings.mResumePlaybackMarkMs * 1000ll.
+            maxRebufferingMarkUs = mBufferingSettings.mResumePlaybackMarkMs * 1000ll;
+        }
         // isFinished when duration is 0 checks for EOS result only
-        if (bufferedDurationUs > mBufferingSettings.mInitialWatermarkMs * 1000
+        if (bufferedDurationUs > initialMarkUs
                 || src->isFinished(/* duration */ 0)) {
             ++preparedCount;
         }
@@ -366,15 +361,15 @@
             ++overflowCount;
             ++finishedCount;
         } else {
-            if (bufferedDurationUs < mBufferingSettings.mRebufferingWatermarkLowMs * 1000) {
+            // TODO: redefine kUnderflowMarkMs to a fair value,
+            if (bufferedDurationUs < kUnderflowMarkMs * 1000) {
                 ++underflowCount;
             }
-            if (bufferedDurationUs > mBufferingSettings.mRebufferingWatermarkHighMs * 1000) {
+            if (bufferedDurationUs > maxRebufferingMarkUs) {
                 ++overflowCount;
             }
             int64_t startServerMarkUs =
-                    (mBufferingSettings.mRebufferingWatermarkLowMs
-                        + mBufferingSettings.mRebufferingWatermarkHighMs) / 2 * 1000ll;
+                    (kUnderflowMarkMs * 1000ll + maxRebufferingMarkUs) / 2;
             if (bufferedDurationUs < startServerMarkUs) {
                 ++startCount;
             }
@@ -512,36 +507,6 @@
     } else if (msg->what() == kWhatSignalEOS) {
         onSignalEOS(msg);
         return;
-    } else if (msg->what() == kWhatSetBufferingSettings) {
-        sp<AReplyToken> replyID;
-        CHECK(msg->senderAwaitsResponse(&replyID));
-
-        BufferingSettings buffering;
-        readFromAMessage(msg, &buffering);
-
-        status_t err = OK;
-        if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
-                || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
-                || (buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs
-                    && buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode))) {
-            err = BAD_VALUE;
-        } else {
-            if (buffering.mInitialBufferingMode == BUFFERING_MODE_NONE) {
-                buffering.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
-            }
-            if (buffering.mRebufferingMode == BUFFERING_MODE_NONE) {
-                buffering.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
-                buffering.mRebufferingWatermarkHighMs = INT32_MAX;
-            }
-
-            mBufferingSettings = buffering;
-        }
-
-        sp<AMessage> response = new AMessage;
-        response->setInt32("err", err);
-        response->postReply(replyID);
-
-        return;
     }
 
     CHECK_EQ(msg->what(), kWhatNotify);
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index 0812991..03fce08 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -40,7 +40,7 @@
             uid_t uid = 0,
             bool isSDP = false);
 
-    virtual status_t getDefaultBufferingSettings(
+    virtual status_t getBufferingSettings(
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
@@ -71,7 +71,6 @@
         kWhatPerformSeek     = 'seek',
         kWhatPollBuffering   = 'poll',
         kWhatSignalEOS       = 'eos ',
-        kWhatSetBufferingSettings = 'sBuS',
     };
 
     enum State {
@@ -109,6 +108,8 @@
     bool mBuffering;
     bool mInPreparationPhase;
     bool mEOSPending;
+
+    Mutex mBufferingSettingsLock;
     BufferingSettings mBufferingSettings;
 
     sp<ALooper> mLooper;
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index fc0803b..388ca20 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -24,10 +24,10 @@
 #include "AnotherPacketSource.h"
 #include "NuPlayerStreamListener.h"
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
@@ -51,19 +51,14 @@
     }
 }
 
-status_t NuPlayer::StreamingSource::getDefaultBufferingSettings(
+status_t NuPlayer::StreamingSource::getBufferingSettings(
         BufferingSettings *buffering /* nonnull */) {
     *buffering = BufferingSettings();
     return OK;
 }
 
 status_t NuPlayer::StreamingSource::setBufferingSettings(
-        const BufferingSettings &buffering) {
-    if (buffering.mInitialBufferingMode != BUFFERING_MODE_NONE
-            || buffering.mRebufferingMode != BUFFERING_MODE_NONE) {
-        return BAD_VALUE;
-    }
-
+        const BufferingSettings & /* buffering */) {
     return OK;
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.h b/media/libmediaplayerservice/nuplayer/StreamingSource.h
index 2e1d2b3..76d1d0b 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.h
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.h
@@ -32,7 +32,7 @@
             const sp<AMessage> &notify,
             const sp<IStreamSource> &source);
 
-    virtual status_t getDefaultBufferingSettings(
+    virtual status_t getBufferingSettings(
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
diff --git a/media/libmediaplayerservice/tests/Android.bp b/media/libmediaplayerservice/tests/Android.bp
new file mode 100644
index 0000000..d6c1d27
--- /dev/null
+++ b/media/libmediaplayerservice/tests/Android.bp
@@ -0,0 +1,24 @@
+cc_test {
+
+    name: "DrmSessionManager_test",
+
+    tags: ["tests"],
+
+    srcs: ["DrmSessionManager_test.cpp"],
+
+    shared_libs: [
+        "liblog",
+        "libmediaplayerservice",
+        "libmediadrm",
+        "libutils",
+        "android.hardware.drm@1.0",
+    ],
+
+    compile_multilib: "32",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+}
diff --git a/media/libmediaplayerservice/tests/Android.mk b/media/libmediaplayerservice/tests/Android.mk
deleted file mode 100644
index 0b9b85f..0000000
--- a/media/libmediaplayerservice/tests/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := DrmSessionManager_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-	DrmSessionManager_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libmediaplayerservice \
-	libmediadrm \
-	libutils \
-	android.hardware.drm@1.0 \
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/include \
-	frameworks/av/media/libmediaplayerservice \
-
-LOCAL_CFLAGS += -Werror -Wall
-
-LOCAL_32_BIT_ONLY := true
-
-include $(BUILD_NATIVE_TEST)
-
diff --git a/media/libnbaio/Android.bp b/media/libnbaio/Android.bp
index 4220b77..a4df38d 100644
--- a/media/libnbaio/Android.bp
+++ b/media/libnbaio/Android.bp
@@ -41,11 +41,8 @@
         "AudioBufferProviderSource.cpp",
         "AudioStreamInSource.cpp",
         "AudioStreamOutSink.cpp",
-        "NBLog.cpp",
-        "PerformanceAnalysis.cpp",
         "Pipe.cpp",
         "PipeReader.cpp",
-        "ReportPerformance.cpp",
         "SourceAudioBufferProvider.cpp",
     ],
 
diff --git a/media/libnbaio/OWNERS b/media/libnbaio/OWNERS
index f9cb567..eece71f 100644
--- a/media/libnbaio/OWNERS
+++ b/media/libnbaio/OWNERS
@@ -1 +1,2 @@
 gkasten@google.com
+hunga@google.com
diff --git a/media/libnbaio/PerformanceAnalysis.cpp b/media/libnbaio/PerformanceAnalysis.cpp
deleted file mode 100644
index fb3bddc..0000000
--- a/media/libnbaio/PerformanceAnalysis.cpp
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#define LOG_TAG "PerformanceAnalysis"
-// #define LOG_NDEBUG 0
-
-#include <algorithm>
-#include <climits>
-#include <deque>
-#include <iostream>
-#include <math.h>
-#include <numeric>
-#include <vector>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <time.h>
-#include <new>
-#include <audio_utils/roundup.h>
-#include <media/nbaio/NBLog.h>
-#include <media/nbaio/PerformanceAnalysis.h>
-#include <media/nbaio/ReportPerformance.h>
-// #include <utils/CallStack.h> // used to print callstack
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include <queue>
-#include <utility>
-
-namespace android {
-
-namespace ReportPerformance {
-
-PerformanceAnalysis::PerformanceAnalysis() {
-    // These variables will be (FIXME) learned from the data
-    kPeriodMs = 4; // typical buffer period (mode)
-    // average number of Ms spent processing buffer
-    kPeriodMsCPU = static_cast<int>(kPeriodMs * kRatio);
-}
-
-// converts a time series into a map. key: buffer period length. value: count
-static std::map<int, int> buildBuckets(const std::vector<int64_t> &samples) {
-    // TODO allow buckets of variable resolution
-    std::map<int, int> buckets;
-    for (size_t i = 1; i < samples.size(); ++i) {
-        ++buckets[deltaMs(samples[i - 1], samples[i])];
-    }
-    return buckets;
-}
-
-static int widthOf(int x) {
-    int width = 0;
-    while (x > 0) {
-        ++width;
-        x /= 10;
-    }
-    return width;
-}
-
-// Given a series of audio processing wakeup timestamps,
-// buckets the time intervals into a histogram, searches for
-// outliers, analyzes the outlier series for unexpectedly
-// small or large values and stores these as peaks, and flushes
-// the timestamp series from memory.
-void PerformanceAnalysis::processAndFlushTimeStampSeries() {
-    // 1) analyze the series to store all outliers and their exact timestamps:
-    storeOutlierData(mTimeStampSeries);
-
-    // 2) detect peaks in the outlier series
-    detectPeaks();
-
-    // 3) compute its histogram, append to mRecentHists and clear the time series
-    mRecentHists.emplace_back(static_cast<timestamp>(mTimeStampSeries[0]),
-                              buildBuckets(mTimeStampSeries));
-    // do not let mRecentHists exceed capacity
-    // ALOGD("mRecentHists size: %d", static_cast<int>(mRecentHists.size()));
-    if (mRecentHists.size() >= kRecentHistsCapacity) {
-        //  ALOGD("popped back mRecentHists");
-        mRecentHists.pop_front();
-    }
-    mTimeStampSeries.clear();
-}
-
-// forces short-term histogram storage to avoid adding idle audio time interval
-// to buffer period data
-void PerformanceAnalysis::handleStateChange() {
-    ALOGD("handleStateChange");
-    processAndFlushTimeStampSeries();
-    return;
-}
-
-// Takes a single buffer period timestamp entry information and stores it in a
-// temporary series of timestamps. Once the series is full, the data is analyzed,
-// stored, and emptied.
-void PerformanceAnalysis::logTsEntry(int64_t ts) {
-    // TODO might want to filter excessively high outliers, which are usually caused
-    // by the thread being inactive.
-    // Store time series data for each reader in order to bucket it once there
-    // is enough data. Then, write to recentHists as a histogram.
-    mTimeStampSeries.push_back(ts);
-    // if length of the time series has reached kShortHistSize samples,
-    // analyze the data and flush the timestamp series from memory
-    if (mTimeStampSeries.size() >= kShortHistSize) {
-        processAndFlushTimeStampSeries();
-    }
-}
-
-// When the short-term histogram array mRecentHists has reached capacity,
-// merge histograms for data compression and store them in mLongTermHists
-// clears mRecentHists
-// TODO: have logTsEntry write directly to mLongTermHists, discard mRecentHists,
-// start a new histogram when a peak occurs
-void PerformanceAnalysis::processAndFlushRecentHists() {
-
-    // Buckets is used to aggregate short-term histograms.
-    Histogram buckets;
-    timestamp startingTs = mRecentHists[0].first;
-
-    for (const auto &shortHist: mRecentHists) {
-        // If the time between starting and ending timestamps has reached the maximum,
-        // add the current histogram (buckets) to the long-term histogram buffer,
-        // clear buckets, and start a new long-term histogram aggregation process.
-        if (deltaMs(startingTs, shortHist.first) >= kMaxHistTimespanMs) {
-            mLongTermHists.emplace_back(startingTs, std::move(buckets));
-            buckets.clear();
-            startingTs = shortHist.first;
-            // When memory is full, delete oldest histogram
-            // TODO use a circular buffer
-            if (mLongTermHists.size() >= kLongTermHistsCapacity) {
-                mLongTermHists.pop_front();
-            }
-        }
-
-        // add current histogram to buckets
-        for (const auto &countPair : shortHist.second) {
-            buckets[countPair.first] += countPair.second;
-        }
-    }
-    mRecentHists.clear();
-    // TODO: decide when/where to call writeToFile
-    // TODO: add a thread-specific extension to the file name
-    static const char* const kName = (const char *) "/data/misc/audioserver/sample_results.txt";
-    writeToFile(mOutlierData, mLongTermHists, kName, false);
-}
-
-// Given a series of outlier intervals (mOutlier data),
-// looks for changes in distribution (peaks), which can be either positive or negative.
-// The function sets the mean to the starting value and sigma to 0, and updates
-// them as long as no peak is detected. When a value is more than 'threshold'
-// standard deviations from the mean, a peak is detected and the mean and sigma
-// are set to the peak value and 0.
-void PerformanceAnalysis::detectPeaks() {
-    if (mOutlierData.empty()) {
-        return;
-    }
-
-    // compute mean of the distribution. Used to check whether a value is large
-    const double kTypicalDiff = std::accumulate(
-        mOutlierData.begin(), mOutlierData.end(), 0,
-        [](auto &a, auto &b){return a + b.first;}) / mOutlierData.size();
-    // ALOGD("typicalDiff %f", kTypicalDiff);
-
-    // iterator at the beginning of a sequence, or updated to the most recent peak
-    std::deque<std::pair<uint64_t, uint64_t>>::iterator start = mOutlierData.begin();
-    // the mean and standard deviation are updated every time a peak is detected
-    // initialize first time. The mean from the previous sequence is stored
-    // for the next sequence. Here, they are initialized for the first time.
-    if (mPeakDetectorMean < 0) {
-        mPeakDetectorMean = static_cast<double>(start->first);
-        mPeakDetectorSd = 0;
-    }
-    auto sqr = [](auto x){ return x * x; };
-    for (auto it = mOutlierData.begin(); it != mOutlierData.end(); ++it) {
-        // no surprise occurred:
-        // the new element is a small number of standard deviations from the mean
-        if ((fabs(it->first - mPeakDetectorMean) < kStddevThreshold * mPeakDetectorSd) ||
-             // or: right after peak has been detected, the delta is smaller than average
-            (mPeakDetectorSd == 0 && fabs(it->first - mPeakDetectorMean) < kTypicalDiff)) {
-            // update the mean and sd:
-            // count number of elements (distance between start interator and current)
-            const int kN = std::distance(start, it) + 1;
-            // usual formulas for mean and sd
-            mPeakDetectorMean = std::accumulate(start, it + 1, 0.0,
-                                   [](auto &a, auto &b){return a + b.first;}) / kN;
-            mPeakDetectorSd = sqrt(std::accumulate(start, it + 1, 0.0,
-                      [=](auto &a, auto &b){ return a + sqr(b.first - mPeakDetectorMean);})) /
-                      ((kN > 1)? kN - 1 : kN); // kN - 1: mean is correlated with variance
-        }
-        // surprising value: store peak timestamp and reset mean, sd, and start iterator
-        else {
-            mPeakTimestamps.emplace_back(it->second);
-            // TODO: remove pop_front once a circular buffer is in place
-            if (mPeakTimestamps.size() >= kPeakSeriesSize) {
-                mPeakTimestamps.pop_front();
-            }
-            mPeakDetectorMean = static_cast<double>(it->first);
-            mPeakDetectorSd = 0;
-            start = it;
-        }
-    }
-    return;
-}
-
-// Called by LogTsEntry. The input is a vector of timestamps.
-// Finds outliers and writes to mOutlierdata.
-// Each value in mOutlierdata consists of: <outlier timestamp, time elapsed since previous outlier>.
-// e.g. timestamps (ms) 1, 4, 5, 16, 18, 28 will produce pairs (4, 5), (13, 18).
-// This function is applied to the time series before it is converted into a histogram.
-void PerformanceAnalysis::storeOutlierData(const std::vector<int64_t> &timestamps) {
-    if (timestamps.size() < 1) {
-        return;
-    }
-    // first pass: need to initialize
-    if (mElapsed == 0) {
-        mPrevNs = timestamps[0];
-    }
-    for (const auto &ts: timestamps) {
-        const uint64_t diffMs = static_cast<uint64_t>(deltaMs(mPrevNs, ts));
-        if (diffMs >= static_cast<uint64_t>(kOutlierMs)) {
-            mOutlierData.emplace_back(mElapsed, static_cast<uint64_t>(mPrevNs));
-            // Remove oldest value if the vector is full
-            // TODO: remove pop_front once circular buffer is in place
-            // FIXME: make sure kShortHistSize is large enough that that data will never be lost
-            // before being written to file or to a FIFO
-            if (mOutlierData.size() >= kOutlierSeriesSize) {
-                mOutlierData.pop_front();
-            }
-            mElapsed = 0;
-        }
-        mElapsed += diffMs;
-        mPrevNs = ts;
-    }
-}
-
-
-// FIXME: delete this temporary test code, recycled for various new functions
-void PerformanceAnalysis::testFunction() {
-    // produces values (4: 5000000), (13: 18000000)
-    // ns timestamps of buffer periods
-    const std::vector<int64_t>kTempTestData = {1000000, 4000000, 5000000,
-                                               16000000, 18000000, 28000000};
-    PerformanceAnalysis::storeOutlierData(kTempTestData);
-    for (const auto &outlier: mOutlierData) {
-        ALOGE("PerformanceAnalysis test %lld: %lld",
-              static_cast<long long>(outlier.first), static_cast<long long>(outlier.second));
-    }
-    detectPeaks();
-}
-
-// TODO Make it return a std::string instead of modifying body --> is this still relevant?
-// TODO consider changing all ints to uint32_t or uint64_t
-// TODO: move this to ReportPerformance, probably make it a friend function of PerformanceAnalysis
-void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) {
-    if (mRecentHists.size() < 1) {
-        ALOGD("reportPerformance: mRecentHists is empty");
-        return;
-    }
-    ALOGD("reportPerformance: hists size %d", static_cast<int>(mRecentHists.size()));
-    // TODO: more elaborate data analysis
-    std::map<int, int> buckets;
-    for (const auto &shortHist: mRecentHists) {
-        for (const auto &countPair : shortHist.second) {
-            buckets[countPair.first] += countPair.second;
-        }
-    }
-
-    // underscores and spaces length corresponds to maximum width of histogram
-    static const int kLen = 40;
-    std::string underscores(kLen, '_');
-    std::string spaces(kLen, ' ');
-
-    auto it = buckets.begin();
-    int maxDelta = it->first;
-    int maxCount = it->second;
-    // Compute maximum values
-    while (++it != buckets.end()) {
-        if (it->first > maxDelta) {
-            maxDelta = it->first;
-        }
-        if (it->second > maxCount) {
-            maxCount = it->second;
-        }
-    }
-    int height = log2(maxCount) + 1; // maxCount > 0, safe to call log2
-    const int leftPadding = widthOf(1 << height);
-    const int colWidth = std::max(std::max(widthOf(maxDelta) + 1, 3), leftPadding + 2);
-    int scalingFactor = 1;
-    // scale data if it exceeds maximum height
-    if (height > maxHeight) {
-        scalingFactor = (height + maxHeight) / maxHeight;
-        height /= scalingFactor;
-    }
-    body->appendFormat("\n%*s", leftPadding + 11, "Occurrences");
-    // write histogram label line with bucket values
-    body->appendFormat("\n%s", " ");
-    body->appendFormat("%*s", leftPadding, " ");
-    for (auto const &x : buckets) {
-        body->appendFormat("%*d", colWidth, x.second);
-    }
-    // write histogram ascii art
-    body->appendFormat("\n%s", " ");
-    for (int row = height * scalingFactor; row >= 0; row -= scalingFactor) {
-        const int value = 1 << row;
-        body->appendFormat("%.*s", leftPadding, spaces.c_str());
-        for (auto const &x : buckets) {
-          body->appendFormat("%.*s%s", colWidth - 1, spaces.c_str(), x.second < value ? " " : "|");
-        }
-        body->appendFormat("\n%s", " ");
-    }
-    // print x-axis
-    const int columns = static_cast<int>(buckets.size());
-    body->appendFormat("%*c", leftPadding, ' ');
-    body->appendFormat("%.*s", (columns + 1) * colWidth, underscores.c_str());
-    body->appendFormat("\n%s", " ");
-
-    // write footer with bucket labels
-    body->appendFormat("%*s", leftPadding, " ");
-    for (auto const &x : buckets) {
-        body->appendFormat("%*d", colWidth, x.first);
-    }
-    body->appendFormat("%.*s%s", colWidth, spaces.c_str(), "ms\n");
-
-    // Now report glitches
-    body->appendFormat("\ntime elapsed between glitches and glitch timestamps\n");
-    for (const auto &outlier: mOutlierData) {
-        body->appendFormat("%lld: %lld\n", static_cast<long long>(outlier.first),
-                           static_cast<long long>(outlier.second));
-    }
-
-}
-
-
-// Produces a log warning if the timing of recent buffer periods caused a glitch
-// Computes sum of running window of three buffer periods
-// Checks whether the buffer periods leave enough CPU time for the next one
-// e.g. if a buffer period is expected to be 4 ms and a buffer requires 3 ms of CPU time,
-// here are some glitch cases:
-// 4 + 4 + 6 ; 5 + 4 + 5; 2 + 2 + 10
-// TODO: develop this code to track changes in histogram distribution in addition
-// to / instead of glitches.
-void PerformanceAnalysis::alertIfGlitch(const std::vector<int64_t> &samples) {
-    std::deque<int> periods(kNumBuff, kPeriodMs);
-    for (size_t i = 2; i < samples.size(); ++i) { // skip first time entry
-        periods.push_front(deltaMs(samples[i - 1], samples[i]));
-        periods.pop_back();
-        // TODO: check that all glitch cases are covered
-        if (std::accumulate(periods.begin(), periods.end(), 0) > kNumBuff * kPeriodMs +
-            kPeriodMs - kPeriodMsCPU) {
-                ALOGW("A glitch occurred");
-                periods.assign(kNumBuff, kPeriodMs);
-        }
-    }
-    return;
-}
-
-} // namespace ReportPerformance
-
-}   // namespace android
diff --git a/media/libnbaio/ReportPerformance.cpp b/media/libnbaio/ReportPerformance.cpp
deleted file mode 100644
index dc50ada..0000000
--- a/media/libnbaio/ReportPerformance.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "ReportPerformance"
-
-#include <fstream>
-#include <iostream>
-#include <queue>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <utility>
-#include <media/nbaio/NBLog.h>
-#include <media/nbaio/PerformanceAnalysis.h>
-#include <media/nbaio/ReportPerformance.h>
-// #include <utils/CallStack.h> // used to print callstack
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-namespace android {
-
-namespace ReportPerformance {
-
-// Writes outlier intervals, timestamps, and histograms spanning long time intervals to a file.
-// TODO: format the data efficiently and write different types of data to different files
-void writeToFile(std::deque<std::pair<outlierInterval, timestamp>> &outlierData,
-                                    std::deque<std::pair<timestamp, Histogram>> &hists,
-                                    const char * kName,
-                                    bool append) {
-    ALOGD("writing performance data to file");
-    if (outlierData.empty() || hists.empty()) {
-        return;
-    }
-
-    std::ofstream ofs;
-    ofs.open(kName, append ? std::ios::app : std::ios::trunc);
-    if (!ofs.is_open()) {
-        ALOGW("couldn't open file %s", kName);
-        return;
-    }
-    ofs << "Outlier data: interval and timestamp\n";
-    for (const auto &outlier : outlierData) {
-        ofs << outlier.first << ": " << outlier.second << "\n";
-    }
-    ofs << "Histogram data\n";
-    for (const auto &hist : hists) {
-        ofs << "\ttimestamp\n";
-        ofs << hist.first << "\n";
-        ofs << "\tbuckets and counts\n";
-        for (const auto &bucket : hist.second) {
-            ofs << bucket.first << ": " << bucket.second << "\n";
-        }
-    }
-    ofs.close();
-}
-
-} // namespace ReportPerformance
-
-}   // namespace android
diff --git a/media/libnbaio/include/media/nbaio/NBLog.h b/media/libnbaio/include/media/nbaio/NBLog.h
deleted file mode 100644
index 3e48ee1..0000000
--- a/media/libnbaio/include/media/nbaio/NBLog.h
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Non-blocking event logger intended for safe communication between processes via shared memory
-
-#ifndef ANDROID_MEDIA_NBLOG_H
-#define ANDROID_MEDIA_NBLOG_H
-
-#include <binder/IMemory.h>
-#include <audio_utils/fifo.h>
-#include <utils/Mutex.h>
-#include <utils/threads.h>
-
-#include <map>
-#include <deque>
-#include <set>
-#include <vector>
-
-namespace android {
-
-class String8;
-
-class NBLog {
-
-public:
-
-typedef uint64_t log_hash_t;
-
-// FIXME Everything needed for client (writer API and registration) should be isolated
-//       from the rest of the implementation.
-class Writer;
-class Reader;
-
-enum Event : uint8_t {
-    EVENT_RESERVED,
-    EVENT_STRING,               // ASCII string, not NUL-terminated
-    // TODO: make timestamp optional
-    EVENT_TIMESTAMP,            // clock_gettime(CLOCK_MONOTONIC)
-    EVENT_INTEGER,              // integer value entry
-    EVENT_FLOAT,                // floating point value entry
-    EVENT_PID,                  // process ID and process name
-    EVENT_AUTHOR,               // author index (present in merged logs) tracks entry's original log
-    EVENT_START_FMT,            // logFormat start event: entry includes format string, following
-                                // entries contain format arguments
-    EVENT_HASH,                 // unique HASH of log origin, originates from hash of file name
-                                // and line number
-    EVENT_HISTOGRAM_ENTRY_TS,   // single datum for timestamp histogram
-    EVENT_AUDIO_STATE,          // audio on/off event: logged upon FastMixer::onStateChange() call
-    EVENT_END_FMT,              // end of logFormat argument list
-
-    EVENT_UPPER_BOUND,          // to check for invalid events
-};
-
-private:
-
-// ---------------------------------------------------------------------------
-// API for handling format entry operations
-
-// a formatted entry has the following structure:
-//    * START_FMT entry, containing the format string
-//    * TIMESTAMP entry
-//    * HASH entry
-//    * author entry of the thread that generated it (optional, present in merged log)
-//    * format arg1
-//    * format arg2
-//    * ...
-//    * END_FMT entry
-
-// entry representation in memory
-struct entry {
-    const uint8_t type;
-    const uint8_t length;
-    const uint8_t data[0];
-};
-
-// entry tail representation (after data)
-struct ending {
-    uint8_t length;
-    uint8_t next[0];
-};
-
-// entry iterator
-class EntryIterator {
-public:
-    EntryIterator();
-    explicit EntryIterator(const uint8_t *entry);
-    EntryIterator(const EntryIterator &other);
-
-    // dereference underlying entry
-    const entry&    operator*() const;
-    const entry*    operator->() const;
-    // advance to next entry
-    EntryIterator&       operator++(); // ++i
-    // back to previous entry
-    EntryIterator&       operator--(); // --i
-    EntryIterator        next() const;
-    EntryIterator        prev() const;
-    bool            operator!=(const EntryIterator &other) const;
-    int             operator-(const EntryIterator &other) const;
-
-    bool            hasConsistentLength() const;
-    void            copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
-    void            copyData(uint8_t *dst) const;
-
-    template<typename T>
-    inline const T& payload() {
-        return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
-    }
-
-    inline operator const uint8_t*() const {
-        return ptr;
-    }
-
-private:
-    const uint8_t  *ptr;
-};
-
-class AbstractEntry {
-public:
-
-    // Entry starting in the given pointer
-    explicit AbstractEntry(const uint8_t *entry);
-    virtual ~AbstractEntry() {}
-
-    // build concrete entry of appropriate class from pointer
-    static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
-
-    // get format entry timestamp
-    // TODO consider changing to uint64_t
-    virtual int64_t      timestamp() const = 0;
-
-    // get format entry's unique id
-    virtual log_hash_t   hash() const = 0;
-
-    // entry's author index (-1 if none present)
-    // a Merger has a vector of Readers, author simply points to the index of the
-    // Reader that originated the entry
-    // TODO consider changing to uint32_t
-    virtual int          author() const = 0;
-
-    // copy entry, adding author before timestamp, returns iterator to end of entry
-    virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
-                                       int author) const = 0;
-
-protected:
-    // copies ordinary entry from src to dst, and returns length of entry
-    // size_t      copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
-    const uint8_t  *mEntry;
-};
-
-class FormatEntry : public AbstractEntry {
-public:
-    // explicit FormatEntry(const EntryIterator &it);
-    explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
-    virtual ~FormatEntry() {}
-
-    EntryIterator begin() const;
-
-    // Entry's format string
-    const   char* formatString() const;
-
-    // Enrty's format string length
-            size_t      formatStringLength() const;
-
-    // Format arguments (excluding format string, timestamp and author)
-            EntryIterator    args() const;
-
-    // get format entry timestamp
-    virtual int64_t     timestamp() const override;
-
-    // get format entry's unique id
-    virtual log_hash_t  hash() const override;
-
-    // entry's author index (-1 if none present)
-    // a Merger has a vector of Readers, author simply points to the index of the
-    // Reader that originated the entry
-    virtual int         author() const override;
-
-    // copy entry, adding author before timestamp, returns size of original entry
-    virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
-                                       int author) const override;
-
-};
-
-class HistogramEntry : public AbstractEntry {
-public:
-    explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {
-    }
-    virtual ~HistogramEntry() {}
-
-    virtual int64_t     timestamp() const override;
-
-    virtual log_hash_t  hash() const override;
-
-    virtual int         author() const override;
-
-    virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
-                                       int author) const override;
-
-};
-
-// ---------------------------------------------------------------------------
-
-// representation of a single log entry in private memory
-struct Entry {
-    Entry(Event event, const void *data, size_t length)
-        : mEvent(event), mLength(length), mData(data) { }
-    /*virtual*/ ~Entry() { }
-
-    // used during writing to format Entry information as follows: [type][length][data ... ][length]
-    int     copyEntryDataAt(size_t offset) const;
-
-private:
-    friend class Writer;
-    Event       mEvent;     // event type
-    uint8_t     mLength;    // length of additional data, 0 <= mLength <= kMaxLength
-    const void *mData;      // event type-specific data
-    static const size_t kMaxLength = 255;
-public:
-    // mEvent, mLength, mData[...], duplicate mLength
-    static const size_t kOverhead = sizeof(entry) + sizeof(ending);
-    // endind length of previous entry
-    static const size_t kPreviousLengthOffset = - sizeof(ending) +
-                                                offsetof(ending, length);
-};
-
-struct HistTsEntry {
-    log_hash_t hash;
-    int64_t ts;
-}; //TODO __attribute__((packed));
-
-struct HistTsEntryWithAuthor {
-    log_hash_t hash;
-    int64_t ts;
-    int author;
-}; //TODO __attribute__((packed));
-
-using StateTsEntryWithAuthor = HistTsEntryWithAuthor;
-
-struct HistIntEntry {
-    log_hash_t hash;
-    int value;
-}; //TODO __attribute__((packed));
-
-// representation of a single log entry in shared memory
-//  byte[0]             mEvent
-//  byte[1]             mLength
-//  byte[2]             mData[0]
-//  ...
-//  byte[2+i]           mData[i]
-//  ...
-//  byte[2+mLength-1]   mData[mLength-1]
-//  byte[2+mLength]     duplicate copy of mLength to permit reverse scan
-//  byte[3+mLength]     start of next log entry
-
-    static void    appendInt(String8 *body, const void *data);
-    static void    appendFloat(String8 *body, const void *data);
-    static void    appendPID(String8 *body, const void *data, size_t length);
-    static void    appendTimestamp(String8 *body, const void *data);
-    static size_t  fmtEntryLength(const uint8_t *data);
-    static String8 bufferDump(const uint8_t *buffer, size_t size);
-    static String8 bufferDump(const EntryIterator &it);
-public:
-
-// Located in shared memory, must be POD.
-// Exactly one process must explicitly call the constructor or use placement new.
-// Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
-struct Shared {
-    Shared() /* mRear initialized via default constructor */ { }
-    /*virtual*/ ~Shared() { }
-
-    audio_utils_fifo_index  mRear;  // index one byte past the end of most recent Entry
-    char    mBuffer[0];             // circular buffer for entries
-};
-
-public:
-
-// ---------------------------------------------------------------------------
-
-// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
-// For now it is just a namespace for sharedSize().
-class Timeline : public RefBase {
-public:
-#if 0
-    Timeline(size_t size, void *shared = NULL);
-    virtual ~Timeline();
-#endif
-
-    // Input parameter 'size' is the desired size of the timeline in byte units.
-    // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
-    static size_t sharedSize(size_t size);
-
-#if 0
-private:
-    friend class    Writer;
-    friend class    Reader;
-
-    const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
-    bool            mOwn;       // whether I own the memory at mShared
-    Shared* const   mShared;    // pointer to shared memory
-#endif
-};
-
-// ---------------------------------------------------------------------------
-
-// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
-// calling Writer methods.  If you need multi-thread safety for writing, use LockedWriter.
-class Writer : public RefBase {
-public:
-    Writer();                   // dummy nop implementation without shared memory
-
-    // Input parameter 'size' is the desired size of the timeline in byte units.
-    // The size of the shared memory must be at least Timeline::sharedSize(size).
-    Writer(void *shared, size_t size);
-    Writer(const sp<IMemory>& iMemory, size_t size);
-
-    virtual ~Writer();
-
-    // FIXME needs comments, and some should be private
-    virtual void    log(const char *string);
-    virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
-    virtual void    logvf(const char *fmt, va_list ap);
-    virtual void    logTimestamp();
-    virtual void    logTimestamp(const int64_t ts);
-    virtual void    logInteger(const int x);
-    virtual void    logFloat(const float x);
-    virtual void    logPID();
-    virtual void    logFormat(const char *fmt, log_hash_t hash, ...);
-    virtual void    logVFormat(const char *fmt, log_hash_t hash, va_list ap);
-    virtual void    logStart(const char *fmt);
-    virtual void    logEnd();
-    virtual void    logHash(log_hash_t hash);
-    virtual void    logEventHistTs(Event event, log_hash_t hash);
-
-    virtual bool    isEnabled() const;
-
-    // return value for all of these is the previous isEnabled()
-    virtual bool    setEnabled(bool enabled);   // but won't enable if no shared memory
-            bool    enable()    { return setEnabled(true); }
-            bool    disable()   { return setEnabled(false); }
-
-    sp<IMemory>     getIMemory() const  { return mIMemory; }
-
-private:
-    // 0 <= length <= kMaxLength
-    // writes a single Entry to the FIFO
-    void    log(Event event, const void *data, size_t length);
-    // checks validity of an event before calling log above this one
-    void    log(const Entry *entry, bool trusted = false);
-
-    Shared* const   mShared;    // raw pointer to shared memory
-    sp<IMemory>     mIMemory;   // ref-counted version, initialized in constructor and then const
-    audio_utils_fifo * const mFifo;                 // FIFO itself,
-                                                    // non-NULL unless constructor fails
-    audio_utils_fifo_writer * const mFifoWriter;    // used to write to FIFO,
-                                                    // non-NULL unless dummy constructor used
-    bool            mEnabled;   // whether to actually log
-
-    // cached pid and process name to use in %p format specifier
-    // total tag length is mPidTagSize and process name is not zero terminated
-    char   *mPidTag;
-    size_t  mPidTagSize;
-};
-
-// ---------------------------------------------------------------------------
-
-// Similar to Writer, but safe for multiple threads to call concurrently
-class LockedWriter : public Writer {
-public:
-    LockedWriter();
-    LockedWriter(void *shared, size_t size);
-
-    virtual void    log(const char *string);
-    virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
-    virtual void    logvf(const char *fmt, va_list ap);
-    virtual void    logTimestamp();
-    virtual void    logTimestamp(const int64_t ts);
-    virtual void    logInteger(const int x);
-    virtual void    logFloat(const float x);
-    virtual void    logPID();
-    virtual void    logStart(const char *fmt);
-    virtual void    logEnd();
-    virtual void    logHash(log_hash_t hash);
-
-    virtual bool    isEnabled() const;
-    virtual bool    setEnabled(bool enabled);
-
-private:
-    mutable Mutex   mLock;
-};
-
-// ---------------------------------------------------------------------------
-
-class Reader : public RefBase {
-public:
-
-    // A snapshot of a readers buffer
-    // This is raw data. No analysis has been done on it
-    class Snapshot {
-    public:
-        Snapshot() : mData(NULL), mLost(0) {}
-
-        Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
-
-        ~Snapshot() { delete[] mData; }
-
-        // copy of the buffer
-        uint8_t *data() const { return mData; }
-
-        // amount of data lost (given by audio_utils_fifo_reader)
-        size_t   lost() const { return mLost; }
-
-        // iterator to beginning of readable segment of snapshot
-        // data between begin and end has valid entries
-        EntryIterator begin() { return mBegin; }
-
-        // iterator to end of readable segment of snapshot
-        EntryIterator end() { return mEnd; }
-
-    private:
-        friend class Reader;
-        uint8_t              *mData;
-        size_t                mLost;
-        EntryIterator mBegin;
-        EntryIterator mEnd;
-    };
-
-    // Input parameter 'size' is the desired size of the timeline in byte units.
-    // The size of the shared memory must be at least Timeline::sharedSize(size).
-    Reader(const void *shared, size_t size);
-    Reader(const sp<IMemory>& iMemory, size_t size);
-
-    virtual ~Reader();
-
-    // get snapshot of readers fifo buffer, effectively consuming the buffer
-    std::unique_ptr<Snapshot> getSnapshot();
-    // dump a particular snapshot of the reader
-    // TODO: move dump to PerformanceAnalysis. Model/view/controller design
-    void     dump(int fd, size_t indent, Snapshot & snap);
-    // dump the current content of the reader's buffer (call getSnapshot() and previous dump())
-    void     dump(int fd, size_t indent = 0);
-    bool     isIMemory(const sp<IMemory>& iMemory) const;
-
-private:
-
-    static const std::set<Event> startingTypes;
-    static const std::set<Event> endingTypes;
-    /*const*/ Shared* const mShared;    // raw pointer to shared memory, actually const but not
-                                        // declared as const because audio_utils_fifo() constructor
-    sp<IMemory> mIMemory;       // ref-counted version, assigned only in constructor
-    int     mFd;                // file descriptor
-    int     mIndent;            // indentation level
-    audio_utils_fifo * const mFifo;                 // FIFO itself,
-                                                    // non-NULL unless constructor fails
-    audio_utils_fifo_reader * const mFifoReader;    // used to read from FIFO,
-                                                    // non-NULL unless constructor fails
-
-    // TODO: it might be clearer, instead of a direct map from source location to vector of
-    // timestamps, if we instead first mapped from source location to an object that
-    // represented that location. And one_of its fields would be a vector of timestamps.
-    // That would allow us to record other information about the source location beyond timestamps.
-    void    dumpLine(const String8& timestamp, String8& body);
-
-    EntryIterator   handleFormat(const FormatEntry &fmtEntry,
-                                         String8 *timestamp,
-                                         String8 *body);
-    // dummy method for handling absent author entry
-    virtual void handleAuthor(const AbstractEntry& /*fmtEntry*/, String8* /*body*/) {}
-
-    // Searches for the last entry of type <type> in the range [front, back)
-    // back has to be entry-aligned. Returns nullptr if none enconuntered.
-    static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
-                                         const std::set<Event> &types);
-
-    static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
-};
-
-// Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
-class NamedReader {
-public:
-    NamedReader() { mName[0] = '\0'; } // for Vector
-    NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
-        mReader(reader)
-        { strlcpy(mName, name, sizeof(mName)); }
-    ~NamedReader() { }
-    const sp<NBLog::Reader>&  reader() const { return mReader; }
-    const char*               name() const { return mName; }
-
-private:
-    sp<NBLog::Reader>   mReader;
-    static const size_t kMaxName = 32;
-    char                mName[kMaxName];
-};
-
-// ---------------------------------------------------------------------------
-
-class Merger : public RefBase {
-public:
-    Merger(const void *shared, size_t size);
-
-    virtual ~Merger() {}
-
-    void addReader(const NamedReader &reader);
-    // TODO add removeReader
-    void merge();
-    // FIXME This is returning a reference to a shared variable that needs a lock
-    const std::vector<NamedReader>& getNamedReaders() const;
-private:
-    // vector of the readers the merger is supposed to merge from.
-    // every reader reads from a writer's buffer
-    // FIXME Needs to be protected by a lock
-    std::vector<NamedReader> mNamedReaders;
-
-    // TODO Need comments on all of these
-    Shared * const mShared;
-    std::unique_ptr<audio_utils_fifo> mFifo;
-    std::unique_ptr<audio_utils_fifo_writer> mFifoWriter;
-};
-
-class MergeReader : public Reader {
-public:
-    MergeReader(const void *shared, size_t size, Merger &merger);
-private:
-    // FIXME Needs to be protected by a lock,
-    //       because even though our use of it is read-only there may be asynchronous updates
-    const std::vector<NamedReader>& mNamedReaders;
-    // handle author entry by looking up the author's name and appending it to the body
-    // returns number of bytes read from fmtEntry
-    void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
-};
-
-// MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
-// when triggered, it awakes for a lapse of time, during which it periodically merges; if
-// retriggered, the timeout is reset.
-// The thread is triggered on AudioFlinger binder activity.
-class MergeThread : public Thread {
-public:
-    MergeThread(Merger &merger);
-    virtual ~MergeThread() override;
-
-    // Reset timeout and activate thread to merge periodically if it's idle
-    void wakeup();
-
-    // Set timeout period until the merging thread goes idle again
-    void setTimeoutUs(int time);
-
-private:
-    virtual bool threadLoop() override;
-
-    // the merger who actually does the work of merging the logs
-    Merger&     mMerger;
-
-    // mutex for the condition variable
-    Mutex       mMutex;
-
-    // condition variable to activate merging on timeout >= 0
-    Condition   mCond;
-
-    // time left until the thread blocks again (in microseconds)
-    int         mTimeoutUs;
-
-    // merging period when the thread is awake
-    static const int  kThreadSleepPeriodUs = 1000000 /*1s*/;
-
-    // initial timeout value when triggered
-    static const int  kThreadWakeupPeriodUs = 3000000 /*3s*/;
-};
-
-};  // class NBLog
-
-// TODO put somewhere else
-static inline int64_t get_monotonic_ns() {
-    timespec ts;
-    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
-        return (uint64_t) ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
-    }
-    return 0; // should not happen.
-}
-
-}   // namespace android
-
-#endif  // ANDROID_MEDIA_NBLOG_H
diff --git a/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h b/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
deleted file mode 100644
index b0dc148..0000000
--- a/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Non-blocking event logger intended for safe communication between processes via shared memory
-
-#ifndef ANDROID_MEDIA_PERFORMANCEANALYSIS_H
-#define ANDROID_MEDIA_PERFORMANCEANALYSIS_H
-
-#include <map>
-#include <deque>
-#include <vector>
-#include "NBLog.h"
-#include "ReportPerformance.h"
-
-namespace android {
-
-namespace ReportPerformance {
-
-class PerformanceAnalysis {
-    // This class stores and analyzes audio processing wakeup timestamps from NBLog
-    // FIXME: currently, all performance data is stored in deques. Need to add a mutex.
-    // FIXME: continue this way until analysis is done in a separate thread. Then, use
-    // the fifo writer utilities.
-public:
-
-    PerformanceAnalysis();
-
-    // Given a series of audio processing wakeup timestamps,
-    // compresses and and analyzes the data, and flushes
-    // the timestamp series from memory.
-    void processAndFlushTimeStampSeries();
-
-    // Called when an audio on/off event is read from the buffer,
-    // e.g. EVENT_AUDIO_STATE.
-    // calls flushTimeStampSeries on the data up to the event,
-    // effectively discarding the idle audio time interval
-    void handleStateChange();
-
-    // When the short-term histogram array mRecentHists has reached capacity,
-    // merges histograms for data compression and stores them in mLongTermHists
-    void processAndFlushRecentHists();
-
-    // Writes wakeup timestamp entry to log and runs analysis
-    // TODO: make this thread safe. Each thread should have its own instance
-    // of PerformanceAnalysis.
-    void logTsEntry(timestamp_raw ts);
-
-    // FIXME: make peakdetector and storeOutlierData a single function
-    // Input: mOutlierData. Looks at time elapsed between outliers
-    // finds significant changes in the distribution
-    // writes timestamps of significant changes to mPeakTimestamps
-    void detectPeaks();
-
-    // runs analysis on timestamp series before it is converted to a histogram
-    // finds outliers
-    // writes to mOutlierData <time elapsed since previous outlier, outlier timestamp>
-    void storeOutlierData(const std::vector<timestamp_raw> &timestamps);
-
-    // input: series of short histograms. Generates a string of analysis of the buffer periods
-    // TODO: WIP write more detailed analysis
-    // FIXME: move this data visualization to a separate class. Model/view/controller
-    void reportPerformance(String8 *body, int maxHeight = 10);
-
-    // TODO: delete this. temp for testing
-    void testFunction();
-
-    // This function used to detect glitches in a time series
-    // TODO incorporate this into the analysis (currently unused)
-    void alertIfGlitch(const std::vector<timestamp_raw> &samples);
-
-private:
-
-    // stores outlier analysis: <elapsed time between outliers in ms, outlier timestamp>
-    std::deque<std::pair<outlierInterval, timestamp>> mOutlierData;
-
-    // stores each timestamp at which a peak was detected
-    // a peak is a moment at which the average outlier interval changed significantly
-    std::deque<timestamp> mPeakTimestamps;
-
-    // TODO: turn these into circular buffers for better data flow
-    // FIFO of small histograms
-    // stores fixed-size short buffer period histograms with timestamp of first sample
-    std::deque<std::pair<timestamp, Histogram>> mRecentHists;
-
-    // FIFO of small histograms
-    // stores fixed-size long-term buffer period histograms with timestamp of first sample
-    std::deque<std::pair<timestamp, Histogram>> mLongTermHists;
-
-    // vector of timestamps, collected from NBLog for a (TODO) specific thread
-    // when a vector reaches its maximum size, the data is processed and flushed
-    std::vector<timestamp_raw> mTimeStampSeries;
-
-    static const int kMsPerSec = 1000;
-
-    // Parameters used when detecting outliers
-    // TODO: learn some of these from the data, delete unused ones
-    // FIXME: decide whether to make kPeriodMs static.
-    static const int kNumBuff = 3; // number of buffers considered in local history
-    int kPeriodMs; // current period length is ideally 4 ms
-    static const int kOutlierMs = 7; // values greater or equal to this cause glitches
-    // DAC processing time for 4 ms buffer
-    static constexpr double kRatio = 0.75; // estimate of CPU time as ratio of period length
-    int kPeriodMsCPU; // compute based on kPeriodLen and kRatio
-
-    // Peak detection: number of standard deviations from mean considered a significant change
-    static const int kStddevThreshold = 5;
-
-    // capacity allocated to data structures
-    // TODO: adjust all of these values
-    static const int kRecentHistsCapacity = 100; // number of short-term histograms stored in memory
-    static const int kShortHistSize = 50; // number of samples in a short-term histogram
-    static const int kOutlierSeriesSize = 100; // number of values stored in outlier array
-    static const int kPeakSeriesSize = 100; // number of values stored in peak array
-    static const int kLongTermHistsCapacity = 20; // number of long-term histogram stored in memory
-    // maximum elapsed time between first and last timestamp of a long-term histogram
-    static const int kMaxHistTimespanMs = 5 * kMsPerSec;
-
-    // these variables are stored in-class to ensure continuity while analyzing the timestamp
-    // series one short sequence at a time: the variables are not re-initialized every time.
-    // FIXME: create inner class for these variables and decide which other ones to add to it
-    double mPeakDetectorMean = -1;
-    double mPeakDetectorSd = -1;
-    // variables for storeOutlierData
-    uint64_t mElapsed = 0;
-    int64_t mPrevNs = -1;
-
-};
-
-} // namespace ReportPerformance
-
-}   // namespace android
-
-#endif  // ANDROID_MEDIA_PERFORMANCEANALYSIS_H
diff --git a/media/libnbaio/include/media/nbaio/ReportPerformance.h b/media/libnbaio/include/media/nbaio/ReportPerformance.h
deleted file mode 100644
index 27d2810..0000000
--- a/media/libnbaio/include/media/nbaio/ReportPerformance.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIA_REPORTPERFORMANCE_H
-#define ANDROID_MEDIA_REPORTPERFORMANCE_H
-
-#include <deque>
-#include <map>
-#include <vector>
-
-namespace android {
-
-// This class is used by reportPerformance function
-// TODO move reportPerformance function to ReportPerformance.cpp
-class String8;
-
-namespace ReportPerformance {
-
-// stores a histogram: key: observed buffer period. value: count
-// TODO: unsigned, unsigned
-using Histogram = std::map<int, int>;
-
-using outlierInterval = uint64_t;
-// int64_t timestamps are converted to uint64_t in PerformanceAnalysis::storeOutlierData,
-// and all analysis functions use uint64_t.
-using timestamp = uint64_t;
-using timestamp_raw = int64_t;
-
-// FIXME: decide whether to use 64 or 32 bits
-// TODO: the code has a mix of typedef and using. Standardize to one or the other.
-typedef uint64_t log_hash_t;
-
-static inline int deltaMs(int64_t ns1, int64_t ns2) {
-    return (ns2 - ns1) / (1000 * 1000);
-}
-
-static inline uint32_t log2(uint32_t x) {
-    // This works for x > 0
-    return 31 - __builtin_clz(x);
-}
-
-// Writes outlier intervals, timestamps, and histograms spanning long time
-// intervals to a file.
-void writeToFile(std::deque<std::pair<outlierInterval, timestamp>> &outlierData,
-                 std::deque<std::pair<timestamp, Histogram>> &hists,
-                 const char * kName,
-                 bool append);
-
-} // namespace ReportPerformance
-
-}   // namespace android
-
-#endif  // ANDROID_MEDIA_REPORTPERFORMANCE_H
diff --git a/media/libnblog/Android.bp b/media/libnblog/Android.bp
new file mode 100644
index 0000000..74aaf77
--- /dev/null
+++ b/media/libnblog/Android.bp
@@ -0,0 +1,28 @@
+cc_library_shared {
+
+    name: "libnblog",
+
+    srcs: [
+        "NBLog.cpp",
+        "PerformanceAnalysis.cpp",
+        "ReportPerformance.cpp",
+    ],
+
+    shared_libs: [
+        "libaudioutils",
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    include_dirs: ["system/media/audio_utils/include"],
+
+    export_include_dirs: ["include"],
+
+}
diff --git a/media/libnbaio/NBLog.cpp b/media/libnblog/NBLog.cpp
similarity index 86%
rename from media/libnbaio/NBLog.cpp
rename to media/libnblog/NBLog.cpp
index 2f639d2..c8c7195 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnblog/NBLog.cpp
@@ -12,88 +12,16 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
+ *
  */
 
-/*
-* Documentation: Workflow summary for histogram data processing:
-* For more details on FIFO, please see system/media/audio_utils; doxygen
-* TODO: add this documentation to doxygen once it is further developed
-* 1) Writing buffer period timestamp to the circular buffer
-* onWork()
-*     Called every period length (e.g., 4ms)
-*     Calls LOG_HIST_TS
-* LOG_HIST_TS
-*     Hashes file name and line number, and writes single timestamp to buffer
-*     calls NBLOG::Writer::logEventHistTS once
-* NBLOG::Writer::logEventHistTS
-*     calls NBLOG::Writer::log on hash and current timestamp
-*     time is in CLOCK_MONOTONIC converted to ns
-* NBLOG::Writer::log(Event, const void*, size_t)
-*     Initializes Entry, a struct containing one log entry
-*     Entry contains the event type (mEvent), data length (mLength),
-*     and data pointer (mData)
-*     TODO: why mLength (max length of buffer data)  must be <= kMaxLength = 255?
-*     calls NBLOG::Writer::log(Entry *, bool)
-* NBLog::Writer::log(Entry *, bool)
-*     Calls copyEntryDataAt to format data as follows in temp array:
-*     [type][length][data ... ][length]
-*     calls audio_utils_fifo_writer.write on temp
-* audio_utils_fifo_writer.write
-*     calls obtain(), memcpy (reference in doxygen)
-*     returns number of frames written
-* ssize_t audio_utils_fifo_reader::obtain
-*     Determines readable buffer section via pointer arithmetic on reader
-*     and writer pointers
-* Similarly, LOG_AUDIO_STATE() is called by onStateChange whenever audio is
-* turned on or off, and writes this notification to the FIFO.
-*
-* 2) reading the data from shared memory
-* Thread::threadloop()
-*     TODO: add description?
-* NBLog::MergeThread::threadLoop()
-*     calls NBLog::Merger::merge
-* NBLog::Merger::merge
-*     Merges snapshots sorted by timestamp
-*     for each reader in vector of class NamedReader,
-*     callsNamedReader::reader()->getSnapshot
-*     TODO: check whether the rest of this function is relevant
-* NBLog::Reader::getSnapshot
-*     copies snapshot of reader's fifo buffer into its own buffer
-*     calls mFifoReader->obtain to find readable data
-*     sets snapshot.begin() and .end() iterators to boundaries of valid entries
-*     moves the fifo reader index to after the last entry read
-*     in this case, the buffer is in shared memory. in (4), the buffer is private
-*
-* 3) reading the data from private buffer
-* MediaLogService::dump
-*     calls NBLog::Reader::dump(CONSOLE)
-*     The private buffer contains all logs for all readers in shared memory
-* NBLog::Reader::dump(int)
-*     calls getSnapshot on the current reader
-*     calls dump(int, size_t, Snapshot)
-* NBLog::Reader::dump(int, size, snapshot)
-*     iterates through snapshot's events and switches based on their type
-*     (string, timestamp, etc...)
-*     In the case of EVENT_HISTOGRAM_ENTRY_TS, adds a list of timestamp sequences
-*     (histogram entry) to NBLog::mHists
-*     TODO: add every HISTOGRAM_ENTRY_TS to two
-*     circular buffers: one short-term and one long-term (can add even longer-term
-*     structures in the future). When dump is called, print everything currently
-*     in the buffer.
-* NBLog::drawHistogram
-*     input: timestamp array
-*     buckets this to a histogram and prints
-*
-*/
-
 #define LOG_TAG "NBLog"
-// #define LOG_NDEBUG 0
 
 #include <algorithm>
 #include <climits>
 #include <deque>
 #include <fstream>
-// #include <inttypes.h>
 #include <iostream>
 #include <math.h>
 #include <numeric>
@@ -106,10 +34,10 @@
 #include <time.h>
 #include <new>
 #include <audio_utils/roundup.h>
-#include <media/nbaio/NBLog.h>
-#include <media/nbaio/PerformanceAnalysis.h>
-#include <media/nbaio/ReportPerformance.h>
-// #include <utils/CallStack.h> // used to print callstack
+#include <media/nblog/NBLog.h>
+#include <media/nblog/PerformanceAnalysis.h>
+#include <media/nblog/ReportPerformance.h>
+#include <utils/CallStack.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
 
@@ -760,14 +688,15 @@
 // ---------------------------------------------------------------------------
 
 const std::set<NBLog::Event> NBLog::Reader::startingTypes {NBLog::Event::EVENT_START_FMT,
-                                                           NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS};
+        NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
+        NBLog::Event::EVENT_AUDIO_STATE};
 const std::set<NBLog::Event> NBLog::Reader::endingTypes   {NBLog::Event::EVENT_END_FMT,
-                                                           NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
-                                                           NBLog::Event::EVENT_AUDIO_STATE};
+        NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
+        NBLog::Event::EVENT_AUDIO_STATE};
 
 NBLog::Reader::Reader(const void *shared, size_t size)
-    : mShared((/*const*/ Shared *) shared), /*mIMemory*/
-      mFd(-1), mIndent(0),
+    : mFd(-1), mIndent(0), mLost(0),
+      mShared((/*const*/ Shared *) shared), /*mIMemory*/
       mFifo(mShared != NULL ?
         new audio_utils_fifo(size, sizeof(uint8_t),
             mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
@@ -805,6 +734,9 @@
     return nullptr; // no entry found
 }
 
+// Copies content of a Reader FIFO into its Snapshot
+// The Snapshot has the same raw data, but represented as a sequence of entries
+// and an EntryIterator making it possible to process the data.
 std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot()
 {
     if (mFifoReader == NULL) {
@@ -870,24 +802,11 @@
 
 }
 
-// TODO: move this to PerformanceAnalysis
-// TODO: make call to dump periodic so that data in shared FIFO does not get overwritten
-void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
+// Takes raw content of the local merger FIFO, processes log entries, and
+// writes the data to a map of class PerformanceAnalysis, based on their thread ID.
+void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot)
 {
-    mFd = fd;
-    mIndent = indent;
     String8 timestamp, body;
-    // FIXME: this is not thread safe
-    // TODO: need a separate instance of performanceAnalysis for each thread
-    // used to store data and to call analysis functions
-    static ReportPerformance::PerformanceAnalysis performanceAnalysis;
-    size_t lost = snapshot.lost() + (snapshot.begin() - EntryIterator(snapshot.data()));
-    if (lost > 0) {
-        body.appendFormat("warning: lost %zu bytes worth of events", lost);
-        // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
-        //      log to push it out.  Consider keeping the timestamp/body between calls to copyEntryDataAt().
-        dumpLine(timestamp, body);
-    }
 
     for (auto entry = snapshot.begin(); entry != snapshot.end();) {
         switch (entry->type) {
@@ -902,12 +821,22 @@
             memcpy(&hash, &(data->hash), sizeof(hash));
             int64_t ts;
             memcpy(&ts, &data->ts, sizeof(ts));
-            performanceAnalysis.logTsEntry(ts);
+            // TODO: hash for histogram ts and audio state need to match
+            // and correspond to audio production source file location
+            mThreadPerformanceAnalysis[data->author][0 /*hash*/].logTsEntry(ts);
             ++entry;
             break;
         }
         case EVENT_AUDIO_STATE: {
-            performanceAnalysis.handleStateChange();
+            HistTsEntryWithAuthor *data = (HistTsEntryWithAuthor *) (entry->data);
+            // TODO This memcpies are here to avoid unaligned memory access crash.
+            // There's probably a more efficient way to do it
+            log_hash_t hash;
+            memcpy(&hash, &(data->hash), sizeof(hash));
+            // TODO: remove ts if unused
+            int64_t ts;
+            memcpy(&ts, &data->ts, sizeof(ts));
+            mThreadPerformanceAnalysis[data->author][0 /*hash*/].handleStateChange();
             ++entry;
             break;
         }
@@ -922,19 +851,25 @@
             break;
         }
     }
-    performanceAnalysis.reportPerformance(&body);
+    // FIXME: decide whether to print the warnings here or elsewhere
     if (!body.isEmpty()) {
         dumpLine(timestamp, body);
     }
 }
 
-void NBLog::Reader::dump(int fd, size_t indent)
+void NBLog::MergeReader::getAndProcessSnapshot()
 {
-    // get a snapshot, dump it
+    // get a snapshot, process it
     std::unique_ptr<Snapshot> snap = getSnapshot();
-    dump(fd, indent, *snap);
+    getAndProcessSnapshot(*snap);
 }
 
+void NBLog::MergeReader::dump(int fd, int indent) {
+    // TODO: add a mutex around media.log dump
+    ReportPerformance::dump(fd, indent, mThreadPerformanceAnalysis);
+}
+
+// Writes a string to the console
 void NBLog::Reader::dumpLine(const String8 &timestamp, String8 &body)
 {
     if (mFd >= 0) {
@@ -1093,6 +1028,7 @@
       {}
 
 void NBLog::Merger::addReader(const NBLog::NamedReader &reader) {
+
     // FIXME This is called by binder thread in MediaLogService::registerWriter
     //       but the access to shared variable mNamedReaders is not yet protected by a lock.
     mNamedReaders.push_back(reader);
@@ -1116,7 +1052,7 @@
     return i1.ts > i2.ts || (i1.ts == i2.ts && i1.index > i2.index);
 }
 
-// Merge registered readers, sorted by timestamp
+// Merge registered readers, sorted by timestamp, and write data to a single FIFO in local memory
 void NBLog::Merger::merge() {
     // FIXME This is called by merge thread
     //       but the access to shared variable mNamedReaders is not yet protected by a lock.
@@ -1173,8 +1109,9 @@
 
 // ---------------------------------------------------------------------------
 
-NBLog::MergeThread::MergeThread(NBLog::Merger &merger)
+NBLog::MergeThread::MergeThread(NBLog::Merger &merger, NBLog::MergeReader &mergeReader)
     : mMerger(merger),
+      mMergeReader(mergeReader),
       mTimeoutUs(0) {}
 
 NBLog::MergeThread::~MergeThread() {
@@ -1196,7 +1133,12 @@
         mTimeoutUs -= kThreadSleepPeriodUs;
     }
     if (doMerge) {
+        // Merge data from all the readers
         mMerger.merge();
+        // Process the data collected by mMerger and write it to PerformanceAnalysis
+        // FIXME: decide whether to call getAndProcessSnapshot every time
+        // or whether to have a separate thread that calls it with a lower frequency
+        mMergeReader.getAndProcessSnapshot();
     }
     return true;
 }
diff --git a/media/libnblog/PerformanceAnalysis.cpp b/media/libnblog/PerformanceAnalysis.cpp
new file mode 100644
index 0000000..478c460
--- /dev/null
+++ b/media/libnblog/PerformanceAnalysis.cpp
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#define LOG_TAG "PerformanceAnalysis"
+// #define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <climits>
+#include <deque>
+#include <iostream>
+#include <math.h>
+#include <numeric>
+#include <vector>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <time.h>
+#include <new>
+#include <audio_utils/roundup.h>
+#include <media/nblog/NBLog.h>
+#include <media/nblog/PerformanceAnalysis.h>
+#include <media/nblog/ReportPerformance.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <queue>
+#include <utility>
+
+namespace android {
+
+namespace ReportPerformance {
+
+// Given an audio processing wakeup timestamp, buckets the time interval
+// since the previous timestamp into a histogram, searches for
+// outliers, analyzes the outlier series for unexpectedly
+// small or large values and stores these as peaks
+void PerformanceAnalysis::logTsEntry(timestamp ts) {
+    // after a state change, start a new series and do not
+    // record time intervals in-between
+    if (mBufferPeriod.mPrevTs == 0) {
+        mBufferPeriod.mPrevTs = ts;
+        return;
+    }
+
+    // calculate time interval between current and previous timestamp
+    const msInterval diffMs = static_cast<msInterval>(
+        deltaMs(mBufferPeriod.mPrevTs, ts));
+
+    const int diffJiffy = deltaJiffy(mBufferPeriod.mPrevTs, ts);
+
+    // old versus new weight ratio when updating the buffer period mean
+    static constexpr double exponentialWeight = 0.999;
+    // update buffer period mean with exponential weighting
+    mBufferPeriod.mMean = (mBufferPeriod.mMean < 0) ? diffMs :
+            exponentialWeight * mBufferPeriod.mMean + (1.0 - exponentialWeight) * diffMs;
+    // set mOutlierFactor to a smaller value for the fastmixer thread
+    const int kFastMixerMax = 10;
+    // NormalMixer times vary much more than FastMixer times.
+    // TODO: mOutlierFactor values are set empirically based on what appears to be
+    // an outlier. Learn these values from the data.
+    mBufferPeriod.mOutlierFactor = mBufferPeriod.mMean < kFastMixerMax ? 1.8 : 2.0;
+    // set outlier threshold
+    mBufferPeriod.mOutlier = mBufferPeriod.mMean * mBufferPeriod.mOutlierFactor;
+
+    // Check whether the time interval between the current timestamp
+    // and the previous one is long enough to count as an outlier
+    const bool isOutlier = detectAndStoreOutlier(diffMs);
+    // If an outlier was found, check whether it was a peak
+    if (isOutlier) {
+        /*bool isPeak =*/ detectAndStorePeak(
+            mOutlierData[0].first, mOutlierData[0].second);
+        // TODO: decide whether to insert a new empty histogram if a peak
+        // TODO: remove isPeak if unused to avoid "unused variable" error
+        // occurred at the current timestamp
+    }
+
+    // Insert a histogram to mHists if it is empty, or
+    // close the current histogram and insert a new empty one if
+    // if the current histogram has spanned its maximum time interval.
+    if (mHists.empty() ||
+        deltaMs(mHists[0].first, ts) >= kMaxLength.HistTimespanMs) {
+        mHists.emplace_front(ts, std::map<int, int>());
+        // When memory is full, delete oldest histogram
+        // TODO: use a circular buffer
+        if (mHists.size() >= kMaxLength.Hists) {
+            mHists.resize(kMaxLength.Hists);
+        }
+    }
+    // add current time intervals to histogram
+    ++mHists[0].second[diffJiffy];
+    // update previous timestamp
+    mBufferPeriod.mPrevTs = ts;
+}
+
+
+// forces short-term histogram storage to avoid adding idle audio time interval
+// to buffer period data
+void PerformanceAnalysis::handleStateChange() {
+    mBufferPeriod.mPrevTs = 0;
+    return;
+}
+
+
+// Checks whether the time interval between two outliers is far enough from
+// a typical delta to be considered a peak.
+// looks for changes in distribution (peaks), which can be either positive or negative.
+// The function sets the mean to the starting value and sigma to 0, and updates
+// them as long as no peak is detected. When a value is more than 'threshold'
+// standard deviations from the mean, a peak is detected and the mean and sigma
+// are set to the peak value and 0.
+bool PerformanceAnalysis::detectAndStorePeak(msInterval diff, timestamp ts) {
+    bool isPeak = false;
+    if (mOutlierData.empty()) {
+        return false;
+    }
+    // Update mean of the distribution
+    // TypicalDiff is used to check whether a value is unusually large
+    // when we cannot use standard deviations from the mean because the sd is set to 0.
+    mOutlierDistribution.mTypicalDiff = (mOutlierDistribution.mTypicalDiff *
+            (mOutlierData.size() - 1) + diff) / mOutlierData.size();
+
+    // Initialize short-term mean at start of program
+    if (mOutlierDistribution.mMean == 0) {
+        mOutlierDistribution.mMean = diff;
+    }
+    // Update length of current sequence of outliers
+    mOutlierDistribution.mN++;
+
+    // Check whether a large deviation from the mean occurred.
+    // If the standard deviation has been reset to zero, the comparison is
+    // instead to the mean of the full mOutlierInterval sequence.
+    if ((fabs(diff - mOutlierDistribution.mMean) <
+            mOutlierDistribution.kMaxDeviation * mOutlierDistribution.mSd) ||
+            (mOutlierDistribution.mSd == 0 &&
+            fabs(diff - mOutlierDistribution.mMean) <
+            mOutlierDistribution.mTypicalDiff)) {
+        // update the mean and sd using online algorithm
+        // https://en.wikipedia.org/wiki/
+        // Algorithms_for_calculating_variance#Online_algorithm
+        mOutlierDistribution.mN++;
+        const double kDelta = diff - mOutlierDistribution.mMean;
+        mOutlierDistribution.mMean += kDelta / mOutlierDistribution.mN;
+        const double kDelta2 = diff - mOutlierDistribution.mMean;
+        mOutlierDistribution.mM2 += kDelta * kDelta2;
+        mOutlierDistribution.mSd = (mOutlierDistribution.mN < 2) ? 0 :
+                sqrt(mOutlierDistribution.mM2 / (mOutlierDistribution.mN - 1));
+    } else {
+        // new value is far from the mean:
+        // store peak timestamp and reset mean, sd, and short-term sequence
+        isPeak = true;
+        mPeakTimestamps.emplace_front(ts);
+        // if mPeaks has reached capacity, delete oldest data
+        // Note: this means that mOutlierDistribution values do not exactly
+        // match the data we have in mPeakTimestamps, but this is not an issue
+        // in practice for estimating future peaks.
+        // TODO: turn this into a circular buffer
+        if (mPeakTimestamps.size() >= kMaxLength.Peaks) {
+            mPeakTimestamps.resize(kMaxLength.Peaks);
+        }
+        mOutlierDistribution.mMean = 0;
+        mOutlierDistribution.mSd = 0;
+        mOutlierDistribution.mN = 0;
+        mOutlierDistribution.mM2 = 0;
+    }
+    return isPeak;
+}
+
+
+// Determines whether the difference between a timestamp and the previous
+// one is beyond a threshold. If yes, stores the timestamp as an outlier
+// and writes to mOutlierdata in the following format:
+// Time elapsed since previous outlier: Timestamp of start of outlier
+// e.g. timestamps (ms) 1, 4, 5, 16, 18, 28 will produce pairs (4, 5), (13, 18).
+// TODO: learn what timestamp sequences correlate with glitches instead of
+// manually designing a heuristic.
+bool PerformanceAnalysis::detectAndStoreOutlier(const msInterval diffMs) {
+    bool isOutlier = false;
+    if (diffMs >= mBufferPeriod.mOutlier) {
+        isOutlier = true;
+        mOutlierData.emplace_front(
+                mOutlierDistribution.mElapsed, mBufferPeriod.mPrevTs);
+        // Remove oldest value if the vector is full
+        // TODO: turn this into a circular buffer
+        // TODO: make sure kShortHistSize is large enough that that data will never be lost
+        // before being written to file or to a FIFO
+        if (mOutlierData.size() >= kMaxLength.Outliers) {
+            mOutlierData.resize(kMaxLength.Outliers);
+        }
+        mOutlierDistribution.mElapsed = 0;
+    }
+    mOutlierDistribution.mElapsed += diffMs;
+    return isOutlier;
+}
+
+static int widthOf(int x) {
+    int width = 0;
+    if (x < 0) {
+        width++;
+        x = x == INT_MIN ? INT_MAX : -x;
+    }
+    // assert (x >= 0)
+    do {
+        ++width;
+        x /= 10;
+    } while (x > 0);
+    return width;
+}
+
+// computes the column width required for a specific histogram value
+inline int numberWidth(double number, int leftPadding) {
+    // Added values account for whitespaces needed around numbers, and for the
+    // dot and decimal digit not accounted for by widthOf
+    return std::max(std::max(widthOf(static_cast<int>(number)) + 3, 2), leftPadding + 1);
+}
+
+// rounds value to precision based on log-distance from mean
+inline double logRound(double x, double mean) {
+    // Larger values decrease range of high resolution and prevent overflow
+    // of a histogram on the console.
+    // The following formula adjusts kBase based on the buffer period length.
+    // Different threads have buffer periods ranging from 2 to 40. The
+    // formula below maps buffer period 2 to kBase = ~1, 4 to ~2, 20 to ~3, 40 to ~4.
+    // TODO: tighten this for higher means, the data still overflows
+    const double kBase = log(mean) / log(2.2);
+    const double power = floor(
+        log(abs(x - mean) / mean) / log(kBase)) + 2;
+    // do not round values close to the mean
+    if (power < 1) {
+        return x;
+    }
+    const int factor = static_cast<int>(pow(10, power));
+    return (static_cast<int>(x) * factor) / factor;
+}
+
+// TODO Make it return a std::string instead of modifying body
+// TODO: move this to ReportPerformance, probably make it a friend function
+// of PerformanceAnalysis
+void PerformanceAnalysis::reportPerformance(String8 *body, int author, log_hash_t hash,
+                                            int maxHeight) {
+    if (mHists.empty()) {
+        return;
+    }
+
+    // ms of active audio in displayed histogram
+    double elapsedMs = 0;
+    // starting timestamp of histogram
+    timestamp startingTs = mHists[0].first;
+
+    // histogram which stores .1 precision ms counts instead of Jiffy multiple counts
+    std::map<double, int> buckets;
+    for (const auto &shortHist: mHists) {
+        for (const auto &countPair : shortHist.second) {
+            const double ms = static_cast<double>(countPair.first) / kJiffyPerMs;
+            buckets[logRound(ms, mBufferPeriod.mMean)] += countPair.second;
+            elapsedMs += ms * countPair.second;
+        }
+    }
+
+    // underscores and spaces length corresponds to maximum width of histogram
+    static const int kLen = 200;
+    std::string underscores(kLen, '_');
+    std::string spaces(kLen, ' ');
+
+    auto it = buckets.begin();
+    double maxDelta = it->first;
+    int maxCount = it->second;
+    // Compute maximum values
+    while (++it != buckets.end()) {
+        if (it->first > maxDelta) {
+            maxDelta = it->first;
+        }
+        if (it->second > maxCount) {
+            maxCount = it->second;
+        }
+    }
+    int height = log2(maxCount) + 1; // maxCount > 0, safe to call log2
+    const int leftPadding = widthOf(1 << height);
+    const int bucketWidth = numberWidth(maxDelta, leftPadding);
+    int scalingFactor = 1;
+    // scale data if it exceeds maximum height
+    if (height > maxHeight) {
+        scalingFactor = (height + maxHeight) / maxHeight;
+        height /= scalingFactor;
+    }
+    body->appendFormat("\n%*s %3.2f %s", leftPadding + 11,
+            "Occurrences in", (elapsedMs / kMsPerSec), "seconds of audio:");
+    body->appendFormat("\n%*s%d, %lld, %lld\n", leftPadding + 11,
+            "Thread, hash, starting timestamp: ", author,
+            static_cast<long long int>(hash), static_cast<long long int>(startingTs));
+    // write histogram label line with bucket values
+    body->appendFormat("\n%s", " ");
+    body->appendFormat("%*s", leftPadding, " ");
+    for (auto const &x : buckets) {
+        const int colWidth = numberWidth(x.first, leftPadding);
+        body->appendFormat("%*d", colWidth, x.second);
+    }
+    // write histogram ascii art
+    body->appendFormat("\n%s", " ");
+    for (int row = height * scalingFactor; row >= 0; row -= scalingFactor) {
+        const int value = 1 << row;
+        body->appendFormat("%.*s", leftPadding, spaces.c_str());
+        for (auto const &x : buckets) {
+            const int colWidth = numberWidth(x.first, leftPadding);
+            body->appendFormat("%.*s%s", colWidth - 1,
+                               spaces.c_str(), x.second < value ? " " : "|");
+        }
+        body->appendFormat("\n%s", " ");
+    }
+    // print x-axis
+    const int columns = static_cast<int>(buckets.size());
+    body->appendFormat("%*c", leftPadding, ' ');
+    body->appendFormat("%.*s", (columns + 1) * bucketWidth, underscores.c_str());
+    body->appendFormat("\n%s", " ");
+
+    // write footer with bucket labels
+    body->appendFormat("%*s", leftPadding, " ");
+    for (auto const &x : buckets) {
+        const int colWidth = numberWidth(x.first, leftPadding);
+        body->appendFormat("%*.*f", colWidth, 1, x.first);
+    }
+    body->appendFormat("%.*s%s", bucketWidth, spaces.c_str(), "ms\n");
+
+    // Now report glitches
+    body->appendFormat("\ntime elapsed between glitches and glitch timestamps:\n");
+    for (const auto &outlier: mOutlierData) {
+        body->appendFormat("%lld: %lld\n", static_cast<long long>(outlier.first),
+                           static_cast<long long>(outlier.second));
+    }
+}
+
+//------------------------------------------------------------------------------
+
+// writes summary of performance into specified file descriptor
+void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) {
+    String8 body;
+    const char* const kDirectory = "/data/misc/audioserver/";
+    for (auto & thread : threadPerformanceAnalysis) {
+        for (auto & hash: thread.second) {
+            PerformanceAnalysis& curr = hash.second;
+            // write performance data to console
+            curr.reportPerformance(&body, thread.first, hash.first);
+            if (!body.isEmpty()) {
+                dumpLine(fd, indent, body);
+                body.clear();
+            }
+            // write to file
+            writeToFile(curr.mHists, curr.mOutlierData, curr.mPeakTimestamps,
+                        kDirectory, false, thread.first, hash.first);
+        }
+    }
+}
+
+
+// Writes a string into specified file descriptor
+void dumpLine(int fd, int indent, const String8 &body) {
+    dprintf(fd, "%.*s%s \n", indent, "", body.string());
+}
+
+} // namespace ReportPerformance
+
+}   // namespace android
diff --git a/media/libnblog/ReportPerformance.cpp b/media/libnblog/ReportPerformance.cpp
new file mode 100644
index 0000000..827e731
--- /dev/null
+++ b/media/libnblog/ReportPerformance.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ReportPerformance"
+
+#include <fstream>
+#include <iostream>
+#include <queue>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sstream>
+#include <sys/prctl.h>
+#include <sys/time.h>
+#include <utility>
+#include <media/nblog/NBLog.h>
+#include <media/nblog/PerformanceAnalysis.h>
+#include <media/nblog/ReportPerformance.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+namespace android {
+
+namespace ReportPerformance {
+
+
+// TODO: use a function like this to extract logic from writeToFile
+// https://stackoverflow.com/a/9279620
+
+// Writes outlier intervals, timestamps, and histograms spanning long time intervals to file.
+// TODO: write data in binary format
+void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists,
+                 const std::deque<std::pair<msInterval, timestamp>> &outlierData,
+                 const std::deque<timestamp> &peakTimestamps,
+                 const char * directory, bool append, int author, log_hash_t hash) {
+
+    // TODO: remove old files, implement rotating files as in AudioFlinger.cpp
+
+    if (outlierData.empty() && hists.empty() && peakTimestamps.empty()) {
+        ALOGW("No data, returning.");
+        return;
+    }
+
+    std::stringstream outlierName;
+    std::stringstream histogramName;
+    std::stringstream peakName;
+
+    // get current time
+    char currTime[16]; //YYYYMMDDHHMMSS + '\0' + one unused
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    struct tm tm;
+    localtime_r(&tv.tv_sec, &tm);
+    strftime(currTime, sizeof(currTime), "%Y%m%d%H%M%S", &tm);
+
+    // generate file names
+    std::stringstream common;
+    common << author << "_" << hash << "_" << currTime << ".csv";
+
+    histogramName << directory << "histograms_" << common.str();
+    outlierName << directory << "outliers_" << common.str();
+    peakName << directory << "peaks_" << common.str();
+
+    std::ofstream hfs;
+    hfs.open(histogramName.str(), append ? std::ios::app : std::ios::trunc);
+    if (!hfs.is_open()) {
+        ALOGW("couldn't open file %s", histogramName.str().c_str());
+        return;
+    }
+    // each histogram is written as a line where the first value is the timestamp and
+    // subsequent values are pairs of buckets and counts. Each value is separated
+    // by a comma, and each histogram is separated by a newline.
+    for (auto hist = hists.begin(); hist != hists.end(); ++hist) {
+        hfs << hist->first << ", ";
+        for (auto bucket = hist->second.begin(); bucket != hist->second.end(); ++bucket) {
+            hfs << bucket->first / static_cast<double>(kJiffyPerMs)
+                << ", " << bucket->second;
+            if (std::next(bucket) != end(hist->second)) {
+                hfs << ", ";
+            }
+        }
+        if (std::next(hist) != end(hists)) {
+            hfs << "\n";
+        }
+    }
+    hfs.close();
+
+    std::ofstream ofs;
+    ofs.open(outlierName.str(), append ? std::ios::app : std::ios::trunc);
+    if (!ofs.is_open()) {
+        ALOGW("couldn't open file %s", outlierName.str().c_str());
+        return;
+    }
+    // outliers are written as pairs separated by newlines, where each
+    // pair's values are separated by a comma
+    for (const auto &outlier : outlierData) {
+        ofs << outlier.first << ", " << outlier.second << "\n";
+    }
+    ofs.close();
+
+    std::ofstream pfs;
+    pfs.open(peakName.str(), append ? std::ios::app : std::ios::trunc);
+    if (!pfs.is_open()) {
+        ALOGW("couldn't open file %s", peakName.str().c_str());
+        return;
+    }
+    // peaks are simply timestamps separated by commas
+    for (auto peak = peakTimestamps.begin(); peak != peakTimestamps.end(); ++peak) {
+        pfs << *peak;
+        if (std::next(peak) != end(peakTimestamps)) {
+            pfs << ", ";
+        }
+    }
+    pfs.close();
+}
+
+} // namespace ReportPerformance
+
+}   // namespace android
diff --git a/media/libnblog/include/media/nblog/NBLog.h b/media/libnblog/include/media/nblog/NBLog.h
new file mode 100644
index 0000000..ebb88f0
--- /dev/null
+++ b/media/libnblog/include/media/nblog/NBLog.h
@@ -0,0 +1,613 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Non-blocking event logger intended for safe communication between processes via shared memory
+
+#ifndef ANDROID_MEDIA_NBLOG_H
+#define ANDROID_MEDIA_NBLOG_H
+
+#include <deque>
+#include <map>
+#include <set>
+#include <vector>
+
+#include <audio_utils/fifo.h>
+#include <binder/IMemory.h>
+#include <media/nblog/PerformanceAnalysis.h>
+#include <media/nblog/ReportPerformance.h>
+#include <utils/Mutex.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class String8;
+
+class NBLog {
+
+public:
+
+    using log_hash_t = ReportPerformance::log_hash_t;
+
+    // FIXME Everything needed for client (writer API and registration) should be isolated
+    //       from the rest of the implementation.
+    class Writer;
+    class Reader;
+
+    enum Event : uint8_t {
+        EVENT_RESERVED,
+        EVENT_STRING,               // ASCII string, not NUL-terminated
+                                    // TODO: make timestamp optional
+        EVENT_TIMESTAMP,            // clock_gettime(CLOCK_MONOTONIC)
+        EVENT_INTEGER,              // integer value entry
+        EVENT_FLOAT,                // floating point value entry
+        EVENT_PID,                  // process ID and process name
+        EVENT_AUTHOR,               // author index (present in merged logs) tracks entry's
+                                    // original log
+        EVENT_START_FMT,            // logFormat start event: entry includes format string,
+                                    // following entries contain format arguments
+        EVENT_HASH,                 // unique HASH of log origin, originates from hash of file name
+                                    // and line number
+        EVENT_HISTOGRAM_ENTRY_TS,   // single datum for timestamp histogram
+        EVENT_AUDIO_STATE,          // audio on/off event: logged on FastMixer::onStateChange call
+        EVENT_END_FMT,              // end of logFormat argument list
+
+        EVENT_UPPER_BOUND,          // to check for invalid events
+    };
+
+private:
+
+    // ---------------------------------------------------------------------------
+    // API for handling format entry operations
+
+    // a formatted entry has the following structure:
+    //    * START_FMT entry, containing the format string
+    //    * TIMESTAMP entry
+    //    * HASH entry
+    //    * author entry of the thread that generated it (optional, present in merged log)
+    //    * format arg1
+    //    * format arg2
+    //    * ...
+    //    * END_FMT entry
+
+    // entry representation in memory
+    struct entry {
+        const uint8_t type;
+        const uint8_t length;
+        const uint8_t data[0];
+    };
+
+    // entry tail representation (after data)
+    struct ending {
+        uint8_t length;
+        uint8_t next[0];
+    };
+
+    // entry iterator
+    class EntryIterator {
+    public:
+        EntryIterator();
+        explicit EntryIterator(const uint8_t *entry);
+        EntryIterator(const EntryIterator &other);
+
+        // dereference underlying entry
+        const entry&    operator*() const;
+        const entry*    operator->() const;
+        // advance to next entry
+        EntryIterator&       operator++(); // ++i
+        // back to previous entry
+        EntryIterator&       operator--(); // --i
+        EntryIterator        next() const;
+        EntryIterator        prev() const;
+        bool            operator!=(const EntryIterator &other) const;
+        int             operator-(const EntryIterator &other) const;
+
+        bool            hasConsistentLength() const;
+        void            copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
+        void            copyData(uint8_t *dst) const;
+
+        template<typename T>
+        inline const T& payload() {
+            return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
+        }
+
+        inline operator const uint8_t*() const {
+            return ptr;
+        }
+
+    private:
+        const uint8_t  *ptr;
+    };
+
+    class AbstractEntry {
+    public:
+
+        // Entry starting in the given pointer
+        explicit AbstractEntry(const uint8_t *entry);
+        virtual ~AbstractEntry() {}
+
+        // build concrete entry of appropriate class from pointer
+        static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
+
+        // get format entry timestamp
+        virtual int64_t      timestamp() const = 0;
+
+        // get format entry's unique id
+        virtual log_hash_t   hash() const = 0;
+
+        // entry's author index (-1 if none present)
+        // a Merger has a vector of Readers, author simply points to the index of the
+        // Reader that originated the entry
+        // TODO consider changing to uint32_t
+        virtual int          author() const = 0;
+
+        // copy entry, adding author before timestamp, returns iterator to end of entry
+        virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+                                                int author) const = 0;
+
+    protected:
+        // copies ordinary entry from src to dst, and returns length of entry
+        // size_t      copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
+        const uint8_t  *mEntry;
+    };
+
+    class FormatEntry : public AbstractEntry {
+    public:
+        // explicit FormatEntry(const EntryIterator &it);
+        explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
+        virtual ~FormatEntry() {}
+
+        EntryIterator begin() const;
+
+        // Entry's format string
+        const   char* formatString() const;
+
+        // Enrty's format string length
+        size_t      formatStringLength() const;
+
+        // Format arguments (excluding format string, timestamp and author)
+        EntryIterator    args() const;
+
+        // get format entry timestamp
+        virtual int64_t     timestamp() const override;
+
+        // get format entry's unique id
+        virtual log_hash_t  hash() const override;
+
+        // entry's author index (-1 if none present)
+        // a Merger has a vector of Readers, author simply points to the index of the
+        // Reader that originated the entry
+        virtual int         author() const override;
+
+        // copy entry, adding author before timestamp, returns size of original entry
+        virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+                                                int author) const override;
+
+    };
+
+    class HistogramEntry : public AbstractEntry {
+    public:
+        explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {
+        }
+        virtual ~HistogramEntry() {}
+
+        virtual int64_t     timestamp() const override;
+
+        virtual log_hash_t  hash() const override;
+
+        virtual int         author() const override;
+
+        virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+                                                int author) const override;
+
+    };
+
+    // ---------------------------------------------------------------------------
+
+    // representation of a single log entry in private memory
+    struct Entry {
+        Entry(Event event, const void *data, size_t length)
+            : mEvent(event), mLength(length), mData(data) { }
+        /*virtual*/ ~Entry() { }
+
+        // used during writing to format Entry information as follows:
+        // [type][length][data ... ][length]
+        int     copyEntryDataAt(size_t offset) const;
+
+    private:
+        friend class Writer;
+        Event       mEvent;     // event type
+        uint8_t     mLength;    // length of additional data, 0 <= mLength <= kMaxLength
+        const void *mData;      // event type-specific data
+        static const size_t kMaxLength = 255;
+    public:
+        // mEvent, mLength, mData[...], duplicate mLength
+        static const size_t kOverhead = sizeof(entry) + sizeof(ending);
+        // endind length of previous entry
+        static const size_t kPreviousLengthOffset = - sizeof(ending) +
+            offsetof(ending, length);
+    };
+
+    struct HistTsEntry {
+        log_hash_t hash;
+        int64_t ts;
+    }; //TODO __attribute__((packed));
+
+    struct HistTsEntryWithAuthor {
+        log_hash_t hash;
+        int64_t ts;
+        int author;
+    }; //TODO __attribute__((packed));
+
+    struct HistIntEntry {
+        log_hash_t hash;
+        int value;
+    }; //TODO __attribute__((packed));
+
+    // representation of a single log entry in shared memory
+    //  byte[0]             mEvent
+    //  byte[1]             mLength
+    //  byte[2]             mData[0]
+    //  ...
+    //  byte[2+i]           mData[i]
+    //  ...
+    //  byte[2+mLength-1]   mData[mLength-1]
+    //  byte[2+mLength]     duplicate copy of mLength to permit reverse scan
+    //  byte[3+mLength]     start of next log entry
+
+    static void    appendInt(String8 *body, const void *data);
+    static void    appendFloat(String8 *body, const void *data);
+    static void    appendPID(String8 *body, const void *data, size_t length);
+    static void    appendTimestamp(String8 *body, const void *data);
+    static size_t  fmtEntryLength(const uint8_t *data);
+    static String8 bufferDump(const uint8_t *buffer, size_t size);
+    static String8 bufferDump(const EntryIterator &it);
+public:
+
+    // Located in shared memory, must be POD.
+    // Exactly one process must explicitly call the constructor or use placement new.
+    // Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
+    struct Shared {
+        Shared() /* mRear initialized via default constructor */ { }
+        /*virtual*/ ~Shared() { }
+
+        audio_utils_fifo_index  mRear;  // index one byte past the end of most recent Entry
+        char    mBuffer[0];             // circular buffer for entries
+    };
+
+public:
+
+    // ---------------------------------------------------------------------------
+
+    // FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
+    // For now it is just a namespace for sharedSize().
+    class Timeline : public RefBase {
+    public:
+#if 0
+        Timeline(size_t size, void *shared = NULL);
+        virtual ~Timeline();
+#endif
+
+        // Input parameter 'size' is the desired size of the timeline in byte units.
+        // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
+        static size_t sharedSize(size_t size);
+
+#if 0
+    private:
+        friend class    Writer;
+        friend class    Reader;
+
+        const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
+        bool            mOwn;       // whether I own the memory at mShared
+        Shared* const   mShared;    // pointer to shared memory
+#endif
+    };
+
+    // ---------------------------------------------------------------------------
+
+    // Writer is thread-safe with respect to Reader, but not with respect to multiple threads
+    // calling Writer methods.  If you need multi-thread safety for writing, use LockedWriter.
+    class Writer : public RefBase {
+    public:
+        Writer();                   // dummy nop implementation without shared memory
+
+        // Input parameter 'size' is the desired size of the timeline in byte units.
+        // The size of the shared memory must be at least Timeline::sharedSize(size).
+        Writer(void *shared, size_t size);
+        Writer(const sp<IMemory>& iMemory, size_t size);
+
+        virtual ~Writer();
+
+        // FIXME needs comments, and some should be private
+        virtual void    log(const char *string);
+        virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+        virtual void    logvf(const char *fmt, va_list ap);
+        virtual void    logTimestamp();
+        virtual void    logTimestamp(const int64_t ts);
+        virtual void    logInteger(const int x);
+        virtual void    logFloat(const float x);
+        virtual void    logPID();
+        virtual void    logFormat(const char *fmt, log_hash_t hash, ...);
+        virtual void    logVFormat(const char *fmt, log_hash_t hash, va_list ap);
+        virtual void    logStart(const char *fmt);
+        virtual void    logEnd();
+        virtual void    logHash(log_hash_t hash);
+        virtual void    logEventHistTs(Event event, log_hash_t hash);
+
+        virtual bool    isEnabled() const;
+
+        // return value for all of these is the previous isEnabled()
+        virtual bool    setEnabled(bool enabled);   // but won't enable if no shared memory
+        bool    enable()    { return setEnabled(true); }
+        bool    disable()   { return setEnabled(false); }
+
+        sp<IMemory>     getIMemory() const  { return mIMemory; }
+
+    private:
+        // 0 <= length <= kMaxLength
+        // writes a single Entry to the FIFO
+        void    log(Event event, const void *data, size_t length);
+        // checks validity of an event before calling log above this one
+        void    log(const Entry *entry, bool trusted = false);
+
+        Shared* const   mShared;    // raw pointer to shared memory
+        sp<IMemory>     mIMemory;   // ref-counted version, initialized in constructor
+                                    // and then const
+        audio_utils_fifo * const mFifo;                 // FIFO itself, non-NULL
+                                                        // unless constructor fails
+        audio_utils_fifo_writer * const mFifoWriter;    // used to write to FIFO, non-NULL
+                                                        // unless dummy constructor used
+        bool            mEnabled;   // whether to actually log
+
+        // cached pid and process name to use in %p format specifier
+        // total tag length is mPidTagSize and process name is not zero terminated
+        char   *mPidTag;
+        size_t  mPidTagSize;
+    };
+
+    // ---------------------------------------------------------------------------
+
+    // Similar to Writer, but safe for multiple threads to call concurrently
+    class LockedWriter : public Writer {
+    public:
+        LockedWriter();
+        LockedWriter(void *shared, size_t size);
+
+        virtual void    log(const char *string);
+        virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+        virtual void    logvf(const char *fmt, va_list ap);
+        virtual void    logTimestamp();
+        virtual void    logTimestamp(const int64_t ts);
+        virtual void    logInteger(const int x);
+        virtual void    logFloat(const float x);
+        virtual void    logPID();
+        virtual void    logStart(const char *fmt);
+        virtual void    logEnd();
+        virtual void    logHash(log_hash_t hash);
+
+        virtual bool    isEnabled() const;
+        virtual bool    setEnabled(bool enabled);
+
+    private:
+        mutable Mutex   mLock;
+    };
+
+    // ---------------------------------------------------------------------------
+
+    class Reader : public RefBase {
+    public:
+        // A snapshot of a readers buffer
+        // This is raw data. No analysis has been done on it
+        class Snapshot {
+        public:
+            Snapshot() : mData(NULL), mLost(0) {}
+
+            Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
+
+            ~Snapshot() { delete[] mData; }
+
+            // copy of the buffer
+            uint8_t *data() const { return mData; }
+
+            // amount of data lost (given by audio_utils_fifo_reader)
+            size_t   lost() const { return mLost; }
+
+            // iterator to beginning of readable segment of snapshot
+            // data between begin and end has valid entries
+            EntryIterator begin() { return mBegin; }
+
+            // iterator to end of readable segment of snapshot
+            EntryIterator end() { return mEnd; }
+
+        private:
+            friend class MergeReader;
+            friend class Reader;
+            uint8_t              *mData;
+            size_t                mLost;
+            EntryIterator mBegin;
+            EntryIterator mEnd;
+        };
+
+        // Input parameter 'size' is the desired size of the timeline in byte units.
+        // The size of the shared memory must be at least Timeline::sharedSize(size).
+        Reader(const void *shared, size_t size);
+        Reader(const sp<IMemory>& iMemory, size_t size);
+
+        virtual ~Reader();
+
+        // get snapshot of readers fifo buffer, effectively consuming the buffer
+        std::unique_ptr<Snapshot> getSnapshot();
+
+        bool     isIMemory(const sp<IMemory>& iMemory) const;
+
+    protected:
+        // print a summary of the performance to the console
+        void    dumpLine(const String8& timestamp, String8& body);
+        EntryIterator   handleFormat(const FormatEntry &fmtEntry,
+                                     String8 *timestamp,
+                                     String8 *body);
+        int mFd;                // file descriptor
+        int mIndent;            // indentation level
+        int mLost;              // bytes of data lost before buffer was read
+
+    private:
+        static const std::set<Event> startingTypes;
+        static const std::set<Event> endingTypes;
+
+        // declared as const because audio_utils_fifo() constructor
+        sp<IMemory> mIMemory;       // ref-counted version, assigned only in constructor
+
+        /*const*/ Shared* const mShared;    // raw pointer to shared memory, actually const but not
+        audio_utils_fifo * const mFifo;                 // FIFO itself,
+        // non-NULL unless constructor fails
+        audio_utils_fifo_reader * const mFifoReader;    // used to read from FIFO,
+        // non-NULL unless constructor fails
+
+        // Searches for the last entry of type <type> in the range [front, back)
+        // back has to be entry-aligned. Returns nullptr if none enconuntered.
+        static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
+                                                   const std::set<Event> &types);
+
+        // dummy method for handling absent author entry
+        virtual void handleAuthor(const AbstractEntry& /*fmtEntry*/, String8* /*body*/) {}
+    };
+
+    // Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
+    class NamedReader {
+    public:
+        NamedReader() { mName[0] = '\0'; } // for Vector
+        NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
+            mReader(reader)
+            { strlcpy(mName, name, sizeof(mName)); }
+        ~NamedReader() { }
+        const sp<NBLog::Reader>&  reader() const { return mReader; }
+        const char*               name() const { return mName; }
+
+    private:
+        sp<NBLog::Reader>   mReader;
+        static const size_t kMaxName = 32;
+        char                mName[kMaxName];
+    };
+
+    // ---------------------------------------------------------------------------
+
+    // This class is used to read data from each thread's individual FIFO in shared memory
+    // and write it to a single FIFO in local memory.
+    class Merger : public RefBase {
+    public:
+        Merger(const void *shared, size_t size);
+
+        virtual ~Merger() {}
+
+        void addReader(const NamedReader &reader);
+        // TODO add removeReader
+        void merge();
+
+        // FIXME This is returning a reference to a shared variable that needs a lock
+        const std::vector<NamedReader>& getNamedReaders() const;
+
+    private:
+        // vector of the readers the merger is supposed to merge from.
+        // every reader reads from a writer's buffer
+        // FIXME Needs to be protected by a lock
+        std::vector<NamedReader> mNamedReaders;
+
+        Shared * const mShared; // raw pointer to shared memory
+        std::unique_ptr<audio_utils_fifo> mFifo; // FIFO itself
+        std::unique_ptr<audio_utils_fifo_writer> mFifoWriter; // used to write to FIFO
+    };
+
+    // This class has a pointer to the FIFO in local memory which stores the merged
+    // data collected by NBLog::Merger from all NamedReaders. It is used to process
+    // this data and write the result to PerformanceAnalysis.
+    class MergeReader : public Reader {
+    public:
+        MergeReader(const void *shared, size_t size, Merger &merger);
+
+        void dump(int fd, int indent = 0);
+        // process a particular snapshot of the reader
+        void getAndProcessSnapshot(Snapshot & snap);
+        // call getSnapshot of the content of the reader's buffer and process the data
+        void getAndProcessSnapshot();
+
+    private:
+        // FIXME Needs to be protected by a lock,
+        //       because even though our use of it is read-only there may be asynchronous updates
+        const std::vector<NamedReader>& mNamedReaders;
+
+        // analyzes, compresses and stores the merged data
+        // contains a separate instance for every author (thread), and for every source file
+        // location within each author
+        ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis;
+
+        // handle author entry by looking up the author's name and appending it to the body
+        // returns number of bytes read from fmtEntry
+        void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
+    };
+
+    // MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
+    // when triggered, it awakes for a lapse of time, during which it periodically merges; if
+    // retriggered, the timeout is reset.
+    // The thread is triggered on AudioFlinger binder activity.
+    class MergeThread : public Thread {
+    public:
+        MergeThread(Merger &merger, MergeReader &mergeReader);
+        virtual ~MergeThread() override;
+
+        // Reset timeout and activate thread to merge periodically if it's idle
+        void wakeup();
+
+        // Set timeout period until the merging thread goes idle again
+        void setTimeoutUs(int time);
+
+    private:
+        virtual bool threadLoop() override;
+
+        // the merger who actually does the work of merging the logs
+        Merger&     mMerger;
+
+        // the mergereader used to process data merged by mMerger
+        MergeReader& mMergeReader;
+
+        // mutex for the condition variable
+        Mutex       mMutex;
+
+        // condition variable to activate merging on timeout >= 0
+        Condition   mCond;
+
+        // time left until the thread blocks again (in microseconds)
+        int         mTimeoutUs;
+
+        // merging period when the thread is awake
+        static const int  kThreadSleepPeriodUs = 1000000 /*1s*/;
+
+        // initial timeout value when triggered
+        static const int  kThreadWakeupPeriodUs = 3000000 /*3s*/;
+    };
+
+};  // class NBLog
+
+// TODO put somewhere else
+static inline int64_t get_monotonic_ns() {
+    timespec ts;
+    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+        return (uint64_t) ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+    }
+    return 0; // should not happen.
+}
+
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_NBLOG_H
diff --git a/media/libnblog/include/media/nblog/PerformanceAnalysis.h b/media/libnblog/include/media/nblog/PerformanceAnalysis.h
new file mode 100644
index 0000000..ddfe9d6
--- /dev/null
+++ b/media/libnblog/include/media/nblog/PerformanceAnalysis.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_PERFORMANCEANALYSIS_H
+#define ANDROID_MEDIA_PERFORMANCEANALYSIS_H
+
+#include <deque>
+#include <map>
+#include <vector>
+
+#include <media/nblog/ReportPerformance.h>
+
+namespace android {
+
+namespace ReportPerformance {
+
+class PerformanceAnalysis;
+
+// a map of PerformanceAnalysis instances
+// The outer key is for the thread, the inner key for the source file location.
+using PerformanceAnalysisMap = std::map<int, std::map<log_hash_t, PerformanceAnalysis>>;
+
+class PerformanceAnalysis {
+    // This class stores and analyzes audio processing wakeup timestamps from NBLog
+    // FIXME: currently, all performance data is stored in deques. Turn these into circular
+    // buffers.
+    // TODO: add a mutex.
+public:
+
+    PerformanceAnalysis() {};
+
+    friend void dump(int fd, int indent,
+                     PerformanceAnalysisMap &threadPerformanceAnalysis);
+
+    // Called in the case of an audio on/off event, e.g., EVENT_AUDIO_STATE.
+    // Used to discard idle time intervals
+    void handleStateChange();
+
+    // Writes wakeup timestamp entry to log and runs analysis
+    void logTsEntry(timestamp ts);
+
+    // FIXME: make peakdetector and storeOutlierData a single function
+    // Input: mOutlierData. Looks at time elapsed between outliers
+    // finds significant changes in the distribution
+    // writes timestamps of significant changes to mPeakTimestamps
+    bool detectAndStorePeak(msInterval delta, timestamp ts);
+
+    // stores timestamps of intervals above a threshold: these are assumed outliers.
+    // writes to mOutlierData <time elapsed since previous outlier, outlier timestamp>
+    bool detectAndStoreOutlier(const msInterval diffMs);
+
+    // Generates a string of analysis of the buffer periods and prints to console
+    // FIXME: move this data visualization to a separate class. Model/view/controller
+    void reportPerformance(String8 *body, int author, log_hash_t hash,
+                           int maxHeight = 10);
+
+private:
+
+    // TODO use a circular buffer for the deques and vectors below
+
+    // stores outlier analysis:
+    // <elapsed time between outliers in ms, outlier beginning timestamp>
+    std::deque<std::pair<msInterval, timestamp>> mOutlierData;
+
+    // stores each timestamp at which a peak was detected
+    // a peak is a moment at which the average outlier interval changed significantly
+    std::deque<timestamp> mPeakTimestamps;
+
+    // stores buffer period histograms with timestamp of first sample
+    std::deque<std::pair<timestamp, Histogram>> mHists;
+
+    // Parameters used when detecting outliers
+    struct BufferPeriod {
+        double    mMean = -1;          // average time between audio processing wakeups
+        double    mOutlierFactor = -1; // values > mMean * mOutlierFactor are outliers
+        double    mOutlier = -1;       // this is set to mMean * mOutlierFactor
+        timestamp mPrevTs = -1;        // previous timestamp
+    } mBufferPeriod;
+
+    // capacity allocated to data structures
+    struct MaxLength {
+        size_t Hists; // number of histograms stored in memory
+        size_t Outliers; // number of values stored in outlier array
+        size_t Peaks; // number of values stored in peak array
+        int HistTimespanMs; // maximum histogram timespan
+    };
+    // These values allow for 10 hours of data allowing for a glitch and a peak
+    // as often as every 3 seconds
+    static constexpr MaxLength kMaxLength = {.Hists = 60, .Outliers = 12000,
+            .Peaks = 12000, .HistTimespanMs = 10 * kSecPerMin * kMsPerSec };
+
+    // these variables ensure continuity while analyzing the timestamp
+    // series one sample at a time.
+    // TODO: change this to a running variance/mean class
+    struct OutlierDistribution {
+        msInterval mMean = 0;         // sample mean since previous peak
+        msInterval mSd = 0;           // sample sd since previous peak
+        msInterval mElapsed = 0;      // time since previous detected outlier
+        const int  kMaxDeviation = 5; // standard deviations from the mean threshold
+        msInterval mTypicalDiff = 0;  // global mean of outliers
+        double     mN = 0;            // length of sequence since the last peak
+        double     mM2 = 0;           // used to calculate sd
+    } mOutlierDistribution;
+};
+
+void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis);
+void dumpLine(int fd, int indent, const String8 &body);
+
+} // namespace ReportPerformance
+
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_PERFORMANCEANALYSIS_H
diff --git a/media/libnblog/include/media/nblog/ReportPerformance.h b/media/libnblog/include/media/nblog/ReportPerformance.h
new file mode 100644
index 0000000..ec0842f
--- /dev/null
+++ b/media/libnblog/include/media/nblog/ReportPerformance.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_REPORTPERFORMANCE_H
+#define ANDROID_MEDIA_REPORTPERFORMANCE_H
+
+#include <deque>
+#include <map>
+#include <vector>
+
+namespace android {
+
+// The String8 class is used by reportPerformance function
+class String8;
+
+namespace ReportPerformance {
+
+constexpr int kMsPerSec = 1000;
+constexpr int kSecPerMin = 60;
+
+constexpr int kJiffyPerMs = 10; // time unit for histogram as a multiple of milliseconds
+
+// stores a histogram: key: observed buffer period (multiple of jiffy). value: count
+using Histogram = std::map<int, int>;
+
+using msInterval = double;
+using jiffyInterval = double;
+
+using timestamp = int64_t;
+
+using log_hash_t = uint64_t;
+
+static inline int deltaMs(int64_t ns1, int64_t ns2) {
+    return (ns2 - ns1) / (1000 * 1000);
+}
+
+static inline int deltaJiffy(int64_t ns1, int64_t ns2) {
+    return (kJiffyPerMs * (ns2 - ns1)) / (1000 * 1000);
+}
+
+static inline uint32_t log2(uint32_t x) {
+    // This works for x > 0
+    return 31 - __builtin_clz(x);
+}
+
+// Writes outlier intervals, timestamps, peaks timestamps, and histograms to a file.
+void writeToFile(const std::deque<std::pair<timestamp, Histogram>> &hists,
+                 const std::deque<std::pair<msInterval, timestamp>> &outlierData,
+                 const std::deque<timestamp> &peakTimestamps,
+                 const char * kDirectory, bool append, int author, log_hash_t hash);
+
+} // namespace ReportPerformance
+
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_REPORTPERFORMANCE_H
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 8b1e1c3..281af47 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -30,8 +30,8 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
+#include <media/MediaSource.h>
 #include <media/mediarecorder.h>
 
 namespace android {
@@ -67,7 +67,7 @@
 }
 
 
-status_t AACWriter::addSource(const sp<IMediaSource> &source) {
+status_t AACWriter::addSource(const sp<MediaSource> &source) {
     if (mInitCheck != OK) {
         return mInitCheck;
     }
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index a2eb9a8..d9fdfe3 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -28,8 +28,7 @@
 
 #include <media/stagefright/ACodec.h>
 
-#include <binder/MemoryDealer.h>
-
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -55,7 +54,6 @@
 #include <media/openmax/OMX_IndexExt.h>
 #include <media/openmax/OMX_AsString.h>
 
-#include "include/avc_utils.h"
 #include "include/ACodecBufferChannel.h"
 #include "include/DataConverter.h"
 #include "include/SecureBuffer.h"
@@ -575,8 +573,6 @@
     memset(&mLastNativeWindowCrop, 0, sizeof(mLastNativeWindowCrop));
 
     changeState(mUninitializedState);
-
-    mTrebleFlag = false;
 }
 
 ACodec::~ACodec() {
@@ -828,11 +824,7 @@
 status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
     CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
 
-    if (getTrebleFlag()) {
-        CHECK(mAllocator[portIndex] == NULL);
-    } else {
-        CHECK(mDealer[portIndex] == NULL);
-    }
+    CHECK(mAllocator[portIndex] == NULL);
     CHECK(mBuffers[portIndex].isEmpty());
 
     status_t err;
@@ -874,7 +866,10 @@
                 }
             }
 
-            size_t alignment = MemoryDealer::getAllocationAlignment();
+            size_t alignment = 32; // This is the value currently returned by
+                                   // MemoryDealer::getAllocationAlignment().
+                                   // TODO: Fix this when Treble has
+                                   // MemoryHeap/MemoryDealer.
 
             ALOGV("[%s] Allocating %u buffers of size %zu (from %u using %s) on %s port",
                     mComponentName.c_str(),
@@ -896,18 +891,15 @@
             }
 
             if (mode != IOMX::kPortModePresetSecureBuffer) {
-                if (getTrebleFlag()) {
-                    mAllocator[portIndex] = TAllocator::getService("ashmem");
-                    if (mAllocator[portIndex] == nullptr) {
-                        ALOGE("hidl allocator on port %d is null",
-                                (int)portIndex);
-                        return NO_MEMORY;
-                    }
-                } else {
-                    size_t totalSize = def.nBufferCountActual *
-                            (alignedSize + alignedConvSize);
-                    mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec");
+                mAllocator[portIndex] = TAllocator::getService("ashmem");
+                if (mAllocator[portIndex] == nullptr) {
+                    ALOGE("hidl allocator on port %d is null",
+                            (int)portIndex);
+                    return NO_MEMORY;
                 }
+                // TODO: When Treble has MemoryHeap/MemoryDealer, we should
+                // specify the heap size to be
+                // def.nBufferCountActual * (alignedSize + alignedConvSize).
             }
 
             const sp<AMessage> &format =
@@ -936,23 +928,55 @@
                             : new SecureBuffer(format, native_handle, bufSize);
                     info.mCodecData = info.mData;
                 } else {
-                    if (getTrebleFlag()) {
+                    bool success;
+                    auto transStatus = mAllocator[portIndex]->allocate(
+                            bufSize,
+                            [&success, &hidlMemToken](
+                                    bool s,
+                                    hidl_memory const& m) {
+                                success = s;
+                                hidlMemToken = m;
+                            });
+
+                    if (!transStatus.isOk()) {
+                        ALOGE("hidl's AshmemAllocator failed at the "
+                                "transport: %s",
+                                transStatus.description().c_str());
+                        return NO_MEMORY;
+                    }
+                    if (!success) {
+                        return NO_MEMORY;
+                    }
+                    hidlMem = mapMemory(hidlMemToken);
+                    if (hidlMem == nullptr) {
+                        return NO_MEMORY;
+                    }
+                    err = mOMXNode->useBuffer(
+                            portIndex, hidlMemToken, &info.mBufferID);
+
+                    if (mode == IOMX::kPortModeDynamicANWBuffer) {
+                        VideoNativeMetadata* metaData = (VideoNativeMetadata*)(
+                                (void*)hidlMem->getPointer());
+                        metaData->nFenceFd = -1;
+                    }
+
+                    info.mCodecData = new SharedMemoryBuffer(
+                            format, hidlMem);
+                    info.mCodecRef = hidlMem;
+
+                    // if we require conversion, allocate conversion buffer for client use;
+                    // otherwise, reuse codec buffer
+                    if (mConverter[portIndex] != NULL) {
+                        CHECK_GT(conversionBufferSize, (size_t)0);
                         bool success;
-                        auto transStatus = mAllocator[portIndex]->allocate(
-                                bufSize,
+                        mAllocator[portIndex]->allocate(
+                                conversionBufferSize,
                                 [&success, &hidlMemToken](
                                         bool s,
                                         hidl_memory const& m) {
                                     success = s;
                                     hidlMemToken = m;
                                 });
-
-                        if (!transStatus.isOk()) {
-                            ALOGE("hidl's AshmemAllocator failed at the "
-                                    "transport: %s",
-                                    transStatus.description().c_str());
-                            return NO_MEMORY;
-                        }
                         if (!success) {
                             return NO_MEMORY;
                         }
@@ -960,67 +984,8 @@
                         if (hidlMem == nullptr) {
                             return NO_MEMORY;
                         }
-                        err = mOMXNode->useBuffer(
-                                portIndex, hidlMemToken, &info.mBufferID);
-                    } else {
-                        mem = mDealer[portIndex]->allocate(bufSize);
-                        if (mem == NULL || mem->pointer() == NULL) {
-                            return NO_MEMORY;
-                        }
-
-                        err = mOMXNode->useBuffer(
-                                portIndex, mem, &info.mBufferID);
-                    }
-
-                    if (mode == IOMX::kPortModeDynamicANWBuffer) {
-                        VideoNativeMetadata* metaData = (VideoNativeMetadata*)(
-                                getTrebleFlag() ?
-                                (void*)hidlMem->getPointer() : mem->pointer());
-                        metaData->nFenceFd = -1;
-                    }
-
-                    if (getTrebleFlag()) {
-                        info.mCodecData = new SharedMemoryBuffer(
-                                format, hidlMem);
-                        info.mCodecRef = hidlMem;
-                    } else {
-                        info.mCodecData = new SharedMemoryBuffer(
-                                format, mem);
-                        info.mCodecRef = mem;
-                    }
-
-                    // if we require conversion, allocate conversion buffer for client use;
-                    // otherwise, reuse codec buffer
-                    if (mConverter[portIndex] != NULL) {
-                        CHECK_GT(conversionBufferSize, (size_t)0);
-                        if (getTrebleFlag()) {
-                            bool success;
-                            mAllocator[portIndex]->allocate(
-                                    conversionBufferSize,
-                                    [&success, &hidlMemToken](
-                                            bool s,
-                                            hidl_memory const& m) {
-                                        success = s;
-                                        hidlMemToken = m;
-                                    });
-                            if (!success) {
-                                return NO_MEMORY;
-                            }
-                            hidlMem = mapMemory(hidlMemToken);
-                            if (hidlMem == nullptr) {
-                                return NO_MEMORY;
-                            }
-                            info.mData = new SharedMemoryBuffer(format, hidlMem);
-                            info.mMemRef = hidlMem;
-                        } else {
-                            mem = mDealer[portIndex]->allocate(
-                                    conversionBufferSize);
-                            if (mem == NULL|| mem->pointer() == NULL) {
-                                return NO_MEMORY;
-                            }
-                            info.mData = new SharedMemoryBuffer(format, mem);
-                            info.mMemRef = mem;
-                        }
+                        info.mData = new SharedMemoryBuffer(format, hidlMem);
+                        info.mMemRef = hidlMem;
                     } else {
                         info.mData = info.mCodecData;
                         info.mMemRef = info.mCodecRef;
@@ -1581,11 +1546,7 @@
         }
     }
 
-    if (getTrebleFlag()) {
-        mAllocator[portIndex].clear();
-    } else {
-        mDealer[portIndex].clear();
-    }
+    mAllocator[portIndex].clear();
     return err;
 }
 
@@ -3781,6 +3742,8 @@
     } else {
         mFps = (double)framerate;
     }
+    // propagate framerate to the output so that the muxer has it
+    outputFormat->setInt32("frame-rate", (int32_t)mFps);
 
     video_def->xFramerate = (OMX_U32)(mFps * 65536);
     video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
@@ -6052,7 +6015,7 @@
             }
 #if 0
             if (mCodec->mNativeWindow == NULL) {
-                if (IsIDR(info->mData)) {
+                if (IsIDR(info->mData->data(), info->mData->size())) {
                     ALOGI("IDR frame");
                 }
             }
@@ -6249,13 +6212,8 @@
 
     if (mDeathNotifier != NULL) {
         if (mCodec->mOMXNode != NULL) {
-            if (mCodec->getTrebleFlag()) {
-                auto tOmxNode = mCodec->mOMXNode->getHalInterface();
-                tOmxNode->unlinkToDeath(mDeathNotifier);
-            } else {
-                sp<IBinder> binder = IInterface::asBinder(mCodec->mOMXNode);
-                binder->unlinkToDeath(mDeathNotifier);
-            }
+            auto tOmxNode = mCodec->mOMXNode->getHalInterface();
+            tOmxNode->unlinkToDeath(mDeathNotifier);
         }
         mDeathNotifier.clear();
     }
@@ -6403,8 +6361,7 @@
         componentName = matchingCodecs[matchIndex];
 
         OMXClient client;
-        bool trebleFlag;
-        if (client.connect(owners[matchIndex].c_str(), &trebleFlag) != OK) {
+        if (client.connect(owners[matchIndex].c_str()) != OK) {
             mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
             return false;
         }
@@ -6417,7 +6374,6 @@
         androidSetThreadPriority(tid, prevPriority);
 
         if (err == OK) {
-            mCodec->setTrebleFlag(trebleFlag);
             break;
         } else {
             ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str());
@@ -6439,17 +6395,9 @@
     }
 
     mDeathNotifier = new DeathNotifier(notify);
-    if (mCodec->getTrebleFlag()) {
-        auto tOmxNode = omxNode->getHalInterface();
-        if (!tOmxNode->linkToDeath(mDeathNotifier, 0)) {
-            mDeathNotifier.clear();
-        }
-    } else {
-        if (IInterface::asBinder(omxNode)->linkToDeath(mDeathNotifier) != OK) {
-            // This was a local binder, if it dies so do we, we won't care
-            // about any notifications in the afterlife.
-            mDeathNotifier.clear();
-        }
+    auto tOmxNode = omxNode->getHalInterface();
+    if (!tOmxNode->linkToDeath(mDeathNotifier, 0)) {
+        mDeathNotifier.clear();
     }
 
     notify = new AMessage(kWhatOMXMessageList, mCodec);
@@ -7856,11 +7804,7 @@
                             mCodec->mBuffers[kPortIndexOutput].size());
                     err = FAILED_TRANSACTION;
                 } else {
-                    if (mCodec->getTrebleFlag()) {
-                        mCodec->mAllocator[kPortIndexOutput].clear();
-                    } else {
-                        mCodec->mDealer[kPortIndexOutput].clear();
-                    }
+                    mCodec->mAllocator[kPortIndexOutput].clear();
                 }
 
                 if (err == OK) {
@@ -8462,12 +8406,4 @@
     return OK;
 }
 
-void ACodec::setTrebleFlag(bool trebleFlag) {
-    mTrebleFlag = trebleFlag;
-}
-
-bool ACodec::getTrebleFlag() const {
-    return mTrebleFlag;
-}
-
 }  // namespace android
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 961b57f..910abc6 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -25,8 +25,8 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
+#include <media/MediaSource.h>
 #include <media/mediarecorder.h>
 
 namespace android {
@@ -54,7 +54,7 @@
     return mInitCheck;
 }
 
-status_t AMRWriter::addSource(const sp<IMediaSource> &source) {
+status_t AMRWriter::addSource(const sp<MediaSource> &source) {
     if (mInitCheck != OK) {
         return mInitCheck;
     }
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
index 5a6211e..406074b 100644
--- a/media/libstagefright/AVIExtractor.cpp
+++ b/media/libstagefright/AVIExtractor.cpp
@@ -18,14 +18,14 @@
 #define LOG_TAG "AVIExtractor"
 #include <utils/Log.h>
 
-#include "include/avc_utils.h"
 #include "include/AVIExtractor.h"
 
 #include <binder/ProcessState.h>
+#include <media/DataSource.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index ac4e819..0c71487 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -4,37 +4,55 @@
     vendor_available: true,
 }
 
+cc_library_static {
+    name: "libstagefright_esds",
+
+    srcs: ["ESDS.cpp"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: ["libmedia"],
+}
+
 cc_library_shared {
     name: "libstagefright",
 
     srcs: [
         "ACodec.cpp",
         "ACodecBufferChannel.cpp",
-        "AACExtractor.cpp",
         "AACWriter.cpp",
-        "AMRExtractor.cpp",
         "AMRWriter.cpp",
         "AudioPlayer.cpp",
         "AudioSource.cpp",
         "BufferImpl.cpp",
         "CodecBase.cpp",
         "CallbackDataSource.cpp",
+        "CallbackMediaSource.cpp",
         "CameraSource.cpp",
         "CameraSourceTimeLapse.cpp",
         "DataConverter.cpp",
-        "DataSource.cpp",
+        "DataSourceFactory.cpp",
         "DataURISource.cpp",
-        "ESDS.cpp",
         "FileSource.cpp",
-        "FLACExtractor.cpp",
+        "FrameDecoder.cpp",
         "FrameRenderTracker.cpp",
         "HTTPBase.cpp",
         "HevcUtils.cpp",
-        "ItemTable.cpp",
+        "InterfaceUtils.cpp",
         "JPEGSource.cpp",
-        "MP3Extractor.cpp",
         "MPEG2TSWriter.cpp",
-        "MPEG4Extractor.cpp",
         "MPEG4Writer.cpp",
         "MediaAdapter.cpp",
         "MediaClock.cpp",
@@ -42,19 +60,16 @@
         "MediaCodecList.cpp",
         "MediaCodecListOverrides.cpp",
         "MediaCodecSource.cpp",
-        "MediaExtractor.cpp",
+        "MediaExtractorFactory.cpp",
         "MediaSync.cpp",
-        "MidiExtractor.cpp",
         "http/MediaHTTP.cpp",
         "MediaMuxer.cpp",
-        "MediaSource.cpp",
         "NuCachedSource2.cpp",
         "NuMediaExtractor.cpp",
         "OMXClient.cpp",
         "OmxInfoBuilder.cpp",
-        "OggExtractor.cpp",
-        "SampleIterator.cpp",
-        "SampleTable.cpp",
+        "RemoteMediaExtractor.cpp",
+        "RemoteMediaSource.cpp",
         "SimpleDecodingSource.cpp",
         "SkipCutBuffer.cpp",
         "StagefrightMediaScanner.cpp",
@@ -63,49 +78,37 @@
         "SurfaceUtils.cpp",
         "ThrottledSource.cpp",
         "Utils.cpp",
-        "VBRISeeker.cpp",
         "VideoFrameScheduler.cpp",
-        "WAVExtractor.cpp",
-        "XINGSeeker.cpp",
-        "avc_utils.cpp",
     ],
 
     shared_libs: [
         "libaudioutils",
         "libbinder",
         "libcamera_client",
-        "libcrypto",
         "libcutils",
         "libdl",
         "libdrmframework",
-        "libexpat",
         "libgui",
         "liblog",
         "libmedia",
+        "libmedia_omx",
         "libaudioclient",
+        "libmediaextractor",
         "libmediametrics",
         "libmediautils",
         "libnetd_client",
-        "libsonivox",
         "libui",
         "libutils",
-        "libvorbisidec",
-        "libmediadrm",
-        "libnativewindow",
-
         "libmedia_helper",
-        "libstagefright_omx_utils",
-        "libstagefright_flacdec",
         "libstagefright_foundation",
+        "libstagefright_omx",
+        "libstagefright_omx_utils",
         "libstagefright_xmlparser",
         "libdl",
         "libRScpp",
         "libhidlbase",
         "libhidlmemory",
         "android.hidl.allocator@1.0",
-        "android.hidl.memory@1.0",
-        "android.hidl.token@1.0-utils",
-        "android.hardware.cas@1.0",
         "android.hardware.cas.native@1.0",
         "android.hardware.media.omx@1.0",
     ],
@@ -113,13 +116,13 @@
     static_libs: [
         "libstagefright_color_conversion",
         "libyuv_static",
-        "libstagefright_matroska",
         "libstagefright_mediafilter",
         "libstagefright_webm",
         "libstagefright_timedtext",
         "libvpx",
         "libwebm",
-        "libstagefright_mpeg2ts",
+        "libstagefright_mpeg2support",
+        "libstagefright_esds",
         "libstagefright_id3",
         "libFLAC",
     ],
@@ -160,6 +163,7 @@
 }
 
 subdirs = [
+    "codec2",
     "codecs/*",
     "colorconversion",
     "filters",
@@ -168,13 +172,11 @@
     "http",
     "httplive",
     "id3",
-    "matroska",
     "mpeg2ts",
     "omx",
     "rtsp",
     "tests",
     "timedtext",
     "webm",
-    "wifi-display",
     "xmlparser",
 ]
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index b3fb8d4..16ea5b5b 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -23,6 +23,7 @@
 
 #include <binder/IPCThreadState.h>
 #include <media/AudioTrack.h>
+#include <media/MediaSource.h>
 #include <media/openmax/OMX_Audio.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALookup.h>
@@ -30,7 +31,6 @@
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
@@ -67,7 +67,7 @@
     }
 }
 
-void AudioPlayer::setSource(const sp<IMediaSource> &source) {
+void AudioPlayer::setSource(const sp<MediaSource> &source) {
     CHECK(mSource == NULL);
     mSource = source;
 }
@@ -363,7 +363,7 @@
     // When offloading, the OMX component is not used so this hack
     // is not needed
     if (!useOffload()) {
-        wp<IMediaSource> tmp = mSource;
+        wp<MediaSource> tmp = mSource;
         mSource.clear();
         while (tmp.promote() != NULL) {
             usleep(1000);
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index f2b1f10..b8da980 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -52,7 +52,7 @@
 AudioSource::AudioSource(
         audio_source_t inputSource, const String16 &opPackageName,
         uint32_t sampleRate, uint32_t channelCount, uint32_t outSampleRate,
-        uid_t uid, pid_t pid)
+        uid_t uid, pid_t pid, audio_port_handle_t selectedDeviceId)
     : mStarted(false),
       mSampleRate(sampleRate),
       mOutSampleRate(outSampleRate > 0 ? outSampleRate : sampleRate),
@@ -101,7 +101,9 @@
                     AudioRecord::TRANSFER_DEFAULT,
                     AUDIO_INPUT_FLAG_NONE,
                     uid,
-                    pid);
+                    pid,
+                    NULL /*pAttributes*/,
+                    selectedDeviceId);
         mInitCheck = mRecord->initCheck();
         if (mInitCheck != OK) {
             mRecord.clear();
@@ -465,4 +467,35 @@
     return value;
 }
 
+status_t AudioSource::setInputDevice(audio_port_handle_t deviceId) {
+    if (mRecord != 0) {
+        return mRecord->setInputDevice(deviceId);
+    }
+    return NO_INIT;
+}
+
+status_t AudioSource::getRoutedDeviceId(audio_port_handle_t* deviceId) {
+    if (mRecord != 0) {
+        *deviceId = mRecord->getRoutedDeviceId();
+        return NO_ERROR;
+    }
+    return NO_INIT;
+}
+
+status_t AudioSource::addAudioDeviceCallback(
+        const sp<AudioSystem::AudioDeviceCallback>& callback) {
+    if (mRecord != 0) {
+        return mRecord->addAudioDeviceCallback(callback);
+    }
+    return NO_INIT;
+}
+
+status_t AudioSource::removeAudioDeviceCallback(
+        const sp<AudioSystem::AudioDeviceCallback>& callback) {
+    if (mRecord != 0) {
+        return mRecord->removeAudioDeviceCallback(callback);
+    }
+    return NO_INIT;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/CallbackMediaSource.cpp b/media/libstagefright/CallbackMediaSource.cpp
new file mode 100644
index 0000000..54e6142
--- /dev/null
+++ b/media/libstagefright/CallbackMediaSource.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/stagefright/CallbackMediaSource.h>
+#include <media/IMediaSource.h>
+
+namespace android {
+
+CallbackMediaSource::CallbackMediaSource(const sp<IMediaSource> &source)
+    :mSource(source) {}
+
+CallbackMediaSource::~CallbackMediaSource() {}
+
+status_t CallbackMediaSource::start(MetaData *params) {
+    return mSource->start(params);
+}
+
+status_t CallbackMediaSource::stop() {
+    return mSource->stop();
+}
+
+sp<MetaData> CallbackMediaSource::getFormat() {
+    return mSource->getFormat();
+}
+
+status_t CallbackMediaSource::read(MediaBuffer **buffer, const ReadOptions *options) {
+    return mSource->read(buffer, reinterpret_cast<const ReadOptions*>(options));
+}
+
+status_t CallbackMediaSource::pause() {
+    return mSource->pause();
+}
+
+status_t CallbackMediaSource::setBuffers(const Vector<MediaBuffer *> &buffers) {
+    return mSource->setBuffers(buffers);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
deleted file mode 100644
index c22053e..0000000
--- a/media/libstagefright/DataSource.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-//#define LOG_NDEBUG 0
-#define LOG_TAG "DataSource"
-
-#include "include/CallbackDataSource.h"
-#include "include/HTTPBase.h"
-#include "include/NuCachedSource2.h"
-
-#include <media/IDataSource.h>
-#include <media/IMediaHTTPConnection.h>
-#include <media/IMediaHTTPService.h>
-#include <media/stagefright/foundation/ADebug.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 <media/stagefright/RemoteDataSource.h>
-#include <media/stagefright/Utils.h>
-#include <utils/String8.h>
-
-#include <cutils/properties.h>
-
-#include <private/android_filesystem_config.h>
-
-namespace android {
-
-bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
-    *x = 0;
-
-    uint8_t byte[2];
-    if (readAt(offset, byte, 2) != 2) {
-        return false;
-    }
-
-    *x = (byte[0] << 8) | byte[1];
-
-    return true;
-}
-
-bool DataSource::getUInt24(off64_t offset, uint32_t *x) {
-    *x = 0;
-
-    uint8_t byte[3];
-    if (readAt(offset, byte, 3) != 3) {
-        return false;
-    }
-
-    *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
-
-    return true;
-}
-
-bool DataSource::getUInt32(off64_t offset, uint32_t *x) {
-    *x = 0;
-
-    uint32_t tmp;
-    if (readAt(offset, &tmp, 4) != 4) {
-        return false;
-    }
-
-    *x = ntohl(tmp);
-
-    return true;
-}
-
-bool DataSource::getUInt64(off64_t offset, uint64_t *x) {
-    *x = 0;
-
-    uint64_t tmp;
-    if (readAt(offset, &tmp, 8) != 8) {
-        return false;
-    }
-
-    *x = ntoh64(tmp);
-
-    return true;
-}
-
-bool DataSource::getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
-    if (size == 2) {
-        return getUInt16(offset, x);
-    }
-    if (size == 1) {
-        uint8_t tmp;
-        if (readAt(offset, &tmp, 1) == 1) {
-            *x = tmp;
-            return true;
-        }
-    }
-    return false;
-}
-
-bool DataSource::getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
-    if (size == 4) {
-        return getUInt32(offset, x);
-    }
-    if (size == 2) {
-        uint16_t tmp;
-        if (getUInt16(offset, &tmp)) {
-            *x = tmp;
-            return true;
-        }
-    }
-    return false;
-}
-
-bool DataSource::getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
-    if (size == 8) {
-        return getUInt64(offset, x);
-    }
-    if (size == 4) {
-        uint32_t tmp;
-        if (getUInt32(offset, &tmp)) {
-            *x = tmp;
-            return true;
-        }
-    }
-    return false;
-}
-
-status_t DataSource::getSize(off64_t *size) {
-    *size = 0;
-
-    return ERROR_UNSUPPORTED;
-}
-
-sp<IDataSource> DataSource::getIDataSource() const {
-    return nullptr;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// static
-sp<DataSource> DataSource::CreateFromURI(
-        const sp<IMediaHTTPService> &httpService,
-        const char *uri,
-        const KeyedVector<String8, String8> *headers,
-        String8 *contentType,
-        HTTPBase *httpSource) {
-    if (contentType != NULL) {
-        *contentType = "";
-    }
-
-    sp<DataSource> source;
-    if (!strncasecmp("file://", uri, 7)) {
-        source = new FileSource(uri + 7);
-    } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
-        if (httpService == NULL) {
-            ALOGE("Invalid http service!");
-            return NULL;
-        }
-
-        if (httpSource == NULL) {
-            sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
-            if (conn == NULL) {
-                ALOGE("Failed to make http connection from http service!");
-                return NULL;
-            }
-            httpSource = new MediaHTTP(conn);
-        }
-
-        String8 cacheConfig;
-        bool disconnectAtHighwatermark = false;
-        KeyedVector<String8, String8> nonCacheSpecificHeaders;
-        if (headers != NULL) {
-            nonCacheSpecificHeaders = *headers;
-            NuCachedSource2::RemoveCacheSpecificHeaders(
-                    &nonCacheSpecificHeaders,
-                    &cacheConfig,
-                    &disconnectAtHighwatermark);
-        }
-
-        if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
-            ALOGE("Failed to connect http source!");
-            return NULL;
-        }
-
-        if (contentType != NULL) {
-            *contentType = httpSource->getMIMEType();
-        }
-
-        source = NuCachedSource2::Create(
-                httpSource,
-                cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
-                disconnectAtHighwatermark);
-    } else if (!strncasecmp("data:", uri, 5)) {
-        source = DataURISource::Create(uri);
-    } else {
-        // Assume it's a filename.
-        source = new FileSource(uri);
-    }
-
-    if (source == NULL || source->initCheck() != OK) {
-        return NULL;
-    }
-
-    return source;
-}
-
-sp<DataSource> DataSource::CreateFromFd(int fd, int64_t offset, int64_t length) {
-    sp<FileSource> source = new FileSource(fd, offset, length);
-    return source->initCheck() != OK ? nullptr : source;
-}
-
-sp<DataSource> DataSource::CreateMediaHTTP(const sp<IMediaHTTPService> &httpService) {
-    if (httpService == NULL) {
-        return NULL;
-    }
-
-    sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
-    if (conn == NULL) {
-        return NULL;
-    } else {
-        return new MediaHTTP(conn);
-    }
-}
-
-sp<DataSource> DataSource::CreateFromIDataSource(const sp<IDataSource> &source) {
-    return new TinyCacheSource(new CallbackDataSource(source));
-}
-
-String8 DataSource::getMIMEType() const {
-    return String8("application/octet-stream");
-}
-
-sp<IDataSource> DataSource::asIDataSource() {
-    return RemoteDataSource::wrap(sp<DataSource>(this));
-}
-
-}  // namespace android
diff --git a/media/libstagefright/DataSourceFactory.cpp b/media/libstagefright/DataSourceFactory.cpp
new file mode 100644
index 0000000..aee858c
--- /dev/null
+++ b/media/libstagefright/DataSourceFactory.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DataSource"
+
+#include "include/HTTPBase.h"
+#include "include/NuCachedSource2.h"
+
+#include <media/IMediaHTTPConnection.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/DataURISource.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaHTTP.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// static
+sp<DataSource> DataSourceFactory::CreateFromURI(
+        const sp<IMediaHTTPService> &httpService,
+        const char *uri,
+        const KeyedVector<String8, String8> *headers,
+        String8 *contentType,
+        HTTPBase *httpSource) {
+    if (contentType != NULL) {
+        *contentType = "";
+    }
+
+    sp<DataSource> source;
+    if (!strncasecmp("file://", uri, 7)) {
+        source = new FileSource(uri + 7);
+    } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
+        if (httpService == NULL) {
+            ALOGE("Invalid http service!");
+            return NULL;
+        }
+
+        if (httpSource == NULL) {
+            sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
+            if (conn == NULL) {
+                ALOGE("Failed to make http connection from http service!");
+                return NULL;
+            }
+            httpSource = new MediaHTTP(conn);
+        }
+
+        String8 cacheConfig;
+        bool disconnectAtHighwatermark = false;
+        KeyedVector<String8, String8> nonCacheSpecificHeaders;
+        if (headers != NULL) {
+            nonCacheSpecificHeaders = *headers;
+            NuCachedSource2::RemoveCacheSpecificHeaders(
+                    &nonCacheSpecificHeaders,
+                    &cacheConfig,
+                    &disconnectAtHighwatermark);
+        }
+
+        if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
+            ALOGE("Failed to connect http source!");
+            return NULL;
+        }
+
+        if (contentType != NULL) {
+            *contentType = httpSource->getMIMEType();
+        }
+
+        source = NuCachedSource2::Create(
+                httpSource,
+                cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+                disconnectAtHighwatermark);
+    } else if (!strncasecmp("data:", uri, 5)) {
+        source = DataURISource::Create(uri);
+    } else {
+        // Assume it's a filename.
+        source = new FileSource(uri);
+    }
+
+    if (source == NULL || source->initCheck() != OK) {
+        return NULL;
+    }
+
+    return source;
+}
+
+sp<DataSource> DataSourceFactory::CreateFromFd(int fd, int64_t offset, int64_t length) {
+    sp<FileSource> source = new FileSource(fd, offset, length);
+    return source->initCheck() != OK ? nullptr : source;
+}
+
+sp<DataSource> DataSourceFactory::CreateMediaHTTP(const sp<IMediaHTTPService> &httpService) {
+    if (httpService == NULL) {
+        return NULL;
+    }
+
+    sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
+    if (conn == NULL) {
+        return NULL;
+    } else {
+        return new MediaHTTP(conn);
+    }
+}
+
+}  // namespace android
diff --git a/media/libstagefright/ESDS.cpp b/media/libstagefright/ESDS.cpp
index c31720d..ea059e8 100644
--- a/media/libstagefright/ESDS.cpp
+++ b/media/libstagefright/ESDS.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "ESDS"
 #include <utils/Log.h>
 
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 
 #include "include/ESDS.h"
 
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
new file mode 100644
index 0000000..fa5f37ec
--- /dev/null
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -0,0 +1,608 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FrameDecoder"
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <gui/Surface.h>
+
+#include "include/FrameDecoder.h"
+#include <media/ICrypto.h>
+#include <media/IMediaSource.h>
+#include <media/MediaCodecBuffer.h>
+#include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/ColorConverter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/Utils.h>
+#include <private/media/VideoFrame.h>
+
+namespace android {
+
+static const int64_t kBufferTimeOutUs = 30000ll; // 30 msec
+static const size_t kRetryCount = 20; // must be >0
+
+VideoFrame *FrameDecoder::allocVideoFrame(
+        int32_t width, int32_t height, bool metaOnly) {
+    int32_t rotationAngle;
+    if (!mTrackMeta->findInt32(kKeyRotation, &rotationAngle)) {
+        rotationAngle = 0;  // By default, no rotation
+    }
+
+    uint32_t type;
+    const void *iccData;
+    size_t iccSize;
+    if (!mTrackMeta->findData(kKeyIccProfile, &type, &iccData, &iccSize)){
+        iccData = NULL;
+        iccSize = 0;
+    }
+
+    int32_t sarWidth, sarHeight;
+    int32_t displayWidth, displayHeight;
+    if (mTrackMeta->findInt32(kKeySARWidth, &sarWidth)
+            && mTrackMeta->findInt32(kKeySARHeight, &sarHeight)
+            && sarHeight != 0) {
+        displayWidth = (width * sarWidth) / sarHeight;
+        displayHeight = height;
+    } else if (mTrackMeta->findInt32(kKeyDisplayWidth, &displayWidth)
+                && mTrackMeta->findInt32(kKeyDisplayHeight, &displayHeight)
+                && displayWidth > 0 && displayHeight > 0
+                && width > 0 && height > 0) {
+        ALOGV("found display size %dx%d", displayWidth, displayHeight);
+    } else {
+        displayWidth = width;
+        displayHeight = height;
+    }
+
+    return new VideoFrame(width, height, displayWidth, displayHeight,
+            rotationAngle, mDstBpp, !metaOnly, iccData, iccSize);
+}
+
+bool FrameDecoder::setDstColorFormat(android_pixel_format_t colorFormat) {
+    switch (colorFormat) {
+        case HAL_PIXEL_FORMAT_RGB_565:
+        {
+            mDstFormat = OMX_COLOR_Format16bitRGB565;
+            mDstBpp = 2;
+            return true;
+        }
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        {
+            mDstFormat = OMX_COLOR_Format32BitRGBA8888;
+            mDstBpp = 4;
+            return true;
+        }
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+        {
+            mDstFormat = OMX_COLOR_Format32bitBGRA8888;
+            mDstBpp = 4;
+            return true;
+        }
+        default:
+        {
+            ALOGE("Unsupported color format: %d", colorFormat);
+            break;
+        }
+    }
+    return false;
+}
+
+VideoFrame* FrameDecoder::extractFrame(
+        int64_t frameTimeUs, int option, int colorFormat, bool metaOnly) {
+    if (!setDstColorFormat((android_pixel_format_t)colorFormat)) {
+        return NULL;
+    }
+
+    if (metaOnly) {
+        int32_t width, height;
+        CHECK(trackMeta()->findInt32(kKeyWidth, &width));
+        CHECK(trackMeta()->findInt32(kKeyHeight, &height));
+        return allocVideoFrame(width, height, true);
+    }
+
+    status_t err = extractInternal(frameTimeUs, 1, option);
+    if (err != OK) {
+        return NULL;
+    }
+
+    return mFrames.size() > 0 ? mFrames[0].release() : NULL;
+}
+
+status_t FrameDecoder::extractFrames(
+        int64_t frameTimeUs, size_t numFrames, int option, int colorFormat,
+        std::vector<VideoFrame*>* frames) {
+    if (!setDstColorFormat((android_pixel_format_t)colorFormat)) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    status_t err = extractInternal(frameTimeUs, numFrames, option);
+    if (err != OK) {
+        return err;
+    }
+
+    for (size_t i = 0; i < mFrames.size(); i++) {
+        frames->push_back(mFrames[i].release());
+    }
+    return OK;
+}
+
+status_t FrameDecoder::extractInternal(
+        int64_t frameTimeUs, size_t numFrames, int option) {
+
+    MediaSource::ReadOptions options;
+    sp<AMessage> videoFormat = onGetFormatAndSeekOptions(
+            frameTimeUs, numFrames, option, &options);
+    if (videoFormat == NULL) {
+        ALOGE("video format or seek mode not supported");
+        return ERROR_UNSUPPORTED;
+    }
+
+    status_t err;
+    sp<ALooper> looper = new ALooper;
+    looper->start();
+    sp<MediaCodec> decoder = MediaCodec::CreateByComponentName(
+            looper, mComponentName, &err);
+    if (decoder.get() == NULL || err != OK) {
+        ALOGW("Failed to instantiate decoder [%s]", mComponentName.c_str());
+        return (decoder.get() == NULL) ? NO_MEMORY : err;
+    }
+
+    err = decoder->configure(videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
+    if (err != OK) {
+        ALOGW("configure returned error %d (%s)", err, asString(err));
+        decoder->release();
+        return err;
+    }
+
+    err = decoder->start();
+    if (err != OK) {
+        ALOGW("start returned error %d (%s)", err, asString(err));
+        decoder->release();
+        return err;
+    }
+
+    err = mSource->start();
+    if (err != OK) {
+        ALOGW("source failed to start: %d (%s)", err, asString(err));
+        decoder->release();
+        return err;
+    }
+
+    Vector<sp<MediaCodecBuffer> > inputBuffers;
+    err = decoder->getInputBuffers(&inputBuffers);
+    if (err != OK) {
+        ALOGW("failed to get input buffers: %d (%s)", err, asString(err));
+        decoder->release();
+        mSource->stop();
+        return err;
+    }
+
+    Vector<sp<MediaCodecBuffer> > outputBuffers;
+    err = decoder->getOutputBuffers(&outputBuffers);
+    if (err != OK) {
+        ALOGW("failed to get output buffers: %d (%s)", err, asString(err));
+        decoder->release();
+        mSource->stop();
+        return err;
+    }
+
+    sp<AMessage> outputFormat = NULL;
+    bool haveMoreInputs = true;
+    size_t index, offset, size;
+    int64_t timeUs;
+    size_t retriesLeft = kRetryCount;
+    bool done = false;
+    bool firstSample = true;
+    do {
+        size_t inputIndex = -1;
+        int64_t ptsUs = 0ll;
+        uint32_t flags = 0;
+        sp<MediaCodecBuffer> codecBuffer = NULL;
+
+        while (haveMoreInputs) {
+            err = decoder->dequeueInputBuffer(&inputIndex, kBufferTimeOutUs);
+            if (err != OK) {
+                ALOGW("Timed out waiting for input");
+                if (retriesLeft) {
+                    err = OK;
+                }
+                break;
+            }
+            codecBuffer = inputBuffers[inputIndex];
+
+            MediaBuffer *mediaBuffer = NULL;
+
+            err = mSource->read(&mediaBuffer, &options);
+            options.clearSeekTo();
+            if (err != OK) {
+                ALOGW("Input Error or EOS");
+                haveMoreInputs = false;
+                if (!firstSample && err == ERROR_END_OF_STREAM) {
+                    err = OK;
+                }
+                break;
+            }
+
+            if (mediaBuffer->range_length() > codecBuffer->capacity()) {
+                ALOGE("buffer size (%zu) too large for codec input size (%zu)",
+                        mediaBuffer->range_length(), codecBuffer->capacity());
+                haveMoreInputs = false;
+                err = BAD_VALUE;
+            } else {
+                codecBuffer->setRange(0, mediaBuffer->range_length());
+
+                CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &ptsUs));
+                memcpy(codecBuffer->data(),
+                        (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
+                        mediaBuffer->range_length());
+
+                onInputReceived(codecBuffer, mediaBuffer->meta_data(), firstSample, &flags);
+                firstSample = false;
+            }
+
+            mediaBuffer->release();
+            break;
+        }
+
+        if (haveMoreInputs && inputIndex < inputBuffers.size()) {
+            ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
+                    codecBuffer->size(), ptsUs, flags);
+
+            err = decoder->queueInputBuffer(
+                    inputIndex,
+                    codecBuffer->offset(),
+                    codecBuffer->size(),
+                    ptsUs,
+                    flags);
+
+            if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+                haveMoreInputs = false;
+            }
+
+            // we don't expect an output from codec config buffer
+            if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
+                continue;
+            }
+        }
+
+        while (err == OK) {
+            // wait for a decoded buffer
+            err = decoder->dequeueOutputBuffer(
+                    &index,
+                    &offset,
+                    &size,
+                    &timeUs,
+                    &flags,
+                    kBufferTimeOutUs);
+
+            if (err == INFO_FORMAT_CHANGED) {
+                ALOGV("Received format change");
+                err = decoder->getOutputFormat(&outputFormat);
+            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
+                ALOGV("Output buffers changed");
+                err = decoder->getOutputBuffers(&outputBuffers);
+            } else {
+                if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) {
+                    ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
+                    err = OK;
+                } else if (err == OK) {
+                    // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
+                    // from the extractor, decode to the specified frame. Otherwise we're done.
+                    ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
+                    sp<MediaCodecBuffer> videoFrameBuffer = outputBuffers.itemAt(index);
+
+                    err = onOutputReceived(videoFrameBuffer, outputFormat, timeUs, &done);
+
+                    decoder->releaseOutputBuffer(index);
+                } else {
+                    ALOGW("Received error %d (%s) instead of output", err, asString(err));
+                    done = true;
+                }
+                break;
+            }
+        }
+    } while (err == OK && !done);
+
+    mSource->stop();
+    decoder->release();
+
+    if (err != OK) {
+        ALOGE("failed to get video frame (err %d)", err);
+    }
+
+    return err;
+}
+
+sp<AMessage> VideoFrameDecoder::onGetFormatAndSeekOptions(
+        int64_t frameTimeUs, size_t numFrames, int seekMode, MediaSource::ReadOptions *options) {
+    mSeekMode = static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
+    if (mSeekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
+            mSeekMode > MediaSource::ReadOptions::SEEK_FRAME_INDEX) {
+        ALOGE("Unknown seek mode: %d", mSeekMode);
+        return NULL;
+    }
+    mNumFrames = numFrames;
+
+    const char *mime;
+    if (!trackMeta()->findCString(kKeyMIMEType, &mime)) {
+        ALOGE("Could not find mime type");
+        return NULL;
+    }
+
+    mIsAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
+            || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+
+    if (frameTimeUs < 0) {
+        int64_t thumbNailTime;
+        if (!trackMeta()->findInt64(kKeyThumbnailTime, &thumbNailTime)
+                || thumbNailTime < 0) {
+            thumbNailTime = 0;
+        }
+        options->setSeekTo(thumbNailTime, mSeekMode);
+    } else {
+        options->setSeekTo(frameTimeUs, mSeekMode);
+    }
+
+    sp<AMessage> videoFormat;
+    if (convertMetaDataToMessage(trackMeta(), &videoFormat) != OK) {
+        ALOGE("b/23680780");
+        ALOGW("Failed to convert meta data to message");
+        return NULL;
+    }
+
+    // TODO: Use Flexible color instead
+    videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+
+    // For the thumbnail extraction case, try to allocate single buffer in both
+    // input and output ports, if seeking to a sync frame. NOTE: This request may
+    // fail if component requires more than that for decoding.
+    bool isSeekingClosest = (mSeekMode == MediaSource::ReadOptions::SEEK_CLOSEST)
+            || (mSeekMode == MediaSource::ReadOptions::SEEK_FRAME_INDEX);
+    if (!isSeekingClosest) {
+        videoFormat->setInt32("android._num-input-buffers", 1);
+        videoFormat->setInt32("android._num-output-buffers", 1);
+    }
+    return videoFormat;
+}
+
+status_t VideoFrameDecoder::onInputReceived(
+        const sp<MediaCodecBuffer> &codecBuffer,
+        const sp<MetaData> &sampleMeta, bool firstSample, uint32_t *flags) {
+    bool isSeekingClosest = (mSeekMode == MediaSource::ReadOptions::SEEK_CLOSEST)
+            || (mSeekMode == MediaSource::ReadOptions::SEEK_FRAME_INDEX);
+
+    if (firstSample && isSeekingClosest) {
+        sampleMeta->findInt64(kKeyTargetTime, &mTargetTimeUs);
+        ALOGV("Seeking closest: targetTimeUs=%lld", (long long)mTargetTimeUs);
+    }
+
+    if (mIsAvcOrHevc && !isSeekingClosest
+            && IsIDR(codecBuffer->data(), codecBuffer->size())) {
+        // Only need to decode one IDR frame, unless we're seeking with CLOSEST
+        // option, in which case we need to actually decode to targetTimeUs.
+        *flags |= MediaCodec::BUFFER_FLAG_EOS;
+    }
+    return OK;
+}
+
+status_t VideoFrameDecoder::onOutputReceived(
+        const sp<MediaCodecBuffer> &videoFrameBuffer,
+        const sp<AMessage> &outputFormat,
+        int64_t timeUs, bool *done) {
+    bool shouldOutput = (mTargetTimeUs < 0ll) || (timeUs >= mTargetTimeUs);
+
+    // If this is not the target frame, skip color convert.
+    if (!shouldOutput) {
+        *done = false;
+        return OK;
+    }
+
+    *done = (++mNumFramesDecoded >= mNumFrames);
+
+    int32_t width, height;
+    CHECK(outputFormat != NULL);
+    CHECK(outputFormat->findInt32("width", &width));
+    CHECK(outputFormat->findInt32("height", &height));
+
+    int32_t crop_left, crop_top, crop_right, crop_bottom;
+    if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
+        crop_left = crop_top = 0;
+        crop_right = width - 1;
+        crop_bottom = height - 1;
+    }
+
+    VideoFrame *frame = allocVideoFrame(
+            (crop_right - crop_left + 1),
+            (crop_bottom - crop_top + 1),
+            false /*metaOnly*/);
+    addFrame(frame);
+
+    int32_t srcFormat;
+    CHECK(outputFormat->findInt32("color-format", &srcFormat));
+
+    ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
+
+    if (converter.isValid()) {
+        converter.convert(
+                (const uint8_t *)videoFrameBuffer->data(),
+                width, height,
+                crop_left, crop_top, crop_right, crop_bottom,
+                frame->mData,
+                frame->mWidth,
+                frame->mHeight,
+                crop_left, crop_top, crop_right, crop_bottom);
+        return OK;
+    }
+
+    ALOGE("Unable to convert from format 0x%08x to 0x%08x",
+                srcFormat, dstFormat());
+    return ERROR_UNSUPPORTED;
+}
+
+sp<AMessage> ImageDecoder::onGetFormatAndSeekOptions(
+        int64_t frameTimeUs, size_t /*numFrames*/,
+        int /*seekMode*/, MediaSource::ReadOptions *options) {
+    sp<MetaData> overrideMeta;
+    if (frameTimeUs < 0) {
+        uint32_t type;
+        const void *data;
+        size_t size;
+        int64_t thumbNailTime = 0;
+        int32_t thumbnailWidth, thumbnailHeight;
+
+        // if we have a stand-alone thumbnail, set up the override meta,
+        // and set seekTo time to -1.
+        if (trackMeta()->findInt32(kKeyThumbnailWidth, &thumbnailWidth)
+         && trackMeta()->findInt32(kKeyThumbnailHeight, &thumbnailHeight)
+         && trackMeta()->findData(kKeyThumbnailHVCC, &type, &data, &size)){
+            overrideMeta = new MetaData(*(trackMeta()));
+            overrideMeta->remove(kKeyDisplayWidth);
+            overrideMeta->remove(kKeyDisplayHeight);
+            overrideMeta->setInt32(kKeyWidth, thumbnailWidth);
+            overrideMeta->setInt32(kKeyHeight, thumbnailHeight);
+            overrideMeta->setData(kKeyHVCC, type, data, size);
+            thumbNailTime = -1ll;
+            ALOGV("thumbnail: %dx%d", thumbnailWidth, thumbnailHeight);
+        }
+        options->setSeekTo(thumbNailTime);
+    } else {
+        options->setSeekTo(frameTimeUs);
+    }
+
+    mGridRows = mGridCols = 1;
+    if (overrideMeta == NULL) {
+        // check if we're dealing with a tiled heif
+        int32_t gridWidth, gridHeight, gridRows, gridCols;
+        if (trackMeta()->findInt32(kKeyGridWidth, &gridWidth) && gridWidth > 0
+         && trackMeta()->findInt32(kKeyGridHeight, &gridHeight) && gridHeight > 0
+         && trackMeta()->findInt32(kKeyGridRows, &gridRows) && gridRows > 0
+         && trackMeta()->findInt32(kKeyGridCols, &gridCols) && gridCols > 0) {
+            int32_t width, height;
+            CHECK(trackMeta()->findInt32(kKeyWidth, &width));
+            CHECK(trackMeta()->findInt32(kKeyHeight, &height));
+
+            if (width <= gridWidth * gridCols && height <= gridHeight * gridRows) {
+                ALOGV("grid: %dx%d, size: %dx%d, picture size: %dx%d",
+                        gridCols, gridRows, gridWidth, gridHeight, width, height);
+
+                overrideMeta = new MetaData(*(trackMeta()));
+                overrideMeta->setInt32(kKeyWidth, gridWidth);
+                overrideMeta->setInt32(kKeyHeight, gridHeight);
+                mGridCols = gridCols;
+                mGridRows = gridRows;
+            } else {
+                ALOGE("bad grid: %dx%d, size: %dx%d, picture size: %dx%d",
+                        gridCols, gridRows, gridWidth, gridHeight, width, height);
+            }
+        }
+        if (overrideMeta == NULL) {
+            overrideMeta = trackMeta();
+        }
+    }
+
+    sp<AMessage> videoFormat;
+    if (convertMetaDataToMessage(overrideMeta, &videoFormat) != OK) {
+        ALOGE("b/23680780");
+        ALOGW("Failed to convert meta data to message");
+        return NULL;
+    }
+
+    // TODO: Use Flexible color instead
+    videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+
+    if ((mGridRows == 1) && (mGridCols == 1)) {
+        videoFormat->setInt32("android._num-input-buffers", 1);
+        videoFormat->setInt32("android._num-output-buffers", 1);
+    }
+    return videoFormat;
+}
+
+status_t ImageDecoder::onOutputReceived(
+        const sp<MediaCodecBuffer> &videoFrameBuffer,
+        const sp<AMessage> &outputFormat, int64_t /*timeUs*/, bool *done) {
+    int32_t width, height;
+    CHECK(outputFormat != NULL);
+    CHECK(outputFormat->findInt32("width", &width));
+    CHECK(outputFormat->findInt32("height", &height));
+
+    int32_t imageWidth, imageHeight;
+    CHECK(trackMeta()->findInt32(kKeyWidth, &imageWidth));
+    CHECK(trackMeta()->findInt32(kKeyHeight, &imageHeight));
+
+    if (mFrame == NULL) {
+        mFrame = allocVideoFrame(imageWidth, imageHeight, false /*metaOnly*/);
+
+        addFrame(mFrame);
+    }
+
+    int32_t srcFormat;
+    CHECK(outputFormat->findInt32("color-format", &srcFormat));
+
+    ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
+
+    int32_t dstLeft, dstTop, dstRight, dstBottom;
+    int32_t numTiles = mGridRows * mGridCols;
+
+    dstLeft = mTilesDecoded % mGridCols * width;
+    dstTop = mTilesDecoded / mGridCols * height;
+    dstRight = dstLeft + width - 1;
+    dstBottom = dstTop + height - 1;
+
+    int32_t crop_left, crop_top, crop_right, crop_bottom;
+    if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
+        crop_left = crop_top = 0;
+        crop_right = width - 1;
+        crop_bottom = height - 1;
+    }
+
+    // apply crop on bottom-right
+    // TODO: need to move this into the color converter itself.
+    if (dstRight >= imageWidth) {
+        crop_right = imageWidth - dstLeft - 1;
+        dstRight = dstLeft + crop_right;
+    }
+    if (dstBottom >= imageHeight) {
+        crop_bottom = imageHeight - dstTop - 1;
+        dstBottom = dstTop + crop_bottom;
+    }
+
+    *done = (++mTilesDecoded >= numTiles);
+
+    if (converter.isValid()) {
+        converter.convert(
+                (const uint8_t *)videoFrameBuffer->data(),
+                width, height,
+                crop_left, crop_top, crop_right, crop_bottom,
+                mFrame->mData,
+                mFrame->mWidth,
+                mFrame->mHeight,
+                dstLeft, dstTop, dstRight, dstBottom);
+        return OK;
+    }
+
+    ALOGE("Unable to convert from format 0x%08x to 0x%08x",
+                srcFormat, dstFormat());
+    return ERROR_UNSUPPORTED;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/HevcUtils.cpp b/media/libstagefright/HevcUtils.cpp
index 7d463a9..91deca5 100644
--- a/media/libstagefright/HevcUtils.cpp
+++ b/media/libstagefright/HevcUtils.cpp
@@ -21,12 +21,12 @@
 #include <utility>
 
 #include "include/HevcUtils.h"
-#include "include/avc_utils.h"
 
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
 
diff --git a/media/libstagefright/InterfaceUtils.cpp b/media/libstagefright/InterfaceUtils.cpp
new file mode 100644
index 0000000..cf9fdf8
--- /dev/null
+++ b/media/libstagefright/InterfaceUtils.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/CallbackDataSource.h"
+
+#include <media/stagefright/CallbackMediaSource.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/RemoteDataSource.h>
+#include <media/stagefright/RemoteMediaExtractor.h>
+#include <media/stagefright/RemoteMediaSource.h>
+
+namespace android {
+
+sp<DataSource> CreateDataSourceFromIDataSource(const sp<IDataSource> &source) {
+    if (source == nullptr) {
+        return nullptr;
+    }
+    return new TinyCacheSource(new CallbackDataSource(source));
+}
+
+sp<IDataSource> CreateIDataSourceFromDataSource(const sp<DataSource> &source) {
+    if (source == nullptr) {
+        return nullptr;
+    }
+    return RemoteDataSource::wrap(source);
+}
+
+sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(const sp<MediaExtractor> &extractor) {
+    if (extractor == nullptr) {
+        return nullptr;
+    }
+    return RemoteMediaExtractor::wrap(extractor);
+}
+
+sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source) {
+    if (source == nullptr) {
+        return nullptr;
+    }
+    return new CallbackMediaSource(source);
+}
+
+sp<IMediaSource> CreateIMediaSourceFromMediaSource(const sp<MediaSource> &source) {
+    if (source == nullptr) {
+        return nullptr;
+    }
+    return RemoteMediaSource::wrap(source);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
index bafa4b2..ee3aedb 100644
--- a/media/libstagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -18,8 +18,8 @@
 #define LOG_TAG "JPEGSource"
 #include <utils/Log.h>
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/JPEGSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index 03ea959..4c85b0d 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -16,18 +16,18 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MPEG2TSWriter"
-#include <media/stagefright/foundation/ADebug.h>
 
+#include <media/MediaSource.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/MPEG2TSWriter.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
 #include <arpa/inet.h>
 
 #include "include/ESDS.h"
@@ -35,7 +35,7 @@
 namespace android {
 
 struct MPEG2TSWriter::SourceInfo : public AHandler {
-    explicit SourceInfo(const sp<IMediaSource> &source);
+    explicit SourceInfo(const sp<MediaSource> &source);
 
     void start(const sp<AMessage> &notify, const sp<MetaData> &params);
     void stop();
@@ -69,7 +69,7 @@
         kWhatRead  = 'read',
     };
 
-    sp<IMediaSource> mSource;
+    sp<MediaSource> mSource;
     sp<ALooper> mLooper;
     sp<AMessage> mNotify;
 
@@ -91,7 +91,7 @@
     DISALLOW_EVIL_CONSTRUCTORS(SourceInfo);
 };
 
-MPEG2TSWriter::SourceInfo::SourceInfo(const sp<IMediaSource> &source)
+MPEG2TSWriter::SourceInfo::SourceInfo(const sp<MediaSource> &source)
     : mSource(source),
       mLooper(new ALooper),
       mEOSReceived(false),
@@ -499,7 +499,7 @@
     }
 }
 
-status_t MPEG2TSWriter::addSource(const sp<IMediaSource> &source) {
+status_t MPEG2TSWriter::addSource(const sp<MediaSource> &source) {
     CHECK(!mStarted);
 
     sp<MetaData> meta = source->getFormat();
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 7786c4d..1fe5f60 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -32,23 +32,24 @@
 
 #include <functional>
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/ColorUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/Utils.h>
 #include <media/mediarecorder.h>
 #include <cutils/properties.h>
 
 #include "include/ESDS.h"
 #include "include/HevcUtils.h"
-#include "include/avc_utils.h"
 
 #ifndef __predict_false
 #define __predict_false(exp) __builtin_expect((exp) != 0, 0)
@@ -100,7 +101,7 @@
 
 class MPEG4Writer::Track {
 public:
-    Track(MPEG4Writer *owner, const sp<IMediaSource> &source, size_t trackId);
+    Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
 
     ~Track();
 
@@ -111,14 +112,18 @@
 
     int64_t getDurationUs() const;
     int64_t getEstimatedTrackSizeBytes() const;
+    int32_t getMetaSizeIncrease() const;
     void writeTrackHeader(bool use32BitOffset = true);
     int64_t getMinCttsOffsetTimeUs();
     void bufferChunk(int64_t timestampUs);
     bool isAvc() const { return mIsAvc; }
     bool isHevc() const { return mIsHevc; }
+    bool isHeic() const { return mIsHeic; }
     bool isAudio() const { return mIsAudio; }
     bool isMPEG4() const { return mIsMPEG4; }
+    bool usePrefix() const { return mIsAvc || mIsHevc || mIsHeic; }
     void addChunkOffset(off64_t offset);
+    void addItemOffsetAndSize(off64_t offset, size_t size);
     int32_t getTrackId() const { return mTrackId; }
     status_t dump(int fd, const Vector<String16>& args) const;
     static const char *getFourCCForMime(const char *mime);
@@ -271,7 +276,7 @@
 
     MPEG4Writer *mOwner;
     sp<MetaData> mMeta;
-    sp<IMediaSource> mSource;
+    sp<MediaSource> mSource;
     volatile bool mDone;
     volatile bool mPaused;
     volatile bool mResumed;
@@ -280,6 +285,7 @@
     bool mIsHevc;
     bool mIsAudio;
     bool mIsVideo;
+    bool mIsHeic;
     bool mIsMPEG4;
     bool mGotStartKeyFrame;
     bool mIsMalformed;
@@ -346,6 +352,16 @@
     int64_t mPreviousTrackTimeUs;
     int64_t mTrackEveryTimeDurationUs;
 
+    int32_t mRotation;
+
+    Vector<uint16_t> mProperties;
+    Vector<uint16_t> mDimgRefs;
+    int32_t mIsPrimary;
+    int32_t mWidth, mHeight;
+    int32_t mGridWidth, mGridHeight;
+    int32_t mGridRows, mGridCols;
+    size_t mNumTiles, mTileIndex;
+
     // Update the audio track's drift information.
     void updateDriftTime(const sp<MetaData>& meta);
 
@@ -385,7 +401,6 @@
 
     // Simple validation on the codec specific data
     status_t checkCodecSpecificData() const;
-    int32_t mRotation;
 
     void updateTrackSizeEstimate();
     void addOneStscTableEntry(size_t chunkId, size_t sampleId);
@@ -473,13 +488,18 @@
     mUse32BitOffset = true;
     mOffset = 0;
     mMdatOffset = 0;
-    mMoovBoxBuffer = NULL;
-    mMoovBoxBufferOffset = 0;
-    mWriteMoovBoxToMemory = false;
+    mInMemoryCache = NULL;
+    mInMemoryCacheOffset = 0;
+    mInMemoryCacheSize = 0;
+    mWriteBoxToMemory = false;
     mFreeBoxOffset = 0;
     mStreamableFile = false;
-    mEstimatedMoovBoxSize = 0;
     mTimeScale = -1;
+    mHasFileLevelMeta = false;
+    mHasMoovBox = false;
+    mPrimaryItemId = 0;
+    mAssociationEntryCount = 0;
+    mNumGrids = 0;
 
     // Following variables only need to be set for the first recording session.
     // And they will stay the same for all the recording sessions.
@@ -566,13 +586,15 @@
         }
     } else if (!strncasecmp(mime, "application/", 12)) {
         return "mett";
+    } else if (!strcasecmp(MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, mime)) {
+        return "heic";
     } else {
         ALOGE("Track (%s) other than video/audio/metadata is not supported", mime);
     }
     return NULL;
 }
 
-status_t MPEG4Writer::addSource(const sp<IMediaSource> &source) {
+status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
     Mutex::Autolock l(mLock);
     if (mStarted) {
         ALOGE("Attempt to add source AFTER recording is started");
@@ -594,6 +616,9 @@
     Track *track = new Track(this, source, 1 + mTracks.size());
     mTracks.push_back(track);
 
+    mHasMoovBox |= !track->isHeic();
+    mHasFileLevelMeta |= track->isHeic();
+
     return OK;
 }
 
@@ -655,6 +680,32 @@
 #endif
 }
 
+int64_t MPEG4Writer::estimateFileLevelMetaSize() {
+    // base meta size
+    int64_t metaSize =     12  // meta fullbox header
+                         + 33  // hdlr box
+                         + 14  // pitm box
+                         + 16  // iloc box (fixed size portion)
+                         + 14  // iinf box (fixed size portion)
+                         + 32  // iprp box (fixed size protion)
+                         + 8   // idat box (when empty)
+                         + 12  // iref box (when empty)
+                         ;
+
+    for (List<Track *>::iterator it = mTracks.begin();
+         it != mTracks.end(); ++it) {
+        if ((*it)->isHeic()) {
+            metaSize += (*it)->getMetaSizeIncrease();
+        }
+    }
+
+    ALOGV("estimated meta size: %lld", (long long) metaSize);
+
+    // Need at least 8-byte padding at the end, otherwise the left-over
+    // freebox may become malformed
+    return metaSize + 8;
+}
+
 int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
     // This implementation is highly experimental/heurisitic.
     //
@@ -714,7 +765,11 @@
     ALOGI("limits: %" PRId64 "/%" PRId64 " bytes/us, bit rate: %d bps and the"
          " estimated moov size %" PRId64 " bytes",
          mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
-    return factor * size;
+
+    int64_t estimatedSize = factor * size;
+    CHECK_GE(estimatedSize, 8);
+
+    return estimatedSize;
 }
 
 status_t MPEG4Writer::start(MetaData *param) {
@@ -796,63 +851,70 @@
          mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes);
 
     /*
-     * mWriteMoovBoxToMemory is true if the amount of data in moov box is
-     * smaller than the reserved free space at the beginning of a file, AND
-     * when the content of moov box is constructed. Note that video/audio
-     * frame data is always written to the file but not in the memory.
+     * mWriteBoxToMemory is true if the amount of data in a file-level meta or
+     * moov box is smaller than the reserved free space at the beginning of a
+     * file, AND when the content of the box is constructed. Note that video/
+     * audio frame data is always written to the file but not in the memory.
      *
-     * Before stop()/reset() is called, mWriteMoovBoxToMemory is always
+     * Before stop()/reset() is called, mWriteBoxToMemory is always
      * false. When reset() is called at the end of a recording session,
-     * Moov box needs to be constructed.
+     * file-level meta and/or moov box needs to be constructed.
      *
-     * 1) Right before a moov box is constructed, mWriteMoovBoxToMemory
-     * to set to mStreamableFile so that if
-     * the file is intended to be streamable, it is set to true;
-     * otherwise, it is set to false. When the value is set to false,
-     * all the content of the moov box is written immediately to
+     * 1) Right before the box is constructed, mWriteBoxToMemory to set to
+     * mStreamableFile so that if the file is intended to be streamable, it
+     * is set to true; otherwise, it is set to false. When the value is set
+     * to false, all the content of that box is written immediately to
      * the end of the file. When the value is set to true, all the
-     * content of the moov box is written to an in-memory cache,
-     * mMoovBoxBuffer, util the following condition happens. Note
+     * content of that box is written to an in-memory cache,
+     * mInMemoryCache, util the following condition happens. Note
      * that the size of the in-memory cache is the same as the
      * reserved free space at the beginning of the file.
      *
-     * 2) While the data of the moov box is written to an in-memory
+     * 2) While the data of the box is written to an in-memory
      * cache, the data size is checked against the reserved space.
-     * If the data size surpasses the reserved space, subsequent moov
-     * data could no longer be hold in the in-memory cache. This also
+     * If the data size surpasses the reserved space, subsequent box data
+     * could no longer be hold in the in-memory cache. This also
      * indicates that the reserved space was too small. At this point,
-     * _all_ moov data must be written to the end of the file.
-     * mWriteMoovBoxToMemory must be set to false to direct the write
+     * _all_ subsequent box data must be written to the end of the file.
+     * mWriteBoxToMemory must be set to false to direct the write
      * to the file.
      *
-     * 3) If the data size in moov box is smaller than the reserved
-     * space after moov box is completely constructed, the in-memory
-     * cache copy of the moov box is written to the reserved free
-     * space. Thus, immediately after the moov is completedly
-     * constructed, mWriteMoovBoxToMemory is always set to false.
+     * 3) If the data size in the box is smaller than the reserved
+     * space after the box is completely constructed, the in-memory
+     * cache copy of the box is written to the reserved free space.
+     * mWriteBoxToMemory is always set to false after all boxes that
+     * using the in-memory cache have been constructed.
      */
-    mWriteMoovBoxToMemory = false;
-    mMoovBoxBuffer = NULL;
-    mMoovBoxBufferOffset = 0;
+    mWriteBoxToMemory = false;
+    mInMemoryCache = NULL;
+    mInMemoryCacheOffset = 0;
+
+
+    ALOGV("muxer starting: mHasMoovBox %d, mHasFileLevelMeta %d",
+            mHasMoovBox, mHasFileLevelMeta);
 
     writeFtypBox(param);
 
     mFreeBoxOffset = mOffset;
 
-    if (mEstimatedMoovBoxSize == 0) {
+    if (mInMemoryCacheSize == 0) {
         int32_t bitRate = -1;
-        if (param) {
-            param->findInt32(kKeyBitRate, &bitRate);
+        if (mHasFileLevelMeta) {
+            mInMemoryCacheSize += estimateFileLevelMetaSize();
         }
-        mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
+        if (mHasMoovBox) {
+            if (param) {
+                param->findInt32(kKeyBitRate, &bitRate);
+            }
+            mInMemoryCacheSize += estimateMoovBoxSize(bitRate);
+        }
     }
-    CHECK_GE(mEstimatedMoovBoxSize, 8);
     if (mStreamableFile) {
         // Reserve a 'free' box only for streamable file
         lseek64(mFd, mFreeBoxOffset, SEEK_SET);
-        writeInt32(mEstimatedMoovBoxSize);
+        writeInt32(mInMemoryCacheSize);
         write("free", 4);
-        mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
+        mMdatOffset = mFreeBoxOffset + mInMemoryCacheSize;
     } else {
         mMdatOffset = mOffset;
     }
@@ -964,8 +1026,8 @@
     mFd = -1;
     mInitCheck = NO_INIT;
     mStarted = false;
-    free(mMoovBoxBuffer);
-    mMoovBoxBuffer = NULL;
+    free(mInMemoryCache);
+    mInMemoryCache = NULL;
 }
 
 void MPEG4Writer::finishCurrentSession() {
@@ -1008,13 +1070,18 @@
     status_t err = OK;
     int64_t maxDurationUs = 0;
     int64_t minDurationUs = 0x7fffffffffffffffLL;
+    int32_t nonImageTrackCount = 0;
     for (List<Track *>::iterator it = mTracks.begin();
-         it != mTracks.end(); ++it) {
+        it != mTracks.end(); ++it) {
         status_t status = (*it)->stop(stopSource);
         if (err == OK && status != OK) {
             err = status;
         }
 
+        // skip image tracks
+        if ((*it)->isHeic()) continue;
+        nonImageTrackCount++;
+
         int64_t durationUs = (*it)->getDurationUs();
         if (durationUs > maxDurationUs) {
             maxDurationUs = durationUs;
@@ -1024,7 +1091,7 @@
         }
     }
 
-    if (mTracks.size() > 1) {
+    if (nonImageTrackCount > 1) {
         ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us",
             minDurationUs, maxDurationUs);
     }
@@ -1050,45 +1117,43 @@
     }
     lseek64(mFd, mOffset, SEEK_SET);
 
-    // Construct moov box now
-    mMoovBoxBufferOffset = 0;
-    mWriteMoovBoxToMemory = mStreamableFile;
-    if (mWriteMoovBoxToMemory) {
+    // Construct file-level meta and moov box now
+    mInMemoryCacheOffset = 0;
+    mWriteBoxToMemory = mStreamableFile;
+    if (mWriteBoxToMemory) {
         // There is no need to allocate in-memory cache
-        // for moov box if the file is not streamable.
+        // if the file is not streamable.
 
-        mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
-        CHECK(mMoovBoxBuffer != NULL);
-    }
-    writeMoovBox(maxDurationUs);
-
-    // mWriteMoovBoxToMemory could be set to false in
-    // MPEG4Writer::write() method
-    if (mWriteMoovBoxToMemory) {
-        mWriteMoovBoxToMemory = false;
-        // Content of the moov box is saved in the cache, and the in-memory
-        // moov box needs to be written to the file in a single shot.
-
-        CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize);
-
-        // Moov box
-        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
-        mOffset = mFreeBoxOffset;
-        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset);
-
-        // Free box
-        lseek64(mFd, mOffset, SEEK_SET);
-        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
-        write("free", 4);
-    } else {
-        ALOGI("The mp4 file will not be streamable.");
+        mInMemoryCache = (uint8_t *) malloc(mInMemoryCacheSize);
+        CHECK(mInMemoryCache != NULL);
     }
 
-    // Free in-memory cache for moov box
-    if (mMoovBoxBuffer != NULL) {
-        free(mMoovBoxBuffer);
-        mMoovBoxBuffer = NULL;
-        mMoovBoxBufferOffset = 0;
+    if (mHasFileLevelMeta) {
+        writeFileLevelMetaBox();
+        if (mWriteBoxToMemory) {
+            writeCachedBoxToFile("meta");
+        } else {
+            ALOGI("The file meta box is written at the end.");
+        }
+    }
+
+    if (mHasMoovBox) {
+        writeMoovBox(maxDurationUs);
+        // mWriteBoxToMemory could be set to false in
+        // MPEG4Writer::write() method
+        if (mWriteBoxToMemory) {
+            writeCachedBoxToFile("moov");
+        } else {
+            ALOGI("The mp4 file will not be streamable.");
+        }
+    }
+    mWriteBoxToMemory = false;
+
+    // Free in-memory cache for box writing
+    if (mInMemoryCache != NULL) {
+        free(mInMemoryCache);
+        mInMemoryCache = NULL;
+        mInMemoryCacheOffset = 0;
     }
 
     CHECK(mBoxes.empty());
@@ -1097,6 +1162,42 @@
     return err;
 }
 
+/*
+ * Writes currently cached box into file.
+ *
+ * Must be called while mWriteBoxToMemory is true, and will not modify
+ * mWriteBoxToMemory. After the call, remaining cache size will be
+ * reduced and buffer offset will be set to the beginning of the cache.
+ */
+void MPEG4Writer::writeCachedBoxToFile(const char *type) {
+    CHECK(mWriteBoxToMemory);
+
+    mWriteBoxToMemory = false;
+    // Content of the box is saved in the cache, and the in-memory
+    // box needs to be written to the file in a single shot.
+
+    CHECK_LE(mInMemoryCacheOffset + 8, mInMemoryCacheSize);
+
+    // Cached box
+    lseek64(mFd, mFreeBoxOffset, SEEK_SET);
+    mOffset = mFreeBoxOffset;
+    write(mInMemoryCache, 1, mInMemoryCacheOffset);
+
+    // Free box
+    lseek64(mFd, mOffset, SEEK_SET);
+    mFreeBoxOffset = mOffset;
+    writeInt32(mInMemoryCacheSize - mInMemoryCacheOffset);
+    write("free", 4);
+
+    // Rewind buffering to the beginning, and restore mWriteBoxToMemory flag
+    mInMemoryCacheSize -= mInMemoryCacheOffset;
+    mInMemoryCacheOffset = 0;
+    mWriteBoxToMemory = true;
+
+    ALOGV("dumped out %s box, estimated size remaining %lld",
+            type, (long long)mInMemoryCacheSize);
+}
+
 uint32_t MPEG4Writer::getMpeg4Time() {
     time_t now = time(NULL);
     // MP4 file uses time counting seconds since midnight, Jan. 1, 1904
@@ -1141,14 +1242,16 @@
     if (mAreGeoTagsAvailable) {
         writeUdtaBox();
     }
-    writeMetaBox();
+    writeMoovLevelMetaBox();
     // Loop through all the tracks to get the global time offset if there is
     // any ctts table appears in a video track.
     int64_t minCttsOffsetTimeUs = kMaxCttsOffsetTimeUs;
     for (List<Track *>::iterator it = mTracks.begin();
         it != mTracks.end(); ++it) {
-        minCttsOffsetTimeUs =
-            std::min(minCttsOffsetTimeUs, (*it)->getMinCttsOffsetTimeUs());
+        if (!(*it)->isHeic()) {
+            minCttsOffsetTimeUs =
+                std::min(minCttsOffsetTimeUs, (*it)->getMinCttsOffsetTimeUs());
+        }
     }
     ALOGI("Ajust the moov start time from %lld us -> %lld us",
             (long long)mStartTimestampUs,
@@ -1158,7 +1261,9 @@
 
     for (List<Track *>::iterator it = mTracks.begin();
         it != mTracks.end(); ++it) {
-        (*it)->writeTrackHeader(mUse32BitOffset);
+        if (!(*it)->isHeic()) {
+            (*it)->writeTrackHeader(mUse32BitOffset);
+        }
     }
     endBox();  // moov
 }
@@ -1167,17 +1272,31 @@
     beginBox("ftyp");
 
     int32_t fileType;
-    if (param && param->findInt32(kKeyFileType, &fileType) &&
-        fileType != OUTPUT_FORMAT_MPEG_4) {
+    if (!param || !param->findInt32(kKeyFileType, &fileType)) {
+        fileType = OUTPUT_FORMAT_MPEG_4;
+    }
+    if (fileType != OUTPUT_FORMAT_MPEG_4 && fileType != OUTPUT_FORMAT_HEIF) {
         writeFourcc("3gp4");
         writeInt32(0);
         writeFourcc("isom");
         writeFourcc("3gp4");
     } else {
-        writeFourcc("mp42");
+        // Only write "heic" as major brand if the client specified HEIF
+        // AND we indeed receive some image heic tracks.
+        if (fileType == OUTPUT_FORMAT_HEIF && mHasFileLevelMeta) {
+            writeFourcc("heic");
+        } else {
+            writeFourcc("mp42");
+        }
         writeInt32(0);
-        writeFourcc("isom");
-        writeFourcc("mp42");
+        if (mHasFileLevelMeta) {
+            writeFourcc("mif1");
+            writeFourcc("heic");
+        }
+        if (mHasMoovBox) {
+            writeFourcc("isom");
+            writeFourcc("mp42");
+        }
     }
 
     endBox();
@@ -1224,15 +1343,21 @@
     mLock.unlock();
 }
 
-off64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
+off64_t MPEG4Writer::addSample_l(
+        MediaBuffer *buffer, bool usePrefix, size_t *bytesWritten) {
     off64_t old_offset = mOffset;
 
-    ::write(mFd,
-          (const uint8_t *)buffer->data() + buffer->range_offset(),
-          buffer->range_length());
+    if (usePrefix) {
+        addMultipleLengthPrefixedSamples_l(buffer);
+    } else {
+        ::write(mFd,
+              (const uint8_t *)buffer->data() + buffer->range_offset(),
+              buffer->range_length());
 
-    mOffset += buffer->range_length();
+        mOffset += buffer->range_length();
+    }
 
+    *bytesWritten = mOffset - old_offset;
     return old_offset;
 }
 
@@ -1250,9 +1375,7 @@
     }
 }
 
-off64_t MPEG4Writer::addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer) {
-    off64_t old_offset = mOffset;
-
+void MPEG4Writer::addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer) {
     const size_t kExtensionNALSearchRange = 64; // bytes to look for non-VCL NALUs
 
     const uint8_t *dataStart = (const uint8_t *)buffer->data() + buffer->range_offset();
@@ -1277,13 +1400,9 @@
     buffer->set_range(buffer->range_offset() + currentNalOffset,
             buffer->range_length() - currentNalOffset);
     addLengthPrefixedSample_l(buffer);
-
-    return old_offset;
 }
 
-off64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
-    off64_t old_offset = mOffset;
-
+void MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
     size_t length = buffer->range_length();
 
     if (mUse4ByteNalLength) {
@@ -1311,40 +1430,35 @@
         ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length);
         mOffset += length + 2;
     }
-
-    return old_offset;
 }
 
 size_t MPEG4Writer::write(
         const void *ptr, size_t size, size_t nmemb) {
 
     const size_t bytes = size * nmemb;
-    if (mWriteMoovBoxToMemory) {
+    if (mWriteBoxToMemory) {
 
-        off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
-        if (moovBoxSize > mEstimatedMoovBoxSize) {
-            // The reserved moov box at the beginning of the file
-            // is not big enough. Moov box should be written to
-            // the end of the file from now on, but not to the
-            // in-memory cache.
+        off64_t boxSize = 8 + mInMemoryCacheOffset + bytes;
+        if (boxSize > mInMemoryCacheSize) {
+            // The reserved free space at the beginning of the file is not big
+            // enough. Boxes should be written to the end of the file from now
+            // on, but not to the in-memory cache.
 
-            // We write partial moov box that is in the memory to
-            // the file first.
+            // We write partial box that is in the memory to the file first.
             for (List<off64_t>::iterator it = mBoxes.begin();
                  it != mBoxes.end(); ++it) {
                 (*it) += mOffset;
             }
             lseek64(mFd, mOffset, SEEK_SET);
-            ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset);
+            ::write(mFd, mInMemoryCache, mInMemoryCacheOffset);
             ::write(mFd, ptr, bytes);
-            mOffset += (bytes + mMoovBoxBufferOffset);
+            mOffset += (bytes + mInMemoryCacheOffset);
 
-            // All subsequent moov box content will be written
-            // to the end of the file.
-            mWriteMoovBoxToMemory = false;
+            // All subsequent boxes will be written to the end of the file.
+            mWriteBoxToMemory = false;
         } else {
-            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
-            mMoovBoxBufferOffset += bytes;
+            memcpy(mInMemoryCache + mInMemoryCacheOffset, ptr, bytes);
+            mInMemoryCacheOffset += bytes;
         }
     } else {
         ::write(mFd, ptr, size * nmemb);
@@ -1354,8 +1468,8 @@
 }
 
 void MPEG4Writer::beginBox(uint32_t id) {
-    mBoxes.push_back(mWriteMoovBoxToMemory?
-            mMoovBoxBufferOffset: mOffset);
+    mBoxes.push_back(mWriteBoxToMemory?
+            mInMemoryCacheOffset: mOffset);
 
     writeInt32(0);
     writeInt32(id);
@@ -1364,8 +1478,8 @@
 void MPEG4Writer::beginBox(const char *fourcc) {
     CHECK_EQ(strlen(fourcc), 4u);
 
-    mBoxes.push_back(mWriteMoovBoxToMemory?
-            mMoovBoxBufferOffset: mOffset);
+    mBoxes.push_back(mWriteBoxToMemory?
+            mInMemoryCacheOffset: mOffset);
 
     writeInt32(0);
     writeFourcc(fourcc);
@@ -1377,9 +1491,9 @@
     off64_t offset = *--mBoxes.end();
     mBoxes.erase(--mBoxes.end());
 
-    if (mWriteMoovBoxToMemory) {
-       int32_t x = htonl(mMoovBoxBufferOffset - offset);
-       memcpy(mMoovBoxBuffer + offset, &x, 4);
+    if (mWriteBoxToMemory) {
+        int32_t x = htonl(mInMemoryCacheOffset - offset);
+        memcpy(mInMemoryCache + offset, &x, 4);
     } else {
         lseek64(mFd, offset, SEEK_SET);
         writeInt32(mOffset - offset);
@@ -1538,7 +1652,7 @@
     if (mMaxFileSizeLimitBytes == 0) {
         return false;
     }
-    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
+    int64_t nTotalBytesEstimate = static_cast<int64_t>(mInMemoryCacheSize);
     for (List<Track *>::iterator it = mTracks.begin();
          it != mTracks.end(); ++it) {
         nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
@@ -1561,7 +1675,7 @@
         return false;
     }
 
-    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
+    int64_t nTotalBytesEstimate = static_cast<int64_t>(mInMemoryCacheSize);
     for (List<Track *>::iterator it = mTracks.begin();
          it != mTracks.end(); ++it) {
         nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
@@ -1583,7 +1697,7 @@
 
     for (List<Track *>::iterator it = mTracks.begin();
          it != mTracks.end(); ++it) {
-        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
+        if (!(*it)->isHeic() && (*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
             return true;
         }
     }
@@ -1626,7 +1740,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 MPEG4Writer::Track::Track(
-        MPEG4Writer *owner, const sp<IMediaSource> &source, size_t trackId)
+        MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
     : mOwner(owner),
       mMeta(source->getFormat()),
       mSource(source),
@@ -1655,7 +1769,16 @@
       mGotAllCodecSpecificData(false),
       mReachedEOS(false),
       mStartTimestampUs(-1),
-      mRotation(0) {
+      mRotation(0),
+      mIsPrimary(0),
+      mWidth(0),
+      mHeight(0),
+      mGridWidth(0),
+      mGridHeight(0),
+      mGridRows(0),
+      mGridCols(0),
+      mNumTiles(1),
+      mTileIndex(0) {
     getCodecSpecificDataFromInputFormatIfPossible();
 
     const char *mime;
@@ -1664,6 +1787,7 @@
     mIsHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
     mIsAudio = !strncasecmp(mime, "audio/", 6);
     mIsVideo = !strncasecmp(mime, "video/", 6);
+    mIsHeic = !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
     mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
                !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
 
@@ -1675,7 +1799,27 @@
         }
     }
 
-    setTimeScale();
+    if (!mIsHeic) {
+        setTimeScale();
+    } else {
+        CHECK(mMeta->findInt32(kKeyWidth, &mWidth) && (mWidth > 0));
+        CHECK(mMeta->findInt32(kKeyHeight, &mHeight) && (mHeight > 0));
+
+        int32_t gridWidth, gridHeight, gridRows, gridCols;
+        if (mMeta->findInt32(kKeyGridWidth, &gridWidth) && (gridWidth > 0) &&
+            mMeta->findInt32(kKeyGridHeight, &gridHeight) && (gridHeight > 0) &&
+            mMeta->findInt32(kKeyGridRows, &gridRows) && (gridRows > 0) &&
+            mMeta->findInt32(kKeyGridCols, &gridCols) && (gridCols > 0)) {
+            mGridWidth = gridWidth;
+            mGridHeight = gridHeight;
+            mGridRows = gridRows;
+            mGridCols = gridCols;
+            mNumTiles = gridRows * gridCols;
+        }
+        if (!mMeta->findInt32(kKeyTrackIsDefault, &mIsPrimary)) {
+            mIsPrimary = false;
+        }
+    }
 }
 
 // Clear all the internal states except the CSD data.
@@ -1723,15 +1867,15 @@
 }
 
 void MPEG4Writer::Track::updateTrackSizeEstimate() {
-
-    uint32_t stcoBoxCount = (mOwner->use32BitFileOffset()
-                            ? mStcoTableEntries->count()
-                            : mCo64TableEntries->count());
-    int64_t stcoBoxSizeBytes = stcoBoxCount * 4;
-    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4);
-
     mEstimatedTrackSizeBytes = mMdatSizeBytes;  // media data size
-    if (!mOwner->isFileStreamable()) {
+
+    if (!isHeic() && !mOwner->isFileStreamable()) {
+        uint32_t stcoBoxCount = (mOwner->use32BitFileOffset()
+                                ? mStcoTableEntries->count()
+                                : mCo64TableEntries->count());
+        int64_t stcoBoxSizeBytes = stcoBoxCount * 4;
+        int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4);
+
         // Reserved free space is not large enough to hold
         // all meta data and thus wasted.
         mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 +  // stsc box size
@@ -1745,10 +1889,9 @@
 
 void MPEG4Writer::Track::addOneStscTableEntry(
         size_t chunkId, size_t sampleId) {
-
-        mStscTableEntries->add(htonl(chunkId));
-        mStscTableEntries->add(htonl(sampleId));
-        mStscTableEntries->add(htonl(1));
+    mStscTableEntries->add(htonl(chunkId));
+    mStscTableEntries->add(htonl(sampleId));
+    mStscTableEntries->add(htonl(1));
 }
 
 void MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
@@ -1794,6 +1937,7 @@
 }
 
 void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
+    CHECK(!mIsHeic);
     if (mOwner->use32BitFileOffset()) {
         uint32_t value = offset;
         mStcoTableEntries->add(htonl(value));
@@ -1802,6 +1946,70 @@
     }
 }
 
+void MPEG4Writer::Track::addItemOffsetAndSize(off64_t offset, size_t size) {
+    CHECK(mIsHeic);
+
+    if (offset > UINT32_MAX || size > UINT32_MAX) {
+        ALOGE("offset or size is out of range: %lld, %lld",
+                (long long) offset, (long long) size);
+        mIsMalformed = true;
+    }
+    if (mIsMalformed) {
+        return;
+    }
+    if (mTileIndex >= mNumTiles) {
+        ALOGW("Ignoring excess tiles!");
+        return;
+    }
+
+    if (mProperties.empty()) {
+        mProperties.push_back(mOwner->addProperty_l({
+            .type = FOURCC('h', 'v', 'c', 'C'),
+            .hvcc = ABuffer::CreateAsCopy(mCodecSpecificData, mCodecSpecificDataSize)
+        }));
+
+        mProperties.push_back(mOwner->addProperty_l({
+            .type = FOURCC('i', 's', 'p', 'e'),
+            .width = (mNumTiles > 1) ? mGridWidth : mWidth,
+            .height = (mNumTiles > 1) ? mGridHeight : mHeight,
+        }));
+    }
+
+    uint16_t itemId = mOwner->addItem_l({
+        .itemType = "hvc1",
+        .isPrimary = (mNumTiles > 1) ? false : (mIsPrimary != 0),
+        .isHidden = (mNumTiles > 1),
+        .offset = (uint32_t)offset,
+        .size = (uint32_t)size,
+        .properties = mProperties,
+    });
+
+    mTileIndex++;
+    if (mNumTiles > 1) {
+        mDimgRefs.push_back(itemId);
+
+        if (mTileIndex == mNumTiles) {
+            mProperties.clear();
+            mProperties.push_back(mOwner->addProperty_l({
+                .type = FOURCC('i', 's', 'p', 'e'),
+                .width = mWidth,
+                .height = mHeight,
+            }));
+            mOwner->addItem_l({
+                .itemType = "grid",
+                .isPrimary = (mIsPrimary != 0),
+                .isHidden = false,
+                .rows = (uint32_t)mGridRows,
+                .cols = (uint32_t)mGridCols,
+                .width = (uint32_t)mWidth,
+                .height = (uint32_t)mHeight,
+                .properties = mProperties,
+                .dimgRefs = mDimgRefs,
+            });
+        }
+    }
+}
+
 void MPEG4Writer::Track::setTimeScale() {
     ALOGV("setTimeScale");
     // Default time scale
@@ -1854,7 +2062,8 @@
     size_t size = 0;
     if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
         mMeta->findData(kKeyAVCC, &type, &data, &size);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
+               !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
         mMeta->findData(kKeyHVCC, &type, &data, &size);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
@@ -1944,14 +2153,16 @@
         chunk->mTimeStampUs, chunk->mTrack->getTrackType());
 
     int32_t isFirstSample = true;
+    bool usePrefix = chunk->mTrack->usePrefix();
     while (!chunk->mSamples.empty()) {
         List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
 
-        off64_t offset = (chunk->mTrack->isAvc() || chunk->mTrack->isHevc())
-                                ? addMultipleLengthPrefixedSamples_l(*it)
-                                : addSample_l(*it);
+        size_t bytesWritten;
+        off64_t offset = addSample_l(*it, usePrefix, &bytesWritten);
 
-        if (isFirstSample) {
+        if (chunk->mTrack->isHeic()) {
+            chunk->mTrack->addItemOffsetAndSize(offset, bytesWritten);
+        } else if (isFirstSample) {
             chunk->mTrack->addChunkOffset(offset);
             isFirstSample = false;
         }
@@ -2636,7 +2847,7 @@
                             (const uint8_t *)buffer->data()
                                 + buffer->range_offset(),
                             buffer->range_length());
-                } else if (mIsHevc) {
+                } else if (mIsHevc || mIsHeic) {
                     err = makeHEVCCodecSpecificData(
                             (const uint8_t *)buffer->data()
                                 + buffer->range_offset(),
@@ -2661,7 +2872,8 @@
         }
 
         // Per-frame metadata sample's size must be smaller than max allowed.
-        if (!mIsVideo && !mIsAudio && buffer->range_length() >= kMaxMetadataSize) {
+        if (!mIsVideo && !mIsAudio && !mIsHeic &&
+                buffer->range_length() >= kMaxMetadataSize) {
             ALOGW("Buffer size is %zu. Maximum metadata buffer size is %lld for %s track",
                     buffer->range_length(), (long long)kMaxMetadataSize, trackName);
             buffer->release();
@@ -2682,10 +2894,10 @@
         buffer->release();
         buffer = NULL;
 
-        if (mIsAvc || mIsHevc) StripStartcode(copy);
+        if (usePrefix()) StripStartcode(copy);
 
         size_t sampleSize = copy->range_length();
-        if (mIsAvc || mIsHevc) {
+        if (usePrefix()) {
             if (mOwner->useNalLengthFour()) {
                 sampleSize += 4;
             } else {
@@ -2947,15 +3159,19 @@
             trackProgressStatus(timestampUs);
         }
         if (!hasMultipleTracks) {
-            off64_t offset = (mIsAvc || mIsHevc) ? mOwner->addMultipleLengthPrefixedSamples_l(copy)
-                                 : mOwner->addSample_l(copy);
+            size_t bytesWritten;
+            off64_t offset = mOwner->addSample_l(copy, usePrefix(), &bytesWritten);
 
-            uint32_t count = (mOwner->use32BitFileOffset()
-                        ? mStcoTableEntries->count()
-                        : mCo64TableEntries->count());
+            if (mIsHeic) {
+                addItemOffsetAndSize(offset, bytesWritten);
+            } else {
+                uint32_t count = (mOwner->use32BitFileOffset()
+                            ? mStcoTableEntries->count()
+                            : mCo64TableEntries->count());
 
-            if (count == 0) {
-                addChunkOffset(offset);
+                if (count == 0) {
+                    addChunkOffset(offset);
+                }
             }
             copy->release();
             copy = NULL;
@@ -2963,7 +3179,10 @@
         }
 
         mChunkSamples.push_back(copy);
-        if (interleaveDurationUs == 0) {
+        if (mIsHeic) {
+            bufferChunk(0 /*timestampUs*/);
+            ++nChunks;
+        } else if (interleaveDurationUs == 0) {
             addOneStscTableEntry(++nChunks, 1);
             bufferChunk(timestampUs);
         } else {
@@ -2996,42 +3215,49 @@
 
     mOwner->trackProgressStatus(mTrackId, -1, err);
 
-    // Last chunk
-    if (!hasMultipleTracks) {
-        addOneStscTableEntry(1, mStszTableEntries->count());
-    } else if (!mChunkSamples.empty()) {
-        addOneStscTableEntry(++nChunks, mChunkSamples.size());
-        bufferChunk(timestampUs);
-    }
-
-    // We don't really know how long the last frame lasts, since
-    // there is no frame time after it, just repeat the previous
-    // frame's duration.
-    if (mStszTableEntries->count() == 1) {
-        lastDurationUs = 0;  // A single sample's duration
-        lastDurationTicks = 0;
-    } else {
-        ++sampleCount;  // Count for the last sample
-    }
-
-    if (mStszTableEntries->count() <= 2) {
-        addOneSttsTableEntry(1, lastDurationTicks);
-        if (sampleCount - 1 > 0) {
-            addOneSttsTableEntry(sampleCount - 1, lastDurationTicks);
+    if (mIsHeic) {
+        if (!mChunkSamples.empty()) {
+            bufferChunk(0);
+            ++nChunks;
         }
     } else {
-        addOneSttsTableEntry(sampleCount, lastDurationTicks);
-    }
-
-    // The last ctts box may not have been written yet, and this
-    // is to make sure that we write out the last ctts box.
-    if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
-        if (cttsSampleCount > 0) {
-            addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+        // Last chunk
+        if (!hasMultipleTracks) {
+            addOneStscTableEntry(1, mStszTableEntries->count());
+        } else if (!mChunkSamples.empty()) {
+            addOneStscTableEntry(++nChunks, mChunkSamples.size());
+            bufferChunk(timestampUs);
         }
-    }
 
-    mTrackDurationUs += lastDurationUs;
+        // We don't really know how long the last frame lasts, since
+        // there is no frame time after it, just repeat the previous
+        // frame's duration.
+        if (mStszTableEntries->count() == 1) {
+            lastDurationUs = 0;  // A single sample's duration
+            lastDurationTicks = 0;
+        } else {
+            ++sampleCount;  // Count for the last sample
+        }
+
+        if (mStszTableEntries->count() <= 2) {
+            addOneSttsTableEntry(1, lastDurationTicks);
+            if (sampleCount - 1 > 0) {
+                addOneSttsTableEntry(sampleCount - 1, lastDurationTicks);
+            }
+        } else {
+            addOneSttsTableEntry(sampleCount, lastDurationTicks);
+        }
+
+        // The last ctts box may not have been written yet, and this
+        // is to make sure that we write out the last ctts box.
+        if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
+            if (cttsSampleCount > 0) {
+                addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+            }
+        }
+
+        mTrackDurationUs += lastDurationUs;
+    }
     mReachedEOS = true;
 
     sendTrackSummary(hasMultipleTracks);
@@ -3053,7 +3279,7 @@
         return true;
     }
 
-    if (mStszTableEntries->count() == 0) {                      // no samples written
+    if (!mIsHeic && mStszTableEntries->count() == 0) {  // no samples written
         ALOGE("The number of recorded samples is 0");
         return true;
     }
@@ -3199,13 +3425,28 @@
     return mEstimatedTrackSizeBytes;
 }
 
+int32_t MPEG4Writer::Track::getMetaSizeIncrease() const {
+    CHECK(mIsHeic);
+    return    20                           // 1. 'ispe' property
+            + (8 + mCodecSpecificDataSize) // 2. 'hvcC' property
+            + (20                          // 3. extra 'ispe'
+            + (8 + 2 + 2 + mNumTiles * 2)  // 4. 'dimg' ref
+            + 12)                          // 5. ImageGrid in 'idat' (worst case)
+            * (mNumTiles > 1)              // -  (3~5: applicable only if grid)
+            + (16                          // 6. increase to 'iloc'
+            + 21                           // 7. increase to 'iinf'
+            + (3 + 2 * 2))                 // 8. increase to 'ipma' (worst case)
+            * (mNumTiles + 1);             // -  (6~8: are per-item)
+}
+
 status_t MPEG4Writer::Track::checkCodecSpecificData() const {
     const char *mime;
     CHECK(mMeta->findCString(kKeyMIMEType, &mime));
     if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
         !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
         !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) ||
-        !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
+        !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime) ||
+        !strcasecmp(MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, mime)) {
         if (!mCodecSpecificData ||
             mCodecSpecificDataSize <= 0) {
             ALOGE("Missing codec specific data");
@@ -3222,7 +3463,10 @@
 }
 
 const char *MPEG4Writer::Track::getTrackType() const {
-    return mIsAudio ? "Audio" : (mIsVideo ? "Video" : "Metadata");
+    return mIsAudio ? "Audio" :
+           mIsVideo ? "Video" :
+           mIsHeic  ? "Image" :
+                      "Metadata";
 }
 
 void MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
@@ -3792,11 +4036,11 @@
     endBox();
 }
 
-void MPEG4Writer::writeHdlr() {
+void MPEG4Writer::writeHdlr(const char *handlerType) {
     beginBox("hdlr");
     writeInt32(0); // Version, Flags
     writeInt32(0); // Predefined
-    writeFourcc("mdta");
+    writeFourcc(handlerType);
     writeInt32(0); // Reserved[0]
     writeInt32(0); // Reserved[1]
     writeInt32(0); // Reserved[2]
@@ -3876,19 +4120,283 @@
     endBox(); // ilst
 }
 
-void MPEG4Writer::writeMetaBox() {
+void MPEG4Writer::writeMoovLevelMetaBox() {
     size_t count = mMetaKeys->countEntries();
     if (count == 0) {
         return;
     }
 
     beginBox("meta");
-    writeHdlr();
+    writeHdlr("mdta");
     writeKeys();
     writeIlst();
     endBox();
 }
 
+void MPEG4Writer::writeIlocBox() {
+    beginBox("iloc");
+    // Use version 1 to allow construction method 1 that refers to
+    // data in idat box inside meta box.
+    writeInt32(0x01000000); // Version = 1, Flags = 0
+    writeInt16(0x4400);     // offset_size = length_size = 4
+                            // base_offset_size = index_size = 0
+
+    // 16-bit item_count
+    size_t itemCount = mItems.size();
+    if (itemCount > 65535) {
+        ALOGW("Dropping excess items: itemCount %zu", itemCount);
+        itemCount = 65535;
+    }
+    writeInt16((uint16_t)itemCount);
+
+    for (size_t i = 0; i < itemCount; i++) {
+        writeInt16(mItems[i].itemId);
+        bool isGrid = mItems[i].isGrid();
+
+        writeInt16(isGrid ? 1 : 0); // construction_method
+        writeInt16(0); // data_reference_index = 0
+        writeInt16(1); // extent_count = 1
+
+        if (isGrid) {
+            // offset into the 'idat' box
+            writeInt32(mNumGrids++ * 8);
+            writeInt32(8);
+        } else {
+            writeInt32(mItems[i].offset);
+            writeInt32(mItems[i].size);
+        }
+    }
+    endBox();
+}
+
+void MPEG4Writer::writeInfeBox(
+        uint16_t itemId, const char *itemType, uint32_t flags) {
+    beginBox("infe");
+    writeInt32(0x02000000 | flags); // Version = 2, Flags = 0
+    writeInt16(itemId);
+    writeInt16(0);          //item_protection_index = 0
+    writeFourcc(itemType);
+    writeCString("");       // item_name
+    endBox();
+}
+
+void MPEG4Writer::writeIinfBox() {
+    beginBox("iinf");
+    writeInt32(0);          // Version = 0, Flags = 0
+
+    // 16-bit item_count
+    size_t itemCount = mItems.size();
+    if (itemCount > 65535) {
+        ALOGW("Dropping excess items: itemCount %zu", itemCount);
+        itemCount = 65535;
+    }
+
+    writeInt16((uint16_t)itemCount);
+    for (size_t i = 0; i < itemCount; i++) {
+        writeInfeBox(mItems[i].itemId, mItems[i].itemType,
+                mItems[i].isHidden ? 1 : 0);
+    }
+
+    endBox();
+}
+
+void MPEG4Writer::writeIdatBox() {
+    beginBox("idat");
+
+    for (size_t i = 0; i < mItems.size(); i++) {
+        if (mItems[i].isGrid()) {
+            writeInt8(0); // version
+            // flags == 1 means 32-bit width,height
+            int8_t flags = (mItems[i].width > 65535 || mItems[i].height > 65535);
+            writeInt8(flags);
+            writeInt8(mItems[i].rows - 1);
+            writeInt8(mItems[i].cols - 1);
+            if (flags) {
+                writeInt32(mItems[i].width);
+                writeInt32(mItems[i].height);
+            } else {
+                writeInt16((uint16_t)mItems[i].width);
+                writeInt16((uint16_t)mItems[i].height);
+            }
+        }
+    }
+
+    endBox();
+}
+
+void MPEG4Writer::writeIrefBox() {
+    beginBox("iref");
+    writeInt32(0);          // Version = 0, Flags = 0
+    {
+        for (size_t i = 0; i < mItems.size(); i++) {
+            if (!mItems[i].isGrid()) {
+                continue;
+            }
+            beginBox("dimg");
+            writeInt16(mItems[i].itemId);
+            size_t refCount = mItems[i].dimgRefs.size();
+            if (refCount > 65535) {
+                ALOGW("too many entries in dimg");
+                refCount = 65535;
+            }
+            writeInt16((uint16_t)refCount);
+            for (size_t refIndex = 0; refIndex < refCount; refIndex++) {
+                writeInt16(mItems[i].dimgRefs[refIndex]);
+            }
+            endBox();
+        }
+    }
+    endBox();
+}
+
+void MPEG4Writer::writePitmBox() {
+    beginBox("pitm");
+    writeInt32(0);          // Version = 0, Flags = 0
+    writeInt16(mPrimaryItemId);
+    endBox();
+}
+
+void MPEG4Writer::writeIpcoBox() {
+    beginBox("ipco");
+    size_t numProperties = mProperties.size();
+    if (numProperties > 32767) {
+        ALOGW("Dropping excess properties: numProperties %zu", numProperties);
+        numProperties = 32767;
+    }
+    for (size_t propIndex = 0; propIndex < numProperties; propIndex++) {
+        if (mProperties[propIndex].type == FOURCC('h', 'v', 'c', 'C')) {
+            beginBox("hvcC");
+            sp<ABuffer> hvcc = mProperties[propIndex].hvcc;
+            // Patch avcc's lengthSize field to match the number
+            // of bytes we use to indicate the size of a nal unit.
+            uint8_t *ptr = (uint8_t *)hvcc->data();
+            ptr[21] = (ptr[21] & 0xfc) | (useNalLengthFour() ? 3 : 1);
+            write(hvcc->data(), hvcc->size());
+            endBox();
+        } else if (mProperties[propIndex].type == FOURCC('i', 's', 'p', 'e')) {
+            beginBox("ispe");
+            writeInt32(0); // Version = 0, Flags = 0
+            writeInt32(mProperties[propIndex].width);
+            writeInt32(mProperties[propIndex].height);
+            endBox();
+        } else {
+            ALOGW("Skipping unrecognized property: type 0x%08x",
+                    mProperties[propIndex].type);
+        }
+    }
+    endBox();
+}
+
+void MPEG4Writer::writeIpmaBox() {
+    beginBox("ipma");
+    uint32_t flags = (mProperties.size() > 127) ? 1 : 0;
+    writeInt32(flags); // Version = 0
+
+    writeInt32(mAssociationEntryCount);
+    for (size_t itemIndex = 0; itemIndex < mItems.size(); itemIndex++) {
+        const Vector<uint16_t> &properties = mItems[itemIndex].properties;
+        if (properties.empty()) {
+            continue;
+        }
+        writeInt16(mItems[itemIndex].itemId);
+
+        size_t entryCount = properties.size();
+        if (entryCount > 255) {
+            ALOGW("Dropping excess associations: entryCount %zu", entryCount);
+            entryCount = 255;
+        }
+        writeInt8((uint8_t)entryCount);
+        for (size_t propIndex = 0; propIndex < entryCount; propIndex++) {
+            if (flags & 1) {
+                writeInt16((1 << 15) | properties[propIndex]);
+            } else {
+                writeInt8((1 << 7) | properties[propIndex]);
+            }
+        }
+    }
+    endBox();
+}
+
+void MPEG4Writer::writeIprpBox() {
+    beginBox("iprp");
+    writeIpcoBox();
+    writeIpmaBox();
+    endBox();
+}
+
+void MPEG4Writer::writeFileLevelMetaBox() {
+    if (mItems.empty()) {
+        ALOGE("no valid item was found");
+        return;
+    }
+
+    // patch up the mPrimaryItemId and count items with prop associations
+    for (size_t index = 0; index < mItems.size(); index++) {
+        if (mItems[index].isPrimary) {
+            mPrimaryItemId = mItems[index].itemId;
+        }
+
+        if (!mItems[index].properties.empty()) {
+            mAssociationEntryCount++;
+        }
+    }
+
+    if (mPrimaryItemId == 0) {
+        ALOGW("didn't find primary, using first item");
+        mPrimaryItemId = mItems[0].itemId;
+    }
+
+    beginBox("meta");
+    writeInt32(0); // Version = 0, Flags = 0
+    writeHdlr("pict");
+    writeIlocBox();
+    writeIinfBox();
+    writePitmBox();
+    writeIprpBox();
+    if (mNumGrids > 0) {
+        writeIdatBox();
+        writeIrefBox();
+    }
+    endBox();
+}
+
+uint16_t MPEG4Writer::addProperty_l(const ItemProperty &prop) {
+    char typeStr[5];
+    MakeFourCCString(prop.type, typeStr);
+    ALOGV("addProperty_l: %s", typeStr);
+
+    mProperties.push_back(prop);
+
+    // returning 1-based property index
+    return mProperties.size();
+}
+
+uint16_t MPEG4Writer::addItem_l(const ItemInfo &info) {
+    ALOGV("addItem_l: type %s, offset %u, size %u",
+            info.itemType, info.offset, info.size);
+
+    size_t index = mItems.size();
+    mItems.push_back(info);
+
+    // make the item id start at 10000
+    mItems.editItemAt(index).itemId = index + 10000;
+
+#if (LOG_NDEBUG==0)
+    if (!info.properties.empty()) {
+        AString str;
+        for (size_t i = 0; i < info.properties.size(); i++) {
+            if (i > 0) {
+                str.append(", ");
+            }
+            str.append(info.properties[i]);
+        }
+        ALOGV("addItem_l: id %d, properties: %s", mItems[index].itemId, str.c_str());
+    }
+#endif // (LOG_NDEBUG==0)
+
+    return mItems[index].itemId;
+}
+
 /*
  * Geodata is stored according to ISO-6709 standard.
  */
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
index 3aa0061..15843a2 100644
--- a/media/libstagefright/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -17,11 +17,12 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaClock"
 #include <utils/Log.h>
+#include <map>
 
 #include <media/stagefright/MediaClock.h>
 
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
 
 namespace android {
 
@@ -29,15 +30,52 @@
 // If larger than this threshold, it's treated as discontinuity.
 static const int64_t kAnchorFluctuationAllowedUs = 10000ll;
 
+MediaClock::Timer::Timer(const sp<AMessage> &notify, int64_t mediaTimeUs, int64_t adjustRealUs)
+    : mNotify(notify),
+      mMediaTimeUs(mediaTimeUs),
+      mAdjustRealUs(adjustRealUs) {
+}
+
 MediaClock::MediaClock()
     : mAnchorTimeMediaUs(-1),
       mAnchorTimeRealUs(-1),
       mMaxTimeMediaUs(INT64_MAX),
       mStartingTimeMediaUs(-1),
-      mPlaybackRate(1.0) {
+      mPlaybackRate(1.0),
+      mGeneration(0) {
+    mLooper = new ALooper;
+    mLooper->setName("MediaClock");
+    mLooper->start(false /* runOnCallingThread */,
+                   false /* canCallJava */,
+                   ANDROID_PRIORITY_AUDIO);
+}
+
+void MediaClock::init() {
+    mLooper->registerHandler(this);
 }
 
 MediaClock::~MediaClock() {
+    reset();
+    if (mLooper != NULL) {
+        mLooper->unregisterHandler(id());
+        mLooper->stop();
+    }
+}
+
+void MediaClock::reset() {
+    Mutex::Autolock autoLock(mLock);
+    auto it = mTimers.begin();
+    while (it != mTimers.end()) {
+        it->mNotify->setInt32("reason", TIMER_REASON_RESET);
+        it->mNotify->post();
+        it = mTimers.erase(it);
+    }
+    mAnchorTimeMediaUs = -1;
+    mAnchorTimeRealUs = -1;
+    mMaxTimeMediaUs = INT64_MAX;
+    mStartingTimeMediaUs = -1;
+    mPlaybackRate = 1.0;
+    ++mGeneration;
 }
 
 void MediaClock::setStartingTimeMedia(int64_t startingTimeMediaUs) {
@@ -82,6 +120,9 @@
     }
     mAnchorTimeRealUs = nowUs;
     mAnchorTimeMediaUs = nowMediaUs;
+
+    ++mGeneration;
+    processTimers_l();
 }
 
 void MediaClock::updateMaxTimeMedia(int64_t maxTimeMediaUs) {
@@ -105,6 +146,11 @@
     }
     mAnchorTimeRealUs = nowUs;
     mPlaybackRate = rate;
+
+    if (rate > 0.0) {
+        ++mGeneration;
+        processTimers_l();
+    }
 }
 
 float MediaClock::getPlaybackRate() const {
@@ -165,4 +211,106 @@
     return OK;
 }
 
+void MediaClock::addTimer(const sp<AMessage> &notify, int64_t mediaTimeUs,
+                          int64_t adjustRealUs) {
+    Mutex::Autolock autoLock(mLock);
+
+    bool updateTimer = (mPlaybackRate != 0.0);
+    if (updateTimer) {
+        auto it = mTimers.begin();
+        while (it != mTimers.end()) {
+            if (((it->mAdjustRealUs - (double)adjustRealUs) * (double)mPlaybackRate
+                + (it->mMediaTimeUs - mediaTimeUs)) <= 0) {
+                updateTimer = false;
+                break;
+            }
+            ++it;
+        }
+    }
+
+    mTimers.emplace_back(notify, mediaTimeUs, adjustRealUs);
+
+    if (updateTimer) {
+        ++mGeneration;
+        processTimers_l();
+    }
+}
+
+void MediaClock::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatTimeIsUp:
+        {
+            int32_t generation;
+            CHECK(msg->findInt32("generation", &generation));
+
+            Mutex::Autolock autoLock(mLock);
+            if (generation != mGeneration) {
+                break;
+            }
+            processTimers_l();
+            break;
+        }
+
+        default:
+            TRESPASS();
+            break;
+    }
+}
+
+void MediaClock::processTimers_l() {
+    int64_t nowMediaTimeUs;
+    status_t status = getMediaTime_l(
+            ALooper::GetNowUs(), &nowMediaTimeUs, false /* allowPastMaxTime */);
+
+    if (status != OK) {
+        return;
+    }
+
+    int64_t nextLapseRealUs = INT64_MAX;
+    std::multimap<int64_t, Timer> notifyList;
+    auto it = mTimers.begin();
+    while (it != mTimers.end()) {
+        double diff = it->mAdjustRealUs * (double)mPlaybackRate
+            + it->mMediaTimeUs - nowMediaTimeUs;
+        int64_t diffMediaUs;
+        if (diff > (double)INT64_MAX) {
+            diffMediaUs = INT64_MAX;
+        } else if (diff < (double)INT64_MIN) {
+            diffMediaUs = INT64_MIN;
+        } else {
+            diffMediaUs = diff;
+        }
+
+        if (diffMediaUs <= 0) {
+            notifyList.emplace(diffMediaUs, *it);
+            it = mTimers.erase(it);
+        } else {
+            if (mPlaybackRate != 0.0
+                && (double)diffMediaUs < INT64_MAX * (double)mPlaybackRate) {
+                int64_t targetRealUs = diffMediaUs / (double)mPlaybackRate;
+                if (targetRealUs < nextLapseRealUs) {
+                    nextLapseRealUs = targetRealUs;
+                }
+            }
+            ++it;
+        }
+    }
+
+    auto itNotify = notifyList.begin();
+    while (itNotify != notifyList.end()) {
+        itNotify->second.mNotify->setInt32("reason", TIMER_REASON_REACHED);
+        itNotify->second.mNotify->post();
+        itNotify = notifyList.erase(itNotify);
+    }
+
+    if (mTimers.empty() || mPlaybackRate == 0.0 || mAnchorTimeMediaUs < 0
+        || nextLapseRealUs == INT64_MAX) {
+        return;
+    }
+
+    sp<AMessage> msg = new AMessage(kWhatTimeIsUp, this);
+    msg->setInt32("generation", mGeneration);
+    msg->post(nextLapseRealUs);
+}
+
 }  // namespace android
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 759e42d..4fedab6 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -18,7 +18,6 @@
 #define LOG_TAG "MediaCodec"
 #include <inttypes.h>
 
-#include "include/avc_utils.h"
 #include "include/SecureBuffer.h"
 #include "include/SharedMemoryBuffer.h"
 #include "include/SoftwareRenderer.h"
@@ -41,6 +40,7 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/ACodec.h>
 #include <media/stagefright/BufferProducerWrapper.h>
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 4652594..54265a4 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -24,23 +24,21 @@
 
 #include <media/IMediaCodecList.h>
 #include <media/IMediaPlayerService.h>
-#include <media/IMediaCodecService.h>
 #include <media/MediaCodecInfo.h>
-#include <media/MediaDefs.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/OmxInfoBuilder.h>
 #include <media/stagefright/omx/OMXUtils.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
+#include <xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h>
 
 #include <sys/stat.h>
 #include <utils/threads.h>
 
 #include <cutils/properties.h>
-#include <expat.h>
 
 #include <algorithm>
 
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index d808e5b..cf800b2 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -24,6 +24,7 @@
 #include <gui/Surface.h>
 #include <media/ICrypto.h>
 #include <media/MediaCodecBuffer.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -33,7 +34,6 @@
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaCodecSource.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
@@ -643,7 +643,9 @@
 
     if (mStopping && reachedEOS) {
         ALOGI("encoder (%s) stopped", mIsVideo ? "video" : "audio");
-        mPuller->stopSource();
+        if (mPuller != NULL) {
+            mPuller->stopSource();
+        }
         ALOGV("source (%s) stopped", mIsVideo ? "video" : "audio");
         // posting reply to everyone that's waiting
         List<sp<AReplyToken>>::iterator it;
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
deleted file mode 100644
index c91c82b..0000000
--- a/media/libstagefright/MediaExtractor.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaExtractor"
-#include <utils/Log.h>
-#include <inttypes.h>
-#include <pwd.h>
-
-#include "include/AMRExtractor.h"
-#include "include/MP3Extractor.h"
-#include "include/MPEG4Extractor.h"
-#include "include/WAVExtractor.h"
-#include "include/OggExtractor.h"
-#include "include/MPEG2PSExtractor.h"
-#include "include/MPEG2TSExtractor.h"
-#include "include/FLACExtractor.h"
-#include "include/AACExtractor.h"
-#include "include/MidiExtractor.h"
-
-#include "matroska/MatroskaExtractor.h"
-
-#include <binder/IServiceManager.h>
-#include <binder/MemoryDealer.h>
-
-#include <media/MediaAnalyticsItem.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MetaData.h>
-#include <media/IMediaExtractorService.h>
-#include <cutils/properties.h>
-#include <utils/String8.h>
-#include <private/android_filesystem_config.h>
-
-// still doing some on/off toggling here.
-#define MEDIA_LOG       1
-
-
-namespace android {
-
-// key for media statistics
-static const char *kKeyExtractor = "extractor";
-// attrs for media statistics
-static const char *kExtractorMime = "android.media.mediaextractor.mime";
-static const char *kExtractorTracks = "android.media.mediaextractor.ntrk";
-static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
-
-MediaExtractor::MediaExtractor() {
-    if (!LOG_NDEBUG) {
-        uid_t uid = getuid();
-        struct passwd *pw = getpwuid(uid);
-        ALOGI("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
-    }
-
-    mAnalyticsItem = NULL;
-    if (MEDIA_LOG) {
-        mAnalyticsItem = new MediaAnalyticsItem(kKeyExtractor);
-        (void) mAnalyticsItem->generateSessionID();
-    }
-}
-
-MediaExtractor::~MediaExtractor() {
-
-    // log the current record, provided it has some information worth recording
-    if (MEDIA_LOG) {
-        if (mAnalyticsItem != NULL) {
-            if (mAnalyticsItem->count() > 0) {
-                mAnalyticsItem->setFinalized(true);
-                mAnalyticsItem->selfrecord();
-            }
-        }
-    }
-    if (mAnalyticsItem != NULL) {
-        delete mAnalyticsItem;
-        mAnalyticsItem = NULL;
-    }
-}
-
-sp<MetaData> MediaExtractor::getMetaData() {
-    return new MetaData;
-}
-
-status_t MediaExtractor::getMetrics(Parcel *reply) {
-
-    if (mAnalyticsItem == NULL || reply == NULL) {
-        return UNKNOWN_ERROR;
-    }
-
-    populateMetrics();
-    mAnalyticsItem->writeToParcel(reply);
-
-    return OK;
-}
-
-void MediaExtractor::populateMetrics() {
-    ALOGV("MediaExtractor::populateMetrics");
-    // normally overridden in subclasses
-}
-
-uint32_t MediaExtractor::flags() const {
-    return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
-}
-
-// static
-sp<IMediaExtractor> MediaExtractor::Create(
-        const sp<DataSource> &source, const char *mime) {
-    ALOGV("MediaExtractor::Create %s", mime);
-
-    if (!property_get_bool("media.stagefright.extractremote", true)) {
-        // local extractor
-        ALOGW("creating media extractor in calling process");
-        return CreateFromService(source, mime);
-    } else {
-        // remote extractor
-        ALOGV("get service manager");
-        sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
-
-        if (binder != 0) {
-            sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
-            sp<IMediaExtractor> ex = mediaExService->makeExtractor(source->asIDataSource(), mime);
-            return ex;
-        } else {
-            ALOGE("extractor service not running");
-            return NULL;
-        }
-    }
-    return NULL;
-}
-
-sp<MediaExtractor> MediaExtractor::CreateFromService(
-        const sp<DataSource> &source, const char *mime) {
-
-    ALOGV("MediaExtractor::CreateFromService %s", mime);
-    RegisterDefaultSniffers();
-
-    // initialize source decryption if needed
-    source->DrmInitialization(nullptr /* mime */);
-
-    sp<AMessage> meta;
-
-    String8 tmp;
-    if (mime == NULL) {
-        float confidence;
-        if (!sniff(source, &tmp, &confidence, &meta)) {
-            ALOGW("FAILED to autodetect media content.");
-
-            return NULL;
-        }
-
-        mime = tmp.string();
-        ALOGV("Autodetected media content as '%s' with confidence %.2f",
-             mime, confidence);
-    }
-
-    MediaExtractor *ret = NULL;
-    if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
-            || !strcasecmp(mime, "audio/mp4")) {
-        ret = new MPEG4Extractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
-        ret = new MP3Extractor(source, meta);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
-            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
-        ret = new AMRExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
-        ret = new FLACExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
-        ret = new WAVExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
-        ret = new OggExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
-        ret = new MatroskaExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
-        ret = new MPEG2TSExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
-        ret = new AACExtractor(source, meta);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
-        ret = new MPEG2PSExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) {
-        ret = new MidiExtractor(source);
-    }
-
-    if (ret != NULL) {
-       // track the container format (mpeg, aac, wvm, etc)
-       if (MEDIA_LOG) {
-          if (ret->mAnalyticsItem != NULL) {
-              size_t ntracks = ret->countTracks();
-              ret->mAnalyticsItem->setCString(kExtractorFormat,  ret->name());
-              // tracks (size_t)
-              ret->mAnalyticsItem->setInt32(kExtractorTracks,  ntracks);
-              // metadata
-              sp<MetaData> pMetaData = ret->getMetaData();
-              if (pMetaData != NULL) {
-                String8 xx = pMetaData->toString();
-                // 'titl' -- but this verges into PII
-                // 'mime'
-                const char *mime = NULL;
-                if (pMetaData->findCString(kKeyMIMEType, &mime)) {
-                    ret->mAnalyticsItem->setCString(kExtractorMime,  mime);
-                }
-                // what else is interesting and not already available?
-              }
-	  }
-       }
-    }
-
-    return ret;
-}
-
-Mutex MediaExtractor::gSnifferMutex;
-List<MediaExtractor::SnifferFunc> MediaExtractor::gSniffers;
-bool MediaExtractor::gSniffersRegistered = false;
-
-// static
-bool MediaExtractor::sniff(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
-    *mimeType = "";
-    *confidence = 0.0f;
-    meta->clear();
-
-    {
-        Mutex::Autolock autoLock(gSnifferMutex);
-        if (!gSniffersRegistered) {
-            return false;
-        }
-    }
-
-    for (List<SnifferFunc>::iterator it = gSniffers.begin();
-         it != gSniffers.end(); ++it) {
-        String8 newMimeType;
-        float newConfidence;
-        sp<AMessage> newMeta;
-        if ((*it)(source, &newMimeType, &newConfidence, &newMeta)) {
-            if (newConfidence > *confidence) {
-                *mimeType = newMimeType;
-                *confidence = newConfidence;
-                *meta = newMeta;
-            }
-        }
-    }
-
-    return *confidence > 0.0;
-}
-
-// static
-void MediaExtractor::RegisterSniffer_l(SnifferFunc func) {
-    for (List<SnifferFunc>::iterator it = gSniffers.begin();
-         it != gSniffers.end(); ++it) {
-        if (*it == func) {
-            return;
-        }
-    }
-
-    gSniffers.push_back(func);
-}
-
-// static
-void MediaExtractor::RegisterDefaultSniffers() {
-    Mutex::Autolock autoLock(gSnifferMutex);
-    if (gSniffersRegistered) {
-        return;
-    }
-
-    RegisterSniffer_l(SniffMPEG4);
-    RegisterSniffer_l(SniffMatroska);
-    RegisterSniffer_l(SniffOgg);
-    RegisterSniffer_l(SniffWAV);
-    RegisterSniffer_l(SniffFLAC);
-    RegisterSniffer_l(SniffAMR);
-    RegisterSniffer_l(SniffMPEG2TS);
-    RegisterSniffer_l(SniffMP3);
-    RegisterSniffer_l(SniffAAC);
-    RegisterSniffer_l(SniffMPEG2PS);
-    RegisterSniffer_l(SniffMidi);
-
-    gSniffersRegistered = true;
-}
-
-
-}  // namespace android
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
new file mode 100644
index 0000000..1b12510
--- /dev/null
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaExtractor"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include <media/DataSource.h>
+#include <media/MediaAnalyticsItem.h>
+#include <media/MediaExtractor.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaExtractorFactory.h>
+#include <media/stagefright/MetaData.h>
+#include <media/IMediaExtractor.h>
+#include <media/IMediaExtractorService.h>
+#include <cutils/properties.h>
+#include <utils/String8.h>
+
+#include <dirent.h>
+#include <dlfcn.h>
+
+namespace android {
+
+// attrs for media statistics
+static const char *kExtractorMime = "android.media.mediaextractor.mime";
+static const char *kExtractorTracks = "android.media.mediaextractor.ntrk";
+static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
+
+// static
+sp<IMediaExtractor> MediaExtractorFactory::Create(
+        const sp<DataSource> &source, const char *mime) {
+    ALOGV("MediaExtractorFactory::Create %s", mime);
+
+    if (!property_get_bool("media.stagefright.extractremote", true)) {
+        // local extractor
+        ALOGW("creating media extractor in calling process");
+        sp<MediaExtractor> extractor = CreateFromService(source, mime);
+        return CreateIMediaExtractorFromMediaExtractor(extractor);
+    } else {
+        // remote extractor
+        ALOGV("get service manager");
+        sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
+
+        if (binder != 0) {
+            sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
+            sp<IMediaExtractor> ex = mediaExService->makeExtractor(
+                    CreateIDataSourceFromDataSource(source), mime);
+            return ex;
+        } else {
+            ALOGE("extractor service not running");
+            return NULL;
+        }
+    }
+    return NULL;
+}
+
+sp<MediaExtractor> MediaExtractorFactory::CreateFromService(
+        const sp<DataSource> &source, const char *mime) {
+
+    ALOGV("MediaExtractorFactory::CreateFromService %s", mime);
+    RegisterDefaultSniffers();
+
+    // initialize source decryption if needed
+    source->DrmInitialization(nullptr /* mime */);
+
+    sp<AMessage> meta;
+
+    MediaExtractor::CreatorFunc creator = NULL;
+    String8 tmp;
+    float confidence;
+    creator = sniff(source, &tmp, &confidence, &meta);
+    if (!creator) {
+        ALOGV("FAILED to autodetect media content.");
+        return NULL;
+    }
+
+    mime = tmp.string();
+    ALOGV("Autodetected media content as '%s' with confidence %.2f",
+         mime, confidence);
+
+    MediaExtractor *ret = creator(source, meta);
+
+    if (ret != NULL) {
+        // track the container format (mpeg, aac, wvm, etc)
+        if (MEDIA_LOG) {
+            if (ret->mAnalyticsItem != NULL) {
+                size_t ntracks = ret->countTracks();
+                ret->mAnalyticsItem->setCString(kExtractorFormat,  ret->name());
+                // tracks (size_t)
+                ret->mAnalyticsItem->setInt32(kExtractorTracks,  ntracks);
+                // metadata
+                sp<MetaData> pMetaData = ret->getMetaData();
+                if (pMetaData != NULL) {
+                    String8 xx = pMetaData->toString();
+                    // 'titl' -- but this verges into PII
+                    // 'mime'
+                    const char *mime = NULL;
+                    if (pMetaData->findCString(kKeyMIMEType, &mime)) {
+                        ret->mAnalyticsItem->setCString(kExtractorMime,  mime);
+                    }
+                    // what else is interesting and not already available?
+                }
+            }
+        }
+    }
+
+    return ret;
+}
+
+Mutex MediaExtractorFactory::gSnifferMutex;
+List<MediaExtractor::ExtractorDef> MediaExtractorFactory::gSniffers;
+bool MediaExtractorFactory::gSniffersRegistered = false;
+
+// static
+MediaExtractor::CreatorFunc MediaExtractorFactory::sniff(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
+    *mimeType = "";
+    *confidence = 0.0f;
+    meta->clear();
+
+    {
+        Mutex::Autolock autoLock(gSnifferMutex);
+        if (!gSniffersRegistered) {
+            return NULL;
+        }
+    }
+
+    MediaExtractor::CreatorFunc curCreator = NULL;
+    MediaExtractor::CreatorFunc bestCreator = NULL;
+    for (List<MediaExtractor::ExtractorDef>::iterator it = gSniffers.begin();
+         it != gSniffers.end(); ++it) {
+        String8 newMimeType;
+        float newConfidence;
+        sp<AMessage> newMeta;
+        if ((curCreator = (*it).sniff(source, &newMimeType, &newConfidence, &newMeta))) {
+            if (newConfidence > *confidence) {
+                *mimeType = newMimeType;
+                *confidence = newConfidence;
+                *meta = newMeta;
+                bestCreator = curCreator;
+            }
+        }
+    }
+
+    return bestCreator;
+}
+
+// static
+void MediaExtractorFactory::RegisterSniffer_l(const MediaExtractor::ExtractorDef &def) {
+    // sanity check check struct version, uuid, name
+    if (def.def_version == 0 || def.def_version > MediaExtractor::EXTRACTORDEF_VERSION) {
+        ALOGE("don't understand extractor format %u, ignoring.", def.def_version);
+        return;
+    }
+    if (memcmp(&def.extractor_uuid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) {
+        ALOGE("invalid UUID, ignoring");
+        return;
+    }
+    if (def.extractor_name == NULL || strlen(def.extractor_name) == 0) {
+        ALOGE("extractors should have a name, ignoring");
+        return;
+    }
+
+    for (List<MediaExtractor::ExtractorDef>::iterator it = gSniffers.begin();
+            it != gSniffers.end(); ++it) {
+        if (memcmp(&((*it).extractor_uuid), &def.extractor_uuid, 16) == 0) {
+            // there's already an extractor with the same uuid
+            if ((*it).extractor_version < def.extractor_version) {
+                // this one is newer, replace the old one
+                ALOGW("replacing extractor '%s' version %u with version %u",
+                        def.extractor_name,
+                        (*it).extractor_version,
+                        def.extractor_version);
+                gSniffers.erase(it);
+                break;
+            } else {
+                ALOGW("ignoring extractor '%s' version %u in favor of version %u",
+                        def.extractor_name,
+                        def.extractor_version,
+                        (*it).extractor_version);
+                return;
+            }
+        }
+    }
+    ALOGV("registering extractor for %s", def.extractor_name);
+    gSniffers.push_back(def);
+}
+
+// static
+void MediaExtractorFactory::RegisterDefaultSniffers() {
+    Mutex::Autolock autoLock(gSnifferMutex);
+    if (gSniffersRegistered) {
+        return;
+    }
+
+    auto registerExtractors = [](const char *libDirPath) -> void {
+        DIR *libDir = opendir(libDirPath);
+        if (libDir) {
+            struct dirent* libEntry;
+            while ((libEntry = readdir(libDir))) {
+                String8 libPath = String8(libDirPath) + libEntry->d_name;
+                void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
+                if (libHandle) {
+                    MediaExtractor::GetExtractorDef getsniffer =
+                            (MediaExtractor::GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
+                    if (getsniffer) {
+                        ALOGV("registering sniffer for %s", libPath.string());
+                        RegisterSniffer_l(getsniffer());
+                    } else {
+                        ALOGW("%s does not contain sniffer", libPath.string());
+                        dlclose(libHandle);
+                    }
+                } else {
+                    ALOGW("couldn't dlopen(%s)", libPath.string());
+                }
+            }
+
+            closedir(libDir);
+        } else {
+            ALOGE("couldn't opendir(%s)", libDirPath);
+        }
+    };
+
+    registerExtractors("/system/lib"
+#ifdef __LP64__
+            "64"
+#endif
+            "/extractors/");
+
+    registerExtractors("/vendor/lib"
+#ifdef __LP64__
+            "64"
+#endif
+            "/extractors/");
+
+    gSniffersRegistered = true;
+}
+
+
+}  // namespace android
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index c7b8888..62daac8 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -23,6 +23,8 @@
 
 #include <media/stagefright/MediaMuxer.h>
 
+#include <media/mediarecorder.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -31,17 +33,22 @@
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/Utils.h>
 
 namespace android {
 
+static bool isMp4Format(MediaMuxer::OutputFormat format) {
+    return format == MediaMuxer::OUTPUT_FORMAT_MPEG_4 ||
+           format == MediaMuxer::OUTPUT_FORMAT_THREE_GPP ||
+           format == MediaMuxer::OUTPUT_FORMAT_HEIF;
+}
+
 MediaMuxer::MediaMuxer(int fd, OutputFormat format)
     : mFormat(format),
       mState(UNINITIALIZED) {
-    if (format == OUTPUT_FORMAT_MPEG_4 || format == OUTPUT_FORMAT_THREE_GPP) {
+    if (isMp4Format(format)) {
         mWriter = new MPEG4Writer(fd);
     } else if (format == OUTPUT_FORMAT_WEBM) {
         mWriter = new WebmWriter(fd);
@@ -49,6 +56,10 @@
 
     if (mWriter != NULL) {
         mFileMeta = new MetaData;
+        if (format == OUTPUT_FORMAT_HEIF) {
+            // Note that the key uses recorder file types.
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_HEIF);
+        }
         mState = INITIALIZED;
     }
 }
@@ -108,8 +119,8 @@
         ALOGE("setLocation() must be called before start().");
         return INVALID_OPERATION;
     }
-    if (mFormat != OUTPUT_FORMAT_MPEG_4 && mFormat != OUTPUT_FORMAT_THREE_GPP) {
-        ALOGE("setLocation() is only supported for .mp4 pr .3gp output.");
+    if (!isMp4Format(mFormat)) {
+        ALOGE("setLocation() is only supported for .mp4, .3gp or .heic output.");
         return INVALID_OPERATION;
     }
 
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index 9278381..ba14e5d 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -61,6 +61,7 @@
         mNextBufferItemMediaUs(-1),
         mPlaybackRate(0.0) {
     mMediaClock = new MediaClock;
+    mMediaClock->init();
 
     // initialize settings
     mPlaybackSettings = AUDIO_PLAYBACK_RATE_DEFAULT;
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 640cb82..a176382 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -23,28 +23,40 @@
 #include "include/ESDS.h"
 #include "include/NuCachedSource2.h"
 
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
 namespace android {
 
+NuMediaExtractor::Sample::Sample()
+    : mBuffer(NULL),
+      mSampleTimeUs(-1ll) {
+}
+
+NuMediaExtractor::Sample::Sample(MediaBuffer *buffer, int64_t timeUs)
+    : mBuffer(buffer),
+      mSampleTimeUs(timeUs) {
+}
+
 NuMediaExtractor::NuMediaExtractor()
     : mTotalBitrate(-1ll),
       mDurationUs(-1ll) {
 }
 
 NuMediaExtractor::~NuMediaExtractor() {
-    releaseTrackSamples();
+    releaseAllTrackSamples();
 
     for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
         TrackInfo *info = &mSelectedTracks.editItemAt(i);
@@ -70,13 +82,13 @@
     }
 
     sp<DataSource> dataSource =
-        DataSource::CreateFromURI(httpService, path, headers);
+        DataSourceFactory::CreateFromURI(httpService, path, headers);
 
     if (dataSource == NULL) {
         return -ENOENT;
     }
 
-    mImpl = MediaExtractor::Create(dataSource);
+    mImpl = MediaExtractorFactory::Create(dataSource);
 
     if (mImpl == NULL) {
         return ERROR_UNSUPPORTED;
@@ -112,7 +124,7 @@
         return err;
     }
 
-    mImpl = MediaExtractor::Create(fileSource);
+    mImpl = MediaExtractorFactory::Create(fileSource);
 
     if (mImpl == NULL) {
         return ERROR_UNSUPPORTED;
@@ -142,7 +154,7 @@
         return err;
     }
 
-    mImpl = MediaExtractor::Create(source);
+    mImpl = MediaExtractorFactory::Create(source);
 
     if (mImpl == NULL) {
         return ERROR_UNSUPPORTED;
@@ -286,7 +298,8 @@
     return OK;
 }
 
-status_t NuMediaExtractor::selectTrack(size_t index) {
+status_t NuMediaExtractor::selectTrack(size_t index,
+        int64_t startTimeUs, MediaSource::ReadOptions::SeekMode mode) {
     Mutex::Autolock autoLock(mLock);
 
     if (mImpl == NULL) {
@@ -309,31 +322,56 @@
     sp<IMediaSource> source = mImpl->getTrack(index);
 
     if (source == nullptr) {
+        ALOGE("track %zu is empty", index);
         return ERROR_MALFORMED;
     }
 
     status_t ret = source->start();
     if (ret != OK) {
+        ALOGE("track %zu failed to start", index);
         return ret;
     }
 
+    sp<MetaData> meta = source->getFormat();
+    if (meta == NULL) {
+        ALOGE("track %zu has no meta data", index);
+        return ERROR_MALFORMED;
+    }
+
+    const char *mime;
+    if (!meta->findCString(kKeyMIMEType, &mime)) {
+        ALOGE("track %zu has no mime type in meta data", index);
+        return ERROR_MALFORMED;
+    }
+    ALOGV("selectTrack, track[%zu]: %s", index, mime);
+
     mSelectedTracks.push();
     TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1);
 
     info->mSource = source;
     info->mTrackIndex = index;
+    if (!strncasecmp(mime, "audio/", 6)) {
+        info->mTrackType = MEDIA_TRACK_TYPE_AUDIO;
+        info->mMaxFetchCount = 64;
+    } else if (!strncasecmp(mime, "video/", 6)) {
+        info->mTrackType = MEDIA_TRACK_TYPE_VIDEO;
+        info->mMaxFetchCount = 8;
+    } else {
+        info->mTrackType = MEDIA_TRACK_TYPE_UNKNOWN;
+        info->mMaxFetchCount = 1;
+    }
     info->mFinalResult = OK;
-    info->mSample = NULL;
-    info->mSampleTimeUs = -1ll;
+    releaseTrackSamples(info);
     info->mTrackFlags = 0;
 
-    const char *mime;
-    CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
-
     if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
         info->mTrackFlags |= kIsVorbis;
     }
 
+    if (startTimeUs >= 0) {
+        fetchTrackSamples(info, startTimeUs, mode);
+    }
+
     return OK;
 }
 
@@ -364,12 +402,7 @@
 
     TrackInfo *info = &mSelectedTracks.editItemAt(i);
 
-    if (info->mSample != NULL) {
-        info->mSample->release();
-        info->mSample = NULL;
-
-        info->mSampleTimeUs = -1ll;
-    }
+    releaseTrackSamples(info);
 
     CHECK_EQ((status_t)OK, info->mSource->stop());
 
@@ -378,79 +411,136 @@
     return OK;
 }
 
-void NuMediaExtractor::releaseTrackSamples() {
-    for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
-        TrackInfo *info = &mSelectedTracks.editItemAt(i);
+void NuMediaExtractor::releaseOneSample(TrackInfo *info) {
+    if (info == NULL || info->mSamples.empty()) {
+        return;
+    }
 
-        if (info->mSample != NULL) {
-            info->mSample->release();
-            info->mSample = NULL;
+    auto it = info->mSamples.begin();
+    if (it->mBuffer != NULL) {
+        it->mBuffer->release();
+    }
+    info->mSamples.erase(it);
+}
 
-            info->mSampleTimeUs = -1ll;
+void NuMediaExtractor::releaseTrackSamples(TrackInfo *info) {
+    if (info == NULL) {
+        return;
+    }
+
+    auto it = info->mSamples.begin();
+    while (it != info->mSamples.end()) {
+        if (it->mBuffer != NULL) {
+            it->mBuffer->release();
         }
+        it = info->mSamples.erase(it);
     }
 }
 
-ssize_t NuMediaExtractor::fetchTrackSamples(
+void NuMediaExtractor::releaseAllTrackSamples() {
+    for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
+        releaseTrackSamples(&mSelectedTracks.editItemAt(i));
+    }
+}
+
+ssize_t NuMediaExtractor::fetchAllTrackSamples(
         int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
     TrackInfo *minInfo = NULL;
     ssize_t minIndex = -1;
 
     for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
         TrackInfo *info = &mSelectedTracks.editItemAt(i);
+        fetchTrackSamples(info, seekTimeUs, mode);
 
-        if (seekTimeUs >= 0ll) {
-            info->mFinalResult = OK;
-
-            if (info->mSample != NULL) {
-                info->mSample->release();
-                info->mSample = NULL;
-                info->mSampleTimeUs = -1ll;
-            }
-        } else if (info->mFinalResult != OK) {
+        if (info->mSamples.empty()) {
             continue;
         }
 
-        if (info->mSample == NULL) {
-            MediaSource::ReadOptions options;
-            if (seekTimeUs >= 0ll) {
-                options.setSeekTo(seekTimeUs, mode);
-            }
-            status_t err = info->mSource->read(&info->mSample, &options);
-
-            if (err != OK) {
-                CHECK(info->mSample == NULL);
-
-                info->mFinalResult = err;
-
-                if (info->mFinalResult != ERROR_END_OF_STREAM) {
-                    ALOGW("read on track %zu failed with error %d",
-                          info->mTrackIndex, err);
-                }
-
-                info->mSampleTimeUs = -1ll;
-                continue;
-            } else {
-                CHECK(info->mSample != NULL);
-                CHECK(info->mSample->meta_data()->findInt64(
-                            kKeyTime, &info->mSampleTimeUs));
-            }
-        }
-
-        if (minInfo == NULL  || info->mSampleTimeUs < minInfo->mSampleTimeUs) {
+        if (minInfo == NULL) {
             minInfo = info;
             minIndex = i;
+        } else {
+            auto it = info->mSamples.begin();
+            auto itMin = minInfo->mSamples.begin();
+            if (it->mSampleTimeUs < itMin->mSampleTimeUs) {
+                minInfo = info;
+                minIndex = i;
+            }
         }
     }
 
     return minIndex;
 }
 
+void NuMediaExtractor::fetchTrackSamples(TrackInfo *info,
+        int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
+    if (info == NULL) {
+        return;
+    }
+
+    MediaSource::ReadOptions options;
+    if (seekTimeUs >= 0ll) {
+        options.setSeekTo(seekTimeUs, mode);
+        info->mFinalResult = OK;
+        releaseTrackSamples(info);
+    } else if (info->mFinalResult != OK || !info->mSamples.empty()) {
+        return;
+    }
+
+    status_t err = OK;
+    Vector<MediaBuffer *> mediaBuffers;
+    if (info->mSource->supportReadMultiple()) {
+        options.setNonBlocking();
+        err = info->mSource->readMultiple(&mediaBuffers, info->mMaxFetchCount, &options);
+    } else {
+        MediaBuffer *mbuf = NULL;
+        err = info->mSource->read(&mbuf, &options);
+        if (err == OK && mbuf != NULL) {
+            mediaBuffers.push_back(mbuf);
+        }
+    }
+
+    info->mFinalResult = err;
+    if (err != OK && err != ERROR_END_OF_STREAM) {
+        ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err);
+        size_t count = mediaBuffers.size();
+        for (size_t id = 0; id < count; ++id) {
+            MediaBuffer *mbuf = mediaBuffers[id];
+            if (mbuf != NULL) {
+                mbuf->release();
+            }
+        }
+        return;
+    }
+
+    size_t count = mediaBuffers.size();
+    bool releaseRemaining = false;
+    for (size_t id = 0; id < count; ++id) {
+        int64_t timeUs;
+        MediaBuffer *mbuf = mediaBuffers[id];
+        if (mbuf == NULL) {
+            continue;
+        }
+        if (releaseRemaining) {
+            mbuf->release();
+            continue;
+        }
+        if (mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) {
+            info->mSamples.emplace_back(mbuf, timeUs);
+        } else {
+            mbuf->meta_data()->dumpToLog();
+            info->mFinalResult = ERROR_MALFORMED;
+            mbuf->release();
+            releaseRemaining = true;
+        }
+    }
+}
+
 status_t NuMediaExtractor::seekTo(
         int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) {
     Mutex::Autolock autoLock(mLock);
 
-    ssize_t minIndex = fetchTrackSamples(timeUs, mode);
+    ssize_t minIndex = fetchAllTrackSamples(timeUs, mode);
 
     if (minIndex < 0) {
         return ERROR_END_OF_STREAM;
@@ -462,7 +552,7 @@
 status_t NuMediaExtractor::advance() {
     Mutex::Autolock autoLock(mLock);
 
-    ssize_t minIndex = fetchTrackSamples();
+    ssize_t minIndex = fetchAllTrackSamples();
 
     if (minIndex < 0) {
         return ERROR_END_OF_STREAM;
@@ -470,28 +560,26 @@
 
     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
 
-    info->mSample->release();
-    info->mSample = NULL;
-    info->mSampleTimeUs = -1ll;
+    releaseOneSample(info);
 
     return OK;
 }
 
-status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer) {
+status_t NuMediaExtractor::appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer) {
     int32_t numPageSamples;
-    if (!info->mSample->meta_data()->findInt32(
+    if (!mbuf->meta_data()->findInt32(
             kKeyValidSamples, &numPageSamples)) {
         numPageSamples = -1;
     }
 
-    memcpy((uint8_t *)buffer->data() + info->mSample->range_length(),
+    memcpy((uint8_t *)buffer->data() + mbuf->range_length(),
            &numPageSamples,
            sizeof(numPageSamples));
 
     uint32_t type;
     const void *data;
     size_t size, size2;
-    if (info->mSample->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+    if (mbuf->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
         // Signal numPageSamples (a plain int32_t) is appended at the end,
         // i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes
         if (SIZE_MAX - size < sizeof(int32_t)) {
@@ -509,9 +597,9 @@
         int32_t zero = 0;
         memcpy(adata, data, size);
         memcpy(adata + size, &zero, sizeof(zero));
-        info->mSample->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
+        mbuf->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
 
-        if (info->mSample->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
+        if (mbuf->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
             if (size2 != size) {
                 return ERROR_MALFORMED;
             }
@@ -524,7 +612,7 @@
         // append sizeof(numPageSamples) to plain sizes.
         int32_t int32Size = sizeof(numPageSamples);
         memcpy(adata + size, &int32Size, sizeof(int32Size));
-        info->mSample->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
+        mbuf->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
     }
 
     return OK;
@@ -533,7 +621,7 @@
 status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) {
     Mutex::Autolock autoLock(mLock);
 
-    ssize_t minIndex = fetchTrackSamples();
+    ssize_t minIndex = fetchAllTrackSamples();
 
     if (minIndex < 0) {
         return ERROR_END_OF_STREAM;
@@ -541,7 +629,8 @@
 
     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
 
-    size_t sampleSize = info->mSample->range_length();
+    auto it = info->mSamples.begin();
+    size_t sampleSize = it->mBuffer->range_length();
 
     if (info->mTrackFlags & kIsVorbis) {
         // Each sample's data is suffixed by the number of page samples
@@ -554,14 +643,14 @@
     }
 
     const uint8_t *src =
-        (const uint8_t *)info->mSample->data()
-            + info->mSample->range_offset();
+        (const uint8_t *)it->mBuffer->data()
+            + it->mBuffer->range_offset();
 
-    memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length());
+    memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length());
 
     status_t err = OK;
     if (info->mTrackFlags & kIsVorbis) {
-        err = appendVorbisNumPageSamples(info, buffer);
+        err = appendVorbisNumPageSamples(it->mBuffer, buffer);
     }
 
     if (err == OK) {
@@ -574,7 +663,7 @@
 status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
     Mutex::Autolock autoLock(mLock);
 
-    ssize_t minIndex = fetchTrackSamples();
+    ssize_t minIndex = fetchAllTrackSamples();
 
     if (minIndex < 0) {
         return ERROR_END_OF_STREAM;
@@ -589,14 +678,14 @@
 status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) {
     Mutex::Autolock autoLock(mLock);
 
-    ssize_t minIndex = fetchTrackSamples();
+    ssize_t minIndex = fetchAllTrackSamples();
 
     if (minIndex < 0) {
         return ERROR_END_OF_STREAM;
     }
 
     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
-    *sampleTimeUs = info->mSampleTimeUs;
+    *sampleTimeUs = info->mSamples.begin()->mSampleTimeUs;
 
     return OK;
 }
@@ -606,14 +695,14 @@
 
     *sampleMeta = NULL;
 
-    ssize_t minIndex = fetchTrackSamples();
+    ssize_t minIndex = fetchAllTrackSamples();
 
     if (minIndex < 0) {
         return ERROR_END_OF_STREAM;
     }
 
     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
-    *sampleMeta = info->mSample->meta_data();
+    *sampleMeta = info->mSamples.begin()->mBuffer->meta_data();
 
     return OK;
 }
@@ -624,7 +713,7 @@
 }
 
 bool NuMediaExtractor::getTotalBitrate(int64_t *bitrate) const {
-    if (mTotalBitrate >= 0) {
+    if (mTotalBitrate > 0) {
         *bitrate = mTotalBitrate;
         return true;
     }
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 5f50e46..9375de1 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -25,7 +25,6 @@
 #include <cutils/properties.h>
 
 #include <binder/IServiceManager.h>
-#include <media/IMediaCodecService.h>
 #include <media/stagefright/OMXClient.h>
 
 #include <media/IOMX.h>
@@ -38,70 +37,25 @@
 }
 
 status_t OMXClient::connect() {
-    return connect("default", nullptr);
+    return connect("default");
 }
 
-status_t OMXClient::connect(bool* trebleFlag) {
-    if (property_get_bool("persist.media.treble_omx", true)) {
-        if (trebleFlag != nullptr) {
-            *trebleFlag = true;
-        }
-        return connectTreble();
-    }
-    if (trebleFlag != nullptr) {
-        *trebleFlag = false;
-    }
-    return connectLegacy();
-}
-
-status_t OMXClient::connect(const char* name, bool* trebleFlag) {
-    if (property_get_bool("persist.media.treble_omx", true)) {
-        if (trebleFlag != nullptr) {
-            *trebleFlag = true;
-        }
-        return connectTreble(name);
-    }
-    if (trebleFlag != nullptr) {
-        *trebleFlag = false;
-    }
-    return connectLegacy();
-}
-
-status_t OMXClient::connectLegacy() {
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> codecbinder = sm->getService(String16("media.codec"));
-    sp<IMediaCodecService> codecservice = interface_cast<IMediaCodecService>(codecbinder);
-
-    if (codecservice.get() == NULL) {
-        ALOGE("Cannot obtain IMediaCodecService");
-        return NO_INIT;
-    }
-
-    mOMX = codecservice->getOMX();
-    if (mOMX.get() == NULL) {
-        ALOGE("Cannot obtain mediacodec IOMX");
-        return NO_INIT;
-    }
-
-    return OK;
-}
-
-status_t OMXClient::connectTreble(const char* name) {
+status_t OMXClient::connect(const char* name) {
     using namespace ::android::hardware::media::omx::V1_0;
     if (name == nullptr) {
         name = "default";
     }
     sp<IOmx> tOmx = IOmx::getService(name);
     if (tOmx.get() == nullptr) {
-        ALOGE("Cannot obtain Treble IOmx.");
+        ALOGE("Cannot obtain IOmx service.");
         return NO_INIT;
     }
     if (!tOmx->isRemote()) {
-        ALOGE("Treble IOmx is in passthrough mode.");
+        ALOGE("IOmx service running in passthrough mode.");
         return NO_INIT;
     }
     mOMX = new utils::LWOmx(tOmx);
-    ALOGI("Treble IOmx obtained");
+    ALOGI("IOmx service obtained");
     return OK;
 }
 
@@ -109,4 +63,8 @@
     mOMX.clear();
 }
 
+sp<IOMX> OMXClient::interface() {
+    return mOMX;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index 8717a79..a6ebadd 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -24,8 +24,7 @@
 #include <utils/Log.h>
 #include <cutils/properties.h>
 
-#include <binder/IServiceManager.h>
-#include <media/IMediaCodecService.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 #include <media/stagefright/OmxInfoBuilder.h>
 #include <media/stagefright/ACodec.h>
 
@@ -34,10 +33,9 @@
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
 #include <media/stagefright/omx/OMXUtils.h>
 
-#include <media/IOMXStore.h>
 #include <media/IOMX.h>
-#include <media/MediaDefs.h>
 #include <media/omx/1.0/WOmx.h>
+#include <media/stagefright/omx/1.0/OmxStore.h>
 
 #include <media/openmax/OMX_Index.h>
 #include <media/openmax/OMX_IndexExt.h>
@@ -48,10 +46,18 @@
 
 namespace android {
 
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using namespace ::android::hardware::media::omx::V1_0;
+
 namespace /* unnamed */ {
 
+bool hasPrefix(const hidl_string& s, const char* prefix) {
+    return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
+}
+
 status_t queryCapabilities(
-        const IOMXStore::NodeInfo& node, const char* mime, bool isEncoder,
+        const IOmxStore::NodeInfo& node, const char* mime, bool isEncoder,
         MediaCodecInfo::CapabilitiesWriter* caps) {
     sp<ACodec> codec = new ACodec();
     status_t err = codec->queryCapabilities(
@@ -62,14 +68,13 @@
     for (const auto& attribute : node.attributes) {
         // All features have an int32 value except
         // "feature-bitrate-modes", which has a string value.
-        if ((attribute.key.compare(0, 8, "feature-") == 0) &&
-                (attribute.key.compare(8, 15, "bitrate-modes")
-                 != 0)) {
-            // If this attribute.key is a feature that is not a bitrate
-            // control, add an int32 value.
+        if (hasPrefix(attribute.key, "feature-") &&
+                !hasPrefix(attribute.key, "feature-bitrate-modes")) {
+            // If this attribute.key is a feature that is not bitrate modes,
+            // add an int32 value.
             caps->addDetail(
                     attribute.key.c_str(),
-                    attribute.value == "1" ? 1 : 0);
+                    hasPrefix(attribute.value, "1") ? 1 : 0);
         } else {
             // Non-feature attributes
             caps->addDetail(
@@ -85,138 +90,70 @@
 }
 
 status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
-    bool treble;
-    sp<IOMX> omx;
-    std::vector<IOMXStore::RoleInfo> roles;
+    // Obtain IOmxStore
+    sp<IOmxStore> omxStore = IOmxStore::getService();
+    if (omxStore == nullptr) {
+        ALOGE("Cannot find an IOmxStore service.");
+        return NO_INIT;
+    }
 
-    treble = property_get_bool("persist.media.treble_omx", true);
-    if (treble) {
-        using namespace ::android::hardware::media::omx::V1_0;
-        using ::android::hardware::hidl_vec;
-        using ::android::hardware::hidl_string;
-
-        // Obtain IOmxStore
-        sp<IOmxStore> omxStore = IOmxStore::getService();
+    // List service attributes (global settings)
+    Status status;
+    hidl_vec<IOmxStore::RoleInfo> roles;
+    auto transStatus = omxStore->listRoles(
+            [&roles] (
+            const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
+                roles = inRoleList;
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("Fail to obtain codec roles from IOmxStore.");
+        return NO_INIT;
+    } else if (roles.size() == 0) {
+        ALOGW("IOmxStore has empty implementation. "
+                "Creating a local default instance...");
+        omxStore = new implementation::OmxStore();
         if (omxStore == nullptr) {
-            ALOGE("Cannot connect to an IOmxStore instance.");
+            ALOGE("Cannot create a local default instance.");
             return NO_INIT;
         }
-
-        // List service attributes (global settings)
-        Status status;
-        hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
-        auto transStatus = omxStore->listServiceAttributes(
-                [&status, &serviceAttributes]
-                (Status inStatus, const hidl_vec<IOmxStore::ServiceAttribute>&
-                        inAttributes) {
-                    status = inStatus;
-                    serviceAttributes = inAttributes;
-                });
-        if (!transStatus.isOk()) {
-            ALOGE("Fail to obtain global settings from IOmxStore.");
-            return NO_INIT;
-        }
-        if (status != Status::OK) {
-            ALOGE("IOmxStore reports parsing error.");
-            return NO_INIT;
-        }
-        for (const auto& p : serviceAttributes) {
-            writer->addGlobalSetting(
-                    p.key.c_str(), p.value.c_str());
-        }
-
-        // List roles and convert to IOMXStore's format
+        ALOGI("IOmxStore local default instance created.");
         transStatus = omxStore->listRoles(
-                [&roles]
-                (const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
-                    roles.reserve(inRoleList.size());
-                    for (const auto& inRole : inRoleList) {
-                        IOMXStore::RoleInfo role;
-                        role.role = inRole.role;
-                        role.type = inRole.type;
-                        role.isEncoder = inRole.isEncoder;
-                        role.preferPlatformNodes = inRole.preferPlatformNodes;
-                        std::vector<IOMXStore::NodeInfo>& nodes =
-                                role.nodes;
-                        nodes.reserve(inRole.nodes.size());
-                        for (const auto& inNode : inRole.nodes) {
-                            IOMXStore::NodeInfo node;
-                            node.name = inNode.name;
-                            node.owner = inNode.owner;
-                            std::vector<IOMXStore::Attribute>& attributes =
-                                    node.attributes;
-                            attributes.reserve(inNode.attributes.size());
-                            for (const auto& inAttr : inNode.attributes) {
-                                IOMXStore::Attribute attr;
-                                attr.key = inAttr.key;
-                                attr.value = inAttr.value;
-                                attributes.push_back(std::move(attr));
-                            }
-                            nodes.push_back(std::move(node));
-                        }
-                        roles.push_back(std::move(role));
-                    }
+                [&roles] (
+                const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
+                    roles = inRoleList;
                 });
         if (!transStatus.isOk()) {
-            ALOGE("Fail to obtain codec roles from IOmxStore.");
-            return NO_INIT;
-        }
-    } else {
-        // Obtain IOMXStore
-        sp<IServiceManager> sm = defaultServiceManager();
-        if (sm == nullptr) {
-            ALOGE("Cannot obtain the default service manager.");
-            return NO_INIT;
-        }
-        sp<IBinder> codecBinder = sm->getService(String16("media.codec"));
-        if (codecBinder == nullptr) {
-            ALOGE("Cannot obtain the media codec service.");
-            return NO_INIT;
-        }
-        sp<IMediaCodecService> codecService =
-                interface_cast<IMediaCodecService>(codecBinder);
-        if (codecService == nullptr) {
-            ALOGE("Wrong type of media codec service obtained.");
-            return NO_INIT;
-        }
-        omx = codecService->getOMX();
-        if (omx == nullptr) {
-            ALOGE("Cannot connect to an IOMX instance.");
-        }
-        sp<IOMXStore> omxStore = codecService->getOMXStore();
-        if (omxStore == nullptr) {
-            ALOGE("Cannot connect to an IOMXStore instance.");
-            return NO_INIT;
-        }
-
-        // List service attributes (global settings)
-        std::vector<IOMXStore::Attribute> serviceAttributes;
-        status_t status = omxStore->listServiceAttributes(&serviceAttributes);
-        if (status != OK) {
-            ALOGE("Fail to obtain global settings from IOMXStore.");
-            return NO_INIT;
-        }
-        for (const auto& p : serviceAttributes) {
-            writer->addGlobalSetting(
-                    p.key.c_str(), p.value.c_str());
-        }
-
-        // List roles
-        status = omxStore->listRoles(&roles);
-        if (status != OK) {
-            ALOGE("Fail to obtain codec roles from IOMXStore.");
+            ALOGE("Fail to obtain codec roles from local IOmxStore.");
             return NO_INIT;
         }
     }
 
+    hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
+    transStatus = omxStore->listServiceAttributes(
+            [&status, &serviceAttributes] (
+            Status inStatus,
+            const hidl_vec<IOmxStore::ServiceAttribute>& inAttributes) {
+                status = inStatus;
+                serviceAttributes = inAttributes;
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("Fail to obtain global settings from IOmxStore.");
+        return NO_INIT;
+    }
+    if (status != Status::OK) {
+        ALOGE("IOmxStore reports parsing error.");
+        return NO_INIT;
+    }
+    for (const auto& p : serviceAttributes) {
+        writer->addGlobalSetting(
+                p.key.c_str(), p.value.c_str());
+    }
+
     // Convert roles to lists of codecs
 
-    // codec name -> index into swCodecs
-    std::map<std::string, std::unique_ptr<MediaCodecInfoWriter> >
-            swCodecName2Info;
-    // codec name -> index into hwCodecs
-    std::map<std::string, std::unique_ptr<MediaCodecInfoWriter> >
-            hwCodecName2Info;
+    // codec name -> index into swCodecs/hwCodecs
+    std::map<hidl_string, std::unique_ptr<MediaCodecInfoWriter>>
+            swCodecName2Info, hwCodecName2Info;
     // owner name -> MediaCodecInfo
     // This map will be used to obtain the correct IOmx service(s) needed for
     // creating IOmxNode instances and querying capabilities.
@@ -230,10 +167,10 @@
         // If preferPlatformNodes is true, hardware nodes must be added after
         // platform (software) nodes. hwCodecs is used to hold hardware nodes
         // that need to be added after software nodes for the same role.
-        std::vector<const IOMXStore::NodeInfo*> hwCodecs;
+        std::vector<const IOmxStore::NodeInfo*> hwCodecs;
         for (const auto& node : role.nodes) {
             const auto& nodeName = node.name;
-            bool isSoftware = nodeName.compare(0, 10, "OMX.google") == 0;
+            bool isSoftware = hasPrefix(nodeName, "OMX.google");
             MediaCodecInfoWriter* info;
             if (isSoftware) {
                 auto c2i = swCodecName2Info.find(nodeName);
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
new file mode 100644
index 0000000..1dd7986
--- /dev/null
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/MediaSource.h>
+#include <media/stagefright/RemoteMediaExtractor.h>
+
+namespace android {
+
+RemoteMediaExtractor::RemoteMediaExtractor(const sp<MediaExtractor> &extractor)
+    :mExtractor(extractor) {}
+
+RemoteMediaExtractor::~RemoteMediaExtractor() {}
+
+size_t RemoteMediaExtractor::countTracks() {
+    return mExtractor->countTracks();
+}
+
+sp<IMediaSource> RemoteMediaExtractor::getTrack(size_t index) {
+    sp<MediaSource> source = mExtractor->getTrack(index);
+    return (source.get() == nullptr) ? nullptr : CreateIMediaSourceFromMediaSource(source);
+}
+
+sp<MetaData> RemoteMediaExtractor::getTrackMetaData(size_t index, uint32_t flags) {
+    return mExtractor->getTrackMetaData(index, flags);
+}
+
+sp<MetaData> RemoteMediaExtractor::getMetaData() {
+    return mExtractor->getMetaData();
+}
+
+status_t RemoteMediaExtractor::getMetrics(Parcel *reply) {
+    return mExtractor->getMetrics(reply);
+}
+
+uint32_t RemoteMediaExtractor::flags() const {
+    return mExtractor->flags();
+}
+
+char* RemoteMediaExtractor::getDrmTrackInfo(size_t trackID, int * len) {
+    return mExtractor->getDrmTrackInfo(trackID, len);
+}
+
+void RemoteMediaExtractor::setUID(uid_t uid) {
+    return mExtractor->setUID(uid);
+}
+
+status_t RemoteMediaExtractor::setMediaCas(const HInterfaceToken &casToken) {
+    return mExtractor->setMediaCas(casToken);
+}
+
+const char * RemoteMediaExtractor::name() {
+    return mExtractor->name();
+}
+
+void RemoteMediaExtractor::release() {
+    return mExtractor->release();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// static
+sp<IMediaExtractor> RemoteMediaExtractor::wrap(const sp<MediaExtractor> &extractor) {
+    if (extractor.get() == nullptr) {
+        return nullptr;
+    }
+    return new RemoteMediaExtractor(extractor);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/RemoteMediaSource.cpp b/media/libstagefright/RemoteMediaSource.cpp
new file mode 100644
index 0000000..7a2a46b
--- /dev/null
+++ b/media/libstagefright/RemoteMediaSource.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/stagefright/RemoteMediaSource.h>
+#include <media/IMediaSource.h>
+
+namespace android {
+
+RemoteMediaSource::RemoteMediaSource(const sp<MediaSource> &source)
+    :mSource(source) {}
+
+RemoteMediaSource::~RemoteMediaSource() {}
+
+status_t RemoteMediaSource::start(MetaData *params) {
+    return mSource->start(params);
+}
+
+status_t RemoteMediaSource::stop() {
+    return mSource->stop();
+}
+
+sp<MetaData> RemoteMediaSource::getFormat() {
+    return mSource->getFormat();
+}
+
+status_t RemoteMediaSource::read(MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
+    return mSource->read(buffer, reinterpret_cast<const MediaSource::ReadOptions*>(options));
+}
+
+status_t RemoteMediaSource::pause() {
+    return mSource->pause();
+}
+
+status_t RemoteMediaSource::setBuffers(const Vector<MediaBuffer *> &buffers) {
+    return mSource->setBuffers(buffers);
+}
+
+status_t RemoteMediaSource::setStopTimeUs(int64_t stopTimeUs) {
+    return mSource->setStopTimeUs(stopTimeUs);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// static
+sp<IMediaSource> RemoteMediaSource::wrap(const sp<MediaSource> &source) {
+    if (source.get() == nullptr) {
+        return nullptr;
+    }
+    return new RemoteMediaSource(source);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index 90b8603..67e6748 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -36,13 +36,13 @@
 
 //static
 sp<SimpleDecodingSource> SimpleDecodingSource::Create(
-        const sp<IMediaSource> &source, uint32_t flags) {
+        const sp<MediaSource> &source, uint32_t flags) {
     return SimpleDecodingSource::Create(source, flags, nullptr, nullptr);
 }
 
 //static
 sp<SimpleDecodingSource> SimpleDecodingSource::Create(
-        const sp<IMediaSource> &source, uint32_t flags, const sp<ANativeWindow> &nativeWindow,
+        const sp<MediaSource> &source, uint32_t flags, const sp<ANativeWindow> &nativeWindow,
         const char *desiredCodec) {
     sp<Surface> surface = static_cast<Surface*>(nativeWindow.get());
     const char *mime = NULL;
@@ -99,7 +99,7 @@
 }
 
 SimpleDecodingSource::SimpleDecodingSource(
-        const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
+        const sp<MediaCodec> &codec, const sp<MediaSource> &source, const sp<ALooper> &looper,
         bool usingSurface, bool isVorbis, const sp<AMessage> &format)
     : mCodec(codec),
       mSource(source),
@@ -212,7 +212,7 @@
     status_t res;
 
     // flush codec on seek
-    IMediaSource::ReadOptions::SeekMode mode;
+    MediaSource::ReadOptions::SeekMode mode;
     if (options != NULL && options->getSeekTo(&out_pts, &mode)) {
         me->mQueuedInputEOS = false;
         me->mGotOutputEOS = false;
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 103da95..e2db0f5 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -20,37 +20,24 @@
 #include <inttypes.h>
 
 #include <utils/Log.h>
-#include <gui/Surface.h>
 
-#include "include/avc_utils.h"
+#include "include/FrameDecoder.h"
 #include "include/StagefrightMetadataRetriever.h"
 
-#include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
-#include <media/MediaCodecBuffer.h>
-
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ColorConverter.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
 #include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
 #include <media/CharacterEncodingDetector.h>
 
 namespace android {
 
-static const int64_t kBufferTimeOutUs = 30000ll; // 30 msec
-static const size_t kRetryCount = 20; // must be >0
-
 StagefrightMetadataRetriever::StagefrightMetadataRetriever()
     : mParsedMetaData(false),
       mAlbumArt(NULL) {
@@ -78,14 +65,14 @@
     ALOGV("setDataSource(%s)", uri);
 
     clearMetadata();
-    mSource = DataSource::CreateFromURI(httpService, uri, headers);
+    mSource = DataSourceFactory::CreateFromURI(httpService, uri, headers);
 
     if (mSource == NULL) {
         ALOGE("Unable to create data source for '%s'.", uri);
         return UNKNOWN_ERROR;
     }
 
-    mExtractor = MediaExtractor::Create(mSource);
+    mExtractor = MediaExtractorFactory::Create(mSource);
 
     if (mExtractor == NULL) {
         ALOGE("Unable to instantiate an extractor for '%s'.", uri);
@@ -115,7 +102,7 @@
         return err;
     }
 
-    mExtractor = MediaExtractor::Create(mSource);
+    mExtractor = MediaExtractorFactory::Create(mSource);
 
     if (mExtractor == NULL) {
         mSource.clear();
@@ -132,7 +119,7 @@
 
     clearMetadata();
     mSource = source;
-    mExtractor = MediaExtractor::Create(mSource, mime);
+    mExtractor = MediaExtractorFactory::Create(mSource, mime);
 
     if (mExtractor == NULL) {
         ALOGE("Failed to instantiate a MediaExtractor.");
@@ -143,469 +130,124 @@
     return OK;
 }
 
-static VideoFrame *allocVideoFrame(
-        const sp<MetaData> &trackMeta, int32_t width, int32_t height, int32_t bpp, bool metaOnly) {
-    int32_t rotationAngle;
-    if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
-        rotationAngle = 0;  // By default, no rotation
-    }
+VideoFrame* StagefrightMetadataRetriever::getImageAtIndex(
+        int index, int colorFormat, bool metaOnly) {
 
-    uint32_t type;
-    const void *iccData;
-    size_t iccSize;
-    if (!trackMeta->findData(kKeyIccProfile, &type, &iccData, &iccSize)){
-        iccData = NULL;
-        iccSize = 0;
-    }
+    ALOGV("getImageAtIndex: index: %d colorFormat: %d, metaOnly: %d",
+            index, colorFormat, metaOnly);
 
-    int32_t sarWidth, sarHeight;
-    int32_t displayWidth, displayHeight;
-    if (trackMeta->findInt32(kKeySARWidth, &sarWidth)
-            && trackMeta->findInt32(kKeySARHeight, &sarHeight)
-            && sarHeight != 0) {
-        displayWidth = (width * sarWidth) / sarHeight;
-        displayHeight = height;
-    } else if (trackMeta->findInt32(kKeyDisplayWidth, &displayWidth)
-                && trackMeta->findInt32(kKeyDisplayHeight, &displayHeight)
-                && displayWidth > 0 && displayHeight > 0
-                && width > 0 && height > 0) {
-        ALOGV("found display size %dx%d", displayWidth, displayHeight);
-    } else {
-        displayWidth = width;
-        displayHeight = height;
-    }
-
-    return new VideoFrame(width, height, displayWidth, displayHeight,
-            rotationAngle, bpp, !metaOnly, iccData, iccSize);
-}
-
-static bool getDstColorFormat(android_pixel_format_t colorFormat,
-        OMX_COLOR_FORMATTYPE *omxColorFormat, int32_t *bpp) {
-    switch (colorFormat) {
-        case HAL_PIXEL_FORMAT_RGB_565:
-        {
-            *omxColorFormat = OMX_COLOR_Format16bitRGB565;
-            *bpp = 2;
-            return true;
-        }
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-        {
-            *omxColorFormat = OMX_COLOR_Format32BitRGBA8888;
-            *bpp = 4;
-            return true;
-        }
-        case HAL_PIXEL_FORMAT_BGRA_8888:
-        {
-            *omxColorFormat = OMX_COLOR_Format32bitBGRA8888;
-            *bpp = 4;
-            return true;
-        }
-        default:
-        {
-            ALOGE("Unsupported color format: %d", colorFormat);
-            break;
-        }
-    }
-    return false;
-}
-
-static VideoFrame *extractVideoFrame(
-        const AString &componentName,
-        const sp<MetaData> &trackMeta,
-        const sp<IMediaSource> &source,
-        int64_t frameTimeUs,
-        int seekMode,
-        int colorFormat,
-        bool metaOnly) {
-    sp<MetaData> format = source->getFormat();
-
-    MediaSource::ReadOptions::SeekMode mode =
-            static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
-    if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
-        seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {
-        ALOGE("Unknown seek mode: %d", seekMode);
+    if (mExtractor.get() == NULL) {
+        ALOGE("no extractor.");
         return NULL;
     }
 
-    int32_t dstBpp;
-    OMX_COLOR_FORMATTYPE dstFormat;
-    if (!getDstColorFormat(
-            (android_pixel_format_t)colorFormat, &dstFormat, &dstBpp)) {
-        return NULL;
-    }
+    size_t n = mExtractor->countTracks();
+    size_t i;
+    int imageCount = 0;
 
-    if (metaOnly) {
-        int32_t width, height;
-        CHECK(trackMeta->findInt32(kKeyWidth, &width));
-        CHECK(trackMeta->findInt32(kKeyHeight, &height));
-        return allocVideoFrame(trackMeta, width, height, dstBpp, true);
-    }
+    for (i = 0; i < n; ++i) {
+        sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+        ALOGV("getting track %zu of %zu, meta=%s", i, n, meta->toString().c_str());
 
-    MediaSource::ReadOptions options;
-    sp<MetaData> overrideMeta;
-    if (frameTimeUs < 0) {
-        uint32_t type;
-        const void *data;
-        size_t size;
-        int64_t thumbNailTime;
-        int32_t thumbnailWidth, thumbnailHeight;
+        const char *mime;
+        CHECK(meta->findCString(kKeyMIMEType, &mime));
 
-        // if we have a stand-alone thumbnail, set up the override meta,
-        // and set seekTo time to -1.
-        if (trackMeta->findInt32(kKeyThumbnailWidth, &thumbnailWidth)
-         && trackMeta->findInt32(kKeyThumbnailHeight, &thumbnailHeight)
-         && trackMeta->findData(kKeyThumbnailHVCC, &type, &data, &size)){
-            overrideMeta = new MetaData(*trackMeta);
-            overrideMeta->remove(kKeyDisplayWidth);
-            overrideMeta->remove(kKeyDisplayHeight);
-            overrideMeta->setInt32(kKeyWidth, thumbnailWidth);
-            overrideMeta->setInt32(kKeyHeight, thumbnailHeight);
-            overrideMeta->setData(kKeyHVCC, type, data, size);
-            thumbNailTime = -1ll;
-            ALOGV("thumbnail: %dx%d", thumbnailWidth, thumbnailHeight);
-        } else if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)
-                || thumbNailTime < 0) {
-            thumbNailTime = 0;
-        }
-
-        options.setSeekTo(thumbNailTime, mode);
-    } else {
-        options.setSeekTo(frameTimeUs, mode);
-    }
-
-    int32_t gridRows = 1, gridCols = 1;
-    if (overrideMeta == NULL) {
-        // check if we're dealing with a tiled heif
-        int32_t gridWidth, gridHeight;
-        if (trackMeta->findInt32(kKeyGridWidth, &gridWidth) && gridWidth > 0
-         && trackMeta->findInt32(kKeyGridHeight, &gridHeight) && gridHeight > 0) {
-            int32_t width, height, displayWidth, displayHeight;
-            CHECK(trackMeta->findInt32(kKeyWidth, &width));
-            CHECK(trackMeta->findInt32(kKeyHeight, &height));
-            CHECK(trackMeta->findInt32(kKeyDisplayWidth, &displayWidth));
-            CHECK(trackMeta->findInt32(kKeyDisplayHeight, &displayHeight));
-
-            if (width >= displayWidth && height >= displayHeight
-                    && (width % gridWidth == 0) && (height % gridHeight == 0)) {
-                ALOGV("grid config: %dx%d, display %dx%d, grid %dx%d",
-                        width, height, displayWidth, displayHeight, gridWidth, gridHeight);
-
-                overrideMeta = new MetaData(*trackMeta);
-                overrideMeta->remove(kKeyDisplayWidth);
-                overrideMeta->remove(kKeyDisplayHeight);
-                overrideMeta->setInt32(kKeyWidth, gridWidth);
-                overrideMeta->setInt32(kKeyHeight, gridHeight);
-                gridCols = width / gridWidth;
-                gridRows = height / gridHeight;
-            } else {
-                ALOGE("Bad grid config: %dx%d, display %dx%d, grid %dx%d",
-                        width, height, displayWidth, displayHeight, gridWidth, gridHeight);
+        if (!strncasecmp(mime, "image/", 6)) {
+            int32_t isPrimary;
+            if ((index < 0 && meta->findInt32(
+                    kKeyTrackIsDefault, &isPrimary) && isPrimary)
+                    || (index == imageCount++)) {
+                break;
             }
         }
-        if (overrideMeta == NULL) {
-            overrideMeta = trackMeta;
-        }
     }
-    int32_t numTiles = gridRows * gridCols;
 
-    sp<AMessage> videoFormat;
-    if (convertMetaDataToMessage(overrideMeta, &videoFormat) != OK) {
-        ALOGE("b/23680780");
-        ALOGW("Failed to convert meta data to message");
+    if (i == n) {
+        ALOGE("image track not found.");
         return NULL;
     }
 
-    // TODO: Use Flexible color instead
-    videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+    sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
 
-    // For the thumbnail extraction case, try to allocate single buffer in both
-    // input and output ports, if seeking to a sync frame. NOTE: This request may
-    // fail if component requires more than that for decoding.
-    bool isSeekingClosest = (seekMode == MediaSource::ReadOptions::SEEK_CLOSEST);
-    bool decodeSingleFrame = !isSeekingClosest && (numTiles == 1);
-    if (decodeSingleFrame) {
-        videoFormat->setInt32("android._num-input-buffers", 1);
-        videoFormat->setInt32("android._num-output-buffers", 1);
-    }
+    sp<IMediaSource> source = mExtractor->getTrack(i);
 
-    status_t err;
-    sp<ALooper> looper = new ALooper;
-    looper->start();
-    sp<MediaCodec> decoder = MediaCodec::CreateByComponentName(
-            looper, componentName, &err);
-
-    if (decoder.get() == NULL || err != OK) {
-        ALOGW("Failed to instantiate decoder [%s]", componentName.c_str());
+    if (source.get() == NULL) {
+        ALOGE("unable to instantiate image track.");
         return NULL;
     }
 
-    err = decoder->configure(videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
-    if (err != OK) {
-        ALOGW("configure returned error %d (%s)", err, asString(err));
-        decoder->release();
-        return NULL;
-    }
-
-    err = decoder->start();
-    if (err != OK) {
-        ALOGW("start returned error %d (%s)", err, asString(err));
-        decoder->release();
-        return NULL;
-    }
-
-    err = source->start();
-    if (err != OK) {
-        ALOGW("source failed to start: %d (%s)", err, asString(err));
-        decoder->release();
-        return NULL;
-    }
-
-    Vector<sp<MediaCodecBuffer> > inputBuffers;
-    err = decoder->getInputBuffers(&inputBuffers);
-    if (err != OK) {
-        ALOGW("failed to get input buffers: %d (%s)", err, asString(err));
-        decoder->release();
-        source->stop();
-        return NULL;
-    }
-
-    Vector<sp<MediaCodecBuffer> > outputBuffers;
-    err = decoder->getOutputBuffers(&outputBuffers);
-    if (err != OK) {
-        ALOGW("failed to get output buffers: %d (%s)", err, asString(err));
-        decoder->release();
-        source->stop();
-        return NULL;
-    }
-
-    sp<AMessage> outputFormat = NULL;
-    bool haveMoreInputs = true;
-    size_t index, offset, size;
-    int64_t timeUs;
-    size_t retriesLeft = kRetryCount;
-    bool done = false;
     const char *mime;
-    bool success = format->findCString(kKeyMIMEType, &mime);
-    if (!success) {
-        ALOGE("Could not find mime type");
-        return NULL;
+    CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
+    ALOGV("extracting from %s track", mime);
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
+        mime = MEDIA_MIMETYPE_VIDEO_HEVC;
+        trackMeta = new MetaData(*trackMeta);
+        trackMeta->setCString(kKeyMIMEType, mime);
     }
 
-    bool isAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
-            || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+    Vector<AString> matchingCodecs;
+    MediaCodecList::findMatchingCodecs(
+            mime,
+            false, /* encoder */
+            MediaCodecList::kPreferSoftwareCodecs,
+            &matchingCodecs);
 
-    bool firstSample = true;
-    int64_t targetTimeUs = -1ll;
+    for (size_t i = 0; i < matchingCodecs.size(); ++i) {
+        const AString &componentName = matchingCodecs[i];
+        ImageDecoder decoder(componentName, trackMeta, source);
+        VideoFrame* frame = decoder.extractFrame(
+                0 /*frameTimeUs*/, 0 /*seekMode*/, colorFormat, metaOnly);
 
-    VideoFrame *frame = NULL;
-    int32_t tilesDecoded = 0;
-
-    do {
-        size_t inputIndex = -1;
-        int64_t ptsUs = 0ll;
-        uint32_t flags = 0;
-        sp<MediaCodecBuffer> codecBuffer = NULL;
-
-        while (haveMoreInputs) {
-            err = decoder->dequeueInputBuffer(&inputIndex, kBufferTimeOutUs);
-            if (err != OK) {
-                ALOGW("Timed out waiting for input");
-                if (retriesLeft) {
-                    err = OK;
-                }
-                break;
-            }
-            codecBuffer = inputBuffers[inputIndex];
-
-            MediaBuffer *mediaBuffer = NULL;
-
-            err = source->read(&mediaBuffer, &options);
-            options.clearSeekTo();
-            if (err != OK) {
-                ALOGW("Input Error or EOS");
-                haveMoreInputs = false;
-                if (err == ERROR_END_OF_STREAM) {
-                    err = OK;
-                }
-                break;
-            }
-            if (firstSample && isSeekingClosest) {
-                mediaBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs);
-                ALOGV("Seeking closest: targetTimeUs=%lld", (long long)targetTimeUs);
-            }
-            firstSample = false;
-
-            if (mediaBuffer->range_length() > codecBuffer->capacity()) {
-                ALOGE("buffer size (%zu) too large for codec input size (%zu)",
-                        mediaBuffer->range_length(), codecBuffer->capacity());
-                haveMoreInputs = false;
-                err = BAD_VALUE;
-            } else {
-                codecBuffer->setRange(0, mediaBuffer->range_length());
-
-                CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &ptsUs));
-                memcpy(codecBuffer->data(),
-                        (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
-                        mediaBuffer->range_length());
-            }
-
-            mediaBuffer->release();
-            break;
+        if (frame != NULL) {
+            return frame;
         }
-
-        if (haveMoreInputs && inputIndex < inputBuffers.size()) {
-            if (isAvcOrHevc && IsIDR(codecBuffer) && decodeSingleFrame) {
-                // Only need to decode one IDR frame, unless we're seeking with CLOSEST
-                // option, in which case we need to actually decode to targetTimeUs.
-                haveMoreInputs = false;
-                flags |= MediaCodec::BUFFER_FLAG_EOS;
-            }
-
-            ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
-                    codecBuffer->size(), ptsUs, flags);
-            err = decoder->queueInputBuffer(
-                    inputIndex,
-                    codecBuffer->offset(),
-                    codecBuffer->size(),
-                    ptsUs,
-                    flags);
-
-            // we don't expect an output from codec config buffer
-            if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
-                continue;
-            }
-        }
-
-        while (err == OK) {
-            // wait for a decoded buffer
-            err = decoder->dequeueOutputBuffer(
-                    &index,
-                    &offset,
-                    &size,
-                    &timeUs,
-                    &flags,
-                    kBufferTimeOutUs);
-
-            if (err == INFO_FORMAT_CHANGED) {
-                ALOGV("Received format change");
-                err = decoder->getOutputFormat(&outputFormat);
-            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
-                ALOGV("Output buffers changed");
-                err = decoder->getOutputBuffers(&outputBuffers);
-            } else {
-                if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) {
-                    ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
-                    err = OK;
-                } else if (err == OK) {
-                    // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
-                    // from the extractor, decode to the specified frame. Otherwise we're done.
-                    ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
-                    sp<MediaCodecBuffer> videoFrameBuffer = outputBuffers.itemAt(index);
-
-                    int32_t width, height;
-                    CHECK(outputFormat != NULL);
-                    CHECK(outputFormat->findInt32("width", &width));
-                    CHECK(outputFormat->findInt32("height", &height));
-
-                    int32_t crop_left, crop_top, crop_right, crop_bottom;
-                    if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
-                        crop_left = crop_top = 0;
-                        crop_right = width - 1;
-                        crop_bottom = height - 1;
-                    }
-
-                    if (frame == NULL) {
-                        frame = allocVideoFrame(
-                                trackMeta,
-                                (crop_right - crop_left + 1) * gridCols,
-                                (crop_bottom - crop_top + 1) * gridRows,
-                                dstBpp,
-                                false /*metaOnly*/);
-                    }
-
-                    int32_t srcFormat;
-                    CHECK(outputFormat->findInt32("color-format", &srcFormat));
-
-                    ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat);
-
-                    int32_t dstLeft, dstTop, dstRight, dstBottom;
-                    if (numTiles == 1) {
-                        dstLeft = crop_left;
-                        dstTop = crop_top;
-                        dstRight = crop_right;
-                        dstBottom = crop_bottom;
-                    } else {
-                        dstLeft = tilesDecoded % gridCols * width;
-                        dstTop = tilesDecoded / gridCols * height;
-                        dstRight = dstLeft + width - 1;
-                        dstBottom = dstTop + height - 1;
-                    }
-
-                    if (converter.isValid()) {
-                        err = converter.convert(
-                                (const uint8_t *)videoFrameBuffer->data(),
-                                width, height,
-                                crop_left, crop_top, crop_right, crop_bottom,
-                                frame->mData,
-                                frame->mWidth,
-                                frame->mHeight,
-                                dstLeft, dstTop, dstRight, dstBottom);
-                    } else {
-                        ALOGE("Unable to convert from format 0x%08x to 0x%08x",
-                                srcFormat, dstFormat);
-
-                        err = ERROR_UNSUPPORTED;
-                    }
-
-                    done = (targetTimeUs < 0ll) || (timeUs >= targetTimeUs);
-                    if (numTiles > 1) {
-                        tilesDecoded++;
-                        done &= (tilesDecoded >= numTiles);
-                    }
-                    err = decoder->releaseOutputBuffer(index);
-                } else {
-                    ALOGW("Received error %d (%s) instead of output", err, asString(err));
-                    done = true;
-                }
-                break;
-            }
-        }
-    } while (err == OK && !done);
-
-    source->stop();
-    decoder->release();
-
-    if (err != OK) {
-        ALOGE("failed to get video frame (err %d)", err);
-        delete frame;
-        frame = NULL;
+        ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
     }
 
-    return frame;
+    return NULL;
 }
 
-VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
+VideoFrame* StagefrightMetadataRetriever::getFrameAtTime(
         int64_t timeUs, int option, int colorFormat, bool metaOnly) {
-
     ALOGV("getFrameAtTime: %" PRId64 " us option: %d colorFormat: %d, metaOnly: %d",
             timeUs, option, colorFormat, metaOnly);
 
+    VideoFrame *frame;
+    status_t err = getFrameInternal(
+            timeUs, 1, option, colorFormat, metaOnly, &frame, NULL /*outFrames*/);
+    return (err == OK) ? frame : NULL;
+}
+
+status_t StagefrightMetadataRetriever::getFrameAtIndex(
+        std::vector<VideoFrame*>* frames,
+        int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
+    ALOGV("getFrameAtIndex: frameIndex %d, numFrames %d, colorFormat: %d, metaOnly: %d",
+            frameIndex, numFrames, colorFormat, metaOnly);
+
+    return getFrameInternal(
+            frameIndex, numFrames, MediaSource::ReadOptions::SEEK_FRAME_INDEX,
+            colorFormat, metaOnly, NULL /*outFrame*/, frames);
+}
+
+status_t StagefrightMetadataRetriever::getFrameInternal(
+        int64_t timeUs, int numFrames, int option, int colorFormat, bool metaOnly,
+        VideoFrame **outFrame, std::vector<VideoFrame*>* outFrames) {
     if (mExtractor.get() == NULL) {
-        ALOGV("no extractor.");
-        return NULL;
+        ALOGE("no extractor.");
+        return NO_INIT;
     }
 
     sp<MetaData> fileMeta = mExtractor->getMetaData();
 
     if (fileMeta == NULL) {
-        ALOGV("extractor doesn't publish metadata, failed to initialize?");
-        return NULL;
+        ALOGE("extractor doesn't publish metadata, failed to initialize?");
+        return NO_INIT;
     }
 
     int32_t drm = 0;
     if (fileMeta->findInt32(kKeyIsDRM, &drm) && drm != 0) {
         ALOGE("frame grab not allowed.");
-        return NULL;
+        return ERROR_DRM_UNKNOWN;
     }
 
     size_t n = mExtractor->countTracks();
@@ -622,8 +264,8 @@
     }
 
     if (i == n) {
-        ALOGV("no video track found.");
-        return NULL;
+        ALOGE("no video track found.");
+        return INVALID_OPERATION;
     }
 
     sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
@@ -633,7 +275,7 @@
 
     if (source.get() == NULL) {
         ALOGV("unable to instantiate video track.");
-        return NULL;
+        return UNKNOWN_ERROR;
     }
 
     const void *data;
@@ -656,16 +298,25 @@
 
     for (size_t i = 0; i < matchingCodecs.size(); ++i) {
         const AString &componentName = matchingCodecs[i];
-        VideoFrame *frame = extractVideoFrame(
-                componentName, trackMeta, source, timeUs, option, colorFormat, metaOnly);
-
-        if (frame != NULL) {
-            return frame;
+        VideoFrameDecoder decoder(componentName, trackMeta, source);
+        if (outFrame != NULL) {
+            *outFrame = decoder.extractFrame(
+                    timeUs, option, colorFormat, metaOnly);
+            if (*outFrame != NULL) {
+                return OK;
+            }
+        } else if (outFrames != NULL) {
+            status_t err = decoder.extractFrames(
+                    timeUs, numFrames, option, colorFormat, outFrames);
+            if (err == OK) {
+                return OK;
+            }
         }
-        ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
+        ALOGV("%s failed to extract frame, trying next decoder.", componentName.c_str());
     }
 
-    return NULL;
+    ALOGE("all codecs failed to extract frame.");
+    return UNKNOWN_ERROR;
 }
 
 MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
@@ -797,8 +448,14 @@
     bool hasVideo = false;
     int32_t videoWidth = -1;
     int32_t videoHeight = -1;
+    int32_t videoFrameCount = 0;
     int32_t audioBitrate = -1;
     int32_t rotationAngle = -1;
+    int32_t imageCount = 0;
+    int32_t imagePrimary = 0;
+    int32_t imageWidth = -1;
+    int32_t imageHeight = -1;
+    int32_t imageRotation = -1;
 
     // The overall duration is the duration of the longest track.
     int64_t maxDurationUs = 0;
@@ -829,6 +486,21 @@
                 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
                     rotationAngle = 0;
                 }
+                if (!trackMeta->findInt32(kKeyFrameCount, &videoFrameCount)) {
+                    videoFrameCount = 0;
+                }
+            } else if (!strncasecmp("image/", mime, 6)) {
+                int32_t isPrimary;
+                if (trackMeta->findInt32(
+                        kKeyTrackIsDefault, &isPrimary) && isPrimary) {
+                    imagePrimary = imageCount;
+                    CHECK(trackMeta->findInt32(kKeyWidth, &imageWidth));
+                    CHECK(trackMeta->findInt32(kKeyHeight, &imageHeight));
+                    if (!trackMeta->findInt32(kKeyRotation, &imageRotation)) {
+                        imageRotation = 0;
+                    }
+                }
+                imageCount++;
             } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
                 const char *lang;
                 if (trackMeta->findCString(kKeyMediaLanguage, &lang)) {
@@ -867,6 +539,30 @@
 
         sprintf(tmp, "%d", rotationAngle);
         mMetaData.add(METADATA_KEY_VIDEO_ROTATION, String8(tmp));
+
+        if (videoFrameCount > 0) {
+            sprintf(tmp, "%d", videoFrameCount);
+            mMetaData.add(METADATA_KEY_VIDEO_FRAME_COUNT, String8(tmp));
+        }
+    }
+
+    if (imageCount > 0) {
+        mMetaData.add(METADATA_KEY_HAS_IMAGE, String8("yes"));
+
+        sprintf(tmp, "%d", imageCount);
+        mMetaData.add(METADATA_KEY_IMAGE_COUNT, String8(tmp));
+
+        sprintf(tmp, "%d", imagePrimary);
+        mMetaData.add(METADATA_KEY_IMAGE_PRIMARY, String8(tmp));
+
+        sprintf(tmp, "%d", imageWidth);
+        mMetaData.add(METADATA_KEY_IMAGE_WIDTH, String8(tmp));
+
+        sprintf(tmp, "%d", imageHeight);
+        mMetaData.add(METADATA_KEY_IMAGE_HEIGHT, String8(tmp));
+
+        sprintf(tmp, "%d", imageRotation);
+        mMetaData.add(METADATA_KEY_IMAGE_ROTATION, String8(tmp));
     }
 
     if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 3ef8f2a..53699ef 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -27,7 +27,6 @@
 #include "include/ESDS.h"
 #include "include/HevcUtils.h"
 
-#include <arpa/inet.h>
 #include <cutils/properties.h>
 #include <media/openmax/OMX_Audio.h>
 #include <media/openmax/OMX_Video.h>
@@ -37,6 +36,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALookup.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/AudioSystem.h>
@@ -47,39 +47,6 @@
 
 namespace android {
 
-uint16_t U16_AT(const uint8_t *ptr) {
-    return ptr[0] << 8 | ptr[1];
-}
-
-uint32_t U32_AT(const uint8_t *ptr) {
-    return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
-}
-
-uint64_t U64_AT(const uint8_t *ptr) {
-    return ((uint64_t)U32_AT(ptr)) << 32 | U32_AT(ptr + 4);
-}
-
-uint16_t U16LE_AT(const uint8_t *ptr) {
-    return ptr[0] | (ptr[1] << 8);
-}
-
-uint32_t U32LE_AT(const uint8_t *ptr) {
-    return ptr[3] << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0];
-}
-
-uint64_t U64LE_AT(const uint8_t *ptr) {
-    return ((uint64_t)U32LE_AT(ptr + 4)) << 32 | U32LE_AT(ptr);
-}
-
-// XXX warning: these won't work on big-endian host.
-uint64_t ntoh64(uint64_t x) {
-    return ((uint64_t)ntohl(x & 0xffffffff) << 32) | ntohl(x >> 32);
-}
-
-uint64_t hton64(uint64_t x) {
-    return ((uint64_t)htonl(x & 0xffffffff) << 32) | htonl(x >> 32);
-}
-
 static status_t copyNALUToABuffer(sp<ABuffer> *buffer, const uint8_t *ptr, size_t length) {
     if (((*buffer)->size() + 4 + length) > ((*buffer)->capacity() - (*buffer)->offset())) {
         sp<ABuffer> tmpBuffer = new (std::nothrow) ABuffer((*buffer)->size() + 4 + length + 1024);
@@ -672,7 +639,8 @@
         msg->setString("language", lang);
     }
 
-    if (!strncasecmp("video/", mime, 6)) {
+    if (!strncasecmp("video/", mime, 6) ||
+            !strncasecmp("image/", mime, 6)) {
         int32_t width, height;
         if (!meta->findInt32(kKeyWidth, &width)
                 || !meta->findInt32(kKeyHeight, &height)) {
@@ -696,6 +664,23 @@
             msg->setInt32("sar-height", sarHeight);
         }
 
+        if (!strncasecmp("image/", mime, 6)) {
+            int32_t gridWidth, gridHeight, gridRows, gridCols;
+            if (meta->findInt32(kKeyGridWidth, &gridWidth)
+                    && meta->findInt32(kKeyHeight, &gridHeight)
+                    && meta->findInt32(kKeyGridRows, &gridRows)
+                    && meta->findInt32(kKeyGridCols, &gridCols)) {
+                msg->setInt32("grid-width", gridWidth);
+                msg->setInt32("grid-height", gridHeight);
+                msg->setInt32("grid-rows", gridRows);
+                msg->setInt32("grid-cols", gridCols);
+            }
+            int32_t isPrimary;
+            if (meta->findInt32(kKeyTrackIsDefault, &isPrimary) && isPrimary) {
+                msg->setInt32("is-default", 1);
+            }
+        }
+
         int32_t colorFormat;
         if (meta->findInt32(kKeyColorFormat, &colorFormat)) {
             msg->setInt32("color-format", colorFormat);
@@ -1327,7 +1312,7 @@
         meta->setCString(kKeyMediaLanguage, lang.c_str());
     }
 
-    if (mime.startsWith("video/")) {
+    if (mime.startsWith("video/") || mime.startsWith("image/")) {
         int32_t width;
         int32_t height;
         if (msg->findInt32("width", &width) && msg->findInt32("height", &height)) {
@@ -1351,6 +1336,26 @@
             meta->setInt32(kKeyDisplayHeight, displayHeight);
         }
 
+        if (mime.startsWith("image/")){
+            int32_t isPrimary;
+            if (msg->findInt32("is-default", &isPrimary) && isPrimary) {
+                meta->setInt32(kKeyTrackIsDefault, 1);
+            }
+            int32_t gridWidth, gridHeight, gridRows, gridCols;
+            if (msg->findInt32("grid-width", &gridWidth)) {
+                meta->setInt32(kKeyGridWidth, gridWidth);
+            }
+            if (msg->findInt32("grid-height", &gridHeight)) {
+                meta->setInt32(kKeyGridHeight, gridHeight);
+            }
+            if (msg->findInt32("grid-rows", &gridRows)) {
+                meta->setInt32(kKeyGridRows, gridRows);
+            }
+            if (msg->findInt32("grid-cols", &gridCols)) {
+                meta->setInt32(kKeyGridCols, gridCols);
+            }
+        }
+
         int32_t colorFormat;
         if (msg->findInt32("color-format", &colorFormat)) {
             meta->setInt32(kKeyColorFormat, colorFormat);
@@ -1467,7 +1472,8 @@
             // for transporting the CSD to muxers.
             reassembleESDS(csd0, esds.data());
             meta->setData(kKeyESDS, kKeyESDS, esds.data(), esds.size());
-        } else if (mime == MEDIA_MIMETYPE_VIDEO_HEVC) {
+        } else if (mime == MEDIA_MIMETYPE_VIDEO_HEVC ||
+                   mime == MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC) {
             std::vector<uint8_t> hvcc(csd0size + 1024);
             size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
             meta->setData(kKeyHVCC, kKeyHVCC, hvcc.data(), outsize);
@@ -1809,41 +1815,17 @@
 }
 
 void writeToAMessage(const sp<AMessage> &msg, const BufferingSettings &buffering) {
-    msg->setInt32("init-mode", buffering.mInitialBufferingMode);
-    msg->setInt32("rebuffer-mode", buffering.mRebufferingMode);
-    msg->setInt32("init-ms", buffering.mInitialWatermarkMs);
-    msg->setInt32("init-kb", buffering.mInitialWatermarkKB);
-    msg->setInt32("rebuffer-low-ms", buffering.mRebufferingWatermarkLowMs);
-    msg->setInt32("rebuffer-high-ms", buffering.mRebufferingWatermarkHighMs);
-    msg->setInt32("rebuffer-low-kb", buffering.mRebufferingWatermarkLowKB);
-    msg->setInt32("rebuffer-high-kb", buffering.mRebufferingWatermarkHighKB);
+    msg->setInt32("init-ms", buffering.mInitialMarkMs);
+    msg->setInt32("resume-playback-ms", buffering.mResumePlaybackMarkMs);
 }
 
 void readFromAMessage(const sp<AMessage> &msg, BufferingSettings *buffering /* nonnull */) {
     int32_t value;
-    if (msg->findInt32("init-mode", &value)) {
-        buffering->mInitialBufferingMode = (BufferingMode)value;
-    }
-    if (msg->findInt32("rebuffer-mode", &value)) {
-        buffering->mRebufferingMode = (BufferingMode)value;
-    }
     if (msg->findInt32("init-ms", &value)) {
-        buffering->mInitialWatermarkMs = value;
+        buffering->mInitialMarkMs = value;
     }
-    if (msg->findInt32("init-kb", &value)) {
-        buffering->mInitialWatermarkKB = value;
-    }
-    if (msg->findInt32("rebuffer-low-ms", &value)) {
-        buffering->mRebufferingWatermarkLowMs = value;
-    }
-    if (msg->findInt32("rebuffer-high-ms", &value)) {
-        buffering->mRebufferingWatermarkHighMs = value;
-    }
-    if (msg->findInt32("rebuffer-low-kb", &value)) {
-        buffering->mRebufferingWatermarkLowKB = value;
-    }
-    if (msg->findInt32("rebuffer-high-kb", &value)) {
-        buffering->mRebufferingWatermarkHighKB = value;
+    if (msg->findInt32("resume-playback-ms", &value)) {
+        buffering->mResumePlaybackMarkMs = value;
     }
 }
 
@@ -1879,13 +1861,5 @@
     return result;
 }
 
-void MakeFourCCString(uint32_t x, char *s) {
-    s[0] = x >> 24;
-    s[1] = (x >> 16) & 0xff;
-    s[2] = (x >> 8) & 0xff;
-    s[3] = x & 0xff;
-    s[4] = '\0';
-}
-
 }  // namespace android
 
diff --git a/media/libstagefright/codec2/Android.bp b/media/libstagefright/codec2/Android.bp
new file mode 100644
index 0000000..311a20b
--- /dev/null
+++ b/media/libstagefright/codec2/Android.bp
@@ -0,0 +1,32 @@
+cc_library_shared {
+    name: "libstagefright_codec2",
+
+    tags: [
+        "optional",
+    ],
+
+    srcs: ["C2.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/codec2/include",
+        "frameworks/native/include/media/hardware",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: false, // true,
+        diag: {
+            cfi: false, // true,
+        },
+    },
+
+    ldflags: ["-Wl,-Bsymbolic"],
+}
+
+subdirs = [
+    "tests",
+    "vndk",
+]
diff --git a/media/libstagefright/codec2/Android.mk b/media/libstagefright/codec2/Android.mk
deleted file mode 100644
index ef06ed7..0000000
--- a/media/libstagefright/codec2/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-        C2.cpp    \
-
-LOCAL_C_INCLUDES += \
-        $(TOP)/frameworks/av/media/libstagefright/codec2/include \
-        $(TOP)/frameworks/native/include/media/hardware \
-
-LOCAL_MODULE:= libstagefright_codec2
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CLANG := true
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
-LOCAL_SANITIZE_DIAG := cfi
-
-include $(BUILD_SHARED_LIBRARY)
-
-################################################################################
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codec2/include/C2.h b/media/libstagefright/codec2/include/C2.h
index 7d00a03..01d1341 100644
--- a/media/libstagefright/codec2/include/C2.h
+++ b/media/libstagefright/codec2/include/C2.h
@@ -66,8 +66,8 @@
  * mitigate binary breaks by adhering to the following conventions:
  *
  * - at most one vtable with placeholder virtual methods
- * - all optional/placeholder virtual methods returning a status_t, with C2_NOT_IMPLEMENTED not
- *   requiring any update to input/output arguments.
+ * - all optional/placeholder virtual methods returning a c2_status_t, with C2_OMITTED not requiring
+ *   any update to input/output arguments.
  * - limiting symbol export of inline methods
  * - use of pimpl (or shared-pimpl)
  *
@@ -98,49 +98,62 @@
  * C2String: basic string implementation
  */
 typedef std::string C2String;
+
+/**
+ * C2StringLiteral: basic string literal implementation.
+ * \note these are never owned by any object, and can only refer to C string literals.
+ */
 typedef const char *C2StringLiteral;
 
 /**
- * C2Error: status codes used.
+ * c2_status_t: status codes used.
  */
-typedef int32_t C2Error;
-enum {
+enum c2_status_t : int32_t {
+
+/*
+ * Use android status constants if available. Otherwise, define the android status constants as
+ * additional enum values using POSIX errno constants.
+ */
 #ifndef __ANDROID__
-    OK                  = 0,
+    ALREADY_EXISTS      = -EEXIST,
     BAD_VALUE           = -EINVAL,
     BAD_INDEX           = -EOVERFLOW,
-    UNKNOWN_TRANSACTION = -EBADMSG,
-    ALREADY_EXISTS      = -EEXIST,
-    NAME_NOT_FOUND      = -ENOENT,
+    FAILED_TRANSACTION  = -ENOTSUP,
     INVALID_OPERATION   = -ENOSYS,
+    NAME_NOT_FOUND      = -ENOENT,
     NO_MEMORY           = -ENOMEM,
+    NO_INIT             = -ENODEV,
+    OK                  = 0,
     PERMISSION_DENIED   = -EPERM,
     TIMED_OUT           = -ETIMEDOUT,
-    UNKNOWN_ERROR       = -EINVAL,
+    UNKNOWN_ERROR       = -EFAULT,
+    UNKNOWN_TRANSACTION = -EBADMSG,
 #endif
 
-    C2_OK               = OK,                   ///< operation completed successfully
+    C2_OK        = OK,                   ///< operation completed successfully
 
     // bad input
-    C2_BAD_VALUE        = BAD_VALUE,            ///< argument has invalid value (user error)
-    C2_BAD_INDEX        = BAD_INDEX,            ///< argument uses invalid index (user error)
-    C2_UNSUPPORTED      = UNKNOWN_TRANSACTION,  ///< argument/index is value but not supported \todo is this really BAD_INDEX/VALUE?
+    C2_BAD_VALUE = BAD_VALUE,            ///< argument has invalid value (user error)
+    C2_BAD_INDEX = BAD_INDEX,            ///< argument uses invalid index (user error)
+    C2_CANNOT_DO = FAILED_TRANSACTION,   ///< argument/index is valid but not possible
 
     // bad sequencing of events
-    C2_DUPLICATE        = ALREADY_EXISTS,       ///< object already exists
-    C2_NOT_FOUND        = NAME_NOT_FOUND,       ///< object not found
-    C2_BAD_STATE        = INVALID_OPERATION,    ///< operation is not permitted in the current state
+    C2_DUPLICATE = ALREADY_EXISTS,       ///< object already exists
+    C2_NOT_FOUND = NAME_NOT_FOUND,       ///< object not found
+    C2_BAD_STATE = INVALID_OPERATION,    ///< operation is not permitted in the current state
 
     // bad environment
-    C2_NO_MEMORY        = NO_MEMORY,            ///< not enough memory to complete operation
-    C2_NO_PERMISSION    = PERMISSION_DENIED,    ///< missing permission to complete operation
-    C2_TIMED_OUT        = TIMED_OUT,            ///< operation did not complete within timeout
+    C2_NO_MEMORY = NO_MEMORY,            ///< not enough memory to complete operation
+    C2_REFUSED   = PERMISSION_DENIED,    ///< missing permission to complete operation
+
+    C2_TIMED_OUT = TIMED_OUT,            ///< operation did not complete within timeout
 
     // bad versioning
-    C2_NOT_IMPLEMENTED  = UNKNOWN_TRANSACTION,  ///< operation is not implemented (optional only) \todo for now reuse error code
+    C2_OMITTED   = UNKNOWN_TRANSACTION,  ///< operation is not implemented/supported (optional only)
 
     // unknown fatal
-    C2_CORRUPTED        = UNKNOWN_ERROR,        ///< some unexpected error prevented the operation
+    C2_CORRUPTED = UNKNOWN_ERROR,        ///< some unexpected error prevented the operation
+    C2_NO_INIT   = NO_INIT,              ///< status has not been initialized
 };
 
 /// @}
diff --git a/media/libstagefright/codec2/include/C2Buffer.h b/media/libstagefright/codec2/include/C2Buffer.h
index 9f6b487..d978e42 100644
--- a/media/libstagefright/codec2/include/C2Buffer.h
+++ b/media/libstagefright/codec2/include/C2Buffer.h
@@ -88,10 +88,10 @@
      * \retval C2_TIMED_OUT     the fence has not been signaled within the timeout
      * \retval C2_BAD_STATE     the fence has been abandoned without being signaled (it will never
      *                          be signaled)
-     * \retval C2_NO_PERMISSION no permission to wait for the fence (unexpected - system)
+     * \retval C2_REFUSED       no permission to wait for the fence (unexpected - system)
      * \retval C2_CORRUPTED     some unknown error prevented waiting for the fence (unexpected)
      */
-    C2Error wait(nsecs_t timeoutNs);
+    c2_status_t wait(nsecs_t timeoutNs);
 
     /**
      * Used to check if this fence is valid (if there is a chance for it to be signaled.)
@@ -154,11 +154,11 @@
      *
      * \retval C2_OK            the fence(s) were successfully signaled
      * \retval C2_BAD_STATE     the fence(s) have already been abandoned or merged (caller error)
-     * \retval C2_ALREADY_EXISTS the fence(s) have already been signaled (caller error)
-     * \retval C2_NO_PERMISSION no permission to signal the fence (unexpected - system)
+     * \retval C2_DUPLICATE     the fence(s) have already been signaled (caller error)
+     * \retval C2_REFUSED       no permission to signal the fence (unexpected - system)
      * \retval C2_CORRUPTED     some unknown error prevented signaling the fence(s) (unexpected)
      */
-    C2Error fire();
+    c2_status_t fire();
 
     /**
      * Trigger this event from the merging of the supplied fences. This means that it will be
@@ -167,12 +167,12 @@
      *
      * \retval C2_OK            the merging was successfully done
      * \retval C2_NO_MEMORY     not enough memory to perform the merging
-     * \retval C2_ALREADY_EXISTS    the fence have already been merged (caller error)
+     * \retval C2_DUPLICATE     the fence have already been merged (caller error)
      * \retval C2_BAD_STATE     the fence have already been signaled or abandoned (caller error)
-     * \retval C2_NO_PERMISSION no permission to merge the fence (unexpected - system)
+     * \retval C2_REFUSED       no permission to merge the fence (unexpected - system)
      * \retval C2_CORRUPTED     some unknown error prevented merging the fence(s) (unexpected)
      */
-    C2Error merge(std::vector<C2Fence> fences);
+    c2_status_t merge(std::vector<C2Fence> fences);
 
     /**
      * Abandons the event and any associated fence(s).
@@ -182,11 +182,11 @@
      *
      * \retval C2_OK            the fence(s) were successfully signaled
      * \retval C2_BAD_STATE     the fence(s) have already been signaled or merged (caller error)
-     * \retval C2_ALREADY_EXISTS    the fence(s) have already been abandoned (caller error)
-     * \retval C2_NO_PERMISSION no permission to abandon the fence (unexpected - system)
+     * \retval C2_DUPLICATE     the fence(s) have already been abandoned (caller error)
+     * \retval C2_REFUSED       no permission to abandon the fence (unexpected - system)
      * \retval C2_CORRUPTED     some unknown error prevented signaling the fence(s) (unexpected)
      */
-    C2Error abandon();
+    c2_status_t abandon();
 
 private:
     class Impl;
@@ -197,15 +197,15 @@
 /// @{
 
 /**
- * Interface for objects that encapsulate an updatable error value.
+ * Interface for objects that encapsulate an updatable status value.
  */
-struct _C2InnateError {
-    inline C2Error error() const { return mError; }
+struct _C2InnateStatus {
+    inline c2_status_t status() const { return mStatus; }
 
 protected:
-    _C2InnateError(C2Error error) : mError(error) { }
+    _C2InnateStatus(c2_status_t status) : mStatus(status) { }
 
-    C2Error mError; // this error is updatable by the object
+    c2_status_t mStatus; // this status is updatable by the object
 };
 
 /// @}
@@ -223,13 +223,17 @@
      *
      * \return acquired object potentially invalidated if waiting for the fence failed.
      */
-    T get();
+    T get() {
+        // TODO:
+        // wait();
+        return mT;
+    }
 
 protected:
-    C2Acquirable(C2Error error, C2Fence fence, T t) : C2Fence(fence), mInitialError(error), mT(t) { }
+    C2Acquirable(c2_status_t error, C2Fence fence, T t) : C2Fence(fence), mInitialError(error), mT(t) { }
 
 private:
-    C2Error mInitialError;
+    c2_status_t mInitialError;
     T mT; // TODO: move instead of copy
 };
 
@@ -268,7 +272,7 @@
         : mCapacity(parent == nullptr ? 0 : parent->capacity()) { }
 
 private:
-    const uint32_t mCapacity;
+    uint32_t mCapacity;
 /// @}
 };
 
@@ -429,7 +433,7 @@
     /**
      * \return pointer to the start of the block or nullptr on error.
      */
-    const uint8_t *data();
+    const uint8_t *data() const;
 
     /**
      * Returns a portion of this view.
@@ -445,7 +449,11 @@
     /**
      * \return error during the creation/mapping of this view.
      */
-    C2Error error();
+    c2_status_t error() const;
+
+protected:
+    C2ReadView(const _C2LinearCapacityAspect *parent, const uint8_t *data);
+    explicit C2ReadView(c2_status_t error);
 
 private:
     class Impl;
@@ -474,7 +482,11 @@
     /**
      * \return error during the creation/mapping of this view.
      */
-    C2Error error();
+    c2_status_t error() const;
+
+protected:
+    C2WriteView(const _C2LinearRangeAspect *parent, uint8_t *base);
+    explicit C2WriteView(c2_status_t error);
 
 private:
     class Impl;
@@ -516,7 +528,13 @@
      */
     C2Fence fence() const { return mFence; }
 
+protected:
+    C2ConstLinearBlock(std::shared_ptr<C2LinearAllocation> alloc);
+    C2ConstLinearBlock(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size);
+
 private:
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
     C2Fence mFence;
 };
 
@@ -544,6 +562,14 @@
      *    The block shall be modified only until firing the event for the fence.
      */
     C2ConstLinearBlock share(size_t offset, size_t size, C2Fence fence);
+
+protected:
+    C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc);
+    C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size);
+
+private:
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
 };
 
 /// @}
@@ -605,7 +631,7 @@
      * \retval C2_TIMED_OUT     the reservation timed out \todo when?
      * \retval C2_CORRUPTED     some unknown error prevented reserving space. (unexpected)
      */
-    C2Error reserve(size_t size, C2Fence *fence /* nullable */);
+    c2_status_t reserve(size_t size, C2Fence *fence /* nullable */);
 
     /**
      * Abandons a portion of this segment. This will move to the beginning of this segment.
@@ -618,7 +644,7 @@
      * \retval C2_TIMED_OUT     the operation timed out (unexpected)
      * \retval C2_CORRUPTED     some unknown error prevented abandoning the data (unexpected)
      */
-    C2Error abandon(size_t size);
+    c2_status_t abandon(size_t size);
 
     /**
      * Share a portion as block(s) with consumers (these are moved to the used section).
@@ -635,7 +661,7 @@
      * \retval C2_TIMED_OUT     the operation timed out (unexpected)
      * \retval C2_CORRUPTED     some unknown error prevented sharing the data (unexpected)
      */
-    C2Error share(size_t size, C2Fence fence, std::list<C2ConstLinearBlock> &blocks);
+    c2_status_t share(size_t size, C2Fence fence, std::list<C2ConstLinearBlock> &blocks);
 
     /**
      * Returns the beginning offset of this segment from the start of this circular block.
@@ -669,7 +695,7 @@
     /**
      * \return error during the creation/mapping of this view.
      */
-    C2Error error();
+    c2_status_t error() const;
 };
 
 /**
@@ -690,7 +716,7 @@
      * \param size    number of bytes to commit to the next segment
      * \param fence   fence used for the commit (the fence must signal before the data is committed)
      */
-    C2Error commit(size_t size, C2Fence fence);
+    c2_status_t commit(size_t size, C2Fence fence);
 
     /**
      * Maps this block into memory and returns a write view for it.
@@ -741,10 +767,10 @@
     uint32_t mWidth;
     uint32_t mHeight;
 
-    inline C2Rect(uint32_t width, uint32_t height)
+    constexpr inline C2Rect(uint32_t width, uint32_t height)
         : C2Rect(width, height, 0, 0) { }
 
-    inline C2Rect(uint32_t width, uint32_t height, uint32_t left, uint32_t top)
+    constexpr inline C2Rect(uint32_t width, uint32_t height, uint32_t left, uint32_t top)
         : mLeft(left), mTop(top), mWidth(width), mHeight(height) { }
 
     // utility methods
@@ -895,29 +921,51 @@
 public:
     // crop can be an empty rect, does not have to line up with subsampling
     // NOTE: we do not support floating-point crop
-    inline const C2Rect crop() { return mCrop; }
+    inline const C2Rect crop() const { return mCrop; }
 
     /**
      *  Sets crop to crop intersected with [(0,0) .. (width, height)]
      */
-    inline void setCrop_be(const C2Rect &crop);
+    inline void setCrop_be(const C2Rect &crop) {
+        mCrop.mLeft = std::min(width(), crop.mLeft);
+        mCrop.mTop = std::min(height(), crop.mTop);
+        // It's guaranteed that mCrop.mLeft <= width() && mCrop.mTop <= height()
+        mCrop.mWidth = std::min(width() - mCrop.mLeft, crop.mWidth);
+        mCrop.mHeight = std::min(height() - mCrop.mTop, crop.mHeight);
+    }
 
     /**
      * If crop is within the dimensions of this object, it sets crop to it.
      *
      * \return true iff crop is within the dimensions of this object
      */
-    inline bool setCrop(const C2Rect &crop);
+    inline bool setCrop(const C2Rect &crop) {
+        if (width() < crop.mWidth || height() < crop.mHeight
+                || width() - crop.mWidth < crop.mLeft || height() - crop.mHeight < crop.mTop) {
+            return false;
+        }
+        mCrop = crop;
+        return true;
+    }
+
+protected:
+    inline _C2PlanarSection(const _C2PlanarCapacityAspect *parent)
+        : _C2PlanarCapacityAspect(parent), mCrop(width(), height()) {}
 
 private:
     C2Rect mCrop;
 /// @}
 };
 
+class C2GraphicAllocation;
+
 class C2Block2D : public _C2PlanarSection {
 public:
     const C2Handle *handle() const;
 
+protected:
+    C2Block2D(const std::shared_ptr<C2GraphicAllocation> &alloc);
+
 private:
     class Impl;
     std::shared_ptr<Impl> mImpl;
@@ -935,14 +983,25 @@
 class C2GraphicView : public _C2PlanarSection {
 public:
     /**
-     * \return pointer to the start of the block or nullptr on error.
+     * \return array of pointers to the start of the planes or nullptr on error.
+     * Regardless of crop rect, they always point to the top-left corner of
+     * each plane.  Access outside of the crop rect results in an undefined
+     * behavior.
      */
-    const uint8_t *data() const;
+    const uint8_t *const *data() const;
 
     /**
-     * \return pointer to the start of the block or nullptr on error.
+     * \return array of pointers to the start of the planes or nullptr on error.
+     * Regardless of crop rect, they always point to the top-left corner of
+     * each plane.  Access outside of the crop rect results in an undefined
+     * behavior.
      */
-    uint8_t *data();
+    uint8_t *const *data();
+
+    /**
+     * \return layout of the graphic block to interpret the returned data.
+     */
+    const C2PlaneLayout layout() const;
 
     /**
      * Returns a section of this view.
@@ -957,7 +1016,14 @@
     /**
      * \return error during the creation/mapping of this view.
      */
-    C2Error error() const;
+    c2_status_t error() const;
+
+protected:
+    C2GraphicView(
+            const _C2PlanarCapacityAspect *parent,
+            uint8_t *const *data,
+            const C2PlaneLayout& layout);
+    explicit C2GraphicView(c2_status_t error);
 
 private:
     class Impl;
@@ -996,7 +1062,12 @@
      */
     C2Fence fence() const { return mFence; }
 
+protected:
+    C2ConstGraphicBlock(const std::shared_ptr<C2GraphicAllocation> &alloc, C2Fence fence);
+
 private:
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
     C2Fence mFence;
 };
 
@@ -1024,6 +1095,13 @@
      *    The block shall be modified only until firing the event for the fence.
      */
     C2ConstGraphicBlock share(const C2Rect &crop, C2Fence fence);
+
+protected:
+    explicit C2GraphicBlock(const std::shared_ptr<C2GraphicAllocation> &alloc);
+
+private:
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
 };
 
 /// @}
@@ -1089,7 +1167,8 @@
 
 protected:
     // no public constructor
-    // C2BufferData(const std::shared_ptr<const Impl> &impl) : mImpl(impl) {}
+    explicit C2BufferData(const std::list<C2ConstLinearBlock> &blocks);
+    explicit C2BufferData(const std::list<C2ConstGraphicBlock> &blocks);
 };
 
 /**
@@ -1145,7 +1224,7 @@
      * \retval C2_NO_MEMORY not enough memory to register for this callback
      * \retval C2_CORRUPTED an unknown error prevented the registration (unexpected)
      */
-    C2Error registerOnDestroyNotify(OnDestroyNotify *onDestroyNotify, void *arg = nullptr);
+    c2_status_t registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg = nullptr);
 
     /**
      * Unregisters a previously registered pre-destroy notification.
@@ -1157,7 +1236,7 @@
      * \retval C2_NOT_FOUND the notification was not found
      * \retval C2_CORRUPTED an unknown error prevented the registration (unexpected)
      */
-    C2Error unregisterOnDestroyNotify(OnDestroyNotify *onDestroyNotify, void *arg = nullptr);
+    c2_status_t unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg = nullptr);
 
     ///@}
 
@@ -1183,7 +1262,7 @@
      * \retval C2_NO_MEMORY not enough memory to attach the metadata (this return value is not
      *                      used if the same kind of metadata is already attached to the buffer).
      */
-    C2Error setInfo(const std::shared_ptr<C2Info> &info);
+    c2_status_t setInfo(const std::shared_ptr<C2Info> &info);
 
     /**
      * Checks if there is a certain type of metadata attached to this buffer.
@@ -1193,14 +1272,17 @@
      * \return true iff there is a metadata with the parameter type attached to this buffer.
      */
     bool hasInfo(C2Param::Type index) const;
-    std::shared_ptr<C2Info> removeInfo(C2Param::Type index) const;
+    std::shared_ptr<C2Info> removeInfo(C2Param::Type index);
     ///@}
 
 protected:
     // no public constructor
-    inline C2Buffer() = default;
+    explicit C2Buffer(const std::list<C2ConstLinearBlock> &blocks);
+    explicit C2Buffer(const std::list<C2ConstGraphicBlock> &blocks);
 
 private:
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
 //    Type _mType;
 };
 
@@ -1295,14 +1377,15 @@
      * \todo Do we need to support sync operation as we could just wait for the fence?
      *
      * \retval C2_OK        the operation was successful
-     * \retval C2_NO_PERMISSION no permission to map the portion
+     * \retval C2_REFUSED   no permission to map the portion
      * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_DUPLICATE if the allocation is already mapped.
      * \retval C2_NO_MEMORY not enough memory to complete the operation
      * \retval C2_BAD_VALUE the parameters (offset/size) are invalid or outside the allocation, or
      *                      the usage flags are invalid (caller error)
      * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
      */
-    virtual C2Error map(
+    virtual c2_status_t map(
             size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd /* nullable */,
             void **addr /* nonnull */) = 0;
 
@@ -1320,12 +1403,13 @@
      *
      * \retval C2_OK        the operation was successful
      * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_NOT_FOUND if the allocation was not mapped previously.
      * \retval C2_BAD_VALUE the parameters (addr/size) do not correspond to previously mapped
      *                      regions (caller error)
      * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
-     * \retval C2_NO_PERMISSION no permission to unmap the portion (unexpected - system)
+     * \retval C2_REFUSED   no permission to unmap the portion (unexpected - system)
      */
-    virtual C2Error unmap(void *addr, size_t size, int *fenceFd /* nullable */) = 0;
+    virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd /* nullable */) = 0;
 
     /**
      * Returns true if this is a valid allocation.
@@ -1379,8 +1463,8 @@
      * \todo Do we need to support sync operation as we could just wait for the fence?
      *
      * \retval C2_OK        the operation was successful
-     * \retval C2_NO_PERMISSION no permission to map the section
-     * \retval C2_ALREADY_EXISTS there is already a mapped region (caller error)
+     * \retval C2_REFUSED   no permission to map the section
+     * \retval C2_DUPLICATE there is already a mapped region (caller error)
      * \retval C2_TIMED_OUT the operation timed out
      * \retval C2_NO_MEMORY not enough memory to complete the operation
      * \retval C2_BAD_VALUE the parameters (rect) are invalid or outside the allocation, or the
@@ -1388,7 +1472,7 @@
      * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
 
      */
-    virtual C2Error map(
+    virtual c2_status_t map(
             C2Rect rect, C2MemoryUsage usage, int *fenceFd,
             // TODO: return <addr, size> buffers with plane sizes
             C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
@@ -1406,9 +1490,9 @@
      * \retval C2_TIMED_OUT the operation timed out
      * \retval C2_NOT_FOUND there is no mapped region (caller error)
      * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
-     * \retval C2_NO_PERMISSION no permission to unmap the section (unexpected - system)
+     * \retval C2_REFUSED   no permission to unmap the section (unexpected - system)
      */
-    virtual C2Error unmap(C2Fence *fenceFd /* nullable */) = 0;
+    virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) = 0;
 
     /**
      * Returns true if this is a valid allocation.
@@ -1425,10 +1509,11 @@
     /**
      * Returns true if this is the same allocation as |other|.
      */
-    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) = 0;
+    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const = 0;
 
 protected:
-    virtual ~C2GraphicAllocation();
+    using _C2PlanarCapacityAspect::_C2PlanarCapacityAspect;
+    virtual ~C2GraphicAllocation() = default;
 };
 
 /**
@@ -1444,32 +1529,90 @@
 class C2Allocator {
 public:
     /**
+     * Allocator ID type.
+     */
+    typedef uint32_t id_t;
+
+    /**
+     * Allocation types. This is a bitmask and is used in C2Allocator::Info
+     * to list the supported allocation types of an allocator.
+     */
+    enum type_t : uint32_t {
+        LINEAR  = 1 << 0, //
+        GRAPHIC = 1 << 1,
+    };
+
+    /**
+     * Information about an allocator.
+     *
+     * Allocators don't have a query API so all queriable information is stored here.
+     */
+    struct Traits {
+        C2String name;              ///< allocator name
+        id_t id;                    ///< allocator ID
+        type_t supportedTypes;      ///< supported allocation types
+        C2MemoryUsage minimumUsage; ///< usage that is minimally required for allocations
+        C2MemoryUsage maximumUsage; ///< usage that is maximally allowed for allocations
+    };
+
+    /**
+     * Returns the unique name of this allocator.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the name of this allocator.
+     * \retval an empty string if there was not enough memory to allocate the actual name.
+     */
+    virtual C2String getName() const = 0;
+
+    /**
+     * Returns a unique ID for this allocator. This ID is used to get this allocator from the
+     * allocator store, and to identify this allocator across all processes.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return a unique ID for this allocator.
+     */
+    virtual id_t getId() const = 0;
+
+    /**
+     * Returns the allocator traits.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * Allocators don't have a full-fledged query API, only this method.
+     *
+     * \return allocator information
+     */
+    virtual std::shared_ptr<const Traits> getTraits() const = 0;
+
+    /**
      * Allocates a 1D allocation of given |capacity| and |usage|. If successful, the allocation is
      * stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
      *
-     * \param capacity        the size of requested allocation (the allocation could be slightly
+     * \param capacity      the size of requested allocation (the allocation could be slightly
      *                      larger, e.g. to account for any system-required alignment)
-     * \param usage           the memory usage info for the requested allocation. \note that the
+     * \param usage         the memory usage info for the requested allocation. \note that the
      *                      returned allocation may be later used/mapped with different usage.
      *                      The allocator should layout the buffer to be optimized for this usage,
      *                      but must support any usage. One exception: protected buffers can
      *                      only be used in a protected scenario.
-     * \param allocation      pointer to where the allocation shall be stored on success. nullptr
+     * \param allocation    pointer to where the allocation shall be stored on success. nullptr
      *                      will be stored here on failure
      *
      * \retval C2_OK        the allocation was successful
      * \retval C2_NO_MEMORY not enough memory to complete the allocation
      * \retval C2_TIMED_OUT the allocation timed out
-     * \retval C2_NO_PERMISSION     no permission to complete the allocation
+     * \retval C2_REFUSED   no permission to complete the allocation
      * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
-     * \retval C2_UNSUPPORTED       this allocator does not support 1D allocations
+     * \retval C2_OMITTED   this allocator does not support 1D allocations
      * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
      */
-    virtual C2Error allocateLinearBuffer(
+    virtual c2_status_t newLinearAllocation(
             uint32_t capacity __unused, C2MemoryUsage usage __unused,
             std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
         *allocation = nullptr;
-        return C2_UNSUPPORTED;
+        return C2_OMITTED;
     }
 
     /**
@@ -1478,55 +1621,55 @@
      *
      * \param handle      the handle for the existing allocation
      * \param allocation  pointer to where the allocation shall be stored on success. nullptr
-     *                  will be stored here on failure
+     *                    will be stored here on failure
      *
      * \retval C2_OK        the allocation was recreated successfully
      * \retval C2_NO_MEMORY not enough memory to recreate the allocation
      * \retval C2_TIMED_OUT the recreation timed out (unexpected)
-     * \retval C2_NO_PERMISSION     no permission to recreate the allocation
+     * \retval C2_REFUSED   no permission to recreate the allocation
      * \retval C2_BAD_VALUE invalid handle (caller error)
-     * \retval C2_UNSUPPORTED       this allocator does not support 1D allocations
+     * \retval C2_OMITTED   this allocator does not support 1D allocations
      * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
      */
-    virtual C2Error recreateLinearBuffer(
+    virtual c2_status_t priorLinearAllocation(
             const C2Handle *handle __unused,
             std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
         *allocation = nullptr;
-        return C2_UNSUPPORTED;
+        return C2_OMITTED;
     }
 
     /**
      * Allocates a 2D allocation of given |width|, |height|, |format| and |usage|. If successful,
      * the allocation is stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
      *
-     * \param width           the width of requested allocation (the allocation could be slightly
+     * \param width         the width of requested allocation (the allocation could be slightly
      *                      larger, e.g. to account for any system-required alignment)
-     * \param height          the height of requested allocation (the allocation could be slightly
+     * \param height        the height of requested allocation (the allocation could be slightly
      *                      larger, e.g. to account for any system-required alignment)
-     * \param format          the pixel format of requested allocation. This could be a vendor
+     * \param format        the pixel format of requested allocation. This could be a vendor
      *                      specific format.
-     * \param usage           the memory usage info for the requested allocation. \note that the
+     * \param usage         the memory usage info for the requested allocation. \note that the
      *                      returned allocation may be later used/mapped with different usage.
      *                      The allocator should layout the buffer to be optimized for this usage,
      *                      but must support any usage. One exception: protected buffers can
      *                      only be used in a protected scenario.
-     * \param allocation      pointer to where the allocation shall be stored on success. nullptr
+     * \param allocation    pointer to where the allocation shall be stored on success. nullptr
      *                      will be stored here on failure
      *
      * \retval C2_OK        the allocation was successful
      * \retval C2_NO_MEMORY not enough memory to complete the allocation
      * \retval C2_TIMED_OUT the allocation timed out
-     * \retval C2_NO_PERMISSION     no permission to complete the allocation
+     * \retval C2_REFUSED   no permission to complete the allocation
      * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error)
-     * \retval C2_UNSUPPORTED       this allocator does not support 2D allocations
+     * \retval C2_OMITTED   this allocator does not support 2D allocations
      * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
      */
-    virtual C2Error allocateGraphicBuffer(
+    virtual c2_status_t newGraphicAllocation(
             uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
             C2MemoryUsage usage __unused,
             std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
         *allocation = nullptr;
-        return C2_UNSUPPORTED;
+        return C2_OMITTED;
     }
 
     /**
@@ -1535,21 +1678,21 @@
      *
      * \param handle      the handle for the existing allocation
      * \param allocation  pointer to where the allocation shall be stored on success. nullptr
-     *                  will be stored here on failure
+     *                    will be stored here on failure
      *
      * \retval C2_OK        the allocation was recreated successfully
      * \retval C2_NO_MEMORY not enough memory to recreate the allocation
      * \retval C2_TIMED_OUT the recreation timed out (unexpected)
-     * \retval C2_NO_PERMISSION     no permission to recreate the allocation
+     * \retval C2_REFUSED   no permission to recreate the allocation
      * \retval C2_BAD_VALUE invalid handle (caller error)
-     * \retval C2_UNSUPPORTED       this allocator does not support 2D allocations
+     * \retval C2_OMITTED   this allocator does not support 2D allocations
      * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected)
      */
-    virtual C2Error recreateGraphicBuffer(
+    virtual c2_status_t priorGraphicAllocation(
             const C2Handle *handle __unused,
             std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
         *allocation = nullptr;
-        return C2_UNSUPPORTED;
+        return C2_OMITTED;
     }
 
 protected:
@@ -1559,110 +1702,143 @@
 };
 
 /**
- *  Block allocators are used by components to allocate memory for output buffers. They can
- *  support either linear (1D), circular (1D) or graphic (2D) allocations.
+ *  Block pools are used by components to obtain output buffers in an efficient way. They can
+ *  support either linear (1D), circular (1D) or graphic (2D) blocks.
+ *
+ *  Block pools decouple the recycling of memory/allocations from the components. They are meant to
+ *  be an opaque service (there are no public APIs other than obtaining blocks) provided by the
+ *  platform. Block pools are also meant to decouple allocations from memory used by buffers. This
+ *  is accomplished by allowing pools to allot multiple memory 'blocks' on a single allocation. As
+ *  their name suggest, block pools maintain a pool of memory blocks. When a component asks for
+ *  a memory block, pools will try to return a free memory block already in the pool. If no such
+ *  block exists, they will allocate memory using the backing allocator and allot a block on that
+ *  allocation. When blocks are no longer used in the system, they are recycled back to the block
+ *  pool and are available as free blocks.
  *
  *  Never constructed on stack.
- *
- *  Block allocators are provided by the framework.
  */
-class C2BlockAllocator {
+class C2BlockPool {
 public:
     /**
-     * Allocates a linear writeable block of given |capacity| and |usage|. If successful, the
+     * Block pool ID type.
+     */
+    typedef uint64_t local_id_t;
+
+    enum : local_id_t {
+        BASIC_LINEAR = 0,  ///< ID of basic (unoptimized) block pool for fetching 1D blocks
+        BASIC_GRAPHIC = 1, ///< ID of basic (unoptimized) block pool for fetching 2D blocks
+        PLATFORM_START = 0x10,
+    };
+
+    /**
+     * Returns the ID for this block pool. This ID is used to get this block pool from the platform.
+     * It is only valid in the current process.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return a local ID for this block pool.
+     */
+    virtual local_id_t getLocalId() const = 0;
+
+    /**
+     * Returns the ID of the backing allocator of this block pool.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the ID of the backing allocator of this block pool.
+     */
+    virtual C2Allocator::id_t getAllocatorId() const = 0;
+
+    /**
+     * Obtains a linear writeable block of given |capacity| and |usage|. If successful, the
      * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
      *
-     * \param capacity        the size of requested block.
-     * \param usage           the memory usage info for the requested allocation. \note that the
-     *                      returned allocation may be later used/mapped with different usage.
-     *                      The allocator shall lay out the buffer to be optimized for this usage,
-     *                      but must support any usage. One exception: protected buffers can
-     *                      only be used in a protected scenario.
-     * \param block      pointer to where the allocated block shall be stored on success. nullptr
-     *                      will be stored here on failure
+     * \param capacity the size of requested block.
+     * \param usage    the memory usage info for the requested block. Returned blocks will be
+     *                 optimized for this usage, but may be used with any usage. One exception:
+     *                 protected blocks/buffers can only be used in a protected scenario.
+     * \param block    pointer to where the obtained block shall be stored on success. nullptr will
+     *                 be stored here on failure
      *
-     * \retval C2_OK        the allocation was successful
-     * \retval C2_NO_MEMORY not enough memory to complete the allocation
-     * \retval C2_TIMED_OUT the allocation timed out
-     * \retval C2_NO_PERMISSION     no permission to complete the allocation
+     * \retval C2_OK        the operation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_REFUSED   no permission to complete any required allocation
      * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
-     * \retval C2_UNSUPPORTED       this allocator does not support linear allocations
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+     * \retval C2_OMITTED   this pool does not support linear blocks
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
      */
-    virtual C2Error allocateLinearBlock(
+    virtual c2_status_t fetchLinearBlock(
             uint32_t capacity __unused, C2MemoryUsage usage __unused,
             std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
         *block = nullptr;
-        return C2_UNSUPPORTED;
+        return C2_OMITTED;
     }
 
     /**
-     * Allocates a circular writeable block of given |capacity| and |usage|. If successful, the
+     * Obtains a circular writeable block of given |capacity| and |usage|. If successful, the
      * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
      *
-     * \param capacity        the size of requested circular block. (the allocation could be slightly
-     *                      larger, e.g. to account for any system-required alignment)
-     * \param usage           the memory usage info for the requested allocation. \note that the
-     *                      returned allocation may be later used/mapped with different usage.
-     *                      The allocator shall lay out the buffer to be optimized for this usage,
-     *                      but must support any usage. One exception: protected buffers can
-     *                      only be used in a protected scenario.
-     * \param block      pointer to where the allocated block shall be stored on success. nullptr
-     *                      will be stored here on failure
+     * \param capacity the size of requested circular block. (note: the size of the obtained
+     *                 block could be slightly larger, e.g. to accommodate any system-required
+     *                 alignment)
+     * \param usage    the memory usage info for the requested block. Returned blocks will be
+     *                 optimized for this usage, but may be used with any usage. One exception:
+     *                 protected blocks/buffers can only be used in a protected scenario.
+     * \param block    pointer to where the obtained block shall be stored on success. nullptr
+     *                 will be stored here on failure
      *
-     * \retval C2_OK            the allocation was successful
-     * \retval C2_NO_MEMORY     not enough memory to complete the allocation
-     * \retval C2_TIMED_OUT     the allocation timed out
-     * \retval C2_NO_PERMISSION     no permission to complete the allocation
-     * \retval C2_BAD_VALUE     capacity or usage are not supported (invalid) (caller error)
-     * \retval C2_UNSUPPORTED   this allocator does not support circular allocations
-     * \retval C2_CORRUPTED     some unknown, unrecoverable error occured during allocation (unexpected)
+     * \retval C2_OK        the operation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_REFUSED   no permission to complete any required allocation
+     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this pool does not support circular blocks
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
      */
-    virtual C2Error allocateCircularBlock(
+    virtual c2_status_t fetchCircularBlock(
             uint32_t capacity __unused, C2MemoryUsage usage __unused,
             std::shared_ptr<C2CircularBlock> *block /* nonnull */) {
         *block = nullptr;
-        return C2_UNSUPPORTED;
+        return C2_OMITTED;
     }
 
     /**
-     * Allocates a 2D graphic block of given |width|, |height|, |format| and |usage|. If successful,
-     * the allocation is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+     * Obtains a 2D graphic block of given |width|, |height|, |format| and |usage|. If successful,
+     * the block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
      *
-     * \param width           the width of requested allocation (the allocation could be slightly
-     *                      larger, e.g. to account for any system-required alignment)
-     * \param height          the height of requested allocation (the allocation could be slightly
-     *                      larger, e.g. to account for any system-required alignment)
-     * \param format          the pixel format of requested allocation. This could be a vendor
-     *                      specific format.
-     * \param usage           the memory usage info for the requested allocation. \note that the
-     *                      returned allocation may be later used/mapped with different usage.
-     *                      The allocator should layout the buffer to be optimized for this usage,
-     *                      but must support any usage. One exception: protected buffers can
-     *                      only be used in a protected scenario.
-     * \param block      pointer to where the allocation shall be stored on success. nullptr
-     *                      will be stored here on failure
+     * \param width  the width of requested block (the obtained block could be slightly larger, e.g.
+     *               to accommodate any system-required alignment)
+     * \param height the height of requested block (the obtained block could be slightly larger,
+     *               e.g. to accommodate any system-required alignment)
+     * \param format the pixel format of requested block. This could be a vendor specific format.
+     * \param usage  the memory usage info for the requested block. Returned blocks will be
+     *               optimized for this usage, but may be used with any usage. One exception:
+     *               protected blocks/buffers can only be used in a protected scenario.
+     * \param block  pointer to where the obtained block shall be stored on success. nullptr
+     *               will be stored here on failure
      *
-     * \retval C2_OK            the allocation was successful
-     * \retval C2_NO_MEMORY     not enough memory to complete the allocation
-     * \retval C2_TIMED_OUT     the allocation timed out
-     * \retval C2_NO_PERMISSION     no permission to complete the allocation
-     * \retval C2_BAD_VALUE     width, height, format or usage are not supported (invalid) (caller error)
-     * \retval C2_UNSUPPORTED   this allocator does not support 2D allocations
-     * \retval C2_CORRUPTED     some unknown, unrecoverable error occured during allocation (unexpected)
+     * \retval C2_OK        the operation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_REFUSED   no permission to complete any required allocation
+     * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller
+     *                      error)
+     * \retval C2_OMITTED   this pool does not support 2D blocks
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
      */
-    virtual C2Error allocateGraphicBlock(
+    virtual c2_status_t fetchGraphicBlock(
             uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
             C2MemoryUsage usage __unused,
             std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
         *block = nullptr;
-        return C2_UNSUPPORTED;
+        return C2_OMITTED;
     }
 
 protected:
-    C2BlockAllocator() = default;
+    C2BlockPool() = default;
 
-    virtual ~C2BlockAllocator() = default;
+    virtual ~C2BlockPool() = default;
 };
 
 /// @}
diff --git a/media/libstagefright/codec2/include/C2Component.h b/media/libstagefright/codec2/include/C2Component.h
index 1ee9302..2dbf7ea 100644
--- a/media/libstagefright/codec2/include/C2Component.h
+++ b/media/libstagefright/codec2/include/C2Component.h
@@ -36,23 +36,29 @@
 
 class C2Component;
 
-class C2ComponentListener {
-public:
-    virtual void onWorkDone(std::weak_ptr<C2Component> component,
-                            std::vector<std::unique_ptr<C2Work>> workItems) = 0;
+struct C2FieldSupportedValuesQuery {
+    enum Type : uint32_t {
+        POSSIBLE, ///< query all possible values regardless of other settings
+        CURRENT,  ///< query currently possible values given dependent settings
+    };
 
-    virtual void onTripped(std::weak_ptr<C2Component> component,
-                           std::vector<std::shared_ptr<C2SettingResult>> settingResult) = 0;
+    const C2ParamField field;
+    const Type type;
+    c2_status_t status;
+    C2FieldSupportedValues values;
 
-    virtual void onError(std::weak_ptr<C2Component> component,
-                         uint32_t errorCode) = 0;
+    C2FieldSupportedValuesQuery(const C2ParamField &field_, Type type_)
+        : field(field_), type(type_), status(C2_NO_INIT) { }
 
-    // virtual void onTunnelReleased(<from>, <to>) = 0;
+    static C2FieldSupportedValuesQuery&&
+    Current(const C2ParamField &field_) {
+        return std::move(C2FieldSupportedValuesQuery(field_, CURRENT));
+    }
 
-    // virtual void onComponentReleased(<id>) = 0;
-
-protected:
-    virtual ~C2ComponentListener();
+    static C2FieldSupportedValuesQuery&&
+    Possible(const C2ParamField &field_) {
+        return std::move(C2FieldSupportedValuesQuery(field_, POSSIBLE));
+    }
 };
 
 /**
@@ -93,7 +99,7 @@
      *
      * \return a unique node ID for this component or component interface instance.
      */
-    virtual node_id getId() const = 0;
+    virtual c2_node_id_t getId() const = 0;
 
     /**
      * Queries a set of parameters from the component or interface object.
@@ -129,7 +135,7 @@
      * \retval C2_CORRUPTED some unknown error prevented the querying of the parameters
      *                      (unexpected)
      */
-    virtual status_t query_nb(
+    virtual c2_status_t query_nb(
         const std::vector<C2Param* const> &stackParams,
         const std::vector<C2Param::Index> &heapParamIndices,
         std::vector<std::unique_ptr<C2Param>>* const heapParams) const = 0;
@@ -166,7 +172,7 @@
      * \retval C2_CORRUPTED some unknown error prevented the update of the parameters
      *                      (unexpected)
      */
-    virtual status_t config_nb(
+    virtual c2_status_t config_nb(
             const std::vector<C2Param* const> &params,
             std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
 
@@ -205,7 +211,7 @@
      * \retval C2_CORRUPTED some unknown error prevented the update of the parameters
      *                      (unexpected)
      */
-    virtual status_t commit_sm(
+    virtual c2_status_t commit_sm(
             const std::vector<C2Param* const> &params,
             std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
 
@@ -224,13 +230,14 @@
      *
      * \retval C2_OK        the tunnel was successfully created
      * \retval C2_BAD_INDEX the target component does not exist
-     * \retval C2_ALREADY_EXIST the tunnel already exists
-     * \retval C2_UNSUPPORTED  the tunnel is not supported
+     * \retval C2_DUPLICATE the tunnel already exists
+     * \retval C2_OMITTED   tunneling is not supported by this component
+     * \retval C2_CANNOT_DO the specific tunnel is not supported
      *
      * \retval C2_TIMED_OUT could not create the tunnel within the time limit (unexpected)
      * \retval C2_CORRUPTED some unknown error prevented the creation of the tunnel (unexpected)
      */
-    virtual status_t createTunnel_sm(node_id targetComponent) = 0;
+    virtual c2_status_t createTunnel_sm(c2_node_id_t targetComponent) = 0;
 
     /**
      * Releases a tunnel from this component to the target component.
@@ -246,50 +253,122 @@
      * \retval C2_OK        the tunnel was marked for release successfully
      * \retval C2_BAD_INDEX the target component does not exist
      * \retval C2_NOT_FOUND the tunnel does not exist
+     * \retval C2_OMITTED   tunneling is not supported by this component
      *
      * \retval C2_TIMED_OUT could not mark the tunnel for release within the time limit (unexpected)
      * \retval C2_CORRUPTED some unknown error prevented the release of the tunnel (unexpected)
      */
-    virtual status_t releaseTunnel_sm(node_id targetComponent) = 0;
-
+    virtual c2_status_t releaseTunnel_sm(c2_node_id_t targetComponent) = 0;
 
     // REFLECTION MECHANISM (USED FOR EXTENSION)
     // =============================================================================================
 
     /**
-     * Returns the parameter reflector.
-     *
-     * This is used to describe parameter fields.
-     *
-     * \return a shared parameter reflector object.
-     */
-    virtual std::shared_ptr<C2ParamReflector> getParamReflector() const = 0;
-
-    /**
      * Returns the set of supported parameters.
      *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
      * \param[out] params a vector of supported parameters will be appended to this vector.
      *
      * \retval C2_OK        the operation completed successfully.
      * \retval C2_NO_MEMORY not enough memory to complete this method.
      */
-    virtual status_t getSupportedParams(
+    virtual c2_status_t querySupportedParams_nb(
             std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const = 0;
 
     /**
+     * Retrieves the supported values for the queried fields.
      *
-     * \todo should this take a list considering that setting some fields may further limit other
-     * fields in the same list?
+     * Client SHALL set the parameter-field specifier and the type of supported values query (e.g.
+     * currently supported values, or potential supported values) in fields.
+     * Upon return the component SHALL fill in the supported values for the fields listed as well
+     * as a status for each field. Component shall process all fields queried even if some queries
+     * fail.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \param[in out] fields a vector of fields descriptor structures.
+     *
+     * \retval C2_OK        the operation completed successfully.
+     * \retval C2_BAD_INDEX at least one field was not recognized as a component field
      */
-    virtual status_t getSupportedValues(
-            const std::vector<const C2ParamField> fields,
-            std::vector<C2FieldSupportedValues>* const values) const = 0;
+    virtual c2_status_t querySupportedValues_nb(
+            std::vector<C2FieldSupportedValuesQuery> &fields) const = 0;
 
     virtual ~C2ComponentInterface() = default;
 };
 
 class C2Component {
 public:
+    class Listener {
+    public:
+        virtual void onWorkDone_nb(std::weak_ptr<C2Component> component,
+                                std::vector<std::unique_ptr<C2Work>> workItems) = 0;
+
+        virtual void onTripped_nb(std::weak_ptr<C2Component> component,
+                               std::vector<std::shared_ptr<C2SettingResult>> settingResult) = 0;
+
+        virtual void onError_nb(std::weak_ptr<C2Component> component,
+                             uint32_t errorCode) = 0;
+
+        // virtual void onTunnelReleased(<from>, <to>) = 0;
+
+        // virtual void onComponentReleased(<id>) = 0;
+
+    protected:
+        virtual ~Listener() = default;
+    };
+
+    /**
+     * Sets the listener for this component
+     *
+     * This method MUST be supported in all states. The listener can only be set to non-null value
+     * in non-running state (that does not include tripped or error). It can be set to nullptr in
+     * any state. Components only use the listener in running state.
+     *
+     * If listener is nullptr, the component SHALL guarantee that no more listener callbacks are
+     * done to the original listener once this method returns. (Any pending listener callbacks will
+     * need to be completed during this call - hence this call may be temporarily blocking.)
+     *
+     * This method may be momentarily blocking, but must return within 5ms.
+     *
+     * Component SHALL handle listener notifications from the same thread (the thread used is
+     * at the component's discretion.)
+     *
+     * \note This could also be accomplished by passing a weak_ptr to a component-specific listener
+     * here and requiring the client to always promote the weak_ptr before any callback. This would
+     * put the burden on the client to clear the listener - wait for its deletion - at which point
+     * it is guaranteed that no more listener callbacks will occur.
+     *
+     * \todo TBD is this needed? or move it to createComponent()
+     *
+     * \param listener the component listener object
+     *
+     * \retval C2_BAD_STATE attempting to change the listener in the running state (user error)
+     * \retval C2_OK        listener was updated successfully.
+     */
+    virtual c2_status_t setListener_sm(const std::shared_ptr<Listener> &listener) = 0;
+
+    /**
+     * Information about a component.
+     */
+    struct Traits {
+    // public:
+    // TBD
+    #if 0
+        C2String name;             ///< name of the component
+        C2DomainKind domain;       ///< component domain (e.g. audio or video)
+        C2ComponentKind type;      ///< component type (e.g. encoder, decoder or filter)
+        C2StringLiteral mediaType; ///< media type supported by the component
+
+        /**
+         * name alias(es) for backward compatibility.
+         * \note Multiple components can have the same alias as long as their media-type differs.
+         */
+        std::vector<C2StringLiteral> aliases; ///< name aliases for backward compatibility
+    #endif
+    };
+
     // METHODS AVAILABLE WHEN RUNNING
     // =============================================================================================
 
@@ -305,12 +384,12 @@
      *
      * \retval C2_OK        the work was successfully queued
      * \retval C2_BAD_INDEX some component(s) in the work do(es) not exist
-     * \retval C2_UNSUPPORTED  the components are not tunneled
+     * \retval C2_CANNOT_DO the components are not tunneled
      *
      * \retval C2_NO_MEMORY not enough memory to queue the work
      * \retval C2_CORRUPTED some unknown error prevented queuing the work (unexpected)
      */
-    virtual status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) = 0;
+    virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) = 0;
 
     /**
      * Announces a work to be queued later for the component. This reserves a slot for the queue
@@ -322,14 +401,23 @@
      *
      * \retval C2_OK        the work announcement has been successfully recorded
      * \retval C2_BAD_INDEX some component(s) in the work outline do(es) not exist
-     * \retval C2_UNSUPPORTED  the componentes are not tunneled
+     * \retval C2_CANNOT_DO the componentes are not tunneled
      *
      * \retval C2_NO_MEMORY not enough memory to record the work announcement
      * \retval C2_CORRUPTED some unknown error prevented recording the announcement (unexpected)
      *
      * \todo Can this be rolled into queue_nb?
+     * \todo Expose next work item for each component to detect stalls
      */
-    virtual status_t announce_nb(const std::vector<C2WorkOutline> &items) = 0;
+    virtual c2_status_t announce_nb(const std::vector<C2WorkOutline> &items) = 0;
+
+    enum flush_mode_t : uint32_t {
+        /// flush work from this component only
+        FLUSH_COMPONENT,
+        /// flush work from this component and all components connected downstream from it via
+        /// tunneling
+        FLUSH_CHAIN,
+    };
 
     /**
      * Discards and abandons any pending work for the component, and optionally any component
@@ -353,22 +441,33 @@
      *
      * Work that could not be abandoned or discarded immediately SHALL be marked to be
      * discarded at the earliest opportunity, and SHALL be returned via the onWorkDone() callback.
+     * This shall be completed within 500ms.
      *
-     * \param flushThrough    flush work from this component and all components connected downstream
-     *                      from it via tunneling.
+     * \param mode flush mode
      *
-     * \retval C2_OK        the work announcement has been successfully recorded
+     * \retval C2_OK        the component has been successfully flushed
      * \retval C2_TIMED_OUT the flush could not be completed within the time limit (unexpected)
      * \retval C2_CORRUPTED some unknown error prevented flushing from completion (unexpected)
      */
-    virtual status_t flush_sm(bool flushThrough, std::list<std::unique_ptr<C2Work>>* const flushedWork) = 0;
+    virtual c2_status_t flush_sm(flush_mode_t mode, std::list<std::unique_ptr<C2Work>>* const flushedWork) = 0;
+
+    enum drain_mode_t : uint32_t {
+        /// drain component only
+        DRAIN_COMPONENT,
+        /// marks the last work item with a persistent "end-of-stream" marker that will drain
+        /// downstream components
+        /// \todo this may confuse work-ordering downstream
+        DRAIN_CHAIN,
+        /**
+         * \todo define this; we could place EOS to all upstream components, just this component, or
+         *       all upstream and downstream component.
+         * \todo should EOS carry over to downstream components?
+         */
+    };
 
     /**
-     * Drains the component, and optionally downstream components
-     *
-     * \todo define this; we could place EOS to all upstream components, just this component, or
-     *       all upstream and downstream component.
-     * \todo should EOS carry over to downstream components?
+     * Drains the component, and optionally downstream components. This is a signalling method;
+     * as such it does not wait for any work completion.
      *
      * Marks last work item as "end-of-stream", so component is notified not to wait for further
      * work before it processes work already queued. This method is called to set the end-of-stream
@@ -381,16 +480,13 @@
      *
      * Work that is completed SHALL be returned via the onWorkDone() callback.
      *
-     * \param drainThrough    marks the last work item with a persistent "end-of-stream" marker that
-     *                      will drain downstream components.
+     * \param mode drain mode
      *
-     * \todo this may confuse work-ordering downstream; could be an mode enum
-     *
-     * \retval C2_OK        the work announcement has been successfully recorded
+     * \retval C2_OK        the drain request has been successfully recorded
      * \retval C2_TIMED_OUT the flush could not be completed within the time limit (unexpected)
      * \retval C2_CORRUPTED some unknown error prevented flushing from completion (unexpected)
      */
-    virtual status_t drain_nb(bool drainThrough) = 0;
+    virtual c2_status_t drain_nb(drain_mode_t mode) = 0;
 
     // STATE CHANGE METHODS
     // =============================================================================================
@@ -404,14 +500,12 @@
      * there are no immediate guarantees. Though there are guarantees for responsiveness immediately
      * after start returns.
      *
-     * \todo Could we just start a ComponentInterface to get a Component?
-     *
-     * \retval C2_OK        the work announcement has been successfully recorded
+     * \retval C2_OK        the component has started successfully
      * \retval C2_NO_MEMORY not enough memory to start the component
      * \retval C2_TIMED_OUT the component could not be started within the time limit (unexpected)
      * \retval C2_CORRUPTED some unknown error prevented starting the component (unexpected)
      */
-    virtual status_t start() = 0;
+    virtual c2_status_t start() = 0;
 
     /**
      * Stops the component.
@@ -428,14 +522,14 @@
      * This does not alter any settings and tunings that may have resulted in a tripped state.
      * (Is this material given the definition? Perhaps in case we want to start again.)
      */
-    virtual status_t stop() = 0;
+    virtual c2_status_t stop() = 0;
 
     /**
      * Resets the component.
      *
-     * This method MUST be supported in running (including tripped) state.
+     * This method MUST be supported in all (including tripped) state.
      *
-     * This method MUST be supported during any other call (\todo or just blocking ones?)
+     * This method MUST be supported during any other blocking call.
      *
      * This method MUST return withing 500ms.
      *
@@ -447,22 +541,24 @@
      * This brings settings back to their default - "guaranteeing" no tripped space.
      *
      * \todo reclaim support - it seems that since ownership is passed, this will allow reclaiming stuff.
+     *
+     * \retval C2_OK        the component has been reset
+     * \retval C2_TIMED_OUT the component could not be reset within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented resetting the component (unexpected)
      */
     virtual void reset() = 0;
 
     /**
      * Releases the component.
      *
-     * This method MUST be supported in any state. (\todo Or shall we force reset() first to bring
-     * to a known state?)
+     * This method MUST be supported in stopped state.
      *
-     * This method MUST return withing 500ms.
+     * This method MUST return withing 500ms. Upon return all references shall be abandoned.
      *
-     * \todo should this return completed work, since client will just free it? Also, if it unblocks
-     * a stop, where should completed work be returned?
-     *
-     * TODO: does it matter if this call has a short time limit? Yes, as upon return all references
-     * shall be abandoned.
+     * \retval C2_OK        the component has been released
+     * \retval C2_BAD_STATE the component is running
+     * \retval C2_TIMED_OUT the component could not be released within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented releasing the component (unexpected)
      */
     virtual void release() = 0;
 
@@ -489,6 +585,8 @@
     /**
      * \return a vector of supported parameter indices parsed by this info parser.
      *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
      * \todo sticky vs. non-sticky params? this may be communicated by param-reflector.
      */
     virtual const std::vector<C2Param::Index> getParsedParams() const = 0;
@@ -502,31 +600,54 @@
      * \retval C2_TIMED_OUT could not reset the parser within the time limit (unexpected)
      * \retval C2_CORRUPTED some unknown error prevented the resetting of the parser (unexpected)
      */
-    virtual status_t reset() { return C2_OK; }
+    virtual c2_status_t reset() { return C2_OK; }
 
-    virtual status_t parseFrame(C2BufferPack &frame);
+    virtual c2_status_t parseFrame(C2BufferPack &frame);
 
     virtual ~C2FrameInfoParser() = default;
 };
 
-struct C2ComponentInfo {
-    // TBD
-
-};
-
 class C2AllocatorStore {
 public:
-    // TBD
+    typedef C2Allocator::id_t id_t;
 
-    enum Type {
-        LINEAR,     ///< basic linear allocator type
-        GRALLOC,    ///< basic gralloc allocator type
+    enum : C2Allocator::id_t {
+        DEFAULT_LINEAR,     ///< basic linear allocator type
+        DEFAULT_GRAPHIC,    ///< basic graphic allocator type
+        PLATFORM_START = 0x10,
+        VENDOR_START   = 0x100,
     };
 
     /**
-     * Creates an allocator.
+     * Returns the unique name of this allocator store.
      *
-     * \param type      the type of allocator to create
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the name of this allocator store.
+     * \retval an empty string if there was not enough memory to allocate the actual name.
+     */
+    virtual C2String getName() const = 0;
+
+    /**
+     * Returns the set of allocators supported by this allocator store.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \retval vector of allocator information (as shared pointers)
+     * \retval an empty vector if there was not enough memory to allocate the whole vector.
+     */
+    virtual std::vector<std::shared_ptr<const C2Allocator::Traits>> listAllocators_nb() const = 0;
+
+    /**
+     * Retrieves/creates a shared allocator object.
+     *
+     * This method MUST be return within 5ms.
+     *
+     * The allocator is created on first use, and the same allocator is returned on subsequent
+     * concurrent uses in the same process. The allocator is freed when it is no longer referenced.
+     *
+     * \param id      the ID of the allocator to create. This is defined by the store, but
+     *                the ID of the default linear and graphic allocators is formalized.
      * \param allocator shared pointer where the created allocator is stored. Cleared on failure
      *                  and updated on success.
      *
@@ -537,12 +658,28 @@
      * \retval C2_NOT_FOUND no such allocator
      * \retval C2_NO_MEMORY not enough memory to create the allocator
      */
-    virtual status_t createAllocator(Type type, std::shared_ptr<C2Allocator>* const allocator) = 0;
+    virtual c2_status_t fetchAllocator(id_t id, std::shared_ptr<C2Allocator>* const allocator) = 0;
 
     virtual ~C2AllocatorStore() = default;
 };
 
 class C2ComponentStore {
+public:
+    /**
+     * Returns the name of this component or component interface object.
+     * This is a unique name for this component or component interface 'class'; however, multiple
+     * instances of this component SHALL have the same name.
+     *
+     * This method MUST be supported in any state. This call does not change the state nor the
+     * internal states of the component.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the name of this component or component interface object.
+     * \retval an empty string if there was not enough memory to allocate the actual name.
+     */
+    virtual C2String getName() const = 0;
+
     /**
      * Creates a component.
      *
@@ -559,7 +696,8 @@
      * \retval C2_NOT_FOUND no such component
      * \retval C2_NO_MEMORY not enough memory to create the component
      */
-    virtual status_t createComponent(C2String name, std::shared_ptr<C2Component>* const component);
+    virtual c2_status_t createComponent(
+            C2String name, std::shared_ptr<C2Component>* const component) = 0;
 
     /**
      * Creates a component interface.
@@ -580,26 +718,27 @@
      *
      * \todo Do we need an interface, or could this just be a component that is never started?
      */
-    virtual status_t createInterface(C2String name, std::shared_ptr<C2ComponentInterface>* const interface);
+    virtual c2_status_t createInterface(
+            C2String name, std::shared_ptr<C2ComponentInterface>* const interface) = 0;
 
     /**
      * Returns the list of components supported by this component store.
      *
-     * This method SHALL return within 1ms.
+     * This method may be momentarily blocking, but MUST return within 5ms.
      *
      * \retval vector of component information.
      */
-    virtual std::vector<std::unique_ptr<const C2ComponentInfo>> getComponents();
+    virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents_sm() const = 0;
 
     // -------------------------------------- UTILITY METHODS --------------------------------------
 
     // on-demand buffer layout conversion (swizzling)
-    virtual status_t copyBuffer(std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst);
+    //
+    virtual c2_status_t copyBuffer(
+            std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) = 0;
 
-    // status_t selectPreferredColor(formats<A>, formats<B>);
-
-    // GLOBAL SETTINGS
-    // system-wide stride & slice-height (???)
+    // -------------------------------------- CONFIGURATION API -----------------------------------
+    // e.g. for global settings (system-wide stride, etc.)
 
     /**
      * Queries a set of system-wide parameters.
@@ -611,16 +750,16 @@
      *
      * \note Parameter values do not depend on the order of query.
      *
-     * This method MUST be "non-blocking" and return within 1ms.
+     * This method may be momentarily blocking, but MUST return within 5ms.
      *
-     * \param stackParams     a list of params queried. These are initialized specific to each
+     * \param stackParams   a list of params queried. These are initialized specific to each
      *                      setting; e.g. size and index are set and rest of the members are
      *                      cleared.
      *                      NOTE: Flexible settings that are of incorrect size will be invalidated.
      * \param heapParamIndices a vector of param indices for params to be queried and returned on the
      *                      heap. These parameters will be returned in heapParams. Unsupported param
      *                      indices will be ignored.
-     * \param heapParams      a list of params where to which the supported heap parameters will be
+     * \param heapParams    a list of params where to which the supported heap parameters will be
      *                      appended in the order they appear in heapParamIndices.
      *
      * \retval C2_OK        all parameters could be queried
@@ -630,10 +769,10 @@
      * \retval C2_CORRUPTED some unknown error prevented the querying of the parameters
      *                      (unexpected)
      */
-    virtual status_t query_nb(
+    virtual c2_status_t query_sm(
         const std::vector<C2Param* const> &stackParams,
         const std::vector<C2Param::Index> &heapParamIndices,
-        std::vector<std::unique_ptr<C2Param>>* const heapParams) = 0;
+        std::vector<std::unique_ptr<C2Param>>* const heapParams) const = 0;
 
     /**
      * Sets a set of system-wide parameters.
@@ -648,15 +787,15 @@
      * \note Parameter tuning DOES depend on the order of the tuning parameters. E.g. some parameter
      * update may allow some subsequent parameter update.
      *
-     * This method MUST be "non-blocking" and return within 1ms.
+     * This method may be momentarily blocking, but MUST return within 5ms.
      *
-     * \param params          a list of parameter updates. These will be updated to the actual
+     * \param params        a list of parameter updates. These will be updated to the actual
      *                      parameter values after the updates (this is because tuning is performed
      *                      at best effort).
      *                      \todo params that could not be updated are not marked here, so are
      *                      confusing - are they "existing" values or intended to be configured
      *                      values?
-     * \param failures        a list of parameter failures
+     * \param failures      a list of parameter failures
      *
      * \retval C2_OK        all parameters could be updated successfully
      * \retval C2_BAD_INDEX all supported parameters could be updated successfully, but some
@@ -669,9 +808,95 @@
      * \retval C2_CORRUPTED some unknown error prevented the update of the parameters
      *                      (unexpected)
      */
-    virtual status_t config_nb(
+    virtual c2_status_t config_sm(
             const std::vector<C2Param* const> &params,
-            std::list<std::unique_ptr<C2SettingResult>>* const failures) = 0;
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
+
+    /**
+     * Atomically sets a set of system-wide parameters.
+     *
+     * \note There are no settable system-wide parameters defined thus far, but may be added in the
+     * future.
+     *
+     * The component store SHALL update all supported configuration at best effort(TBD)
+     * (unless configured otherwise) and skip unsupported ones. If any errors are encountered
+     * (other than unsupported parameters), the configuration SHALL be aborted as if it did not
+     * happen.
+     *
+     * \note Parameter tuning DOES depend on the order of the tuning parameters. E.g. some parameter
+     * update may allow some subsequent parameter update.
+     *
+     * This method may be momentarily blocking, but MUST return within 5ms.
+     *
+     * \param params[in,out] a list of parameter updates. These will be updated to the actual
+     *                       parameter values after the updates (this is because tuning is performed
+     *                       at best effort).
+     *                       \todo params that could not be updated are not marked here, so are
+     *                       confusing - are they "existing" values or intended to be configured
+     *                       values?
+     * \param failures[out]  a list of parameter failures
+     *
+     * \retval C2_OK        all parameters could be updated successfully
+     * \retval C2_BAD_INDEX all supported parameters could be updated successfully, but some
+     *                      parameters were not supported
+     * \retval C2_BAD_VALUE some supported parameters could not be updated successfully because
+     *                      they contained unsupported values. These are returned in |failures|.
+     * \retval C2_NO_MEMORY some supported parameters could not be updated successfully because
+     *                      they contained unsupported values, but could not allocate a failure
+     *                      object for them.
+     * \retval C2_CORRUPTED some unknown error prevented the update of the parameters
+     *                      (unexpected)
+     */
+    virtual c2_status_t commit_sm(
+            const std::vector<C2Param* const> &params,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
+
+    // REFLECTION MECHANISM (USED FOR EXTENSION)
+    // =============================================================================================
+
+    /**
+     * Returns the parameter reflector.
+     *
+     * This is used to describe parameter fields. This is shared for all components created by
+     * this component store.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return a shared parameter reflector object.
+     */
+    virtual std::shared_ptr<C2ParamReflector> getParamReflector() const = 0;
+
+    /**
+     * Returns the set of supported parameters.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \param[out] params a vector of supported parameters will be appended to this vector.
+     *
+     * \retval C2_OK        the operation completed successfully.
+     * \retval C2_NO_MEMORY not enough memory to complete this method.
+     */
+    virtual c2_status_t querySupportedParams_nb(
+            std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const = 0;
+
+    /**
+     * Retrieves the supported values for the queried fields.
+     *
+     * Client SHALL set the parameter-field specifier and the type of supported values query (e.g.
+     * currently supported values, or potential supported values) in fields.
+     * Upon return the store SHALL fill in the supported values for the fields listed as well
+     * as a status for each field. Store shall process all fields queried even if some queries
+     * fail.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \param[in out] fields a vector of fields descriptor structures.
+     *
+     * \retval C2_OK        the operation completed successfully.
+     * \retval C2_BAD_INDEX at least one field was not recognized as a component store field
+     */
+    virtual c2_status_t querySupportedValues_nb(
+            std::vector<C2FieldSupportedValuesQuery> &fields) const = 0;
 
     virtual ~C2ComponentStore() = default;
 };
diff --git a/media/libstagefright/codec2/include/C2Config.h b/media/libstagefright/codec2/include/C2Config.h
index 30e9193..0568432 100644
--- a/media/libstagefright/codec2/include/C2Config.h
+++ b/media/libstagefright/codec2/include/C2Config.h
@@ -41,7 +41,7 @@
 enum name : type { __VA_ARGS__ }; \
 DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, type, names, __VA_ARGS__)
 
-enum C2ParamIndexKind : uint32_t {
+enum C2ParamIndexKind : C2Param::ParamIndex {
     /// domain
     kParamIndexDomain,
 
@@ -61,17 +61,20 @@
     kParamIndexMime,
     kParamIndexStreamCount,
     kParamIndexFormat,
+    kParamIndexBlockPools,
+
+    kParamIndexMaxVideoSizeHint,
+    kParamIndexVideoSizeTuning,
 
     // video info
 
     kParamIndexStructStart = 0x1,
     kParamIndexVideoSize,
-    kParamIndexMaxVideoSizeHint,
 
     kParamIndexParamStart = 0x800,
 };
 
-C2ENUM(C2DomainKind, int32_t,
+C2ENUM(C2DomainKind, uint32_t,
     C2DomainVideo,
     C2DomainAudio,
     C2DomainOther = C2DomainAudio + 1
@@ -124,6 +127,8 @@
 
 typedef C2StreamParam<C2Tuning, C2Uint32Value, kParamIndexFormat> C2StreamFormatConfig;
 
+typedef C2PortParam<C2Tuning, C2Uint64Array, kParamIndexBlockPools> C2PortBlockPoolsTuning;
+
 /*
    Component description fields:
 
@@ -230,19 +235,19 @@
     int32_t mWidth;     ///< video width
     int32_t mHeight;    ///< video height
 
-    DEFINE_AND_DESCRIBE_C2STRUCT(VideoSize)
+    DEFINE_AND_DESCRIBE_BASE_C2STRUCT(VideoSize)
     C2FIELD(mWidth, "width")
     C2FIELD(mHeight, "height")
 };
 
 // video size for video decoder [OUT]
-typedef C2StreamParam<C2Info, C2VideoSizeStruct> C2VideoSizeStreamInfo;
+typedef C2StreamParam<C2Info, C2VideoSizeStruct, kParamIndexVideoSize> C2VideoSizeStreamInfo;
 
 // max video size for video decoder [IN]
 typedef C2PortParam<C2Setting, C2VideoSizeStruct, kParamIndexMaxVideoSizeHint> C2MaxVideoSizeHintPortSetting;
 
 // video encoder size [IN]
-typedef C2StreamParam<C2Tuning, C2VideoSizeStruct> C2VideoSizeStreamTuning;
+typedef C2StreamParam<C2Tuning, C2VideoSizeStruct, kParamIndexVideoSizeTuning> C2VideoSizeStreamTuning;
 
 /// @}
 
diff --git a/media/libstagefright/codec2/include/C2Param.h b/media/libstagefright/codec2/include/C2Param.h
index fd43061..f0b92a3 100644
--- a/media/libstagefright/codec2/include/C2Param.h
+++ b/media/libstagefright/codec2/include/C2Param.h
@@ -71,7 +71,7 @@
  *     an error for the specific setting, but should continue to apply other settings.
  *     TODO: this currently may result in unintended results.
  *
- * **NOTE:** unlike OMX, params are not versioned. Instead, a new struct with new base index
+ * **NOTE:** unlike OMX, params are not versioned. Instead, a new struct with new param index
  * SHALL be added as new versions are required.
  *
  * The proper subtype (Setting, Info or Param) is incorporated into the class type. Define structs
@@ -104,7 +104,7 @@
     // layout:
     //
     //      +------+-----+---+------+--------+----|------+--------------+
-    //      | kind | dir | - |stream|streamID|flex|vendor|  base index  |
+    //      | kind | dir | - |stream|streamID|flex|vendor|  core index  |
     //      +------+-----+---+------+--------+----+------+--------------+
     //  bit: 31..30 29.28       25   24 .. 17  16    15   14    ..     0
     //
@@ -121,6 +121,19 @@
     };
 
     /**
+     * Parameter index is associated with each parameter. It is used to identify and distinguish
+     * global parameters, and also parameters on a given port or stream. They must be unique for the
+     * set of global parameters, as well as for the set of parameters on each port or each stream,
+     * but the same parameter index can be used for parameters on different streams or ports, as
+     * well as for global parameters and port/stream parameters.
+     *
+     * Parameter index is also used to describe the layout of the parameter structures. Multiple
+     * parameter types can share the same layout, but the layout for all parameters with the same
+     * parameter index across all components must be identical.
+     */
+    typedef uint32_t ParamIndex;
+
+    /**
      * base index (including the vendor extension bit) is a global index for
      * C2 parameter structs. (e.g. the same indices cannot be reused for different
      * structs for different components).
@@ -149,7 +162,7 @@
             kFlexibleFlag  = 0x00010000,
             kVendorFlag    = 0x00008000,
             kParamMask     = 0x0000FFFF,
-            kBaseMask      = kParamMask | kFlexibleFlag,
+            kCoreMask      = kParamMask | kFlexibleFlag,
         };
 
     public:
@@ -170,11 +183,12 @@
         /// returns true iff this is a flexible parameter (with variable size)
         inline bool isFlexible() const { return mIndex & kFlexibleFlag; }
 
-        /// returns the base type: the index for the underlying struct
-        inline unsigned int baseIndex() const { return mIndex & kBaseMask; }
+        /// returns the core parameter type (index) for the underlying struct.
+        /// This is the combination of the parameter index and the flexible flag.
+        inline unsigned int coreIndex() const { return mIndex & kCoreMask; }
 
-        /// returns the param index for the underlying struct
-        inline unsigned int paramIndex() const { return mIndex & kParamMask; }
+        /// returns the parameter index for the underlying struct
+        inline ParamIndex paramIndex() const { return mIndex & kParamMask; }
 
         DEFINE_FIELD_BASED_COMPARISON_OPERATORS(BaseIndex, mIndex)
 
@@ -330,6 +344,10 @@
     /// returns the parameter type: the parameter index without the stream ID
     inline uint32_t type() const { return _mIndex.type(); }
 
+    /// returns the index of this parameter
+    /// \todo: should we restrict this to C2ParamField?
+    inline uint32_t index() const { return (uint32_t)_mIndex; }
+
     /// returns the kind of this parameter
     inline Kind kind() const { return _mIndex.kind(); }
 
@@ -362,6 +380,17 @@
         return param;
     }
 
+    /// Returns managed clone of |orig| at heap.
+    inline static std::unique_ptr<C2Param> Copy(const C2Param &orig) {
+        if (orig.size() == 0) {
+            return nullptr;
+        }
+        void *mem = ::operator new (orig.size());
+        C2Param *param = new (mem) C2Param(orig.size(), orig._mIndex);
+        param->updateFrom(orig);
+        return std::unique_ptr<C2Param>(param);
+    }
+
 #if 0
     template<typename P, class=decltype(C2Param(P()))>
     P *As() { return P::From(this); }
@@ -439,8 +468,8 @@
     friend struct _C2ParamInspector; // for testing
 
     /// returns the base type: the index for the underlying struct (for testing
-    /// as this can be gotten by the baseIndex enum)
-    inline uint32_t _baseIndex() const { return _mIndex.baseIndex(); }
+    /// as this can be gotten by the coreIndex enum)
+    inline uint32_t _coreIndex() const { return _mIndex.coreIndex(); }
 
     /// returns true iff |o| has the same size and index as this. This performs the
     /// basic check for equality.
@@ -537,7 +566,6 @@
     /**
      * Constructor used to identify a field in an object.
      *
-     * \param U[type] pointer to the object that contains this field
      * \param pm[im] member pointer to the field
      */
     template<typename R, typename T, typename B=typename std::remove_extent<R>::type>
@@ -572,23 +600,93 @@
 };
 
 /**
- * Structure uniquely specifying a field in a configuration
+ * Structure uniquely specifying a 'field' in a configuration. The field
+ * can be a field of a configuration, a subfield of a field of a configuration,
+ * and even the whole configuration. Moreover, if the field can point to an
+ * element in a array field, or to the entire array field.
+ *
+ * This structure is used for querying supported values for a field, as well
+ * as communicating configuration failures and conflicts when trying to change
+ * a configuration for a component/interface or a store.
  */
 struct C2ParamField {
 //public:
-    // TODO: fix what this is for T[] (for now size becomes T[1])
+    /**
+     * Create a field identifier using a configuration parameter (variable),
+     * and a pointer to member.
+     *
+     * ~~~~~~~~~~~~~ (.cpp)
+     *
+     * struct C2SomeParam {
+     *   uint32_t mField;
+     *   uint32_t mArray[2];
+     *   C2OtherStruct mStruct;
+     *   uint32_t mFlexArray[];
+     * } *mParam;
+     *
+     * C2ParamField(mParam, &mParam->mField);
+     * C2ParamField(mParam, &mParam->mArray);
+     * C2ParamField(mParam, &mParam->mArray[0]);
+     * C2ParamField(mParam, &mParam->mStruct.mSubField);
+     * C2ParamField(mParam, &mParam->mFlexArray);
+     * C2ParamField(mParam, &mParam->mFlexArray[2]);
+     *
+     * ~~~~~~~~~~~~~
+     *
+     * \todo fix what this is for T[] (for now size becomes T[1])
+     *
+     * \param param pointer to parameter
+     * \param offset member pointer
+     */
     template<typename S, typename T>
     inline C2ParamField(S* param, T* offset)
         : _mIndex(param->index()),
           _mFieldId(offset) {}
 
+    /**
+     * Create a field identifier using a configuration parameter (variable),
+     * and a member pointer. This method cannot be used to refer to an
+     * array element or a subfield.
+     *
+     * ~~~~~~~~~~~~~ (.cpp)
+     *
+     * C2SomeParam mParam;
+     * C2ParamField(&mParam, &C2SomeParam::mMemberField);
+     *
+     * ~~~~~~~~~~~~~
+     *
+     * \param p pointer to parameter
+     * \param T member pointer to the field member
+     */
     template<typename R, typename T, typename U>
-    inline C2ParamField(U *p, R T::* pm) : _mIndex(p->type()), _mFieldId(p, pm) { }
+    inline C2ParamField(U *p, R T::* pm) : _mIndex(p->index()), _mFieldId(p, pm) { }
 
+    /**
+     * Create a field identifier to a configuration parameter (variable).
+     *
+     * ~~~~~~~~~~~~~ (.cpp)
+     *
+     * C2SomeParam mParam;
+     * C2ParamField(&mParam);
+     *
+     * ~~~~~~~~~~~~~
+     *
+     * \param param pointer to parameter
+     */
+    template<typename S>
+    inline C2ParamField(S* param)
+        : _mIndex(param->index()), _mFieldId(0u, param->size()) {}
+
+    /**
+     * Equality operator.
+     */
     inline bool operator==(const C2ParamField &other) const {
         return _mIndex == other._mIndex && _mFieldId == other._mFieldId;
     }
 
+    /**
+     * Ordering operator.
+     */
     inline bool operator<(const C2ParamField &other) const {
         return _mIndex < other._mIndex ||
             (_mIndex == other._mIndex && _mFieldId < other._mFieldId);
@@ -597,8 +695,8 @@
     DEFINE_OTHER_COMPARISON_OPERATORS(C2ParamField)
 
 private:
-    C2Param::Index _mIndex;
-    _C2FieldId _mFieldId;
+    C2Param::Index _mIndex; ///< parameter index
+    _C2FieldId _mFieldId;   ///< field identifier
 };
 
 /**
@@ -641,7 +739,7 @@
 
     // constructors - implicit
     template<typename T>
-    C2Value(T value)  : mType(typeFor<T>()),  mValue(value) { }
+    C2Value(T value)  : mType(typeFor<T>()), mValue(value) { }
 
     C2Value() : mType(NO_INIT) { }
 
@@ -661,11 +759,11 @@
     Primitive mValue;
 };
 
-template<> const int32_t &C2Value::Primitive::ref<int32_t>() const { return i32; }
-template<> const int64_t &C2Value::Primitive::ref<int64_t>() const { return i64; }
-template<> const uint32_t &C2Value::Primitive::ref<uint32_t>() const { return u32; }
-template<> const uint64_t &C2Value::Primitive::ref<uint64_t>() const { return u64; }
-template<> const float &C2Value::Primitive::ref<float>() const { return fp; }
+template<> inline const int32_t &C2Value::Primitive::ref<int32_t>() const { return i32; }
+template<> inline const int64_t &C2Value::Primitive::ref<int64_t>() const { return i64; }
+template<> inline const uint32_t &C2Value::Primitive::ref<uint32_t>() const { return u32; }
+template<> inline const uint64_t &C2Value::Primitive::ref<uint64_t>() const { return u64; }
+template<> inline const float &C2Value::Primitive::ref<float>() const { return fp; }
 
 template<> constexpr C2Value::Type C2Value::typeFor<int32_t>() { return INT32; }
 template<> constexpr C2Value::Type C2Value::typeFor<int64_t>() { return INT64; }
@@ -700,7 +798,7 @@
                         ///< however, bytes cannot be individually addressed by clients.
 
         // complex types
-        STRUCT_FLAG = 0x10000, ///< structs. Marked with this flag in addition to their baseIndex.
+        STRUCT_FLAG = 0x10000, ///< structs. Marked with this flag in addition to their coreIndex.
     };
 
     typedef std::pair<C2String, C2Value::Primitive> named_value_type;
@@ -791,12 +889,12 @@
         return getType(&underlying);
     }
 
-    // verify C2Struct by having a fieldList and a baseIndex.
+    // verify C2Struct by having a fieldList and a coreIndex.
     template<typename T,
-             class=decltype(T::baseIndex + 1), class=decltype(T::fieldList)>
+             class=decltype(T::coreIndex + 1), class=decltype(T::fieldList)>
     inline static Type getType(T*) {
         static_assert(!std::is_base_of<C2Param, T>::value, "cannot use C2Params as fields");
-        return (Type)(T::baseIndex | STRUCT_FLAG);
+        return (Type)(T::coreIndex | STRUCT_FLAG);
     }
 };
 
@@ -821,7 +919,7 @@
 struct C2StructDescriptor {
 public:
     /// Returns the parameter type
-    inline C2Param::BaseIndex baseIndex() const { return _mType.baseIndex(); }
+    inline C2Param::BaseIndex coreIndex() const { return _mType.coreIndex(); }
 
     // Returns the number of fields in this param (not counting any recursive fields).
     // Must be at least 1 for valid params.
@@ -838,7 +936,7 @@
 
     template<typename T>
     inline C2StructDescriptor(T*)
-        : C2StructDescriptor(T::baseIndex, T::fieldList) { }
+        : C2StructDescriptor(T::coreIndex, T::fieldList) { }
 
     inline C2StructDescriptor(
             C2Param::BaseIndex type,
@@ -903,25 +1001,32 @@
 };
 
 /// \ingroup internal
-/// Define a structure without baseIndex.
-#define DEFINE_C2STRUCT_NO_BASE(name) \
+/// Define a structure without coreIndex.
+#define DEFINE_BASE_C2STRUCT(name) \
 public: \
     typedef C2##name##Struct _type; /**< type name shorthand */ \
     const static std::initializer_list<const C2FieldDescriptor> fieldList; /**< structure fields */
 
-/// Define a structure with matching baseIndex.
+/// Define a structure with matching coreIndex.
 #define DEFINE_C2STRUCT(name) \
 public: \
-    enum : uint32_t { baseIndex = kParamIndex##name }; \
-    DEFINE_C2STRUCT_NO_BASE(name)
+    enum : uint32_t { coreIndex = kParamIndex##name }; \
+    DEFINE_BASE_C2STRUCT(name)
 
-/// Define a flexible structure with matching baseIndex.
+/// Define a flexible structure without coreIndex.
+#define DEFINE_BASE_FLEX_C2STRUCT(name, flexMember) \
+public: \
+    FLEX(C2##name##Struct, flexMember) \
+    DEFINE_BASE_C2STRUCT(name)
+
+/// Define a flexible structure with matching coreIndex.
 #define DEFINE_FLEX_C2STRUCT(name, flexMember) \
 public: \
     FLEX(C2##name##Struct, flexMember) \
-    enum : uint32_t { baseIndex = kParamIndex##name | C2Param::BaseIndex::_kFlexibleFlag }; \
-    DEFINE_C2STRUCT_NO_BASE(name)
+    enum : uint32_t { coreIndex = kParamIndex##name | C2Param::BaseIndex::_kFlexibleFlag }; \
+    DEFINE_BASE_C2STRUCT(name)
 
+#ifdef __C2_GENERATE_GLOBAL_VARS__
 /// \ingroup internal
 /// Describe a structure of a templated structure.
 #define DESCRIBE_TEMPLATED_C2STRUCT(strukt, list) \
@@ -932,6 +1037,12 @@
 /// Describe the fields of a structure using an initializer list.
 #define DESCRIBE_C2STRUCT(name, list) \
     const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = list;
+#else
+/// \if 0
+#define DESCRIBE_TEMPLATED_C2STRUCT(strukt, list)
+#define DESCRIBE_C2STRUCT(name, list)
+/// \endif
+#endif
 
 /**
  * Describe a field of a structure.
@@ -1011,6 +1122,7 @@
  *  ~~~~~~~~~~~~~
  *
  */
+#ifdef __C2_GENERATE_GLOBAL_VARS__
 #define C2FIELD(member, name) \
   C2FieldDescriptor(&((_type*)(nullptr))->member, name),
 
@@ -1018,18 +1130,57 @@
 #define C2SOLE_FIELD(member, name) \
   C2FieldDescriptor(&_type::member, name, 0)
 
-/// Define a structure with matching baseIndex and start describing its fields.
+/// Define a structure with matching coreIndex and start describing its fields.
 /// This must be at the end of the structure definition.
 #define DEFINE_AND_DESCRIBE_C2STRUCT(name) \
-    DEFINE_C2STRUCT(name) }  C2_PACK; \
+    DEFINE_C2STRUCT(name) } C2_PACK; \
     const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = {
 
-/// Define a flexible structure with matching baseIndex and start describing its fields.
+/// Define a flexible structure with matching coreIndex and start describing its fields.
 /// This must be at the end of the structure definition.
 #define DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember) \
     DEFINE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; \
     const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = {
 
+/// Define a base structure (with no coreIndex) and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_BASE_C2STRUCT(name) \
+    DEFINE_BASE_C2STRUCT(name) } C2_PACK; \
+    const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = {
+
+/// Define a flexible base structure (with no coreIndex) and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_BASE_FLEX_C2STRUCT(name, flexMember) \
+    DEFINE_BASE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; \
+    const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = {
+
+#else
+/// \if 0
+/* Alternate declaration of field definitions in case no field list is to be generated.
+   TRICKY: use namespace declaration to handle closing bracket that is normally after
+   these macros. */
+#define C2FIELD(member, name)
+/// \deprecated
+#define C2SOLE_FIELD(member, name)
+/// Define a structure with matching coreIndex and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_C2STRUCT(name) \
+    DEFINE_C2STRUCT(name) }  C2_PACK; namespace ignored {
+/// Define a flexible structure with matching coreIndex and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember) \
+    DEFINE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; namespace ignored {
+/// Define a base structure (with no coreIndex) and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_BASE_C2STRUCT(name) \
+    DEFINE_BASE_C2STRUCT(name) } C2_PACK; namespace ignored {
+/// Define a flexible base structure (with no coreIndex) and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_BASE_FLEX_C2STRUCT(name, flexMember) \
+    DEFINE_BASE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; namespace ignored {
+/// \endif
+#endif
+
 /**
  * Parameter reflector class.
  *
@@ -1043,7 +1194,8 @@
     /**
      *  Describes a parameter structure.
      *
-     *  \param[in] paramIndex the base index of the parameter structure
+     *  \param[in] coreIndex the base index of the parameter structure containing at least the
+     *  core index
      *
      *  \return the description of the parameter structure
      *  \retval nullptr if the parameter is not supported by this reflector
@@ -1056,55 +1208,13 @@
      *  descriptions, but we want to conserve memory if client only wants the description
      *  of a few indices.
      */
-    virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::BaseIndex paramIndex) = 0;
+    virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::BaseIndex coreIndex) = 0;
 
 protected:
     virtual ~C2ParamReflector() = default;
 };
 
 /**
- * A useable supported values for a field.
- *
- * This can be either a range or a set of values. The range can be linear or geometric with a
- * clear minimum and maximum value, and can have an optional step size or geometric ratio. Values
- * can optionally represent flags.
- *
- * \note Do not use flags to represent bitfields. Use individual values or separate fields instead.
- */
-template<typename T>
-struct C2TypedFieldSupportedValues {
-//public:
-    enum Type {
-        RANGE,      ///< a numeric range that can be continuous or discrete
-        VALUES,     ///< a list of values
-        FLAGS       ///< a list of flags that can be OR-ed
-    };
-
-    Type type;
-
-    struct {
-        T min;
-        T max;
-        T step;
-        T nom;
-        T denom;
-    } range;
-    std::vector<T> values;
-
-    C2TypedFieldSupportedValues(T min, T max, T step = T(std::is_floating_point<T>::value ? 0 : 1))
-        : type(RANGE),
-          range{min, max, step, (T)1, (T)1} { }
-
-    C2TypedFieldSupportedValues(T min, T max, T nom, T den) :
-        type(RANGE),
-        range{min, max, (T)0, nom, den} { }
-
-    C2TypedFieldSupportedValues(bool flags, std::initializer_list<T> list) :
-        type(flags ? FLAGS : VALUES),
-        values(list) {}
-};
-
-/**
  * Generic supported values for a field.
  *
  * This can be either a range or a set of values. The range can be linear or geometric with a
@@ -1116,6 +1226,7 @@
 struct C2FieldSupportedValues {
 //public:
     enum Type {
+        EMPTY,      ///< no supported values
         RANGE,      ///< a numeric range that can be continuous or discrete
         VALUES,     ///< a list of values
         FLAGS       ///< a list of flags that can be OR-ed
@@ -1134,6 +1245,10 @@
     } range;
     std::vector<Primitive> values;
 
+    C2FieldSupportedValues()
+        : type(EMPTY) {
+    }
+
     template<typename T>
     C2FieldSupportedValues(T min, T max, T step = T(std::is_floating_point<T>::value ? 0 : 1))
         : type(RANGE),
@@ -1153,6 +1268,18 @@
         }
     }
 
+    template<typename T>
+    C2FieldSupportedValues(bool flags, const std::vector<T>& list)
+        : type(flags ? FLAGS : VALUES),
+          range{(T)0, (T)0, (T)0, (T)0, (T)0} {
+        for(T value : list) {
+            values.emplace_back(value);
+        }
+    }
+
+    /// \internal
+    /// \todo: create separate values vs. flags initializer as for flags we want
+    /// to list both allowed and disallowed flags
     template<typename T, typename E=decltype(C2FieldDescriptor::namedValuesFor(*(T*)0))>
     C2FieldSupportedValues(bool flags, const T*)
         : type(flags ? FLAGS : VALUES),
@@ -1164,6 +1291,21 @@
     }
 };
 
+/**
+ * Spported values for a specific field.
+ *
+ * This is a pair of the field specifier together with an optional supported values object.
+ * This structure is used when reporting parameter configuration failures and conflicts.
+ */
+struct C2ParamFieldValues {
+    C2ParamField paramOrField; ///< the field or parameter
+    /// optional supported values for the field if paramOrField specifies an actual field that is
+    /// numeric (non struct, blob or string). Supported values for arrays (including string and
+    /// blobs) describe the supported values for each element (character for string, and bytes for
+    /// blobs). It is optional for read-only strings and blobs.
+    std::unique_ptr<C2FieldSupportedValues> values;
+};
+
 /// @}
 
 }  // namespace android
diff --git a/media/libstagefright/codec2/include/C2ParamDef.h b/media/libstagefright/codec2/include/C2ParamDef.h
index f369617..8656629 100644
--- a/media/libstagefright/codec2/include/C2ParamDef.h
+++ b/media/libstagefright/codec2/include/C2ParamDef.h
@@ -59,35 +59,35 @@
                         || decltype(_C2Comparable_impl::__testNE<S>(0))::value> {
 };
 
-///  Helper class that checks if a type has a baseIndex constant.
-struct C2_HIDE _C2BaseIndexHelper_impl
+///  Helper class that checks if a type has a coreIndex constant.
+struct C2_HIDE _C2CoreIndexHelper_impl
 {
-    template<typename S, int=S::baseIndex>
-    static std::true_type __testBaseIndex(int);
+    template<typename S, int=S::coreIndex>
+    static std::true_type __testCoreIndex(int);
     template<typename>
-    static std::false_type __testBaseIndex(...);
+    static std::false_type __testCoreIndex(...);
 };
 
-/// Helper template that verifies a type's baseIndex and creates it if the type does not have one.
-template<typename S, int BaseIndex,
-        bool HasBase=decltype(_C2BaseIndexHelper_impl::__testBaseIndex<S>(0))::value>
-struct C2_HIDE C2BaseIndexOverride {
-    // TODO: what if we allow structs without baseIndex?
-    static_assert(BaseIndex == S::baseIndex, "baseIndex differs from structure");
+/// Helper template that verifies a type's coreIndex and creates it if the type does not have one.
+template<typename S, int CoreIndex,
+        bool HasBase=decltype(_C2CoreIndexHelper_impl::__testCoreIndex<S>(0))::value>
+struct C2_HIDE C2CoreIndexOverride {
+    // TODO: what if we allow structs without coreIndex?
+    static_assert(CoreIndex == S::coreIndex, "coreIndex differs from structure");
 };
 
-/// Specialization for types without a baseIndex.
-template<typename S, int BaseIndex>
-struct C2_HIDE C2BaseIndexOverride<S, BaseIndex, false> {
+/// Specialization for types without a coreIndex.
+template<typename S, int CoreIndex>
+struct C2_HIDE C2CoreIndexOverride<S, CoreIndex, false> {
 public:
     enum : uint32_t {
-        baseIndex = BaseIndex, ///< baseIndex override.
+        coreIndex = CoreIndex, ///< coreIndex override.
     };
 };
 
-/// Helper template that adds a baseIndex to a type if it does not have one.
-template<typename S, int BaseIndex>
-struct C2_HIDE C2AddBaseIndex : public S, public C2BaseIndexOverride<S, BaseIndex> {};
+/// Helper template that adds a coreIndex to a type if it does not have one.
+template<typename S, int CoreIndex>
+struct C2_HIDE C2AddCoreIndex : public S, public C2CoreIndexOverride<S, CoreIndex> {};
 
 /**
  * \brief Helper class to check struct requirements for parameters.
@@ -96,7 +96,7 @@
  *  - verify default constructor, no virtual methods, and no equality operators.
  *  - expose typeIndex, and non-flex flexSize.
  */
-template<typename S, int BaseIndex, unsigned TypeIndex>
+template<typename S, int CoreIndex, unsigned TypeIndex>
 struct C2_HIDE C2StructCheck {
     static_assert(
             std::is_default_constructible<S>::value, "C2 structure must have default constructor");
@@ -105,7 +105,7 @@
 
 public:
     enum : uint32_t {
-        typeIndex = BaseIndex | TypeIndex
+        typeIndex = CoreIndex | TypeIndex
     };
 
 protected:
@@ -161,17 +161,19 @@
  * \brief Helper class to check flexible struct requirements and add common operations.
  *
  * Features:
- *  - expose baseIndex and fieldList (this is normally inherited from the struct, but flexible
+ *  - expose coreIndex and fieldList (this is normally inherited from the struct, but flexible
  *    structs cannot be base classes and thus inherited from)
  *  - disable copy assignment and construction (TODO: this is already done in the FLEX macro for the
  *    flexible struct, so may not be needed here)
  */
-template<typename S, int BaseIndex, unsigned TypeIndex>
-struct C2_HIDE C2FlexStructCheck : public C2StructCheck<S, BaseIndex, TypeIndex> {
+template<typename S, int ParamIndex, unsigned TypeIndex>
+struct C2_HIDE C2FlexStructCheck :
+// add flexible flag as C2StructCheck defines typeIndex
+        public C2StructCheck<S, ParamIndex | C2Param::BaseIndex::_kFlexibleFlag, TypeIndex> {
 public:
     enum : uint32_t {
         /// \hideinitializer
-        baseIndex = BaseIndex | C2Param::BaseIndex::_kFlexibleFlag, ///< flexible struct base-index
+        coreIndex = ParamIndex | C2Param::BaseIndex::_kFlexibleFlag, ///< flexible struct core-index
     };
 
     const static std::initializer_list<const C2FieldDescriptor> fieldList; // TODO assign here
@@ -181,8 +183,8 @@
 
 protected:
     // cannot copy flexible params
-    C2FlexStructCheck(const C2FlexStructCheck<S, BaseIndex, TypeIndex> &) = delete;
-    C2FlexStructCheck& operator= (const C2FlexStructCheck<S, BaseIndex, TypeIndex> &) = delete;
+    C2FlexStructCheck(const C2FlexStructCheck<S, ParamIndex, TypeIndex> &) = delete;
+    C2FlexStructCheck& operator= (const C2FlexStructCheck<S, ParamIndex, TypeIndex> &) = delete;
 
     // constants used for helper methods
     enum : uint32_t {
@@ -215,8 +217,9 @@
 
 // TODO: this probably does not work.
 /// Expose fieldList from subClass;
-template<typename S, int BaseIndex, unsigned TypeIndex>
-const std::initializer_list<const C2FieldDescriptor> C2FlexStructCheck<S, BaseIndex, TypeIndex>::fieldList = S::fieldList;
+template<typename S, int ParamIndex, unsigned TypeIndex>
+const std::initializer_list<const C2FieldDescriptor>
+C2FlexStructCheck<S, ParamIndex, TypeIndex>::fieldList = S::fieldList;
 
 /// Define From() cast operators for params.
 #define DEFINE_CAST_OPERATORS(_type) \
@@ -299,7 +302,7 @@
  * Global-parameter template.
  *
  * Base template to define a global setting/tuning or info based on a structure and
- * an optional BaseIndex. Global parameters are not tied to a port (input or output).
+ * an optional ParamIndex. Global parameters are not tied to a port (input or output).
  *
  * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
  * structure can be accessed directly, and constructors and potential public methods are also
@@ -307,13 +310,14 @@
  *
  * \tparam T param type C2Setting, C2Tuning or C2Info
  * \tparam S wrapped structure
- * \tparam BaseIndex optional base-index override. Must be specified for common/reused structures.
+ * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
+ * structures.
  */
-template<typename T, typename S, int BaseIndex=S::baseIndex, class Flex=void>
-struct C2_HIDE C2GlobalParam : public T, public S, public C2BaseIndexOverride<S, BaseIndex>,
-        public C2StructCheck<S, BaseIndex, T::indexFlags | T::Type::kDirGlobal> {
+template<typename T, typename S, int ParamIndex=S::coreIndex, class Flex=void>
+struct C2_HIDE C2GlobalParam : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
+        public C2StructCheck<S, ParamIndex, T::indexFlags | T::Type::kDirGlobal> {
 private:
-    typedef C2GlobalParam<T, S, BaseIndex> _type;
+    typedef C2GlobalParam<T, S, ParamIndex> _type;
 
 public:
     /// Wrapper around base structure's constructor.
@@ -327,21 +331,22 @@
  * Global-parameter template for flexible structures.
  *
  * Base template to define a global setting/tuning or info based on a flexible structure and
- * an optional BaseIndex. Global parameters are not tied to a port (input or output).
+ * an optional ParamIndex. Global parameters are not tied to a port (input or output).
  *
  * \tparam T param type C2Setting, C2Tuning or C2Info
  * \tparam S wrapped flexible structure
- * \tparam BaseIndex optional base-index override. Must be specified for common/reused structures.
+ * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
+ *         structures.
  *
  * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
  * structures can be accessed via the m member variable; however, the constructors of the structure
  * are wrapped directly. (This is because flexible types cannot be subclassed.)
  */
-template<typename T, typename S, int BaseIndex>
-struct C2_HIDE C2GlobalParam<T, S, BaseIndex, IF_FLEXIBLE(S)>
-    : public T, public C2FlexStructCheck<S, BaseIndex, T::indexFlags | T::Type::kDirGlobal> {
+template<typename T, typename S, int ParamIndex>
+struct C2_HIDE C2GlobalParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
+    : public T, public C2FlexStructCheck<S, ParamIndex, T::indexFlags | T::Type::kDirGlobal> {
 private:
-    typedef C2GlobalParam<T, S, BaseIndex> _type;
+    typedef C2GlobalParam<T, S, ParamIndex> _type;
 
     /// Wrapper around base structure's constructor.
     template<typename ...Args>
@@ -359,12 +364,13 @@
  * Port-parameter template.
  *
  * Base template to define a port setting/tuning or info based on a structure and
- * an optional BaseIndex. Port parameters are tied to a port (input or output), but not to a
+ * an optional ParamIndex. Port parameters are tied to a port (input or output), but not to a
  * specific stream.
  *
  * \tparam T param type C2Setting, C2Tuning or C2Info
  * \tparam S wrapped structure
- * \tparam BaseIndex optional base-index override. Must be specified for common/reused structures.
+ * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
+ *         structures.
  *
  * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
  * structure can be accessed directly, and constructors and potential public methods are also
@@ -373,11 +379,11 @@
  * There are 3 flavors of port parameters: unspecified, input and output. Parameters with
  * unspecified port expose a setPort method, and add an initial port parameter to the constructor.
  */
-template<typename T, typename S, int BaseIndex=S::baseIndex, class Flex=void>
-struct C2_HIDE C2PortParam : public T, public S, public C2BaseIndexOverride<S, BaseIndex>,
-        private C2StructCheck<S, BaseIndex, T::indexFlags | T::Index::kDirUndefined> {
+template<typename T, typename S, int ParamIndex=S::coreIndex, class Flex=void>
+struct C2_HIDE C2PortParam : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
+        private C2StructCheck<S, ParamIndex, T::indexFlags | T::Index::kDirUndefined> {
 private:
-    typedef C2PortParam<T, S, BaseIndex> _type;
+    typedef C2PortParam<T, S, ParamIndex> _type;
 
 public:
     /// Default constructor.
@@ -392,8 +398,8 @@
     DEFINE_CAST_OPERATORS(_type)
 
     /// Specialization for an input port parameter.
-    struct input : public T, public S, public C2BaseIndexOverride<S, BaseIndex>,
-            public C2StructCheck<S, BaseIndex, T::indexFlags | T::Index::kDirInput> {
+    struct input : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
+            public C2StructCheck<S, ParamIndex, T::indexFlags | T::Index::kDirInput> {
         /// Wrapper around base structure's constructor.
         template<typename ...Args>
         inline input(const Args(&... args)) : T(sizeof(_type), input::typeIndex), S(args...) { }
@@ -403,8 +409,8 @@
     };
 
     /// Specialization for an output port parameter.
-    struct output : public T, public S, public C2BaseIndexOverride<S, BaseIndex>,
-            public C2StructCheck<S, BaseIndex, T::indexFlags | T::Index::kDirOutput> {
+    struct output : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
+            public C2StructCheck<S, ParamIndex, T::indexFlags | T::Index::kDirOutput> {
         /// Wrapper around base structure's constructor.
         template<typename ...Args>
         inline output(const Args(&... args)) : T(sizeof(_type), output::typeIndex), S(args...) { }
@@ -417,12 +423,13 @@
  * Port-parameter template for flexible structures.
  *
  * Base template to define a port setting/tuning or info based on a flexible structure and
- * an optional BaseIndex. Port parameters are tied to a port (input or output), but not to a
+ * an optional ParamIndex. Port parameters are tied to a port (input or output), but not to a
  * specific stream.
  *
  * \tparam T param type C2Setting, C2Tuning or C2Info
  * \tparam S wrapped flexible structure
- * \tparam BaseIndex optional base-index override. Must be specified for common/reused structures.
+ * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
+ *         structures.
  *
  * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
  * structures can be accessed via the m member variable; however, the constructors of the structure
@@ -431,11 +438,11 @@
  * There are 3 flavors of port parameters: unspecified, input and output. Parameters with
  * unspecified port expose a setPort method, and add an initial port parameter to the constructor.
  */
-template<typename T, typename S, int BaseIndex>
-struct C2_HIDE C2PortParam<T, S, BaseIndex, IF_FLEXIBLE(S)>
-    : public T, public C2FlexStructCheck<S, BaseIndex, T::indexFlags | T::Type::kDirUndefined> {
+template<typename T, typename S, int ParamIndex>
+struct C2_HIDE C2PortParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
+    : public T, public C2FlexStructCheck<S, ParamIndex, T::indexFlags | T::Type::kDirUndefined> {
 private:
-    typedef C2PortParam<T, S, BaseIndex> _type;
+    typedef C2PortParam<T, S, ParamIndex> _type;
 
     /// Default constructor for basic allocation: new(flexCount) P.
     inline C2PortParam(size_t flexCount) : T(_type::calcSize(flexCount), _type::typeIndex) { }
@@ -455,8 +462,8 @@
     DEFINE_CAST_OPERATORS(_type)
 
     /// Specialization for an input port parameter.
-    struct input : public T, public C2BaseIndexOverride<S, BaseIndex>,
-            public C2FlexStructCheck<S, BaseIndex, T::indexFlags | T::Index::kDirInput> {
+    struct input : public T,
+            public C2FlexStructCheck<S, ParamIndex, T::indexFlags | T::Index::kDirInput> {
     private:
         /// Wrapper around base structure's constructor while also specifying port/direction.
         template<typename ...Args>
@@ -471,8 +478,8 @@
     };
 
     /// Specialization for an output port parameter.
-    struct output : public T, public C2BaseIndexOverride<S, BaseIndex>,
-            public C2FlexStructCheck<S, BaseIndex, T::indexFlags | T::Index::kDirOutput> {
+    struct output : public T,
+            public C2FlexStructCheck<S, ParamIndex, T::indexFlags | T::Index::kDirOutput> {
     private:
         /// Wrapper around base structure's constructor while also specifying port/direction.
         template<typename ...Args>
@@ -491,12 +498,13 @@
  * Stream-parameter template.
  *
  * Base template to define a stream setting/tuning or info based on a structure and
- * an optional BaseIndex. Stream parameters are tied to a specific stream on a port (input or
+ * an optional ParamIndex. Stream parameters are tied to a specific stream on a port (input or
  * output).
  *
  * \tparam T param type C2Setting, C2Tuning or C2Info
  * \tparam S wrapped structure
- * \tparam BaseIndex optional base-index override. Must be specified for common/reused structures.
+ * \tparam ParamIndex optional paramter index override. Must be specified for base/reused
+ *         structures.
  *
  * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
  * structure can be accessed directly, and constructors and potential public methods are also
@@ -507,12 +515,12 @@
  * parameters with unspecified port expose a setPort method, and add an additional initial port
  * parameter to the constructor.
  */
-template<typename T, typename S, int BaseIndex=S::baseIndex, class Flex=void>
-struct C2_HIDE C2StreamParam : public T, public S, public C2BaseIndexOverride<S, BaseIndex>,
-        private C2StructCheck<S, BaseIndex,
+template<typename T, typename S, int ParamIndex=S::coreIndex, class Flex=void>
+struct C2_HIDE C2StreamParam : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
+        private C2StructCheck<S, ParamIndex,
                 T::indexFlags | T::Index::kStreamFlag | T::Index::kDirUndefined> {
 private:
-    typedef C2StreamParam<T, S, BaseIndex> _type;
+    typedef C2StreamParam<T, S, ParamIndex> _type;
 
 public:
     /// Default constructor. Port/direction and stream-ID is undefined.
@@ -531,8 +539,8 @@
     DEFINE_CAST_OPERATORS(_type)
 
     /// Specialization for an input stream parameter.
-    struct input : public T, public S, public C2BaseIndexOverride<S, BaseIndex>,
-            public C2StructCheck<S, BaseIndex,
+    struct input : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
+            public C2StructCheck<S, ParamIndex,
                     T::indexFlags | T::Index::kStreamFlag | T::Type::kDirInput> {
         /// Default constructor. Stream-ID is undefined.
         inline input() : T(sizeof(_type), input::typeIndex) { }
@@ -547,8 +555,8 @@
     };
 
     /// Specialization for an output stream parameter.
-    struct output : public T, public S, public C2BaseIndexOverride<S, BaseIndex>,
-            public C2StructCheck<S, BaseIndex,
+    struct output : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
+            public C2StructCheck<S, ParamIndex,
                     T::indexFlags | T::Index::kStreamFlag | T::Type::kDirOutput> {
         /// Default constructor. Stream-ID is undefined.
         inline output() : T(sizeof(_type), output::typeIndex) { }
@@ -567,12 +575,13 @@
  * Stream-parameter template for flexible structures.
  *
  * Base template to define a stream setting/tuning or info based on a flexible structure and
- * an optional BaseIndex. Stream parameters are tied to a specific stream on a port (input or
+ * an optional ParamIndex. Stream parameters are tied to a specific stream on a port (input or
  * output).
  *
  * \tparam T param type C2Setting, C2Tuning or C2Info
  * \tparam S wrapped flexible structure
- * \tparam BaseIndex optional base-index override. Must be specified for common/reused structures.
+ * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
+ *         structures.
  *
  * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
  * structures can be accessed via the m member variable; however, the constructors of the structure
@@ -583,13 +592,13 @@
  * parameters with unspecified port expose a setPort method, and add an additional initial port
  * parameter to the constructor.
  */
-template<typename T, typename S, int BaseIndex>
-struct C2_HIDE C2StreamParam<T, S, BaseIndex, IF_FLEXIBLE(S)>
-    : public T, public C2BaseIndexOverride<S, BaseIndex>,
-      private C2FlexStructCheck<S, BaseIndex,
+template<typename T, typename S, int ParamIndex>
+struct C2_HIDE C2StreamParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
+    : public T,
+      public C2FlexStructCheck<S, ParamIndex,
               T::indexFlags | T::Index::kStreamFlag | T::Index::kDirUndefined> {
 private:
-    typedef C2StreamParam<T, S> _type;
+    typedef C2StreamParam<T, S, ParamIndex> _type;
     /// Default constructor. Port/direction and stream-ID is undefined.
     inline C2StreamParam(size_t flexCount) : T(_type::calcSize(flexCount), _type::typeIndex, 0u) { }
     /// Wrapper around base structure's constructor while also specifying port/direction and
@@ -611,8 +620,8 @@
     DEFINE_CAST_OPERATORS(_type)
 
     /// Specialization for an input stream parameter.
-    struct input : public T, public C2BaseIndexOverride<S, BaseIndex>,
-            public C2FlexStructCheck<S, BaseIndex,
+    struct input : public T,
+            public C2FlexStructCheck<S, ParamIndex,
                     T::indexFlags | T::Index::kStreamFlag | T::Type::kDirInput> {
     private:
         /// Default constructor. Stream-ID is undefined.
@@ -633,8 +642,8 @@
     };
 
     /// Specialization for an output stream parameter.
-    struct output : public T, public C2BaseIndexOverride<S, BaseIndex>,
-            public C2FlexStructCheck<S, BaseIndex,
+    struct output : public T,
+            public C2FlexStructCheck<S, ParamIndex,
                     T::indexFlags | T::Index::kStreamFlag | T::Type::kDirOutput> {
     private:
         /// Default constructor. Stream-ID is undefined.
@@ -659,7 +668,7 @@
 
 /**
  * \ingroup internal
- * A structure template encapsulating a single element with default constructors and no base-index.
+ * A structure template encapsulating a single element with default constructors and no core-index.
  */
 template<typename T>
 struct C2SimpleValueStruct {
@@ -668,7 +677,7 @@
     inline C2SimpleValueStruct() = default;
     // Constructor with an initial value.
     inline C2SimpleValueStruct(T value) : mValue(value) {}
-    DEFINE_C2STRUCT_NO_BASE(SimpleValue)
+    DEFINE_BASE_C2STRUCT(SimpleValue)
 };
 
 // TODO: move this and next to some generic place
@@ -757,7 +766,7 @@
 
 /**
  * Specialization for a flexible blob and string arrays. A structure template encapsulating a single
- * flexible array member with default flexible constructors and no base-index. This type cannot be
+ * flexible array member with default flexible constructors and no core-index. This type cannot be
  * constructed on its own as it's size is 0.
  *
  * \internal This is different from C2SimpleArrayStruct<T[]> simply because its member has the name
@@ -770,7 +779,7 @@
     T mValue[];
 
     inline C2SimpleValueStruct() = default;
-    DEFINE_C2STRUCT_NO_BASE(SimpleValue)
+    DEFINE_BASE_C2STRUCT(SimpleValue)
     FLEX(C2SimpleValueStruct, mValue)
 
 private:
@@ -792,7 +801,7 @@
 
 /**
  * A structure template encapsulating a single flexible array element of a specific type (T) with
- * default constructors and no base-index. This type cannot be constructed on its own as it's size
+ * default constructors and no core-index. This type cannot be constructed on its own as it's size
  * is 0. Instead, it is meant to be used as a parameter, e.g.
  *
  *   typedef C2StreamParam<C2Info, C2SimpleArrayStruct<C2MyFancyStruct>,
@@ -806,8 +815,8 @@
     T mValues[]; ///< array member
     /// Default constructor
     inline C2SimpleArrayStruct() = default;
-    DEFINE_C2STRUCT_NO_BASE(SimpleArray)
-    FLEX(C2SimpleArrayStruct, mValues)
+    DEFINE_BASE_FLEX_C2STRUCT(SimpleArray, mValues)
+    //FLEX(C2SimpleArrayStruct, mValues)
 
 private:
     /// Construct from a C2MemoryBlock.
diff --git a/media/libstagefright/codec2/include/C2Work.h b/media/libstagefright/codec2/include/C2Work.h
index a42d11a..105cf81 100644
--- a/media/libstagefright/codec2/include/C2Work.h
+++ b/media/libstagefright/codec2/include/C2Work.h
@@ -28,42 +28,56 @@
 #include <list>
 #include <vector>
 
-typedef int status_t;
-
 namespace android {
 
 /// \defgroup work Work and data processing
 /// @{
 
+/**
+ * Information describing the reason a parameter settings may fail, or
+ * may be overriden.
+ */
 struct C2SettingResult {
-    enum Failure {
+    enum Failure : uint32_t {
         READ_ONLY,  ///< parameter is read-only and cannot be set
         MISMATCH,   ///< parameter mismatches input data
         BAD_VALUE,  ///< parameter does not accept value
         BAD_TYPE,   ///< parameter is not supported
         BAD_PORT,   ///< parameter is not supported on the specific port
         BAD_INDEX,  ///< parameter is not supported on the specific stream
-        CONFLICT,   ///< parameter is in conflict with another setting
+        CONFLICT,   ///< parameter is in conflict with an/other setting(s)
+        /// parameter is out of range due to other settings (this failure mode
+        /// can only be used for strict parameters)
+        UNSUPPORTED,
+
+
+        /// requested parameter value is in conflict with an/other setting(s)
+        /// and has been corrected to the closest supported value. This failure
+        /// mode is given to provide suggestion to the client as to how to
+        /// enable the requested parameter value.
+        INFO_CONFLICT,
     };
 
-    C2ParamField field;
-    Failure failure;
-    std::unique_ptr<C2FieldSupportedValues> supportedValues; //< if different from normal (e.g. in conflict w/another param or input data)
-    std::list<C2ParamField> conflictingFields;
+    Failure failure;    ///< failure code
+
+    /// Failing (or corrected) field. Currently supported values for the field. This is set if
+    /// different from the globally supported values (e.g. due to restrictions by another param or
+    /// input data)
+    /// \todo need to define suggestions for masks to be set and unset.
+    C2ParamFieldValues field;
+
+    /// Conflicting parameters or fields with optional suggestions with (optional) suggested values
+    /// for any conflicting fields to avoid the conflict.
+    std::list<C2ParamFieldValues> conflicts;
 };
 
 // ================================================================================================
 //  WORK
 // ================================================================================================
 
-// node_id-s
-typedef uint32_t node_id;
-
-enum flags_t : uint32_t {
-    BUFFERFLAG_CODEC_CONFIG,
-    BUFFERFLAG_DROP_FRAME,
-    BUFFERFLAG_END_OF_STREAM,
-};
+// c2_node_id_t-s
+typedef uint32_t c2_node_id_t;
+typedef c2_node_id_t c2_node_id_t;
 
 enum {
     kParamIndexWorkOrdinal,
@@ -82,6 +96,12 @@
 
 struct C2BufferPack {
 //public:
+    enum flags_t : uint32_t {
+        FLAG_CODEC_CONFIG  = (1 << 0),
+        FLAG_DROP_FRAME    = (1 << 1),
+        FLAG_END_OF_STREAM = (1 << 2),
+    };
+
     flags_t  flags;
     C2WorkOrdinalStruct ordinal;
     std::vector<std::shared_ptr<C2Buffer>> buffers;
@@ -94,13 +114,13 @@
 struct C2Worklet {
 //public:
     // IN
-    node_id component;
+    c2_node_id_t component;
 
     std::list<std::unique_ptr<C2Param>> tunings; //< tunings to be applied before processing this
                                                  // worklet
     std::list<C2Param::Type> requestedInfos;
-    std::vector<std::shared_ptr<C2BlockAllocator>> allocators; //< This vector shall be the same size as
-                                                          //< output.buffers.
+    std::vector<std::shared_ptr<C2BlockPool>> allocators; //< This vector shall be the same size as
+                                                          //< output.buffers. \deprecated
 
     // OUT
     C2BufferPack output;
@@ -146,13 +166,13 @@
     std::list<std::unique_ptr<C2Worklet>> worklets;
 
     uint32_t worklets_processed;
-    status_t result;
+    c2_status_t result;
 };
 
 struct C2WorkOutline {
 //public:
     C2WorkOrdinalStruct ordinal;
-    std::list<node_id> chain;
+    std::list<c2_node_id_t> chain;
 };
 
 /// @}
diff --git a/media/libstagefright/codec2/tests/Android.bp b/media/libstagefright/codec2/tests/Android.bp
new file mode 100644
index 0000000..cf75061
--- /dev/null
+++ b/media/libstagefright/codec2/tests/Android.bp
@@ -0,0 +1,106 @@
+cc_test {
+    name: "codec2_param_test",
+
+    tags: [
+        "tests",
+    ],
+
+    srcs: [
+        "C2Param_test.cpp",
+        "vndk/C2UtilTest.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/codec2/include",
+        "frameworks/av/media/libstagefright/codec2/vndk/include",
+    ],
+
+    // param tests must not depend on any codec2 libraries as all params should be templated
+    shared_libs: [
+    ],
+
+    static_libs: [
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-std=c++14",
+    ],
+}
+
+cc_test {
+    name: "codec2_test",
+
+    tags: [
+        "tests",
+    ],
+
+    srcs: [
+        "vndk/C2BufferTest.cpp",
+        "C2_test.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/codec2/include",
+        "frameworks/av/media/libstagefright/codec2/vndk/include",
+    ],
+
+    shared_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+        "libcutils",
+        "libhidlbase",
+        "libion",
+        "liblog",
+        "libstagefright_codec2",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libstagefright_codec2_vndk",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-std=c++14",
+    ],
+}
+
+cc_test {
+    name: "codec2_interface_test",
+
+    tags: [
+        "tests",
+    ],
+
+    srcs: [
+        "C2ComponentInterface_test.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/codec2/include",
+        "frameworks/av/media/libstagefright/codec2/vndk/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "libhidlbase",
+        "libion",
+        "liblog",
+        "libstagefright_codec2",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libstagefright_codec2_vndk",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-std=c++14",
+    ],
+}
diff --git a/media/libstagefright/codec2/tests/Android.mk b/media/libstagefright/codec2/tests/Android.mk
deleted file mode 100644
index 49c4253..0000000
--- a/media/libstagefright/codec2/tests/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := codec2_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-	vndk/C2UtilTest.cpp \
-	C2_test.cpp \
-	C2Param_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libstagefright_codec2 \
-	liblog
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/media/libstagefright/codec2/include \
-	frameworks/av/media/libstagefright/codec2/vndk/include \
-	$(TOP)/frameworks/native/include/media/openmax \
-
-LOCAL_CFLAGS += -Werror -Wall -std=c++14
-LOCAL_CLANG := true
-
-include $(BUILD_NATIVE_TEST)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp b/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp
new file mode 100644
index 0000000..0613b5a
--- /dev/null
+++ b/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp
@@ -0,0 +1,714 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "C2ComponentInterface_test"
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+
+#if !defined(UNUSED)
+#define UNUSED(expr)                                                           \
+  do {                                                                         \
+      (void)(expr);                                                            \
+  } while (0)
+
+#endif //!defined(UNUSED)
+
+namespace android {
+
+template <class T> std::unique_ptr<T> alloc_unique_cstr(const char *cstr) {
+    size_t len = strlen(cstr);
+    std::unique_ptr<T> ptr = T::alloc_unique(len);
+    memcpy(ptr->m.mValue, cstr, len);
+    return ptr;
+}
+
+class C2CompIntfTest : public ::testing::Test {
+protected:
+    C2CompIntfTest() {}
+    ~C2CompIntfTest() override {}
+
+    void setComponent(std::shared_ptr<C2ComponentInterface> intf) {
+        mIntf = intf;
+    }
+
+    void resetResults() {
+        mIntf = nullptr;
+        mParamResults.clear();
+    }
+
+    template <typename T> void testUnsupportedParam();
+
+    template <typename T> void testSupportedParam();
+
+    // testReadOnlyParam() and testWritableParam() are the main functions for testing a parameter.
+    // A caller should find out if a tested parameter is read-only or writable before calling them
+    // and it must call one of the corresponded them.
+
+    // If a parameter is read-only this is called.
+    // Test read-only parameter |preParam|. The test expects failure while config() with |newParam|,
+    // and make sure |preParam| stay unchanged.
+    template <typename T>
+    void testReadOnlyParam(const T &preParam, const T &newParam);
+
+    // If a parameter is writable this is called.
+    // Test one filed |writableField| for given writable parameter |param|.
+    // |validValues| contains all values obtained from querySupportedValues() for |writableField|.
+    // The test checks validity for config() with each value, and make sure values are config-ed
+    // by query() them out. |invalidValues| contains some values which are not in |validValues|.
+    // The test expects C2_BAD_VALUE while config() with these values,
+    // and |param| should stay unchanged.
+    template <typename TParam, typename TRealField, typename TField>
+    void testWritableParam(TParam *const param, TRealField *const writableField,
+                           const std::vector<TField> &validValues,
+                           const std::vector<TField> &invalidValues);
+
+    // Test all the defined parameters in C2Param.h.
+    void testMain(std::shared_ptr<C2ComponentInterface> intf,
+                  const std::string &componentName);
+
+    // Check permission of parameter type |T| for testing interface.
+    // This should be called first of the testing per parameter type,
+    // therefore different testing process is applied according to the permission type.
+    template <typename T>
+    void checkParamPermission(
+            int *const writable,
+            const std::vector<std::shared_ptr<C2ParamDescriptor>> &supportedParams);
+
+private:
+    enum ParamPermission : int {
+        WRITABLE,
+        READONLY,
+        UNSUPPORTED,
+    };
+
+    struct paramTestInfo {
+        std::string name;
+        int result;
+        paramTestInfo(const char *name_, int result_)
+            : name(name_), result(result_) {}
+    };
+
+    // queryOnStack() and queryonHeap() both call an interface's query_nb() and
+    // check if a component has a parameter whose type is |T|.
+    // If a component has, the value should be copied into an argument, that is
+    // |p| in queryOnStack() and |heapParams| in queryOnHeap().
+    // The return value is c2_status_t (e.g. C2_OK).
+    template <typename T> c2_status_t queryOnStack(T *const p);
+
+    template <typename T>
+    c2_status_t queryOnHeap(const T &p,
+                         std::vector<std::unique_ptr<C2Param>> *const heapParams);
+
+    // Get a value whose type is |T| in a component. The value is copied to |param|.
+    // This should be called only if a component has the parameter.
+    template <typename T> void getValue(T *const param);
+
+    // Check if the parameter's value in component is equal to |expected| and
+    // queryOnStack() and queryOnHeap() are succeeded. When this function called,
+    // it should be guaranteed a component has the parameter.
+    template <typename T> void queryParamAsExpected(const T &expected);
+
+    // Test if query functions works correctly for supported parameters.
+    // "Support" means here a component has the parameter.
+    template <typename T> void querySupportedParam();
+
+    // Test query functions works correctly for unsupported parameters.
+    // "Unsupport" means here a component doesn't have the parameter.
+    template <typename T> void queryUnsupportedParam();
+
+    // Execute an interface's config_nb(). |T| is a single parameter type, not std::vector.
+    // config() creates std::vector<C2Param *const> {p} and passes it to config_nb().
+    template <typename T>
+    c2_status_t
+    config(T *const p,
+           std::vector<std::unique_ptr<C2SettingResult>> *const failures);
+
+    // Test if config works correctly for read-only parameters.
+    // Because the failure of config() is assumed, |newParam| doesn't matter.
+    template <typename T> void configReadOnlyParam(const T &newParam);
+
+    // Test if config works correctly for writable parameters.
+    // This changes the parameter's value to |newParam|.
+    // |stConfig| is a return value of config().
+    template <typename T> void configWritableParamValidValue(const T &newParam, c2_status_t *stConfig);
+
+    // Test if config works correctly in the case an invalid value |newParam| is tried to write
+    // to an writable parameter.
+    template <typename T> void configWritableParamInvalidValue(const T &newParam);
+
+    // Create values for testing from |validValueInfos|. The values are returned as arguments.
+    // |validValues| : valid values, which can be written for the parameter.
+    // |InvalidValues| : invalid values, which cannot be written for the parameter.
+    //                   config() should be failed if these values are used as new values.
+    // This function should be called only for writable and supported parameters.
+    template <typename TField>
+    void getTestValues(const C2FieldSupportedValues &validValueInfos,
+                       std::vector<TField> *const validValues,
+                       std::vector<TField> *const invalidValues);
+
+    // Output the summary of test results. Categorizes parameters with their configuration.
+    void outputResults(const std::string &name);
+
+    std::shared_ptr<C2ComponentInterface> mIntf;
+    std::vector<paramTestInfo> mParamResults;
+    std::string mCurrentParamName;
+};
+
+// factory function
+// TODO(hiroh): Add factory functions for other types.
+template <typename T> std::unique_ptr<T> makeParam() {
+    return std::make_unique<T>();
+}
+
+template <> std::unique_ptr<C2PortMimeConfig::input> makeParam() {
+    // TODO(hiroh): Set more precise length.
+    return C2PortMimeConfig::input::alloc_unique(100);
+}
+
+#define TRACED_FAILURE(func)                            \
+    do {                                                \
+        SCOPED_TRACE(mCurrentParamName);             \
+        func;                                           \
+        if (::testing::Test::HasFatalFailure()) {       \
+            return;                                     \
+        }                                               \
+    } while (false)
+
+template <typename T> c2_status_t C2CompIntfTest::queryOnStack(T *const p) {
+    std::vector<C2Param *const> stackParams{p};
+    return mIntf->query_nb(stackParams, {}, nullptr);
+}
+
+template <typename T>
+c2_status_t C2CompIntfTest::queryOnHeap(
+        const T &p, std::vector<std::unique_ptr<C2Param>> *const heapParams) {
+    uint32_t index = p.type();
+    if (p.forStream()) {
+        index |= ((p.stream() << 17) & 0x01FE0000) | 0x02000000;
+    }
+    return mIntf->query_nb({}, {index}, heapParams);
+}
+
+template <typename T> void C2CompIntfTest::getValue(T *const param) {
+    // When getValue() is called, a component has to have the parameter.
+    ASSERT_EQ(C2_OK, queryOnStack(param));
+}
+
+template <typename T>
+void C2CompIntfTest::queryParamAsExpected(const T &expected) {
+    // TODO(hiroh): Don't create param on stack and call queryOnStack for flex params.
+    // Note that all the current supported parameters are non-flex params.
+    T stack;
+    std::unique_ptr<T> pHeap = makeParam<T>();
+    std::vector<std::unique_ptr<C2Param>> heapParams;
+
+    ASSERT_EQ(C2_OK, queryOnStack(&stack));
+
+    // |stack| is a parameter value. The parameter size shouldn't be 0.
+    EXPECT_NE(0u, stack.size());
+    EXPECT_EQ(stack, expected);
+
+    ASSERT_EQ(C2_OK, queryOnHeap(*pHeap, &heapParams));
+
+    // |*heapParams[0]| is a parameter value. The size of |heapParams| has to be one.
+    ASSERT_EQ(1u, heapParams.size());
+    EXPECT_TRUE(heapParams[0]);
+    EXPECT_EQ(*heapParams[0], expected);
+}
+
+template <typename T> void C2CompIntfTest::querySupportedParam() {
+    std::unique_ptr<T> param = makeParam<T>();
+    // The current parameter's value is acquired by getValue(), which should be succeeded.
+    getValue(param.get());
+    queryParamAsExpected(*param);
+}
+
+template <typename T> void C2CompIntfTest::queryUnsupportedParam() {
+    // TODO(hiroh): Don't create param on stack and call queryOnStack for flex params.
+    // Note that all the current supported parameters are non-flex params.
+    T stack;
+    std::unique_ptr<T> pHeap = makeParam<T>();
+    std::vector<std::unique_ptr<C2Param>> heapParams;
+    // If a component doesn't have the parameter, queryOnStack() and queryOnHeap()
+    // should return C2_BAD_INDEX.
+    ASSERT_EQ(C2_BAD_INDEX, queryOnStack(&stack));
+    EXPECT_FALSE(stack);
+    ASSERT_EQ(C2_BAD_INDEX, queryOnHeap(*pHeap, &heapParams));
+    EXPECT_EQ(0u, heapParams.size());
+}
+
+template <typename T>
+c2_status_t C2CompIntfTest::config(
+        T *const p, std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
+    std::vector<C2Param *const> params{p};
+    return mIntf->config_nb(params, failures);
+}
+
+// Create a new parameter copied from |p|.
+template <typename T> std::unique_ptr<T> makeParamFrom(const T &p) {
+    std::unique_ptr<T> retP = makeParam<T>();
+    EXPECT_TRUE(retP->updateFrom(p));
+    EXPECT_TRUE(memcmp(retP.get(), &p, sizeof(T)) == 0);
+    return retP;
+}
+
+template <typename T>
+void C2CompIntfTest::configReadOnlyParam(const T &newParam) {
+    std::unique_ptr<T> p = makeParamFrom(newParam);
+
+    std::vector<C2Param *const> params{p.get()};
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+
+    // config_nb should be failed because a parameter is read-only.
+    ASSERT_EQ(C2_BAD_VALUE, mIntf->config_nb(params, &failures));
+    ASSERT_EQ(1u, failures.size());
+    EXPECT_EQ(C2SettingResult::READ_ONLY, failures[0]->failure);
+}
+
+template <typename T>
+void C2CompIntfTest::configWritableParamValidValue(const T &newParam, c2_status_t *configResult) {
+    std::unique_ptr<T> p = makeParamFrom(newParam);
+
+    std::vector<C2Param *const> params{p.get()};
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+    // In most cases, config_nb return C2_OK and the parameter's value should be changed
+    // to |newParam|, which is confirmed in a caller of configWritableParamValueValue().
+    // However, this can return ~~~~ and the parameter's values is not changed,
+    // because there may be dependent limitations between fields or between parameters.
+    // TODO(hiroh): I have to fill the return value. Comments in C2Component.h doesn't mention
+    // about the return value when conflict happens. I set C2_BAD_VALUE to it temporarily now.
+    c2_status_t stConfig = mIntf->config_nb(params, &failures);
+    if (stConfig == C2_OK) {
+        EXPECT_EQ(0u, failures.size());
+    } else {
+        ASSERT_EQ(C2_BAD_VALUE, stConfig);
+        EXPECT_EQ(1u, failures.size());
+        EXPECT_EQ(C2SettingResult::CONFLICT, failures[0]->failure);
+    }
+    *configResult = stConfig;
+}
+
+template <typename T>
+void C2CompIntfTest::configWritableParamInvalidValue(const T &newParam) {
+    std::unique_ptr<T> p = makeParamFrom(newParam);
+
+    std::vector<C2Param *const> params{p.get()};
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+    // Although a parameter is writable, config_nb should be failed,
+    // because a new value is invalid.
+    ASSERT_EQ(C2_BAD_VALUE, mIntf->config_nb(params, &failures));
+    ASSERT_EQ(1u, failures.size());
+    EXPECT_EQ(C2SettingResult::BAD_VALUE, failures[0]->failure);
+}
+
+// There is only used enum type for the field type, that is C2DomainKind.
+// If another field type is added, it is necessary to add function for that.
+template <>
+void C2CompIntfTest::getTestValues(
+        const C2FieldSupportedValues &validValueInfos,
+        std::vector<C2DomainKind> *const validValues,
+        std::vector<C2DomainKind> *const invalidValues) {
+    UNUSED(validValueInfos);
+    validValues->emplace_back(C2DomainVideo);
+    validValues->emplace_back(C2DomainAudio);
+    validValues->emplace_back(C2DomainOther);
+
+    // There is no invalid value.
+    UNUSED(invalidValues);
+}
+
+template <typename TField>
+void C2CompIntfTest::getTestValues(
+        const C2FieldSupportedValues &validValueInfos,
+        std::vector<TField> *const validValues,
+        std::vector<TField> *const invalidValues) {
+
+    // The supported values are represented by C2Values. C2Value::Primitive needs to
+    // be transformed to a primitive value. This function is one to do that.
+    auto prim2Value = [](const C2Value::Primitive &prim) -> TField {
+        if (std::is_same<TField, int32_t>::value) {
+            return prim.i32;
+        } else if (std::is_same<TField, uint32_t>::value) {
+            return prim.u32;
+        } else if (std::is_same<TField, int64_t>::value) {
+            return prim.i64;
+        } else if (std::is_same<TField, uint64_t>::value) {
+            return prim.u64;
+        } else if (std::is_same<TField, float>::value) {
+            return prim.fp;
+        }
+        static_assert(std::is_same<TField, int32_t>::value ||
+                      std::is_same<TField, uint32_t>::value ||
+                      std::is_same<TField, int64_t>::value ||
+                      std::is_same<TField, uint64_t>::value ||
+                      std::is_same<TField, float>::value, "Invalid TField type.");
+        return 0;
+    };
+
+    // The size of validValueInfos is one.
+    const auto &c2FSV = validValueInfos;
+
+    switch (c2FSV.type) {
+    case C2FieldSupportedValues::Type::EMPTY: {
+        invalidValues->emplace_back(TField(0));
+        // TODO(hiroh) : Should other invalid values be tested?
+        break;
+    }
+    case C2FieldSupportedValues::Type::RANGE: {
+        const auto &range = c2FSV.range;
+        auto rmin = prim2Value(range.min);
+        auto rmax = prim2Value(range.max);
+        auto rstep = prim2Value(range.step);
+
+        ASSERT_LE(rmin, rmax);
+
+        if (rstep != 0) {
+            // Increase linear
+            for (auto v = rmin; v <= rmax; v += rstep) {
+                validValues->emplace_back(v);
+            }
+            if (rmin > std::numeric_limits<TField>::min()) {
+                invalidValues->emplace_back(rmin - 1);
+            }
+            if (rmax < std::numeric_limits<TField>::max()) {
+                invalidValues->emplace_back(rmax + 1);
+            }
+            const unsigned int N = validValues->size();
+            if (N >= 2) {
+                if (std::is_same<TField, float>::value) {
+                    invalidValues->emplace_back((validValues->at(0) + validValues->at(1)) / 2);
+                    invalidValues->emplace_back((validValues->at(N - 2) + validValues->at(N - 1)) / 2);
+                } else {
+                    if (rstep > 1) {
+                        invalidValues->emplace_back(validValues->at(0) + 1);
+                        invalidValues->emplace_back(validValues->at(N - 1) - 1);
+                    }
+                }
+            }
+        } else {
+            // There should be two cases, except linear case.
+            // 1. integer geometric case
+            // 2. float geometric case
+
+            auto nom = prim2Value(range.nom);
+            auto denom = prim2Value(range.denom);
+
+            // If both range.nom and range.denom are 1 and step is 0, we should use
+            // VALUES, shouldn't we?
+            ASSERT_FALSE(nom == 1 && denom == 1);
+
+            // (nom / denom) is not less than 1.
+            ASSERT_FALSE(denom == 0);
+            ASSERT_LE(denom, nom);
+            for (auto v = rmin; v <= rmax; v = v * nom / denom) {
+                validValues->emplace_back(v);
+            }
+
+            if (rmin > std::numeric_limits<TField>::min()) {
+                invalidValues->emplace_back(rmin - 1);
+            }
+            if (rmax < std::numeric_limits<TField>::max()) {
+                invalidValues->emplace_back(rmax + 1);
+            }
+
+            const unsigned int N = validValues->size();
+            if (N >= 2) {
+                if (std::is_same<TField, float>::value) {
+                    invalidValues->emplace_back((validValues->at(0) + validValues->at(1)) / 2);
+                    invalidValues->emplace_back((validValues->at(N - 2) + validValues->at(N - 1)) / 2);
+                } else {
+                    if (validValues->at(1) - validValues->at(0) > 1) {
+                        invalidValues->emplace_back(validValues->at(0) + 1);
+                    }
+                    if (validValues->at(N - 1) - validValues->at(N - 2) > 1) {
+                        invalidValues->emplace_back(validValues->at(N - 1) - 1);
+                    }
+                }
+            }
+        }
+        break;
+    }
+    case C2FieldSupportedValues::Type::VALUES: {
+        for (const C2Value::Primitive &prim : c2FSV.values) {
+            validValues->emplace_back(prim2Value(prim));
+        }
+        auto minv = *std::min_element(validValues->begin(), validValues->end());
+        auto maxv = *std::max_element(validValues->begin(), validValues->end());
+        if (minv - 1 > std::numeric_limits<TField>::min()) {
+            invalidValues->emplace_back(minv - 1);
+        }
+        if (maxv + 1 < std::numeric_limits<TField>::max()) {
+            invalidValues->emplace_back(maxv + 1);
+        }
+        break;
+    }
+    case C2FieldSupportedValues::Type::FLAGS: {
+        // TODO(hiroh) : Implement the case that param.type is FLAGS.
+        break;
+    }
+    }
+}
+
+template <typename T>
+void C2CompIntfTest::testReadOnlyParam(const T &preParam, const T &newParam) {
+    TRACED_FAILURE(configReadOnlyParam(newParam));
+    // Parameter value must not be changed
+    TRACED_FAILURE(queryParamAsExpected(preParam));
+}
+
+template <typename TParam, typename TRealField, typename TField>
+void C2CompIntfTest::testWritableParam(
+        TParam *const param, TRealField *const writableField,
+        const std::vector<TField> &validValues,
+        const std::vector<TField> &invalidValues) {
+    c2_status_t stConfig;
+
+    // Get the parameter's value in the beginning in order to reset the value at the end.
+    TRACED_FAILURE(getValue(param));
+    std::unique_ptr<TParam> defaultParam = makeParamFrom(*param);
+
+    // Test valid values
+    for (const auto &val : validValues) {
+        std::unique_ptr<TParam> preParam = makeParamFrom(*param);
+
+        // Param is try to be changed
+        *writableField = val;
+        TRACED_FAILURE(configWritableParamValidValue(*param, &stConfig));
+        if (stConfig == C2_OK) {
+            TRACED_FAILURE(queryParamAsExpected(*param));
+        } else {
+            // Param is unchanged because a field value conflicts with other field or parameter.
+            TRACED_FAILURE(queryParamAsExpected(*preParam));
+        }
+    }
+
+    // Store the current parameter in order to test |param| is unchanged
+    // after trying to write an invalid value.
+    std::unique_ptr<TParam> lastValidParam = makeParamFrom(*param);
+
+    // Test invalid values
+    for (const auto &val : invalidValues) {
+        // Param is changed
+        *writableField = val;
+        TRACED_FAILURE(configWritableParamInvalidValue(*param));
+        TRACED_FAILURE(queryParamAsExpected(*lastValidParam));
+    }
+    // Reset the parameter by config().
+    TRACED_FAILURE(configWritableParamValidValue(*defaultParam, &stConfig));
+}
+
+template <typename T> void C2CompIntfTest::testUnsupportedParam() {
+    TRACED_FAILURE(queryUnsupportedParam<T>());
+}
+
+template <typename T> void C2CompIntfTest::testSupportedParam() {
+    TRACED_FAILURE(querySupportedParam<T>());
+}
+
+bool isSupportedParam(
+        const C2Param &param,
+        const std::vector<std::shared_ptr<C2ParamDescriptor>> &sParams) {
+    for (const auto &pd : sParams) {
+        if (param.type() == pd->type().type()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+template <typename T>
+void C2CompIntfTest::checkParamPermission(
+    int *const result,
+    const std::vector<std::shared_ptr<C2ParamDescriptor>> &supportedParams) {
+    std::unique_ptr<T> param = makeParam<T>();
+
+    if (!isSupportedParam(*param, supportedParams)) {
+        // If a parameter isn't supported, it just finish after calling testUnsupportedParam().
+        testUnsupportedParam<T>();
+        *result = ParamPermission::UNSUPPORTED;
+        return;
+    }
+
+    testSupportedParam<T>();
+
+    TRACED_FAILURE(getValue(param.get()));
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+    // Config does not change the parameter, because param is the present param.
+    // This config is executed to find out if a parameter is read-only or writable.
+    c2_status_t stStack = config(param.get(), &failures);
+    if (stStack == C2_BAD_VALUE) {
+        // Read-only
+        std::unique_ptr<T> newParam = makeParam<T>();
+        testReadOnlyParam(*param, *newParam);
+        *result = ParamPermission::READONLY;
+    } else {
+        // Writable
+        EXPECT_EQ(stStack, C2_OK);
+        *result = ParamPermission::WRITABLE;
+    }
+}
+
+void C2CompIntfTest::outputResults(const std::string &name) {
+    std::vector<std::string> params[3];
+    for (const auto &testInfo : mParamResults) {
+        int result = testInfo.result;
+        ASSERT_TRUE(0 <= result && result <= 2);
+        params[result].emplace_back(testInfo.name);
+    }
+    const char *resultString[] = {"Writable", "Read-Only", "Unsupported"};
+    printf("\n----TEST RESULTS (%s)----\n\n", name.c_str());
+    for (int i = 0; i < 3; i++) {
+        printf("[ %s ]\n", resultString[i]);
+        for (const auto &t : params[i]) {
+            printf("%s\n", t.c_str());
+        }
+        printf("\n");
+    }
+}
+
+#define TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, field_name_) \
+    do {                                                                \
+        std::unique_ptr<TParam_> param = makeParam<TParam_>();          \
+        std::vector<C2FieldSupportedValuesQuery> validValueInfos = {    \
+            C2FieldSupportedValuesQuery::Current(                       \
+                    C2ParamField(param.get(), &field_type_name_::field_name_)) \
+        };                                                              \
+        ASSERT_EQ(C2_OK,                                                \
+                  mIntf->querySupportedValues_nb(validValueInfos));     \
+        ASSERT_EQ(1u, validValueInfos.size());                          \
+        std::vector<decltype(param->field_name_)> validValues;          \
+        std::vector<decltype(param->field_name_)> invalidValues;        \
+        getTestValues(validValueInfos[0].values, &validValues, &invalidValues);   \
+        testWritableParam(param.get(), &param->field_name_, validValues,\
+                          invalidValues);                               \
+    } while (0)
+
+#define TEST_VSSTRUCT_WRITABLE_FIELD(TParam_, field_type_name_)         \
+    do {                                                                \
+        TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, mWidth); \
+        TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, mHeight);\
+    } while (0)
+
+#define TEST_U32_WRITABLE_FIELD(TParam_, field_type_name_)              \
+  TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, mValue)
+
+#define TEST_ENUM_WRITABLE_FIELD(TParam_, field_type_name_)             \
+  TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, mValue)
+
+// TODO(hiroh): Support parameters based on char[] and uint32_t[].
+//#define TEST_STRING_WRITABLE_FIELD(TParam_, field_type_name_)
+// TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, m.mValue)
+//#define TEST_U32ARRAY_WRITABLE_FIELD(Tparam_, field_type_name_)
+// TEST_GENERAL_WRITABLE_FIELD(Tparam_, uint32_t[], field_type_name_, mValues)
+
+#define EACH_TEST(TParam_, field_type_name_, test_name)                 \
+    do {                                                                \
+      int result = 0;                                                   \
+      this->mCurrentParamName = #TParam_;                            \
+      checkParamPermission<TParam_>(&result, supportedParams);          \
+      if (result == ParamPermission::WRITABLE) {                        \
+          test_name(TParam_, field_type_name_);                         \
+      }                                                                 \
+      mParamResults.emplace_back(#TParam_, result);                      \
+  } while (0)
+
+#define EACH_TEST_SELF(type_, test_name) EACH_TEST(type_, type_, test_name)
+#define EACH_TEST_INPUT(type_, test_name) EACH_TEST(type_::input, type_, test_name)
+#define EACH_TEST_OUTPUT(type_, test_name) EACH_TEST(type_::output, type_, test_name)
+void C2CompIntfTest::testMain(std::shared_ptr<C2ComponentInterface> intf,
+                              const std::string &componentName) {
+    setComponent(intf);
+
+    std::vector<std::shared_ptr<C2ParamDescriptor>> supportedParams;
+    ASSERT_EQ(C2_OK, mIntf->querySupportedParams_nb(&supportedParams));
+
+    EACH_TEST_SELF(C2ComponentLatencyInfo, TEST_U32_WRITABLE_FIELD);
+    EACH_TEST_SELF(C2ComponentTemporalInfo, TEST_U32_WRITABLE_FIELD);
+    EACH_TEST_INPUT(C2PortLatencyInfo, TEST_U32_WRITABLE_FIELD);
+    EACH_TEST_OUTPUT(C2PortLatencyInfo, TEST_U32_WRITABLE_FIELD);
+    EACH_TEST_INPUT(C2StreamFormatConfig, TEST_U32_WRITABLE_FIELD);
+    EACH_TEST_OUTPUT(C2StreamFormatConfig, TEST_U32_WRITABLE_FIELD);
+    EACH_TEST_INPUT(C2PortStreamCountConfig, TEST_U32_WRITABLE_FIELD);
+    EACH_TEST_OUTPUT(C2PortStreamCountConfig, TEST_U32_WRITABLE_FIELD);
+
+    EACH_TEST_SELF(C2ComponentDomainInfo, TEST_ENUM_WRITABLE_FIELD);
+
+    // TODO(hiroh): Support parameters based on uint32_t[] and char[].
+    // EACH_TEST_INPUT(C2PortMimeConfig, TEST_STRING_WRITABLE_FIELD);
+    // EACH_TEST_OUTPUT(C2PortMimeConfig, TEST_STRING_WRITABLE_FIELD);
+    // EACH_TEST_INPUT(C2StreamMimeConfig, TEST_STRING_WRITABLE_FIELD);
+    // EACH_TEST_OUTPUT(C2StreamMimeConfig, TEST_STRING_WRITABLE_FIELD);
+
+    // EACH_TEST_SELF(C2SupportedParamsInfo, TEST_U32ARRAY_WRITABLE_FIELD);
+    // EACH_TEST_SELF(C2RequiredParamsInfo, TEST_U32ARRAY_WRITABLE_FIELD);
+    // EACH_TEST_SELF(C2ReadOnlyParamsInfo, TEST_U32ARRAY_WRITABLE_FIELD);
+    // EACH_TEST_SELF(C2RequestedInfosInfo, TEST_U32ARRAY_WRITABLE_FIELD);
+
+    EACH_TEST_INPUT(C2VideoSizeStreamInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
+    EACH_TEST_OUTPUT(C2VideoSizeStreamInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
+    EACH_TEST_INPUT(C2VideoSizeStreamTuning, TEST_VSSTRUCT_WRITABLE_FIELD);
+    EACH_TEST_OUTPUT(C2VideoSizeStreamTuning, TEST_VSSTRUCT_WRITABLE_FIELD);
+    EACH_TEST_INPUT(C2MaxVideoSizeHintPortSetting, TEST_VSSTRUCT_WRITABLE_FIELD);
+    EACH_TEST_OUTPUT(C2MaxVideoSizeHintPortSetting, TEST_VSSTRUCT_WRITABLE_FIELD);
+
+    outputResults(componentName);
+    resetResults();
+}
+
+TEST_F(C2CompIntfTest, C2V4L2CodecIntf) {
+
+    // Read a shared object library.
+    void* compLib = dlopen("system/lib/libv4l2_codec2.so", RTLD_NOW);
+
+    if (!compLib) {
+        printf("Cannot open library: %s.\n", dlerror());
+        FAIL();
+        return;
+    }
+
+    typedef C2ComponentStore* create_t();
+    create_t* create_store= (create_t*) dlsym(compLib, "create_store");
+    const char* dlsym_error = dlerror();
+    if (dlsym_error) {
+        printf("Cannot load symbol create: %s.\n", dlsym_error);
+        FAIL();
+        return;
+    }
+
+    typedef void destroy_t(C2ComponentStore*);
+    destroy_t* destroy_store = (destroy_t*) dlsym(compLib, "destroy_store");
+    dlsym_error = dlerror();
+    if (dlsym_error) {
+        printf("Cannot load symbol destroy: %s.\n", dlsym_error);
+        FAIL();
+        return;
+    }
+
+    std::shared_ptr<C2ComponentStore> componentStore(create_store(), destroy_store);
+    std::shared_ptr<C2ComponentInterface> componentIntf;
+    componentStore->createInterface("v4l2.decoder", &componentIntf);
+    auto componentName = "C2V4L2Codec";
+    testMain(componentIntf, componentName);
+}
+
+} // namespace android
diff --git a/media/libstagefright/codec2/tests/C2Param_test.cpp b/media/libstagefright/codec2/tests/C2Param_test.cpp
index ec82c84..a688d2c 100644
--- a/media/libstagefright/codec2/tests/C2Param_test.cpp
+++ b/media/libstagefright/codec2/tests/C2Param_test.cpp
@@ -19,6 +19,7 @@
 
 #include <gtest/gtest.h>
 
+#define __C2_GENERATE_GLOBAL_VARS__
 #include <util/C2ParamUtils.h>
 #include <C2ParamDef.h>
 
@@ -92,9 +93,9 @@
 struct C2SizeStruct {
     int32_t mNumber;
     int32_t mHeight;
-    enum : uint32_t { baseIndex = kParamIndexSize };                        // <= needed for C2FieldDescriptor
+    enum : uint32_t { coreIndex = kParamIndexSize };                        // <= needed for C2FieldDescriptor
     const static std::initializer_list<const C2FieldDescriptor> fieldList;  // <= needed for C2FieldDescriptor
-    const static FD::Type TYPE = (FD::Type)(baseIndex | FD::STRUCT_FLAG);
+    const static FD::Type TYPE = (FD::Type)(coreIndex | FD::STRUCT_FLAG);
 };
 
 DEFINE_NO_NAMED_VALUES_FOR(C2SizeStruct)
@@ -120,7 +121,7 @@
     bool mYesNo[100];
 
     const static std::initializer_list<const C2FieldDescriptor> fieldList;
-    // enum : uint32_t { baseIndex = kParamIndexTest };
+    // enum : uint32_t { coreIndex = kParamIndexTest };
     // typedef C2TestStruct_A _type;
 } __attribute__((packed));
 
@@ -295,7 +296,7 @@
     int32_t mFlex[];
 
     const static std::initializer_list<const C2FieldDescriptor> fieldList;
-    // enum : uint32_t { baseIndex = kParamIndexTestFlex, flexSize = 4 };
+    // enum : uint32_t { coreIndex = kParamIndexTestFlex, flexSize = 4 };
     // typedef C2TestStruct_FlexS32 _type;
     // typedef int32_t flexType;
 };
@@ -309,7 +310,7 @@
     int32_t mFlex[];
 
     const static std::initializer_list<const C2FieldDescriptor> fieldList;
-    // enum : uint32_t { baseIndex = kParamIndexTestFlexEnd, flexSize = 4 };
+    // enum : uint32_t { coreIndex = kParamIndexTestFlexEnd, flexSize = 4 };
     // typedef C2TestStruct_FlexEnd _type;
     // typedef int32_t flexType;
 };
@@ -364,7 +365,7 @@
     int64_t mFlexSigned64[];
 
     const static std::initializer_list<const C2FieldDescriptor> fieldList;
-    // enum : uint32_t { baseIndex = kParamIndexTestFlexS64, flexSize = 8 };
+    // enum : uint32_t { coreIndex = kParamIndexTestFlexS64, flexSize = 8 };
     // typedef C2TestStruct_FlexS64 _type;
     // typedef int64_t flexType;
 };
@@ -378,7 +379,7 @@
     int64_t mSigned64Flex[];
 
     const static std::initializer_list<const C2FieldDescriptor> fieldList;
-    // enum : uint32_t { baseIndex = C2TestStruct_FlexEndS64, flexSize = 8 };
+    // enum : uint32_t { coreIndex = C2TestStruct_FlexEndS64, flexSize = 8 };
     // typedef C2TestStruct_FlexEndS64 _type;
     // typedef int64_t flexType;
 };
@@ -425,7 +426,7 @@
     C2SizeStruct mFlexSize[];
 
     const static std::initializer_list<const C2FieldDescriptor> fieldList;
-    // enum : uint32_t { baseIndex = kParamIndexTestFlexSize, flexSize = 8 };
+    // enum : uint32_t { coreIndex = kParamIndexTestFlexSize, flexSize = 8 };
     // typedef C2TestStruct_FlexSize _type;
     // typedef C2SizeStruct flexType;
 };
@@ -439,7 +440,7 @@
     C2SizeStruct mSizeFlex[];
 
     const static std::initializer_list<const C2FieldDescriptor> fieldList;
-    // enum : uint32_t { baseIndex = C2TestStruct_FlexEndSize, flexSize = 8 };
+    // enum : uint32_t { coreIndex = C2TestStruct_FlexEndSize, flexSize = 8 };
     // typedef C2TestStruct_FlexEndSize _type;
     // typedef C2SizeStruct flexType;
 };
@@ -470,6 +471,29 @@
     C2FIELD(mFlexSize, "flex")
 }) // ; optional
 
+struct C2TestBaseFlexEndSizeStruct {
+    int32_t mSigned32;
+    C2SizeStruct mFlexSize[];
+    C2TestBaseFlexEndSizeStruct() {}
+
+    DEFINE_BASE_FLEX_C2STRUCT(TestBaseFlexEndSize, mFlexSize)
+} C2_PACK;
+
+DESCRIBE_C2STRUCT(TestBaseFlexEndSize, {
+    C2FIELD(mSigned32, "s32")
+    C2FIELD(mFlexSize, "flex")
+}) // ; optional
+
+struct C2TestBaseFlexEndSize2Struct {
+    int32_t mSigned32;
+    C2SizeStruct mFlexSize[];
+    C2TestBaseFlexEndSize2Struct() {}
+
+    DEFINE_AND_DESCRIBE_BASE_FLEX_C2STRUCT(TestBaseFlexEndSize2, mFlexSize)
+    C2FIELD(mSigned32, "s32")
+    C2FIELD(mFlexSize, "flex")
+};
+
 template<>
 std::vector<std::vector<const C2FieldDescriptor>>
 //std::initializer_list<std::initializer_list<const C2FieldDescriptor>>
@@ -479,6 +503,8 @@
         C2TestStruct_FlexEndSize::fieldList,
         C2TestFlexSizeStruct::fieldList,
         C2TestFlexEndSizeStruct::fieldList,
+        C2TestBaseFlexEndSizeStruct::fieldList,
+        C2TestBaseFlexEndSize2Struct::fieldList,
     };
 }
 
@@ -497,6 +523,9 @@
     EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&((C2TestFlexEndSizeStruct*)0)->mSigned32));
     EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&((C2TestFlexEndSizeStruct*)0)->mFlexSize));
 
+    EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&((C2TestBaseFlexEndSizeStruct*)0)->mSigned32));
+    EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&((C2TestBaseFlexEndSizeStruct*)0)->mFlexSize));
+
     // member pointer constructor
     EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::mSigned32));
     EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::mSigned64));
@@ -511,6 +540,9 @@
     EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId((C2TestFlexEndSizeStruct*)0, &C2TestFlexEndSizeStruct::mSigned32));
     EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId((C2TestFlexEndSizeStruct*)0, &C2TestFlexEndSizeStruct::mFlexSize));
 
+    EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId((C2TestBaseFlexEndSizeStruct*)0, &C2TestBaseFlexEndSizeStruct::mSigned32));
+    EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId((C2TestBaseFlexEndSizeStruct*)0, &C2TestBaseFlexEndSizeStruct::mFlexSize));
+
     // member pointer sans type pointer
     EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&C2TestStruct_A::mSigned32));
     EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&C2TestStruct_A::mSigned64));
@@ -525,8 +557,12 @@
     EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&C2TestFlexEndSizeStruct::mSigned32));
     EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&C2TestFlexEndSizeStruct::mFlexSize));
 
+    EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&C2TestBaseFlexEndSizeStruct::mSigned32));
+    EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&C2TestBaseFlexEndSizeStruct::mFlexSize));
+
     typedef C2GlobalParam<C2Info, C2TestAStruct> C2TestAInfo;
     typedef C2GlobalParam<C2Info, C2TestFlexEndSizeStruct> C2TestFlexEndSizeInfo;
+    typedef C2GlobalParam<C2Info, C2TestBaseFlexEndSizeStruct, kParamIndexTestFlexEndSize> C2TestFlexEndSizeInfoFromBase;
 
     // pointer constructor in C2Param
     EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&((C2TestAInfo*)0)->mSigned32));
@@ -542,6 +578,9 @@
     EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&((C2TestFlexEndSizeInfo*)0)->m.mSigned32));
     EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId(&((C2TestFlexEndSizeInfo*)0)->m.mFlexSize));
 
+    EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&((C2TestFlexEndSizeInfoFromBase*)0)->m.mSigned32));
+    EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId(&((C2TestFlexEndSizeInfoFromBase*)0)->m.mFlexSize));
+
     // member pointer in C2Param
     EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::mSigned32));
     EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::mSigned64));
@@ -557,6 +596,8 @@
     // EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&C2TestFlexEndSizeInfo::m.mSigned32));
     // EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId(&C2TestFlexEndSizeInfo::m.mFlexSize));
 
+    // EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&C2TestFlexEndSizeInfoFromBase::m.mSigned32));
+    // EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId(&C2TestFlexEndSizeInfoFromBase::m.mFlexSize));
 
 
 }
@@ -635,6 +676,10 @@
     typedef C2GlobalParam<C2Info, C2TestFlexEndSizeStruct> C2TestFlexEndSizeInfo;
     static_assert(offsetof(C2TestFlexEndSizeInfo, m.mSigned32) == 8, "offset should be 8");
     static_assert(offsetof(C2TestFlexEndSizeInfo, m.mFlexSize) == 12, "offset should be 12");
+
+    typedef C2GlobalParam<C2Info, C2TestBaseFlexEndSizeStruct, kParamIndexTestFlexEndSize> C2TestFlexEndSizeInfoFromBase;
+    static_assert(offsetof(C2TestFlexEndSizeInfoFromBase, m.mSigned32) == 8, "offset should be 8");
+    static_assert(offsetof(C2TestFlexEndSizeInfoFromBase, m.mFlexSize) == 12, "offset should be 12");
 }
 
 /* ===================================== PARAM USAGE TESTS ===================================== */
@@ -648,6 +693,15 @@
     C2FIELD(mNumber, "number")
 };
 
+struct C2NumberBaseStruct {
+    int32_t mNumber;
+    C2NumberBaseStruct() {}
+    C2NumberBaseStruct(int32_t _number) : mNumber(_number) {}
+
+    DEFINE_AND_DESCRIBE_BASE_C2STRUCT(NumberBase)
+    C2FIELD(mNumber, "number")
+};
+
 struct C2NumbersStruct {
     int32_t mNumbers[];
     C2NumbersStruct() {}
@@ -690,7 +744,7 @@
 
 struct C2NumbersStruct {
     int32_t mNumbers[];
-    enum { baseIndex = kParamIndexNumber };
+    enum { coreIndex = kParamIndexNumber };
     const static std::initializer_list<const C2FieldDescriptor> fieldList;
     C2NumbersStruct() {}
 
@@ -724,7 +778,7 @@
 
         C2Param::Index index(paramType);
         switch (paramType) {
-        case C2NumberConfig::baseIndex:
+        case C2NumberConfig::coreIndex:
             return std::unique_ptr<C2ParamDescriptor>(new C2ParamDescriptor{
                 true /* isRequired */,
                 "number",
@@ -773,19 +827,21 @@
 
 struct _C2ParamInspector {
     static void StaticTest();
+    static void StaticFromBaseTest();
     static void StaticFlexTest();
+    static void StaticFlexFromBaseTest();
 };
 
 // TEST_F(_C2ParamInspector, StaticTest) {
 void _C2ParamInspector::StaticTest() {
     typedef C2Param::Index I;
 
-    // C2NumberStruct: baseIndex = kIndex                          (args)
-    static_assert(C2NumberStruct::baseIndex == kParamIndexNumber, "bad index");
+    // C2NumberStruct: coreIndex = kIndex                          (args)
+    static_assert(C2NumberStruct::coreIndex == kParamIndexNumber, "bad index");
     static_assert(sizeof(C2NumberStruct) == 4, "bad size");
 
     // C2NumberTuning:             kIndex | tun | global           (args)
-    static_assert(C2NumberTuning::baseIndex == kParamIndexNumber, "bad index");
+    static_assert(C2NumberTuning::coreIndex == kParamIndexNumber, "bad index");
     static_assert(C2NumberTuning::typeIndex == (kParamIndexNumber | I::kTypeTuning | I::kDirGlobal), "bad index");
     static_assert(sizeof(C2NumberTuning) == 12, "bad size");
 
@@ -797,11 +853,11 @@
     static_assert(sizeof(C2NumberPortTuning) == 12, "bad size");
     // C2NumberPortTuning::input:  kIndex | tun | port | input     (args)
     // C2NumberPortTuning::output: kIndex | tun | port | output    (args)
-    static_assert(C2NumberPortTuning::input::baseIndex ==
+    static_assert(C2NumberPortTuning::input::coreIndex ==
                   kParamIndexNumber, "bad index");
     static_assert(C2NumberPortTuning::input::typeIndex ==
                   (kParamIndexNumber | I::kTypeTuning | I::kDirInput), "bad index");
-    static_assert(C2NumberPortTuning::output::baseIndex ==
+    static_assert(C2NumberPortTuning::output::coreIndex ==
                   kParamIndexNumber, "bad index");
     static_assert(C2NumberPortTuning::output::typeIndex ==
                   (kParamIndexNumber | I::kTypeTuning | I::kDirOutput), "bad index");
@@ -818,11 +874,11 @@
     static_assert(sizeof(C2NumberStreamTuning) == 12u, "bad size");
     // C2NumberStreamTuning::input kIndex | tun | str | input      (int, args)
     // C2NumberStreamTuning::output kIx   | tun | str | output     (int, args)
-    static_assert(C2NumberStreamTuning::input::baseIndex ==
+    static_assert(C2NumberStreamTuning::input::coreIndex ==
                   kParamIndexNumber, "bad index");
     static_assert(C2NumberStreamTuning::input::typeIndex ==
                   (kParamIndexNumber | I::kTypeTuning | I::kDirInput | I::kStreamFlag), "bad index");
-    static_assert(C2NumberStreamTuning::output::baseIndex ==
+    static_assert(C2NumberStreamTuning::output::coreIndex ==
                   kParamIndexNumber, "bad index");
     static_assert(C2NumberStreamTuning::output::typeIndex ==
                   (kParamIndexNumber | I::kTypeTuning | I::kDirOutput | I::kStreamFlag), "bad index");
@@ -836,15 +892,80 @@
     static_assert(offsetof(C2NumberStreamTuning::output, mNumber) == 8, "bad offset");
 }
 
+void _C2ParamInspector::StaticFromBaseTest() {
+    enum { kParamIndexMy = 3102 };
+    typedef C2NumberBaseStruct C2MyStruct;
+    typedef C2GlobalParam<C2Setting, C2MyStruct, kParamIndexMy> C2MySetting;
+    typedef   C2PortParam<C2Setting, C2MyStruct, kParamIndexMy> C2MyPortSetting;
+    typedef C2StreamParam<C2Setting, C2MyStruct, kParamIndexMy> C2MyStreamSetting;
+
+    typedef C2Param::Index I;
+
+    // C2MyStruct has no coreIndex
+    //static_assert(C2MyStruct::coreIndex == kParamIndexMy, "bad index");
+    static_assert(sizeof(C2MyStruct) == 4, "bad size");
+
+    // C2MySetting:             kIndex | tun | global           (args)
+    static_assert(C2MySetting::coreIndex == kParamIndexMy, "bad index");
+    static_assert(C2MySetting::typeIndex == (kParamIndexMy | I::kTypeSetting | I::kDirGlobal), "bad index");
+    static_assert(sizeof(C2MySetting) == 12, "bad size");
+
+    static_assert(offsetof(C2MySetting, _mSize) == 0, "bad size");
+    static_assert(offsetof(C2MySetting, _mIndex) == 4, "bad offset");
+    static_assert(offsetof(C2MySetting, mNumber) == 8, "bad offset");
+
+    // C2MyPortSetting:         kIndex | tun | port             (bool, args)
+    static_assert(sizeof(C2MyPortSetting) == 12, "bad size");
+    // C2MyPortSetting::input:  kIndex | tun | port | input     (args)
+    // C2MyPortSetting::output: kIndex | tun | port | output    (args)
+    static_assert(C2MyPortSetting::input::coreIndex ==
+                  kParamIndexMy, "bad index");
+    static_assert(C2MyPortSetting::input::typeIndex ==
+                  (kParamIndexMy | I::kTypeSetting | I::kDirInput), "bad index");
+    static_assert(C2MyPortSetting::output::coreIndex ==
+                  kParamIndexMy, "bad index");
+    static_assert(C2MyPortSetting::output::typeIndex ==
+                  (kParamIndexMy | I::kTypeSetting | I::kDirOutput), "bad index");
+    static_assert(sizeof(C2MyPortSetting::input) == 12, "bad size");
+    static_assert(sizeof(C2MyPortSetting::output) == 12, "bad size");
+    static_assert(offsetof(C2MyPortSetting::input, _mSize) == 0, "bad size");
+    static_assert(offsetof(C2MyPortSetting::input, _mIndex) == 4, "bad offset");
+    static_assert(offsetof(C2MyPortSetting::input, mNumber) == 8, "bad offset");
+    static_assert(offsetof(C2MyPortSetting::output, _mSize) == 0, "bad size");
+    static_assert(offsetof(C2MyPortSetting::output, _mIndex) == 4, "bad offset");
+    static_assert(offsetof(C2MyPortSetting::output, mNumber) == 8, "bad offset");
+
+    // C2MyStreamSetting:       kIndex | tun | str              (bool, uint, args)
+    static_assert(sizeof(C2MyStreamSetting) == 12u, "bad size");
+    // C2MyStreamSetting::input kIndex | tun | str | input      (int, args)
+    // C2MyStreamSetting::output kIx   | tun | str | output     (int, args)
+    static_assert(C2MyStreamSetting::input::coreIndex ==
+                  kParamIndexMy, "bad index");
+    static_assert(C2MyStreamSetting::input::typeIndex ==
+                  (kParamIndexMy | I::kTypeSetting | I::kDirInput | I::kStreamFlag), "bad index");
+    static_assert(C2MyStreamSetting::output::coreIndex ==
+                  kParamIndexMy, "bad index");
+    static_assert(C2MyStreamSetting::output::typeIndex ==
+                  (kParamIndexMy | I::kTypeSetting | I::kDirOutput | I::kStreamFlag), "bad index");
+    static_assert(sizeof(C2MyStreamSetting::input) == 12u, "bad size");
+    static_assert(sizeof(C2MyStreamSetting::output) == 12u, "bad size");
+    static_assert(offsetof(C2MyStreamSetting::input, _mSize) == 0, "bad size");
+    static_assert(offsetof(C2MyStreamSetting::input, _mIndex) == 4, "bad offset");
+    static_assert(offsetof(C2MyStreamSetting::input, mNumber) == 8, "bad offset");
+    static_assert(offsetof(C2MyStreamSetting::output, _mSize) == 0, "bad size");
+    static_assert(offsetof(C2MyStreamSetting::output, _mIndex) == 4, "bad offset");
+    static_assert(offsetof(C2MyStreamSetting::output, mNumber) == 8, "bad offset");
+}
+
 void _C2ParamInspector::StaticFlexTest() {
     typedef C2Param::Index I;
 
-    // C2NumbersStruct: baseIndex = kIndex                          (args)
-    static_assert(C2NumbersStruct::baseIndex == (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
+    // C2NumbersStruct: coreIndex = kIndex                          (args)
+    static_assert(C2NumbersStruct::coreIndex == (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
     static_assert(sizeof(C2NumbersStruct) == 0, "bad size");
 
     // C2NumbersTuning:             kIndex | tun | global           (args)
-    static_assert(C2NumbersTuning::baseIndex == (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
+    static_assert(C2NumbersTuning::coreIndex == (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
     static_assert(C2NumbersTuning::typeIndex == (I::kFlexibleFlag | kParamIndexNumbers | I::kTypeTuning | I::kDirGlobal), "bad index");
     static_assert(sizeof(C2NumbersTuning) == 8, "bad size");
 
@@ -856,11 +977,11 @@
     static_assert(sizeof(C2NumbersPortTuning) == 8, "bad size");
     // C2NumbersPortTuning::input:  kIndex | tun | port | input     (args)
     // C2NumbersPortTuning::output: kIndex | tun | port | output    (args)
-    static_assert(C2NumbersPortTuning::input::baseIndex ==
+    static_assert(C2NumbersPortTuning::input::coreIndex ==
                   (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
     static_assert(C2NumbersPortTuning::input::typeIndex ==
                   (I::kFlexibleFlag | kParamIndexNumbers | I::kTypeTuning | I::kDirInput), "bad index");
-    static_assert(C2NumbersPortTuning::output::baseIndex ==
+    static_assert(C2NumbersPortTuning::output::coreIndex ==
                   (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
     static_assert(C2NumbersPortTuning::output::typeIndex ==
                   (I::kFlexibleFlag | kParamIndexNumbers | I::kTypeTuning | I::kDirOutput), "bad index");
@@ -877,11 +998,11 @@
     static_assert(sizeof(C2NumbersStreamTuning) == 8, "bad size");
     // C2NumbersStreamTuning::input kIndex | tun | str | input      (int, args)
     // C2NumbersStreamTuning::output kIx   | tun | str | output     (int, args)
-    static_assert(C2NumbersStreamTuning::input::baseIndex ==
+    static_assert(C2NumbersStreamTuning::input::coreIndex ==
                   (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
     static_assert(C2NumbersStreamTuning::input::typeIndex ==
                   (I::kFlexibleFlag | kParamIndexNumbers | I::kTypeTuning | I::kDirInput | I::kStreamFlag), "bad index");
-    static_assert(C2NumbersStreamTuning::output::baseIndex ==
+    static_assert(C2NumbersStreamTuning::output::coreIndex ==
                   (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
     static_assert(C2NumbersStreamTuning::output::typeIndex ==
                   (I::kFlexibleFlag | kParamIndexNumbers | I::kTypeTuning | I::kDirOutput | I::kStreamFlag), "bad index");
@@ -895,6 +1016,80 @@
     static_assert(offsetof(C2NumbersStreamTuning::output, m.mNumbers) == 8, "bad offset");
 }
 
+template<bool, unsigned ...N>
+struct _print_as_warning { };
+
+template<unsigned ...N>
+struct _print_as_warning<true, N...> : std::true_type { };
+
+#define static_assert_equals(a, b, msg) \
+static_assert(_print_as_warning<(a) == (b), a, b>::value, msg)
+
+void _C2ParamInspector::StaticFlexFromBaseTest() {
+    enum { kParamIndexMy = 1203 };
+    typedef C2TestBaseFlexEndSizeStruct C2MyStruct;
+    typedef C2GlobalParam<C2Info, C2MyStruct, kParamIndexMy> C2MyInfo;
+    typedef   C2PortParam<C2Info, C2MyStruct, kParamIndexMy> C2MyPortInfo;
+    typedef C2StreamParam<C2Info, C2MyStruct, kParamIndexMy> C2MyStreamInfo;
+
+    typedef C2Param::Index I;
+
+    // C2MyStruct has no coreIndex
+    //static_assert(C2MyStruct::coreIndex == (I::kFlexibleFlag | kParamIndexMy), "bad index");
+    static_assert(sizeof(C2MyStruct) == 4, "bad size");
+
+    // C2MyInfo:             kIndex | tun | global           (args)
+    static_assert_equals(C2MyInfo::coreIndex, (I::kFlexibleFlag | kParamIndexMy), "bad index");
+    static_assert_equals(C2MyInfo::typeIndex, (I::kFlexibleFlag | kParamIndexMy | I::kTypeInfo | I::kDirGlobal), "bad index");
+    static_assert(sizeof(C2MyInfo) == 12, "bad size");
+
+    static_assert(offsetof(C2MyInfo, _mSize) == 0, "bad size");
+    static_assert(offsetof(C2MyInfo, _mIndex) == 4, "bad offset");
+    static_assert(offsetof(C2MyInfo, m.mSigned32) == 8, "bad offset");
+
+    // C2MyPortInfo:         kIndex | tun | port             (bool, args)
+    static_assert(sizeof(C2MyPortInfo) == 12, "bad size");
+    // C2MyPortInfo::input:  kIndex | tun | port | input     (args)
+    // C2MyPortInfo::output: kIndex | tun | port | output    (args)
+    static_assert(C2MyPortInfo::input::coreIndex ==
+                  (I::kFlexibleFlag | kParamIndexMy), "bad index");
+    static_assert(C2MyPortInfo::input::typeIndex ==
+                  (I::kFlexibleFlag | kParamIndexMy | I::kTypeInfo | I::kDirInput), "bad index");
+    static_assert(C2MyPortInfo::output::coreIndex ==
+                  (I::kFlexibleFlag | kParamIndexMy), "bad index");
+    static_assert(C2MyPortInfo::output::typeIndex ==
+                  (I::kFlexibleFlag | kParamIndexMy | I::kTypeInfo | I::kDirOutput), "bad index");
+    static_assert(sizeof(C2MyPortInfo::input) == 12, "bad size");
+    static_assert(sizeof(C2MyPortInfo::output) == 12, "bad size");
+    static_assert(offsetof(C2MyPortInfo::input, _mSize) == 0, "bad size");
+    static_assert(offsetof(C2MyPortInfo::input, _mIndex) == 4, "bad offset");
+    static_assert(offsetof(C2MyPortInfo::input, m.mSigned32) == 8, "bad offset");
+    static_assert(offsetof(C2MyPortInfo::output, _mSize) == 0, "bad size");
+    static_assert(offsetof(C2MyPortInfo::output, _mIndex) == 4, "bad offset");
+    static_assert(offsetof(C2MyPortInfo::output, m.mSigned32) == 8, "bad offset");
+
+    // C2MyStreamInfo:       kIndex | tun | str              (bool, uint, args)
+    static_assert(sizeof(C2MyStreamInfo) == 12, "bad size");
+    // C2MyStreamInfo::input kIndex | tun | str | input      (int, args)
+    // C2MyStreamInfo::output kIx   | tun | str | output     (int, args)
+    static_assert(C2MyStreamInfo::input::coreIndex ==
+                  (I::kFlexibleFlag | kParamIndexMy), "bad index");
+    static_assert(C2MyStreamInfo::input::typeIndex ==
+                  (I::kFlexibleFlag | kParamIndexMy | I::kTypeInfo | I::kDirInput | I::kStreamFlag), "bad index");
+    static_assert(C2MyStreamInfo::output::coreIndex ==
+                  (I::kFlexibleFlag | kParamIndexMy), "bad index");
+    static_assert(C2MyStreamInfo::output::typeIndex ==
+                  (I::kFlexibleFlag | kParamIndexMy | I::kTypeInfo | I::kDirOutput | I::kStreamFlag), "bad index");
+    static_assert(sizeof(C2MyStreamInfo::input) == 12, "bad size");
+    static_assert(sizeof(C2MyStreamInfo::output) == 12, "bad size");
+    static_assert(offsetof(C2MyStreamInfo::input, _mSize) == 0, "bad size");
+    static_assert(offsetof(C2MyStreamInfo::input, _mIndex) == 4, "bad offset");
+    static_assert(offsetof(C2MyStreamInfo::input, m.mSigned32) == 8, "bad offset");
+    static_assert(offsetof(C2MyStreamInfo::output, _mSize) == 0, "bad size");
+    static_assert(offsetof(C2MyStreamInfo::output, _mIndex) == 4, "bad offset");
+    static_assert(offsetof(C2MyStreamInfo::output, m.mSigned32) == 8, "bad offset");
+}
+
 TEST_F(C2ParamTest, ParamOpsTest) {
     const C2NumberStruct str(100);
     C2NumberStruct bstr;
@@ -903,10 +1098,10 @@
         EXPECT_EQ(100, str.mNumber);
         bstr.mNumber = 100;
 
-        C2Param::BaseIndex index = C2NumberStruct::baseIndex;
+        C2Param::BaseIndex index = C2NumberStruct::coreIndex;
         EXPECT_FALSE(index.isVendor());
         EXPECT_FALSE(index.isFlexible());
-        EXPECT_EQ(index.baseIndex(), kParamIndexNumber);
+        EXPECT_EQ(index.coreIndex(), kParamIndexNumber);
         EXPECT_EQ(index.paramIndex(), kParamIndexNumber);
     }
 
@@ -940,15 +1135,15 @@
         EXPECT_EQ(tun, btun);
 
         // index
-        EXPECT_EQ(C2Param::Type(tun.type()).baseIndex(), C2NumberStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(tun.type()).coreIndex(), C2NumberStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(tun.type()).paramIndex(), kParamIndexNumber);
         EXPECT_EQ(tun.type(), C2NumberTuning::typeIndex);
         EXPECT_EQ(tun.stream(), ~0u);
 
-        C2Param::BaseIndex index = C2NumberTuning::baseIndex;
+        C2Param::BaseIndex index = C2NumberTuning::coreIndex;
         EXPECT_FALSE(index.isVendor());
         EXPECT_FALSE(index.isFlexible());
-        EXPECT_EQ(index.baseIndex(), kParamIndexNumber);
+        EXPECT_EQ(index.coreIndex(), kParamIndexNumber);
         EXPECT_EQ(index.paramIndex(), kParamIndexNumber);
 
         C2Param::Type type = C2NumberTuning::typeIndex;
@@ -968,6 +1163,10 @@
         EXPECT_EQ(C2NumberStreamTuning::From(&tun), nullptr);
         EXPECT_EQ(C2NumberStreamTuning::input::From(&tun), nullptr);
         EXPECT_EQ(C2NumberStreamTuning::output::From(&tun), nullptr);
+
+        EXPECT_EQ(*(C2Param::Copy(btun)), btun);
+        btun.invalidate();
+        EXPECT_FALSE(C2Param::Copy(btun));
     }
 
     const C2NumberPortTuning outp1(true, 100), inp1(false, 100);
@@ -1090,22 +1289,22 @@
         EXPECT_TRUE(inp1 == boutp1);
 
         // index
-        EXPECT_EQ(C2Param::Type(inp1.type()).baseIndex(), C2NumberStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(inp1.type()).coreIndex(), C2NumberStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(inp1.type()).paramIndex(), kParamIndexNumber);
         EXPECT_EQ(inp1.type(), C2NumberPortTuning::input::typeIndex);
         EXPECT_EQ(inp1.stream(), ~0u);
 
-        EXPECT_EQ(C2Param::Type(inp2.type()).baseIndex(), C2NumberStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(inp2.type()).coreIndex(), C2NumberStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(inp2.type()).paramIndex(), kParamIndexNumber);
         EXPECT_EQ(inp2.type(), C2NumberPortTuning::input::typeIndex);
         EXPECT_EQ(inp2.stream(), ~0u);
 
-        EXPECT_EQ(C2Param::Type(outp1.type()).baseIndex(), C2NumberStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(outp1.type()).coreIndex(), C2NumberStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(outp1.type()).paramIndex(), kParamIndexNumber);
         EXPECT_EQ(outp1.type(), C2NumberPortTuning::output::typeIndex);
         EXPECT_EQ(outp1.stream(), ~0u);
 
-        EXPECT_EQ(C2Param::Type(outp2.type()).baseIndex(), C2NumberStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(outp2.type()).coreIndex(), C2NumberStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(outp2.type()).paramIndex(), kParamIndexNumber);
         EXPECT_EQ(outp2.type(), C2NumberPortTuning::output::typeIndex);
         EXPECT_EQ(outp2.stream(), ~0u);
@@ -1113,13 +1312,13 @@
         C2Param::BaseIndex index = C2NumberPortTuning::input::typeIndex;
         EXPECT_FALSE(index.isVendor());
         EXPECT_FALSE(index.isFlexible());
-        EXPECT_EQ(index.baseIndex(), kParamIndexNumber);
+        EXPECT_EQ(index.coreIndex(), kParamIndexNumber);
         EXPECT_EQ(index.paramIndex(), kParamIndexNumber);
 
         index = C2NumberPortTuning::output::typeIndex;
         EXPECT_FALSE(index.isVendor());
         EXPECT_FALSE(index.isFlexible());
-        EXPECT_EQ(index.baseIndex(), kParamIndexNumber);
+        EXPECT_EQ(index.coreIndex(), kParamIndexNumber);
         EXPECT_EQ(index.paramIndex(), kParamIndexNumber);
 
         C2Param::Type type = C2NumberPortTuning::input::typeIndex;
@@ -1171,6 +1370,11 @@
         EXPECT_EQ(C2NumberStreamTuning::output::From(&inp2), nullptr);
         EXPECT_EQ(C2NumberStreamTuning::output::From(&outp1), nullptr);
         EXPECT_EQ(C2NumberStreamTuning::output::From(&outp2), nullptr);
+
+        EXPECT_EQ(*(C2Param::Copy(inp1)), inp1);
+        EXPECT_EQ(*(C2Param::Copy(inp2)), inp2);
+        EXPECT_EQ(*(C2Param::Copy(outp1)), outp1);
+        EXPECT_EQ(*(C2Param::Copy(outp2)), outp2);
     }
 
     const C2NumberStreamTuning outs1(true, 1u, 100), ins1(false, 1u, 100);
@@ -1305,32 +1509,32 @@
         EXPECT_TRUE(ins1 == bouts1);
 
         // index
-        EXPECT_EQ(C2Param::Type(ins1.type()).baseIndex(), C2NumberStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(ins1.type()).coreIndex(), C2NumberStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(ins1.type()).paramIndex(), kParamIndexNumber);
         EXPECT_EQ(ins1.type(), C2NumberStreamTuning::input::typeIndex);
 
-        EXPECT_EQ(C2Param::Type(ins2.type()).baseIndex(), C2NumberStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(ins2.type()).coreIndex(), C2NumberStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(ins2.type()).paramIndex(), kParamIndexNumber);
         EXPECT_EQ(ins2.type(), C2NumberStreamTuning::input::typeIndex);
 
-        EXPECT_EQ(C2Param::Type(outs1.type()).baseIndex(), C2NumberStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(outs1.type()).coreIndex(), C2NumberStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(outs1.type()).paramIndex(), kParamIndexNumber);
         EXPECT_EQ(outs1.type(), C2NumberStreamTuning::output::typeIndex);
 
-        EXPECT_EQ(C2Param::Type(outs2.type()).baseIndex(), C2NumberStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(outs2.type()).coreIndex(), C2NumberStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(outs2.type()).paramIndex(), kParamIndexNumber);
         EXPECT_EQ(outs2.type(), C2NumberStreamTuning::output::typeIndex);
 
         C2Param::BaseIndex index = C2NumberStreamTuning::input::typeIndex;
         EXPECT_FALSE(index.isVendor());
         EXPECT_FALSE(index.isFlexible());
-        EXPECT_EQ(index.baseIndex(), kParamIndexNumber);
+        EXPECT_EQ(index.coreIndex(), kParamIndexNumber);
         EXPECT_EQ(index.paramIndex(), kParamIndexNumber);
 
         index = C2NumberStreamTuning::output::typeIndex;
         EXPECT_FALSE(index.isVendor());
         EXPECT_FALSE(index.isFlexible());
-        EXPECT_EQ(index.baseIndex(), kParamIndexNumber);
+        EXPECT_EQ(index.coreIndex(), kParamIndexNumber);
         EXPECT_EQ(index.paramIndex(), kParamIndexNumber);
 
         C2Param::Type type = C2NumberStreamTuning::input::typeIndex;
@@ -1383,6 +1587,10 @@
         EXPECT_EQ(C2NumberStreamTuning::output::From(&outs1), (C2NumberStreamTuning::output*)&outs1);
         EXPECT_EQ(C2NumberStreamTuning::output::From(&outs2), &outs2);
 
+        EXPECT_EQ(*(C2Param::Copy(ins1)), ins1);
+        EXPECT_EQ(*(C2Param::Copy(ins2)), ins2);
+        EXPECT_EQ(*(C2Param::Copy(outs1)), outs1);
+        EXPECT_EQ(*(C2Param::Copy(outs2)), outs2);
     }
 
     {
@@ -1406,11 +1614,11 @@
     }
 }
 
-void StaticTestAddBaseIndex() {
+void StaticTestAddCoreIndex() {
     struct nobase {};
-    struct base { enum : uint32_t { baseIndex = 1 }; };
-    static_assert(C2AddBaseIndex<nobase, 2>::baseIndex == 2, "should be 2");
-    static_assert(C2AddBaseIndex<base, 1>::baseIndex == 1, "should be 1");
+    struct base { enum : uint32_t { coreIndex = 1 }; };
+    static_assert(C2AddCoreIndex<nobase, 2>::coreIndex == 2, "should be 2");
+    static_assert(C2AddCoreIndex<base, 1>::coreIndex == 1, "should be 1");
 }
 
 class TestFlexHelper {
@@ -1450,10 +1658,10 @@
 //        EXPECT_EQ(100, str->m.mNumbers[0]);
         (void)&bstr.mNumbers[0];
 
-        C2Param::BaseIndex index = C2NumbersStruct::baseIndex;
+        C2Param::BaseIndex index = C2NumbersStruct::coreIndex;
         EXPECT_FALSE(index.isVendor());
         EXPECT_TRUE(index.isFlexible());
-        EXPECT_EQ(index.baseIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
+        EXPECT_EQ(index.coreIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
         EXPECT_EQ(index.paramIndex(), kParamIndexNumbers);
     }
 
@@ -1490,15 +1698,15 @@
         EXPECT_EQ(*tun, *btun);
 
         // index
-        EXPECT_EQ(C2Param::Type(tun->type()).baseIndex(), C2NumbersStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(tun->type()).coreIndex(), C2NumbersStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(tun->type()).paramIndex(), kParamIndexNumbers);
         EXPECT_EQ(tun->type(), C2NumbersTuning::typeIndex);
         EXPECT_EQ(tun->stream(), ~0u);
 
-        C2Param::BaseIndex index = C2NumbersTuning::baseIndex;
+        C2Param::BaseIndex index = C2NumbersTuning::coreIndex;
         EXPECT_FALSE(index.isVendor());
         EXPECT_TRUE(index.isFlexible());
-        EXPECT_EQ(index.baseIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
+        EXPECT_EQ(index.coreIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
         EXPECT_EQ(index.paramIndex(), kParamIndexNumbers);
 
         C2Param::Type type = C2NumbersTuning::typeIndex;
@@ -1518,6 +1726,8 @@
         EXPECT_EQ(C2NumbersStreamTuning::From(tun.get()), nullptr);
         EXPECT_EQ(C2NumbersStreamTuning::input::From(tun.get()), nullptr);
         EXPECT_EQ(C2NumbersStreamTuning::output::From(tun.get()), nullptr);
+
+        EXPECT_EQ(*(C2Param::Copy(*tun)), *tun);
     }
 
     std::unique_ptr<C2NumbersPortTuning> outp1_(C2NumbersPortTuning::alloc_unique(1, true)),
@@ -1657,22 +1867,22 @@
         EXPECT_TRUE(*inp1 == *boutp1);
 
         // index
-        EXPECT_EQ(C2Param::Type(inp1->type()).baseIndex(), C2NumbersStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(inp1->type()).coreIndex(), C2NumbersStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(inp1->type()).paramIndex(), kParamIndexNumbers);
         EXPECT_EQ(inp1->type(), C2NumbersPortTuning::input::typeIndex);
         EXPECT_EQ(inp1->stream(), ~0u);
 
-        EXPECT_EQ(C2Param::Type(inp2->type()).baseIndex(), C2NumbersStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(inp2->type()).coreIndex(), C2NumbersStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(inp2->type()).paramIndex(), kParamIndexNumbers);
         EXPECT_EQ(inp2->type(), C2NumbersPortTuning::input::typeIndex);
         EXPECT_EQ(inp2->stream(), ~0u);
 
-        EXPECT_EQ(C2Param::Type(outp1->type()).baseIndex(), C2NumbersStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(outp1->type()).coreIndex(), C2NumbersStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(outp1->type()).paramIndex(), kParamIndexNumbers);
         EXPECT_EQ(outp1->type(), C2NumbersPortTuning::output::typeIndex);
         EXPECT_EQ(outp1->stream(), ~0u);
 
-        EXPECT_EQ(C2Param::Type(outp2->type()).baseIndex(), C2NumbersStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(outp2->type()).coreIndex(), C2NumbersStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(outp2->type()).paramIndex(), kParamIndexNumbers);
         EXPECT_EQ(outp2->type(), C2NumbersPortTuning::output::typeIndex);
         EXPECT_EQ(outp2->stream(), ~0u);
@@ -1680,13 +1890,13 @@
         C2Param::BaseIndex index = C2NumbersPortTuning::input::typeIndex;
         EXPECT_FALSE(index.isVendor());
         EXPECT_TRUE(index.isFlexible());
-        EXPECT_EQ(index.baseIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
+        EXPECT_EQ(index.coreIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
         EXPECT_EQ(index.paramIndex(), kParamIndexNumbers);
 
         index = C2NumbersPortTuning::output::typeIndex;
         EXPECT_FALSE(index.isVendor());
         EXPECT_TRUE(index.isFlexible());
-        EXPECT_EQ(index.baseIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
+        EXPECT_EQ(index.coreIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
         EXPECT_EQ(index.paramIndex(), kParamIndexNumbers);
 
         C2Param::Type type = C2NumbersPortTuning::input::typeIndex;
@@ -1739,6 +1949,10 @@
         EXPECT_EQ(C2NumbersStreamTuning::output::From(outp1.get()), nullptr);
         EXPECT_EQ(C2NumbersStreamTuning::output::From(outp2.get()), nullptr);
 
+        EXPECT_EQ(*(C2Param::Copy(*inp1)), *inp1);
+        EXPECT_EQ(*(C2Param::Copy(*inp2)), *inp2);
+        EXPECT_EQ(*(C2Param::Copy(*outp1)), *outp1);
+        EXPECT_EQ(*(C2Param::Copy(*outp2)), *outp2);
     }
 
     std::unique_ptr<C2NumbersStreamTuning> outs1_(C2NumbersStreamTuning::alloc_unique(1, true, 1u));
@@ -1890,32 +2104,32 @@
         EXPECT_TRUE(*ins1 == *bouts1);
 
         // index
-        EXPECT_EQ(C2Param::Type(ins1->type()).baseIndex(), C2NumbersStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(ins1->type()).coreIndex(), C2NumbersStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(ins1->type()).paramIndex(), kParamIndexNumbers);
         EXPECT_EQ(ins1->type(), C2NumbersStreamTuning::input::typeIndex);
 
-        EXPECT_EQ(C2Param::Type(ins2->type()).baseIndex(), C2NumbersStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(ins2->type()).coreIndex(), C2NumbersStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(ins2->type()).paramIndex(), kParamIndexNumbers);
         EXPECT_EQ(ins2->type(), C2NumbersStreamTuning::input::typeIndex);
 
-        EXPECT_EQ(C2Param::Type(outs1->type()).baseIndex(), C2NumbersStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(outs1->type()).coreIndex(), C2NumbersStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(outs1->type()).paramIndex(), kParamIndexNumbers);
         EXPECT_EQ(outs1->type(), C2NumbersStreamTuning::output::typeIndex);
 
-        EXPECT_EQ(C2Param::Type(outs2->type()).baseIndex(), C2NumbersStruct::baseIndex);
+        EXPECT_EQ(C2Param::Type(outs2->type()).coreIndex(), C2NumbersStruct::coreIndex);
         EXPECT_EQ(C2Param::Type(outs2->type()).paramIndex(), kParamIndexNumbers);
         EXPECT_EQ(outs2->type(), C2NumbersStreamTuning::output::typeIndex);
 
         C2Param::BaseIndex index = C2NumbersStreamTuning::input::typeIndex;
         EXPECT_FALSE(index.isVendor());
         EXPECT_TRUE(index.isFlexible());
-        EXPECT_EQ(index.baseIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
+        EXPECT_EQ(index.coreIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
         EXPECT_EQ(index.paramIndex(), kParamIndexNumbers);
 
         index = C2NumbersStreamTuning::output::typeIndex;
         EXPECT_FALSE(index.isVendor());
         EXPECT_TRUE(index.isFlexible());
-        EXPECT_EQ(index.baseIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
+        EXPECT_EQ(index.coreIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
         EXPECT_EQ(index.paramIndex(), kParamIndexNumbers);
 
         C2Param::Type type = C2NumbersStreamTuning::input::typeIndex;
@@ -1968,6 +2182,10 @@
         EXPECT_EQ(C2NumbersStreamTuning::output::From(outs1.get()), (C2NumbersStreamTuning::output*)outs1.get());
         EXPECT_EQ(C2NumbersStreamTuning::output::From(outs2.get()), outs2.get());
 
+        EXPECT_EQ(*(C2Param::Copy(*ins1)), *ins1);
+        EXPECT_EQ(*(C2Param::Copy(*ins2)), *ins2);
+        EXPECT_EQ(*(C2Param::Copy(*outs1)), *outs1);
+        EXPECT_EQ(*(C2Param::Copy(*outs2)), *outs2);
     }
 
     {
@@ -2173,73 +2391,43 @@
 
 typedef C2PortParam<C2Tuning, C2VideoConfigStruct> C2VideoConfigPortTuning;
 
-class MyReflector : public C2ParamReflector {
-private:
-    std::unique_ptr<C2VideoConfigPortTuning::input> inputVideoConfigTuning;
-    std::unique_ptr<C2VideoConfigPortTuning::output> outputVideoConfigTuning;
-
-public:
-    void describeSupportedValues() {
-        C2TypedFieldSupportedValues<int32_t> supportedWidths(16, 1920, 8);
-        C2FieldSupportedValues supportedWidths2(16, 1920, 8);
-
-
-        std::list<C2FieldSupportedValues> supported;
-        //supported.emplace_push(inputVideoConfigTuning->mNumber, range(16, 1920, 8));
-        //supported.emplace_push(inputVideoConfigTuning->mHeight, range(16, 1088, 8));
-        //supported.emplace_push(inputVideoConfigTuning->mMetadataType, all_enums);
-        //supported.emplace_push(inputVideoConfigTuning->mSupportedFormats, { 0, 1, 5, 7 });
-    }
-
-    virtual std::unique_ptr<android::C2StructDescriptor> describe(C2Param::BaseIndex paramType) {
-        switch (paramType.baseIndex()) {
-        case C2VideoConfigPortTuning::baseIndex:
-            return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor{
-                paramType.baseIndex(),
-                C2VideoConfigPortTuning::fieldList,
-            });
-        }
-        return nullptr;
-    }
-};
-
 class MyComponentInstance : public C2ComponentInterface {
 public:
-    virtual C2String getName() const {
+    virtual C2String getName() const override {
         /// \todo this seems too specific
         return "sample.interface";
     };
 
-    virtual node_id getId() const {
+    virtual c2_node_id_t getId() const override {
         /// \todo how are these shared?
         return 0;
     }
 
-    virtual status_t commit_sm(
+    virtual c2_status_t commit_sm(
             const std::vector<C2Param* const> &params,
-            std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
         (void)params;
         (void)failures;
-        return C2_UNSUPPORTED;
+        return C2_OMITTED;
     }
 
-    virtual status_t config_nb(
+    virtual c2_status_t config_nb(
             const std::vector<C2Param* const> &params,
-            std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
         (void)params;
         (void)failures;
-        return C2_UNSUPPORTED;
+        return C2_OMITTED;
     }
 
-    virtual status_t createTunnel_sm(node_id targetComponent) {
+    virtual c2_status_t createTunnel_sm(c2_node_id_t targetComponent) override {
         (void)targetComponent;
-        return C2_UNSUPPORTED;
+        return C2_OMITTED;
     }
 
-    virtual status_t query_nb(
+    virtual c2_status_t query_nb(
             const std::vector<C2Param* const> &stackParams,
             const std::vector<C2Param::Index> &heapParamIndices,
-            std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
+            std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
         for (C2Param* const param : stackParams) {
             if (!*param) { // param is already invalid - remember it
                 continue;
@@ -2262,7 +2450,7 @@
         for (const C2Param::Index index : heapParamIndices) {
             if (mMyParams.count(index)) {
                 C2Param & myParam = mMyParams.find(index)->second;
-                std::unique_ptr<C2Param> paramCopy(C2Param::From(&myParam, myParam.size()));
+                std::unique_ptr<C2Param> paramCopy(C2Param::Copy(myParam));
                 heapParams->push_back(std::move(paramCopy));
             }
         }
@@ -2278,9 +2466,9 @@
         mMyParams.insert({mDomainInfo.type(), mDomainInfo});
     }
 
-    virtual status_t releaseTunnel_sm(node_id targetComponent) {
+    virtual c2_status_t releaseTunnel_sm(c2_node_id_t targetComponent) override {
         (void)targetComponent;
-        return C2_UNSUPPORTED;
+        return C2_OMITTED;
     }
 
     class MyParamReflector : public C2ParamReflector {
@@ -2289,9 +2477,9 @@
     public:
         MyParamReflector(const MyComponentInstance *i) : instance(i) { }
 
-        virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::BaseIndex paramIndex) {
-            switch (paramIndex.baseIndex()) {
-            case decltype(instance->mDomainInfo)::baseIndex:
+        virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::BaseIndex paramIndex) override {
+            switch (paramIndex.coreIndex()) {
+            case decltype(instance->mDomainInfo)::coreIndex:
             default:
                 return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor{
                     instance->mDomainInfo.type(),
@@ -2302,38 +2490,38 @@
         }
     };
 
-    virtual status_t getSupportedValues(
-            const std::vector<const C2ParamField> fields,
-            std::vector<C2FieldSupportedValues>* const values) const {
-        for (const C2ParamField &field : fields) {
-            if (field == C2ParamField(&mDomainInfo, &C2ComponentDomainInfo::mValue)) {
-                values->push_back(C2FieldSupportedValues(
+    virtual c2_status_t querySupportedValues_nb(
+            std::vector<C2FieldSupportedValuesQuery> &fields) const override {
+        for (C2FieldSupportedValuesQuery &query : fields) {
+            if (query.field == C2ParamField(&mDomainInfo, &C2ComponentDomainInfo::mValue)) {
+                query.values = C2FieldSupportedValues(
                     false /* flag */,
                     &mDomainInfo.mValue
                     //,
                     //{(int32_t)C2DomainVideo}
-                ));
+                );
+                query.status = C2_OK;
+            } else {
+                query.status = C2_BAD_INDEX;
             }
         }
         return C2_OK;
     }
 
-    virtual std::shared_ptr<C2ParamReflector> getParamReflector() const {
+    std::shared_ptr<C2ParamReflector> getParamReflector() const {
         return std::shared_ptr<C2ParamReflector>(new MyParamReflector(this));
     }
 
-    virtual status_t getSupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const {
+    virtual c2_status_t querySupportedParams_nb(
+            std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override {
         params->push_back(std::make_shared<C2ParamDescriptor>(
                 true /* required */, "_domain", &mDomainInfo));
-        return C2_OK;
-    }
-
-    status_t getSupportedParams2(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) {
         params->push_back(std::shared_ptr<C2ParamDescriptor>(
                 new C2ParamDescriptor(true /* required */, "_domain", &mDomainInfo)));
         return C2_OK;
     }
 
+    virtual ~MyComponentInstance() override = default;
 };
 
 template<typename E, bool S=std::is_enum<E>::value>
@@ -2382,9 +2570,9 @@
 template<typename T>
 void dumpFSV(const C2FieldSupportedValues &sv, T*t) {
     using namespace std;
-    cout << (std::is_enum<T>::value ? (std::is_signed<typename std::underlying_type<T>::type>::value ? "i" : "u")
+    cout << (std::is_enum<T>::value ? (std::is_signed<typename lax_underlying_type<T>::type>::value ? "i" : "u")
              : std::is_integral<T>::value ? std::is_signed<T>::value ? "i" : "u" : "f")
-        << (8 * sizeof(T));
+         << (8 * sizeof(T));
     if (sv.type == sv.RANGE) {
         cout << ".range(" << get(sv.range.min, t);
         if (get(sv.range.step, t) != std::is_integral<T>::value) {
@@ -2466,7 +2654,7 @@
 void dumpStruct(const C2StructDescriptor &sd) {
     using namespace std;
     cout << "struct ";
-    dumpType(sd.baseIndex());
+    dumpType(sd.coreIndex());
     cout << " {" << endl;
     //C2FieldDescriptor &f;
     for (const C2FieldDescriptor &f : sd) {
@@ -2510,22 +2698,41 @@
 
 TEST_F(C2ParamTest, ReflectorTest) {
     C2ComponentDomainInfo domainInfo;
-    std::shared_ptr<C2ComponentInterface> comp(new MyComponentInstance);
-    std::vector<C2FieldSupportedValues> values;
+    std::shared_ptr<MyComponentInstance> myComp(new MyComponentInstance);
+    std::shared_ptr<C2ComponentInterface> comp = myComp;
 
     std::unique_ptr<C2StructDescriptor> desc{
-        comp->getParamReflector()->describe(C2ComponentDomainInfo::indexFlags)};
+        myComp->getParamReflector()->describe(C2ComponentDomainInfo::indexFlags)};
     dumpStruct(*desc);
 
-    EXPECT_EQ(
-        C2_OK,
-        comp->getSupportedValues(
-            { C2ParamField(&domainInfo, &C2ComponentDomainInfo::mValue) },
-            &values)
-    );
+    std::vector<C2FieldSupportedValuesQuery> query = {
+        { C2ParamField(&domainInfo, &C2ComponentDomainInfo::mValue),
+          C2FieldSupportedValuesQuery::CURRENT },
+        C2FieldSupportedValuesQuery(C2ParamField(&domainInfo, &C2ComponentDomainInfo::mValue),
+          C2FieldSupportedValuesQuery::CURRENT),
+        C2FieldSupportedValuesQuery::Current(C2ParamField(&domainInfo, &C2ComponentDomainInfo::mValue)),
+    };
+
+    EXPECT_EQ(C2_OK, comp->querySupportedValues_nb(query));
+
+    for (const C2FieldSupportedValuesQuery &q : query) {
+        dumpFSV(q.values, &domainInfo.mValue);
+    }
+}
+
+TEST_F(C2ParamTest, FieldSupportedValuesTest) {
+    typedef C2GlobalParam<C2Info, C2Uint32Value, 0> Uint32TestInfo;
+    Uint32TestInfo t;
+    std::vector<C2FieldSupportedValues> values;
+    values.push_back(C2FieldSupportedValues(0, 10, 1));  // min, max, step
+    values.push_back(C2FieldSupportedValues(1, 64, 2, 1));  // min, max, nom, den
+    values.push_back(C2FieldSupportedValues(false, {1, 2, 3}));  // flags, std::initializer_list
+    uint32_t val[] = {1, 3, 5, 7};
+    std::vector<uint32_t> v(std::begin(val), std::end(val));
+    values.push_back(C2FieldSupportedValues(false, v));  // flags, std::vector
 
     for (const C2FieldSupportedValues &sv : values) {
-        dumpFSV(sv, &domainInfo.mValue);
+        dumpFSV(sv, &t.mValue);
     }
 }
 
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
new file mode 100644
index 0000000..1bcf070
--- /dev/null
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -0,0 +1,533 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <C2AllocatorIon.h>
+#include <C2AllocatorGralloc.h>
+#include <C2Buffer.h>
+#include <C2BufferPriv.h>
+#include <C2ParamDef.h>
+
+#include <system/graphics.h>
+
+namespace android {
+
+class C2BufferTest : public ::testing::Test {
+public:
+    C2BufferTest()
+        : mLinearAllocator(std::make_shared<C2AllocatorIon>()),
+          mSize(0u),
+          mAddr(nullptr),
+          mGraphicAllocator(std::make_shared<C2AllocatorGralloc>()) {
+    }
+
+    ~C2BufferTest() = default;
+
+    void allocateLinear(size_t capacity) {
+        c2_status_t err = mLinearAllocator->newLinearAllocation(
+                capacity,
+                { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+                &mLinearAllocation);
+        if (err != C2_OK) {
+            mLinearAllocation.reset();
+            FAIL() << "C2Allocator::newLinearAllocation() failed: " << err;
+        }
+    }
+
+    void mapLinear(size_t offset, size_t size, uint8_t **addr) {
+        ASSERT_TRUE(mLinearAllocation);
+        c2_status_t err = mLinearAllocation->map(
+                offset,
+                size,
+                { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+                // TODO: fence
+                nullptr,
+                &mAddr);
+        if (err != C2_OK) {
+            mAddr = nullptr;
+            FAIL() << "C2LinearAllocation::map() failed: " << err;
+        }
+        ASSERT_NE(nullptr, mAddr);
+        mSize = size;
+        *addr = (uint8_t *)mAddr;
+    }
+
+    void unmapLinear() {
+        ASSERT_TRUE(mLinearAllocation);
+        ASSERT_NE(nullptr, mAddr);
+        ASSERT_NE(0u, mSize);
+
+        // TODO: fence
+        ASSERT_EQ(C2_OK, mLinearAllocation->unmap(mAddr, mSize, nullptr));
+        mSize = 0u;
+        mAddr = nullptr;
+    }
+
+    std::shared_ptr<C2BlockPool> makeLinearBlockPool() {
+        return std::make_shared<C2BasicLinearBlockPool>(mLinearAllocator);
+    }
+
+    void allocateGraphic(uint32_t width, uint32_t height) {
+        c2_status_t err = mGraphicAllocator->newGraphicAllocation(
+                width,
+                height,
+                HAL_PIXEL_FORMAT_YCBCR_420_888,
+                { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+                &mGraphicAllocation);
+        if (err != C2_OK) {
+            mGraphicAllocation.reset();
+            FAIL() << "C2Allocator::newGraphicAllocation() failed: " << err;
+        }
+    }
+
+    void mapGraphic(C2Rect rect, C2PlaneLayout *layout, uint8_t **addr) {
+        ASSERT_TRUE(mGraphicAllocation);
+        c2_status_t err = mGraphicAllocation->map(
+                rect,
+                { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+                // TODO: fence
+                nullptr,
+                layout,
+                addr);
+        if (err != C2_OK) {
+            addr[C2PlaneLayout::Y] = nullptr;
+            addr[C2PlaneLayout::U] = nullptr;
+            addr[C2PlaneLayout::V] = nullptr;
+            FAIL() << "C2GraphicAllocation::map() failed: " << err;
+        }
+    }
+
+    void unmapGraphic() {
+        ASSERT_TRUE(mGraphicAllocation);
+
+        // TODO: fence
+        ASSERT_EQ(C2_OK, mGraphicAllocation->unmap(nullptr));
+    }
+
+    std::shared_ptr<C2BlockPool> makeGraphicBlockPool() {
+        return std::make_shared<C2BasicGraphicBlockPool>(mGraphicAllocator);
+    }
+
+private:
+    std::shared_ptr<C2Allocator> mLinearAllocator;
+    std::shared_ptr<C2LinearAllocation> mLinearAllocation;
+    size_t mSize;
+    void *mAddr;
+
+    std::shared_ptr<C2Allocator> mGraphicAllocator;
+    std::shared_ptr<C2GraphicAllocation> mGraphicAllocation;
+};
+
+TEST_F(C2BufferTest, LinearAllocationTest) {
+    constexpr size_t kCapacity = 1024u * 1024u;
+
+    allocateLinear(kCapacity);
+
+    uint8_t *addr = nullptr;
+    mapLinear(0u, kCapacity, &addr);
+    ASSERT_NE(nullptr, addr);
+
+    for (size_t i = 0; i < kCapacity; ++i) {
+        addr[i] = i % 100u;
+    }
+
+    unmapLinear();
+    addr = nullptr;
+
+    mapLinear(kCapacity / 3, kCapacity / 3, &addr);
+    ASSERT_NE(nullptr, addr);
+    for (size_t i = 0; i < kCapacity / 3; ++i) {
+        ASSERT_EQ((i + kCapacity / 3) % 100, addr[i]) << " at i = " << i;
+    }
+}
+
+TEST_F(C2BufferTest, BlockPoolTest) {
+    constexpr size_t kCapacity = 1024u * 1024u;
+
+    std::shared_ptr<C2BlockPool> blockPool(makeLinearBlockPool());
+
+    std::shared_ptr<C2LinearBlock> block;
+    ASSERT_EQ(C2_OK, blockPool->fetchLinearBlock(
+            kCapacity,
+            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+            &block));
+    ASSERT_TRUE(block);
+
+    C2Acquirable<C2WriteView> writeViewHolder = block->map();
+    C2WriteView writeView = writeViewHolder.get();
+    ASSERT_EQ(C2_OK, writeView.error());
+    ASSERT_EQ(kCapacity, writeView.capacity());
+    ASSERT_EQ(0u, writeView.offset());
+    ASSERT_EQ(kCapacity, writeView.size());
+
+    uint8_t *data = writeView.data();
+    ASSERT_NE(nullptr, data);
+    for (size_t i = 0; i < writeView.size(); ++i) {
+        data[i] = i % 100u;
+    }
+
+    C2Fence fence;
+    C2ConstLinearBlock constBlock = block->share(
+            kCapacity / 3, kCapacity / 3, fence);
+
+    C2Acquirable<C2ReadView> readViewHolder = constBlock.map();
+    C2ReadView readView = readViewHolder.get();
+    ASSERT_EQ(C2_OK, readView.error());
+    ASSERT_EQ(kCapacity / 3, readView.capacity());
+
+    // TODO: fence
+    const uint8_t *constData = readView.data();
+    ASSERT_NE(nullptr, constData);
+    for (size_t i = 0; i < readView.capacity(); ++i) {
+        ASSERT_EQ((i + kCapacity / 3) % 100u, constData[i]) << " at i = " << i
+                << "; data = " << static_cast<void *>(data)
+                << "; constData = " << static_cast<const void *>(constData);
+    }
+
+    readView = readView.subView(333u, 100u);
+    ASSERT_EQ(C2_OK, readView.error());
+    ASSERT_EQ(100u, readView.capacity());
+
+    constData = readView.data();
+    ASSERT_NE(nullptr, constData);
+    for (size_t i = 0; i < readView.capacity(); ++i) {
+        ASSERT_EQ((i + 333u + kCapacity / 3) % 100u, constData[i]) << " at i = " << i;
+    }
+}
+
+void fillPlane(const C2Rect rect, const C2PlaneInfo info, uint8_t *addr, uint8_t value) {
+    for (uint32_t row = 0; row < rect.mHeight / info.mVertSubsampling; ++row) {
+        int32_t rowOffset = (row + rect.mTop / info.mVertSubsampling) * info.mRowInc;
+        for (uint32_t col = 0; col < rect.mWidth / info.mHorizSubsampling; ++col) {
+            int32_t colOffset = (col + rect.mLeft / info.mHorizSubsampling) * info.mColInc;
+            addr[rowOffset + colOffset] = value;
+        }
+    }
+}
+
+bool verifyPlane(const C2Rect rect, const C2PlaneInfo info, const uint8_t *addr, uint8_t value) {
+    for (uint32_t row = 0; row < rect.mHeight / info.mVertSubsampling; ++row) {
+        int32_t rowOffset = (row + rect.mTop / info.mVertSubsampling) * info.mRowInc;
+        for (uint32_t col = 0; col < rect.mWidth / info.mHorizSubsampling; ++col) {
+            int32_t colOffset = (col + rect.mLeft / info.mHorizSubsampling) * info.mColInc;
+            if (addr[rowOffset + colOffset] != value) {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+TEST_F(C2BufferTest, GraphicAllocationTest) {
+    constexpr uint32_t kWidth = 320;
+    constexpr uint32_t kHeight = 240;
+
+    allocateGraphic(kWidth, kHeight);
+
+    uint8_t *addr[C2PlaneLayout::MAX_NUM_PLANES];
+    C2Rect rect{ 0, 0, kWidth, kHeight };
+    C2PlaneLayout layout;
+    mapGraphic(rect, &layout, addr);
+    ASSERT_NE(nullptr, addr[C2PlaneLayout::Y]);
+    ASSERT_NE(nullptr, addr[C2PlaneLayout::U]);
+    ASSERT_NE(nullptr, addr[C2PlaneLayout::V]);
+
+    uint8_t *y = addr[C2PlaneLayout::Y];
+    C2PlaneInfo yInfo = layout.mPlanes[C2PlaneLayout::Y];
+    uint8_t *u = addr[C2PlaneLayout::U];
+    C2PlaneInfo uInfo = layout.mPlanes[C2PlaneLayout::U];
+    uint8_t *v = addr[C2PlaneLayout::V];
+    C2PlaneInfo vInfo = layout.mPlanes[C2PlaneLayout::V];
+
+    fillPlane(rect, yInfo, y, 0);
+    fillPlane(rect, uInfo, u, 0);
+    fillPlane(rect, vInfo, v, 0);
+    fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, yInfo, y, 0x12);
+    fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, uInfo, u, 0x34);
+    fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, vInfo, v, 0x56);
+
+    unmapGraphic();
+
+    mapGraphic(rect, &layout, addr);
+    ASSERT_NE(nullptr, addr[C2PlaneLayout::Y]);
+    ASSERT_NE(nullptr, addr[C2PlaneLayout::U]);
+    ASSERT_NE(nullptr, addr[C2PlaneLayout::V]);
+
+    y = addr[C2PlaneLayout::Y];
+    yInfo = layout.mPlanes[C2PlaneLayout::Y];
+    u = addr[C2PlaneLayout::U];
+    uInfo = layout.mPlanes[C2PlaneLayout::U];
+    v = addr[C2PlaneLayout::V];
+    vInfo = layout.mPlanes[C2PlaneLayout::V];
+
+    ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, yInfo, y, 0x12));
+    ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, uInfo, u, 0x34));
+    ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, vInfo, v, 0x56));
+    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, yInfo, y, 0));
+    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, uInfo, u, 0));
+    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, vInfo, v, 0));
+    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, yInfo, y, 0));
+    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, uInfo, u, 0));
+    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, vInfo, v, 0));
+}
+
+TEST_F(C2BufferTest, GraphicBlockPoolTest) {
+    constexpr uint32_t kWidth = 320;
+    constexpr uint32_t kHeight = 240;
+
+    std::shared_ptr<C2BlockPool> blockPool(makeGraphicBlockPool());
+
+    std::shared_ptr<C2GraphicBlock> block;
+    ASSERT_EQ(C2_OK, blockPool->fetchGraphicBlock(
+            kWidth,
+            kHeight,
+            HAL_PIXEL_FORMAT_YCBCR_420_888,
+            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+            &block));
+    ASSERT_TRUE(block);
+
+    C2Acquirable<C2GraphicView> graphicViewHolder = block->map();
+    C2GraphicView graphicView = graphicViewHolder.get();
+    ASSERT_EQ(C2_OK, graphicView.error());
+    ASSERT_EQ(kWidth, graphicView.width());
+    ASSERT_EQ(kHeight, graphicView.height());
+
+    uint8_t *const *data = graphicView.data();
+    C2PlaneLayout layout = graphicView.layout();
+    ASSERT_NE(nullptr, data);
+
+    uint8_t *y = data[C2PlaneLayout::Y];
+    C2PlaneInfo yInfo = layout.mPlanes[C2PlaneLayout::Y];
+    uint8_t *u = data[C2PlaneLayout::U];
+    C2PlaneInfo uInfo = layout.mPlanes[C2PlaneLayout::U];
+    uint8_t *v = data[C2PlaneLayout::V];
+    C2PlaneInfo vInfo = layout.mPlanes[C2PlaneLayout::V];
+
+    fillPlane({ 0, 0, kWidth, kHeight }, yInfo, y, 0);
+    fillPlane({ 0, 0, kWidth, kHeight }, uInfo, u, 0);
+    fillPlane({ 0, 0, kWidth, kHeight }, vInfo, v, 0);
+    fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, yInfo, y, 0x12);
+    fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, uInfo, u, 0x34);
+    fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, vInfo, v, 0x56);
+
+    C2Fence fence;
+    C2ConstGraphicBlock constBlock = block->share(
+            { 0, 0, kWidth, kHeight }, fence);
+    block.reset();
+
+    C2Acquirable<const C2GraphicView> constViewHolder = constBlock.map();
+    const C2GraphicView constGraphicView = constViewHolder.get();
+    ASSERT_EQ(C2_OK, constGraphicView.error());
+    ASSERT_EQ(kWidth, constGraphicView.width());
+    ASSERT_EQ(kHeight, constGraphicView.height());
+
+    const uint8_t *const *constData = constGraphicView.data();
+    layout = graphicView.layout();
+    ASSERT_NE(nullptr, constData);
+
+    const uint8_t *cy = constData[C2PlaneLayout::Y];
+    yInfo = layout.mPlanes[C2PlaneLayout::Y];
+    const uint8_t *cu = constData[C2PlaneLayout::U];
+    uInfo = layout.mPlanes[C2PlaneLayout::U];
+    const uint8_t *cv = constData[C2PlaneLayout::V];
+    vInfo = layout.mPlanes[C2PlaneLayout::V];
+
+    ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, yInfo, cy, 0x12));
+    ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, uInfo, cu, 0x34));
+    ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, vInfo, cv, 0x56));
+    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, yInfo, cy, 0));
+    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, uInfo, cu, 0));
+    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, vInfo, cv, 0));
+    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, yInfo, cy, 0));
+    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, uInfo, cu, 0));
+    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, vInfo, cv, 0));
+}
+
+class BufferData : public C2BufferData {
+public:
+    explicit BufferData(const std::list<C2ConstLinearBlock> &blocks) : C2BufferData(blocks) {}
+    explicit BufferData(const std::list<C2ConstGraphicBlock> &blocks) : C2BufferData(blocks) {}
+};
+
+class Buffer : public C2Buffer {
+public:
+    explicit Buffer(const std::list<C2ConstLinearBlock> &blocks) : C2Buffer(blocks) {}
+    explicit Buffer(const std::list<C2ConstGraphicBlock> &blocks) : C2Buffer(blocks) {}
+};
+
+TEST_F(C2BufferTest, BufferDataTest) {
+    std::shared_ptr<C2BlockPool> linearBlockPool(makeLinearBlockPool());
+    std::shared_ptr<C2BlockPool> graphicBlockPool(makeGraphicBlockPool());
+
+    constexpr uint32_t kWidth1 = 320;
+    constexpr uint32_t kHeight1 = 240;
+    constexpr C2Rect kCrop1(kWidth1, kHeight1);
+    constexpr uint32_t kWidth2 = 176;
+    constexpr uint32_t kHeight2 = 144;
+    constexpr C2Rect kCrop2(kWidth2, kHeight2);
+    constexpr size_t kCapacity1 = 1024u;
+    constexpr size_t kCapacity2 = 2048u;
+
+    std::shared_ptr<C2LinearBlock> linearBlock1;
+    std::shared_ptr<C2LinearBlock> linearBlock2;
+    ASSERT_EQ(C2_OK, linearBlockPool->fetchLinearBlock(
+            kCapacity1,
+            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+            &linearBlock1));
+    ASSERT_EQ(C2_OK, linearBlockPool->fetchLinearBlock(
+            kCapacity2,
+            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+            &linearBlock2));
+    std::shared_ptr<C2GraphicBlock> graphicBlock1;
+    std::shared_ptr<C2GraphicBlock> graphicBlock2;
+    ASSERT_EQ(C2_OK, graphicBlockPool->fetchGraphicBlock(
+            kWidth1,
+            kHeight1,
+            HAL_PIXEL_FORMAT_YCBCR_420_888,
+            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+            &graphicBlock1));
+    ASSERT_EQ(C2_OK, graphicBlockPool->fetchGraphicBlock(
+            kWidth2,
+            kHeight2,
+            HAL_PIXEL_FORMAT_YCBCR_420_888,
+            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+            &graphicBlock2));
+
+    std::shared_ptr<C2BufferData> data(new BufferData({ linearBlock1->share(0, kCapacity1, C2Fence()) }));
+    EXPECT_EQ(C2BufferData::LINEAR, data->type());
+    ASSERT_EQ(1u, data->linearBlocks().size());
+    EXPECT_EQ(linearBlock1->handle(), data->linearBlocks().front().handle());
+    EXPECT_TRUE(data->graphicBlocks().empty());
+
+    data.reset(new BufferData({
+        linearBlock1->share(0, kCapacity1, C2Fence()),
+        linearBlock2->share(0, kCapacity2, C2Fence()),
+    }));
+    EXPECT_EQ(C2BufferData::LINEAR_CHUNKS, data->type());
+    ASSERT_EQ(2u, data->linearBlocks().size());
+    EXPECT_EQ(linearBlock1->handle(), data->linearBlocks().front().handle());
+    EXPECT_EQ(linearBlock2->handle(), data->linearBlocks().back().handle());
+    EXPECT_TRUE(data->graphicBlocks().empty());
+
+    data.reset(new BufferData({ graphicBlock1->share(kCrop1, C2Fence()) }));
+    EXPECT_EQ(C2BufferData::GRAPHIC, data->type());
+    ASSERT_EQ(1u, data->graphicBlocks().size());
+    EXPECT_EQ(graphicBlock1->handle(), data->graphicBlocks().front().handle());
+    EXPECT_TRUE(data->linearBlocks().empty());
+
+    data.reset(new BufferData({
+        graphicBlock1->share(kCrop1, C2Fence()),
+        graphicBlock2->share(kCrop2, C2Fence()),
+    }));
+    EXPECT_EQ(C2BufferData::GRAPHIC_CHUNKS, data->type());
+    ASSERT_EQ(2u, data->graphicBlocks().size());
+    EXPECT_EQ(graphicBlock1->handle(), data->graphicBlocks().front().handle());
+    EXPECT_EQ(graphicBlock2->handle(), data->graphicBlocks().back().handle());
+    EXPECT_TRUE(data->linearBlocks().empty());
+}
+
+void DestroyCallback(const C2Buffer * /* buf */, void *arg) {
+    std::function<void(void)> *cb = (std::function<void(void)> *)arg;
+    (*cb)();
+}
+
+enum : uint32_t {
+    kParamIndexNumber1,
+    kParamIndexNumber2,
+};
+
+typedef C2GlobalParam<C2Info, C2Int32Value, kParamIndexNumber1> C2Number1Info;
+typedef C2GlobalParam<C2Info, C2Int32Value, kParamIndexNumber2> C2Number2Info;
+
+TEST_F(C2BufferTest, BufferTest) {
+    std::shared_ptr<C2BlockPool> alloc(makeLinearBlockPool());
+    constexpr size_t kCapacity = 1024u;
+    std::shared_ptr<C2LinearBlock> block;
+
+    ASSERT_EQ(C2_OK, alloc->fetchLinearBlock(
+            kCapacity,
+            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+            &block));
+
+    std::atomic_bool destroyed(false);
+    std::function<void(void)> arg = [&destroyed](){ destroyed = true; };
+
+    std::shared_ptr<C2Buffer> buffer(new Buffer( { block->share(0, kCapacity, C2Fence()) }));
+    ASSERT_EQ(C2_OK, buffer->registerOnDestroyNotify(&DestroyCallback, &arg));
+    EXPECT_FALSE(destroyed);
+    ASSERT_EQ(C2_DUPLICATE, buffer->registerOnDestroyNotify(&DestroyCallback, &arg));
+    buffer.reset();
+    EXPECT_TRUE(destroyed);
+
+    buffer.reset(new Buffer( { block->share(0, kCapacity, C2Fence()) }));
+    destroyed = false;
+    ASSERT_EQ(C2_OK, buffer->registerOnDestroyNotify(&DestroyCallback, &arg));
+    EXPECT_FALSE(destroyed);
+    ASSERT_EQ(C2_NOT_FOUND, buffer->unregisterOnDestroyNotify(&DestroyCallback, nullptr));
+    ASSERT_EQ(C2_OK, buffer->unregisterOnDestroyNotify(&DestroyCallback, &arg));
+    EXPECT_FALSE(destroyed);
+    ASSERT_EQ(C2_NOT_FOUND, buffer->unregisterOnDestroyNotify(&DestroyCallback, &arg));
+    buffer.reset();
+    EXPECT_FALSE(destroyed);
+
+    std::shared_ptr<C2Info> info1(new C2Number1Info(1));
+    std::shared_ptr<C2Info> info2(new C2Number2Info(2));
+    buffer.reset(new Buffer( { block->share(0, kCapacity, C2Fence()) }));
+    EXPECT_TRUE(buffer->infos().empty());
+    EXPECT_FALSE(buffer->hasInfo(info1->type()));
+    EXPECT_FALSE(buffer->hasInfo(info2->type()));
+
+    ASSERT_EQ(C2_OK, buffer->setInfo(info1));
+    EXPECT_EQ(1u, buffer->infos().size());
+    EXPECT_EQ(*info1, *buffer->infos().front());
+    EXPECT_TRUE(buffer->hasInfo(info1->type()));
+    EXPECT_FALSE(buffer->hasInfo(info2->type()));
+
+    ASSERT_EQ(C2_OK, buffer->setInfo(info2));
+    EXPECT_EQ(2u, buffer->infos().size());
+    EXPECT_TRUE(buffer->hasInfo(info1->type()));
+    EXPECT_TRUE(buffer->hasInfo(info2->type()));
+
+    std::shared_ptr<C2Info> removed = buffer->removeInfo(info1->type());
+    ASSERT_TRUE(removed);
+    EXPECT_EQ(*removed, *info1);
+    EXPECT_EQ(1u, buffer->infos().size());
+    EXPECT_EQ(*info2, *buffer->infos().front());
+    EXPECT_FALSE(buffer->hasInfo(info1->type()));
+    EXPECT_TRUE(buffer->hasInfo(info2->type()));
+
+    removed = buffer->removeInfo(info1->type());
+    ASSERT_FALSE(removed);
+    EXPECT_EQ(1u, buffer->infos().size());
+    EXPECT_FALSE(buffer->hasInfo(info1->type()));
+    EXPECT_TRUE(buffer->hasInfo(info2->type()));
+
+    std::shared_ptr<C2Info> info3(new C2Number2Info(3));
+    ASSERT_EQ(C2_OK, buffer->setInfo(info3));
+    EXPECT_EQ(1u, buffer->infos().size());
+    EXPECT_FALSE(buffer->hasInfo(info1->type()));
+    EXPECT_TRUE(buffer->hasInfo(info2->type()));
+
+    removed = buffer->removeInfo(info2->type());
+    ASSERT_TRUE(removed);
+    EXPECT_EQ(*info3, *removed);
+    EXPECT_TRUE(buffer->infos().empty());
+    EXPECT_FALSE(buffer->hasInfo(info1->type()));
+    EXPECT_FALSE(buffer->hasInfo(info2->type()));
+}
+
+} // namespace android
diff --git a/media/libstagefright/codec2/vndk/Android.bp b/media/libstagefright/codec2/vndk/Android.bp
new file mode 100644
index 0000000..64ce5e6
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/Android.bp
@@ -0,0 +1,39 @@
+cc_library_static {
+    name: "libstagefright_codec2_vndk",
+
+    srcs: [
+        "C2AllocatorIon.cpp",
+        "C2AllocatorGralloc.cpp",
+        "C2Buffer.cpp",
+        "C2Config.cpp",
+        "C2Store.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/codec2/include",
+        "frameworks/av/media/libstagefright/codec2/vndk/include",
+        "frameworks/native/include/media/hardware",
+    ],
+
+    shared_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+        "libbinder",
+        "libcutils",
+        "libdl",
+        "libhardware",
+        "libhidlbase",
+        "libion",
+        "liblog",
+        "libmedia",
+        "libstagefright_foundation",
+        "libui",
+        "libutils",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-std=c++14",
+    ],
+}
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
new file mode 100644
index 0000000..da8372c
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2AllocatorGralloc"
+#include <utils/Log.h>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <hardware/gralloc.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2Buffer.h>
+
+namespace android {
+
+using ::android::hardware::graphics::allocator::V2_0::IAllocator;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+using ::android::hardware::graphics::mapper::V2_0::Error;
+using ::android::hardware::graphics::mapper::V2_0::IMapper;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_vec;
+
+/* ===================================== GRALLOC ALLOCATION ==================================== */
+static c2_status_t maperr2error(Error maperr) {
+    switch (maperr) {
+        case Error::NONE:           return C2_OK;
+        case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE;
+        case Error::BAD_BUFFER:     return C2_BAD_VALUE;
+        case Error::BAD_VALUE:      return C2_BAD_VALUE;
+        case Error::NO_RESOURCES:   return C2_NO_MEMORY;
+        case Error::UNSUPPORTED:    return C2_CANNOT_DO;
+    }
+    return C2_CORRUPTED;
+}
+
+class C2AllocationGralloc : public C2GraphicAllocation {
+public:
+    virtual ~C2AllocationGralloc() override;
+
+    virtual c2_status_t map(
+            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+            C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
+    virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) override;
+    virtual bool isValid() const override { return true; }
+    virtual const C2Handle *handle() const override { return mHandle; }
+    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;
+
+    // internal methods
+    // |handle| will be moved.
+    C2AllocationGralloc(
+              const IMapper::BufferDescriptorInfo &info,
+              const sp<IMapper> &mapper,
+              hidl_handle &handle);
+    int dup() const;
+    c2_status_t status() const;
+
+private:
+    const IMapper::BufferDescriptorInfo mInfo;
+    const sp<IMapper> mMapper;
+    const hidl_handle mHandle;
+    buffer_handle_t mBuffer;
+    bool mLocked;
+};
+
+C2AllocationGralloc::C2AllocationGralloc(
+          const IMapper::BufferDescriptorInfo &info,
+          const sp<IMapper> &mapper,
+          hidl_handle &handle)
+    : C2GraphicAllocation(info.width, info.height),
+      mInfo(info),
+      mMapper(mapper),
+      mHandle(std::move(handle)),
+      mBuffer(nullptr),
+      mLocked(false) {}
+
+C2AllocationGralloc::~C2AllocationGralloc() {
+    if (!mBuffer) {
+        return;
+    }
+    if (mLocked) {
+        unmap(nullptr);
+    }
+    mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
+}
+
+c2_status_t C2AllocationGralloc::map(
+        C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+        C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+    // TODO
+    (void) fenceFd;
+    (void) usage;
+
+    if (mBuffer && mLocked) {
+        return C2_DUPLICATE;
+    }
+    if (!layout || !addr) {
+        return C2_BAD_VALUE;
+    }
+
+    c2_status_t err = C2_OK;
+    if (!mBuffer) {
+        mMapper->importBuffer(
+                mHandle, [&err, this](const auto &maperr, const auto &buffer) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        mBuffer = static_cast<buffer_handle_t>(buffer);
+                    }
+                });
+        if (err != C2_OK) {
+            return err;
+        }
+    }
+
+    if (mInfo.format == PixelFormat::YCBCR_420_888 || mInfo.format == PixelFormat::YV12) {
+        YCbCrLayout ycbcrLayout;
+        mMapper->lockYCbCr(
+                const_cast<native_handle_t *>(mBuffer),
+                BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+                { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
+                // TODO: fence
+                hidl_handle(),
+                [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        ycbcrLayout = mapLayout;
+                    }
+                });
+        if (err != C2_OK) {
+            return err;
+        }
+        addr[C2PlaneLayout::Y] = (uint8_t *)ycbcrLayout.y;
+        addr[C2PlaneLayout::U] = (uint8_t *)ycbcrLayout.cb;
+        addr[C2PlaneLayout::V] = (uint8_t *)ycbcrLayout.cr;
+        layout->mType = C2PlaneLayout::MEDIA_IMAGE_TYPE_YUV;
+        layout->mNumPlanes = 3;
+        layout->mPlanes[C2PlaneLayout::Y] = {
+            C2PlaneInfo::Y,                 // mChannel
+            1,                              // mColInc
+            (int32_t)ycbcrLayout.yStride,   // mRowInc
+            1,                              // mHorizSubsampling
+            1,                              // mVertSubsampling
+            8,                              // mBitDepth
+            8,                              // mAllocatedDepth
+        };
+        layout->mPlanes[C2PlaneLayout::U] = {
+            C2PlaneInfo::Cb,                  // mChannel
+            (int32_t)ycbcrLayout.chromaStep,  // mColInc
+            (int32_t)ycbcrLayout.cStride,     // mRowInc
+            2,                                // mHorizSubsampling
+            2,                                // mVertSubsampling
+            8,                                // mBitDepth
+            8,                                // mAllocatedDepth
+        };
+        layout->mPlanes[C2PlaneLayout::V] = {
+            C2PlaneInfo::Cr,                  // mChannel
+            (int32_t)ycbcrLayout.chromaStep,  // mColInc
+            (int32_t)ycbcrLayout.cStride,     // mRowInc
+            2,                                // mHorizSubsampling
+            2,                                // mVertSubsampling
+            8,                                // mBitDepth
+            8,                                // mAllocatedDepth
+        };
+    } else {
+        void *pointer = nullptr;
+        mMapper->lock(
+                const_cast<native_handle_t *>(mBuffer),
+                BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+                { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
+                // TODO: fence
+                hidl_handle(),
+                [&err, &pointer](const auto &maperr, const auto &mapPointer) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        pointer = mapPointer;
+                    }
+                });
+        if (err != C2_OK) {
+            return err;
+        }
+        // TODO
+        return C2_OMITTED;
+    }
+    mLocked = true;
+
+    return C2_OK;
+}
+
+c2_status_t C2AllocationGralloc::unmap(C2Fence *fenceFd /* nullable */) {
+    // TODO: fence
+    c2_status_t err = C2_OK;
+    mMapper->unlock(
+            const_cast<native_handle_t *>(mBuffer),
+            [&err, &fenceFd](const auto &maperr, const auto &releaseFence) {
+                // TODO
+                (void) fenceFd;
+                (void) releaseFence;
+                err = maperr2error(maperr);
+                if (err == C2_OK) {
+                    // TODO: fence
+                }
+            });
+    if (err == C2_OK) {
+        mLocked = false;
+    }
+    return err;
+}
+
+bool C2AllocationGralloc::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const {
+    return other && other->handle() == handle();
+}
+
+/* ===================================== GRALLOC ALLOCATOR ==================================== */
+class C2AllocatorGralloc::Impl {
+public:
+    Impl();
+
+    id_t getId() const;
+
+    C2String getName() const;
+
+    c2_status_t newGraphicAllocation(
+            uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
+            std::shared_ptr<C2GraphicAllocation> *allocation);
+
+    c2_status_t priorGraphicAllocation(
+            const C2Handle *handle,
+            std::shared_ptr<C2GraphicAllocation> *allocation);
+
+    c2_status_t status() const { return mInit; }
+
+private:
+    c2_status_t mInit;
+    sp<IAllocator> mAllocator;
+    sp<IMapper> mMapper;
+};
+
+C2AllocatorGralloc::Impl::Impl() : mInit(C2_OK) {
+    // TODO: share a global service
+    mAllocator = IAllocator::getService();
+    mMapper = IMapper::getService();
+    if (mAllocator == nullptr || mMapper == nullptr) {
+        mInit = C2_CORRUPTED;
+    }
+}
+
+C2Allocator::id_t C2AllocatorGralloc::Impl::getId() const {
+    return 1; /// \todo implement ID
+}
+
+C2String C2AllocatorGralloc::Impl::getName() const {
+    return "android.allocator.gralloc";
+}
+
+c2_status_t C2AllocatorGralloc::Impl::newGraphicAllocation(
+        uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    // TODO: buffer usage should be determined according to |usage|
+    (void) usage;
+
+    IMapper::BufferDescriptorInfo info = {
+        width,
+        height,
+        1u,  // layerCount
+        (PixelFormat)format,
+        BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+    };
+    c2_status_t err = C2_OK;
+    BufferDescriptor desc;
+    mMapper->createDescriptor(
+            info, [&err, &desc](const auto &maperr, const auto &descriptor) {
+                err = maperr2error(maperr);
+                if (err == C2_OK) {
+                    desc = descriptor;
+                }
+            });
+    if (err != C2_OK) {
+        return err;
+    }
+
+    // IAllocator shares IMapper error codes.
+    hidl_handle buffer;
+    mAllocator->allocate(
+            desc,
+            1u,
+            [&err, &buffer](const auto &maperr, const auto &stride, auto &buffers) {
+                (void) stride;
+                err = maperr2error(maperr);
+                if (err != C2_OK) {
+                    return;
+                }
+                if (buffers.size() != 1u) {
+                    err = C2_CORRUPTED;
+                    return;
+                }
+                buffer = std::move(buffers[0]);
+            });
+    if (err != C2_OK) {
+        return err;
+    }
+
+    allocation->reset(new C2AllocationGralloc(info, mMapper, buffer));
+    return C2_OK;
+}
+
+c2_status_t C2AllocatorGralloc::Impl::priorGraphicAllocation(
+        const C2Handle *handle,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    (void) handle;
+
+    // TODO: need to figure out BufferDescriptorInfo from the handle.
+    allocation->reset();
+    return C2_OMITTED;
+}
+
+C2AllocatorGralloc::C2AllocatorGralloc() : mImpl(new Impl) {}
+
+C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
+
+C2Allocator::id_t C2AllocatorGralloc::getId() const {
+    return mImpl->getId();
+}
+
+C2String C2AllocatorGralloc::getName() const {
+    return mImpl->getName();
+}
+
+c2_status_t C2AllocatorGralloc::newGraphicAllocation(
+        uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    return mImpl->newGraphicAllocation(width, height, format, usage, allocation);
+}
+
+c2_status_t C2AllocatorGralloc::priorGraphicAllocation(
+        const C2Handle *handle,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    return mImpl->priorGraphicAllocation(handle, allocation);
+}
+
+c2_status_t C2AllocatorGralloc::status() const {
+    return mImpl->status();
+}
+
+} // namespace android
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
new file mode 100644
index 0000000..acd69af
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2AllocatorIon"
+#include <utils/Log.h>
+
+#include <ion/ion.h>
+#include <sys/mman.h>
+
+#include <C2AllocatorIon.h>
+#include <C2Buffer.h>
+#include <C2ErrnoUtils.h>
+
+namespace android {
+
+/* ========================================= ION HANDLE ======================================== */
+struct C2HandleIon : public C2Handle {
+    C2HandleIon(int ionFd, ion_user_handle_t buffer) : C2Handle(cHeader),
+          mFds{ ionFd, buffer },
+          mInts{ kMagic } { }
+
+    static bool isValid(const C2Handle * const o);
+
+    int ionFd() const { return mFds.mIon; }
+    ion_user_handle_t buffer() const { return mFds.mBuffer; }
+
+    void setBuffer(ion_user_handle_t bufferFd) { mFds.mBuffer = bufferFd; }
+
+protected:
+    struct {
+        int mIon;
+        int mBuffer; // ion_user_handle_t
+    } mFds;
+    struct {
+        int mMagic;
+    } mInts;
+
+private:
+    typedef C2HandleIon _type;
+    enum {
+        kMagic = 'ion1',
+        numFds = sizeof(mFds) / sizeof(int),
+        numInts = sizeof(mInts) / sizeof(int),
+        version = sizeof(C2Handle) + sizeof(mFds) + sizeof(mInts)
+    };
+    //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
+    const static C2Handle cHeader;
+};
+
+const C2Handle C2HandleIon::cHeader = {
+    C2HandleIon::version,
+    C2HandleIon::numFds,
+    C2HandleIon::numInts,
+    {}
+};
+
+// static
+bool C2HandleIon::isValid(const C2Handle * const o) {
+    if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
+        return false;
+    }
+    const C2HandleIon *other = static_cast<const C2HandleIon*>(o);
+    return other->mInts.mMagic == kMagic;
+}
+
+// TODO: is the dup of an ion fd identical to ion_share?
+
+/* ======================================= ION ALLOCATION ====================================== */
+class C2AllocationIon : public C2LinearAllocation {
+public:
+    virtual c2_status_t map(
+        size_t offset, size_t size, C2MemoryUsage usage, int *fence,
+        void **addr /* nonnull */) override;
+    virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd) override;
+    virtual bool isValid() const override;
+    virtual ~C2AllocationIon() override;
+    virtual const C2Handle *handle() const override;
+    virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const override;
+
+    // internal methods
+    C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags);
+    C2AllocationIon(int ionFd, size_t size, int shareFd);
+    int dup() const;
+    c2_status_t status() const;
+
+protected:
+    class Impl;
+    Impl *mImpl;
+};
+
+class C2AllocationIon::Impl {
+public:
+    // NOTE: using constructor here instead of a factory method as we will need the
+    // error value and this simplifies the error handling by the wrapper.
+    Impl(int ionFd, size_t capacity, size_t align, unsigned heapMask, unsigned flags)
+        : mInit(C2_OK),
+          mHandle(ionFd, -1),
+          mMapFd(-1),
+          mCapacity(capacity) {
+        ion_user_handle_t buffer = -1;
+        int ret = ion_alloc(mHandle.ionFd(), mCapacity, align, heapMask, flags, &buffer);
+        if (ret == 0) {
+            mHandle.setBuffer(buffer);
+        } else {
+            mInit = c2_map_errno<ENOMEM, EACCES, EINVAL>(-ret);
+        }
+    }
+
+    Impl(int ionFd, size_t capacity, int shareFd)
+        : mInit(C2_OK),
+          mHandle(ionFd, -1),
+          mMapFd(-1),
+          mCapacity(capacity) {
+        ion_user_handle_t buffer;
+        int ret = ion_import(mHandle.ionFd(), shareFd, &buffer);
+        switch (-ret) {
+        case 0:
+            mHandle.setBuffer(buffer);
+            break;
+        case EBADF: // bad ion handle - should not happen
+        case ENOTTY: // bad ion driver
+            mInit = C2_CORRUPTED;
+            break;
+        default:
+            mInit = c2_map_errno<ENOMEM, EACCES, EINVAL>(-ret);
+            break;
+        }
+        (void)mCapacity; // TODO
+    }
+
+    c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
+        (void)fenceFd; // TODO: wait for fence
+        *addr = nullptr;
+        int prot = PROT_NONE;
+        int flags = MAP_PRIVATE;
+        if (usage.mConsumer & GRALLOC_USAGE_SW_READ_MASK) {
+            prot |= PROT_READ;
+        }
+        if (usage.mProducer & GRALLOC_USAGE_SW_WRITE_MASK) {
+            prot |= PROT_WRITE;
+            flags = MAP_SHARED;
+        }
+
+        size_t alignmentBytes = offset % PAGE_SIZE;
+        size_t mapOffset = offset - alignmentBytes;
+        size_t mapSize = size + alignmentBytes;
+
+        c2_status_t err = C2_OK;
+        if (mMapFd == -1) {
+            int ret = ion_map(mHandle.ionFd(), mHandle.buffer(), mapSize, prot,
+                              flags, mapOffset, (unsigned char**)&mMapAddr, &mMapFd);
+            if (ret) {
+                mMapFd = -1;
+                *addr = nullptr;
+                err = c2_map_errno<EINVAL>(-ret);
+            } else {
+                *addr = (uint8_t *)mMapAddr + alignmentBytes;
+                mMapAlignmentBytes = alignmentBytes;
+                mMapSize = mapSize;
+            }
+        } else {
+            mMapAddr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
+            if (mMapAddr == MAP_FAILED) {
+                mMapAddr = *addr = nullptr;
+                err = c2_map_errno<EINVAL>(errno);
+            } else {
+                *addr = (uint8_t *)mMapAddr + alignmentBytes;
+                mMapAlignmentBytes = alignmentBytes;
+                mMapSize = mapSize;
+            }
+        }
+        return err;
+    }
+
+    c2_status_t unmap(void *addr, size_t size, int *fenceFd) {
+        if (addr != (uint8_t *)mMapAddr + mMapAlignmentBytes ||
+                size + mMapAlignmentBytes != mMapSize) {
+            return C2_BAD_VALUE;
+        }
+        int err = munmap(mMapAddr, mMapSize);
+        if (err != 0) {
+            return c2_map_errno<EINVAL>(errno);
+        }
+        if (fenceFd) {
+            *fenceFd = -1;
+        }
+        return C2_OK;
+    }
+
+    ~Impl() {
+        if (mMapFd != -1) {
+            close(mMapFd);
+            mMapFd = -1;
+        }
+
+        (void)ion_free(mHandle.ionFd(), mHandle.buffer());
+    }
+
+    c2_status_t status() const {
+        return mInit;
+    }
+
+    const C2Handle * handle() const {
+        return &mHandle;
+    }
+
+    int dup() const {
+        int fd = -1;
+        if (mInit != 0 || ion_share(mHandle.ionFd(), mHandle.buffer(), &fd) != 0) {
+            fd = -1;
+        }
+        return fd;
+    }
+
+private:
+    c2_status_t mInit;
+    C2HandleIon mHandle;
+    int mMapFd; // only one for now
+    void *mMapAddr;
+    size_t mMapAlignmentBytes;
+    size_t mMapSize;
+    size_t mCapacity;
+};
+
+c2_status_t C2AllocationIon::map(
+    size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
+    return mImpl->map(offset, size, usage, fenceFd, addr);
+}
+
+c2_status_t C2AllocationIon::unmap(void *addr, size_t size, int *fenceFd) {
+    return mImpl->unmap(addr, size, fenceFd);
+}
+
+bool C2AllocationIon::isValid() const {
+    return mImpl->status() == C2_OK;
+}
+
+c2_status_t C2AllocationIon::status() const {
+    return mImpl->status();
+}
+
+bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
+    return other != nullptr &&
+        other->handle(); // TODO
+}
+
+const C2Handle *C2AllocationIon::handle() const {
+    return mImpl->handle();
+}
+
+C2AllocationIon::~C2AllocationIon() {
+    delete mImpl;
+}
+
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags)
+    : C2LinearAllocation(size),
+      mImpl(new Impl(ionFd, size, align, heapMask, flags)) { }
+
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd)
+    : C2LinearAllocation(size),
+      mImpl(new Impl(ionFd, size, shareFd)) { }
+
+int C2AllocationIon::dup() const {
+    return mImpl->dup();
+}
+
+/* ======================================= ION ALLOCATOR ====================================== */
+C2AllocatorIon::C2AllocatorIon() : mInit(C2_OK), mIonFd(ion_open()) {
+    if (mIonFd < 0) {
+        switch (errno) {
+        case ENOENT:    mInit = C2_OMITTED; break;
+        default:        mInit = c2_map_errno<EACCES>(errno); break;
+        }
+    }
+}
+
+C2AllocatorIon::~C2AllocatorIon() {
+    if (mInit == C2_OK) {
+        ion_close(mIonFd);
+    }
+}
+
+C2Allocator::id_t C2AllocatorIon::getId() const {
+    return 0; /// \todo implement ID
+}
+
+C2String C2AllocatorIon::getName() const {
+    return "android.allocator.ion";
+}
+
+c2_status_t C2AllocatorIon::newLinearAllocation(
+        uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation> *allocation) {
+    if (allocation == nullptr) {
+        return C2_BAD_VALUE;
+    }
+
+    allocation->reset();
+    if (mInit != C2_OK) {
+        return mInit;
+    }
+
+    // get align, heapMask and flags
+    //size_t align = 1;
+    size_t align = 0;
+    unsigned heapMask = ~0;
+    unsigned flags = 0;
+    //TODO
+    (void) usage;
+#if 0
+    int err = mUsageMapper(usage, capacity, &align, &heapMask, &flags);
+    if (err < 0) {
+        return c2_map_errno<EINVAL, ENOMEM, EACCES>(-err);
+    }
+#endif
+
+    std::shared_ptr<C2AllocationIon> alloc
+        = std::make_shared<C2AllocationIon>(mIonFd, capacity, align, heapMask, flags);
+    c2_status_t ret = alloc->status();
+    if (ret == C2_OK) {
+        *allocation = alloc;
+    }
+    return ret;
+}
+
+c2_status_t C2AllocatorIon::priorLinearAllocation(
+        const C2Handle *handle, std::shared_ptr<C2LinearAllocation> *allocation) {
+    *allocation = nullptr;
+    if (mInit != C2_OK) {
+        return mInit;
+    }
+
+    if (!C2HandleIon::isValid(handle)) {
+        return C2_BAD_VALUE;
+    }
+
+    // TODO: get capacity and validate it
+    const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
+    std::shared_ptr<C2AllocationIon> alloc
+        = std::make_shared<C2AllocationIon>(mIonFd, 0 /* capacity */, h->buffer());
+    c2_status_t ret = alloc->status();
+    if (ret == C2_OK) {
+        *allocation = alloc;
+    }
+    return ret;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
new file mode 100644
index 0000000..d9bde7a
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -0,0 +1,747 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2Buffer"
+#include <utils/Log.h>
+
+#include <map>
+
+#include <C2BufferPriv.h>
+
+namespace android {
+
+namespace {
+
+// Inherit from the parent, share with the friend.
+
+class DummyCapacityAspect : public _C2LinearCapacityAspect {
+    using _C2LinearCapacityAspect::_C2LinearCapacityAspect;
+    friend class ::android::C2ReadView;
+    friend class ::android::C2ConstLinearBlock;
+};
+
+class C2DefaultReadView : public C2ReadView {
+    using C2ReadView::C2ReadView;
+    friend class ::android::C2ConstLinearBlock;
+};
+
+class C2DefaultWriteView : public C2WriteView {
+    using C2WriteView::C2WriteView;
+    friend class ::android::C2LinearBlock;
+};
+
+class C2AcquirableReadView : public C2Acquirable<C2ReadView> {
+    using C2Acquirable::C2Acquirable;
+    friend class ::android::C2ConstLinearBlock;
+};
+
+class C2AcquirableWriteView : public C2Acquirable<C2WriteView> {
+    using C2Acquirable::C2Acquirable;
+    friend class ::android::C2LinearBlock;
+};
+
+class C2DefaultConstLinearBlock : public C2ConstLinearBlock {
+    using C2ConstLinearBlock::C2ConstLinearBlock;
+    friend class ::android::C2LinearBlock;
+};
+
+class C2DefaultLinearBlock : public C2LinearBlock {
+    using C2LinearBlock::C2LinearBlock;
+    friend class ::android::C2BasicLinearBlockPool;
+};
+
+class C2DefaultGraphicView : public C2GraphicView {
+    using C2GraphicView::C2GraphicView;
+    friend class ::android::C2ConstGraphicBlock;
+    friend class ::android::C2GraphicBlock;
+};
+
+class C2AcquirableConstGraphicView : public C2Acquirable<const C2GraphicView> {
+    using C2Acquirable::C2Acquirable;
+    friend class ::android::C2ConstGraphicBlock;
+};
+
+class C2AcquirableGraphicView : public C2Acquirable<C2GraphicView> {
+    using C2Acquirable::C2Acquirable;
+    friend class ::android::C2GraphicBlock;
+};
+
+class C2DefaultConstGraphicBlock : public C2ConstGraphicBlock {
+    using C2ConstGraphicBlock::C2ConstGraphicBlock;
+    friend class ::android::C2GraphicBlock;
+};
+
+class C2DefaultGraphicBlock : public C2GraphicBlock {
+    using C2GraphicBlock::C2GraphicBlock;
+    friend class ::android::C2BasicGraphicBlockPool;
+};
+
+class C2DefaultBufferData : public C2BufferData {
+    using C2BufferData::C2BufferData;
+    friend class ::android::C2Buffer;
+};
+
+}  // namespace
+
+/* ========================================== 1D BLOCK ========================================= */
+
+class C2Block1D::Impl {
+public:
+    const C2Handle *handle() const {
+        return mAllocation->handle();
+    }
+
+    Impl(std::shared_ptr<C2LinearAllocation> alloc)
+        : mAllocation(alloc) {}
+
+private:
+    std::shared_ptr<C2LinearAllocation> mAllocation;
+};
+
+const C2Handle *C2Block1D::handle() const {
+    return mImpl->handle();
+};
+
+C2Block1D::C2Block1D(std::shared_ptr<C2LinearAllocation> alloc)
+    : _C2LinearRangeAspect(alloc.get()), mImpl(new Impl(alloc)) {
+}
+
+C2Block1D::C2Block1D(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size)
+    : _C2LinearRangeAspect(alloc.get(), offset, size), mImpl(new Impl(alloc)) {
+}
+
+class C2ReadView::Impl {
+public:
+    explicit Impl(const uint8_t *data)
+        : mData(data), mError(C2_OK) {}
+
+    explicit Impl(c2_status_t error)
+        : mData(nullptr), mError(error) {}
+
+    const uint8_t *data() const {
+        return mData;
+    }
+
+    c2_status_t error() const {
+        return mError;
+    }
+
+private:
+    const uint8_t *mData;
+    c2_status_t mError;
+};
+
+C2ReadView::C2ReadView(const _C2LinearCapacityAspect *parent, const uint8_t *data)
+    : _C2LinearCapacityAspect(parent), mImpl(std::make_shared<Impl>(data)) {}
+
+C2ReadView::C2ReadView(c2_status_t error)
+    : _C2LinearCapacityAspect(0u), mImpl(std::make_shared<Impl>(error)) {}
+
+const uint8_t *C2ReadView::data() const {
+    return mImpl->data();
+}
+
+C2ReadView C2ReadView::subView(size_t offset, size_t size) const {
+    if (offset > capacity()) {
+        offset = capacity();
+    }
+    if (size > capacity() - offset) {
+        size = capacity() - offset;
+    }
+    // TRICKY: newCapacity will just be used to grab the size.
+    DummyCapacityAspect newCapacity((uint32_t)size);
+    return C2ReadView(&newCapacity, data() + offset);
+}
+
+c2_status_t C2ReadView::error() const {
+    return mImpl->error();
+}
+
+class C2WriteView::Impl {
+public:
+    explicit Impl(uint8_t *base)
+        : mBase(base), mError(C2_OK) {}
+
+    explicit Impl(c2_status_t error)
+        : mBase(nullptr), mError(error) {}
+
+    uint8_t *base() const {
+        return mBase;
+    }
+
+    c2_status_t error() const {
+        return mError;
+    }
+
+private:
+    uint8_t *mBase;
+    c2_status_t mError;
+};
+
+C2WriteView::C2WriteView(const _C2LinearRangeAspect *parent, uint8_t *base)
+    : _C2EditableLinearRange(parent), mImpl(std::make_shared<Impl>(base)) {}
+
+C2WriteView::C2WriteView(c2_status_t error)
+    : _C2EditableLinearRange(nullptr), mImpl(std::make_shared<Impl>(error)) {}
+
+uint8_t *C2WriteView::base() { return mImpl->base(); }
+
+uint8_t *C2WriteView::data() { return mImpl->base() + offset(); }
+
+c2_status_t C2WriteView::error() const { return mImpl->error(); }
+
+class C2ConstLinearBlock::Impl {
+public:
+    explicit Impl(std::shared_ptr<C2LinearAllocation> alloc)
+        : mAllocation(alloc), mBase(nullptr), mSize(0u), mError(C2_CORRUPTED) {}
+
+    ~Impl() {
+        if (mBase != nullptr) {
+            // TODO: fence
+            c2_status_t err = mAllocation->unmap(mBase, mSize, nullptr);
+            if (err != C2_OK) {
+                // TODO: Log?
+            }
+        }
+    }
+
+    C2ConstLinearBlock subBlock(size_t offset, size_t size) const {
+        return C2ConstLinearBlock(mAllocation, offset, size);
+    }
+
+    void map(size_t offset, size_t size) {
+        if (mBase == nullptr) {
+            void *base = nullptr;
+            mError = mAllocation->map(
+                    offset, size, { C2MemoryUsage::kSoftwareRead, 0 }, nullptr, &base);
+            // TODO: fence
+            if (mError == C2_OK) {
+                mBase = (uint8_t *)base;
+                mSize = size;
+            }
+        }
+    }
+
+    const uint8_t *base() const { return mBase; }
+
+    c2_status_t error() const { return mError; }
+
+private:
+    std::shared_ptr<C2LinearAllocation> mAllocation;
+    uint8_t *mBase;
+    size_t mSize;
+    c2_status_t mError;
+};
+
+C2ConstLinearBlock::C2ConstLinearBlock(std::shared_ptr<C2LinearAllocation> alloc)
+    : C2Block1D(alloc), mImpl(std::make_shared<Impl>(alloc)) {}
+
+C2ConstLinearBlock::C2ConstLinearBlock(
+        std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size)
+    : C2Block1D(alloc, offset, size), mImpl(std::make_shared<Impl>(alloc)) {}
+
+C2Acquirable<C2ReadView> C2ConstLinearBlock::map() const {
+    mImpl->map(offset(), size());
+    if (mImpl->base() == nullptr) {
+        C2DefaultReadView view(mImpl->error());
+        return C2AcquirableReadView(mImpl->error(), mFence, view);
+    }
+    DummyCapacityAspect newCapacity(size());
+    C2DefaultReadView view(&newCapacity, mImpl->base());
+    return C2AcquirableReadView(mImpl->error(), mFence, view);
+}
+
+C2ConstLinearBlock C2ConstLinearBlock::subBlock(size_t offset, size_t size) const {
+    return mImpl->subBlock(offset, size);
+}
+
+class C2LinearBlock::Impl {
+public:
+    Impl(std::shared_ptr<C2LinearAllocation> alloc)
+        : mAllocation(alloc), mBase(nullptr), mSize(0u), mError(C2_CORRUPTED) {}
+
+    ~Impl() {
+        if (mBase != nullptr) {
+            // TODO: fence
+            c2_status_t err = mAllocation->unmap(mBase, mSize, nullptr);
+            if (err != C2_OK) {
+                // TODO: Log?
+            }
+        }
+    }
+
+    void map(size_t capacity) {
+        if (mBase == nullptr) {
+            void *base = nullptr;
+            // TODO: fence
+            mError = mAllocation->map(
+                    0u,
+                    capacity,
+                    { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+                    nullptr,
+                    &base);
+            if (mError == C2_OK) {
+                mBase = (uint8_t *)base;
+                mSize = capacity;
+            }
+        }
+    }
+
+    C2ConstLinearBlock share(size_t offset, size_t size, C2Fence &fence) {
+        // TODO
+        (void) fence;
+        return C2DefaultConstLinearBlock(mAllocation, offset, size);
+    }
+
+    uint8_t *base() const { return mBase; }
+
+    c2_status_t error() const { return mError; }
+
+    C2Fence fence() const { return mFence; }
+
+private:
+    std::shared_ptr<C2LinearAllocation> mAllocation;
+    uint8_t *mBase;
+    size_t mSize;
+    c2_status_t mError;
+    C2Fence mFence;
+};
+
+C2LinearBlock::C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc)
+    : C2Block1D(alloc),
+      mImpl(new Impl(alloc)) {}
+
+C2LinearBlock::C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size)
+    : C2Block1D(alloc, offset, size),
+      mImpl(new Impl(alloc)) {}
+
+C2Acquirable<C2WriteView> C2LinearBlock::map() {
+    mImpl->map(capacity());
+    if (mImpl->base() == nullptr) {
+        C2DefaultWriteView view(mImpl->error());
+        return C2AcquirableWriteView(mImpl->error(), mImpl->fence(), view);
+    }
+    C2DefaultWriteView view(this, mImpl->base());
+    view.setOffset_be(offset());
+    view.setSize_be(size());
+    return C2AcquirableWriteView(mImpl->error(), mImpl->fence(), view);
+}
+
+C2ConstLinearBlock C2LinearBlock::share(size_t offset, size_t size, C2Fence fence) {
+    return mImpl->share(offset, size, fence);
+}
+
+C2BasicLinearBlockPool::C2BasicLinearBlockPool(
+        const std::shared_ptr<C2Allocator> &allocator)
+  : mAllocator(allocator) {}
+
+c2_status_t C2BasicLinearBlockPool::fetchLinearBlock(
+        uint32_t capacity,
+        C2MemoryUsage usage,
+        std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+    block->reset();
+
+    std::shared_ptr<C2LinearAllocation> alloc;
+    c2_status_t err = mAllocator->newLinearAllocation(capacity, usage, &alloc);
+    if (err != C2_OK) {
+        return err;
+    }
+
+    block->reset(new C2DefaultLinearBlock(alloc));
+
+    return C2_OK;
+}
+
+/* ========================================== 2D BLOCK ========================================= */
+
+class C2Block2D::Impl {
+public:
+    const C2Handle *handle() const {
+        return mAllocation->handle();
+    }
+
+    Impl(const std::shared_ptr<C2GraphicAllocation> &alloc)
+        : mAllocation(alloc) {}
+
+private:
+    std::shared_ptr<C2GraphicAllocation> mAllocation;
+};
+
+C2Block2D::C2Block2D(const std::shared_ptr<C2GraphicAllocation> &alloc)
+    : _C2PlanarSection(alloc.get()), mImpl(new Impl(alloc)) {}
+
+const C2Handle *C2Block2D::handle() const {
+    return mImpl->handle();
+}
+
+class C2GraphicView::Impl {
+public:
+    Impl(uint8_t *const *data, const C2PlaneLayout &layout)
+        : mData(data), mLayout(layout), mError(C2_OK) {}
+    explicit Impl(c2_status_t error) : mData(nullptr), mError(error) {}
+
+    uint8_t *const *data() const { return mData; }
+    const C2PlaneLayout &layout() const { return mLayout; }
+    c2_status_t error() const { return mError; }
+
+private:
+    uint8_t *const *mData;
+    C2PlaneLayout mLayout;
+    c2_status_t mError;
+};
+
+C2GraphicView::C2GraphicView(
+        const _C2PlanarCapacityAspect *parent,
+        uint8_t *const *data,
+        const C2PlaneLayout& layout)
+    : _C2PlanarSection(parent), mImpl(new Impl(data, layout)) {}
+
+C2GraphicView::C2GraphicView(c2_status_t error)
+    : _C2PlanarSection(nullptr), mImpl(new Impl(error)) {}
+
+const uint8_t *const *C2GraphicView::data() const {
+    return mImpl->data();
+}
+
+uint8_t *const *C2GraphicView::data() {
+    return mImpl->data();
+}
+
+const C2PlaneLayout C2GraphicView::layout() const {
+    return mImpl->layout();
+}
+
+const C2GraphicView C2GraphicView::subView(const C2Rect &rect) const {
+    C2GraphicView view(this, mImpl->data(), mImpl->layout());
+    view.setCrop_be(rect);
+    return view;
+}
+
+C2GraphicView C2GraphicView::subView(const C2Rect &rect) {
+    C2GraphicView view(this, mImpl->data(), mImpl->layout());
+    view.setCrop_be(rect);
+    return view;
+}
+
+c2_status_t C2GraphicView::error() const {
+    return mImpl->error();
+}
+
+class C2ConstGraphicBlock::Impl {
+public:
+    explicit Impl(const std::shared_ptr<C2GraphicAllocation> &alloc)
+        : mAllocation(alloc), mData{ nullptr } {}
+
+    ~Impl() {
+        if (mData[0] != nullptr) {
+            // TODO: fence
+            mAllocation->unmap(nullptr);
+        }
+    }
+
+    c2_status_t map(C2Rect rect) {
+        if (mData[0] != nullptr) {
+            // Already mapped.
+            return C2_OK;
+        }
+        c2_status_t err = mAllocation->map(
+                rect,
+                { C2MemoryUsage::kSoftwareRead, 0 },
+                nullptr,
+                &mLayout,
+                mData);
+        if (err != C2_OK) {
+            memset(mData, 0, sizeof(mData));
+        }
+        return err;
+    }
+
+    C2ConstGraphicBlock subBlock(const C2Rect &rect, C2Fence fence) const {
+        C2ConstGraphicBlock block(mAllocation, fence);
+        block.setCrop_be(rect);
+        return block;
+    }
+
+    uint8_t *const *data() const {
+        return mData[0] == nullptr ? nullptr : &mData[0];
+    }
+
+    const C2PlaneLayout &layout() const { return mLayout; }
+
+private:
+    std::shared_ptr<C2GraphicAllocation> mAllocation;
+    C2PlaneLayout mLayout;
+    uint8_t *mData[C2PlaneLayout::MAX_NUM_PLANES];
+};
+
+C2ConstGraphicBlock::C2ConstGraphicBlock(
+        const std::shared_ptr<C2GraphicAllocation> &alloc, C2Fence fence)
+    : C2Block2D(alloc), mImpl(new Impl(alloc)), mFence(fence) {}
+
+C2Acquirable<const C2GraphicView> C2ConstGraphicBlock::map() const {
+    c2_status_t err = mImpl->map(crop());
+    if (err != C2_OK) {
+        C2DefaultGraphicView view(err);
+        return C2AcquirableConstGraphicView(err, mFence, view);
+    }
+    C2DefaultGraphicView view(this, mImpl->data(), mImpl->layout());
+    return C2AcquirableConstGraphicView(err, mFence, view);
+}
+
+C2ConstGraphicBlock C2ConstGraphicBlock::subBlock(const C2Rect &rect) const {
+    return mImpl->subBlock(rect, mFence);
+}
+
+class C2GraphicBlock::Impl {
+public:
+    explicit Impl(const std::shared_ptr<C2GraphicAllocation> &alloc)
+        : mAllocation(alloc), mData{ nullptr } {}
+
+    ~Impl() {
+        if (mData[0] != nullptr) {
+            // TODO: fence
+            mAllocation->unmap(nullptr);
+        }
+    }
+
+    c2_status_t map(C2Rect rect) {
+        if (mData[0] != nullptr) {
+            // Already mapped.
+            return C2_OK;
+        }
+        uint8_t *data[C2PlaneLayout::MAX_NUM_PLANES];
+        c2_status_t err = mAllocation->map(
+                rect,
+                { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+                nullptr,
+                &mLayout,
+                data);
+        if (err == C2_OK) {
+            memcpy(mData, data, sizeof(mData));
+        } else {
+            memset(mData, 0, sizeof(mData));
+        }
+        return err;
+    }
+
+    C2ConstGraphicBlock share(const C2Rect &crop, C2Fence fence) const {
+        C2DefaultConstGraphicBlock block(mAllocation, fence);
+        block.setCrop_be(crop);
+        return block;
+    }
+
+    uint8_t *const *data() const {
+        return mData[0] == nullptr ? nullptr : mData;
+    }
+
+    const C2PlaneLayout &layout() const { return mLayout; }
+
+private:
+    std::shared_ptr<C2GraphicAllocation> mAllocation;
+    C2PlaneLayout mLayout;
+    uint8_t *mData[C2PlaneLayout::MAX_NUM_PLANES];
+};
+
+C2GraphicBlock::C2GraphicBlock(const std::shared_ptr<C2GraphicAllocation> &alloc)
+    : C2Block2D(alloc), mImpl(new Impl(alloc)) {}
+
+C2Acquirable<C2GraphicView> C2GraphicBlock::map() {
+    c2_status_t err = mImpl->map(crop());
+    if (err != C2_OK) {
+        C2DefaultGraphicView view(err);
+        // TODO: fence
+        return C2AcquirableGraphicView(err, C2Fence(), view);
+    }
+    C2DefaultGraphicView view(this, mImpl->data(), mImpl->layout());
+    // TODO: fence
+    return C2AcquirableGraphicView(err, C2Fence(), view);
+}
+
+C2ConstGraphicBlock C2GraphicBlock::share(const C2Rect &crop, C2Fence fence) {
+    return mImpl->share(crop, fence);
+}
+
+C2BasicGraphicBlockPool::C2BasicGraphicBlockPool(
+        const std::shared_ptr<C2Allocator> &allocator)
+  : mAllocator(allocator) {}
+
+c2_status_t C2BasicGraphicBlockPool::fetchGraphicBlock(
+        uint32_t width,
+        uint32_t height,
+        uint32_t format,
+        C2MemoryUsage usage,
+        std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+    block->reset();
+
+    std::shared_ptr<C2GraphicAllocation> alloc;
+    c2_status_t err = mAllocator->newGraphicAllocation(width, height, format, usage, &alloc);
+    if (err != C2_OK) {
+        return err;
+    }
+
+    block->reset(new C2DefaultGraphicBlock(alloc));
+
+    return C2_OK;
+}
+
+/* ========================================== BUFFER ========================================= */
+
+class C2BufferData::Impl {
+public:
+    explicit Impl(const std::list<C2ConstLinearBlock> &blocks)
+        : mType(blocks.size() == 1 ? LINEAR : LINEAR_CHUNKS),
+          mLinearBlocks(blocks) {
+    }
+
+    explicit Impl(const std::list<C2ConstGraphicBlock> &blocks)
+        : mType(blocks.size() == 1 ? GRAPHIC : GRAPHIC_CHUNKS),
+          mGraphicBlocks(blocks) {
+    }
+
+    Type type() const { return mType; }
+    const std::list<C2ConstLinearBlock> &linearBlocks() const { return mLinearBlocks; }
+    const std::list<C2ConstGraphicBlock> &graphicBlocks() const { return mGraphicBlocks; }
+
+private:
+    Type mType;
+    std::list<C2ConstLinearBlock> mLinearBlocks;
+    std::list<C2ConstGraphicBlock> mGraphicBlocks;
+};
+
+C2BufferData::C2BufferData(const std::list<C2ConstLinearBlock> &blocks) : mImpl(new Impl(blocks)) {}
+C2BufferData::C2BufferData(const std::list<C2ConstGraphicBlock> &blocks) : mImpl(new Impl(blocks)) {}
+
+C2BufferData::Type C2BufferData::type() const { return mImpl->type(); }
+
+const std::list<C2ConstLinearBlock> C2BufferData::linearBlocks() const {
+    return mImpl->linearBlocks();
+}
+
+const std::list<C2ConstGraphicBlock> C2BufferData::graphicBlocks() const {
+    return mImpl->graphicBlocks();
+}
+
+class C2Buffer::Impl {
+public:
+    Impl(C2Buffer *thiz, const std::list<C2ConstLinearBlock> &blocks)
+        : mThis(thiz), mData(blocks) {}
+    Impl(C2Buffer *thiz, const std::list<C2ConstGraphicBlock> &blocks)
+        : mThis(thiz), mData(blocks) {}
+
+    ~Impl() {
+        for (const auto &pair : mNotify) {
+            pair.first(mThis, pair.second);
+        }
+    }
+
+    const C2BufferData &data() const { return mData; }
+
+    c2_status_t registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
+        auto it = std::find_if(
+                mNotify.begin(), mNotify.end(),
+                [onDestroyNotify, arg] (const auto &pair) {
+                    return pair.first == onDestroyNotify && pair.second == arg;
+                });
+        if (it != mNotify.end()) {
+            return C2_DUPLICATE;
+        }
+        mNotify.emplace_back(onDestroyNotify, arg);
+        return C2_OK;
+    }
+
+    c2_status_t unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
+        auto it = std::find_if(
+                mNotify.begin(), mNotify.end(),
+                [onDestroyNotify, arg] (const auto &pair) {
+                    return pair.first == onDestroyNotify && pair.second == arg;
+                });
+        if (it == mNotify.end()) {
+            return C2_NOT_FOUND;
+        }
+        mNotify.erase(it);
+        return C2_OK;
+    }
+
+    std::list<std::shared_ptr<const C2Info>> infos() const {
+        std::list<std::shared_ptr<const C2Info>> result(mInfos.size());
+        std::transform(
+                mInfos.begin(), mInfos.end(), result.begin(),
+                [] (const auto &elem) { return elem.second; });
+        return result;
+    }
+
+    c2_status_t setInfo(const std::shared_ptr<C2Info> &info) {
+        // To "update" you need to erase the existing one if any, and then insert.
+        (void) mInfos.erase(info->type());
+        (void) mInfos.insert({ info->type(), info });
+        return C2_OK;
+    }
+
+    bool hasInfo(C2Param::Type index) const {
+        return mInfos.count(index.type()) > 0;
+    }
+
+    std::shared_ptr<C2Info> removeInfo(C2Param::Type index) {
+        auto it = mInfos.find(index.type());
+        if (it == mInfos.end()) {
+            return nullptr;
+        }
+        std::shared_ptr<C2Info> ret = it->second;
+        (void) mInfos.erase(it);
+        return ret;
+    }
+
+private:
+    C2Buffer * const mThis;
+    C2DefaultBufferData mData;
+    std::map<uint32_t, std::shared_ptr<C2Info>> mInfos;
+    std::list<std::pair<OnDestroyNotify, void *>> mNotify;
+};
+
+C2Buffer::C2Buffer(const std::list<C2ConstLinearBlock> &blocks)
+    : mImpl(new Impl(this, blocks)) {}
+
+C2Buffer::C2Buffer(const std::list<C2ConstGraphicBlock> &blocks)
+    : mImpl(new Impl(this, blocks)) {}
+
+const C2BufferData C2Buffer::data() const { return mImpl->data(); }
+
+c2_status_t C2Buffer::registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
+    return mImpl->registerOnDestroyNotify(onDestroyNotify, arg);
+}
+
+c2_status_t C2Buffer::unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
+    return mImpl->unregisterOnDestroyNotify(onDestroyNotify, arg);
+}
+
+const std::list<std::shared_ptr<const C2Info>> C2Buffer::infos() const {
+    return mImpl->infos();
+}
+
+c2_status_t C2Buffer::setInfo(const std::shared_ptr<C2Info> &info) {
+    return mImpl->setInfo(info);
+}
+
+bool C2Buffer::hasInfo(C2Param::Type index) const {
+    return mImpl->hasInfo(index);
+}
+
+std::shared_ptr<C2Info> C2Buffer::removeInfo(C2Param::Type index) {
+    return mImpl->removeInfo(index);
+}
+
+} // namespace android
diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/codec2/vndk/C2Config.cpp
similarity index 69%
copy from media/libstagefright/MediaSource.cpp
copy to media/libstagefright/codec2/vndk/C2Config.cpp
index a17757a..6acf524 100644
--- a/media/libstagefright/MediaSource.cpp
+++ b/media/libstagefright/codec2/vndk/C2Config.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/MediaSource.h>
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2Config"
 
-namespace android {
-
-MediaSource::MediaSource() {}
-
-MediaSource::~MediaSource() {}
-
-}  // namespace android
+/**
+ * Define and initialize global config field descriptors in this cpp file
+ */
+#define __C2_GENERATE_GLOBAL_VARS__
+#include <C2Config.h>
diff --git a/media/libstagefright/codec2/vndk/C2Store.cpp b/media/libstagefright/codec2/vndk/C2Store.cpp
new file mode 100644
index 0000000..73ffaea
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2Store.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <C2AllocatorGralloc.h>
+#include <C2AllocatorIon.h>
+#include <C2BufferPriv.h>
+#include <C2Component.h>
+#include <C2PlatformSupport.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+
+namespace android {
+
+class C2PlatformAllocatorStore : public C2AllocatorStore {
+public:
+    enum : id_t {
+        ION = PLATFORM_START,
+        GRALLOC,
+    };
+
+    C2PlatformAllocatorStore(
+        /* ionmapper */
+    );
+
+    virtual c2_status_t fetchAllocator(id_t id, std::shared_ptr<C2Allocator> *const allocator) override;
+
+    virtual std::vector<std::shared_ptr<const C2Allocator::Traits>> listAllocators_nb() const override {
+        return std::vector<std::shared_ptr<const C2Allocator::Traits>>(); /// \todo
+    }
+
+    virtual C2String getName() const override {
+        return "android.allocator-store";
+    }
+
+private:
+    // returns a shared-singleton ion allocator
+    std::shared_ptr<C2Allocator> fetchIonAllocator();
+
+    // returns a shared-singleton gralloc allocator
+    std::shared_ptr<C2Allocator> fetchGrallocAllocator();
+};
+
+C2PlatformAllocatorStore::C2PlatformAllocatorStore() {
+}
+
+c2_status_t C2PlatformAllocatorStore::fetchAllocator(
+        id_t id, std::shared_ptr<C2Allocator> *const allocator) {
+    allocator->reset();
+    switch (id) {
+    // TODO: should we implement a generic registry for all, and use that?
+    case C2PlatformAllocatorStore::ION:
+    case C2AllocatorStore::DEFAULT_LINEAR:
+        *allocator = fetchIonAllocator();
+        break;
+
+    case C2PlatformAllocatorStore::GRALLOC:
+    case C2AllocatorStore::DEFAULT_GRAPHIC:
+        *allocator = fetchGrallocAllocator();
+        break;
+
+    default:
+        return C2_NOT_FOUND;
+    }
+    if (*allocator == nullptr) {
+        return C2_NO_MEMORY;
+    }
+    return C2_OK;
+}
+
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStore::fetchIonAllocator() {
+    static std::mutex mutex;
+    static std::weak_ptr<C2Allocator> ionAllocator;
+    std::lock_guard<std::mutex> lock(mutex);
+    std::shared_ptr<C2Allocator> allocator = ionAllocator.lock();
+    if (allocator == nullptr) {
+        allocator = std::make_shared<C2AllocatorIon>();
+        ionAllocator = allocator;
+    }
+    return allocator;
+}
+
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStore::fetchGrallocAllocator() {
+    static std::mutex mutex;
+    static std::weak_ptr<C2Allocator> grallocAllocator;
+    std::lock_guard<std::mutex> lock(mutex);
+    std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
+    if (allocator == nullptr) {
+        allocator = std::make_shared<C2AllocatorGralloc>();
+        grallocAllocator = allocator;
+    }
+    return allocator;
+}
+
+std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore() {
+    return std::make_shared<C2PlatformAllocatorStore>();
+}
+
+c2_status_t GetCodec2BlockPool(
+        C2BlockPool::local_id_t id, std::shared_ptr<const C2Component> component,
+        std::shared_ptr<C2BlockPool> *pool) {
+    pool->reset();
+    if (!component) {
+        return C2_BAD_VALUE;
+    }
+    // TODO support pre-registered block pools
+    std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
+    std::shared_ptr<C2Allocator> allocator;
+    c2_status_t res = C2_NOT_FOUND;
+
+    switch (id) {
+    case C2BlockPool::BASIC_LINEAR:
+        res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
+        if (res == OK) {
+            *pool = std::make_shared<C2BasicLinearBlockPool>(allocator);
+        }
+        break;
+    case C2BlockPool::BASIC_GRAPHIC:
+        res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
+        if (res == OK) {
+            *pool = std::make_shared<C2BasicGraphicBlockPool>(allocator);
+        }
+        break;
+    default:
+        break;
+    }
+    return res;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
new file mode 100644
index 0000000..374b0ed
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
@@ -0,0 +1,62 @@
+
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
+#define STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
+
+#include <functional>
+
+#include <C2Buffer.h>
+
+namespace android {
+
+class C2AllocatorGralloc : public C2Allocator {
+public:
+    // (usage, capacity) => (align, heapMask, flags)
+    typedef std::function<int (C2MemoryUsage, size_t,
+                      /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
+
+    virtual id_t getId() const override;
+
+    virtual C2String getName() const override;
+
+    virtual std::shared_ptr<const Traits> getTraits() const override {
+        return nullptr; // \todo
+    }
+
+    virtual c2_status_t newGraphicAllocation(
+            uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+            std::shared_ptr<C2GraphicAllocation> *allocation) override;
+
+    virtual c2_status_t priorGraphicAllocation(
+            const C2Handle *handle,
+            std::shared_ptr<C2GraphicAllocation> *allocation) override;
+
+    C2AllocatorGralloc();
+
+    c2_status_t status() const;
+
+    virtual ~C2AllocatorGralloc() override;
+
+private:
+    class Impl;
+    Impl *mImpl;
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
new file mode 100644
index 0000000..bb815f9
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
+#define STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
+
+#include <functional>
+
+#include <C2Buffer.h>
+
+namespace android {
+
+class C2AllocatorIon : public C2Allocator {
+public:
+    // (usage, capacity) => (align, heapMask, flags)
+    typedef std::function<int (C2MemoryUsage, size_t,
+                      /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
+
+    virtual id_t getId() const override;
+
+    virtual C2String getName() const override;
+
+    virtual std::shared_ptr<const Traits> getTraits() const override {
+        return nullptr; // \todo
+    }
+
+    virtual c2_status_t newLinearAllocation(
+            uint32_t capacity, C2MemoryUsage usage,
+            std::shared_ptr<C2LinearAllocation> *allocation) override;
+
+    virtual c2_status_t priorLinearAllocation(
+            const C2Handle *handle,
+            std::shared_ptr<C2LinearAllocation> *allocation) override;
+
+    C2AllocatorIon();
+
+    virtual c2_status_t status() const { return mInit; }
+
+    virtual ~C2AllocatorIon() override;
+
+private:
+    c2_status_t mInit;
+    int mIonFd;
+    usage_mapper_fn mUsageMapper;
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
new file mode 100644
index 0000000..875a8c2
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
+#define STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
+
+#include <functional>
+
+#include <C2Buffer.h>
+
+namespace android {
+
+class C2BasicLinearBlockPool : public C2BlockPool {
+public:
+    explicit C2BasicLinearBlockPool(const std::shared_ptr<C2Allocator> &allocator);
+
+    virtual ~C2BasicLinearBlockPool() override = default;
+
+    virtual C2Allocator::id_t getAllocatorId() const override {
+        return mAllocator->getId();
+    }
+
+    virtual local_id_t getLocalId() const override {
+        return BASIC_LINEAR;
+    }
+
+    virtual c2_status_t fetchLinearBlock(
+            uint32_t capacity,
+            C2MemoryUsage usage,
+            std::shared_ptr<C2LinearBlock> *block /* nonnull */) override;
+
+    // TODO: fetchCircularBlock
+
+private:
+    const std::shared_ptr<C2Allocator> mAllocator;
+};
+
+class C2BasicGraphicBlockPool : public C2BlockPool {
+public:
+    explicit C2BasicGraphicBlockPool(const std::shared_ptr<C2Allocator> &allocator);
+
+    virtual ~C2BasicGraphicBlockPool() override = default;
+
+    virtual C2Allocator::id_t getAllocatorId() const override {
+        return mAllocator->getId();
+    }
+
+    virtual local_id_t getLocalId() const override {
+        return BASIC_GRAPHIC;
+    }
+
+    virtual c2_status_t fetchGraphicBlock(
+            uint32_t width,
+            uint32_t height,
+            uint32_t format,
+            C2MemoryUsage usage,
+            std::shared_ptr<C2GraphicBlock> *block /* nonnull */) override;
+
+private:
+    const std::shared_ptr<C2Allocator> mAllocator;
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h b/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
new file mode 100644
index 0000000..41132b9
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+#define STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+
+#include <errno.h>
+#include <C2.h>
+
+namespace android {
+
+// standard ERRNO mappings
+template<int N> constexpr c2_status_t _c2_errno2status_impl();
+template<> constexpr c2_status_t _c2_errno2status_impl<0>()       { return C2_OK; }
+template<> constexpr c2_status_t _c2_errno2status_impl<EINVAL>()  { return C2_BAD_VALUE; }
+template<> constexpr c2_status_t _c2_errno2status_impl<EACCES>()  { return C2_REFUSED; }
+template<> constexpr c2_status_t _c2_errno2status_impl<EPERM>()   { return C2_REFUSED; }
+template<> constexpr c2_status_t _c2_errno2status_impl<ENOMEM>()  { return C2_NO_MEMORY; }
+
+// map standard errno-s to the equivalent c2_status_t
+template<int... N> struct _c2_map_errno_impl;
+template<int E, int ... N> struct _c2_map_errno_impl<E, N...> {
+    static c2_status_t map(int result) {
+        if (result == E) {
+            return _c2_errno2status_impl <E>();
+        } else {
+            return _c2_map_errno_impl<N...>::map(result);
+        }
+    }
+};
+template<> struct _c2_map_errno_impl<> {
+    static c2_status_t map(int result) {
+        return result == 0 ? C2_OK : C2_CORRUPTED;
+    }
+};
+
+template<int... N>
+c2_status_t c2_map_errno(int result) {
+    return _c2_map_errno_impl<N...>::map(result);
+}
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+
diff --git a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
new file mode 100644
index 0000000..8e45705
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
+#define STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
+
+#include <C2Component.h>
+
+#include <memory>
+
+namespace android {
+
+/**
+ * Returns the platform allocator store.
+ * \retval nullptr if the platform allocator store could not be obtained
+ */
+std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore();
+
+/**
+ * Retrieves a block pool for a component.
+ *
+ * \param id        the local ID of the block pool
+ * \param component the component using the block pool (must be non-null)
+ * \param pool      pointer to where the obtained block pool shall be stored on success. nullptr
+ *                  will be stored here on failure
+ *
+ * \retval C2_OK        the operation was successful
+ * \retval C2_BAD_VALUE the component is null
+ * \retval C2_NOT_FOUND if the block pool does not exist
+ * \retval C2_NO_MEMORY not enough memory to fetch the block pool (this return value is only
+ *                      possible for basic pools)
+ * \retval C2_TIMED_OUT the operation timed out (this return value is only possible for basic pools)
+ * \retval C2_REFUSED   no permission to complete any required allocation (this return value is only
+ *                      possible for basic pools)
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected,
+ *                      this return value is only possible for basic pools)
+ */
+c2_status_t GetCodec2BlockPool(
+        C2BlockPool::local_id_t id, std::shared_ptr<const C2Component> component,
+        std::shared_ptr<C2BlockPool> *pool);
+
+/**
+ * Component factory object that enables to create a component and/or interface from a dynamically
+ * linked library. This is needed because the component/interfaces are managed objects, but we
+ * cannot safely create a managed object and pass it in C.
+ *
+ * Components/interfaces typically inherit from std::enable_shared_from_this, but C requires
+ * passing simple pointer, and shared_ptr constructor needs to know the class to be constructed
+ * derives from enable_shared_from_this.
+ *
+ */
+class C2ComponentFactory {
+public:
+    /**
+     * Creates a component.
+     *
+     * This method SHALL return within 100ms.
+     *
+     * \param component shared pointer where the created component is stored. Cleared on
+     *                  failure and updated on success.
+     * \param id        component ID for the created component
+     *
+     * \retval C2_OK        the component was created successfully
+     * \retval C2_TIMED_OUT could not create the component within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented the creation of the component (unexpected)
+     *
+     * \retval C2_NO_MEMORY not enough memory to create the component
+     */
+    virtual c2_status_t createComponent(
+            std::shared_ptr<C2Component>* const component, c2_node_id_t id) = 0;
+
+    /**
+     * Creates a component interface.
+     *
+     * This method SHALL return within 100ms.
+     *
+     * \param interface shared pointer where the created interface is stored. Cleared on
+     *                  failure and updated on success.
+     * \param id        component interface ID for the created interface
+     *
+     * \retval C2_OK        the component interface was created successfully
+     * \retval C2_TIMED_OUT could not create the component interface within the time limit
+     *                      (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented the creation of the component interface
+     *                      (unexpected)
+     *
+     * \retval C2_NO_MEMORY not enough memory to create the component interface
+     */
+    virtual c2_status_t createInterface(
+            std::shared_ptr<C2ComponentInterface>* const interface, c2_node_id_t id) = 0;
+
+    virtual ~C2ComponentFactory() = default;
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
diff --git a/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h b/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h
index edae303..5ce6071 100644
--- a/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h
+++ b/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h
@@ -222,7 +222,7 @@
     friend class C2ParamTest_ParamUtilsTest_Test;
 
 public:
-    static std::vector<C2String> getEnumValuesFromString(C2StringLiteral value) {
+    static std::vector<C2String> parseEnumValuesFromString(C2StringLiteral value) {
         std::vector<C2String> foundNames;
         size_t pos = 0, len = strlen(value);
         do {
@@ -278,7 +278,7 @@
 C2_HIDE
 void addC2Params(std::list<const C2FieldDescriptor> &fields, _C2Tuple<T, Params...> *)
 {
-    //C2Param::index_t index = T::baseIndex;
+    //C2Param::index_t index = T::coreIndex;
     //(void)index;
     fields.insert(fields.end(), T::fieldList);
     addC2Params(fields, (_C2Tuple<Params...> *)nullptr);
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
deleted file mode 100644
index e64c1b7..0000000
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
+++ /dev/null
@@ -1,84 +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 SOFT_AAC_ENCODER_H_
-
-#define SOFT_AAC_ENCODER_H_
-
-#include <media/stagefright/omx/SimpleSoftOMXComponent.h>
-
-struct VO_AUDIO_CODECAPI;
-struct VO_MEM_OPERATOR;
-
-namespace android {
-
-struct SoftAACEncoder : public SimpleSoftOMXComponent {
-    SoftAACEncoder(
-            const char *name,
-            const OMX_CALLBACKTYPE *callbacks,
-            OMX_PTR appData,
-            OMX_COMPONENTTYPE **component);
-
-protected:
-    virtual ~SoftAACEncoder();
-
-    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 onReset();
-
-private:
-    enum {
-        kNumBuffers             = 4,
-        kNumSamplesPerFrame     = 1024,
-    };
-
-    void *mEncoderHandle;
-    VO_AUDIO_CODECAPI *mApiHandle;
-    VO_MEM_OPERATOR  *mMemOperator;
-
-    OMX_U32 mNumChannels;
-    OMX_U32 mSampleRate;
-    OMX_U32 mBitRate;
-
-    bool mSentCodecSpecificData;
-    size_t mInputSize;
-    int16_t *mInputFrame;
-    int64_t mInputTimeUs;
-
-    bool mSawInputEOS;
-
-    uint8_t mAudioSpecificConfigData[2];
-
-    bool mSignalledError;
-
-    void initPorts();
-    status_t initEncoder();
-
-    status_t setAudioSpecificConfigData();
-    status_t setAudioParams();
-
-    DISALLOW_EVIL_CONSTRUCTORS(SoftAACEncoder);
-};
-
-}  // namespace android
-
-#endif  // SOFT_AAC_ENCODER_H_
diff --git a/media/libstagefright/codecs/avcdec/Android.bp b/media/libstagefright/codecs/avcdec/Android.bp
index 34db19b..5dcffd5 100644
--- a/media/libstagefright/codecs/avcdec/Android.bp
+++ b/media/libstagefright/codecs/avcdec/Android.bp
@@ -22,7 +22,6 @@
     ],
 
     shared_libs: [
-        "libmedia_omx",
         "libstagefright_omx",
         "libstagefright_foundation",
         "libutils",
@@ -42,3 +41,44 @@
     ldflags: ["-Wl,-Bsymbolic"],
     compile_multilib: "32",
 }
+
+cc_library_shared {
+    name: "libstagefright_soft_c2avcdec",
+
+    static_libs: [
+        "libavcdec",
+        "libstagefright_codec2_vndk",
+    ],
+    srcs: ["C2SoftAvcDec.cpp"],
+
+    include_dirs: [
+        "external/libavc/decoder",
+        "external/libavc/common",
+        "frameworks/av/media/libstagefright/codec2/include",
+        "frameworks/av/media/libstagefright/codec2/vndk/include",
+    ],
+
+    shared_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+        "libhidlbase",
+        "libion",
+        "liblog",
+        "libmedia",
+        "libstagefright_codec2",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: false, // true,
+        diag: {
+            cfi: false, // true,
+        },
+    },
+
+    ldflags: ["-Wl,-Bsymbolic"],
+}
diff --git a/media/libstagefright/codecs/avcdec/C2AvcConfig.h b/media/libstagefright/codecs/avcdec/C2AvcConfig.h
new file mode 100644
index 0000000..a7e0d95
--- /dev/null
+++ b/media/libstagefright/codecs/avcdec/C2AvcConfig.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2AVCCONFIG_H_
+#define C2AVCCONFIG_H_
+
+#include <C2Config.h>
+
+namespace android {
+
+enum : uint32_t {
+    kParamIndexAvcProfile = kParamIndexParamStart + 1,
+    kParamIndexAvcLevel,
+    kParamIndexBlockSize,
+    kParamIndexAlignment,
+    kParamIndexFramerate,
+    kParamIndexBlocksPerSecond,
+};
+
+enum C2AvcProfileIdc : uint32_t {
+    kAvcProfileUnknown  = 0,
+    kAvcProfileBaseline = 66,
+    kAvcProfileMain     = 77,
+    kAvcProfileExtended = 88,
+    kAvcProfileHigh     = 100,
+    kAvcProfileHigh10   = 110,
+    kAvcProfileHigh422  = 122,
+    kAvcProfileHigh444  = 144,
+};
+
+enum C2AvcLevelIdc : uint32_t {
+    kAvcLevelUnknown = 0,
+    kAvcLevel10      = 10,
+    kAvcLevel1b      = 9,
+    kAvcLevel11      = 11,
+    kAvcLevel12      = 12,
+    kAvcLevel13      = 13,
+    kAvcLevel20      = 20,
+    kAvcLevel21      = 21,
+    kAvcLevel22      = 22,
+    kAvcLevel30      = 30,
+    kAvcLevel31      = 31,
+    kAvcLevel32      = 32,
+    kAvcLevel40      = 40,
+    kAvcLevel41      = 41,
+    kAvcLevel42      = 42,
+    kAvcLevel50      = 50,
+    kAvcLevel51      = 51,
+    kAvcLevel52      = 52,
+};
+
+// profile for AVC video decoder [IN]
+typedef C2StreamParam<C2Info, C2SimpleValueStruct<C2AvcProfileIdc>, kParamIndexAvcProfile>
+    C2AvcProfileInfo;
+
+// level for AVC video decoder [IN]
+typedef C2StreamParam<C2Info, C2SimpleValueStruct<C2AvcLevelIdc>, kParamIndexAvcLevel>
+    C2AvcLevelInfo;
+
+// block size [OUT]
+typedef C2StreamParam<C2Info, C2VideoSizeStruct, kParamIndexBlockSize> C2BlockSizeInfo;
+
+// alignment [OUT]
+typedef C2StreamParam<C2Info, C2VideoSizeStruct, kParamIndexAlignment> C2AlignmentInfo;
+
+// frame rate [OUT, hint]
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexFramerate> C2FrameRateInfo;
+
+// blocks-per-second [OUT, hint]
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexBlocksPerSecond> C2BlocksPerSecondInfo;
+
+} // namespace android
+
+#endif  // C2AVCCONFIG_H_
diff --git a/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp
new file mode 100644
index 0000000..c74ca6d
--- /dev/null
+++ b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp
@@ -0,0 +1,1490 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "C2SoftAvcDec"
+#include <utils/Log.h>
+
+#include <cmath>
+#include <thread>
+
+#include "ih264_typedefs.h"
+#include "iv.h"
+#include "ivd.h"
+#include "ih264d.h"
+#include "C2SoftAvcDec.h"
+
+#include <C2PlatformSupport.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <utils/misc.h>
+
+#include "ih264d_defs.h"
+
+namespace {
+
+template <class T>
+inline int32_t floor32(T arg) {
+   return (int32_t) std::llround(std::floor(arg));
+}
+
+} // namespace
+
+namespace android {
+
+struct iv_obj_t : public ::iv_obj_t {};
+struct ivd_video_decode_ip_t : public ::ivd_video_decode_ip_t {};
+struct ivd_video_decode_op_t : public ::ivd_video_decode_op_t {};
+
+#define PRINT_TIME  ALOGV
+
+#define componentName                   "video_decoder.avc"
+// #define codingType                      OMX_VIDEO_CodingAVC
+#define CODEC_MIME_TYPE                 MEDIA_MIMETYPE_VIDEO_AVC
+
+/** Function and structure definitions to keep code similar for each codec */
+#define ivdec_api_function              ih264d_api_function
+#define ivdext_create_ip_t              ih264d_create_ip_t
+#define ivdext_create_op_t              ih264d_create_op_t
+#define ivdext_delete_ip_t              ih264d_delete_ip_t
+#define ivdext_delete_op_t              ih264d_delete_op_t
+#define ivdext_ctl_set_num_cores_ip_t   ih264d_ctl_set_num_cores_ip_t
+#define ivdext_ctl_set_num_cores_op_t   ih264d_ctl_set_num_cores_op_t
+
+#define IVDEXT_CMD_CTL_SET_NUM_CORES    \
+        (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
+
+namespace {
+
+using SupportedValuesWithFields = C2SoftAvcDecIntf::SupportedValuesWithFields;
+
+uint32_t restoreIndex(const C2Param *param) {
+    return (param->forStream() ? (0x02000000 | ((param->stream() << 17) & 0x01FE0000)) : 0)
+            | param->type();
+}
+
+struct ValidateParam {
+    explicit ValidateParam(
+            const std::map<C2ParamField, SupportedValuesWithFields> &supportedValues)
+        : mSupportedValues(supportedValues) {}
+
+    template <class T, bool SIGNED = std::is_signed<T>::value, size_t SIZE = sizeof(T)>
+    struct Getter {
+        static T get(const C2Value::Primitive &) {
+            static_assert(!std::is_arithmetic<T>::value, "non-arithmetic type");
+            static_assert(!std::is_floating_point<T>::value || std::is_same<T, float>::value,
+                    "float is the only supported floating point type");
+            static_assert(sizeof(T) <= 8, "type exceeds 64-bit");
+        }
+    };
+
+    template <class T>
+    bool validateField(
+            const C2FieldSupportedValues &supportedValues, const T &value) {
+        switch (supportedValues.type) {
+        case C2FieldSupportedValues::EMPTY:
+            {
+                return false;
+            }
+        case C2FieldSupportedValues::RANGE:
+            {
+                // TODO: handle step, nom, denom
+                return Getter<T>::get(supportedValues.range.min) <= value
+                        && value <= Getter<T>::get(supportedValues.range.max);
+            }
+        case C2FieldSupportedValues::VALUES:
+            {
+                for (const auto &val : supportedValues.values) {
+                    if (Getter<T>::get(val) == value) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        case C2FieldSupportedValues::FLAGS:
+            // TODO
+            return false;
+        }
+        return false;
+    }
+
+protected:
+    const std::map<C2ParamField, SupportedValuesWithFields> &mSupportedValues;
+};
+
+template <>
+struct ValidateParam::Getter<float> {
+    static float get(const C2Value::Primitive &value) { return value.fp; }
+};
+template <class T>
+struct ValidateParam::Getter<T, true, 8u> {
+    static int64_t get(const C2Value::Primitive &value) { return value.i64; }
+};
+template <class T>
+struct ValidateParam::Getter<T, true, 4u> {
+    static int32_t get(const C2Value::Primitive &value) { return value.i32; }
+};
+template <class T>
+struct ValidateParam::Getter<T, false, 8u> {
+    static uint64_t get(const C2Value::Primitive &value) { return value.u64; }
+};
+template <class T>
+struct ValidateParam::Getter<T, false, 4u> {
+    static uint32_t get(const C2Value::Primitive &value) { return value.u32; }
+};
+
+template <class T>
+struct ValidateSimpleParam : public ValidateParam {
+    explicit ValidateSimpleParam(
+            const std::map<C2ParamField, SupportedValuesWithFields> &supportedValues)
+        : ValidateParam(supportedValues) {}
+
+    std::unique_ptr<C2SettingResult> operator() (C2Param *c2param) {
+        T* param = (T*)c2param;
+        C2ParamField field(param, &T::mValue);
+        const C2FieldSupportedValues &supportedValues = mSupportedValues.at(field).supported;
+        if (!validateField(supportedValues, param->mValue)) {
+            return std::unique_ptr<C2SettingResult>(
+                    new C2SettingResult {C2SettingResult::BAD_VALUE, {field, nullptr}, {}});
+        }
+        return nullptr;
+    }
+};
+
+template <class T>
+struct ValidateVideoSize : public ValidateParam {
+    explicit ValidateVideoSize(
+            const std::map<C2ParamField, SupportedValuesWithFields> &supportedValues)
+        : ValidateParam(supportedValues) {}
+
+    std::unique_ptr<C2SettingResult> operator() (C2Param *c2param) {
+        T* param = (T*)c2param;
+        C2ParamField field(param, &T::mWidth);
+        const C2FieldSupportedValues &supportedWidth = mSupportedValues.at(field).supported;
+        if (!validateField(supportedWidth, param->mWidth)) {
+            return std::unique_ptr<C2SettingResult>(
+                    new C2SettingResult {C2SettingResult::BAD_VALUE, {field, nullptr}, {}});
+        }
+        field = C2ParamField(param, &T::mHeight);
+        const C2FieldSupportedValues &supportedHeight = mSupportedValues.at(field).supported;
+        if (!validateField(supportedHeight, param->mHeight)) {
+            return std::unique_ptr<C2SettingResult>(
+                    new C2SettingResult {C2SettingResult::BAD_VALUE, {field, nullptr}, {}});
+        }
+        return nullptr;
+    }
+};
+
+template <class T>
+struct ValidateCString {
+    explicit ValidateCString(const char *expected) : mExpected(expected) {}
+
+    std::unique_ptr<C2SettingResult> operator() (C2Param *c2param) {
+        T* param = (T*)c2param;
+        if (strncmp(param->m.mValue, mExpected, param->flexCount()) != 0) {
+            return std::unique_ptr<C2SettingResult>(
+                    new C2SettingResult {C2SettingResult::BAD_VALUE, {C2ParamField(param, &T::m), nullptr}, {}});
+        }
+        return nullptr;
+    }
+
+private:
+    const char *mExpected;
+};
+
+class GraphicBuffer : public C2Buffer {
+public:
+    explicit GraphicBuffer(const std::shared_ptr<C2GraphicBlock> &block)
+        : C2Buffer({ block->share(C2Rect(block->width(), block->height()), ::android::C2Fence()) }) {}
+};
+
+}  // namespace
+
+#define CASE(member) \
+    case decltype(component->member)::coreIndex: \
+        return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor( \
+                static_cast<decltype(component->member) *>(nullptr)))
+
+class C2SoftAvcDecIntf::ParamReflector : public C2ParamReflector {
+public:
+    virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::BaseIndex coreIndex) override {
+        constexpr C2SoftAvcDecIntf *component = nullptr;
+        switch (coreIndex.coreIndex()) {
+        CASE(mDomainInfo);
+        CASE(mInputStreamCount);
+        CASE(mInputStreamFormat);
+        // Output counterparts for the above would be redundant.
+        CASE(mVideoSize);
+        CASE(mMaxVideoSizeHint);
+
+        // port mime configs are stored as unique_ptr.
+        case C2PortMimeConfig::coreIndex:
+            return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor(
+                    static_cast<C2PortMimeConfig *>(nullptr)));
+        }
+        return nullptr;
+    }
+};
+#undef CASE
+
+// static const CodecProfileLevel kProfileLevels[] = {
+//     { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel52 },
+//     { OMX_VIDEO_AVCProfileMain,     OMX_VIDEO_AVCLevel52 },
+//     { OMX_VIDEO_AVCProfileHigh,     OMX_VIDEO_AVCLevel52 },
+// };
+C2SoftAvcDecIntf::C2SoftAvcDecIntf(const char *name, c2_node_id_t id)
+    : mName(name),
+      mId(id),
+      mDomainInfo(C2DomainVideo),
+      mInputStreamCount(1u),
+      mOutputStreamCount(1u),
+      mInputStreamFormat(0u, C2FormatCompressed),
+      mOutputStreamFormat(0u, C2FormatVideo),
+      mProfile(0u, kAvcProfileUnknown),
+      mLevel(0u, kAvcLevelUnknown),
+      mBlockSize(0u),
+      mAlignment(0u),
+      mFrameRate(0u, 0),
+      mBlocksPerSecond(0u, 0),
+      mParamReflector(new ParamReflector) {
+
+    mInputPortMime = C2PortMimeConfig::input::alloc_unique(strlen(CODEC_MIME_TYPE) + 1);
+    strcpy(mInputPortMime->m.mValue, CODEC_MIME_TYPE);
+    mOutputPortMime = C2PortMimeConfig::output::alloc_unique(strlen(MEDIA_MIMETYPE_VIDEO_RAW) + 1);
+    strcpy(mOutputPortMime->m.mValue, MEDIA_MIMETYPE_VIDEO_RAW);
+
+    mVideoSize.mWidth = 320;
+    mVideoSize.mHeight = 240;
+    mBlockSize.mWidth = 16;
+    mBlockSize.mHeight = 16;
+    mAlignment.mWidth = 2;
+    mAlignment.mHeight = 2;
+
+    mMaxVideoSizeHint.mWidth = H264_MAX_FRAME_WIDTH;
+    mMaxVideoSizeHint.mHeight = H264_MAX_FRAME_HEIGHT;
+
+    mOutputBlockPools = C2PortBlockPoolsTuning::output::alloc_unique({});
+
+    auto insertParam = [&params = mParams] (C2Param *param) {
+        params[restoreIndex(param)] = param;
+    };
+
+    auto markReadOnly = [&supported = mSupportedValues] (auto *param) {
+        supported.emplace(
+                C2ParamField(param, &std::remove_pointer<decltype(param)>::type::mValue),
+                C2FieldSupportedValues(false /* flags */, {}));
+    };
+
+    auto markReadOnlyVideoSize = [&supported = mSupportedValues] (auto *param) {
+        supported.emplace(
+                C2ParamField(param, &std::remove_pointer<decltype(param)>::type::mWidth),
+                C2FieldSupportedValues(false /* flags */, {}));
+        supported.emplace(
+                C2ParamField(param, &std::remove_pointer<decltype(param)>::type::mHeight),
+                C2FieldSupportedValues(false /* flags */, {}));
+    };
+
+    insertParam(&mDomainInfo);
+    markReadOnly(&mDomainInfo);
+    mFieldVerifiers[restoreIndex(&mDomainInfo)] =
+            ValidateSimpleParam<decltype(mDomainInfo)>(mSupportedValues);
+
+    insertParam(mInputPortMime.get());
+    mFieldVerifiers[restoreIndex(mInputPortMime.get())] =
+            ValidateCString<std::remove_reference<decltype(*mInputPortMime)>::type>(CODEC_MIME_TYPE);
+
+    insertParam(&mInputStreamCount);
+    markReadOnly(&mInputStreamCount);
+    mFieldVerifiers[restoreIndex(&mInputStreamCount)] =
+            ValidateSimpleParam<decltype(mInputStreamCount)>(mSupportedValues);
+
+    insertParam(mOutputPortMime.get());
+    mFieldVerifiers[restoreIndex(mOutputPortMime.get())] =
+            ValidateCString<std::remove_reference<decltype(*mOutputPortMime)>::type>(MEDIA_MIMETYPE_VIDEO_RAW);
+
+    insertParam(&mOutputStreamCount);
+    markReadOnly(&mOutputStreamCount);
+    mFieldVerifiers[restoreIndex(&mOutputStreamCount)] =
+            ValidateSimpleParam<decltype(mOutputStreamCount)>(mSupportedValues);
+
+    insertParam(&mInputStreamFormat);
+    markReadOnly(&mInputStreamFormat);
+    mFieldVerifiers[restoreIndex(&mInputStreamFormat)] =
+            ValidateSimpleParam<decltype(mInputStreamFormat)>(mSupportedValues);
+
+    insertParam(&mOutputStreamFormat);
+    markReadOnly(&mOutputStreamFormat);
+    mFieldVerifiers[restoreIndex(&mOutputStreamFormat)] =
+            ValidateSimpleParam<decltype(mOutputStreamFormat)>(mSupportedValues);
+
+    insertParam(&mVideoSize);
+    markReadOnlyVideoSize(&mVideoSize);
+    mFieldVerifiers[restoreIndex(&mVideoSize)] =
+            ValidateVideoSize<decltype(mVideoSize)>(mSupportedValues);
+
+    insertParam(&mMaxVideoSizeHint);
+    mSupportedValues.emplace(
+            C2ParamField(&mMaxVideoSizeHint, &C2MaxVideoSizeHintPortSetting::mWidth),
+            C2FieldSupportedValues(H264_MIN_FRAME_WIDTH, H264_MAX_FRAME_WIDTH, mAlignment.mWidth));
+    mSupportedValues.emplace(
+            C2ParamField(&mMaxVideoSizeHint, &C2MaxVideoSizeHintPortSetting::mHeight),
+            C2FieldSupportedValues(H264_MIN_FRAME_HEIGHT, H264_MAX_FRAME_HEIGHT, mAlignment.mHeight));
+    mFieldVerifiers[restoreIndex(&mMaxVideoSizeHint)] =
+            ValidateVideoSize<decltype(mMaxVideoSizeHint)>(mSupportedValues);
+
+    insertParam(&mProfile);
+    mSupportedValues.emplace(
+            C2ParamField(&mProfile, &C2AvcProfileInfo::mValue),
+            C2FieldSupportedValues(false /* flags */, {
+                kAvcProfileUnknown,
+                kAvcProfileBaseline,
+                kAvcProfileMain,
+                kAvcProfileHigh,
+            }));
+    mFieldVerifiers[restoreIndex(&mProfile)] =
+            ValidateSimpleParam<decltype(mProfile)>(mSupportedValues);
+
+    insertParam(&mLevel);
+    mSupportedValues.emplace(
+            C2ParamField(&mLevel, &C2AvcLevelInfo::mValue),
+            C2FieldSupportedValues(false /* flags */, {
+                kAvcLevelUnknown,
+                kAvcLevel10,
+                kAvcLevel1b,
+                kAvcLevel11,
+                kAvcLevel12,
+                kAvcLevel13,
+                kAvcLevel20,
+                kAvcLevel21,
+                kAvcLevel22,
+                kAvcLevel30,
+                kAvcLevel31,
+                kAvcLevel32,
+                kAvcLevel40,
+                kAvcLevel41,
+                kAvcLevel42,
+                kAvcLevel50,
+                kAvcLevel51,
+                kAvcLevel52,
+            }));
+    mFieldVerifiers[restoreIndex(&mLevel)] =
+            ValidateSimpleParam<decltype(mLevel)>(mSupportedValues);
+
+    insertParam(&mBlockSize);
+    markReadOnlyVideoSize(&mBlockSize);
+    mFieldVerifiers[restoreIndex(&mBlockSize)] =
+            ValidateVideoSize<decltype(mBlockSize)>(mSupportedValues);
+
+    insertParam(&mAlignment);
+    markReadOnlyVideoSize(&mAlignment);
+    mFieldVerifiers[restoreIndex(&mAlignment)] =
+            ValidateVideoSize<decltype(mAlignment)>(mSupportedValues);
+
+    insertParam(&mFrameRate);
+    mSupportedValues.emplace(
+            C2ParamField(&mFrameRate, &C2FrameRateInfo::mValue),
+            C2FieldSupportedValues(0, 240));
+    mFieldVerifiers[restoreIndex(&mFrameRate)] =
+            ValidateSimpleParam<decltype(mFrameRate)>(mSupportedValues);
+
+    insertParam(&mBlocksPerSecond);
+    mSupportedValues.emplace(
+            C2ParamField(&mFrameRate, &C2BlocksPerSecondInfo::mValue),
+            C2FieldSupportedValues(0, 244800));
+    mFieldVerifiers[restoreIndex(&mBlocksPerSecond)] =
+            ValidateSimpleParam<decltype(mBlocksPerSecond)>(mSupportedValues);
+
+    mParamDescs.push_back(std::make_shared<C2ParamDescriptor>(
+            true, "_domain", &mDomainInfo));
+    mParamDescs.push_back(std::make_shared<C2ParamDescriptor>(
+            true, "_input_port_mime", mInputPortMime.get()));
+    mParamDescs.push_back(std::make_shared<C2ParamDescriptor>(
+            true, "_input_stream_count", &mInputStreamCount));
+    mParamDescs.push_back(std::make_shared<C2ParamDescriptor>(
+            true, "_output_port_mime", mOutputPortMime.get()));
+    mParamDescs.push_back(std::make_shared<C2ParamDescriptor>(
+            true, "_output_stream_count", &mOutputStreamCount));
+    mParamDescs.push_back(std::make_shared<C2ParamDescriptor>(
+            true, "_input_stream_format", &mInputStreamFormat));
+    mParamDescs.push_back(std::make_shared<C2ParamDescriptor>(
+            true, "_output_stream_format", &mOutputStreamFormat));
+    mParamDescs.push_back(std::make_shared<C2ParamDescriptor>(
+            false, "_video_size", &mVideoSize));
+    mParamDescs.push_back(std::make_shared<C2ParamDescriptor>(
+            false, "_max_video_size_hint", &mMaxVideoSizeHint));
+    mParamDescs.push_back(std::make_shared<C2ParamDescriptor>(
+            false, "_output_block_pools", mOutputBlockPools.get()));
+}
+
+C2String C2SoftAvcDecIntf::getName() const {
+    return mName;
+}
+
+c2_node_id_t C2SoftAvcDecIntf::getId() const {
+    return mId;
+}
+
+c2_status_t C2SoftAvcDecIntf::query_nb(
+        const std::vector<C2Param* const> & stackParams,
+        const std::vector<C2Param::Index> & heapParamIndices,
+        std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
+    for (C2Param* const param : stackParams) {
+        if (!*param) {
+            continue;
+        }
+
+        uint32_t index = restoreIndex(param);
+        if (!mParams.count(index)) {
+            // TODO: add support for output-block-pools (this will be done when we move all
+            // config to shared ptr)
+            continue;
+        }
+
+        C2Param *myParam = mParams.find(index)->second;
+        if (myParam->size() != param->size()) {
+            param->invalidate();
+            continue;
+        }
+
+        param->updateFrom(*myParam);
+    }
+
+    for (const C2Param::Index index : heapParamIndices) {
+        if (mParams.count(index)) {
+            C2Param *myParam = mParams.find(index)->second;
+            heapParams->emplace_back(C2Param::Copy(*myParam));
+        }
+    }
+
+    return C2_OK;
+}
+
+c2_status_t C2SoftAvcDecIntf::config_nb(
+        const std::vector<C2Param* const> &params,
+        std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+    c2_status_t err = C2_OK;
+    for (C2Param *param : params) {
+        uint32_t index = restoreIndex(param);
+        if (param->index() == mOutputBlockPools.get()->index()) {
+            // setting output block pools
+            mOutputBlockPools.reset(
+                    (C2PortBlockPoolsTuning::output *)C2Param::Copy(*param).release());
+            continue;
+        }
+
+        if (mParams.count(index) == 0) {
+            // We can't create C2SettingResult with no field, so just skipping in this case.
+            err = C2_BAD_INDEX;
+            continue;
+        }
+        C2Param *myParam = mParams.find(index)->second;
+        std::unique_ptr<C2SettingResult> result;
+        if (!(result = mFieldVerifiers[index](param))) {
+            myParam->updateFrom(*param);
+            updateSupportedValues();
+        } else {
+            failures->push_back(std::move(result));
+            err = C2_BAD_VALUE;
+        }
+    }
+    return err;
+}
+
+c2_status_t C2SoftAvcDecIntf::commit_sm(
+        const std::vector<C2Param* const> &params,
+        std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+    // TODO
+    return config_nb(params, failures);
+}
+
+c2_status_t C2SoftAvcDecIntf::createTunnel_sm(c2_node_id_t targetComponent) {
+    // Tunneling is not supported
+    (void) targetComponent;
+    return C2_OMITTED;
+}
+
+c2_status_t C2SoftAvcDecIntf::releaseTunnel_sm(c2_node_id_t targetComponent) {
+    // Tunneling is not supported
+    (void) targetComponent;
+    return C2_OMITTED;
+}
+
+std::shared_ptr<C2ParamReflector> C2SoftAvcDecIntf::getParamReflector() const {
+    return mParamReflector;
+}
+
+c2_status_t C2SoftAvcDecIntf::querySupportedParams_nb(
+        std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const {
+    params->insert(params->begin(), mParamDescs.begin(), mParamDescs.end());
+    return C2_OK;
+}
+
+c2_status_t C2SoftAvcDecIntf::querySupportedValues_nb(
+        std::vector<C2FieldSupportedValuesQuery> &fields) const {
+    c2_status_t res = C2_OK;
+    for (C2FieldSupportedValuesQuery &query : fields) {
+        if (mSupportedValues.count(query.field) == 0) {
+            query.status = C2_BAD_INDEX;
+            res = C2_BAD_INDEX;
+        } else {
+            query.status = C2_OK;
+            query.values = mSupportedValues.at(query.field).supported;
+        }
+    }
+    return res;
+}
+
+void C2SoftAvcDecIntf::updateSupportedValues() {
+    int32_t maxWidth = H264_MAX_FRAME_WIDTH;
+    int32_t maxHeight = H264_MAX_FRAME_HEIGHT;
+    // cf: Rec. ITU-T H.264 A.3
+    int maxFrameRate = 172;
+    std::vector<C2ParamField> fields;
+    if (mLevel.mValue != kAvcLevelUnknown) {
+        // cf: Rec. ITU-T H.264 Table A-1
+        constexpr int MaxFS[] = {
+        //  0       1       2       3       4       5       6       7       8       9
+            0,      0,      0,      0,      0,      0,      0,      0,      0,      99,
+            99,     396,    396,    396,    0,      0,      0,      0,      0,      0,
+            396,    792,    1620,   0,      0,      0,      0,      0,      0,      0,
+            1620,   3600,   5120,   0,      0,      0,      0,      0,      0,      0,
+            8192,   8192,   8704,   0,      0,      0,      0,      0,      0,      0,
+            22080,  36864,  36864,
+        };
+        constexpr int MaxMBPS[] = {
+        //  0       1       2       3       4       5       6       7       8       9
+            0,      0,      0,      0,      0,      0,      0,      0,      0,      1485,
+            1485,   3000,   6000,   11880,  0,      0,      0,      0,      0,      0,
+            11880,  19800,  20250,  0,      0,      0,      0,      0,      0,      0,
+            40500,  108000, 216000, 0,      0,      0,      0,      0,      0,      0,
+            245760, 245760, 522240, 0,      0,      0,      0,      0,      0,      0,
+            589824, 983040, 2073600,
+        };
+
+        // cf: Rec. ITU-T H.264 A.3.1
+        maxWidth = std::min(maxWidth, floor32(std::sqrt(MaxFS[mLevel.mValue] * 8)) * MB_SIZE);
+        maxHeight = std::min(maxHeight, floor32(std::sqrt(MaxFS[mLevel.mValue] * 8)) * MB_SIZE);
+        int32_t MBs = ((mVideoSize.mWidth + 15) / 16) * ((mVideoSize.mHeight + 15) / 16);
+        maxFrameRate = std::min(maxFrameRate, MaxMBPS[mLevel.mValue] / MBs);
+        fields.push_back(C2ParamField(&mLevel, &C2AvcLevelInfo::mValue));
+    }
+
+    SupportedValuesWithFields &maxWidthVals = mSupportedValues.at(
+            C2ParamField(&mMaxVideoSizeHint, &C2MaxVideoSizeHintPortSetting::mWidth));
+    maxWidthVals.supported.range.max = maxWidth;
+    maxWidthVals.restrictingFields.clear();
+    maxWidthVals.restrictingFields.insert(fields.begin(), fields.end());
+
+    SupportedValuesWithFields &maxHeightVals = mSupportedValues.at(
+            C2ParamField(&mMaxVideoSizeHint, &C2MaxVideoSizeHintPortSetting::mHeight));
+    maxHeightVals.supported.range.max = maxHeight;
+    maxHeightVals.restrictingFields.clear();
+    maxHeightVals.restrictingFields.insert(fields.begin(), fields.end());
+
+    SupportedValuesWithFields &frameRate = mSupportedValues.at(
+            C2ParamField(&mFrameRate, &C2FrameRateInfo::mValue));
+    frameRate.supported.range.max = maxFrameRate;
+    frameRate.restrictingFields.clear();
+    frameRate.restrictingFields.insert(fields.begin(), fields.end());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class C2SoftAvcDec::QueueProcessThread {
+public:
+    QueueProcessThread() : mExitRequested(false), mRunning(false) {}
+
+    ~QueueProcessThread() {
+        if (mThread && mThread->joinable()) {
+            mExitRequested = true;
+            mThread->join();
+        }
+    }
+
+    void start(std::weak_ptr<C2SoftAvcDec> component) {
+        mThread.reset(new std::thread([this, component] () {
+            mRunning = true;
+            while (auto comp = component.lock()) {
+                if (mExitRequested) break;
+                comp->processQueue();
+            }
+            mRunning = false;
+        }));
+    }
+
+    void requestExit() {
+        mExitRequested = true;
+    }
+
+    bool isRunning() {
+        return mRunning;
+    }
+
+private:
+    std::atomic_bool mExitRequested;
+    std::atomic_bool mRunning;
+    std::unique_ptr<std::thread> mThread;
+};
+
+C2SoftAvcDec::C2SoftAvcDec(
+        const char *name,
+        c2_node_id_t id)
+    : mIntf(std::make_shared<C2SoftAvcDecIntf>(name, id)),
+      mThread(new QueueProcessThread),
+      mCodecCtx(NULL),
+      mFlushOutBuffer(NULL),
+      mIvColorFormat(IV_YUV_420P),
+      mChangingResolution(false),
+      mSignalledError(false),
+      mWidth(320),
+      mHeight(240),
+      mInputOffset(0) {
+    GETTIME(&mTimeStart, NULL);
+
+    // If input dump is enabled, then open create an empty file
+    GENERATE_FILE_NAMES();
+    CREATE_DUMP_FILE(mInFile);
+}
+
+C2SoftAvcDec::~C2SoftAvcDec() {
+    CHECK_EQ(deInitDecoder(), (status_t)OK);
+}
+
+c2_status_t C2SoftAvcDec::setListener_sm(
+        const std::shared_ptr<C2Component::Listener> &listener) {
+    std::unique_lock<std::mutex> lock(mListenerLock);
+    // TODO: we really need to lock the running check as well
+    if (listener && mThread->isRunning()) {
+        return C2_BAD_STATE;
+    }
+    mListener = listener;
+    if (mActiveListener && !listener) {
+        // wait until no active listeners are in use
+        mActiveListenerChanged.wait(lock, [this]{ return !mActiveListener; });
+    }
+    return C2_OK;
+}
+
+c2_status_t C2SoftAvcDec::queue_nb(
+        std::list<std::unique_ptr<C2Work>>* const items) {
+    if (!mThread->isRunning()) {
+        return C2_CORRUPTED;
+    }
+    std::unique_lock<std::mutex> lock(mQueueLock);
+    while (!items->empty()) {
+        // TODO: examine item and update width/height?
+        mQueue.emplace_back(std::move(items->front()));
+        items->pop_front();
+    }
+    mQueueCond.notify_all();
+    return C2_OK;
+}
+
+c2_status_t C2SoftAvcDec::announce_nb(const std::vector<C2WorkOutline> &items) {
+    // Tunneling is not supported
+    (void) items;
+    return C2_OMITTED;
+}
+
+c2_status_t C2SoftAvcDec::flush_sm(
+        flush_mode_t mode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
+    // Tunneling is not supported
+    (void) mode;
+
+    if (!mThread->isRunning()) {
+        return C2_CORRUPTED;
+    }
+    {
+        std::unique_lock<std::mutex> lock(mQueueLock);
+        while (!mQueue.empty()) {
+            flushedWork->emplace_back(std::move(mQueue.front()));
+            mQueue.pop_front();
+        }
+        mQueueCond.notify_all();
+    }
+    {
+        std::unique_lock<std::mutex> lock(mPendingLock);
+        for (auto &elem : mPendingWork) {
+            flushedWork->emplace_back(std::move(elem.second));
+        }
+        mPendingWork.clear();
+    }
+    return C2_OK;
+}
+
+c2_status_t C2SoftAvcDec::drain_nb(drain_mode_t mode) {
+    // Tunneling is not supported
+    (void) mode;
+
+    if (!mThread->isRunning()) {
+        return C2_CORRUPTED;
+    }
+    std::unique_lock<std::mutex> lock(mQueueLock);
+    if (!mQueue.empty()) {
+        C2BufferPack &lastInput = mQueue.back()->input;
+        lastInput.flags = (C2BufferPack::flags_t)(lastInput.flags | C2BufferPack::FLAG_END_OF_STREAM);
+        mQueueCond.notify_all();
+    }
+    return C2_OK;
+}
+
+c2_status_t C2SoftAvcDec::start() {
+    if (!mThread->isRunning()) {
+        mThread->start(shared_from_this());
+    }
+    return C2_OK;
+}
+
+c2_status_t C2SoftAvcDec::stop() {
+    ALOGV("stop");
+    std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
+    std::chrono::system_clock::time_point deadline = now + std::chrono::milliseconds(500);
+
+    mThread->requestExit();
+    while (mThread->isRunning() && (now = std::chrono::system_clock::now()) < deadline) {
+        std::this_thread::yield();
+        std::unique_lock<std::mutex> lock(mQueueLock);
+        mQueueCond.notify_all();
+    }
+    if (mThread->isRunning()) {
+        return C2_TIMED_OUT;
+    }
+
+    mSignalledError = false;
+    resetDecoder();
+    resetPlugin();
+
+    return C2_OK;
+}
+
+void C2SoftAvcDec::reset() {
+    if (mThread->isRunning()) {
+        stop();
+    }
+    // TODO
+}
+
+void C2SoftAvcDec::release() {
+    if (mThread->isRunning()) {
+        stop();
+    }
+    // TODO
+}
+
+std::shared_ptr<C2ComponentInterface> C2SoftAvcDec::intf() {
+    return mIntf;
+}
+
+void C2SoftAvcDec::processQueue() {
+    if (mIsInFlush) {
+        setFlushMode();
+
+        /* Allocate a picture buffer to flushed data */
+        uint32_t displayStride = mWidth;
+        uint32_t displayHeight = mHeight;
+
+        uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
+        mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize);
+        if (NULL == mFlushOutBuffer) {
+            ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize);
+            return;
+        }
+
+        while (true) {
+            ivd_video_decode_ip_t s_dec_ip;
+            ivd_video_decode_op_t s_dec_op;
+            IV_API_CALL_STATUS_T status;
+            size_t sizeY, sizeUV;
+
+            setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0, 0u);
+
+            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
+            if (0 == s_dec_op.u4_output_present) {
+                resetPlugin();
+                break;
+            }
+        }
+
+        if (mFlushOutBuffer) {
+            free(mFlushOutBuffer);
+            mFlushOutBuffer = NULL;
+        }
+        mIsInFlush = false;
+    }
+
+    std::unique_ptr<C2Work> work;
+    {
+        std::unique_lock<std::mutex> lock(mQueueLock);
+        if (mQueue.empty()) {
+            mQueueCond.wait(lock);
+        }
+        if (mQueue.empty()) {
+            ALOGV("empty queue");
+            return;
+        }
+        work.swap(mQueue.front());
+        mQueue.pop_front();
+    }
+
+    // Process the work
+    process(work);
+
+    std::vector<std::unique_ptr<C2Work>> done;
+    {
+        std::unique_lock<std::mutex> lock(mPendingLock);
+        uint32_t index = work->input.ordinal.frame_index;
+        mPendingWork[index].swap(work);
+
+        if (work) {
+            work->result = C2_CORRUPTED;
+            done.emplace_back(std::move(work));
+        }
+    }
+
+    if (!done.empty()) {
+        std::unique_lock<std::mutex> lock(mListenerLock);
+        mActiveListener = mListener;
+
+        if (mActiveListener) {
+            lock.unlock();
+            mActiveListener->onWorkDone_nb(shared_from_this(), std::move(done));
+            lock.lock();
+            mActiveListener.reset();
+            mActiveListenerChanged.notify_all();
+        }
+    }
+}
+
+
+static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
+    UNUSED(ctxt);
+    return memalign(alignment, size);
+}
+
+static void ivd_aligned_free(void *ctxt, void *buf) {
+    UNUSED(ctxt);
+    free(buf);
+    return;
+}
+
+static size_t GetCPUCoreCount() {
+    long cpuCoreCount = 1;
+#if defined(_SC_NPROCESSORS_ONLN)
+    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+    // _SC_NPROC_ONLN must be defined...
+    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
+#endif
+    CHECK(cpuCoreCount >= 1);
+    ALOGV("Number of CPU cores: %ld", cpuCoreCount);
+    return (size_t)cpuCoreCount;
+}
+
+void C2SoftAvcDec::logVersion() {
+    ivd_ctl_getversioninfo_ip_t s_ctl_ip;
+    ivd_ctl_getversioninfo_op_t s_ctl_op;
+    UWORD8 au1_buf[512];
+    IV_API_CALL_STATUS_T status;
+
+    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
+    s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
+    s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
+    s_ctl_ip.pv_version_buffer = au1_buf;
+    s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf);
+
+    status =
+        ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in getting version number: 0x%x",
+                s_ctl_op.u4_error_code);
+    } else {
+        ALOGV("Ittiam decoder version number: %s",
+                (char *)s_ctl_ip.pv_version_buffer);
+    }
+    return;
+}
+
+status_t C2SoftAvcDec::setParams(size_t stride) {
+    ivd_ctl_set_config_ip_t s_ctl_ip;
+    ivd_ctl_set_config_op_t s_ctl_op;
+    IV_API_CALL_STATUS_T status;
+    s_ctl_ip.u4_disp_wd = (UWORD32)stride;
+    s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
+
+    s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
+    s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
+    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
+    s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
+    s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
+
+    ALOGV("Set the run-time (dynamic) parameters stride = %zu", stride);
+    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in setting the run-time parameters: 0x%x",
+                s_ctl_op.u4_error_code);
+
+        return UNKNOWN_ERROR;
+    }
+    return OK;
+}
+
+status_t C2SoftAvcDec::resetPlugin() {
+    mReceivedEOS = false;
+    mInputOffset = 0;
+
+    /* Initialize both start and end times */
+    gettimeofday(&mTimeStart, NULL);
+    gettimeofday(&mTimeEnd, NULL);
+
+    return OK;
+}
+
+status_t C2SoftAvcDec::resetDecoder() {
+    ivd_ctl_reset_ip_t s_ctl_ip;
+    ivd_ctl_reset_op_t s_ctl_op;
+    IV_API_CALL_STATUS_T status;
+
+    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
+    s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
+    s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
+
+    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
+    if (IV_SUCCESS != status) {
+        ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
+        return UNKNOWN_ERROR;
+    }
+    mSignalledError = false;
+
+    /* Set number of cores/threads to be used by the codec */
+    setNumCores();
+
+    mStride = 0;
+    return OK;
+}
+
+status_t C2SoftAvcDec::setNumCores() {
+    ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
+    ivdext_ctl_set_num_cores_op_t s_set_cores_op;
+    IV_API_CALL_STATUS_T status;
+    s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
+    s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
+    s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
+    s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
+    status = ivdec_api_function(
+            mCodecCtx, (void *)&s_set_cores_ip, (void *)&s_set_cores_op);
+    if (IV_SUCCESS != status) {
+        ALOGE("Error in setting number of cores: 0x%x",
+                s_set_cores_op.u4_error_code);
+        return UNKNOWN_ERROR;
+    }
+    return OK;
+}
+
+status_t C2SoftAvcDec::setFlushMode() {
+    IV_API_CALL_STATUS_T status;
+    ivd_ctl_flush_ip_t s_video_flush_ip;
+    ivd_ctl_flush_op_t s_video_flush_op;
+
+    s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
+    s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
+    s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
+
+    /* Set the decoder in Flush mode, subsequent decode() calls will flush */
+    status = ivdec_api_function(
+            mCodecCtx, (void *)&s_video_flush_ip, (void *)&s_video_flush_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
+                s_video_flush_op.u4_error_code);
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+status_t C2SoftAvcDec::initDecoder() {
+    IV_API_CALL_STATUS_T status;
+
+    mNumCores = GetCPUCoreCount();
+    mCodecCtx = NULL;
+
+    mStride = mWidth;
+
+    /* Initialize the decoder */
+    {
+        ivdext_create_ip_t s_create_ip;
+        ivdext_create_op_t s_create_op;
+
+        void *dec_fxns = (void *)ivdec_api_function;
+
+        s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
+        s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
+        s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
+        s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
+        s_create_ip.s_ivd_create_ip_t.e_output_format = (IV_COLOR_FORMAT_T)mIvColorFormat;
+        s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
+        s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
+        s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
+
+        status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
+
+        mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
+        mCodecCtx->pv_fxns = dec_fxns;
+        mCodecCtx->u4_size = sizeof(iv_obj_t);
+
+        if (status != IV_SUCCESS) {
+            ALOGE("Error in create: 0x%x",
+                    s_create_op.s_ivd_create_op_t.u4_error_code);
+            deInitDecoder();
+            mCodecCtx = NULL;
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    /* Reset the plugin state */
+    resetPlugin();
+
+    /* Set the run time (dynamic) parameters */
+    setParams(mStride);
+
+    /* Set number of cores/threads to be used by the codec */
+    setNumCores();
+
+    /* Get codec version */
+    logVersion();
+
+    mFlushNeeded = false;
+    return OK;
+}
+
+status_t C2SoftAvcDec::deInitDecoder() {
+    size_t i;
+    IV_API_CALL_STATUS_T status;
+
+    if (mCodecCtx) {
+        ivdext_delete_ip_t s_delete_ip;
+        ivdext_delete_op_t s_delete_op;
+
+        s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
+        s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
+
+        s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
+
+        status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op);
+        if (status != IV_SUCCESS) {
+            ALOGE("Error in delete: 0x%x",
+                    s_delete_op.s_ivd_delete_op_t.u4_error_code);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+
+    mChangingResolution = false;
+
+    return OK;
+}
+
+bool C2SoftAvcDec::getVUIParams() {
+    IV_API_CALL_STATUS_T status;
+    ih264d_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip;
+    ih264d_ctl_get_vui_params_op_t s_ctl_get_vui_params_op;
+
+    s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+    s_ctl_get_vui_params_ip.e_sub_cmd =
+        (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_GET_VUI_PARAMS;
+
+    s_ctl_get_vui_params_ip.u4_size =
+        sizeof(ih264d_ctl_get_vui_params_ip_t);
+
+    s_ctl_get_vui_params_op.u4_size = sizeof(ih264d_ctl_get_vui_params_op_t);
+
+    status = ivdec_api_function(
+            (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_vui_params_ip,
+            (void *)&s_ctl_get_vui_params_op);
+
+    if (status != IV_SUCCESS) {
+        ALOGW("Error in getting VUI params: 0x%x",
+                s_ctl_get_vui_params_op.u4_error_code);
+        return false;
+    }
+
+    int32_t primaries = s_ctl_get_vui_params_op.u1_colour_primaries;
+    int32_t transfer = s_ctl_get_vui_params_op.u1_tfr_chars;
+    int32_t coeffs = s_ctl_get_vui_params_op.u1_matrix_coeffs;
+    bool fullRange = s_ctl_get_vui_params_op.u1_video_full_range_flag;
+
+    ColorAspects colorAspects;
+    ColorUtils::convertIsoColorAspectsToCodecAspects(
+            primaries, transfer, coeffs, fullRange, colorAspects);
+
+    // Update color aspects if necessary.
+    if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
+        mBitstreamColorAspects = colorAspects;
+        status_t err = handleColorAspectsChange();
+        CHECK(err == OK);
+    }
+    return true;
+}
+
+bool C2SoftAvcDec::setDecodeArgs(
+        ivd_video_decode_ip_t *ps_dec_ip,
+        ivd_video_decode_op_t *ps_dec_op,
+        C2ReadView *inBuffer,
+        C2GraphicView *outBuffer,
+        uint32_t workIndex,
+        size_t inOffset) {
+    size_t width = mWidth;
+    size_t height = mHeight;
+    size_t sizeY = width * height;
+    size_t sizeUV;
+
+    ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
+    ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
+
+    ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
+
+    /* When in flush and after EOS with zero byte input,
+     * inBuffer is set to zero. Hence check for non-null */
+    if (inBuffer) {
+        ps_dec_ip->u4_ts = workIndex;
+        ps_dec_ip->pv_stream_buffer = const_cast<uint8_t *>(inBuffer->data()) + inOffset;
+        ps_dec_ip->u4_num_Bytes = inBuffer->capacity() - inOffset;
+    } else {
+        ps_dec_ip->u4_ts = 0;
+        ps_dec_ip->pv_stream_buffer = NULL;
+        ps_dec_ip->u4_num_Bytes = 0;
+    }
+
+    sizeUV = sizeY / 4;
+    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
+    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
+    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
+
+    if (outBuffer) {
+        if (outBuffer->width() < width ||
+                outBuffer->height() < height) {
+            ALOGE("Output buffer too small: provided (%dx%d) required (%zux%zu)",
+                  outBuffer->width(), outBuffer->height(), width, height);
+            return false;
+        }
+        ps_dec_ip->s_out_buffer.pu1_bufs[0] = outBuffer->data()[0];
+        ps_dec_ip->s_out_buffer.pu1_bufs[1] = outBuffer->data()[1];
+        ps_dec_ip->s_out_buffer.pu1_bufs[2] = outBuffer->data()[2];
+    } else {
+        // mFlushOutBuffer always has the right size.
+        ps_dec_ip->s_out_buffer.pu1_bufs[0] = mFlushOutBuffer;
+        ps_dec_ip->s_out_buffer.pu1_bufs[1] = mFlushOutBuffer + sizeY;
+        ps_dec_ip->s_out_buffer.pu1_bufs[2] = mFlushOutBuffer + sizeY + sizeUV;
+    }
+
+    ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
+    return true;
+}
+
+void C2SoftAvcDec::process(std::unique_ptr<C2Work> &work) {
+    if (mSignalledError) {
+        return;
+    }
+
+    if (NULL == mCodecCtx) {
+        if (OK != initDecoder()) {
+            ALOGE("Failed to initialize decoder");
+            // TODO: notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
+            mSignalledError = true;
+            return;
+        }
+    }
+    if (mWidth != mStride) {
+        /* Set the run-time (dynamic) parameters */
+        mStride = mWidth;
+        setParams(mStride);
+    }
+
+    const C2ConstLinearBlock &buffer =
+            work->input.buffers[0]->data().linearBlocks().front();
+    if (buffer.capacity() == 0) {
+        // TODO: result?
+
+        std::vector<std::unique_ptr<C2Work>> done;
+        done.emplace_back(std::move(work));
+        mListener->onWorkDone_nb(shared_from_this(), std::move(done));
+        if (!(work->input.flags & C2BufferPack::FLAG_END_OF_STREAM)) {
+            return;
+        }
+
+        mReceivedEOS = true;
+        // TODO: flush
+    } else if (work->input.flags & C2BufferPack::FLAG_END_OF_STREAM) {
+        mReceivedEOS = true;
+    }
+
+    C2ReadView input = work->input.buffers[0]->data().linearBlocks().front().map().get();
+    uint32_t workIndex = work->input.ordinal.frame_index & 0xFFFFFFFF;
+
+    // TODO: populate --- assume display order?
+    if (!mAllocatedBlock) {
+        // TODO: error handling
+        // TODO: format & usage
+        uint32_t format = HAL_PIXEL_FORMAT_YV12;
+        C2MemoryUsage usage = { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite };
+        // TODO: lock access to interface
+        C2BlockPool::local_id_t poolId =
+            mIntf->mOutputBlockPools->flexCount() ?
+                    mIntf->mOutputBlockPools->m.mValues[0] : C2BlockPool::BASIC_GRAPHIC;
+        if (!mOutputBlockPool || mOutputBlockPool->getLocalId() != poolId) {
+            c2_status_t err = GetCodec2BlockPool(poolId, shared_from_this(), &mOutputBlockPool);
+            if (err != C2_OK) {
+                // TODO: trip
+            }
+        }
+        ALOGE("using allocator %u", mOutputBlockPool->getAllocatorId());
+
+        (void)mOutputBlockPool->fetchGraphicBlock(
+                mWidth, mHeight, format, usage, &mAllocatedBlock);
+        ALOGE("provided (%dx%d) required (%dx%d)", mAllocatedBlock->width(), mAllocatedBlock->height(), mWidth, mHeight);
+    }
+    C2GraphicView output = mAllocatedBlock->map().get();
+    ALOGE("mapped err = %d", output.error());
+
+    size_t inOffset = 0u;
+    while (inOffset < input.capacity()) {
+        ivd_video_decode_ip_t s_dec_ip;
+        ivd_video_decode_op_t s_dec_op;
+        WORD32 timeDelay, timeTaken;
+        size_t sizeY, sizeUV;
+
+        if (!setDecodeArgs(&s_dec_ip, &s_dec_op, &input, &output, workIndex, inOffset)) {
+            ALOGE("Decoder arg setup failed");
+            // TODO: notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+            mSignalledError = true;
+            return;
+        }
+        ALOGE("Decoder arg setup succeeded");
+        // If input dump is enabled, then write to file
+        DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes, mInputOffset);
+
+        GETTIME(&mTimeStart, NULL);
+        /* Compute time elapsed between end of previous decode()
+         * to start of current decode() */
+        TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
+
+        IV_API_CALL_STATUS_T status;
+        status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
+
+        bool unsupportedResolution =
+            (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & 0xFF));
+
+        /* Check for unsupported dimensions */
+        if (unsupportedResolution) {
+            ALOGE("Unsupported resolution : %dx%d", mWidth, mHeight);
+            // TODO: notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
+            mSignalledError = true;
+            return;
+        }
+
+        bool allocationFailed = (IVD_MEM_ALLOC_FAILED == (s_dec_op.u4_error_code & 0xFF));
+        if (allocationFailed) {
+            ALOGE("Allocation failure in decoder");
+            // TODO: notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
+            mSignalledError = true;
+            return;
+        }
+
+        bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
+
+        getVUIParams();
+
+        GETTIME(&mTimeEnd, NULL);
+        /* Compute time taken for decode() */
+        TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
+
+        PRINT_TIME("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
+               s_dec_op.u4_num_bytes_consumed);
+        ALOGI("bytes total=%u", input.capacity());
+        if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
+            mFlushNeeded = true;
+        }
+
+        if (1 != s_dec_op.u4_frame_decoded_flag) {
+            /* If the input did not contain picture data, then ignore
+             * the associated timestamp */
+            //mTimeStampsValid[workIndex] = false;
+        }
+
+        // If the decoder is in the changing resolution mode and there is no output present,
+        // that means the switching is done and it's ready to reset the decoder and the plugin.
+        if (mChangingResolution && !s_dec_op.u4_output_present) {
+            ALOGV("changing resolution");
+            mChangingResolution = false;
+            resetDecoder();
+            resetPlugin();
+            mStride = mWidth;
+            setParams(mStride);
+            return;
+        }
+
+        if (resChanged) {
+            ALOGV("res changed");
+            mChangingResolution = true;
+            if (mFlushNeeded) {
+                setFlushMode();
+            }
+            return;
+        }
+
+        // Combine the resolution change and coloraspects change in one PortSettingChange event
+        // if necessary.
+        if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
+            uint32_t width = s_dec_op.u4_pic_wd;
+            uint32_t height = s_dec_op.u4_pic_ht;
+            ALOGV("width = %u height = %u", width, height);
+            if (width != mWidth || height != mHeight) {
+                mAllocatedBlock.reset();
+                mWidth = width;
+                mHeight = height;
+            }
+        } else if (mUpdateColorAspects) {
+            //notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
+            //    kDescribeColorAspectsIndex, NULL);
+            ALOGV("update color aspect");
+            mUpdateColorAspects = false;
+            return;
+        }
+
+        if (s_dec_op.u4_output_present) {
+            ALOGV("output_present");
+            // TODO: outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
+            std::vector<std::unique_ptr<C2Work>> done;
+            done.push_back(std::move(mPendingWork[s_dec_op.u4_ts]));
+            done[0]->worklets.front()->output.buffers.clear();
+            done[0]->worklets.front()->output.buffers.emplace_back(
+                    std::make_shared<GraphicBuffer>(std::move(mAllocatedBlock)));
+            done[0]->worklets.front()->output.ordinal = done[0]->input.ordinal;
+            mListener->onWorkDone_nb(shared_from_this(), std::move(done));
+        } else if (mIsInFlush) {
+            ALOGV("flush");
+            /* If in flush mode and no output is returned by the codec,
+             * then come out of flush mode */
+            mIsInFlush = false;
+
+            /* If EOS was recieved on input port and there is no output
+             * from the codec, then signal EOS on output port */
+            if (mReceivedEOS) {
+                // TODO
+                // outHeader->nFilledLen = 0;
+                // outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
+
+                // outInfo->mOwnedByUs = false;
+                // outQueue.erase(outQueue.begin());
+                // outInfo = NULL;
+                // notifyFillBufferDone(outHeader);
+                // outHeader = NULL;
+                resetPlugin();
+            }
+        }
+        inOffset += s_dec_op.u4_num_bytes_consumed;
+    }
+    /* If input EOS is seen and decoder is not in flush mode,
+     * set the decoder in flush mode.
+     * There can be a case where EOS is sent along with last picture data
+     * In that case, only after decoding that input data, decoder has to be
+     * put in flush. This case is handled here  */
+
+    if (mReceivedEOS && !mIsInFlush) {
+        setFlushMode();
+    }
+}
+
+bool C2SoftAvcDec::colorAspectsDiffer(
+        const ColorAspects &a, const ColorAspects &b) {
+    if (a.mRange != b.mRange
+        || a.mPrimaries != b.mPrimaries
+        || a.mTransfer != b.mTransfer
+        || a.mMatrixCoeffs != b.mMatrixCoeffs) {
+        return true;
+    }
+    return false;
+}
+
+void C2SoftAvcDec::updateFinalColorAspects(
+        const ColorAspects &otherAspects, const ColorAspects &preferredAspects) {
+    Mutex::Autolock autoLock(mColorAspectsLock);
+    ColorAspects newAspects;
+    newAspects.mRange = preferredAspects.mRange != ColorAspects::RangeUnspecified ?
+        preferredAspects.mRange : otherAspects.mRange;
+    newAspects.mPrimaries = preferredAspects.mPrimaries != ColorAspects::PrimariesUnspecified ?
+        preferredAspects.mPrimaries : otherAspects.mPrimaries;
+    newAspects.mTransfer = preferredAspects.mTransfer != ColorAspects::TransferUnspecified ?
+        preferredAspects.mTransfer : otherAspects.mTransfer;
+    newAspects.mMatrixCoeffs = preferredAspects.mMatrixCoeffs != ColorAspects::MatrixUnspecified ?
+        preferredAspects.mMatrixCoeffs : otherAspects.mMatrixCoeffs;
+
+    // Check to see if need update mFinalColorAspects.
+    if (colorAspectsDiffer(mFinalColorAspects, newAspects)) {
+        mFinalColorAspects = newAspects;
+        mUpdateColorAspects = true;
+    }
+}
+
+status_t C2SoftAvcDec::handleColorAspectsChange() {
+//    int perference = getColorAspectPreference();
+//    ALOGD("Color Aspects preference: %d ", perference);
+//
+//     if (perference == kPreferBitstream) {
+//         updateFinalColorAspects(mDefaultColorAspects, mBitstreamColorAspects);
+//     } else if (perference == kPreferContainer) {
+//         updateFinalColorAspects(mBitstreamColorAspects, mDefaultColorAspects);
+//     } else {
+//         return OMX_ErrorUnsupportedSetting;
+//     }
+    updateFinalColorAspects(mDefaultColorAspects, mBitstreamColorAspects);
+    return C2_OK;
+}
+
+class C2SoftAvcDecFactory : public C2ComponentFactory {
+public:
+    virtual c2_status_t createComponent(
+            std::shared_ptr<C2Component>* const component, c2_node_id_t id) override {
+        *component = std::make_shared<C2SoftAvcDec>("avc", id);
+        return C2_OK;
+    }
+
+    virtual c2_status_t createInterface(
+            std::shared_ptr<C2ComponentInterface>* const interface, c2_node_id_t id) override {
+        *interface = std::make_shared<C2SoftAvcDecIntf>("avc", id);
+        return C2_OK;
+    }
+
+    virtual ~C2SoftAvcDecFactory() override = default;
+};
+
+}  // namespace android
+
+extern "C" ::android::C2ComponentFactory* CreateCodec2Factory() {
+    return new ::android::C2SoftAvcDecFactory();
+}
+
+extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory* factory) {
+    delete factory;
+}
diff --git a/media/libstagefright/codecs/avcdec/C2SoftAvcDec.h b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.h
new file mode 100644
index 0000000..5deaf5d
--- /dev/null
+++ b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.h
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2_SOFT_H264_DEC_H_
+
+#define C2_SOFT_H264_DEC_H_
+
+#include <condition_variable>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <unordered_map>
+
+#include <util/C2ParamUtils.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+
+#include "C2AvcConfig.h"
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/ColorUtils.h>
+
+#include <sys/time.h>
+
+namespace android {
+
+struct iv_obj_t;
+struct ivd_video_decode_ip_t;
+struct ivd_video_decode_op_t;
+
+/** Number of entries in the time-stamp array */
+#define MAX_PENDING_WORKS 64
+
+/** Maximum number of cores supported by the codec */
+#define CODEC_MAX_NUM_CORES 4
+
+#define CODEC_MAX_WIDTH     1920
+
+#define CODEC_MAX_HEIGHT    1088
+
+/** Input buffer size */
+#define INPUT_BUF_SIZE (1024 * 1024)
+
+#define MIN(a, b) ((a) < (b)) ? (a) : (b)
+
+/** Used to remove warnings about unused parameters */
+#define UNUSED(x) ((void)(x))
+
+/** Get time */
+#define GETTIME(a, b) gettimeofday(a, b);
+
+/** Compute difference between start and end */
+#define TIME_DIFF(start, end, diff) \
+    diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
+            ((end).tv_usec - (start).tv_usec);
+
+
+class C2SoftAvcDecIntf : public C2ComponentInterface {
+public:
+    struct SupportedValuesWithFields {
+        C2FieldSupportedValues supported;
+        std::set<C2ParamField> restrictingFields;
+
+        SupportedValuesWithFields(const C2FieldSupportedValues &supported) : supported(supported) {}
+    };
+
+    C2SoftAvcDecIntf(const char *name, c2_node_id_t id);
+    virtual ~C2SoftAvcDecIntf() = default;
+
+    // From C2ComponentInterface
+    virtual C2String getName() const override;
+    virtual c2_node_id_t getId() const override;
+    virtual c2_status_t query_nb(
+            const std::vector<C2Param* const> &stackParams,
+            const std::vector<C2Param::Index> &heapParamIndices,
+            std::vector<std::unique_ptr<C2Param>>* const heapParams) const override;
+    virtual c2_status_t config_nb(
+            const std::vector<C2Param* const> &params,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
+    virtual c2_status_t commit_sm(
+            const std::vector<C2Param* const> &params,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
+    virtual c2_status_t createTunnel_sm(c2_node_id_t targetComponent) override;
+    virtual c2_status_t releaseTunnel_sm(c2_node_id_t targetComponent) override;
+    // TODO: move this into some common store class
+    std::shared_ptr<C2ParamReflector> getParamReflector() const;
+    virtual c2_status_t querySupportedParams_nb(
+            std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override;
+    virtual c2_status_t querySupportedValues_nb(
+            std::vector<C2FieldSupportedValuesQuery> &fields) const override;
+
+private:
+    class ParamReflector;
+
+    const C2String mName;
+    const c2_node_id_t mId;
+
+    C2ComponentDomainInfo mDomainInfo;
+    // TODO: config desc
+    std::unique_ptr<C2PortMimeConfig::input> mInputPortMime;
+    C2PortStreamCountConfig::input mInputStreamCount;
+    std::unique_ptr<C2PortMimeConfig::output> mOutputPortMime;
+    C2PortStreamCountConfig::output mOutputStreamCount;
+    // TODO: C2StreamMimeConfig mInputStreamMime;
+    // TODO: C2StreamMimeConfig mOutputStreamMime;
+    C2StreamFormatConfig::input mInputStreamFormat;
+    std::unique_ptr<C2PortBlockPoolsTuning::output> mOutputBlockPools;
+    C2StreamFormatConfig::output mOutputStreamFormat;
+    C2VideoSizeStreamInfo::output mVideoSize;
+    C2MaxVideoSizeHintPortSetting::input mMaxVideoSizeHint;
+    C2AvcProfileInfo::input mProfile;
+    C2AvcLevelInfo::input mLevel;
+    C2BlockSizeInfo::output mBlockSize;
+    C2AlignmentInfo::output mAlignment;
+    C2FrameRateInfo::output mFrameRate;
+    C2BlocksPerSecondInfo::output mBlocksPerSecond;
+
+    std::shared_ptr<C2ParamReflector> mParamReflector;
+
+    std::unordered_map<uint32_t, C2Param *> mParams;
+    // C2ParamField is LessThanComparable
+    std::map<C2ParamField, SupportedValuesWithFields> mSupportedValues;
+    std::unordered_map<
+            uint32_t, std::function<std::unique_ptr<C2SettingResult>(C2Param *)>> mFieldVerifiers;
+    std::vector<std::shared_ptr<C2ParamDescriptor>> mParamDescs;
+
+    void updateSupportedValues();
+    friend class C2SoftAvcDec;
+};
+
+class C2SoftAvcDec
+    : public C2Component,
+      public std::enable_shared_from_this<C2SoftAvcDec> {
+public:
+    C2SoftAvcDec(const char *name, c2_node_id_t id);
+    virtual ~C2SoftAvcDec();
+
+    // From C2Component
+    virtual c2_status_t setListener_sm(const std::shared_ptr<Listener> &listener) override;
+    virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) override;
+    virtual c2_status_t announce_nb(const std::vector<C2WorkOutline> &items) override;
+    virtual c2_status_t flush_sm(
+            flush_mode_t mode, std::list<std::unique_ptr<C2Work>>* const flushedWork) override;
+    virtual c2_status_t drain_nb(drain_mode_t mode) override;
+    virtual c2_status_t start() override;
+    virtual c2_status_t stop() override;
+    virtual void reset() override;
+    virtual void release() override;
+    virtual std::shared_ptr<C2ComponentInterface> intf() override;
+
+private:
+    class QueueProcessThread;
+
+    Mutex mColorAspectsLock;
+    // color aspects passed from the framework.
+    ColorAspects mDefaultColorAspects;
+    // color aspects parsed from the bitstream.
+    ColorAspects mBitstreamColorAspects;
+    // final color aspects after combining the above two aspects.
+    ColorAspects mFinalColorAspects;
+    bool mUpdateColorAspects;
+
+    bool colorAspectsDiffer(const ColorAspects &a, const ColorAspects &b);
+
+    // This functions takes two color aspects and updates the mFinalColorAspects
+    // based on |preferredAspects|.
+    void updateFinalColorAspects(
+            const ColorAspects &otherAspects, const ColorAspects &preferredAspects);
+
+    // This function will update the mFinalColorAspects based on codec preference.
+    status_t handleColorAspectsChange();
+
+    // Number of input and output buffers
+    enum {
+        kNumBuffers = 8
+    };
+
+    using IndexType = decltype(C2WorkOrdinalStruct().frame_index);
+
+    const std::shared_ptr<C2SoftAvcDecIntf> mIntf;
+    std::shared_ptr<Listener> mListener;
+    std::shared_ptr<Listener> mActiveListener;
+    std::mutex mListenerLock;
+    std::condition_variable mActiveListenerChanged;
+
+    std::shared_ptr<C2BlockPool> mOutputBlockPool;
+
+    std::mutex mQueueLock;
+    std::condition_variable mQueueCond;
+    std::list<std::unique_ptr<C2Work>> mQueue;
+
+    std::mutex mPendingLock;
+    std::unordered_map<IndexType, std::unique_ptr<C2Work>> mPendingWork;
+
+    std::unique_ptr<QueueProcessThread> mThread;
+
+    std::shared_ptr<C2GraphicBlock> mAllocatedBlock;
+
+    iv_obj_t *mCodecCtx;         // Codec context
+
+    size_t mNumCores;            // Number of cores to be uesd by the codec
+
+    struct timeval mTimeStart;   // Time at the start of decode()
+    struct timeval mTimeEnd;     // Time at the end of decode()
+
+    // Internal buffer to be used to flush out the buffers from decoder
+    uint8_t *mFlushOutBuffer;
+
+#ifdef FILE_DUMP_ENABLE
+    char mInFile[200];
+#endif /* FILE_DUMP_ENABLE */
+
+    int mIvColorFormat;        // Ittiam Color format
+
+    bool mIsInFlush;        // codec is flush mode
+    bool mReceivedEOS;      // EOS is receieved on input port
+
+    // The input stream has changed to a different resolution, which is still supported by the
+    // codec. So the codec is switching to decode the new resolution.
+    bool mChangingResolution;
+    bool mFlushNeeded;
+    bool mSignalledError;
+    uint32_t mWidth;
+    uint32_t mHeight;
+    uint32_t mStride;
+    size_t mInputOffset;
+
+    void processQueue();
+    void process(std::unique_ptr<C2Work> &work);
+
+    status_t initDecoder();
+    status_t deInitDecoder();
+    status_t setFlushMode();
+    status_t setParams(size_t stride);
+    void logVersion();
+    status_t setNumCores();
+    status_t resetDecoder();
+    status_t resetPlugin();
+
+    bool setDecodeArgs(
+            ivd_video_decode_ip_t *ps_dec_ip,
+            ivd_video_decode_op_t *ps_dec_op,
+            C2ReadView *inBuffer,
+            C2GraphicView *outBuffer,
+            uint32_t timeStampIx,
+            size_t inOffset);
+
+    bool getVUIParams();
+
+    DISALLOW_EVIL_CONSTRUCTORS(C2SoftAvcDec);
+};
+
+#ifdef FILE_DUMP_ENABLE
+
+#define INPUT_DUMP_PATH     "/sdcard/media/avcd_input"
+#define INPUT_DUMP_EXT      "h264"
+
+#define GENERATE_FILE_NAMES() {                         \
+    GETTIME(&mTimeStart, NULL);                         \
+    strcpy(mInFile, "");                                \
+    sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH,  \
+            mTimeStart.tv_sec, mTimeStart.tv_usec,      \
+            INPUT_DUMP_EXT);                            \
+}
+
+#define CREATE_DUMP_FILE(m_filename) {                  \
+    FILE *fp = fopen(m_filename, "wb");                 \
+    if (fp != NULL) {                                   \
+        fclose(fp);                                     \
+    } else {                                            \
+        ALOGD("Could not open file %s", m_filename);    \
+    }                                                   \
+}
+#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)\
+{                                                       \
+    FILE *fp = fopen(m_filename, "ab");                 \
+    if (fp != NULL && m_buf != NULL && m_offset == 0) { \
+        int i;                                          \
+        i = fwrite(m_buf, 1, m_size, fp);               \
+        ALOGD("fwrite ret %d to write %d", i, m_size);  \
+        if (i != (int) m_size) {                        \
+            ALOGD("Error in fwrite, returned %d", i);   \
+            perror("Error in write to file");           \
+        }                                               \
+    } else if (fp == NULL) {                            \
+        ALOGD("Could not write to file %s", m_filename);\
+    }                                                   \
+    if (fp) {                                           \
+        fclose(fp);                                     \
+    }                                                   \
+}
+#else /* FILE_DUMP_ENABLE */
+#define INPUT_DUMP_PATH
+#define INPUT_DUMP_EXT
+#define OUTPUT_DUMP_PATH
+#define OUTPUT_DUMP_EXT
+#define GENERATE_FILE_NAMES()
+#define CREATE_DUMP_FILE(m_filename)
+#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)
+#endif /* FILE_DUMP_ENABLE */
+
+} // namespace android
+
+#endif  // C2_SOFT_H264_DEC_H_
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index dae6e79..1622561 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -171,7 +171,7 @@
 status_t SoftAVC::resetPlugin() {
     mIsInFlush = false;
     mReceivedEOS = false;
-    mInputOffset = 0;
+
     memset(mTimeStamps, 0, sizeof(mTimeStamps));
     memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
 
@@ -334,6 +334,7 @@
     SoftVideoDecoderOMXComponent::onReset();
 
     mSignalledError = false;
+    mInputOffset = 0;
     resetDecoder();
     resetPlugin();
 }
@@ -465,7 +466,8 @@
             free(mFlushOutBuffer);
             mFlushOutBuffer = NULL;
         }
-
+    } else {
+        mInputOffset = 0;
     }
 }
 
diff --git a/media/libstagefright/codecs/avcenc/Android.bp b/media/libstagefright/codecs/avcenc/Android.bp
index 5203126..4a0411e 100644
--- a/media/libstagefright/codecs/avcenc/Android.bp
+++ b/media/libstagefright/codecs/avcenc/Android.bp
@@ -17,7 +17,7 @@
     ],
 
     shared_libs: [
-        "libmedia_omx",
+        "libstagefright_foundation",
         "libstagefright_omx",
         "libutils",
         "liblog",
diff --git a/media/libstagefright/codecs/cmds/Android.bp b/media/libstagefright/codecs/cmds/Android.bp
new file mode 100644
index 0000000..e44e53c
--- /dev/null
+++ b/media/libstagefright/codecs/cmds/Android.bp
@@ -0,0 +1,50 @@
+cc_binary {
+    name: "codec2",
+
+    srcs: [
+        "codec2.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/codec2/include",
+        "frameworks/av/media/libstagefright/codec2/vndk/include",
+    ],
+
+    shared_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+        "libbinder",
+        "libcutils",
+        "libgui",
+        "libhidlbase",
+        "libion",
+        "liblog",
+        "libstagefright",
+        "libstagefright_codec2",
+        "libstagefright_foundation",
+        "libstagefright_soft_c2avcdec",
+        "libui",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libstagefright_codec2_vndk",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-std=c++14",
+    ],
+
+//    sanitize: {
+//        cfi: true,
+//        misc_undefined: [
+//            "unsigned-integer-overflow",
+//            "signed-integer-overflow",
+//        ],
+//        diag: {
+//            cfi: true,
+//        },
+//    },
+}
diff --git a/media/libstagefright/codecs/cmds/codec2.cpp b/media/libstagefright/codecs/cmds/codec2.cpp
new file mode 100644
index 0000000..8e2c4b9
--- /dev/null
+++ b/media/libstagefright/codecs/cmds/codec2.cpp
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <thread>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "codec2"
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <media/DataSource.h>
+#include <media/ICrypto.h>
+#include <media/IMediaHTTPService.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaExtractorFactory.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include <gui/GLConsumer.h>
+#include <gui/IProducerListener.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <util/C2ParamUtils.h>
+#include <C2Buffer.h>
+#include <C2BufferPriv.h>
+#include <C2Component.h>
+#include <C2PlatformSupport.h>
+#include <C2Work.h>
+
+extern "C" ::android::C2ComponentFactory *CreateCodec2Factory();
+extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory *);
+
+#include "../avcdec/C2SoftAvcDec.h"
+
+using namespace android;
+using namespace std::chrono_literals;
+
+namespace {
+
+class LinearBuffer : public C2Buffer {
+public:
+    explicit LinearBuffer(const std::shared_ptr<C2LinearBlock> &block)
+        : C2Buffer({ block->share(block->offset(), block->size(), ::android::C2Fence()) }) {}
+};
+
+class Listener;
+
+class SimplePlayer {
+public:
+    SimplePlayer();
+    ~SimplePlayer();
+
+    void onWorkDone(std::weak_ptr<C2Component> component,
+                    std::vector<std::unique_ptr<C2Work>> workItems);
+    void onTripped(std::weak_ptr<C2Component> component,
+                   std::vector<std::shared_ptr<C2SettingResult>> settingResult);
+    void onError(std::weak_ptr<C2Component> component, uint32_t errorCode);
+
+    void play(const sp<IMediaSource> &source);
+
+private:
+    typedef std::unique_lock<std::mutex> ULock;
+
+    std::shared_ptr<Listener> mListener;
+    std::shared_ptr<C2Component> mComponent;
+
+    sp<IProducerListener> mProducerListener;
+
+    std::shared_ptr<C2Allocator> mAllocIon;
+    std::shared_ptr<C2BlockPool> mLinearPool;
+
+    std::mutex mQueueLock;
+    std::condition_variable mQueueCondition;
+    std::list<std::unique_ptr<C2Work>> mWorkQueue;
+
+    std::mutex mProcessedLock;
+    std::condition_variable mProcessedCondition;
+    std::list<std::unique_ptr<C2Work>> mProcessedWork;
+
+    sp<Surface> mSurface;
+    sp<SurfaceComposerClient> mComposerClient;
+    sp<SurfaceControl> mControl;
+};
+
+class Listener : public C2Component::Listener {
+public:
+    explicit Listener(SimplePlayer *thiz) : mThis(thiz) {}
+    virtual ~Listener() = default;
+
+    virtual void onWorkDone_nb(std::weak_ptr<C2Component> component,
+                            std::vector<std::unique_ptr<C2Work>> workItems) override {
+        mThis->onWorkDone(component, std::move(workItems));
+    }
+
+    virtual void onTripped_nb(std::weak_ptr<C2Component> component,
+                           std::vector<std::shared_ptr<C2SettingResult>> settingResult) override {
+        mThis->onTripped(component, settingResult);
+    }
+
+    virtual void onError_nb(std::weak_ptr<C2Component> component,
+                         uint32_t errorCode) override {
+        mThis->onError(component, errorCode);
+    }
+
+private:
+    SimplePlayer * const mThis;
+};
+
+
+SimplePlayer::SimplePlayer()
+    : mListener(new Listener(this)),
+      mProducerListener(new DummyProducerListener),
+      mComposerClient(new SurfaceComposerClient) {
+    CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
+
+    std::shared_ptr<C2AllocatorStore> store = GetCodec2PlatformAllocatorStore();
+    CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mAllocIon), C2_OK);
+    mLinearPool = std::make_shared<C2BasicLinearBlockPool>(mAllocIon);
+
+    mControl = mComposerClient->createSurface(
+            String8("A Surface"),
+            1280,
+            800,
+            HAL_PIXEL_FORMAT_YV12);
+            //PIXEL_FORMAT_RGB_565);
+
+    CHECK(mControl != NULL);
+    CHECK(mControl->isValid());
+
+    SurfaceComposerClient::Transaction{}
+            .setLayer(mControl, INT_MAX)
+            .show(mControl)
+            .apply();
+
+    mSurface = mControl->getSurface();
+    CHECK(mSurface != NULL);
+    mSurface->connect(NATIVE_WINDOW_API_CPU, mProducerListener);
+}
+
+SimplePlayer::~SimplePlayer() {
+    mComposerClient->dispose();
+}
+
+void SimplePlayer::onWorkDone(
+        std::weak_ptr<C2Component> component, std::vector<std::unique_ptr<C2Work>> workItems) {
+    (void) component;
+    ULock l(mProcessedLock);
+    for (auto & item : workItems) {
+        mProcessedWork.push_back(std::move(item));
+    }
+    mProcessedCondition.notify_all();
+}
+
+void SimplePlayer::onTripped(
+        std::weak_ptr<C2Component> component,
+        std::vector<std::shared_ptr<C2SettingResult>> settingResult) {
+    (void) component;
+    (void) settingResult;
+    // TODO
+}
+
+void SimplePlayer::onError(std::weak_ptr<C2Component> component, uint32_t errorCode) {
+    (void) component;
+    (void) errorCode;
+    // TODO
+}
+
+void SimplePlayer::play(const sp<IMediaSource> &source) {
+    sp<AMessage> format;
+    (void) convertMetaDataToMessage(source->getFormat(), &format);
+
+    sp<ABuffer> csd0, csd1;
+    format->findBuffer("csd-0", &csd0);
+    format->findBuffer("csd-1", &csd1);
+
+    status_t err = source->start();
+
+    if (err != OK) {
+        fprintf(stderr, "source returned error %d (0x%08x)\n", err, err);
+        return;
+    }
+
+    std::unique_ptr<C2ComponentFactory> factory(CreateCodec2Factory());
+    std::shared_ptr<C2Component> component;
+    (void)factory->createComponent(&component, 0);
+    DestroyCodec2Factory(factory.release());
+
+    (void)component->setListener_sm(mListener);
+    std::unique_ptr<C2PortBlockPoolsTuning::output> pools =
+        C2PortBlockPoolsTuning::output::alloc_unique({ (uint64_t)C2BlockPool::BASIC_GRAPHIC });
+    std::vector<std::unique_ptr<C2SettingResult>> result;
+    (void)component->intf()->config_nb({pools.get()}, &result);
+    component->start();
+
+    for (int i = 0; i < 8; ++i) {
+        mWorkQueue.emplace_back(new C2Work);
+    }
+
+    std::atomic_bool running(true);
+    std::thread surfaceThread([this, &running]() {
+        const sp<IGraphicBufferProducer> &igbp = mSurface->getIGraphicBufferProducer();
+        while (running) {
+            std::unique_ptr<C2Work> work;
+            {
+                ULock l(mProcessedLock);
+                if (mProcessedWork.empty()) {
+                    mProcessedCondition.wait_for(l, 100ms);
+                    if (mProcessedWork.empty()) {
+                        continue;
+                    }
+                }
+                work.swap(mProcessedWork.front());
+                mProcessedWork.pop_front();
+            }
+            int slot;
+            sp<Fence> fence;
+            const std::shared_ptr<C2Buffer> &output = work->worklets.front()->output.buffers[0];
+            const C2ConstGraphicBlock &block = output->data().graphicBlocks().front();
+            sp<GraphicBuffer> buffer(new GraphicBuffer(
+                    block.handle(),
+                    GraphicBuffer::CLONE_HANDLE,
+                    block.width(),
+                    block.height(),
+                    HAL_PIXEL_FORMAT_YV12,
+                    1,
+                    (uint64_t)GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                    block.width()));
+
+            status_t err = igbp->attachBuffer(&slot, buffer);
+
+            IGraphicBufferProducer::QueueBufferInput qbi(
+                    work->worklets.front()->output.ordinal.timestamp * 1000ll,
+                    false,
+                    HAL_DATASPACE_UNKNOWN,
+                    Rect(block.width(), block.height()),
+                    NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
+                    0,
+                    Fence::NO_FENCE,
+                    0);
+            IGraphicBufferProducer::QueueBufferOutput qbo;
+            err = igbp->queueBuffer(slot, qbi, &qbo);
+
+            work->input.buffers.clear();
+            work->worklets.clear();
+
+            ULock l(mQueueLock);
+            mWorkQueue.push_back(std::move(work));
+            mQueueCondition.notify_all();
+        }
+    });
+
+    long numFrames = 0;
+    mLinearPool.reset(new C2BasicLinearBlockPool(mAllocIon));
+
+    for (;;) {
+        size_t size = 0u;
+        void *data = nullptr;
+        int64_t timestamp = 0u;
+        MediaBuffer *buffer = nullptr;
+        sp<ABuffer> csd;
+        if (csd0 != nullptr) {
+            csd = csd0;
+            csd0 = nullptr;
+        } else if (csd1 != nullptr) {
+            csd = csd1;
+            csd1 = nullptr;
+        } else {
+            status_t err = source->read(&buffer);
+            if (err != OK) {
+                CHECK(buffer == NULL);
+
+                if (err == INFO_FORMAT_CHANGED) {
+                    continue;
+                }
+
+                break;
+            }
+            sp<MetaData> meta = buffer->meta_data();
+            CHECK(meta->findInt64(kKeyTime, &timestamp));
+
+            size = buffer->size();
+            data = buffer->data();
+        }
+
+        if (csd != nullptr) {
+            size = csd->size();
+            data = csd->data();
+        }
+
+        // Prepare C2Work
+
+        std::unique_ptr<C2Work> work;
+        while (!work) {
+            ULock l(mQueueLock);
+            if (!mWorkQueue.empty()) {
+                work.swap(mWorkQueue.front());
+                mWorkQueue.pop_front();
+            } else {
+                mQueueCondition.wait_for(l, 100ms);
+            }
+        }
+        work->input.flags = (C2BufferPack::flags_t)0;
+        work->input.ordinal.timestamp = timestamp;
+        work->input.ordinal.frame_index = numFrames;
+
+        std::shared_ptr<C2LinearBlock> block;
+        mLinearPool->fetchLinearBlock(
+                size,
+                { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+                &block);
+        C2WriteView view = block->map().get();
+        if (view.error() != C2_OK) {
+            fprintf(stderr, "C2LinearBlock::map() failed : %d", view.error());
+            break;
+        }
+        memcpy(view.base(), data, size);
+
+        work->input.buffers.clear();
+        work->input.buffers.emplace_back(new LinearBuffer(block));
+        work->worklets.clear();
+        work->worklets.emplace_back(new C2Worklet);
+
+        std::list<std::unique_ptr<C2Work>> items;
+        items.push_back(std::move(work));
+
+        // DO THE DECODING
+        component->queue_nb(&items);
+
+        if (buffer) {
+            buffer->release();
+            buffer = NULL;
+        }
+
+        ++numFrames;
+    }
+    source->stop();
+    component->release();
+
+    running.store(false);
+    surfaceThread.join();
+    printf("\n");
+}
+
+}  // namespace
+
+static void usage(const char *me) {
+    fprintf(stderr, "usage: %s [options] [input_filename]\n", me);
+    fprintf(stderr, "       -h(elp)\n");
+}
+
+int main(int argc, char **argv) {
+    android::ProcessState::self()->startThreadPool();
+
+    int res;
+    while ((res = getopt(argc, argv, "h")) >= 0) {
+        switch (res) {
+            case 'h':
+            default:
+            {
+                usage(argv[0]);
+                exit(1);
+                break;
+            }
+        }
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    if (argc < 1) {
+        fprintf(stderr, "No input file specified\n");
+        return 1;
+    }
+
+    status_t err = OK;
+    SimplePlayer player;
+
+    for (int k = 0; k < argc && err == OK; ++k) {
+        const char *filename = argv[k];
+
+        sp<DataSource> dataSource =
+            DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
+
+        if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
+            fprintf(stderr, "Unable to create data source.\n");
+            return 1;
+        }
+
+        Vector<sp<IMediaSource> > mediaSources;
+        sp<IMediaSource> mediaSource;
+
+        sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
+
+        if (extractor == NULL) {
+            fprintf(stderr, "could not create extractor.\n");
+            return -1;
+        }
+
+        sp<MetaData> meta = extractor->getMetaData();
+
+        if (meta != NULL) {
+            const char *mime;
+            if (!meta->findCString(kKeyMIMEType, &mime)) {
+                fprintf(stderr, "extractor did not provide MIME type.\n");
+                return -1;
+            }
+        }
+
+        size_t numTracks = extractor->countTracks();
+
+        size_t i;
+        for (i = 0; i < numTracks; ++i) {
+            meta = extractor->getTrackMetaData(
+                    i, MediaExtractor::kIncludeExtensiveMetaData);
+
+            if (meta == NULL) {
+                break;
+            }
+            const char *mime;
+            meta->findCString(kKeyMIMEType, &mime);
+
+            // TODO: allowing AVC only for the time being
+            if (!strncasecmp(mime, "video/avc", 9)) {
+                break;
+            }
+
+            meta = NULL;
+        }
+
+        if (meta == NULL) {
+            fprintf(stderr, "No AVC track found.\n");
+            return -1;
+        }
+
+        mediaSource = extractor->getTrack(i);
+        if (mediaSource == nullptr) {
+            fprintf(stderr, "skip NULL track %zu, total tracks %zu.\n", i, numTracks);
+            return -1;
+        }
+
+        player.play(mediaSource);
+    }
+
+    return 0;
+}
diff --git a/media/libstagefright/codecs/flac/enc/Android.bp b/media/libstagefright/codecs/flac/enc/Android.bp
index 066917b..854f7ce 100644
--- a/media/libstagefright/codecs/flac/enc/Android.bp
+++ b/media/libstagefright/codecs/flac/enc/Android.bp
@@ -22,7 +22,6 @@
     },
 
     shared_libs: [
-        "libmedia_omx",
         "libstagefright_omx",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/codecs/g711/dec/Android.bp b/media/libstagefright/codecs/g711/dec/Android.bp
index fff72a8..07e5052 100644
--- a/media/libstagefright/codecs/g711/dec/Android.bp
+++ b/media/libstagefright/codecs/g711/dec/Android.bp
@@ -13,7 +13,7 @@
     ],
 
     shared_libs: [
-        "libmedia_omx",
+        "libstagefright_foundation",
         "libstagefright_omx",
         "libutils",
         "liblog",
diff --git a/media/libstagefright/codecs/gsm/dec/Android.bp b/media/libstagefright/codecs/gsm/dec/Android.bp
index 753eeef..0739ad4 100644
--- a/media/libstagefright/codecs/gsm/dec/Android.bp
+++ b/media/libstagefright/codecs/gsm/dec/Android.bp
@@ -27,7 +27,7 @@
     },
 
     shared_libs: [
-        "libmedia_omx",
+        "libstagefright_foundation",
         "libstagefright_omx",
         "libutils",
         "liblog",
diff --git a/media/libstagefright/codecs/hevcdec/Android.bp b/media/libstagefright/codecs/hevcdec/Android.bp
index d9a5ee3..f19ba00 100644
--- a/media/libstagefright/codecs/hevcdec/Android.bp
+++ b/media/libstagefright/codecs/hevcdec/Android.bp
@@ -32,7 +32,6 @@
     },
 
     shared_libs: [
-        "libmedia_omx",
         "libstagefright_omx",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.bp b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
index 1216ae5..e57bb78 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
@@ -93,7 +93,6 @@
     static_libs: ["libstagefright_m4vh263dec"],
 
     shared_libs: [
-        "libmedia_omx",
         "libstagefright_omx",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
index a95b807..8a3fe34 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
@@ -4,8 +4,7 @@
 
     srcs: [
         "src/bitstream_io.cpp",
-        "src/combined_encode.cpp",
-        "src/datapart_encode.cpp",
+        "src/combined_encode.cpp", "src/datapart_encode.cpp",
         "src/dct.cpp",
         "src/findhalfpel.cpp",
         "src/fastcodemb.cpp",
@@ -80,7 +79,7 @@
     static_libs: ["libstagefright_m4vh263enc"],
 
     shared_libs: [
-        "libmedia_omx",
+        "libstagefright_foundation",
         "libstagefright_omx",
         "libutils",
         "liblog",
diff --git a/media/libstagefright/codecs/mp3dec/Android.bp b/media/libstagefright/codecs/mp3dec/Android.bp
index c554a99..5a0e282 100644
--- a/media/libstagefright/codecs/mp3dec/Android.bp
+++ b/media/libstagefright/codecs/mp3dec/Android.bp
@@ -107,7 +107,6 @@
     },
 
     shared_libs: [
-        "libmedia_omx",
         "libstagefright_omx",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/codecs/mpeg2dec/Android.bp b/media/libstagefright/codecs/mpeg2dec/Android.bp
index 9590e9f..9b8a188 100644
--- a/media/libstagefright/codecs/mpeg2dec/Android.bp
+++ b/media/libstagefright/codecs/mpeg2dec/Android.bp
@@ -22,7 +22,6 @@
     ],
 
     shared_libs: [
-        "libmedia_omx",
         "libstagefright_omx",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/codecs/on2/dec/Android.bp b/media/libstagefright/codecs/on2/dec/Android.bp
index 59c1f5d..a4eed8c 100644
--- a/media/libstagefright/codecs/on2/dec/Android.bp
+++ b/media/libstagefright/codecs/on2/dec/Android.bp
@@ -15,7 +15,6 @@
     static_libs: ["libvpx"],
 
     shared_libs: [
-        "libmedia_omx",
         "libstagefright_omx",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/codecs/on2/enc/Android.bp b/media/libstagefright/codecs/on2/enc/Android.bp
index 5a52225..b21ffa1 100644
--- a/media/libstagefright/codecs/on2/enc/Android.bp
+++ b/media/libstagefright/codecs/on2/enc/Android.bp
@@ -32,7 +32,6 @@
     static_libs: ["libvpx"],
 
     shared_libs: [
-        "libmedia_omx",
         "libstagefright_omx",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.bp b/media/libstagefright/codecs/on2/h264dec/Android.bp
index 0984283..f484509 100644
--- a/media/libstagefright/codecs/on2/h264dec/Android.bp
+++ b/media/libstagefright/codecs/on2/h264dec/Android.bp
@@ -117,6 +117,7 @@
 
     shared_libs: [
         "libmedia",
+        "libmedia_omx",
         "libstagefright_omx",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/codecs/opus/dec/Android.bp b/media/libstagefright/codecs/opus/dec/Android.bp
index 88d6ec4..32a4f32 100644
--- a/media/libstagefright/codecs/opus/dec/Android.bp
+++ b/media/libstagefright/codecs/opus/dec/Android.bp
@@ -14,7 +14,6 @@
 
     shared_libs: [
         "libopus",
-        "libmedia_omx",
         "libstagefright_omx",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/codecs/tests/Android.mk b/media/libstagefright/codecs/tests/Android.mk
new file mode 100644
index 0000000..ea188ea
--- /dev/null
+++ b/media/libstagefright/codecs/tests/Android.mk
@@ -0,0 +1,40 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	C2SoftAvcDec_test.cpp \
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := c2_google_component_test
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libstagefright_codec2 \
+	libstagefright_foundation \
+	libstagefright_soft_c2avcdec \
+	liblog \
+
+LOCAL_C_INCLUDES := \
+	frameworks/av/media/libstagefright/codec2/include \
+	frameworks/av/media/libstagefright/codec2/vndk/include \
+	frameworks/av/media/libstagefright/codecs/avcdec \
+
+LOCAL_CFLAGS += -Werror -Wall -std=c++14
+LOCAL_CLANG := true
+
+include $(BUILD_NATIVE_TEST)
diff --git a/media/libstagefright/codecs/tests/C2SoftAvcDec_test.cpp b/media/libstagefright/codecs/tests/C2SoftAvcDec_test.cpp
new file mode 100644
index 0000000..d5ccb8d
--- /dev/null
+++ b/media/libstagefright/codecs/tests/C2SoftAvcDec_test.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2SoftAvcDec_test"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include <media/stagefright/foundation/MediaDefs.h>
+
+#include "C2SoftAvcDec.h"
+
+namespace android {
+
+namespace {
+
+template <class T>
+std::unique_ptr<T> alloc_unique_cstr(const char *cstr) {
+    std::unique_ptr<T> ptr = T::alloc_unique(strlen(cstr) + 1);
+    strcpy(ptr->m.mValue, cstr);
+    return ptr;
+}
+
+}  // namespace
+
+
+class C2SoftAvcDecTest : public ::testing::Test {
+public:
+    C2SoftAvcDecTest() : mIntf(new C2SoftAvcDecIntf("dummy", 0u)) {}
+    ~C2SoftAvcDecTest() = default;
+
+    template <typename T>
+    void testReadOnlyParam(const T *expected, const T *invalid);
+
+    template <typename T>
+    void testReadOnlyParamOnStack(const T *expected, const T *invalid);
+
+    template <typename T>
+    void testReadOnlyParamOnHeap(const T *expected, const T *invalid);
+
+    template <typename T>
+    void testReadOnlyFlexParam(
+            const std::unique_ptr<T> &expected, const std::unique_ptr<T> &invalid);
+
+protected:
+    std::shared_ptr<C2SoftAvcDecIntf> mIntf;
+};
+
+template <typename T>
+void C2SoftAvcDecTest::testReadOnlyParam(const T *expected, const T *invalid) {
+    testReadOnlyParamOnStack(expected, invalid);
+    testReadOnlyParamOnHeap(expected, invalid);
+}
+
+template <typename T>
+void C2SoftAvcDecTest::testReadOnlyParamOnStack(const T *expected, const T *invalid) {
+    T param;
+    ASSERT_EQ(C2_OK, mIntf->query_nb({&param}, {}, nullptr));
+    ASSERT_EQ(*expected, param);
+
+    std::vector<C2Param * const> params{ (C2Param * const)invalid };
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+    ASSERT_EQ(C2_BAD_VALUE, mIntf->config_nb(params, &failures));
+
+    // The param must not change after failed config.
+    ASSERT_EQ(C2_OK, mIntf->query_nb({&param}, {}, nullptr));
+    ASSERT_EQ(*expected, param);
+}
+
+template <typename T>
+void C2SoftAvcDecTest::testReadOnlyParamOnHeap(const T *expected, const T *invalid) {
+    std::vector<std::unique_ptr<C2Param>> heapParams;
+
+    uint32_t index = expected->type();
+    if (expected->forStream()) {
+        index |= ((expected->stream() << 17) & 0x01FE0000) | 0x02000000;
+    }
+
+    ASSERT_EQ(C2_OK, mIntf->query_nb({}, {index}, &heapParams));
+    ASSERT_EQ(1u, heapParams.size());
+    ASSERT_EQ(*expected, *heapParams[0]);
+
+    std::vector<C2Param * const> params{ (C2Param * const)invalid };
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+    ASSERT_EQ(C2_BAD_VALUE, mIntf->config_nb(params, &failures));
+
+    // The param must not change after failed config.
+    heapParams.clear();
+    ASSERT_EQ(C2_OK, mIntf->query_nb({}, {index}, &heapParams));
+    ASSERT_EQ(1u, heapParams.size());
+    ASSERT_EQ(*expected, *heapParams[0]);
+}
+
+template <typename T>
+void C2SoftAvcDecTest::testReadOnlyFlexParam(
+        const std::unique_ptr<T> &expected, const std::unique_ptr<T> &invalid) {
+    std::vector<std::unique_ptr<C2Param>> heapParams;
+
+    uint32_t index = expected->type();
+    if (expected->forStream()) {
+        index |= ((expected->stream() << 17) & 0x01FE0000) | 0x02000000;
+    }
+
+    ASSERT_EQ(C2_OK, mIntf->query_nb({}, {index}, &heapParams));
+    ASSERT_EQ(1u, heapParams.size());
+    ASSERT_EQ(*expected, *heapParams[0]);
+
+    std::vector<C2Param * const> params{ invalid.get() };
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+    ASSERT_EQ(C2_BAD_VALUE, mIntf->config_nb(params, &failures));
+
+    // The param must not change after failed config.
+    heapParams.clear();
+    ASSERT_EQ(C2_OK, mIntf->query_nb({}, {index}, &heapParams));
+    ASSERT_EQ(1u, heapParams.size());
+    ASSERT_EQ(*expected, *heapParams[0]);
+}
+
+
+TEST_F(C2SoftAvcDecTest, TestNameAndId) {
+    EXPECT_STREQ("dummy", mIntf->getName().c_str());
+    EXPECT_EQ(0u, mIntf->getId());
+}
+
+TEST_F(C2SoftAvcDecTest, TestDomainInfo) {
+    C2ComponentDomainInfo expected(C2DomainVideo);
+    C2ComponentDomainInfo invalid(C2DomainAudio);
+    testReadOnlyParam(&expected, &invalid);
+}
+
+TEST_F(C2SoftAvcDecTest, TestInputStreamCount) {
+    C2PortStreamCountConfig::input expected(1);
+    C2PortStreamCountConfig::input invalid(100);
+    testReadOnlyParam(&expected, &invalid);
+}
+
+TEST_F(C2SoftAvcDecTest, TestOutputStreamCount) {
+    C2PortStreamCountConfig::output expected(1);
+    C2PortStreamCountConfig::output invalid(100);
+    testReadOnlyParam(&expected, &invalid);
+}
+
+TEST_F(C2SoftAvcDecTest, TestInputPortMime) {
+    std::unique_ptr<C2PortMimeConfig::input> expected(
+            alloc_unique_cstr<C2PortMimeConfig::input>(MEDIA_MIMETYPE_VIDEO_AVC));
+    std::unique_ptr<C2PortMimeConfig::input> invalid(
+            alloc_unique_cstr<C2PortMimeConfig::input>(MEDIA_MIMETYPE_VIDEO_RAW));
+    testReadOnlyFlexParam(expected, invalid);
+}
+
+TEST_F(C2SoftAvcDecTest, TestOutputPortMime) {
+    std::unique_ptr<C2PortMimeConfig::output> expected(
+            alloc_unique_cstr<C2PortMimeConfig::output>(MEDIA_MIMETYPE_VIDEO_RAW));
+    std::unique_ptr<C2PortMimeConfig::output> invalid(
+            alloc_unique_cstr<C2PortMimeConfig::output>(MEDIA_MIMETYPE_VIDEO_AVC));
+    testReadOnlyFlexParam(expected, invalid);
+}
+
+TEST_F(C2SoftAvcDecTest, TestInputStreamFormat) {
+    C2StreamFormatConfig::input expected(0u, C2FormatCompressed);
+    C2StreamFormatConfig::input invalid(0u, C2FormatVideo);
+    testReadOnlyParam(&expected, &invalid);
+}
+
+TEST_F(C2SoftAvcDecTest, TestOutputStreamFormat) {
+    C2StreamFormatConfig::output expected(0u, C2FormatVideo);
+    C2StreamFormatConfig::output invalid(0u, C2FormatCompressed);
+    testReadOnlyParam(&expected, &invalid);
+}
+
+} // namespace android
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.bp b/media/libstagefright/codecs/vorbis/dec/Android.bp
index 628b36c..b7a6c1c 100644
--- a/media/libstagefright/codecs/vorbis/dec/Android.bp
+++ b/media/libstagefright/codecs/vorbis/dec/Android.bp
@@ -14,7 +14,6 @@
 
     shared_libs: [
         "libvorbisidec",
-        "libmedia_omx",
         "libstagefright_omx",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 0982006..cbb38fd 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -129,6 +129,12 @@
             dstWidth, dstHeight,
             dstCropLeft, dstCropTop, dstCropRight, dstCropBottom, mDstFormat);
 
+    if (!((src.mCropLeft & 1) == 0
+        && src.cropWidth() == dst.cropWidth()
+        && src.cropHeight() == dst.cropHeight())) {
+        return ERROR_UNSUPPORTED;
+    }
+
     status_t err;
 
     switch (mSrcFormat) {
@@ -172,12 +178,6 @@
 
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((src.mCropLeft & 1) == 0
-        && src.cropWidth() == dst.cropWidth()
-        && src.cropHeight() == dst.cropHeight())) {
-        return ERROR_UNSUPPORTED;
-    }
-
     uint16_t *dst_ptr = (uint16_t *)dst.mBits
         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
@@ -232,12 +232,6 @@
 
 status_t ColorConverter::convertYUV420PlanarUseLibYUV(
         const BitmapParams &src, const BitmapParams &dst) {
-    if (!((src.mCropLeft & 1) == 0
-            && src.cropWidth() == dst.cropWidth()
-            && src.cropHeight() == dst.cropHeight())) {
-        return ERROR_UNSUPPORTED;
-    }
-
     uint8_t *dst_ptr = (uint8_t *)dst.mBits
         + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
 
@@ -338,12 +332,6 @@
 }
 status_t ColorConverter::convertYUV420Planar(
         const BitmapParams &src, const BitmapParams &dst) {
-    if (!((src.mCropLeft & 1) == 0
-            && src.cropWidth() == dst.cropWidth()
-            && src.cropHeight() == dst.cropHeight())) {
-        return ERROR_UNSUPPORTED;
-    }
-
     uint8_t *kAdjustedClip = initClip();
 
     uint8_t *dst_ptr = (uint8_t *)dst.mBits
@@ -422,12 +410,6 @@
         const BitmapParams &src, const BitmapParams &dst) {
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((src.mCropLeft & 1) == 0
-            && src.cropWidth() == dst.cropWidth()
-            && src.cropHeight() == dst.cropHeight())) {
-        return ERROR_UNSUPPORTED;
-    }
-
     uint16_t *dst_ptr = (uint16_t *)dst.mBits
         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
@@ -496,12 +478,6 @@
 
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((src.mCropLeft & 1) == 0
-            && src.cropWidth() == dst.cropWidth()
-            && src.cropHeight() == dst.cropHeight())) {
-        return ERROR_UNSUPPORTED;
-    }
-
     uint16_t *dst_ptr = (uint16_t *)dst.mBits
         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
@@ -568,12 +544,6 @@
         const BitmapParams &src, const BitmapParams &dst) {
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((src.mCropLeft & 1) == 0
-            && src.cropWidth() == dst.cropWidth()
-            && src.cropHeight() == dst.cropHeight())) {
-        return ERROR_UNSUPPORTED;
-    }
-
     uint16_t *dst_ptr = (uint16_t *)dst.mBits
         + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index 1b9fe0f..581e51b 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
     name: "libstagefright_flacdec",
     vendor_available: true,
     vndk: {
@@ -27,10 +27,15 @@
         },
     },
 
-    static_libs: ["libFLAC"],
+    static: {
+        whole_static_libs: ["libFLAC"],
+    },
+
+    shared: {
+        static_libs: ["libFLAC"],
+    },
 
     shared_libs: [
-        "libcutils",
         "liblog",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/foundation/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp
index f8b7b41..eafdc37 100644
--- a/media/libstagefright/foundation/ANetworkSession.cpp
+++ b/media/libstagefright/foundation/ANetworkSession.cpp
@@ -33,22 +33,11 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/hexdump.h>
 
 namespace android {
 
-static uint16_t U16_AT(const uint8_t *ptr) {
-    return ptr[0] << 8 | ptr[1];
-}
-
-static uint32_t U32_AT(const uint8_t *ptr) {
-    return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
-}
-
-static uint64_t U64_AT(const uint8_t *ptr) {
-    return ((uint64_t)U32_AT(ptr)) << 32 | U32_AT(ptr + 4);
-}
-
 static const size_t kMaxUDPSize = 1500;
 static const int32_t kMaxUDPRetries = 200;
 
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 221af1d..c087a27 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -13,6 +13,8 @@
     include_dirs: [
         "frameworks/av/include",
         "frameworks/native/include",
+        "frameworks/native/libs/arect/include",
+        "frameworks/native/libs/nativebase/include",
     ],
 
     local_include_dirs: [
@@ -30,7 +32,6 @@
 
     export_shared_lib_headers: [
         "libbinder",
-        "libui",
     ],
 
     cflags: [
@@ -42,10 +43,8 @@
     shared_libs: [
         "libbinder",
         "libutils",
-        "libui",
         "libcutils",
         "liblog",
-        "libpowermanager",
     ],
 
     srcs: [
@@ -61,23 +60,18 @@
         "ANetworkSession.cpp",
         "AString.cpp",
         "AStringUtils.cpp",
-        "AWakeLock.cpp",
+        "ByteUtils.cpp",
         "ColorUtils.cpp",
         "MediaBuffer.cpp",
         "MediaBufferGroup.cpp",
+        "MediaDefs.cpp",
         "MetaData.cpp",
         "ParsedMessage.cpp",
+        "avc_utils.cpp",
         "base64.cpp",
         "hexdump.cpp",
     ],
 
-    target: {
-        vendor: {
-            exclude_shared_libs: ["libpowermanager"],
-            exclude_srcs: ["AWakeLock.cpp"],
-        },
-    },
-
     clang: true,
 
     sanitize: {
diff --git a/media/libstagefright/foundation/ByteUtils.cpp b/media/libstagefright/foundation/ByteUtils.cpp
new file mode 100644
index 0000000..14d40aa
--- /dev/null
+++ b/media/libstagefright/foundation/ByteUtils.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ByteUtils"
+
+#include <media/stagefright/foundation/ByteUtils.h>
+
+namespace android {
+
+uint16_t U16_AT(const uint8_t *ptr) {
+    return ptr[0] << 8 | ptr[1];
+}
+
+uint32_t U32_AT(const uint8_t *ptr) {
+    return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
+}
+
+uint64_t U64_AT(const uint8_t *ptr) {
+    return ((uint64_t)U32_AT(ptr)) << 32 | U32_AT(ptr + 4);
+}
+
+uint16_t U16LE_AT(const uint8_t *ptr) {
+    return ptr[0] | (ptr[1] << 8);
+}
+
+uint32_t U32LE_AT(const uint8_t *ptr) {
+    return ptr[3] << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0];
+}
+
+uint64_t U64LE_AT(const uint8_t *ptr) {
+    return ((uint64_t)U32LE_AT(ptr + 4)) << 32 | U32LE_AT(ptr);
+}
+
+// XXX warning: these won't work on big-endian host.
+uint64_t ntoh64(uint64_t x) {
+    return ((uint64_t)ntohl(x & 0xffffffff) << 32) | ntohl(x >> 32);
+}
+
+uint64_t hton64(uint64_t x) {
+    return ((uint64_t)htonl(x & 0xffffffff) << 32) | htonl(x >> 32);
+}
+
+void MakeFourCCString(uint32_t x, char *s) {
+    s[0] = x >> 24;
+    s[1] = (x >> 16) & 0xff;
+    s[2] = (x >> 8) & 0xff;
+    s[3] = x & 0xff;
+    s[4] = '\0';
+}
+
+}  // namespace android
diff --git a/media/libmedia/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
similarity index 94%
rename from media/libmedia/MediaDefs.cpp
rename to media/libstagefright/foundation/MediaDefs.cpp
index 544a6ae..1695c75 100644
--- a/media/libmedia/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-#include <media/MediaDefs.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 
 namespace android {
 
 const char *MEDIA_MIMETYPE_IMAGE_JPEG = "image/jpeg";
+const char *MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC = "image/vnd.android.heic";
 
 const char *MEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
 const char *MEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
@@ -58,6 +59,7 @@
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS = "video/mp2ts";
 const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS = "video/mp2p";
+const char *MEDIA_MIMETYPE_CONTAINER_HEIF = "image/heif";
 
 const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt";
 const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/foundation/avc_utils.cpp
similarity index 98%
rename from media/libstagefright/avc_utils.cpp
rename to media/libstagefright/foundation/avc_utils.cpp
index b75b468..bfaeb21 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/foundation/avc_utils.cpp
@@ -18,10 +18,10 @@
 #define LOG_TAG "avc_utils"
 #include <utils/Log.h>
 
-#include "include/avc_utils.h"
 
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
@@ -468,11 +468,9 @@
     return meta;
 }
 
-template <typename T>
-bool IsIDRInternal(const sp<T> &buffer) {
-    const uint8_t *data = buffer->data();
-    size_t size = buffer->size();
-
+bool IsIDR(const uint8_t *data, size_t size) {
+//    const uint8_t *data = buffer->data();
+//    size_t size = buffer->size();
     bool foundIDR = false;
 
     const uint8_t *nalStart;
@@ -494,14 +492,6 @@
     return foundIDR;
 }
 
-bool IsIDR(const sp<ABuffer> &buffer) {
-    return IsIDRInternal(buffer);
-}
-
-bool IsIDR(const sp<MediaCodecBuffer> &buffer) {
-    return IsIDRInternal(buffer);
-}
-
 bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit) {
     const uint8_t *data = accessUnit->data();
     size_t size = accessUnit->size();
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/ByteUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ByteUtils.h
new file mode 100644
index 0000000..dc4125f
--- /dev/null
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ByteUtils.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BYTE_UTILS_H
+
+#define BYTE_UTILS_H
+
+#include <arpa/inet.h>
+
+namespace android {
+
+#define FOURCC(c1, c2, c3, c4) \
+    ((c1) << 24 | (c2) << 16 | (c3) << 8 | (c4))
+
+uint16_t U16_AT(const uint8_t *ptr);
+uint32_t U32_AT(const uint8_t *ptr);
+uint64_t U64_AT(const uint8_t *ptr);
+
+uint16_t U16LE_AT(const uint8_t *ptr);
+uint32_t U32LE_AT(const uint8_t *ptr);
+uint64_t U64LE_AT(const uint8_t *ptr);
+
+uint64_t ntoh64(uint64_t x);
+uint64_t hton64(uint64_t x);
+
+void MakeFourCCString(uint32_t x, char *s);
+
+}  // namespace android
+
+#endif  // BYTE_UTILS_H
+
diff --git a/media/libmedia/include/media/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
similarity index 96%
rename from media/libmedia/include/media/MediaDefs.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index 7f17013..25be89f 100644
--- a/media/libmedia/include/media/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -21,6 +21,7 @@
 namespace android {
 
 extern const char *MEDIA_MIMETYPE_IMAGE_JPEG;
+extern const char *MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC;
 
 extern const char *MEDIA_MIMETYPE_VIDEO_VP8;
 extern const char *MEDIA_MIMETYPE_VIDEO_VP9;
@@ -60,6 +61,7 @@
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS;
 extern const char *MEDIA_MIMETYPE_CONTAINER_AVI;
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS;
+extern const char *MEDIA_MIMETYPE_CONTAINER_HEIF;
 
 extern const char *MEDIA_MIMETYPE_TEXT_3GPP;
 extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP;
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
similarity index 97%
rename from media/libstagefright/include/avc_utils.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
index d05906a..f4eb692 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
@@ -84,8 +84,7 @@
 class MetaData;
 sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit);
 
-bool IsIDR(const sp<ABuffer> &accessUnit);
-bool IsIDR(const sp<MediaCodecBuffer> &accessUnit);
+bool IsIDR(const uint8_t *data, size_t size);
 bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit);
 uint32_t FindAVCLayerId(const uint8_t *data, size_t size);
 
diff --git a/media/libstagefright/foundation/tests/Utils_test.cpp b/media/libstagefright/foundation/tests/Utils_test.cpp
index 0439d5c..fc2e044 100644
--- a/media/libstagefright/foundation/tests/Utils_test.cpp
+++ b/media/libstagefright/foundation/tests/Utils_test.cpp
@@ -22,7 +22,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AStringUtils.h>
 #include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/Utils.h> // for FOURCC
+#include <media/stagefright/foundation/ByteUtils.h> // for FOURCC
 
 namespace android {
 
diff --git a/media/libstagefright/http/Android.bp b/media/libstagefright/http/Android.bp
index 5d90b0a..2e49fc4 100644
--- a/media/libstagefright/http/Android.bp
+++ b/media/libstagefright/http/Android.bp
@@ -12,7 +12,6 @@
     shared_libs: [
         "liblog",
         "libutils",
-        "libbinder",
         "libandroid_runtime",
         "libmedia",
     ],
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index e415334..ac113b8 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -36,8 +36,18 @@
         "libcrypto",
         "libcutils",
         "libmedia",
+        "libmediaextractor",
         "libstagefright",
         "libstagefright_foundation",
         "libutils",
+        "libhidlbase",
+        "android.hardware.cas@1.0",
+        "android.hardware.cas.native@1.0",
     ],
+
+    static_libs: [
+        "libstagefright_id3",
+        "libstagefright_mpeg2support",
+    ],
+
 }
diff --git a/media/libstagefright/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index 793695a..3fef764 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -21,12 +21,12 @@
 #include "HTTPDownloader.h"
 #include "M3UParser.h"
 
+#include <media/DataSource.h>
 #include <media/IMediaHTTPConnection.h>
 #include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaHTTP.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
 #include <openssl/aes.h>
 #include <openssl/md5.h>
diff --git a/media/libstagefright/httplive/LiveDataSource.h b/media/libstagefright/httplive/LiveDataSource.h
index b7be637..91e9f9f 100644
--- a/media/libstagefright/httplive/LiveDataSource.h
+++ b/media/libstagefright/httplive/LiveDataSource.h
@@ -18,8 +18,8 @@
 
 #define LIVE_DATA_SOURCE_H_
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/DataSource.h>
 #include <utils/threads.h>
 #include <utils/List.h>
 
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 143fd59..4c2e0d4 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -49,6 +49,10 @@
 const int64_t LiveSession::kUpSwitchMarginUs = 5000000ll;
 const int64_t LiveSession::kResumeThresholdUs = 100000ll;
 
+//TODO: redefine this mark to a fair value
+// default buffer underflow mark
+static const int kUnderflowMarkMs = 1000;  // 1 second
+
 struct LiveSession::BandwidthEstimator : public RefBase {
     BandwidthEstimator();
 
@@ -840,7 +844,7 @@
                     // (If we don't have that cushion we'd rather cancel and try again.)
                     int64_t delayUs =
                         switchUp ?
-                            (mBufferingSettings.mRebufferingWatermarkLowMs * 1000ll + 1000000ll)
+                            (kUnderflowMarkMs * 1000ll + 1000000ll)
                             : 0;
                     bool needResumeUntil = false;
                     sp<AMessage> stopParams = msg;
@@ -2202,14 +2206,14 @@
         ++activeCount;
         int64_t readyMarkUs =
             (mInPreparationPhase ?
-                mBufferingSettings.mInitialWatermarkMs :
-                mBufferingSettings.mRebufferingWatermarkHighMs) * 1000ll;
+                mBufferingSettings.mInitialMarkMs :
+                mBufferingSettings.mResumePlaybackMarkMs) * 1000ll;
         if (bufferedDurationUs > readyMarkUs
                 || mPacketSources[i]->isFinished(0)) {
             ++readyCount;
         }
         if (!mPacketSources[i]->isFinished(0)) {
-            if (bufferedDurationUs < mBufferingSettings.mRebufferingWatermarkLowMs * 1000ll) {
+            if (bufferedDurationUs < kUnderflowMarkMs * 1000ll) {
                 ++underflowCount;
             }
             if (bufferedDurationUs > mUpSwitchMark) {
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 71feb9a..71d625f 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -23,6 +23,7 @@
 #include <cutils/properties.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 00cf142..b46694b 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -23,7 +23,6 @@
 #include "HTTPDownloader.h"
 #include "LiveSession.h"
 #include "M3UParser.h"
-#include "include/avc_utils.h"
 #include "include/ID3.h"
 #include "mpeg2ts/AnotherPacketSource.h"
 #include "mpeg2ts/HlsSampleDecryptor.h"
@@ -31,6 +30,8 @@
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
@@ -1828,7 +1829,7 @@
                             (long long)timeUs - mStartTimeUs,
                             mIDRFound);
                     if (isAvc) {
-                        if (IsIDR(accessUnit)) {
+                        if (IsIDR(accessUnit->data(), accessUnit->size())) {
                             mVideoBuffer->clear();
                             FSLOGV(stream, "found IDR, clear mVideoBuffer");
                             mIDRFound = true;
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 58d8b13..61403be 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -20,9 +20,9 @@
 
 #include "../include/ID3.h"
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <utils/String8.h>
 #include <byteswap.h>
 
diff --git a/media/libstagefright/include/AVIExtractor.h b/media/libstagefright/include/AVIExtractor.h
index 3be505c..1223c80 100644
--- a/media/libstagefright/include/AVIExtractor.h
+++ b/media/libstagefright/include/AVIExtractor.h
@@ -18,9 +18,9 @@
 
 #define AVI_EXTRACTOR_H_
 
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
 #include <utils/Vector.h>
 
 namespace android {
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index 0d775e6..9f413cd 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_CALLBACKDATASOURCE_H
 #define ANDROID_CALLBACKDATASOURCE_H
 
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 
 namespace android {
diff --git a/media/libstagefright/include/FrameDecoder.h b/media/libstagefright/include/FrameDecoder.h
new file mode 100644
index 0000000..d7c074c
--- /dev/null
+++ b/media/libstagefright/include/FrameDecoder.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAME_DECODER_H_
+#define FRAME_DECODER_H_
+
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/MediaSource.h>
+#include <media/openmax/OMX_Video.h>
+#include <system/graphics-base.h>
+
+namespace android {
+
+struct AMessage;
+class MediaCodecBuffer;
+class VideoFrame;
+
+struct FrameDecoder {
+    FrameDecoder(
+            const AString &componentName,
+            const sp<MetaData> &trackMeta,
+            const sp<IMediaSource> &source) :
+                mComponentName(componentName),
+                mTrackMeta(trackMeta),
+                mSource(source),
+                mDstFormat(OMX_COLOR_Format16bitRGB565),
+                mDstBpp(2) {}
+
+    VideoFrame* extractFrame(
+            int64_t frameTimeUs,
+            int option,
+            int colorFormat,
+            bool metaOnly);
+
+    status_t extractFrames(
+            int64_t frameTimeUs,
+            size_t numFrames,
+            int option,
+            int colorFormat,
+            std::vector<VideoFrame*>* frames);
+
+protected:
+    virtual ~FrameDecoder() {}
+
+    virtual sp<AMessage> onGetFormatAndSeekOptions(
+            int64_t frameTimeUs,
+            size_t numFrames,
+            int seekMode,
+            MediaSource::ReadOptions *options) = 0;
+
+    virtual status_t onInputReceived(
+            const sp<MediaCodecBuffer> &codecBuffer,
+            const sp<MetaData> &sampleMeta,
+            bool firstSample,
+            uint32_t *flags) = 0;
+
+    virtual status_t onOutputReceived(
+            const sp<MediaCodecBuffer> &videoFrameBuffer,
+            const sp<AMessage> &outputFormat,
+            int64_t timeUs,
+            bool *done) = 0;
+
+    VideoFrame *allocVideoFrame(int32_t width, int32_t height, bool metaOnly);
+
+    sp<MetaData> trackMeta()     const      { return mTrackMeta; }
+    OMX_COLOR_FORMATTYPE dstFormat() const  { return mDstFormat; }
+    int32_t dstBpp()             const      { return mDstBpp; }
+
+    void addFrame(VideoFrame *frame) {
+        mFrames.push_back(std::unique_ptr<VideoFrame>(frame));
+    }
+
+private:
+    AString mComponentName;
+    sp<MetaData> mTrackMeta;
+    sp<IMediaSource> mSource;
+    OMX_COLOR_FORMATTYPE mDstFormat;
+    int32_t mDstBpp;
+    std::vector<std::unique_ptr<VideoFrame> > mFrames;
+
+    bool setDstColorFormat(android_pixel_format_t colorFormat);
+    status_t extractInternal(int64_t frameTimeUs, size_t numFrames, int option);
+
+    DISALLOW_EVIL_CONSTRUCTORS(FrameDecoder);
+};
+
+struct VideoFrameDecoder : public FrameDecoder {
+    VideoFrameDecoder(
+            const AString &componentName,
+            const sp<MetaData> &trackMeta,
+            const sp<IMediaSource> &source) :
+                FrameDecoder(componentName, trackMeta, source),
+                mIsAvcOrHevc(false),
+                mSeekMode(MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC),
+                mTargetTimeUs(-1ll),
+                mNumFrames(0),
+                mNumFramesDecoded(0) {}
+
+protected:
+    virtual sp<AMessage> onGetFormatAndSeekOptions(
+            int64_t frameTimeUs,
+            size_t numFrames,
+            int seekMode,
+            MediaSource::ReadOptions *options) override;
+
+    virtual status_t onInputReceived(
+            const sp<MediaCodecBuffer> &codecBuffer,
+            const sp<MetaData> &sampleMeta,
+            bool firstSample,
+            uint32_t *flags) override;
+
+    virtual status_t onOutputReceived(
+            const sp<MediaCodecBuffer> &videoFrameBuffer,
+            const sp<AMessage> &outputFormat,
+            int64_t timeUs,
+            bool *done) override;
+
+private:
+    bool mIsAvcOrHevc;
+    MediaSource::ReadOptions::SeekMode mSeekMode;
+    int64_t mTargetTimeUs;
+    size_t mNumFrames;
+    size_t mNumFramesDecoded;
+};
+
+struct ImageDecoder : public FrameDecoder {
+    ImageDecoder(
+            const AString &componentName,
+            const sp<MetaData> &trackMeta,
+            const sp<IMediaSource> &source) :
+                FrameDecoder(componentName, trackMeta, source),
+                mFrame(NULL), mGridRows(1), mGridCols(1), mTilesDecoded(0) {}
+
+protected:
+    virtual sp<AMessage> onGetFormatAndSeekOptions(
+            int64_t frameTimeUs,
+            size_t numFrames,
+            int seekMode,
+            MediaSource::ReadOptions *options) override;
+
+    virtual status_t onInputReceived(
+            const sp<MediaCodecBuffer> &codecBuffer __unused,
+            const sp<MetaData> &sampleMeta __unused,
+            bool firstSample __unused,
+            uint32_t *flags __unused) override { return OK; }
+
+    virtual status_t onOutputReceived(
+            const sp<MediaCodecBuffer> &videoFrameBuffer,
+            const sp<AMessage> &outputFormat,
+            int64_t timeUs,
+            bool *done) override;
+
+private:
+    VideoFrame *mFrame;
+    int32_t mGridRows;
+    int32_t mGridCols;
+    int32_t mTilesDecoded;
+};
+
+}  // namespace android
+
+#endif  // FRAME_DECODER_H_
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index d325e30..26d7e8a 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -18,8 +18,8 @@
 
 #define HTTP_BASE_H_
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <utils/threads.h>
 
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index 2639280..1a34817 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -18,9 +18,9 @@
 
 #define NU_CACHED_SOURCE_2_H_
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AHandlerReflector.h>
-#include <media/stagefright/DataSource.h>
 
 namespace android {
 
diff --git a/media/libstagefright/include/OmxNodeOwner.h b/media/libstagefright/include/OmxNodeOwner.h
deleted file mode 100644
index 64ec7f7..0000000
--- a/media/libstagefright/include/OmxNodeOwner.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef OMX_NODE_OWNER_H_
-
-#define OMX_NODE_OWNER_H_
-
-namespace android {
-
-struct OMXNodeInstance;
-
-/**
- * This struct is needed to separate OMX from OMXNodeInstance.
- *
- * TODO: This might not be needed after Treble transition is complete.
- */
-struct OmxNodeOwner {
-    virtual status_t freeNode(const sp<OMXNodeInstance> &instance) = 0;
-    virtual ~OmxNodeOwner() {}
-};
-
-}
-
-#endif  // OMX_NODE_OWNER_H_
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index 277eb3e..58442fe 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -40,7 +40,14 @@
     virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
     virtual status_t setDataSource(const sp<DataSource>& source, const char *mime);
 
-    virtual VideoFrame *getFrameAtTime(int64_t timeUs, int option, int colorFormat, bool metaOnly);
+    virtual VideoFrame* getFrameAtTime(
+            int64_t timeUs, int option, int colorFormat, bool metaOnly);
+    virtual VideoFrame* getImageAtIndex(
+            int index, int colorFormat, bool metaOnly);
+    virtual status_t getFrameAtIndex(
+            std::vector<VideoFrame*>* frames,
+            int frameIndex, int numFrames, int colorFormat, bool metaOnly);
+
     virtual MediaAlbumArt *extractAlbumArt();
     virtual const char *extractMetadata(int keyCode);
 
@@ -56,6 +63,10 @@
     // Delete album art and clear metadata.
     void clearMetadata();
 
+    status_t getFrameInternal(
+            int64_t timeUs, int numFrames, int option, int colorFormat, bool metaOnly,
+            VideoFrame **outFrame, std::vector<VideoFrame*>* outFrames);
+
     StagefrightMetadataRetriever(const StagefrightMetadataRetriever &);
 
     StagefrightMetadataRetriever &operator=(
diff --git a/media/libstagefright/include/ThrottledSource.h b/media/libstagefright/include/ThrottledSource.h
index 673268b..8ef298a 100644
--- a/media/libstagefright/include/ThrottledSource.h
+++ b/media/libstagefright/include/ThrottledSource.h
@@ -18,7 +18,7 @@
 
 #define THROTTLED_SOURCE_H_
 
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
 #include <utils/threads.h>
 
 namespace android {
diff --git a/media/libstagefright/include/media/stagefright/AACWriter.h b/media/libstagefright/include/media/stagefright/AACWriter.h
index a1f63d7..aa60a19 100644
--- a/media/libstagefright/include/media/stagefright/AACWriter.h
+++ b/media/libstagefright/include/media/stagefright/AACWriter.h
@@ -31,7 +31,7 @@
 
     status_t initCheck() const;
 
-    virtual status_t addSource(const sp<IMediaSource> &source);
+    virtual status_t addSource(const sp<MediaSource> &source);
     virtual bool reachedEOS();
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop() { return reset(); }
@@ -48,7 +48,7 @@
 
     int   mFd;
     status_t mInitCheck;
-    sp<IMediaSource> mSource;
+    sp<MediaSource> mSource;
     bool mStarted;
     volatile bool mPaused;
     volatile bool mResumed;
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 424246d..d1a9d25 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -95,11 +95,6 @@
 
     static status_t getOMXChannelMapping(size_t numChannels, OMX_AUDIO_CHANNELTYPE map[]);
 
-    // Save the flag.
-    void setTrebleFlag(bool trebleFlag);
-    // Return the saved flag.
-    bool getTrebleFlag() const;
-
 protected:
     virtual ~ACodec();
 
@@ -233,9 +228,7 @@
     sp<IOMX> mOMX;
     sp<IOMXNode> mOMXNode;
     int32_t mNodeGeneration;
-    bool mTrebleFlag;
     sp<TAllocator> mAllocator[2];
-    sp<MemoryDealer> mDealer[2];
 
     bool mUsingNativeWindow;
     sp<ANativeWindow> mNativeWindow;
diff --git a/media/libstagefright/include/media/stagefright/AMRWriter.h b/media/libstagefright/include/media/stagefright/AMRWriter.h
index fbbdf2e..7d2c879 100644
--- a/media/libstagefright/include/media/stagefright/AMRWriter.h
+++ b/media/libstagefright/include/media/stagefright/AMRWriter.h
@@ -20,7 +20,6 @@
 
 #include <stdio.h>
 
-#include <media/IMediaSource.h>
 #include <media/stagefright/MediaWriter.h>
 #include <utils/threads.h>
 
@@ -33,7 +32,7 @@
 
     status_t initCheck() const;
 
-    virtual status_t addSource(const sp<IMediaSource> &source);
+    virtual status_t addSource(const sp<MediaSource> &source);
     virtual bool reachedEOS();
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop() { return reset(); }
@@ -45,7 +44,7 @@
 private:
     int   mFd;
     status_t mInitCheck;
-    sp<IMediaSource> mSource;
+    sp<MediaSource> mSource;
     bool mStarted;
     volatile bool mPaused;
     volatile bool mResumed;
diff --git a/media/libstagefright/include/media/stagefright/AudioPlayer.h b/media/libstagefright/include/media/stagefright/AudioPlayer.h
index f7499b6..e971762 100644
--- a/media/libstagefright/include/media/stagefright/AudioPlayer.h
+++ b/media/libstagefright/include/media/stagefright/AudioPlayer.h
@@ -18,7 +18,7 @@
 
 #define AUDIO_PLAYER_H_
 
-#include <media/IMediaSource.h>
+#include <media/MediaSource.h>
 #include <media/MediaPlayerInterface.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <utils/threads.h>
@@ -50,7 +50,7 @@
     virtual ~AudioPlayer();
 
     // Caller retains ownership of "source".
-    void setSource(const sp<IMediaSource> &source);
+    void setSource(const sp<MediaSource> &source);
 
     status_t start(bool sourceAlreadyStarted = false);
 
@@ -66,7 +66,7 @@
     status_t getPlaybackRate(AudioPlaybackRate *rate /* nonnull */);
 
 private:
-    sp<IMediaSource> mSource;
+    sp<MediaSource> mSource;
     sp<AudioTrack> mAudioTrack;
 
     MediaBuffer *mInputBuffer;
diff --git a/media/libstagefright/include/media/stagefright/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
index 1595be4..9414aab 100644
--- a/media/libstagefright/include/media/stagefright/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -20,7 +20,7 @@
 
 #include <media/AudioRecord.h>
 #include <media/AudioSystem.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <utils/List.h>
 
@@ -40,7 +40,8 @@
             uint32_t channels,
             uint32_t outSampleRate = 0,
             uid_t uid = -1,
-            pid_t pid = -1);
+            pid_t pid = -1,
+            audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
 
     status_t initCheck() const;
 
@@ -58,6 +59,11 @@
     status_t dataCallback(const AudioRecord::Buffer& buffer);
     virtual void signalBufferReturned(MediaBuffer *buffer);
 
+    status_t setInputDevice(audio_port_handle_t deviceId);
+    status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
+    status_t addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+    status_t removeAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+
 protected:
     virtual ~AudioSource();
 
diff --git a/media/libstagefright/include/media/stagefright/CallbackMediaSource.h b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
new file mode 100644
index 0000000..a09348f
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CALLBACK_MEDIA_SOURCE_H_
+#define CALLBACK_MEDIA_SOURCE_H_
+
+#include <media/MediaSource.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+// A stagefright MediaSource that wraps a binder IMediaSource.
+class CallbackMediaSource : public MediaSource {
+public:
+    explicit CallbackMediaSource(const sp<IMediaSource> &source);
+    virtual ~CallbackMediaSource();
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+    virtual sp<MetaData> getFormat();
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL);
+    virtual status_t pause();
+    virtual status_t setBuffers(const Vector<MediaBuffer *> &buffers);
+
+private:
+    sp<IMediaSource> mSource;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CallbackMediaSource);
+};
+
+}  // namespace android
+
+#endif  // CALLBACK_MEDIA_SOURCE_H_
diff --git a/media/libstagefright/include/media/stagefright/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
index d6149c0..945e1be 100644
--- a/media/libstagefright/include/media/stagefright/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -19,8 +19,8 @@
 #define CAMERA_SOURCE_H_
 
 #include <deque>
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaSource.h>
 #include <camera/android/hardware/ICamera.h>
 #include <camera/ICameraRecordingProxy.h>
 #include <camera/ICameraRecordingProxyListener.h>
diff --git a/media/libstagefright/include/media/stagefright/DataSourceFactory.h b/media/libstagefright/include/media/stagefright/DataSourceFactory.h
new file mode 100644
index 0000000..89add13
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/DataSourceFactory.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DATA_SOURCE_FACTORY_H_
+
+#define DATA_SOURCE_FACTORY_H_
+
+#include <sys/types.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct IMediaHTTPService;
+class String8;
+struct HTTPBase;
+
+class DataSourceFactory {
+public:
+    static sp<DataSource> CreateFromURI(
+            const sp<IMediaHTTPService> &httpService,
+            const char *uri,
+            const KeyedVector<String8, String8> *headers = NULL,
+            String8 *contentType = NULL,
+            HTTPBase *httpSource = NULL);
+
+    static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
+    static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
+};
+
+}  // namespace android
+
+#endif  // DATA_SOURCE_FACTORY_H_
diff --git a/media/libstagefright/include/media/stagefright/DataURISource.h b/media/libstagefright/include/media/stagefright/DataURISource.h
index 693562e..cf8d68e 100644
--- a/media/libstagefright/include/media/stagefright/DataURISource.h
+++ b/media/libstagefright/include/media/stagefright/DataURISource.h
@@ -18,7 +18,7 @@
 
 #define DATA_URI_SOURCE_H_
 
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/ABase.h>
 
 namespace android {
diff --git a/media/libstagefright/include/media/stagefright/FileSource.h b/media/libstagefright/include/media/stagefright/FileSource.h
index 7267e9a..b4b5c3c 100644
--- a/media/libstagefright/include/media/stagefright/FileSource.h
+++ b/media/libstagefright/include/media/stagefright/FileSource.h
@@ -20,7 +20,7 @@
 
 #include <stdio.h>
 
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <utils/threads.h>
 #include <drm/DrmManagerClient.h>
diff --git a/media/libstagefright/include/media/stagefright/InterfaceUtils.h b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
new file mode 100644
index 0000000..783f109
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INTERFACE_UTILS_H_
+#define INTERFACE_UTILS_H_
+
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
+#include <media/IMediaExtractor.h>
+#include <media/IMediaSource.h>
+
+namespace android {
+
+// Creates a DataSource which wraps the given IDataSource object.
+sp<DataSource> CreateDataSourceFromIDataSource(const sp<IDataSource> &source);
+
+// creates an IDataSource wrapper to the DataSource.
+sp<IDataSource> CreateIDataSourceFromDataSource(const sp<DataSource> &source);
+
+// Creates an IMediaExtractor wrapper to the given MediaExtractor.
+sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(const sp<MediaExtractor> &extractor);
+
+// Creates a MediaSource which wraps the given IMediaSource object.
+sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source);
+
+// Creates an IMediaSource wrapper to the given MediaSource.
+sp<IMediaSource> CreateIMediaSourceFromMediaSource(const sp<MediaSource> &source);
+
+}  // namespace android
+
+#endif  // INTERFACE_UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/JPEGSource.h b/media/libstagefright/include/media/stagefright/JPEGSource.h
index 1b7e91b..9fcbfc2 100644
--- a/media/libstagefright/include/media/stagefright/JPEGSource.h
+++ b/media/libstagefright/include/media/stagefright/JPEGSource.h
@@ -18,7 +18,7 @@
 
 #define JPEG_SOURCE_H_
 
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 
 namespace android {
 
diff --git a/media/libstagefright/include/media/stagefright/MPEG2TSWriter.h b/media/libstagefright/include/media/stagefright/MPEG2TSWriter.h
index 4516fb6..3d7960b 100644
--- a/media/libstagefright/include/media/stagefright/MPEG2TSWriter.h
+++ b/media/libstagefright/include/media/stagefright/MPEG2TSWriter.h
@@ -34,7 +34,7 @@
             void *cookie,
             ssize_t (*write)(void *cookie, const void *data, size_t size));
 
-    virtual status_t addSource(const sp<IMediaSource> &source);
+    virtual status_t addSource(const sp<MediaSource> &source);
     virtual status_t start(MetaData *param = NULL);
     virtual status_t stop() { return reset(); }
     virtual status_t pause();
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 1c7b4a6..5d2c120 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -20,7 +20,6 @@
 
 #include <stdio.h>
 
-#include <media/IMediaSource.h>
 #include <media/stagefright/MediaWriter.h>
 #include <utils/List.h>
 #include <utils/threads.h>
@@ -32,6 +31,7 @@
 struct AMessage;
 class MediaBuffer;
 class MetaData;
+struct ABuffer;
 
 class MPEG4Writer : public MediaWriter {
 public:
@@ -40,7 +40,7 @@
     // Limitations
     // No more than one video and/or one audio source can be added, but
     // multiple metadata sources can be added.
-    virtual status_t addSource(const sp<IMediaSource> &source);
+    virtual status_t addSource(const sp<MediaSource> &source);
 
     // Returns INVALID_OPERATION if there is no source or track.
     virtual status_t start(MetaData *param = NULL);
@@ -101,12 +101,12 @@
     bool mSendNotify;
     off64_t mOffset;
     off_t mMdatOffset;
-    uint8_t *mMoovBoxBuffer;
-    off64_t mMoovBoxBufferOffset;
-    bool  mWriteMoovBoxToMemory;
+    uint8_t *mInMemoryCache;
+    off64_t mInMemoryCacheOffset;
+    off64_t mInMemoryCacheSize;
+    bool  mWriteBoxToMemory;
     off64_t mFreeBoxOffset;
     bool mStreamableFile;
-    off64_t mEstimatedMoovBoxSize;
     off64_t mMoovExtraSize;
     uint32_t mInterleaveDurationUs;
     int32_t mTimeScale;
@@ -133,6 +133,8 @@
     status_t startTracks(MetaData *params);
     size_t numTracks();
     int64_t estimateMoovBoxSize(int32_t bitRate);
+    int64_t estimateFileLevelMetaSize();
+    void writeCachedBoxToFile(const char *type);
 
     struct Chunk {
         Track               *mTrack;        // Owner
@@ -165,6 +167,46 @@
     List<ChunkInfo> mChunkInfos;            // Chunk infos
     Condition       mChunkReadyCondition;   // Signal that chunks are available
 
+    // HEIF writing
+    typedef struct _ItemInfo {
+        bool isGrid() const { return !strcmp("grid", itemType); }
+        const char *itemType;
+        uint16_t itemId;
+        bool isPrimary;
+        bool isHidden;
+        union {
+            // image item
+            struct {
+                uint32_t offset;
+                uint32_t size;
+            };
+            // grid item
+            struct {
+                uint32_t rows;
+                uint32_t cols;
+                uint32_t width;
+                uint32_t height;
+            };
+        };
+        Vector<uint16_t> properties;
+        Vector<uint16_t> dimgRefs;
+    } ItemInfo;
+
+    typedef struct _ItemProperty {
+        uint32_t type;
+        int32_t width;
+        int32_t height;
+        sp<ABuffer> hvcc;
+    } ItemProperty;
+
+    bool mHasFileLevelMeta;
+    bool mHasMoovBox;
+    uint32_t mPrimaryItemId;
+    uint32_t mAssociationEntryCount;
+    uint32_t mNumGrids;
+    Vector<ItemInfo> mItems;
+    Vector<ItemProperty> mProperties;
+
     // Writer thread handling
     status_t startWriterThread();
     void stopWriterThread();
@@ -210,9 +252,11 @@
     void initInternal(int fd, bool isFirstSession);
 
     // Acquire lock before calling these methods
-    off64_t addSample_l(MediaBuffer *buffer);
-    off64_t addLengthPrefixedSample_l(MediaBuffer *buffer);
-    off64_t addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer);
+    off64_t addSample_l(MediaBuffer *buffer, bool usePrefix, size_t *bytesWritten);
+    void addLengthPrefixedSample_l(MediaBuffer *buffer);
+    void addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer);
+    uint16_t addProperty_l(const ItemProperty &);
+    uint16_t addItem_l(const ItemInfo &);
 
     bool exceedsFileSizeLimit();
     bool use32BitFileOffset() const;
@@ -231,10 +275,23 @@
     void finishCurrentSession();
 
     void addDeviceMeta();
-    void writeHdlr();
+    void writeHdlr(const char *handlerType);
     void writeKeys();
     void writeIlst();
-    void writeMetaBox();
+    void writeMoovLevelMetaBox();
+
+    // HEIF writing
+    void writeIlocBox();
+    void writeInfeBox(uint16_t itemId, const char *type, uint32_t flags);
+    void writeIinfBox();
+    void writeIpcoBox();
+    void writeIpmaBox();
+    void writeIprpBox();
+    void writeIdatBox();
+    void writeIrefBox();
+    void writePitmBox();
+    void writeFileLevelMetaBox();
+
     void sendSessionSummary();
     void release();
     status_t switchFd();
diff --git a/media/libstagefright/include/media/stagefright/MediaAdapter.h b/media/libstagefright/include/media/stagefright/MediaAdapter.h
index 369fce6..4b47160 100644
--- a/media/libstagefright/include/media/stagefright/MediaAdapter.h
+++ b/media/libstagefright/include/media/stagefright/MediaAdapter.h
@@ -17,8 +17,8 @@
 #ifndef MEDIA_ADAPTER_H
 #define MEDIA_ADAPTER_H
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/threads.h>
diff --git a/media/libstagefright/include/media/stagefright/MediaClock.h b/media/libstagefright/include/media/stagefright/MediaClock.h
index dd1a809..7511913 100644
--- a/media/libstagefright/include/media/stagefright/MediaClock.h
+++ b/media/libstagefright/include/media/stagefright/MediaClock.h
@@ -18,7 +18,8 @@
 
 #define MEDIA_CLOCK_H_
 
-#include <media/stagefright/foundation/ABase.h>
+#include <list>
+#include <media/stagefright/foundation/AHandler.h>
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
 
@@ -26,8 +27,14 @@
 
 struct AMessage;
 
-struct MediaClock : public RefBase {
+struct MediaClock : public AHandler {
+    enum {
+        TIMER_REASON_REACHED = 0,
+        TIMER_REASON_RESET = 1,
+    };
+
     MediaClock();
+    void init();
 
     void setStartingTimeMedia(int64_t startingTimeMediaUs);
 
@@ -54,15 +61,38 @@
     // The result is saved in |outRealUs|.
     status_t getRealTimeFor(int64_t targetMediaUs, int64_t *outRealUs) const;
 
+    // request to set up a timer. The target time is |mediaTimeUs|, adjusted by
+    // system time of |adjustRealUs|. In other words, the wake up time is
+    // mediaTimeUs + (adjustRealUs / playbackRate)
+    void addTimer(const sp<AMessage> &notify, int64_t mediaTimeUs, int64_t adjustRealUs = 0);
+
+    void reset();
+
 protected:
     virtual ~MediaClock();
 
+    virtual void onMessageReceived(const sp<AMessage> &msg);
+
 private:
+    enum {
+        kWhatTimeIsUp = 'tIsU',
+    };
+
+    struct Timer {
+        Timer(const sp<AMessage> &notify, int64_t mediaTimeUs, int64_t adjustRealUs);
+        const sp<AMessage> mNotify;
+        int64_t mMediaTimeUs;
+        int64_t mAdjustRealUs;
+    };
+
     status_t getMediaTime_l(
             int64_t realUs,
             int64_t *outMediaUs,
             bool allowPastMaxTime) const;
 
+    void processTimers_l();
+
+    sp<ALooper> mLooper;
     mutable Mutex mLock;
 
     int64_t mAnchorTimeMediaUs;
@@ -72,6 +102,9 @@
 
     float mPlaybackRate;
 
+    int32_t mGeneration;
+    std::list<Timer> mTimers;
+
     DISALLOW_EVIL_CONSTRUCTORS(MediaClock);
 };
 
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecSource.h b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
index 3ac539e..bc0653d 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecSource.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
@@ -17,10 +17,10 @@
 #ifndef MediaCodecSource_H_
 #define MediaCodecSource_H_
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AHandlerReflector.h>
 #include <media/stagefright/foundation/Mutexed.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/PersistentSurface.h>
 
 namespace android {
diff --git a/media/libstagefright/include/media/stagefright/MediaDefs.h b/media/libstagefright/include/media/stagefright/MediaDefs.h
index 359fb69..d20c5da 100644
--- a/media/libstagefright/include/media/stagefright/MediaDefs.h
+++ b/media/libstagefright/include/media/stagefright/MediaDefs.h
@@ -26,6 +26,6 @@
  *
  */
 
-#include <media/MediaDefs.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 
 #endif  // STAGEFRIGHT_MEDIA_DEFS_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractor.h b/media/libstagefright/include/media/stagefright/MediaExtractor.h
deleted file mode 100644
index 6ec7eaf..0000000
--- a/media/libstagefright/include/media/stagefright/MediaExtractor.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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 MEDIA_EXTRACTOR_H_
-
-#define MEDIA_EXTRACTOR_H_
-
-#include <media/IMediaExtractor.h>
-#include <media/IMediaSource.h>
-#include <media/MediaAnalyticsItem.h>
-
-namespace android {
-class DataSource;
-struct MediaSource;
-class MetaData;
-
-class MediaExtractor : public BnMediaExtractor {
-public:
-    static sp<IMediaExtractor> Create(
-            const sp<DataSource> &source, const char *mime = NULL);
-    static sp<MediaExtractor> CreateFromService(
-            const sp<DataSource> &source, const char *mime = NULL);
-
-    virtual size_t countTracks() = 0;
-    virtual sp<IMediaSource> getTrack(size_t index) = 0;
-
-    enum GetTrackMetaDataFlags {
-        kIncludeExtensiveMetaData = 1
-    };
-    virtual sp<MetaData> getTrackMetaData(
-            size_t index, uint32_t flags = 0) = 0;
-
-    // Return container specific meta-data. The default implementation
-    // returns an empty metadata object.
-    virtual sp<MetaData> getMetaData();
-
-    status_t getMetrics(Parcel *reply);
-
-    enum Flags {
-        CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button"
-        CAN_SEEK_FORWARD   = 2,  // the "seek 10secs forward button"
-        CAN_PAUSE          = 4,
-        CAN_SEEK           = 8,  // the "seek bar"
-    };
-
-    // If subclasses do _not_ override this, the default is
-    // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
-    virtual uint32_t flags() const;
-
-    // for DRM
-    virtual char* getDrmTrackInfo(size_t /*trackID*/, int * /*len*/) {
-        return NULL;
-    }
-    virtual void setUID(uid_t /*uid*/) {
-    }
-    virtual status_t setMediaCas(const HInterfaceToken &/*casToken*/) override {
-        return INVALID_OPERATION;
-    }
-
-    virtual const char * name() { return "<unspecified>"; }
-
-    virtual void release() {}
-
-protected:
-    MediaExtractor();
-    virtual ~MediaExtractor();
-
-    MediaAnalyticsItem *mAnalyticsItem;
-
-    virtual void populateMetrics();
-
-private:
-
-    typedef bool (*SnifferFunc)(
-            const sp<DataSource> &source, String8 *mimeType,
-            float *confidence, sp<AMessage> *meta);
-
-    static Mutex gSnifferMutex;
-    static List<SnifferFunc> gSniffers;
-    static bool gSniffersRegistered;
-
-    // The sniffer can optionally fill in "meta" with an AMessage containing
-    // a dictionary of values that helps the corresponding extractor initialize
-    // its state without duplicating effort already exerted by the sniffer.
-    static void RegisterSniffer_l(SnifferFunc func);
-
-    static bool sniff(const sp<DataSource> &source,
-            String8 *mimeType, float *confidence, sp<AMessage> *meta);
-
-    static void RegisterDefaultSniffers();
-
-    MediaExtractor(const MediaExtractor &);
-    MediaExtractor &operator=(const MediaExtractor &);
-};
-
-}  // namespace android
-
-#endif  // MEDIA_EXTRACTOR_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
new file mode 100644
index 0000000..96298f9
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_EXTRACTOR_FACTORY_H_
+
+#define MEDIA_EXTRACTOR_FACTORY_H_
+
+#include <stdio.h>
+
+#include <media/IMediaExtractor.h>
+#include <media/MediaExtractor.h>
+
+namespace android {
+
+class DataSource;
+
+class MediaExtractorFactory {
+public:
+    static sp<IMediaExtractor> Create(
+            const sp<DataSource> &source, const char *mime = NULL);
+    static sp<MediaExtractor> CreateFromService(
+            const sp<DataSource> &source, const char *mime = NULL);
+
+private:
+    static Mutex gSnifferMutex;
+    static List<MediaExtractor::ExtractorDef> gSniffers;
+    static bool gSniffersRegistered;
+
+    static void RegisterSniffer_l(const MediaExtractor::ExtractorDef &def);
+
+    static MediaExtractor::CreatorFunc sniff(const sp<DataSource> &source,
+            String8 *mimeType, float *confidence, sp<AMessage> *meta);
+
+    static void RegisterDefaultSniffers();
+};
+
+}  // namespace android
+
+#endif  // MEDIA_EXTRACTOR_FACTORY_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaMuxer.h b/media/libstagefright/include/media/stagefright/MediaMuxer.h
index 63c3ca5..66f4d72 100644
--- a/media/libstagefright/include/media/stagefright/MediaMuxer.h
+++ b/media/libstagefright/include/media/stagefright/MediaMuxer.h
@@ -48,6 +48,7 @@
         OUTPUT_FORMAT_MPEG_4      = 0,
         OUTPUT_FORMAT_WEBM        = 1,
         OUTPUT_FORMAT_THREE_GPP   = 2,
+        OUTPUT_FORMAT_HEIF        = 3,
         OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
     };
 
diff --git a/media/libstagefright/include/media/stagefright/MediaWriter.h b/media/libstagefright/include/media/stagefright/MediaWriter.h
index cd4af4d..c4bba0e 100644
--- a/media/libstagefright/include/media/stagefright/MediaWriter.h
+++ b/media/libstagefright/include/media/stagefright/MediaWriter.h
@@ -19,8 +19,8 @@
 #define MEDIA_WRITER_H_
 
 #include <utils/RefBase.h>
+#include <media/MediaSource.h>
 #include <media/IMediaRecorderClient.h>
-#include <media/IMediaSource.h>
 
 namespace android {
 
@@ -32,7 +32,7 @@
           mMaxFileDurationLimitUs(0) {
     }
 
-    virtual status_t addSource(const sp<IMediaSource> &source) = 0;
+    virtual status_t addSource(const sp<MediaSource> &source) = 0;
     virtual bool reachedEOS() = 0;
     virtual status_t start(MetaData *params = NULL) = 0;
     virtual status_t stop() = 0;
diff --git a/media/libstagefright/include/media/stagefright/MetaData.h b/media/libstagefright/include/media/stagefright/MetaData.h
index 6cfde9c..3438c56 100644
--- a/media/libstagefright/include/media/stagefright/MetaData.h
+++ b/media/libstagefright/include/media/stagefright/MetaData.h
@@ -215,7 +215,11 @@
 
     kKeyGridWidth        = 'grdW', // int32_t, HEIF grid width
     kKeyGridHeight       = 'grdH', // int32_t, HEIF grid height
+    kKeyGridRows         = 'grdR', // int32_t, HEIF grid rows
+    kKeyGridCols         = 'grdC', // int32_t, HEIF grid columns
     kKeyIccProfile       = 'prof', // raw data, ICC prifile data
+    kKeyIsPrimaryImage   = 'prim', // bool (int32_t), image track is the primary image
+    kKeyFrameCount       = 'nfrm', // int32_t, total number of frame in video track
 };
 
 enum {
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 6a93bd5..5af0745 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -17,9 +17,11 @@
 #ifndef NU_MEDIA_EXTRACTOR_H_
 #define NU_MEDIA_EXTRACTOR_H_
 
+#include <list>
+#include <media/mediaplayer.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/IMediaExtractor.h>
+#include <media/MediaSource.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
@@ -67,7 +69,9 @@
 
     status_t getFileFormat(sp<AMessage> *format) const;
 
-    status_t selectTrack(size_t index);
+    status_t selectTrack(size_t index, int64_t startTimeUs = -1ll,
+            MediaSource::ReadOptions::SeekMode mode =
+                MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
     status_t unselectTrack(size_t index);
 
     status_t seekTo(
@@ -75,8 +79,12 @@
             MediaSource::ReadOptions::SeekMode mode =
                 MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
 
+    // Each selected track has a read pointer.
+    // advance() advances the read pointer with the lowest timestamp.
     status_t advance();
+    // readSampleData() reads the sample with the lowest timestamp.
     status_t readSampleData(const sp<ABuffer> &buffer);
+
     status_t getSampleTrackIndex(size_t *trackIndex);
     status_t getSampleTime(int64_t *sampleTimeUs);
     status_t getSampleMeta(sp<MetaData> *sampleMeta);
@@ -96,12 +104,20 @@
         kMaxTrackCount = 16384,
     };
 
+    struct Sample {
+        Sample();
+        Sample(MediaBuffer *buffer, int64_t timeUs);
+        MediaBuffer *mBuffer;
+        int64_t mSampleTimeUs;
+    };
+
     struct TrackInfo {
         sp<IMediaSource> mSource;
         size_t mTrackIndex;
+        media_track_type mTrackType;
+        size_t mMaxFetchCount;
         status_t mFinalResult;
-        MediaBuffer *mSample;
-        int64_t mSampleTimeUs;
+        std::list<Sample> mSamples;
 
         uint32_t mTrackFlags;  // bitmask of "TrackFlags"
     };
@@ -117,16 +133,23 @@
     int64_t mTotalBitrate;  // in bits/sec
     int64_t mDurationUs;
 
-    ssize_t fetchTrackSamples(
+    ssize_t fetchAllTrackSamples(
+            int64_t seekTimeUs = -1ll,
+            MediaSource::ReadOptions::SeekMode mode =
+                MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
+    void fetchTrackSamples(
+            TrackInfo *info,
             int64_t seekTimeUs = -1ll,
             MediaSource::ReadOptions::SeekMode mode =
                 MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
 
-    void releaseTrackSamples();
+    void releaseOneSample(TrackInfo *info);
+    void releaseTrackSamples(TrackInfo *info);
+    void releaseAllTrackSamples();
 
     bool getTotalBitrate(int64_t *bitRate) const;
     status_t updateDurationAndBitrate();
-    status_t appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer);
+    status_t appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor);
 };
diff --git a/media/libstagefright/include/media/stagefright/OMXClient.h b/media/libstagefright/include/media/stagefright/OMXClient.h
index 2f159b0..bb133d3 100644
--- a/media/libstagefright/include/media/stagefright/OMXClient.h
+++ b/media/libstagefright/include/media/stagefright/OMXClient.h
@@ -27,16 +27,10 @@
     OMXClient();
 
     status_t connect();
-    status_t connect(bool* trebleFlag);
-    status_t connect(const char* name, bool* trebleFlag = nullptr);
-
-    status_t connectLegacy();
-    status_t connectTreble(const char* name = "default");
+    status_t connect(const char* name);
     void disconnect();
 
-    sp<IOMX> interface() {
-        return mOMX;
-    }
+    sp<IOMX> interface();
 
 private:
     sp<IOMX> mOMX;
diff --git a/media/libstagefright/include/media/stagefright/RemoteDataSource.h b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
index c91ddfc..e191e6a 100644
--- a/media/libstagefright/include/media/stagefright/RemoteDataSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
@@ -19,8 +19,8 @@
 
 #include <binder/IMemory.h>
 #include <binder/MemoryDealer.h>
+#include <media/DataSource.h>
 #include <media/IDataSource.h>
-#include <media/stagefright/DataSource.h>
 
 namespace android {
 
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
new file mode 100644
index 0000000..b5a4b34
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef REMOTE_MEDIA_EXTRACTOR_H_
+#define REMOTE_MEDIA_EXTRACTOR_H_
+
+#include <media/IMediaExtractor.h>
+#include <media/MediaExtractor.h>
+
+namespace android {
+
+// IMediaExtractor wrapper to the MediaExtractor.
+class RemoteMediaExtractor : public BnMediaExtractor {
+public:
+    static sp<IMediaExtractor> wrap(const sp<MediaExtractor> &extractor);
+
+    virtual ~RemoteMediaExtractor();
+    virtual size_t countTracks();
+    virtual sp<IMediaSource> getTrack(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags = 0);
+    virtual sp<MetaData> getMetaData();
+    virtual status_t getMetrics(Parcel *reply);
+    virtual uint32_t flags() const;
+    virtual char* getDrmTrackInfo(size_t trackID, int * len);
+    virtual void setUID(uid_t uid);
+    virtual status_t setMediaCas(const HInterfaceToken &casToken);
+    virtual const char * name();
+    virtual void release();
+
+private:
+    sp<MediaExtractor> mExtractor;
+
+    explicit RemoteMediaExtractor(const sp<MediaExtractor> &extractor);
+
+    DISALLOW_EVIL_CONSTRUCTORS(RemoteMediaExtractor);
+};
+
+}  // namespace android
+
+#endif  // REMOTE_MEDIA_EXTRACTOR_H_
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
new file mode 100644
index 0000000..ba5414a
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef REMOTE_MEDIA_SOURCE_H_
+#define REMOTE_MEDIA_SOURCE_H_
+
+#include <media/IMediaSource.h>
+#include <media/MediaSource.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+// IMediaSrouce wrapper to the MediaSource.
+class RemoteMediaSource : public BnMediaSource {
+public:
+    static sp<IMediaSource> wrap(const sp<MediaSource> &source);
+    virtual ~RemoteMediaSource();
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+    virtual sp<MetaData> getFormat();
+    virtual status_t read(
+            MediaBuffer **buffer,
+            const MediaSource::ReadOptions *options = NULL);
+    virtual status_t pause();
+    virtual status_t setBuffers(const Vector<MediaBuffer *> &buffers);
+    virtual status_t setStopTimeUs(int64_t stopTimeUs);
+
+private:
+    sp<MediaSource> mSource;
+
+    explicit RemoteMediaSource(const sp<MediaSource> &source);
+
+    DISALLOW_EVIL_CONSTRUCTORS(RemoteMediaSource);
+};
+
+}  // namespace android
+
+#endif  // REMOTE_MEDIA_SOURCE_H_
diff --git a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
index a000fde..5060dc1 100644
--- a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
+++ b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
@@ -17,7 +17,7 @@
 #ifndef SIMPLE_DECODING_SOURCE_H_
 #define SIMPLE_DECODING_SOURCE_H_
 
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/foundation/Mutexed.h>
 
@@ -45,12 +45,12 @@
     // does not support secure input or pausing.
     // if |desiredCodec| is given, use this specific codec.
     static sp<SimpleDecodingSource> Create(
-            const sp<IMediaSource> &source, uint32_t flags,
+            const sp<MediaSource> &source, uint32_t flags,
             const sp<ANativeWindow> &nativeWindow,
             const char *desiredCodec = NULL);
 
     static sp<SimpleDecodingSource> Create(
-            const sp<IMediaSource> &source, uint32_t flags = 0);
+            const sp<MediaSource> &source, uint32_t flags = 0);
 
     virtual ~SimpleDecodingSource();
 
@@ -73,11 +73,11 @@
 private:
     // Construct this using a codec, source and looper.
     SimpleDecodingSource(
-            const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
+            const sp<MediaCodec> &codec, const sp<MediaSource> &source, const sp<ALooper> &looper,
             bool usingSurface, bool isVorbis, const sp<AMessage> &format);
 
     sp<MediaCodec> mCodec;
-    sp<IMediaSource> mSource;
+    sp<MediaSource> mSource;
     sp<ALooper> mLooper;
     bool mUsingSurface;
     bool mIsVorbis;
diff --git a/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
index d1677fa..2e495f9 100644
--- a/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
@@ -22,7 +22,7 @@
 
 #include <utils/threads.h>
 #include <utils/Vector.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
 
 #include <media/hardware/MetadataBufferType.h>
diff --git a/media/libstagefright/include/media/stagefright/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h
index 77cbd4c..7d4a611 100644
--- a/media/libstagefright/include/media/stagefright/Utils.h
+++ b/media/libstagefright/include/media/stagefright/Utils.h
@@ -28,20 +28,6 @@
 
 namespace android {
 
-#define FOURCC(c1, c2, c3, c4) \
-    ((c1) << 24 | (c2) << 16 | (c3) << 8 | (c4))
-
-uint16_t U16_AT(const uint8_t *ptr);
-uint32_t U32_AT(const uint8_t *ptr);
-uint64_t U64_AT(const uint8_t *ptr);
-
-uint16_t U16LE_AT(const uint8_t *ptr);
-uint32_t U32LE_AT(const uint8_t *ptr);
-uint64_t U64LE_AT(const uint8_t *ptr);
-
-uint64_t ntoh64(uint64_t x);
-uint64_t hton64(uint64_t x);
-
 class MetaData;
 struct AMessage;
 status_t convertMetaDataToMessage(
@@ -95,7 +81,6 @@
 void readFromAMessage(const sp<AMessage> &msg, BufferingSettings *buffering /* nonnull */);
 
 AString nameForFd(int fd);
-void MakeFourCCString(uint32_t x, char *s);
 }  // namespace android
 
 #endif  // UTILS_H_
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index a256a4d..cd60a6c 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -21,7 +21,6 @@
 #include "AnotherPacketSource.h"
 #include "CasManager.h"
 #include "ESQueue.h"
-#include "include/avc_utils.h"
 
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
 #include <cutils/native_handle.h>
@@ -29,11 +28,12 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
 #include <media/IStreamSource.h>
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 41c19cd..6079afc 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -20,9 +20,9 @@
 
 #include <sys/types.h>
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaSource.h>
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
 #include <utils/RefBase.h>
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
index 21259c4..7654eb3 100644
--- a/media/libstagefright/mpeg2ts/Android.bp
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -1,5 +1,5 @@
 cc_library_static {
-    name: "libstagefright_mpeg2ts",
+    name: "libstagefright_mpeg2support",
 
     srcs: [
         "AnotherPacketSource.cpp",
@@ -7,8 +7,6 @@
         "CasManager.cpp",
         "ESQueue.cpp",
         "HlsSampleDecryptor.cpp",
-        "MPEG2PSExtractor.cpp",
-        "MPEG2TSExtractor.cpp",
     ],
 
     include_dirs: [
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 433b1fc..1dac171 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -19,13 +19,12 @@
 
 #include "AnotherPacketSource.h"
 
-#include "include/avc_utils.h"
-
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
@@ -663,7 +662,7 @@
                         && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
             }
         }
-        if (isAvc && !IsIDR(buffer)) {
+        if (isAvc && !IsIDR(buffer->data(), buffer->size())) {
             continue;
         }
 
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index b0890d7..3abd573 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -18,8 +18,8 @@
 
 #define ANOTHER_PACKET_SOURCE_H_
 
+#include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
 #include <utils/threads.h>
 #include <utils/List.h>
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 1cf9744..b621fd0 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -24,15 +24,14 @@
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
 #include <media/cas/DescramblerAPI.h>
 #include <media/hardware/CryptoAPI.h>
 
-#include "include/avc_utils.h"
-
 #include <inttypes.h>
 #include <netinet/in.h>
 
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index bd3c1c6..8539864 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -9,8 +9,6 @@
         "FrameDropper.cpp",
         "GraphicBufferSource.cpp",
         "BWGraphicBufferSource.cpp",
-        "OMX.cpp",
-        "OMXStore.cpp",
         "OMXMaster.cpp",
         "OMXNodeInstance.cpp",
         "OMXUtils.cpp",
@@ -57,16 +55,12 @@
         "libhidlmemory",
         "libhidltransport",
         "libnativewindow", // TODO(b/62923479): use header library
-        "android.hidl.memory@1.0",
-        "android.hidl.token@1.0-utils",
-        "android.hardware.media@1.0",
+        "libvndksupport",
         "android.hardware.media.omx@1.0",
-        "android.hardware.graphics.common@1.0",
         "android.hardware.graphics.bufferqueue@1.0",
     ],
 
     export_shared_lib_headers: [
-        "android.hidl.memory@1.0",
         "libmedia_omx",
         "libstagefright_foundation",
         "libstagefright_xmlparser",
@@ -109,6 +103,7 @@
     ],
     shared_libs: [
         "libmedia_omx",
+        "libstagefright_foundation",
         "liblog",
     ],
     export_shared_lib_headers: [
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 1917d2a..a70005e 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -1199,7 +1199,8 @@
     Mutex::Autolock autoLock(mMutex);
 
     mSkipFramesBeforeNs =
-            (skipFramesBeforeUs > 0) ? (skipFramesBeforeUs * 1000) : -1ll;
+            (skipFramesBeforeUs > 0 && skipFramesBeforeUs <= INT64_MAX / 1000) ?
+            (skipFramesBeforeUs * 1000) : -1ll;
 
     return OK;
 }
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
deleted file mode 100644
index 09c4019..0000000
--- a/media/libstagefright/omx/OMX.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * 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 <inttypes.h>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "OMX"
-#include <utils/Log.h>
-
-#include <dlfcn.h>
-
-#include <media/stagefright/omx/OMX.h>
-#include <media/stagefright/omx/OMXNodeInstance.h>
-#include <media/stagefright/omx/BWGraphicBufferSource.h>
-#include <media/stagefright/omx/OMXMaster.h>
-#include <media/stagefright/omx/OMXUtils.h>
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace android {
-
-// node ids are created by concatenating the pid with a 16-bit counter
-static size_t kMaxNodeInstances = (1 << 16);
-
-OMX::OMX() : mMaster(new OMXMaster), mParser() {
-}
-
-OMX::~OMX() {
-    delete mMaster;
-    mMaster = NULL;
-}
-
-void OMX::binderDied(const wp<IBinder> &the_late_who) {
-    sp<OMXNodeInstance> instance;
-
-    {
-        Mutex::Autolock autoLock(mLock);
-
-        ssize_t index = mLiveNodes.indexOfKey(the_late_who);
-
-        if (index < 0) {
-            ALOGE("b/27597103, nonexistent observer on binderDied");
-            android_errorWriteLog(0x534e4554, "27597103");
-            return;
-        }
-
-        instance = mLiveNodes.editValueAt(index);
-        mLiveNodes.removeItemsAt(index);
-    }
-
-    instance->onObserverDied();
-}
-
-status_t OMX::listNodes(List<ComponentInfo> *list) {
-    list->clear();
-
-    OMX_U32 index = 0;
-    char componentName[256];
-    while (mMaster->enumerateComponents(
-                componentName, sizeof(componentName), index) == OMX_ErrorNone) {
-        list->push_back(ComponentInfo());
-        ComponentInfo &info = *--list->end();
-
-        info.mName = componentName;
-
-        Vector<String8> roles;
-        OMX_ERRORTYPE err =
-            mMaster->getRolesOfComponent(componentName, &roles);
-
-        if (err == OMX_ErrorNone) {
-            for (OMX_U32 i = 0; i < roles.size(); ++i) {
-                info.mRoles.push_back(roles[i]);
-            }
-        }
-
-        ++index;
-    }
-
-    return OK;
-}
-
-status_t OMX::allocateNode(
-        const char *name, const sp<IOMXObserver> &observer,
-        sp<IOMXNode> *omxNode) {
-    Mutex::Autolock autoLock(mLock);
-
-    omxNode->clear();
-
-    if (mLiveNodes.size() == kMaxNodeInstances) {
-        return NO_MEMORY;
-    }
-
-    sp<OMXNodeInstance> instance = new OMXNodeInstance(this, observer, name);
-
-    OMX_COMPONENTTYPE *handle;
-    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
-            name, &OMXNodeInstance::kCallbacks,
-            instance.get(), &handle);
-
-    if (err != OMX_ErrorNone) {
-        ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err);
-
-        return StatusFromOMXError(err);
-    }
-    instance->setHandle(handle);
-
-    // Find quirks from mParser
-    const auto& codec = mParser.getCodecMap().find(name);
-    if (codec == mParser.getCodecMap().cend()) {
-        ALOGW("Failed to obtain quirks for omx component '%s' from XML files",
-                name);
-    } else {
-        uint32_t quirks = 0;
-        for (const auto& quirk : codec->second.quirkSet) {
-            if (quirk == "requires-allocate-on-input-ports") {
-                quirks |= OMXNodeInstance::
-                        kRequiresAllocateBufferOnInputPorts;
-            }
-            if (quirk == "requires-allocate-on-output-ports") {
-                quirks |= OMXNodeInstance::
-                        kRequiresAllocateBufferOnOutputPorts;
-            }
-        }
-        instance->setQuirks(quirks);
-    }
-
-    mLiveNodes.add(IInterface::asBinder(observer), instance);
-    IInterface::asBinder(observer)->linkToDeath(this);
-
-    *omxNode = instance;
-
-    return OK;
-}
-
-status_t OMX::freeNode(const sp<OMXNodeInstance> &instance) {
-    if (instance == NULL) {
-        return OK;
-    }
-
-    {
-        Mutex::Autolock autoLock(mLock);
-        ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer()));
-        if (index < 0) {
-            // This could conceivably happen if the observer dies at roughly the
-            // same time that a client attempts to free the node explicitly.
-
-            // NOTE: it's guaranteed that this method is called at most once per
-            //       instance.
-            ALOGV("freeNode: instance already removed from book-keeping.");
-        } else {
-            mLiveNodes.removeItemsAt(index);
-            IInterface::asBinder(instance->observer())->unlinkToDeath(this);
-        }
-    }
-
-    CHECK(instance->handle() != NULL);
-    OMX_ERRORTYPE err = mMaster->destroyComponentInstance(
-            static_cast<OMX_COMPONENTTYPE *>(instance->handle()));
-    ALOGV("freeNode: handle destroyed: %p", instance->handle());
-
-    return StatusFromOMXError(err);
-}
-
-status_t OMX::createInputSurface(
-        sp<IGraphicBufferProducer> *bufferProducer,
-        sp<IGraphicBufferSource> *bufferSource) {
-    if (bufferProducer == NULL || bufferSource == NULL) {
-        ALOGE("b/25884056");
-        return BAD_VALUE;
-    }
-
-    sp<GraphicBufferSource> graphicBufferSource = new GraphicBufferSource();
-    status_t err = graphicBufferSource->initCheck();
-    if (err != OK) {
-        ALOGE("Failed to create persistent input surface: %s (%d)",
-                strerror(-err), err);
-        return err;
-    }
-
-    *bufferProducer = graphicBufferSource->getIGraphicBufferProducer();
-    *bufferSource = new BWGraphicBufferSource(graphicBufferSource);
-
-    return OK;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index fd97fdc..0967b5f 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -22,6 +22,8 @@
 #include <media/stagefright/omx/SoftOMXPlugin.h>
 #include <media/stagefright/foundation/ADebug.h>
 
+#include <vndksupport/linker.h>
+
 #include <dlfcn.h>
 #include <fcntl.h>
 
@@ -67,7 +69,7 @@
 }
 
 void OMXMaster::addPlugin(const char *libname) {
-    mVendorLibHandle = dlopen(libname, RTLD_NOW);
+    mVendorLibHandle = android_load_sphal_library(libname, RTLD_NOW);
 
     if (mVendorLibHandle == NULL) {
         return;
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 015a148..ff58eb6 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -344,7 +344,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 OMXNodeInstance::OMXNodeInstance(
-        OmxNodeOwner *owner, const sp<IOMXObserver> &observer, const char *name)
+        Omx *owner, const sp<IOMXObserver> &observer, const char *name)
     : mOwner(owner),
       mHandle(NULL),
       mObserver(observer),
diff --git a/media/libstagefright/omx/OMXStore.cpp b/media/libstagefright/omx/OMXStore.cpp
deleted file mode 100644
index 345336d..0000000
--- a/media/libstagefright/omx/OMXStore.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "OMXStore"
-#include <utils/Log.h>
-
-#include <media/stagefright/omx/OMXUtils.h>
-#include <media/stagefright/omx/OMX.h>
-#include <media/stagefright/omx/OMXStore.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-
-#include <map>
-#include <string>
-
-namespace android {
-
-namespace {
-    struct RoleProperties {
-        std::string type;
-        bool isEncoder;
-        bool preferPlatformNodes;
-        std::multimap<size_t, IOMXStore::NodeInfo> nodeList;
-    };
-}  // Unnamed namespace
-
-OMXStore::OMXStore(
-        const char* owner,
-        const char* const* searchDirs,
-        const char* mainXmlName,
-        const char* performanceXmlName,
-        const char* profilingResultsXmlPath) {
-    MediaCodecsXmlParser parser(
-            searchDirs,
-            mainXmlName,
-            performanceXmlName,
-            profilingResultsXmlPath);
-    mParsingStatus = parser.getParsingStatus();
-
-    const auto& serviceAttributeMap = parser.getServiceAttributeMap();
-    mServiceAttributeList.reserve(serviceAttributeMap.size());
-    for (const auto& attributePair : serviceAttributeMap) {
-        Attribute attribute;
-        attribute.key = attributePair.first;
-        attribute.value = attributePair.second;
-        mServiceAttributeList.push_back(std::move(attribute));
-    }
-
-    const auto& roleMap = parser.getRoleMap();
-    mRoleList.reserve(roleMap.size());
-    for (const auto& rolePair : roleMap) {
-        RoleInfo role;
-        role.role = rolePair.first;
-        role.type = rolePair.second.type;
-        role.isEncoder = rolePair.second.isEncoder;
-        // TODO: Currently, preferPlatformNodes information is not available in
-        // the xml file. Once we have a way to provide this information, it
-        // should be parsed properly.
-        role.preferPlatformNodes = rolePair.first.compare(0, 5, "audio") == 0;
-        std::vector<NodeInfo>& nodeList = role.nodes;
-        nodeList.reserve(rolePair.second.nodeList.size());
-        for (const auto& nodePair : rolePair.second.nodeList) {
-            NodeInfo node;
-            node.name = nodePair.second.name;
-            node.owner = owner;
-            std::vector<Attribute>& attributeList = node.attributes;
-            attributeList.reserve(nodePair.second.attributeList.size());
-            for (const auto& attributePair : nodePair.second.attributeList) {
-                Attribute attribute;
-                attribute.key = attributePair.first;
-                attribute.value = attributePair.second;
-                attributeList.push_back(std::move(attribute));
-            }
-            nodeList.push_back(std::move(node));
-        }
-        mRoleList.push_back(std::move(role));
-    }
-
-    mPrefix = parser.getCommonPrefix();
-}
-
-status_t OMXStore::listServiceAttributes(std::vector<Attribute>* attributes) {
-    *attributes = mServiceAttributeList;
-    return mParsingStatus;
-}
-
-status_t OMXStore::getNodePrefix(std::string* prefix) {
-    *prefix = mPrefix;
-    return mParsingStatus;
-}
-
-status_t OMXStore::listRoles(std::vector<RoleInfo>* roleList) {
-    *roleList = mRoleList;
-    return mParsingStatus;
-}
-
-status_t OMXStore::getOmx(const std::string& name, sp<IOMX>* omx) {
-    *omx = new OMX();
-    return NO_ERROR;
-}
-
-OMXStore::~OMXStore() {
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/omx/OMXUtils.cpp b/media/libstagefright/omx/OMXUtils.cpp
index 5894837..e032985 100644
--- a/media/libstagefright/omx/OMXUtils.cpp
+++ b/media/libstagefright/omx/OMXUtils.cpp
@@ -22,9 +22,9 @@
 #include <media/stagefright/omx/OMXUtils.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/hardware/HardwareAPI.h>
-#include <media/MediaDefs.h>
 #include <system/graphics-base.h>
 
 namespace android {
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index cb811a0..8e92539 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -26,8 +26,8 @@
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 #include <media/hardware/HardwareAPI.h>
-#include <media/MediaDefs.h>
 
 namespace android {
 
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index f33bdc0..fa15ab3 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -26,9 +26,9 @@
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 #include <media/hardware/HardwareAPI.h>
 #include <media/openmax/OMX_IndexExt.h>
-#include <media/MediaDefs.h>
 
 #include <ui/Fence.h>
 #include <ui/GraphicBufferMapper.h>
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
index a6a9d3e..baa7b81 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
@@ -20,13 +20,13 @@
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <media/stagefright/omx/OMXNodeInstance.h>
 #include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 
 namespace android {
 
 struct OMXMaster;
+struct OMXNodeInstance;
 
 namespace hardware {
 namespace media {
@@ -50,10 +50,9 @@
 using ::android::wp;
 
 using ::android::OMXMaster;
-using ::android::OmxNodeOwner;
 using ::android::OMXNodeInstance;
 
-struct Omx : public IOmx, public hidl_death_recipient, public OmxNodeOwner {
+struct Omx : public IOmx, public hidl_death_recipient {
     Omx();
     virtual ~Omx();
 
@@ -68,8 +67,8 @@
     // Method from hidl_death_recipient
     void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
 
-    // Method from OmxNodeOwner
-    virtual status_t freeNode(sp<OMXNodeInstance> const& instance) override;
+    // Method for OMXNodeInstance
+    status_t freeNode(sp<OMXNodeInstance> const& instance);
 
 protected:
     OMXMaster* mMaster;
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMX.h b/media/libstagefright/omx/include/media/stagefright/omx/OMX.h
deleted file mode 100644
index 594b4c0..0000000
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMX.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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_OMX_H_
-#define ANDROID_OMX_H_
-
-#include <media/IOMX.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-#include "OmxNodeOwner.h"
-
-namespace android {
-
-struct OMXMaster;
-struct OMXNodeInstance;
-
-class OMX : public BnOMX,
-            public OmxNodeOwner,
-            public IBinder::DeathRecipient {
-public:
-    OMX();
-
-    virtual status_t listNodes(List<ComponentInfo> *list);
-
-    virtual status_t allocateNode(
-            const char *name, const sp<IOMXObserver> &observer,
-            sp<IOMXNode> *omxNode);
-
-    virtual status_t createInputSurface(
-            sp<IGraphicBufferProducer> *bufferProducer,
-            sp<IGraphicBufferSource> *bufferSource);
-
-    virtual void binderDied(const wp<IBinder> &the_late_who);
-
-    virtual status_t freeNode(const sp<OMXNodeInstance>& instance);
-
-protected:
-    virtual ~OMX();
-
-private:
-    Mutex mLock;
-    OMXMaster *mMaster;
-    MediaCodecsXmlParser mParser;
-
-    KeyedVector<wp<IBinder>, sp<OMXNodeInstance> > mLiveNodes;
-
-    OMX(const OMX &);
-    OMX &operator=(const OMX &);
-};
-
-}  // namespace android
-
-#endif  // ANDROID_OMX_H_
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
index 1065ca5..c436121 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
@@ -25,9 +25,9 @@
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
 #include <utils/SortedVector.h>
-#include "OmxNodeOwner.h"
 
 #include <android/hidl/memory/1.0/IMemory.h>
+#include <media/stagefright/omx/1.0/Omx.h>
 
 namespace android {
 class GraphicBuffer;
@@ -35,11 +35,12 @@
 class IOMXObserver;
 struct OMXMaster;
 class OMXBuffer;
-typedef hidl::memory::V1_0::IMemory IHidlMemory;
+using IHidlMemory = hidl::memory::V1_0::IMemory;
+using hardware::media::omx::V1_0::implementation::Omx;
 
 struct OMXNodeInstance : public BnOMXNode {
     OMXNodeInstance(
-            OmxNodeOwner *owner, const sp<IOMXObserver> &observer, const char *name);
+            Omx *owner, const sp<IOMXObserver> &observer, const char *name);
 
     void setHandle(OMX_HANDLETYPE handle);
 
@@ -122,7 +123,7 @@
 
     Mutex mLock;
 
-    OmxNodeOwner *mOwner;
+    Omx *mOwner;
     OMX_HANDLETYPE mHandle;
     sp<IOMXObserver> mObserver;
     sp<CallbackDispatcher> mDispatcher;
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h
deleted file mode 100644
index e00d713..0000000
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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_OMXSTORE_H_
-#define ANDROID_OMXSTORE_H_
-
-#include <media/IOMXStore.h>
-#include <media/IOMX.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-
-#include <vector>
-#include <string>
-
-namespace android {
-
-class OMXStore : public BnOMXStore {
-public:
-    OMXStore(
-            const char* owner = "default",
-            const char* const* searchDirs
-                = MediaCodecsXmlParser::defaultSearchDirs,
-            const char* mainXmlName
-                = MediaCodecsXmlParser::defaultMainXmlName,
-            const char* performanceXmlName
-                = MediaCodecsXmlParser::defaultPerformanceXmlName,
-            const char* profilingResultsXmlPath
-                = MediaCodecsXmlParser::defaultProfilingResultsXmlPath);
-
-    status_t listServiceAttributes(
-            std::vector<Attribute>* attributes) override;
-
-    status_t getNodePrefix(std::string* prefix) override;
-
-    status_t listRoles(std::vector<RoleInfo>* roleList) override;
-
-    status_t getOmx(const std::string& name, sp<IOMX>* omx) override;
-
-    ~OMXStore() override;
-
-protected:
-    status_t mParsingStatus;
-    std::string mPrefix;
-    std::vector<Attribute> mServiceAttributeList;
-    std::vector<RoleInfo> mRoleList;
-};
-
-}  // namespace android
-
-#endif  // ANDROID_OMXSTORE_H_
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
index 8bcb99e..999d9d4 100644
--- a/media/libstagefright/omx/tests/Android.bp
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -8,6 +8,8 @@
         "libstagefright",
         "libbinder",
         "libmedia",
+        "libmedia_omx",
+        "libmediaextractor",
         "libutils",
         "liblog",
         "libstagefright_foundation",
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 3266439..86c7211e 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -25,20 +25,22 @@
 
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
-#include <binder/MemoryDealer.h>
+#include <cutils/properties.h>
+#include <media/DataSource.h>
 #include <media/IMediaHTTPService.h>
-#include <media/IMediaCodecService.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
+#include <media/OMXBuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/SimpleDecodingSource.h>
-#include <media/OMXBuffer.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <media/omx/1.0/WOmx.h>
 #include <system/window.h>
@@ -67,7 +69,7 @@
 /////////////////////////////////////////////////////////////////////
 
 Harness::Harness()
-    : mInitCheck(NO_INIT), mUseTreble(false) {
+    : mInitCheck(NO_INIT) {
     mInitCheck = initOMX();
 }
 
@@ -79,21 +81,12 @@
 }
 
 status_t Harness::initOMX() {
-    if (property_get_bool("persist.media.treble_omx", true)) {
-        using namespace ::android::hardware::media::omx::V1_0;
-        sp<IOmx> tOmx = IOmx::getService();
-        if (tOmx == nullptr) {
-            return NO_INIT;
-        }
-        mOMX = new utils::LWOmx(tOmx);
-        mUseTreble = true;
-    } else {
-        sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder = sm->getService(String16("media.codec"));
-        sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
-        mOMX = service->getOMX();
-        mUseTreble = false;
+    using namespace ::android::hardware::media::omx::V1_0;
+    sp<IOmx> tOmx = IOmx::getService();
+    if (tOmx == nullptr) {
+        return NO_INIT;
     }
+    mOMX = new utils::LWOmx(tOmx);
 
     return mOMX != 0 ? OK : NO_INIT;
 }
@@ -221,25 +214,19 @@
     for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
         Buffer buffer;
         buffer.mFlags = 0;
-        if (mUseTreble) {
-            bool success;
-            auto transStatus = mAllocator->allocate(def.nBufferSize,
-                    [&success, &buffer](
-                            bool s,
-                            hidl_memory const& m) {
-                        success = s;
-                        buffer.mHidlMemory = m;
-                    });
-            EXPECT(transStatus.isOk(),
-                    "Cannot call allocator");
-            EXPECT(success,
-                    "Cannot allocate memory");
-            err = mOMXNode->useBuffer(portIndex, buffer.mHidlMemory, &buffer.mID);
-        } else {
-            buffer.mMemory = mDealer->allocate(def.nBufferSize);
-            CHECK(buffer.mMemory != NULL);
-            err = mOMXNode->useBuffer(portIndex, buffer.mMemory, &buffer.mID);
-        }
+        bool success;
+        auto transStatus = mAllocator->allocate(def.nBufferSize,
+                [&success, &buffer](
+                        bool s,
+                        hidl_memory const& m) {
+                    success = s;
+                    buffer.mHidlMemory = m;
+                });
+        EXPECT(transStatus.isOk(),
+                "Cannot call allocator");
+        EXPECT(success,
+                "Cannot allocate memory");
+        err = mOMXNode->useBuffer(portIndex, buffer.mHidlMemory, &buffer.mID);
 
         EXPECT_SUCCESS(err, "useBuffer");
 
@@ -291,13 +278,13 @@
 
 static sp<IMediaExtractor> CreateExtractorFromURI(const char *uri) {
     sp<DataSource> source =
-        DataSource::CreateFromURI(NULL /* httpService */, uri);
+        DataSourceFactory::CreateFromURI(NULL /* httpService */, uri);
 
     if (source == NULL) {
         return NULL;
     }
 
-    return MediaExtractor::Create(source);
+    return MediaExtractorFactory::Create(source);
 }
 
 status_t Harness::testStateTransitions(
@@ -308,13 +295,11 @@
         return OK;
     }
 
-    if (mUseTreble) {
-        mAllocator = IAllocator::getService("ashmem");
-        EXPECT(mAllocator != nullptr,
-                "Cannot obtain hidl AshmemAllocator");
-    } else {
-        mDealer = new MemoryDealer(16 * 1024 * 1024, "OMXHarness");
-    }
+    mAllocator = IAllocator::getService("ashmem");
+    EXPECT(mAllocator != nullptr,
+            "Cannot obtain hidl AshmemAllocator");
+    // TODO: When Treble has MemoryHeap/MemoryDealer, we should specify the heap
+    // size to be 16 * 1024 * 1024.
 
     sp<CodecObserver> observer = new CodecObserver(this, ++mCurGeneration);
 
@@ -543,7 +528,7 @@
     return NULL;
 }
 
-static sp<IMediaSource> CreateSourceForMime(const char *mime) {
+static sp<MediaSource> CreateSourceForMime(const char *mime) {
     const char *url = GetURLForMime(mime);
 
     if (url == NULL) {
@@ -564,7 +549,7 @@
         CHECK(meta->findCString(kKeyMIMEType, &trackMime));
 
         if (!strcasecmp(mime, trackMime)) {
-            return extractor->getTrack(i);
+            return CreateMediaSourceFromIMediaSource(extractor->getTrack(i));
         }
     }
 
@@ -610,7 +595,7 @@
         return OK;
     }
 
-    sp<IMediaSource> source = CreateSourceForMime(mime);
+    sp<MediaSource> source = CreateSourceForMime(mime);
 
     if (source == NULL) {
         printf("  * Unable to open test content for type '%s', "
@@ -620,14 +605,14 @@
         return OK;
     }
 
-    sp<IMediaSource> seekSource = CreateSourceForMime(mime);
+    sp<MediaSource> seekSource = CreateSourceForMime(mime);
     if (source == NULL || seekSource == NULL) {
         return UNKNOWN_ERROR;
     }
 
     CHECK_EQ(seekSource->start(), (status_t)OK);
 
-    sp<IMediaSource> codec = SimpleDecodingSource::Create(
+    sp<MediaSource> codec = SimpleDecodingSource::Create(
             source, 0 /* flags */, NULL /* nativeWindow */, componentName);
 
     CHECK(codec != NULL);
diff --git a/media/libstagefright/omx/tests/OMXHarness.h b/media/libstagefright/omx/tests/OMXHarness.h
index 4fc0f79..dca787c 100644
--- a/media/libstagefright/omx/tests/OMXHarness.h
+++ b/media/libstagefright/omx/tests/OMXHarness.h
@@ -93,8 +93,6 @@
     Condition mMessageAddedCondition;
     int32_t mLastMsgGeneration;
     int32_t mCurGeneration;
-    bool mUseTreble;
-    sp<MemoryDealer> mDealer;
     sp<IAllocator> mAllocator;
 
     status_t initOMX();
diff --git a/media/libstagefright/rtsp/AH263Assembler.cpp b/media/libstagefright/rtsp/AH263Assembler.cpp
index 75cd911..3436e95 100644
--- a/media/libstagefright/rtsp/AH263Assembler.cpp
+++ b/media/libstagefright/rtsp/AH263Assembler.cpp
@@ -25,7 +25,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 
 namespace android {
 
diff --git a/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
index dca5c89..0988774 100644
--- a/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
@@ -26,10 +26,10 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
 
 namespace android {
 
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
index 156004c..1e434cb 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -27,8 +27,8 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/Utils.h>
 
 #include <ctype.h>
 #include <stdint.h>
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 8ba9e02..68f8bdd 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -23,8 +23,6 @@
 #include "ARawAudioAssembler.h"
 #include "ASessionDescription.h"
 
-#include "include/avc_utils.h"
-
 #include <ctype.h>
 
 #include <media/stagefright/foundation/ABitReader.h>
@@ -32,6 +30,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 1f6b6f7..8604b69 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -22,13 +22,13 @@
 
 #include <fcntl.h>
 
+#include <media/MediaSource.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/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/ByteOrder.h>
 
@@ -104,7 +104,7 @@
     mFd = -1;
 }
 
-status_t ARTPWriter::addSource(const sp<IMediaSource> &source) {
+status_t ARTPWriter::addSource(const sp<MediaSource> &source) {
     mSource = source;
     return OK;
 }
diff --git a/media/libstagefright/rtsp/ARTPWriter.h b/media/libstagefright/rtsp/ARTPWriter.h
index 3c7042e..92a64f2 100644
--- a/media/libstagefright/rtsp/ARTPWriter.h
+++ b/media/libstagefright/rtsp/ARTPWriter.h
@@ -37,7 +37,7 @@
 struct ARTPWriter : public MediaWriter {
     explicit ARTPWriter(int fd);
 
-    virtual status_t addSource(const sp<IMediaSource> &source);
+    virtual status_t addSource(const sp<MediaSource> &source);
     virtual bool reachedEOS();
     virtual status_t start(MetaData *params);
     virtual status_t stop();
@@ -72,7 +72,7 @@
     int mRTCPFd;
 #endif
 
-    sp<IMediaSource> mSource;
+    sp<MediaSource> mSource;
     sp<ALooper> mLooper;
     sp<AHandlerReflector<ARTPWriter> > mReflector;
 
diff --git a/media/libstagefright/rtsp/VideoSource.h b/media/libstagefright/rtsp/VideoSource.h
index ae0c85b..4be9bf6 100644
--- a/media/libstagefright/rtsp/VideoSource.h
+++ b/media/libstagefright/rtsp/VideoSource.h
@@ -18,9 +18,9 @@
 
 #define VIDEO_SOURCE_H_
 
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 
 namespace android {
diff --git a/media/libstagefright/rtsp/rtp_test.cpp b/media/libstagefright/rtsp/rtp_test.cpp
index e612a8d..98a8fb4 100644
--- a/media/libstagefright/rtsp/rtp_test.cpp
+++ b/media/libstagefright/rtsp/rtp_test.cpp
@@ -20,10 +20,10 @@
 
 #include <binder/ProcessState.h>
 
+#include <media/DataSource.h>
 #include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/SimpleDecodingSource.h>
diff --git a/media/libstagefright/tests/DummyRecorder.cpp b/media/libstagefright/tests/DummyRecorder.cpp
index 8f17088..4f560cb 100644
--- a/media/libstagefright/tests/DummyRecorder.cpp
+++ b/media/libstagefright/tests/DummyRecorder.cpp
@@ -17,8 +17,8 @@
 #define LOG_TAG "DummyRecorder"
 // #define LOG_NDEBUG 0
 
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaSource.h>
 #include "DummyRecorder.h"
 
 #include <utils/Log.h>
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index 7c464ff..051108f 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -94,10 +94,10 @@
             ASSERT_TRUE(mSurfaceControl != NULL);
             ASSERT_TRUE(mSurfaceControl->isValid());
 
-            SurfaceComposerClient::openGlobalTransaction();
-            ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
-            ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
-            SurfaceComposerClient::closeGlobalTransaction();
+            SurfaceComposerClient::Transaction{}
+                    .setLayer(mSurfaceControl, 0x7FFFFFFF)
+                    .show(mSurfaceControl)
+                    .apply();
 
             sp<ANativeWindow> window = mSurfaceControl->getSurface();
             mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
diff --git a/media/libstagefright/timedtext/TextDescriptions.cpp b/media/libstagefright/timedtext/TextDescriptions.cpp
index c762a74..088eaae 100644
--- a/media/libstagefright/timedtext/TextDescriptions.cpp
+++ b/media/libstagefright/timedtext/TextDescriptions.cpp
@@ -15,7 +15,7 @@
  */
 
 #include "TextDescriptions.h"
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/MediaErrors.h>
 
 namespace android {
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index 71bfbc9..420890b 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -252,7 +252,7 @@
 }
 
 WebmFrameMediaSourceThread::WebmFrameMediaSourceThread(
-        const sp<IMediaSource>& source,
+        const sp<MediaSource>& source,
         int type,
         LinkedBlockingQueue<const sp<WebmFrame> >& sink,
         uint64_t timeCodeScale,
diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/WebmFrameThread.h
index 528984f..76c91f1 100644
--- a/media/libstagefright/webm/WebmFrameThread.h
+++ b/media/libstagefright/webm/WebmFrameThread.h
@@ -20,8 +20,8 @@
 #include "WebmFrame.h"
 #include "LinkedBlockingQueue.h"
 
+#include <media/MediaSource.h>
 #include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaSource.h>
 
 #include <utils/List.h>
 #include <utils/Errors.h>
@@ -123,7 +123,7 @@
 class WebmFrameMediaSourceThread: public WebmFrameSourceThread {
 public:
     WebmFrameMediaSourceThread(
-            const sp<IMediaSource>& source,
+            const sp<MediaSource>& source,
             int type,
             LinkedBlockingQueue<const sp<WebmFrame> >& sink,
             uint64_t timeCodeScale,
@@ -142,7 +142,7 @@
     }
 
 private:
-    const sp<IMediaSource> mSource;
+    const sp<MediaSource> mSource;
     const uint64_t mTimeCodeScale;
     uint64_t mStartTimeUs;
 
diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
index d6c6930..4d73eb8 100644
--- a/media/libstagefright/webm/WebmWriter.cpp
+++ b/media/libstagefright/webm/WebmWriter.cpp
@@ -360,7 +360,7 @@
     return err;
 }
 
-status_t WebmWriter::addSource(const sp<IMediaSource> &source) {
+status_t WebmWriter::addSource(const sp<MediaSource> &source) {
     Mutex::Autolock l(mLock);
     if (mStarted) {
         ALOGE("Attempt to add source AFTER recording is started");
diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/WebmWriter.h
index 9f3b19f..ffe4c79 100644
--- a/media/libstagefright/webm/WebmWriter.h
+++ b/media/libstagefright/webm/WebmWriter.h
@@ -21,7 +21,7 @@
 #include "WebmFrameThread.h"
 #include "LinkedBlockingQueue.h"
 
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
 #include <media/stagefright/MediaWriter.h>
 
 #include <utils/Errors.h>
@@ -40,7 +40,7 @@
     ~WebmWriter() { reset(); }
 
 
-    virtual status_t addSource(const sp<IMediaSource> &source);
+    virtual status_t addSource(const sp<MediaSource> &source);
     virtual status_t start(MetaData *param = NULL);
     virtual status_t stop();
     virtual status_t pause();
@@ -85,7 +85,7 @@
         const char *mName;
         sp<WebmElement> (*mMakeTrack)(const sp<MetaData>&);
 
-        sp<IMediaSource> mSource;
+        sp<MediaSource> mSource;
         sp<WebmElement> mTrackEntry;
         sp<WebmFrameSourceThread> mThread;
         LinkedBlockingQueue<const sp<WebmFrame> > mSink;
diff --git a/media/libstagefright/wifi-display/Android.bp b/media/libstagefright/wifi-display/Android.bp
deleted file mode 100644
index fb08c5b..0000000
--- a/media/libstagefright/wifi-display/Android.bp
+++ /dev/null
@@ -1,51 +0,0 @@
-cc_library_shared {
-    name: "libstagefright_wfd",
-
-    srcs: [
-        "MediaSender.cpp",
-        "Parameters.cpp",
-        "rtp/RTPSender.cpp",
-        "source/Converter.cpp",
-        "source/MediaPuller.cpp",
-        "source/PlaybackSession.cpp",
-        "source/RepeaterSource.cpp",
-        "source/TSPacketizer.cpp",
-        "source/WifiDisplaySource.cpp",
-        "VideoFormats.cpp",
-    ],
-
-    include_dirs: [
-        "frameworks/av/media/libstagefright",
-        "frameworks/native/include/media/openmax",
-        "frameworks/native/include/media/hardware",
-        "frameworks/av/media/libstagefright/mpeg2ts",
-    ],
-
-    shared_libs: [
-        "libbinder",
-        "libcutils",
-        "liblog",
-        "libmedia",
-        "libstagefright",
-        "libstagefright_foundation",
-        "libui",
-        "libgui",
-        "libutils",
-    ],
-
-    cflags: [
-        "-Wno-multichar",
-        "-Werror",
-        "-Wall",
-    ],
-
-    sanitize: {
-        misc_undefined: [
-            "signed-integer-overflow",
-        ],
-        cfi: true,
-        diag: {
-            cfi: true,
-        },
-    },
-}
diff --git a/media/libstagefright/wifi-display/MediaSender.cpp b/media/libstagefright/wifi-display/MediaSender.cpp
deleted file mode 100644
index cc412f5..0000000
--- a/media/libstagefright/wifi-display/MediaSender.cpp
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Copyright 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaSender"
-#include <utils/Log.h>
-
-#include "MediaSender.h"
-
-#include "rtp/RTPSender.h"
-#include "source/TSPacketizer.h"
-
-#include "include/avc_utils.h"
-
-#include <media/IHDCP.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/ANetworkSession.h>
-#include <ui/GraphicBuffer.h>
-
-namespace android {
-
-MediaSender::MediaSender(
-        const sp<ANetworkSession> &netSession,
-        const sp<AMessage> &notify)
-    : mNetSession(netSession),
-      mNotify(notify),
-      mMode(MODE_UNDEFINED),
-      mGeneration(0),
-      mPrevTimeUs(-1ll),
-      mInitDoneCount(0),
-      mLogFile(NULL) {
-    // mLogFile = fopen("/data/misc/log.ts", "wb");
-}
-
-MediaSender::~MediaSender() {
-    if (mLogFile != NULL) {
-        fclose(mLogFile);
-        mLogFile = NULL;
-    }
-}
-
-status_t MediaSender::setHDCP(const sp<IHDCP> &hdcp) {
-    if (mMode != MODE_UNDEFINED) {
-        return INVALID_OPERATION;
-    }
-
-    mHDCP = hdcp;
-
-    return OK;
-}
-
-ssize_t MediaSender::addTrack(const sp<AMessage> &format, uint32_t flags) {
-    if (mMode != MODE_UNDEFINED) {
-        return INVALID_OPERATION;
-    }
-
-    TrackInfo info;
-    info.mFormat = format;
-    info.mFlags = flags;
-    info.mPacketizerTrackIndex = -1;
-
-    AString mime;
-    CHECK(format->findString("mime", &mime));
-    info.mIsAudio = !strncasecmp("audio/", mime.c_str(), 6);
-
-    size_t index = mTrackInfos.size();
-    mTrackInfos.push_back(info);
-
-    return index;
-}
-
-status_t MediaSender::initAsync(
-        ssize_t trackIndex,
-        const char *remoteHost,
-        int32_t remoteRTPPort,
-        RTPSender::TransportMode rtpMode,
-        int32_t remoteRTCPPort,
-        RTPSender::TransportMode rtcpMode,
-        int32_t *localRTPPort) {
-    if (trackIndex < 0) {
-        if (mMode != MODE_UNDEFINED) {
-            return INVALID_OPERATION;
-        }
-
-        uint32_t flags = 0;
-        if (mHDCP != NULL) {
-            // XXX Determine proper HDCP version.
-            flags |= TSPacketizer::EMIT_HDCP20_DESCRIPTOR;
-        }
-        mTSPacketizer = new TSPacketizer(flags);
-
-        status_t err = OK;
-        for (size_t i = 0; i < mTrackInfos.size(); ++i) {
-            TrackInfo *info = &mTrackInfos.editItemAt(i);
-
-            ssize_t packetizerTrackIndex =
-                mTSPacketizer->addTrack(info->mFormat);
-
-            if (packetizerTrackIndex < 0) {
-                err = packetizerTrackIndex;
-                break;
-            }
-
-            info->mPacketizerTrackIndex = packetizerTrackIndex;
-        }
-
-        if (err == OK) {
-            sp<AMessage> notify = new AMessage(kWhatSenderNotify, this);
-            notify->setInt32("generation", mGeneration);
-            mTSSender = new RTPSender(mNetSession, notify);
-            looper()->registerHandler(mTSSender);
-
-            err = mTSSender->initAsync(
-                    remoteHost,
-                    remoteRTPPort,
-                    rtpMode,
-                    remoteRTCPPort,
-                    rtcpMode,
-                    localRTPPort);
-
-            if (err != OK) {
-                looper()->unregisterHandler(mTSSender->id());
-                mTSSender.clear();
-            }
-        }
-
-        if (err != OK) {
-            for (size_t i = 0; i < mTrackInfos.size(); ++i) {
-                TrackInfo *info = &mTrackInfos.editItemAt(i);
-                info->mPacketizerTrackIndex = -1;
-            }
-
-            mTSPacketizer.clear();
-            return err;
-        }
-
-        mMode = MODE_TRANSPORT_STREAM;
-        mInitDoneCount = 1;
-
-        return OK;
-    }
-
-    if (mMode == MODE_TRANSPORT_STREAM) {
-        return INVALID_OPERATION;
-    }
-
-    if ((size_t)trackIndex >= mTrackInfos.size()) {
-        return -ERANGE;
-    }
-
-    TrackInfo *info = &mTrackInfos.editItemAt(trackIndex);
-
-    if (info->mSender != NULL) {
-        return INVALID_OPERATION;
-    }
-
-    sp<AMessage> notify = new AMessage(kWhatSenderNotify, this);
-    notify->setInt32("generation", mGeneration);
-    notify->setSize("trackIndex", trackIndex);
-
-    info->mSender = new RTPSender(mNetSession, notify);
-    looper()->registerHandler(info->mSender);
-
-    status_t err = info->mSender->initAsync(
-            remoteHost,
-            remoteRTPPort,
-            rtpMode,
-            remoteRTCPPort,
-            rtcpMode,
-            localRTPPort);
-
-    if (err != OK) {
-        looper()->unregisterHandler(info->mSender->id());
-        info->mSender.clear();
-
-        return err;
-    }
-
-    if (mMode == MODE_UNDEFINED) {
-        mInitDoneCount = mTrackInfos.size();
-    }
-
-    mMode = MODE_ELEMENTARY_STREAMS;
-
-    return OK;
-}
-
-status_t MediaSender::queueAccessUnit(
-        size_t trackIndex, const sp<ABuffer> &accessUnit) {
-    if (mMode == MODE_UNDEFINED) {
-        return INVALID_OPERATION;
-    }
-
-    if (trackIndex >= mTrackInfos.size()) {
-        return -ERANGE;
-    }
-
-    if (mMode == MODE_TRANSPORT_STREAM) {
-        TrackInfo *info = &mTrackInfos.editItemAt(trackIndex);
-        info->mAccessUnits.push_back(accessUnit);
-
-        mTSPacketizer->extractCSDIfNecessary(info->mPacketizerTrackIndex);
-
-        for (;;) {
-            ssize_t minTrackIndex = -1;
-            int64_t minTimeUs = -1ll;
-
-            for (size_t i = 0; i < mTrackInfos.size(); ++i) {
-                const TrackInfo &info = mTrackInfos.itemAt(i);
-
-                if (info.mAccessUnits.empty()) {
-                    minTrackIndex = -1;
-                    minTimeUs = -1ll;
-                    break;
-                }
-
-                int64_t timeUs;
-                const sp<ABuffer> &accessUnit = *info.mAccessUnits.begin();
-                CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
-                if (minTrackIndex < 0 || timeUs < minTimeUs) {
-                    minTrackIndex = i;
-                    minTimeUs = timeUs;
-                }
-            }
-
-            if (minTrackIndex < 0) {
-                return OK;
-            }
-
-            TrackInfo *info = &mTrackInfos.editItemAt(minTrackIndex);
-            sp<ABuffer> accessUnit = *info->mAccessUnits.begin();
-            info->mAccessUnits.erase(info->mAccessUnits.begin());
-
-            sp<ABuffer> tsPackets;
-            status_t err = packetizeAccessUnit(
-                    minTrackIndex, accessUnit, &tsPackets);
-
-            if (err == OK) {
-                if (mLogFile != NULL) {
-                    fwrite(tsPackets->data(), 1, tsPackets->size(), mLogFile);
-                }
-
-                int64_t timeUs;
-                CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-                tsPackets->meta()->setInt64("timeUs", timeUs);
-
-                err = mTSSender->queueBuffer(
-                        tsPackets,
-                        33 /* packetType */,
-                        RTPSender::PACKETIZATION_TRANSPORT_STREAM);
-            }
-
-            if (err != OK) {
-                return err;
-            }
-        }
-    }
-
-    TrackInfo *info = &mTrackInfos.editItemAt(trackIndex);
-
-    return info->mSender->queueBuffer(
-            accessUnit,
-            info->mIsAudio ? 96 : 97 /* packetType */,
-            info->mIsAudio
-                ? RTPSender::PACKETIZATION_AAC : RTPSender::PACKETIZATION_H264);
-}
-
-void MediaSender::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        case kWhatSenderNotify:
-        {
-            int32_t generation;
-            CHECK(msg->findInt32("generation", &generation));
-            if (generation != mGeneration) {
-                break;
-            }
-
-            onSenderNotify(msg);
-            break;
-        }
-
-        default:
-            TRESPASS();
-    }
-}
-
-void MediaSender::onSenderNotify(const sp<AMessage> &msg) {
-    int32_t what;
-    CHECK(msg->findInt32("what", &what));
-
-    switch (what) {
-        case RTPSender::kWhatInitDone:
-        {
-            --mInitDoneCount;
-
-            int32_t err;
-            CHECK(msg->findInt32("err", &err));
-
-            if (err != OK) {
-                notifyInitDone(err);
-                ++mGeneration;
-                break;
-            }
-
-            if (mInitDoneCount == 0) {
-                notifyInitDone(OK);
-            }
-            break;
-        }
-
-        case RTPSender::kWhatError:
-        {
-            int32_t err;
-            CHECK(msg->findInt32("err", &err));
-
-            notifyError(err);
-            break;
-        }
-
-        case kWhatNetworkStall:
-        {
-            size_t numBytesQueued;
-            CHECK(msg->findSize("numBytesQueued", &numBytesQueued));
-
-            notifyNetworkStall(numBytesQueued);
-            break;
-        }
-
-        case kWhatInformSender:
-        {
-            int64_t avgLatencyUs;
-            CHECK(msg->findInt64("avgLatencyUs", &avgLatencyUs));
-
-            int64_t maxLatencyUs;
-            CHECK(msg->findInt64("maxLatencyUs", &maxLatencyUs));
-
-            sp<AMessage> notify = mNotify->dup();
-            notify->setInt32("what", kWhatInformSender);
-            notify->setInt64("avgLatencyUs", avgLatencyUs);
-            notify->setInt64("maxLatencyUs", maxLatencyUs);
-            notify->post();
-            break;
-        }
-
-        default:
-            TRESPASS();
-    }
-}
-
-void MediaSender::notifyInitDone(status_t err) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatInitDone);
-    notify->setInt32("err", err);
-    notify->post();
-}
-
-void MediaSender::notifyError(status_t err) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatError);
-    notify->setInt32("err", err);
-    notify->post();
-}
-
-void MediaSender::notifyNetworkStall(size_t numBytesQueued) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatNetworkStall);
-    notify->setSize("numBytesQueued", numBytesQueued);
-    notify->post();
-}
-
-status_t MediaSender::packetizeAccessUnit(
-        size_t trackIndex,
-        sp<ABuffer> accessUnit,
-        sp<ABuffer> *tsPackets) {
-    const TrackInfo &info = mTrackInfos.itemAt(trackIndex);
-
-    uint32_t flags = 0;
-
-    bool isHDCPEncrypted = false;
-    uint64_t inputCTR;
-    uint8_t HDCP_private_data[16];
-
-    bool manuallyPrependSPSPPS =
-        !info.mIsAudio
-        && (info.mFlags & FLAG_MANUALLY_PREPEND_SPS_PPS)
-        && IsIDR(accessUnit);
-
-    if (mHDCP != NULL && !info.mIsAudio) {
-        isHDCPEncrypted = true;
-
-        if (manuallyPrependSPSPPS) {
-            accessUnit = mTSPacketizer->prependCSD(
-                    info.mPacketizerTrackIndex, accessUnit);
-        }
-
-        status_t err;
-        native_handle_t* handle;
-        if (accessUnit->meta()->findPointer("handle", (void**)&handle)
-                && handle != NULL) {
-            int32_t rangeLength, rangeOffset;
-            sp<AMessage> notify;
-            CHECK(accessUnit->meta()->findInt32("rangeOffset", &rangeOffset));
-            CHECK(accessUnit->meta()->findInt32("rangeLength", &rangeLength));
-            CHECK(accessUnit->meta()->findMessage("notify", &notify)
-                    && notify != NULL);
-            CHECK_GE((int32_t)accessUnit->size(), rangeLength);
-
-            sp<GraphicBuffer> grbuf(new GraphicBuffer(
-                    rangeOffset + rangeLength /* width */, 1 /* height */,
-                    HAL_PIXEL_FORMAT_Y8, 1 /* layerCount */,
-                    GRALLOC_USAGE_HW_VIDEO_ENCODER,
-                    rangeOffset + rangeLength /* stride */, handle,
-                    false /* keepOwnership */));
-
-            err = mHDCP->encryptNative(
-                    grbuf, rangeOffset, rangeLength,
-                    trackIndex  /* streamCTR */,
-                    &inputCTR,
-                    accessUnit->data());
-            notify->post();
-        } else {
-            err = mHDCP->encrypt(
-                    accessUnit->data(), accessUnit->size(),
-                    trackIndex  /* streamCTR */,
-                    &inputCTR,
-                    accessUnit->data());
-        }
-
-        if (err != OK) {
-            ALOGE("Failed to HDCP-encrypt media data (err %d)",
-                  err);
-
-            return err;
-        }
-
-        HDCP_private_data[0] = 0x00;
-
-        HDCP_private_data[1] =
-            (((trackIndex >> 30) & 3) << 1) | 1;
-
-        HDCP_private_data[2] = (trackIndex >> 22) & 0xff;
-
-        HDCP_private_data[3] =
-            (((trackIndex >> 15) & 0x7f) << 1) | 1;
-
-        HDCP_private_data[4] = (trackIndex >> 7) & 0xff;
-
-        HDCP_private_data[5] =
-            ((trackIndex & 0x7f) << 1) | 1;
-
-        HDCP_private_data[6] = 0x00;
-
-        HDCP_private_data[7] =
-            (((inputCTR >> 60) & 0x0f) << 1) | 1;
-
-        HDCP_private_data[8] = (inputCTR >> 52) & 0xff;
-
-        HDCP_private_data[9] =
-            (((inputCTR >> 45) & 0x7f) << 1) | 1;
-
-        HDCP_private_data[10] = (inputCTR >> 37) & 0xff;
-
-        HDCP_private_data[11] =
-            (((inputCTR >> 30) & 0x7f) << 1) | 1;
-
-        HDCP_private_data[12] = (inputCTR >> 22) & 0xff;
-
-        HDCP_private_data[13] =
-            (((inputCTR >> 15) & 0x7f) << 1) | 1;
-
-        HDCP_private_data[14] = (inputCTR >> 7) & 0xff;
-
-        HDCP_private_data[15] =
-            ((inputCTR & 0x7f) << 1) | 1;
-
-        flags |= TSPacketizer::IS_ENCRYPTED;
-    } else if (manuallyPrependSPSPPS) {
-        flags |= TSPacketizer::PREPEND_SPS_PPS_TO_IDR_FRAMES;
-    }
-
-    int64_t timeUs = ALooper::GetNowUs();
-    if (mPrevTimeUs < 0ll || mPrevTimeUs + 100000ll <= timeUs) {
-        flags |= TSPacketizer::EMIT_PCR;
-        flags |= TSPacketizer::EMIT_PAT_AND_PMT;
-
-        mPrevTimeUs = timeUs;
-    }
-
-    mTSPacketizer->packetize(
-            info.mPacketizerTrackIndex,
-            accessUnit,
-            tsPackets,
-            flags,
-            !isHDCPEncrypted ? NULL : HDCP_private_data,
-            !isHDCPEncrypted ? 0 : sizeof(HDCP_private_data),
-            info.mIsAudio ? 2 : 0 /* numStuffingBytes */);
-
-    return OK;
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/wifi-display/MediaSender.h b/media/libstagefright/wifi-display/MediaSender.h
deleted file mode 100644
index 04538ea..0000000
--- a/media/libstagefright/wifi-display/MediaSender.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef MEDIA_SENDER_H_
-
-#define MEDIA_SENDER_H_
-
-#include "rtp/RTPSender.h"
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AHandler.h>
-#include <utils/Errors.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-struct ABuffer;
-struct ANetworkSession;
-struct AMessage;
-struct IHDCP;
-struct TSPacketizer;
-
-// This class facilitates sending of data from one or more media tracks
-// through one or more RTP channels, either providing a 1:1 mapping from
-// track to RTP channel or muxing all tracks into a single RTP channel and
-// using transport stream encapsulation.
-// Optionally the (video) data is encrypted using the provided hdcp object.
-struct MediaSender : public AHandler {
-    enum {
-        kWhatInitDone,
-        kWhatError,
-        kWhatNetworkStall,
-        kWhatInformSender,
-    };
-
-    MediaSender(
-            const sp<ANetworkSession> &netSession,
-            const sp<AMessage> &notify);
-
-    status_t setHDCP(const sp<IHDCP> &hdcp);
-
-    enum FlagBits {
-        FLAG_MANUALLY_PREPEND_SPS_PPS = 1,
-    };
-    ssize_t addTrack(const sp<AMessage> &format, uint32_t flags);
-
-    // If trackIndex == -1, initialize for transport stream muxing.
-    status_t initAsync(
-            ssize_t trackIndex,
-            const char *remoteHost,
-            int32_t remoteRTPPort,
-            RTPSender::TransportMode rtpMode,
-            int32_t remoteRTCPPort,
-            RTPSender::TransportMode rtcpMode,
-            int32_t *localRTPPort);
-
-    status_t queueAccessUnit(
-            size_t trackIndex, const sp<ABuffer> &accessUnit);
-
-protected:
-    virtual void onMessageReceived(const sp<AMessage> &msg);
-    virtual ~MediaSender();
-
-private:
-    enum {
-        kWhatSenderNotify,
-    };
-
-    enum Mode {
-        MODE_UNDEFINED,
-        MODE_TRANSPORT_STREAM,
-        MODE_ELEMENTARY_STREAMS,
-    };
-
-    struct TrackInfo {
-        sp<AMessage> mFormat;
-        uint32_t mFlags;
-        sp<RTPSender> mSender;
-        List<sp<ABuffer> > mAccessUnits;
-        ssize_t mPacketizerTrackIndex;
-        bool mIsAudio;
-    };
-
-    sp<ANetworkSession> mNetSession;
-    sp<AMessage> mNotify;
-
-    sp<IHDCP> mHDCP;
-
-    Mode mMode;
-    int32_t mGeneration;
-
-    Vector<TrackInfo> mTrackInfos;
-
-    sp<TSPacketizer> mTSPacketizer;
-    sp<RTPSender> mTSSender;
-    int64_t mPrevTimeUs;
-
-    size_t mInitDoneCount;
-
-    FILE *mLogFile;
-
-    void onSenderNotify(const sp<AMessage> &msg);
-
-    void notifyInitDone(status_t err);
-    void notifyError(status_t err);
-    void notifyNetworkStall(size_t numBytesQueued);
-
-    status_t packetizeAccessUnit(
-            size_t trackIndex,
-            sp<ABuffer> accessUnit,
-            sp<ABuffer> *tsPackets);
-
-    DISALLOW_EVIL_CONSTRUCTORS(MediaSender);
-};
-
-}  // namespace android
-
-#endif  // MEDIA_SENDER_H_
-
diff --git a/media/libstagefright/wifi-display/Parameters.cpp b/media/libstagefright/wifi-display/Parameters.cpp
deleted file mode 100644
index d2a61ea..0000000
--- a/media/libstagefright/wifi-display/Parameters.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 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 "Parameters.h"
-
-#include <media/stagefright/MediaErrors.h>
-
-namespace android {
-
-// static
-sp<Parameters> Parameters::Parse(const char *data, size_t size) {
-    sp<Parameters> params = new Parameters;
-    status_t err = params->parse(data, size);
-
-    if (err != OK) {
-        return NULL;
-    }
-
-    return params;
-}
-
-Parameters::Parameters() {}
-
-Parameters::~Parameters() {}
-
-status_t Parameters::parse(const char *data, size_t size) {
-    size_t i = 0;
-    while (i < size) {
-        size_t nameStart = i;
-        while (i < size && data[i] != ':') {
-            ++i;
-        }
-
-        if (i == size || i == nameStart) {
-            return ERROR_MALFORMED;
-        }
-
-        AString name(&data[nameStart], i - nameStart);
-        name.trim();
-        name.tolower();
-
-        ++i;
-
-        size_t valueStart = i;
-
-        while (i + 1 < size && (data[i] != '\r' || data[i + 1] != '\n')) {
-            ++i;
-        }
-
-        AString value(&data[valueStart], i - valueStart);
-        value.trim();
-
-        mDict.add(name, value);
-
-        while (i + 1 < size && data[i] == '\r' && data[i + 1] == '\n') {
-            i += 2;
-        }
-    }
-
-    return OK;
-}
-
-bool Parameters::findParameter(const char *name, AString *value) const {
-    AString key = name;
-    key.tolower();
-
-    ssize_t index = mDict.indexOfKey(key);
-
-    if (index < 0) {
-        value->clear();
-
-        return false;
-    }
-
-    *value = mDict.valueAt(index);
-    return true;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/wifi-display/Parameters.h b/media/libstagefright/wifi-display/Parameters.h
deleted file mode 100644
index a5e787e..0000000
--- a/media/libstagefright/wifi-display/Parameters.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 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 <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AString.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-struct Parameters : public RefBase {
-    static sp<Parameters> Parse(const char *data, size_t size);
-
-    bool findParameter(const char *name, AString *value) const;
-
-protected:
-    virtual ~Parameters();
-
-private:
-    KeyedVector<AString, AString> mDict;
-
-    Parameters();
-    status_t parse(const char *data, size_t size);
-
-    DISALLOW_EVIL_CONSTRUCTORS(Parameters);
-};
-
-}  // namespace android
diff --git a/media/libstagefright/wifi-display/VideoFormats.cpp b/media/libstagefright/wifi-display/VideoFormats.cpp
deleted file mode 100644
index dbc511c..0000000
--- a/media/libstagefright/wifi-display/VideoFormats.cpp
+++ /dev/null
@@ -1,550 +0,0 @@
-/*
- * Copyright 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "VideoFormats"
-#include <utils/Log.h>
-
-#include "VideoFormats.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace android {
-
-// static
-const VideoFormats::config_t VideoFormats::mResolutionTable[][32] = {
-    {
-        // CEA Resolutions
-        { 640, 480, 60, false, 0, 0},
-        { 720, 480, 60, false, 0, 0},
-        { 720, 480, 60, true, 0, 0},
-        { 720, 576, 50, false, 0, 0},
-        { 720, 576, 50, true, 0, 0},
-        { 1280, 720, 30, false, 0, 0},
-        { 1280, 720, 60, false, 0, 0},
-        { 1920, 1080, 30, false, 0, 0},
-        { 1920, 1080, 60, false, 0, 0},
-        { 1920, 1080, 60, true, 0, 0},
-        { 1280, 720, 25, false, 0, 0},
-        { 1280, 720, 50, false, 0, 0},
-        { 1920, 1080, 25, false, 0, 0},
-        { 1920, 1080, 50, false, 0, 0},
-        { 1920, 1080, 50, true, 0, 0},
-        { 1280, 720, 24, false, 0, 0},
-        { 1920, 1080, 24, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-    },
-    {
-        // VESA Resolutions
-        { 800, 600, 30, false, 0, 0},
-        { 800, 600, 60, false, 0, 0},
-        { 1024, 768, 30, false, 0, 0},
-        { 1024, 768, 60, false, 0, 0},
-        { 1152, 864, 30, false, 0, 0},
-        { 1152, 864, 60, false, 0, 0},
-        { 1280, 768, 30, false, 0, 0},
-        { 1280, 768, 60, false, 0, 0},
-        { 1280, 800, 30, false, 0, 0},
-        { 1280, 800, 60, false, 0, 0},
-        { 1360, 768, 30, false, 0, 0},
-        { 1360, 768, 60, false, 0, 0},
-        { 1366, 768, 30, false, 0, 0},
-        { 1366, 768, 60, false, 0, 0},
-        { 1280, 1024, 30, false, 0, 0},
-        { 1280, 1024, 60, false, 0, 0},
-        { 1400, 1050, 30, false, 0, 0},
-        { 1400, 1050, 60, false, 0, 0},
-        { 1440, 900, 30, false, 0, 0},
-        { 1440, 900, 60, false, 0, 0},
-        { 1600, 900, 30, false, 0, 0},
-        { 1600, 900, 60, false, 0, 0},
-        { 1600, 1200, 30, false, 0, 0},
-        { 1600, 1200, 60, false, 0, 0},
-        { 1680, 1024, 30, false, 0, 0},
-        { 1680, 1024, 60, false, 0, 0},
-        { 1680, 1050, 30, false, 0, 0},
-        { 1680, 1050, 60, false, 0, 0},
-        { 1920, 1200, 30, false, 0, 0},
-        { 1920, 1200, 60, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-    },
-    {
-        // HH Resolutions
-        { 800, 480, 30, false, 0, 0},
-        { 800, 480, 60, false, 0, 0},
-        { 854, 480, 30, false, 0, 0},
-        { 854, 480, 60, false, 0, 0},
-        { 864, 480, 30, false, 0, 0},
-        { 864, 480, 60, false, 0, 0},
-        { 640, 360, 30, false, 0, 0},
-        { 640, 360, 60, false, 0, 0},
-        { 960, 540, 30, false, 0, 0},
-        { 960, 540, 60, false, 0, 0},
-        { 848, 480, 30, false, 0, 0},
-        { 848, 480, 60, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-        { 0, 0, 0, false, 0, 0},
-    }
-};
-
-VideoFormats::VideoFormats() {
-    memcpy(mConfigs, mResolutionTable, sizeof(mConfigs));
-
-    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
-        mResolutionEnabled[i] = 0;
-    }
-
-    setNativeResolution(RESOLUTION_CEA, 0);  // default to 640x480 p60
-}
-
-void VideoFormats::setNativeResolution(ResolutionType type, size_t index) {
-    CHECK_LT(type, kNumResolutionTypes);
-    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
-
-    mNativeType = type;
-    mNativeIndex = index;
-
-    setResolutionEnabled(type, index);
-}
-
-void VideoFormats::getNativeResolution(
-        ResolutionType *type, size_t *index) const {
-    *type = mNativeType;
-    *index = mNativeIndex;
-}
-
-void VideoFormats::disableAll() {
-    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
-        mResolutionEnabled[i] = 0;
-        for (size_t j = 0; j < 32; j++) {
-            mConfigs[i][j].profile = mConfigs[i][j].level = 0;
-        }
-    }
-}
-
-void VideoFormats::enableAll() {
-    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
-        mResolutionEnabled[i] = 0xffffffff;
-        for (size_t j = 0; j < 32; j++) {
-            mConfigs[i][j].profile = (1ul << PROFILE_CBP);
-            mConfigs[i][j].level = (1ul << LEVEL_31);
-        }
-    }
-}
-
-void VideoFormats::enableResolutionUpto(
-        ResolutionType type, size_t index,
-        ProfileType profile, LevelType level) {
-    size_t width, height, fps, score;
-    bool interlaced;
-    if (!GetConfiguration(type, index, &width, &height,
-            &fps, &interlaced)) {
-        ALOGE("Maximum resolution not found!");
-        return;
-    }
-    score = width * height * fps * (!interlaced + 1);
-    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
-        for (size_t j = 0; j < 32; j++) {
-            if (GetConfiguration((ResolutionType)i, j,
-                    &width, &height, &fps, &interlaced)
-                    && score >= width * height * fps * (!interlaced + 1)) {
-                setResolutionEnabled((ResolutionType)i, j);
-                setProfileLevel((ResolutionType)i, j, profile, level);
-            }
-        }
-    }
-}
-
-void VideoFormats::setResolutionEnabled(
-        ResolutionType type, size_t index, bool enabled) {
-    CHECK_LT(type, kNumResolutionTypes);
-    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
-
-    if (enabled) {
-        mResolutionEnabled[type] |= (1ul << index);
-        mConfigs[type][index].profile = (1ul << PROFILE_CBP);
-        mConfigs[type][index].level = (1ul << LEVEL_31);
-    } else {
-        mResolutionEnabled[type] &= ~(1ul << index);
-        mConfigs[type][index].profile = 0;
-        mConfigs[type][index].level = 0;
-    }
-}
-
-void VideoFormats::setProfileLevel(
-        ResolutionType type, size_t index,
-        ProfileType profile, LevelType level) {
-    CHECK_LT(type, kNumResolutionTypes);
-    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
-
-    mConfigs[type][index].profile = (1ul << profile);
-    mConfigs[type][index].level = (1ul << level);
-}
-
-void VideoFormats::getProfileLevel(
-        ResolutionType type, size_t index,
-        ProfileType *profile, LevelType *level) const{
-    CHECK_LT(type, kNumResolutionTypes);
-    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
-
-    int i, bestProfile = -1, bestLevel = -1;
-
-    for (i = 0; i < kNumProfileTypes; ++i) {
-        if (mConfigs[type][index].profile & (1ul << i)) {
-            bestProfile = i;
-        }
-    }
-
-    for (i = 0; i < kNumLevelTypes; ++i) {
-        if (mConfigs[type][index].level & (1ul << i)) {
-            bestLevel = i;
-        }
-    }
-
-    if (bestProfile == -1 || bestLevel == -1) {
-        ALOGE("Profile or level not set for resolution type %d, index %zu",
-                type, index);
-        bestProfile = PROFILE_CBP;
-        bestLevel = LEVEL_31;
-    }
-
-    *profile = (ProfileType) bestProfile;
-    *level = (LevelType) bestLevel;
-}
-
-bool VideoFormats::isResolutionEnabled(
-        ResolutionType type, size_t index) const {
-    CHECK_LT(type, kNumResolutionTypes);
-    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));
-
-    return mResolutionEnabled[type] & (1ul << index);
-}
-
-// static
-bool VideoFormats::GetConfiguration(
-        ResolutionType type,
-        size_t index,
-        size_t *width, size_t *height, size_t *framesPerSecond,
-        bool *interlaced) {
-    CHECK_LT(type, kNumResolutionTypes);
-
-    if (index >= 32) {
-        return false;
-    }
-
-    const config_t *config = &mResolutionTable[type][index];
-
-    if (config->width == 0) {
-        return false;
-    }
-
-    if (width) {
-        *width = config->width;
-    }
-
-    if (height) {
-        *height = config->height;
-    }
-
-    if (framesPerSecond) {
-        *framesPerSecond = config->framesPerSecond;
-    }
-
-    if (interlaced) {
-        *interlaced = config->interlaced;
-    }
-
-    return true;
-}
-
-bool VideoFormats::parseH264Codec(const char *spec) {
-    unsigned profile, level, res[3];
-
-    if (sscanf(
-            spec,
-            "%02x %02x %08X %08X %08X",
-            &profile,
-            &level,
-            &res[0],
-            &res[1],
-            &res[2]) != 5) {
-        return false;
-    }
-
-    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
-        for (size_t j = 0; j < 32; ++j) {
-            if (res[i] & (1ul << j)){
-                mResolutionEnabled[i] |= (1ul << j);
-                if (profile > mConfigs[i][j].profile) {
-                    // prefer higher profile (even if level is lower)
-                    mConfigs[i][j].profile = profile;
-                    mConfigs[i][j].level = level;
-                } else if (profile == mConfigs[i][j].profile &&
-                           level > mConfigs[i][j].level) {
-                    mConfigs[i][j].level = level;
-                }
-            }
-        }
-    }
-
-    return true;
-}
-
-// static
-bool VideoFormats::GetProfileLevel(
-        ProfileType profile, LevelType level, unsigned *profileIdc,
-        unsigned *levelIdc, unsigned *constraintSet) {
-    CHECK_LT(profile, kNumProfileTypes);
-    CHECK_LT(level, kNumLevelTypes);
-
-    static const unsigned kProfileIDC[kNumProfileTypes] = {
-        66,     // PROFILE_CBP
-        100,    // PROFILE_CHP
-    };
-
-    static const unsigned kLevelIDC[kNumLevelTypes] = {
-        31,     // LEVEL_31
-        32,     // LEVEL_32
-        40,     // LEVEL_40
-        41,     // LEVEL_41
-        42,     // LEVEL_42
-    };
-
-    static const unsigned kConstraintSet[kNumProfileTypes] = {
-        0xc0,   // PROFILE_CBP
-        0x0c,   // PROFILE_CHP
-    };
-
-    if (profileIdc) {
-        *profileIdc = kProfileIDC[profile];
-    }
-
-    if (levelIdc) {
-        *levelIdc = kLevelIDC[level];
-    }
-
-    if (constraintSet) {
-        *constraintSet = kConstraintSet[profile];
-    }
-
-    return true;
-}
-
-bool VideoFormats::parseFormatSpec(const char *spec) {
-    CHECK_EQ(kNumResolutionTypes, 3);
-
-    disableAll();
-
-    unsigned native, dummy;
-    size_t size = strlen(spec);
-    size_t offset = 0;
-
-    if (sscanf(spec, "%02x %02x ", &native, &dummy) != 2) {
-        return false;
-    }
-
-    offset += 6; // skip native and preferred-display-mode-supported
-    CHECK_LE(offset + 58, size);
-    while (offset < size) {
-        parseH264Codec(spec + offset);
-        offset += 60; // skip H.264-codec + ", "
-    }
-
-    mNativeIndex = native >> 3;
-    mNativeType = (ResolutionType)(native & 7);
-
-    bool success;
-    if (mNativeType >= kNumResolutionTypes) {
-        success = false;
-    } else {
-        success = GetConfiguration(
-                mNativeType, mNativeIndex, NULL, NULL, NULL, NULL);
-    }
-
-    if (!success) {
-        ALOGW("sink advertised an illegal native resolution, fortunately "
-              "this value is ignored for the time being...");
-    }
-
-    return true;
-}
-
-AString VideoFormats::getFormatSpec(bool forM4Message) const {
-    CHECK_EQ(kNumResolutionTypes, 3);
-
-    // wfd_video_formats:
-    // 1 byte "native"
-    // 1 byte "preferred-display-mode-supported" 0 or 1
-    // one or more avc codec structures
-    //   1 byte profile
-    //   1 byte level
-    //   4 byte CEA mask
-    //   4 byte VESA mask
-    //   4 byte HH mask
-    //   1 byte latency
-    //   2 byte min-slice-slice
-    //   2 byte slice-enc-params
-    //   1 byte framerate-control-support
-    //   max-hres (none or 2 byte)
-    //   max-vres (none or 2 byte)
-
-    return AStringPrintf(
-            "%02x 00 %02x %02x %08x %08x %08x 00 0000 0000 00 none none",
-            forM4Message ? 0x00 : ((mNativeIndex << 3) | mNativeType),
-            mConfigs[mNativeType][mNativeIndex].profile,
-            mConfigs[mNativeType][mNativeIndex].level,
-            mResolutionEnabled[0],
-            mResolutionEnabled[1],
-            mResolutionEnabled[2]);
-}
-
-// static
-bool VideoFormats::PickBestFormat(
-        const VideoFormats &sinkSupported,
-        const VideoFormats &sourceSupported,
-        ResolutionType *chosenType,
-        size_t *chosenIndex,
-        ProfileType *chosenProfile,
-        LevelType *chosenLevel) {
-#if 0
-    // Support for the native format is a great idea, the spec includes
-    // these features, but nobody supports it and the tests don't validate it.
-
-    ResolutionType nativeType;
-    size_t nativeIndex;
-    sinkSupported.getNativeResolution(&nativeType, &nativeIndex);
-    if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) {
-        if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) {
-            ALOGI("Choosing sink's native resolution");
-            *chosenType = nativeType;
-            *chosenIndex = nativeIndex;
-            return true;
-        }
-    } else {
-        ALOGW("Sink advertised native resolution that it doesn't "
-              "actually support... ignoring");
-    }
-
-    sourceSupported.getNativeResolution(&nativeType, &nativeIndex);
-    if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) {
-        if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) {
-            ALOGI("Choosing source's native resolution");
-            *chosenType = nativeType;
-            *chosenIndex = nativeIndex;
-            return true;
-        }
-    } else {
-        ALOGW("Source advertised native resolution that it doesn't "
-              "actually support... ignoring");
-    }
-#endif
-
-    bool first = true;
-    uint32_t bestScore = 0;
-    size_t bestType = 0;
-    size_t bestIndex = 0;
-    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
-        for (size_t j = 0; j < 32; ++j) {
-            size_t width, height, framesPerSecond;
-            bool interlaced;
-            if (!GetConfiguration(
-                        (ResolutionType)i,
-                        j,
-                        &width, &height, &framesPerSecond, &interlaced)) {
-                break;
-            }
-
-            if (!sinkSupported.isResolutionEnabled((ResolutionType)i, j)
-                    || !sourceSupported.isResolutionEnabled(
-                        (ResolutionType)i, j)) {
-                continue;
-            }
-
-            ALOGV("type %zu, index %zu, %zu x %zu %c%zu supported",
-                  i, j, width, height, interlaced ? 'i' : 'p', framesPerSecond);
-
-            uint32_t score = width * height * framesPerSecond;
-            if (!interlaced) {
-                score *= 2;
-            }
-
-            if (first || score > bestScore) {
-                bestScore = score;
-                bestType = i;
-                bestIndex = j;
-
-                first = false;
-            }
-        }
-    }
-
-    if (first) {
-        return false;
-    }
-
-    *chosenType = (ResolutionType)bestType;
-    *chosenIndex = bestIndex;
-
-    // Pick the best profile/level supported by both sink and source.
-    ProfileType srcProfile, sinkProfile;
-    LevelType srcLevel, sinkLevel;
-    sourceSupported.getProfileLevel(
-                        (ResolutionType)bestType, bestIndex,
-                        &srcProfile, &srcLevel);
-    sinkSupported.getProfileLevel(
-                        (ResolutionType)bestType, bestIndex,
-                        &sinkProfile, &sinkLevel);
-    *chosenProfile = srcProfile < sinkProfile ? srcProfile : sinkProfile;
-    *chosenLevel = srcLevel < sinkLevel ? srcLevel : sinkLevel;
-
-    return true;
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/wifi-display/VideoFormats.h b/media/libstagefright/wifi-display/VideoFormats.h
deleted file mode 100644
index fd38fd1..0000000
--- a/media/libstagefright/wifi-display/VideoFormats.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef VIDEO_FORMATS_H_
-
-#define VIDEO_FORMATS_H_
-
-#include <media/stagefright/foundation/ABase.h>
-
-#include <stdint.h>
-
-namespace android {
-
-struct AString;
-
-// This class encapsulates that video resolution capabilities of a wfd source
-// or sink as outlined in the wfd specs. Currently three sets of resolutions
-// are specified, each of which supports up to 32 resolutions.
-// In addition to its capabilities each sink/source also publishes its
-// "native" resolution, presumably one that is preferred among all others
-// because it wouldn't require any scaling and directly corresponds to the
-// display capabilities/pixels.
-struct VideoFormats {
-    VideoFormats();
-
-    struct config_t {
-        size_t width, height, framesPerSecond;
-        bool interlaced;
-        unsigned char profile, level;
-    };
-
-    enum ProfileType {
-        PROFILE_CBP = 0,
-        PROFILE_CHP,
-        kNumProfileTypes,
-    };
-
-    enum LevelType {
-        LEVEL_31 = 0,
-        LEVEL_32,
-        LEVEL_40,
-        LEVEL_41,
-        LEVEL_42,
-        kNumLevelTypes,
-    };
-
-    enum ResolutionType {
-        RESOLUTION_CEA,
-        RESOLUTION_VESA,
-        RESOLUTION_HH,
-        kNumResolutionTypes,
-    };
-
-    void setNativeResolution(ResolutionType type, size_t index);
-    void getNativeResolution(ResolutionType *type, size_t *index) const;
-
-    void disableAll();
-    void enableAll();
-    void enableResolutionUpto(
-            ResolutionType type, size_t index,
-            ProfileType profile, LevelType level);
-
-    void setResolutionEnabled(
-            ResolutionType type, size_t index, bool enabled = true);
-
-    bool isResolutionEnabled(ResolutionType type, size_t index) const;
-
-    void setProfileLevel(
-            ResolutionType type, size_t index,
-            ProfileType profile, LevelType level);
-
-    void getProfileLevel(
-            ResolutionType type, size_t index,
-            ProfileType *profile, LevelType *level) const;
-
-    static bool GetConfiguration(
-            ResolutionType type, size_t index,
-            size_t *width, size_t *height, size_t *framesPerSecond,
-            bool *interlaced);
-
-    static bool GetProfileLevel(
-            ProfileType profile, LevelType level,
-            unsigned *profileIdc, unsigned *levelIdc,
-            unsigned *constraintSet);
-
-    bool parseFormatSpec(const char *spec);
-    AString getFormatSpec(bool forM4Message = false) const;
-
-    static bool PickBestFormat(
-            const VideoFormats &sinkSupported,
-            const VideoFormats &sourceSupported,
-            ResolutionType *chosenType,
-            size_t *chosenIndex,
-            ProfileType *chosenProfile,
-            LevelType *chosenLevel);
-
-private:
-    bool parseH264Codec(const char *spec);
-    ResolutionType mNativeType;
-    size_t mNativeIndex;
-
-    uint32_t mResolutionEnabled[kNumResolutionTypes];
-    static const config_t mResolutionTable[kNumResolutionTypes][32];
-    config_t mConfigs[kNumResolutionTypes][32];
-
-    DISALLOW_EVIL_CONSTRUCTORS(VideoFormats);
-};
-
-}  // namespace android
-
-#endif  // VIDEO_FORMATS_H_
-
diff --git a/media/libstagefright/wifi-display/rtp/RTPBase.h b/media/libstagefright/wifi-display/rtp/RTPBase.h
deleted file mode 100644
index 194f1ee..0000000
--- a/media/libstagefright/wifi-display/rtp/RTPBase.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef RTP_BASE_H_
-
-#define RTP_BASE_H_
-
-namespace android {
-
-struct RTPBase {
-    enum PacketizationMode {
-        PACKETIZATION_TRANSPORT_STREAM,
-        PACKETIZATION_H264,
-        PACKETIZATION_AAC,
-        PACKETIZATION_NONE,
-    };
-
-    enum TransportMode {
-        TRANSPORT_UNDEFINED,
-        TRANSPORT_NONE,
-        TRANSPORT_UDP,
-        TRANSPORT_TCP,
-        TRANSPORT_TCP_INTERLEAVED,
-    };
-
-    // Really UDP _payload_ size
-    const unsigned int kMaxUDPPacketSize = 1472;   // 1472 good, 1473 bad on Android@Home
-
-    static int32_t PickRandomRTPPort();
-};
-
-}  // namespace android
-
-#endif  // RTP_BASE_H_
-
-
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
deleted file mode 100644
index ca9fdd2..0000000
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ /dev/null
@@ -1,808 +0,0 @@
-/*
- * Copyright 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "RTPSender"
-#include <utils/Log.h>
-
-#include "RTPSender.h"
-
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/ANetworkSession.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-
-#include "include/avc_utils.h"
-
-namespace android {
-
-RTPSender::RTPSender(
-        const sp<ANetworkSession> &netSession,
-        const sp<AMessage> &notify)
-    : mNetSession(netSession),
-      mNotify(notify),
-      mRTPMode(TRANSPORT_UNDEFINED),
-      mRTCPMode(TRANSPORT_UNDEFINED),
-      mRTPSessionID(0),
-      mRTCPSessionID(0),
-      mRTPConnected(false),
-      mRTCPConnected(false),
-      mLastNTPTime(0),
-      mLastRTPTime(0),
-      mNumRTPSent(0),
-      mNumRTPOctetsSent(0),
-      mNumSRsSent(0),
-      mRTPSeqNo(0),
-      mHistorySize(0) {
-}
-
-RTPSender::~RTPSender() {
-    if (mRTCPSessionID != 0) {
-        mNetSession->destroySession(mRTCPSessionID);
-        mRTCPSessionID = 0;
-    }
-
-    if (mRTPSessionID != 0) {
-        mNetSession->destroySession(mRTPSessionID);
-        mRTPSessionID = 0;
-    }
-}
-
-// static
-int32_t RTPBase::PickRandomRTPPort() {
-    // Pick an even integer in range [1024, 65534)
-
-    static const size_t kRange = (65534 - 1024) / 2;
-
-    return (int32_t)(((float)(kRange + 1) * rand()) / RAND_MAX) * 2 + 1024;
-}
-
-status_t RTPSender::initAsync(
-        const char *remoteHost,
-        int32_t remoteRTPPort,
-        TransportMode rtpMode,
-        int32_t remoteRTCPPort,
-        TransportMode rtcpMode,
-        int32_t *outLocalRTPPort) {
-    if (mRTPMode != TRANSPORT_UNDEFINED
-            || rtpMode == TRANSPORT_UNDEFINED
-            || rtpMode == TRANSPORT_NONE
-            || rtcpMode == TRANSPORT_UNDEFINED) {
-        return INVALID_OPERATION;
-    }
-
-    CHECK_NE(rtpMode, TRANSPORT_TCP_INTERLEAVED);
-    CHECK_NE(rtcpMode, TRANSPORT_TCP_INTERLEAVED);
-
-    if ((rtcpMode == TRANSPORT_NONE && remoteRTCPPort >= 0)
-            || (rtcpMode != TRANSPORT_NONE && remoteRTCPPort < 0)) {
-        return INVALID_OPERATION;
-    }
-
-    sp<AMessage> rtpNotify = new AMessage(kWhatRTPNotify, this);
-
-    sp<AMessage> rtcpNotify;
-    if (remoteRTCPPort >= 0) {
-        rtcpNotify = new AMessage(kWhatRTCPNotify, this);
-    }
-
-    CHECK_EQ(mRTPSessionID, 0);
-    CHECK_EQ(mRTCPSessionID, 0);
-
-    int32_t localRTPPort;
-
-    for (;;) {
-        localRTPPort = PickRandomRTPPort();
-
-        status_t err;
-        if (rtpMode == TRANSPORT_UDP) {
-            err = mNetSession->createUDPSession(
-                    localRTPPort,
-                    remoteHost,
-                    remoteRTPPort,
-                    rtpNotify,
-                    &mRTPSessionID);
-        } else {
-            CHECK_EQ(rtpMode, TRANSPORT_TCP);
-            err = mNetSession->createTCPDatagramSession(
-                    localRTPPort,
-                    remoteHost,
-                    remoteRTPPort,
-                    rtpNotify,
-                    &mRTPSessionID);
-        }
-
-        if (err != OK) {
-            continue;
-        }
-
-        if (remoteRTCPPort < 0) {
-            break;
-        }
-
-        if (rtcpMode == TRANSPORT_UDP) {
-            err = mNetSession->createUDPSession(
-                    localRTPPort + 1,
-                    remoteHost,
-                    remoteRTCPPort,
-                    rtcpNotify,
-                    &mRTCPSessionID);
-        } else {
-            CHECK_EQ(rtcpMode, TRANSPORT_TCP);
-            err = mNetSession->createTCPDatagramSession(
-                    localRTPPort + 1,
-                    remoteHost,
-                    remoteRTCPPort,
-                    rtcpNotify,
-                    &mRTCPSessionID);
-        }
-
-        if (err == OK) {
-            break;
-        }
-
-        mNetSession->destroySession(mRTPSessionID);
-        mRTPSessionID = 0;
-    }
-
-    if (rtpMode == TRANSPORT_UDP) {
-        mRTPConnected = true;
-    }
-
-    if (rtcpMode == TRANSPORT_UDP) {
-        mRTCPConnected = true;
-    }
-
-    mRTPMode = rtpMode;
-    mRTCPMode = rtcpMode;
-    *outLocalRTPPort = localRTPPort;
-
-    if (mRTPMode == TRANSPORT_UDP
-            && (mRTCPMode == TRANSPORT_UDP || mRTCPMode == TRANSPORT_NONE)) {
-        notifyInitDone(OK);
-    }
-
-    return OK;
-}
-
-status_t RTPSender::queueBuffer(
-        const sp<ABuffer> &buffer, uint8_t packetType, PacketizationMode mode) {
-    status_t err;
-
-    switch (mode) {
-        case PACKETIZATION_NONE:
-            err = queueRawPacket(buffer, packetType);
-            break;
-
-        case PACKETIZATION_TRANSPORT_STREAM:
-            err = queueTSPackets(buffer, packetType);
-            break;
-
-        case PACKETIZATION_H264:
-            err  = queueAVCBuffer(buffer, packetType);
-            break;
-
-        default:
-            TRESPASS();
-    }
-
-    return err;
-}
-
-status_t RTPSender::queueRawPacket(
-        const sp<ABuffer> &packet, uint8_t packetType) {
-    CHECK_LE(packet->size(), kMaxUDPPacketSize - 12);
-
-    int64_t timeUs;
-    CHECK(packet->meta()->findInt64("timeUs", &timeUs));
-
-    sp<ABuffer> udpPacket = new ABuffer(12 + packet->size());
-
-    udpPacket->setInt32Data(mRTPSeqNo);
-
-    uint8_t *rtp = udpPacket->data();
-    rtp[0] = 0x80;
-    rtp[1] = packetType;
-
-    rtp[2] = (mRTPSeqNo >> 8) & 0xff;
-    rtp[3] = mRTPSeqNo & 0xff;
-    ++mRTPSeqNo;
-
-    uint32_t rtpTime = (timeUs * 9) / 100ll;
-
-    rtp[4] = rtpTime >> 24;
-    rtp[5] = (rtpTime >> 16) & 0xff;
-    rtp[6] = (rtpTime >> 8) & 0xff;
-    rtp[7] = rtpTime & 0xff;
-
-    rtp[8] = kSourceID >> 24;
-    rtp[9] = (kSourceID >> 16) & 0xff;
-    rtp[10] = (kSourceID >> 8) & 0xff;
-    rtp[11] = kSourceID & 0xff;
-
-    memcpy(&rtp[12], packet->data(), packet->size());
-
-    return sendRTPPacket(
-            udpPacket,
-            true /* storeInHistory */,
-            true /* timeValid */,
-            ALooper::GetNowUs());
-}
-
-status_t RTPSender::queueTSPackets(
-        const sp<ABuffer> &tsPackets, uint8_t packetType) {
-    CHECK_EQ(0u, tsPackets->size() % 188);
-
-    int64_t timeUs;
-    CHECK(tsPackets->meta()->findInt64("timeUs", &timeUs));
-
-    size_t srcOffset = 0;
-    while (srcOffset < tsPackets->size()) {
-        sp<ABuffer> udpPacket =
-            new ABuffer(12 + kMaxNumTSPacketsPerRTPPacket * 188);
-
-        udpPacket->setInt32Data(mRTPSeqNo);
-
-        uint8_t *rtp = udpPacket->data();
-        rtp[0] = 0x80;
-        rtp[1] = packetType;
-
-        rtp[2] = (mRTPSeqNo >> 8) & 0xff;
-        rtp[3] = mRTPSeqNo & 0xff;
-        ++mRTPSeqNo;
-
-        int64_t nowUs = ALooper::GetNowUs();
-        uint32_t rtpTime = (nowUs * 9) / 100ll;
-
-        rtp[4] = rtpTime >> 24;
-        rtp[5] = (rtpTime >> 16) & 0xff;
-        rtp[6] = (rtpTime >> 8) & 0xff;
-        rtp[7] = rtpTime & 0xff;
-
-        rtp[8] = kSourceID >> 24;
-        rtp[9] = (kSourceID >> 16) & 0xff;
-        rtp[10] = (kSourceID >> 8) & 0xff;
-        rtp[11] = kSourceID & 0xff;
-
-        size_t numTSPackets = (tsPackets->size() - srcOffset) / 188;
-        if (numTSPackets > kMaxNumTSPacketsPerRTPPacket) {
-            numTSPackets = kMaxNumTSPacketsPerRTPPacket;
-        }
-
-        memcpy(&rtp[12], tsPackets->data() + srcOffset, numTSPackets * 188);
-
-        udpPacket->setRange(0, 12 + numTSPackets * 188);
-
-        srcOffset += numTSPackets * 188;
-        bool isLastPacket = (srcOffset == tsPackets->size());
-
-        status_t err = sendRTPPacket(
-                udpPacket,
-                true /* storeInHistory */,
-                isLastPacket /* timeValid */,
-                timeUs);
-
-        if (err != OK) {
-            return err;
-        }
-    }
-
-    return OK;
-}
-
-status_t RTPSender::queueAVCBuffer(
-        const sp<ABuffer> &accessUnit, uint8_t packetType) {
-    int64_t timeUs;
-    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
-    uint32_t rtpTime = (timeUs * 9 / 100ll);
-
-    List<sp<ABuffer> > packets;
-
-    sp<ABuffer> out = new ABuffer(kMaxUDPPacketSize);
-    size_t outBytesUsed = 12;  // Placeholder for RTP header.
-
-    const uint8_t *data = accessUnit->data();
-    size_t size = accessUnit->size();
-    const uint8_t *nalStart;
-    size_t nalSize;
-    while (getNextNALUnit(
-                &data, &size, &nalStart, &nalSize,
-                true /* startCodeFollows */) == OK) {
-        size_t bytesNeeded = nalSize + 2;
-        if (outBytesUsed == 12) {
-            ++bytesNeeded;
-        }
-
-        if (outBytesUsed + bytesNeeded > out->capacity()) {
-            bool emitSingleNALPacket = false;
-
-            if (outBytesUsed == 12
-                    && outBytesUsed + nalSize <= out->capacity()) {
-                // We haven't emitted anything into the current packet yet and
-                // this NAL unit fits into a single-NAL-unit-packet while
-                // it wouldn't have fit as part of a STAP-A packet.
-
-                memcpy(out->data() + outBytesUsed, nalStart, nalSize);
-                outBytesUsed += nalSize;
-
-                emitSingleNALPacket = true;
-            }
-
-            if (outBytesUsed > 12) {
-                out->setRange(0, outBytesUsed);
-                packets.push_back(out);
-                out = new ABuffer(kMaxUDPPacketSize);
-                outBytesUsed = 12;  // Placeholder for RTP header
-            }
-
-            if (emitSingleNALPacket) {
-                continue;
-            }
-        }
-
-        if (outBytesUsed + bytesNeeded <= out->capacity()) {
-            uint8_t *dst = out->data() + outBytesUsed;
-
-            if (outBytesUsed == 12) {
-                *dst++ = 24;  // STAP-A header
-            }
-
-            *dst++ = (nalSize >> 8) & 0xff;
-            *dst++ = nalSize & 0xff;
-            memcpy(dst, nalStart, nalSize);
-
-            outBytesUsed += bytesNeeded;
-            continue;
-        }
-
-        // This single NAL unit does not fit into a single RTP packet,
-        // we need to emit an FU-A.
-
-        CHECK_EQ(outBytesUsed, 12u);
-
-        uint8_t nalType = nalStart[0] & 0x1f;
-        uint8_t nri = (nalStart[0] >> 5) & 3;
-
-        size_t srcOffset = 1;
-        while (srcOffset < nalSize) {
-            size_t copy = out->capacity() - outBytesUsed - 2;
-            if (copy > nalSize - srcOffset) {
-                copy = nalSize - srcOffset;
-            }
-
-            uint8_t *dst = out->data() + outBytesUsed;
-            dst[0] = (nri << 5) | 28;
-
-            dst[1] = nalType;
-
-            if (srcOffset == 1) {
-                dst[1] |= 0x80;
-            }
-
-            if (srcOffset + copy == nalSize) {
-                dst[1] |= 0x40;
-            }
-
-            memcpy(&dst[2], nalStart + srcOffset, copy);
-            srcOffset += copy;
-
-            out->setRange(0, outBytesUsed + copy + 2);
-
-            packets.push_back(out);
-            out = new ABuffer(kMaxUDPPacketSize);
-            outBytesUsed = 12;  // Placeholder for RTP header
-        }
-    }
-
-    if (outBytesUsed > 12) {
-        out->setRange(0, outBytesUsed);
-        packets.push_back(out);
-    }
-
-    while (!packets.empty()) {
-        sp<ABuffer> out = *packets.begin();
-        packets.erase(packets.begin());
-
-        out->setInt32Data(mRTPSeqNo);
-
-        bool last = packets.empty();
-
-        uint8_t *dst = out->data();
-
-        dst[0] = 0x80;
-
-        dst[1] = packetType;
-        if (last) {
-            dst[1] |= 1 << 7;  // M-bit
-        }
-
-        dst[2] = (mRTPSeqNo >> 8) & 0xff;
-        dst[3] = mRTPSeqNo & 0xff;
-        ++mRTPSeqNo;
-
-        dst[4] = rtpTime >> 24;
-        dst[5] = (rtpTime >> 16) & 0xff;
-        dst[6] = (rtpTime >> 8) & 0xff;
-        dst[7] = rtpTime & 0xff;
-        dst[8] = kSourceID >> 24;
-        dst[9] = (kSourceID >> 16) & 0xff;
-        dst[10] = (kSourceID >> 8) & 0xff;
-        dst[11] = kSourceID & 0xff;
-
-        status_t err = sendRTPPacket(out, true /* storeInHistory */);
-
-        if (err != OK) {
-            return err;
-        }
-    }
-
-    return OK;
-}
-
-status_t RTPSender::sendRTPPacket(
-        const sp<ABuffer> &buffer, bool storeInHistory,
-        bool timeValid, int64_t timeUs) {
-    CHECK(mRTPConnected);
-
-    status_t err = mNetSession->sendRequest(
-            mRTPSessionID, buffer->data(), buffer->size(),
-            timeValid, timeUs);
-
-    if (err != OK) {
-        return err;
-    }
-
-    mLastNTPTime = GetNowNTP();
-    mLastRTPTime = U32_AT(buffer->data() + 4);
-
-    ++mNumRTPSent;
-    mNumRTPOctetsSent += buffer->size() - 12;
-
-    if (storeInHistory) {
-        if (mHistorySize == kMaxHistorySize) {
-            mHistory.erase(mHistory.begin());
-        } else {
-            ++mHistorySize;
-        }
-        mHistory.push_back(buffer);
-    }
-
-    return OK;
-}
-
-// static
-uint64_t RTPSender::GetNowNTP() {
-    struct timeval tv;
-    gettimeofday(&tv, NULL /* timezone */);
-
-    uint64_t nowUs = tv.tv_sec * 1000000ll + tv.tv_usec;
-
-    nowUs += ((70ll * 365 + 17) * 24) * 60 * 60 * 1000000ll;
-
-    uint64_t hi = nowUs / 1000000ll;
-    uint64_t lo = ((1ll << 32) * (nowUs % 1000000ll)) / 1000000ll;
-
-    return (hi << 32) | lo;
-}
-
-void RTPSender::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        case kWhatRTPNotify:
-        case kWhatRTCPNotify:
-            onNetNotify(msg->what() == kWhatRTPNotify, msg);
-            break;
-
-        default:
-            TRESPASS();
-    }
-}
-
-void RTPSender::onNetNotify(bool isRTP, const sp<AMessage> &msg) {
-    int32_t reason;
-    CHECK(msg->findInt32("reason", &reason));
-
-    switch (reason) {
-        case ANetworkSession::kWhatError:
-        {
-            int32_t sessionID;
-            CHECK(msg->findInt32("sessionID", &sessionID));
-
-            int32_t err;
-            CHECK(msg->findInt32("err", &err));
-
-            int32_t errorOccuredDuringSend;
-            CHECK(msg->findInt32("send", &errorOccuredDuringSend));
-
-            AString detail;
-            CHECK(msg->findString("detail", &detail));
-
-            ALOGE("An error occurred during %s in session %d "
-                  "(%d, '%s' (%s)).",
-                  errorOccuredDuringSend ? "send" : "receive",
-                  sessionID,
-                  err,
-                  detail.c_str(),
-                  strerror(-err));
-
-            mNetSession->destroySession(sessionID);
-
-            if (sessionID == mRTPSessionID) {
-                mRTPSessionID = 0;
-            } else if (sessionID == mRTCPSessionID) {
-                mRTCPSessionID = 0;
-            }
-
-            if (!mRTPConnected
-                    || (mRTPMode != TRANSPORT_NONE && !mRTCPConnected)) {
-                // We haven't completed initialization, attach the error
-                // to the notification instead.
-                notifyInitDone(err);
-                break;
-            }
-
-            notifyError(err);
-            break;
-        }
-
-        case ANetworkSession::kWhatDatagram:
-        {
-            sp<ABuffer> data;
-            CHECK(msg->findBuffer("data", &data));
-
-            if (isRTP) {
-                ALOGW("Huh? Received data on RTP connection...");
-            } else {
-                onRTCPData(data);
-            }
-            break;
-        }
-
-        case ANetworkSession::kWhatConnected:
-        {
-            int32_t sessionID;
-            CHECK(msg->findInt32("sessionID", &sessionID));
-
-            if  (isRTP) {
-                CHECK_EQ(mRTPMode, TRANSPORT_TCP);
-                CHECK_EQ(sessionID, mRTPSessionID);
-                mRTPConnected = true;
-            } else {
-                CHECK_EQ(mRTCPMode, TRANSPORT_TCP);
-                CHECK_EQ(sessionID, mRTCPSessionID);
-                mRTCPConnected = true;
-            }
-
-            if (mRTPConnected
-                    && (mRTCPMode == TRANSPORT_NONE || mRTCPConnected)) {
-                notifyInitDone(OK);
-            }
-            break;
-        }
-
-        case ANetworkSession::kWhatNetworkStall:
-        {
-            size_t numBytesQueued;
-            CHECK(msg->findSize("numBytesQueued", &numBytesQueued));
-
-            notifyNetworkStall(numBytesQueued);
-            break;
-        }
-
-        default:
-            TRESPASS();
-    }
-}
-
-status_t RTPSender::onRTCPData(const sp<ABuffer> &buffer) {
-    const uint8_t *data = buffer->data();
-    size_t size = buffer->size();
-
-    while (size > 0) {
-        if (size < 8) {
-            // Too short to be a valid RTCP header
-            return ERROR_MALFORMED;
-        }
-
-        if ((data[0] >> 6) != 2) {
-            // Unsupported version.
-            return ERROR_UNSUPPORTED;
-        }
-
-        if (data[0] & 0x20) {
-            // Padding present.
-
-            size_t paddingLength = data[size - 1];
-
-            if (paddingLength + 12 > size) {
-                // If we removed this much padding we'd end up with something
-                // that's too short to be a valid RTP header.
-                return ERROR_MALFORMED;
-            }
-
-            size -= paddingLength;
-        }
-
-        size_t headerLength = 4 * (data[2] << 8 | data[3]) + 4;
-
-        if (size < headerLength) {
-            // Only received a partial packet?
-            return ERROR_MALFORMED;
-        }
-
-        switch (data[1]) {
-            case 200:
-            case 201:  // RR
-                parseReceiverReport(data, headerLength);
-                break;
-
-            case 202:  // SDES
-            case 203:
-                break;
-
-            case 204:  // APP
-                parseAPP(data, headerLength);
-                break;
-
-            case 205:  // TSFB (transport layer specific feedback)
-                parseTSFB(data, headerLength);
-                break;
-
-            case 206:  // PSFB (payload specific feedback)
-                // hexdump(data, headerLength);
-                break;
-
-            default:
-            {
-                ALOGW("Unknown RTCP packet type %u of size %zu",
-                        (unsigned)data[1], headerLength);
-                break;
-            }
-        }
-
-        data += headerLength;
-        size -= headerLength;
-    }
-
-    return OK;
-}
-
-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.",
-          100.0f * fractionLost);
-
-    return OK;
-}
-
-status_t RTPSender::parseTSFB(const uint8_t *data, size_t size) {
-    if ((data[0] & 0x1f) != 1) {
-        return ERROR_UNSUPPORTED;  // We only support NACK for now.
-    }
-
-    uint32_t srcId = U32_AT(&data[8]);
-    if (srcId != kSourceID) {
-        return ERROR_MALFORMED;
-    }
-
-    for (size_t i = 12; i < size; i += 4) {
-        uint16_t seqNo = U16_AT(&data[i]);
-        uint16_t blp = U16_AT(&data[i + 2]);
-
-        List<sp<ABuffer> >::iterator it = mHistory.begin();
-        bool foundSeqNo = false;
-        while (it != mHistory.end()) {
-            const sp<ABuffer> &buffer = *it;
-
-            uint16_t bufferSeqNo = buffer->int32Data() & 0xffff;
-
-            bool retransmit = false;
-            if (bufferSeqNo == seqNo) {
-                retransmit = true;
-            } else if (blp != 0) {
-                for (size_t i = 0; i < 16; ++i) {
-                    if ((blp & (1 << i))
-                        && (bufferSeqNo == ((seqNo + i + 1) & 0xffff))) {
-                        blp &= ~(1 << i);
-                        retransmit = true;
-                    }
-                }
-            }
-
-            if (retransmit) {
-                ALOGV("retransmitting seqNo %d", bufferSeqNo);
-
-                CHECK_EQ((status_t)OK,
-                         sendRTPPacket(buffer, false /* storeInHistory */));
-
-                if (bufferSeqNo == seqNo) {
-                    foundSeqNo = true;
-                }
-
-                if (foundSeqNo && blp == 0) {
-                    break;
-                }
-            }
-
-            ++it;
-        }
-
-        if (!foundSeqNo || blp != 0) {
-            ALOGI("Some sequence numbers were no longer available for "
-                  "retransmission (seqNo = %d, foundSeqNo = %d, blp = 0x%04x)",
-                  seqNo, foundSeqNo, blp);
-
-            if (!mHistory.empty()) {
-                int32_t earliest = (*mHistory.begin())->int32Data() & 0xffff;
-                int32_t latest = (*--mHistory.end())->int32Data() & 0xffff;
-
-                ALOGI("have seq numbers from %d - %d", earliest, latest);
-            }
-        }
-    }
-
-    return OK;
-}
-
-status_t RTPSender::parseAPP(const uint8_t *data, size_t size) {
-    static const size_t late_offset = 8;
-    static const char late_string[] = "late";
-    static const size_t avgLatencyUs_offset = late_offset + sizeof(late_string) - 1;
-    static const size_t maxLatencyUs_offset = avgLatencyUs_offset + sizeof(int64_t);
-
-    if ((size >= (maxLatencyUs_offset + sizeof(int64_t)))
-            && !memcmp(late_string, &data[late_offset], sizeof(late_string) - 1)) {
-        int64_t avgLatencyUs = (int64_t)U64_AT(&data[avgLatencyUs_offset]);
-        int64_t maxLatencyUs = (int64_t)U64_AT(&data[maxLatencyUs_offset]);
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatInformSender);
-        notify->setInt64("avgLatencyUs", avgLatencyUs);
-        notify->setInt64("maxLatencyUs", maxLatencyUs);
-        notify->post();
-    }
-
-    return OK;
-}
-
-void RTPSender::notifyInitDone(status_t err) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatInitDone);
-    notify->setInt32("err", err);
-    notify->post();
-}
-
-void RTPSender::notifyError(status_t err) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatError);
-    notify->setInt32("err", err);
-    notify->post();
-}
-
-void RTPSender::notifyNetworkStall(size_t numBytesQueued) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatNetworkStall);
-    notify->setSize("numBytesQueued", numBytesQueued);
-    notify->post();
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.h b/media/libstagefright/wifi-display/rtp/RTPSender.h
deleted file mode 100644
index bedfd01..0000000
--- a/media/libstagefright/wifi-display/rtp/RTPSender.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef RTP_SENDER_H_
-
-#define RTP_SENDER_H_
-
-#include "RTPBase.h"
-
-#include <media/stagefright/foundation/AHandler.h>
-
-namespace android {
-
-struct ABuffer;
-struct ANetworkSession;
-
-// An object of this class facilitates sending of media data over an RTP
-// channel. The channel is established over a UDP or TCP connection depending
-// on which "TransportMode" was chosen. In addition different RTP packetization
-// schemes are supported such as "Transport Stream Packets over RTP",
-// or "AVC/H.264 encapsulation as specified in RFC 3984 (non-interleaved mode)"
-struct RTPSender : public RTPBase, public AHandler {
-    enum {
-        kWhatInitDone,
-        kWhatError,
-        kWhatNetworkStall,
-        kWhatInformSender,
-    };
-    RTPSender(
-            const sp<ANetworkSession> &netSession,
-            const sp<AMessage> &notify);
-
-    status_t initAsync(
-              const char *remoteHost,
-              int32_t remoteRTPPort,
-              TransportMode rtpMode,
-              int32_t remoteRTCPPort,
-              TransportMode rtcpMode,
-              int32_t *outLocalRTPPort);
-
-    status_t queueBuffer(
-            const sp<ABuffer> &buffer,
-            uint8_t packetType,
-            PacketizationMode mode);
-
-protected:
-    virtual ~RTPSender();
-    virtual void onMessageReceived(const sp<AMessage> &msg);
-
-private:
-    enum {
-        kWhatRTPNotify,
-        kWhatRTCPNotify,
-    };
-
-    const unsigned int kMaxNumTSPacketsPerRTPPacket = (kMaxUDPPacketSize - 12) / 188;
-    const unsigned int kMaxHistorySize              = 1024;
-    const unsigned int kSourceID                    = 0xdeadbeef;
-
-    sp<ANetworkSession> mNetSession;
-    sp<AMessage> mNotify;
-    TransportMode mRTPMode;
-    TransportMode mRTCPMode;
-    int32_t mRTPSessionID;
-    int32_t mRTCPSessionID;
-    bool mRTPConnected;
-    bool mRTCPConnected;
-
-    uint64_t mLastNTPTime;
-    uint32_t mLastRTPTime;
-    uint32_t mNumRTPSent;
-    uint32_t mNumRTPOctetsSent;
-    uint32_t mNumSRsSent;
-
-    uint32_t mRTPSeqNo;
-
-    List<sp<ABuffer> > mHistory;
-    size_t mHistorySize;
-
-    static uint64_t GetNowNTP();
-
-    status_t queueRawPacket(const sp<ABuffer> &tsPackets, uint8_t packetType);
-    status_t queueTSPackets(const sp<ABuffer> &tsPackets, uint8_t packetType);
-    status_t queueAVCBuffer(const sp<ABuffer> &accessUnit, uint8_t packetType);
-
-    status_t sendRTPPacket(
-            const sp<ABuffer> &packet, bool storeInHistory,
-            bool timeValid = false, int64_t timeUs = -1ll);
-
-    void onNetNotify(bool isRTP, const sp<AMessage> &msg);
-
-    status_t onRTCPData(const sp<ABuffer> &data);
-    status_t parseReceiverReport(const uint8_t *data, size_t size);
-    status_t parseTSFB(const uint8_t *data, size_t size);
-    status_t parseAPP(const uint8_t *data, size_t size);
-
-    void notifyInitDone(status_t err);
-    void notifyError(status_t err);
-    void notifyNetworkStall(size_t numBytesQueued);
-
-    DISALLOW_EVIL_CONSTRUCTORS(RTPSender);
-};
-
-}  // namespace android
-
-#endif  // RTP_SENDER_H_
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp
deleted file mode 100644
index 273af18..0000000
--- a/media/libstagefright/wifi-display/source/Converter.cpp
+++ /dev/null
@@ -1,821 +0,0 @@
-/*
- * Copyright 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 "Converter"
-#include <utils/Log.h>
-
-#include "Converter.h"
-
-#include "MediaPuller.h"
-#include "include/avc_utils.h"
-
-#include <cutils/properties.h>
-#include <gui/Surface.h>
-#include <media/ICrypto.h>
-#include <media/MediaCodecBuffer.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaCodec.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-
-#include <arpa/inet.h>
-
-#include <OMX_Video.h>
-
-namespace android {
-
-Converter::Converter(
-        const sp<AMessage> &notify,
-        const sp<ALooper> &codecLooper,
-        const sp<AMessage> &outputFormat,
-        uint32_t flags)
-    : mNotify(notify),
-      mCodecLooper(codecLooper),
-      mOutputFormat(outputFormat),
-      mFlags(flags),
-      mIsVideo(false),
-      mIsH264(false),
-      mIsPCMAudio(false),
-      mNeedToManuallyPrependSPSPPS(false),
-      mDoMoreWorkPending(false)
-#if ENABLE_SILENCE_DETECTION
-      ,mFirstSilentFrameUs(-1ll)
-      ,mInSilentMode(false)
-#endif
-      ,mPrevVideoBitrate(-1)
-      ,mNumFramesToDrop(0)
-      ,mEncodingSuspended(false)
-    {
-    AString mime;
-    CHECK(mOutputFormat->findString("mime", &mime));
-
-    if (!strncasecmp("video/", mime.c_str(), 6)) {
-        mIsVideo = true;
-
-        mIsH264 = !strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC);
-    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime.c_str())) {
-        mIsPCMAudio = true;
-    }
-}
-
-void Converter::releaseEncoder() {
-    if (mEncoder == NULL) {
-        return;
-    }
-
-    mEncoder->release();
-    mEncoder.clear();
-
-    mInputBufferQueue.clear();
-    mEncoderInputBuffers.clear();
-    mEncoderOutputBuffers.clear();
-}
-
-Converter::~Converter() {
-    CHECK(mEncoder == NULL);
-}
-
-void Converter::shutdownAsync() {
-    ALOGV("shutdown");
-    (new AMessage(kWhatShutdown, this))->post();
-}
-
-status_t Converter::init() {
-    status_t err = initEncoder();
-
-    if (err != OK) {
-        releaseEncoder();
-    }
-
-    return err;
-}
-
-sp<IGraphicBufferProducer> Converter::getGraphicBufferProducer() {
-    CHECK(mFlags & FLAG_USE_SURFACE_INPUT);
-    return mGraphicBufferProducer;
-}
-
-size_t Converter::getInputBufferCount() const {
-    return mEncoderInputBuffers.size();
-}
-
-sp<AMessage> Converter::getOutputFormat() const {
-    return mOutputFormat;
-}
-
-bool Converter::needToManuallyPrependSPSPPS() const {
-    return mNeedToManuallyPrependSPSPPS;
-}
-
-// static
-int32_t Converter::GetInt32Property(
-        const char *propName, int32_t defaultValue) {
-    char val[PROPERTY_VALUE_MAX];
-    if (property_get(propName, val, NULL)) {
-        char *end;
-        unsigned long x = strtoul(val, &end, 10);
-
-        if (*end == '\0' && end > val && x > 0) {
-            return x;
-        }
-    }
-
-    return defaultValue;
-}
-
-status_t Converter::initEncoder() {
-    AString outputMIME;
-    CHECK(mOutputFormat->findString("mime", &outputMIME));
-
-    bool isAudio = !strncasecmp(outputMIME.c_str(), "audio/", 6);
-
-    if (!mIsPCMAudio) {
-        mEncoder = MediaCodec::CreateByType(
-                mCodecLooper, outputMIME.c_str(), true /* encoder */);
-
-        if (mEncoder == NULL) {
-            return ERROR_UNSUPPORTED;
-        }
-    }
-
-    if (mIsPCMAudio) {
-        return OK;
-    }
-
-    int32_t audioBitrate = GetInt32Property("media.wfd.audio-bitrate", 128000);
-    int32_t videoBitrate = GetInt32Property("media.wfd.video-bitrate", 5000000);
-    mPrevVideoBitrate = videoBitrate;
-
-    ALOGI("using audio bitrate of %d bps, video bitrate of %d bps",
-          audioBitrate, videoBitrate);
-
-    if (isAudio) {
-        mOutputFormat->setInt32("bitrate", audioBitrate);
-    } else {
-        mOutputFormat->setInt32("bitrate", videoBitrate);
-        mOutputFormat->setInt32("bitrate-mode", OMX_Video_ControlRateConstant);
-        mOutputFormat->setInt32("frame-rate", 30);
-        mOutputFormat->setInt32("i-frame-interval", 15);  // Iframes every 15 secs
-
-        // Configure encoder to use intra macroblock refresh mode
-        mOutputFormat->setInt32("intra-refresh-mode", OMX_VIDEO_IntraRefreshCyclic);
-
-        int width, height, mbs;
-        if (!mOutputFormat->findInt32("width", &width)
-                || !mOutputFormat->findInt32("height", &height)) {
-            return ERROR_UNSUPPORTED;
-        }
-
-        // Update macroblocks in a cyclic fashion with 10% of all MBs within
-        // frame gets updated at one time. It takes about 10 frames to
-        // completely update a whole video frame. If the frame rate is 30,
-        // it takes about 333 ms in the best case (if next frame is not an IDR)
-        // to recover from a lost/corrupted packet.
-        mbs = (((width + 15) / 16) * ((height + 15) / 16) * 10) / 100;
-        mOutputFormat->setInt32("intra-refresh-CIR-mbs", mbs);
-    }
-
-    ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str());
-
-    mNeedToManuallyPrependSPSPPS = false;
-
-    status_t err = NO_INIT;
-
-    if (!isAudio) {
-        sp<AMessage> tmp = mOutputFormat->dup();
-        tmp->setInt32("prepend-sps-pps-to-idr-frames", 1);
-
-        err = mEncoder->configure(
-                tmp,
-                NULL /* nativeWindow */,
-                NULL /* crypto */,
-                MediaCodec::CONFIGURE_FLAG_ENCODE);
-
-        if (err == OK) {
-            // Encoder supported prepending SPS/PPS, we don't need to emulate
-            // it.
-            mOutputFormat = tmp;
-        } else {
-            mNeedToManuallyPrependSPSPPS = true;
-
-            ALOGI("We going to manually prepend SPS and PPS to IDR frames.");
-        }
-    }
-
-    if (err != OK) {
-        // We'll get here for audio or if we failed to configure the encoder
-        // to automatically prepend SPS/PPS in the case of video.
-
-        err = mEncoder->configure(
-                    mOutputFormat,
-                    NULL /* nativeWindow */,
-                    NULL /* crypto */,
-                    MediaCodec::CONFIGURE_FLAG_ENCODE);
-    }
-
-    if (err != OK) {
-        return err;
-    }
-
-    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;
-    }
-
-    if (mFlags & FLAG_USE_SURFACE_INPUT) {
-        scheduleDoMoreWork();
-    }
-
-    return OK;
-}
-
-void Converter::notifyError(status_t err) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatError);
-    notify->setInt32("err", err);
-    notify->post();
-}
-
-// static
-bool Converter::IsSilence(const sp<ABuffer> &accessUnit) {
-    const uint8_t *ptr = accessUnit->data();
-    const uint8_t *end = ptr + accessUnit->size();
-    while (ptr < end) {
-        if (*ptr != 0) {
-            return false;
-        }
-        ++ptr;
-    }
-
-    return true;
-}
-
-void Converter::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        case kWhatMediaPullerNotify:
-        {
-            int32_t what;
-            CHECK(msg->findInt32("what", &what));
-
-            if (!mIsPCMAudio && mEncoder == NULL) {
-                ALOGV("got msg '%s' after encoder shutdown.",
-                      msg->debugString().c_str());
-
-                if (what == MediaPuller::kWhatAccessUnit) {
-                    sp<ABuffer> accessUnit;
-                    CHECK(msg->findBuffer("accessUnit", &accessUnit));
-
-                    accessUnit->setMediaBufferBase(NULL);
-                }
-                break;
-            }
-
-            if (what == MediaPuller::kWhatEOS) {
-                mInputBufferQueue.push_back(NULL);
-
-                feedEncoderInputBuffers();
-
-                scheduleDoMoreWork();
-            } else {
-                CHECK_EQ(what, MediaPuller::kWhatAccessUnit);
-
-                sp<ABuffer> accessUnit;
-                CHECK(msg->findBuffer("accessUnit", &accessUnit));
-
-                if (mNumFramesToDrop > 0 || mEncodingSuspended) {
-                    if (mNumFramesToDrop > 0) {
-                        --mNumFramesToDrop;
-                        ALOGI("dropping frame.");
-                    }
-
-                    accessUnit->setMediaBufferBase(NULL);
-                    break;
-                }
-
-#if 0
-                MediaBuffer *mbuf =
-                    (MediaBuffer *)(accessUnit->getMediaBufferBase());
-                if (mbuf != NULL) {
-                    ALOGI("queueing mbuf %p", mbuf);
-                    mbuf->release();
-                }
-#endif
-
-#if ENABLE_SILENCE_DETECTION
-                if (!mIsVideo) {
-                    if (IsSilence(accessUnit)) {
-                        if (mInSilentMode) {
-                            break;
-                        }
-
-                        int64_t nowUs = ALooper::GetNowUs();
-
-                        if (mFirstSilentFrameUs < 0ll) {
-                            mFirstSilentFrameUs = nowUs;
-                        } else if (nowUs >= mFirstSilentFrameUs + 10000000ll) {
-                            mInSilentMode = true;
-                            ALOGI("audio in silent mode now.");
-                            break;
-                        }
-                    } else {
-                        if (mInSilentMode) {
-                            ALOGI("audio no longer in silent mode.");
-                        }
-                        mInSilentMode = false;
-                        mFirstSilentFrameUs = -1ll;
-                    }
-                }
-#endif
-
-                mInputBufferQueue.push_back(accessUnit);
-
-                feedEncoderInputBuffers();
-
-                scheduleDoMoreWork();
-            }
-            break;
-        }
-
-        case kWhatEncoderActivity:
-        {
-#if 0
-            int64_t whenUs;
-            if (msg->findInt64("whenUs", &whenUs)) {
-                int64_t nowUs = ALooper::GetNowUs();
-                ALOGI("[%s] kWhatEncoderActivity after %lld us",
-                      mIsVideo ? "video" : "audio", nowUs - whenUs);
-            }
-#endif
-
-            mDoMoreWorkPending = false;
-
-            if (mEncoder == NULL) {
-                break;
-            }
-
-            status_t err = doMoreWork();
-
-            if (err != OK) {
-                notifyError(err);
-            } else {
-                scheduleDoMoreWork();
-            }
-            break;
-        }
-
-        case kWhatRequestIDRFrame:
-        {
-            if (mEncoder == NULL) {
-                break;
-            }
-
-            if (mIsVideo) {
-                ALOGV("requesting IDR frame");
-                mEncoder->requestIDRFrame();
-            }
-            break;
-        }
-
-        case kWhatShutdown:
-        {
-            ALOGI("shutting down %s encoder", mIsVideo ? "video" : "audio");
-
-            releaseEncoder();
-
-            AString mime;
-            CHECK(mOutputFormat->findString("mime", &mime));
-            ALOGI("encoder (%s) shut down.", mime.c_str());
-
-            sp<AMessage> notify = mNotify->dup();
-            notify->setInt32("what", kWhatShutdownCompleted);
-            notify->post();
-            break;
-        }
-
-        case kWhatDropAFrame:
-        {
-            ++mNumFramesToDrop;
-            break;
-        }
-
-        case kWhatReleaseOutputBuffer:
-        {
-            if (mEncoder != NULL) {
-                size_t bufferIndex;
-                CHECK(msg->findInt32("bufferIndex", (int32_t*)&bufferIndex));
-                CHECK(bufferIndex < mEncoderOutputBuffers.size());
-                mEncoder->releaseOutputBuffer(bufferIndex);
-            }
-            break;
-        }
-
-        case kWhatSuspendEncoding:
-        {
-            int32_t suspend;
-            CHECK(msg->findInt32("suspend", &suspend));
-
-            mEncodingSuspended = suspend;
-
-            if (mFlags & FLAG_USE_SURFACE_INPUT) {
-                sp<AMessage> params = new AMessage;
-                params->setInt32("drop-input-frames",suspend);
-                mEncoder->setParameters(params);
-            }
-            break;
-        }
-
-        default:
-            TRESPASS();
-    }
-}
-
-void Converter::scheduleDoMoreWork() {
-    if (mIsPCMAudio) {
-        // There's no encoder involved in this case.
-        return;
-    }
-
-    if (mDoMoreWorkPending) {
-        return;
-    }
-
-    mDoMoreWorkPending = true;
-
-#if 1
-    if (mEncoderActivityNotify == NULL) {
-        mEncoderActivityNotify = new AMessage(kWhatEncoderActivity, this);
-    }
-    mEncoder->requestActivityNotification(mEncoderActivityNotify->dup());
-#else
-    sp<AMessage> notify = new AMessage(kWhatEncoderActivity, this);
-    notify->setInt64("whenUs", ALooper::GetNowUs());
-    mEncoder->requestActivityNotification(notify);
-#endif
-}
-
-status_t Converter::feedRawAudioInputBuffers() {
-    // Split incoming PCM audio into buffers of 6 AUs of 80 audio frames each
-    // and add a 4 byte header according to the wifi display specs.
-
-    while (!mInputBufferQueue.empty()) {
-        sp<ABuffer> buffer = *mInputBufferQueue.begin();
-        mInputBufferQueue.erase(mInputBufferQueue.begin());
-
-        int16_t *ptr = (int16_t *)buffer->data();
-        int16_t *stop = (int16_t *)(buffer->data() + buffer->size());
-        while (ptr < stop) {
-            *ptr = htons(*ptr);
-            ++ptr;
-        }
-
-        static const size_t kFrameSize = 2 * sizeof(int16_t);  // stereo
-        static const size_t kFramesPerAU = 80;
-        static const size_t kNumAUsPerPESPacket = 6;
-
-        if (mPartialAudioAU != NULL) {
-            size_t bytesMissingForFullAU =
-                kNumAUsPerPESPacket * kFramesPerAU * kFrameSize
-                - mPartialAudioAU->size() + 4;
-
-            size_t copy = buffer->size();
-            if(copy > bytesMissingForFullAU) {
-                copy = bytesMissingForFullAU;
-            }
-
-            memcpy(mPartialAudioAU->data() + mPartialAudioAU->size(),
-                   buffer->data(),
-                   copy);
-
-            mPartialAudioAU->setRange(0, mPartialAudioAU->size() + copy);
-
-            buffer->setRange(buffer->offset() + copy, buffer->size() - copy);
-
-            int64_t timeUs;
-            CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
-            int64_t copyUs = (int64_t)((copy / kFrameSize) * 1E6 / 48000.0);
-            timeUs += copyUs;
-            buffer->meta()->setInt64("timeUs", timeUs);
-
-            if (bytesMissingForFullAU == copy) {
-                sp<AMessage> notify = mNotify->dup();
-                notify->setInt32("what", kWhatAccessUnit);
-                notify->setBuffer("accessUnit", mPartialAudioAU);
-                notify->post();
-
-                mPartialAudioAU.clear();
-            }
-        }
-
-        while (buffer->size() > 0) {
-            sp<ABuffer> partialAudioAU =
-                new ABuffer(
-                        4
-                        + kNumAUsPerPESPacket * kFrameSize * kFramesPerAU);
-
-            uint8_t *ptr = partialAudioAU->data();
-            ptr[0] = 0xa0;  // 10100000b
-            ptr[1] = kNumAUsPerPESPacket;
-            ptr[2] = 0;  // reserved, audio _emphasis_flag = 0
-
-            static const unsigned kQuantizationWordLength = 0;  // 16-bit
-            static const unsigned kAudioSamplingFrequency = 2;  // 48Khz
-            static const unsigned kNumberOfAudioChannels = 1;  // stereo
-
-            ptr[3] = (kQuantizationWordLength << 6)
-                    | (kAudioSamplingFrequency << 3)
-                    | kNumberOfAudioChannels;
-
-            size_t copy = buffer->size();
-            if (copy > partialAudioAU->size() - 4) {
-                copy = partialAudioAU->size() - 4;
-            }
-
-            memcpy(&ptr[4], buffer->data(), copy);
-
-            partialAudioAU->setRange(0, 4 + copy);
-            buffer->setRange(buffer->offset() + copy, buffer->size() - copy);
-
-            int64_t timeUs;
-            CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
-            partialAudioAU->meta()->setInt64("timeUs", timeUs);
-
-            int64_t copyUs = (int64_t)((copy / kFrameSize) * 1E6 / 48000.0);
-            timeUs += copyUs;
-            buffer->meta()->setInt64("timeUs", timeUs);
-
-            if (copy == partialAudioAU->capacity() - 4) {
-                sp<AMessage> notify = mNotify->dup();
-                notify->setInt32("what", kWhatAccessUnit);
-                notify->setBuffer("accessUnit", partialAudioAU);
-                notify->post();
-
-                partialAudioAU.clear();
-                continue;
-            }
-
-            mPartialAudioAU = partialAudioAU;
-        }
-    }
-
-    return OK;
-}
-
-status_t Converter::feedEncoderInputBuffers() {
-    if (mIsPCMAudio) {
-        return feedRawAudioInputBuffers();
-    }
-
-    while (!mInputBufferQueue.empty()
-            && !mAvailEncoderInputIndices.empty()) {
-        sp<ABuffer> buffer = *mInputBufferQueue.begin();
-        mInputBufferQueue.erase(mInputBufferQueue.begin());
-
-        size_t bufferIndex = *mAvailEncoderInputIndices.begin();
-        mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin());
-
-        int64_t timeUs = 0ll;
-        uint32_t flags = 0;
-
-        if (buffer != NULL) {
-            CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
-            memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(),
-                   buffer->data(),
-                   buffer->size());
-
-            MediaBuffer *mediaBuffer =
-                (MediaBuffer *)(buffer->getMediaBufferBase());
-            if (mediaBuffer != NULL) {
-                mEncoderInputBuffers.itemAt(bufferIndex)->setMediaBufferBase(
-                        mediaBuffer);
-
-                buffer->setMediaBufferBase(NULL);
-            }
-        } else {
-            flags = MediaCodec::BUFFER_FLAG_EOS;
-        }
-
-        status_t err = mEncoder->queueInputBuffer(
-                bufferIndex, 0, (buffer == NULL) ? 0 : buffer->size(),
-                timeUs, flags);
-
-        if (err != OK) {
-            return err;
-        }
-    }
-
-    return OK;
-}
-
-sp<ABuffer> Converter::prependCSD(const sp<ABuffer> &accessUnit) const {
-    CHECK(mCSD0 != NULL);
-
-    sp<ABuffer> dup = new ABuffer(accessUnit->size() + mCSD0->size());
-    memcpy(dup->data(), mCSD0->data(), mCSD0->size());
-    memcpy(dup->data() + mCSD0->size(), accessUnit->data(), accessUnit->size());
-
-    int64_t timeUs;
-    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
-    dup->meta()->setInt64("timeUs", timeUs);
-
-    return dup;
-}
-
-status_t Converter::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<AMessage> notify = mNotify->dup();
-            notify->setInt32("what", kWhatEOS);
-            notify->post();
-        } else {
-#if 0
-            if (mIsVideo) {
-                int32_t videoBitrate = GetInt32Property(
-                        "media.wfd.video-bitrate", 5000000);
-
-                setVideoBitrate(videoBitrate);
-            }
-#endif
-
-            sp<ABuffer> buffer;
-            sp<MediaCodecBuffer> outbuf = mEncoderOutputBuffers.itemAt(bufferIndex);
-
-            if (outbuf->meta()->findPointer("handle", (void**)&handle) &&
-                    handle != NULL) {
-                int32_t rangeLength, rangeOffset;
-                CHECK(outbuf->meta()->findInt32("rangeOffset", &rangeOffset));
-                CHECK(outbuf->meta()->findInt32("rangeLength", &rangeLength));
-                outbuf->meta()->setPointer("handle", NULL);
-
-                // MediaSender will post the following message when HDCP
-                // is done, to release the output buffer back to encoder.
-                sp<AMessage> notify(new AMessage(kWhatReleaseOutputBuffer, this));
-                notify->setInt32("bufferIndex", bufferIndex);
-
-                buffer = new ABuffer(
-                        rangeLength > (int32_t)size ? rangeLength : size);
-                buffer->meta()->setPointer("handle", handle);
-                buffer->meta()->setInt32("rangeOffset", rangeOffset);
-                buffer->meta()->setInt32("rangeLength", rangeLength);
-                buffer->meta()->setMessage("notify", notify);
-            } else {
-                buffer = new ABuffer(size);
-            }
-
-            buffer->meta()->setInt64("timeUs", timeUs);
-
-            ALOGV("[%s] time %lld us (%.2f secs)",
-                    mIsVideo ? "video" : "audio", (long long)timeUs, timeUs / 1E6);
-
-            memcpy(buffer->data(), outbuf->base() + offset, size);
-
-            if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
-                if (!handle) {
-                    if (mIsH264) {
-                        mCSD0 = buffer;
-                    }
-                    mOutputFormat->setBuffer("csd-0", buffer);
-                }
-            } else {
-                if (mNeedToManuallyPrependSPSPPS
-                        && mIsH264
-                        && (mFlags & FLAG_PREPEND_CSD_IF_NECESSARY)
-                        && IsIDR(buffer)) {
-                    buffer = prependCSD(buffer);
-                }
-
-                sp<AMessage> notify = mNotify->dup();
-                notify->setInt32("what", kWhatAccessUnit);
-                notify->setBuffer("accessUnit", buffer);
-                notify->post();
-            }
-        }
-
-        if (!handle) {
-            mEncoder->releaseOutputBuffer(bufferIndex);
-        }
-
-        if (flags & MediaCodec::BUFFER_FLAG_EOS) {
-            break;
-        }
-    }
-
-    return err;
-}
-
-void Converter::requestIDRFrame() {
-    (new AMessage(kWhatRequestIDRFrame, this))->post();
-}
-
-void Converter::dropAFrame() {
-    // Unsupported in surface input mode.
-    CHECK(!(mFlags & FLAG_USE_SURFACE_INPUT));
-
-    (new AMessage(kWhatDropAFrame, this))->post();
-}
-
-void Converter::suspendEncoding(bool suspend) {
-    sp<AMessage> msg = new AMessage(kWhatSuspendEncoding, this);
-    msg->setInt32("suspend", suspend);
-    msg->post();
-}
-
-int32_t Converter::getVideoBitrate() const {
-    return mPrevVideoBitrate;
-}
-
-void Converter::setVideoBitrate(int32_t bitRate) {
-    if (mIsVideo && mEncoder != NULL && bitRate != mPrevVideoBitrate) {
-        sp<AMessage> params = new AMessage;
-        params->setInt32("video-bitrate", bitRate);
-
-        mEncoder->setParameters(params);
-
-        mPrevVideoBitrate = bitRate;
-    }
-}
-
-}  // namespace android
diff --git a/media/libstagefright/wifi-display/source/Converter.h b/media/libstagefright/wifi-display/source/Converter.h
deleted file mode 100644
index ad95ab5..0000000
--- a/media/libstagefright/wifi-display/source/Converter.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 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 CONVERTER_H_
-
-#define CONVERTER_H_
-
-#include <media/stagefright/foundation/AHandler.h>
-
-namespace android {
-
-struct ABuffer;
-class IGraphicBufferProducer;
-struct MediaCodec;
-class MediaCodecBuffer;
-
-#define ENABLE_SILENCE_DETECTION        0
-
-// Utility class that receives media access units and converts them into
-// media access unit of a different format.
-// Right now this'll convert raw video into H.264 and raw audio into AAC.
-struct Converter : public AHandler {
-    enum {
-        kWhatAccessUnit,
-        kWhatEOS,
-        kWhatError,
-        kWhatShutdownCompleted,
-    };
-
-    enum FlagBits {
-        FLAG_USE_SURFACE_INPUT          = 1,
-        FLAG_PREPEND_CSD_IF_NECESSARY   = 2,
-    };
-    Converter(const sp<AMessage> &notify,
-              const sp<ALooper> &codecLooper,
-              const sp<AMessage> &outputFormat,
-              uint32_t flags = 0);
-
-    status_t init();
-
-    sp<IGraphicBufferProducer> getGraphicBufferProducer();
-
-    size_t getInputBufferCount() const;
-
-    sp<AMessage> getOutputFormat() const;
-    bool needToManuallyPrependSPSPPS() const;
-
-    void feedAccessUnit(const sp<ABuffer> &accessUnit);
-    void signalEOS();
-
-    void requestIDRFrame();
-
-    void dropAFrame();
-    void suspendEncoding(bool suspend);
-
-    void shutdownAsync();
-
-    int32_t getVideoBitrate() const;
-    void setVideoBitrate(int32_t bitrate);
-
-    static int32_t GetInt32Property(const char *propName, int32_t defaultValue);
-
-    enum {
-        // MUST not conflict with private enums below.
-        kWhatMediaPullerNotify = 'pulN',
-    };
-
-protected:
-    virtual ~Converter();
-    virtual void onMessageReceived(const sp<AMessage> &msg);
-
-private:
-    enum {
-        kWhatDoMoreWork,
-        kWhatRequestIDRFrame,
-        kWhatSuspendEncoding,
-        kWhatShutdown,
-        kWhatEncoderActivity,
-        kWhatDropAFrame,
-        kWhatReleaseOutputBuffer,
-    };
-
-    sp<AMessage> mNotify;
-    sp<ALooper> mCodecLooper;
-    sp<AMessage> mOutputFormat;
-    uint32_t mFlags;
-    bool mIsVideo;
-    bool mIsH264;
-    bool mIsPCMAudio;
-    bool mNeedToManuallyPrependSPSPPS;
-
-    sp<MediaCodec> mEncoder;
-    sp<AMessage> mEncoderActivityNotify;
-
-    sp<IGraphicBufferProducer> mGraphicBufferProducer;
-
-    Vector<sp<MediaCodecBuffer> > mEncoderInputBuffers;
-    Vector<sp<MediaCodecBuffer> > mEncoderOutputBuffers;
-
-    List<size_t> mAvailEncoderInputIndices;
-
-    List<sp<ABuffer> > mInputBufferQueue;
-
-    sp<ABuffer> mCSD0;
-
-    bool mDoMoreWorkPending;
-
-#if ENABLE_SILENCE_DETECTION
-    int64_t mFirstSilentFrameUs;
-    bool mInSilentMode;
-#endif
-
-    sp<ABuffer> mPartialAudioAU;
-
-    int32_t mPrevVideoBitrate;
-
-    int32_t mNumFramesToDrop;
-    bool mEncodingSuspended;
-
-    status_t initEncoder();
-    void releaseEncoder();
-
-    status_t feedEncoderInputBuffers();
-
-    void scheduleDoMoreWork();
-    status_t doMoreWork();
-
-    void notifyError(status_t err);
-
-    // Packetizes raw PCM audio data available in mInputBufferQueue
-    // into a format suitable for transport stream inclusion and
-    // notifies the observer.
-    status_t feedRawAudioInputBuffers();
-
-    static bool IsSilence(const sp<ABuffer> &accessUnit);
-
-    sp<ABuffer> prependCSD(const sp<ABuffer> &accessUnit) const;
-
-    DISALLOW_EVIL_CONSTRUCTORS(Converter);
-};
-
-}  // namespace android
-
-#endif  // CONVERTER_H_
diff --git a/media/libstagefright/wifi-display/source/MediaPuller.cpp b/media/libstagefright/wifi-display/source/MediaPuller.cpp
deleted file mode 100644
index ce07a4e..0000000
--- a/media/libstagefright/wifi-display/source/MediaPuller.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright 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 "MediaPuller"
-#include <utils/Log.h>
-
-#include "MediaPuller.h"
-
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-MediaPuller::MediaPuller(
-        const sp<MediaSource> &source, const sp<AMessage> &notify)
-    : mSource(source),
-      mNotify(notify),
-      mPullGeneration(0),
-      mIsAudio(false),
-      mPaused(false) {
-    sp<MetaData> meta = source->getFormat();
-    const char *mime;
-    CHECK(meta->findCString(kKeyMIMEType, &mime));
-
-    mIsAudio = !strncasecmp(mime, "audio/", 6);
-}
-
-MediaPuller::~MediaPuller() {
-}
-
-status_t MediaPuller::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 MediaPuller::start() {
-    return postSynchronouslyAndReturnError(new AMessage(kWhatStart, this));
-}
-
-void MediaPuller::stopAsync(const sp<AMessage> &notify) {
-    sp<AMessage> msg = new AMessage(kWhatStop, this);
-    msg->setMessage("notify", notify);
-    msg->post();
-}
-
-void MediaPuller::pause() {
-    (new AMessage(kWhatPause, this))->post();
-}
-
-void MediaPuller::resume() {
-    (new AMessage(kWhatResume, this))->post();
-}
-
-void MediaPuller::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        case kWhatStart:
-        {
-            status_t err;
-            if (mIsAudio) {
-                // This atrocity causes AudioSource to deliver absolute
-                // systemTime() based timestamps (off by 1 us).
-                sp<MetaData> params = new MetaData;
-                params->setInt64(kKeyTime, 1ll);
-                err = mSource->start(params.get());
-            } else {
-                err = mSource->start();
-                if (err != OK) {
-                    ALOGE("source failed to start w/ err %d", err);
-                }
-            }
-
-            if (err == OK) {
-                schedulePull();
-            }
-
-            sp<AMessage> response = new AMessage;
-            response->setInt32("err", err);
-
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-            response->postReply(replyID);
-            break;
-        }
-
-        case kWhatStop:
-        {
-            sp<MetaData> meta = mSource->getFormat();
-            const char *tmp;
-            CHECK(meta->findCString(kKeyMIMEType, &tmp));
-            AString mime = tmp;
-
-            ALOGI("MediaPuller(%s) stopping.", mime.c_str());
-            mSource->stop();
-            ALOGI("MediaPuller(%s) stopped.", mime.c_str());
-            ++mPullGeneration;
-
-            sp<AMessage> notify;
-            CHECK(msg->findMessage("notify", &notify));
-            notify->post();
-            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;
-                }
-
-                schedulePull();
-                break;
-            }
-
-            if (err != OK) {
-                if (err == ERROR_END_OF_STREAM) {
-                    ALOGI("stream ended.");
-                } else {
-                    ALOGE("error %d reading stream.", err);
-                }
-
-                sp<AMessage> notify = mNotify->dup();
-                notify->setInt32("what", kWhatEOS);
-                notify->post();
-            } else {
-                int64_t timeUs;
-                CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
-
-                sp<ABuffer> accessUnit = new ABuffer(mbuf->range_length());
-
-                memcpy(accessUnit->data(),
-                       (const uint8_t *)mbuf->data() + mbuf->range_offset(),
-                       mbuf->range_length());
-
-                accessUnit->meta()->setInt64("timeUs", timeUs);
-
-                if (mIsAudio) {
-                    mbuf->release();
-                    mbuf = NULL;
-                } else {
-                    // video encoder will release MediaBuffer when done
-                    // with underlying data.
-                    accessUnit->setMediaBufferBase(mbuf);
-                }
-
-                sp<AMessage> notify = mNotify->dup();
-
-                notify->setInt32("what", kWhatAccessUnit);
-                notify->setBuffer("accessUnit", accessUnit);
-                notify->post();
-
-                if (mbuf != NULL) {
-                    ALOGV("posted mbuf %p", mbuf);
-                }
-
-                schedulePull();
-            }
-            break;
-        }
-
-        case kWhatPause:
-        {
-            mPaused = true;
-            break;
-        }
-
-        case kWhatResume:
-        {
-            mPaused = false;
-            break;
-        }
-
-        default:
-            TRESPASS();
-    }
-}
-
-void MediaPuller::schedulePull() {
-    sp<AMessage> msg = new AMessage(kWhatPull, this);
-    msg->setInt32("generation", mPullGeneration);
-    msg->post();
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/wifi-display/source/MediaPuller.h b/media/libstagefright/wifi-display/source/MediaPuller.h
deleted file mode 100644
index 1291bb3..0000000
--- a/media/libstagefright/wifi-display/source/MediaPuller.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 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 MEDIA_PULLER_H_
-
-#define MEDIA_PULLER_H_
-
-#include <media/stagefright/foundation/AHandler.h>
-
-namespace android {
-
-struct MediaSource;
-
-struct MediaPuller : public AHandler {
-    enum {
-        kWhatEOS,
-        kWhatAccessUnit
-    };
-
-    MediaPuller(const sp<MediaSource> &source, const sp<AMessage> &notify);
-
-    status_t start();
-    void stopAsync(const sp<AMessage> &notify);
-
-    void pause();
-    void resume();
-
-protected:
-    virtual void onMessageReceived(const sp<AMessage> &msg);
-    virtual ~MediaPuller();
-
-private:
-    enum {
-        kWhatStart,
-        kWhatStop,
-        kWhatPull,
-        kWhatPause,
-        kWhatResume,
-    };
-
-    sp<MediaSource> mSource;
-    sp<AMessage> mNotify;
-    int32_t mPullGeneration;
-    bool mIsAudio;
-    bool mPaused;
-
-    status_t postSynchronouslyAndReturnError(const sp<AMessage> &msg);
-    void schedulePull();
-
-    DISALLOW_EVIL_CONSTRUCTORS(MediaPuller);
-};
-
-}  // namespace android
-
-#endif  // MEDIA_PULLER_H_
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
deleted file mode 100644
index f1ecca0..0000000
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ /dev/null
@@ -1,1112 +0,0 @@
-/*
- * Copyright 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 "PlaybackSession"
-#include <utils/Log.h>
-
-#include "PlaybackSession.h"
-
-#include "Converter.h"
-#include "MediaPuller.h"
-#include "RepeaterSource.h"
-#include "include/avc_utils.h"
-#include "WifiDisplaySource.h"
-
-#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>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/AudioSource.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/NuMediaExtractor.h>
-#include <media/stagefright/SurfaceMediaSource.h>
-#include <media/stagefright/Utils.h>
-
-#include <OMX_IVCommon.h>
-
-namespace android {
-
-struct WifiDisplaySource::PlaybackSession::Track : public AHandler {
-    enum {
-        kWhatStopped,
-    };
-
-    Track(const sp<AMessage> &notify,
-          const sp<ALooper> &pullLooper,
-          const sp<ALooper> &codecLooper,
-          const sp<MediaPuller> &mediaPuller,
-          const sp<Converter> &converter);
-
-    Track(const sp<AMessage> &notify, const sp<AMessage> &format);
-
-    void setRepeaterSource(const sp<RepeaterSource> &source);
-
-    sp<AMessage> getFormat();
-    bool isAudio() const;
-
-    const sp<Converter> &converter() const;
-    const sp<RepeaterSource> &repeaterSource() const;
-
-    ssize_t mediaSenderTrackIndex() const;
-    void setMediaSenderTrackIndex(size_t index);
-
-    status_t start();
-    void stopAsync();
-
-    void pause();
-    void resume();
-
-    void queueAccessUnit(const sp<ABuffer> &accessUnit);
-    sp<ABuffer> dequeueAccessUnit();
-
-    bool hasOutputBuffer(int64_t *timeUs) const;
-    void queueOutputBuffer(const sp<ABuffer> &accessUnit);
-    sp<ABuffer> dequeueOutputBuffer();
-
-#if SUSPEND_VIDEO_IF_IDLE
-    bool isSuspended() const;
-#endif
-
-    size_t countQueuedOutputBuffers() const {
-        return mQueuedOutputBuffers.size();
-    }
-
-    void requestIDRFrame();
-
-protected:
-    virtual void onMessageReceived(const sp<AMessage> &msg);
-    virtual ~Track();
-
-private:
-    enum {
-        kWhatMediaPullerStopped,
-    };
-
-    sp<AMessage> mNotify;
-    sp<ALooper> mPullLooper;
-    sp<ALooper> mCodecLooper;
-    sp<MediaPuller> mMediaPuller;
-    sp<Converter> mConverter;
-    sp<AMessage> mFormat;
-    bool mStarted;
-    ssize_t mMediaSenderTrackIndex;
-    bool mIsAudio;
-    List<sp<ABuffer> > mQueuedAccessUnits;
-    sp<RepeaterSource> mRepeaterSource;
-    List<sp<ABuffer> > mQueuedOutputBuffers;
-    int64_t mLastOutputBufferQueuedTimeUs;
-
-    static bool IsAudioFormat(const sp<AMessage> &format);
-
-    DISALLOW_EVIL_CONSTRUCTORS(Track);
-};
-
-WifiDisplaySource::PlaybackSession::Track::Track(
-        const sp<AMessage> &notify,
-        const sp<ALooper> &pullLooper,
-        const sp<ALooper> &codecLooper,
-        const sp<MediaPuller> &mediaPuller,
-        const sp<Converter> &converter)
-    : mNotify(notify),
-      mPullLooper(pullLooper),
-      mCodecLooper(codecLooper),
-      mMediaPuller(mediaPuller),
-      mConverter(converter),
-      mStarted(false),
-      mIsAudio(IsAudioFormat(mConverter->getOutputFormat())),
-      mLastOutputBufferQueuedTimeUs(-1ll) {
-}
-
-WifiDisplaySource::PlaybackSession::Track::Track(
-        const sp<AMessage> &notify, const sp<AMessage> &format)
-    : mNotify(notify),
-      mFormat(format),
-      mStarted(false),
-      mIsAudio(IsAudioFormat(format)),
-      mLastOutputBufferQueuedTimeUs(-1ll) {
-}
-
-WifiDisplaySource::PlaybackSession::Track::~Track() {
-    CHECK(!mStarted);
-}
-
-// static
-bool WifiDisplaySource::PlaybackSession::Track::IsAudioFormat(
-        const sp<AMessage> &format) {
-    AString mime;
-    CHECK(format->findString("mime", &mime));
-
-    return !strncasecmp(mime.c_str(), "audio/", 6);
-}
-
-sp<AMessage> WifiDisplaySource::PlaybackSession::Track::getFormat() {
-    return mFormat != NULL ? mFormat : mConverter->getOutputFormat();
-}
-
-bool WifiDisplaySource::PlaybackSession::Track::isAudio() const {
-    return mIsAudio;
-}
-
-const sp<Converter> &WifiDisplaySource::PlaybackSession::Track::converter() const {
-    return mConverter;
-}
-
-const sp<RepeaterSource> &
-WifiDisplaySource::PlaybackSession::Track::repeaterSource() const {
-    return mRepeaterSource;
-}
-
-ssize_t WifiDisplaySource::PlaybackSession::Track::mediaSenderTrackIndex() const {
-    CHECK_GE(mMediaSenderTrackIndex, 0);
-    return mMediaSenderTrackIndex;
-}
-
-void WifiDisplaySource::PlaybackSession::Track::setMediaSenderTrackIndex(
-        size_t index) {
-    mMediaSenderTrackIndex = index;
-}
-
-status_t WifiDisplaySource::PlaybackSession::Track::start() {
-    ALOGV("Track::start isAudio=%d", mIsAudio);
-
-    CHECK(!mStarted);
-
-    status_t err = OK;
-
-    if (mMediaPuller != NULL) {
-        err = mMediaPuller->start();
-    }
-
-    if (err == OK) {
-        mStarted = true;
-    }
-
-    return err;
-}
-
-void WifiDisplaySource::PlaybackSession::Track::stopAsync() {
-    ALOGV("Track::stopAsync isAudio=%d", mIsAudio);
-
-    if (mConverter != NULL) {
-        mConverter->shutdownAsync();
-    }
-
-    sp<AMessage> msg = new AMessage(kWhatMediaPullerStopped, this);
-
-    if (mStarted && mMediaPuller != NULL) {
-        if (mRepeaterSource != NULL) {
-            // Let's unblock MediaPuller's MediaSource::read().
-            mRepeaterSource->wakeUp();
-        }
-
-        mMediaPuller->stopAsync(msg);
-    } else {
-        mStarted = false;
-        msg->post();
-    }
-}
-
-void WifiDisplaySource::PlaybackSession::Track::pause() {
-    mMediaPuller->pause();
-}
-
-void WifiDisplaySource::PlaybackSession::Track::resume() {
-    mMediaPuller->resume();
-}
-
-void WifiDisplaySource::PlaybackSession::Track::onMessageReceived(
-        const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        case kWhatMediaPullerStopped:
-        {
-            mConverter.clear();
-
-            mStarted = false;
-
-            sp<AMessage> notify = mNotify->dup();
-            notify->setInt32("what", kWhatStopped);
-            notify->post();
-
-            ALOGI("kWhatStopped %s posted", mIsAudio ? "audio" : "video");
-            break;
-        }
-
-        default:
-            TRESPASS();
-    }
-}
-
-void WifiDisplaySource::PlaybackSession::Track::queueAccessUnit(
-        const sp<ABuffer> &accessUnit) {
-    mQueuedAccessUnits.push_back(accessUnit);
-}
-
-sp<ABuffer> WifiDisplaySource::PlaybackSession::Track::dequeueAccessUnit() {
-    if (mQueuedAccessUnits.empty()) {
-        return NULL;
-    }
-
-    sp<ABuffer> accessUnit = *mQueuedAccessUnits.begin();
-    CHECK(accessUnit != NULL);
-
-    mQueuedAccessUnits.erase(mQueuedAccessUnits.begin());
-
-    return accessUnit;
-}
-
-void WifiDisplaySource::PlaybackSession::Track::setRepeaterSource(
-        const sp<RepeaterSource> &source) {
-    mRepeaterSource = source;
-}
-
-void WifiDisplaySource::PlaybackSession::Track::requestIDRFrame() {
-    if (mIsAudio) {
-        return;
-    }
-
-    if (mRepeaterSource != NULL) {
-        mRepeaterSource->wakeUp();
-    }
-
-    mConverter->requestIDRFrame();
-}
-
-bool WifiDisplaySource::PlaybackSession::Track::hasOutputBuffer(
-        int64_t *timeUs) const {
-    *timeUs = 0ll;
-
-    if (mQueuedOutputBuffers.empty()) {
-        return false;
-    }
-
-    const sp<ABuffer> &outputBuffer = *mQueuedOutputBuffers.begin();
-
-    CHECK(outputBuffer->meta()->findInt64("timeUs", timeUs));
-
-    return true;
-}
-
-void WifiDisplaySource::PlaybackSession::Track::queueOutputBuffer(
-        const sp<ABuffer> &accessUnit) {
-    mQueuedOutputBuffers.push_back(accessUnit);
-    mLastOutputBufferQueuedTimeUs = ALooper::GetNowUs();
-}
-
-sp<ABuffer> WifiDisplaySource::PlaybackSession::Track::dequeueOutputBuffer() {
-    CHECK(!mQueuedOutputBuffers.empty());
-
-    sp<ABuffer> outputBuffer = *mQueuedOutputBuffers.begin();
-    mQueuedOutputBuffers.erase(mQueuedOutputBuffers.begin());
-
-    return outputBuffer;
-}
-
-#if SUSPEND_VIDEO_IF_IDLE
-bool WifiDisplaySource::PlaybackSession::Track::isSuspended() const {
-    if (!mQueuedOutputBuffers.empty()) {
-        return false;
-    }
-
-    if (mLastOutputBufferQueuedTimeUs < 0ll) {
-        // We've never seen an output buffer queued, but tracks start
-        // out live, not suspended.
-        return false;
-    }
-
-    // If we've not seen new output data for 60ms or more, we consider
-    // this track suspended for the time being.
-    return (ALooper::GetNowUs() - mLastOutputBufferQueuedTimeUs) > 60000ll;
-}
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-
-WifiDisplaySource::PlaybackSession::PlaybackSession(
-        const String16 &opPackageName,
-        const sp<ANetworkSession> &netSession,
-        const sp<AMessage> &notify,
-        const in_addr &interfaceAddr,
-        const sp<IHDCP> &hdcp,
-        const char *path)
-    : mOpPackageName(opPackageName),
-      mNetSession(netSession),
-      mNotify(notify),
-      mInterfaceAddr(interfaceAddr),
-      mHDCP(hdcp),
-      mLocalRTPPort(-1),
-      mWeAreDead(false),
-      mPaused(false),
-      mLastLifesignUs(),
-      mVideoTrackIndex(-1),
-      mPrevTimeUs(-1ll),
-      mPullExtractorPending(false),
-      mPullExtractorGeneration(0),
-      mFirstSampleTimeRealUs(-1ll),
-      mFirstSampleTimeUs(-1ll) {
-    if (path != NULL) {
-        mMediaPath.setTo(path);
-    }
-}
-
-status_t WifiDisplaySource::PlaybackSession::init(
-        const char *clientIP,
-        int32_t clientRtp,
-        RTPSender::TransportMode rtpMode,
-        int32_t clientRtcp,
-        RTPSender::TransportMode rtcpMode,
-        bool enableAudio,
-        bool usePCMAudio,
-        bool enableVideo,
-        VideoFormats::ResolutionType videoResolutionType,
-        size_t videoResolutionIndex,
-        VideoFormats::ProfileType videoProfileType,
-        VideoFormats::LevelType videoLevelType) {
-    sp<AMessage> notify = new AMessage(kWhatMediaSenderNotify, this);
-    mMediaSender = new MediaSender(mNetSession, notify);
-    looper()->registerHandler(mMediaSender);
-
-    mMediaSender->setHDCP(mHDCP);
-
-    status_t err = setupPacketizer(
-            enableAudio,
-            usePCMAudio,
-            enableVideo,
-            videoResolutionType,
-            videoResolutionIndex,
-            videoProfileType,
-            videoLevelType);
-
-    if (err == OK) {
-        err = mMediaSender->initAsync(
-                -1 /* trackIndex */,
-                clientIP,
-                clientRtp,
-                rtpMode,
-                clientRtcp,
-                rtcpMode,
-                &mLocalRTPPort);
-    }
-
-    if (err != OK) {
-        mLocalRTPPort = -1;
-
-        looper()->unregisterHandler(mMediaSender->id());
-        mMediaSender.clear();
-
-        return err;
-    }
-
-    updateLiveness();
-
-    return OK;
-}
-
-WifiDisplaySource::PlaybackSession::~PlaybackSession() {
-}
-
-int32_t WifiDisplaySource::PlaybackSession::getRTPPort() const {
-    return mLocalRTPPort;
-}
-
-int64_t WifiDisplaySource::PlaybackSession::getLastLifesignUs() const {
-    return mLastLifesignUs;
-}
-
-void WifiDisplaySource::PlaybackSession::updateLiveness() {
-    mLastLifesignUs = ALooper::GetNowUs();
-}
-
-status_t WifiDisplaySource::PlaybackSession::play() {
-    updateLiveness();
-
-    (new AMessage(kWhatResume, this))->post();
-
-    return OK;
-}
-
-status_t WifiDisplaySource::PlaybackSession::onMediaSenderInitialized() {
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        CHECK_EQ((status_t)OK, mTracks.editValueAt(i)->start());
-    }
-
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatSessionEstablished);
-    notify->post();
-
-    return OK;
-}
-
-status_t WifiDisplaySource::PlaybackSession::pause() {
-    updateLiveness();
-
-    (new AMessage(kWhatPause, this))->post();
-
-    return OK;
-}
-
-void WifiDisplaySource::PlaybackSession::destroyAsync() {
-    ALOGI("destroyAsync");
-
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        mTracks.valueAt(i)->stopAsync();
-    }
-}
-
-void WifiDisplaySource::PlaybackSession::onMessageReceived(
-        const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        case kWhatConverterNotify:
-        {
-            if (mWeAreDead) {
-                ALOGV("dropping msg '%s' because we're dead",
-                      msg->debugString().c_str());
-
-                break;
-            }
-
-            int32_t what;
-            CHECK(msg->findInt32("what", &what));
-
-            size_t trackIndex;
-            CHECK(msg->findSize("trackIndex", &trackIndex));
-
-            if (what == Converter::kWhatAccessUnit) {
-                sp<ABuffer> accessUnit;
-                CHECK(msg->findBuffer("accessUnit", &accessUnit));
-
-                const sp<Track> &track = mTracks.valueFor(trackIndex);
-
-                status_t err = mMediaSender->queueAccessUnit(
-                        track->mediaSenderTrackIndex(),
-                        accessUnit);
-
-                if (err != OK) {
-                    notifySessionDead();
-                }
-                break;
-            } else if (what == Converter::kWhatEOS) {
-                CHECK_EQ(what, Converter::kWhatEOS);
-
-                ALOGI("output EOS on track %zu", trackIndex);
-
-                ssize_t index = mTracks.indexOfKey(trackIndex);
-                CHECK_GE(index, 0);
-
-                const sp<Converter> &converter =
-                    mTracks.valueAt(index)->converter();
-                looper()->unregisterHandler(converter->id());
-
-                mTracks.removeItemsAt(index);
-
-                if (mTracks.isEmpty()) {
-                    ALOGI("Reached EOS");
-                }
-            } else if (what != Converter::kWhatShutdownCompleted) {
-                CHECK_EQ(what, Converter::kWhatError);
-
-                status_t err;
-                CHECK(msg->findInt32("err", &err));
-
-                ALOGE("converter signaled error %d", err);
-
-                notifySessionDead();
-            }
-            break;
-        }
-
-        case kWhatMediaSenderNotify:
-        {
-            int32_t what;
-            CHECK(msg->findInt32("what", &what));
-
-            if (what == MediaSender::kWhatInitDone) {
-                status_t err;
-                CHECK(msg->findInt32("err", &err));
-
-                if (err == OK) {
-                    onMediaSenderInitialized();
-                } else {
-                    notifySessionDead();
-                }
-            } else if (what == MediaSender::kWhatError) {
-                notifySessionDead();
-            } else if (what == MediaSender::kWhatNetworkStall) {
-                size_t numBytesQueued;
-                CHECK(msg->findSize("numBytesQueued", &numBytesQueued));
-
-                if (mVideoTrackIndex >= 0) {
-                    const sp<Track> &videoTrack =
-                        mTracks.valueFor(mVideoTrackIndex);
-
-                    sp<Converter> converter = videoTrack->converter();
-                    if (converter != NULL) {
-                        converter->dropAFrame();
-                    }
-                }
-            } else if (what == MediaSender::kWhatInformSender) {
-                onSinkFeedback(msg);
-            } else {
-                TRESPASS();
-            }
-            break;
-        }
-
-        case kWhatTrackNotify:
-        {
-            int32_t what;
-            CHECK(msg->findInt32("what", &what));
-
-            size_t trackIndex;
-            CHECK(msg->findSize("trackIndex", &trackIndex));
-
-            if (what == Track::kWhatStopped) {
-                ALOGI("Track %zu stopped", trackIndex);
-
-                sp<Track> track = mTracks.valueFor(trackIndex);
-                looper()->unregisterHandler(track->id());
-                mTracks.removeItem(trackIndex);
-                track.clear();
-
-                if (!mTracks.isEmpty()) {
-                    ALOGI("not all tracks are stopped yet");
-                    break;
-                }
-
-                looper()->unregisterHandler(mMediaSender->id());
-                mMediaSender.clear();
-
-                sp<AMessage> notify = mNotify->dup();
-                notify->setInt32("what", kWhatSessionDestroyed);
-                notify->post();
-            }
-            break;
-        }
-
-        case kWhatPause:
-        {
-            if (mExtractor != NULL) {
-                ++mPullExtractorGeneration;
-                mFirstSampleTimeRealUs = -1ll;
-                mFirstSampleTimeUs = -1ll;
-            }
-
-            if (mPaused) {
-                break;
-            }
-
-            for (size_t i = 0; i < mTracks.size(); ++i) {
-                mTracks.editValueAt(i)->pause();
-            }
-
-            mPaused = true;
-            break;
-        }
-
-        case kWhatResume:
-        {
-            if (mExtractor != NULL) {
-                schedulePullExtractor();
-            }
-
-            if (!mPaused) {
-                break;
-            }
-
-            for (size_t i = 0; i < mTracks.size(); ++i) {
-                mTracks.editValueAt(i)->resume();
-            }
-
-            mPaused = false;
-            break;
-        }
-
-        case kWhatPullExtractorSample:
-        {
-            int32_t generation;
-            CHECK(msg->findInt32("generation", &generation));
-
-            if (generation != mPullExtractorGeneration) {
-                break;
-            }
-
-            mPullExtractorPending = false;
-
-            onPullExtractor();
-            break;
-        }
-
-        default:
-            TRESPASS();
-    }
-}
-
-void WifiDisplaySource::PlaybackSession::onSinkFeedback(const sp<AMessage> &msg) {
-    int64_t avgLatencyUs;
-    CHECK(msg->findInt64("avgLatencyUs", &avgLatencyUs));
-
-    int64_t maxLatencyUs;
-    CHECK(msg->findInt64("maxLatencyUs", &maxLatencyUs));
-
-    ALOGI("sink reports avg. latency of %lld ms (max %lld ms)",
-          avgLatencyUs / 1000ll,
-          maxLatencyUs / 1000ll);
-
-    if (mVideoTrackIndex >= 0) {
-        const sp<Track> &videoTrack = mTracks.valueFor(mVideoTrackIndex);
-        sp<Converter> converter = videoTrack->converter();
-
-        if (converter != NULL) {
-            int32_t videoBitrate =
-                Converter::GetInt32Property("media.wfd.video-bitrate", -1);
-
-            char val[PROPERTY_VALUE_MAX];
-            if (videoBitrate < 0
-                    && property_get("media.wfd.video-bitrate", val, NULL)
-                    && !strcasecmp("adaptive", val)) {
-                videoBitrate = converter->getVideoBitrate();
-
-                if (avgLatencyUs > 300000ll) {
-                    videoBitrate *= 0.6;
-                } else if (avgLatencyUs < 100000ll) {
-                    videoBitrate *= 1.1;
-                }
-            }
-
-            if (videoBitrate > 0) {
-                if (videoBitrate < 500000) {
-                    videoBitrate = 500000;
-                } else if (videoBitrate > 10000000) {
-                    videoBitrate = 10000000;
-                }
-
-                if (videoBitrate != converter->getVideoBitrate()) {
-                    ALOGI("setting video bitrate to %d bps", videoBitrate);
-
-                    converter->setVideoBitrate(videoBitrate);
-                }
-            }
-        }
-
-        sp<RepeaterSource> repeaterSource = videoTrack->repeaterSource();
-        if (repeaterSource != NULL) {
-            double rateHz =
-                Converter::GetInt32Property(
-                        "media.wfd.video-framerate", -1);
-
-            char val[PROPERTY_VALUE_MAX];
-            if (rateHz < 0.0
-                    && property_get("media.wfd.video-framerate", val, NULL)
-                    && !strcasecmp("adaptive", val)) {
-                 rateHz = repeaterSource->getFrameRate();
-
-                if (avgLatencyUs > 300000ll) {
-                    rateHz *= 0.9;
-                } else if (avgLatencyUs < 200000ll) {
-                    rateHz *= 1.1;
-                }
-            }
-
-            if (rateHz > 0) {
-                if (rateHz < 5.0) {
-                    rateHz = 5.0;
-                } else if (rateHz > 30.0) {
-                    rateHz = 30.0;
-                }
-
-                if (rateHz != repeaterSource->getFrameRate()) {
-                    ALOGI("setting frame rate to %.2f Hz", rateHz);
-
-                    repeaterSource->setFrameRate(rateHz);
-                }
-            }
-        }
-    }
-}
-
-status_t WifiDisplaySource::PlaybackSession::setupMediaPacketizer(
-        bool enableAudio, bool enableVideo) {
-    mExtractor = new NuMediaExtractor;
-
-    status_t err = mExtractor->setDataSource(
-            NULL /* httpService */, mMediaPath.c_str());
-
-    if (err != OK) {
-        return err;
-    }
-
-    size_t n = mExtractor->countTracks();
-    bool haveAudio = false;
-    bool haveVideo = false;
-    for (size_t i = 0; i < n; ++i) {
-        sp<AMessage> format;
-        err = mExtractor->getTrackFormat(i, &format);
-
-        if (err != OK) {
-            continue;
-        }
-
-        AString mime;
-        CHECK(format->findString("mime", &mime));
-
-        bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6);
-        bool isVideo = !strncasecmp(mime.c_str(), "video/", 6);
-
-        if (isAudio && enableAudio && !haveAudio) {
-            haveAudio = true;
-        } else if (isVideo && enableVideo && !haveVideo) {
-            haveVideo = true;
-        } else {
-            continue;
-        }
-
-        err = mExtractor->selectTrack(i);
-
-        size_t trackIndex = mTracks.size();
-
-        sp<AMessage> notify = new AMessage(kWhatTrackNotify, this);
-        notify->setSize("trackIndex", trackIndex);
-
-        sp<Track> track = new Track(notify, format);
-        looper()->registerHandler(track);
-
-        mTracks.add(trackIndex, track);
-
-        mExtractorTrackToInternalTrack.add(i, trackIndex);
-
-        if (isVideo) {
-            mVideoTrackIndex = trackIndex;
-        }
-
-        uint32_t flags = MediaSender::FLAG_MANUALLY_PREPEND_SPS_PPS;
-
-        ssize_t mediaSenderTrackIndex =
-            mMediaSender->addTrack(format, flags);
-        CHECK_GE(mediaSenderTrackIndex, 0);
-
-        track->setMediaSenderTrackIndex(mediaSenderTrackIndex);
-
-        if ((haveAudio || !enableAudio) && (haveVideo || !enableVideo)) {
-            break;
-        }
-    }
-
-    return OK;
-}
-
-void WifiDisplaySource::PlaybackSession::schedulePullExtractor() {
-    if (mPullExtractorPending) {
-        return;
-    }
-
-    int64_t delayUs = 1000000; // default delay is 1 sec
-    int64_t sampleTimeUs;
-    status_t err = mExtractor->getSampleTime(&sampleTimeUs);
-
-    if (err == OK) {
-        int64_t nowUs = ALooper::GetNowUs();
-
-        if (mFirstSampleTimeRealUs < 0ll) {
-            mFirstSampleTimeRealUs = nowUs;
-            mFirstSampleTimeUs = sampleTimeUs;
-        }
-
-        int64_t whenUs = sampleTimeUs - mFirstSampleTimeUs + mFirstSampleTimeRealUs;
-        delayUs = whenUs - nowUs;
-    } else {
-        ALOGW("could not get sample time (%d)", err);
-    }
-
-    sp<AMessage> msg = new AMessage(kWhatPullExtractorSample, this);
-    msg->setInt32("generation", mPullExtractorGeneration);
-    msg->post(delayUs);
-
-    mPullExtractorPending = true;
-}
-
-void WifiDisplaySource::PlaybackSession::onPullExtractor() {
-    sp<ABuffer> accessUnit = new ABuffer(1024 * 1024);
-    status_t err = mExtractor->readSampleData(accessUnit);
-    if (err != OK) {
-        // EOS.
-        return;
-    }
-
-    int64_t timeUs;
-    CHECK_EQ((status_t)OK, mExtractor->getSampleTime(&timeUs));
-
-    accessUnit->meta()->setInt64(
-            "timeUs", mFirstSampleTimeRealUs + timeUs - mFirstSampleTimeUs);
-
-    size_t trackIndex;
-    CHECK_EQ((status_t)OK, mExtractor->getSampleTrackIndex(&trackIndex));
-
-    sp<AMessage> msg = new AMessage(kWhatConverterNotify, this);
-
-    msg->setSize(
-            "trackIndex", mExtractorTrackToInternalTrack.valueFor(trackIndex));
-
-    msg->setInt32("what", Converter::kWhatAccessUnit);
-    msg->setBuffer("accessUnit", accessUnit);
-    msg->post();
-
-    mExtractor->advance();
-
-    schedulePullExtractor();
-}
-
-status_t WifiDisplaySource::PlaybackSession::setupPacketizer(
-        bool enableAudio,
-        bool usePCMAudio,
-        bool enableVideo,
-        VideoFormats::ResolutionType videoResolutionType,
-        size_t videoResolutionIndex,
-        VideoFormats::ProfileType videoProfileType,
-        VideoFormats::LevelType videoLevelType) {
-    CHECK(enableAudio || enableVideo);
-
-    if (!mMediaPath.empty()) {
-        return setupMediaPacketizer(enableAudio, enableVideo);
-    }
-
-    if (enableVideo) {
-        status_t err = addVideoSource(
-                videoResolutionType, videoResolutionIndex, videoProfileType,
-                videoLevelType);
-
-        if (err != OK) {
-            return err;
-        }
-    }
-
-    if (!enableAudio) {
-        return OK;
-    }
-
-    return addAudioSource(usePCMAudio);
-}
-
-status_t WifiDisplaySource::PlaybackSession::addSource(
-        bool isVideo, const sp<MediaSource> &source, bool isRepeaterSource,
-        bool usePCMAudio, unsigned profileIdc, unsigned levelIdc,
-        unsigned constraintSet, size_t *numInputBuffers) {
-    CHECK(!usePCMAudio || !isVideo);
-    CHECK(!isRepeaterSource || isVideo);
-    CHECK(!profileIdc || isVideo);
-    CHECK(!levelIdc || isVideo);
-    CHECK(!constraintSet || isVideo);
-
-    sp<ALooper> pullLooper = new ALooper;
-    pullLooper->setName("pull_looper");
-
-    pullLooper->start(
-            false /* runOnCallingThread */,
-            false /* canCallJava */,
-            PRIORITY_AUDIO);
-
-    sp<ALooper> codecLooper = new ALooper;
-    codecLooper->setName("codec_looper");
-
-    codecLooper->start(
-            false /* runOnCallingThread */,
-            false /* canCallJava */,
-            PRIORITY_AUDIO);
-
-    size_t trackIndex;
-
-    sp<AMessage> notify;
-
-    trackIndex = mTracks.size();
-
-    sp<AMessage> format;
-    status_t err = convertMetaDataToMessage(source->getFormat(), &format);
-    CHECK_EQ(err, (status_t)OK);
-
-    if (isVideo) {
-        format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
-        format->setInt32(
-                "android._input-metadata-buffer-type", kMetadataBufferTypeANWBuffer);
-        format->setInt32("android._store-metadata-in-buffers-output", (mHDCP != NULL)
-                && (mHDCP->getCaps() & HDCPModule::HDCP_CAPS_ENCRYPT_NATIVE));
-        format->setInt32(
-                "color-format", OMX_COLOR_FormatAndroidOpaque);
-        format->setInt32("profile-idc", profileIdc);
-        format->setInt32("level-idc", levelIdc);
-        format->setInt32("constraint-set", constraintSet);
-    } else {
-        if (usePCMAudio) {
-            format->setInt32("pcm-encoding", kAudioEncodingPcm16bit);
-            format->setString("mime", MEDIA_MIMETYPE_AUDIO_RAW);
-        } else {
-            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
-        }
-    }
-
-    notify = new AMessage(kWhatConverterNotify, this);
-    notify->setSize("trackIndex", trackIndex);
-
-    sp<Converter> converter = new Converter(notify, codecLooper, format);
-
-    looper()->registerHandler(converter);
-
-    err = converter->init();
-    if (err != OK) {
-        ALOGE("%s converter returned err %d", isVideo ? "video" : "audio", err);
-
-        looper()->unregisterHandler(converter->id());
-        return err;
-    }
-
-    notify = new AMessage(Converter::kWhatMediaPullerNotify, converter);
-    notify->setSize("trackIndex", trackIndex);
-
-    sp<MediaPuller> puller = new MediaPuller(source, notify);
-    pullLooper->registerHandler(puller);
-
-    if (numInputBuffers != NULL) {
-        *numInputBuffers = converter->getInputBufferCount();
-    }
-
-    notify = new AMessage(kWhatTrackNotify, this);
-    notify->setSize("trackIndex", trackIndex);
-
-    sp<Track> track = new Track(
-            notify, pullLooper, codecLooper, puller, converter);
-
-    if (isRepeaterSource) {
-        track->setRepeaterSource(static_cast<RepeaterSource *>(source.get()));
-    }
-
-    looper()->registerHandler(track);
-
-    mTracks.add(trackIndex, track);
-
-    if (isVideo) {
-        mVideoTrackIndex = trackIndex;
-    }
-
-    uint32_t flags = 0;
-    if (converter->needToManuallyPrependSPSPPS()) {
-        flags |= MediaSender::FLAG_MANUALLY_PREPEND_SPS_PPS;
-    }
-
-    ssize_t mediaSenderTrackIndex =
-        mMediaSender->addTrack(converter->getOutputFormat(), flags);
-    CHECK_GE(mediaSenderTrackIndex, 0);
-
-    track->setMediaSenderTrackIndex(mediaSenderTrackIndex);
-
-    return OK;
-}
-
-status_t WifiDisplaySource::PlaybackSession::addVideoSource(
-        VideoFormats::ResolutionType videoResolutionType,
-        size_t videoResolutionIndex,
-        VideoFormats::ProfileType videoProfileType,
-        VideoFormats::LevelType videoLevelType) {
-    size_t width, height, framesPerSecond;
-    bool interlaced;
-    CHECK(VideoFormats::GetConfiguration(
-                videoResolutionType,
-                videoResolutionIndex,
-                &width,
-                &height,
-                &framesPerSecond,
-                &interlaced));
-
-    unsigned profileIdc, levelIdc, constraintSet;
-    CHECK(VideoFormats::GetProfileLevel(
-                videoProfileType,
-                videoLevelType,
-                &profileIdc,
-                &levelIdc,
-                &constraintSet));
-
-    sp<SurfaceMediaSource> source = new SurfaceMediaSource(width, height);
-
-    source->setUseAbsoluteTimestamps();
-
-    sp<RepeaterSource> videoSource =
-        new RepeaterSource(source, framesPerSecond);
-
-    size_t numInputBuffers;
-    status_t err = addSource(
-            true /* isVideo */, videoSource, true /* isRepeaterSource */,
-            false /* usePCMAudio */, profileIdc, levelIdc, constraintSet,
-            &numInputBuffers);
-
-    if (err != OK) {
-        return err;
-    }
-
-    err = source->setMaxAcquiredBufferCount(numInputBuffers);
-    CHECK_EQ(err, (status_t)OK);
-
-    mProducer = source->getProducer();
-
-    return OK;
-}
-
-status_t WifiDisplaySource::PlaybackSession::addAudioSource(bool usePCMAudio) {
-    sp<AudioSource> audioSource = new AudioSource(
-            AUDIO_SOURCE_REMOTE_SUBMIX,
-            mOpPackageName,
-            48000 /* sampleRate */,
-            2 /* channelCount */);
-
-    if (audioSource->initCheck() == OK) {
-        return addSource(
-                false /* isVideo */, audioSource, false /* isRepeaterSource */,
-                usePCMAudio, 0 /* profileIdc */, 0 /* levelIdc */,
-                0 /* constraintSet */, NULL /* numInputBuffers */);
-    }
-
-    ALOGW("Unable to instantiate audio source");
-
-    return OK;
-}
-
-sp<IGraphicBufferProducer> WifiDisplaySource::PlaybackSession::getSurfaceTexture() {
-    return mProducer;
-}
-
-void WifiDisplaySource::PlaybackSession::requestIDRFrame() {
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        const sp<Track> &track = mTracks.valueAt(i);
-
-        track->requestIDRFrame();
-    }
-}
-
-void WifiDisplaySource::PlaybackSession::notifySessionDead() {
-    // Inform WifiDisplaySource of our premature death (wish).
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatSessionDead);
-    notify->post();
-
-    mWeAreDead = true;
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h
deleted file mode 100644
index f6673df..0000000
--- a/media/libstagefright/wifi-display/source/PlaybackSession.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 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 PLAYBACK_SESSION_H_
-
-#define PLAYBACK_SESSION_H_
-
-#include "MediaSender.h"
-#include "VideoFormats.h"
-#include "WifiDisplaySource.h"
-
-#include <utils/String16.h>
-
-namespace android {
-
-struct ABuffer;
-struct IHDCP;
-class IGraphicBufferProducer;
-struct MediaPuller;
-struct MediaSource;
-struct MediaSender;
-struct NuMediaExtractor;
-
-// Encapsulates the state of an RTP/RTCP session in the context of wifi
-// display.
-struct WifiDisplaySource::PlaybackSession : public AHandler {
-    PlaybackSession(
-            const String16 &opPackageName,
-            const sp<ANetworkSession> &netSession,
-            const sp<AMessage> &notify,
-            const struct in_addr &interfaceAddr,
-            const sp<IHDCP> &hdcp,
-            const char *path = NULL);
-
-    status_t init(
-            const char *clientIP,
-            int32_t clientRtp,
-            RTPSender::TransportMode rtpMode,
-            int32_t clientRtcp,
-            RTPSender::TransportMode rtcpMode,
-            bool enableAudio,
-            bool usePCMAudio,
-            bool enableVideo,
-            VideoFormats::ResolutionType videoResolutionType,
-            size_t videoResolutionIndex,
-            VideoFormats::ProfileType videoProfileType,
-            VideoFormats::LevelType videoLevelType);
-
-    void destroyAsync();
-
-    int32_t getRTPPort() const;
-
-    int64_t getLastLifesignUs() const;
-    void updateLiveness();
-
-    status_t play();
-    status_t finishPlay();
-    status_t pause();
-
-    sp<IGraphicBufferProducer> getSurfaceTexture();
-
-    void requestIDRFrame();
-
-    enum {
-        kWhatSessionDead,
-        kWhatBinaryData,
-        kWhatSessionEstablished,
-        kWhatSessionDestroyed,
-    };
-
-protected:
-    virtual void onMessageReceived(const sp<AMessage> &msg);
-    virtual ~PlaybackSession();
-
-private:
-    struct Track;
-
-    enum {
-        kWhatMediaPullerNotify,
-        kWhatConverterNotify,
-        kWhatTrackNotify,
-        kWhatUpdateSurface,
-        kWhatPause,
-        kWhatResume,
-        kWhatMediaSenderNotify,
-        kWhatPullExtractorSample,
-    };
-
-    String16 mOpPackageName;
-
-    sp<ANetworkSession> mNetSession;
-    sp<AMessage> mNotify;
-    in_addr mInterfaceAddr;
-    sp<IHDCP> mHDCP;
-    AString mMediaPath;
-
-    sp<MediaSender> mMediaSender;
-    int32_t mLocalRTPPort;
-
-    bool mWeAreDead;
-    bool mPaused;
-
-    int64_t mLastLifesignUs;
-
-    sp<IGraphicBufferProducer> mProducer;
-
-    KeyedVector<size_t, sp<Track> > mTracks;
-    ssize_t mVideoTrackIndex;
-
-    int64_t mPrevTimeUs;
-
-    sp<NuMediaExtractor> mExtractor;
-    KeyedVector<size_t, size_t> mExtractorTrackToInternalTrack;
-    bool mPullExtractorPending;
-    int32_t mPullExtractorGeneration;
-    int64_t mFirstSampleTimeRealUs;
-    int64_t mFirstSampleTimeUs;
-
-    status_t setupMediaPacketizer(bool enableAudio, bool enableVideo);
-
-    status_t setupPacketizer(
-            bool enableAudio,
-            bool usePCMAudio,
-            bool enableVideo,
-            VideoFormats::ResolutionType videoResolutionType,
-            size_t videoResolutionIndex,
-            VideoFormats::ProfileType videoProfileType,
-            VideoFormats::LevelType videoLevelType);
-
-    status_t addSource(
-            bool isVideo,
-            const sp<MediaSource> &source,
-            bool isRepeaterSource,
-            bool usePCMAudio,
-            unsigned profileIdc,
-            unsigned levelIdc,
-            unsigned contraintSet,
-            size_t *numInputBuffers);
-
-    status_t addVideoSource(
-            VideoFormats::ResolutionType videoResolutionType,
-            size_t videoResolutionIndex,
-            VideoFormats::ProfileType videoProfileType,
-            VideoFormats::LevelType videoLevelType);
-
-    status_t addAudioSource(bool usePCMAudio);
-
-    status_t onMediaSenderInitialized();
-
-    void notifySessionDead();
-
-    void schedulePullExtractor();
-    void onPullExtractor();
-
-    void onSinkFeedback(const sp<AMessage> &msg);
-
-    DISALLOW_EVIL_CONSTRUCTORS(PlaybackSession);
-};
-
-}  // namespace android
-
-#endif  // PLAYBACK_SESSION_H_
-
diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.cpp b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
deleted file mode 100644
index af6b663..0000000
--- a/media/libstagefright/wifi-display/source/RepeaterSource.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-//#define LOG_NDEBUG 0
-#define LOG_TAG "RepeaterSource"
-#include <utils/Log.h>
-
-#include "RepeaterSource.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/MetaData.h>
-
-namespace android {
-
-RepeaterSource::RepeaterSource(const sp<MediaSource> &source, double rateHz)
-    : mStarted(false),
-      mSource(source),
-      mRateHz(rateHz),
-      mBuffer(NULL),
-      mResult(OK),
-      mLastBufferUpdateUs(-1ll),
-      mStartTimeUs(-1ll),
-      mFrameCount(0) {
-}
-
-RepeaterSource::~RepeaterSource() {
-    CHECK(!mStarted);
-}
-
-double RepeaterSource::getFrameRate() const {
-    return mRateHz;
-}
-
-void RepeaterSource::setFrameRate(double rateHz) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (rateHz == mRateHz) {
-        return;
-    }
-
-    if (mStartTimeUs >= 0ll) {
-        int64_t nextTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
-        mStartTimeUs = nextTimeUs;
-        mFrameCount = 0;
-    }
-    mRateHz = rateHz;
-}
-
-status_t RepeaterSource::start(MetaData *params) {
-    CHECK(!mStarted);
-
-    status_t err = mSource->start(params);
-
-    if (err != OK) {
-        return err;
-    }
-
-    mBuffer = NULL;
-    mResult = OK;
-    mStartTimeUs = -1ll;
-    mFrameCount = 0;
-
-    mLooper = new ALooper;
-    mLooper->setName("repeater_looper");
-    mLooper->start();
-
-    mReflector = new AHandlerReflector<RepeaterSource>(this);
-    mLooper->registerHandler(mReflector);
-
-    postRead();
-
-    mStarted = true;
-
-    return OK;
-}
-
-status_t RepeaterSource::stop() {
-    CHECK(mStarted);
-
-    ALOGV("stopping");
-
-    status_t err = mSource->stop();
-
-    if (mLooper != NULL) {
-        mLooper->stop();
-        mLooper.clear();
-
-        mReflector.clear();
-    }
-
-    if (mBuffer != NULL) {
-        ALOGV("releasing mbuf %p", mBuffer);
-        mBuffer->release();
-        mBuffer = NULL;
-    }
-
-
-    ALOGV("stopped");
-
-    mStarted = false;
-
-    return err;
-}
-
-sp<MetaData> RepeaterSource::getFormat() {
-    return mSource->getFormat();
-}
-
-status_t RepeaterSource::read(
-        MediaBuffer **buffer, const ReadOptions *options) {
-    int64_t seekTimeUs;
-    ReadOptions::SeekMode seekMode;
-    CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &seekMode));
-
-    for (;;) {
-        int64_t bufferTimeUs = -1ll;
-
-        if (mStartTimeUs < 0ll) {
-            Mutex::Autolock autoLock(mLock);
-            while ((mLastBufferUpdateUs < 0ll || mBuffer == NULL)
-                    && mResult == OK) {
-                mCondition.wait(mLock);
-            }
-
-            ALOGV("now resuming.");
-            mStartTimeUs = ALooper::GetNowUs();
-            bufferTimeUs = mStartTimeUs;
-        } else {
-            bufferTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
-
-            int64_t nowUs = ALooper::GetNowUs();
-            int64_t delayUs = bufferTimeUs - nowUs;
-
-            if (delayUs > 0ll) {
-                usleep(delayUs);
-            }
-        }
-
-        bool stale = false;
-
-        {
-            Mutex::Autolock autoLock(mLock);
-            if (mResult != OK) {
-                CHECK(mBuffer == NULL);
-                return mResult;
-            }
-
-#if SUSPEND_VIDEO_IF_IDLE
-            int64_t nowUs = ALooper::GetNowUs();
-            if (nowUs - mLastBufferUpdateUs > 1000000ll) {
-                mLastBufferUpdateUs = -1ll;
-                stale = true;
-            } else
-#endif
-            {
-                mBuffer->add_ref();
-                *buffer = mBuffer;
-                (*buffer)->meta_data()->setInt64(kKeyTime, bufferTimeUs);
-                ++mFrameCount;
-            }
-        }
-
-        if (!stale) {
-            break;
-        }
-
-        mStartTimeUs = -1ll;
-        mFrameCount = 0;
-        ALOGV("now dormant");
-    }
-
-    return OK;
-}
-
-void RepeaterSource::postRead() {
-    (new AMessage(kWhatRead, mReflector))->post();
-}
-
-void RepeaterSource::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        case kWhatRead:
-        {
-            MediaBuffer *buffer;
-            status_t err = mSource->read(&buffer);
-
-            ALOGV("read mbuf %p", buffer);
-
-            Mutex::Autolock autoLock(mLock);
-            if (mBuffer != NULL) {
-                mBuffer->release();
-                mBuffer = NULL;
-            }
-            mBuffer = buffer;
-            mResult = err;
-            mLastBufferUpdateUs = ALooper::GetNowUs();
-
-            mCondition.broadcast();
-
-            if (err == OK) {
-                postRead();
-            }
-            break;
-        }
-
-        default:
-            TRESPASS();
-    }
-}
-
-void RepeaterSource::wakeUp() {
-    ALOGV("wakeUp");
-    Mutex::Autolock autoLock(mLock);
-    if (mLastBufferUpdateUs < 0ll && mBuffer != NULL) {
-        mLastBufferUpdateUs = ALooper::GetNowUs();
-        mCondition.broadcast();
-    }
-}
-
-}  // namespace android
diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.h b/media/libstagefright/wifi-display/source/RepeaterSource.h
deleted file mode 100644
index 8d414fd..0000000
--- a/media/libstagefright/wifi-display/source/RepeaterSource.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef REPEATER_SOURCE_H_
-
-#define REPEATER_SOURCE_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AHandlerReflector.h>
-#include <media/stagefright/MediaSource.h>
-
-#define SUSPEND_VIDEO_IF_IDLE   0
-
-namespace android {
-
-// This MediaSource delivers frames at a constant rate by repeating buffers
-// if necessary.
-struct RepeaterSource : public MediaSource {
-    RepeaterSource(const sp<MediaSource> &source, double rateHz);
-
-    virtual status_t start(MetaData *params);
-    virtual status_t stop();
-    virtual sp<MetaData> getFormat();
-
-    virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options);
-
-    void onMessageReceived(const sp<AMessage> &msg);
-
-    // If RepeaterSource is currently dormant, because SurfaceFlinger didn't
-    // send updates in a while, this is its wakeup call.
-    void wakeUp();
-
-    double getFrameRate() const;
-    void setFrameRate(double rateHz);
-
-protected:
-    virtual ~RepeaterSource();
-
-private:
-    enum {
-        kWhatRead,
-    };
-
-    Mutex mLock;
-    Condition mCondition;
-
-    bool mStarted;
-
-    sp<MediaSource> mSource;
-    double mRateHz;
-
-    sp<ALooper> mLooper;
-    sp<AHandlerReflector<RepeaterSource> > mReflector;
-
-    MediaBuffer *mBuffer;
-    status_t mResult;
-    int64_t mLastBufferUpdateUs;
-
-    int64_t mStartTimeUs;
-    int32_t mFrameCount;
-
-    void postRead();
-
-    DISALLOW_EVIL_CONSTRUCTORS(RepeaterSource);
-};
-
-}  // namespace android
-
-#endif // REPEATER_SOURCE_H_
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
deleted file mode 100644
index 865ba94..0000000
--- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp
+++ /dev/null
@@ -1,1055 +0,0 @@
-/*
- * Copyright 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 "TSPacketizer"
-#include <utils/Log.h>
-
-#include "TSPacketizer.h"
-#include "include/avc_utils.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 <arpa/inet.h>
-
-namespace android {
-
-struct TSPacketizer::Track : public RefBase {
-    Track(const sp<AMessage> &format,
-          unsigned PID, unsigned streamType, unsigned streamID);
-
-    unsigned PID() const;
-    unsigned streamType() const;
-    unsigned streamID() const;
-
-    // Returns the previous value.
-    unsigned incrementContinuityCounter();
-
-    bool isAudio() const;
-    bool isVideo() const;
-
-    bool isH264() const;
-    bool isAAC() const;
-    bool lacksADTSHeader() const;
-    bool isPCMAudio() const;
-
-    sp<ABuffer> prependCSD(const sp<ABuffer> &accessUnit) const;
-    sp<ABuffer> prependADTSHeader(const sp<ABuffer> &accessUnit) const;
-
-    size_t countDescriptors() const;
-    sp<ABuffer> descriptorAt(size_t index) const;
-
-    void finalize();
-    void extractCSDIfNecessary();
-
-protected:
-    virtual ~Track();
-
-private:
-    sp<AMessage> mFormat;
-
-    unsigned mPID;
-    unsigned mStreamType;
-    unsigned mStreamID;
-    unsigned mContinuityCounter;
-
-    AString mMIME;
-    Vector<sp<ABuffer> > mCSD;
-
-    Vector<sp<ABuffer> > mDescriptors;
-
-    bool mAudioLacksATDSHeaders;
-    bool mFinalized;
-    bool mExtractedCSD;
-
-    DISALLOW_EVIL_CONSTRUCTORS(Track);
-};
-
-TSPacketizer::Track::Track(
-        const sp<AMessage> &format,
-        unsigned PID, unsigned streamType, unsigned streamID)
-    : mFormat(format),
-      mPID(PID),
-      mStreamType(streamType),
-      mStreamID(streamID),
-      mContinuityCounter(0),
-      mAudioLacksATDSHeaders(false),
-      mFinalized(false),
-      mExtractedCSD(false) {
-    CHECK(format->findString("mime", &mMIME));
-}
-
-void TSPacketizer::Track::extractCSDIfNecessary() {
-    if (mExtractedCSD) {
-        return;
-    }
-
-    if (!strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)
-            || !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
-        for (size_t i = 0;; ++i) {
-            sp<ABuffer> csd;
-            if (!mFormat->findBuffer(AStringPrintf("csd-%d", i).c_str(), &csd)) {
-                break;
-            }
-
-            mCSD.push(csd);
-        }
-
-        if (!strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
-            int32_t isADTS;
-            if (!mFormat->findInt32("is-adts", &isADTS) || isADTS == 0) {
-                mAudioLacksATDSHeaders = true;
-            }
-        }
-    }
-
-    mExtractedCSD = true;
-}
-
-TSPacketizer::Track::~Track() {
-}
-
-unsigned TSPacketizer::Track::PID() const {
-    return mPID;
-}
-
-unsigned TSPacketizer::Track::streamType() const {
-    return mStreamType;
-}
-
-unsigned TSPacketizer::Track::streamID() const {
-    return mStreamID;
-}
-
-unsigned TSPacketizer::Track::incrementContinuityCounter() {
-    unsigned prevCounter = mContinuityCounter;
-
-    if (++mContinuityCounter == 16) {
-        mContinuityCounter = 0;
-    }
-
-    return prevCounter;
-}
-
-bool TSPacketizer::Track::isAudio() const {
-    return !strncasecmp("audio/", mMIME.c_str(), 6);
-}
-
-bool TSPacketizer::Track::isVideo() const {
-    return !strncasecmp("video/", mMIME.c_str(), 6);
-}
-
-bool TSPacketizer::Track::isH264() const {
-    return !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_VIDEO_AVC);
-}
-
-bool TSPacketizer::Track::isAAC() const {
-    return !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_AUDIO_AAC);
-}
-
-bool TSPacketizer::Track::isPCMAudio() const {
-    return !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_AUDIO_RAW);
-}
-
-bool TSPacketizer::Track::lacksADTSHeader() const {
-    return mAudioLacksATDSHeaders;
-}
-
-sp<ABuffer> TSPacketizer::Track::prependCSD(
-        const sp<ABuffer> &accessUnit) const {
-    size_t size = 0;
-    for (size_t i = 0; i < mCSD.size(); ++i) {
-        size += mCSD.itemAt(i)->size();
-    }
-
-    sp<ABuffer> dup = new ABuffer(accessUnit->size() + size);
-    size_t offset = 0;
-    for (size_t i = 0; i < mCSD.size(); ++i) {
-        const sp<ABuffer> &csd = mCSD.itemAt(i);
-
-        memcpy(dup->data() + offset, csd->data(), csd->size());
-        offset += csd->size();
-    }
-
-    memcpy(dup->data() + offset, accessUnit->data(), accessUnit->size());
-
-    return dup;
-}
-
-sp<ABuffer> TSPacketizer::Track::prependADTSHeader(
-        const sp<ABuffer> &accessUnit) const {
-    CHECK_EQ(mCSD.size(), 1u);
-
-    const uint8_t *codec_specific_data = mCSD.itemAt(0)->data();
-
-    const uint32_t aac_frame_length = accessUnit->size() + 7;
-
-    sp<ABuffer> dup = new ABuffer(aac_frame_length);
-
-    unsigned profile = (codec_specific_data[0] >> 3) - 1;
-
-    unsigned sampling_freq_index =
-        ((codec_specific_data[0] & 7) << 1)
-        | (codec_specific_data[1] >> 7);
-
-    unsigned channel_configuration =
-        (codec_specific_data[1] >> 3) & 0x0f;
-
-    uint8_t *ptr = dup->data();
-
-    *ptr++ = 0xff;
-    *ptr++ = 0xf9;  // b11111001, ID=1(MPEG-2), layer=0, protection_absent=1
-
-    *ptr++ =
-        profile << 6
-        | sampling_freq_index << 2
-        | ((channel_configuration >> 2) & 1);  // private_bit=0
-
-    // original_copy=0, home=0, copyright_id_bit=0, copyright_id_start=0
-    *ptr++ =
-        (channel_configuration & 3) << 6
-        | aac_frame_length >> 11;
-    *ptr++ = (aac_frame_length >> 3) & 0xff;
-    *ptr++ = (aac_frame_length & 7) << 5;
-
-    // adts_buffer_fullness=0, number_of_raw_data_blocks_in_frame=0
-    *ptr++ = 0;
-
-    memcpy(ptr, accessUnit->data(), accessUnit->size());
-
-    return dup;
-}
-
-size_t TSPacketizer::Track::countDescriptors() const {
-    return mDescriptors.size();
-}
-
-sp<ABuffer> TSPacketizer::Track::descriptorAt(size_t index) const {
-    CHECK_LT(index, mDescriptors.size());
-    return mDescriptors.itemAt(index);
-}
-
-void TSPacketizer::Track::finalize() {
-    if (mFinalized) {
-        return;
-    }
-
-    if (isH264()) {
-        {
-            // AVC video descriptor (40)
-
-            sp<ABuffer> descriptor = new ABuffer(6);
-            uint8_t *data = descriptor->data();
-            data[0] = 40;  // descriptor_tag
-            data[1] = 4;  // descriptor_length
-
-            if (mCSD.size() > 0) {
-                CHECK_GE(mCSD.size(), 1u);
-                const sp<ABuffer> &sps = mCSD.itemAt(0);
-                CHECK(!memcmp("\x00\x00\x00\x01", sps->data(), 4));
-                CHECK_GE(sps->size(), 7u);
-                // profile_idc, constraint_set*, level_idc
-                memcpy(&data[2], sps->data() + 4, 3);
-            } else {
-                int32_t profileIdc, levelIdc, constraintSet;
-                CHECK(mFormat->findInt32("profile-idc", &profileIdc));
-                CHECK(mFormat->findInt32("level-idc", &levelIdc));
-                CHECK(mFormat->findInt32("constraint-set", &constraintSet));
-                CHECK_GE(profileIdc, 0);
-                CHECK_GE(levelIdc, 0);
-                data[2] = profileIdc;    // profile_idc
-                data[3] = constraintSet; // constraint_set*
-                data[4] = levelIdc;      // level_idc
-            }
-
-            // AVC_still_present=0, AVC_24_hour_picture_flag=0, reserved
-            data[5] = 0x3f;
-
-            mDescriptors.push_back(descriptor);
-        }
-
-        {
-            // AVC timing and HRD descriptor (42)
-
-            sp<ABuffer> descriptor = new ABuffer(4);
-            uint8_t *data = descriptor->data();
-            data[0] = 42;  // descriptor_tag
-            data[1] = 2;  // descriptor_length
-
-            // hrd_management_valid_flag = 0
-            // reserved = 111111b
-            // picture_and_timing_info_present = 0
-
-            data[2] = 0x7e;
-
-            // fixed_frame_rate_flag = 0
-            // temporal_poc_flag = 0
-            // picture_to_display_conversion_flag = 0
-            // reserved = 11111b
-            data[3] = 0x1f;
-
-            mDescriptors.push_back(descriptor);
-        }
-    } else if (isPCMAudio()) {
-        // LPCM audio stream descriptor (0x83)
-
-        int32_t channelCount;
-        CHECK(mFormat->findInt32("channel-count", &channelCount));
-        CHECK_EQ(channelCount, 2);
-
-        int32_t sampleRate;
-        CHECK(mFormat->findInt32("sample-rate", &sampleRate));
-        CHECK(sampleRate == 44100 || sampleRate == 48000);
-
-        sp<ABuffer> descriptor = new ABuffer(4);
-        uint8_t *data = descriptor->data();
-        data[0] = 0x83;  // descriptor_tag
-        data[1] = 2;  // descriptor_length
-
-        unsigned sampling_frequency = (sampleRate == 44100) ? 1 : 2;
-
-        data[2] = (sampling_frequency << 5)
-                    | (3 /* reserved */ << 1)
-                    | 0 /* emphasis_flag */;
-
-        data[3] =
-            (1 /* number_of_channels = stereo */ << 5)
-            | 0xf /* reserved */;
-
-        mDescriptors.push_back(descriptor);
-    }
-
-    mFinalized = true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-TSPacketizer::TSPacketizer(uint32_t flags)
-    : mFlags(flags),
-      mPATContinuityCounter(0),
-      mPMTContinuityCounter(0) {
-    initCrcTable();
-
-    if (flags & (EMIT_HDCP20_DESCRIPTOR | EMIT_HDCP21_DESCRIPTOR)) {
-        int32_t hdcpVersion;
-        if (flags & EMIT_HDCP20_DESCRIPTOR) {
-            CHECK(!(flags & EMIT_HDCP21_DESCRIPTOR));
-            hdcpVersion = 0x20;
-        } else {
-            CHECK(!(flags & EMIT_HDCP20_DESCRIPTOR));
-
-            // HDCP2.0 _and_ HDCP 2.1 specs say to set the version
-            // inside the HDCP descriptor to 0x20!!!
-            hdcpVersion = 0x20;
-        }
-
-        // HDCP descriptor
-        sp<ABuffer> descriptor = new ABuffer(7);
-        uint8_t *data = descriptor->data();
-        data[0] = 0x05;  // descriptor_tag
-        data[1] = 5;  // descriptor_length
-        data[2] = 'H';
-        data[3] = 'D';
-        data[4] = 'C';
-        data[5] = 'P';
-        data[6] = hdcpVersion;
-
-        mProgramInfoDescriptors.push_back(descriptor);
-    }
-}
-
-TSPacketizer::~TSPacketizer() {
-}
-
-ssize_t TSPacketizer::addTrack(const sp<AMessage> &format) {
-    AString mime;
-    CHECK(format->findString("mime", &mime));
-
-    unsigned PIDStart;
-    bool isVideo = !strncasecmp("video/", mime.c_str(), 6);
-    bool isAudio = !strncasecmp("audio/", mime.c_str(), 6);
-
-    if (isVideo) {
-        PIDStart = 0x1011;
-    } else if (isAudio) {
-        PIDStart = 0x1100;
-    } else {
-        return ERROR_UNSUPPORTED;
-    }
-
-    unsigned streamType;
-    unsigned streamIDStart;
-    unsigned streamIDStop;
-
-    if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) {
-        streamType = 0x1b;
-        streamIDStart = 0xe0;
-        streamIDStop = 0xef;
-    } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
-        streamType = 0x0f;
-        streamIDStart = 0xc0;
-        streamIDStop = 0xdf;
-    } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) {
-        streamType = 0x83;
-        streamIDStart = 0xbd;
-        streamIDStop = 0xbd;
-    } else {
-        return ERROR_UNSUPPORTED;
-    }
-
-    size_t numTracksOfThisType = 0;
-    unsigned PID = PIDStart;
-
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        const sp<Track> &track = mTracks.itemAt(i);
-
-        if (track->streamType() == streamType) {
-            ++numTracksOfThisType;
-        }
-
-        if ((isAudio && track->isAudio()) || (isVideo && track->isVideo())) {
-            ++PID;
-        }
-    }
-
-    unsigned streamID = streamIDStart + numTracksOfThisType;
-    if (streamID > streamIDStop) {
-        return -ERANGE;
-    }
-
-    sp<Track> track = new Track(format, PID, streamType, streamID);
-    return mTracks.add(track);
-}
-
-status_t TSPacketizer::extractCSDIfNecessary(size_t trackIndex) {
-    if (trackIndex >= mTracks.size()) {
-        return -ERANGE;
-    }
-
-    const sp<Track> &track = mTracks.itemAt(trackIndex);
-    track->extractCSDIfNecessary();
-
-    return OK;
-}
-
-status_t TSPacketizer::packetize(
-        size_t trackIndex,
-        const sp<ABuffer> &_accessUnit,
-        sp<ABuffer> *packets,
-        uint32_t flags,
-        const uint8_t *PES_private_data, size_t PES_private_data_len,
-        size_t numStuffingBytes) {
-    sp<ABuffer> accessUnit = _accessUnit;
-
-    int64_t timeUs;
-    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
-    packets->clear();
-
-    if (trackIndex >= mTracks.size()) {
-        return -ERANGE;
-    }
-
-    const sp<Track> &track = mTracks.itemAt(trackIndex);
-
-    if (track->isH264() && (flags & PREPEND_SPS_PPS_TO_IDR_FRAMES)
-            && IsIDR(accessUnit)) {
-        // prepend codec specific data, i.e. SPS and PPS.
-        accessUnit = track->prependCSD(accessUnit);
-    } else if (track->isAAC() && track->lacksADTSHeader()) {
-        CHECK(!(flags & IS_ENCRYPTED));
-        accessUnit = track->prependADTSHeader(accessUnit);
-    }
-
-    // 0x47
-    // transport_error_indicator = b0
-    // payload_unit_start_indicator = b1
-    // transport_priority = b0
-    // PID
-    // transport_scrambling_control = b00
-    // adaptation_field_control = b??
-    // continuity_counter = b????
-    // -- payload follows
-    // packet_startcode_prefix = 0x000001
-    // stream_id
-    // PES_packet_length = 0x????
-    // reserved = b10
-    // PES_scrambling_control = b00
-    // PES_priority = b0
-    // data_alignment_indicator = b1
-    // copyright = b0
-    // original_or_copy = b0
-    // PTS_DTS_flags = b10  (PTS only)
-    // ESCR_flag = b0
-    // ES_rate_flag = b0
-    // DSM_trick_mode_flag = b0
-    // additional_copy_info_flag = b0
-    // PES_CRC_flag = b0
-    // PES_extension_flag = b0
-    // PES_header_data_length = 0x05
-    // reserved = b0010 (PTS)
-    // PTS[32..30] = b???
-    // reserved = b1
-    // PTS[29..15] = b??? ???? ???? ???? (15 bits)
-    // reserved = b1
-    // PTS[14..0] = b??? ???? ???? ???? (15 bits)
-    // reserved = b1
-    // the first fragment of "buffer" follows
-
-    // Each transport packet (except for the last one contributing to the PES
-    // payload) must contain a multiple of 16 bytes of payload per HDCP spec.
-    bool alignPayload =
-        (mFlags & (EMIT_HDCP20_DESCRIPTOR | EMIT_HDCP21_DESCRIPTOR));
-
-    /*
-       a) The very first PES transport stream packet contains
-
-       4 bytes of TS header
-       ... padding
-       14 bytes of static PES header
-       PES_private_data_len + 1 bytes (only if PES_private_data_len > 0)
-       numStuffingBytes bytes
-
-       followed by the payload
-
-       b) Subsequent PES transport stream packets contain
-
-       4 bytes of TS header
-       ... padding
-
-       followed by the payload
-    */
-
-    size_t PES_packet_length = accessUnit->size() + 8 + numStuffingBytes;
-    if (PES_private_data_len > 0) {
-        PES_packet_length += PES_private_data_len + 1;
-    }
-
-    size_t numTSPackets = 1;
-
-    {
-        // Make sure the PES header fits into a single TS packet:
-        size_t PES_header_size = 14 + numStuffingBytes;
-        if (PES_private_data_len > 0) {
-            PES_header_size += PES_private_data_len + 1;
-        }
-
-        CHECK_LE(PES_header_size, 188u - 4u);
-
-        size_t sizeAvailableForPayload = 188 - 4 - PES_header_size;
-        size_t numBytesOfPayload = accessUnit->size();
-
-        if (numBytesOfPayload > sizeAvailableForPayload) {
-            numBytesOfPayload = sizeAvailableForPayload;
-
-            if (alignPayload && numBytesOfPayload > 16) {
-                numBytesOfPayload -= (numBytesOfPayload % 16);
-            }
-        }
-
-        size_t numPaddingBytes = sizeAvailableForPayload - numBytesOfPayload;
-        ALOGV("packet 1 contains %zd padding bytes and %zd bytes of payload",
-              numPaddingBytes, numBytesOfPayload);
-
-        size_t numBytesOfPayloadRemaining = accessUnit->size() - numBytesOfPayload;
-
-#if 0
-        // The following hopefully illustrates the logic that led to the
-        // more efficient computation in the #else block...
-
-        while (numBytesOfPayloadRemaining > 0) {
-            size_t sizeAvailableForPayload = 188 - 4;
-
-            size_t numBytesOfPayload = numBytesOfPayloadRemaining;
-
-            if (numBytesOfPayload > sizeAvailableForPayload) {
-                numBytesOfPayload = sizeAvailableForPayload;
-
-                if (alignPayload && numBytesOfPayload > 16) {
-                    numBytesOfPayload -= (numBytesOfPayload % 16);
-                }
-            }
-
-            size_t numPaddingBytes = sizeAvailableForPayload - numBytesOfPayload;
-            ALOGI("packet %zd contains %zd padding bytes and %zd bytes of payload",
-                    numTSPackets + 1, numPaddingBytes, numBytesOfPayload);
-
-            numBytesOfPayloadRemaining -= numBytesOfPayload;
-            ++numTSPackets;
-        }
-#else
-        // This is how many bytes of payload each subsequent TS packet
-        // can contain at most.
-        sizeAvailableForPayload = 188 - 4;
-        size_t sizeAvailableForAlignedPayload = sizeAvailableForPayload;
-        if (alignPayload) {
-            // We're only going to use a subset of the available space
-            // since we need to make each fragment a multiple of 16 in size.
-            sizeAvailableForAlignedPayload -=
-                (sizeAvailableForAlignedPayload % 16);
-        }
-
-        size_t numFullTSPackets =
-            numBytesOfPayloadRemaining / sizeAvailableForAlignedPayload;
-
-        numTSPackets += numFullTSPackets;
-
-        numBytesOfPayloadRemaining -=
-            numFullTSPackets * sizeAvailableForAlignedPayload;
-
-        // numBytesOfPayloadRemaining < sizeAvailableForAlignedPayload
-        if (numFullTSPackets == 0 && numBytesOfPayloadRemaining > 0) {
-            // There wasn't enough payload left to form a full aligned payload,
-            // the last packet doesn't have to be aligned.
-            ++numTSPackets;
-        } else if (numFullTSPackets > 0
-                && numBytesOfPayloadRemaining
-                    + sizeAvailableForAlignedPayload > sizeAvailableForPayload) {
-            // The last packet emitted had a full aligned payload and together
-            // with the bytes remaining does exceed the unaligned payload
-            // size, so we need another packet.
-            ++numTSPackets;
-        }
-#endif
-    }
-
-    if (flags & EMIT_PAT_AND_PMT) {
-        numTSPackets += 2;
-    }
-
-    if (flags & EMIT_PCR) {
-        ++numTSPackets;
-    }
-
-    sp<ABuffer> buffer = new ABuffer(numTSPackets * 188);
-    uint8_t *packetDataStart = buffer->data();
-
-    if (flags & EMIT_PAT_AND_PMT) {
-        // Program Association Table (PAT):
-        // 0x47
-        // transport_error_indicator = b0
-        // payload_unit_start_indicator = b1
-        // transport_priority = b0
-        // PID = b0000000000000 (13 bits)
-        // transport_scrambling_control = b00
-        // adaptation_field_control = b01 (no adaptation field, payload only)
-        // continuity_counter = b????
-        // skip = 0x00
-        // --- payload follows
-        // table_id = 0x00
-        // section_syntax_indicator = b1
-        // must_be_zero = b0
-        // reserved = b11
-        // section_length = 0x00d
-        // transport_stream_id = 0x0000
-        // reserved = b11
-        // version_number = b00001
-        // current_next_indicator = b1
-        // section_number = 0x00
-        // last_section_number = 0x00
-        //   one program follows:
-        //   program_number = 0x0001
-        //   reserved = b111
-        //   program_map_PID = kPID_PMT (13 bits!)
-        // CRC = 0x????????
-
-        if (++mPATContinuityCounter == 16) {
-            mPATContinuityCounter = 0;
-        }
-
-        uint8_t *ptr = packetDataStart;
-        *ptr++ = 0x47;
-        *ptr++ = 0x40;
-        *ptr++ = 0x00;
-        *ptr++ = 0x10 | mPATContinuityCounter;
-        *ptr++ = 0x00;
-
-        uint8_t *crcDataStart = ptr;
-        *ptr++ = 0x00;
-        *ptr++ = 0xb0;
-        *ptr++ = 0x0d;
-        *ptr++ = 0x00;
-        *ptr++ = 0x00;
-        *ptr++ = 0xc3;
-        *ptr++ = 0x00;
-        *ptr++ = 0x00;
-        *ptr++ = 0x00;
-        *ptr++ = 0x01;
-        *ptr++ = 0xe0 | (kPID_PMT >> 8);
-        *ptr++ = kPID_PMT & 0xff;
-
-        CHECK_EQ(ptr - crcDataStart, 12);
-        uint32_t crc = htonl(crc32(crcDataStart, ptr - crcDataStart));
-        memcpy(ptr, &crc, 4);
-        ptr += 4;
-
-        size_t sizeLeft = packetDataStart + 188 - ptr;
-        memset(ptr, 0xff, sizeLeft);
-
-        packetDataStart += 188;
-
-        // Program Map (PMT):
-        // 0x47
-        // transport_error_indicator = b0
-        // payload_unit_start_indicator = b1
-        // transport_priority = b0
-        // PID = kPID_PMT (13 bits)
-        // transport_scrambling_control = b00
-        // adaptation_field_control = b01 (no adaptation field, payload only)
-        // continuity_counter = b????
-        // skip = 0x00
-        // -- payload follows
-        // table_id = 0x02
-        // section_syntax_indicator = b1
-        // must_be_zero = b0
-        // reserved = b11
-        // section_length = 0x???
-        // program_number = 0x0001
-        // reserved = b11
-        // version_number = b00001
-        // current_next_indicator = b1
-        // section_number = 0x00
-        // last_section_number = 0x00
-        // reserved = b111
-        // PCR_PID = kPCR_PID (13 bits)
-        // reserved = b1111
-        // program_info_length = 0x???
-        //   program_info_descriptors follow
-        // one or more elementary stream descriptions follow:
-        //   stream_type = 0x??
-        //   reserved = b111
-        //   elementary_PID = b? ???? ???? ???? (13 bits)
-        //   reserved = b1111
-        //   ES_info_length = 0x000
-        // CRC = 0x????????
-
-        if (++mPMTContinuityCounter == 16) {
-            mPMTContinuityCounter = 0;
-        }
-
-        ptr = packetDataStart;
-        *ptr++ = 0x47;
-        *ptr++ = 0x40 | (kPID_PMT >> 8);
-        *ptr++ = kPID_PMT & 0xff;
-        *ptr++ = 0x10 | mPMTContinuityCounter;
-        *ptr++ = 0x00;
-
-        crcDataStart = ptr;
-        *ptr++ = 0x02;
-
-        *ptr++ = 0x00;  // section_length to be filled in below.
-        *ptr++ = 0x00;
-
-        *ptr++ = 0x00;
-        *ptr++ = 0x01;
-        *ptr++ = 0xc3;
-        *ptr++ = 0x00;
-        *ptr++ = 0x00;
-        *ptr++ = 0xe0 | (kPID_PCR >> 8);
-        *ptr++ = kPID_PCR & 0xff;
-
-        size_t program_info_length = 0;
-        for (size_t i = 0; i < mProgramInfoDescriptors.size(); ++i) {
-            program_info_length += mProgramInfoDescriptors.itemAt(i)->size();
-        }
-
-        CHECK_LT(program_info_length, 0x400u);
-        *ptr++ = 0xf0 | (program_info_length >> 8);
-        *ptr++ = (program_info_length & 0xff);
-
-        for (size_t i = 0; i < mProgramInfoDescriptors.size(); ++i) {
-            const sp<ABuffer> &desc = mProgramInfoDescriptors.itemAt(i);
-            memcpy(ptr, desc->data(), desc->size());
-            ptr += desc->size();
-        }
-
-        for (size_t i = 0; i < mTracks.size(); ++i) {
-            const sp<Track> &track = mTracks.itemAt(i);
-
-            // Make sure all the decriptors have been added.
-            track->finalize();
-
-            *ptr++ = track->streamType();
-            *ptr++ = 0xe0 | (track->PID() >> 8);
-            *ptr++ = track->PID() & 0xff;
-
-            size_t ES_info_length = 0;
-            for (size_t i = 0; i < track->countDescriptors(); ++i) {
-                ES_info_length += track->descriptorAt(i)->size();
-            }
-            CHECK_LE(ES_info_length, 0xfffu);
-
-            *ptr++ = 0xf0 | (ES_info_length >> 8);
-            *ptr++ = (ES_info_length & 0xff);
-
-            for (size_t i = 0; i < track->countDescriptors(); ++i) {
-                const sp<ABuffer> &descriptor = track->descriptorAt(i);
-                memcpy(ptr, descriptor->data(), descriptor->size());
-                ptr += descriptor->size();
-            }
-        }
-
-        size_t section_length = ptr - (crcDataStart + 3) + 4 /* CRC */;
-
-        crcDataStart[1] = 0xb0 | (section_length >> 8);
-        crcDataStart[2] = section_length & 0xff;
-
-        crc = htonl(crc32(crcDataStart, ptr - crcDataStart));
-        memcpy(ptr, &crc, 4);
-        ptr += 4;
-
-        sizeLeft = packetDataStart + 188 - ptr;
-        memset(ptr, 0xff, sizeLeft);
-
-        packetDataStart += 188;
-    }
-
-    if (flags & EMIT_PCR) {
-        // PCR stream
-        // 0x47
-        // transport_error_indicator = b0
-        // payload_unit_start_indicator = b1
-        // transport_priority = b0
-        // PID = kPCR_PID (13 bits)
-        // transport_scrambling_control = b00
-        // adaptation_field_control = b10 (adaptation field only, no payload)
-        // continuity_counter = b0000 (does not increment)
-        // adaptation_field_length = 183
-        // discontinuity_indicator = b0
-        // random_access_indicator = b0
-        // elementary_stream_priority_indicator = b0
-        // PCR_flag = b1
-        // OPCR_flag = b0
-        // splicing_point_flag = b0
-        // transport_private_data_flag = b0
-        // adaptation_field_extension_flag = b0
-        // program_clock_reference_base = b?????????????????????????????????
-        // reserved = b111111
-        // program_clock_reference_extension = b?????????
-
-        int64_t nowUs = ALooper::GetNowUs();
-
-        uint64_t PCR = nowUs * 27;  // PCR based on a 27MHz clock
-        uint64_t PCR_base = PCR / 300;
-        uint32_t PCR_ext = PCR % 300;
-
-        uint8_t *ptr = packetDataStart;
-        *ptr++ = 0x47;
-        *ptr++ = 0x40 | (kPID_PCR >> 8);
-        *ptr++ = kPID_PCR & 0xff;
-        *ptr++ = 0x20;
-        *ptr++ = 0xb7;  // adaptation_field_length
-        *ptr++ = 0x10;
-        *ptr++ = (PCR_base >> 25) & 0xff;
-        *ptr++ = (PCR_base >> 17) & 0xff;
-        *ptr++ = (PCR_base >> 9) & 0xff;
-        *ptr++ = ((PCR_base & 1) << 7) | 0x7e | ((PCR_ext >> 8) & 1);
-        *ptr++ = (PCR_ext & 0xff);
-
-        size_t sizeLeft = packetDataStart + 188 - ptr;
-        memset(ptr, 0xff, sizeLeft);
-
-        packetDataStart += 188;
-    }
-
-    uint64_t PTS = (timeUs * 9ll) / 100ll;
-
-    if (PES_packet_length >= 65536) {
-        // This really should only happen for video.
-        CHECK(track->isVideo());
-
-        // It's valid to set this to 0 for video according to the specs.
-        PES_packet_length = 0;
-    }
-
-    size_t sizeAvailableForPayload = 188 - 4 - 14 - numStuffingBytes;
-    if (PES_private_data_len > 0) {
-        sizeAvailableForPayload -= PES_private_data_len + 1;
-    }
-
-    size_t copy = accessUnit->size();
-
-    if (copy > sizeAvailableForPayload) {
-        copy = sizeAvailableForPayload;
-
-        if (alignPayload && copy > 16) {
-            copy -= (copy % 16);
-        }
-    }
-
-    size_t numPaddingBytes = sizeAvailableForPayload - copy;
-
-    uint8_t *ptr = packetDataStart;
-    *ptr++ = 0x47;
-    *ptr++ = 0x40 | (track->PID() >> 8);
-    *ptr++ = track->PID() & 0xff;
-
-    *ptr++ = (numPaddingBytes > 0 ? 0x30 : 0x10)
-                | track->incrementContinuityCounter();
-
-    if (numPaddingBytes > 0) {
-        *ptr++ = numPaddingBytes - 1;
-        if (numPaddingBytes >= 2) {
-            *ptr++ = 0x00;
-            memset(ptr, 0xff, numPaddingBytes - 2);
-            ptr += numPaddingBytes - 2;
-        }
-    }
-
-    *ptr++ = 0x00;
-    *ptr++ = 0x00;
-    *ptr++ = 0x01;
-    *ptr++ = track->streamID();
-    *ptr++ = PES_packet_length >> 8;
-    *ptr++ = PES_packet_length & 0xff;
-    *ptr++ = 0x84;
-    *ptr++ = (PES_private_data_len > 0) ? 0x81 : 0x80;
-
-    size_t headerLength = 0x05 + numStuffingBytes;
-    if (PES_private_data_len > 0) {
-        headerLength += 1 + PES_private_data_len;
-    }
-
-    *ptr++ = headerLength;
-
-    *ptr++ = 0x20 | (((PTS >> 30) & 7) << 1) | 1;
-    *ptr++ = (PTS >> 22) & 0xff;
-    *ptr++ = (((PTS >> 15) & 0x7f) << 1) | 1;
-    *ptr++ = (PTS >> 7) & 0xff;
-    *ptr++ = ((PTS & 0x7f) << 1) | 1;
-
-    if (PES_private_data_len > 0) {
-        *ptr++ = 0x8e;  // PES_private_data_flag, reserved.
-        memcpy(ptr, PES_private_data, PES_private_data_len);
-        ptr += PES_private_data_len;
-    }
-
-    for (size_t i = 0; i < numStuffingBytes; ++i) {
-        *ptr++ = 0xff;
-    }
-
-    memcpy(ptr, accessUnit->data(), copy);
-    ptr += copy;
-
-    CHECK_EQ(ptr, packetDataStart + 188);
-    packetDataStart += 188;
-
-    size_t offset = copy;
-    while (offset < accessUnit->size()) {
-        // for subsequent fragments of "buffer":
-        // 0x47
-        // transport_error_indicator = b0
-        // payload_unit_start_indicator = b0
-        // transport_priority = b0
-        // PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex]
-        // transport_scrambling_control = b00
-        // adaptation_field_control = b??
-        // continuity_counter = b????
-        // the fragment of "buffer" follows.
-
-        size_t sizeAvailableForPayload = 188 - 4;
-
-        size_t copy = accessUnit->size() - offset;
-
-        if (copy > sizeAvailableForPayload) {
-            copy = sizeAvailableForPayload;
-
-            if (alignPayload && copy > 16) {
-                copy -= (copy % 16);
-            }
-        }
-
-        size_t numPaddingBytes = sizeAvailableForPayload - copy;
-
-        uint8_t *ptr = packetDataStart;
-        *ptr++ = 0x47;
-        *ptr++ = 0x00 | (track->PID() >> 8);
-        *ptr++ = track->PID() & 0xff;
-
-        *ptr++ = (numPaddingBytes > 0 ? 0x30 : 0x10)
-                    | track->incrementContinuityCounter();
-
-        if (numPaddingBytes > 0) {
-            *ptr++ = numPaddingBytes - 1;
-            if (numPaddingBytes >= 2) {
-                *ptr++ = 0x00;
-                memset(ptr, 0xff, numPaddingBytes - 2);
-                ptr += numPaddingBytes - 2;
-            }
-        }
-
-        memcpy(ptr, accessUnit->data() + offset, copy);
-        ptr += copy;
-        CHECK_EQ(ptr, packetDataStart + 188);
-
-        offset += copy;
-        packetDataStart += 188;
-    }
-
-    CHECK(packetDataStart == buffer->data() + buffer->capacity());
-
-    *packets = buffer;
-
-    return OK;
-}
-
-void TSPacketizer::initCrcTable() {
-    uint32_t poly = 0x04C11DB7;
-
-    for (int i = 0; i < 256; i++) {
-        uint32_t crc = i << 24;
-        for (int j = 0; j < 8; j++) {
-            crc = (crc << 1) ^ ((crc & 0x80000000) ? (poly) : 0);
-        }
-        mCrcTable[i] = crc;
-    }
-}
-
-uint32_t TSPacketizer::crc32(const uint8_t *start, size_t size) const {
-    uint32_t crc = 0xFFFFFFFF;
-    const uint8_t *p;
-
-    for (p = start; p < start + size; ++p) {
-        crc = (crc << 8) ^ mCrcTable[((crc >> 24) ^ *p) & 0xFF];
-    }
-
-    return crc;
-}
-
-sp<ABuffer> TSPacketizer::prependCSD(
-        size_t trackIndex, const sp<ABuffer> &accessUnit) const {
-    CHECK_LT(trackIndex, mTracks.size());
-
-    const sp<Track> &track = mTracks.itemAt(trackIndex);
-    CHECK(track->isH264() && IsIDR(accessUnit));
-
-    int64_t timeUs;
-    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
-    sp<ABuffer> accessUnit2 = track->prependCSD(accessUnit);
-
-    accessUnit2->meta()->setInt64("timeUs", timeUs);
-
-    return accessUnit2;
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.h b/media/libstagefright/wifi-display/source/TSPacketizer.h
deleted file mode 100644
index 0dcb179..0000000
--- a/media/libstagefright/wifi-display/source/TSPacketizer.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 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 TS_PACKETIZER_H_
-
-#define TS_PACKETIZER_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-struct ABuffer;
-struct AMessage;
-
-// Forms the packets of a transport stream given access units.
-// Emits metadata tables (PAT and PMT) and timestamp stream (PCR) based
-// on flags.
-struct TSPacketizer : public RefBase {
-    enum {
-        EMIT_HDCP20_DESCRIPTOR = 1,
-        EMIT_HDCP21_DESCRIPTOR = 2,
-    };
-    explicit TSPacketizer(uint32_t flags);
-
-    // Returns trackIndex or error.
-    ssize_t addTrack(const sp<AMessage> &format);
-
-    enum {
-        EMIT_PAT_AND_PMT                = 1,
-        EMIT_PCR                        = 2,
-        IS_ENCRYPTED                    = 4,
-        PREPEND_SPS_PPS_TO_IDR_FRAMES   = 8,
-    };
-    status_t packetize(
-            size_t trackIndex, const sp<ABuffer> &accessUnit,
-            sp<ABuffer> *packets,
-            uint32_t flags,
-            const uint8_t *PES_private_data, size_t PES_private_data_len,
-            size_t numStuffingBytes = 0);
-
-    status_t extractCSDIfNecessary(size_t trackIndex);
-
-    // XXX to be removed once encoder config option takes care of this for
-    // encrypted mode.
-    sp<ABuffer> prependCSD(
-            size_t trackIndex, const sp<ABuffer> &accessUnit) const;
-
-protected:
-    virtual ~TSPacketizer();
-
-private:
-    enum {
-        kPID_PMT = 0x100,
-        kPID_PCR = 0x1000,
-    };
-
-    struct Track;
-
-    uint32_t mFlags;
-    Vector<sp<Track> > mTracks;
-
-    Vector<sp<ABuffer> > mProgramInfoDescriptors;
-
-    unsigned mPATContinuityCounter;
-    unsigned mPMTContinuityCounter;
-
-    uint32_t mCrcTable[256];
-
-    void initCrcTable();
-    uint32_t crc32(const uint8_t *start, size_t size) const;
-
-    DISALLOW_EVIL_CONSTRUCTORS(TSPacketizer);
-};
-
-}  // namespace android
-
-#endif  // TS_PACKETIZER_H_
-
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
deleted file mode 100644
index 4695e5d..0000000
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ /dev/null
@@ -1,1737 +0,0 @@
-/*
- * Copyright 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 "WifiDisplaySource"
-#include <utils/Log.h>
-
-#include "WifiDisplaySource.h"
-#include "PlaybackSession.h"
-#include "Parameters.h"
-#include "rtp/RTPSender.h"
-
-#include <binder/IServiceManager.h>
-#include <gui/IGraphicBufferProducer.h>
-#include <media/IHDCP.h>
-#include <media/IMediaPlayerService.h>
-#include <media/IRemoteDisplayClient.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/ParsedMessage.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-
-#include <arpa/inet.h>
-#include <cutils/properties.h>
-
-#include <ctype.h>
-
-namespace android {
-
-// static
-const int64_t WifiDisplaySource::kReaperIntervalUs;
-const int64_t WifiDisplaySource::kTeardownTriggerTimeouSecs;
-const int64_t WifiDisplaySource::kPlaybackSessionTimeoutSecs;
-const int64_t WifiDisplaySource::kPlaybackSessionTimeoutUs;
-const AString WifiDisplaySource::sUserAgent = MakeUserAgent();
-
-WifiDisplaySource::WifiDisplaySource(
-        const String16 &opPackageName,
-        const sp<ANetworkSession> &netSession,
-        const sp<IRemoteDisplayClient> &client,
-        const char *path)
-    : mOpPackageName(opPackageName),
-      mState(INITIALIZED),
-      mNetSession(netSession),
-      mClient(client),
-      mSessionID(0),
-      mStopReplyID(NULL),
-      mChosenRTPPort(-1),
-      mUsingPCMAudio(false),
-      mClientSessionID(0),
-      mReaperPending(false),
-      mNextCSeq(1),
-      mUsingHDCP(false),
-      mIsHDCP2_0(false),
-      mHDCPPort(0),
-      mHDCPInitializationComplete(false),
-      mSetupTriggerDeferred(false),
-      mPlaybackSessionEstablished(false) {
-    if (path != NULL) {
-        mMediaPath.setTo(path);
-    }
-
-    mSupportedSourceVideoFormats.disableAll();
-
-    mSupportedSourceVideoFormats.setNativeResolution(
-            VideoFormats::RESOLUTION_CEA, 5);  // 1280x720 p30
-
-    // Enable all resolutions up to 1280x720p30
-    mSupportedSourceVideoFormats.enableResolutionUpto(
-            VideoFormats::RESOLUTION_CEA, 5,
-            VideoFormats::PROFILE_CHP,  // Constrained High Profile
-            VideoFormats::LEVEL_32);    // Level 3.2
-}
-
-WifiDisplaySource::~WifiDisplaySource() {
-}
-
-static status_t PostAndAwaitResponse(
-        const sp<AMessage> &msg, sp<AMessage> *response) {
-    status_t err = msg->postAndAwaitResponse(response);
-
-    if (err != OK) {
-        return err;
-    }
-
-    if (response == NULL || !(*response)->findInt32("err", &err)) {
-        err = OK;
-    }
-
-    return err;
-}
-
-status_t WifiDisplaySource::start(const char *iface) {
-    CHECK_EQ(mState, INITIALIZED);
-
-    sp<AMessage> msg = new AMessage(kWhatStart, this);
-    msg->setString("iface", iface);
-
-    sp<AMessage> response;
-    return PostAndAwaitResponse(msg, &response);
-}
-
-status_t WifiDisplaySource::stop() {
-    sp<AMessage> msg = new AMessage(kWhatStop, this);
-
-    sp<AMessage> response;
-    return PostAndAwaitResponse(msg, &response);
-}
-
-status_t WifiDisplaySource::pause() {
-    sp<AMessage> msg = new AMessage(kWhatPause, this);
-
-    sp<AMessage> response;
-    return PostAndAwaitResponse(msg, &response);
-}
-
-status_t WifiDisplaySource::resume() {
-    sp<AMessage> msg = new AMessage(kWhatResume, this);
-
-    sp<AMessage> response;
-    return PostAndAwaitResponse(msg, &response);
-}
-
-void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        case kWhatStart:
-        {
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
-            AString iface;
-            CHECK(msg->findString("iface", &iface));
-
-            status_t err = OK;
-
-            ssize_t colonPos = iface.find(":");
-
-            unsigned long port;
-
-            if (colonPos >= 0) {
-                const char *s = iface.c_str() + colonPos + 1;
-
-                char *end;
-                port = strtoul(s, &end, 10);
-
-                if (end == s || *end != '\0' || port > 65535) {
-                    err = -EINVAL;
-                } else {
-                    iface.erase(colonPos, iface.size() - colonPos);
-                }
-            } else {
-                port = kWifiDisplayDefaultPort;
-            }
-
-            if (err == OK) {
-                if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) {
-                    sp<AMessage> notify = new AMessage(kWhatRTSPNotify, this);
-
-                    err = mNetSession->createRTSPServer(
-                            mInterfaceAddr, port, notify, &mSessionID);
-                } else {
-                    err = -EINVAL;
-                }
-            }
-
-            mState = AWAITING_CLIENT_CONNECTION;
-
-            sp<AMessage> response = new AMessage;
-            response->setInt32("err", err);
-            response->postReply(replyID);
-            break;
-        }
-
-        case kWhatRTSPNotify:
-        {
-            int32_t reason;
-            CHECK(msg->findInt32("reason", &reason));
-
-            switch (reason) {
-                case ANetworkSession::kWhatError:
-                {
-                    int32_t sessionID;
-                    CHECK(msg->findInt32("sessionID", &sessionID));
-
-                    int32_t err;
-                    CHECK(msg->findInt32("err", &err));
-
-                    AString detail;
-                    CHECK(msg->findString("detail", &detail));
-
-                    ALOGE("An error occurred in session %d (%d, '%s/%s').",
-                          sessionID,
-                          err,
-                          detail.c_str(),
-                          strerror(-err));
-
-                    mNetSession->destroySession(sessionID);
-
-                    if (sessionID == mClientSessionID) {
-                        mClientSessionID = 0;
-
-                        mClient->onDisplayError(
-                                IRemoteDisplayClient::kDisplayErrorUnknown);
-                    }
-                    break;
-                }
-
-                case ANetworkSession::kWhatClientConnected:
-                {
-                    int32_t sessionID;
-                    CHECK(msg->findInt32("sessionID", &sessionID));
-
-                    if (mClientSessionID > 0) {
-                        ALOGW("A client tried to connect, but we already "
-                              "have one.");
-
-                        mNetSession->destroySession(sessionID);
-                        break;
-                    }
-
-                    CHECK_EQ(mState, AWAITING_CLIENT_CONNECTION);
-
-                    CHECK(msg->findString("client-ip", &mClientInfo.mRemoteIP));
-                    CHECK(msg->findString("server-ip", &mClientInfo.mLocalIP));
-
-                    if (mClientInfo.mRemoteIP == mClientInfo.mLocalIP) {
-                        // Disallow connections from the local interface
-                        // for security reasons.
-                        mNetSession->destroySession(sessionID);
-                        break;
-                    }
-
-                    CHECK(msg->findInt32(
-                                "server-port", &mClientInfo.mLocalPort));
-                    mClientInfo.mPlaybackSessionID = -1;
-
-                    mClientSessionID = sessionID;
-
-                    ALOGI("We now have a client (%d) connected.", sessionID);
-
-                    mState = AWAITING_CLIENT_SETUP;
-
-                    status_t err = sendM1(sessionID);
-                    CHECK_EQ(err, (status_t)OK);
-                    break;
-                }
-
-                case ANetworkSession::kWhatData:
-                {
-                    status_t err = onReceiveClientData(msg);
-
-                    if (err != OK) {
-                        mClient->onDisplayError(
-                                IRemoteDisplayClient::kDisplayErrorUnknown);
-                    }
-
-#if 0
-                    // testing only.
-                    char val[PROPERTY_VALUE_MAX];
-                    if (property_get("media.wfd.trigger", val, NULL)) {
-                        if (!strcasecmp(val, "pause") && mState == PLAYING) {
-                            mState = PLAYING_TO_PAUSED;
-                            sendTrigger(mClientSessionID, TRIGGER_PAUSE);
-                        } else if (!strcasecmp(val, "play")
-                                    && mState == PAUSED) {
-                            mState = PAUSED_TO_PLAYING;
-                            sendTrigger(mClientSessionID, TRIGGER_PLAY);
-                        }
-                    }
-#endif
-                    break;
-                }
-
-                case ANetworkSession::kWhatNetworkStall:
-                {
-                    break;
-                }
-
-                default:
-                    TRESPASS();
-            }
-            break;
-        }
-
-        case kWhatStop:
-        {
-            CHECK(msg->senderAwaitsResponse(&mStopReplyID));
-
-            CHECK_LT(mState, AWAITING_CLIENT_TEARDOWN);
-
-            if (mState >= AWAITING_CLIENT_PLAY) {
-                // We have a session, i.e. a previous SETUP succeeded.
-
-                status_t err = sendTrigger(
-                        mClientSessionID, TRIGGER_TEARDOWN);
-
-                if (err == OK) {
-                    mState = AWAITING_CLIENT_TEARDOWN;
-
-                    (new AMessage(kWhatTeardownTriggerTimedOut, this))->post(
-                            kTeardownTriggerTimeouSecs * 1000000ll);
-
-                    break;
-                }
-
-                // fall through.
-            }
-
-            finishStop();
-            break;
-        }
-
-        case kWhatPause:
-        {
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
-            status_t err = OK;
-
-            if (mState != PLAYING) {
-                err = INVALID_OPERATION;
-            } else {
-                mState = PLAYING_TO_PAUSED;
-                sendTrigger(mClientSessionID, TRIGGER_PAUSE);
-            }
-
-            sp<AMessage> response = new AMessage;
-            response->setInt32("err", err);
-            response->postReply(replyID);
-            break;
-        }
-
-        case kWhatResume:
-        {
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
-            status_t err = OK;
-
-            if (mState != PAUSED) {
-                err = INVALID_OPERATION;
-            } else {
-                mState = PAUSED_TO_PLAYING;
-                sendTrigger(mClientSessionID, TRIGGER_PLAY);
-            }
-
-            sp<AMessage> response = new AMessage;
-            response->setInt32("err", err);
-            response->postReply(replyID);
-            break;
-        }
-
-        case kWhatReapDeadClients:
-        {
-            mReaperPending = false;
-
-            if (mClientSessionID == 0
-                    || mClientInfo.mPlaybackSession == NULL) {
-                break;
-            }
-
-            if (mClientInfo.mPlaybackSession->getLastLifesignUs()
-                    + kPlaybackSessionTimeoutUs < ALooper::GetNowUs()) {
-                ALOGI("playback session timed out, reaping.");
-
-                mNetSession->destroySession(mClientSessionID);
-                mClientSessionID = 0;
-
-                mClient->onDisplayError(
-                        IRemoteDisplayClient::kDisplayErrorUnknown);
-            } else {
-                scheduleReaper();
-            }
-            break;
-        }
-
-        case kWhatPlaybackSessionNotify:
-        {
-            int32_t playbackSessionID;
-            CHECK(msg->findInt32("playbackSessionID", &playbackSessionID));
-
-            int32_t what;
-            CHECK(msg->findInt32("what", &what));
-
-            if (what == PlaybackSession::kWhatSessionDead) {
-                ALOGI("playback session wants to quit.");
-
-                mClient->onDisplayError(
-                        IRemoteDisplayClient::kDisplayErrorUnknown);
-            } else if (what == PlaybackSession::kWhatSessionEstablished) {
-                mPlaybackSessionEstablished = true;
-
-                if (mClient != NULL) {
-                    if (!mSinkSupportsVideo) {
-                        mClient->onDisplayConnected(
-                                NULL,  // SurfaceTexture
-                                0, // width,
-                                0, // height,
-                                mUsingHDCP
-                                    ? IRemoteDisplayClient::kDisplayFlagSecure
-                                    : 0,
-                                0);
-                    } else {
-                        size_t width, height;
-
-                        CHECK(VideoFormats::GetConfiguration(
-                                    mChosenVideoResolutionType,
-                                    mChosenVideoResolutionIndex,
-                                    &width,
-                                    &height,
-                                    NULL /* framesPerSecond */,
-                                    NULL /* interlaced */));
-
-                        mClient->onDisplayConnected(
-                                mClientInfo.mPlaybackSession
-                                    ->getSurfaceTexture(),
-                                width,
-                                height,
-                                mUsingHDCP
-                                    ? IRemoteDisplayClient::kDisplayFlagSecure
-                                    : 0,
-                                playbackSessionID);
-                    }
-                }
-
-                finishPlay();
-
-                if (mState == ABOUT_TO_PLAY) {
-                    mState = PLAYING;
-                }
-            } else if (what == PlaybackSession::kWhatSessionDestroyed) {
-                disconnectClient2();
-            } else {
-                CHECK_EQ(what, PlaybackSession::kWhatBinaryData);
-
-                int32_t channel;
-                CHECK(msg->findInt32("channel", &channel));
-
-                sp<ABuffer> data;
-                CHECK(msg->findBuffer("data", &data));
-
-                CHECK_LE(channel, 0xff);
-                CHECK_LE(data->size(), 0xffffu);
-
-                int32_t sessionID;
-                CHECK(msg->findInt32("sessionID", &sessionID));
-
-                char header[4];
-                header[0] = '$';
-                header[1] = channel;
-                header[2] = data->size() >> 8;
-                header[3] = data->size() & 0xff;
-
-                mNetSession->sendRequest(
-                        sessionID, header, sizeof(header));
-
-                mNetSession->sendRequest(
-                        sessionID, data->data(), data->size());
-            }
-            break;
-        }
-
-        case kWhatKeepAlive:
-        {
-            int32_t sessionID;
-            CHECK(msg->findInt32("sessionID", &sessionID));
-
-            if (mClientSessionID != sessionID) {
-                // Obsolete event, client is already gone.
-                break;
-            }
-
-            sendM16(sessionID);
-            break;
-        }
-
-        case kWhatTeardownTriggerTimedOut:
-        {
-            if (mState == AWAITING_CLIENT_TEARDOWN) {
-                ALOGI("TEARDOWN trigger timed out, forcing disconnection.");
-
-                CHECK(mStopReplyID != NULL);
-                finishStop();
-                break;
-            }
-            break;
-        }
-
-        case kWhatHDCPNotify:
-        {
-            int32_t msgCode, ext1, ext2;
-            CHECK(msg->findInt32("msg", &msgCode));
-            CHECK(msg->findInt32("ext1", &ext1));
-            CHECK(msg->findInt32("ext2", &ext2));
-
-            ALOGI("Saw HDCP notification code %d, ext1 %d, ext2 %d",
-                    msgCode, ext1, ext2);
-
-            switch (msgCode) {
-                case HDCPModule::HDCP_INITIALIZATION_COMPLETE:
-                {
-                    mHDCPInitializationComplete = true;
-
-                    if (mSetupTriggerDeferred) {
-                        mSetupTriggerDeferred = false;
-
-                        sendTrigger(mClientSessionID, TRIGGER_SETUP);
-                    }
-                    break;
-                }
-
-                case HDCPModule::HDCP_SHUTDOWN_COMPLETE:
-                case HDCPModule::HDCP_SHUTDOWN_FAILED:
-                {
-                    // Ugly hack to make sure that the call to
-                    // HDCPObserver::notify is completely handled before
-                    // we clear the HDCP instance and unload the shared
-                    // library :(
-                    (new AMessage(kWhatFinishStop2, this))->post(300000ll);
-                    break;
-                }
-
-                default:
-                {
-                    ALOGE("HDCP failure, shutting down.");
-
-                    mClient->onDisplayError(
-                            IRemoteDisplayClient::kDisplayErrorUnknown);
-                    break;
-                }
-            }
-            break;
-        }
-
-        case kWhatFinishStop2:
-        {
-            finishStop2();
-            break;
-        }
-
-        default:
-            TRESPASS();
-    }
-}
-
-void WifiDisplaySource::registerResponseHandler(
-        int32_t sessionID, int32_t cseq, HandleRTSPResponseFunc func) {
-    ResponseID id;
-    id.mSessionID = sessionID;
-    id.mCSeq = cseq;
-    mResponseHandlers.add(id, func);
-}
-
-status_t WifiDisplaySource::sendM1(int32_t sessionID) {
-    AString request = "OPTIONS * RTSP/1.0\r\n";
-    AppendCommonResponse(&request, mNextCSeq);
-
-    request.append(
-            "Require: org.wfa.wfd1.0\r\n"
-            "\r\n");
-
-    status_t err =
-        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
-
-    if (err != OK) {
-        return err;
-    }
-
-    registerResponseHandler(
-            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM1Response);
-
-    ++mNextCSeq;
-
-    return OK;
-}
-
-status_t WifiDisplaySource::sendM3(int32_t sessionID) {
-    AString body =
-        "wfd_content_protection\r\n"
-        "wfd_video_formats\r\n"
-        "wfd_audio_codecs\r\n"
-        "wfd_client_rtp_ports\r\n";
-
-    AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
-    AppendCommonResponse(&request, mNextCSeq);
-
-    request.append("Content-Type: text/parameters\r\n");
-    request.append(AStringPrintf("Content-Length: %d\r\n", body.size()));
-    request.append("\r\n");
-    request.append(body);
-
-    status_t err =
-        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
-
-    if (err != OK) {
-        return err;
-    }
-
-    registerResponseHandler(
-            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM3Response);
-
-    ++mNextCSeq;
-
-    return OK;
-}
-
-status_t WifiDisplaySource::sendM4(int32_t sessionID) {
-    CHECK_EQ(sessionID, mClientSessionID);
-
-    AString body;
-
-    if (mSinkSupportsVideo) {
-        body.append("wfd_video_formats: ");
-
-        VideoFormats chosenVideoFormat;
-        chosenVideoFormat.disableAll();
-        chosenVideoFormat.setNativeResolution(
-                mChosenVideoResolutionType, mChosenVideoResolutionIndex);
-        chosenVideoFormat.setProfileLevel(
-                mChosenVideoResolutionType, mChosenVideoResolutionIndex,
-                mChosenVideoProfile, mChosenVideoLevel);
-
-        body.append(chosenVideoFormat.getFormatSpec(true /* forM4Message */));
-        body.append("\r\n");
-    }
-
-    if (mSinkSupportsAudio) {
-        body.append(
-                AStringPrintf("wfd_audio_codecs: %s\r\n",
-                             (mUsingPCMAudio
-                                ? "LPCM 00000002 00" // 2 ch PCM 48kHz
-                                : "AAC 00000001 00")));  // 2 ch AAC 48kHz
-    }
-
-    body.append(
-            AStringPrintf(
-                "wfd_presentation_URL: rtsp://%s/wfd1.0/streamid=0 none\r\n",
-                mClientInfo.mLocalIP.c_str()));
-
-    body.append(
-            AStringPrintf(
-                "wfd_client_rtp_ports: %s\r\n", mWfdClientRtpPorts.c_str()));
-
-    AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
-    AppendCommonResponse(&request, mNextCSeq);
-
-    request.append("Content-Type: text/parameters\r\n");
-    request.append(AStringPrintf("Content-Length: %d\r\n", body.size()));
-    request.append("\r\n");
-    request.append(body);
-
-    status_t err =
-        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
-
-    if (err != OK) {
-        return err;
-    }
-
-    registerResponseHandler(
-            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM4Response);
-
-    ++mNextCSeq;
-
-    return OK;
-}
-
-status_t WifiDisplaySource::sendTrigger(
-        int32_t sessionID, TriggerType triggerType) {
-    AString body = "wfd_trigger_method: ";
-    switch (triggerType) {
-        case TRIGGER_SETUP:
-            body.append("SETUP");
-            break;
-        case TRIGGER_TEARDOWN:
-            ALOGI("Sending TEARDOWN trigger.");
-            body.append("TEARDOWN");
-            break;
-        case TRIGGER_PAUSE:
-            body.append("PAUSE");
-            break;
-        case TRIGGER_PLAY:
-            body.append("PLAY");
-            break;
-        default:
-            TRESPASS();
-    }
-
-    body.append("\r\n");
-
-    AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
-    AppendCommonResponse(&request, mNextCSeq);
-
-    request.append("Content-Type: text/parameters\r\n");
-    request.append(AStringPrintf("Content-Length: %d\r\n", body.size()));
-    request.append("\r\n");
-    request.append(body);
-
-    status_t err =
-        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
-
-    if (err != OK) {
-        return err;
-    }
-
-    registerResponseHandler(
-            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM5Response);
-
-    ++mNextCSeq;
-
-    return OK;
-}
-
-status_t WifiDisplaySource::sendM16(int32_t sessionID) {
-    AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
-    AppendCommonResponse(&request, mNextCSeq);
-
-    CHECK_EQ(sessionID, mClientSessionID);
-    request.append(
-            AStringPrintf("Session: %d\r\n", mClientInfo.mPlaybackSessionID));
-    request.append("\r\n");  // Empty body
-
-    status_t err =
-        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
-
-    if (err != OK) {
-        return err;
-    }
-
-    registerResponseHandler(
-            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM16Response);
-
-    ++mNextCSeq;
-
-    scheduleKeepAlive(sessionID);
-
-    return OK;
-}
-
-status_t WifiDisplaySource::onReceiveM1Response(
-        int32_t /* sessionID */, const sp<ParsedMessage> &msg) {
-    int32_t statusCode;
-    if (!msg->getStatusCode(&statusCode)) {
-        return ERROR_MALFORMED;
-    }
-
-    if (statusCode != 200) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    return OK;
-}
-
-// sink_audio_list := ("LPCM"|"AAC"|"AC3" HEXDIGIT*8 HEXDIGIT*2)
-//                       (", " sink_audio_list)*
-static void GetAudioModes(const char *s, const char *prefix, uint32_t *modes) {
-    *modes = 0;
-
-    size_t prefixLen = strlen(prefix);
-
-    while (*s != '0') {
-        if (!strncmp(s, prefix, prefixLen) && s[prefixLen] == ' ') {
-            unsigned latency;
-            if (sscanf(&s[prefixLen + 1], "%08x %02x", modes, &latency) != 2) {
-                *modes = 0;
-            }
-
-            return;
-        }
-
-        const char *commaPos = strchr(s, ',');
-        if (commaPos != NULL) {
-            s = commaPos + 1;
-
-            while (isspace(*s)) {
-                ++s;
-            }
-        } else {
-            break;
-        }
-    }
-}
-
-status_t WifiDisplaySource::onReceiveM3Response(
-        int32_t sessionID, const sp<ParsedMessage> &msg) {
-    int32_t statusCode;
-    if (!msg->getStatusCode(&statusCode)) {
-        return ERROR_MALFORMED;
-    }
-
-    if (statusCode != 200) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    sp<Parameters> params =
-        Parameters::Parse(msg->getContent(), strlen(msg->getContent()));
-
-    if (params == NULL) {
-        return ERROR_MALFORMED;
-    }
-
-    AString value;
-    if (!params->findParameter("wfd_client_rtp_ports", &value)) {
-        ALOGE("Sink doesn't report its choice of wfd_client_rtp_ports.");
-        return ERROR_MALFORMED;
-    }
-
-    unsigned port0 = 0, port1 = 0;
-    if (sscanf(value.c_str(),
-               "RTP/AVP/UDP;unicast %u %u mode=play",
-               &port0,
-               &port1) == 2
-        || sscanf(value.c_str(),
-               "RTP/AVP/TCP;unicast %u %u mode=play",
-               &port0,
-               &port1) == 2) {
-            if (port0 == 0 || port0 > 65535 || port1 != 0) {
-                ALOGE("Sink chose its wfd_client_rtp_ports poorly (%s)",
-                      value.c_str());
-
-                return ERROR_MALFORMED;
-            }
-    } else if (strcmp(value.c_str(), "RTP/AVP/TCP;interleaved mode=play")) {
-        ALOGE("Unsupported value for wfd_client_rtp_ports (%s)",
-              value.c_str());
-
-        return ERROR_UNSUPPORTED;
-    }
-
-    mWfdClientRtpPorts = value;
-    mChosenRTPPort = port0;
-
-    if (!params->findParameter("wfd_video_formats", &value)) {
-        ALOGE("Sink doesn't report its choice of wfd_video_formats.");
-        return ERROR_MALFORMED;
-    }
-
-    mSinkSupportsVideo = false;
-
-    if  (!(value == "none")) {
-        mSinkSupportsVideo = true;
-        if (!mSupportedSinkVideoFormats.parseFormatSpec(value.c_str())) {
-            ALOGE("Failed to parse sink provided wfd_video_formats (%s)",
-                  value.c_str());
-
-            return ERROR_MALFORMED;
-        }
-
-        if (!VideoFormats::PickBestFormat(
-                    mSupportedSinkVideoFormats,
-                    mSupportedSourceVideoFormats,
-                    &mChosenVideoResolutionType,
-                    &mChosenVideoResolutionIndex,
-                    &mChosenVideoProfile,
-                    &mChosenVideoLevel)) {
-            ALOGE("Sink and source share no commonly supported video "
-                  "formats.");
-
-            return ERROR_UNSUPPORTED;
-        }
-
-        size_t width, height, framesPerSecond;
-        bool interlaced;
-        CHECK(VideoFormats::GetConfiguration(
-                    mChosenVideoResolutionType,
-                    mChosenVideoResolutionIndex,
-                    &width,
-                    &height,
-                    &framesPerSecond,
-                    &interlaced));
-
-        ALOGI("Picked video resolution %zu x %zu %c%zu",
-              width, height, interlaced ? 'i' : 'p', framesPerSecond);
-
-        ALOGI("Picked AVC profile %d, level %d",
-              mChosenVideoProfile, mChosenVideoLevel);
-    } else {
-        ALOGI("Sink doesn't support video at all.");
-    }
-
-    if (!params->findParameter("wfd_audio_codecs", &value)) {
-        ALOGE("Sink doesn't report its choice of wfd_audio_codecs.");
-        return ERROR_MALFORMED;
-    }
-
-    mSinkSupportsAudio = false;
-
-    if  (!(value == "none")) {
-        mSinkSupportsAudio = true;
-
-        uint32_t modes;
-        GetAudioModes(value.c_str(), "AAC", &modes);
-
-        bool supportsAAC = (modes & 1) != 0;  // AAC 2ch 48kHz
-
-        GetAudioModes(value.c_str(), "LPCM", &modes);
-
-        bool supportsPCM = (modes & 2) != 0;  // LPCM 2ch 48kHz
-
-        if (supportsPCM
-                && property_get_bool("media.wfd.use-pcm-audio", false)) {
-            ALOGI("Using PCM audio.");
-            mUsingPCMAudio = true;
-        } else if (supportsAAC) {
-            ALOGI("Using AAC audio.");
-            mUsingPCMAudio = false;
-        } else if (supportsPCM) {
-            ALOGI("Using PCM audio.");
-            mUsingPCMAudio = true;
-        } else {
-            ALOGI("Sink doesn't support an audio format we do.");
-            return ERROR_UNSUPPORTED;
-        }
-    } else {
-        ALOGI("Sink doesn't support audio at all.");
-    }
-
-    if (!mSinkSupportsVideo && !mSinkSupportsAudio) {
-        ALOGE("Sink supports neither video nor audio...");
-        return ERROR_UNSUPPORTED;
-    }
-
-    mUsingHDCP = false;
-    if (!params->findParameter("wfd_content_protection", &value)) {
-        ALOGI("Sink doesn't appear to support content protection.");
-    } else if (value == "none") {
-        ALOGI("Sink does not support content protection.");
-    } else {
-        mUsingHDCP = true;
-
-        bool isHDCP2_0 = false;
-        if (value.startsWith("HDCP2.0 ")) {
-            isHDCP2_0 = true;
-        } else if (!value.startsWith("HDCP2.1 ")) {
-            ALOGE("malformed wfd_content_protection: '%s'", value.c_str());
-
-            return ERROR_MALFORMED;
-        }
-
-        int32_t hdcpPort;
-        if (!ParsedMessage::GetInt32Attribute(
-                    value.c_str() + 8, "port", &hdcpPort)
-                || hdcpPort < 1 || hdcpPort > 65535) {
-            return ERROR_MALFORMED;
-        }
-
-        mIsHDCP2_0 = isHDCP2_0;
-        mHDCPPort = hdcpPort;
-
-        status_t err = makeHDCP();
-        if (err != OK) {
-            ALOGE("Unable to instantiate HDCP component. "
-                  "Not using HDCP after all.");
-
-            mUsingHDCP = false;
-        }
-    }
-
-    return sendM4(sessionID);
-}
-
-status_t WifiDisplaySource::onReceiveM4Response(
-        int32_t sessionID, const sp<ParsedMessage> &msg) {
-    int32_t statusCode;
-    if (!msg->getStatusCode(&statusCode)) {
-        return ERROR_MALFORMED;
-    }
-
-    if (statusCode != 200) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    if (mUsingHDCP && !mHDCPInitializationComplete) {
-        ALOGI("Deferring SETUP trigger until HDCP initialization completes.");
-
-        mSetupTriggerDeferred = true;
-        return OK;
-    }
-
-    return sendTrigger(sessionID, TRIGGER_SETUP);
-}
-
-status_t WifiDisplaySource::onReceiveM5Response(
-        int32_t /* sessionID */, const sp<ParsedMessage> &msg) {
-    int32_t statusCode;
-    if (!msg->getStatusCode(&statusCode)) {
-        return ERROR_MALFORMED;
-    }
-
-    if (statusCode != 200) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    return OK;
-}
-
-status_t WifiDisplaySource::onReceiveM16Response(
-        int32_t sessionID, const sp<ParsedMessage> & /* msg */) {
-    // If only the response was required to include a "Session:" header...
-
-    CHECK_EQ(sessionID, mClientSessionID);
-
-    if (mClientInfo.mPlaybackSession != NULL) {
-        mClientInfo.mPlaybackSession->updateLiveness();
-    }
-
-    return OK;
-}
-
-void WifiDisplaySource::scheduleReaper() {
-    if (mReaperPending) {
-        return;
-    }
-
-    mReaperPending = true;
-    (new AMessage(kWhatReapDeadClients, this))->post(kReaperIntervalUs);
-}
-
-void WifiDisplaySource::scheduleKeepAlive(int32_t sessionID) {
-    // We need to send updates at least 5 secs before the timeout is set to
-    // expire, make sure the timeout is greater than 5 secs to begin with.
-    CHECK_GT(kPlaybackSessionTimeoutUs, 5000000ll);
-
-    sp<AMessage> msg = new AMessage(kWhatKeepAlive, this);
-    msg->setInt32("sessionID", sessionID);
-    msg->post(kPlaybackSessionTimeoutUs - 5000000ll);
-}
-
-status_t WifiDisplaySource::onReceiveClientData(const sp<AMessage> &msg) {
-    int32_t sessionID;
-    CHECK(msg->findInt32("sessionID", &sessionID));
-
-    sp<RefBase> obj;
-    CHECK(msg->findObject("data", &obj));
-
-    sp<ParsedMessage> data =
-        static_cast<ParsedMessage *>(obj.get());
-
-    ALOGV("session %d received '%s'",
-          sessionID, data->debugString().c_str());
-
-    AString method;
-    AString uri;
-    data->getRequestField(0, &method);
-
-    int32_t cseq;
-    if (!data->findInt32("cseq", &cseq)) {
-        sendErrorResponse(sessionID, "400 Bad Request", -1 /* cseq */);
-        return ERROR_MALFORMED;
-    }
-
-    if (method.startsWith("RTSP/")) {
-        // This is a response.
-
-        ResponseID id;
-        id.mSessionID = sessionID;
-        id.mCSeq = cseq;
-
-        ssize_t index = mResponseHandlers.indexOfKey(id);
-
-        if (index < 0) {
-            ALOGW("Received unsolicited server response, cseq %d", cseq);
-            return ERROR_MALFORMED;
-        }
-
-        HandleRTSPResponseFunc func = mResponseHandlers.valueAt(index);
-        mResponseHandlers.removeItemsAt(index);
-
-        status_t err = (this->*func)(sessionID, data);
-
-        if (err != OK) {
-            ALOGW("Response handler for session %d, cseq %d returned "
-                  "err %d (%s)",
-                  sessionID, cseq, err, strerror(-err));
-
-            return err;
-        }
-
-        return OK;
-    }
-
-    AString version;
-    data->getRequestField(2, &version);
-    if (!(version == AString("RTSP/1.0"))) {
-        sendErrorResponse(sessionID, "505 RTSP Version not supported", cseq);
-        return ERROR_UNSUPPORTED;
-    }
-
-    status_t err;
-    if (method == "OPTIONS") {
-        err = onOptionsRequest(sessionID, cseq, data);
-    } else if (method == "SETUP") {
-        err = onSetupRequest(sessionID, cseq, data);
-    } else if (method == "PLAY") {
-        err = onPlayRequest(sessionID, cseq, data);
-    } else if (method == "PAUSE") {
-        err = onPauseRequest(sessionID, cseq, data);
-    } else if (method == "TEARDOWN") {
-        err = onTeardownRequest(sessionID, cseq, data);
-    } else if (method == "GET_PARAMETER") {
-        err = onGetParameterRequest(sessionID, cseq, data);
-    } else if (method == "SET_PARAMETER") {
-        err = onSetParameterRequest(sessionID, cseq, data);
-    } else {
-        sendErrorResponse(sessionID, "405 Method Not Allowed", cseq);
-
-        err = ERROR_UNSUPPORTED;
-    }
-
-    return err;
-}
-
-status_t WifiDisplaySource::onOptionsRequest(
-        int32_t sessionID,
-        int32_t cseq,
-        const sp<ParsedMessage> &data) {
-    int32_t playbackSessionID;
-    sp<PlaybackSession> playbackSession =
-        findPlaybackSession(data, &playbackSessionID);
-
-    if (playbackSession != NULL) {
-        playbackSession->updateLiveness();
-    }
-
-    AString response = "RTSP/1.0 200 OK\r\n";
-    AppendCommonResponse(&response, cseq);
-
-    response.append(
-            "Public: org.wfa.wfd1.0, SETUP, TEARDOWN, PLAY, PAUSE, "
-            "GET_PARAMETER, SET_PARAMETER\r\n");
-
-    response.append("\r\n");
-
-    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
-
-    if (err == OK) {
-        err = sendM3(sessionID);
-    }
-
-    return err;
-}
-
-status_t WifiDisplaySource::onSetupRequest(
-        int32_t sessionID,
-        int32_t cseq,
-        const sp<ParsedMessage> &data) {
-    CHECK_EQ(sessionID, mClientSessionID);
-    if (mClientInfo.mPlaybackSessionID != -1) {
-        // We only support a single playback session per client.
-        // This is due to the reversed keep-alive design in the wfd specs...
-        sendErrorResponse(sessionID, "400 Bad Request", cseq);
-        return ERROR_MALFORMED;
-    }
-
-    AString transport;
-    if (!data->findString("transport", &transport)) {
-        sendErrorResponse(sessionID, "400 Bad Request", cseq);
-        return ERROR_MALFORMED;
-    }
-
-    RTPSender::TransportMode rtpMode = RTPSender::TRANSPORT_UDP;
-
-    int clientRtp, clientRtcp;
-    if (transport.startsWith("RTP/AVP/TCP;")) {
-        AString interleaved;
-        if (ParsedMessage::GetAttribute(
-                    transport.c_str(), "interleaved", &interleaved)
-                && sscanf(interleaved.c_str(), "%d-%d",
-                          &clientRtp, &clientRtcp) == 2) {
-            rtpMode = RTPSender::TRANSPORT_TCP_INTERLEAVED;
-        } else {
-            bool badRequest = false;
-
-            AString clientPort;
-            if (!ParsedMessage::GetAttribute(
-                        transport.c_str(), "client_port", &clientPort)) {
-                badRequest = true;
-            } else if (sscanf(clientPort.c_str(), "%d-%d",
-                              &clientRtp, &clientRtcp) == 2) {
-            } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
-                // No RTCP.
-                clientRtcp = -1;
-            } else {
-                badRequest = true;
-            }
-
-            if (badRequest) {
-                sendErrorResponse(sessionID, "400 Bad Request", cseq);
-                return ERROR_MALFORMED;
-            }
-
-            rtpMode = RTPSender::TRANSPORT_TCP;
-        }
-    } else if (transport.startsWith("RTP/AVP;unicast;")
-            || transport.startsWith("RTP/AVP/UDP;unicast;")) {
-        bool badRequest = false;
-
-        AString clientPort;
-        if (!ParsedMessage::GetAttribute(
-                    transport.c_str(), "client_port", &clientPort)) {
-            badRequest = true;
-        } else if (sscanf(clientPort.c_str(), "%d-%d",
-                          &clientRtp, &clientRtcp) == 2) {
-        } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
-            // No RTCP.
-            clientRtcp = -1;
-        } else {
-            badRequest = true;
-        }
-
-        if (badRequest) {
-            sendErrorResponse(sessionID, "400 Bad Request", cseq);
-            return ERROR_MALFORMED;
-        }
-#if 1
-    // The older LG dongles doesn't specify client_port=xxx apparently.
-    } else if (transport == "RTP/AVP/UDP;unicast") {
-        clientRtp = 19000;
-        clientRtcp = -1;
-#endif
-    } else {
-        sendErrorResponse(sessionID, "461 Unsupported Transport", cseq);
-        return ERROR_UNSUPPORTED;
-    }
-
-    int32_t playbackSessionID = makeUniquePlaybackSessionID();
-
-    sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, this);
-    notify->setInt32("playbackSessionID", playbackSessionID);
-    notify->setInt32("sessionID", sessionID);
-
-    sp<PlaybackSession> playbackSession =
-        new PlaybackSession(
-                mOpPackageName, mNetSession, notify, mInterfaceAddr, mHDCP, mMediaPath.c_str());
-
-    looper()->registerHandler(playbackSession);
-
-    AString uri;
-    data->getRequestField(1, &uri);
-
-    if (strncasecmp("rtsp://", uri.c_str(), 7)) {
-        sendErrorResponse(sessionID, "400 Bad Request", cseq);
-        return ERROR_MALFORMED;
-    }
-
-    if (!(uri.startsWith("rtsp://") && uri.endsWith("/wfd1.0/streamid=0"))) {
-        sendErrorResponse(sessionID, "404 Not found", cseq);
-        return ERROR_MALFORMED;
-    }
-
-    RTPSender::TransportMode rtcpMode = RTPSender::TRANSPORT_UDP;
-    if (clientRtcp < 0) {
-        rtcpMode = RTPSender::TRANSPORT_NONE;
-    }
-
-    status_t err = playbackSession->init(
-            mClientInfo.mRemoteIP.c_str(),
-            clientRtp,
-            rtpMode,
-            clientRtcp,
-            rtcpMode,
-            mSinkSupportsAudio,
-            mUsingPCMAudio,
-            mSinkSupportsVideo,
-            mChosenVideoResolutionType,
-            mChosenVideoResolutionIndex,
-            mChosenVideoProfile,
-            mChosenVideoLevel);
-
-    if (err != OK) {
-        looper()->unregisterHandler(playbackSession->id());
-        playbackSession.clear();
-    }
-
-    switch (err) {
-        case OK:
-            break;
-        case -ENOENT:
-            sendErrorResponse(sessionID, "404 Not Found", cseq);
-            return err;
-        default:
-            sendErrorResponse(sessionID, "403 Forbidden", cseq);
-            return err;
-    }
-
-    mClientInfo.mPlaybackSessionID = playbackSessionID;
-    mClientInfo.mPlaybackSession = playbackSession;
-
-    AString response = "RTSP/1.0 200 OK\r\n";
-    AppendCommonResponse(&response, cseq, playbackSessionID);
-
-    if (rtpMode == RTPSender::TRANSPORT_TCP_INTERLEAVED) {
-        response.append(
-                AStringPrintf(
-                    "Transport: RTP/AVP/TCP;interleaved=%d-%d;",
-                    clientRtp, clientRtcp));
-    } else {
-        int32_t serverRtp = playbackSession->getRTPPort();
-
-        AString transportString = "UDP";
-        if (rtpMode == RTPSender::TRANSPORT_TCP) {
-            transportString = "TCP";
-        }
-
-        if (clientRtcp >= 0) {
-            response.append(
-                    AStringPrintf(
-                        "Transport: RTP/AVP/%s;unicast;client_port=%d-%d;"
-                        "server_port=%d-%d\r\n",
-                        transportString.c_str(),
-                        clientRtp, clientRtcp, serverRtp, serverRtp + 1));
-        } else {
-            response.append(
-                    AStringPrintf(
-                        "Transport: RTP/AVP/%s;unicast;client_port=%d;"
-                        "server_port=%d\r\n",
-                        transportString.c_str(),
-                        clientRtp, serverRtp));
-        }
-    }
-
-    response.append("\r\n");
-
-    err = mNetSession->sendRequest(sessionID, response.c_str());
-
-    if (err != OK) {
-        return err;
-    }
-
-    mState = AWAITING_CLIENT_PLAY;
-
-    scheduleReaper();
-    scheduleKeepAlive(sessionID);
-
-    return OK;
-}
-
-status_t WifiDisplaySource::onPlayRequest(
-        int32_t sessionID,
-        int32_t cseq,
-        const sp<ParsedMessage> &data) {
-    int32_t playbackSessionID;
-    sp<PlaybackSession> playbackSession =
-        findPlaybackSession(data, &playbackSessionID);
-
-    if (playbackSession == NULL) {
-        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
-        return ERROR_MALFORMED;
-    }
-
-    if (mState != AWAITING_CLIENT_PLAY
-     && mState != PAUSED_TO_PLAYING
-     && mState != PAUSED) {
-        ALOGW("Received PLAY request but we're in state %d", mState);
-
-        sendErrorResponse(
-                sessionID, "455 Method Not Valid in This State", cseq);
-
-        return INVALID_OPERATION;
-    }
-
-    ALOGI("Received PLAY request.");
-    if (mPlaybackSessionEstablished) {
-        finishPlay();
-    } else {
-        ALOGI("deferring PLAY request until session established.");
-    }
-
-    AString response = "RTSP/1.0 200 OK\r\n";
-    AppendCommonResponse(&response, cseq, playbackSessionID);
-    response.append("Range: npt=now-\r\n");
-    response.append("\r\n");
-
-    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
-
-    if (err != OK) {
-        return err;
-    }
-
-    if (mState == PAUSED_TO_PLAYING || mPlaybackSessionEstablished) {
-        mState = PLAYING;
-        return OK;
-    }
-
-    CHECK_EQ(mState, AWAITING_CLIENT_PLAY);
-    mState = ABOUT_TO_PLAY;
-
-    return OK;
-}
-
-void WifiDisplaySource::finishPlay() {
-    const sp<PlaybackSession> &playbackSession =
-        mClientInfo.mPlaybackSession;
-
-    status_t err = playbackSession->play();
-    CHECK_EQ(err, (status_t)OK);
-}
-
-status_t WifiDisplaySource::onPauseRequest(
-        int32_t sessionID,
-        int32_t cseq,
-        const sp<ParsedMessage> &data) {
-    int32_t playbackSessionID;
-    sp<PlaybackSession> playbackSession =
-        findPlaybackSession(data, &playbackSessionID);
-
-    if (playbackSession == NULL) {
-        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
-        return ERROR_MALFORMED;
-    }
-
-    ALOGI("Received PAUSE request.");
-
-    if (mState != PLAYING_TO_PAUSED && mState != PLAYING) {
-        return INVALID_OPERATION;
-    }
-
-    status_t err = playbackSession->pause();
-    CHECK_EQ(err, (status_t)OK);
-
-    AString response = "RTSP/1.0 200 OK\r\n";
-    AppendCommonResponse(&response, cseq, playbackSessionID);
-    response.append("\r\n");
-
-    err = mNetSession->sendRequest(sessionID, response.c_str());
-
-    if (err != OK) {
-        return err;
-    }
-
-    mState = PAUSED;
-
-    return err;
-}
-
-status_t WifiDisplaySource::onTeardownRequest(
-        int32_t sessionID,
-        int32_t cseq,
-        const sp<ParsedMessage> &data) {
-    ALOGI("Received TEARDOWN request.");
-
-    int32_t playbackSessionID;
-    sp<PlaybackSession> playbackSession =
-        findPlaybackSession(data, &playbackSessionID);
-
-    if (playbackSession == NULL) {
-        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
-        return ERROR_MALFORMED;
-    }
-
-    AString response = "RTSP/1.0 200 OK\r\n";
-    AppendCommonResponse(&response, cseq, playbackSessionID);
-    response.append("Connection: close\r\n");
-    response.append("\r\n");
-
-    mNetSession->sendRequest(sessionID, response.c_str());
-
-    if (mState == AWAITING_CLIENT_TEARDOWN) {
-        CHECK(mStopReplyID != NULL);
-        finishStop();
-    } else {
-        mClient->onDisplayError(IRemoteDisplayClient::kDisplayErrorUnknown);
-    }
-
-    return OK;
-}
-
-void WifiDisplaySource::finishStop() {
-    ALOGV("finishStop");
-
-    mState = STOPPING;
-
-    disconnectClientAsync();
-}
-
-void WifiDisplaySource::finishStopAfterDisconnectingClient() {
-    ALOGV("finishStopAfterDisconnectingClient");
-
-    if (mHDCP != NULL) {
-        ALOGI("Initiating HDCP shutdown.");
-        mHDCP->shutdownAsync();
-        return;
-    }
-
-    finishStop2();
-}
-
-void WifiDisplaySource::finishStop2() {
-    ALOGV("finishStop2");
-
-    if (mHDCP != NULL) {
-        mHDCP->setObserver(NULL);
-        mHDCPObserver.clear();
-        mHDCP.clear();
-    }
-
-    if (mSessionID != 0) {
-        mNetSession->destroySession(mSessionID);
-        mSessionID = 0;
-    }
-
-    ALOGI("We're stopped.");
-    mState = STOPPED;
-
-    status_t err = OK;
-
-    sp<AMessage> response = new AMessage;
-    response->setInt32("err", err);
-    response->postReply(mStopReplyID);
-}
-
-status_t WifiDisplaySource::onGetParameterRequest(
-        int32_t sessionID,
-        int32_t cseq,
-        const sp<ParsedMessage> &data) {
-    int32_t playbackSessionID;
-    sp<PlaybackSession> playbackSession =
-        findPlaybackSession(data, &playbackSessionID);
-
-    if (playbackSession == NULL) {
-        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
-        return ERROR_MALFORMED;
-    }
-
-    playbackSession->updateLiveness();
-
-    AString response = "RTSP/1.0 200 OK\r\n";
-    AppendCommonResponse(&response, cseq, playbackSessionID);
-    response.append("\r\n");
-
-    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
-    return err;
-}
-
-status_t WifiDisplaySource::onSetParameterRequest(
-        int32_t sessionID,
-        int32_t cseq,
-        const sp<ParsedMessage> &data) {
-    int32_t playbackSessionID;
-    sp<PlaybackSession> playbackSession =
-        findPlaybackSession(data, &playbackSessionID);
-
-    if (playbackSession == NULL) {
-        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
-        return ERROR_MALFORMED;
-    }
-
-    if (strstr(data->getContent(), "wfd_idr_request\r\n")) {
-        playbackSession->requestIDRFrame();
-    }
-
-    playbackSession->updateLiveness();
-
-    AString response = "RTSP/1.0 200 OK\r\n";
-    AppendCommonResponse(&response, cseq, playbackSessionID);
-    response.append("\r\n");
-
-    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
-    return err;
-}
-
-// static
-void WifiDisplaySource::AppendCommonResponse(
-        AString *response, int32_t cseq, int32_t playbackSessionID) {
-    time_t now = time(NULL);
-    struct tm *now2 = gmtime(&now);
-    char buf[128];
-    strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", now2);
-
-    response->append("Date: ");
-    response->append(buf);
-    response->append("\r\n");
-
-    response->append(AStringPrintf("Server: %s\r\n", sUserAgent.c_str()));
-
-    if (cseq >= 0) {
-        response->append(AStringPrintf("CSeq: %d\r\n", cseq));
-    }
-
-    if (playbackSessionID >= 0ll) {
-        response->append(
-                AStringPrintf(
-                    "Session: %d;timeout=%lld\r\n",
-                    playbackSessionID, kPlaybackSessionTimeoutSecs));
-    }
-}
-
-void WifiDisplaySource::sendErrorResponse(
-        int32_t sessionID,
-        const char *errorDetail,
-        int32_t cseq) {
-    AString response;
-    response.append("RTSP/1.0 ");
-    response.append(errorDetail);
-    response.append("\r\n");
-
-    AppendCommonResponse(&response, cseq);
-
-    response.append("\r\n");
-
-    mNetSession->sendRequest(sessionID, response.c_str());
-}
-
-int32_t WifiDisplaySource::makeUniquePlaybackSessionID() const {
-    return rand();
-}
-
-sp<WifiDisplaySource::PlaybackSession> WifiDisplaySource::findPlaybackSession(
-        const sp<ParsedMessage> &data, int32_t *playbackSessionID) const {
-    if (!data->findInt32("session", playbackSessionID)) {
-        // XXX the older dongles do not always include a "Session:" header.
-        *playbackSessionID = mClientInfo.mPlaybackSessionID;
-        return mClientInfo.mPlaybackSession;
-    }
-
-    if (*playbackSessionID != mClientInfo.mPlaybackSessionID) {
-        return NULL;
-    }
-
-    return mClientInfo.mPlaybackSession;
-}
-
-void WifiDisplaySource::disconnectClientAsync() {
-    ALOGV("disconnectClient");
-
-    if (mClientInfo.mPlaybackSession == NULL) {
-        disconnectClient2();
-        return;
-    }
-
-    if (mClientInfo.mPlaybackSession != NULL) {
-        ALOGV("Destroying PlaybackSession");
-        mClientInfo.mPlaybackSession->destroyAsync();
-    }
-}
-
-void WifiDisplaySource::disconnectClient2() {
-    ALOGV("disconnectClient2");
-
-    if (mClientInfo.mPlaybackSession != NULL) {
-        looper()->unregisterHandler(mClientInfo.mPlaybackSession->id());
-        mClientInfo.mPlaybackSession.clear();
-    }
-
-    if (mClientSessionID != 0) {
-        mNetSession->destroySession(mClientSessionID);
-        mClientSessionID = 0;
-    }
-
-    mClient->onDisplayDisconnected();
-
-    finishStopAfterDisconnectingClient();
-}
-
-struct WifiDisplaySource::HDCPObserver : public BnHDCPObserver {
-    explicit HDCPObserver(const sp<AMessage> &notify);
-
-    virtual void notify(
-            int msg, int ext1, int ext2, const Parcel *obj);
-
-private:
-    sp<AMessage> mNotify;
-
-    DISALLOW_EVIL_CONSTRUCTORS(HDCPObserver);
-};
-
-WifiDisplaySource::HDCPObserver::HDCPObserver(
-        const sp<AMessage> &notify)
-    : mNotify(notify) {
-}
-
-void WifiDisplaySource::HDCPObserver::notify(
-        int msg, int ext1, int ext2, const Parcel * /* obj */) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("msg", msg);
-    notify->setInt32("ext1", ext1);
-    notify->setInt32("ext2", ext2);
-    notify->post();
-}
-
-status_t WifiDisplaySource::makeHDCP() {
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("media.player"));
-
-    sp<IMediaPlayerService> service =
-        interface_cast<IMediaPlayerService>(binder);
-
-    CHECK(service != NULL);
-
-    mHDCP = service->makeHDCP(true /* createEncryptionModule */);
-
-    if (mHDCP == NULL) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    sp<AMessage> notify = new AMessage(kWhatHDCPNotify, this);
-    mHDCPObserver = new HDCPObserver(notify);
-
-    status_t err = mHDCP->setObserver(mHDCPObserver);
-
-    if (err != OK) {
-        ALOGE("Failed to set HDCP observer.");
-
-        mHDCPObserver.clear();
-        mHDCP.clear();
-
-        return err;
-    }
-
-    ALOGI("Initiating HDCP negotiation w/ host %s:%d",
-            mClientInfo.mRemoteIP.c_str(), mHDCPPort);
-
-    err = mHDCP->initAsync(mClientInfo.mRemoteIP.c_str(), mHDCPPort);
-
-    if (err != OK) {
-        return err;
-    }
-
-    return OK;
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
deleted file mode 100644
index c25a675..0000000
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright 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 WIFI_DISPLAY_SOURCE_H_
-
-#define WIFI_DISPLAY_SOURCE_H_
-
-#include "VideoFormats.h"
-
-#include <media/stagefright/foundation/AHandler.h>
-#include <media/stagefright/foundation/ANetworkSession.h>
-
-#include <netinet/in.h>
-
-#include <utils/String16.h>
-
-namespace android {
-
-struct AReplyToken;
-struct IHDCP;
-class IRemoteDisplayClient;
-struct ParsedMessage;
-
-// Represents the RTSP server acting as a wifi display source.
-// Manages incoming connections, sets up Playback sessions as necessary.
-struct WifiDisplaySource : public AHandler {
-    static const unsigned kWifiDisplayDefaultPort = 7236;
-
-    WifiDisplaySource(
-            const String16 &opPackageName,
-            const sp<ANetworkSession> &netSession,
-            const sp<IRemoteDisplayClient> &client,
-            const char *path = NULL);
-
-    status_t start(const char *iface);
-    status_t stop();
-
-    status_t pause();
-    status_t resume();
-
-protected:
-    virtual ~WifiDisplaySource();
-    virtual void onMessageReceived(const sp<AMessage> &msg);
-
-private:
-    struct PlaybackSession;
-    struct HDCPObserver;
-
-    enum State {
-        INITIALIZED,
-        AWAITING_CLIENT_CONNECTION,
-        AWAITING_CLIENT_SETUP,
-        AWAITING_CLIENT_PLAY,
-        ABOUT_TO_PLAY,
-        PLAYING,
-        PLAYING_TO_PAUSED,
-        PAUSED,
-        PAUSED_TO_PLAYING,
-        AWAITING_CLIENT_TEARDOWN,
-        STOPPING,
-        STOPPED,
-    };
-
-    enum {
-        kWhatStart,
-        kWhatRTSPNotify,
-        kWhatStop,
-        kWhatPause,
-        kWhatResume,
-        kWhatReapDeadClients,
-        kWhatPlaybackSessionNotify,
-        kWhatKeepAlive,
-        kWhatHDCPNotify,
-        kWhatFinishStop2,
-        kWhatTeardownTriggerTimedOut,
-    };
-
-    struct ResponseID {
-        int32_t mSessionID;
-        int32_t mCSeq;
-
-        bool operator<(const ResponseID &other) const {
-            return mSessionID < other.mSessionID
-                || (mSessionID == other.mSessionID
-                        && mCSeq < other.mCSeq);
-        }
-    };
-
-    typedef status_t (WifiDisplaySource::*HandleRTSPResponseFunc)(
-            int32_t sessionID, const sp<ParsedMessage> &msg);
-
-    static const int64_t kReaperIntervalUs = 1000000ll;
-
-    // We request that the dongle send us a "TEARDOWN" in order to
-    // perform an orderly shutdown. We're willing to wait up to 2 secs
-    // for this message to arrive, after that we'll force a disconnect
-    // instead.
-    static const int64_t kTeardownTriggerTimeouSecs = 2;
-
-    static const int64_t kPlaybackSessionTimeoutSecs = 30;
-
-    static const int64_t kPlaybackSessionTimeoutUs =
-        kPlaybackSessionTimeoutSecs * 1000000ll;
-
-    static const AString sUserAgent;
-
-    String16 mOpPackageName;
-
-    State mState;
-    VideoFormats mSupportedSourceVideoFormats;
-    sp<ANetworkSession> mNetSession;
-    sp<IRemoteDisplayClient> mClient;
-    AString mMediaPath;
-    struct in_addr mInterfaceAddr;
-    int32_t mSessionID;
-
-    sp<AReplyToken> mStopReplyID;
-
-    AString mWfdClientRtpPorts;
-    int32_t mChosenRTPPort;  // extracted from "wfd_client_rtp_ports"
-
-    bool mSinkSupportsVideo;
-    VideoFormats mSupportedSinkVideoFormats;
-
-    VideoFormats::ResolutionType mChosenVideoResolutionType;
-    size_t mChosenVideoResolutionIndex;
-    VideoFormats::ProfileType mChosenVideoProfile;
-    VideoFormats::LevelType mChosenVideoLevel;
-
-    bool mSinkSupportsAudio;
-
-    bool mUsingPCMAudio;
-    int32_t mClientSessionID;
-
-    struct ClientInfo {
-        AString mRemoteIP;
-        AString mLocalIP;
-        int32_t mLocalPort;
-        int32_t mPlaybackSessionID;
-        sp<PlaybackSession> mPlaybackSession;
-    };
-    ClientInfo mClientInfo;
-
-    bool mReaperPending;
-
-    int32_t mNextCSeq;
-
-    KeyedVector<ResponseID, HandleRTSPResponseFunc> mResponseHandlers;
-
-    // HDCP specific section >>>>
-    bool mUsingHDCP;
-    bool mIsHDCP2_0;
-    int32_t mHDCPPort;
-    sp<IHDCP> mHDCP;
-    sp<HDCPObserver> mHDCPObserver;
-
-    bool mHDCPInitializationComplete;
-    bool mSetupTriggerDeferred;
-
-    bool mPlaybackSessionEstablished;
-
-    status_t makeHDCP();
-    // <<<< HDCP specific section
-
-    status_t sendM1(int32_t sessionID);
-    status_t sendM3(int32_t sessionID);
-    status_t sendM4(int32_t sessionID);
-
-    enum TriggerType {
-        TRIGGER_SETUP,
-        TRIGGER_TEARDOWN,
-        TRIGGER_PAUSE,
-        TRIGGER_PLAY,
-    };
-
-    // M5
-    status_t sendTrigger(int32_t sessionID, TriggerType triggerType);
-
-    status_t sendM16(int32_t sessionID);
-
-    status_t onReceiveM1Response(
-            int32_t sessionID, const sp<ParsedMessage> &msg);
-
-    status_t onReceiveM3Response(
-            int32_t sessionID, const sp<ParsedMessage> &msg);
-
-    status_t onReceiveM4Response(
-            int32_t sessionID, const sp<ParsedMessage> &msg);
-
-    status_t onReceiveM5Response(
-            int32_t sessionID, const sp<ParsedMessage> &msg);
-
-    status_t onReceiveM16Response(
-            int32_t sessionID, const sp<ParsedMessage> &msg);
-
-    void registerResponseHandler(
-            int32_t sessionID, int32_t cseq, HandleRTSPResponseFunc func);
-
-    status_t onReceiveClientData(const sp<AMessage> &msg);
-
-    status_t onOptionsRequest(
-            int32_t sessionID,
-            int32_t cseq,
-            const sp<ParsedMessage> &data);
-
-    status_t onSetupRequest(
-            int32_t sessionID,
-            int32_t cseq,
-            const sp<ParsedMessage> &data);
-
-    status_t onPlayRequest(
-            int32_t sessionID,
-            int32_t cseq,
-            const sp<ParsedMessage> &data);
-
-    status_t onPauseRequest(
-            int32_t sessionID,
-            int32_t cseq,
-            const sp<ParsedMessage> &data);
-
-    status_t onTeardownRequest(
-            int32_t sessionID,
-            int32_t cseq,
-            const sp<ParsedMessage> &data);
-
-    status_t onGetParameterRequest(
-            int32_t sessionID,
-            int32_t cseq,
-            const sp<ParsedMessage> &data);
-
-    status_t onSetParameterRequest(
-            int32_t sessionID,
-            int32_t cseq,
-            const sp<ParsedMessage> &data);
-
-    void sendErrorResponse(
-            int32_t sessionID,
-            const char *errorDetail,
-            int32_t cseq);
-
-    static void AppendCommonResponse(
-            AString *response, int32_t cseq, int32_t playbackSessionID = -1ll);
-
-    void scheduleReaper();
-    void scheduleKeepAlive(int32_t sessionID);
-
-    int32_t makeUniquePlaybackSessionID() const;
-
-    sp<PlaybackSession> findPlaybackSession(
-            const sp<ParsedMessage> &data, int32_t *playbackSessionID) const;
-
-    void finishStop();
-    void disconnectClientAsync();
-    void disconnectClient2();
-    void finishStopAfterDisconnectingClient();
-    void finishStop2();
-
-    void finishPlay();
-
-    DISALLOW_EVIL_CONSTRUCTORS(WifiDisplaySource);
-};
-
-}  // namespace android
-
-#endif  // WIFI_DISPLAY_SOURCE_H_
diff --git a/media/libstagefright/xmlparser/Android.bp b/media/libstagefright/xmlparser/Android.bp
index 3507284..a4fa342 100644
--- a/media/libstagefright/xmlparser/Android.bp
+++ b/media/libstagefright/xmlparser/Android.bp
@@ -15,10 +15,7 @@
 
     shared_libs: [
         "libexpat",
-        "libutils",
         "liblog",
-        "libcutils",
-        "libstagefright_foundation",
         "libstagefright_omx_utils",
     ],
 
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 0d48de1..cea2f9e 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -67,9 +67,9 @@
     shared_libs: [
         "libbinder",
         "libmedia",
+        "libmedia_omx",
         "libmedia_jni",
         "libmediadrm",
-        "libskia",
         "libstagefright",
         "libstagefright_foundation",
         "liblog",
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index c4ff537..20b1667 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -37,8 +37,8 @@
         mTimestamp(timestamp), mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
 }
 
-// Can only be called by free() with mLock hold
 AImage::~AImage() {
+    Mutex::Autolock _l(mLock);
     if (!mIsClosed) {
         LOG_ALWAYS_FATAL(
                 "Error: AImage %p is deleted before returning buffer to AImageReader!", this);
@@ -78,7 +78,6 @@
         ALOGE("Cannot free AImage before close!");
         return;
     }
-    Mutex::Autolock _l(mLock);
     delete this;
 }
 
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index fd6ecb5..be635ff 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -657,7 +657,7 @@
 
 EXPORT
 media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
-    ALOGE("%s", __FUNCTION__);
+    ALOGV("%s", __FUNCTION__);
     if (reader == nullptr || window == nullptr) {
         ALOGE("%s: invalid argument. reader %p, window %p",
                 __FUNCTION__, reader, window);
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 128edba..11dedbb 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -367,6 +367,13 @@
 }
 
 EXPORT
+AMediaFormat* AMediaCodec_getBufferFormat(AMediaCodec *mData, size_t index) {
+    sp<AMessage> format;
+    mData->mCodec->getOutputFormat(index, &format);
+    return AMediaFormat_fromMsg(&format);
+}
+
+EXPORT
 media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
     if (render) {
         return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
diff --git a/media/ndk/OWNERS b/media/ndk/OWNERS
new file mode 100644
index 0000000..11e8340
--- /dev/null
+++ b/media/ndk/OWNERS
@@ -0,0 +1,5 @@
+marcone@google.com
+# For AImage/AImageReader
+etalvala@google.com
+yinchiayeh@google.com
+zhijunhe@google.com
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index a8667c9..e3b99d0 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -305,9 +305,9 @@
 /**
  * AImageReader constructor similar to {@link AImageReader_new} that takes an additional parameter
  * for the consumer usage. All other parameters and the return values are identical to those passed
- * to {@line AImageReader_new}.
+ * to {@link AImageReader_new}.
  *
- * <p>If the {@code format} is {@link AIMAGE_FORMAT_PRIVATE}, the created {@link AImageReader}
+ * <p>If the \c format is {@link AIMAGE_FORMAT_PRIVATE}, the created {@link AImageReader}
  * will produce images whose contents are not directly accessible by the application. The application can
  * still acquire images from this {@link AImageReader} and access {@link AHardwareBuffer} via
  * {@link AImage_getHardwareBuffer()}. The {@link AHardwareBuffer} gained this way can then
@@ -322,7 +322,7 @@
  * AImageReader}s using other format such as {@link AIMAGE_FORMAT_YUV_420_888}.</p>
  *
  * <p>Note that not all format and usage flag combination is supported by the {@link AImageReader},
- * especially if {@code format} is {@link AIMAGE_FORMAT_PRIVATE}, {@code usage} must not include either
+ * especially if \c format is {@link AIMAGE_FORMAT_PRIVATE}, \c usage must not include either
  * {@link AHARDWAREBUFFER_USAGE_READ_RARELY} or {@link AHARDWAREBUFFER_USAGE_READ_OFTEN}</p>
  *
  * @param width The default width in pixels of the Images that this reader will produce.
@@ -367,7 +367,7 @@
         int32_t width, int32_t height, int32_t format, uint64_t usage, int32_t maxImages,
         /*out*/ AImageReader** reader);
 
-/*
+/**
  * Acquire the next {@link AImage} from the image reader's queue asynchronously.
  *
  * <p>AImageReader acquire method similar to {@link AImageReader_acquireNextImage} that takes an
@@ -377,7 +377,7 @@
  * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
  *         buffer is ready to consume. When synchronization fence is not needed, fence will be set
  *         to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
- *         use syscalls such as {@code poll()}, {@code epoll()}, {@code select()} to wait for the
+ *         use syscalls such as \c poll(), \c epoll(), \c select() to wait for the
  *         fence fd to change status before attempting to access the {@link AImage} returned.
  *
  * @see sync.h
@@ -386,7 +386,7 @@
 media_status_t AImageReader_acquireNextImageAsync(
         AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd);
 
-/*
+/**
  * Acquire the latest {@link AImage} from the image reader's queue asynchronously, dropping older
  * images.
  *
@@ -397,7 +397,7 @@
  * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
  *         buffer is ready to consume. When synchronization fence is not needed, fence will be set
  *         to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
- *         use syscalls such as {@code poll()}, {@code epoll()}, {@code select()} to wait for the
+ *         use syscalls such as \c poll(), \c epoll(), \c select() to wait for the
  *         fence fd to change status before attempting to access the {@link AImage} returned.
  *
  * @see sync.h
diff --git a/media/ndk/include/media/NdkMediaCodec.h b/media/ndk/include/media/NdkMediaCodec.h
index 144de2d..b15de38 100644
--- a/media/ndk/include/media/NdkMediaCodec.h
+++ b/media/ndk/include/media/NdkMediaCodec.h
@@ -180,6 +180,12 @@
 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec*);
 
 /**
+ * Get format of the buffer. The specified buffer index must have been previously obtained from
+ * dequeueOutputBuffer.
+ */
+AMediaFormat* AMediaCodec_getBufferFormat(AMediaCodec*, size_t index);
+
+/**
  * If you are done with a buffer, use this call to return the buffer to
  * the codec. If you previously specified a surface when configuring this
  * video decoder you can optionally render the buffer.
diff --git a/media/utils/OWNERS b/media/utils/OWNERS
new file mode 100644
index 0000000..f9cb567
--- /dev/null
+++ b/media/utils/OWNERS
@@ -0,0 +1 @@
+gkasten@google.com
diff --git a/services/OWNERS b/services/OWNERS
index d500dce..d5d00da 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -1,4 +1,4 @@
 elaurent@google.com
 etalvala@google.com
-gkasten@android.com
+gkasten@google.com
 hunga@google.com
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index d0454d4..7419e64 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -51,6 +51,7 @@
     libmedialogservice \
     libmediautils \
     libnbaio \
+    libnblog \
     libpowermanager \
     libserviceutility \
     libmediautils \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 39f04fb..9cb0357 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -641,38 +641,52 @@
 
 // IAudioFlinger interface
 
-
-sp<IAudioTrack> AudioFlinger::createTrack(
-        audio_stream_type_t streamType,
-        uint32_t sampleRate,
-        audio_format_t format,
-        audio_channel_mask_t channelMask,
-        size_t *frameCount,
-        audio_output_flags_t *flags,
-        const sp<IMemory>& sharedBuffer,
-        audio_io_handle_t output,
-        pid_t pid,
-        pid_t tid,
-        audio_session_t *sessionId,
-        int clientUid,
-        status_t *status,
-        audio_port_handle_t portId)
+sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input,
+                                          CreateTrackOutput& output,
+                                          status_t *status)
 {
     sp<PlaybackThread::Track> track;
     sp<TrackHandle> trackHandle;
     sp<Client> client;
     status_t lStatus;
-    audio_session_t lSessionId;
+    audio_stream_type_t streamType;
+    audio_port_handle_t portId;
 
+    bool updatePid = (input.clientInfo.clientPid == -1);
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    if (pid == -1 || !isTrustedCallingUid(callingUid)) {
+    uid_t clientUid = input.clientInfo.clientUid;
+    if (!isTrustedCallingUid(callingUid)) {
+        ALOGW_IF(clientUid != callingUid,
+                "%s uid %d tried to pass itself off as %d",
+                __FUNCTION__, callingUid, clientUid);
+        clientUid = callingUid;
+        updatePid = true;
+    }
+    pid_t clientPid = input.clientInfo.clientPid;
+    if (updatePid) {
         const pid_t callingPid = IPCThreadState::self()->getCallingPid();
-        ALOGW_IF(pid != -1 && pid != callingPid,
+        ALOGW_IF(clientPid != -1 && clientPid != callingPid,
                  "%s uid %d pid %d tried to pass itself off as pid %d",
-                 __func__, callingUid, callingPid, pid);
-        pid = callingPid;
+                 __func__, callingUid, callingPid, clientPid);
+        clientPid = callingPid;
     }
 
+    audio_session_t sessionId = input.sessionId;
+    if (sessionId == AUDIO_SESSION_ALLOCATE) {
+        sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
+    }
+    output.sessionId = sessionId;
+    output.outputId = AUDIO_IO_HANDLE_NONE;
+    output.selectedDeviceId = input.selectedDeviceId;
+
+    lStatus = AudioSystem::getOutputForAttr(&input.attr, &output.outputId, sessionId, &streamType,
+                                            clientUid, &input.config, input.flags,
+                                            &output.selectedDeviceId, &portId);
+
+    if (lStatus != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
+        ALOGE("createTrack() getOutputForAttr() return error %d or invalid output handle", lStatus);
+        goto Exit;
+    }
     // client AudioTrack::set already implements AUDIO_STREAM_DEFAULT => AUDIO_STREAM_MUSIC,
     // but if someone uses binder directly they could bypass that and cause us to crash
     if (uint32_t(streamType) >= AUDIO_STREAM_CNT) {
@@ -681,91 +695,76 @@
         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);
+    if (!audio_is_output_channel(input.config.channel_mask)) {
+        ALOGE("createTrack() invalid channel mask %#x", input.config.channel_mask);
         lStatus = BAD_VALUE;
         goto Exit;
     }
 
     // further format checks are performed by createTrack_l() depending on the thread type
-    if (!audio_is_valid_format(format)) {
-        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()");
+    if (!audio_is_valid_format(input.config.format)) {
+        ALOGE("createTrack() invalid format %#x", input.config.format);
         lStatus = BAD_VALUE;
         goto Exit;
     }
 
     {
         Mutex::Autolock _l(mLock);
-        PlaybackThread *thread = checkPlaybackThread_l(output);
+        PlaybackThread *thread = checkPlaybackThread_l(output.outputId);
         if (thread == NULL) {
-            ALOGE("no playback thread found for output handle %d", output);
+            ALOGE("no playback thread found for output handle %d", output.outputId);
             lStatus = BAD_VALUE;
             goto Exit;
         }
 
-        client = registerPid(pid);
+        client = registerPid(clientPid);
 
         PlaybackThread *effectThread = NULL;
-        if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
-            if (audio_unique_id_get_use(*sessionId) != AUDIO_UNIQUE_ID_USE_SESSION) {
-                ALOGE("createTrack() invalid session ID %d", *sessionId);
-                lStatus = BAD_VALUE;
-                goto Exit;
-            }
-            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(lSessionId);
-                    if (sessions & ThreadBase::EFFECT_SESSION) {
-                        effectThread = t.get();
-                        break;
-                    }
+        // 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.outputId) {
+                uint32_t sessions = t->hasAudioSession(sessionId);
+                if (sessions & ThreadBase::EFFECT_SESSION) {
+                    effectThread = t.get();
+                    break;
                 }
             }
-        } else {
-            // if no audio session id is provided, create one here
-            lSessionId = (audio_session_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
-            if (sessionId != NULL) {
-                *sessionId = lSessionId;
-            }
         }
-        ALOGV("createTrack() lSessionId: %d", lSessionId);
+        ALOGV("createTrack() sessionId: %d", sessionId);
 
-        track = thread->createTrack_l(client, streamType, sampleRate, format,
-                channelMask, frameCount, sharedBuffer, lSessionId, flags, tid,
-                clientUid, &lStatus, portId);
+        output.sampleRate = input.config.sample_rate;
+        output.frameCount = input.frameCount;
+        output.notificationFrameCount = input.notificationFrameCount;
+        output.flags = input.flags;
+
+        track = thread->createTrack_l(client, streamType, &output.sampleRate, input.config.format,
+                                      input.config.channel_mask,
+                                      &output.frameCount, &output.notificationFrameCount,
+                                      input.notificationsPerBuffer, input.speed,
+                                      input.sharedBuffer, sessionId, &output.flags,
+                                      input.clientInfo.clientTid, clientUid, &lStatus, portId);
         LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0));
         // we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
 
+        output.afFrameCount = thread->frameCount();
+        output.afSampleRate = thread->sampleRate();
+        output.afLatencyMs = thread->latency();
+
         // 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);
+            moveEffectChain_l(sessionId, effectThread, thread, true);
         }
 
         // Look for sync events awaiting for a session to be used.
         for (size_t i = 0; i < mPendingSyncEvents.size(); i++) {
-            if (mPendingSyncEvents[i]->triggerSession() == lSessionId) {
+            if (mPendingSyncEvents[i]->triggerSession() == sessionId) {
                 if (thread->isValidSyncEvent(mPendingSyncEvents[i])) {
                     if (lStatus == NO_ERROR) {
                         (void) track->setSyncEvent(mPendingSyncEvents[i]);
@@ -778,7 +777,7 @@
             }
         }
 
-        setAudioHwSyncForSession_l(thread, lSessionId);
+        setAudioHwSyncForSession_l(thread, sessionId);
     }
 
     if (lStatus != NO_ERROR) {
@@ -798,6 +797,9 @@
     trackHandle = new TrackHandle(track);
 
 Exit:
+    if (lStatus != NO_ERROR && output.outputId != AUDIO_IO_HANDLE_NONE) {
+        AudioSystem::releaseOutput(output.outputId, streamType, sessionId);
+    }
     *status = lStatus;
     return trackHandle;
 }
@@ -1566,7 +1568,7 @@
 
 // ----------------------------------------------------------------------------
 
-sp<IAudioRecord> AudioFlinger::openRecord(
+sp<media::IAudioRecord> AudioFlinger::openRecord(
         audio_io_handle_t input,
         uint32_t sampleRate,
         audio_format_t format,
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 63898a0..506420c 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -33,7 +33,6 @@
 #include <media/IAudioFlinger.h>
 #include <media/IAudioFlingerClient.h>
 #include <media/IAudioTrack.h>
-#include <media/IAudioRecord.h>
 #include <media/AudioSystem.h>
 #include <media/AudioTrack.h>
 #include <media/MmapStreamInterface.h>
@@ -72,10 +71,12 @@
 
 #include <powermanager/IPowerManager.h>
 
-#include <media/nbaio/NBLog.h>
+#include <media/nblog/NBLog.h>
 #include <private/media/AudioEffectShared.h>
 #include <private/media/AudioTrackShared.h>
 
+#include "android/media/BnAudioRecord.h"
+
 namespace android {
 
 class AudioMixer;
@@ -113,23 +114,11 @@
     virtual     status_t    dump(int fd, const Vector<String16>& args);
 
     // IAudioFlinger interface, in binder opcode order
-    virtual sp<IAudioTrack> createTrack(
-                                audio_stream_type_t streamType,
-                                uint32_t sampleRate,
-                                audio_format_t format,
-                                audio_channel_mask_t channelMask,
-                                size_t *pFrameCount,
-                                audio_output_flags_t *flags,
-                                const sp<IMemory>& sharedBuffer,
-                                audio_io_handle_t output,
-                                pid_t pid,
-                                pid_t tid,
-                                audio_session_t *sessionId,
-                                int clientUid,
-                                status_t *status /*non-NULL*/,
-                                audio_port_handle_t portId);
+    virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
+                                        CreateTrackOutput& output,
+                                        status_t *status);
 
-    virtual sp<IAudioRecord> openRecord(
+    virtual sp<media::IAudioRecord> openRecord(
                                 audio_io_handle_t input,
                                 uint32_t sampleRate,
                                 audio_format_t format,
@@ -537,6 +526,13 @@
     };
 
     // --- PlaybackThread ---
+#ifdef FLOAT_EFFECT_CHAIN
+#define EFFECT_BUFFER_FORMAT AUDIO_FORMAT_PCM_FLOAT
+using effect_buffer_t = float;
+#else
+#define EFFECT_BUFFER_FORMAT AUDIO_FORMAT_PCM_16_BIT
+using effect_buffer_t = int16_t;
+#endif
 
 #include "Threads.h"
 
@@ -556,10 +552,10 @@
         virtual void        pause();
         virtual status_t    attachAuxEffect(int effectId);
         virtual status_t    setParameters(const String8& keyValuePairs);
-        virtual VolumeShaper::Status applyVolumeShaper(
-                const sp<VolumeShaper::Configuration>& configuration,
-                const sp<VolumeShaper::Operation>& operation) override;
-        virtual sp<VolumeShaper::State> getVolumeShaperState(int id) override;
+        virtual media::VolumeShaper::Status applyVolumeShaper(
+                const sp<media::VolumeShaper::Configuration>& configuration,
+                const sp<media::VolumeShaper::Operation>& operation) override;
+        virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) override;
         virtual status_t    getTimestamp(AudioTimestamp& timestamp);
         virtual void        signal(); // signal playback thread for a change in control block
 
@@ -571,15 +567,13 @@
     };
 
     // server side of the client's IAudioRecord
-    class RecordHandle : public android::BnAudioRecord {
+    class RecordHandle : public android::media::BnAudioRecord {
     public:
         explicit RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
         virtual             ~RecordHandle();
-        virtual status_t    start(int /*AudioSystem::sync_event_t*/ event,
-                audio_session_t triggerSession);
-        virtual void        stop();
-        virtual status_t onTransact(
-            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+        virtual binder::Status    start(int /*AudioSystem::sync_event_t*/ event,
+                int /*audio_session_t*/ triggerSession);
+        virtual binder::Status   stop();
     private:
         const sp<RecordThread::RecordTrack> mRecordTrack;
 
diff --git a/services/audioflinger/Configuration.h b/services/audioflinger/Configuration.h
index 845697a..bad46dc 100644
--- a/services/audioflinger/Configuration.h
+++ b/services/audioflinger/Configuration.h
@@ -41,4 +41,7 @@
 // uncomment to log CPU statistics every n wall clock seconds
 //#define DEBUG_CPU_USAGE 10
 
+// define FLOAT_EFFECT_CHAIN to request float effects (falls back to int16_t if unavailable)
+#define FLOAT_EFFECT_CHAIN
+
 #endif // ANDROID_AUDIOFLINGER_CONFIGURATION_H
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index bd5f146..e77907a 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -19,6 +19,8 @@
 #define LOG_TAG "AudioFlinger"
 //#define LOG_NDEBUG 0
 
+#include <algorithm>
+
 #include "Configuration.h"
 #include <utils/Log.h>
 #include <system/audio_effects/effect_aec.h>
@@ -47,8 +49,6 @@
 #define ALOGVV(a...) do { } while(0)
 #endif
 
-#define min(a, b) ((a) < (b) ? (a) : (b))
-
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -73,6 +73,9 @@
       // mDisableWaitCnt is set by process() and updateState() and not used before then
       mSuspended(false),
       mAudioFlinger(thread->mAudioFlinger)
+#ifdef FLOAT_EFFECT_CHAIN
+      , mSupportsFloat(false)
+#endif
 {
     ALOGV("Constructor %p pinned %d", this, pinned);
     int lStatus;
@@ -285,31 +288,114 @@
         return;
     }
 
+    // TODO: Implement multichannel effects; here outChannelCount == FCC_2 == 2
+    const uint32_t inChannelCount =
+            audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
+    const uint32_t outChannelCount =
+            audio_channel_count_from_out_mask(mConfig.outputCfg.channels);
+    const bool auxType =
+            (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY;
+
     if (isProcessEnabled()) {
-        // do 32 bit to 16 bit conversion for auxiliary effect input buffer
-        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
-            ditherAndClamp(mConfig.inputCfg.buffer.s32,
-                                        mConfig.inputCfg.buffer.s32,
-                                        mConfig.inputCfg.buffer.frameCount/2);
-        }
         int ret;
         if (isProcessImplemented()) {
-            // do the actual processing in the effect engine
+            if (auxType) {
+                // We overwrite the aux input buffer here and clear after processing.
+                // Note that aux input buffers are format q4_27.
+#ifdef FLOAT_EFFECT_CHAIN
+                if (mSupportsFloat) {
+                    // Do in-place float conversion for auxiliary effect input buffer.
+                    static_assert(sizeof(float) <= sizeof(int32_t),
+                            "in-place conversion requires sizeof(float) <= sizeof(int32_t)");
+
+                    const int32_t * const p32 = mConfig.inputCfg.buffer.s32;
+                    float * const pFloat = mConfig.inputCfg.buffer.f32;
+                    memcpy_to_float_from_q4_27(pFloat, p32, mConfig.inputCfg.buffer.frameCount);
+                } else {
+                    memcpy_to_i16_from_q4_27(mConfig.inputCfg.buffer.s16,
+                            mConfig.inputCfg.buffer.s32,
+                            mConfig.inputCfg.buffer.frameCount);
+                }
+#else
+                memcpy_to_i16_from_q4_27(mConfig.inputCfg.buffer.s16,
+                                            mConfig.inputCfg.buffer.s32,
+                                            mConfig.inputCfg.buffer.frameCount);
+#endif
+            }
+#ifdef FLOAT_EFFECT_CHAIN
+            if (mSupportsFloat) {
+                ret = mEffectInterface->process();
+            } else {
+                {   // convert input to int16_t as effect doesn't support float.
+                    if (!auxType) {
+                        if (mInBuffer16.get() == nullptr) {
+                            ALOGW("%s: mInBuffer16 is null, bypassing", __func__);
+                            goto data_bypass;
+                        }
+                        const float * const pIn = mInBuffer->audioBuffer()->f32;
+                        int16_t * const pIn16 = mInBuffer16->audioBuffer()->s16;
+                        memcpy_to_i16_from_float(
+                                pIn16, pIn, inChannelCount * mConfig.inputCfg.buffer.frameCount);
+                    }
+                    if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+                        if (mOutBuffer16.get() == nullptr) {
+                            ALOGW("%s: mOutBuffer16 is null, bypassing", __func__);
+                            goto data_bypass;
+                        }
+                        int16_t * const pOut16 = mOutBuffer16->audioBuffer()->s16;
+                        const float * const pOut = mOutBuffer->audioBuffer()->f32;
+                        memcpy_to_i16_from_float(
+                                pOut16,
+                                pOut,
+                                outChannelCount * mConfig.outputCfg.buffer.frameCount);
+                    }
+                }
+
+                ret = mEffectInterface->process();
+
+                {   // convert output back to float.
+                    const int16_t * const pOut16 = mOutBuffer16->audioBuffer()->s16;
+                    float * const pOut = mOutBuffer->audioBuffer()->f32;
+                    memcpy_to_float_from_i16(
+                            pOut, pOut16, outChannelCount * mConfig.outputCfg.buffer.frameCount);
+                }
+            }
+#else
             ret = mEffectInterface->process();
+#endif
         } else {
-            if (mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
-                size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2;  //always stereo here
-                int16_t *in = mConfig.inputCfg.buffer.s16;
-                int16_t *out = mConfig.outputCfg.buffer.s16;
+#ifdef FLOAT_EFFECT_CHAIN
+            data_bypass:
+#endif
+            if (!auxType  /* aux effects do not require data bypass */
+                    && mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw
+                    && inChannelCount == outChannelCount) {
+                const size_t sampleCount = std::min(
+                        mConfig.inputCfg.buffer.frameCount,
+                        mConfig.outputCfg.buffer.frameCount) * outChannelCount;
+
+#ifdef FLOAT_EFFECT_CHAIN
+                const float * const in = mConfig.inputCfg.buffer.f32;
+                float * const out = mConfig.outputCfg.buffer.f32;
 
                 if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
-                    for (size_t i = 0; i < frameCnt; i++) {
-                        out[i] = clamp16((int32_t)out[i] + (int32_t)in[i]);
-                    }
+                    accumulate_float(out, in, sampleCount);
                 } else {
-                    memcpy(mConfig.outputCfg.buffer.raw, mConfig.inputCfg.buffer.raw,
-                           frameCnt * sizeof(int16_t));
+                    memcpy(mConfig.outputCfg.buffer.f32, mConfig.inputCfg.buffer.f32,
+                            sampleCount * sizeof(*mConfig.outputCfg.buffer.f32));
                 }
+
+#else
+                const int16_t * const in = mConfig.inputCfg.buffer.s16;
+                int16_t * const out = mConfig.outputCfg.buffer.s16;
+
+                if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+                    accumulate_i16(out, in, sampleCount);
+                } else {
+                    memcpy(mConfig.outputCfg.buffer.s16, mConfig.inputCfg.buffer.s16,
+                            sampleCount * sizeof(*mConfig.outputCfg.buffer.s16));
+                }
+#endif
             }
             ret = -ENODATA;
         }
@@ -319,22 +405,33 @@
         }
 
         // clear auxiliary effect input buffer for next accumulation
-        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
-            memset(mConfig.inputCfg.buffer.raw, 0,
-                   mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
+        if (auxType) {
+            // input always q4_27 regardless of FLOAT_EFFECT_CHAIN.
+            const size_t size =
+                    mConfig.inputCfg.buffer.frameCount * inChannelCount * sizeof(int32_t);
+            memset(mConfig.inputCfg.buffer.raw, 0, size);
         }
     } else if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT &&
+                // mInBuffer->audioBuffer()->raw != mOutBuffer->audioBuffer()->raw
                 mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
         // If an insert effect is idle and input buffer is different from output buffer,
         // accumulate input onto output
         sp<EffectChain> chain = mChain.promote();
-        if (chain != 0 && chain->activeTrackCnt() != 0) {
-            size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2;  //always stereo here
-            int16_t *in = mConfig.inputCfg.buffer.s16;
-            int16_t *out = mConfig.outputCfg.buffer.s16;
-            for (size_t i = 0; i < frameCnt; i++) {
-                out[i] = clamp16((int32_t)out[i] + (int32_t)in[i]);
-            }
+        if (chain != 0
+                && chain->activeTrackCnt() != 0
+                && inChannelCount == outChannelCount) {
+            const size_t sampleCount = std::min(
+                    mConfig.inputCfg.buffer.frameCount,
+                    mConfig.outputCfg.buffer.frameCount) * outChannelCount;
+#ifdef FLOAT_EFFECT_CHAIN
+            const float * const in = mConfig.inputCfg.buffer.f32;
+            float * const out = mConfig.outputCfg.buffer.f32;
+            accumulate_float(out, in, sampleCount);
+#else
+            const int16_t * const in = mConfig.inputCfg.buffer.s16;
+            int16_t * const out = mConfig.outputCfg.buffer.s16;
+            accumulate_i16(out, in, sampleCount);
+#endif
         }
     }
 }
@@ -349,6 +446,7 @@
 
 status_t AudioFlinger::EffectModule::configure()
 {
+    ALOGVV("configure() started");
     status_t status;
     sp<ThreadBase> thread;
     uint32_t size;
@@ -384,8 +482,8 @@
         }
     }
 
-    mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
-    mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    mConfig.inputCfg.format = EFFECT_BUFFER_FORMAT;
+    mConfig.outputCfg.format = EFFECT_BUFFER_FORMAT;
     mConfig.inputCfg.samplingRate = thread->sampleRate();
     mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate;
     mConfig.inputCfg.bufferProvider.cookie = NULL;
@@ -413,12 +511,6 @@
     mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
     mConfig.inputCfg.buffer.frameCount = thread->frameCount();
     mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
-    if (mInBuffer != 0) {
-        mInBuffer->setFrameCount(mConfig.inputCfg.buffer.frameCount);
-    }
-    if (mOutBuffer != 0) {
-        mOutBuffer->setFrameCount(mConfig.outputCfg.buffer.frameCount);
-    }
 
     ALOGV("configure() %p thread %p buffer %p framecount %zu",
             this, thread.get(), mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
@@ -430,32 +522,60 @@
                                        &mConfig,
                                        &size,
                                        &cmdStatus);
-    if (status == 0) {
+    if (status == NO_ERROR) {
         status = cmdStatus;
+#ifdef FLOAT_EFFECT_CHAIN
+        mSupportsFloat = true;
+#endif
     }
-
-    if (status == 0 &&
-            (memcmp(&mDescriptor.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0)) {
-        uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
-        effect_param_t *p = (effect_param_t *)buf32;
-
-        p->psize = sizeof(uint32_t);
-        p->vsize = sizeof(uint32_t);
-        size = sizeof(int);
-        *(int32_t *)p->data = VISUALIZER_PARAM_LATENCY;
-
-        uint32_t latency = 0;
-        PlaybackThread *pbt = thread->mAudioFlinger->checkPlaybackThread_l(thread->mId);
-        if (pbt != NULL) {
-            latency = pbt->latency_l();
+#ifdef FLOAT_EFFECT_CHAIN
+    else {
+        ALOGV("EFFECT_CMD_SET_CONFIG failed with float format, retry with int16_t.");
+        mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+        mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+        status = mEffectInterface->command(EFFECT_CMD_SET_CONFIG,
+                                           sizeof(effect_config_t),
+                                           &mConfig,
+                                           &size,
+                                           &cmdStatus);
+        if (status == NO_ERROR) {
+            status = cmdStatus;
+            mSupportsFloat = false;
+            ALOGVV("config worked with 16 bit");
+        } else {
+            ALOGE("%s failed %d with int16_t (as well as float)", __func__, status);
         }
+    }
+#endif
 
-        *((int32_t *)p->data + 1)= latency;
-        mEffectInterface->command(EFFECT_CMD_SET_PARAM,
-                                  sizeof(effect_param_t) + 8,
-                                  &buf32,
-                                  &size,
-                                  &cmdStatus);
+    if (status == NO_ERROR) {
+        // Establish Buffer strategy
+        setInBuffer(mInBuffer);
+        setOutBuffer(mOutBuffer);
+
+        // Update visualizer latency
+        if (memcmp(&mDescriptor.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) {
+            uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+            effect_param_t *p = (effect_param_t *)buf32;
+
+            p->psize = sizeof(uint32_t);
+            p->vsize = sizeof(uint32_t);
+            size = sizeof(int);
+            *(int32_t *)p->data = VISUALIZER_PARAM_LATENCY;
+
+            uint32_t latency = 0;
+            PlaybackThread *pbt = thread->mAudioFlinger->checkPlaybackThread_l(thread->mId);
+            if (pbt != NULL) {
+                latency = pbt->latency_l();
+            }
+
+            *((int32_t *)p->data + 1)= latency;
+            mEffectInterface->command(EFFECT_CMD_SET_PARAM,
+                    sizeof(effect_param_t) + 8,
+                    &buf32,
+                    &size,
+                    &cmdStatus);
+        }
     }
 
     mMaxDisableWaitCnt = (MAX_DISABLE_TIME_MS * mConfig.outputCfg.samplingRate) /
@@ -463,6 +583,7 @@
 
 exit:
     mStatus = status;
+    ALOGVV("configure ended");
     return status;
 }
 
@@ -774,6 +895,7 @@
 }
 
 void AudioFlinger::EffectModule::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
+    ALOGVV("setInBuffer %p",(&buffer));
     if (buffer != 0) {
         mConfig.inputCfg.buffer.raw = buffer->audioBuffer()->raw;
         buffer->setFrameCount(mConfig.inputCfg.buffer.frameCount);
@@ -781,10 +903,43 @@
         mConfig.inputCfg.buffer.raw = NULL;
     }
     mInBuffer = buffer;
-    mEffectInterface->setInBuffer(buffer);
+    if (buffer != nullptr) { // FIXME: EffectHalHidl::setInBuffer should accept null input.
+        mEffectInterface->setInBuffer(buffer);
+    }
+
+#ifdef FLOAT_EFFECT_CHAIN
+    // aux effects do in place conversion to float - we don't allocate mInBuffer16 for them.
+    // Theoretically insert effects can also do in-place conversions (destroying
+    // the original buffer) when the output buffer is identical to the input buffer,
+    // but we don't optimize for it here.
+    const bool auxType = (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY;
+    if (!auxType && !mSupportsFloat && mInBuffer.get() != nullptr) {
+        // we need to translate - create hidl shared buffer and intercept
+        const size_t inFrameCount = mConfig.inputCfg.buffer.frameCount;
+        const int inChannels = audio_channel_count_from_out_mask(mConfig.inputCfg.channels);
+        const size_t size = inChannels * inFrameCount * sizeof(int16_t);
+
+        ALOGV("%s: setInBuffer updating for inChannels:%d inFrameCount:%zu total size:%zu",
+                __func__, inChannels, inFrameCount, size);
+
+        if (size > 0 && (mInBuffer16.get() == nullptr || size > mInBuffer16->getSize())) {
+            mInBuffer16.clear();
+            ALOGV("%s: allocating mInBuffer16 %zu", __func__, size);
+            (void)EffectBufferHalInterface::allocate(size, &mInBuffer16);
+        }
+        if (mInBuffer16.get() != nullptr) {
+            // FIXME: confirm buffer has enough size.
+            mInBuffer16->setFrameCount(inFrameCount);
+            mEffectInterface->setInBuffer(mInBuffer16);
+        } else if (size > 0) {
+            ALOGE("%s cannot create mInBuffer16", __func__);
+        }
+    }
+#endif
 }
 
 void AudioFlinger::EffectModule::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
+    ALOGVV("setOutBuffer %p",(&buffer));
     if (buffer != 0) {
         mConfig.outputCfg.buffer.raw = buffer->audioBuffer()->raw;
         buffer->setFrameCount(mConfig.outputCfg.buffer.frameCount);
@@ -792,7 +947,34 @@
         mConfig.outputCfg.buffer.raw = NULL;
     }
     mOutBuffer = buffer;
-    mEffectInterface->setOutBuffer(buffer);
+    if (buffer != nullptr) {
+        mEffectInterface->setOutBuffer(buffer);
+    }
+
+#ifdef FLOAT_EFFECT_CHAIN
+    // Note: Any effect that does not accumulate does not need mOutBuffer16 and
+    // can do in-place conversion from int16_t to float.  We don't optimize here.
+    if (!mSupportsFloat && mOutBuffer.get() != nullptr) {
+        const size_t outFrameCount = mConfig.outputCfg.buffer.frameCount;
+        const int outChannels = audio_channel_count_from_out_mask(mConfig.outputCfg.channels);
+        const size_t size = outChannels * outFrameCount * sizeof(int16_t);
+
+        ALOGV("%s: setOutBuffer updating for outChannels:%d outFrameCount:%zu total size:%zu",
+                __func__, outChannels, outFrameCount, size);
+
+        if (size > 0 && (mOutBuffer16.get() == nullptr || size > mOutBuffer16->getSize())) {
+            mOutBuffer16.clear();
+            ALOGV("%s: allocating mOutBuffer16 %zu", __func__, size);
+            (void)EffectBufferHalInterface::allocate(size, &mOutBuffer16);
+        }
+        if (mOutBuffer16.get() != nullptr) {
+            mOutBuffer16->setFrameCount(outFrameCount);
+            mEffectInterface->setOutBuffer(mOutBuffer16);
+        } else if (size > 0) {
+            ALOGE("%s cannot create mOutBuffer16", __func__);
+        }
+    }
+#endif
 }
 
 status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
@@ -1126,6 +1308,22 @@
             formatToString((audio_format_t)mConfig.outputCfg.format).c_str());
     result.append(buffer);
 
+#ifdef FLOAT_EFFECT_CHAIN
+    if (!mSupportsFloat) {
+        int16_t* pIn16 = mInBuffer16 != 0 ? mInBuffer16->audioBuffer()->s16 : NULL;
+        int16_t* pOut16 = mOutBuffer16 != 0 ? mOutBuffer16->audioBuffer()->s16 : NULL;
+
+        result.append("\t\t- Float and int16 buffers\n");
+        result.append("\t\t\tIn_float   In_int16   Out_float  Out_int16\n");
+        snprintf(buffer, SIZE,"\t\t\t%p %p %p %p\n",
+                mConfig.inputCfg.buffer.raw,
+                pIn16,
+                pOut16,
+                mConfig.outputCfg.buffer.raw);
+        result.append(buffer);
+    }
+#endif
+
     snprintf(buffer, SIZE, "\t\t%zu Clients:\n", mHandles.size());
     result.append(buffer);
     result.append("\t\t\t  Pid Priority Ctrl Locked client server\n");
@@ -1602,8 +1800,11 @@
     // and sample format changes for effects.
     // Currently effects processing is only available for stereo, AUDIO_FORMAT_PCM_16_BIT
     // (4 bytes frame size)
+
     const size_t frameSize =
-            audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT) * min(FCC_2, thread->channelCount());
+            audio_bytes_per_sample(EFFECT_BUFFER_FORMAT)
+            * std::min((uint32_t)FCC_2, thread->channelCount());
+
     memset(mInBuffer->audioBuffer()->raw, 0, thread->frameCount() * frameSize);
     mInBuffer->commit();
 }
@@ -1718,8 +1919,13 @@
         // calling the process in effect engine
         size_t numSamples = thread->frameCount();
         sp<EffectBufferHalInterface> halBuffer;
+#ifdef FLOAT_EFFECT_CHAIN
+        status_t result = EffectBufferHalInterface::allocate(
+                numSamples * sizeof(float), &halBuffer);
+#else
         status_t result = EffectBufferHalInterface::allocate(
                 numSamples * sizeof(int32_t), &halBuffer);
+#endif
         if (result != OK) return result;
         effect->setInBuffer(halBuffer);
         // auxiliary effects output samples to chain input buffer for further processing
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index e29798b..1864e0f 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -168,6 +168,12 @@
     bool     mSuspended;            // effect is suspended: temporarily disabled by framework
     bool     mOffloaded;            // effect is currently offloaded to the audio DSP
     wp<AudioFlinger>    mAudioFlinger;
+
+#ifdef FLOAT_EFFECT_CHAIN
+    bool    mSupportsFloat;         // effect supports float processing
+    sp<EffectBufferHalInterface> mInBuffer16;  // Buffers for interacting with HAL at 16 bits
+    sp<EffectBufferHalInterface> mOutBuffer16;
+#endif
 };
 
 // The EffectHandle class implements the IEffect interface. It provides resources
@@ -308,14 +314,14 @@
     void setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
         mInBuffer = buffer;
     }
-    int16_t *inBuffer() const {
-        return mInBuffer != 0 ? reinterpret_cast<int16_t*>(mInBuffer->ptr()) : NULL;
+    effect_buffer_t *inBuffer() const {
+        return mInBuffer != 0 ? reinterpret_cast<effect_buffer_t*>(mInBuffer->ptr()) : NULL;
     }
     void setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
         mOutBuffer = buffer;
     }
-    int16_t *outBuffer() const {
-        return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
+    effect_buffer_t *outBuffer() const {
+        return mOutBuffer != 0 ? reinterpret_cast<effect_buffer_t*>(mOutBuffer->ptr()) : NULL;
     }
 
     void incTrackCnt() { android_atomic_inc(&mTrackCnt); }
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index c10fa05..ace586c 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -138,8 +138,6 @@
 
 void FastMixer::onStateChange()
 {
-    // log that audio was turned on/off
-    LOG_AUDIO_STATE();
     const FastMixerState * const current = (const FastMixerState *) mCurrent;
     const FastMixerState * const previous = (const FastMixerState *) mPrevious;
     FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;
@@ -336,7 +334,13 @@
 
 void FastMixer::onWork()
 {
-    LOG_HIST_TS();
+    // TODO: pass an ID parameter to indicate which time series we want to write to in NBLog.cpp
+    // Or: pass both of these into a single call with a boolean
+    if (mIsWarm) {
+        LOG_HIST_TS();
+    } else {
+        LOG_AUDIO_STATE();
+    }
     const FastMixerState * const current = (const FastMixerState *) mCurrent;
     FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;
     const FastMixerState::Command command = mCommand;
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index 5a55c7a..2be1e91 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -21,7 +21,7 @@
 #include <system/audio.h>
 #include <media/ExtendedAudioBufferProvider.h>
 #include <media/nbaio/NBAIO.h>
-#include <media/nbaio/NBLog.h>
+#include <media/nblog/NBLog.h>
 #include "FastThreadState.h"
 
 namespace android {
diff --git a/services/audioflinger/FastThreadState.h b/services/audioflinger/FastThreadState.h
index f18f846..54c0dc6 100644
--- a/services/audioflinger/FastThreadState.h
+++ b/services/audioflinger/FastThreadState.h
@@ -19,7 +19,7 @@
 
 #include "Configuration.h"
 #include <stdint.h>
-#include <media/nbaio/NBLog.h>
+#include <media/nblog/NBLog.h>
 
 namespace android {
 
diff --git a/services/audioflinger/OWNERS b/services/audioflinger/OWNERS
index 703e4d2..d02d9e0 100644
--- a/services/audioflinger/OWNERS
+++ b/services/audioflinger/OWNERS
@@ -1,3 +1,4 @@
 hunga@google.com
 jmtrivi@google.com
 mnaganov@google.com
+gkasten@google.com
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 1c1a989..e97bb06 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -68,8 +68,8 @@
             status_t    attachAuxEffect(int EffectId);
             void        setAuxBuffer(int EffectId, int32_t *buffer);
             int32_t     *auxBuffer() const { return mAuxBuffer; }
-            void        setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; }
-            int16_t     *mainBuffer() const { return mMainBuffer; }
+            void        setMainBuffer(effect_buffer_t *buffer) { mMainBuffer = buffer; }
+            effect_buffer_t *mainBuffer() const { return mMainBuffer; }
             int         auxEffectId() const { return mAuxEffectId; }
     virtual status_t    getTimestamp(AudioTimestamp& timestamp);
             void        signal();
@@ -82,11 +82,11 @@
     virtual bool        isFastTrack() const { return (mFlags & AUDIO_OUTPUT_FLAG_FAST) != 0; }
 
 // implement volume handling.
-   VolumeShaper::Status applyVolumeShaper(
-                                const sp<VolumeShaper::Configuration>& configuration,
-                                const sp<VolumeShaper::Operation>& operation);
-sp<VolumeShaper::State> getVolumeShaperState(int id);
-    sp<VolumeHandler>   getVolumeHandler() { return mVolumeHandler; }
+    media::VolumeShaper::Status applyVolumeShaper(
+                                const sp<media::VolumeShaper::Configuration>& configuration,
+                                const sp<media::VolumeShaper::Operation>& operation);
+    sp<media::VolumeShaper::State> getVolumeShaperState(int id);
+    sp<media::VolumeHandler>   getVolumeHandler() { return mVolumeHandler; }
 
 protected:
     // for numerous
@@ -150,7 +150,8 @@
                                     // allocated statically at track creation time,
                                     // and is even allocated (though unused) for fast tracks
                                     // FIXME don't allocate track name for fast tracks
-    int16_t             *mMainBuffer;
+    effect_buffer_t     *mMainBuffer;
+
     int32_t             *mAuxBuffer;
     int                 mAuxEffectId;
     bool                mHasVolumeController;
@@ -163,7 +164,7 @@
 
     ExtendedTimestamp  mSinkTimestamp;
 
-    sp<VolumeHandler>  mVolumeHandler; // handles multiple VolumeShaper configs and operations
+    sp<media::VolumeHandler>  mVolumeHandler; // handles multiple VolumeShaper configs and operations
 
 private:
     // The following fields are only for fast tracks, and should be in a subclass
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index e202ca4..b2a1e18 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1837,10 +1837,13 @@
 sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
         const sp<AudioFlinger::Client>& client,
         audio_stream_type_t streamType,
-        uint32_t sampleRate,
+        uint32_t *pSampleRate,
         audio_format_t format,
         audio_channel_mask_t channelMask,
         size_t *pFrameCount,
+        size_t *pNotificationFrameCount,
+        uint32_t notificationsPerBuffer,
+        float speed,
         const sp<IMemory>& sharedBuffer,
         audio_session_t sessionId,
         audio_output_flags_t *flags,
@@ -1850,9 +1853,16 @@
         audio_port_handle_t portId)
 {
     size_t frameCount = *pFrameCount;
+    size_t notificationFrameCount = *pNotificationFrameCount;
     sp<Track> track;
     status_t lStatus;
     audio_output_flags_t outputFlags = mOutput->flags;
+    audio_output_flags_t requestedFlags = *flags;
+
+    if (*pSampleRate == 0) {
+        *pSampleRate = mSampleRate;
+    }
+    uint32_t sampleRate = *pSampleRate;
 
     // special case for FAST flag considered OK if fast mixer is present
     if (hasFastMixer()) {
@@ -1929,36 +1939,114 @@
         *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST);
       }
     }
-    // For normal PCM streaming tracks, update minimum frame count.
-    // For compatibility with AudioTrack calculation, buffer depth is forced
-    // to be at least 2 x the normal mixer frame count and cover audio hardware latency.
-    // This is probably too conservative, but legacy application code may depend on it.
-    // If you change this calculation, also review the start threshold which is related.
-    if (!(*flags & AUDIO_OUTPUT_FLAG_FAST)
-            && audio_has_proportional_frames(format) && sharedBuffer == 0) {
-        // this must match AudioTrack.cpp calculateMinFrameCount().
-        // TODO: Move to a common library
-        uint32_t latencyMs = 0;
-        lStatus = mOutput->stream->getLatency(&latencyMs);
-        if (lStatus != OK) {
-            ALOGE("Error when retrieving output stream latency: %d", lStatus);
+
+    if (!audio_has_proportional_frames(format)) {
+        if (sharedBuffer != 0) {
+            // Same comment as below about ignoring frameCount parameter for set()
+            frameCount = sharedBuffer->size();
+        } else if (frameCount == 0) {
+            frameCount = mNormalFrameCount;
+        }
+        if (notificationFrameCount != frameCount) {
+            notificationFrameCount = frameCount;
+        }
+    } else if (sharedBuffer != 0) {
+        // FIXME: Ensure client side memory buffers need
+        // not have additional alignment beyond sample
+        // (e.g. 16 bit stereo accessed as 32 bit frame).
+        size_t alignment = audio_bytes_per_sample(format);
+        if (alignment & 1) {
+            // for AUDIO_FORMAT_PCM_24_BIT_PACKED (not exposed through Java).
+            alignment = 1;
+        }
+        uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
+        size_t frameSize = channelCount * audio_bytes_per_sample(format);
+        if (channelCount > 1) {
+            // More than 2 channels does not require stronger alignment than stereo
+            alignment <<= 1;
+        }
+        if (((uintptr_t)sharedBuffer->pointer() & (alignment - 1)) != 0) {
+            ALOGE("Invalid buffer alignment: address %p, channel count %u",
+                  sharedBuffer->pointer(), channelCount);
+            lStatus = BAD_VALUE;
             goto Exit;
         }
-        uint32_t minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate);
-        if (minBufCount < 2) {
-            minBufCount = 2;
+
+        // 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() / frameSize;
+    } else {
+        size_t minFrameCount = 0;
+        // For fast tracks we try to respect the application's request for notifications per buffer.
+        if (*flags & AUDIO_OUTPUT_FLAG_FAST) {
+            if (notificationsPerBuffer > 0) {
+                // Avoid possible arithmetic overflow during multiplication.
+                if (notificationsPerBuffer > SIZE_MAX / mFrameCount) {
+                    ALOGE("Requested notificationPerBuffer=%u ignored for HAL frameCount=%zu",
+                          notificationsPerBuffer, mFrameCount);
+                } else {
+                    minFrameCount = mFrameCount * notificationsPerBuffer;
+                }
+            }
+        } else {
+            // For normal PCM streaming tracks, update minimum frame count.
+            // Buffer depth is forced to be at least 2 x the normal mixer frame count and
+            // cover audio hardware latency.
+            // This is probably too conservative, but legacy application code may depend on it.
+            // If you change this calculation, also review the start threshold which is related.
+            uint32_t latencyMs = latency_l();
+            if (latencyMs == 0) {
+                ALOGE("Error when retrieving output stream latency");
+                lStatus = UNKNOWN_ERROR;
+                goto Exit;
+            }
+
+            minFrameCount = AudioSystem::calculateMinFrameCount(latencyMs, mNormalFrameCount,
+                                mSampleRate, sampleRate, speed /*, 0 mNotificationsPerBufferReq*/);
+
         }
-        // For normal mixing tracks, if speed is > 1.0f (normal), AudioTrack
-        // or the client should compute and pass in a larger buffer request.
-        size_t minFrameCount =
-                minBufCount * sourceFramesNeededWithTimestretch(
-                        sampleRate, mNormalFrameCount,
-                        mSampleRate, AUDIO_TIMESTRETCH_SPEED_NORMAL /*speed*/);
-        if (frameCount < minFrameCount) { // including frameCount == 0
+        if (frameCount < minFrameCount) {
             frameCount = minFrameCount;
         }
     }
+
+    // Make sure that application is notified with sufficient margin before underrun.
+    // The client can divide the AudioTrack buffer into sub-buffers,
+    // and expresses its desire to server as the notification frame count.
+    if (sharedBuffer == 0 && audio_is_linear_pcm(format)) {
+        size_t maxNotificationFrames;
+        if (*flags & AUDIO_OUTPUT_FLAG_FAST) {
+            // notify every HAL buffer, regardless of the size of the track buffer
+            maxNotificationFrames = mFrameCount;
+        } else {
+            // For normal tracks, use at least double-buffering if no sample rate conversion,
+            // or at least triple-buffering if there is sample rate conversion
+            const int nBuffering = sampleRate == mSampleRate ? 2 : 3;
+            maxNotificationFrames = frameCount / nBuffering;
+            // If client requested a fast track but this was denied, then use the smaller maximum.
+            if (requestedFlags & AUDIO_OUTPUT_FLAG_FAST) {
+                size_t maxNotificationFramesFastDenied = FMS_20 * sampleRate / 1000;
+                if (maxNotificationFrames > maxNotificationFramesFastDenied) {
+                    maxNotificationFrames = maxNotificationFramesFastDenied;
+                }
+            }
+        }
+        if (notificationFrameCount == 0 || notificationFrameCount > maxNotificationFrames) {
+            if (notificationFrameCount == 0) {
+                ALOGD("Client defaulted notificationFrames to %zu for frameCount %zu",
+                    maxNotificationFrames, frameCount);
+            } else {
+                ALOGW("Client adjusted notificationFrames from %zu to %zu for frameCount %zu",
+                      notificationFrameCount, maxNotificationFrames, frameCount);
+            }
+            notificationFrameCount = maxNotificationFrames;
+        }
+    }
+
     *pFrameCount = frameCount;
+    *pNotificationFrameCount = notificationFrameCount;
 
     switch (mType) {
 
@@ -2449,7 +2537,7 @@
     free(mEffectBuffer);
     mEffectBuffer = NULL;
     if (mEffectBufferEnabled) {
-        mEffectBufferFormat = AUDIO_FORMAT_PCM_16_BIT; // Note: Effects support 16b only
+        mEffectBufferFormat = EFFECT_BUFFER_FORMAT;
         mEffectBufferSize = mNormalFrameCount * mChannelCount
                 * audio_bytes_per_sample(mEffectBufferFormat);
         (void)posix_memalign(&mEffectBuffer, 32, mEffectBufferSize);
@@ -2638,6 +2726,7 @@
 // shared by MIXER and DIRECT, overridden by DUPLICATING
 ssize_t AudioFlinger::PlaybackThread::threadLoop_write()
 {
+    LOG_HIST_TS();
     mInWrite = true;
     ssize_t bytesWritten;
     const size_t offset = mCurrentWriteLength - mBytesRemaining;
@@ -2795,8 +2884,7 @@
             &halInBuffer);
     if (result != OK) return result;
     halOutBuffer = halInBuffer;
-    int16_t *buffer = reinterpret_cast<int16_t*>(halInBuffer->externalData());
-
+    effect_buffer_t *buffer = reinterpret_cast<effect_buffer_t*>(halInBuffer->externalData());
     ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
     if (session > AUDIO_SESSION_OUTPUT_MIX) {
         // Only one effect chain can be present in direct output thread and it uses
@@ -2804,10 +2892,14 @@
         if (mType != DIRECT) {
             size_t numSamples = mNormalFrameCount * mChannelCount;
             status_t result = EffectBufferHalInterface::allocate(
-                    numSamples * sizeof(int16_t),
+                    numSamples * sizeof(effect_buffer_t),
                     &halInBuffer);
             if (result != OK) return result;
+#ifdef FLOAT_EFFECT_CHAIN
+            buffer = halInBuffer->audioBuffer()->f32;
+#else
             buffer = halInBuffer->audioBuffer()->s16;
+#endif
             ALOGV("addEffectChain_l() creating new input buffer %p session %d",
                     buffer, session);
         }
@@ -2882,7 +2974,7 @@
             for (size_t i = 0; i < mTracks.size(); ++i) {
                 sp<Track> track = mTracks[i];
                 if (session == track->sessionId()) {
-                    track->setMainBuffer(reinterpret_cast<int16_t*>(mSinkBuffer));
+                    track->setMainBuffer(reinterpret_cast<effect_buffer_t*>(mSinkBuffer));
                     chain->decTrackCnt();
                 }
             }
@@ -3116,6 +3208,10 @@
 
                     threadLoop_standby();
 
+                    // This is where we go into standby
+                    if (!mStandby) {
+                        LOG_AUDIO_STATE();
+                    }
                     mStandby = true;
                 }
 
@@ -3307,10 +3403,14 @@
                         // 2. threadLoop_mix (significant for heavy mixing, especially
                         //                    on low tier processors)
 
-                        // it's OK if deltaMs is an overestimate.
-                        const int32_t deltaMs =
-                                (lastWriteFinished - previousLastWriteFinished) / 1000000;
-                        const int32_t throttleMs = mHalfBufferMs - deltaMs;
+                        // it's OK if deltaMs (and deltaNs) is an overestimate.
+                        nsecs_t deltaNs;
+                        // deltaNs = lastWriteFinished - previousLastWriteFinished;
+                        __builtin_sub_overflow(
+                            lastWriteFinished,previousLastWriteFinished, &deltaNs);
+                        const int32_t deltaMs = deltaNs / 1000000;
+
+                        const int32_t throttleMs = (int32_t)mHalfBufferMs - deltaMs;
                         if ((signed)mHalfBufferMs >= throttleMs && throttleMs > 0) {
                             usleep(throttleMs * 1000);
                             // notify of throttle start on verbose log
@@ -4457,7 +4557,7 @@
                 mAudioMixer->setParameter(
                         name,
                         AudioMixer::TRACK,
-                        AudioMixer::MIXER_FORMAT, (void *)AUDIO_FORMAT_PCM_16_BIT);
+                        AudioMixer::MIXER_FORMAT, (void *)EFFECT_BUFFER_FORMAT);
                 mAudioMixer->setParameter(
                         name,
                         AudioMixer::TRACK,
@@ -5449,7 +5549,7 @@
         mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true),
         mOffloadUnderrunPosition(~0LL)
 {
-    //FIXME: mStandby should be set to true by ThreadBase constructor
+    //FIXME: mStandby should be set to true by ThreadBase constructo
     mStandby = true;
     mKeepWakeLock = property_get_bool("ro.audio.offload_wakelock", true /* default_value */);
 }
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index dd2b89b..c7b60d6 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -485,6 +485,7 @@
                 // Updated by updateSuspendedSessions_l() only.
                 KeyedVector< audio_session_t, KeyedVector< int, sp<SuspendedSessionDesc> > >
                                         mSuspendedSessions;
+                // TODO: add comment and adjust size as needed
                 static const size_t     kLogSize = 4 * 1024;
                 sp<NBLog::Writer>       mNBLogWriter;
                 bool                    mSystemReady;
@@ -705,10 +706,13 @@
                 sp<Track>   createTrack_l(
                                 const sp<AudioFlinger::Client>& client,
                                 audio_stream_type_t streamType,
-                                uint32_t sampleRate,
+                                uint32_t *sampleRate,
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
                                 size_t *pFrameCount,
+                                size_t *pNotificationFrameCount,
+                                uint32_t notificationsPerBuffer,
+                                float speed,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_session_t sessionId,
                                 audio_output_flags_t *flags,
@@ -737,11 +741,10 @@
     virtual     String8     getParameters(const String8& keys);
     virtual     void        ioConfigChanged(audio_io_config_event event, pid_t pid = 0);
                 status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
-                // 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); };
+                effect_buffer_t *sinkBuffer() const {
+                    return reinterpret_cast<effect_buffer_t *>(mSinkBuffer); };
 
     virtual     void detachAuxEffect_l(int effectId);
                 status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track>& track,
@@ -984,6 +987,7 @@
     sp<NBAIO_Source>        mTeeSource;
 #endif
     uint32_t                mScreenState;   // cached copy of gScreenState
+    // TODO: add comment and adjust size as needed
     static const size_t     kFastMixerLogSize = 8 * 1024;
     sp<NBLog::Writer>       mFastMixerNBLogWriter;
 
@@ -1456,6 +1460,7 @@
             // If a fast capture is present, the Pipe as IMemory, otherwise clear
             sp<IMemory>                         mPipeMemory;
 
+            // TODO: add comment and adjust size as needed
             static const size_t                 kFastCaptureLogSize = 4 * 1024;
             sp<NBLog::Writer>                   mFastCaptureNBLogWriter;
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 0f25153..1445572 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -52,6 +52,7 @@
 
 namespace android {
 
+using media::VolumeShaper;
 // ----------------------------------------------------------------------------
 //      TrackBase
 // ----------------------------------------------------------------------------
@@ -394,12 +395,12 @@
     mSharedBuffer(sharedBuffer),
     mStreamType(streamType),
     mName(-1),  // see note below
-    mMainBuffer(thread->mixBuffer()),
+    mMainBuffer(thread->sinkBuffer()),
     mAuxBuffer(NULL),
     mAuxEffectId(0), mHasVolumeController(false),
     mPresentationCompleteFrames(0),
     mFrameMap(16 /* sink-frame-to-track-frame map memory */),
-    mVolumeHandler(new VolumeHandler(sampleRate)),
+    mVolumeHandler(new media::VolumeHandler(sampleRate)),
     // mSinkTimestamp
     mFastIndex(-1),
     mCachedVolume(1.0),
@@ -1561,14 +1562,16 @@
     mRecordTrack->destroy();
 }
 
-status_t AudioFlinger::RecordHandle::start(int /*AudioSystem::sync_event_t*/ event,
-        audio_session_t triggerSession) {
+binder::Status AudioFlinger::RecordHandle::start(int /*AudioSystem::sync_event_t*/ event,
+        int /*audio_session_t*/ triggerSession) {
     ALOGV("RecordHandle::start()");
-    return mRecordTrack->start((AudioSystem::sync_event_t)event, triggerSession);
+    return binder::Status::fromStatusT(
+        mRecordTrack->start((AudioSystem::sync_event_t)event, (audio_session_t) triggerSession));
 }
 
-void AudioFlinger::RecordHandle::stop() {
+binder::Status AudioFlinger::RecordHandle::stop() {
     stop_nonvirtual();
+    return binder::Status::ok();
 }
 
 void AudioFlinger::RecordHandle::stop_nonvirtual() {
@@ -1576,12 +1579,6 @@
     mRecordTrack->stop();
 }
 
-status_t AudioFlinger::RecordHandle::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    return BnAudioRecord::onTransact(code, data, reply, flags);
-}
-
 // ----------------------------------------------------------------------------
 
 // RecordTrack constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
diff --git a/services/audioflinger/TypedLogger.h b/services/audioflinger/TypedLogger.h
index 909af09..38c3c02 100644
--- a/services/audioflinger/TypedLogger.h
+++ b/services/audioflinger/TypedLogger.h
@@ -18,7 +18,9 @@
 #ifndef ANDROID_TYPED_LOGGER_H
 #define ANDROID_TYPED_LOGGER_H
 
-#include <media/nbaio/NBLog.h>
+// This is the client API for the typed logger.
+
+#include <media/nblog/NBLog.h>
 #include <algorithm>
 
 /*
@@ -62,7 +64,8 @@
 }
 
 template <typename T, size_t n>
-constexpr T fnv1a(const char (&file)[n], int i = n - 1) {
+__attribute__((no_sanitize("unsigned-integer-overflow")))
+constexpr T fnv1a(const char (&file)[n], ssize_t i = (ssize_t)n - 1) {
     return i == -1 ? offset_basis<T>() : (fnv1a<T>(file, i - 1) ^ file[i]) * FNV_prime<T>();
 }
 
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 7b19f58..1a32433 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -109,12 +109,7 @@
     //
 
     // 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;
+    virtual audio_io_handle_t getOutput(audio_stream_type_t stream) = 0;
     virtual status_t getOutputForAttr(const audio_attributes_t *attr,
                                         audio_io_handle_t *output,
                                         audio_session_t session,
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 31f0550..9bd68e1 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -35,7 +35,8 @@
  * A device mask for all audio input devices that are considered "virtual" when evaluating
  * active inputs in getActiveInputs()
  */
-#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL  (AUDIO_DEVICE_IN_REMOTE_SUBMIX)
+#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX|\
+        AUDIO_DEVICE_IN_BUS|AUDIO_DEVICE_IN_FM_TUNER)
 
 
 /**
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 8593444..4d3c3b5 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -46,17 +46,17 @@
     for (int i = 0; i < NUM_STRATEGIES; i++) {
         mStrategyMutedByDevice[i] = false;
     }
-    if (port != NULL) {
-        port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
-        if (port->mGains.size() > 0) {
-            port->mGains[0]->getDefaultConfig(&mGain);
+    if (mPort.get() != nullptr) {
+        mPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
+        if (mPort->mGains.size() > 0) {
+            mPort->mGains[0]->getDefaultConfig(&mGain);
         }
     }
 }
 
 audio_module_handle_t AudioOutputDescriptor::getModuleHandle() const
 {
-    return mPort->getModuleHandle();
+    return mPort.get() != nullptr ? mPort->getModuleHandle() : AUDIO_MODULE_HANDLE_NONE;
 }
 
 audio_port_handle_t AudioOutputDescriptor::getId() const
@@ -175,9 +175,9 @@
     dstConfig->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT;
 }
 
-void AudioOutputDescriptor::toAudioPort(
-                                                    struct audio_port *port) const
+void AudioOutputDescriptor::toAudioPort(struct audio_port *port) const
 {
+    // Should not be called for duplicated ports, see SwAudioOutputDescriptor::toAudioPortConfig.
     mPort->toAudioPort(port);
     port->id = mId;
     port->ext.mix.hw_module = getModuleHandle();
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index a224004..0908ffc 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -140,19 +140,19 @@
     }
 
     string minValueMBLiteral = getXmlAttribute(root, Attributes::minValueMB);
-    uint32_t minValueMB;
+    int32_t minValueMB;
     if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
         gain->setMinValueInMb(minValueMB);
     }
 
     string maxValueMBLiteral = getXmlAttribute(root, Attributes::maxValueMB);
-    uint32_t maxValueMB;
+    int32_t maxValueMB;
     if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
         gain->setMaxValueInMb(maxValueMB);
     }
 
     string defaultValueMBLiteral = getXmlAttribute(root, Attributes::defaultValueMB);
-    uint32_t defaultValueMB;
+    int32_t defaultValueMB;
     if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
         gain->setDefaultValueInMb(defaultValueMB);
     }
diff --git a/services/audiopolicy/config/audio_policy_configuration.xml b/services/audiopolicy/config/audio_policy_configuration.xml
index 7af2f81..73efe8e 100644
--- a/services/audiopolicy/config/audio_policy_configuration.xml
+++ b/services/audiopolicy/config/audio_policy_configuration.xml
@@ -163,37 +163,16 @@
                        sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
                 <route type="mix" sink="Wired Headphones"
                        sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
-                <route type="mix" sink="Telephony Tx"
-                       sources="voice_tx"/>
                 <route type="mix" sink="primary input"
                        sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
                 <route type="mix" sink="Telephony Tx"
-                       sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
+                       sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic, voice_tx"/>
                 <route type="mix" sink="voice_rx"
                        sources="Telephony Rx"/>
             </routes>
 
         </module>
 
-        <!-- HDMI Audio HAL -->
-        <module description="HDMI Audio HAL" name="hdmi" version="2.0">
-            <mixPorts>
-                <mixPort name="hdmi output" role="source">
-                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000"/>
-                </mixPort>
-            </mixPorts>
-            <devicePorts>
-                <devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink">
-                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
-                </devicePort>
-            </devicePorts>
-            <routes>
-                <route type="mix" sink="HDMI Out"
-                       sources="hdmi output"/>
-            </routes>
-        </module>
-
         <!-- A2dp Audio HAL -->
         <xi:include href="a2dp_audio_policy_configuration.xml"/>
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index bdfaf2f..62cbfc1 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -751,20 +751,22 @@
     return profile;
 }
 
-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 AudioPolicyManager::getOutput(audio_stream_type_t stream)
 {
     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);
 
-    return getOutputForDevice(device, AUDIO_SESSION_ALLOCATE, stream, samplingRate, format,
-                              channelMask, flags, offloadInfo);
+    // Note that related method getOutputForAttr() uses getOutputForDevice() not selectOutput().
+    // We use selectOutput() here since we don't have the desired AudioTrack sample rate,
+    // format, flags, etc. This may result in some discrepancy for functions that utilize
+    // getOutput() solely on audio_stream_type such as AudioSystem::getOutputFrameCount()
+    // and AudioSystem::getOutputSamplingRate().
+
+    SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
+    audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
+
+    ALOGV("getOutput() stream %d selected device %08x, output %d", stream, device, output);
+    return output;
 }
 
 status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
@@ -874,48 +876,6 @@
     audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
     status_t status;
 
-#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");
-            sp<AudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(NULL,
-                                                                               mpClientInterface);
-            outputDesc->mDevice = mTestDevice;
-            outputDesc->mLatency = mTestLatencyMs;
-            outputDesc->mFlags =
-                    (audio_output_flags_t)(mDirectOutput ? AUDIO_OUTPUT_FLAG_DIRECT : 0);
-            outputDesc->mRefCount[stream] = 0;
-            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
-            config.sample_rate = mTestSamplingRate;
-            config.channel_mask = mTestChannels;
-            config.format = mTestFormat;
-            if (offloadInfo != NULL) {
-                config.offload_info = *offloadInfo;
-            }
-            status = mpClientInterface->openOutput(0,
-                                                  &mTestOutputs[mCurOutput],
-                                                  &config,
-                                                  &outputDesc->mDevice,
-                                                  String8(""),
-                                                  &outputDesc->mLatency,
-                                                  outputDesc->mFlags);
-            if (status == NO_ERROR) {
-                outputDesc->mSamplingRate = config.sample_rate;
-                outputDesc->mFormat = config.format;
-                outputDesc->mChannelMask = config.channel_mask;
-                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
@@ -984,12 +944,12 @@
                     (channelMask == outputDesc->mChannelMask)) {
                   if (session == outputDesc->mDirectClientSession) {
                       outputDesc->mDirectOpenCount++;
-                      ALOGV("getOutput() reusing direct output %d for session %d",
+                      ALOGV("getOutputForDevice() reusing direct output %d for session %d",
                             mOutputs.keyAt(i), session);
                       return mOutputs.keyAt(i);
                   } else {
-                      ALOGV("getOutput() do not reuse direct output because current client (%d) "
-                            "is not the same as requesting client (%d)",
+                      ALOGV("getOutputForDevice() do not reuse direct output because"
+                              "current client (%d) is not the same as requesting client (%d)",
                             outputDesc->mDirectClientSession, session);
                       goto non_direct_output;
                   }
@@ -1044,7 +1004,7 @@
             (samplingRate != 0 && samplingRate != config.sample_rate) ||
             (format != AUDIO_FORMAT_DEFAULT && !audio_formats_match(format, config.format)) ||
             (channelMask != 0 && channelMask != config.channel_mask)) {
-            ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d,"
+            ALOGV("getOutputForDevice() 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);
@@ -1067,7 +1027,7 @@
 
         addOutput(output, outputDesc);
         mPreviousOutputs = mOutputs;
-        ALOGV("getOutput() returns new direct output %d", output);
+        ALOGV("getOutputForDevice() returns new direct output %d", output);
         mpClientInterface->onAudioPortListUpdate();
         return output;
     }
@@ -1094,8 +1054,9 @@
         flags = (audio_output_flags_t)(flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
         output = selectOutput(outputs, flags, format);
     }
-    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);
+    ALOGW_IF((output == 0), "getOutputForDevice() could not find output for stream %d, "
+            "samplingRate %d, format %d, channels %x, flags %x",
+            stream, samplingRate, format, channelMask, flags);
 
     return output;
 }
@@ -1148,8 +1109,9 @@
             int commonFlags = popcount(outputDesc->mProfile->getFlags() & flags);
             if (commonFlags >= maxCommonFlags) {
                 if (commonFlags == maxCommonFlags) {
-                    if (AudioPort::isBetterFormatMatch(
-                            outputDesc->mFormat, bestFormatForFlags, format)) {
+                    if (format != AUDIO_FORMAT_INVALID
+                            && AudioPort::isBetterFormatMatch(
+                                    outputDesc->mFormat, bestFormatForFlags, format)) {
                         outputForFlags = outputs[i];
                         bestFormatForFlags = outputDesc->mFormat;
                     }
@@ -1266,6 +1228,12 @@
     bool force = !outputDesc->isActive() &&
             (outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
 
+    // requiresMuteCheck is false when we can bypass mute strategy.
+    // It covers a common case when there is no materially active audio
+    // and muting would result in unnecessary delay and dropped audio.
+    const uint32_t outputLatencyMs = outputDesc->latency();
+    bool requiresMuteCheck = outputDesc->isActive(outputLatencyMs * 2);  // account for drain
+
     // 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()
@@ -1289,29 +1257,44 @@
         for (size_t i = 0; i < mOutputs.size(); i++) {
             sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
             if (desc != outputDesc) {
+                // An output has a shared device if
+                // - managed by the same hw module
+                // - supports the currently selected device
+                const bool sharedDevice = outputDesc->sharesHwModuleWith(desc)
+                        && (desc->supportedDevices() & device) != AUDIO_DEVICE_NONE;
+
                 // force a device change if any other output is:
                 // - managed by the same hw module
-                // - has a current device selection that differs from selected device.
                 // - supports currently selected device
+                // - has a current device selection that differs from selected device.
                 // - has an active audio patch
                 // 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) &&
+                // change the device currently selected by the other output.
+                if (sharedDevice &&
                         desc->device() != device &&
-                        desc->supportedDevices() & device &&
                         desc->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
                     force = true;
                 }
                 // wait for audio on other active outputs to be presented when starting
                 // a notification so that audio focus effect can propagate, or that a mute/unmute
                 // event occurred for beacon
-                uint32_t latency = desc->latency();
-                if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
-                    waitMs = latency;
+                const uint32_t latencyMs = desc->latency();
+                const bool isActive = desc->isActive(latencyMs * 2);  // account for drain
+
+                if (shouldWait && isActive && (waitMs < latencyMs)) {
+                    waitMs = latencyMs;
                 }
+
+                // Require mute check if another output is on a shared device
+                // and currently active to have proper drain and avoid pops.
+                // Note restoring AudioTracks onto this output needs to invoke
+                // a volume ramp if there is no mute.
+                requiresMuteCheck |= sharedDevice && isActive;
             }
         }
-        uint32_t muteWaitMs = setOutputDevice(outputDesc, device, force, 0, NULL, address);
+
+        const uint32_t muteWaitMs =
+                setOutputDevice(outputDesc, device, force, 0, NULL, address, requiresMuteCheck);
 
         // handle special case for sonification while in call
         if (isInCall()) {
@@ -1336,6 +1319,14 @@
         if (waitMs > muteWaitMs) {
             *delayMs = waitMs - muteWaitMs;
         }
+
+        // FIXME: A device change (muteWaitMs > 0) likely introduces a volume change.
+        // A volume change enacted by APM with 0 delay is not synchronous, as it goes
+        // via AudioCommandThread to AudioFlinger.  Hence it is possible that the volume
+        // change occurs after the MixerThread starts and causes a stream volume
+        // glitch.
+        //
+        // We do not introduce additional delay here.
     }
 
     return NO_ERROR;
@@ -1454,19 +1445,6 @@
         return;
     }
 
-#ifdef AUDIO_POLICY_TEST
-    int testIndex = testOutputIndex(output);
-    if (testIndex != 0) {
-        sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
-        if (outputDesc->isActive()) {
-            mpClientInterface->closeOutput(output);
-            removeOutput(output);
-            mTestOutputs[testIndex] = 0;
-        }
-        return;
-    }
-#endif //AUDIO_POLICY_TEST
-
     // Routing
     mOutputRoutes.removeRoute(session);
 
@@ -1685,7 +1663,7 @@
         } else if (profileFlags != AUDIO_INPUT_FLAG_NONE) {
             profileFlags = AUDIO_INPUT_FLAG_NONE; // retry
         } else { // fail
-            ALOGW("getInputForDevice() could not find profile for device 0x%X,"
+            ALOGW("getInputForDevice() could not find profile for device 0x%X, "
                   "samplingRate %u, format %#x, channelMask 0x%X, flags %#x",
                     device, samplingRate, format, channelMask, flags);
             return input;
@@ -3581,9 +3559,6 @@
 
 AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
     :
-#ifdef AUDIO_POLICY_TEST
-    Thread(false),
-#endif //AUDIO_POLICY_TEST
     mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
     mA2dpSuspended(false),
     mAudioPortGeneration(1),
@@ -3824,37 +3799,10 @@
     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->mIoHandle, 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));
    }
@@ -3873,164 +3821,6 @@
     return hasPrimaryOutput() ? NO_ERROR : NO_INIT;
 }
 
-#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(AudioParameter::keyStreamSupportedFormats), 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(AudioParameter::keyStreamSupportedChannels), 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(AudioParameter::keyStreamSupportedSamplingRates), 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"));
-
-                mpClientInterface->closeOutput(mpClientInterface->closeOutput(mPrimaryOutput););
-
-                audio_module_handle_t moduleHandle = mPrimaryOutput->getModuleHandle();
-
-                removeOutput(mPrimaryOutput->mIoHandle);
-                sp<SwAudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(NULL,
-                                                                               mpClientInterface);
-                outputDesc->mDevice = AUDIO_DEVICE_OUT_SPEAKER;
-                audio_config_t config = AUDIO_CONFIG_INITIALIZER;
-                config.sample_rate = outputDesc->mSamplingRate;
-                config.channel_mask = outputDesc->mChannelMask;
-                config.format = outputDesc->mFormat;
-                audio_io_handle_t handle;
-                status_t status = mpClientInterface->openOutput(moduleHandle,
-                                                                &handle,
-                                                                &config,
-                                                                &outputDesc->mDevice,
-                                                                String8(""),
-                                                                &outputDesc->mLatency,
-                                                                outputDesc->mFlags);
-                if (status != NO_ERROR) {
-                    ALOGE("Failed to reopen hardware output stream, "
-                        "samplingRate: %d, format %d, channels %d",
-                        outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannelMask);
-                } else {
-                    outputDesc->mSamplingRate = config.sample_rate;
-                    outputDesc->mChannelMask = config.channel_mask;
-                    outputDesc->mFormat = config.format;
-                    mPrimaryOutput = outputDesc;
-                    AudioParameter outputCmd = AudioParameter();
-                    outputCmd.addInt(String8("set_id"), 0);
-                    mpClientInterface->setParameters(handle, outputCmd.toString());
-                    addOutput(handle, 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 output, const sp<SwAudioOutputDescriptor>& outputDesc)
@@ -5055,21 +4845,24 @@
                                              bool force,
                                              int delayMs,
                                              audio_patch_handle_t *patchHandle,
-                                             const char* address)
+                                             const char *address,
+                                             bool requiresMuteCheck)
 {
     ALOGV("setOutputDevice() device %04x delayMs %d", device, delayMs);
     AudioParameter param;
     uint32_t muteWaitMs;
 
     if (outputDesc->isDuplicated()) {
-        muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs);
-        muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs);
+        muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs,
+                nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
+        muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs,
+                nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
         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->supportedDevices()) == 0)) {
+            ((device & outputDesc->supportedDevices()) == AUDIO_DEVICE_NONE)) {
         return 0;
     }
 
@@ -5083,7 +4876,14 @@
     if (device != AUDIO_DEVICE_NONE) {
         outputDesc->mDevice = device;
     }
-    muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+    // if the outputs are not materially active, there is no need to mute.
+    if (requiresMuteCheck) {
+        muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+    } else {
+        ALOGV("%s: suppressing checkDeviceMuteStrategies", __func__);
+        muteWaitMs = 0;
+    }
 
     // Do not change the routing if:
     //      the requested device is AUDIO_DEVICE_NONE
@@ -5795,6 +5595,11 @@
             case AUDIO_FORMAT_E_AC3:
             case AUDIO_FORMAT_DTS:
             case AUDIO_FORMAT_DTS_HD:
+                // If ALWAYS, remove all other surround formats here since we will add them later.
+                if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
+                    formats.removeAt(formatIndex);
+                    formatIndex--;
+                }
                 supportsOtherSurround = true;
                 break;
             case AUDIO_FORMAT_IEC61937:
@@ -5840,8 +5645,7 @@
         // If ALWAYS, add support for raw surround formats if all are missing.
         // This assumes that if any of these formats are reported by the HAL
         // then the report is valid and should not be modified.
-        if ((forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS)
-                && !supportsOtherSurround) {
+        if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
             formats.add(AUDIO_FORMAT_E_AC3);
             formats.add(AUDIO_FORMAT_DTS);
             formats.add(AUDIO_FORMAT_DTS_HD);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 82c4c35..11894dc 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -76,10 +76,6 @@
 // ----------------------------------------------------------------------------
 
 class AudioPolicyManager : public AudioPolicyInterface, public AudioPolicyManagerObserver
-
-#ifdef AUDIO_POLICY_TEST
-    , public Thread
-#endif //AUDIO_POLICY_TEST
 {
 
 public:
@@ -103,12 +99,7 @@
 
         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 audio_io_handle_t getOutput(audio_stream_type_t stream);
         virtual status_t getOutputForAttr(const audio_attributes_t *attr,
                                           audio_io_handle_t *output,
                                           audio_session_t session,
@@ -304,7 +295,8 @@
                              bool force = false,
                              int delayMs = 0,
                              audio_patch_handle_t *patchHandle = NULL,
-                             const char* address = NULL);
+                             const char *address = nullptr,
+                             bool requiresMuteCheck = true);
         status_t resetOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
                                    int delayMs = 0,
                                    audio_patch_handle_t *patchHandle = NULL);
@@ -419,11 +411,6 @@
         {
             return mEffects.getMaxEffectsMemory();
         }
-#ifdef AUDIO_POLICY_TEST
-        virtual     bool        threadLoop();
-                    void        exit();
-        int testOutputIndex(audio_io_handle_t output);
-#endif //AUDIO_POLICY_TEST
 
         SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device,
                                                             const SwAudioOutputCollection& openOutputs);
@@ -574,22 +561,6 @@
         AudioPolicyMixCollection mPolicyMixes; // list of registered mixes
         audio_io_handle_t mMusicEffectOutput;     // output selected for music effects
 
-
-#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
-
         uint32_t nextAudioPortGeneration();
 
         // Audio Policy Engine Interface.
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index b7bce55..bd94e3e 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -141,12 +141,7 @@
     return mAudioPolicyManager->getForceUse(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)
+audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream)
 {
     if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
         return AUDIO_IO_HANDLE_NONE;
@@ -156,8 +151,7 @@
     }
     ALOGV("getOutput()");
     Mutex::Autolock _l(mLock);
-    return mAudioPolicyManager->getOutput(stream, samplingRate,
-                                    format, channelMask, flags, offloadInfo);
+    return mAudioPolicyManager->getOutput(stream);
 }
 
 status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
@@ -173,7 +167,7 @@
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
-    ALOGV("getOutput()");
+    ALOGV("getOutputForAttr()");
     Mutex::Autolock _l(mLock);
 
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index b417631..7af2e74 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -859,7 +859,7 @@
     }
 
     // check same pending commands with later time stamps and eliminate them
-    for (i = mAudioCommands.size()-1; i >= 0; i--) {
+    for (i = (ssize_t)mAudioCommands.size()-1; i >= 0; i--) {
         sp<AudioCommand> command2 = mAudioCommands[i];
         // commands are sorted by increasing time stamp: no need to scan the rest of mAudioCommands
         if (command2->mTime <= command->mTime) break;
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 38d4b17..268697e 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -68,13 +68,7 @@
     virtual status_t setPhoneState(audio_mode_t state);
     virtual status_t 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 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 = 0,
-                                        audio_output_flags_t flags =
-                                                AUDIO_OUTPUT_FLAG_NONE,
-                                        const audio_offload_info_t *offloadInfo = NULL);
+    virtual audio_io_handle_t getOutput(audio_stream_type_t stream);
     virtual status_t getOutputForAttr(const audio_attributes_t *attr,
                                       audio_io_handle_t *output,
                                       audio_session_t session,
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
old mode 100644
new mode 100755
index d8b7af2..d1bbdaf
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -395,7 +395,7 @@
     }
 
     // Read JFIF segment markers, skip over segment data
-    size = 0;
+    size = MARKER_LENGTH; //jump SOI;
     while (size <= maxSize - MARKER_LENGTH) {
         segment_t *segment = (segment_t*)(jpegBuffer + size);
         uint8_t type = checkJpegMarker(segment->marker);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index c03e8a2..a376ab4 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -193,7 +193,7 @@
          */
         SurfaceMap surfaceMap;
         Vector<int32_t> outputStreamIds;
-        for (sp<Surface> surface : request.mSurfaceList) {
+        for (const sp<Surface>& surface : request.mSurfaceList) {
             if (surface == 0) continue;
 
             sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
@@ -530,10 +530,11 @@
     }
 
     int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
+    std::vector<int> surfaceIds;
     err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width,
             streamInfo.height, streamInfo.format, streamInfo.dataSpace,
             static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
-            &streamId, outputConfiguration.getSurfaceSetID(), isShared);
+            &streamId, &surfaceIds, outputConfiguration.getSurfaceSetID(), isShared);
 
     if (err != OK) {
         res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
@@ -545,7 +546,8 @@
         for (auto& binder : binders) {
             ALOGV("%s: mStreamMap add binder %p streamId %d, surfaceId %d",
                     __FUNCTION__, binder.get(), streamId, i);
-            mStreamMap.add(binder, StreamSurfaceId(streamId, i++));
+            mStreamMap.add(binder, StreamSurfaceId(streamId, surfaceIds[i]));
+            i++;
         }
 
         mStreamInfoMap[streamId] = streamInfo;
@@ -592,10 +594,12 @@
     }
     int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
     std::vector<sp<Surface>> noSurface;
+    std::vector<int> surfaceIds;
     err = mDevice->createStream(noSurface, /*hasDeferredConsumer*/true, width,
             height, format, dataSpace,
             static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
-            &streamId, outputConfiguration.getSurfaceSetID(), isShared, consumerUsage);
+            &streamId, &surfaceIds, outputConfiguration.getSurfaceSetID(), isShared,
+            consumerUsage);
 
     if (err != OK) {
         res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
@@ -721,6 +725,130 @@
     return res;
 }
 
+binder::Status CameraDeviceClient::updateOutputConfiguration(int streamId,
+        const hardware::camera2::params::OutputConfiguration &outputConfiguration) {
+    ATRACE_CALL();
+
+    binder::Status res;
+    if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) {
+        return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
+    }
+
+    const std::vector<sp<IGraphicBufferProducer> >& bufferProducers =
+            outputConfiguration.getGraphicBufferProducers();
+    auto producerCount = bufferProducers.size();
+    if (producerCount == 0) {
+        ALOGE("%s: bufferProducers must not be empty", __FUNCTION__);
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                "bufferProducers must not be empty");
+    }
+
+    // The first output is the one associated with the output configuration.
+    // It should always be present, valid and the corresponding stream id should match.
+    sp<IBinder> binder = IInterface::asBinder(bufferProducers[0]);
+    ssize_t index = mStreamMap.indexOfKey(binder);
+    if (index == NAME_NOT_FOUND) {
+        ALOGE("%s: Outputconfiguration is invalid", __FUNCTION__);
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                "OutputConfiguration is invalid");
+    }
+    if (mStreamMap.valueFor(binder).streamId() != streamId) {
+        ALOGE("%s: Stream Id: %d provided doesn't match the id: %d in the stream map",
+                __FUNCTION__, streamId, mStreamMap.valueFor(binder).streamId());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                "Stream id is invalid");
+    }
+
+    std::vector<size_t> removedSurfaceIds;
+    std::vector<sp<IBinder>> removedOutputs;
+    std::vector<sp<Surface>> newOutputs;
+    std::vector<OutputStreamInfo> streamInfos;
+    KeyedVector<sp<IBinder>, sp<IGraphicBufferProducer>> newOutputsMap;
+    for (auto &it : bufferProducers) {
+        newOutputsMap.add(IInterface::asBinder(it), it);
+    }
+
+    for (size_t i = 0; i < mStreamMap.size(); i++) {
+        ssize_t idx = newOutputsMap.indexOfKey(mStreamMap.keyAt(i));
+        if (idx == NAME_NOT_FOUND) {
+            if (mStreamMap[i].streamId() == streamId) {
+                removedSurfaceIds.push_back(mStreamMap[i].surfaceId());
+                removedOutputs.push_back(mStreamMap.keyAt(i));
+            }
+        } else {
+            if (mStreamMap[i].streamId() != streamId) {
+                ALOGE("%s: Output surface already part of a different stream", __FUNCTION__);
+                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                        "Target Surface is invalid");
+            }
+            newOutputsMap.removeItemsAt(idx);
+        }
+    }
+
+    for (size_t i = 0; i < newOutputsMap.size(); i++) {
+        OutputStreamInfo outInfo;
+        sp<Surface> surface;
+        res = createSurfaceFromGbp(outInfo, /*isStreamInfoValid*/ false, surface,
+                newOutputsMap.valueAt(i));
+        if (!res.isOk())
+            return res;
+
+        // Stream sharing is only supported for IMPLEMENTATION_DEFINED
+        // formats.
+        if (outInfo.format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+            String8 msg = String8::format("Camera %s: Stream sharing is only supported for "
+                    "IMPLEMENTATION_DEFINED format", mCameraIdStr.string());
+            ALOGW("%s: %s", __FUNCTION__, msg.string());
+            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+        }
+        streamInfos.push_back(outInfo);
+        newOutputs.push_back(surface);
+    }
+
+    //Trivial case no changes required
+    if (removedSurfaceIds.empty() && newOutputs.empty()) {
+        return binder::Status::ok();
+    }
+
+    KeyedVector<sp<Surface>, size_t> outputMap;
+    auto ret = mDevice->updateStream(streamId, newOutputs, streamInfos, removedSurfaceIds,
+            &outputMap);
+    if (ret != OK) {
+        switch (ret) {
+            case NAME_NOT_FOUND:
+            case BAD_VALUE:
+            case -EBUSY:
+                res = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                        "Camera %s: Error updating stream: %s (%d)",
+                        mCameraIdStr.string(), strerror(ret), ret);
+                break;
+            default:
+                res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
+                        "Camera %s: Error updating stream: %s (%d)",
+                        mCameraIdStr.string(), strerror(ret), ret);
+                break;
+        }
+    } else {
+        for (const auto &it : removedOutputs) {
+            mStreamMap.removeItem(it);
+        }
+
+        for (size_t i = 0; i < outputMap.size(); i++) {
+            mStreamMap.add(IInterface::asBinder(outputMap.keyAt(i)->getIGraphicBufferProducer()),
+                    StreamSurfaceId(streamId, outputMap.valueAt(i)));
+        }
+
+        ALOGV("%s: Camera %s: Successful stream ID %d update",
+                  __FUNCTION__, mCameraIdStr.string(), streamId);
+    }
+
+    return res;
+}
+
 bool CameraDeviceClient::isPublicFormat(int32_t format)
 {
     switch(format) {
@@ -1242,15 +1370,12 @@
     }
 
     std::vector<sp<Surface>> consumerSurfaces;
-    std::vector<size_t> consumerSurfaceIds;
-    size_t surfaceId = 0;
     for (auto& bufferProducer : bufferProducers) {
         // Don't create multiple streams for the same target surface
         ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
         if (index != NAME_NOT_FOUND) {
             ALOGV("Camera %s: Surface already has a stream created "
                     " for it (ID %zd)", mCameraIdStr.string(), index);
-            surfaceId++;
             continue;
         }
 
@@ -1262,8 +1387,6 @@
             return res;
 
         consumerSurfaces.push_back(surface);
-        consumerSurfaceIds.push_back(surfaceId);
-        surfaceId++;
     }
 
     // Gracefully handle case where finalizeOutputConfigurations is called
@@ -1275,12 +1398,13 @@
 
     // Finish the deferred stream configuration with the surface.
     status_t err;
-    err = mDevice->setConsumerSurfaces(streamId, consumerSurfaces);
+    std::vector<int> consumerSurfaceIds;
+    err = mDevice->setConsumerSurfaces(streamId, consumerSurfaces, &consumerSurfaceIds);
     if (err == OK) {
         for (size_t i = 0; i < consumerSurfaces.size(); i++) {
             sp<IBinder> binder = IInterface::asBinder(
                     consumerSurfaces[i]->getIGraphicBufferProducer());
-            ALOGV("%s: mStreamMap add binder %p streamId %d, surfaceId %zu", __FUNCTION__,
+            ALOGV("%s: mStreamMap add binder %p streamId %d, surfaceId %d", __FUNCTION__,
                     binder.get(), streamId, consumerSurfaceIds[i]);
             mStreamMap.add(binder, StreamSurfaceId(streamId, consumerSurfaceIds[i]));
         }
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 50661cb..e1a11db 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -26,6 +26,8 @@
 #include "common/FrameProcessorBase.h"
 #include "common/Camera2ClientBase.h"
 
+using android::camera3::OutputStreamInfo;
+
 namespace android {
 
 struct CameraDeviceClientBase :
@@ -131,6 +133,10 @@
     // Prepare stream by preallocating up to maxCount of its buffers
     virtual binder::Status prepare2(int32_t maxCount, int32_t streamId) override;
 
+    // Update an output configuration
+    virtual binder::Status updateOutputConfiguration(int streamId,
+            const hardware::camera2::params::OutputConfiguration &outputConfiguration) override;
+
     // Finalize the output configurations with surfaces not added before.
     virtual binder::Status finalizeOutputConfigurations(int32_t streamId,
             const hardware::camera2::params::OutputConfiguration &outputConfiguration) override;
@@ -206,24 +212,6 @@
 
     }; // class StreamSurfaceId
 
-    // OutputStreamInfo describes the property of a camera stream.
-    class OutputStreamInfo {
-    public:
-        int width;
-        int height;
-        int format;
-        android_dataspace dataSpace;
-        uint64_t consumerUsage;
-        bool finalized = false;
-        OutputStreamInfo() :
-                width(-1), height(-1), format(-1), dataSpace(HAL_DATASPACE_UNKNOWN),
-                consumerUsage(0) {}
-        OutputStreamInfo(int _width, int _height, int _format, android_dataspace _dataSpace,
-                uint64_t _consumerUsage) :
-                    width(_width), height(_height), format(_format),
-                    dataSpace(_dataSpace), consumerUsage(_consumerUsage) {}
-    };
-
 private:
     /** ICameraDeviceUser interface-related private members */
 
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 51ef160..4ce82dc 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -156,13 +156,14 @@
     result = "  Device dump:\n";
     write(fd, result.string(), result.size());
 
-    if (!mDevice.get()) {
+    sp<CameraDeviceBase> device = mDevice;
+    if (!device.get()) {
         result = "  *** Device is detached\n";
         write(fd, result.string(), result.size());
         return NO_ERROR;
     }
 
-    status_t res = mDevice->dump(fd, args);
+    status_t res = device->dump(fd, args);
     if (res != OK) {
         result = String8::format("   Error dumping device: %s (%d)",
                 strerror(-res), res);
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 3919bfa..68384b0 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -23,6 +23,7 @@
 #include <utils/String8.h>
 #include <utils/String16.h>
 #include <utils/Vector.h>
+#include <utils/KeyedVector.h>
 #include <utils/Timers.h>
 #include <utils/List.h>
 
@@ -118,6 +119,7 @@
     virtual status_t createStream(sp<Surface> consumer,
             uint32_t width, uint32_t height, int format,
             android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
+            std::vector<int> *surfaceIds = nullptr,
             int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
             bool isShared = false, uint64_t consumerUsage = 0) = 0;
 
@@ -131,6 +133,7 @@
     virtual status_t createStream(const std::vector<sp<Surface>>& consumers,
             bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
             android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
+            std::vector<int> *surfaceIds = nullptr,
             int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
             bool isShared = false, uint64_t consumerUsage = 0) = 0;
 
@@ -347,8 +350,15 @@
      * Set the deferred consumer surface and finish the rest of the stream configuration.
      */
     virtual status_t setConsumerSurfaces(int streamId,
-            const std::vector<sp<Surface>>& consumers) = 0;
+            const std::vector<sp<Surface>>& consumers, std::vector<int> *surfaceIds /*out*/) = 0;
 
+    /**
+     * Update a given stream.
+     */
+    virtual status_t updateStream(int streamId, const std::vector<sp<Surface>> &newSurfaces,
+            const std::vector<android::camera3::OutputStreamInfo> &outputInfo,
+            const std::vector<size_t> &removedSurfaceIds,
+            KeyedVector<sp<Surface>, size_t> *outputMap/*out*/) = 0;
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index ced1d3a..e0a2dd4 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1222,7 +1222,7 @@
 status_t Camera3Device::createStream(sp<Surface> consumer,
             uint32_t width, uint32_t height, int format,
             android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
-            int streamSetId, bool isShared, uint64_t consumerUsage) {
+            std::vector<int> *surfaceIds, int streamSetId, bool isShared, uint64_t consumerUsage) {
     ATRACE_CALL();
 
     if (consumer == nullptr) {
@@ -1234,14 +1234,15 @@
     consumers.push_back(consumer);
 
     return createStream(consumers, /*hasDeferredConsumer*/ false, width, height,
-            format, dataSpace, rotation, id, streamSetId, isShared, consumerUsage);
+            format, dataSpace, rotation, id, surfaceIds, streamSetId, isShared, consumerUsage);
 }
 
 status_t Camera3Device::createStream(const std::vector<sp<Surface>>& consumers,
         bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
         android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
-        int streamSetId, bool isShared, uint64_t consumerUsage) {
+        std::vector<int> *surfaceIds, int streamSetId, bool isShared, uint64_t consumerUsage) {
     ATRACE_CALL();
+
     Mutex::Autolock il(mInterfaceLock);
     nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
     Mutex::Autolock l(mLock);
@@ -1330,6 +1331,19 @@
                 width, height, format, dataSpace, rotation,
                 mTimestampOffset, streamSetId);
     }
+
+    size_t consumerCount = consumers.size();
+    for (size_t i = 0; i < consumerCount; i++) {
+        int id = newStream->getSurfaceId(consumers[i]);
+        if (id < 0) {
+            SET_ERR_L("Invalid surface id");
+            return BAD_VALUE;
+        }
+        if (surfaceIds != nullptr) {
+            surfaceIds->push_back(id);
+        }
+    }
+
     newStream->setStatusTracker(mStatusTracker);
 
     newStream->setBufferManager(mBufferManager);
@@ -1936,10 +1950,15 @@
 }
 
 status_t Camera3Device::setConsumerSurfaces(int streamId,
-        const std::vector<sp<Surface>>& consumers) {
+        const std::vector<sp<Surface>>& consumers, std::vector<int> *surfaceIds) {
     ATRACE_CALL();
     ALOGV("%s: Camera %s: set consumer surface for stream %d",
             __FUNCTION__, mId.string(), streamId);
+
+    if (surfaceIds == nullptr) {
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
 
@@ -1960,6 +1979,15 @@
         return res;
     }
 
+    for (auto &consumer : consumers) {
+        int id = stream->getSurfaceId(consumer);
+        if (id < 0) {
+            CLOGE("Invalid surface id!");
+            return BAD_VALUE;
+        }
+        surfaceIds->push_back(id);
+    }
+
     if (stream->isConsumerConfigurationDeferred()) {
         if (!stream->isConfiguring()) {
             CLOGE("Stream %d was already fully configured.", streamId);
@@ -1977,6 +2005,40 @@
     return OK;
 }
 
+status_t Camera3Device::updateStream(int streamId, const std::vector<sp<Surface>> &newSurfaces,
+        const std::vector<OutputStreamInfo> &outputInfo,
+        const std::vector<size_t> &removedSurfaceIds, KeyedVector<sp<Surface>, size_t> *outputMap) {
+    Mutex::Autolock il(mInterfaceLock);
+    Mutex::Autolock l(mLock);
+
+    ssize_t idx = mOutputStreams.indexOfKey(streamId);
+    if (idx == NAME_NOT_FOUND) {
+        CLOGE("Stream %d is unknown", streamId);
+        return idx;
+    }
+
+    for (const auto &it : removedSurfaceIds) {
+        if (mRequestThread->isOutputSurfacePending(streamId, it)) {
+            CLOGE("Shared surface still part of a pending request!");
+            return -EBUSY;
+        }
+    }
+
+    sp<Camera3OutputStreamInterface> stream = mOutputStreams[idx];
+    status_t res = stream->updateStream(newSurfaces, outputInfo, removedSurfaceIds, outputMap);
+    if (res != OK) {
+        CLOGE("Stream %d failed to update stream (error %d %s) ",
+              streamId, res, strerror(-res));
+        if (res == UNKNOWN_ERROR) {
+            SET_ERR_L("%s: Stream update failed to revert to previous output configuration!",
+                    __FUNCTION__);
+        }
+        return res;
+    }
+
+    return res;
+}
+
 /**
  * Camera3Device private methods
  */
@@ -4342,6 +4404,46 @@
     return false;
 }
 
+bool Camera3Device::RequestThread::isOutputSurfacePending(int streamId, size_t surfaceId) {
+    ATRACE_CALL();
+    Mutex::Autolock l(mRequestLock);
+
+    for (const auto& nextRequest : mNextRequests) {
+        for (const auto& s : nextRequest.captureRequest->mOutputSurfaces) {
+            if (s.first == streamId) {
+                const auto &it = std::find(s.second.begin(), s.second.end(), surfaceId);
+                if (it != s.second.end()) {
+                    return true;
+                }
+            }
+        }
+    }
+
+    for (const auto& request : mRequestQueue) {
+        for (const auto& s : request->mOutputSurfaces) {
+            if (s.first == streamId) {
+                const auto &it = std::find(s.second.begin(), s.second.end(), surfaceId);
+                if (it != s.second.end()) {
+                  return true;
+                }
+            }
+        }
+    }
+
+    for (const auto& request : mRepeatingRequests) {
+        for (const auto& s : request->mOutputSurfaces) {
+            if (s.first == streamId) {
+                const auto &it = std::find(s.second.begin(), s.second.end(), surfaceId);
+                if (it != s.second.end()) {
+                  return true;
+                }
+            }
+        }
+    }
+
+    return false;
+}
+
 nsecs_t Camera3Device::getExpectedInFlightDuration() {
     ATRACE_CALL();
     Mutex::Autolock al(mInFlightLock);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index fbbbd08..357b893 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -44,6 +44,8 @@
 #include "utils/LatencyHistogram.h"
 #include <camera_metadata_hidden.h>
 
+using android::camera3::OutputStreamInfo;
+
 /**
  * Function pointer types with C calling convention to
  * use for HAL callback functions.
@@ -117,11 +119,13 @@
     status_t createStream(sp<Surface> consumer,
             uint32_t width, uint32_t height, int format,
             android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
+            std::vector<int> *surfaceIds = nullptr,
             int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
             bool isShared = false, uint64_t consumerUsage = 0) override;
     status_t createStream(const std::vector<sp<Surface>>& consumers,
             bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
             android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
+            std::vector<int> *surfaceIds = nullptr,
             int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
             bool isShared = false, uint64_t consumerUsage = 0) override;
 
@@ -176,7 +180,17 @@
      * Set the deferred consumer surfaces to the output stream and finish the deferred
      * consumer configuration.
      */
-    status_t setConsumerSurfaces(int streamId, const std::vector<sp<Surface>>& consumers) override;
+    status_t setConsumerSurfaces(
+            int streamId, const std::vector<sp<Surface>>& consumers,
+            std::vector<int> *surfaceIds /*out*/) override;
+
+    /**
+     * Update a given stream.
+     */
+    status_t updateStream(int streamId, const std::vector<sp<Surface>> &newSurfaces,
+            const std::vector<OutputStreamInfo> &outputInfo,
+            const std::vector<size_t> &removedSurfaceIds,
+            KeyedVector<sp<Surface>, size_t> *outputMap/*out*/);
 
   private:
 
@@ -705,6 +719,12 @@
          */
         bool isStreamPending(sp<camera3::Camera3StreamInterface>& stream);
 
+        /**
+         * Returns true if the surface is a target of any queued or repeating
+         * capture request
+         */
+        bool isOutputSurfacePending(int streamId, size_t surfaceId);
+
         // dump processCaptureRequest latency
         void dumpCaptureRequestLatency(int fd, const char* name) {
             mRequestLatency.dump(fd, name);
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index 6e2978f..4b36ea2 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -113,6 +113,15 @@
             __FUNCTION__, mId);
     return INVALID_OPERATION;
 }
+
+status_t Camera3DummyStream::updateStream(const std::vector<sp<Surface>> &/*outputSurfaces*/,
+            const std::vector<OutputStreamInfo> &/*outputInfo*/,
+            const std::vector<size_t> &/*removedSurfaceIds*/,
+            KeyedVector<sp<Surface>, size_t> * /*outputMap*/) {
+    ALOGE("%s: this method is not supported!", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
 }; // namespace camera3
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index 492fb49..3212031 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -71,6 +71,19 @@
      */
     virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers);
 
+    /**
+     * Query the output surface id.
+     */
+    virtual ssize_t getSurfaceId(const sp<Surface> &/*surface*/) { return 0; }
+
+    /**
+     * Update the stream output surfaces.
+     */
+    virtual status_t updateStream(const std::vector<sp<Surface>> &outputSurfaces,
+            const std::vector<OutputStreamInfo> &outputInfo,
+            const std::vector<size_t> &removedSurfaceIds,
+            KeyedVector<sp<Surface>, size_t> *outputMap/*out*/);
+
   protected:
 
     /**
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index dcaefe3..329172a 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -691,6 +691,14 @@
     return OK;
 }
 
+status_t Camera3OutputStream::updateStream(const std::vector<sp<Surface>> &/*outputSurfaces*/,
+            const std::vector<OutputStreamInfo> &/*outputInfo*/,
+            const std::vector<size_t> &/*removedSurfaceIds*/,
+            KeyedVector<sp<Surface>, size_t> * /*outputMapo*/) {
+    ALOGE("%s: this method is not supported!", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
 void Camera3OutputStream::BufferReleasedListener::onBufferReleased() {
     sp<Camera3OutputStream> stream = mParent.promote();
     if (stream == nullptr) {
@@ -728,7 +736,7 @@
         const std::vector<sp<GraphicBuffer>>& removedBuffers) {
     sp<Camera3StreamBufferFreedListener> callback = mBufferFreedListener.promote();
     if (callback != nullptr) {
-        for (auto gb : removedBuffers) {
+        for (const auto& gb : removedBuffers) {
             callback->onBufferFreed(mId, gb->handle);
         }
     }
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 7023d5d..fbb14fe 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -172,6 +172,19 @@
      */
     status_t setBufferManager(sp<Camera3BufferManager> bufferManager);
 
+    /**
+     * Query the ouput surface id.
+     */
+    virtual ssize_t getSurfaceId(const sp<Surface> &/*surface*/) { return 0; }
+
+    /**
+     * Update the stream output surfaces.
+     */
+    virtual status_t updateStream(const std::vector<sp<Surface>> &outputSurfaces,
+            const std::vector<OutputStreamInfo> &outputInfo,
+            const std::vector<size_t> &removedSurfaceIds,
+            KeyedVector<sp<Surface>, size_t> *outputMap/*out*/);
+
   protected:
     Camera3OutputStream(int id, camera3_stream_type_t type,
             uint32_t width, uint32_t height, int format,
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index 8107dd0..edfbab1 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -18,6 +18,7 @@
 #define ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_INTERFACE_H
 
 #include "Camera3StreamInterface.h"
+#include <utils/KeyedVector.h>
 
 namespace android {
 
@@ -59,6 +60,19 @@
      *
      */
     virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd) = 0;
+
+    /**
+     * Query the surface id.
+     */
+    virtual ssize_t getSurfaceId(const sp<Surface> &surface) = 0;
+
+    /**
+     * Update the stream output surfaces.
+     */
+    virtual status_t updateStream(const std::vector<sp<Surface>> &outputSurfaces,
+            const std::vector<OutputStreamInfo> &outputInfo,
+            const std::vector<size_t> &removedSurfaceIds,
+            KeyedVector<sp<Surface>, size_t> *outputMap/*out*/) = 0;
 };
 
 } // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 5051711..1c9417b 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -20,6 +20,8 @@
 
 namespace camera3 {
 
+const size_t Camera3SharedOutputStream::kMaxOutputs;
+
 Camera3SharedOutputStream::Camera3SharedOutputStream(int id,
         const std::vector<sp<Surface>>& surfaces,
         uint32_t width, uint32_t height, int format,
@@ -28,8 +30,14 @@
         nsecs_t timestampOffset, int setId) :
         Camera3OutputStream(id, CAMERA3_STREAM_OUTPUT, width, height,
                             format, dataSpace, rotation, consumerUsage,
-                            timestampOffset, setId),
-        mSurfaces(surfaces) {
+                            timestampOffset, setId) {
+    size_t consumerCount = std::min(surfaces.size(), kMaxOutputs);
+    if (surfaces.size() > consumerCount) {
+        ALOGE("%s: Trying to add more consumers than the maximum ", __func__);
+    }
+    for (size_t i = 0; i < consumerCount; i++) {
+        mSurfaces[i] = surfaces[i];
+    }
 }
 
 Camera3SharedOutputStream::~Camera3SharedOutputStream() {
@@ -44,7 +52,16 @@
     uint64_t usage;
     getEndpointUsage(&usage);
 
-    res = mStreamSplitter->connect(mSurfaces, usage, camera3_stream::max_buffers, &mConsumer);
+    std::unordered_map<size_t, sp<Surface>> initialSurfaces;
+    for (size_t i = 0; i < kMaxOutputs; i++) {
+        if (mSurfaces[i] != nullptr) {
+            initialSurfaces.emplace(i, mSurfaces[i]);
+        }
+    }
+
+    android::PixelFormat format = isFormatOverridden() ? getOriginalFormat() : getFormat();
+    res = mStreamSplitter->connect(initialSurfaces, usage, mUsage, camera3_stream::max_buffers,
+            getWidth(), getHeight(), format, &mConsumer);
     if (res != OK) {
         ALOGE("%s: Failed to connect to stream splitter: %s(%d)",
                 __FUNCTION__, strerror(-res), res);
@@ -68,7 +85,11 @@
 
 bool Camera3SharedOutputStream::isConsumerConfigurationDeferred(size_t surface_id) const {
     Mutex::Autolock l(mLock);
-    return (surface_id >= mSurfaces.size());
+    if (surface_id >= kMaxOutputs) {
+        return true;
+    }
+
+    return (mSurfaces[surface_id] == nullptr);
 }
 
 status_t Camera3SharedOutputStream::setConsumers(const std::vector<sp<Surface>>& surfaces) {
@@ -85,11 +106,17 @@
             return INVALID_OPERATION;
         }
 
-        mSurfaces.push_back(surface);
+        ssize_t id = getNextSurfaceIdLocked();
+        if (id < 0) {
+            ALOGE("%s: No surface ids available!", __func__);
+            return NO_MEMORY;
+        }
+
+        mSurfaces[id] = surface;
 
         // Only call addOutput if the splitter has been connected.
         if (mStreamSplitter != nullptr) {
-            ret = mStreamSplitter->addOutput(surface);
+            ret = mStreamSplitter->addOutput(id, surface);
             if (ret != OK) {
                 ALOGE("%s: addOutput failed with error code %d", __FUNCTION__, ret);
                 return ret;
@@ -200,9 +227,9 @@
         // Called before shared buffer queue is constructed.
         *usage = getPresetConsumerUsage();
 
-        for (auto surface : mSurfaces) {
-            if (surface != nullptr) {
-                res = getEndpointUsageForSurface(&u, surface);
+        for (size_t id = 0; id < kMaxOutputs; id++) {
+            if (mSurfaces[id] != nullptr) {
+                res = getEndpointUsageForSurface(&u, mSurfaces[id]);
                 *usage |= u;
             }
         }
@@ -215,6 +242,140 @@
     return res;
 }
 
+ssize_t Camera3SharedOutputStream::getNextSurfaceIdLocked() {
+    ssize_t id = -1;
+    for (size_t i = 0; i < kMaxOutputs; i++) {
+        if (mSurfaces[i] == nullptr) {
+            id = i;
+            break;
+        }
+    }
+
+    return id;
+}
+
+ssize_t Camera3SharedOutputStream::getSurfaceId(const sp<Surface> &surface) {
+    Mutex::Autolock l(mLock);
+    ssize_t id = -1;
+    for (size_t i = 0; i < kMaxOutputs; i++) {
+        if (mSurfaces[i] == surface) {
+            id = i;
+            break;
+        }
+    }
+
+    return id;
+}
+
+status_t Camera3SharedOutputStream::revertPartialUpdateLocked(
+        const KeyedVector<sp<Surface>, size_t> &removedSurfaces,
+        const KeyedVector<sp<Surface>, size_t> &attachedSurfaces) {
+    status_t ret = OK;
+
+    for (size_t i = 0; i < attachedSurfaces.size(); i++) {
+        size_t index = attachedSurfaces.valueAt(i);
+        if (mStreamSplitter != nullptr) {
+            ret = mStreamSplitter->removeOutput(index);
+            if (ret != OK) {
+                return UNKNOWN_ERROR;
+            }
+        }
+        mSurfaces[index] = nullptr;
+    }
+
+    for (size_t i = 0; i < removedSurfaces.size(); i++) {
+        size_t index = removedSurfaces.valueAt(i);
+        if (mStreamSplitter != nullptr) {
+            ret = mStreamSplitter->addOutput(index, removedSurfaces.keyAt(i));
+            if (ret != OK) {
+                return UNKNOWN_ERROR;
+            }
+        }
+        mSurfaces[index] = removedSurfaces.keyAt(i);
+    }
+
+    return ret;
+}
+
+status_t Camera3SharedOutputStream::updateStream(const std::vector<sp<Surface>> &outputSurfaces,
+        const std::vector<OutputStreamInfo> &outputInfo,
+        const std::vector<size_t> &removedSurfaceIds,
+        KeyedVector<sp<Surface>, size_t> *outputMap) {
+    status_t ret = OK;
+    Mutex::Autolock l(mLock);
+
+    if ((outputMap == nullptr) || (outputInfo.size() != outputSurfaces.size()) ||
+            (outputSurfaces.size() > kMaxOutputs)) {
+        return BAD_VALUE;
+    }
+
+    uint64_t usage;
+    getEndpointUsage(&usage);
+    KeyedVector<sp<Surface>, size_t> removedSurfaces;
+    //Check whether the new surfaces are compatible.
+    for (const auto &infoIt : outputInfo) {
+        bool imgReaderUsage = (infoIt.consumerUsage & GRALLOC_USAGE_SW_READ_OFTEN) ? true : false;
+        bool sizeMismatch = ((static_cast<uint32_t>(infoIt.width) != getWidth()) ||
+                                (static_cast<uint32_t> (infoIt.height) != getHeight())) ?
+                                true : false;
+        if ((imgReaderUsage && sizeMismatch) ||
+                (infoIt.format != getOriginalFormat() && infoIt.format != getFormat()) ||
+                (infoIt.dataSpace != getDataSpace() &&
+                 infoIt.dataSpace != getOriginalDataSpace())) {
+            ALOGE("%s: Shared surface parameters format: 0x%x dataSpace: 0x%x "
+                    " don't match source stream format: 0x%x  dataSpace: 0x%x", __FUNCTION__,
+                    infoIt.format, infoIt.dataSpace, getFormat(), getDataSpace());
+            return BAD_VALUE;
+        }
+    }
+
+    //First remove all absent outputs
+    for (const auto &it : removedSurfaceIds) {
+        if (mStreamSplitter != nullptr) {
+            ret = mStreamSplitter->removeOutput(it);
+            if (ret != OK) {
+                ALOGE("%s: failed with error code %d", __FUNCTION__, ret);
+                status_t res = revertPartialUpdateLocked(removedSurfaces, *outputMap);
+                if (res != OK) {
+                    return res;
+                }
+                return ret;
+
+            }
+        }
+        mSurfaces[it] = nullptr;
+        removedSurfaces.add(mSurfaces[it], it);
+    }
+
+    //Next add the new outputs
+    for (const auto &it : outputSurfaces) {
+        ssize_t surfaceId = getNextSurfaceIdLocked();
+        if (surfaceId < 0) {
+            ALOGE("%s: No more available output slots!", __FUNCTION__);
+            status_t res = revertPartialUpdateLocked(removedSurfaces, *outputMap);
+            if (res != OK) {
+                return res;
+            }
+            return NO_MEMORY;
+        }
+        if (mStreamSplitter != nullptr) {
+            ret = mStreamSplitter->addOutput(surfaceId, it);
+            if (ret != OK) {
+                ALOGE("%s: failed with error code %d", __FUNCTION__, ret);
+                status_t res = revertPartialUpdateLocked(removedSurfaces, *outputMap);
+                if (res != OK) {
+                    return res;
+                }
+                return ret;
+            }
+        }
+        mSurfaces[surfaceId] = it;
+        outputMap->add(it, surfaceId);
+    }
+
+    return ret;
+}
+
 } // namespace camera3
 
 } // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index 22bb2fc..6eab8bd 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -46,9 +46,24 @@
 
     virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers);
 
+    virtual ssize_t getSurfaceId(const sp<Surface> &surface);
+
+    virtual status_t updateStream(const std::vector<sp<Surface>> &outputSurfaces,
+            const std::vector<OutputStreamInfo> &outputInfo,
+            const std::vector<size_t> &removedSurfaceIds,
+            KeyedVector<sp<Surface>, size_t> *outputMap/*out*/);
+
 private:
-    // Surfaces passed in constructor from app
-    std::vector<sp<Surface> > mSurfaces;
+
+    static const size_t kMaxOutputs = 4;
+
+    // Map surfaceId -> output surfaces
+    sp<Surface> mSurfaces[kMaxOutputs];
+
+    ssize_t getNextSurfaceIdLocked();
+
+    status_t revertPartialUpdateLocked(const KeyedVector<sp<Surface>, size_t> &removedSurfaces,
+            const KeyedVector<sp<Surface>, size_t> &attachedSurfaces);
 
     /**
      * The Camera3StreamSplitter object this stream uses for stream
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index cc9bf8e..9ed7184 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -43,6 +43,24 @@
 
 class StatusTracker;
 
+// OutputStreamInfo describes the property of a camera stream.
+class OutputStreamInfo {
+    public:
+        int width;
+        int height;
+        int format;
+        android_dataspace dataSpace;
+        uint64_t consumerUsage;
+        bool finalized = false;
+        OutputStreamInfo() :
+            width(-1), height(-1), format(-1), dataSpace(HAL_DATASPACE_UNKNOWN),
+            consumerUsage(0) {}
+        OutputStreamInfo(int _width, int _height, int _format, android_dataspace _dataSpace,
+                uint64_t _consumerUsage) :
+            width(_width), height(_height), format(_format),
+            dataSpace(_dataSpace), consumerUsage(_consumerUsage) {}
+};
+
 /**
  * An interface for managing a single stream of input and/or output data from
  * the camera device.
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index a0a50c2..49a10dc 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -38,8 +38,9 @@
 
 namespace android {
 
-status_t Camera3StreamSplitter::connect(const std::vector<sp<Surface> >& surfaces,
-        uint64_t consumerUsage, size_t halMaxBuffers, sp<Surface>* consumer) {
+status_t Camera3StreamSplitter::connect(const std::unordered_map<size_t, sp<Surface>> &surfaces,
+        uint64_t consumerUsage, uint64_t producerUsage, size_t halMaxBuffers, uint32_t width,
+        uint32_t height, android::PixelFormat format, sp<Surface>* consumer) {
     ATRACE_CALL();
     if (consumer == nullptr) {
         SP_LOGE("%s: consumer pointer is NULL", __FUNCTION__);
@@ -62,12 +63,12 @@
     mConsumerName = getUniqueConsumerName();
     // Add output surfaces. This has to be before creating internal buffer queue
     // in order to get max consumer side buffers.
-    for (size_t i = 0; i < surfaces.size(); i++) {
-        if (surfaces[i] == nullptr) {
+    for (auto &it : surfaces) {
+        if (it.second == nullptr) {
             SP_LOGE("%s: Fatal: surface is NULL", __FUNCTION__);
             return BAD_VALUE;
         }
-        res = addOutputLocked(surfaces[i]);
+        res = addOutputLocked(it.first, it.second);
         if (res != OK) {
             SP_LOGE("%s: Failed to add output surface: %s(%d)",
                     __FUNCTION__, strerror(-res), res);
@@ -94,8 +95,20 @@
         return NO_MEMORY;
     }
 
+    res = mProducer->setAsyncMode(true);
+    if (res != OK) {
+        SP_LOGE("%s: Failed to enable input queue async mode: %s(%d)", __FUNCTION__,
+                strerror(-res), res);
+        return res;
+    }
+
     res = mConsumer->consumerConnect(this, /* controlledByApp */ false);
 
+    mWidth = width;
+    mHeight = height;
+    mFormat = format;
+    mProducerUsage = producerUsage;
+
     SP_LOGV("%s: connected", __FUNCTION__);
     return res;
 }
@@ -117,10 +130,13 @@
     mNotifiers.clear();
 
     for (auto& output : mOutputs) {
-        output->disconnect(NATIVE_WINDOW_API_CAMERA);
+        if (output.second != nullptr) {
+            output.second->disconnect(NATIVE_WINDOW_API_CAMERA);
+        }
     }
     mOutputs.clear();
     mOutputSlots.clear();
+    mConsumerBufferCount.clear();
 
     mConsumer->consumerDisconnect();
 
@@ -139,10 +155,10 @@
     disconnect();
 }
 
-status_t Camera3StreamSplitter::addOutput(const sp<Surface>& outputQueue) {
+status_t Camera3StreamSplitter::addOutput(size_t surfaceId, const sp<Surface>& outputQueue) {
     ATRACE_CALL();
     Mutex::Autolock lock(mMutex);
-    status_t res = addOutputLocked(outputQueue);
+    status_t res = addOutputLocked(surfaceId, outputQueue);
 
     if (res != OK) {
         SP_LOGE("%s: addOutputLocked failed %d", __FUNCTION__, res);
@@ -154,18 +170,30 @@
     return res;
 }
 
-status_t Camera3StreamSplitter::addOutputLocked(const sp<Surface>& outputQueue) {
+status_t Camera3StreamSplitter::addOutputLocked(size_t surfaceId, const sp<Surface>& outputQueue) {
     ATRACE_CALL();
     if (outputQueue == nullptr) {
         SP_LOGE("addOutput: outputQueue must not be NULL");
         return BAD_VALUE;
     }
 
+    if (mOutputs[surfaceId] != nullptr) {
+        SP_LOGE("%s: surfaceId: %u already taken!", __FUNCTION__, (unsigned) surfaceId);
+        return BAD_VALUE;
+    }
+
+  status_t res = native_window_set_buffers_dimensions(outputQueue.get(),
+            mWidth, mHeight);
+    if (res != NO_ERROR) {
+        SP_LOGE("addOutput: failed to set buffer dimensions (%d)", res);
+        return res;
+    }
+
     sp<IGraphicBufferProducer> gbp = outputQueue->getIGraphicBufferProducer();
     // Connect to the buffer producer
     sp<OutputListener> listener(new OutputListener(this, gbp));
     IInterface::asBinder(gbp)->linkToDeath(listener);
-    status_t res = outputQueue->connect(NATIVE_WINDOW_API_CAMERA, listener);
+    res = outputQueue->connect(NATIVE_WINDOW_API_CAMERA, listener);
     if (res != NO_ERROR) {
         SP_LOGE("addOutput: failed to connect (%d)", res);
         return res;
@@ -208,7 +236,8 @@
     }
 
     // Add new entry into mOutputs
-    mOutputs.push_back(gbp);
+    mOutputs[surfaceId] = gbp;
+    mConsumerBufferCount[surfaceId] = maxConsumerBuffers;
     mNotifiers[gbp] = listener;
     mOutputSlots[gbp] = std::make_unique<OutputSlots>(totalBufferCount);
 
@@ -216,8 +245,72 @@
     return NO_ERROR;
 }
 
+status_t Camera3StreamSplitter::removeOutput(size_t surfaceId) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+
+    status_t res = removeOutputLocked(surfaceId);
+    if (res != OK) {
+        SP_LOGE("%s: removeOutputLocked failed %d", __FUNCTION__, res);
+        return res;
+    }
+
+    res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers+1);
+    if (res != OK) {
+        SP_LOGE("%s: setMaxAcquiredBufferCount failed %d", __FUNCTION__, res);
+        return res;
+    }
+
+    return res;
+}
+
+status_t Camera3StreamSplitter::removeOutputLocked(size_t surfaceId) {
+    if (mOutputs[surfaceId] == nullptr) {
+        SP_LOGE("%s: output surface is not present!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    sp<IGraphicBufferProducer> gbp = mOutputs[surfaceId];
+    //Search and decrement the ref. count of any buffers that are
+    //still attached to the removed surface.
+    std::vector<uint64_t> pendingBufferIds;
+    auto& outputSlots = *mOutputSlots[gbp];
+    for (const auto &it : outputSlots) {
+        if (it.get() != nullptr) {
+            pendingBufferIds.push_back(it->getId());
+        }
+    }
+    mOutputs[surfaceId] = nullptr;
+    mOutputSlots[gbp] = nullptr;
+    for (const auto &id : pendingBufferIds) {
+        decrementBufRefCountLocked(id, surfaceId);
+    }
+
+    auto res = IInterface::asBinder(gbp)->unlinkToDeath(mNotifiers[gbp]);
+    if (res != OK) {
+        SP_LOGE("%s: Failed to unlink producer death listener: %d ", __FUNCTION__, res);
+        return res;
+    }
+
+    res = gbp->disconnect(NATIVE_WINDOW_API_CAMERA);
+    if (res != OK) {
+        SP_LOGE("%s: Unable disconnect from producer interface: %d ", __FUNCTION__, res);
+        return res;
+    }
+
+    mNotifiers[gbp] = nullptr;
+    if (mConsumerBufferCount[surfaceId] < mMaxHalBuffers) {
+        mMaxConsumerBuffers -= mConsumerBufferCount[surfaceId];
+    } else {
+        SP_LOGE("%s: Cached consumer buffer count mismatch!", __FUNCTION__);
+    }
+    mConsumerBufferCount[surfaceId] = 0;
+
+    return res;
+}
+
 status_t Camera3StreamSplitter::outputBufferLocked(const sp<IGraphicBufferProducer>& output,
-        const BufferItem& bufferItem) {
+        const BufferItem& bufferItem, size_t surfaceId) {
     ATRACE_CALL();
     status_t res;
     IGraphicBufferProducer::QueueBufferInput queueInput(
@@ -242,6 +335,11 @@
 
     SP_LOGV("%s: Queuing buffer to buffer queue %p slot %d returns %d",
             __FUNCTION__, output.get(), slot, res);
+    //During buffer queue 'mMutex' is not held which makes the removal of
+    //"output" possible. Check whether this is the case and return.
+    if (mOutputSlots[output] == nullptr) {
+        return res;
+    }
     if (res != OK) {
         if (res != NO_INIT && res != DEAD_OBJECT) {
             SP_LOGE("Queuing buffer to output failed (%d)", res);
@@ -250,7 +348,7 @@
         // that, increment the release count so that we still release this
         // buffer eventually, and move on to the next output
         onAbandonedLocked();
-        decrementBufRefCountLocked(bufferItem.mGraphicBuffer->getId(), output);
+        decrementBufRefCountLocked(bufferItem.mGraphicBuffer->getId(), surfaceId);
         return res;
     }
 
@@ -258,7 +356,7 @@
     // queue, no onBufferReleased is called by the buffer queue.
     // Proactively trigger the callback to avoid buffer loss.
     if (queueOutput.bufferReplaced) {
-        onBufferReleasedByOutputLocked(output);
+        onBufferReleasedByOutputLocked(output, surfaceId);
     }
 
     return res;
@@ -271,7 +369,6 @@
 
 status_t Camera3StreamSplitter::notifyBufferReleased(const sp<GraphicBuffer>& buffer) {
     ATRACE_CALL();
-    status_t res = OK;
 
     Mutex::Autolock lock(mMutex);
 
@@ -279,17 +376,7 @@
     std::unique_ptr<BufferTracker> tracker_ptr = std::move(mBuffers[bufferId]);
     mBuffers.erase(bufferId);
 
-    for (const auto surface : tracker_ptr->requestedSurfaces()) {
-        sp<IGraphicBufferProducer>& gbp = mOutputs[surface];
-        OutputSlots& outputSlots = *(mOutputSlots[gbp]);
-        int slot = getSlotForOutputLocked(gbp, buffer);
-        if (slot != BufferItem::INVALID_BUFFER_SLOT) {
-             gbp->detachBuffer(slot);
-             outputSlots[slot].clear();
-        }
-    }
-
-    return res;
+    return OK;
 }
 
 status_t Camera3StreamSplitter::attachBufferToOutputs(ANativeWindowBuffer* anb,
@@ -307,7 +394,15 @@
 
     for (auto& surface_id : surface_ids) {
         sp<IGraphicBufferProducer>& gbp = mOutputs[surface_id];
-        int slot = BufferItem::INVALID_BUFFER_SLOT;
+        if (gbp.get() == nullptr) {
+            //Output surface got likely removed by client.
+            continue;
+        }
+        int slot = getSlotForOutputLocked(gbp, gb);
+        if (slot != BufferItem::INVALID_BUFFER_SLOT) {
+            //Buffer is already attached to this output surface.
+            continue;
+        }
         //Temporarly Unlock the mutex when trying to attachBuffer to the output
         //queue, because attachBuffer could block in case of a slow consumer. If
         //we block while holding the lock, onFrameAvailable and onBufferReleased
@@ -320,12 +415,17 @@
                     __FUNCTION__, gbp.get(), strerror(-res), res);
             return res;
         }
+        //During buffer attach 'mMutex' is not held which makes the removal of
+        //"gbp" possible. Check whether this is the case and continue.
+        if (mOutputSlots[gbp] == nullptr) {
+            continue;
+        }
         auto& outputSlots = *mOutputSlots[gbp];
         if (outputSlots[slot] != nullptr) {
             // If the buffer is attached to a slot which already contains a buffer,
             // the previous buffer will be removed from the output queue. Decrement
             // the reference count accordingly.
-            decrementBufRefCountLocked(outputSlots[slot]->getId(), gbp);
+            decrementBufRefCountLocked(outputSlots[slot]->getId(), surface_id);
         }
         SP_LOGV("%s: Attached buffer %p to slot %d on output %p.",__FUNCTION__, gb.get(),
                 slot, gbp.get());
@@ -349,7 +449,21 @@
         mOnFrameAvailableRes.store(res);
         return;
     }
-    if (mBuffers.find(bufferItem.mGraphicBuffer->getId()) == mBuffers.end()) {
+
+    uint64_t bufferId;
+    if (bufferItem.mGraphicBuffer != nullptr) {
+        mInputSlots[bufferItem.mSlot] = bufferItem;
+    } else if (bufferItem.mAcquireCalled) {
+        bufferItem.mGraphicBuffer = mInputSlots[bufferItem.mSlot].mGraphicBuffer;
+        mInputSlots[bufferItem.mSlot].mFrameNumber = bufferItem.mFrameNumber;
+    } else {
+        SP_LOGE("%s: Invalid input graphic buffer!", __FUNCTION__);
+        res = BAD_VALUE;
+        return;
+    }
+    bufferId = bufferItem.mGraphicBuffer->getId();
+
+    if (mBuffers.find(bufferId) == mBuffers.end()) {
         SP_LOGE("%s: Acquired buffer doesn't exist in attached buffer map",
                 __FUNCTION__);
         mOnFrameAvailableRes.store(INVALID_OPERATION);
@@ -359,24 +473,19 @@
     SP_LOGV("acquired buffer %" PRId64 " from input at slot %d",
             bufferItem.mGraphicBuffer->getId(), bufferItem.mSlot);
 
-    res = mConsumer->detachBuffer(bufferItem.mSlot);
-    if (res != NO_ERROR) {
-        SP_LOGE("%s: detaching buffer from input failed (%d)", __FUNCTION__, res);
-        mOnFrameAvailableRes.store(res);
-        return;
-    }
-
     // Attach and queue the buffer to each of the outputs
-    BufferTracker& tracker = *(mBuffers[bufferItem.mGraphicBuffer->getId()]);
+    BufferTracker& tracker = *(mBuffers[bufferId]);
 
     SP_LOGV("%s: BufferTracker for buffer %" PRId64 ", number of requests %zu",
            __FUNCTION__, bufferItem.mGraphicBuffer->getId(), tracker.requestedSurfaces().size());
     for (const auto id : tracker.requestedSurfaces()) {
 
-        LOG_ALWAYS_FATAL_IF(id >= mOutputs.size(),
-                "requested surface id exceeding max registered ids");
+        if (mOutputs[id] == nullptr) {
+            //Output surface got likely removed by client.
+            continue;
+        }
 
-        res = outputBufferLocked(mOutputs[id], bufferItem);
+        res = outputBufferLocked(mOutputs[id], bufferItem, id);
         if (res != OK) {
             SP_LOGE("%s: outputBufferLocked failed %d", __FUNCTION__, res);
             mOnFrameAvailableRes.store(res);
@@ -389,12 +498,14 @@
     mOnFrameAvailableRes.store(res);
 }
 
-void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id,
-        const sp<IGraphicBufferProducer>& from) {
+void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id, size_t surfaceId) {
     ATRACE_CALL();
-    size_t referenceCount = mBuffers[id]->decrementReferenceCountLocked();
 
-    removeSlotForOutputLocked(from, mBuffers[id]->getBuffer());
+    if (mBuffers[id] == nullptr) {
+        return;
+    }
+
+    size_t referenceCount = mBuffers[id]->decrementReferenceCountLocked(surfaceId);
     if (referenceCount > 0) {
         return;
     }
@@ -407,11 +518,18 @@
     std::unique_ptr<BufferTracker> tracker_ptr = std::move(mBuffers[id]);
     mBuffers.erase(id);
 
-    // Attach and release the buffer back to the input
-    int consumerSlot = BufferItem::INVALID_BUFFER_SLOT;
-    status_t res = mConsumer->attachBuffer(&consumerSlot, tracker_ptr->getBuffer());
-    if (res != NO_ERROR) {
-        SP_LOGE("%s: attaching buffer to input failed (%d)", __FUNCTION__, res);
+    uint64_t bufferId = tracker_ptr->getBuffer()->getId();
+    int consumerSlot = -1;
+    uint64_t frameNumber;
+    for (const auto &it : mInputSlots) {
+        if (it.second.mGraphicBuffer->getId() == bufferId) {
+            consumerSlot = it.second.mSlot;
+            frameNumber = it.second.mFrameNumber;
+            break;
+        }
+    }
+    if (consumerSlot == -1) {
+        SP_LOGE("%s: Buffer missing inside input slots!", __FUNCTION__);
         return;
     }
 
@@ -424,8 +542,9 @@
     // splitter lock.
     sp<IGraphicBufferConsumer> consumer(mConsumer);
     mMutex.unlock();
+    int res = NO_ERROR;
     if (consumer != nullptr) {
-        res = consumer->releaseBuffer(consumerSlot, /* frameNumber */ 0,
+        res = consumer->releaseBuffer(consumerSlot, frameNumber,
                 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker_ptr->getMergedFence());
     } else {
         SP_LOGE("%s: consumer has become null!", __FUNCTION__);
@@ -442,27 +561,61 @@
     ATRACE_CALL();
     Mutex::Autolock lock(mMutex);
 
-    onBufferReleasedByOutputLocked(from);
+    size_t surfaceId = 0;
+    bool found = false;
+    for (const auto& it : mOutputs) {
+        if (it.second == from) {
+            found = true;
+            surfaceId = it.first;
+            break;
+        }
+    }
+    if (!found) {
+        SP_LOGV("%s: output surface not registered anymore!", __FUNCTION__);
+        return;
+    }
+
+    onBufferReleasedByOutputLocked(from, surfaceId);
 }
 
 void Camera3StreamSplitter::onBufferReleasedByOutputLocked(
-        const sp<IGraphicBufferProducer>& from) {
+        const sp<IGraphicBufferProducer>& from, size_t surfaceId) {
     ATRACE_CALL();
     sp<GraphicBuffer> buffer;
     sp<Fence> fence;
-    status_t res = from->detachNextBuffer(&buffer, &fence);
+    if (mOutputSlots[from] == nullptr) {
+        //Output surface got likely removed by client.
+        return;
+    }
+    auto outputSlots = *mOutputSlots[from];
+
+    int slot = BufferItem::INVALID_BUFFER_SLOT;
+    auto res = from->dequeueBuffer(&slot, &fence, mWidth, mHeight, mFormat, mProducerUsage,
+            nullptr, nullptr);
     if (res == NO_INIT) {
         // If we just discovered that this output has been abandoned, note that,
         // but we can't do anything else, since buffer is invalid
         onAbandonedLocked();
         return;
-    } else if (res == NO_MEMORY) {
-        SP_LOGV("%s: No free buffers", __FUNCTION__);
+    } else if (res == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+        SP_LOGE("%s: Producer needs to re-allocate buffer!", __FUNCTION__);
+        SP_LOGE("%s: This should not happen with buffer allocation disabled!", __FUNCTION__);
         return;
-    } else if (res != OK) {
-        SP_LOGE("%s: detaching buffer from output failed (%d)", __FUNCTION__, res);
+    } else if (res == IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
+        SP_LOGE("%s: All slot->buffer mapping should be released!", __FUNCTION__);
+        SP_LOGE("%s: This should not happen with buffer allocation disabled!", __FUNCTION__);
+        return;
+    } else if (res == NO_MEMORY) {
+        SP_LOGE("%s: No free buffers", __FUNCTION__);
+        return;
+    } else if (res == WOULD_BLOCK) {
+        SP_LOGE("%s: Dequeue call will block", __FUNCTION__);
+        return;
+    } else if (res != OK || (slot == BufferItem::INVALID_BUFFER_SLOT)) {
+        SP_LOGE("%s: dequeue buffer from output failed (%d)", __FUNCTION__, res);
         return;
     }
+    buffer = outputSlots[slot];
 
     BufferTracker& tracker = *(mBuffers[buffer->getId()]);
     // Merge the release fence of the incoming buffer so that the fence we send
@@ -470,11 +623,11 @@
     if (fence != nullptr && fence->isValid()) {
         tracker.mergeFence(fence);
     }
-    SP_LOGV("detached buffer %" PRId64 " %p from output %p",
+    SP_LOGV("%s: dequeued buffer %" PRId64 " %p from output %p", __FUNCTION__,
             buffer->getId(), buffer.get(), from.get());
 
     // Check to see if this is the last outstanding reference to this buffer
-    decrementBufRefCountLocked(buffer->getId(), from);
+    decrementBufRefCountLocked(buffer->getId(), surfaceId);
 }
 
 void Camera3StreamSplitter::onAbandonedLocked() {
@@ -501,27 +654,11 @@
         }
     }
 
-    SP_LOGE("%s: Cannot find slot for gb %p on output %p", __FUNCTION__, gb.get(),
+    SP_LOGV("%s: Cannot find slot for gb %p on output %p", __FUNCTION__, gb.get(),
             gbp.get());
     return BufferItem::INVALID_BUFFER_SLOT;
 }
 
-status_t Camera3StreamSplitter::removeSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
-        const sp<GraphicBuffer>& gb) {
-    auto& outputSlots = *mOutputSlots[gbp];
-
-    for (size_t i = 0; i < outputSlots.size(); i++) {
-        if (outputSlots[i] == gb) {
-           outputSlots[i].clear();
-           return NO_ERROR;
-        }
-    }
-
-    SP_LOGE("%s: Cannot find slot for gb %p on output %p", __FUNCTION__, gb.get(),
-            gbp.get());
-    return BAD_VALUE;
-}
-
 Camera3StreamSplitter::OutputListener::OutputListener(
         wp<Camera3StreamSplitter> splitter,
         wp<IGraphicBufferProducer> output)
@@ -553,7 +690,14 @@
     mMergedFence = Fence::merge(String8("Camera3StreamSplitter"), mMergedFence, with);
 }
 
-size_t Camera3StreamSplitter::BufferTracker::decrementReferenceCountLocked() {
+size_t Camera3StreamSplitter::BufferTracker::decrementReferenceCountLocked(size_t surfaceId) {
+    const auto& it = std::find(mRequestedSurfaces.begin(), mRequestedSurfaces.end(), surfaceId);
+    if (it == mRequestedSurfaces.end()) {
+        return mReferenceCount;
+    } else {
+        mRequestedSurfaces.erase(it);
+    }
+
     if (mReferenceCount > 0)
         --mReferenceCount;
     return mReferenceCount;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 3b8839e..704f88f 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -51,22 +51,25 @@
 
     // Connect to the stream splitter by creating buffer queue and connecting it
     // with output surfaces.
-    status_t connect(const std::vector<sp<Surface> >& surfaces,
-            uint64_t consumerUsage, size_t halMaxBuffers,
-            sp<Surface>* consumer);
+    status_t connect(const std::unordered_map<size_t, sp<Surface>> &surfaces,
+            uint64_t consumerUsage, uint64_t producerUsage, size_t halMaxBuffers, uint32_t width,
+            uint32_t height, android::PixelFormat format, sp<Surface>* consumer);
 
     // addOutput adds an output BufferQueue to the splitter. The splitter
     // connects to outputQueue as a CPU producer, and any buffers queued
-    // to the input will be queued to each output. It is assumed that all of the
-    // outputs are added before any buffers are queued on the input. If any
-    // output is abandoned by its consumer, the splitter will abandon its input
-    // queue (see onAbandoned).
+    // to the input will be queued to each output. If any  output is abandoned
+    // by its consumer, the splitter will abandon its input queue (see onAbandoned).
     //
     // A return value other than NO_ERROR means that an error has occurred and
     // outputQueue has not been added to the splitter. BAD_VALUE is returned if
     // outputQueue is NULL. See IGraphicBufferProducer::connect for explanations
     // of other error codes.
-    status_t addOutput(const sp<Surface>& outputQueue);
+    status_t addOutput(size_t surfaceId, const sp<Surface>& outputQueue);
+
+    //removeOutput will remove a BufferQueue that was previously added to
+    //the splitter outputs. Any pending buffers in the BufferQueue will get
+    //reclaimed.
+    status_t removeOutput(size_t surfaceId);
 
     // Notification that the graphic buffer has been released to the input
     // BufferQueue. The buffer should be reused by the camera device instead of
@@ -120,7 +123,7 @@
     // This is the implementation of onBufferReleasedByOutput without the mutex locked.
     // It could either be called from onBufferReleasedByOutput or from
     // onFrameAvailable when a buffer in the async buffer queue is overwritten.
-    void onBufferReleasedByOutputLocked(const sp<IGraphicBufferProducer>& from);
+    void onBufferReleasedByOutputLocked(const sp<IGraphicBufferProducer>& from, size_t surfaceId);
 
     // When this is called, the splitter disconnects from (i.e., abandons) its
     // input queue and signals any waiting onFrameAvailable calls to wake up.
@@ -131,7 +134,7 @@
 
     // Decrement the buffer's reference count. Once the reference count becomes
     // 0, return the buffer back to the input BufferQueue.
-    void decrementBufRefCountLocked(uint64_t id, const sp<IGraphicBufferProducer>& from);
+    void decrementBufRefCountLocked(uint64_t id, size_t surfaceId);
 
     // This is a thin wrapper class that lets us determine which BufferQueue
     // the IProducerListener::onBufferReleased callback is associated with. We
@@ -168,7 +171,7 @@
 
         // Returns the new value
         // Only called while mMutex is held
-        size_t decrementReferenceCountLocked();
+        size_t decrementReferenceCountLocked(size_t surfaceId);
 
         const std::vector<size_t> requestedSurfaces() const { return mRequestedSurfaces; }
 
@@ -191,13 +194,15 @@
     // Must be accessed through RefBase
     virtual ~Camera3StreamSplitter();
 
-    status_t addOutputLocked(const sp<Surface>& outputQueue);
+    status_t addOutputLocked(size_t surfaceId, const sp<Surface>& outputQueue);
+
+    status_t removeOutputLocked(size_t surfaceId);
 
     // Send a buffer to particular output, and increment the reference count
     // of the buffer. If this output is abandoned, the buffer's reference count
     // won't be incremented.
     status_t outputBufferLocked(const sp<IGraphicBufferProducer>& output,
-            const BufferItem& bufferItem);
+            const BufferItem& bufferItem, size_t surfaceId);
 
     // Get unique name for the buffer queue consumer
     String8 getUniqueConsumerName();
@@ -205,14 +210,14 @@
     // Helper function to get the BufferQueue slot where a particular buffer is attached to.
     int getSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
             const sp<GraphicBuffer>& gb);
-    // Helper function to remove the buffer from the BufferQueue slot
-    status_t removeSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
-            const sp<GraphicBuffer>& gb);
-
 
     // Sum of max consumer buffers for all outputs
     size_t mMaxConsumerBuffers = 0;
     size_t mMaxHalBuffers = 0;
+    uint32_t mWidth = 0;
+    uint32_t mHeight = 0;
+    android::PixelFormat mFormat = android::PIXEL_FORMAT_NONE;
+    uint64_t mProducerUsage = 0;
 
     static const nsecs_t kDequeueBufferTimeout   = s2ns(1); // 1 sec
 
@@ -223,7 +228,15 @@
     sp<BufferItemConsumer> mBufferItemConsumer;
     sp<Surface> mSurface;
 
-    std::vector<sp<IGraphicBufferProducer> > mOutputs;
+    //Map graphic buffer ids -> buffer items
+    std::unordered_map<uint64_t, BufferItem> mInputSlots;
+
+    //Map surface ids -> gbp outputs
+    std::unordered_map<int, sp<IGraphicBufferProducer> > mOutputs;
+
+    //Map surface ids -> consumer buffer count
+    std::unordered_map<int, size_t > mConsumerBufferCount;
+
     // Map of GraphicBuffer IDs (GraphicBuffer::getId()) to buffer tracking
     // objects (which are mostly for counting how many outputs have released the
     // buffer, but also contain merged release fences).
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index c7f9270..8444444 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -159,7 +159,8 @@
           mMaxRecordAgeNs(kMaxRecordAgeNs),
           mMaxRecordSets(kMaxRecordSets),
           mNewSetInterval(kNewSetIntervalNs),
-          mDumpProto(MediaAnalyticsItem::PROTO_V0) {
+          mDumpProto(MediaAnalyticsItem::PROTO_V1),
+          mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
 
     ALOGD("MediaAnalyticsService created");
     // clear our queues
@@ -299,6 +300,8 @@
 
     bool finalizing = item->getFinalized();
 
+    Mutex::Autolock _l(mLock);
+
     // if finalizing, we'll remove it
     MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew);
     if (oitem != NULL) {
@@ -316,6 +319,7 @@
                 saveItem(mFinalized, oitem, 0);
             }
             // new record could itself be marked finalized...
+            id = item->getSessionID();
             if (finalizing) {
                 summarize(item);
                 saveItem(mFinalized, item, 0);
@@ -323,16 +327,15 @@
             } else {
                 saveItem(mOpen, item, 1);
             }
-            id = item->getSessionID();
         } else {
             // combine the records, send it to finalized if appropriate
             oitem->merge(item);
+            id = oitem->getSessionID();
             if (finalizing) {
                 summarize(oitem);
                 saveItem(mFinalized, oitem, 0);
                 mItemsFinalized++;
             }
-            id = oitem->getSessionID();
 
             // we're responsible for disposing of the dead record
             delete item;
@@ -379,6 +382,7 @@
     String16 summaryOption("-summary");
     bool summary = false;
     String16 protoOption("-proto");
+    int chosenProto = mDumpProtoDefault;
     String16 clearOption("-clear");
     bool clear = false;
     String16 sinceOption("-since");
@@ -398,7 +402,7 @@
             i++;
             if (i < n) {
                 String8 value(args[i]);
-                int proto = MediaAnalyticsItem::PROTO_V0;       // default to original
+                int proto = MediaAnalyticsItem::PROTO_V0;
                 char *endp;
                 const char *p = value.string();
                 proto = strtol(p, &endp, 10);
@@ -408,8 +412,12 @@
                     } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
                         proto = MediaAnalyticsItem::PROTO_LAST;
                     }
-                    mDumpProto = proto;
+                    chosenProto = proto;
+                } else {
+                    result.append("unable to parse value for -proto\n\n");
                 }
+            } else {
+                result.append("missing value for -proto\n\n");
             }
         } else if (args[i] == sinceOption) {
             i++;
@@ -435,7 +443,7 @@
         } else if (args[i] == helpOption) {
             result.append("Recognized parameters:\n");
             result.append("-help        this help message\n");
-            result.append("-proto X     dump using protocol X (defaults to 1)");
+            result.append("-proto #     dump using protocol #");
             result.append("-summary     show summary info\n");
             result.append("-clear       clears out saved records\n");
             result.append("-only X      process records for component X\n");
@@ -448,6 +456,8 @@
 
     Mutex::Autolock _l(mLock);
 
+    mDumpProto = chosenProto;
+
     // we ALWAYS dump this piece
     snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
     result.append(buffer);
@@ -609,21 +619,31 @@
 // XXX: rewrite this to manage persistence, etc.
 
 // insert appropriately into queue
+// caller should hold mLock
 void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) {
 
-    Mutex::Autolock _l(mLock);
-
-    // adding at back of queue (fifo order)
     if (front)  {
+        // for non-finalized stuff, since we expect to reference it again soon,
+        // make it quicker to find (nearer the front of our list)
         l->push_front(item);
     } else {
+        // for finalized records, which we want to dump 'in sequence order'
         l->push_back(item);
     }
 
+    // our reclaim process is for oldest-first queues
+    if (front) {
+        return;
+    }
+
+
     // keep removing old records the front until we're in-bounds (count)
     if (mMaxRecords > 0) {
         while (l->size() > (size_t) mMaxRecords) {
             MediaAnalyticsItem * oitem = *(l->begin());
+            if (oitem == item) {
+                break;
+            }
             l->erase(l->begin());
             delete oitem;
             mItemsDiscarded++;
@@ -637,6 +657,9 @@
         while (l->size() > 0) {
             MediaAnalyticsItem * oitem = *(l->begin());
             nsecs_t when = oitem->getTimestamp();
+            if (oitem == item) {
+                break;
+            }
             // careful about timejumps too
             if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
                 // this (and the rest) are recent enough to keep
@@ -682,6 +705,7 @@
 }
 
 // find the incomplete record that this will overlay
+// caller should hold mLock
 MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) {
     if (nitem == NULL) {
         return NULL;
@@ -689,8 +713,6 @@
 
     MediaAnalyticsItem *item = NULL;
 
-    Mutex::Autolock _l(mLock);
-
     for (List<MediaAnalyticsItem *>::iterator it = theList->begin();
         it != theList->end(); it++) {
         MediaAnalyticsItem *tmp = (*it);
@@ -711,10 +733,9 @@
 
 
 // delete the indicated record
+// caller should hold mLock
 void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) {
 
-    Mutex::Autolock _l(mLock);
-
     for (List<MediaAnalyticsItem *>::iterator it = l->begin();
         it != l->end(); it++) {
         if ((*it)->getSessionID() != item->getSessionID())
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index 52e4631..3b34f44 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -125,6 +125,7 @@
 
     // support for generating output
     int mDumpProto;
+    int mDumpProtoDefault;
     String8 dumpQueue(List<MediaAnalyticsItem*> *);
     String8 dumpQueue(List<MediaAnalyticsItem*> *, nsecs_t, const char *only);
 
diff --git a/services/mediaanalytics/OWNERS b/services/mediaanalytics/OWNERS
new file mode 100644
index 0000000..9af258b
--- /dev/null
+++ b/services/mediaanalytics/OWNERS
@@ -0,0 +1 @@
+essick@google.com
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index faeb0a7..9348ecd 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -1,28 +1,11 @@
 LOCAL_PATH := $(call my-dir)
 
-# service library
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := MediaCodecService.cpp
-LOCAL_SHARED_LIBRARIES := \
-    libmedia_omx \
-    libbinder \
-    libgui \
-    libutils \
-    liblog \
-    libstagefright_omx \
-    libstagefright_xmlparser
-LOCAL_MODULE:= libmediacodecservice
-LOCAL_VENDOR_MODULE := true
-LOCAL_32_BIT_ONLY := true
-include $(BUILD_SHARED_LIBRARY)
-
 # service executable
 include $(CLEAR_VARS)
 LOCAL_REQUIRED_MODULES_arm := mediacodec.policy
 LOCAL_SRC_FILES := main_codecservice.cpp
 LOCAL_SHARED_LIBRARIES := \
     libmedia_omx \
-    libmediacodecservice \
     libbinder \
     libutils \
     libgui \
@@ -42,6 +25,11 @@
 LOCAL_VENDOR_MODULE := true
 LOCAL_32_BIT_ONLY := true
 LOCAL_INIT_RC := android.hardware.media.omx@1.0-service.rc
+
+ifeq ($(PRODUCT_FULL_TREBLE),true)
+LOCAL_CFLAGS += -DUSE_VNDBINDER
+endif
+
 include $(BUILD_EXECUTABLE)
 
 # service seccomp policy
diff --git a/services/mediacodec/MediaCodecService.cpp b/services/mediacodec/MediaCodecService.cpp
deleted file mode 100644
index 6b510c6..0000000
--- a/services/mediacodec/MediaCodecService.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "MediaCodecService"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include "MediaCodecService.h"
-
-namespace android {
-
-sp<IOMX> MediaCodecService::getOMX() {
-
-    Mutex::Autolock autoLock(mOMXLock);
-
-    if (mOMX.get() == NULL) {
-        mOMX = new OMX();
-    }
-
-    return mOMX;
-}
-
-sp<IOMXStore> MediaCodecService::getOMXStore() {
-
-    Mutex::Autolock autoLock(mOMXStoreLock);
-
-    if (mOMXStore.get() == NULL) {
-        mOMXStore = new OMXStore();
-    }
-
-    return mOMXStore;
-}
-
-status_t MediaCodecService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-        uint32_t flags)
-{
-    return BnMediaCodecService::onTransact(code, data, reply, flags);
-}
-
-}   // namespace android
diff --git a/services/mediacodec/MediaCodecService.h b/services/mediacodec/MediaCodecService.h
deleted file mode 100644
index 9301135..0000000
--- a/services/mediacodec/MediaCodecService.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIA_CODEC_SERVICE_H
-#define ANDROID_MEDIA_CODEC_SERVICE_H
-
-#include <binder/BinderService.h>
-#include <media/IMediaCodecService.h>
-#include <media/stagefright/omx/OMX.h>
-#include <media/stagefright/omx/OMXStore.h>
-
-namespace android {
-
-class MediaCodecService : public BinderService<MediaCodecService>,
-        public BnMediaCodecService
-{
-    friend class BinderService<MediaCodecService>;    // for MediaCodecService()
-public:
-    MediaCodecService() : BnMediaCodecService() { }
-    virtual ~MediaCodecService() { }
-    virtual void onFirstRef() { }
-
-    static const char*    getServiceName() { return "media.codec"; }
-
-    virtual sp<IOMX>      getOMX();
-
-    virtual sp<IOMXStore> getOMXStore();
-
-    virtual status_t      onTransact(uint32_t code, const Parcel& data,
-                                     Parcel* reply, uint32_t flags);
-
-private:
-    Mutex                 mOMXLock;
-    sp<IOMX>              mOMX;
-    Mutex                 mOMXStoreLock;
-    sp<IOMXStore>         mOMXStore;
-};
-
-}   // namespace android
-
-#endif  // ANDROID_MEDIA_CODEC_SERVICE_H
diff --git a/services/mediacodec/android.hardware.media.omx@1.0-service.rc b/services/mediacodec/android.hardware.media.omx@1.0-service.rc
index ec51d65..3ef9a85 100644
--- a/services/mediacodec/android.hardware.media.omx@1.0-service.rc
+++ b/services/mediacodec/android.hardware.media.omx@1.0-service.rc
@@ -1,4 +1,4 @@
-service mediacodec /vendor/bin/hw/android.hardware.media.omx@1.0-service
+service vendor.media.omx /vendor/bin/hw/android.hardware.media.omx@1.0-service
     class main
     user mediacodec
     group camera drmrpc mediadrm
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 79d6da5..6f14a42 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -15,22 +15,12 @@
 ** limitations under the License.
 */
 
-#include <fcntl.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <cutils/properties.h>
-
-#include <string>
-
 #include <android-base/logging.h>
 
 // from LOCAL_C_INCLUDES
-#include "MediaCodecService.h"
 #include "minijail.h"
 
+#include <binder/ProcessState.h>
 #include <hidl/HidlTransportSupport.h>
 #include <media/stagefright/omx/1.0/Omx.h>
 #include <media/stagefright/omx/1.0/OmxStore.h>
@@ -45,41 +35,33 @@
 
 int main(int argc __unused, char** argv)
 {
+    strcpy(argv[0], "media.codec");
     LOG(INFO) << "mediacodecservice starting";
-    bool treble = property_get_bool("persist.media.treble_omx", true);
-    if (treble) {
-      android::ProcessState::initWithDriver("/dev/vndbinder");
-    }
-
     signal(SIGPIPE, SIG_IGN);
     SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
 
-    strcpy(argv[0], "media.codec");
+#ifdef USE_VNDBINDER
+    android::ProcessState::initWithDriver("/dev/vndbinder");
+    android::ProcessState::self()->startThreadPool();
+#endif // USE_VNDBINDER
 
     ::android::hardware::configureRpcThreadpool(64, false);
-    sp<ProcessState> proc(ProcessState::self());
 
-    if (treble) {
-        using namespace ::android::hardware::media::omx::V1_0;
-        sp<IOmxStore> omxStore = new implementation::OmxStore();
-        if (omxStore == nullptr) {
-            LOG(ERROR) << "Cannot create IOmxStore HAL service.";
-        } else if (omxStore->registerAsService() != OK) {
-            LOG(ERROR) << "Cannot register IOmxStore HAL service.";
-        }
-        sp<IOmx> omx = new implementation::Omx();
-        if (omx == nullptr) {
-            LOG(ERROR) << "Cannot create IOmx HAL service.";
-        } else if (omx->registerAsService() != OK) {
-            LOG(ERROR) << "Cannot register IOmx HAL service.";
-        } else {
-            LOG(INFO) << "Treble OMX service created.";
-        }
+    using namespace ::android::hardware::media::omx::V1_0;
+    sp<IOmxStore> omxStore = new implementation::OmxStore();
+    if (omxStore == nullptr) {
+        LOG(ERROR) << "Cannot create IOmxStore HAL service.";
+    } else if (omxStore->registerAsService() != OK) {
+        LOG(ERROR) << "Cannot register IOmxStore HAL service.";
+    }
+    sp<IOmx> omx = new implementation::Omx();
+    if (omx == nullptr) {
+        LOG(ERROR) << "Cannot create IOmx HAL service.";
+    } else if (omx->registerAsService() != OK) {
+        LOG(ERROR) << "Cannot register IOmx HAL service.";
     } else {
-        MediaCodecService::instantiate();
-        LOG(INFO) << "Non-Treble OMX service created.";
+        LOG(INFO) << "IOmx HAL service created.";
     }
 
-    ProcessState::self()->startThreadPool();
-    IPCThreadState::self()->joinThreadPool();
+    ::android::hardware::joinRpcThreadpool();
 }
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index 1ebb7ff..2f7b7f7 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -14,6 +14,20 @@
 LOCAL_REQUIRED_MODULES_arm := mediaextractor.policy
 LOCAL_REQUIRED_MODULES_arm64 := mediaextractor.policy
 LOCAL_REQUIRED_MODULES_x86 := mediaextractor.policy
+
+# extractor libraries
+LOCAL_REQUIRED_MODULES := \
+    libaacextractor \
+    libamrextractor \
+    libflacextractor \
+    libmidiextractor \
+    libmkvextractor \
+    libmp3extractor \
+    libmp4extractor \
+    libmpeg2extractor \
+    liboggextractor \
+    libwavextractor \
+
 LOCAL_SRC_FILES := main_extractorservice.cpp
 LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils \
     liblog libbase libicuuc libavservices_minijail
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 08cbef6..f09d7cf 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -20,8 +20,11 @@
 
 #include <utils/Vector.h>
 
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/RemoteDataSource.h>
 #include "MediaExtractorService.h"
 
@@ -31,25 +34,26 @@
         const sp<IDataSource> &remoteSource, const char *mime) {
     ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime);
 
-    sp<DataSource> localSource = DataSource::CreateFromIDataSource(remoteSource);
+    sp<DataSource> localSource = CreateDataSourceFromIDataSource(remoteSource);
 
-    sp<IMediaExtractor> ret = MediaExtractor::CreateFromService(localSource, mime);
+    sp<MediaExtractor> extractor = MediaExtractorFactory::CreateFromService(localSource, mime);
 
     ALOGV("extractor service created %p (%s)",
-            ret.get(),
-            ret == NULL ? "" : ret->name());
+            extractor.get(),
+            extractor == nullptr ? "" : extractor->name());
 
-    if (ret != NULL) {
+    if (extractor != nullptr) {
+        sp<IMediaExtractor> ret = CreateIMediaExtractorFromMediaExtractor(extractor);
         registerMediaExtractor(ret, localSource, mime);
+        return ret;
     }
-
-    return ret;
+    return nullptr;
 }
 
 sp<IDataSource> MediaExtractorService::makeIDataSource(int fd, int64_t offset, int64_t length)
 {
-    sp<DataSource> source = DataSource::CreateFromFd(fd, offset, length);
-    return source.get() != nullptr ? source->asIDataSource() : nullptr;
+    sp<DataSource> source = DataSourceFactory::CreateFromFd(fd, offset, length);
+    return CreateIDataSourceFromDataSource(source);
 }
 
 status_t MediaExtractorService::dump(int fd, const Vector<String16>& args) {
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 4fa69d7..a9ee98d 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -41,6 +41,9 @@
 nanosleep: 1
 getrandom: 1
 
+# for dynamically loading extractors
+pread64: 1
+
 # for FileSource
 readlinkat: 1
 _llseek: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index eed804a..dd71ed7 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -34,6 +34,12 @@
 # for FileSource
 readlinkat: 1
 
+# for dynamically loading extractors
+getdents64: 1
+readlinkat: 1
+pread64: 1
+mremap: 1
+
 # for attaching to debuggerd on process crash
 tgkill: 1
 rt_sigprocmask: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index 3b37f92..ede108e 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -39,6 +39,12 @@
 nanosleep: 1
 getrandom: 1
 
+# for dynamically loading extractors
+getdents64: 1
+readlinkat: 1
+pread64: 1
+mremap: 1
+
 # for FileSource
 readlinkat: 1
 _llseek: 1
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
index 1f811d3..29e6dfc 100644
--- a/services/medialog/Android.bp
+++ b/services/medialog/Android.bp
@@ -11,6 +11,7 @@
         "libbinder",
         "liblog",
         "libnbaio",
+        "libnblog",
         "libutils",
     ],
 
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index a5512e1..1be5544 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -20,19 +20,25 @@
 #include <sys/mman.h>
 #include <utils/Log.h>
 #include <binder/PermissionCache.h>
-#include <media/nbaio/NBLog.h>
+#include <media/nblog/NBLog.h>
 #include <private/android_filesystem_config.h>
 #include "MediaLogService.h"
 
 namespace android {
 
- static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n";
+static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n";
+
+// mMerger, mMergeReader, and mMergeThread all point to the same location in memory
+// mMergerShared. This is the local memory FIFO containing data merged from all
+// individual thread FIFOs in shared memory. mMergeThread is used to periodically
+// call NBLog::Merger::merge() to collect the data and write it to the FIFO, and call
+// NBLog::MergeReader::getAndProcessSnapshot to process the merged data.
 MediaLogService::MediaLogService() :
     BnMediaLogService(),
     mMergerShared((NBLog::Shared*) malloc(NBLog::Timeline::sharedSize(kMergeBufferSize))),
     mMerger(mMergerShared, kMergeBufferSize),
     mMergeReader(mMergerShared, kMergeBufferSize, mMerger),
-    mMergeThread(new NBLog::MergeThread(mMerger))
+    mMergeThread(new NBLog::MergeThread(mMerger, mMergeReader))
 {
     mMergeThread->run("MergeThread");
 }
@@ -123,15 +129,10 @@
                 } else {
                     ALOGI("%s:", namedReader.name());
                 }
-                // TODO This code is for testing, remove it when done
-                // namedReader.reader()->dump(fd, 0 /*indent*/);
             }
-
             mLock.unlock();
         }
     }
-
-    // FIXME request merge to make sure log is up to date
     mMergeReader.dump(fd);
     return NO_ERROR;
 }
diff --git a/services/medialog/MediaLogService.h b/services/medialog/MediaLogService.h
index 39d9cc0..c945d1f 100644
--- a/services/medialog/MediaLogService.h
+++ b/services/medialog/MediaLogService.h
@@ -19,7 +19,7 @@
 
 #include <binder/BinderService.h>
 #include <media/IMediaLogService.h>
-#include <media/nbaio/NBLog.h>
+#include <media/nblog/NBLog.h>
 
 namespace android {
 
diff --git a/services/medialog/OWNERS b/services/medialog/OWNERS
index fb8b8ee..21723ba 100644
--- a/services/medialog/OWNERS
+++ b/services/medialog/OWNERS
@@ -1,3 +1,3 @@
 elaurent@google.com
-gkasten@android.com
+gkasten@google.com
 hunga@google.com
diff --git a/services/minijail/OWNERS b/services/minijail/OWNERS
new file mode 100644
index 0000000..19f4f9f
--- /dev/null
+++ b/services/minijail/OWNERS
@@ -0,0 +1,2 @@
+jorgelo@google.com
+marcone@google.com
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index 75392bd..549a4e9 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -15,7 +15,7 @@
  */
 
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioClientTracker"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -64,8 +64,7 @@
 // Create a tracker for the client.
 aaudio_result_t AAudioClientTracker::registerClient(pid_t pid,
                                          const sp<IAAudioClient>& client) {
-    ALOGV("AAudioClientTracker::registerClient(), calling pid = %d, getpid() = %d\n",
-          pid, getpid());
+    ALOGV("registerClient(), calling pid = %d, getpid() = %d\n", pid, getpid());
 
     std::lock_guard<std::mutex> lock(mLock);
     if (mNotificationClients.count(pid) == 0) {
@@ -74,18 +73,16 @@
 
         sp<IBinder> binder = IInterface::asBinder(client);
         status_t status = binder->linkToDeath(notificationClient);
-        ALOGW_IF(status != NO_ERROR,
-                 "AAudioClientTracker::registerClient() linkToDeath = %d\n", status);
+        ALOGW_IF(status != NO_ERROR, "registerClient() linkToDeath = %d\n", status);
         return AAudioConvert_androidToAAudioResult(status);
     } else {
-        ALOGW("AAudioClientTracker::registerClient(%d) already registered!", pid);
+        ALOGW("registerClient(%d) already registered!", pid);
         return AAUDIO_OK; // TODO should this be considered an error
     }
 }
 
 void AAudioClientTracker::unregisterClient(pid_t pid) {
-    ALOGV("AAudioClientTracker::unregisterClient(), calling pid = %d, getpid() = %d\n",
-          pid, getpid());
+    ALOGV("unregisterClient(), calling pid = %d, getpid() = %d\n", pid, getpid());
     std::lock_guard<std::mutex> lock(mLock);
     mNotificationClients.erase(pid);
 }
@@ -103,12 +100,12 @@
 aaudio_result_t
 AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
     aaudio_result_t result = AAUDIO_OK;
-    ALOGV("AAudioClientTracker::registerClientStream(%d, %p)\n", pid, serviceStream.get());
+    ALOGV("registerClientStream(%d, %p)\n", pid, serviceStream.get());
     std::lock_guard<std::mutex> lock(mLock);
     sp<NotificationClient> notificationClient = mNotificationClients[pid];
     if (notificationClient == 0) {
         // This will get called the first time the audio server registers an internal stream.
-        ALOGV("AAudioClientTracker::registerClientStream(%d,) unrecognized pid\n", pid);
+        ALOGV("registerClientStream(%d,) unrecognized pid\n", pid);
         notificationClient = new NotificationClient(pid);
         mNotificationClients[pid] = notificationClient;
     }
@@ -120,15 +117,15 @@
 aaudio_result_t
 AAudioClientTracker::unregisterClientStream(pid_t pid,
                                             sp<AAudioServiceStreamBase> serviceStream) {
-    ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
+    ALOGV("unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
     std::lock_guard<std::mutex> lock(mLock);
     auto it = mNotificationClients.find(pid);
     if (it != mNotificationClients.end()) {
-        ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p) found NotificationClient\n",
+        ALOGV("unregisterClientStream(%d, %p) found NotificationClient\n",
               pid, serviceStream.get());
         it->second->unregisterClientStream(serviceStream);
     } else {
-        ALOGE("AAudioClientTracker::unregisterClientStream(%d, %p) missing NotificationClient\n",
+        ALOGE("unregisterClientStream(%d, %p) missing NotificationClient\n",
               pid, serviceStream.get());
     }
     return AAUDIO_OK;
@@ -136,11 +133,11 @@
 
 AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
         : mProcessId(pid) {
-    //ALOGD("AAudioClientTracker::NotificationClient(%d) created %p\n", pid, this);
+    //ALOGD("NotificationClient(%d) created %p\n", pid, this);
 }
 
 AAudioClientTracker::NotificationClient::~NotificationClient() {
-    //ALOGD("AAudioClientTracker::~NotificationClient() destroyed %p\n", this);
+    //ALOGD("~NotificationClient() destroyed %p\n", this);
 }
 
 int32_t AAudioClientTracker::NotificationClient::getStreamCount() {
@@ -172,14 +169,14 @@
 
         {
             std::lock_guard<std::mutex> lock(mLock);
-            for (auto serviceStream : mStreams) {
+            for (const auto& serviceStream : mStreams) {
                 streamsToClose.insert(serviceStream);
             }
         }
 
-        for (auto serviceStream : streamsToClose) {
+        for (const auto& serviceStream : streamsToClose) {
             aaudio_handle_t handle = serviceStream->getHandle();
-            ALOGW("AAudioClientTracker::binderDied() close abandoned stream 0x%08X\n", handle);
+            ALOGW("binderDied() close abandoned stream 0x%08X\n", handle);
             aaudioService->closeStream(handle);
         }
         // mStreams should be empty now
@@ -200,7 +197,7 @@
     }
 
     result << "  client: pid = " << mProcessId << " has " << mStreams.size() << " streams\n";
-    for (auto serviceStream : mStreams) {
+    for (const auto& serviceStream : mStreams) {
         result << "     stream: 0x" << std::hex << serviceStream->getHandle() << std::dec << "\n";
     }
 
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index f996f74..b0c3771 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -102,7 +102,7 @@
         }
     }
 
-    ALOGV("AAudioEndpointManager.findExclusiveEndpoint_l(), found %p for device = %d",
+    ALOGV("findExclusiveEndpoint_l(), found %p for device = %d",
           endpoint.get(), configuration.getDeviceId());
     return endpoint;
 }
@@ -118,7 +118,7 @@
         }
     }
 
-    ALOGV("AAudioEndpointManager.findSharedEndpoint_l(), found %p for device = %d",
+    ALOGV("findSharedEndpoint_l(), found %p for device = %d",
           endpoint.get(), configuration.getDeviceId());
     return endpoint;
 }
@@ -146,23 +146,23 @@
 
     // If we find an existing one then this one cannot be exclusive.
     if (endpoint.get() != nullptr) {
-        ALOGE("AAudioEndpointManager.openExclusiveEndpoint() already in use");
+        ALOGE("openExclusiveEndpoint() already in use");
         // Already open so do not allow a second stream.
         return nullptr;
     } else {
         sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP();
-        ALOGE("AAudioEndpointManager.openEndpoint(),created MMAP %p", endpointMMap.get());
+        ALOGD("openEndpoint(),created MMAP %p", endpointMMap.get());
         endpoint = endpointMMap;
 
         aaudio_result_t result = endpoint->open(request);
         if (result != AAUDIO_OK) {
-            ALOGE("AAudioEndpointManager.openEndpoint(), open failed");
+            ALOGE("openEndpoint(), open failed");
             endpoint.clear();
         } else {
             mExclusiveStreams.push_back(endpointMMap);
         }
 
-        ALOGD("AAudioEndpointManager.openEndpoint(), created %p for device = %d",
+        ALOGD("openEndpoint(), created %p for device = %d",
               endpoint.get(), configuration.getDeviceId());
     }
 
@@ -203,13 +203,13 @@
         if (endpoint.get() != nullptr) {
             aaudio_result_t result = endpoint->open(request);
             if (result != AAUDIO_OK) {
-                ALOGE("AAudioEndpointManager.openEndpoint(), open failed");
+                ALOGE("openSharedEndpoint(), open failed");
                 endpoint.clear();
             } else {
                 mSharedStreams.push_back(endpoint);
             }
         }
-        ALOGD("AAudioEndpointManager.openSharedEndpoint(), created %p for device = %d, dir = %d",
+        ALOGD("openSharedEndpoint(), created %p for device = %d, dir = %d",
               endpoint.get(), configuration.getDeviceId(), (int)direction);
         IPCThreadState::self()->restoreCallingIdentity(token);
     }
@@ -239,14 +239,14 @@
     int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
     serviceEndpoint->setOpenCount(newRefCount);
 
-    // If no longer in use then close and delete it.
+    // If no longer in use then actually close it.
     if (newRefCount <= 0) {
         mExclusiveStreams.erase(
                 std::remove(mExclusiveStreams.begin(), mExclusiveStreams.end(), serviceEndpoint),
                 mExclusiveStreams.end());
 
         serviceEndpoint->close();
-        ALOGD("AAudioEndpointManager::closeExclusiveEndpoint() %p for device %d",
+        ALOGD("closeExclusiveEndpoint() %p for device %d",
               serviceEndpoint.get(), serviceEndpoint->getDeviceId());
     }
 }
@@ -261,14 +261,14 @@
     int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
     serviceEndpoint->setOpenCount(newRefCount);
 
-    // If no longer in use then close and delete it.
+    // If no longer in use then actually close it.
     if (newRefCount <= 0) {
         mSharedStreams.erase(
                 std::remove(mSharedStreams.begin(), mSharedStreams.end(), serviceEndpoint),
                 mSharedStreams.end());
 
         serviceEndpoint->close();
-        ALOGD("AAudioEndpointManager::closeSharedEndpoint() %p for device %d",
+        ALOGD("closeSharedEndpoint() %p for device %d",
               serviceEndpoint.get(), serviceEndpoint->getDeviceId());
     }
 }
diff --git a/services/oboeservice/AAudioMixer.cpp b/services/oboeservice/AAudioMixer.cpp
index 952aa82..b031888 100644
--- a/services/oboeservice/AAudioMixer.cpp
+++ b/services/oboeservice/AAudioMixer.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioMixer"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -49,10 +49,9 @@
     memset(mOutputBuffer, 0, mBufferSizeInBytes);
 }
 
-bool AAudioMixer::mix(int trackIndex, FifoBuffer *fifo, float volume) {
+int32_t AAudioMixer::mix(int streamIndex, FifoBuffer *fifo, bool allowUnderflow) {
     WrappingBuffer wrappingBuffer;
     float *destination = mOutputBuffer;
-    fifo_frames_t framesLeft = mFramesPerBurst;
 
 #if AAUDIO_MIXER_ATRACE_ENABLED
     ATRACE_BEGIN("aaMix");
@@ -63,48 +62,57 @@
 #if AAUDIO_MIXER_ATRACE_ENABLED
     if (ATRACE_ENABLED()) {
         char rdyText[] = "aaMixRdy#";
-        char letter = 'A' + (trackIndex % 26);
+        char letter = 'A' + (streamIndex % 26);
         rdyText[sizeof(rdyText) - 2] = letter;
         ATRACE_INT(rdyText, fullFrames);
     }
 #else /* MIXER_ATRACE_ENABLED */
     (void) trackIndex;
-    (void) fullFrames;
 #endif /* AAUDIO_MIXER_ATRACE_ENABLED */
 
+    // If allowUnderflow then always advance by one burst even if we do not have the data.
+    // Otherwise the stream timing will drift whenever there is an underflow.
+    // This actual underflow can then be detected by the client for XRun counting.
+    //
+    // Generally, allowUnderflow will be false when stopping a stream and we want to
+    // use up whatever data is in the queue.
+    fifo_frames_t framesDesired = mFramesPerBurst;
+    if (!allowUnderflow && fullFrames < framesDesired) {
+        framesDesired = fullFrames; // just use what is available then stop
+    }
+
     // Mix data in one or two parts.
     int partIndex = 0;
+    int32_t framesLeft = framesDesired;
     while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
-        fifo_frames_t framesToMix = framesLeft;
-        fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
-        if (framesAvailable > 0) {
-            if (framesToMix > framesAvailable) {
-                framesToMix = framesAvailable;
+        fifo_frames_t framesToMixFromPart = framesLeft;
+        fifo_frames_t framesAvailableFromPart = wrappingBuffer.numFrames[partIndex];
+        if (framesAvailableFromPart > 0) {
+            if (framesToMixFromPart > framesAvailableFromPart) {
+                framesToMixFromPart = framesAvailableFromPart;
             }
-            mixPart(destination, (float *)wrappingBuffer.data[partIndex], framesToMix, volume);
+            mixPart(destination, (float *)wrappingBuffer.data[partIndex],
+                    framesToMixFromPart);
 
-            destination += framesToMix * mSamplesPerFrame;
-            framesLeft -= framesToMix;
+            destination += framesToMixFromPart * mSamplesPerFrame;
+            framesLeft -= framesToMixFromPart;
         }
         partIndex++;
     }
-    // Always advance by one burst even if we do not have the data.
-    // Otherwise the stream timing will drift whenever there is an underflow.
-    // This actual underflow can then be detected by the client for XRun counting.
-    fifo->getFifoControllerBase()->advanceReadIndex(mFramesPerBurst);
+    fifo->getFifoControllerBase()->advanceReadIndex(framesDesired);
 
 #if AAUDIO_MIXER_ATRACE_ENABLED
     ATRACE_END();
 #endif /* AAUDIO_MIXER_ATRACE_ENABLED */
 
-    return (framesLeft > 0); // did not get all the frames we needed, ie. "underflow"
+    return (framesDesired - framesLeft); // framesRead
 }
 
-void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames, float volume) {
+void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames) {
     int32_t numSamples = numFrames * mSamplesPerFrame;
     // TODO maybe optimize using SIMD
     for (int sampleIndex = 0; sampleIndex < numSamples; sampleIndex++) {
-        *destination++ += *source++ * volume;
+        *destination++ += *source++;
     }
 }
 
diff --git a/services/oboeservice/AAudioMixer.h b/services/oboeservice/AAudioMixer.h
index a8090bc..d5abc5b 100644
--- a/services/oboeservice/AAudioMixer.h
+++ b/services/oboeservice/AAudioMixer.h
@@ -33,22 +33,24 @@
 
     /**
      * Mix from this FIFO
-     * @param fifo
-     * @param volume
-     * @return true if underflowed
+     * @param streamIndex for marking stream variables in systrace
+     * @param fifo to read from
+     * @param allowUnderflow if true then allow mixer to advance read index past the write index
+     * @return frames read from this stream
      */
-    bool mix(int trackIndex, android::FifoBuffer *fifo, float volume);
-
-    void mixPart(float *destination, float *source, int32_t numFrames, float volume);
+    int32_t mix(int streamIndex, android::FifoBuffer *fifo, bool allowUnderflow);
 
     float *getOutputBuffer();
 
+    int32_t getFramesPerBurst() const { return mFramesPerBurst; }
+
 private:
+    void mixPart(float *destination, float *source, int32_t numFrames);
+
     float   *mOutputBuffer = nullptr;
     int32_t  mSamplesPerFrame = 0;
     int32_t  mFramesPerBurst = 0;
     int32_t  mBufferSizeInBytes = 0;
 };
 
-
 #endif //AAUDIO_AAUDIO_MIXER_H
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 5a3488d..51ae665 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -92,14 +92,14 @@
     if (pid != mAudioClient.clientPid) {
         int32_t count = AAudioClientTracker::getInstance().getStreamCount(pid);
         if (count >= MAX_STREAMS_PER_PROCESS) {
-            ALOGE("AAudioService::openStream(): exceeded max streams per process %d >= %d",
+            ALOGE("openStream(): exceeded max streams per process %d >= %d",
                   count,  MAX_STREAMS_PER_PROCESS);
             return AAUDIO_ERROR_UNAVAILABLE;
         }
     }
 
     if (sharingMode != AAUDIO_SHARING_MODE_EXCLUSIVE && sharingMode != AAUDIO_SHARING_MODE_SHARED) {
-        ALOGE("AAudioService::openStream(): unrecognized sharing mode = %d", sharingMode);
+        ALOGE("openStream(): unrecognized sharing mode = %d", sharingMode);
         return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
     }
 
@@ -114,7 +114,7 @@
         result = serviceStream->open(request);
         if (result != AAUDIO_OK) {
             // Clear it so we can possibly fall back to using a shared stream.
-            ALOGW("AAudioService::openStream(), could not open in EXCLUSIVE mode");
+            ALOGW("openStream(), could not open in EXCLUSIVE mode");
             serviceStream.clear();
         }
     }
@@ -128,12 +128,12 @@
 
     if (result != AAUDIO_OK) {
         serviceStream.clear();
-        ALOGE("AAudioService::openStream(): failed, return %d = %s",
+        ALOGE("openStream(): failed, return %d = %s",
               result, AAudio_convertResultToText(result));
         return result;
     } else {
         aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
-        ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
+        ALOGD("openStream(): handle = 0x%08X", handle);
         serviceStream->setHandle(handle);
         pid_t pid = request.getProcessId();
         AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
@@ -146,11 +146,11 @@
     // Check permission and ownership first.
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::closeStream(0x%0x), illegal stream handle", streamHandle);
+        ALOGE("closeStream(0x%0x), illegal stream handle", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 
-    ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
+    ALOGD("closeStream(0x%08X)", streamHandle);
     // Remove handle from tracker so that we cannot look up the raw address any more.
     // removeStreamByHandle() uses a lock so that if there are two simultaneous closes
     // then only one will get the pointer and do the close.
@@ -161,7 +161,7 @@
         AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
         return AAUDIO_OK;
     } else {
-        ALOGW("AAudioService::closeStream(0x%0x) being handled by another thread", streamHandle);
+        ALOGW("closeStream(0x%0x) being handled by another thread", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 }
@@ -192,7 +192,7 @@
                 aaudio::AudioEndpointParcelable &parcelable) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
+        ALOGE("getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 
@@ -204,7 +204,7 @@
 aaudio_result_t AAudioService::startStream(aaudio_handle_t streamHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
+        ALOGE("startStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 
@@ -214,7 +214,7 @@
 aaudio_result_t AAudioService::pauseStream(aaudio_handle_t streamHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::pauseStream(), illegal stream handle = 0x%0x", streamHandle);
+        ALOGE("pauseStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     aaudio_result_t result = serviceStream->pause();
@@ -224,7 +224,7 @@
 aaudio_result_t AAudioService::stopStream(aaudio_handle_t streamHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::stopStream(), illegal stream handle = 0x%0x", streamHandle);
+        ALOGE("stopStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     aaudio_result_t result = serviceStream->stop();
@@ -234,7 +234,7 @@
 aaudio_result_t AAudioService::flushStream(aaudio_handle_t streamHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::flushStream(), illegal stream handle = 0x%0x", streamHandle);
+        ALOGE("flushStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     return serviceStream->flush();
@@ -245,11 +245,11 @@
                                                    int64_t periodNanoseconds) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
+        ALOGE("registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     if (serviceStream->getRegisteredThread() != AAudioServiceStreamBase::ILLEGAL_THREAD_ID) {
-        ALOGE("AAudioService::registerAudioThread(), thread already registered");
+        ALOGE("registerAudioThread(), thread already registered");
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
@@ -258,7 +258,7 @@
     int err = android::requestPriority(ownerPid, clientThreadId,
                                        DEFAULT_AUDIO_PRIORITY, true /* isForApp */);
     if (err != 0){
-        ALOGE("AAudioService::registerAudioThread(%d) failed, errno = %d, priority = %d",
+        ALOGE("registerAudioThread(%d) failed, errno = %d, priority = %d",
               clientThreadId, errno, DEFAULT_AUDIO_PRIORITY);
         return AAUDIO_ERROR_INTERNAL;
     } else {
@@ -270,12 +270,11 @@
                                                      pid_t clientThreadId) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::unregisterAudioThread(), illegal stream handle = 0x%0x",
-              streamHandle);
+        ALOGE("unregisterAudioThread(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     if (serviceStream->getRegisteredThread() != clientThreadId) {
-        ALOGE("AAudioService::unregisterAudioThread(), wrong thread");
+        ALOGE("unregisterAudioThread(), wrong thread");
         return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
     }
     serviceStream->setRegisteredThread(0);
@@ -287,8 +286,7 @@
                                   audio_port_handle_t *clientHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::startClient(), illegal stream handle = 0x%0x",
-              streamHandle);
+        ALOGE("startClient(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     return serviceStream->startClient(client, clientHandle);
@@ -298,8 +296,7 @@
                                           audio_port_handle_t clientHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
-        ALOGE("AAudioService::stopClient(), illegal stream handle = 0x%0x",
-              streamHandle);
+        ALOGE("stopClient(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     return serviceStream->stopClient(clientHandle);
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 3095bc9..f917675 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -60,6 +60,7 @@
     result << "    Reference Count:      " << mOpenCount << "\n";
     result << "    Requested Device Id:  " << mRequestedDeviceId << "\n";
     result << "    Device Id:            " << getDeviceId() << "\n";
+    result << "    Connected:            " << mConnected.load() << "\n";
     result << "    Registered Streams:" << "\n";
     result << AAudioServiceStreamShared::dumpHeader() << "\n";
     for (const auto stream : mRegisteredStreams) {
@@ -74,7 +75,9 @@
 
 void AAudioServiceEndpoint::disconnectRegisteredStreams() {
     std::lock_guard<std::mutex> lock(mLockStreams);
+    mConnected.store(false);
     for (const auto stream : mRegisteredStreams) {
+        ALOGD("disconnectRegisteredStreams() stop and disconnect %p", stream.get());
         stream->stop();
         stream->disconnect();
     }
@@ -96,6 +99,9 @@
 }
 
 bool AAudioServiceEndpoint::matches(const AAudioStreamConfiguration& configuration) {
+    if (!mConnected.load()) {
+        return false; // Only use an endpoint if it is connected to a device.
+    }
     if (configuration.getDirection() != getDirection()) {
         return false;
     }
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 2ef6234..6312c51 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -97,6 +97,10 @@
         mOpenCount = count;
     }
 
+    bool isConnected() const {
+        return mConnected;
+    }
+
 protected:
     void                     disconnectRegisteredStreams();
 
@@ -111,6 +115,8 @@
     int32_t                  mOpenCount = 0;
     int32_t                  mRequestedDeviceId = 0;
 
+    std::atomic<bool>        mConnected{true};
+
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index c7d9b8e..efac788 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceEndpointCapture"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -57,8 +57,7 @@
 
 // Read data from the shared MMAP stream and then distribute it to the client streams.
 void *AAudioServiceEndpointCapture::callbackLoop() {
-    ALOGD("AAudioServiceEndpointCapture(): callbackLoop() entering");
-    int32_t underflowCount = 0;
+    ALOGD("callbackLoop() entering");
     aaudio_result_t result = AAUDIO_OK;
     int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
 
@@ -73,7 +72,7 @@
             disconnectRegisteredStreams();
             break;
         } else if (result != getFramesPerBurst()) {
-            ALOGW("AAudioServiceEndpointCapture(): callbackLoop() read %d / %d",
+            ALOGW("callbackLoop() read %d / %d",
                   result, getFramesPerBurst());
             break;
         }
@@ -102,9 +101,10 @@
                             int64_t positionOffset = mmapFramesRead - clientFramesWritten;
                             streamShared->setTimestampPositionOffset(positionOffset);
 
+                            // Is the buffer too full to write a burst?
                             if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
-                                getFramesPerBurst()) {
-                                underflowCount++;
+                                    getFramesPerBurst()) {
+                                streamShared->incrementXRunCount();
                             } else {
                                 fifo->write(mDistributionBuffer, getFramesPerBurst());
                             }
@@ -125,6 +125,6 @@
         }
     }
 
-    ALOGD("AAudioServiceEndpointCapture(): callbackLoop() exiting, %d underflows", underflowCount);
+    ALOGD("callbackLoop() exiting");
     return NULL; // TODO review
 }
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 7e6e247..a61994d 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -140,7 +140,7 @@
                                                           this, // callback
                                                           mMmapStream,
                                                           &mPortHandle);
-    ALOGD("AAudioServiceEndpointMMAP::open() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
+    ALOGD("open() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
           mMmapClient.clientUid,  mMmapClient.clientPid, mPortHandle);
     if (status != OK) {
         ALOGE("openMmapStream returned status %d", status);
@@ -148,7 +148,7 @@
     }
 
     if (deviceId == AAUDIO_UNSPECIFIED) {
-        ALOGW("AAudioServiceEndpointMMAP::open() - openMmapStream() failed to set deviceId");
+        ALOGW("open() - openMmapStream() failed to set deviceId");
     }
     setDeviceId(deviceId);
 
@@ -159,7 +159,7 @@
     }
     status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
     if (status != OK) {
-        ALOGE("AAudioServiceEndpointMMAP::open() - createMmapBuffer() failed with status %d %s",
+        ALOGE("open() - createMmapBuffer() failed with status %d %s",
               status, strerror(-status));
         result = AAUDIO_ERROR_UNAVAILABLE;
         goto error;
@@ -186,7 +186,7 @@
             // Fallback is handled by caller but indicate what is possible in case
             // this is used in the future
             setSharingMode(AAUDIO_SHARING_MODE_SHARED);
-            ALOGW("AAudioServiceEndpointMMAP::open() - exclusive FD cannot be used by client");
+            ALOGW("open() - exclusive FD cannot be used by client");
             result = AAUDIO_ERROR_UNAVAILABLE;
             goto error;
         }
@@ -201,7 +201,7 @@
     // Assume that AudioFlinger will close the original shared_memory_fd.
     mAudioDataFileDescriptor.reset(dup(mMmapBufferinfo.shared_memory_fd));
     if (mAudioDataFileDescriptor.get() == -1) {
-        ALOGE("AAudioServiceEndpointMMAP::open() - could not dup shared_memory_fd");
+        ALOGE("open() - could not dup shared_memory_fd");
         result = AAUDIO_ERROR_INTERNAL;
         goto error;
     }
@@ -219,10 +219,10 @@
         burstMicros = mFramesPerBurst * static_cast<int64_t>(1000000) / getSampleRate();
     } while (burstMicros < burstMinMicros);
 
-    ALOGD("AAudioServiceEndpointMMAP::open() original burst = %d, minMicros = %d, to burst = %d\n",
+    ALOGD("open() original burst = %d, minMicros = %d, to burst = %d\n",
           mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
 
-    ALOGD("AAudioServiceEndpointMMAP::open() actual rate = %d, channels = %d"
+    ALOGD("open() actual rate = %d, channels = %d"
           ", deviceId = %d, capacity = %d\n",
           getSampleRate(), getSamplesPerFrame(), deviceId, getBufferCapacity());
 
@@ -236,7 +236,7 @@
 aaudio_result_t AAudioServiceEndpointMMAP::close() {
 
     if (mMmapStream != 0) {
-        ALOGD("AAudioServiceEndpointMMAP::close() clear() endpoint");
+        ALOGD("close() clear() endpoint");
         // Needs to be explicitly cleared or CTS will fail but it is not clear why.
         mMmapStream.clear();
         // Apparently the above close is asynchronous. An attempt to open a new device
@@ -271,12 +271,12 @@
 aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
                                                        audio_port_handle_t *clientHandle) {
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
-    ALOGD("AAudioServiceEndpointMMAP::startClient(%p(uid=%d, pid=%d))",
+    ALOGD("startClient(%p(uid=%d, pid=%d))",
           &client, client.clientUid, client.clientPid);
     audio_port_handle_t originalHandle =  *clientHandle;
     status_t status = mMmapStream->start(client, clientHandle);
     aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
-    ALOGD("AAudioServiceEndpointMMAP::startClient() , %d => %d returns %d",
+    ALOGD("startClient() , %d => %d returns %d",
           originalHandle, *clientHandle, result);
     return result;
 }
@@ -284,7 +284,7 @@
 aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t clientHandle) {
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
     aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
-    ALOGD("AAudioServiceEndpointMMAP::stopClient(%d) returns %d", clientHandle, result);
+    ALOGD("stopClient(%d) returns %d", clientHandle, result);
     return result;
 }
 
@@ -296,7 +296,7 @@
         return AAUDIO_ERROR_NULL;
     }
     status_t status = mMmapStream->getMmapPosition(&position);
-    ALOGV("AAudioServiceEndpointMMAP::getFreeRunningPosition() status= %d, pos = %d, nanos = %lld\n",
+    ALOGV("getFreeRunningPosition() status= %d, pos = %d, nanos = %lld\n",
           status, position.position_frames, (long long) position.time_nanoseconds);
     aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
     if (result == AAUDIO_ERROR_UNAVAILABLE) {
@@ -319,7 +319,7 @@
 
 
 void AAudioServiceEndpointMMAP::onTearDown() {
-    ALOGD("AAudioServiceEndpointMMAP::onTearDown() called");
+    ALOGD("onTearDown() called");
     disconnectRegisteredStreams();
 };
 
@@ -327,7 +327,7 @@
                                               android::Vector<float> values) {
     // TODO do we really need a different volume for each channel?
     float volume = values[0];
-    ALOGD("AAudioServiceEndpointMMAP::onVolumeChanged() volume[0] = %f", volume);
+    ALOGD("onVolumeChanged() volume[0] = %f", volume);
     std::lock_guard<std::mutex> lock(mLockStreams);
     for(const auto stream : mRegisteredStreams) {
         stream->onVolumeChanged(volume);
@@ -335,7 +335,7 @@
 };
 
 void AAudioServiceEndpointMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
-    ALOGD("AAudioServiceEndpointMMAP::onRoutingChanged() called with %d, old = %d",
+    ALOGD("onRoutingChanged() called with dev %d, old = %d",
           deviceId, getDeviceId());
     if (getDeviceId() != AUDIO_PORT_HANDLE_NONE  && getDeviceId() != deviceId) {
         disconnectRegisteredStreams();
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 9b1833a..2601f3f 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -34,6 +34,7 @@
 #include "AAudioServiceStreamShared.h"
 #include "AAudioServiceEndpointPlay.h"
 #include "AAudioServiceEndpointShared.h"
+#include "AAudioServiceStreamBase.h"
 
 using namespace android;  // TODO just import names needed
 using namespace aaudio;   // TODO just import names needed
@@ -82,9 +83,13 @@
             std::lock_guard <std::mutex> lock(mLockStreams);
             for (const auto clientStream : mRegisteredStreams) {
                 int64_t clientFramesRead = 0;
+                bool allowUnderflow = true;
 
-                if (!clientStream->isRunning()) {
-                    continue;
+                aaudio_stream_state_t state = clientStream->getState();
+                if (state == AAUDIO_STREAM_STATE_STOPPING) {
+                    allowUnderflow = false; // just read what is already in the FIFO
+                } else if (state != AAUDIO_STREAM_STATE_STARTED) {
+                    continue; // this stream is not running so skip it.
                 }
 
                 sp<AAudioServiceStreamShared> streamShared =
@@ -104,10 +109,19 @@
                         int64_t positionOffset = mmapFramesWritten - clientFramesRead;
                         streamShared->setTimestampPositionOffset(positionOffset);
 
-                        float volume = 1.0; // to match legacy volume
-                        bool underflowed = mMixer.mix(index, fifo, volume);
-                        if (underflowed) {
-                            streamShared->incrementXRunCount();
+                        int32_t framesMixed = mMixer.mix(index, fifo, allowUnderflow);
+
+                        if (streamShared->isFlowing()) {
+                            // Consider it an underflow if we got less than a burst
+                            // after the data started flowing.
+                            bool underflowed = allowUnderflow
+                                               && framesMixed < mMixer.getFramesPerBurst();
+                            if (underflowed) {
+                                streamShared->incrementXRunCount();
+                            }
+                        } else if (framesMixed > 0) {
+                            // Mark beginning of data flow after a start.
+                            streamShared->setFlowing(true);
                         }
                         clientFramesRead = fifo->getReadCounter();
                     }
@@ -132,7 +146,7 @@
             AAudioServiceEndpointShared::disconnectRegisteredStreams();
             break;
         } else if (result != getFramesPerBurst()) {
-            ALOGW("AAudioServiceEndpoint(): callbackLoop() wrote %d / %d",
+            ALOGW("callbackLoop() wrote %d / %d",
                   result, getFramesPerBurst());
             break;
         }
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index cd40066..6af9e7e 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -47,6 +47,7 @@
            << std::setfill('0') << std::setw(8)
            << std::hex << mStreamInternal->getServiceHandle()
            << std::dec << std::setfill(' ');
+    result << ", XRuns = " << mStreamInternal->getXRunCount();
     result << "\n";
     result << "    Running Stream Count: " << mRunningStreamCount << "\n";
 
@@ -91,7 +92,12 @@
 static void *aaudio_endpoint_thread_proc(void *context) {
     AAudioServiceEndpointShared *endpoint = (AAudioServiceEndpointShared *) context;
     if (endpoint != NULL) {
-        return endpoint->callbackLoop();
+        void *result = endpoint->callbackLoop();
+        // Close now so that the HW resource is freed and we can open a new device.
+        if (!endpoint->isConnected()) {
+            endpoint->close();
+        }
+        return result;
     } else {
         return NULL;
     }
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index e3bd2c1..74cd817 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -30,8 +30,7 @@
 namespace aaudio {
 
 /**
- * This Service class corresponds to a Client stream that shares an MMAP device through a mixer
- * or an input distributor.
+ * This manages an internal stream that is shared by multiple Client streams.
  */
 class AAudioServiceEndpointShared : public AAudioServiceEndpoint {
 
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index ff0b037..635b45c 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -51,7 +51,7 @@
 }
 
 AAudioServiceStreamBase::~AAudioServiceStreamBase() {
-    ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroying %p", this);
+    ALOGD("~AAudioServiceStreamBase() destroying %p", this);
     // If the stream is deleted when OPEN or in use then audio resources will leak.
     // This would indicate an internal error. So we want to find this ASAP.
     LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
@@ -93,7 +93,7 @@
     {
         std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
         if (mUpMessageQueue != nullptr) {
-            ALOGE("AAudioServiceStreamBase::open() called twice");
+            ALOGE("open() called twice");
             return AAUDIO_ERROR_INVALID_STATE;
         }
 
@@ -108,7 +108,7 @@
                                                          request,
                                                          sharingMode);
         if (mServiceEndpoint == nullptr) {
-            ALOGE("AAudioServiceStreamBase::open() openEndpoint() failed");
+            ALOGE("open() openEndpoint() failed");
             result = AAUDIO_ERROR_UNAVAILABLE;
             goto error;
         }
@@ -167,11 +167,13 @@
     }
 
     if (mServiceEndpoint == nullptr) {
-        ALOGE("AAudioServiceStreamBase::start() missing endpoint");
+        ALOGE("start() missing endpoint");
         result = AAUDIO_ERROR_INVALID_STATE;
         goto error;
     }
 
+    setFlowing(false);
+
     // Start with fresh presentation timestamps.
     mAtomicTimestamp.clear();
 
@@ -199,7 +201,7 @@
         return result;
     }
     if (mServiceEndpoint == nullptr) {
-        ALOGE("AAudioServiceStreamShared::pause() missing endpoint");
+        ALOGE("pause() missing endpoint");
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
@@ -215,7 +217,7 @@
 
     result = mServiceEndpoint->stopStream(this, mClientHandle);
     if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
+        ALOGE("pause() mServiceEndpoint returned %d", result);
         disconnect(); // TODO should we return or pause Base first?
     }
 
@@ -231,10 +233,12 @@
     }
 
     if (mServiceEndpoint == nullptr) {
-        ALOGE("AAudioServiceStreamShared::stop() missing endpoint");
+        ALOGE("stop() missing endpoint");
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
+    setState(AAUDIO_STREAM_STATE_STOPPING);
+
     // Send it now because the timestamp gets rounded up when stopStream() is called below.
     // Also we don't need the timestamps while we are shutting down.
     sendCurrentTimestamp(); // warning - this calls a virtual function
@@ -247,7 +251,7 @@
     // TODO wait for data to be played out
     result = mServiceEndpoint->stopStream(this, mClientHandle);
     if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamShared::stop() mServiceEndpoint returned %d", result);
+        ALOGE("stop() mServiceEndpoint returned %d", result);
         disconnect();
         // TODO what to do with result here?
     }
@@ -268,7 +272,7 @@
 
 aaudio_result_t AAudioServiceStreamBase::flush() {
     if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
-        ALOGE("AAudioServiceStreamBase::flush() stream not paused, state = %s",
+        ALOGE("flush() stream not paused, state = %s",
               AAudio_convertStreamStateToText(mState));
         return AAUDIO_ERROR_INVALID_STATE;
     }
@@ -280,7 +284,7 @@
 
 // implement Runnable, periodically send timestamps to client
 void AAudioServiceStreamBase::run() {
-    ALOGD("AAudioServiceStreamBase::run() entering ----------------");
+    ALOGD("run() entering ----------------");
     TimestampScheduler timestampScheduler;
     timestampScheduler.setBurstPeriod(mFramesPerBurst, getSampleRate());
     timestampScheduler.start(AudioClock::getNanoseconds());
@@ -298,7 +302,7 @@
             AudioClock::sleepUntilNanoTime(nextTime);
         }
     }
-    ALOGD("AAudioServiceStreamBase::run() exiting ----------------");
+    ALOGD("run() exiting ----------------");
 }
 
 void AAudioServiceStreamBase::disconnect() {
@@ -309,12 +313,19 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::sendServiceEvent(aaudio_service_event_t event,
-                                               double  dataDouble,
-                                               int64_t dataLong) {
+                                                          double  dataDouble) {
     AAudioServiceMessage command;
     command.what = AAudioServiceMessage::code::EVENT;
     command.event.event = event;
     command.event.dataDouble = dataDouble;
+    return writeUpMessageQueue(&command);
+}
+
+aaudio_result_t AAudioServiceStreamBase::sendServiceEvent(aaudio_service_event_t event,
+                                                          int64_t dataLong) {
+    AAudioServiceMessage command;
+    command.what = AAudioServiceMessage::code::EVENT;
+    command.event.event = event;
     command.event.dataLong = dataLong;
     return writeUpMessageQueue(&command);
 }
@@ -334,6 +345,10 @@
     }
 }
 
+aaudio_result_t AAudioServiceStreamBase::sendXRunCount(int32_t xRunCount) {
+    return sendServiceEvent(AAUDIO_SERVICE_EVENT_XRUN, (int64_t) xRunCount);
+}
+
 aaudio_result_t AAudioServiceStreamBase::sendCurrentTimestamp() {
     AAudioServiceMessage command;
     // Send a timestamp for the clock model.
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index af435b4..29987f6 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -129,11 +129,15 @@
     // -------------------------------------------------------------------
 
     /**
-     * Send a message to the client.
+     * Send a message to the client with an int64_t data value.
      */
     aaudio_result_t sendServiceEvent(aaudio_service_event_t event,
-                                     double  dataDouble = 0.0,
                                      int64_t dataLong = 0);
+    /**
+     * Send a message to the client with an double data value.
+     */
+    aaudio_result_t sendServiceEvent(aaudio_service_event_t event,
+                                     double  dataDouble);
 
     /**
      * Fill in a parcelable description of stream.
@@ -182,6 +186,19 @@
 
     void onVolumeChanged(float volume);
 
+    /**
+     * Set false when the stream is started.
+     * Set true when data is first read from the stream.
+     * @param b
+     */
+    void setFlowing(bool b) {
+        mFlowing = b;
+    }
+
+    bool isFlowing() const {
+        return mFlowing;
+    }
+
 protected:
 
     /**
@@ -204,6 +221,8 @@
 
     aaudio_result_t sendCurrentTimestamp();
 
+    aaudio_result_t sendXRunCount(int32_t xRunCount);
+
     /**
      * @param positionFrames
      * @param timeNanos
@@ -237,6 +256,8 @@
 
 private:
     aaudio_handle_t         mHandle = -1;
+
+    bool                    mFlowing = false;
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 44ba1ca..34ddb4b 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -81,9 +81,7 @@
     return AAUDIO_OK;
 }
 
-/**
- * Start the flow of data.
- */
+// Start the flow of data.
 aaudio_result_t AAudioServiceStreamMMAP::startDevice() {
     aaudio_result_t result = AAudioServiceStreamBase::startDevice();
     if (!mInService && result == AAUDIO_OK) {
@@ -93,9 +91,7 @@
     return result;
 }
 
-/**
- * Stop the flow of data such that start() can resume with loss of data.
- */
+// Stop the flow of data such that start() can resume with loss of data.
 aaudio_result_t AAudioServiceStreamMMAP::pause() {
     if (!isRunning()) {
         return AAUDIO_OK;
@@ -165,9 +161,7 @@
     }
 }
 
-/**
- * Get an immutable description of the data queue from the HAL.
- */
+// Get an immutable description of the data queue from the HAL.
 aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription(
         AudioEndpointParcelable &parcelable)
 {
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 084f996..75d88cf 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -74,7 +74,7 @@
                                                            int32_t framesPerBurst) {
 
     if (requestedCapacityFrames > MAX_FRAMES_PER_BUFFER) {
-        ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() requested capacity %d > max %d",
+        ALOGE("calculateBufferCapacity() requested capacity %d > max %d",
               requestedCapacityFrames, MAX_FRAMES_PER_BUFFER);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
@@ -99,7 +99,7 @@
     }
     // Check for numeric overflow.
     if (numBursts > 0x8000 || framesPerBurst > 0x8000) {
-        ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() overflow, capacity = %d * %d",
+        ALOGE("calculateBufferCapacity() overflow, capacity = %d * %d",
               numBursts, framesPerBurst);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
@@ -107,11 +107,11 @@
 
     // Final sanity check.
     if (capacityInFrames > MAX_FRAMES_PER_BUFFER) {
-        ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() calc capacity %d > max %d",
+        ALOGE("calculateBufferCapacity() calc capacity %d > max %d",
               capacityInFrames, MAX_FRAMES_PER_BUFFER);
         return AAUDIO_ERROR_OUT_OF_RANGE;
     }
-    ALOGD("AAudioServiceStreamShared::calculateBufferCapacity() requested %d frames, actual = %d",
+    ALOGD("calculateBufferCapacity() requested %d frames, actual = %d",
           requestedCapacityFrames, capacityInFrames);
     return capacityInFrames;
 }
@@ -122,7 +122,7 @@
 
     aaudio_result_t result = AAudioServiceStreamBase::open(request, AAUDIO_SHARING_MODE_SHARED);
     if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamBase open() returned %d", result);
+        ALOGE("open() returned %d", result);
         return result;
     }
 
@@ -134,7 +134,7 @@
     if (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) {
         setFormat(AAUDIO_FORMAT_PCM_FLOAT);
     } else if (getFormat() != AAUDIO_FORMAT_PCM_FLOAT) {
-        ALOGE("AAudioServiceStreamShared::open() mAudioFormat = %d, need FLOAT", getFormat());
+        ALOGE("open() mAudioFormat = %d, need FLOAT", getFormat());
         result = AAUDIO_ERROR_INVALID_FORMAT;
         goto error;
     }
@@ -143,7 +143,7 @@
     if (getSampleRate() == AAUDIO_UNSPECIFIED) {
         setSampleRate(mServiceEndpoint->getSampleRate());
     } else if (getSampleRate() != mServiceEndpoint->getSampleRate()) {
-        ALOGE("AAudioServiceStreamShared::open() mSampleRate = %d, need %d",
+        ALOGE("open() mSampleRate = %d, need %d",
               getSampleRate(), mServiceEndpoint->getSampleRate());
         result = AAUDIO_ERROR_INVALID_RATE;
         goto error;
@@ -153,7 +153,7 @@
     if (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) {
         setSamplesPerFrame(mServiceEndpoint->getSamplesPerFrame());
     } else if (getSamplesPerFrame() != mServiceEndpoint->getSamplesPerFrame()) {
-        ALOGE("AAudioServiceStreamShared::open() mSamplesPerFrame = %d, need %d",
+        ALOGE("open() mSamplesPerFrame = %d, need %d",
               getSamplesPerFrame(), mServiceEndpoint->getSamplesPerFrame());
         result = AAUDIO_ERROR_OUT_OF_RANGE;
         goto error;
@@ -173,14 +173,14 @@
         mAudioDataQueue = new SharedRingBuffer();
         result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
         if (result != AAUDIO_OK) {
-            ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
+            ALOGE("open() could not allocate FIFO with %d frames",
                   getBufferCapacity());
             result = AAUDIO_ERROR_NO_MEMORY;
             goto error;
         }
     }
 
-    ALOGD("AAudioServiceStreamShared::open() actual rate = %d, channels = %d, deviceId = %d",
+    ALOGD("open() actual rate = %d, channels = %d, deviceId = %d",
           getSampleRate(), getSamplesPerFrame(), mServiceEndpoint->getDeviceId());
 
     result = mServiceEndpoint->registerStream(keep);
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 8499ea5..3b12e61 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -1,4 +1,4 @@
-/*
+ /*
  * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -80,7 +80,7 @@
     }
 
     void incrementXRunCount() {
-        mXRunCount++;
+        sendXRunCount(++mXRunCount);
     }
 
     int32_t getXRunCount() const {
diff --git a/services/oboeservice/AAudioThread.cpp b/services/oboeservice/AAudioThread.cpp
index c6fb57d..fbb0da4 100644
--- a/services/oboeservice/AAudioThread.cpp
+++ b/services/oboeservice/AAudioThread.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioThread"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -53,7 +53,7 @@
 
 aaudio_result_t AAudioThread::start(Runnable *runnable) {
     if (mHasThread) {
-        ALOGE("AAudioThread::start() - mHasThread already true");
+        ALOGE("start() - mHasThread already true");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     // mRunnable will be read by the new thread when it starts.
@@ -61,7 +61,7 @@
     mRunnable = runnable;
     int err = pthread_create(&mThread, nullptr, AAudioThread_internalThreadProc, this);
     if (err != 0) {
-        ALOGE("AAudioThread::start() - pthread_create() returned %d %s", err, strerror(err));
+        ALOGE("start() - pthread_create() returned %d %s", err, strerror(err));
         return AAudioConvert_androidToAAudioResult(-err);
     } else {
         mHasThread = true;
@@ -71,13 +71,13 @@
 
 aaudio_result_t AAudioThread::stop() {
     if (!mHasThread) {
-        ALOGE("AAudioThread::stop() but no thread running");
+        ALOGE("stop() but no thread running");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     int err = pthread_join(mThread, nullptr);
     mHasThread = false;
     if (err != 0) {
-        ALOGE("AAudioThread::stop() - pthread_join() returned %d %s", err, strerror(err));
+        ALOGE("stop() - pthread_join() returned %d %s", err, strerror(err));
         return AAudioConvert_androidToAAudioResult(-err);
     } else {
         return AAUDIO_OK;
diff --git a/services/oboeservice/SharedMemoryProxy.cpp b/services/oboeservice/SharedMemoryProxy.cpp
index fb991bb..c43ed22 100644
--- a/services/oboeservice/SharedMemoryProxy.cpp
+++ b/services/oboeservice/SharedMemoryProxy.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "SharedMemoryProxy"
 //#define LOG_NDEBUG 0
 #include <log/log.h>
 
@@ -45,12 +45,12 @@
 
     mProxyFileDescriptor = ashmem_create_region("AAudioProxyDataBuffer", mSharedMemorySizeInBytes);
     if (mProxyFileDescriptor < 0) {
-        ALOGE("SharedMemoryProxy::open() ashmem_create_region() failed %d", errno);
+        ALOGE("open() ashmem_create_region() failed %d", errno);
         return AAUDIO_ERROR_INTERNAL;
     }
     int err = ashmem_set_prot_region(mProxyFileDescriptor, PROT_READ|PROT_WRITE);
     if (err < 0) {
-        ALOGE("SharedMemoryProxy::open() ashmem_set_prot_region() failed %d", errno);
+        ALOGE("open() ashmem_set_prot_region() failed %d", errno);
         close(mProxyFileDescriptor);
         mProxyFileDescriptor = -1;
         return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
@@ -62,7 +62,7 @@
                          MAP_SHARED,
                          mOriginalFileDescriptor, 0);
     if (mOriginalSharedMemory == MAP_FAILED) {
-        ALOGE("SharedMemoryProxy::open() original mmap(%d) failed %d (%s)",
+        ALOGE("open() original mmap(%d) failed %d (%s)",
                 mOriginalFileDescriptor, errno, strerror(errno));
         return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
     }
@@ -73,7 +73,7 @@
                          MAP_SHARED,
                          mProxyFileDescriptor, 0);
     if (mProxySharedMemory != mOriginalSharedMemory) {
-        ALOGE("SharedMemoryProxy::open() proxy mmap(%d) failed %d", mProxyFileDescriptor, errno);
+        ALOGE("open() proxy mmap(%d) failed %d", mProxyFileDescriptor, errno);
         munmap(mOriginalSharedMemory, mSharedMemorySizeInBytes);
         mOriginalSharedMemory = nullptr;
         close(mProxyFileDescriptor);
diff --git a/services/oboeservice/SharedRingBuffer.cpp b/services/oboeservice/SharedRingBuffer.cpp
index 83b25b3..2454446 100644
--- a/services/oboeservice/SharedRingBuffer.cpp
+++ b/services/oboeservice/SharedRingBuffer.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "SharedRingBuffer"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -46,14 +46,14 @@
     mSharedMemorySizeInBytes = mDataMemorySizeInBytes + (2 * (sizeof(fifo_counter_t)));
     mFileDescriptor.reset(ashmem_create_region("AAudioSharedRingBuffer", mSharedMemorySizeInBytes));
     if (mFileDescriptor.get() == -1) {
-        ALOGE("SharedRingBuffer::allocate() ashmem_create_region() failed %d", errno);
+        ALOGE("allocate() ashmem_create_region() failed %d", errno);
         return AAUDIO_ERROR_INTERNAL;
     }
-    ALOGV("SharedRingBuffer::allocate() mFileDescriptor = %d\n", mFileDescriptor.get());
+    ALOGV("allocate() mFileDescriptor = %d\n", mFileDescriptor.get());
 
     int err = ashmem_set_prot_region(mFileDescriptor.get(), PROT_READ|PROT_WRITE); // TODO error handling?
     if (err < 0) {
-        ALOGE("SharedRingBuffer::allocate() ashmem_set_prot_region() failed %d", errno);
+        ALOGE("allocate() ashmem_set_prot_region() failed %d", errno);
         mFileDescriptor.reset();
         return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
     }
@@ -64,7 +64,7 @@
                          MAP_SHARED,
                          mFileDescriptor.get(), 0);
     if (mSharedMemory == MAP_FAILED) {
-        ALOGE("SharedRingBuffer::allocate() mmap() failed %d", errno);
+        ALOGE("allocate() mmap() failed %d", errno);
         mFileDescriptor.reset();
         return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
     }
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 22519a3..a7d6e83 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -206,9 +206,10 @@
     service->sendRecognitionEvent(event, module);
 }
 
-sp<IMemory> SoundTriggerHwService::prepareRecognitionEvent_l(
+sp<IMemory> SoundTriggerHwService::prepareRecognitionEvent(
                                                     struct sound_trigger_recognition_event *event)
 {
+    AutoMutex lock(mMemoryDealerLock);
     sp<IMemory> eventMemory;
 
     //sanitize event
@@ -216,21 +217,21 @@
     case SOUND_MODEL_TYPE_KEYPHRASE:
         ALOGW_IF(event->data_size != 0 && event->data_offset !=
                     sizeof(struct sound_trigger_phrase_recognition_event),
-                    "prepareRecognitionEvent_l(): invalid data offset %u for keyphrase event type",
+                    "prepareRecognitionEvent(): invalid data offset %u for keyphrase event type",
                     event->data_offset);
         event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
         break;
     case SOUND_MODEL_TYPE_GENERIC:
         ALOGW_IF(event->data_size != 0 && event->data_offset !=
                     sizeof(struct sound_trigger_generic_recognition_event),
-                    "prepareRecognitionEvent_l(): invalid data offset %u for generic event type",
+                    "prepareRecognitionEvent(): invalid data offset %u for generic event type",
                     event->data_offset);
         event->data_offset = sizeof(struct sound_trigger_generic_recognition_event);
         break;
     case SOUND_MODEL_TYPE_UNKNOWN:
         ALOGW_IF(event->data_size != 0 && event->data_offset !=
                     sizeof(struct sound_trigger_recognition_event),
-                    "prepareRecognitionEvent_l(): invalid data offset %u for unknown event type",
+                    "prepareRecognitionEvent(): invalid data offset %u for unknown event type",
                     event->data_offset);
         event->data_offset = sizeof(struct sound_trigger_recognition_event);
         break;
@@ -251,30 +252,19 @@
 
 void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognition_event *event,
                                                  Module *module)
- {
-     AutoMutex lock(mServiceLock);
-     if (module == NULL) {
-         return;
-     }
-     sp<IMemory> eventMemory = prepareRecognitionEvent_l(event);
-     if (eventMemory == 0) {
-         return;
-     }
-     sp<Module> strongModule;
-     for (size_t i = 0; i < mModules.size(); i++) {
-         if (mModules.valueAt(i).get() == module) {
-             strongModule = mModules.valueAt(i);
-             break;
-         }
-     }
-     if (strongModule == 0) {
-         return;
-     }
+{
+    if (module == NULL) {
+        return;
+    }
+    sp<IMemory> eventMemory = prepareRecognitionEvent(event);
+    if (eventMemory == 0) {
+        return;
+    }
 
     sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
                                                         eventMemory);
-    callbackEvent->setModule(strongModule);
-    sendCallbackEvent_l(callbackEvent);
+    callbackEvent->setModule(module);
+    sendCallbackEvent(callbackEvent);
 }
 
 // static
@@ -293,8 +283,9 @@
     service->sendSoundModelEvent(event, module);
 }
 
-sp<IMemory> SoundTriggerHwService::prepareSoundModelEvent_l(struct sound_trigger_model_event *event)
+sp<IMemory> SoundTriggerHwService::prepareSoundModelEvent(struct sound_trigger_model_event *event)
 {
+    AutoMutex lock(mMemoryDealerLock);
     sp<IMemory> eventMemory;
 
     size_t size = event->data_offset + event->data_size;
@@ -311,30 +302,20 @@
 void SoundTriggerHwService::sendSoundModelEvent(struct sound_trigger_model_event *event,
                                                 Module *module)
 {
-    AutoMutex lock(mServiceLock);
-    sp<IMemory> eventMemory = prepareSoundModelEvent_l(event);
+    sp<IMemory> eventMemory = prepareSoundModelEvent(event);
     if (eventMemory == 0) {
         return;
     }
-    sp<Module> strongModule;
-    for (size_t i = 0; i < mModules.size(); i++) {
-        if (mModules.valueAt(i).get() == module) {
-            strongModule = mModules.valueAt(i);
-            break;
-        }
-    }
-    if (strongModule == 0) {
-        return;
-    }
     sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL,
                                                         eventMemory);
-    callbackEvent->setModule(strongModule);
-    sendCallbackEvent_l(callbackEvent);
+    callbackEvent->setModule(module);
+    sendCallbackEvent(callbackEvent);
 }
 
 
-sp<IMemory> SoundTriggerHwService::prepareServiceStateEvent_l(sound_trigger_service_state_t state)
+sp<IMemory> SoundTriggerHwService::prepareServiceStateEvent(sound_trigger_service_state_t state)
 {
+    AutoMutex lock(mMemoryDealerLock);
     sp<IMemory> eventMemory;
 
     size_t size = sizeof(sound_trigger_service_state_t);
@@ -347,45 +328,33 @@
     return eventMemory;
 }
 
-// call with mServiceLock held
-void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_t state,
+void SoundTriggerHwService::sendServiceStateEvent(sound_trigger_service_state_t state,
                                                   Module *module)
 {
-    sp<IMemory> eventMemory = prepareServiceStateEvent_l(state);
+    sp<IMemory> eventMemory = prepareServiceStateEvent(state);
     if (eventMemory == 0) {
         return;
     }
-    sp<Module> strongModule;
-    for (size_t i = 0; i < mModules.size(); i++) {
-        if (mModules.valueAt(i).get() == module) {
-            strongModule = mModules.valueAt(i);
-            break;
-        }
-    }
-    if (strongModule == 0) {
-        return;
-    }
     sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
                                                         eventMemory);
-    callbackEvent->setModule(strongModule);
-    sendCallbackEvent_l(callbackEvent);
+    callbackEvent->setModule(module);
+    sendCallbackEvent(callbackEvent);
 }
 
-void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_t state,
-                                                    ModuleClient *moduleClient)
+void SoundTriggerHwService::sendServiceStateEvent(sound_trigger_service_state_t state,
+                                                  ModuleClient *moduleClient)
 {
-    sp<IMemory> eventMemory = prepareServiceStateEvent_l(state);
+    sp<IMemory> eventMemory = prepareServiceStateEvent(state);
     if (eventMemory == 0) {
         return;
     }
     sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
                                                         eventMemory);
     callbackEvent->setModuleClient(moduleClient);
-    sendCallbackEvent_l(callbackEvent);
+    sendCallbackEvent(callbackEvent);
 }
 
-// call with mServiceLock held
-void SoundTriggerHwService::sendCallbackEvent_l(const sp<CallbackEvent>& event)
+void SoundTriggerHwService::sendCallbackEvent(const sp<CallbackEvent>& event)
 {
     mCallbackThread->sendCallbackEvent(event);
 }
@@ -404,6 +373,19 @@
             if (moduleClient == 0) {
                 return;
             }
+        } else {
+            // Sanity check on this being a Module we know about.
+            bool foundModule = false;
+            for (size_t i = 0; i < mModules.size(); i++) {
+                if (mModules.valueAt(i).get() == module.get()) {
+                    foundModule = true;
+                    break;
+                }
+            }
+            if (!foundModule) {
+                ALOGE("onCallbackEvent for unknown module");
+                return;
+            }
         }
     }
     if (module != 0) {
@@ -757,11 +739,12 @@
         return;
     }
 
+    Vector< sp<ModuleClient> > clients;
+
     switch (event->mType) {
     case CallbackEvent::TYPE_RECOGNITION: {
         struct sound_trigger_recognition_event *recognitionEvent =
                 (struct sound_trigger_recognition_event *)eventMemory->pointer();
-        sp<ISoundTriggerClient> client;
         {
             AutoMutex lock(mLock);
             sp<Model> model = getModel(recognitionEvent->model);
@@ -776,16 +759,12 @@
 
             recognitionEvent->capture_session = model->mCaptureSession;
             model->mState = Model::STATE_IDLE;
-            client = model->mModuleClient->client();
-        }
-        if (client != 0) {
-            client->onRecognitionEvent(eventMemory);
+            clients.add(model->mModuleClient);
         }
     } break;
     case CallbackEvent::TYPE_SOUNDMODEL: {
         struct sound_trigger_model_event *soundmodelEvent =
                 (struct sound_trigger_model_event *)eventMemory->pointer();
-        sp<ISoundTriggerClient> client;
         {
             AutoMutex lock(mLock);
             sp<Model> model = getModel(soundmodelEvent->model);
@@ -793,29 +772,26 @@
                 ALOGW("%s model == 0", __func__);
                 return;
             }
-            client = model->mModuleClient->client();
-        }
-        if (client != 0) {
-            client->onSoundModelEvent(eventMemory);
+            clients.add(model->mModuleClient);
         }
     } break;
     case CallbackEvent::TYPE_SERVICE_STATE: {
-        Vector< sp<ISoundTriggerClient> > clients;
         {
             AutoMutex lock(mLock);
             for (size_t i = 0; i < mModuleClients.size(); i++) {
                 if (mModuleClients[i] != 0) {
-                    clients.add(mModuleClients[i]->client());
+                    clients.add(mModuleClients[i]);
                 }
             }
         }
-        for (size_t i = 0; i < clients.size(); i++) {
-            clients[i]->onServiceStateChange(eventMemory);
-        }
     } break;
     default:
         LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
     }
+
+    for (size_t i = 0; i < clients.size(); i++) {
+        clients[i]->onCallbackEvent(event);
+    }
 }
 
 sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel(
@@ -878,7 +854,7 @@
                     event.common.type = model->mType;
                     event.common.model = model->mHandle;
                     event.common.data_size = 0;
-                    sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+                    sp<IMemory> eventMemory = service->prepareRecognitionEvent(&event.common);
                     if (eventMemory != 0) {
                         events.add(eventMemory);
                     }
@@ -889,7 +865,7 @@
                     event.common.type = model->mType;
                     event.common.model = model->mHandle;
                     event.common.data_size = 0;
-                    sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+                    sp<IMemory> eventMemory = service->prepareRecognitionEvent(&event.common);
                     if (eventMemory != 0) {
                         events.add(eventMemory);
                     }
@@ -900,7 +876,7 @@
                     event.common.type = model->mType;
                     event.common.model = model->mHandle;
                     event.common.data_size = 0;
-                    sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+                    sp<IMemory> eventMemory = service->prepareRecognitionEvent(&event.common);
                     if (eventMemory != 0) {
                         events.add(eventMemory);
                     }
@@ -915,11 +891,11 @@
         sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
                                                             events[i]);
         callbackEvent->setModule(this);
-        service->sendCallbackEvent_l(callbackEvent);
+        service->sendCallbackEvent(callbackEvent);
     }
 
 exit:
-    service->sendServiceStateEvent_l(state, this);
+    service->sendServiceStateEvent(state, this);
 }
 
 
@@ -1064,7 +1040,7 @@
             return;
         }
     }
-    service->sendServiceStateEvent_l(state, this);
+    service->sendServiceStateEvent(state, this);
 }
 
 void SoundTriggerHwService::ModuleClient::onCallbackEvent(const sp<CallbackEvent>& event)
@@ -1077,19 +1053,26 @@
         return;
     }
 
-    switch (event->mType) {
-    case CallbackEvent::TYPE_SERVICE_STATE: {
-        sp<ISoundTriggerClient> client;
-        {
-            AutoMutex lock(mLock);
-            client = mClient;
-        }
-        if (client !=0 ) {
+    sp<ISoundTriggerClient> client;
+    {
+        AutoMutex lock(mLock);
+        client = mClient;
+    }
+
+    if (client != 0) {
+        switch (event->mType) {
+        case CallbackEvent::TYPE_RECOGNITION: {
+            client->onRecognitionEvent(eventMemory);
+        } break;
+        case CallbackEvent::TYPE_SOUNDMODEL: {
+            client->onSoundModelEvent(eventMemory);
+        } break;
+        case CallbackEvent::TYPE_SERVICE_STATE: {
             client->onServiceStateChange(eventMemory);
+        } break;
+        default:
+            LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
         }
-    } break;
-    default:
-        LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
     }
 }
 
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 95efc4b..708fc98 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -214,19 +214,19 @@
     };
 
     static void recognitionCallback(struct sound_trigger_recognition_event *event, void *cookie);
-           sp<IMemory> prepareRecognitionEvent_l(struct sound_trigger_recognition_event *event);
+           sp<IMemory> prepareRecognitionEvent(struct sound_trigger_recognition_event *event);
            void sendRecognitionEvent(struct sound_trigger_recognition_event *event, Module *module);
 
     static void soundModelCallback(struct sound_trigger_model_event *event, void *cookie);
-           sp<IMemory> prepareSoundModelEvent_l(struct sound_trigger_model_event *event);
+           sp<IMemory> prepareSoundModelEvent(struct sound_trigger_model_event *event);
            void sendSoundModelEvent(struct sound_trigger_model_event *event, Module *module);
 
-           sp<IMemory> prepareServiceStateEvent_l(sound_trigger_service_state_t state);
-           void sendServiceStateEvent_l(sound_trigger_service_state_t state, Module *module);
-           void sendServiceStateEvent_l(sound_trigger_service_state_t state,
-                                        ModuleClient *moduleClient);
+           sp<IMemory> prepareServiceStateEvent(sound_trigger_service_state_t state);
+           void sendServiceStateEvent(sound_trigger_service_state_t state, Module *module);
+           void sendServiceStateEvent(sound_trigger_service_state_t state,
+                                      ModuleClient *moduleClient);
 
-           void sendCallbackEvent_l(const sp<CallbackEvent>& event);
+           void sendCallbackEvent(const sp<CallbackEvent>& event);
            void onCallbackEvent(const sp<CallbackEvent>& event);
 
 private:
@@ -238,6 +238,7 @@
     DefaultKeyedVector< sound_trigger_module_handle_t, sp<Module> >     mModules;
     sp<CallbackThread>  mCallbackThread;
     sp<MemoryDealer>    mMemoryDealer;
+    Mutex               mMemoryDealerLock;
     bool                mCaptureState;
 };
 
diff --git a/tools/OWNERS b/tools/OWNERS
index 6dcb035..f9cb567 100644
--- a/tools/OWNERS
+++ b/tools/OWNERS
@@ -1 +1 @@
-gkasten@android.com
+gkasten@google.com
diff --git a/tools/resampler_tools/OWNERS b/tools/resampler_tools/OWNERS
new file mode 100644
index 0000000..b4a6798
--- /dev/null
+++ b/tools/resampler_tools/OWNERS
@@ -0,0 +1 @@
+hunga@google.com