Merge "Split nblog off from nbaio"
diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
index 7e6297c..8620f36 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -192,12 +192,14 @@
             timestamps.reserve(n);
             handles.reserve(n);
             for (uint32_t i = 0; i < n; i++) {
-                res = data.readInt64(&timestamps[i]);
+                nsecs_t t;
+                res = data.readInt64(&t);
                 if (res != OK) {
                     ALOGE("%s: Failed to read timestamp[%d]: %s (%d)",
                             __FUNCTION__, i, strerror(-res), res);
                     return BAD_VALUE;
                 }
+                timestamps.push_back(t);
             }
             for (uint32_t i = 0; i < n; i++) {
                 native_handle_t* handle = data.readNativeHandle();
diff --git a/camera/ICameraRecordingProxyListener.cpp b/camera/ICameraRecordingProxyListener.cpp
index c954241..66faf8f 100644
--- a/camera/ICameraRecordingProxyListener.cpp
+++ b/camera/ICameraRecordingProxyListener.cpp
@@ -146,12 +146,14 @@
             timestamps.reserve(n);
             handles.reserve(n);
             for (uint32_t i = 0; i < n; i++) {
-                res = data.readInt64(&timestamps[i]);
+                nsecs_t t;
+                res = data.readInt64(&t);
                 if (res != OK) {
                     ALOGE("%s: Failed to read timestamp[%d]: %s (%d)",
                             __FUNCTION__, i, strerror(-res), res);
                     return BAD_VALUE;
                 }
+                timestamps.push_back(t);
             }
             for (uint32_t i = 0; i < n; i++) {
                 native_handle_t* handle = data.readNativeHandle();
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 8308095..28252c0 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -42,7 +42,9 @@
      * Repeating request encountered an error and was stopped.
      *
      * @param lastFrameNumber Frame number of the last frame of the streaming request.
+     * @param repeatingRequestId the ID of the repeating request being stopped
      */
-    oneway void onRepeatingRequestError(in long lastFrameNumber);
+    oneway void onRepeatingRequestError(in long lastFrameNumber,
+                                        in int repeatingRequestId);
     oneway void onRequestQueueEmpty();
 }
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 229b159..3ae208a 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -1353,7 +1353,8 @@
 }
 
 binder::Status
-CameraDevice::ServiceCallback::onRepeatingRequestError(int64_t lastFrameNumber) {
+CameraDevice::ServiceCallback::onRepeatingRequestError(
+        int64_t lastFrameNumber, int32_t stoppedSequenceId) {
     binder::Status ret = binder::Status::ok();
 
     sp<CameraDevice> dev = mDevice.promote();
@@ -1364,7 +1365,9 @@
     Mutex::Autolock _l(dev->mDeviceLock);
 
     int repeatingSequenceId = dev->mRepeatingSequenceId;
-    dev->mRepeatingSequenceId = REQUEST_ID_NONE;
+    if (stoppedSequenceId == repeatingSequenceId) {
+        dev->mRepeatingSequenceId = REQUEST_ID_NONE;
+    }
 
     dev->checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
 
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index c566cd2..855efe1 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -75,7 +75,8 @@
                               const CaptureResultExtras& resultExtras) override;
         binder::Status onPrepared(int streamId) override;
         binder::Status onRequestQueueEmpty() override;
-        binder::Status onRepeatingRequestError(int64_t lastFrameNumber) override;
+        binder::Status onRepeatingRequestError(int64_t lastFrameNumber,
+                int32_t stoppedSequenceId) override;
       private:
         const wp<CameraDevice> mDevice;
     };
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 946e3b8..51d9214 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -217,8 +217,10 @@
         return binder::Status::ok();
     }
 
-    virtual binder::Status onRepeatingRequestError(int64_t lastFrameNumber) {
+    virtual binder::Status onRepeatingRequestError(
+            int64_t lastFrameNumber, int32_t stoppedSequenceId) {
         (void) lastFrameNumber;
+        (void) stoppedSequenceId;
         Mutex::Autolock l(mLock);
         mLastStatus = REPEATING_REQUEST_ERROR;
         mStatusesHit.push_back(mLastStatus);
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/record.cpp b/cmds/stagefright/record.cpp
index 94c2e96..69b00c9 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -320,7 +320,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..7a5d129 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -141,7 +141,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 +174,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 +404,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 +421,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 +510,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 +528,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 +545,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;
@@ -1002,8 +1002,8 @@
             isJPEG = true;
         }
 
-        Vector<sp<IMediaSource> > mediaSources;
-        sp<IMediaSource> mediaSource;
+        Vector<sp<MediaSource> > mediaSources;
+        sp<MediaSource> mediaSource;
 
         if (isJPEG) {
             mediaSource = new JPEGSource(dataSource);
@@ -1049,7 +1049,8 @@
                 bool haveAudio = false;
                 bool haveVideo = false;
                 for (size_t i = 0; i < numTracks; ++i) {
-                    sp<IMediaSource> source = extractor->getTrack(i);
+                    sp<MediaSource> source = MediaSource::CreateFromIMediaSource(
+                            extractor->getTrack(i));
                     if (source == nullptr) {
                         fprintf(stderr, "skip NULL track %zu, track count %zu.\n", i, numTracks);
                         continue;
@@ -1115,7 +1116,7 @@
                            thumbTimeUs, thumbTimeUs / 1E6);
                 }
 
-                mediaSource = extractor->getTrack(i);
+                mediaSource = MediaSource::CreateFromIMediaSource(extractor->getTrack(i));
                 if (mediaSource == nullptr) {
                     fprintf(stderr, "skip NULL track %zu, total tracks %zu.\n", i, numTracks);
                     return -1;
@@ -1128,7 +1129,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..3b7a0e0 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -182,7 +182,7 @@
             continue;
         }
 
-        sp<IMediaSource> track = extractor->getTrack(i);
+        sp<MediaSource> track = MediaSource::CreateFromIMediaSource(extractor->getTrack(i));
         if (track == nullptr) {
             fprintf(stderr, "skip NULL track %zu, total tracks %zu\n", i, numTracks);
             continue;
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index a9302ea..57ff5b8 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -44,6 +44,13 @@
         analyticsItem.setInt64(kParentAttribute, *parentId);
     }
 
+    // Report the package name.
+    if (metricsGroup.has_app_package_name()) {
+      AString app_package_name(metricsGroup.app_package_name().c_str(),
+                               metricsGroup.app_package_name().size());
+      analyticsItem.setPkgName(app_package_name);
+    }
+
     for (int i = 0; i < metricsGroup.metric_size(); ++i) {
         const MetricsGroup_Metric& metric = metricsGroup.metric(i);
         if (!metric.has_name()) {
@@ -73,7 +80,12 @@
     }
 
     analyticsItem.setFinalized(true);
-    analyticsItem.selfrecord();
+    if (!analyticsItem.selfrecord()) {
+      // Note the cast to int is because we build on 32 and 64 bit.
+      // The cast prevents a peculiar printf problem where one format cannot
+      // satisfy both.
+      ALOGE("selfrecord() returned false. sessioId %d", (int) sessionId);
+    }
 
     for (int i = 0; i < metricsGroup.metric_sub_group_size(); ++i) {
         const MetricsGroup& subGroup = metricsGroup.metric_sub_group(i);
diff --git a/drm/libmediadrm/protos/plugin_metrics.proto b/drm/libmediadrm/protos/plugin_metrics.proto
index 2d26f14..7e3bcf5 100644
--- a/drm/libmediadrm/protos/plugin_metrics.proto
+++ b/drm/libmediadrm/protos/plugin_metrics.proto
@@ -44,4 +44,7 @@
 
   // Allow multiple sub groups of metrics.
   repeated MetricsGroup metric_sub_group = 2;
+
+  // Name of the application package associated with the metrics.
+  optional string app_package_name = 3;
 }
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
index 5fdac5c..ec07d87 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
@@ -25,10 +25,28 @@
 
 #include "Session.h"
 
+namespace {
+const android::String8 kStreaming("Streaming");
+const android::String8 kOffline("Offline");
+const android::String8 kTrue("True");
+
+const android::String8 kQueryKeyLicenseType("LicenseType");
+    // Value: "Streaming" or "Offline"
+const android::String8 kQueryKeyPlayAllowed("PlayAllowed");
+    // Value: "True" or "False"
+const android::String8 kQueryKeyRenewAllowed("RenewAllowed");
+    // Value: "True" or "False"
+};
+
 namespace clearkeydrm {
 
 using android::sp;
 
+DrmPlugin::DrmPlugin(SessionLibrary* sessionLibrary)
+        : mSessionLibrary(sessionLibrary) {
+    mPlayPolicy.clear();
+}
+
 status_t DrmPlugin::openSession(Vector<uint8_t>& sessionId) {
     sp<Session> session = mSessionLibrary->createSession();
     sessionId = session->sessionId();
@@ -60,18 +78,28 @@
     if (scope.size() == 0) {
         return android::BAD_VALUE;
     }
+
     if (keyType != kKeyType_Streaming) {
         return android::ERROR_DRM_CANNOT_HANDLE;
     }
+
     *keyRequestType = DrmPlugin::kKeyRequestType_Initial;
     defaultUrl.clear();
     sp<Session> session = mSessionLibrary->findSession(scope);
     if (!session.get()) {
         return android::ERROR_DRM_SESSION_NOT_OPENED;
     }
+
     return session->getKeyRequest(initData, mimeType, &request);
 }
 
+void DrmPlugin::setPlayPolicy() {
+    mPlayPolicy.clear();
+    mPlayPolicy.add(kQueryKeyLicenseType, kStreaming);
+    mPlayPolicy.add(kQueryKeyPlayAllowed, kTrue);
+    mPlayPolicy.add(kQueryKeyRenewAllowed, kTrue);
+}
+
 status_t DrmPlugin::provideKeyResponse(
         const Vector<uint8_t>& scope,
         const Vector<uint8_t>& response,
@@ -83,6 +111,8 @@
     if (!session.get()) {
         return android::ERROR_DRM_SESSION_NOT_OPENED;
     }
+
+    setPlayPolicy();
     status_t res = session->provideKeyResponse(response);
     if (res == android::OK) {
         // This is for testing AMediaDrm_setOnEventListener only.
@@ -111,4 +141,18 @@
     return android::OK;
 }
 
+status_t DrmPlugin::queryKeyStatus(
+        const Vector<uint8_t>& sessionId,
+        KeyedVector<String8, String8>& infoMap) const {
+
+    if (sessionId.size() == 0) {
+        return android::BAD_VALUE;
+    }
+
+    infoMap.clear();
+    for (size_t i = 0; i < mPlayPolicy.size(); ++i) {
+        infoMap.add(mPlayPolicy.keyAt(i), mPlayPolicy.valueAt(i));
+    }
+    return android::OK;
+}
 }  // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index 58421b9..f37a706 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -39,8 +39,8 @@
 
 class DrmPlugin : public android::DrmPlugin {
 public:
-    explicit DrmPlugin(SessionLibrary* sessionLibrary)
-            : mSessionLibrary(sessionLibrary) {}
+    explicit DrmPlugin(SessionLibrary* sessionLibrary);
+
     virtual ~DrmPlugin() {}
 
     virtual status_t openSession(Vector<uint8_t>& sessionId);
@@ -81,13 +81,7 @@
 
     virtual status_t queryKeyStatus(
             const Vector<uint8_t>& sessionId,
-            KeyedVector<String8, String8>& infoMap) const {
-        if (sessionId.size() == 0) {
-            return android::BAD_VALUE;
-        }
-        UNUSED(infoMap);
-        return android::ERROR_DRM_CANNOT_HANDLE;
-    }
+            KeyedVector<String8, String8>& infoMap) const;
 
     virtual status_t getProvisionRequest(
             const String8& cert_type,
@@ -248,9 +242,12 @@
     }
 
 private:
-    DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin);
+    void setPlayPolicy();
 
+    android::KeyedVector<android::String8, android::String8> mPlayPolicy;
     SessionLibrary* mSessionLibrary;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin);
 };
 
 } // namespace clearkeydrm
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/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index 9d42bce..7874f90 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -5,6 +5,9 @@
     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/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp
index 564474f..1711242 100644
--- a/media/img_utils/src/TiffWriter.cpp
+++ b/media/img_utils/src/TiffWriter.cpp
@@ -350,7 +350,7 @@
         if (nextIfd == NULL) {
             break;
         }
-        ifd = nextIfd;
+        ifd = std::move(nextIfd);
     }
     return ifd;
 }
diff --git a/media/libaaudio/Doxyfile b/media/libaaudio/Doxyfile
index e2c4960..7298d11 100644
--- a/media/libaaudio/Doxyfile
+++ b/media/libaaudio/Doxyfile
@@ -744,12 +744,12 @@
 # Note: If this tag is empty the current directory is searched.
 
 INPUT                  = include/aaudio/AAudio.h \
+                         src/binding/AAudioCommon.h \
                          src/legacy/AudioStreamTrack.h \
                          src/legacy/AudioStreamRecord.h \
                          src/legacy/AAudioLegacy.h \
                          src/core/AudioStreamBuilder.h \
                          src/core/AudioStream.h \
-                         src/utility/HandleTracker.h \
                          src/utility/MonotonicCounter.h \
                          src/utility/AudioClock.h \
                          src/utility/AAudioUtilities.h
diff --git a/media/libaaudio/examples/utils/AAudioExampleUtils.h b/media/libaaudio/examples/utils/AAudioExampleUtils.h
index 9ef62c9..c179ce6 100644
--- a/media/libaaudio/examples/utils/AAudioExampleUtils.h
+++ b/media/libaaudio/examples/utils/AAudioExampleUtils.h
@@ -31,18 +31,51 @@
 #define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * 1000)
 
 const char *getSharingModeText(aaudio_sharing_mode_t mode) {
-    const char *modeText = "unknown";
+    const char *text = "unknown";
     switch (mode) {
-    case AAUDIO_SHARING_MODE_EXCLUSIVE:
-        modeText = "EXCLUSIVE";
-        break;
-    case AAUDIO_SHARING_MODE_SHARED:
-        modeText = "SHARED";
-        break;
-    default:
-        break;
+        case AAUDIO_SHARING_MODE_EXCLUSIVE:
+            text = "EXCLUSIVE";
+            break;
+        case AAUDIO_SHARING_MODE_SHARED:
+            text = "SHARED";
+            break;
+        default:
+            break;
     }
-    return modeText;
+    return text;
+}
+
+const char *getPerformanceModeText(aaudio_performance_mode_t mode) {
+    const char *text = "unknown";
+    switch (mode) {
+        case AAUDIO_PERFORMANCE_MODE_NONE:
+            text = "NONE";
+            break;
+        case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
+            text = "LOW_LATENCY";
+            break;
+        case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
+            text = "POWER_SAVING";
+            break;
+        default:
+            break;
+    }
+    return text;
+}
+
+const char *getDirectionText(aaudio_direction_t direction) {
+    const char *text = "unknown";
+    switch (direction) {
+        case AAUDIO_DIRECTION_INPUT:
+            text = "INPUT";
+            break;
+        case AAUDIO_DIRECTION_OUTPUT:
+            text = "OUTPUT";
+            break;
+        default:
+            break;
+    }
+    return text;
 }
 
 static void convertNanosecondsToTimespec(int64_t nanoseconds, struct timespec *time) {
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index d2e7f23..606c4ba 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -36,6 +36,13 @@
 // 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
+
+typedef struct Timestamp {
+    int64_t position;
+    int64_t nanoseconds;
+} Timestamp;
+
 /**
  * Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode.
  */
@@ -227,10 +234,12 @@
 
     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
 
     int            scheduler = 0;
     bool           schedulerChecked = false;
@@ -273,6 +282,17 @@
         sineData->schedulerChecked = true;
     }
 
+    if (sineData->timestampCount < MAX_TIMESTAMPS) {
+        Timestamp *timestamp = &sineData->timestamps[sineData->timestampCount];
+        aaudio_result_t result = AAudioStream_getTimestamp(stream,
+            CLOCK_MONOTONIC, &timestamp->position, &timestamp->nanoseconds);
+        if (result == AAUDIO_OK && // valid?
+                (sineData->timestampCount == 0 || // first one?
+                (timestamp->position != (timestamp - 1)->position))) { // advanced position?
+            sineData->timestampCount++; // keep this one
+        }
+    }
+
     if (numFrames > sineData->maxNumFrames) {
         sineData->maxNumFrames = numFrames;
     }
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 2280b72..4f9cde6 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -120,6 +120,18 @@
         goto error;
     }
 
+    for (int i = 0; i < myData.timestampCount; i++) {
+        Timestamp *timestamp = &myData.timestamps[i];
+        bool retro = (i > 0 &&
+                      ((timestamp->position < (timestamp - 1)->position)
+                       || ((timestamp->nanoseconds < (timestamp - 1)->nanoseconds))));
+        const char *message = retro ? "  <= RETROGRADE!" : "";
+        printf("Timestamp %3d : %8lld, %8lld %s\n", i,
+               (long long) timestamp->position,
+               (long long) timestamp->nanoseconds,
+               message);
+    }
+
     if (myData.schedulerChecked) {
         printf("scheduler = 0x%08x, SCHED_FIFO = 0x%08X\n",
                myData.scheduler,
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
index 112a192..f7a5f9b 100644
--- a/media/libaaudio/src/Android.mk
+++ b/media/libaaudio/src/Android.mk
@@ -38,7 +38,6 @@
     legacy/AudioStreamLegacy.cpp \
     legacy/AudioStreamRecord.cpp \
     legacy/AudioStreamTrack.cpp \
-    utility/HandleTracker.cpp \
     utility/AAudioUtilities.cpp \
     utility/FixedBlockAdapter.cpp \
     utility/FixedBlockReader.cpp \
@@ -99,7 +98,6 @@
     legacy/AudioStreamLegacy.cpp \
     legacy/AudioStreamRecord.cpp \
     legacy/AudioStreamTrack.cpp \
-    utility/HandleTracker.cpp \
     utility/AAudioUtilities.cpp \
     utility/FixedBlockAdapter.cpp \
     utility/FixedBlockReader.cpp \
diff --git a/media/libaaudio/src/binding/AAudioCommon.h b/media/libaaudio/src/binding/AAudioCommon.h
new file mode 100644
index 0000000..e3e9e82
--- /dev/null
+++ b/media/libaaudio/src/binding/AAudioCommon.h
@@ -0,0 +1,32 @@
+/*
+ * 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_AAUDIO_COMMON_H
+#define ANDROID_AAUDIO_COMMON_H
+
+#include <stdint.h>
+
+/*
+ * Internal header that is common to both client and server.
+ *
+ */
+namespace aaudio {
+
+typedef int32_t aaudio_handle_t;
+
+} /* namespace aaudio */
+
+#endif // ANDROID_AAUDIO_COMMON_H
diff --git a/media/libaaudio/src/binding/IAAudioClient.h b/media/libaaudio/src/binding/IAAudioClient.h
index 21cc33b..f21fd93 100644
--- a/media/libaaudio/src/binding/IAAudioClient.h
+++ b/media/libaaudio/src/binding/IAAudioClient.h
@@ -22,7 +22,7 @@
 
 #include <aaudio/AAudio.h>
 
-#include "utility/HandleTracker.h"
+#include "binding/AAudioCommon.h"
 
 namespace android {
 
@@ -33,7 +33,7 @@
 
     DECLARE_META_INTERFACE(AAudioClient);
 
-    virtual void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) = 0;
+    virtual void onStreamChange(aaudio::aaudio_handle_t handle, int32_t opcode, int32_t value) = 0;
 
 };
 
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
index 30b3ead..6bdb826 100644
--- a/media/libaaudio/src/binding/IAAudioService.h
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -24,12 +24,12 @@
 
 #include <aaudio/AAudio.h>
 
+#include "binding/AAudioCommon.h"
 #include "binding/AAudioServiceDefinitions.h"
-#include "binding/AudioEndpointParcelable.h"
-#include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
+#include "binding/AAudioStreamRequest.h"
+#include "binding/AudioEndpointParcelable.h"
 #include "binding/IAAudioClient.h"
-#include "utility/HandleTracker.h"
 
 namespace android {
 
@@ -51,7 +51,7 @@
      * @param configuration contains information about the created stream
      * @return handle to the stream or a negative error
      */
-    virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+    virtual aaudio::aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
                                      aaudio::AAudioStreamConfiguration &configurationOutput) = 0;
 
     virtual aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) = 0;
@@ -89,11 +89,11 @@
     /**
      * Manage the specified thread as a low latency audio thread.
      */
-    virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+    virtual aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle,
                                               pid_t clientThreadId,
                                               int64_t periodNanoseconds) = 0;
 
-    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+    virtual aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
                                                 pid_t clientThreadId) = 0;
 };
 
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 7f2e495..2fdbfaf 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -23,7 +23,6 @@
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 
 #include <stdint.h>
-#include <assert.h>
 
 #include <binder/IServiceManager.h>
 
@@ -55,7 +54,7 @@
 // Wait at least this many times longer than the operation should take.
 #define MIN_TIMEOUT_OPERATIONS    4
 
-#define LOG_TIMESTAMPS   0
+#define LOG_TIMESTAMPS            0
 
 AudioStreamInternal::AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService)
         : AudioStream()
@@ -63,12 +62,11 @@
         , mAudioEndpoint()
         , mServiceStreamHandle(AAUDIO_HANDLE_INVALID)
         , mFramesPerBurst(16)
-        , mStreamVolume(1.0f)
         , mInService(inService)
         , mServiceInterface(serviceInterface)
+        , mAtomicTimestamp()
         , mWakeupDelayNanos(AAudioProperty_getWakeupDelayMicros() * AAUDIO_NANOS_PER_MICROSECOND)
         , mMinimumSleepNanos(AAudioProperty_getMinimumSleepMicros() * AAUDIO_NANOS_PER_MICROSECOND)
-        , mAtomicTimestamp()
         {
     ALOGD("AudioStreamInternal(): mWakeupDelayNanos = %d, mMinimumSleepNanos = %d",
           mWakeupDelayNanos, mMinimumSleepNanos);
@@ -196,10 +194,6 @@
     }
 
     setState(AAUDIO_STREAM_STATE_OPEN);
-    // Only connect to AudioManager if this is a playback stream running in client process.
-    if (!mInService && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
-        init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
-    }
 
     return result;
 
@@ -209,7 +203,8 @@
 }
 
 aaudio_result_t AudioStreamInternal::close() {
-    ALOGD("AudioStreamInternal::close(): mServiceStreamHandle = 0x%08X",
+    aaudio_result_t result = AAUDIO_OK;
+    ALOGD("close(): mServiceStreamHandle = 0x%08X",
              mServiceStreamHandle);
     if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
         // Don't close a stream while it is running.
@@ -218,10 +213,10 @@
             requestStop();
             aaudio_stream_state_t nextState;
             int64_t timeoutNanoseconds = MIN_TIMEOUT_NANOS;
-            aaudio_result_t result = waitForStateChange(currentState, &nextState,
+            result = waitForStateChange(currentState, &nextState,
                                                        timeoutNanoseconds);
             if (result != AAUDIO_OK) {
-                ALOGE("AudioStreamInternal::close() waitForStateChange() returned %d %s",
+                ALOGE("close() waitForStateChange() returned %d %s",
                 result, AAudio_convertResultToText(result));
             }
         }
@@ -232,8 +227,11 @@
         mServiceInterface.closeStream(serviceStreamHandle);
         delete[] mCallbackBuffer;
         mCallbackBuffer = nullptr;
+
         setState(AAUDIO_STREAM_STATE_CLOSED);
-        return mEndPointParcelable.close();
+        result = mEndPointParcelable.close();
+        aaudio_result_t result2 = AudioStream::close();
+        return (result != AAUDIO_OK) ? result : result2;
     } else {
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -250,26 +248,46 @@
     }
 }
 
+/*
+ * It normally takes about 20-30 msec to start a stream on the server.
+ * But the first time can take as much as 200-300 msec. The HW
+ * starts right away so by the time the client gets a chance to write into
+ * the buffer, it is already in a deep underflow state. That can cause the
+ * XRunCount to be non-zero, which could lead an app to tune its latency higher.
+ * To avoid this problem, we set a request for the processing code to start the
+ * client stream at the same position as the server stream.
+ * The processing code will then save the current offset
+ * between client and server and apply that to any position given to the app.
+ */
 aaudio_result_t AudioStreamInternal::requestStart()
 {
     int64_t startTime;
-    ALOGD("AudioStreamInternal()::requestStart()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal::requestStart() mServiceStreamHandle invalid");
+        ALOGE("requestStart() mServiceStreamHandle invalid");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     if (isActive()) {
-        ALOGE("AudioStreamInternal::requestStart() already active");
+        ALOGE("requestStart() already active");
         return AAUDIO_ERROR_INVALID_STATE;
     }
-    aaudio_stream_state_t originalState = getState();
 
+    aaudio_stream_state_t originalState = getState();
+    if (originalState == AAUDIO_STREAM_STATE_DISCONNECTED) {
+        ALOGE("requestStart() but DISCONNECTED");
+        return AAUDIO_ERROR_DISCONNECTED;
+    }
     setState(AAUDIO_STREAM_STATE_STARTING);
-    aaudio_result_t result = AAudioConvert_androidToAAudioResult(startWithStatus());
+
+    // Clear any stale timestamps from the previous run.
+    drainTimestampsFromService();
+
+    aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);
 
     startTime = AudioClock::getNanoseconds();
     mClockModel.start(startTime);
+    mNeedCatchUp.request();  // Ask data processing code to catch up when first timestamp received.
 
+    // Start data callback thread.
     if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) {
         // Launch the callback loop thread.
         int64_t periodNanos = mCallbackFrames
@@ -314,14 +332,16 @@
 aaudio_result_t AudioStreamInternal::requestStopInternal()
 {
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal::requestStopInternal() mServiceStreamHandle invalid = 0x%08X",
+        ALOGE("requestStopInternal() mServiceStreamHandle invalid = 0x%08X",
               mServiceStreamHandle);
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
     mClockModel.stop(AudioClock::getNanoseconds());
     setState(AAUDIO_STREAM_STATE_STOPPING);
-    return AAudioConvert_androidToAAudioResult(stopWithStatus());
+    mAtomicTimestamp.clear();
+
+    return mServiceInterface.stopStream(mServiceStreamHandle);
 }
 
 aaudio_result_t AudioStreamInternal::requestStop()
@@ -336,7 +356,7 @@
 
 aaudio_result_t AudioStreamInternal::registerThread() {
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal::registerThread() mServiceStreamHandle invalid");
+        ALOGE("registerThread() mServiceStreamHandle invalid");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     return mServiceInterface.registerAudioThread(mServiceStreamHandle,
@@ -346,7 +366,7 @@
 
 aaudio_result_t AudioStreamInternal::unregisterThread() {
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
-        ALOGE("AudioStreamInternal::unregisterThread() mServiceStreamHandle invalid");
+        ALOGE("unregisterThread() mServiceStreamHandle invalid");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, gettid());
@@ -374,12 +394,14 @@
     // Generated in server and passed to client. Return latest.
     if (mAtomicTimestamp.isValid()) {
         Timestamp timestamp = mAtomicTimestamp.read();
-        *framePosition = timestamp.getPosition();
-        *timeNanoseconds = timestamp.getNanoseconds();
-        return AAUDIO_OK;
-    } else {
-        return AAUDIO_ERROR_UNAVAILABLE;
+        int64_t position = timestamp.getPosition() + mFramesOffsetFromService;
+        if (position >= 0) {
+            *framePosition = position;
+            *timeNanoseconds = timestamp.getNanoseconds();
+            return AAUDIO_OK;
+        }
     }
+    return AAUDIO_ERROR_INVALID_STATE;
 }
 
 aaudio_result_t AudioStreamInternal::updateStateMachine() {
@@ -394,14 +416,14 @@
     static int64_t oldTime = 0;
     int64_t framePosition = command.timestamp.position;
     int64_t nanoTime = command.timestamp.timestamp;
-    ALOGD("AudioStreamInternal: timestamp says framePosition = %08lld at nanoTime %lld",
+    ALOGD("logTimestamp: timestamp says framePosition = %8lld at nanoTime %lld",
          (long long) framePosition,
          (long long) nanoTime);
     int64_t nanosDelta = nanoTime - oldTime;
     if (nanosDelta > 0 && oldTime > 0) {
         int64_t framesDelta = framePosition - oldPosition;
         int64_t rate = (framesDelta * AAUDIO_NANOS_PER_SECOND) / nanosDelta;
-        ALOGD("AudioStreamInternal: framesDelta = %08lld, nanosDelta = %08lld, rate = %lld",
+        ALOGD("logTimestamp:     framesDelta = %8lld, nanosDelta = %8lld, rate = %lld",
               (long long) framesDelta, (long long) nanosDelta, (long long) rate);
     }
     oldPosition = framePosition;
@@ -478,6 +500,34 @@
     return result;
 }
 
+aaudio_result_t AudioStreamInternal::drainTimestampsFromService() {
+    aaudio_result_t result = AAUDIO_OK;
+
+    while (result == AAUDIO_OK) {
+        AAudioServiceMessage message;
+        if (mAudioEndpoint.readUpCommand(&message) != 1) {
+            break; // no command this time, no problem
+        }
+        switch (message.what) {
+            // ignore most messages
+            case AAudioServiceMessage::code::TIMESTAMP_SERVICE:
+            case AAudioServiceMessage::code::TIMESTAMP_HARDWARE:
+                break;
+
+            case AAudioServiceMessage::code::EVENT:
+                result = onEventFromServer(&message);
+                break;
+
+            default:
+                ALOGE("WARNING - drainTimestampsFromService() Unrecognized what = %d",
+                      (int) message.what);
+                result = AAUDIO_ERROR_INTERNAL;
+                break;
+        }
+    }
+    return result;
+}
+
 // Process all the commands coming from the server.
 aaudio_result_t AudioStreamInternal::processCommands() {
     aaudio_result_t result = AAUDIO_OK;
@@ -502,7 +552,7 @@
             break;
 
         default:
-            ALOGE("WARNING - AudioStreamInternal::processCommands() Unrecognized what = %d",
+            ALOGE("WARNING - processCommands() Unrecognized what = %d",
                  (int) message.what);
             result = AAUDIO_ERROR_INTERNAL;
             break;
@@ -613,7 +663,7 @@
     }
 
     aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(requestedFrames, &actualFrames);
-    ALOGD("AudioStreamInternal::setBufferSize() req = %d => %d", requestedFrames, actualFrames);
+    ALOGD("setBufferSize() req = %d => %d", requestedFrames, actualFrames);
     if (result < 0) {
         return result;
     } else {
@@ -636,32 +686,3 @@
 aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) {
     return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
 }
-
-void AudioStreamInternal::doSetVolume() {
-    // No pan and only left volume is taken into account from IPLayer interface
-    mVolumeRamp.setTarget(mStreamVolume * mVolumeMultiplierL /* * mPanMultiplierL */);
-}
-
-
-//------------------------------------------------------------------------------
-// Implementation of PlayerBase
-status_t AudioStreamInternal::playerStart() {
-    return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.startStream(mServiceStreamHandle));
-}
-
-status_t AudioStreamInternal::playerPause() {
-    return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.pauseStream(mServiceStreamHandle));
-}
-
-status_t AudioStreamInternal::playerStop() {
-    return AAudioConvert_aaudioToAndroidStatus(mServiceInterface.stopStream(mServiceStreamHandle));
-}
-
-status_t AudioStreamInternal::playerSetVolume() {
-    doSetVolume();
-    return NO_ERROR;
-}
-
-void AudioStreamInternal::destroy() {
-    baseDestroy();
-}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 3523294..47024c0 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -18,7 +18,6 @@
 #define ANDROID_AAUDIO_AUDIO_STREAM_INTERNAL_H
 
 #include <stdint.h>
-#include <media/PlayerBase.h>
 #include <aaudio/AAudio.h>
 
 #include "binding/IAAudioService.h"
@@ -36,7 +35,7 @@
 namespace aaudio {
 
 // A stream that talks to the AAudioService or directly to a HAL.
-class AudioStreamInternal : public AudioStream, public android::PlayerBase  {
+class AudioStreamInternal : public AudioStream {
 
 public:
     AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService);
@@ -85,9 +84,6 @@
     // Calculate timeout based on framesPerBurst
     int64_t calculateReasonableTimeout();
 
-    //PlayerBase virtuals
-    virtual void destroy();
-
     aaudio_result_t startClient(const android::AudioClient& client,
                                 audio_port_handle_t *clientHandle);
 
@@ -115,12 +111,15 @@
                             int64_t currentTimeNanos,
                             int64_t *wakeTimePtr) = 0;
 
+    aaudio_result_t drainTimestampsFromService();
+
     aaudio_result_t processCommands();
 
     aaudio_result_t requestStopInternal();
 
     aaudio_result_t stopCallback();
 
+    virtual void advanceClientToMatchServerPosition() = 0;
 
     virtual void onFlushFromServer() {}
 
@@ -135,14 +134,6 @@
     // Calculate timeout for an operation involving framesPerOperation.
     int64_t calculateReasonableTimeout(int32_t framesPerOperation);
 
-    void doSetVolume();
-
-    //PlayerBase virtuals
-    virtual status_t playerStart();
-    virtual status_t playerPause();
-    virtual status_t playerStop();
-    virtual status_t playerSetVolume();
-
     aaudio_format_t          mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED;
 
     IsochronousClockModel    mClockModel;      // timing model for chasing the HAL
@@ -153,9 +144,6 @@
     int32_t                  mFramesPerBurst;     // frames per HAL transfer
     int32_t                  mXRunCount = 0;      // how many underrun events?
 
-    LinearRamp               mVolumeRamp;
-    float                    mStreamVolume;
-
     // Offset from underlying frame position.
     int64_t                  mFramesOffsetFromService = 0; // offset for timestamps
 
@@ -167,6 +155,12 @@
 
     AAudioServiceInterface  &mServiceInterface;   // abstract interface to the service
 
+    SimpleDoubleBuffer<Timestamp>  mAtomicTimestamp;
+
+    AtomicRequestor          mNeedCatchUp;   // Ask read() or write() to sync on first timestamp.
+
+    float                    mStreamVolume = 1.0f;
+
 private:
     /*
      * Asynchronous write with data conversion.
@@ -188,10 +182,7 @@
     AudioEndpointParcelable  mEndPointParcelable; // description of the buffers filled by service
     EndpointDescriptor       mEndpointDescriptor; // buffer description with resolved addresses
 
-    SimpleDoubleBuffer<Timestamp>  mAtomicTimestamp;
-
     int64_t                  mServiceLatencyNanos = 0;
-
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 7b1e53e..b792ecd 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -39,6 +39,21 @@
 
 AudioStreamInternalCapture::~AudioStreamInternalCapture() {}
 
+void AudioStreamInternalCapture::advanceClientToMatchServerPosition() {
+    int64_t readCounter = mAudioEndpoint.getDataReadCounter();
+    int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
+
+    // Bump offset so caller does not see the retrograde motion in getFramesRead().
+    int64_t offset = readCounter - writeCounter;
+    mFramesOffsetFromService += offset;
+    ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld",
+          (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
+
+    // Force readCounter to match writeCounter.
+    // This is because we cannot change the write counter in the hardware.
+    mAudioEndpoint.setDataReadCounter(writeCounter);
+}
+
 // Write the data, block if needed and timeoutMillis > 0
 aaudio_result_t AudioStreamInternalCapture::read(void *buffer, int32_t numFrames,
                                                int64_t timeoutNanoseconds)
@@ -57,6 +72,18 @@
     const char *traceName = "aaRdNow";
     ATRACE_BEGIN(traceName);
 
+    if (mClockModel.isStarting()) {
+        // Still haven't got any timestamps from server.
+        // Keep waiting until we get some valid timestamps then start writing to the
+        // current buffer position.
+        ALOGD("processDataNow() wait for valid timestamps");
+        // Sleep very briefly and hope we get a timestamp soon.
+        *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
+        ATRACE_END();
+        return 0;
+    }
+    // If we have gotten this far then we have at least one timestamp from server.
+
     if (mAudioEndpoint.isFreeRunning()) {
         //ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter");
         // Update data queue based on the timing model.
@@ -65,6 +92,14 @@
         mAudioEndpoint.setDataWriteCounter(estimatedRemoteCounter);
     }
 
+    // This code assumes that we have already received valid timestamps.
+    if (mNeedCatchUp.isRequested()) {
+        // Catch an MMAP pointer that is already advancing.
+        // This will avoid initial underruns caused by a slow cold start.
+        advanceClientToMatchServerPosition();
+        mNeedCatchUp.acknowledge();
+    }
+
     // If the write index passed the read index then consider it an overrun.
     if (mAudioEndpoint.getEmptyFramesAvailable() < 0) {
         mXRunCount++;
@@ -100,8 +135,8 @@
                 // Calculate frame position based off of the readCounter because
                 // the writeCounter might have just advanced in the background,
                 // causing us to sleep until a later burst.
-                int64_t nextReadPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst;
-                wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
+                int64_t nextPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst;
+                wakeTime = mClockModel.convertPositionToTime(nextPosition);
             }
                 break;
             default:
@@ -186,8 +221,7 @@
 }
 
 int64_t AudioStreamInternalCapture::getFramesRead() {
-    int64_t frames = mAudioEndpoint.getDataWriteCounter()
-                               + mFramesOffsetFromService;
+    int64_t frames = mAudioEndpoint.getDataReadCounter() + mFramesOffsetFromService;
     //ALOGD("AudioStreamInternalCapture::getFramesRead() returns %lld", (long long)frames);
     return frames;
 }
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.h b/media/libaaudio/src/client/AudioStreamInternalCapture.h
index 17f37e8..294dbaf 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.h
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.h
@@ -46,6 +46,8 @@
     }
 protected:
 
+    void advanceClientToMatchServerPosition() override;
+
 /**
  * Low level data processing that will not block. It will just read or write as much as it can.
  *
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 31e0a40..1e02eee 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -48,7 +48,8 @@
 
     mClockModel.stop(AudioClock::getNanoseconds());
     setState(AAUDIO_STREAM_STATE_PAUSING);
-    return AAudioConvert_androidToAAudioResult(pauseWithStatus());
+    mAtomicTimestamp.clear();
+    return mServiceInterface.pauseStream(mServiceStreamHandle);
 }
 
 aaudio_result_t AudioStreamInternalPlay::requestPause()
@@ -72,21 +73,25 @@
     return mServiceInterface.flushStream(mServiceStreamHandle);
 }
 
-void AudioStreamInternalPlay::onFlushFromServer() {
+void AudioStreamInternalPlay::advanceClientToMatchServerPosition() {
     int64_t readCounter = mAudioEndpoint.getDataReadCounter();
     int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
 
     // Bump offset so caller does not see the retrograde motion in getFramesRead().
-    int64_t framesFlushed = writeCounter - readCounter;
-    mFramesOffsetFromService += framesFlushed;
-    ALOGD("AudioStreamInternal::onFlushFromServer() readN = %lld, writeN = %lld, offset = %lld",
+    int64_t offset = writeCounter - readCounter;
+    mFramesOffsetFromService += offset;
+    ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld",
           (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
 
-    // Flush written frames by forcing writeCounter to readCounter.
-    // This is because we cannot move the read counter in the hardware.
+    // Force writeCounter to match readCounter.
+    // This is because we cannot change the read counter in the hardware.
     mAudioEndpoint.setDataWriteCounter(readCounter);
 }
 
+void AudioStreamInternalPlay::onFlushFromServer() {
+    advanceClientToMatchServerPosition();
+}
+
 // Write the data, block if needed and timeoutMillis > 0
 aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames,
                                            int64_t timeoutNanoseconds)
@@ -106,6 +111,18 @@
     const char *traceName = "aaWrNow";
     ATRACE_BEGIN(traceName);
 
+    if (mClockModel.isStarting()) {
+        // Still haven't got any timestamps from server.
+        // Keep waiting until we get some valid timestamps then start writing to the
+        // current buffer position.
+        ALOGD("processDataNow() wait for valid timestamps");
+        // Sleep very briefly and hope we get a timestamp soon.
+        *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
+        ATRACE_END();
+        return 0;
+    }
+    // If we have gotten this far then we have at least one timestamp from server.
+
     // If a DMA channel or DSP is reading the other end then we have to update the readCounter.
     if (mAudioEndpoint.isFreeRunning()) {
         // Update data queue based on the timing model.
@@ -114,6 +131,13 @@
         mAudioEndpoint.setDataReadCounter(estimatedReadCounter);
     }
 
+    if (mNeedCatchUp.isRequested()) {
+        // Catch an MMAP pointer that is already advancing.
+        // This will avoid initial underruns caused by a slow cold start.
+        advanceClientToMatchServerPosition();
+        mNeedCatchUp.acknowledge();
+    }
+
     // If the read index passed the write index then consider it an underrun.
     if (mAudioEndpoint.getFullFramesAvailable() < 0) {
         mXRunCount++;
@@ -153,9 +177,9 @@
                 // Calculate frame position based off of the writeCounter because
                 // the readCounter might have just advanced in the background,
                 // causing us to sleep until a later burst.
-                int64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
+                int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
                         - mAudioEndpoint.getBufferSizeInFrames();
-                wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
+                wakeTime = mClockModel.convertPositionToTime(nextPosition);
             }
                 break;
             default:
@@ -266,7 +290,6 @@
     return framesWritten;
 }
 
-
 int64_t AudioStreamInternalPlay::getFramesRead()
 {
     int64_t framesReadHardware;
@@ -340,3 +363,10 @@
           result, (int) isActive());
     return NULL;
 }
+
+//------------------------------------------------------------------------------
+// Implementation of PlayerBase
+status_t AudioStreamInternalPlay::doSetVolume() {
+    mVolumeRamp.setTarget(mStreamVolume * getDuckAndMuteVolume());
+    return android::NO_ERROR;
+}
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index e59d02c..d5c1b1e 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -54,8 +54,12 @@
 
     aaudio_result_t requestPauseInternal();
 
+    void advanceClientToMatchServerPosition() override;
+
     void onFlushFromServer() override;
 
+    android::status_t doSetVolume() override;
+
 /**
  * Low level write that will not block. It will just write as much as it can.
  *
@@ -78,6 +82,9 @@
                                            int32_t numFrames);
 
     int64_t                  mLastFramesRead = 0; // used to prevent retrograde motion
+
+    LinearRamp               mVolumeRamp;
+
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index c06c8a9..bac69f1 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -48,19 +48,26 @@
 }
 
 void IsochronousClockModel::start(int64_t nanoTime) {
-    ALOGD("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime);
+    ALOGV("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime);
     mMarkerNanoTime = nanoTime;
     mState = STATE_STARTING;
 }
 
 void IsochronousClockModel::stop(int64_t nanoTime) {
-    ALOGD("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime);
+    ALOGV("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime);
     setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
     // TODO should we set position?
     mState = STATE_STOPPED;
 }
 
+bool IsochronousClockModel::isStarting() {
+    return mState == STATE_STARTING;
+}
+
 void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nanoTime) {
+//    ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu",
+//         (long long)framePosition,
+//         (long long)nanoTime);
     int64_t framesDelta = framePosition - mMarkerFramePosition;
     int64_t nanosDelta = nanoTime - mMarkerNanoTime;
     if (nanosDelta < 1000) {
@@ -70,9 +77,6 @@
 //    ALOGD("processTimestamp() - mMarkerFramePosition = %lld at mMarkerNanoTime %llu",
 //         (long long)mMarkerFramePosition,
 //         (long long)mMarkerNanoTime);
-//    ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu",
-//         (long long)framePosition,
-//         (long long)nanoTime);
 
     int64_t expectedNanosDelta = convertDeltaPositionToTime(framesDelta);
 //    ALOGD("processTimestamp() - expectedNanosDelta = %lld, nanosDelta = %llu",
@@ -116,6 +120,8 @@
     default:
         break;
     }
+
+//    ALOGD("processTimestamp() - mState = %d", mState);
 }
 
 void IsochronousClockModel::setSampleRate(int32_t sampleRate) {
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 585f53a..7182376 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -36,6 +36,8 @@
     void start(int64_t nanoTime);
     void stop(int64_t nanoTime);
 
+    bool isStarting();
+
     void processTimestamp(int64_t framePosition, int64_t nanoTime);
 
     /**
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 5089b00..1eaee81 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -24,15 +24,14 @@
 #include <aaudio/AAudio.h>
 #include <aaudio/AAudioTesting.h>
 
+#include "AudioClock.h"
 #include "AudioStreamBuilder.h"
 #include "AudioStream.h"
-#include "AudioClock.h"
+#include "binding/AAudioCommon.h"
 #include "client/AudioStreamInternal.h"
-#include "HandleTracker.h"
 
 using namespace aaudio;
 
-
 // Macros for common code that includes a return.
 // TODO Consider using do{}while(0) construct. I tried but it hung AndroidStudio
 #define CONVERT_BUILDER_HANDLE_OR_RETURN() \
@@ -219,6 +218,7 @@
     ALOGD("AAudioStreamBuilder_openStream() returns %d = %s for (%p) ----------------",
           result, AAudio_convertResultToText(result), audioStream);
     if (result == AAUDIO_OK) {
+        audioStream->registerPlayerBase();
         *streamPtr = (AAudioStream*) audioStream;
     } else {
         *streamPtr = nullptr;
@@ -242,6 +242,7 @@
     ALOGD("AAudioStream_close(%p)", stream);
     if (audioStream != nullptr) {
         audioStream->close();
+        audioStream->unregisterPlayerBase();
         delete audioStream;
         return AAUDIO_OK;
     }
@@ -252,7 +253,7 @@
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
     ALOGD("AAudioStream_requestStart(%p) called --------------", stream);
-    aaudio_result_t result = audioStream->requestStart();
+    aaudio_result_t result = audioStream->systemStart();
     ALOGD("AAudioStream_requestStart(%p) returned %d ---------", stream, result);
     return result;
 }
@@ -261,7 +262,7 @@
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
     ALOGD("AAudioStream_requestPause(%p)", stream);
-    return audioStream->requestPause();
+    return audioStream->systemPause();
 }
 
 AAUDIO_API aaudio_result_t  AAudioStream_requestFlush(AAudioStream* stream)
@@ -275,7 +276,7 @@
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
     ALOGD("AAudioStream_requestStop(%p)", stream);
-    return audioStream->requestStop();
+    return audioStream->systemStop();
 }
 
 AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream* stream,
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 4f1cc37..8dcc37a 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioStream"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -29,13 +29,26 @@
 using namespace aaudio;
 
 AudioStream::AudioStream()
-        : mCallbackEnabled(false)
+        : mPlayerBase(new MyPlayerBase(this))
 {
     // mThread is a pthread_t of unknown size so we need memset.
     memset(&mThread, 0, sizeof(mThread));
     setPeriodNanoseconds(0);
 }
 
+AudioStream::~AudioStream() {
+    ALOGD("destroying %p, state = %s", this, AAudio_convertStreamStateToText(getState()));
+    // 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
+                          || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
+                          || getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
+                        "aaudio stream still in use, state = %s",
+                        AAudio_convertStreamStateToText(getState()));
+
+    mPlayerBase->clearParentReference(); // remove reference to this AudioStream
+}
+
 static const char *AudioStream_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
     const char *result;
     switch (sharingMode) {
@@ -90,9 +103,6 @@
     return AAUDIO_OK;
 }
 
-AudioStream::~AudioStream() {
-    close();
-}
 
 aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
                                                 aaudio_stream_state_t *nextState,
@@ -189,3 +199,38 @@
     return err ? AAudioConvert_androidToAAudioResult(-errno) : mThreadRegistrationResult;
 }
 
+
+#if AAUDIO_USE_VOLUME_SHAPER
+android::media::VolumeShaper::Status AudioStream::applyVolumeShaper(
+        const android::media::VolumeShaper::Configuration& configuration __unused,
+        const android::media::VolumeShaper::Operation& operation __unused) {
+    ALOGW("applyVolumeShaper() is not supported");
+    return android::media::VolumeShaper::Status::ok();
+}
+#endif
+
+AudioStream::MyPlayerBase::MyPlayerBase(AudioStream *parent) : mParent(parent) {
+}
+
+AudioStream::MyPlayerBase::~MyPlayerBase() {
+    ALOGV("MyPlayerBase::~MyPlayerBase(%p) deleted", this);
+}
+
+void AudioStream::MyPlayerBase::registerWithAudioManager() {
+    if (!mRegistered) {
+        init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
+        mRegistered = true;
+    }
+}
+
+void AudioStream::MyPlayerBase::unregisterWithAudioManager() {
+    if (mRegistered) {
+        baseDestroy();
+        mRegistered = false;
+    }
+}
+
+
+void AudioStream::MyPlayerBase::destroy() {
+    unregisterWithAudioManager();
+}
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index ad18751..34202d2 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -21,10 +21,18 @@
 #include <mutex>
 #include <stdint.h>
 #include <aaudio/AAudio.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <utils/StrongPointer.h>
 
+#include "media/VolumeShaper.h"
+#include "media/PlayerBase.h"
 #include "utility/AAudioUtilities.h"
 #include "utility/MonotonicCounter.h"
 
+// Cannot get android::media::VolumeShaper to compile!
+#define AAUDIO_USE_VOLUME_SHAPER  0
+
 namespace aaudio {
 
 typedef void *(*aaudio_audio_thread_proc_t)(void *);
@@ -234,8 +242,132 @@
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
+    // This is used by the AudioManager to duck and mute the stream when changing audio focus.
+    void setDuckAndMuteVolume(float duckAndMuteVolume) {
+        mDuckAndMuteVolume = duckAndMuteVolume;
+        doSetVolume(); // apply this change
+    }
+
+    float getDuckAndMuteVolume() {
+        return mDuckAndMuteVolume;
+    }
+
+    // Implement this in the output subclasses.
+    virtual android::status_t doSetVolume() { return android::NO_ERROR; }
+
+#if AAUDIO_USE_VOLUME_SHAPER
+    virtual ::android::binder::Status applyVolumeShaper(
+            const ::android::media::VolumeShaper::Configuration& configuration __unused,
+            const ::android::media::VolumeShaper::Operation& operation __unused);
+#endif
+
+    /**
+     * Register this stream's PlayerBase with the AudioManager if needed.
+     * Only register output streams.
+     * This should only be called for client streams and not for streams
+     * that run in the service.
+     */
+    void registerPlayerBase() {
+        if (getDirection() == AAUDIO_DIRECTION_OUTPUT) {
+            mPlayerBase->registerWithAudioManager();
+        }
+    }
+
+    /**
+     * Unregister this stream's PlayerBase with the AudioManager.
+     * This will only unregister if already registered.
+     */
+    void unregisterPlayerBase() {
+        mPlayerBase->unregisterWithAudioManager();
+    }
+
+    // Pass start request through PlayerBase for tracking.
+    aaudio_result_t systemStart() {
+        mPlayerBase->start();
+        // Pass aaudio_result_t around the PlayerBase interface, which uses status__t.
+        return mPlayerBase->getResult();
+    }
+
+    aaudio_result_t systemPause() {
+        mPlayerBase->pause();
+        return mPlayerBase->getResult();
+    }
+
+    aaudio_result_t systemStop() {
+        mPlayerBase->stop();
+        return mPlayerBase->getResult();
+    }
+
 protected:
 
+    // PlayerBase allows the system to control the stream.
+    // Calling through PlayerBase->start() notifies the AudioManager of the player state.
+    // The AudioManager also can start/stop a stream by calling mPlayerBase->playerStart().
+    // systemStart() ==> mPlayerBase->start()   mPlayerBase->playerStart() ==> requestStart()
+    //                        \                           /
+    //                         ------ AudioManager -------
+    class MyPlayerBase : public android::PlayerBase {
+    public:
+        explicit MyPlayerBase(AudioStream *parent);
+
+        virtual ~MyPlayerBase();
+
+        /**
+         * Register for volume changes and remote control.
+         */
+        void registerWithAudioManager();
+
+        /**
+         * UnRegister.
+         */
+        void unregisterWithAudioManager();
+
+        /**
+         * Just calls unregisterWithAudioManager().
+         */
+        void destroy() override;
+
+        void clearParentReference() { mParent = nullptr; }
+
+        android::status_t playerStart() override {
+            // mParent should NOT be null. So go ahead and crash if it is.
+            mResult = mParent->requestStart();
+            return AAudioConvert_aaudioToAndroidStatus(mResult);
+        }
+
+        android::status_t playerPause() override {
+            mResult = mParent->requestPause();
+            return AAudioConvert_aaudioToAndroidStatus(mResult);
+        }
+
+        android::status_t playerStop() override {
+            mResult = mParent->requestStop();
+            return AAudioConvert_aaudioToAndroidStatus(mResult);
+        }
+
+        android::status_t playerSetVolume() override {
+            // No pan and only left volume is taken into account from IPLayer interface
+            mParent->setDuckAndMuteVolume(mVolumeMultiplierL  /* * mPanMultiplierL */);
+            return android::NO_ERROR;
+        }
+
+#if AAUDIO_USE_VOLUME_SHAPER
+        ::android::binder::Status applyVolumeShaper(
+                const ::android::media::VolumeShaper::Configuration& configuration,
+                const ::android::media::VolumeShaper::Operation& operation) {
+            return mParent->applyVolumeShaper(configuration, operation);
+        }
+#endif
+
+        aaudio_result_t getResult() {
+            return mResult;
+        }
+
+    private:
+        AudioStream          *mParent;
+        aaudio_result_t       mResult = AAUDIO_OK;
+        bool                  mRegistered = false;
+    };
 
     /**
      * This should not be called after the open() call.
@@ -275,7 +407,9 @@
 
     std::mutex           mStreamMutex;
 
-    std::atomic<bool>    mCallbackEnabled;
+    std::atomic<bool>    mCallbackEnabled{false};
+
+    float                mDuckAndMuteVolume = 1.0f;
 
 protected:
 
@@ -288,6 +422,8 @@
     }
 
 private:
+    const android::sp<MyPlayerBase>   mPlayerBase;
+
     // These do not change after open().
     int32_t                mSamplesPerFrame = AAUDIO_UNSPECIFIED;
     int32_t                mSampleRate = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index 2816bac..ee2504d 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <utils/String16.h>
 #include <media/AudioTrack.h>
+#include <media/AudioTimestamp.h>
 #include <aaudio/AAudio.h>
 
 #include "core/AudioStream.h"
@@ -30,7 +31,8 @@
 using namespace aaudio;
 
 AudioStreamLegacy::AudioStreamLegacy()
-        : AudioStream(), mDeviceCallback(new StreamDeviceCallback(this)) {
+        : AudioStream()
+        , mDeviceCallback(new StreamDeviceCallback(this)) {
 }
 
 AudioStreamLegacy::~AudioStreamLegacy() {
@@ -46,33 +48,51 @@
     return AudioStreamLegacy_callback;
 }
 
-// Implement FixedBlockProcessor
-int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
-    int32_t frameCount = numBytes / getBytesPerFrame();
+int32_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer, int32_t numFrames) {
+    if (getDirection() == AAUDIO_DIRECTION_INPUT) {
+        // Increment before because we already got the data from the device.
+        incrementFramesRead(numFrames);
+    }
+
     // Call using the AAudio callback interface.
     AAudioStream_dataCallback appCallback = getDataCallbackProc();
-    return (*appCallback)(
+    aaudio_data_callback_result_t callbackResult = (*appCallback)(
             (AAudioStream *) this,
             getDataCallbackUserData(),
             buffer,
-            frameCount);
+            numFrames);
+
+    if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE
+            && getDirection() == AAUDIO_DIRECTION_OUTPUT) {
+        // Increment after because we are going to write the data to the device.
+        incrementFramesWritten(numFrames);
+    }
+    return callbackResult;
+}
+
+// Implement FixedBlockProcessor
+int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
+    int32_t numFrames = numBytes / getBytesPerFrame();
+    return callDataCallbackFrames(buffer, numFrames);
 }
 
 void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) {
     aaudio_data_callback_result_t callbackResult;
 
-    if (!mCallbackEnabled.load()) {
-        return;
-    }
-
     switch (opcode) {
         case AAUDIO_CALLBACK_OPERATION_PROCESS_DATA: {
-            if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
-                // Note that this code assumes an AudioTrack::Buffer is the same as
-                // AudioRecord::Buffer
-                // TODO define our own AudioBuffer and pass it from the subclasses.
-                AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
-                if (audioBuffer->frameCount == 0) return;
+            checkForDisconnectRequest();
+
+            // Note that this code assumes an AudioTrack::Buffer is the same as
+            // AudioRecord::Buffer
+            // TODO define our own AudioBuffer and pass it from the subclasses.
+            AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
+            if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED || !mCallbackEnabled.load()) {
+                audioBuffer->size = 0; // silence the buffer
+            } else {
+                if (audioBuffer->frameCount == 0) {
+                    return;
+                }
 
                 // If the caller specified an exact size then use a block size adapter.
                 if (mBlockAdapter != nullptr) {
@@ -81,40 +101,28 @@
                             (uint8_t *) audioBuffer->raw, byteCount);
                 } else {
                     // Call using the AAudio callback interface.
-                    callbackResult = (*getDataCallbackProc())(
-                            (AAudioStream *) this,
-                            getDataCallbackUserData(),
-                            audioBuffer->raw,
-                            audioBuffer->frameCount
-                            );
+                    callbackResult = callDataCallbackFrames((uint8_t *)audioBuffer->raw,
+                                                            audioBuffer->frameCount);
                 }
                 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
                     audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame();
-                    incrementClientFrameCounter(audioBuffer->frameCount);
                 } else {
                     audioBuffer->size = 0;
                 }
 
-                if (updateStateMachine() == AAUDIO_OK) {
-                    break; // don't fall through
+                if (updateStateMachine() != AAUDIO_OK) {
+                    forceDisconnect();
+                    mCallbackEnabled.store(false);
                 }
             }
         }
-        /// FALL THROUGH
+            break;
 
         // Stream got rerouted so we disconnect.
-        case AAUDIO_CALLBACK_OPERATION_DISCONNECTED: {
-            setState(AAUDIO_STREAM_STATE_DISCONNECTED);
+        case AAUDIO_CALLBACK_OPERATION_DISCONNECTED:
             ALOGD("processCallbackCommon() stream disconnected");
-            if (getErrorCallbackProc() != nullptr) {
-                (*getErrorCallbackProc())(
-                        (AAudioStream *) this,
-                        getErrorCallbackUserData(),
-                        AAUDIO_ERROR_DISCONNECTED
-                        );
-            }
+            forceDisconnect();
             mCallbackEnabled.store(false);
-        }
             break;
 
         default:
@@ -122,6 +130,30 @@
     }
 }
 
+
+
+void AudioStreamLegacy::checkForDisconnectRequest() {
+    if (mRequestDisconnect.isRequested()) {
+        ALOGD("checkForDisconnectRequest() mRequestDisconnect acknowledged");
+        forceDisconnect();
+        mRequestDisconnect.acknowledge();
+        mCallbackEnabled.store(false);
+    }
+}
+
+void AudioStreamLegacy::forceDisconnect() {
+    if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
+        setState(AAUDIO_STREAM_STATE_DISCONNECTED);
+        if (getErrorCallbackProc() != nullptr) {
+            (*getErrorCallbackProc())(
+                    (AAudioStream *) this,
+                    getErrorCallbackUserData(),
+                    AAUDIO_ERROR_DISCONNECTED
+            );
+        }
+    }
+}
+
 aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
                                                    int64_t *framePosition,
                                                    int64_t *timeNanoseconds,
@@ -139,8 +171,23 @@
             return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
             break;
     }
-    status_t status = extendedTimestamp->getBestTimestamp(framePosition, timeNanoseconds, timebase);
-    return AAudioConvert_androidToAAudioResult(status);
+    ExtendedTimestamp::Location location = ExtendedTimestamp::Location::LOCATION_INVALID;
+    int64_t localPosition;
+    status_t status = extendedTimestamp->getBestTimestamp(&localPosition, timeNanoseconds,
+                                                          timebase, &location);
+    // use MonotonicCounter to prevent retrograde motion.
+    mTimestampPosition.update32((int32_t)localPosition);
+    *framePosition = mTimestampPosition.get();
+
+//    ALOGD("getBestTimestamp() fposition: server = %6lld, kernel = %6lld, location = %d",
+//          (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_SERVER],
+//          (long long) extendedTimestamp->mPosition[ExtendedTimestamp::Location::LOCATION_KERNEL],
+//          (int)location);
+    if (status == WOULD_BLOCK) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    } else {
+        return AAudioConvert_androidToAAudioResult(status);
+    }
 }
 
 void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
@@ -148,15 +195,18 @@
     ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId);
     if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
             getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
-        setState(AAUDIO_STREAM_STATE_DISCONNECTED);
-        // if we have a data callback and the stream is active, send the error callback from
-        // data callback thread when it sees the DISCONNECTED state
-        if (!isDataCallbackActive() && getErrorCallbackProc() != nullptr) {
-            (*getErrorCallbackProc())(
-                    (AAudioStream *) this,
-                    getErrorCallbackUserData(),
-                    AAUDIO_ERROR_DISCONNECTED
-                    );
+        // Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
+        // If we have a data callback and the stream is active, then ask the data callback
+        // to DISCONNECT and call the error callback.
+        if (isDataCallbackActive()) {
+            ALOGD("onAudioDeviceUpdate() request DISCONNECT in data callback due to device change");
+            // If the stream is stopped before the data callback has a chance to handle the
+            // request then the requestStop() and requestPause() methods will handle it after
+            // the callback has stopped.
+            mRequestDisconnect.request();
+        } else {
+            ALOGD("onAudioDeviceUpdate() DISCONNECT the stream now");
+            forceDisconnect();
         }
     }
     setDeviceId(deviceId);
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h
index d2ef3c7..7e28579 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.h
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h
@@ -24,6 +24,7 @@
 
 #include "AudioStream.h"
 #include "AAudioLegacy.h"
+#include "utility/AAudioUtilities.h"
 #include "utility/FixedBlockAdapter.h"
 
 namespace aaudio {
@@ -63,6 +64,8 @@
 
     aaudio_legacy_callback_t getLegacyCallback();
 
+    int32_t callDataCallbackFrames(uint8_t *buffer, int32_t numFrames);
+
     // This is public so it can be called from the C callback function.
     // This is called from the AudioTrack/AudioRecord client.
     virtual void processCallback(int event, void *info) = 0;
@@ -109,6 +112,10 @@
 
     void onAudioDeviceUpdate(audio_port_handle_t deviceId);
 
+    void checkForDisconnectRequest();
+
+    void forceDisconnect();
+
     void onStart() { mCallbackEnabled.store(true); }
     void onStop() { mCallbackEnabled.store(false); }
 
@@ -122,11 +129,14 @@
 
     MonotonicCounter           mFramesWritten;
     MonotonicCounter           mFramesRead;
+    MonotonicCounter           mTimestampPosition;
 
     FixedBlockAdapter         *mBlockAdapter = nullptr;
     aaudio_wrapping_frames_t   mPositionWhenStarting = 0;
     int32_t                    mCallbackBufferSize = 0;
     const android::sp<StreamDeviceCallback>   mDeviceCallback;
+
+    AtomicRequestor            mRequestDisconnect;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 041280d..bc6e60c 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioStreamRecord"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -181,11 +181,12 @@
 {
     // TODO add close() or release() to AudioRecord API then call it from here
     if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
+        mAudioRecord->removeAudioDeviceCallback(mDeviceCallback);
         mAudioRecord.clear();
         setState(AAUDIO_STREAM_STATE_CLOSED);
     }
     mFixedBlockWriter.close();
-    return AAUDIO_OK;
+    return AudioStream::close();
 }
 
 void AudioStreamRecord::processCallback(int event, void *info) {
@@ -233,8 +234,11 @@
     onStop();
     setState(AAUDIO_STREAM_STATE_STOPPING);
     incrementFramesWritten(getFramesRead() - getFramesWritten()); // TODO review
+    mTimestampPosition.set(getFramesRead());
     mAudioRecord->stop();
     mFramesRead.reset32();
+    mTimestampPosition.reset32();
+    checkForDisconnectRequest();
     return AAUDIO_OK;
 }
 
@@ -334,7 +338,9 @@
                                                int64_t *timeNanoseconds) {
     ExtendedTimestamp extendedTimestamp;
     status_t status = mAudioRecord->getTimestamp(&extendedTimestamp);
-    if (status != NO_ERROR) {
+    if (status == WOULD_BLOCK) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    } else if (status != NO_ERROR) {
         return AAudioConvert_androidToAAudioResult(status);
     }
     return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp);
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 155362c..0e9aaef 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioStreamTrack"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -115,7 +115,7 @@
 
     ALOGD("AudioStreamTrack::open(), request notificationFrames = %d, frameCount = %u",
           notificationFrames, (uint)frameCount);
-    mAudioTrack = new AudioTrack();
+    mAudioTrack = new AudioTrack(); // TODO review
     if (getDeviceId() != AAUDIO_UNSPECIFIED) {
         mAudioTrack->setOutputDevice(getDeviceId());
     }
@@ -143,8 +143,7 @@
         return AAudioConvert_androidToAAudioResult(status);
     }
 
-    //TrackPlayerBase init
-    init(mAudioTrack.get(), PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
+    doSetVolume();
 
     // Get the actual values from the AudioTrack.
     setSamplesPerFrame(mAudioTrack->channelCount());
@@ -199,7 +198,7 @@
 aaudio_result_t AudioStreamTrack::close()
 {
     if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
-        destroy();
+        mAudioTrack->removeAudioDeviceCallback(mDeviceCallback);
         setState(AAUDIO_STREAM_STATE_CLOSED);
     }
     mFixedBlockReader.close();
@@ -224,8 +223,7 @@
     return;
 }
 
-aaudio_result_t AudioStreamTrack::requestStart()
-{
+aaudio_result_t AudioStreamTrack::requestStart() {
     std::lock_guard<std::mutex> lock(mStreamMutex);
 
     if (mAudioTrack.get() == nullptr) {
@@ -238,7 +236,7 @@
         return AAudioConvert_androidToAAudioResult(err);
     }
 
-    err = startWithStatus();
+    err = mAudioTrack->start();
     if (err != OK) {
         return AAudioConvert_androidToAAudioResult(err);
     } else {
@@ -248,12 +246,11 @@
     return AAUDIO_OK;
 }
 
-aaudio_result_t AudioStreamTrack::requestPause()
-{
+aaudio_result_t AudioStreamTrack::requestPause() {
     std::lock_guard<std::mutex> lock(mStreamMutex);
 
     if (mAudioTrack.get() == nullptr) {
-        ALOGE("AudioStreamTrack::requestPause() no AudioTrack");
+        ALOGE("requestPause() no AudioTrack");
         return AAUDIO_ERROR_INVALID_STATE;
     } else if (getState() != AAUDIO_STREAM_STATE_STARTING
             && getState() != AAUDIO_STREAM_STATE_STARTED) {
@@ -263,7 +260,8 @@
     }
     onStop();
     setState(AAUDIO_STREAM_STATE_PAUSING);
-    pause();
+    mAudioTrack->pause();
+    checkForDisconnectRequest();
     status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
     if (err != OK) {
         return AAudioConvert_androidToAAudioResult(err);
@@ -285,6 +283,7 @@
     incrementFramesRead(getFramesWritten() - getFramesRead());
     mAudioTrack->flush();
     mFramesWritten.reset32();
+    mTimestampPosition.reset32();
     return AAUDIO_OK;
 }
 
@@ -298,8 +297,11 @@
     onStop();
     setState(AAUDIO_STREAM_STATE_STOPPING);
     incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
-    stop();
+    mTimestampPosition.set(getFramesWritten());
     mFramesWritten.reset32();
+    mTimestampPosition.reset32();
+    mAudioTrack->stop();
+    checkForDisconnectRequest();
     return AAUDIO_OK;
 }
 
@@ -444,8 +446,59 @@
                                      int64_t *timeNanoseconds) {
     ExtendedTimestamp extendedTimestamp;
     status_t status = mAudioTrack->getTimestamp(&extendedTimestamp);
-    if (status != NO_ERROR) {
+    if (status == WOULD_BLOCK) {
+        return AAUDIO_ERROR_INVALID_STATE;
+    } if (status != NO_ERROR) {
         return AAudioConvert_androidToAAudioResult(status);
     }
-    return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp);
+    int64_t position = 0;
+    int64_t nanoseconds = 0;
+    aaudio_result_t result = getBestTimestamp(clockId, &position,
+                                              &nanoseconds, &extendedTimestamp);
+    if (result == AAUDIO_OK) {
+        if (position < getFramesWritten()) {
+            *framePosition = position;
+            *timeNanoseconds = nanoseconds;
+            return result;
+        } else {
+            return AAUDIO_ERROR_INVALID_STATE; // TODO review, documented but not consistent
+        }
+    }
+    return result;
 }
+
+status_t AudioStreamTrack::doSetVolume() {
+    status_t status = NO_INIT;
+    if (mAudioTrack.get() != nullptr) {
+        float volume = getDuckAndMuteVolume();
+        mAudioTrack->setVolume(volume, volume);
+        status = NO_ERROR;
+    }
+    return status;
+}
+
+#if AAUDIO_USE_VOLUME_SHAPER
+
+using namespace android::media::VolumeShaper;
+
+binder::Status AudioStreamTrack::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.get() != nullptr) {
+        ALOGD("applyVolumeShaper() from IPlayer");
+        binder::Status status = mAudioTrack->applyVolumeShaper(spConfiguration, spOperation);
+        if (status < 0) { // a non-negative value is the volume shaper id.
+            ALOGE("applyVolumeShaper() failed with status %d", status);
+        }
+        return binder::Status::fromStatusT(status);
+    } else {
+        ALOGD("applyVolumeShaper()"
+                      " no AudioTrack for volume control from IPlayer");
+        return binder::Status::ok();
+    }
+}
+#endif
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
index 3230ac8..a871db4 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -19,6 +19,7 @@
 
 #include <math.h>
 #include <media/TrackPlayerBase.h>
+#include <media/AudioTrack.h>
 #include <aaudio/AAudio.h>
 
 #include "AudioStreamBuilder.h"
@@ -32,7 +33,7 @@
 /**
  * Internal stream that uses the legacy AudioTrack path.
  */
-class AudioStreamTrack : public AudioStreamLegacy, public android::TrackPlayerBase {
+class AudioStreamTrack : public AudioStreamLegacy {
 public:
     AudioStreamTrack();
 
@@ -76,8 +77,18 @@
         return incrementFramesWritten(frames);
     }
 
+    android::status_t doSetVolume() override;
+
+#if AAUDIO_USE_VOLUME_SHAPER
+    virtual android::binder::Status applyVolumeShaper(
+            const android::media::VolumeShaper::Configuration& configuration,
+            const android::media::VolumeShaper::Operation& operation) override;
+#endif
+
 private:
 
+    android::sp<android::AudioTrack> mAudioTrack;
+
     // adapts between variable sized blocks and fixed size blocks
     FixedBlockReader                 mFixedBlockReader;
 
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index b0c6c94..3afa976 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -272,8 +272,7 @@
 class SimpleDoubleBuffer {
 public:
     SimpleDoubleBuffer()
-            : mValues()
-            , mCounter(0) {}
+            : mValues() {}
 
     __attribute__((no_sanitize("integer")))
     void write(T value) {
@@ -282,6 +281,14 @@
         mCounter++; // Increment AFTER updating storage, OK if it wraps.
     }
 
+    /**
+     * This should only be called by the same thread that calls write() or when
+     * no other thread is calling write.
+     */
+    void clear() {
+        mCounter.store(0);
+    }
+
     T read() const {
         T result;
         int before;
@@ -293,7 +300,7 @@
             int index = (before & 1) ^ 1;
             result = mValues[index];
             after = mCounter.load();
-        } while ((after != before) && --timeout > 0);
+        } while ((after != before) && (after > 0) && (--timeout > 0));
         return result;
     }
 
@@ -306,7 +313,7 @@
 
 private:
     T                    mValues[2];
-    std::atomic<int>     mCounter;
+    std::atomic<int>     mCounter{0};
 };
 
 class Timestamp {
@@ -328,4 +335,35 @@
     int64_t mNanoseconds;
 };
 
+
+/**
+ * Pass a request to another thread.
+ * This is used when one thread, A, wants another thread, B, to do something.
+ * A naive approach would be for A to set a flag and for B to clear it when done.
+ * But that creates a race condition. This technique avoids the race condition.
+ *
+ * Assumes only one requester and one acknowledger.
+ */
+class AtomicRequestor {
+public:
+
+    __attribute__((no_sanitize("integer")))
+    void request() {
+        mRequested++;
+    }
+
+    __attribute__((no_sanitize("integer")))
+    bool isRequested() {
+        return (mRequested.load() - mAcknowledged.load()) > 0;
+    }
+
+    __attribute__((no_sanitize("integer")))
+    void acknowledge() {
+        mAcknowledged++;
+    }
+
+private:
+    std::atomic<int> mRequested{0};
+    std::atomic<int> mAcknowledged{0};
+};
 #endif //UTILITY_AAUDIO_UTILITIES_H
diff --git a/media/libaaudio/src/utility/HandleTracker.cpp b/media/libaaudio/src/utility/HandleTracker.cpp
deleted file mode 100644
index 35ce95a..0000000
--- a/media/libaaudio/src/utility/HandleTracker.cpp
+++ /dev/null
@@ -1,276 +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 "AAudio"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <assert.h>
-#include <functional>
-#include <iomanip>
-#include <new>
-#include <sstream>
-#include <stdint.h>
-#include <utils/Mutex.h>
-
-#include <aaudio/AAudio.h>
-#include "AAudioUtilities.h"
-#include "HandleTracker.h"
-
-using android::Mutex;
-
-// Handle format is: tgggiiii
-// where each letter is 4 bits, t=type, g=generation, i=index
-
-#define TYPE_SIZE           4
-#define GENERATION_SIZE    12
-#define INDEX_SIZE         16
-
-#define GENERATION_INVALID  0
-#define GENERATION_SHIFT    INDEX_SIZE
-
-#define TYPE_MASK           ((1 << TYPE_SIZE) - 1)
-#define GENERATION_MASK     ((1 << GENERATION_SIZE) - 1)
-#define INDEX_MASK          ((1 << INDEX_SIZE) - 1)
-
-#define SLOT_UNAVAILABLE    (-1)
-
-// Error if handle is negative so type is limited to bottom half.
-#define HANDLE_INVALID_TYPE TYPE_MASK
-
-static_assert(HANDLE_TRACKER_MAX_TYPES == (1 << (TYPE_SIZE - 1)),
-    "Mismatch between header and cpp.");
-static_assert(HANDLE_TRACKER_MAX_HANDLES == (1 << (INDEX_SIZE)),
-    "Mismatch between header and cpp.");
-
-HandleTracker::HandleTracker(uint32_t maxHandles)
-        : mMaxHandleCount(maxHandles)
-        , mHandleHeaders(nullptr)
-{
-    assert(maxHandles <= HANDLE_TRACKER_MAX_HANDLES);
-    // Allocate arrays to hold addresses and validation info.
-    mHandleAddresses = (handle_tracker_address_t *)
-            new(std::nothrow) handle_tracker_address_t[maxHandles];
-    if (mHandleAddresses != nullptr) {
-        mHandleHeaders = new(std::nothrow) handle_tracker_header_t[maxHandles];
-
-        if (mHandleHeaders != nullptr) {
-            handle_tracker_header_t initialHeader = buildHeader(0, 1);
-            // Initialize linked list of free nodes. nullptr terminated.
-            for (uint32_t i = 0; i < (maxHandles - 1); i++) {
-                mHandleAddresses[i] = &mHandleAddresses[i + 1]; // point to next node
-                mHandleHeaders[i] = initialHeader;
-            }
-            mNextFreeAddress = &mHandleAddresses[0];
-            mHandleAddresses[maxHandles - 1] = nullptr;
-            mHandleHeaders[maxHandles - 1] = 0;
-        } else {
-            delete[] mHandleAddresses; // so the class appears uninitialized
-            mHandleAddresses = nullptr;
-        }
-    }
-}
-
-HandleTracker::~HandleTracker()
-{
-    Mutex::Autolock _l(mLock);
-    delete[] mHandleAddresses;
-    delete[] mHandleHeaders;
-    mHandleAddresses = nullptr;
-}
-
-bool HandleTracker::isInitialized() const {
-    return mHandleAddresses != nullptr;
-}
-
-
-
-std::string HandleTracker::dump() const {
-    if (!isInitialized()) {
-        return "HandleTracker is not initialized\n";
-    }
-
-    std::stringstream result;
-    const bool isLocked = AAudio_tryUntilTrue(
-            [this]()->bool { return mLock.tryLock(); } /* f */,
-            50 /* times */,
-            20 /* sleepMs */);
-    if (!isLocked) {
-        result << "HandleTracker may be deadlocked\n";
-    }
-
-    result << "HandleTracker:\n";
-    result << "  HandleHeaders:\n";
-    // atLineStart() can be changed to support an arbitrary line breaking algorithm;
-    // it should return true when a new line starts.
-    // For simplicity, we will use a constant 16 items per line.
-    const auto atLineStart = [](int index) -> bool {
-        // Magic constant of 0xf used for mask to detect start every 16 items.
-        return (index & 0xf) == 0; };
-    const auto atLineEnd = [this, &atLineStart](int index) -> bool {
-        return atLineStart(index + 1) || index == mMaxHandleCount - 1; };
-
-    for (int i = 0; i < mMaxHandleCount; ++i) {
-        if (atLineStart(i)) {
-            result << "    ";
-        }
-        result << std::hex << std::setw(4) << std::setfill('0') << mHandleHeaders[i]
-               << (atLineEnd(i) ? "\n" : " ");
-    }
-
-    if (isLocked) {
-        mLock.unlock();
-    }
-    return result.str();
-}
-
-handle_tracker_slot_t HandleTracker::allocateSlot_l() {
-    void **allocated = mNextFreeAddress;
-    if (allocated == nullptr) {
-        return SLOT_UNAVAILABLE;
-    }
-    // Remove this slot from the head of the linked list.
-    mNextFreeAddress = (void **) *allocated;
-    return (allocated - mHandleAddresses);
-}
-
-handle_tracker_generation_t HandleTracker::nextGeneration_l(handle_tracker_slot_t index) {
-    handle_tracker_generation_t generation = (mHandleHeaders[index] + 1) & GENERATION_MASK;
-    // Avoid generation zero so that 0x0 is not a valid handle.
-    if (generation == GENERATION_INVALID) {
-        generation++;
-    }
-    return generation;
-}
-
-aaudio_handle_t HandleTracker::put(handle_tracker_type_t type, void *address)
-{
-    if (type < 0 || type >= HANDLE_TRACKER_MAX_TYPES) {
-        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_OUT_OF_RANGE);
-    }
-    if (!isInitialized()) {
-        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_MEMORY);
-    }
-
-    Mutex::Autolock _l(mLock);
-
-    // Find an empty slot.
-    handle_tracker_slot_t index = allocateSlot_l();
-    if (index == SLOT_UNAVAILABLE) {
-        ALOGE("HandleTracker::put() no room for more handles");
-        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_FREE_HANDLES);
-    }
-
-    // Cycle the generation counter so stale handles can be detected.
-    handle_tracker_generation_t generation = nextGeneration_l(index); // reads header table
-    handle_tracker_header_t inputHeader = buildHeader(type, generation);
-
-    // These two writes may need to be observed by other threads or cores during get().
-    mHandleHeaders[index] = inputHeader;
-    mHandleAddresses[index] = address;
-    // TODO use store release to enforce memory order with get()
-
-    // Generate a handle.
-    aaudio_handle_t handle = buildHandle(inputHeader, index);
-
-    ALOGV("HandleTracker::put(%p) returns 0x%08x", address, handle);
-    return handle;
-}
-
-handle_tracker_slot_t HandleTracker::handleToIndex(handle_tracker_type_t type,
-                                                   aaudio_handle_t handle) const
-{
-    // Validate the handle.
-    handle_tracker_slot_t index = extractIndex(handle);
-    if (index >= mMaxHandleCount) {
-        ALOGE("HandleTracker::handleToIndex() invalid handle = 0x%08X", handle);
-        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
-    }
-    handle_tracker_generation_t handleGeneration = extractGeneration(handle);
-    handle_tracker_header_t inputHeader = buildHeader(type, handleGeneration);
-    // We do not need to synchronize this access to mHandleHeaders because it is constant for
-    // the lifetime of the handle.
-    if (inputHeader != mHandleHeaders[index]) {
-        ALOGE("HandleTracker::handleToIndex() inputHeader = 0x%08x != mHandleHeaders[%d] = 0x%08x",
-             inputHeader, index, mHandleHeaders[index]);
-        return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
-    }
-    return index;
-}
-
-handle_tracker_address_t HandleTracker::get(handle_tracker_type_t type, aaudio_handle_t handle) const
-{
-    if (!isInitialized()) {
-        return nullptr;
-    }
-    handle_tracker_slot_t index = handleToIndex(type, handle);
-    if (index >= 0) {
-        // We do not need to synchronize this access to mHandleHeaders because this slot
-        // is allocated and, therefore, not part of the linked list of free slots.
-        return mHandleAddresses[index];
-    } else {
-        return nullptr;
-    }
-}
-
-handle_tracker_address_t HandleTracker::remove(handle_tracker_type_t type, aaudio_handle_t handle) {
-    if (!isInitialized()) {
-        return nullptr;
-    }
-
-    Mutex::Autolock _l(mLock);
-
-    handle_tracker_slot_t index = handleToIndex(type,handle);
-    if (index >= 0) {
-        handle_tracker_address_t address = mHandleAddresses[index];
-
-        // Invalidate the header type but preserve the generation count.
-        handle_tracker_generation_t generation = mHandleHeaders[index] & GENERATION_MASK;
-        handle_tracker_header_t inputHeader = buildHeader(
-                (handle_tracker_type_t) HANDLE_INVALID_TYPE, generation);
-        mHandleHeaders[index] = inputHeader;
-
-        // Add this slot to the head of the linked list.
-        mHandleAddresses[index] = mNextFreeAddress;
-        mNextFreeAddress = (handle_tracker_address_t *) &mHandleAddresses[index];
-        return address;
-    } else {
-        return nullptr;
-    }
-}
-
-aaudio_handle_t HandleTracker::buildHandle(handle_tracker_header_t typeGeneration,
-                                         handle_tracker_slot_t index) {
-    return (aaudio_handle_t)((typeGeneration << GENERATION_SHIFT) | (index & INDEX_MASK));
-}
-
-handle_tracker_header_t HandleTracker::buildHeader(handle_tracker_type_t type,
-                                    handle_tracker_generation_t generation)
-{
-    return (handle_tracker_header_t) (((type & TYPE_MASK) << GENERATION_SIZE)
-        | (generation & GENERATION_MASK));
-}
-
-handle_tracker_slot_t HandleTracker::extractIndex(aaudio_handle_t handle)
-{
-    return handle & INDEX_MASK;
-}
-
-handle_tracker_generation_t HandleTracker::extractGeneration(aaudio_handle_t handle)
-{
-    return (handle >> GENERATION_SHIFT) & GENERATION_MASK;
-}
diff --git a/media/libaaudio/src/utility/HandleTracker.h b/media/libaaudio/src/utility/HandleTracker.h
deleted file mode 100644
index a4c51c0..0000000
--- a/media/libaaudio/src/utility/HandleTracker.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * 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 UTILITY_HANDLE_TRACKER_H
-#define UTILITY_HANDLE_TRACKER_H
-
-#include <stdint.h>
-#include <string>
-#include <utils/Mutex.h>
-
-typedef int32_t  aaudio_handle_t;
-typedef int32_t  handle_tracker_type_t;       // what kind of handle
-typedef int32_t  handle_tracker_slot_t;       // index in allocation table
-typedef int32_t  handle_tracker_generation_t; // incremented when slot used
-typedef uint16_t handle_tracker_header_t;     // combines type and generation
-typedef void    *handle_tracker_address_t;    // address of something that is stored here
-
-#define HANDLE_TRACKER_MAX_TYPES    (1 << 3)
-#define HANDLE_TRACKER_MAX_HANDLES  (1 << 16)
-
-/**
- * Represent Objects using an integer handle that can be used with Java.
- * This also makes the 'C' ABI more robust.
- *
- * Note that this should only be called from a single thread.
- * If you call it from more than one thread then you need to use your own mutex.
- */
-class HandleTracker {
-
-public:
-    /**
-     * @param maxHandles cannot exceed HANDLE_TRACKER_MAX_HANDLES
-     */
-    HandleTracker(uint32_t maxHandles = 256);
-    virtual ~HandleTracker();
-
-    /**
-     * Don't use if this returns false;
-     * @return true if the internal allocation succeeded
-     */
-    bool isInitialized() const;
-
-    /**
-     * Returns HandleTracker information.
-     *
-     * Will attempt to get the object lock, but will proceed
-     * even if it cannot.
-     *
-     * Each line of information ends with a newline.
-     *
-     * @return a string representing the HandleTracker info.
-     */
-    std::string dump() const;
-
-    /**
-     * Store a pointer and return a handle that can be used to retrieve the pointer.
-     *
-     * It is safe to call put() or remove() from multiple threads.
-     *
-     * @param expectedType the type of the object to be tracked
-     * @param address pointer to be converted to a handle
-     * @return a valid handle or a negative error
-     */
-    aaudio_handle_t put(handle_tracker_type_t expectedType, handle_tracker_address_t address);
-
-    /**
-     * Get the original pointer associated with the handle.
-     * The handle will be validated to prevent stale handles from being reused.
-     * Note that the validation is designed to prevent common coding errors and not
-     * to prevent deliberate hacking.
-     *
-     * @param expectedType shouldmatch the type we passed to put()
-     * @param handle to be converted to a pointer
-     * @return address associated with handle or nullptr
-     */
-    handle_tracker_address_t get(handle_tracker_type_t expectedType, aaudio_handle_t handle) const;
-
-    /**
-     * Free up the storage associated with the handle.
-     * Subsequent attempts to use the handle will fail.
-     *
-     * Do NOT remove() a handle while get() is being called for the same handle from another thread.
-     *
-     * @param expectedType shouldmatch the type we passed to put()
-     * @param handle to be removed from tracking
-     * @return address associated with handle or nullptr if not found
-     */
-    handle_tracker_address_t remove(handle_tracker_type_t expectedType, aaudio_handle_t handle);
-
-private:
-    const int32_t               mMaxHandleCount;   // size of array
-    // This address is const after initialization.
-    handle_tracker_address_t  * mHandleAddresses;  // address of objects or a free linked list node
-    // This address is const after initialization.
-    handle_tracker_header_t   * mHandleHeaders;    // combination of type and generation
-    // head of the linked list of free nodes in mHandleAddresses
-    handle_tracker_address_t  * mNextFreeAddress;
-
-    // This Mutex protects the linked list of free nodes.
-    // The list is managed using mHandleAddresses and mNextFreeAddress.
-    // The data in mHandleHeaders is only changed by put() and remove().
-    mutable android::Mutex      mLock;
-
-    /**
-     * Pull slot off of a list of empty slots.
-     * @return index or a negative error
-     */
-    handle_tracker_slot_t allocateSlot_l();
-
-    /**
-     * Increment the generation for the slot, avoiding zero.
-     */
-    handle_tracker_generation_t nextGeneration_l(handle_tracker_slot_t index);
-
-    /**
-     * Validate the handle and return the corresponding index.
-     * @return slot index or a negative error
-     */
-    handle_tracker_slot_t handleToIndex(aaudio_handle_t handle, handle_tracker_type_t type) const;
-
-    /**
-     * Construct a handle from a header and an index.
-     * @param header combination of a type and a generation
-     * @param index slot index returned from allocateSlot
-     * @return handle or a negative error
-     */
-    static aaudio_handle_t buildHandle(handle_tracker_header_t header, handle_tracker_slot_t index);
-
-    /**
-     * Combine a type and a generation field into a header.
-     */
-    static handle_tracker_header_t buildHeader(handle_tracker_type_t type,
-                handle_tracker_generation_t generation);
-
-    /**
-     * Extract the index from a handle.
-     * Does not validate the handle.
-     * @return index associated with a handle
-     */
-    static handle_tracker_slot_t extractIndex(aaudio_handle_t handle);
-
-    /**
-     * Extract the generation from a handle.
-     * Does not validate the handle.
-     * @return generation associated with a handle
-     */
-    static handle_tracker_generation_t extractGeneration(aaudio_handle_t handle);
-
-};
-
-#endif //UTILITY_HANDLE_TRACKER_H
diff --git a/media/libaaudio/src/utility/MonotonicCounter.h b/media/libaaudio/src/utility/MonotonicCounter.h
index 81d7f89..13c92a2 100644
--- a/media/libaaudio/src/utility/MonotonicCounter.h
+++ b/media/libaaudio/src/utility/MonotonicCounter.h
@@ -41,6 +41,13 @@
     }
 
     /**
+     * set the current value of the counter
+     */
+    void set(int64_t counter) {
+        mCounter64 = counter;
+    }
+
+    /**
      * Advance the counter if delta is positive.
      * @return current value of the counter
      */
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
index 4402919..37b010d 100644
--- a/media/libaaudio/tests/Android.mk
+++ b/media/libaaudio/tests/Android.mk
@@ -5,16 +5,6 @@
     $(call include-path-for, audio-utils) \
     frameworks/av/media/libaaudio/include \
     frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_handle_tracker.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_handle_tracker
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/libaaudio/include \
-    frameworks/av/media/libaaudio/src
 LOCAL_SRC_FILES:= test_marshalling.cpp
 LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
 LOCAL_MODULE := test_aaudio_marshalling
diff --git a/media/libaaudio/tests/test_handle_tracker.cpp b/media/libaaudio/tests/test_handle_tracker.cpp
deleted file mode 100644
index c4db47a..0000000
--- a/media/libaaudio/tests/test_handle_tracker.cpp
+++ /dev/null
@@ -1,117 +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.
- */
-
-// Unit tests for AAudio Handle Tracker
-
-#include <stdlib.h>
-#include <math.h>
-
-#include <gtest/gtest.h>
-
-#include <aaudio/AAudio.h>
-#include "utility/HandleTracker.h"
-
-// Test adding one address.
-TEST(test_handle_tracker, aaudio_handle_tracker) {
-    const int MAX_HANDLES = 4;
-    HandleTracker tracker(MAX_HANDLES);
-    handle_tracker_type_t type = 3; // arbitrary generic type
-    int data; // something that has an address we can use
-    handle_tracker_address_t found;
-
-    // repeat the test several times to see if it breaks
-    const int SEVERAL = 5; // arbitrary
-    for (int i = 0; i < SEVERAL; i++) {
-        // should fail to find a bogus handle
-        found = tracker.get(type, 0);  // bad handle
-        EXPECT_EQ(nullptr, found);
-
-        // create a valid handle and use it to lookup the object again
-        aaudio_handle_t dataHandle = tracker.put(type, &data);
-        ASSERT_TRUE(dataHandle > 0);
-        found = tracker.get(type, dataHandle);
-        EXPECT_EQ(&data, found);
-        found = tracker.get(type, 0); // bad handle
-        EXPECT_EQ(nullptr, found);
-
-        // wrong type
-        found = tracker.get(type+1, dataHandle);
-        EXPECT_EQ(nullptr, found);
-
-        // remove from storage
-        found = tracker.remove(type, dataHandle);
-        EXPECT_EQ(&data, found);
-        // should fail the second time
-        found = tracker.remove(type, dataHandle);
-        EXPECT_EQ(nullptr, found);
-    }
-}
-
-// Test filling the tracker.
-TEST(test_handle_tracker, aaudio_full_up) {
-    const int MAX_HANDLES = 5;
-    HandleTracker tracker(MAX_HANDLES);
-    handle_tracker_type_t type = 4; // arbitrary generic type
-    int data[MAX_HANDLES];
-    aaudio_handle_t handles[MAX_HANDLES];
-    handle_tracker_address_t found;
-
-    // repeat the test several times to see if it breaks
-    const int SEVERAL = 5; // arbitrary
-    for (int i = 0; i < SEVERAL; i++) {
-        for (int i = 0; i < MAX_HANDLES; i++) {
-            // add a handle
-            handles[i] = tracker.put(type, &data[i]);
-            ASSERT_TRUE(handles[i] > 0);
-            found = tracker.get(type, handles[i]);
-            EXPECT_EQ(&data[i], found);
-        }
-
-        // Now that it is full, try to add one more.
-        aaudio_handle_t handle = tracker.put(type, &data[0]);
-        EXPECT_TRUE(handle < 0);
-
-        for (int i = 0; i < MAX_HANDLES; i++) {
-            // look up each handle
-            found = tracker.get(type, handles[i]);
-            EXPECT_EQ(&data[i], found);
-        }
-
-        // remove one from storage
-        found = tracker.remove(type, handles[2]);
-        EXPECT_EQ(&data[2], found);
-        // now try to look up the same handle and fail
-        found = tracker.get(type, handles[2]);
-        EXPECT_EQ(nullptr, found);
-
-        // add that same one back
-        handle = tracker.put(type, &data[2]);
-        ASSERT_TRUE(handle > 0);
-        found = tracker.get(type, handle);
-        EXPECT_EQ(&data[2], found);
-        // now use a stale handle again with a valid index and fail
-        found = tracker.get(type, handles[2]);
-        EXPECT_EQ(nullptr, found);
-
-        // remove them all
-        handles[2] = handle;
-        for (int i = 0; i < MAX_HANDLES; i++) {
-            // look up each handle
-            found = tracker.remove(type, handles[i]);
-            EXPECT_EQ(&data[i], found);
-        }
-    }
-}
diff --git a/media/libaaudio/tests/test_timestamps.cpp b/media/libaaudio/tests/test_timestamps.cpp
index d9ca391..fb363e7 100644
--- a/media/libaaudio/tests/test_timestamps.cpp
+++ b/media/libaaudio/tests/test_timestamps.cpp
@@ -17,23 +17,99 @@
 // Play silence and recover from dead servers or disconnected devices.
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 
 #include <aaudio/AAudio.h>
 #include <aaudio/AAudioTesting.h>
-
 #include "utils/AAudioExampleUtils.h"
+#include "../examples/utils/AAudioExampleUtils.h"
 
-#define DEFAULT_TIMEOUT_NANOS  ((int64_t)1000000000)
+// Arbitrary period for glitches, once per second at 48000 Hz.
+#define FORCED_UNDERRUN_PERIOD_FRAMES    48000
+// How long to sleep in a callback to cause an intentional glitch. For testing.
+#define FORCED_UNDERRUN_SLEEP_MICROS     (10 * 1000)
 
-int main(int argc, char **argv) {
-    (void) argc;
-    (void *)argv;
+#define MAX_TIMESTAMPS          1000
 
+#define DEFAULT_TIMEOUT_NANOS   ((int64_t)1000000000)
+
+#define NUM_SECONDS             1
+#define NUM_LOOPS               4
+
+typedef struct TimestampInfo {
+    int64_t         framesTotal;
+    int64_t         appPosition; // frames
+    int64_t         appNanoseconds;
+    int64_t         timestampPosition;  // frames
+    int64_t         timestampNanos;
+    aaudio_result_t result;
+} TimestampInfo;
+
+typedef struct TimestampCallbackData_s {
+    TimestampInfo  timestamps[MAX_TIMESTAMPS];
+    int64_t        framesTotal = 0;
+    int64_t        nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
+    int32_t        timestampCount = 0; // in timestamps
+    bool           forceUnderruns = false;
+} TimestampCallbackData_t;
+
+// Callback function that fills the audio output buffer.
+aaudio_data_callback_result_t timestampDataCallbackProc(
+        AAudioStream *stream,
+        void *userData,
+        void *audioData __unused,
+        int32_t numFrames
+) {
+
+    // should not happen but just in case...
+    if (userData == nullptr) {
+        printf("ERROR - SimplePlayerDataCallbackProc needs userData\n");
+        return AAUDIO_CALLBACK_RESULT_STOP;
+    }
+    TimestampCallbackData_t *timestampData = (TimestampCallbackData_t *) userData;
+
+    aaudio_direction_t direction = AAudioStream_getDirection(stream);
+    if (direction == AAUDIO_DIRECTION_INPUT) {
+        timestampData->framesTotal += numFrames;
+    }
+
+    if (timestampData->forceUnderruns) {
+        if (timestampData->framesTotal > timestampData->nextFrameToGlitch) {
+            usleep(FORCED_UNDERRUN_SLEEP_MICROS);
+            printf("Simulate glitch at %lld\n", (long long) timestampData->framesTotal);
+            timestampData->nextFrameToGlitch += FORCED_UNDERRUN_PERIOD_FRAMES;
+        }
+    }
+
+    if (timestampData->timestampCount < MAX_TIMESTAMPS) {
+        TimestampInfo *timestamp = &timestampData->timestamps[timestampData->timestampCount];
+        timestamp->result = AAudioStream_getTimestamp(stream,
+                                                      CLOCK_MONOTONIC,
+                                                      &timestamp->timestampPosition,
+                                                      &timestamp->timestampNanos);
+        timestamp->framesTotal = timestampData->framesTotal;
+        timestamp->appPosition = (direction == AAUDIO_DIRECTION_OUTPUT)
+                ? AAudioStream_getFramesWritten(stream)
+                : AAudioStream_getFramesRead(stream);
+        timestamp->appNanoseconds = getNanoseconds();
+        timestampData->timestampCount++;
+    }
+
+    if (direction == AAUDIO_DIRECTION_OUTPUT) {
+        timestampData->framesTotal += numFrames;
+    }
+    return AAUDIO_CALLBACK_RESULT_CONTINUE;
+}
+
+static TimestampCallbackData_t sTimestampData;
+
+static aaudio_result_t testTimeStamps(aaudio_policy_t mmapPolicy,
+                           aaudio_sharing_mode_t sharingMode,
+                           aaudio_performance_mode_t performanceMode,
+                           aaudio_direction_t direction) {
     aaudio_result_t result = AAUDIO_OK;
 
-    int32_t triesLeft = 3;
-    int32_t bufferCapacity;
     int32_t framesPerBurst = 0;
     float *buffer = nullptr;
 
@@ -44,22 +120,20 @@
     int32_t finalBufferSize = 0;
     aaudio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_FLOAT;
     aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
-    int32_t framesMax;
-    int64_t framesTotal;
-    int64_t printAt;
-    int samplesPerBurst;
-    int64_t previousFramePosition = -1;
+    aaudio_sharing_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
 
     AAudioStreamBuilder *aaudioBuilder = nullptr;
     AAudioStream *aaudioStream = nullptr;
 
-    // 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);
+    memset(&sTimestampData, 0, sizeof(sTimestampData));
 
-    printf("Test Timestamps V0.1.1\n");
+    printf("------------ testTimeStamps(policy = %d, sharing = %s, perf = %s, dir = %s) -----------\n",
+           mmapPolicy,
+           getSharingModeText(sharingMode),
+           getPerformanceModeText(performanceMode),
+           getDirectionText(direction));
 
-    AAudio_setMMapPolicy(AAUDIO_POLICY_AUTO);
+    AAudio_setMMapPolicy(mmapPolicy);
 
     // Use an AAudioStreamBuilder to contain requested parameters.
     result = AAudio_createStreamBuilder(&aaudioBuilder);
@@ -70,9 +144,11 @@
     }
 
     // Request stream properties.
-    AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_FLOAT);
-    //AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, AAUDIO_PERFORMANCE_MODE_NONE);
-    AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+    AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_I16);
+    AAudioStreamBuilder_setSharingMode(aaudioBuilder, sharingMode);
+    AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, performanceMode);
+    AAudioStreamBuilder_setDirection(aaudioBuilder, direction);
+    AAudioStreamBuilder_setDataCallback(aaudioBuilder, timestampDataCallbackProc, &sTimestampData);
 
     // Create an AAudioStream using the Builder.
     result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
@@ -87,10 +163,25 @@
     actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
     actualDataFormat = AAudioStream_getFormat(aaudioStream);
 
-    printf("-------- chans = %3d, rate = %6d format = %d\n",
-            actualChannelCount, actualSampleRate, actualDataFormat);
+    actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
+    if (actualSharingMode != sharingMode) {
+        printf("did not get expected sharingMode, got %3d, skipping test\n",
+               actualSharingMode);
+        result = AAUDIO_OK;
+        goto finish;
+    }
+    actualPerformanceMode = AAudioStream_getPerformanceMode(aaudioStream);
+    if (actualPerformanceMode != performanceMode) {
+        printf("did not get expected performanceMode, got %3d, skipping test\n",
+               actualPerformanceMode);
+        result = AAUDIO_OK;
+        goto finish;
+    }
+
+    printf("    chans = %3d, rate = %6d format = %d\n",
+           actualChannelCount, actualSampleRate, actualDataFormat);
     printf("    Is MMAP used? %s\n", AAudioStream_isMMapUsed(aaudioStream)
-                                   ? "yes" : "no");
+                                     ? "yes" : "no");
 
     // This is the number of frames that are read in one chunk by a DMA controller
     // or a DSP or a mixer.
@@ -98,91 +189,151 @@
     printf("    framesPerBurst = %3d\n", framesPerBurst);
 
     originalBufferSize = AAudioStream_getBufferSizeInFrames(aaudioStream);
-    requestedBufferSize = 2 * framesPerBurst;
+    requestedBufferSize = 4 * framesPerBurst;
     finalBufferSize = AAudioStream_setBufferSizeInFrames(aaudioStream, requestedBufferSize);
 
     printf("    BufferSize: original = %4d, requested = %4d, final = %4d\n",
            originalBufferSize, requestedBufferSize, finalBufferSize);
 
-    samplesPerBurst = framesPerBurst * actualChannelCount;
-    buffer = new float[samplesPerBurst];
-
-    result = AAudioStream_requestStart(aaudioStream);
-    if (result != AAUDIO_OK) {
-        printf("AAudioStream_requestStart returned %s",
+    {
+        int64_t position;
+        int64_t nanoseconds;
+        result = AAudioStream_getTimestamp(aaudioStream, CLOCK_MONOTONIC, &position, &nanoseconds);
+        printf("before start, AAudioStream_getTimestamp() returns %s\n",
                AAudio_convertResultToText(result));
-        goto finish;
     }
 
-    // Play silence very briefly.
-    framesMax = actualSampleRate * 4;
-    framesTotal = 0;
-    printAt = actualSampleRate;
-    while (result == AAUDIO_OK && framesTotal < framesMax) {
-        int32_t framesWritten = AAudioStream_write(aaudioStream,
-                                                   buffer, framesPerBurst,
-                                                   DEFAULT_TIMEOUT_NANOS);
-        if (framesWritten < 0) {
-            result = framesWritten;
-            printf("write() returned %s, frames = %d\n",
-                   AAudio_convertResultToText(result), (int)framesTotal);
-            printf("  frames = %d\n", (int)framesTotal);
-        } else if (framesWritten != framesPerBurst) {
-            printf("write() returned %d, frames = %d\n", framesWritten, (int)framesTotal);
-            result = AAUDIO_ERROR_TIMEOUT;
-        } else {
-            framesTotal += framesWritten;
-            if (framesTotal >= printAt) {
-                printf("frames = %d\n", (int)framesTotal);
-                printAt += actualSampleRate;
+    for (int runs = 0; runs < NUM_LOOPS; runs++) {
+        printf("------------------ loop #%d\n", runs);
+
+        int64_t temp = sTimestampData.framesTotal;
+        memset(&sTimestampData, 0, sizeof(sTimestampData));
+        sTimestampData.framesTotal = temp;
+
+        sTimestampData.forceUnderruns = false;
+
+        result = AAudioStream_requestStart(aaudioStream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_requestStart returned %s",
+                   AAudio_convertResultToText(result));
+            goto finish;
+        }
+
+        for (int second = 0; second < NUM_SECONDS; second++) {
+            // Give AAudio callback time to run in the background.
+            sleep(1);
+
+            // Periodically print the progress so we know it hasn't died.
+            printf("framesWritten = %d, XRuns = %d\n",
+                   (int) AAudioStream_getFramesWritten(aaudioStream),
+                   (int) AAudioStream_getXRunCount(aaudioStream)
+            );
+        }
+
+        result = AAudioStream_requestStop(aaudioStream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_requestStop returned %s\n",
+                   AAudio_convertResultToText(result));
+        }
+
+        printf("timestampCount = %d\n", sTimestampData.timestampCount);
+        int printed = 0;
+        for (int i = 0; i < sTimestampData.timestampCount; i++) {
+            TimestampInfo *timestamp = &sTimestampData.timestamps[i];
+            bool posChanged = (timestamp->timestampPosition != (timestamp - 1)->timestampPosition);
+            bool timeChanged = (timestamp->timestampNanos != (timestamp - 1)->timestampNanos);
+            if ((printed < 20) && ((i < 10) || posChanged || timeChanged)) {
+                printf("  %3d : frames %8lld, xferd %8lld", i,
+                       (long long) timestamp->framesTotal,
+                       (long long) timestamp->appPosition);
+                if (timestamp->result != AAUDIO_OK) {
+                    printf(", result = %s\n", AAudio_convertResultToText(timestamp->result));
+                } else {
+                    bool negative = timestamp->timestampPosition < 0;
+                    bool retro = (i > 0 && (timestamp->timestampPosition <
+                                            (timestamp - 1)->timestampPosition));
+                    const char *message = negative ? " <=NEGATIVE!"
+                                                   : (retro ? "  <= RETROGRADE!" : "");
+
+                    double latency = calculateLatencyMillis(timestamp->timestampPosition,
+                                             timestamp->timestampNanos,
+                                             timestamp->appPosition,
+                                             timestamp->appNanoseconds,
+                                             actualSampleRate);
+                    printf(", STAMP: pos = %8lld, nanos = %8lld, lat = %7.1f msec %s\n",
+                           (long long) timestamp->timestampPosition,
+                           (long long) timestamp->timestampNanos,
+                           latency,
+                           message);
+                }
+                printed++;
             }
         }
 
-        // Print timestamps.
-        int64_t framePosition = 0;
-        int64_t frameTime = 0;
-        aaudio_result_t timeResult;
-        timeResult = AAudioStream_getTimestamp(aaudioStream, CLOCK_MONOTONIC,
-                                           &framePosition, &frameTime);
-
-        if (timeResult == AAUDIO_OK) {
-            if (framePosition > (previousFramePosition + 5000)) {
-                int64_t realTime = getNanoseconds();
-                int64_t framesWritten = AAudioStream_getFramesWritten(aaudioStream);
-
-                double latencyMillis = calculateLatencyMillis(framePosition, frameTime,
-                                                              framesWritten, realTime,
-                                                              actualSampleRate);
-
-                printf("--- timestamp: result = %4d, position = %lld, at %lld nanos"
-                               ", latency = %7.2f msec\n",
-                       timeResult,
-                       (long long) framePosition,
-                       (long long) frameTime,
-                       latencyMillis);
-                previousFramePosition = framePosition;
-            }
-        }
+        // Avoid race conditions in AudioFlinger.
+        // There is normally a delay between a real user stopping and restarting a stream.
+        sleep(1);
     }
 
-    result = AAudioStream_requestStop(aaudioStream);
-    if (result != AAUDIO_OK) {
-        printf("AAudioStream_requestStop returned %s\n",
-               AAudio_convertResultToText(result));
-    }
-    result = AAudioStream_close(aaudioStream);
-    if (result != AAUDIO_OK) {
-        printf("AAudioStream_close returned %s\n",
-               AAudio_convertResultToText(result));
-    }
-    aaudioStream = nullptr;
-
-
 finish:
     if (aaudioStream != nullptr) {
         AAudioStream_close(aaudioStream);
     }
     AAudioStreamBuilder_delete(aaudioBuilder);
-    delete[] buffer;
     printf("result = %d = %s\n", result, AAudio_convertResultToText(result));
+
+    return result;
+}
+
+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 Timestamps V0.1.3\n");
+
+    // Legacy
+    aaudio_policy_t policy = AAUDIO_POLICY_NEVER;
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_SHARED,
+                            AAUDIO_PERFORMANCE_MODE_NONE,
+                            AAUDIO_DIRECTION_INPUT);
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_SHARED,
+                            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+                            AAUDIO_DIRECTION_INPUT);
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_SHARED,
+                            AAUDIO_PERFORMANCE_MODE_NONE,
+                            AAUDIO_DIRECTION_OUTPUT);
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_SHARED,
+                            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+                            AAUDIO_DIRECTION_OUTPUT);
+
+    // MMAP
+    policy = AAUDIO_POLICY_ALWAYS;
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_EXCLUSIVE,
+                            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+                            AAUDIO_DIRECTION_INPUT);
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_EXCLUSIVE,
+                            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+                            AAUDIO_DIRECTION_OUTPUT);
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_SHARED,
+                            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+                            AAUDIO_DIRECTION_INPUT);
+    result = testTimeStamps(policy,
+                            AAUDIO_SHARING_MODE_SHARED,
+                            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+                            AAUDIO_DIRECTION_OUTPUT);
+
+    return (result == AAUDIO_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 6402bbb..26a320c 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -120,7 +120,7 @@
         }
         // No lock here: worst case we remove a NULL callback which will be a nop
         if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
-            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+            AudioSystem::removeAudioDeviceCallback(this, mInput);
         }
         IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
         mAudioRecord.clear();
@@ -274,7 +274,7 @@
     mStatus = NO_ERROR;
     mUserData = user;
     // TODO: add audio hardware input latency here
-    mLatency = (1000 * mFrameCount) / mSampleRate;
+    mLatency = (1000LL * mFrameCount) / mSampleRate;
     mMarkerPosition = 0;
     mMarkerReached = false;
     mNewPosition = 0;
@@ -499,19 +499,26 @@
     return mSelectedDeviceId;
 }
 
+// must be called with mLock held
+void AudioRecord::updateRoutedDeviceId_l()
+{
+    // if the record is inactive, do not update actual device as the input stream maybe routed
+    // from a device not relevant to this client because of other active use cases.
+    if (!mActive) {
+        return;
+    }
+    if (mInput != AUDIO_IO_HANDLE_NONE) {
+        audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
+        if (deviceId != AUDIO_PORT_HANDLE_NONE) {
+            mRoutedDeviceId = deviceId;
+        }
+     }
+}
+
 audio_port_handle_t AudioRecord::getRoutedDeviceId() {
     AutoMutex lock(mLock);
-    if (mInput == AUDIO_IO_HANDLE_NONE) {
-        return AUDIO_PORT_HANDLE_NONE;
-    }
-    // if the input stream does not have an active audio patch, use either the device initially
-    // selected by audio policy manager or the last routed device
-    audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
-    if (deviceId == AUDIO_PORT_HANDLE_NONE) {
-        deviceId = mRoutedDeviceId;
-    }
-    mRoutedDeviceId = deviceId;
-    return deviceId;
+    updateRoutedDeviceId_l();
+    return mRoutedDeviceId;
 }
 
 // -------------------------------------------------------------------------
@@ -537,9 +544,6 @@
         return NO_INIT;
     }
 
-    if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
-    }
     audio_io_handle_t input;
 
     // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
@@ -744,6 +748,15 @@
     }
     mNotificationFramesAct = (uint32_t) notificationFrames;
 
+
+    //mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation
+    if (mDeviceCallback != 0 && mInput != input) {
+        if (mInput != AUDIO_IO_HANDLE_NONE) {
+            AudioSystem::removeAudioDeviceCallback(this, mInput);
+        }
+        AudioSystem::addAudioDeviceCallback(this, input);
+    }
+
     // We retain a copy of the I/O handle, but don't own the reference
     mInput = input;
     mRefreshRemaining = true;
@@ -763,10 +776,6 @@
     mDeathNotifier = new DeathNotifier(this);
     IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
 
-    if (mDeviceCallback != 0) {
-        AudioSystem::addAudioDeviceCallback(mDeviceCallback, mInput);
-    }
-
     return NO_ERROR;
 
     // End of retry loop.
@@ -1239,7 +1248,7 @@
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
-    if (mDeviceCallback == callback) {
+    if (mDeviceCallback.unsafe_get() == callback.get()) {
         ALOGW("%s adding same callback!", __FUNCTION__);
         return INVALID_OPERATION;
     }
@@ -1247,9 +1256,9 @@
     if (mInput != AUDIO_IO_HANDLE_NONE) {
         if (mDeviceCallback != 0) {
             ALOGW("%s callback already present!", __FUNCTION__);
-            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+            AudioSystem::removeAudioDeviceCallback(this, mInput);
         }
-        status = AudioSystem::addAudioDeviceCallback(callback, mInput);
+        status = AudioSystem::addAudioDeviceCallback(this, mInput);
     }
     mDeviceCallback = callback;
     return status;
@@ -1263,17 +1272,38 @@
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
-    if (mDeviceCallback != callback) {
+    if (mDeviceCallback.unsafe_get() != callback.get()) {
         ALOGW("%s removing different callback!", __FUNCTION__);
         return INVALID_OPERATION;
     }
+    mDeviceCallback.clear();
     if (mInput != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+        AudioSystem::removeAudioDeviceCallback(this, mInput);
     }
-    mDeviceCallback = 0;
     return NO_ERROR;
 }
 
+void AudioRecord::onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                 audio_port_handle_t deviceId)
+{
+    sp<AudioSystem::AudioDeviceCallback> callback;
+    {
+        AutoMutex lock(mLock);
+        if (audioIo != mInput) {
+            return;
+        }
+        callback = mDeviceCallback.promote();
+        // only update device if the record is active as route changes due to other use cases are
+        // irrelevant for this client
+        if (mActive) {
+            mRoutedDeviceId = deviceId;
+        }
+    }
+    if (callback.get() != nullptr) {
+        callback->onAudioDeviceUpdate(mInput, mRoutedDeviceId);
+    }
+}
+
 // =========================================================================
 
 void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 211bd7d..cdc75ac 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -493,14 +493,16 @@
     if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;
 
     audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
-    Vector < sp<AudioDeviceCallback> > callbacks;
+    Vector < wp<AudioDeviceCallback> > callbacks;
 
     {
         Mutex::Autolock _l(mLock);
 
         switch (event) {
         case AUDIO_OUTPUT_OPENED:
-        case AUDIO_INPUT_OPENED: {
+        case AUDIO_OUTPUT_REGISTERED:
+        case AUDIO_INPUT_OPENED:
+        case AUDIO_INPUT_REGISTERED: {
             sp<AudioIoDescriptor> oldDesc = getIoDescriptor_l(ioDesc->mIoHandle);
             if (oldDesc == 0) {
                 mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
@@ -511,13 +513,19 @@
 
             if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
                 deviceId = ioDesc->getDeviceId();
-                ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
-                if (ioIndex >= 0) {
-                    callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+                if (event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED) {
+                    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
+                    if (ioIndex >= 0) {
+                        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+                    }
                 }
             }
-            ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x "
-                    "frameCount %zu deviceId %d", event == AUDIO_OUTPUT_OPENED ? "output" : "input",
+            ALOGV("ioConfigChanged() new %s %s %d samplingRate %u, format %#x channel mask %#x "
+                    "frameCount %zu deviceId %d",
+                    event == AUDIO_OUTPUT_OPENED || event == AUDIO_OUTPUT_REGISTERED ?
+                            "output" : "input",
+                            event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED ?
+                            "opened" : "registered",
                     ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask,
                     ioDesc->mFrameCount, ioDesc->getDeviceId());
             } break;
@@ -563,9 +571,23 @@
         } break;
         }
     }
+    bool callbackRemoved = false;
     // callbacks.size() != 0 =>  ioDesc->mIoHandle and deviceId are valid
-    for (size_t i = 0; i < callbacks.size(); i++) {
-        callbacks[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
+    for (size_t i = 0; i < callbacks.size(); ) {
+        sp<AudioDeviceCallback> callback = callbacks[i].promote();
+        if (callback.get() != nullptr) {
+            callback->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
+            i++;
+        } else {
+            callbacks.removeAt(i);
+            callbackRemoved = true;
+        }
+    }
+    // clean up callback list while we are here if some clients have disappeared without
+    // unregistering their callback
+    if (callbackRemoved) {
+        Mutex::Autolock _l(mLock);
+        mAudioDeviceCallbacks.replaceValueFor(ioDesc->mIoHandle, callbacks);
     }
 }
 
@@ -618,17 +640,17 @@
 }
 
 status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
-        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
     Mutex::Autolock _l(mLock);
-    Vector < sp<AudioDeviceCallback> > callbacks;
+    Vector < wp<AudioDeviceCallback> > callbacks;
     ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
     if (ioIndex >= 0) {
         callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
     }
 
     for (size_t cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
-        if (callbacks[cbIndex] == callback) {
+        if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
             return INVALID_OPERATION;
         }
     }
@@ -639,18 +661,18 @@
 }
 
 status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
-        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
     Mutex::Autolock _l(mLock);
     ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
     if (ioIndex < 0) {
         return INVALID_OPERATION;
     }
-    Vector < sp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+    Vector < wp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
 
     size_t cbIndex;
     for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
-        if (callbacks[cbIndex] == callback) {
+        if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
             break;
         }
     }
@@ -1128,7 +1150,7 @@
 }
 
 status_t AudioSystem::addAudioDeviceCallback(
-        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
     const sp<AudioFlingerClient> afc = getAudioFlingerClient();
     if (afc == 0) {
@@ -1145,7 +1167,7 @@
 }
 
 status_t AudioSystem::removeAudioDeviceCallback(
-        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
     const sp<AudioFlingerClient> afc = getAudioFlingerClient();
     if (afc == 0) {
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 07875ac..6206be0 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -65,6 +65,14 @@
     return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
 }
 
+// TODO move to audio_utils.
+static inline struct timespec convertNsToTimespec(int64_t ns) {
+    struct timespec tv;
+    tv.tv_sec = static_cast<time_t>(ns / NANOS_PER_SECOND);
+    tv.tv_nsec = static_cast<long>(ns % NANOS_PER_SECOND);
+    return tv;
+}
+
 // current monotonic time in microseconds.
 static int64_t getNowUs()
 {
@@ -270,7 +278,7 @@
         }
         // No lock here: worst case we remove a NULL callback which will be a nop
         if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
-            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+            AudioSystem::removeAudioDeviceCallback(this, mOutput);
         }
         IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
         mAudioTrack.clear();
@@ -541,7 +549,8 @@
     mUpdatePeriod = 0;
     mPosition = 0;
     mReleased = 0;
-    mStartUs = 0;
+    mStartNs = 0;
+    mStartFromZeroUs = 0;
     AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
     mSequence = 1;
     mObservedSequence = mSequence;
@@ -589,6 +598,7 @@
             mStartEts.clear();
         }
     }
+    mStartNs = systemTime(); // save this for timestamp adjustment after starting.
     if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {
         // reset current position as seen by client to 0
         mPosition = 0;
@@ -607,7 +617,8 @@
                             + mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER]),
                     (long long)mStartEts.mFlushed,
                     (long long)mFramesWritten);
-            mFramesWrittenServerOffset = -mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER];
+            // mStartEts is already adjusted by mFramesWrittenServerOffset, so we delta adjust.
+            mFramesWrittenServerOffset -= mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER];
         }
         mFramesWritten = 0;
         mProxy->clearTimestamp(); // need new server push for valid timestamp
@@ -617,7 +628,7 @@
         // since the flush is asynchronous and stop may not fully drain.
         // We save the time when the track is started to later verify whether
         // the counters are realistic (i.e. start from zero after this time).
-        mStartUs = getNowUs();
+        mStartFromZeroUs = mStartNs / 1000;
 
         // force refresh of remaining frames by processAudioBuffer() as last
         // write before stop could be partial.
@@ -1220,19 +1231,26 @@
     return mSelectedDeviceId;
 }
 
+// must be called with mLock held
+void AudioTrack::updateRoutedDeviceId_l()
+{
+    // if the track is inactive, do not update actual device as the output stream maybe routed
+    // to a device not relevant to this client because of other active use cases.
+    if (mState != STATE_ACTIVE) {
+        return;
+    }
+    if (mOutput != AUDIO_IO_HANDLE_NONE) {
+        audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
+        if (deviceId != AUDIO_PORT_HANDLE_NONE) {
+            mRoutedDeviceId = deviceId;
+        }
+    }
+}
+
 audio_port_handle_t AudioTrack::getRoutedDeviceId() {
     AutoMutex lock(mLock);
-    if (mOutput == AUDIO_IO_HANDLE_NONE) {
-        return AUDIO_PORT_HANDLE_NONE;
-    }
-    // if the output stream does not have an active audio patch, use either the device initially
-    // selected by audio policy manager or the last routed device
-    audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
-    if (deviceId == AUDIO_PORT_HANDLE_NONE) {
-        deviceId = mRoutedDeviceId;
-    }
-    mRoutedDeviceId = deviceId;
-    return deviceId;
+    updateRoutedDeviceId_l();
+    return mRoutedDeviceId;
 }
 
 status_t AudioTrack::attachAuxEffect(int effectId)
@@ -1270,7 +1288,7 @@
         ALOGW("getLatency(%d) failed status %d", mOutput, status);
     } else {
         // FIXME don't believe this lie
-        mLatency = mAfLatency + (1000 * mFrameCount) / mSampleRate;
+        mLatency = mAfLatency + (1000LL * mFrameCount) / mSampleRate;
     }
 }
 
@@ -1296,12 +1314,10 @@
         return NO_INIT;
     }
 
-    if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
-    }
     audio_io_handle_t output;
     audio_stream_type_t streamType = mStreamType;
     audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL;
+    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.
@@ -1506,12 +1522,14 @@
     sp<IMemory> iMem = track->getCblk();
     if (iMem == 0) {
         ALOGE("Could not get control block");
-        return NO_INIT;
+        status = NO_INIT;
+        goto release;
     }
     void *iMemPointer = iMem->pointer();
     if (iMemPointer == NULL) {
         ALOGE("Could not get control block pointer");
-        return NO_INIT;
+        status = NO_INIT;
+        goto release;
     }
     // invariant that mAudioTrack != 0 is true only after set() returns successfully
     if (mAudioTrack != 0) {
@@ -1573,6 +1591,15 @@
         }
     }
 
+    //mOutput != output includes the case where mOutput == AUDIO_IO_HANDLE_NONE for first creation
+    if (mDeviceCallback != 0 && mOutput != output) {
+        if (mOutput != AUDIO_IO_HANDLE_NONE) {
+            AudioSystem::removeAudioDeviceCallback(this, mOutput);
+        }
+        AudioSystem::addAudioDeviceCallback(this, output);
+        callbackAdded = true;
+    }
+
     // We retain a copy of the I/O handle, but don't own the reference
     mOutput = output;
     mRefreshRemaining = true;
@@ -1588,7 +1615,8 @@
         buffers = mSharedBuffer->pointer();
         if (buffers == NULL) {
             ALOGE("Could not get buffer pointer");
-            return NO_INIT;
+            status = NO_INIT;
+            goto release;
         }
     }
 
@@ -1633,15 +1661,15 @@
     mDeathNotifier = new DeathNotifier(this);
     IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this);
 
-    if (mDeviceCallback != 0) {
-        AudioSystem::addAudioDeviceCallback(mDeviceCallback, mOutput);
-    }
-
     return NO_ERROR;
     }
 
 release:
     AudioSystem::releaseOutput(output, streamType, mSessionId);
+    if (callbackAdded) {
+        // note: mOutput is always valid is callbackAdded is true
+        AudioSystem::removeAudioDeviceCallback(this, mOutput);
+    }
     if (status == NO_ERROR) {
         status = NO_INIT;
     }
@@ -2088,7 +2116,14 @@
     // Convert frame units to time units
     nsecs_t ns = NS_WHENEVER;
     if (minFrames != (uint32_t) ~0) {
-        ns = framesToNanoseconds(minFrames, sampleRate, speed) + kWaitPeriodNs;
+        // AudioFlinger consumption of client data may be irregular when coming out of device
+        // standby since the kernel buffers require filling. This is throttled to no more than 2x
+        // the expected rate in the MixerThread. Hence, we reduce the estimated time to wait by one
+        // half (but no more than half a second) to improve callback accuracy during these temporary
+        // data surges.
+        const nsecs_t estimatedNs = framesToNanoseconds(minFrames, sampleRate, speed);
+        constexpr nsecs_t maxThrottleCompensationNs = 500000000LL;
+        ns = estimatedNs - min(estimatedNs / 2, maxThrottleCompensationNs) + kWaitPeriodNs;
         ns -= (timeAfterCallbacks - timeBeforeCallbacks);  // account for callback time
         // TODO: Should we warn if the callback time is too long?
         if (ns < 0) ns = 0;
@@ -2573,8 +2608,7 @@
                     if (at < limit) {
                         ALOGV("timestamp pause lag:%lld adjusting from %lld to %lld",
                                 (long long)lag, (long long)at, (long long)limit);
-                        timestamp.mTime.tv_sec = limit / NANOS_PER_SECOND;
-                        timestamp.mTime.tv_nsec = limit % NANOS_PER_SECOND; // compiler opt.
+                        timestamp.mTime = convertNsToTimespec(limit);
                     }
                 }
                 mPreviousLocation = location;
@@ -2617,18 +2651,18 @@
         // the previous song under gapless playback.
         // However, we sometimes see zero timestamps, then a glitch of
         // the previous song's position, and then correct timestamps afterwards.
-        if (mStartUs != 0 && mSampleRate != 0) {
+        if (mStartFromZeroUs != 0 && mSampleRate != 0) {
             static const int kTimeJitterUs = 100000; // 100 ms
             static const int k1SecUs = 1000000;
 
             const int64_t timeNow = getNowUs();
 
-            if (timeNow < mStartUs + k1SecUs) { // within first second of starting
+            if (timeNow < mStartFromZeroUs + k1SecUs) { // within first second of starting
                 const int64_t timestampTimeUs = convertTimespecToUs(timestamp.mTime);
-                if (timestampTimeUs < mStartUs) {
+                if (timestampTimeUs < mStartFromZeroUs) {
                     return WOULD_BLOCK;  // stale timestamp time, occurs before start.
                 }
-                const int64_t deltaTimeUs = timestampTimeUs - mStartUs;
+                const int64_t deltaTimeUs = timestampTimeUs - mStartFromZeroUs;
                 const int64_t deltaPositionByUs = (double)timestamp.mPosition * 1000000
                         / ((double)mSampleRate * mPlaybackRate.mSpeed);
 
@@ -2651,10 +2685,10 @@
                     return WOULD_BLOCK;
                 }
                 if (deltaPositionByUs != 0) {
-                    mStartUs = 0; // don't check again, we got valid nonzero position.
+                    mStartFromZeroUs = 0; // don't check again, we got valid nonzero position.
                 }
             } else {
-                mStartUs = 0; // don't check again, start time expired.
+                mStartFromZeroUs = 0; // don't check again, start time expired.
             }
             mTimestampStartupGlitchReported = false;
         }
@@ -2692,14 +2726,33 @@
     // Prevent retrograde motion in timestamp.
     // This is sometimes caused by erratic reports of the available space in the ALSA drivers.
     if (status == NO_ERROR) {
+        // previousTimestampValid is set to false when starting after a stop or flush.
         if (previousTimestampValid) {
             const int64_t previousTimeNanos =
                     audio_utils_ns_from_timespec(&mPreviousTimestamp.mTime);
-            const int64_t currentTimeNanos = audio_utils_ns_from_timespec(&timestamp.mTime);
+            int64_t currentTimeNanos = audio_utils_ns_from_timespec(&timestamp.mTime);
+
+            // Fix stale time when checking timestamp right after start().
+            //
+            // For offload compatibility, use a default lag value here.
+            // Any time discrepancy between this update and the pause timestamp is handled
+            // by the retrograde check afterwards.
+            const int64_t lagNs = int64_t(mAfLatency * 1000000LL);
+            const int64_t limitNs = mStartNs - lagNs;
+            if (currentTimeNanos < limitNs) {
+                ALOGD("correcting timestamp time for pause, "
+                        "currentTimeNanos: %lld < limitNs: %lld < mStartNs: %lld",
+                        (long long)currentTimeNanos, (long long)limitNs, (long long)mStartNs);
+                timestamp.mTime = convertNsToTimespec(limitNs);
+                currentTimeNanos = limitNs;
+            }
+
+            // retrograde check
             if (currentTimeNanos < previousTimeNanos) {
                 ALOGW("retrograde timestamp time corrected, %lld < %lld",
                         (long long)currentTimeNanos, (long long)previousTimeNanos);
                 timestamp.mTime = mPreviousTimestamp.mTime;
+                // currentTimeNanos not used below.
             }
 
             // Looking at signed delta will work even when the timestamps
@@ -2817,7 +2870,7 @@
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
-    if (mDeviceCallback == callback) {
+    if (mDeviceCallback.unsafe_get() == callback.get()) {
         ALOGW("%s adding same callback!", __FUNCTION__);
         return INVALID_OPERATION;
     }
@@ -2825,9 +2878,9 @@
     if (mOutput != AUDIO_IO_HANDLE_NONE) {
         if (mDeviceCallback != 0) {
             ALOGW("%s callback already present!", __FUNCTION__);
-            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+            AudioSystem::removeAudioDeviceCallback(this, mOutput);
         }
-        status = AudioSystem::addAudioDeviceCallback(callback, mOutput);
+        status = AudioSystem::addAudioDeviceCallback(this, mOutput);
     }
     mDeviceCallback = callback;
     return status;
@@ -2841,17 +2894,39 @@
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
-    if (mDeviceCallback != callback) {
+    if (mDeviceCallback.unsafe_get() != callback.get()) {
         ALOGW("%s removing different callback!", __FUNCTION__);
         return INVALID_OPERATION;
     }
+    mDeviceCallback.clear();
     if (mOutput != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+        AudioSystem::removeAudioDeviceCallback(this, mOutput);
     }
-    mDeviceCallback = 0;
     return NO_ERROR;
 }
 
+
+void AudioTrack::onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                 audio_port_handle_t deviceId)
+{
+    sp<AudioSystem::AudioDeviceCallback> callback;
+    {
+        AutoMutex lock(mLock);
+        if (audioIo != mOutput) {
+            return;
+        }
+        callback = mDeviceCallback.promote();
+        // only update device if the track is active as route changes due to other use cases are
+        // irrelevant for this client
+        if (mState == STATE_ACTIVE) {
+            mRoutedDeviceId = deviceId;
+        }
+    }
+    if (callback.get() != nullptr) {
+        callback->onAudioDeviceUpdate(mOutput, mRoutedDeviceId);
+    }
+}
+
 status_t AudioTrack::pendingDuration(int32_t *msec, ExtendedTimestamp::Location location)
 {
     if (msec == nullptr ||
@@ -2909,7 +2984,7 @@
     case STATE_STOPPED:
         if (isOffloadedOrDirect_l()) {
             // check if we have started in the past to return true.
-            return mStartUs > 0;
+            return mStartFromZeroUs > 0;
         }
         // A normal audio track may still be draining, so
         // check if stream has ended.  This covers fasttrack position
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index 9bc2594..78e392e 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -864,6 +864,13 @@
     if (property_get("gsm.operator.iso-country", value, "") == 0) {
         property_get("gsm.sim.operator.iso-country", value, "");
     }
+    // If dual sim device has two SIM cards inserted and is not registerd to any network,
+    // "," is set to "gsm.operator.iso-country" prop.
+    // In this case, "gsm.sim.operator.iso-country" prop should be used.
+    if (strlen(value) == 1 && strstr(value, ",") != NULL) {
+        property_get("gsm.sim.operator.iso-country", value, "");
+    }
+
     if (strstr(value, "us") != NULL ||
         strstr(value, "ca") != NULL) {
         mRegion = ANSI;
diff --git a/media/libaudioclient/include/media/AudioIoDescriptor.h b/media/libaudioclient/include/media/AudioIoDescriptor.h
index fed86c9..859f1a9 100644
--- a/media/libaudioclient/include/media/AudioIoDescriptor.h
+++ b/media/libaudioclient/include/media/AudioIoDescriptor.h
@@ -20,9 +20,11 @@
 namespace android {
 
 enum audio_io_config_event {
+    AUDIO_OUTPUT_REGISTERED,
     AUDIO_OUTPUT_OPENED,
     AUDIO_OUTPUT_CLOSED,
     AUDIO_OUTPUT_CONFIG_CHANGED,
+    AUDIO_INPUT_REGISTERED,
     AUDIO_INPUT_OPENED,
     AUDIO_INPUT_CLOSED,
     AUDIO_INPUT_CONFIG_CHANGED,
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 74a626e..c6ad1b5 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -36,7 +36,7 @@
 
 // ----------------------------------------------------------------------------
 
-class AudioRecord : public RefBase
+class AudioRecord : public AudioSystem::AudioDeviceCallback
 {
 public:
 
@@ -427,7 +427,12 @@
 
      /* Returns the ID of the audio device actually used by the input to which this AudioRecord
       * is attached.
-      * A value of AUDIO_PORT_HANDLE_NONE indicates the AudioRecord is not attached to any input.
+      * The device ID is relevant only if the AudioRecord is active.
+      * When the AudioRecord is inactive, the device ID returned can be either:
+      * - AUDIO_PORT_HANDLE_NONE if the AudioRecord is not attached to any output.
+      * - The device ID used before paused or stopped.
+      * - The device ID selected by audio policy manager of setOutputDevice() if the AudioRecord
+      * has not been started yet.
       *
       * Parameters:
       *  none.
@@ -457,6 +462,10 @@
             status_t removeAudioDeviceCallback(
                     const sp<AudioSystem::AudioDeviceCallback>& callback);
 
+            // AudioSystem::AudioDeviceCallback> virtuals
+            virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                             audio_port_handle_t deviceId);
+
 private:
     /* If nonContig is non-NULL, it is an output parameter that will be set to the number of
      * additional non-contiguous frames that are predicted to be available immediately,
@@ -564,6 +573,8 @@
             // FIXME enum is faster than strcmp() for parameter 'from'
             status_t restoreRecord_l(const char *from);
 
+            void     updateRoutedDeviceId_l();
+
     sp<AudioRecordThread>   mAudioRecordThread;
     mutable Mutex           mLock;
 
@@ -668,7 +679,7 @@
     audio_port_handle_t     mRoutedDeviceId;   // Device actually selected by audio policy manager:
                                               // May not match the app selection depending on other
                                               // activity and connected devices
-    sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+    wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
     audio_port_handle_t    mPortId;  // unique ID allocated by audio policy
 
 };
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 4d5b317..5a81d83 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -370,9 +370,9 @@
                                          audio_port_handle_t deviceId) = 0;
     };
 
-    static status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+    static status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
                                            audio_io_handle_t audioIo);
-    static status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+    static status_t removeAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
                                               audio_io_handle_t audioIo);
 
     static audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
@@ -403,9 +403,9 @@
                                      const sp<AudioIoDescriptor>& ioDesc);
 
 
-        status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+        status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
                                                audio_io_handle_t audioIo);
-        status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+        status_t removeAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
                                            audio_io_handle_t audioIo);
 
         audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
@@ -413,7 +413,7 @@
     private:
         Mutex                               mLock;
         DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> >   mIoDescriptors;
-        DefaultKeyedVector<audio_io_handle_t, Vector < sp<AudioDeviceCallback> > >
+        DefaultKeyedVector<audio_io_handle_t, Vector < wp<AudioDeviceCallback> > >
                                                                         mAudioDeviceCallbacks;
         // cached values for recording getInputBufferSize() queries
         size_t                              mInBuffSize;    // zero indicates cache is invalid
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 014df20..2adacd7 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -35,7 +35,7 @@
 
 // ----------------------------------------------------------------------------
 
-class AudioTrack : public RefBase
+class AudioTrack : public AudioSystem::AudioDeviceCallback
 {
 public:
 
@@ -605,7 +605,11 @@
 
      /* Returns the ID of the audio device actually used by the output to which this AudioTrack is
       * attached.
-      * A value of AUDIO_PORT_HANDLE_NONE indicates the audio track is not attached to any output.
+      * When the AudioTrack is inactive, the device ID returned can be either:
+      * - AUDIO_PORT_HANDLE_NONE if the AudioTrack is not attached to any output.
+      * - The device ID used before paused or stopped.
+      * - The device ID selected by audio policy manager of setOutputDevice() if the AudioTrack
+      * has not been started yet.
       *
       * Parameters:
       *  none.
@@ -845,6 +849,12 @@
             status_t removeAudioDeviceCallback(
                     const sp<AudioSystem::AudioDeviceCallback>& callback);
 
+            // AudioSystem::AudioDeviceCallback> virtuals
+            virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                             audio_port_handle_t deviceId);
+
+
+
     /* Obtain the pending duration in milliseconds for playback of pure PCM
      * (mixable without embedded timing) data remaining in AudioTrack.
      *
@@ -974,6 +984,8 @@
 
             void     restartIfDisabled();
 
+            void     updateRoutedDeviceId_l();
+
     // Next 4 fields may be changed if IAudioTrack is re-created, but always != 0
     sp<IAudioTrack>         mAudioTrack;
     sp<IMemory>             mCblkMemory;
@@ -1085,8 +1097,10 @@
                                                     // reset by stop() but continues monotonically
                                                     // after new IAudioTrack to restore mPosition,
                                                     // and could be easily widened to uint64_t
-    int64_t                 mStartUs;               // the start time after flush or stop.
+    int64_t                 mStartFromZeroUs;       // the start time after flush or stop,
+                                                    // when position should be 0.
                                                     // only used for offloaded and direct tracks.
+    int64_t                 mStartNs;               // the time when start() is called.
     ExtendedTimestamp       mStartEts;              // Extended timestamp at start for normal
                                                     // AudioTracks.
     AudioTimestamp          mStartTs;               // Timestamp at start for offloaded or direct
@@ -1163,7 +1177,7 @@
     uid_t                   mClientUid;
     pid_t                   mClientPid;
 
-    sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+    wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
     audio_port_handle_t     mPortId;  // unique ID allocated by audio policy
 };
 
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 4f1fed5..aae80b6 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -35,6 +35,15 @@
 // effect_handle_t interface implementation for bass boost
 extern "C" const struct effect_interface_s gLvmEffectInterface;
 
+// Turn on VERY_VERY_VERBOSE_LOGGING to log parameter get and set for effects.
+
+//#define VERY_VERY_VERBOSE_LOGGING
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while (false)
+#endif
+
 #define LVM_ERROR_CHECK(LvmStatus, callingFunc, calledFunc){\
         if ((LvmStatus) == LVM_NULLADDRESS){\
             ALOGV("\tLVM_ERROR : Parameter error - "\
@@ -140,26 +149,43 @@
 void LvmEffect_free            (EffectContext *pContext);
 int  Effect_setConfig          (EffectContext *pContext, effect_config_t *pConfig);
 void Effect_getConfig          (EffectContext *pContext, effect_config_t *pConfig);
-int  BassBoost_setParameter    (EffectContext *pContext, void *pParam, void *pValue);
+int  BassBoost_setParameter    (EffectContext *pContext,
+                                uint32_t       paramSize,
+                                void          *pParam,
+                                uint32_t       valueSize,
+                                void          *pValue);
 int  BassBoost_getParameter    (EffectContext *pContext,
-                               void           *pParam,
-                               uint32_t       *pValueSize,
-                               void           *pValue);
-int  Virtualizer_setParameter  (EffectContext *pContext, void *pParam, void *pValue);
-int  Virtualizer_getParameter  (EffectContext *pContext,
-                               void           *pParam,
-                               uint32_t       *pValueSize,
-                               void           *pValue);
-int  Equalizer_setParameter    (EffectContext *pContext,
-                               void *pParam,
-                               uint32_t valueSize,
-                               void *pValue);
-int  Equalizer_getParameter    (EffectContext *pContext,
+                                uint32_t       paramSize,
                                 void          *pParam,
                                 uint32_t      *pValueSize,
                                 void          *pValue);
-int  Volume_setParameter       (EffectContext *pContext, void *pParam, void *pValue);
+int  Virtualizer_setParameter  (EffectContext *pContext,
+                                uint32_t       paramSize,
+                                void          *pParam,
+                                uint32_t       valueSize,
+                                void          *pValue);
+int  Virtualizer_getParameter  (EffectContext *pContext,
+                                uint32_t       paramSize,
+                                void          *pParam,
+                                uint32_t      *pValueSize,
+                                void          *pValue);
+int  Equalizer_setParameter    (EffectContext *pContext,
+                                uint32_t       paramSize,
+                                void          *pParam,
+                                uint32_t       valueSize,
+                                void          *pValue);
+int  Equalizer_getParameter    (EffectContext *pContext,
+                                uint32_t       paramSize,
+                                void          *pParam,
+                                uint32_t      *pValueSize,
+                                void          *pValue);
+int  Volume_setParameter       (EffectContext *pContext,
+                                uint32_t       paramSize,
+                                void          *pParam,
+                                uint32_t       valueSize,
+                                void          *pValue);
 int  Volume_getParameter       (EffectContext *pContext,
+                                uint32_t       paramSize,
                                 void          *pParam,
                                 uint32_t      *pValueSize,
                                 void          *pValue);
@@ -985,8 +1011,12 @@
     float energyBassBoost = 0;
     float crossCorrection = 0;
 
+    bool eqEnabled = pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE;
+    bool bbEnabled = pContext->pBundledContext->bBassEnabled == LVM_TRUE;
+    bool viEnabled = pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE;
+
     //EQ contribution
-    if (pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE) {
+    if (eqEnabled) {
         for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
             float bandFactor = pContext->pBundledContext->bandGaindB[i]/15.0;
             float bandCoefficient = LimitLevel_bandEnergyCoefficient[i];
@@ -1012,35 +1042,37 @@
         }
         bandFactorSum -= 1.0;
         if (bandFactorSum > 0)
-            crossCorrection = bandFactorSum * 0.7;
+          crossCorrection = bandFactorSum * 0.7;
     }
 
     //BassBoost contribution
-    if (pContext->pBundledContext->bBassEnabled == LVM_TRUE) {
+    if (bbEnabled) {
         float boostFactor = (pContext->pBundledContext->BassStrengthSaved)/1000.0;
         float boostCoefficient = LimitLevel_bassBoostEnergyCoefficient;
 
         energyContribution += boostFactor * boostCoefficient * boostCoefficient;
 
-        for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
-            float bandFactor = pContext->pBundledContext->bandGaindB[i]/15.0;
-            float bandCrossCoefficient = LimitLevel_bassBoostEnergyCrossCoefficient[i];
-            float bandEnergy = boostFactor * bandFactor *
+        if (eqEnabled) {
+            for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
+                float bandFactor = pContext->pBundledContext->bandGaindB[i]/15.0;
+                float bandCrossCoefficient = LimitLevel_bassBoostEnergyCrossCoefficient[i];
+                float bandEnergy = boostFactor * bandFactor *
                     bandCrossCoefficient;
-            if (bandEnergy > 0)
-                energyBassBoost += bandEnergy;
+                if (bandEnergy > 0)
+                  energyBassBoost += bandEnergy;
+            }
         }
     }
 
     //Virtualizer contribution
-    if (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE) {
+    if (viEnabled) {
         energyContribution += LimitLevel_virtualizerContribution *
                 LimitLevel_virtualizerContribution;
     }
 
     double totalEnergyEstimation = sqrt(energyContribution + energyCross + energyBassBoost) -
             crossCorrection;
-    ALOGV(" TOTAL energy estimation: %0.2f", totalEnergyEstimation);
+    ALOGV(" TOTAL energy estimation: %0.2f dB", totalEnergyEstimation);
 
     //roundoff
     int maxLevelRound = (int)(totalEnergyEstimation + 0.99);
@@ -1058,6 +1090,8 @@
     /* Activate the initial settings */
     LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
     LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "LvmEffect_limitLevel")
+
+    ALOGV("LVM_SetControlParameters return:%d", (int)LvmStatus);
     //ALOGV("\tLvmEffect_limitLevel just Set -> %d\n",
     //          ActiveParams.pEQNB_BandDefinition[band].Gain);
 
@@ -1308,6 +1342,8 @@
         ALOGV("\tEffect_setConfig Succesfully called LVM_SetControlParameters\n");
         pContext->pBundledContext->SampleRate = SampleRate;
 
+        LvmEffect_limitLevel(pContext);
+
     }else{
         //ALOGV("\tEffect_setConfig keep sampling rate at %d", SampleRate);
     }
@@ -2165,59 +2201,54 @@
 //
 //----------------------------------------------------------------------------
 
-int BassBoost_getParameter(EffectContext     *pContext,
-                           void              *pParam,
-                           uint32_t          *pValueSize,
-                           void              *pValue){
+int BassBoost_getParameter(EffectContext *pContext,
+                           uint32_t       paramSize,
+                           void          *pParam,
+                           uint32_t      *pValueSize,
+                           void          *pValue) {
     int status = 0;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tBassBoost_getParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (param){
-        case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
-            if (*pValueSize != sizeof(uint32_t)){
-                ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize1 %d", *pValueSize);
-                return -EINVAL;
-            }
-            *pValueSize = sizeof(uint32_t);
-            break;
-        case BASSBOOST_PARAM_STRENGTH:
-            if (*pValueSize != sizeof(int16_t)){
-                ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid pValueSize2 %d", *pValueSize);
-                return -EINVAL;
-            }
-            *pValueSize = sizeof(int16_t);
-            break;
-
-        default:
-            ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid param %d", param);
-            return -EINVAL;
+    if (paramSize < sizeof(int32_t)) {
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
     }
-
-    switch (param){
+    switch (params[0]) {
         case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
-            *(uint32_t *)pValue = 1;
+            if (*pValueSize != sizeof(uint32_t)) {  // legacy: check equality here.
+                ALOGV("%s BASSBOOST_PARAM_STRENGTH_SUPPORTED invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
 
-            //ALOGV("\tBassBoost_getParameter() BASSBOOST_PARAM_STRENGTH_SUPPORTED Value is %d",
-            //        *(uint32_t *)pValue);
+            *(uint32_t *)pValue = 1;
+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH_SUPPORTED %u", __func__, *(uint32_t *)pValue);
             break;
 
         case BASSBOOST_PARAM_STRENGTH:
-            *(int16_t *)pValue = BassGetStrength(pContext);
+            if (*pValueSize != sizeof(int16_t)) {  // legacy: check equality here.
+                ALOGV("%s BASSBOOST_PARAM_STRENGTH invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
 
-            //ALOGV("\tBassBoost_getParameter() BASSBOOST_PARAM_STRENGTH Value is %d",
-            //        *(int16_t *)pValue);
+            *(int16_t *)pValue = BassGetStrength(pContext);
+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH %d", __func__, *(int16_t *)pValue);
             break;
 
         default:
-            ALOGV("\tLVM_ERROR : BassBoost_getParameter() invalid param %d", param);
+            ALOGV("%s invalid param %d", __func__, params[0]);
             status = -EINVAL;
             break;
     }
 
-    //ALOGV("\tBassBoost_getParameter end");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end BassBoost_getParameter */
 
@@ -2236,27 +2267,42 @@
 //
 //----------------------------------------------------------------------------
 
-int BassBoost_setParameter (EffectContext *pContext, void *pParam, void *pValue){
+int BassBoost_setParameter(EffectContext *pContext,
+                           uint32_t       paramSize,
+                           void          *pParam,
+                           uint32_t       valueSize,
+                           void          *pValue) {
     int status = 0;
-    int16_t strength;
-    int32_t *pParamTemp = (int32_t *)pParam;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tBassBoost_setParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (*pParamTemp){
-        case BASSBOOST_PARAM_STRENGTH:
-            strength = *(int16_t *)pValue;
-            //ALOGV("\tBassBoost_setParameter() BASSBOOST_PARAM_STRENGTH value is %d", strength);
-            //ALOGV("\tBassBoost_setParameter() Calling pBassBoost->BassSetStrength");
+    if (paramSize != sizeof(int32_t)) {  // legacy: check equality here.
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
+    }
+    switch (params[0]) {
+        case BASSBOOST_PARAM_STRENGTH: {
+            if (valueSize < sizeof(int16_t)) {
+                ALOGV("%s BASSBOOST_PARAM_STRENGTH invalid valueSize: %u", __func__, valueSize);
+                status = -EINVAL;
+                break;
+            }
+
+            const int16_t strength = *(int16_t *)pValue;
+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH %d", __func__, strength);
+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH Calling BassSetStrength", __func__);
             BassSetStrength(pContext, (int32_t)strength);
-            //ALOGV("\tBassBoost_setParameter() Called pBassBoost->BassSetStrength");
-           break;
+            ALOGVV("%s BASSBOOST_PARAM_STRENGTH Called BassSetStrength", __func__);
+        } break;
+
         default:
-            ALOGV("\tLVM_ERROR : BassBoost_setParameter() invalid param %d", *pParamTemp);
+            ALOGV("%s invalid param %d", __func__, params[0]);
+            status = -EINVAL;
             break;
     }
 
-    //ALOGV("\tBassBoost_setParameter end");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end BassBoost_setParameter */
 
@@ -2281,92 +2327,97 @@
 //
 //----------------------------------------------------------------------------
 
-int Virtualizer_getParameter(EffectContext        *pContext,
-                             void                 *pParam,
-                             uint32_t             *pValueSize,
-                             void                 *pValue){
+int Virtualizer_getParameter(EffectContext *pContext,
+                             uint32_t       paramSize,
+                             void          *pParam,
+                             uint32_t      *pValueSize,
+                             void          *pValue) {
     int status = 0;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tVirtualizer_getParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (param){
-        case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
-            if (*pValueSize != sizeof(uint32_t)){
-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
-                return -EINVAL;
-            }
-            *pValueSize = sizeof(uint32_t);
-            break;
-        case VIRTUALIZER_PARAM_STRENGTH:
-            if (*pValueSize != sizeof(int16_t)){
-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize2 %d",*pValueSize);
-                return -EINVAL;
-            }
-            *pValueSize = sizeof(int16_t);
-            break;
-        case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES:
-            // return value size can only be interpreted as relative to input value,
-            // deferring validity check to below
-            break;
-        case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
-            if (*pValueSize != sizeof(uint32_t)){
-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
-                return -EINVAL;
-            }
-            *pValueSize = sizeof(uint32_t);
-            break;
-        default:
-            ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid param %d", param);
-            return -EINVAL;
+    if (paramSize < sizeof(int32_t)) {
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
     }
-
-    switch (param){
+    switch (params[0]) {
         case VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
-            *(uint32_t *)pValue = 1;
+            if (*pValueSize != sizeof(uint32_t)) { // legacy: check equality here.
+                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH_SUPPORTED invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
 
-            //ALOGV("\tVirtualizer_getParameter() VIRTUALIZER_PARAM_STRENGTH_SUPPORTED Value is %d",
-            //        *(uint32_t *)pValue);
+            *(uint32_t *)pValue = 1;
+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH_SUPPORTED %d", __func__, *(uint32_t *)pValue);
             break;
 
         case VIRTUALIZER_PARAM_STRENGTH:
+            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
+                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
+
             *(int16_t *)pValue = VirtualizerGetStrength(pContext);
 
-            //ALOGV("\tVirtualizer_getParameter() VIRTUALIZER_PARAM_STRENGTH Value is %d",
-            //        *(int16_t *)pValue);
+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH %d", __func__, *(int16_t *)pValue);
             break;
 
         case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES: {
-            const audio_channel_mask_t channelMask = (audio_channel_mask_t) *pParamTemp++;
-            const audio_devices_t deviceType = (audio_devices_t) *pParamTemp;
-            uint32_t nbChannels = audio_channel_count_from_out_mask(channelMask);
-            if (*pValueSize < 3 * nbChannels * sizeof(int32_t)){
-                ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid pValueSize %d",*pValueSize);
-                return -EINVAL;
+            if (paramSize < 3 * sizeof(int32_t)) {
+                ALOGV("%s VIRTUALIZER_PARAM_SPEAKER_ANGLES invalid paramSize: %u",
+                        __func__, paramSize);
+                status = -EINVAL;
+                break;
             }
+
+            const audio_channel_mask_t channelMask = (audio_channel_mask_t) params[1];
+            const audio_devices_t deviceType = (audio_devices_t) params[2];
+            const uint32_t nbChannels = audio_channel_count_from_out_mask(channelMask);
+            const uint32_t valueSizeRequired = 3 * nbChannels * sizeof(int32_t);
+            if (*pValueSize < valueSizeRequired) {
+                ALOGV("%s VIRTUALIZER_PARAM_SPEAKER_ANGLES invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            *pValueSize = valueSizeRequired;
+
             // verify the configuration is supported
             status = VirtualizerIsConfigurationSupported(channelMask, deviceType);
             if (status == 0) {
-                ALOGV("VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES supports mask=0x%x device=0x%x",
-                        channelMask, deviceType);
+                ALOGV("%s VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES mask=0x%x device=0x%x",
+                        __func__, channelMask, deviceType);
                 // configuration is supported, get the angles
                 VirtualizerGetSpeakerAngles(channelMask, deviceType, (int32_t *)pValue);
             }
-            }
-            break;
+        } break;
 
         case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
-            *(uint32_t *)pValue  = (uint32_t) VirtualizerGetVirtualizationMode(pContext);
+            if (*pValueSize != sizeof(uint32_t)) { // legacy: check equality here.
+                ALOGV("%s VIRTUALIZER_PARAM_VIRTUALIZATION_MODE invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
+
+            *(uint32_t *)pValue = (uint32_t) VirtualizerGetVirtualizationMode(pContext);
             break;
 
         default:
-            ALOGV("\tLVM_ERROR : Virtualizer_getParameter() invalid param %d", param);
+            ALOGV("%s invalid param %d", __func__, params[0]);
             status = -EINVAL;
             break;
     }
 
-    ALOGV("\tVirtualizer_getParameter end returning status=%d", status);
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end Virtualizer_getParameter */
 
@@ -2385,37 +2436,57 @@
 //
 //----------------------------------------------------------------------------
 
-int Virtualizer_setParameter (EffectContext *pContext, void *pParam, void *pValue){
+int Virtualizer_setParameter(EffectContext *pContext,
+                             uint32_t       paramSize,
+                             void          *pParam,
+                             uint32_t       valueSize,
+                             void          *pValue) {
     int status = 0;
-    int16_t strength;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tVirtualizer_setParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (param){
-        case VIRTUALIZER_PARAM_STRENGTH:
-            strength = *(int16_t *)pValue;
-            //ALOGV("\tVirtualizer_setParameter() VIRTUALIZER_PARAM_STRENGTH value is %d", strength);
-            //ALOGV("\tVirtualizer_setParameter() Calling pVirtualizer->setStrength");
+    if (paramSize != sizeof(int32_t)) { // legacy: check equality here.
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
+    }
+    switch (params[0]) {
+        case VIRTUALIZER_PARAM_STRENGTH: {
+            if (valueSize < sizeof(int16_t)) {
+                ALOGV("%s VIRTUALIZER_PARAM_STRENGTH invalid valueSize: %u", __func__, valueSize);
+                status = -EINVAL;
+                break;
+            }
+
+            const int16_t strength = *(int16_t *)pValue;
+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH %d", __func__, strength);
+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH Calling VirtualizerSetStrength", __func__);
             VirtualizerSetStrength(pContext, (int32_t)strength);
-            //ALOGV("\tVirtualizer_setParameter() Called pVirtualizer->setStrength");
-           break;
+            ALOGVV("%s VIRTUALIZER_PARAM_STRENGTH Called VirtualizerSetStrength", __func__);
+        } break;
 
         case VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE: {
-            const audio_devices_t deviceType = *(audio_devices_t *) pValue;
-            status = VirtualizerForceVirtualizationMode(pContext, deviceType);
-            //ALOGV("VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE device=0x%x result=%d",
-            //        deviceType, status);
+            if (valueSize < sizeof(int32_t)) {
+                ALOGV("%s VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE invalid valueSize: %u",
+                        __func__, valueSize);
+                android_errorWriteLog(0x534e4554, "64478003");
+                status = -EINVAL;
+                break;
             }
-            break;
+
+            const audio_devices_t deviceType = (audio_devices_t)*(int32_t *)pValue;
+            status = VirtualizerForceVirtualizationMode(pContext, deviceType);
+            ALOGVV("%s VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE device=%#x result=%d",
+                    __func__, deviceType, status);
+        } break;
 
         default:
-            ALOGV("\tLVM_ERROR : Virtualizer_setParameter() invalid param %d", param);
+            ALOGV("%s invalid param %d", __func__, params[0]);
+            status = -EINVAL;
             break;
     }
 
-    //ALOGV("\tVirtualizer_setParameter end");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end Virtualizer_setParameter */
 
@@ -2439,174 +2510,215 @@
 // Side Effects:
 //
 //----------------------------------------------------------------------------
-int Equalizer_getParameter(EffectContext     *pContext,
-                           void              *pParam,
-                           uint32_t          *pValueSize,
-                           void              *pValue){
+int Equalizer_getParameter(EffectContext *pContext,
+                           uint32_t       paramSize,
+                           void          *pParam,
+                           uint32_t      *pValueSize,
+                           void          *pValue) {
     int status = 0;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;
-    int32_t param2;
-    char *name;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tEqualizer_getParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (param) {
+    if (paramSize < sizeof(int32_t)) {
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
+    }
+    switch (params[0]) {
     case EQ_PARAM_NUM_BANDS:
+        if (*pValueSize < sizeof(uint16_t)) {
+            ALOGV("%s EQ_PARAM_NUM_BANDS invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
+        }
+        *pValueSize = sizeof(uint16_t);
+
+        *(uint16_t *)pValue = (uint16_t)FIVEBAND_NUMBANDS;
+        ALOGVV("%s EQ_PARAM_NUM_BANDS %u", __func__, *(uint16_t *)pValue);
+        break;
+
     case EQ_PARAM_CUR_PRESET:
+        if (*pValueSize < sizeof(uint16_t)) {
+            ALOGV("%s EQ_PARAM_CUR_PRESET invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
+        }
+        *pValueSize = sizeof(uint16_t);
+
+        *(uint16_t *)pValue = (uint16_t)EqualizerGetPreset(pContext);
+        ALOGVV("%s EQ_PARAM_CUR_PRESET %u", __func__, *(uint16_t *)pValue);
+        break;
+
     case EQ_PARAM_GET_NUM_OF_PRESETS:
-    case EQ_PARAM_BAND_LEVEL:
-    case EQ_PARAM_GET_BAND:
+        if (*pValueSize < sizeof(uint16_t)) {
+            ALOGV("%s EQ_PARAM_GET_NUM_OF_PRESETS invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
+        }
+        *pValueSize = sizeof(uint16_t);
+
+        *(uint16_t *)pValue = (uint16_t)EqualizerGetNumPresets();
+        ALOGVV("%s EQ_PARAM_GET_NUM_OF_PRESETS %u", __func__, *(uint16_t *)pValue);
+        break;
+
+    case EQ_PARAM_GET_BAND: {
+        if (paramSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_GET_BAND invalid paramSize: %u", __func__, paramSize);
+            status = -EINVAL;
+            break;
+        }
+        if (*pValueSize < sizeof(uint16_t)) {
+            ALOGV("%s EQ_PARAM_GET_BAND invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
+        }
+        *pValueSize = sizeof(uint16_t);
+
+        const int32_t frequency = params[1];
+        *(uint16_t *)pValue = (uint16_t)EqualizerGetBand(pContext, frequency);
+        ALOGVV("%s EQ_PARAM_GET_BAND frequency %d, band %u",
+                __func__, frequency, *(uint16_t *)pValue);
+    } break;
+
+    case EQ_PARAM_BAND_LEVEL: {
+        if (paramSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid paramSize %u", __func__, paramSize);
+            status = -EINVAL;
+            break;
+        }
         if (*pValueSize < sizeof(int16_t)) {
-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 1  %d", *pValueSize);
-            return -EINVAL;
+            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
         }
         *pValueSize = sizeof(int16_t);
-        break;
+
+        const int32_t band = params[1];
+        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
+            if (band < 0) {
+                android_errorWriteLog(0x534e4554, "32438598");
+                ALOGW("%s EQ_PARAM_BAND_LEVEL invalid band %d", __func__, band);
+            }
+            status = -EINVAL;
+            break;
+        }
+        *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, band);
+        ALOGVV("%s EQ_PARAM_BAND_LEVEL band %d, level %d",
+                __func__, band, *(int16_t *)pValue);
+    } break;
 
     case EQ_PARAM_LEVEL_RANGE:
         if (*pValueSize < 2 * sizeof(int16_t)) {
-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 2  %d", *pValueSize);
-            return -EINVAL;
+            ALOGV("%s EQ_PARAM_LEVEL_RANGE invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
         }
         *pValueSize = 2 * sizeof(int16_t);
-        break;
-    case EQ_PARAM_BAND_FREQ_RANGE:
-        if (*pValueSize < 2 * sizeof(int32_t)) {
-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 3  %d", *pValueSize);
-            return -EINVAL;
-        }
-        *pValueSize = 2 * sizeof(int32_t);
-        break;
 
-    case EQ_PARAM_CENTER_FREQ:
-        if (*pValueSize < sizeof(int32_t)) {
-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 5  %d", *pValueSize);
-            return -EINVAL;
-        }
-        *pValueSize = sizeof(int32_t);
-        break;
-
-    case EQ_PARAM_GET_PRESET_NAME:
-        break;
-
-    case EQ_PARAM_PROPERTIES:
-        if (*pValueSize < (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t)) {
-            ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 1  %d", *pValueSize);
-            return -EINVAL;
-        }
-        *pValueSize = (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t);
-        break;
-
-    default:
-        ALOGV("\tLVM_ERROR : Equalizer_getParameter unknown param %d", param);
-        return -EINVAL;
-    }
-
-    switch (param) {
-    case EQ_PARAM_NUM_BANDS:
-        *(uint16_t *)pValue = (uint16_t)FIVEBAND_NUMBANDS;
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_NUM_BANDS %d", *(int16_t *)pValue);
-        break;
-
-    case EQ_PARAM_LEVEL_RANGE:
         *(int16_t *)pValue = -1500;
         *((int16_t *)pValue + 1) = 1500;
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_LEVEL_RANGE min %d, max %d",
-        //      *(int16_t *)pValue, *((int16_t *)pValue + 1));
+        ALOGVV("%s EQ_PARAM_LEVEL_RANGE min %d, max %d",
+                __func__, *(int16_t *)pValue, *((int16_t *)pValue + 1));
         break;
 
-    case EQ_PARAM_BAND_LEVEL:
-        param2 = *pParamTemp;
-        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
+    case EQ_PARAM_BAND_FREQ_RANGE: {
+        if (paramSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_BAND_FREQ_RANGE invalid paramSize: %u", __func__, paramSize);
             status = -EINVAL;
-            if (param2 < 0) {
-                android_errorWriteLog(0x534e4554, "32438598");
-                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d", param2);
-            }
             break;
         }
-        *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, param2);
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_BAND_LEVEL band %d, level %d",
-        //      param2, *(int32_t *)pValue);
-        break;
-
-    case EQ_PARAM_CENTER_FREQ:
-        param2 = *pParamTemp;
-        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
+        if (*pValueSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_BAND_FREQ_RANGE invalid *pValueSize %u", __func__, *pValueSize);
             status = -EINVAL;
-            if (param2 < 0) {
-                android_errorWriteLog(0x534e4554, "32436341");
-                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_CENTER_FREQ band %d", param2);
-            }
             break;
         }
-        *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, param2);
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_CENTER_FREQ band %d, frequency %d",
-        //      param2, *(int32_t *)pValue);
-        break;
+        *pValueSize = 2 * sizeof(int32_t);
 
-    case EQ_PARAM_BAND_FREQ_RANGE:
-        param2 = *pParamTemp;
-        if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
-            status = -EINVAL;
-            if (param2 < 0) {
+        const int32_t band = params[1];
+        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
+            if (band < 0) {
                 android_errorWriteLog(0x534e4554, "32247948");
-                ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d", param2);
+                ALOGW("%s EQ_PARAM_BAND_FREQ_RANGE invalid band %d",
+                        __func__, band);
             }
-            break;
-        }
-        EqualizerGetBandFreqRange(pContext, param2, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d, min %d, max %d",
-        //      param2, *(int32_t *)pValue, *((int32_t *)pValue + 1));
-        break;
-
-    case EQ_PARAM_GET_BAND:
-        param2 = *pParamTemp;
-        *(uint16_t *)pValue = (uint16_t)EqualizerGetBand(pContext, param2);
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_BAND frequency %d, band %d",
-        //      param2, *(uint16_t *)pValue);
-        break;
-
-    case EQ_PARAM_CUR_PRESET:
-        *(uint16_t *)pValue = (uint16_t)EqualizerGetPreset(pContext);
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_CUR_PRESET %d", *(int32_t *)pValue);
-        break;
-
-    case EQ_PARAM_GET_NUM_OF_PRESETS:
-        *(uint16_t *)pValue = (uint16_t)EqualizerGetNumPresets();
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_NUM_OF_PRESETS %d", *(int16_t *)pValue);
-        break;
-
-    case EQ_PARAM_GET_PRESET_NAME:
-        param2 = *pParamTemp;
-        if ((param2 < 0 && param2 != PRESET_CUSTOM) ||  param2 >= EqualizerGetNumPresets()) {
             status = -EINVAL;
-            if (param2 < 0) {
-                android_errorWriteLog(0x534e4554, "32448258");
-                ALOGE("\tERROR Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d",
-                        param2);
+            break;
+        }
+        EqualizerGetBandFreqRange(pContext, band, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
+        ALOGVV("%s EQ_PARAM_BAND_FREQ_RANGE band %d, min %d, max %d",
+                __func__, band, *(int32_t *)pValue, *((int32_t *)pValue + 1));
+
+    } break;
+
+    case EQ_PARAM_CENTER_FREQ: {
+        if (paramSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_CENTER_FREQ invalid paramSize: %u", __func__, paramSize);
+            status = -EINVAL;
+            break;
+        }
+        if (*pValueSize < sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_CENTER_FREQ invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
+        }
+        *pValueSize = sizeof(int32_t);
+
+        const int32_t band = params[1];
+        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
+            status = -EINVAL;
+            if (band < 0) {
+                android_errorWriteLog(0x534e4554, "32436341");
+                ALOGW("%s EQ_PARAM_CENTER_FREQ invalid band %d", __func__, band);
             }
             break;
         }
+        *(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, band);
+        ALOGVV("%s EQ_PARAM_CENTER_FREQ band %d, frequency %d",
+                __func__, band, *(int32_t *)pValue);
+    } break;
 
+    case EQ_PARAM_GET_PRESET_NAME: {
+        if (paramSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_PRESET_NAME invalid paramSize: %u", __func__, paramSize);
+            status = -EINVAL;
+            break;
+        }
         if (*pValueSize < 1) {
-            status = -EINVAL;
             android_errorWriteLog(0x534e4554, "37536407");
+            status = -EINVAL;
             break;
         }
 
-        name = (char *)pValue;
-        strncpy(name, EqualizerGetPresetName(param2), *pValueSize - 1);
+        const int32_t preset = params[1];
+        if ((preset < 0 && preset != PRESET_CUSTOM) ||  preset >= EqualizerGetNumPresets()) {
+            if (preset < 0) {
+                android_errorWriteLog(0x534e4554, "32448258");
+                ALOGE("%s EQ_PARAM_GET_PRESET_NAME preset %d", __func__, preset);
+            }
+            status = -EINVAL;
+            break;
+        }
+
+        char * const name = (char *)pValue;
+        strncpy(name, EqualizerGetPresetName(preset), *pValueSize - 1);
         name[*pValueSize - 1] = 0;
         *pValueSize = strlen(name) + 1;
-        //ALOGV("\tEqualizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d",
-        //      param2, gEqualizerPresets[param2].name, *pValueSize);
-        break;
+        ALOGVV("%s EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d",
+                __func__, preset, gEqualizerPresets[preset].name, *pValueSize);
+
+    } break;
 
     case EQ_PARAM_PROPERTIES: {
+        constexpr uint32_t requiredValueSize = (2 + FIVEBAND_NUMBANDS) * sizeof(uint16_t);
+        if (*pValueSize < requiredValueSize) {
+            ALOGV("%s EQ_PARAM_PROPERTIES invalid *pValueSize %u", __func__, *pValueSize);
+            status = -EINVAL;
+            break;
+        }
+        *pValueSize = requiredValueSize;
+
         int16_t *p = (int16_t *)pValue;
-        ALOGV("\tEqualizer_getParameter() EQ_PARAM_PROPERTIES");
+        ALOGV("%s EQ_PARAM_PROPERTIES", __func__);
         p[0] = (int16_t)EqualizerGetPreset(pContext);
         p[1] = (int16_t)FIVEBAND_NUMBANDS;
         for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
@@ -2615,12 +2727,12 @@
     } break;
 
     default:
-        ALOGV("\tLVM_ERROR : Equalizer_getParameter() invalid param %d", param);
+        ALOGV("%s invalid param %d", __func__, params[0]);
         status = -EINVAL;
         break;
     }
 
-    //GV("\tEqualizer_getParameter end\n");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end Equalizer_getParameter */
 
@@ -2640,74 +2752,89 @@
 // Outputs:
 //
 //----------------------------------------------------------------------------
-int Equalizer_setParameter (EffectContext *pContext,
-                            void *pParam,
-                            uint32_t valueSize,
-                            void *pValue) {
+int Equalizer_setParameter(EffectContext *pContext,
+                           uint32_t       paramSize,
+                           void          *pParam,
+                           uint32_t       valueSize,
+                           void          *pValue) {
     int status = 0;
-    int32_t preset;
-    int32_t band;
-    int32_t level;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;
+    int32_t *params = (int32_t *)pParam;
 
+    ALOGVV("%s start", __func__);
 
-    //ALOGV("\tEqualizer_setParameter start");
-    switch (param) {
-    case EQ_PARAM_CUR_PRESET:
+    if (paramSize < sizeof(int32_t)) {
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
+    }
+    switch (params[0]) {
+    case EQ_PARAM_CUR_PRESET: {
         if (valueSize < sizeof(int16_t)) {
-          status = -EINVAL;
-          break;
+            ALOGV("%s EQ_PARAM_CUR_PRESET invalid valueSize %u", __func__, valueSize);
+            status = -EINVAL;
+            break;
         }
-        preset = (int32_t)(*(uint16_t *)pValue);
+        const int32_t preset = (int32_t)*(uint16_t *)pValue;
 
-        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_CUR_PRESET %d", preset);
-        if ((preset >= EqualizerGetNumPresets())||(preset < 0)) {
+        ALOGVV("%s EQ_PARAM_CUR_PRESET %d", __func__, preset);
+        if (preset >= EqualizerGetNumPresets() || preset < 0) {
+            ALOGV("%s EQ_PARAM_CUR_PRESET invalid preset %d", __func__, preset);
             status = -EINVAL;
             break;
         }
         EqualizerSetPreset(pContext, preset);
-        break;
-    case EQ_PARAM_BAND_LEVEL:
-        if (valueSize < sizeof(int16_t)) {
-          status = -EINVAL;
-          break;
-        }
-        band =  *pParamTemp;
-        level = (int32_t)(*(int16_t *)pValue);
-        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level);
-        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
+    } break;
+
+    case EQ_PARAM_BAND_LEVEL: {
+        if (paramSize < 2 * sizeof(int32_t)) {
+            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid paramSize: %u", __func__, paramSize);
             status = -EINVAL;
+            break;
+        }
+        if (valueSize < sizeof(int16_t)) {
+            ALOGV("%s EQ_PARAM_BAND_LEVEL invalid valueSize %u", __func__, valueSize);
+            status = -EINVAL;
+            break;
+        }
+        const int32_t band =  params[1];
+        const int32_t level = (int32_t)*(int16_t *)pValue;
+        ALOGVV("%s EQ_PARAM_BAND_LEVEL band %d, level %d", __func__, band, level);
+        if (band < 0 || band >= FIVEBAND_NUMBANDS) {
             if (band < 0) {
                 android_errorWriteLog(0x534e4554, "32095626");
-                ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_BAND_LEVEL band %d", band);
+                ALOGE("%s EQ_PARAM_BAND_LEVEL invalid band %d", __func__, band);
             }
+            status = -EINVAL;
             break;
         }
         EqualizerSetBandLevel(pContext, band, level);
-        break;
+    } break;
+
     case EQ_PARAM_PROPERTIES: {
-        //ALOGV("\tEqualizer_setParameter() EQ_PARAM_PROPERTIES");
+        ALOGVV("%s EQ_PARAM_PROPERTIES", __func__);
         if (valueSize < sizeof(int16_t)) {
-          status = -EINVAL;
-          break;
+            ALOGV("%s EQ_PARAM_PROPERTIES invalid valueSize %u", __func__, valueSize);
+            status = -EINVAL;
+            break;
         }
         int16_t *p = (int16_t *)pValue;
         if ((int)p[0] >= EqualizerGetNumPresets()) {
+            ALOGV("%s EQ_PARAM_PROPERTIES invalid preset %d", __func__, (int)p[0]);
             status = -EINVAL;
             break;
         }
         if (p[0] >= 0) {
             EqualizerSetPreset(pContext, (int)p[0]);
         } else {
-            if (valueSize < (2 + FIVEBAND_NUMBANDS) * sizeof(int16_t)) {
+            constexpr uint32_t valueSizeRequired = (2 + FIVEBAND_NUMBANDS) * sizeof(int16_t);
+            if (valueSize < valueSizeRequired) {
               android_errorWriteLog(0x534e4554, "37563371");
-              ALOGE("\tERROR Equalizer_setParameter() EQ_PARAM_PROPERTIES valueSize %d < %d",
-                    (int)valueSize, (int)((2 + FIVEBAND_NUMBANDS) * sizeof(int16_t)));
+              ALOGE("%s EQ_PARAM_PROPERTIES invalid valueSize %u < %u",
+                      __func__, valueSize, valueSizeRequired);
               status = -EINVAL;
               break;
             }
             if ((int)p[1] != FIVEBAND_NUMBANDS) {
+                ALOGV("%s EQ_PARAM_PROPERTIES invalid bands %d", __func__, (int)p[1]);
                 status = -EINVAL;
                 break;
             }
@@ -2716,13 +2843,14 @@
             }
         }
     } break;
+
     default:
-        ALOGV("\tLVM_ERROR : Equalizer_setParameter() invalid param %d", param);
+        ALOGV("%s invalid param %d", __func__, params[0]);
         status = -EINVAL;
         break;
     }
 
-    //ALOGV("\tEqualizer_setParameter end");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end Equalizer_setParameter */
 
@@ -2747,79 +2875,92 @@
 //
 //----------------------------------------------------------------------------
 
-int Volume_getParameter(EffectContext     *pContext,
-                        void              *pParam,
-                        uint32_t          *pValueSize,
-                        void              *pValue){
+int Volume_getParameter(EffectContext *pContext,
+                        uint32_t       paramSize,
+                        void          *pParam,
+                        uint32_t      *pValueSize,
+                        void          *pValue) {
     int status = 0;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tVolume_getParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (param){
+    if (paramSize < sizeof(int32_t)) {
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
+    }
+    switch (params[0]) {
         case VOLUME_PARAM_LEVEL:
-        case VOLUME_PARAM_MAXLEVEL:
-        case VOLUME_PARAM_STEREOPOSITION:
-            if (*pValueSize != sizeof(int16_t)){
-                ALOGV("\tLVM_ERROR : Volume_getParameter() invalid pValueSize 1  %d", *pValueSize);
-                return -EINVAL;
+            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
+                ALOGV("%s VOLUME_PARAM_LEVEL invalid *pValueSize %u", __func__, *pValueSize);
+                status = -EINVAL;
+                break;
             }
-            *pValueSize = sizeof(int16_t);
+            // no need to set *pValueSize
+
+            status = VolumeGetVolumeLevel(pContext, (int16_t *)(pValue));
+            ALOGVV("%s VOLUME_PARAM_LEVEL %d", __func__, *(int16_t *)pValue);
+            break;
+
+        case VOLUME_PARAM_MAXLEVEL:
+            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
+                ALOGV("%s VOLUME_PARAM_MAXLEVEL invalid *pValueSize %u", __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
+
+            // in millibel
+            *(int16_t *)pValue = 0;
+            ALOGVV("%s VOLUME_PARAM_MAXLEVEL %d", __func__, *(int16_t *)pValue);
+            break;
+
+        case VOLUME_PARAM_STEREOPOSITION:
+            if (*pValueSize != sizeof(int16_t)) { // legacy: check equality here.
+                ALOGV("%s VOLUME_PARAM_STEREOPOSITION invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            // no need to set *pValueSize
+
+            VolumeGetStereoPosition(pContext, (int16_t *)pValue);
+            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION %d", __func__, *(int16_t *)pValue);
             break;
 
         case VOLUME_PARAM_MUTE:
+            if (*pValueSize < sizeof(uint32_t)) {
+                ALOGV("%s VOLUME_PARAM_MUTE invalid *pValueSize %u", __func__, *pValueSize);
+                status = -EINVAL;
+                break;
+            }
+            *pValueSize = sizeof(uint32_t);
+
+            status = VolumeGetMute(pContext, (uint32_t *)pValue);
+            ALOGV("%s VOLUME_PARAM_MUTE %u", __func__, *(uint32_t *)pValue);
+            break;
+
         case VOLUME_PARAM_ENABLESTEREOPOSITION:
-            if (*pValueSize < sizeof(int32_t)){
-                ALOGV("\tLVM_ERROR : Volume_getParameter() invalid pValueSize 2  %d", *pValueSize);
-                return -EINVAL;
+            if (*pValueSize < sizeof(int32_t)) {
+                ALOGV("%s VOLUME_PARAM_ENABLESTEREOPOSITION invalid *pValueSize %u",
+                        __func__, *pValueSize);
+                status = -EINVAL;
+                break;
             }
             *pValueSize = sizeof(int32_t);
-            break;
 
-        default:
-            ALOGV("\tLVM_ERROR : Volume_getParameter unknown param %d", param);
-            return -EINVAL;
-    }
-
-    switch (param){
-        case VOLUME_PARAM_LEVEL:
-            status = VolumeGetVolumeLevel(pContext, (int16_t *)(pValue));
-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_LEVEL Value is %d",
-            //        *(int16_t *)pValue);
-            break;
-
-        case VOLUME_PARAM_MAXLEVEL:
-            *(int16_t *)pValue = 0;
-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_MAXLEVEL Value is %d",
-            //        *(int16_t *)pValue);
-            break;
-
-        case VOLUME_PARAM_STEREOPOSITION:
-            VolumeGetStereoPosition(pContext, (int16_t *)pValue);
-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_STEREOPOSITION Value is %d",
-            //        *(int16_t *)pValue);
-            break;
-
-        case VOLUME_PARAM_MUTE:
-            status = VolumeGetMute(pContext, (uint32_t *)pValue);
-            ALOGV("\tVolume_getParameter() VOLUME_PARAM_MUTE Value is %d",
-                    *(uint32_t *)pValue);
-            break;
-
-        case VOLUME_PARAM_ENABLESTEREOPOSITION:
             *(int32_t *)pValue = pContext->pBundledContext->bStereoPositionEnabled;
-            //ALOGV("\tVolume_getParameter() VOLUME_PARAM_ENABLESTEREOPOSITION Value is %d",
-            //        *(uint32_t *)pValue);
+            ALOGVV("%s VOLUME_PARAM_ENABLESTEREOPOSITION %d", __func__, *(int32_t *)pValue);
+
             break;
 
         default:
-            ALOGV("\tLVM_ERROR : Volume_getParameter() invalid param %d", param);
+            ALOGV("%s invalid param %d", __func__, params[0]);
             status = -EINVAL;
             break;
     }
 
-    //ALOGV("\tVolume_getParameter end");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end Volume_getParameter */
 
@@ -2839,55 +2980,87 @@
 //
 //----------------------------------------------------------------------------
 
-int Volume_setParameter (EffectContext *pContext, void *pParam, void *pValue){
-    int      status = 0;
-    int16_t  level;
-    int16_t  position;
-    uint32_t mute;
-    uint32_t positionEnabled;
-    int32_t *pParamTemp = (int32_t *)pParam;
-    int32_t param = *pParamTemp++;
+int Volume_setParameter(EffectContext *pContext,
+                        uint32_t       paramSize,
+                        void          *pParam,
+                        uint32_t       valueSize,
+                        void          *pValue) {
+    int status = 0;
+    int32_t *params = (int32_t *)pParam;
 
-    //ALOGV("\tVolume_setParameter start");
+    ALOGVV("%s start", __func__);
 
-    switch (param){
-        case VOLUME_PARAM_LEVEL:
-            level = *(int16_t *)pValue;
-            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_LEVEL value is %d", level);
-            //ALOGV("\tVolume_setParameter() Calling pVolume->setVolumeLevel");
-            status = VolumeSetVolumeLevel(pContext, (int16_t)level);
-            //ALOGV("\tVolume_setParameter() Called pVolume->setVolumeLevel");
-            break;
+    if (paramSize < sizeof(int32_t)) {
+        ALOGV("%s invalid paramSize: %u", __func__, paramSize);
+        return -EINVAL;
+    }
+    switch (params[0]) {
+        case VOLUME_PARAM_LEVEL: {
+            if (valueSize < sizeof(int16_t)) {
+                ALOGV("%s VOLUME_PARAM_LEVEL invalid valueSize %u", __func__, valueSize);
+                status = -EINVAL;
+                break;
+            }
 
-        case VOLUME_PARAM_MUTE:
-            mute = *(uint32_t *)pValue;
-            //ALOGV("\tVolume_setParameter() Calling pVolume->setMute, mute is %d", mute);
-            //ALOGV("\tVolume_setParameter() Calling pVolume->setMute");
+            const int16_t level = *(int16_t *)pValue;
+            ALOGVV("%s VOLUME_PARAM_LEVEL %d", __func__, level);
+            ALOGVV("%s VOLUME_PARAM_LEVEL Calling VolumeSetVolumeLevel", __func__);
+            status = VolumeSetVolumeLevel(pContext, level);
+            ALOGVV("%s VOLUME_PARAM_LEVEL Called VolumeSetVolumeLevel", __func__);
+        } break;
+
+        case VOLUME_PARAM_MUTE: {
+            if (valueSize < sizeof(uint32_t)) {
+                ALOGV("%s VOLUME_PARAM_MUTE invalid valueSize %u", __func__, valueSize);
+                android_errorWriteLog(0x534e4554, "64477217");
+                status = -EINVAL;
+                break;
+            }
+
+            const uint32_t mute = *(uint32_t *)pValue;
+            ALOGVV("%s VOLUME_PARAM_MUTE %d", __func__, mute);
+            ALOGVV("%s VOLUME_PARAM_MUTE Calling VolumeSetMute", __func__);
             status = VolumeSetMute(pContext, mute);
-            //ALOGV("\tVolume_setParameter() Called pVolume->setMute");
-            break;
+            ALOGVV("%s VOLUME_PARAM_MUTE Called VolumeSetMute", __func__);
+        } break;
 
-        case VOLUME_PARAM_ENABLESTEREOPOSITION:
-            positionEnabled = *(uint32_t *)pValue;
-            (void) VolumeEnableStereoPosition(pContext, positionEnabled);
-            (void) VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
-            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_ENABLESTEREOPOSITION called");
-            break;
+        case VOLUME_PARAM_ENABLESTEREOPOSITION: {
+            if (valueSize < sizeof(uint32_t)) {
+                ALOGV("%s VOLUME_PARAM_ENABLESTEREOPOSITION invalid valueSize %u",
+                        __func__, valueSize);
+                status = -EINVAL;
+                break;
+            }
 
-        case VOLUME_PARAM_STEREOPOSITION:
-            position = *(int16_t *)pValue;
-            //ALOGV("\tVolume_setParameter() VOLUME_PARAM_STEREOPOSITION value is %d", position);
-            //ALOGV("\tVolume_setParameter() Calling pVolume->VolumeSetStereoPosition");
-            status = VolumeSetStereoPosition(pContext, (int16_t)position);
-            //ALOGV("\tVolume_setParameter() Called pVolume->VolumeSetStereoPosition");
-            break;
+            const uint32_t positionEnabled = *(uint32_t *)pValue;
+            status = VolumeEnableStereoPosition(pContext, positionEnabled)
+                    ?: VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
+            ALOGVV("%s VOLUME_PARAM_ENABLESTEREOPOSITION called", __func__);
+        } break;
+
+        case VOLUME_PARAM_STEREOPOSITION: {
+            if (valueSize < sizeof(int16_t)) {
+                ALOGV("%s VOLUME_PARAM_STEREOPOSITION invalid valueSize %u", __func__, valueSize);
+                status = -EINVAL;
+                break;
+            }
+
+            const int16_t position = *(int16_t *)pValue;
+            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION %d", __func__, position);
+            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION Calling VolumeSetStereoPosition",
+                    __func__);
+            status = VolumeSetStereoPosition(pContext, position);
+            ALOGVV("%s VOLUME_PARAM_STEREOPOSITION Called VolumeSetStereoPosition",
+                    __func__);
+        } break;
 
         default:
-            ALOGV("\tLVM_ERROR : Volume_setParameter() invalid param %d", param);
+            ALOGV("%s invalid param %d", __func__, params[0]);
+            status = -EINVAL;
             break;
     }
 
-    //ALOGV("\tVolume_setParameter end");
+    ALOGVV("%s end param: %d, status: %d", __func__, params[0], status);
     return status;
 } /* end Volume_setParameter */
 
@@ -3205,6 +3378,13 @@
     return status;
 }   /* end Effect_process */
 
+// The value offset of an effect parameter is computed by rounding up
+// the parameter size to the next 32 bit alignment.
+static inline uint32_t computeParamVOffset(const effect_param_t *p) {
+    return ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) *
+            sizeof(int32_t);
+}
+
 /* Effect Control Interface Implementation: Command */
 int Effect_command(effect_handle_t  self,
                               uint32_t            cmdCode,
@@ -3315,8 +3495,7 @@
                 ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: psize too big");
                 return -EINVAL;
             }
-            uint32_t paddedParamSize = ((p->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) *
-                    sizeof(int32_t);
+            const uint32_t paddedParamSize = computeParamVOffset(p);
             if ((EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) < paddedParamSize) ||
                 (EFFECT_PARAM_SIZE_MAX - sizeof(effect_param_t) - paddedParamSize <
                     p->vsize)) {
@@ -3338,6 +3517,7 @@
             uint32_t voffset = paddedParamSize;
             if(pContext->EffectType == LVM_BASS_BOOST){
                 p->status = android::BassBoost_getParameter(pContext,
+                                                            p->psize,
                                                             p->data,
                                                             &p->vsize,
                                                             p->data + voffset);
@@ -3350,6 +3530,7 @@
 
             if(pContext->EffectType == LVM_VIRTUALIZER){
                 p->status = android::Virtualizer_getParameter(pContext,
+                                                              p->psize,
                                                               (void *)p->data,
                                                               &p->vsize,
                                                               p->data + voffset);
@@ -3364,6 +3545,7 @@
                 //ALOGV("\tEqualizer_command cmdCode Case: "
                 //        "EFFECT_CMD_GET_PARAM start");
                 p->status = android::Equalizer_getParameter(pContext,
+                                                            p->psize,
                                                             p->data,
                                                             &p->vsize,
                                                             p->data + voffset);
@@ -3378,6 +3560,7 @@
             if(pContext->EffectType == LVM_VOLUME){
                 //ALOGV("\tVolume_command cmdCode Case: EFFECT_CMD_GET_PARAM start");
                 p->status = android::Volume_getParameter(pContext,
+                                                         p->psize,
                                                          (void *)p->data,
                                                          &p->vsize,
                                                          p->data + voffset);
@@ -3407,13 +3590,9 @@
                             "EFFECT_CMD_SET_PARAM: ERROR");
                     return -EINVAL;
                 }
-                effect_param_t *p = (effect_param_t *) pCmdData;
 
-                if (p->psize != sizeof(int32_t)){
-                    ALOGV("\tLVM_ERROR : BassBoost_command cmdCode Case: "
-                            "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
-                    return -EINVAL;
-                }
+                effect_param_t * const p = (effect_param_t *) pCmdData;
+                const uint32_t voffset = computeParamVOffset(p);
 
                 //ALOGV("\tnBassBoost_command cmdSize is %d\n"
                 //        "\tsizeof(effect_param_t) is  %d\n"
@@ -3423,8 +3602,10 @@
                 //        cmdSize, sizeof(effect_param_t), p->psize, p->vsize );
 
                 *(int *)pReplyData = android::BassBoost_setParameter(pContext,
-                                                                    (void *)p->data,
-                                                                    p->data + p->psize);
+                                                                     p->psize,
+                                                                     (void *)p->data,
+                                                                     p->vsize,
+                                                                     p->data + voffset);
             }
             if(pContext->EffectType == LVM_VIRTUALIZER){
               // Warning this log will fail to properly read an int32_t value, assumes int16_t
@@ -3442,13 +3623,9 @@
                             "EFFECT_CMD_SET_PARAM: ERROR");
                     return -EINVAL;
                 }
-                effect_param_t *p = (effect_param_t *) pCmdData;
 
-                if (p->psize != sizeof(int32_t)){
-                    ALOGV("\tLVM_ERROR : Virtualizer_command cmdCode Case: "
-                            "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
-                    return -EINVAL;
-                }
+                effect_param_t * const p = (effect_param_t *) pCmdData;
+                const uint32_t voffset = computeParamVOffset(p);
 
                 //ALOGV("\tnVirtualizer_command cmdSize is %d\n"
                 //        "\tsizeof(effect_param_t) is  %d\n"
@@ -3458,8 +3635,10 @@
                 //        cmdSize, sizeof(effect_param_t), p->psize, p->vsize );
 
                 *(int *)pReplyData = android::Virtualizer_setParameter(pContext,
-                                                                      (void *)p->data,
-                                                                       p->data + p->psize);
+                                                                       p->psize,
+                                                                       (void *)p->data,
+                                                                       p->vsize,
+                                                                       p->data + voffset);
             }
             if(pContext->EffectType == LVM_EQUALIZER){
                //ALOGV("\tEqualizer_command cmdCode Case: "
@@ -3475,12 +3654,15 @@
                             "EFFECT_CMD_SET_PARAM: ERROR");
                     return -EINVAL;
                 }
-                effect_param_t *p = (effect_param_t *) pCmdData;
+
+                effect_param_t * const p = (effect_param_t *) pCmdData;
+                const uint32_t voffset = computeParamVOffset(p);
 
                 *(int *)pReplyData = android::Equalizer_setParameter(pContext,
-                                                                    (void *)p->data,
-                                                                    p->vsize,
-                                                                    p->data + p->psize);
+                                                                     p->psize,
+                                                                     (void *)p->data,
+                                                                     p->vsize,
+                                                                     p->data + voffset);
             }
             if(pContext->EffectType == LVM_VOLUME){
                 //ALOGV("\tVolume_command cmdCode Case: EFFECT_CMD_SET_PARAM start");
@@ -3497,11 +3679,15 @@
                             "EFFECT_CMD_SET_PARAM: ERROR");
                     return -EINVAL;
                 }
-                effect_param_t *p = (effect_param_t *) pCmdData;
+
+                effect_param_t * const p = (effect_param_t *) pCmdData;
+                const uint32_t voffset = computeParamVOffset(p);
 
                 *(int *)pReplyData = android::Volume_setParameter(pContext,
-                                                                 (void *)p->data,
-                                                                 p->data + p->psize);
+                                                                  p->psize,
+                                                                  (void *)p->data,
+                                                                  p->vsize,
+                                                                  p->data + voffset);
             }
             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_PARAM end");
         } break;
@@ -3648,10 +3834,10 @@
             if(rightdB > maxdB){
                 maxdB = rightdB;
             }
-            //ALOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB (%d), "
+            //ALOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB, "
             //      "effect is %d",
             //pContext->pBundledContext->SessionNo, pContext->pBundledContext->SessionId,
-            //(int32_t)maxdB, maxVol<<7, pContext->EffectType);
+            //(int32_t)maxdB, pContext->EffectType);
             //ALOGV("\tEFFECT_CMD_SET_VOLUME: Left is %d, Right is %d", leftVolume, rightVolume);
             //ALOGV("\tEFFECT_CMD_SET_VOLUME: Left %ddB, Right %ddB, Position %ddB",
             //        leftdB, rightdB, pandB);
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index cad89fd..291383a 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -213,7 +213,7 @@
 static const float LimitLevel_bassBoostEnergyCrossCoefficient[FIVEBAND_NUMBANDS] = {
         221.21, 208.10, 28.16, 0.0, 0.0 };
 
-static const float LimitLevel_bassBoostEnergyCoefficient = 7.12;
+static const float LimitLevel_bassBoostEnergyCoefficient = 9.00;
 
 static const float LimitLevel_virtualizerContribution = 1.9;
 
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 1717b49..ee9406d 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -429,9 +429,7 @@
     size_t ii;
     LVM_INT32 temp;
 
-    src += n-1;
-    dst += n-1;
-    for (ii = n; ii != 0; ii--) {
+    for (ii = 0; ii < n; ii++) {
         temp = (LVM_INT32)((*src) * 32768.0f);
         if (temp >= 32767) {
             *dst = 32767;
@@ -440,8 +438,8 @@
         } else {
             *dst = (LVM_INT16)temp;
         }
-        src--;
-        dst--;
+        src++;
+        dst++;
     }
     return;
 }
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index 115baff..4b131a7 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -401,6 +401,10 @@
                 videoFrame->getFlattenedIccData());
     }
     mFrameDecoded = true;
+
+    // Aggressive clear to avoid holding on to resources
+    mRetriever.clear();
+    mDataSource.clear();
     return true;
 }
 
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 12242b3..93656a8 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -63,18 +63,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 +77,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",
     ],
@@ -137,7 +129,6 @@
 
     srcs: [
         "IDataSource.cpp",
-        "IHDCP.cpp",
         "BufferingSettings.cpp",
         "mediaplayer.cpp",
         "IMediaHTTPConnection.cpp",
@@ -190,17 +181,8 @@
         "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",
     ],
 
     export_shared_lib_headers: [
@@ -209,9 +191,6 @@
         "libicuuc",
         "libicui18n",
         "libsonivox",
-        "libmediadrm",
-        "libmedia_helper",
-        "android.hidl.memory@1.0",
     ],
 
     // for memory heap analysis
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
index 2d62419..adfa93d 100644
--- a/media/libmedia/IMediaCodecService.cpp
+++ b/media/libmedia/IMediaCodecService.cpp
@@ -27,7 +27,8 @@
 namespace android {
 
 enum {
-    GET_OMX = IBinder::FIRST_CALL_TRANSACTION
+    GET_OMX = IBinder::FIRST_CALL_TRANSACTION,
+    GET_OMX_STORE
 };
 
 class BpMediaCodecService : public BpInterface<IMediaCodecService>
@@ -45,6 +46,13 @@
         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");
@@ -62,6 +70,12 @@
             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);
     }
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 19b00f3..3c43a72 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -38,7 +38,8 @@
     SETMEDIACAS,
     SETUID,
     NAME,
-    GETMETRICS
+    GETMETRICS,
+    RELEASE,
 };
 
 class BpMediaExtractor : public BpInterface<IMediaExtractor> {
@@ -138,6 +139,13 @@
         ALOGV("name NOT IMPLEMENTED");
         return NULL;
     }
+
+    virtual void release() {
+        ALOGV("release");
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+        remote()->transact(RELEASE, data, &reply);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
@@ -215,6 +223,12 @@
             reply->writeInt32(setMediaCas(casToken));
             return OK;
         }
+        case RELEASE: {
+            ALOGV("release");
+            CHECK_INTERFACE(IMediaExtractor, data, reply);
+            release();
+            return OK;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index cda3b3a..903e503 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -58,6 +58,7 @@
     GET_CURRENT_POSITION,
     GET_DURATION,
     RESET,
+    NOTIFY_AT,
     SET_AUDIO_STREAM_TYPE,
     SET_LOOPING,
     SET_VOLUME,
@@ -328,6 +329,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;
@@ -746,6 +756,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()));
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index a01852c..d135878 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>
@@ -40,7 +39,6 @@
     CREATE_MEDIA_RECORDER,
     CREATE_METADATA_RETRIEVER,
     GET_OMX,
-    MAKE_HDCP,
     ADD_BATTERY_DATA,
     PULL_BATTERY_DATA,
     LISTEN_FOR_REMOTE_DISPLAY,
@@ -90,14 +88,6 @@
         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());
@@ -167,13 +157,6 @@
             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/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index 2a74512..a570ffe 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -101,42 +101,46 @@
     return OK;
 }
 
-void MediaCodecInfo::CapabilitiesBuilder::addProfileLevel(uint32_t profile, uint32_t level) {
+void MediaCodecInfo::CapabilitiesWriter::addDetail(
+        const char* key, const char* value) {
+    mCap->mDetails->setString(key, value);
+}
+
+void MediaCodecInfo::CapabilitiesWriter::addDetail(
+        const char* key, int32_t value) {
+    mCap->mDetails->setInt32(key, value);
+}
+
+void MediaCodecInfo::CapabilitiesWriter::addProfileLevel(
+        uint32_t profile, uint32_t level) {
     ProfileLevel profileLevel;
     profileLevel.mProfile = profile;
     profileLevel.mLevel = level;
-    if (mProfileLevelsSorted.indexOf(profileLevel) < 0) {
-        mProfileLevels.push_back(profileLevel);
-        mProfileLevelsSorted.add(profileLevel);
+    if (mCap->mProfileLevelsSorted.indexOf(profileLevel) < 0) {
+        mCap->mProfileLevels.push_back(profileLevel);
+        mCap->mProfileLevelsSorted.add(profileLevel);
     }
 }
 
-void MediaCodecInfo::CapabilitiesBuilder::addColorFormat(uint32_t format) {
-    if (mColorFormatsSorted.indexOf(format) < 0) {
-        mColorFormats.push(format);
-        mColorFormatsSorted.add(format);
+void MediaCodecInfo::CapabilitiesWriter::addColorFormat(uint32_t format) {
+    if (mCap->mColorFormatsSorted.indexOf(format) < 0) {
+        mCap->mColorFormats.push(format);
+        mCap->mColorFormatsSorted.add(format);
     }
 }
 
-void MediaCodecInfo::CapabilitiesBuilder::addFlags(uint32_t flags) {
-    mFlags |= flags;
+void MediaCodecInfo::CapabilitiesWriter::addFlags(uint32_t flags) {
+    mCap->mFlags |= flags;
+}
+
+MediaCodecInfo::CapabilitiesWriter::CapabilitiesWriter(
+        MediaCodecInfo::Capabilities* cap) : mCap(cap) {
 }
 
 bool MediaCodecInfo::isEncoder() const {
     return mIsEncoder;
 }
 
-bool MediaCodecInfo::hasQuirk(const char *name) const {
-    if (name) {
-        for (size_t ix = 0; ix < mQuirks.size(); ix++) {
-            if (mQuirks.itemAt(ix).equalsIgnoreCase(name)) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
 void MediaCodecInfo::getSupportedMimes(Vector<AString> *mimes) const {
     mimes->clear();
     for (size_t ix = 0; ix < mCaps.size(); ix++) {
@@ -157,20 +161,21 @@
     return mName.c_str();
 }
 
+const char *MediaCodecInfo::getOwnerName() const {
+    return mOwner.c_str();
+}
+
 // static
 sp<MediaCodecInfo> MediaCodecInfo::FromParcel(const Parcel &parcel) {
     AString name = AString::FromParcel(parcel);
+    AString owner = AString::FromParcel(parcel);
     bool isEncoder = static_cast<bool>(parcel.readInt32());
-    sp<MediaCodecInfo> info = new MediaCodecInfo(name, isEncoder, NULL);
+    sp<MediaCodecInfo> info = new MediaCodecInfo;
+    info->mName = name;
+    info->mOwner = owner;
+    info->mIsEncoder = isEncoder;
     size_t size = static_cast<size_t>(parcel.readInt32());
     for (size_t i = 0; i < size; i++) {
-        AString quirk = AString::FromParcel(parcel);
-        if (info != NULL) {
-            info->mQuirks.push_back(quirk);
-        }
-    }
-    size = static_cast<size_t>(parcel.readInt32());
-    for (size_t i = 0; i < size; i++) {
         AString mime = AString::FromParcel(parcel);
         sp<Capabilities> caps = Capabilities::FromParcel(parcel);
         if (caps == NULL)
@@ -184,11 +189,8 @@
 
 status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const {
     mName.writeToParcel(parcel);
+    mOwner.writeToParcel(parcel);
     parcel->writeInt32(mIsEncoder);
-    parcel->writeInt32(mQuirks.size());
-    for (size_t i = 0; i < mQuirks.size(); i++) {
-        mQuirks.itemAt(i).writeToParcel(parcel);
-    }
     parcel->writeInt32(mCaps.size());
     for (size_t i = 0; i < mCaps.size(); i++) {
         mCaps.keyAt(i).writeToParcel(parcel);
@@ -208,86 +210,46 @@
     return -1;
 }
 
-MediaCodecInfo::MediaCodecInfo(AString name, bool encoder, const char *mime)
-    : mName(name),
-      mIsEncoder(encoder),
-      mHasSoleMime(false) {
-    if (mime != NULL) {
-        addMime(mime);
-        mHasSoleMime = true;
-    }
+MediaCodecInfo::MediaCodecInfo() {
 }
 
-status_t MediaCodecInfo::addMime(const char *mime) {
-    if (mHasSoleMime) {
-        ALOGE("Codec '%s' already had its type specified", mName.c_str());
-        return -EINVAL;
-    }
-    ssize_t ix = getCapabilityIndex(mime);
+void MediaCodecInfoWriter::setName(const char* name) {
+    mInfo->mName = name;
+}
+
+void MediaCodecInfoWriter::setOwner(const char* owner) {
+    mInfo->mOwner = owner;
+}
+
+void MediaCodecInfoWriter::setEncoder(bool isEncoder) {
+    mInfo->mIsEncoder = isEncoder;
+}
+
+std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>
+        MediaCodecInfoWriter::addMime(const char *mime) {
+    ssize_t ix = mInfo->getCapabilityIndex(mime);
     if (ix >= 0) {
-        mCurrentCaps = mCaps.valueAt(ix);
-    } else {
-        mCurrentCaps = new Capabilities();
-        mCaps.add(AString(mime), mCurrentCaps);
+        return std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>(
+                new MediaCodecInfo::CapabilitiesWriter(
+                mInfo->mCaps.valueAt(ix).get()));
     }
-    return OK;
+    sp<MediaCodecInfo::Capabilities> caps = new MediaCodecInfo::Capabilities();
+    mInfo->mCaps.add(AString(mime), caps);
+    return std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>(
+            new MediaCodecInfo::CapabilitiesWriter(caps.get()));
 }
 
-status_t MediaCodecInfo::updateMime(const char *mime) {
-    ssize_t ix = getCapabilityIndex(mime);
-    if (ix < 0) {
-        ALOGE("updateMime mime not found %s", mime);
-        return -EINVAL;
-    }
-
-    mCurrentCaps = mCaps.valueAt(ix);
-    return OK;
-}
-
-void MediaCodecInfo::removeMime(const char *mime) {
-    ssize_t ix = getCapabilityIndex(mime);
+bool MediaCodecInfoWriter::removeMime(const char *mime) {
+    ssize_t ix = mInfo->getCapabilityIndex(mime);
     if (ix >= 0) {
-        mCaps.removeItemsAt(ix);
-        // mCurrentCaps will be removed when completed
+        mInfo->mCaps.removeItemsAt(ix);
+        return true;
     }
+    return false;
 }
 
-status_t MediaCodecInfo::initializeCapabilities(const sp<Capabilities> &caps) {
-    // TRICKY: copy data to mCurrentCaps as it is a reference to
-    // an element of the capabilites map.
-    mCurrentCaps->mColorFormats.clear();
-    mCurrentCaps->mColorFormats.appendVector(caps->mColorFormats);
-    mCurrentCaps->mProfileLevels.clear();
-    mCurrentCaps->mProfileLevels.appendVector(caps->mProfileLevels);
-    mCurrentCaps->mFlags = caps->mFlags;
-    mCurrentCaps->mDetails = caps->mDetails;
-    return OK;
-}
-
-void MediaCodecInfo::addQuirk(const char *name) {
-    if (!hasQuirk(name)) {
-        mQuirks.push(name);
-    }
-}
-
-void MediaCodecInfo::complete() {
-    mCurrentCaps = NULL;
-}
-
-void MediaCodecInfo::addDetail(const AString &key, const AString &value) {
-    mCurrentCaps->mDetails->setString(key.c_str(), value.c_str());
-}
-
-void MediaCodecInfo::addFeature(const AString &key, int32_t value) {
-    AString tag = "feature-";
-    tag.append(key);
-    mCurrentCaps->mDetails->setInt32(tag.c_str(), value);
-}
-
-void MediaCodecInfo::addFeature(const AString &key, const char *value) {
-    AString tag = "feature-";
-    tag.append(key);
-    mCurrentCaps->mDetails->setString(tag.c_str(), value);
+MediaCodecInfoWriter::MediaCodecInfoWriter(MediaCodecInfo* info) :
+    mInfo(info) {
 }
 
 }  // namespace android
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
index da3c5a03..59fb1c0 100644
--- a/media/libmedia/include/media/IMediaCodecService.h
+++ b/media/libmedia/include/media/IMediaCodecService.h
@@ -22,6 +22,7 @@
 #include <binder/Parcel.h>
 #include <media/IDataSource.h>
 #include <media/IOMX.h>
+#include <media/IOMXStore.h>
 
 namespace android {
 
@@ -31,6 +32,7 @@
     DECLARE_META_INTERFACE(MediaCodecService);
 
     virtual sp<IOMX> getOMX() = 0;
+    virtual sp<IOMXStore> getOMXStore() = 0;
 };
 
 class BnMediaCodecService: public BnInterface<IMediaCodecService>
diff --git a/media/libmedia/include/media/IMediaExtractor.h b/media/libmedia/include/media/IMediaExtractor.h
index 1e13b65..0ac7673 100644
--- a/media/libmedia/include/media/IMediaExtractor.h
+++ b/media/libmedia/include/media/IMediaExtractor.h
@@ -68,6 +68,8 @@
     virtual void setUID(uid_t uid)  = 0;
 
     virtual const char * name() = 0;
+
+    virtual void release() = 0;
 };
 
 
diff --git a/media/libmedia/include/media/IMediaPlayer.h b/media/libmedia/include/media/IMediaPlayer.h
index e657716..e181338 100644
--- a/media/libmedia/include/media/IMediaPlayer.h
+++ b/media/libmedia/include/media/IMediaPlayer.h
@@ -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;
diff --git a/media/libmedia/include/media/IMediaPlayerService.h b/media/libmedia/include/media/IMediaPlayerService.h
index f21bb3a..398a8c7 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;
@@ -50,7 +49,6 @@
     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/IOMXStore.h b/media/libmedia/include/media/IOMXStore.h
index f739c3b..628db70 100644
--- a/media/libmedia/include/media/IOMXStore.h
+++ b/media/libmedia/include/media/IOMXStore.h
@@ -27,11 +27,6 @@
 #include <vector>
 #include <string>
 
-/*
-#include <OMX_Core.h>
-#include <OMX_Video.h>
-*/
-
 namespace android {
 
 using hardware::media::omx::V1_0::IOmxStore;
diff --git a/media/libmedia/include/media/MediaCodecInfo.h b/media/libmedia/include/media/MediaCodecInfo.h
index ef641d2..ab2cd24 100644
--- a/media/libmedia/include/media/MediaCodecInfo.h
+++ b/media/libmedia/include/media/MediaCodecInfo.h
@@ -18,6 +18,7 @@
 
 #define MEDIA_CODEC_INFO_H_
 
+#include <android-base/macros.h>
 #include <binder/Parcel.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AString.h>
@@ -36,6 +37,9 @@
 
 typedef KeyedVector<AString, AString> CodecSettings;
 
+struct MediaCodecInfoWriter;
+struct MediaCodecListWriter;
+
 struct MediaCodecInfo : public RefBase {
     struct ProfileLevel {
         uint32_t mProfile;
@@ -45,6 +49,8 @@
         }
     };
 
+    struct CapabilitiesWriter;
+
     struct Capabilities : public RefBase {
         enum {
             // decoder flags
@@ -77,72 +83,191 @@
         static sp<Capabilities> FromParcel(const Parcel &parcel);
         status_t writeToParcel(Parcel *parcel) const;
 
-        DISALLOW_EVIL_CONSTRUCTORS(Capabilities);
+        DISALLOW_COPY_AND_ASSIGN(Capabilities);
 
         friend struct MediaCodecInfo;
+        friend struct MediaCodecInfoWriter;
+        friend struct CapabilitiesWriter;
     };
 
-    // Use a subclass to allow setting fields on construction without allowing
-    // to do the same throughout the framework.
-    struct CapabilitiesBuilder : public Capabilities {
+    /**
+     * This class is used for modifying information inside a `Capabilities`
+     * object. An object of type `CapabilitiesWriter` can be obtained by calling
+     * `MediaCodecInfoWriter::addMime()` or
+     * `MediaCodecInfoWriter::updateMime()`.
+     */
+    struct CapabilitiesWriter {
+        /**
+         * Add a key-value pair to the list of details. If the key already
+         * exists, the old value will be replaced.
+         *
+         * A pair added by this function will be accessible by
+         * `Capabilities::getDetails()`. Call `AMessage::getString()` with the
+         * same key to retrieve the value.
+         *
+         * @param key The key.
+         * @param value The string value.
+         */
+        void addDetail(const char* key, const char* value);
+        /**
+         * Add a key-value pair to the list of details. If the key already
+         * exists, the old value will be replaced.
+         *
+         * A pair added by this function will be accessible by
+         * `Capabilities::getDetails()`. Call `AMessage::getInt32()` with the
+         * same key to retrieve the value.
+         *
+         * @param key The key.
+         * @param value The `int32_t` value.
+         */
+        void addDetail(const char* key, int32_t value);
+        /**
+         * Add a profile-level pair. If this profile-level pair already exists,
+         * it will be ignored.
+         *
+         * @param profile The "profile" component.
+         * @param level The "level" component.
+         */
         void addProfileLevel(uint32_t profile, uint32_t level);
+        /**
+         * Add a color format. If this color format already exists, it will be
+         * ignored.
+         *
+         * @param format The color format.
+         */
         void addColorFormat(uint32_t format);
+        /**
+         * Add flags. The underlying operation is bitwise-or. In other words,
+         * bits that have already been set will be ignored.
+         *
+         * @param flags The additional flags.
+         */
         void addFlags(uint32_t flags);
+    private:
+        /**
+         * The associated `Capabilities` object.
+         */
+        Capabilities* mCap;
+        /**
+         * Construct a writer for the given `Capabilities` object.
+         *
+         * @param cap The `Capabilities` object to be written to.
+         */
+        CapabilitiesWriter(Capabilities* cap);
+
+        friend MediaCodecInfoWriter;
     };
 
     bool isEncoder() const;
-    bool hasQuirk(const char *name) const;
     void getSupportedMimes(Vector<AString> *mimes) const;
     const sp<Capabilities> getCapabilitiesFor(const char *mime) const;
     const char *getCodecName() const;
 
     /**
+     * Return the name of the service that hosts the codec. This value is not
+     * visible at the Java level.
+     *
+     * Currently, this is the "instance name" of the IOmx service.
+     */
+    const char *getOwnerName() const;
+
+    /**
      * Serialization over Binder
      */
     static sp<MediaCodecInfo> FromParcel(const Parcel &parcel);
     status_t writeToParcel(Parcel *parcel) const;
 
 private:
-    // variable set only in constructor - these are accessed by MediaCodecList
-    // to avoid duplication of same variables
     AString mName;
+    AString mOwner;
     bool mIsEncoder;
-    bool mHasSoleMime; // was initialized with mime
-
-    Vector<AString> mQuirks;
     KeyedVector<AString, sp<Capabilities> > mCaps;
 
-    sp<Capabilities> mCurrentCaps; // currently initalized capabilities
-
     ssize_t getCapabilityIndex(const char *mime) const;
 
-    /* Methods used by MediaCodecList to construct the info
-     * object from XML.
-     *
-     * After info object is created:
-     * - additional quirks can be added
-     * - additional mimes can be added
-     *   - OMX codec capabilities can be set for the current mime-type
-     *   - a capability detail can be set for the current mime-type
-     *   - a feature can be set for the current mime-type
-     *   - info object can be completed when parsing of a mime-type is done
+    /**
+     * Construct an `MediaCodecInfo` object. After the construction, its
+     * information can be set via an `MediaCodecInfoWriter` object obtained from
+     * `MediaCodecListWriter::addMediaCodecInfo()`.
      */
-    MediaCodecInfo(AString name, bool encoder, const char *mime);
-    void addQuirk(const char *name);
-    status_t addMime(const char *mime);
-    status_t updateMime(const char *mime);
+    MediaCodecInfo();
 
-    status_t initializeCapabilities(const sp<Capabilities> &caps);
-    void addDetail(const AString &key, const AString &value);
-    void addFeature(const AString &key, int32_t value);
-    void addFeature(const AString &key, const char *value);
-    void removeMime(const char *mime);
-    void complete();
+    DISALLOW_COPY_AND_ASSIGN(MediaCodecInfo);
 
-    DISALLOW_EVIL_CONSTRUCTORS(MediaCodecInfo);
-
-    friend struct MediaCodecList;
     friend class MediaCodecListOverridesTest;
+    friend struct MediaCodecInfoWriter;
+    friend struct MediaCodecListWriter;
+};
+
+/**
+ * This class is to be used by a `MediaCodecListBuilderBase` instance to
+ * populate information inside the associated `MediaCodecInfo` object.
+ *
+ * The only place where an instance of `MediaCodecInfoWriter` can be constructed
+ * is `MediaCodecListWriter::addMediaCodecInfo()`. A `MediaCodecListBuilderBase`
+ * instance should call `MediaCodecListWriter::addMediaCodecInfo()` on the given
+ * `MediaCodecListWriter` object given as an input to
+ * `MediaCodecListBuilderBase::buildMediaCodecList()`.
+ */
+struct MediaCodecInfoWriter {
+    /**
+     * Set the name of the codec.
+     *
+     * @param name The new name.
+     */
+    void setName(const char* name);
+    /**
+     * Set the owner name of the codec.
+     *
+     * This "owner name" is the name of the `IOmx` instance that supports this
+     * codec.
+     *
+     * @param owner The new owner name.
+     */
+    void setOwner(const char* owner);
+    /**
+     * Set whether this codec is an encoder or a decoder.
+     *
+     * @param isEncoder Whether this codec is an encoder or a decoder.
+     */
+    void setEncoder(bool isEncoder = true);
+    /**
+     * Add a mime to an indexed list and return a `CapabilitiesWriter` object
+     * that can be used for modifying the associated `Capabilities`.
+     *
+     * If the mime already exists, this function will return the
+     * `CapabilitiesWriter` associated with the mime.
+     *
+     * @param[in] mime The name of a new mime to add.
+     * @return writer The `CapabilitiesWriter` object for modifying the
+     * `Capabilities` associated with the mime. `writer` will be valid
+     * regardless of whether `mime` already exists or not.
+     */
+    std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> addMime(
+            const char* mime);
+    /**
+     * Remove a mime.
+     *
+     * @param mime The name of the mime to remove.
+     * @return `true` if `mime` is removed; `false` if `mime` is not found.
+     */
+    bool removeMime(const char* mime);
+private:
+    /**
+     * The associated `MediaCodecInfo`.
+     */
+    MediaCodecInfo* mInfo;
+    /**
+     * Construct the `MediaCodecInfoWriter` object associated with the given
+     * `MediaCodecInfo` object.
+     *
+     * @param info The underlying `MediaCodecInfo` object.
+     */
+    MediaCodecInfoWriter(MediaCodecInfo* info);
+
+    DISALLOW_COPY_AND_ASSIGN(MediaCodecInfoWriter);
+
+    friend struct MediaCodecListWriter;
 };
 
 }  // namespace android
diff --git a/media/libmedia/include/media/mediaplayer.h b/media/libmedia/include/media/mediaplayer.h
index cb0a99f..25741d3 100644
--- a/media/libmedia/include/media/mediaplayer.h
+++ b/media/libmedia/include/media/mediaplayer.h
@@ -50,6 +50,7 @@
     MEDIA_PAUSED            = 7,
     MEDIA_STOPPED           = 8,
     MEDIA_SKIPPED           = 9,
+    MEDIA_NOTIFY_TIME       = 98,
     MEDIA_TIMED_TEXT        = 99,
     MEDIA_ERROR             = 100,
     MEDIA_INFO              = 200,
@@ -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();
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/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 49101d1..00084c1 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -610,6 +610,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;
@@ -950,6 +959,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;
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 47a147e..31ac4e5 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -59,6 +59,7 @@
 MediaAnalyticsItem::MediaAnalyticsItem()
     : mPid(-1),
       mUid(-1),
+      mPkgVersionCode(0),
       mSessionID(MediaAnalyticsItem::SessionIDNone),
       mTimestamp(0),
       mFinalized(0),
@@ -70,6 +71,7 @@
 MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
     : mPid(-1),
       mUid(-1),
+      mPkgVersionCode(0),
       mSessionID(MediaAnalyticsItem::SessionIDNone),
       mTimestamp(0),
       mFinalized(0),
@@ -98,7 +100,7 @@
 
     // clean attributes
     // contents of the attributes
-    for (size_t i = 0 ; i < mPropSize; i++ ) {
+    for (size_t i = 0 ; i < mPropCount; i++ ) {
         clearProp(&mProps[i]);
     }
     // the attribute records themselves
@@ -298,7 +300,8 @@
         clearProp(prop);
         if (i != mPropCount-1) {
             // in the middle, bring last one down to fill gap
-            mProps[i] = mProps[mPropCount-1];
+            copyProp(prop, &mProps[mPropCount-1]);
+            clearProp(&mProps[mPropCount-1]);
         }
         mPropCount--;
         return true;
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 1fc74a9..614a942 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -8,12 +8,10 @@
 
 LOCAL_SRC_FILES:=               \
     ActivityManager.cpp         \
-    HDCP.cpp                    \
     MediaPlayerFactory.cpp      \
     MediaPlayerService.cpp      \
     MediaRecorderClient.cpp     \
     MetadataRetrieverClient.cpp \
-    RemoteDisplay.cpp           \
     StagefrightRecorder.cpp     \
     TestPlayerStub.cpp          \
 
@@ -35,7 +33,6 @@
     libstagefright_foundation   \
     libstagefright_httplive     \
     libstagefright_omx          \
-    libstagefright_wfd          \
     libutils                    \
     libnativewindow             \
     libhidlbase                 \
@@ -51,7 +48,6 @@
 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                             \
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/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index ba98f18..44ab5da 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -79,9 +79,7 @@
 
 #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;
@@ -349,18 +347,13 @@
     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
@@ -1269,6 +1262,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);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 25691f9..d62dd52 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -229,7 +229,6 @@
 
     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);
@@ -327,6 +326,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);
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/include/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h
index bcdca37..764df70 100644
--- a/media/libmediaplayerservice/include/MediaPlayerInterface.h
+++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h
@@ -225,6 +225,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/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index e0d253d..45a5f27 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -31,6 +31,7 @@
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.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>
@@ -51,7 +52,8 @@
 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),
@@ -65,10 +67,12 @@
       mIsStreaming(false),
       mUIDValid(uidValid),
       mUID(uid),
+      mMediaClock(mediaClock),
       mFd(-1),
       mBitrate(-1ll),
       mPendingReadBufferTypes(0) {
     ALOGV("GenericSource");
+    CHECK(mediaClock != NULL);
 
     mBufferingMonitor = new BufferingMonitor(notify);
     resetDataSource();
@@ -729,17 +733,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 +778,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);
     }
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 4064133..381bcac 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -35,12 +35,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,
@@ -227,6 +229,7 @@
     bool mIsStreaming;
     bool mUIDValid;
     uid_t mUID;
+    const sp<MediaClock> mMediaClock;
     sp<IMediaHTTPService> mHTTPService;
     AString mUri;
     KeyedVector<String8, String8> mUriHeaders;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 274f613..29b1781 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -281,7 +281,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);
 
@@ -304,7 +304,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());
@@ -325,7 +325,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) {
@@ -473,6 +473,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);
@@ -1315,6 +1322,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;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 5e3c48b..eefc2a6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -73,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(
@@ -140,6 +143,7 @@
         kWhatClosedCaptionNotify        = 'capN',
         kWhatRendererNotify             = 'renN',
         kWhatReset                      = 'rset',
+        kWhatNotifyTime                 = 'nfyT',
         kWhatSeek                       = 'seek',
         kWhatPause                      = 'paus',
         kWhatResume                     = 'rsme',
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 19281cd..4005be8 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -78,6 +78,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();
@@ -662,6 +664,11 @@
     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;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index b797ca1..666359a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -65,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);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 323b52d..50db4c9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -549,8 +549,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.
@@ -1153,7 +1155,18 @@
             return writtenAudioDurationUs - (mediaUs - mAudioFirstAnchorTimeMediaUs);
         }
     }
-    return writtenAudioDurationUs - mAudioSink->getPlayedOutDurationUs(nowUs);
+
+    const int64_t audioSinkPlayedUs = mAudioSink->getPlayedOutDurationUs(nowUs);
+    int64_t pendingUs = writtenAudioDurationUs - audioSinkPlayedUs;
+    if (pendingUs < 0) {
+        // This shouldn't happen unless the timestamp is stale.
+        ALOGW("%s: pendingUs %lld < 0, clamping to zero, potential resume after pause "
+                "writtenAudioDurationUs: %lld, audioSinkPlayedUs: %lld",
+                __func__, (long long)pendingUs,
+                (long long)writtenAudioDurationUs, (long long)audioSinkPlayedUs);
+        pendingUs = 0;
+    }
+    return pendingUs;
 }
 
 int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
@@ -1235,82 +1248,48 @@
         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;
+        }
+    }
+    if (!mHasAudio) {
+        // smooth out videos >= 10fps
+        mMediaClock->updateMaxTimeMedia(mediaTimeUs + 100000);
+    }
 
-    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;
 }
@@ -1344,6 +1323,7 @@
 
         realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
     }
+    realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
 
     bool tooLate = false;
 
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 7449aa7..30fb5fe 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -213,7 +213,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;
     }
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 8b1e1c3..9d90dbd 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -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 ec48561..c44e868 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -62,9 +62,6 @@
 #include "include/SharedMemoryBuffer.h"
 #include <media/stagefright/omx/OMXUtils.h>
 
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-
 namespace android {
 
 using binder::Status;
@@ -6344,19 +6341,10 @@
 
     CHECK(mCodec->mOMXNode == NULL);
 
-    OMXClient client;
-    bool trebleFlag;
-    if (client.connect(&trebleFlag) != OK) {
-        mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
-        return false;
-    }
-    mCodec->setTrebleFlag(trebleFlag);
-
-    sp<IOMX> omx = client.interface();
-
     sp<AMessage> notify = new AMessage(kWhatOMXDied, mCodec);
 
     Vector<AString> matchingCodecs;
+    Vector<AString> owners;
 
     AString mime;
 
@@ -6364,9 +6352,31 @@
     int32_t encoder = false;
     if (msg->findString("componentName", &componentName)) {
         sp<IMediaCodecList> list = MediaCodecList::getInstance();
-        if (list != NULL && list->findCodecByName(componentName.c_str()) >= 0) {
-            matchingCodecs.add(componentName);
+        if (list == nullptr) {
+            ALOGE("Unable to obtain MediaCodecList while "
+                    "attempting to create codec \"%s\"",
+                    componentName.c_str());
+            mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
+            return false;
         }
+        ssize_t index = list->findCodecByName(componentName.c_str());
+        if (index < 0) {
+            ALOGE("Unable to find codec \"%s\"",
+                    componentName.c_str());
+            mCodec->signalError(OMX_ErrorInvalidComponent, NAME_NOT_FOUND);
+            return false;
+        }
+        sp<MediaCodecInfo> info = list->getCodecInfo(index);
+        if (info == nullptr) {
+            ALOGE("Unexpected error (index out-of-bound) while "
+                    "retrieving information for codec \"%s\"",
+                    componentName.c_str());
+            mCodec->signalError(OMX_ErrorUndefined, UNKNOWN_ERROR);
+            return false;
+        }
+        matchingCodecs.add(info->getCodecName());
+        owners.add(info->getOwnerName() == nullptr ?
+                "default" : info->getOwnerName());
     } else {
         CHECK(msg->findString("mime", &mime));
 
@@ -6378,10 +6388,12 @@
                 mime.c_str(),
                 encoder, // createEncoder
                 0,       // flags
-                &matchingCodecs);
+                &matchingCodecs,
+                &owners);
     }
 
     sp<CodecObserver> observer = new CodecObserver;
+    sp<IOMX> omx;
     sp<IOMXNode> omxNode;
 
     status_t err = NAME_NOT_FOUND;
@@ -6389,6 +6401,14 @@
             ++matchIndex) {
         componentName = matchingCodecs[matchIndex];
 
+        OMXClient client;
+        bool trebleFlag;
+        if (client.connect(owners[matchIndex].c_str(), &trebleFlag) != OK) {
+            mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
+            return false;
+        }
+        omx = client.interface();
+
         pid_t tid = gettid();
         int prevPriority = androidGetThreadPriority(tid);
         androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
@@ -6396,6 +6416,7 @@
         androidSetThreadPriority(tid, prevPriority);
 
         if (err == OK) {
+            mCodec->setTrebleFlag(trebleFlag);
             break;
         } else {
             ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str());
@@ -8219,16 +8240,15 @@
 }
 
 status_t ACodec::queryCapabilities(
-        const AString &name, const AString &mime, bool isEncoder,
-        sp<MediaCodecInfo::Capabilities> *caps) {
-    (*caps).clear();
-    const char *role = GetComponentRole(isEncoder, mime.c_str());
+        const char* owner, const char* name, const char* mime, bool isEncoder,
+        MediaCodecInfo::CapabilitiesWriter* caps) {
+    const char *role = GetComponentRole(isEncoder, mime);
     if (role == NULL) {
         return BAD_VALUE;
     }
 
     OMXClient client;
-    status_t err = client.connect();
+    status_t err = client.connect(owner);
     if (err != OK) {
         return err;
     }
@@ -8237,7 +8257,7 @@
     sp<CodecObserver> observer = new CodecObserver;
     sp<IOMXNode> omxNode;
 
-    err = omx->allocateNode(name.c_str(), observer, &omxNode);
+    err = omx->allocateNode(name, observer, &omxNode);
     if (err != OK) {
         client.disconnect();
         return err;
@@ -8250,8 +8270,7 @@
         return err;
     }
 
-    sp<MediaCodecInfo::CapabilitiesBuilder> builder = new MediaCodecInfo::CapabilitiesBuilder();
-    bool isVideo = mime.startsWithIgnoreCase("video/");
+    bool isVideo = strncasecmp(mime, "video/", 6) == 0;
 
     if (isVideo) {
         OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
@@ -8266,22 +8285,22 @@
             if (err != OK) {
                 break;
             }
-            builder->addProfileLevel(param.eProfile, param.eLevel);
+            caps->addProfileLevel(param.eProfile, param.eLevel);
 
             // AVC components may not list the constrained profiles explicitly, but
             // decoders that support a profile also support its constrained version.
             // Encoders must explicitly support constrained profiles.
-            if (!isEncoder && mime.equalsIgnoreCase(MEDIA_MIMETYPE_VIDEO_AVC)) {
+            if (!isEncoder && strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) == 0) {
                 if (param.eProfile == OMX_VIDEO_AVCProfileHigh) {
-                    builder->addProfileLevel(OMX_VIDEO_AVCProfileConstrainedHigh, param.eLevel);
+                    caps->addProfileLevel(OMX_VIDEO_AVCProfileConstrainedHigh, param.eLevel);
                 } else if (param.eProfile == OMX_VIDEO_AVCProfileBaseline) {
-                    builder->addProfileLevel(OMX_VIDEO_AVCProfileConstrainedBaseline, param.eLevel);
+                    caps->addProfileLevel(OMX_VIDEO_AVCProfileConstrainedBaseline, param.eLevel);
                 }
             }
 
             if (index == kMaxIndicesToCheck) {
                 ALOGW("[%s] stopping checking profiles after %u: %x/%x",
-                        name.c_str(), index,
+                        name, index,
                         param.eProfile, param.eLevel);
             }
         }
@@ -8305,17 +8324,17 @@
             if (IsFlexibleColorFormat(
                     omxNode, portFormat.eColorFormat, false /* usingNativeWindow */,
                     &flexibleEquivalent)) {
-                builder->addColorFormat(flexibleEquivalent);
+                caps->addColorFormat(flexibleEquivalent);
             }
-            builder->addColorFormat(portFormat.eColorFormat);
+            caps->addColorFormat(portFormat.eColorFormat);
 
             if (index == kMaxIndicesToCheck) {
                 ALOGW("[%s] stopping checking formats after %u: %s(%x)",
-                        name.c_str(), index,
+                        name, index,
                         asString(portFormat.eColorFormat), portFormat.eColorFormat);
             }
         }
-    } else if (mime.equalsIgnoreCase(MEDIA_MIMETYPE_AUDIO_AAC)) {
+    } else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC) == 0) {
         // More audio codecs if they have profiles.
         OMX_AUDIO_PARAM_ANDROID_PROFILETYPE param;
         InitOMXParams(&param);
@@ -8329,11 +8348,11 @@
                 break;
             }
             // For audio, level is ignored.
-            builder->addProfileLevel(param.eProfile, 0 /* level */);
+            caps->addProfileLevel(param.eProfile, 0 /* level */);
 
             if (index == kMaxIndicesToCheck) {
                 ALOGW("[%s] stopping checking profiles after %u: %x",
-                        name.c_str(), index,
+                        name, index,
                         param.eProfile);
             }
         }
@@ -8341,7 +8360,7 @@
         // NOTE: Without Android extensions, OMX does not provide a way to query
         // AAC profile support
         if (param.nProfileIndex == 0) {
-            ALOGW("component %s doesn't support profile query.", name.c_str());
+            ALOGW("component %s doesn't support profile query.", name);
         }
     }
 
@@ -8350,14 +8369,14 @@
         if (omxNode->configureVideoTunnelMode(
                 kPortIndexOutput, OMX_TRUE, 0, &sidebandHandle) == OK) {
             // tunneled playback includes adaptive playback
-            builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback
+            caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback
                     | MediaCodecInfo::Capabilities::kFlagSupportsTunneledPlayback);
         } else if (omxNode->setPortMode(
                 kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer) == OK ||
                 omxNode->prepareForAdaptivePlayback(
                 kPortIndexOutput, OMX_TRUE,
                 1280 /* width */, 720 /* height */) == OK) {
-            builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback);
+            caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback);
         }
     }
 
@@ -8369,11 +8388,10 @@
         if (omxNode->getConfig(
                 (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh,
                 &params, sizeof(params)) == OK) {
-            builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsIntraRefresh);
+            caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsIntraRefresh);
         }
     }
 
-    *caps = builder;
     omxNode->freeNode();
     client.disconnect();
     return OK;
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 2892520..8b4d14d 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -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;
     }
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 961b57f..f53d7f0 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -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/Android.bp b/media/libstagefright/Android.bp
index 130992a..5481ae0 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -19,6 +19,7 @@
         "BufferImpl.cpp",
         "CodecBase.cpp",
         "CallbackDataSource.cpp",
+        "CallbackMediaSource.cpp",
         "CameraSource.cpp",
         "CameraSourceTimeLapse.cpp",
         "DataConverter.cpp",
@@ -51,7 +52,10 @@
         "NuCachedSource2.cpp",
         "NuMediaExtractor.cpp",
         "OMXClient.cpp",
+        "OmxInfoBuilder.cpp",
         "OggExtractor.cpp",
+        "RemoteMediaExtractor.cpp",
+        "RemoteMediaSource.cpp",
         "SampleIterator.cpp",
         "SampleTable.cpp",
         "SimpleDecodingSource.cpp",
@@ -77,7 +81,6 @@
         "libcutils",
         "libdl",
         "libdrmframework",
-        "libexpat",
         "libgui",
         "liblog",
         "libmedia",
@@ -89,19 +92,15 @@
         "libui",
         "libutils",
         "libvorbisidec",
-        "libmediadrm",
-        "libnativewindow",
-
         "libmedia_helper",
+        "libstagefright_omx_utils",
         "libstagefright_flacdec",
         "libstagefright_foundation",
-        "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",
@@ -114,7 +113,6 @@
         "libstagefright_aacenc",
         "libstagefright_matroska",
         "libstagefright_mediafilter",
-        "libstagefright_omx_utils",
         "libstagefright_webm",
         "libstagefright_timedtext",
         "libvpx",
@@ -124,9 +122,12 @@
         "libFLAC",
     ],
 
-    export_shared_lib_headers: ["libmedia"],
+    export_shared_lib_headers: [
+        "libmedia",
+        "android.hidl.allocator@1.0",
+    ],
+
     export_include_dirs: [
-        ".",
         "include",
     ],
 
@@ -173,6 +174,5 @@
     "tests",
     "timedtext",
     "webm",
-    "wifi-display",
     "xmlparser",
 ]
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index b3fb8d4..1d441eb 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -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/CallbackMediaSource.cpp b/media/libstagefright/CallbackMediaSource.cpp
new file mode 100644
index 0000000..cc7147e
--- /dev/null
+++ b/media/libstagefright/CallbackMediaSource.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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>
+
+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 MediaSource::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/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp
index 1b88e5d..99315d6 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/libstagefright/FLACExtractor.cpp
@@ -811,7 +811,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;
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 22df522..2c696e5 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -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;
     }
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index 03ea959..7ed8fce 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -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/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 6f59fac..cef4945 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -354,6 +354,10 @@
 }
 
 MPEG4Extractor::~MPEG4Extractor() {
+    release();
+}
+
+void MPEG4Extractor::release() {
     Track *track = mFirstTrack;
     while (track) {
         Track *next = track->next;
@@ -375,6 +379,12 @@
     for (size_t i = 0; i < mPssh.size(); i++) {
         delete [] mPssh[i].data;
     }
+    mPssh.clear();
+
+    if (mDataSource != NULL) {
+        mDataSource->close();
+        mDataSource.clear();
+    }
 }
 
 uint32_t MPEG4Extractor::flags() const {
@@ -431,6 +441,66 @@
         return NULL;
     }
 
+    int64_t duration;
+    int32_t samplerate;
+    if (track->has_elst && mHeaderTimescale != 0 &&
+            track->meta->findInt64(kKeyDuration, &duration) &&
+            track->meta->findInt32(kKeySampleRate, &samplerate)) {
+
+        track->has_elst = false;
+
+        if (track->elst_segment_duration > INT64_MAX) {
+            goto editlistoverflow;
+        }
+        int64_t segment_duration = track->elst_segment_duration;
+        int64_t media_time = track->elst_media_time;
+        int64_t halfscale = mHeaderTimescale / 2;
+
+        int64_t delay;
+        // delay = ((media_time * samplerate) + halfscale) / mHeaderTimescale;
+        if (__builtin_mul_overflow(media_time, samplerate, &delay) ||
+                __builtin_add_overflow(delay, halfscale, &delay) ||
+                (delay /= mHeaderTimescale, false) ||
+                delay > INT32_MAX ||
+                delay < INT32_MIN) {
+            goto editlistoverflow;
+        }
+        track->meta->setInt32(kKeyEncoderDelay, delay);
+
+        int64_t scaled_duration;
+        // scaled_duration = ((duration * mHeaderTimescale) + 500000) / 1000000;
+        if (__builtin_mul_overflow(duration, mHeaderTimescale, &scaled_duration) ||
+                __builtin_add_overflow(scaled_duration, 500000, &scaled_duration)) {
+            goto editlistoverflow;
+        }
+        scaled_duration /= 1000000;
+
+        int64_t segment_end;
+        int64_t padding;
+        if (__builtin_add_overflow(segment_duration, media_time, &segment_end) ||
+                __builtin_sub_overflow(scaled_duration, segment_end, &padding)) {
+            goto editlistoverflow;
+        }
+
+        if (padding < 0) {
+            // track duration from media header (which is what kKeyDuration is) might
+            // be slightly shorter than the segment duration, which would make the
+            // padding negative. Clamp to zero.
+            padding = 0;
+        }
+
+        int64_t paddingsamples;
+        // paddingsamples = ((padding * samplerate) + halfscale) / mHeaderTimescale;
+        if (__builtin_mul_overflow(padding, samplerate, &paddingsamples) ||
+                __builtin_add_overflow(paddingsamples, halfscale, &paddingsamples) ||
+                (paddingsamples /= mHeaderTimescale, false) ||
+                paddingsamples > INT32_MAX) {
+            goto editlistoverflow;
+        }
+        track->meta->setInt32(kKeyEncoderPadding, paddingsamples);
+    }
+    editlistoverflow:
+
     if ((flags & kIncludeExtensiveMetaData)
             && !track->includes_expensive_metadata) {
         track->includes_expensive_metadata = true;
@@ -980,6 +1050,7 @@
                 track->skipTrack = false;
                 track->timescale = 0;
                 track->meta->setCString(kKeyMIMEType, "application/octet-stream");
+                track->has_elst = false;
             }
 
             off64_t stop_offset = *offset + chunk_size;
@@ -1046,6 +1117,10 @@
         {
             *offset += chunk_size;
 
+            if (!mLastTrack) {
+                return ERROR_MALFORMED;
+            }
+
             // See 14496-12 8.6.6
             uint8_t version;
             if (mDataSource->readAt(data_offset, &version, 1) < 1) {
@@ -1060,8 +1135,6 @@
             if (entry_count != 1) {
                 // we only support a single entry at the moment, for gapless playback
                 ALOGW("ignoring edit list with %d entries", entry_count);
-            } else if (mHeaderTimescale == 0) {
-                ALOGW("ignoring edit list because timescale is 0");
             } else {
                 off64_t entriesoffset = data_offset + 8;
                 uint64_t segment_duration;
@@ -1085,31 +1158,12 @@
                     return ERROR_IO;
                 }
 
-                uint64_t halfscale = mHeaderTimescale / 2;
-                segment_duration = (segment_duration * 1000000 + halfscale)/ mHeaderTimescale;
-                media_time = (media_time * 1000000 + halfscale) / mHeaderTimescale;
-
-                int64_t duration;
-                int32_t samplerate;
-                if (!mLastTrack) {
-                    return ERROR_MALFORMED;
-                }
-                if (mLastTrack->meta->findInt64(kKeyDuration, &duration) &&
-                        mLastTrack->meta->findInt32(kKeySampleRate, &samplerate)) {
-
-                    int64_t delay = (media_time  * samplerate + 500000) / 1000000;
-                    mLastTrack->meta->setInt32(kKeyEncoderDelay, delay);
-
-                    int64_t paddingus = duration - (int64_t)(segment_duration + media_time);
-                    if (paddingus < 0) {
-                        // track duration from media header (which is what kKeyDuration is) might
-                        // be slightly shorter than the segment duration, which would make the
-                        // padding negative. Clamp to zero.
-                        paddingus = 0;
-                    }
-                    int64_t paddingsamples = (paddingus * samplerate + 500000) / 1000000;
-                    mLastTrack->meta->setInt32(kKeyEncoderPadding, paddingsamples);
-                }
+                // save these for later, because the elst atom might precede
+                // the atoms that actually gives us the duration and sample rate
+                // needed to calculate the padding and delay values
+                mLastTrack->has_elst = true;
+                mLastTrack->elst_media_time = media_time;
+                mLastTrack->elst_segment_duration = segment_duration;
             }
             break;
         }
@@ -3290,7 +3344,7 @@
     }
 }
 
-sp<IMediaSource> MPEG4Extractor::getTrack(size_t index) {
+sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
     status_t err;
     if ((err = readMetaData()) != OK) {
         return NULL;
@@ -3489,6 +3543,18 @@
         return ERROR_UNSUPPORTED;
     }
 
+    if (mLastTrack != NULL) {
+        uint32_t maxBitrate = 0;
+        uint32_t avgBitrate = 0;
+        esds.getBitRate(&maxBitrate, &avgBitrate);
+        if (maxBitrate > 0 && maxBitrate < INT32_MAX) {
+            mLastTrack->meta->setInt32(kKeyMaxBitRate, (int32_t)maxBitrate);
+        }
+        if (avgBitrate > 0 && avgBitrate < INT32_MAX) {
+            mLastTrack->meta->setInt32(kKeyBitRate, (int32_t)avgBitrate);
+        }
+    }
+
     const uint8_t *csd;
     size_t csd_size;
     if (esds.getCodecSpecificInfo(
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 7786c4d..8c121b3 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -100,7 +100,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();
 
@@ -271,7 +271,7 @@
 
     MPEG4Writer *mOwner;
     sp<MetaData> mMeta;
-    sp<IMediaSource> mSource;
+    sp<MediaSource> mSource;
     volatile bool mDone;
     volatile bool mPaused;
     volatile bool mResumed;
@@ -572,7 +572,7 @@
     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");
@@ -1626,7 +1626,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),
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 98d101a..759e42d 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -73,6 +73,13 @@
 static const char *kCodecCrypto = "android.media.mediacodec.crypto";   /* 0,1 */
 static const char *kCodecEncoder = "android.media.mediacodec.encoder"; /* 0,1 */
 
+static const char *kCodecBytesIn = "android.media.mediacodec.bytesin";  /* 0..n */
+static const char *kCodecProfile = "android.media.mediacodec.profile";  /* 0..n */
+static const char *kCodecLevel = "android.media.mediacodec.level";  /* 0..n */
+static const char *kCodecMaxWidth = "android.media.mediacodec.maxwidth";  /* 0..n */
+static const char *kCodecMaxHeight = "android.media.mediacodec.maxheight";  /* 0..n */
+static const char *kCodecError = "android.media.mediacodec.errcode";
+static const char *kCodecErrorState = "android.media.mediacodec.errstate";
 
 
 static int64_t getId(const sp<IResourceManagerClient> &client) {
@@ -429,22 +436,6 @@
 }
 
 // static
-status_t MediaCodec::QueryCapabilities(
-        const AString &name, const AString &mime, bool isEncoder,
-        sp<MediaCodecInfo::Capabilities> *caps /* nonnull */) {
-    // TRICKY: this method is used by MediaCodecList/Info during its
-    // initialization. As such, we cannot create a MediaCodec instance
-    // because that requires an initialized MediaCodecList.
-
-    sp<CodecBase> codec = GetCodecBase(name);
-    if (codec == NULL) {
-        return NAME_NOT_FOUND;
-    }
-
-    return codec->queryCapabilities(name, mime, isEncoder, caps);
-}
-
-// static
 sp<PersistentSurface> MediaCodec::CreatePersistentInputSurface() {
     OMXClient client;
     if (client.connect() != OK) {
@@ -476,6 +467,7 @@
       mFlags(0),
       mStickyError(OK),
       mSoftRenderer(NULL),
+      mAnalyticsItem(NULL),
       mResourceManagerClient(new ResourceManagerClient(this)),
       mResourceManagerService(new ResourceManagerServiceProxy(pid)),
       mBatteryStatNotified(false),
@@ -494,6 +486,18 @@
     } else {
         mUid = uid;
     }
+    initAnalyticsItem();
+}
+
+MediaCodec::~MediaCodec() {
+    CHECK_EQ(mState, UNINITIALIZED);
+    mResourceManagerService->removeResource(getId(mResourceManagerClient));
+
+    flushAnalyticsItem();
+}
+
+void MediaCodec::initAnalyticsItem() {
+    CHECK(mAnalyticsItem == NULL);
     // set up our new record, get a sessionID, put it into the in-progress list
     mAnalyticsItem = new MediaAnalyticsItem(kCodecKeyName);
     if (mAnalyticsItem != NULL) {
@@ -503,11 +507,9 @@
     }
 }
 
-MediaCodec::~MediaCodec() {
-    CHECK_EQ(mState, UNINITIALIZED);
-    mResourceManagerService->removeResource(getId(mResourceManagerClient));
-
-    if (mAnalyticsItem != NULL ) {
+void MediaCodec::flushAnalyticsItem() {
+    if (mAnalyticsItem != NULL) {
+        // don't log empty records
         if (mAnalyticsItem->count() > 0) {
             mAnalyticsItem->setFinalized(true);
             mAnalyticsItem->selfrecord();
@@ -700,10 +702,21 @@
         uint32_t flags) {
     sp<AMessage> msg = new AMessage(kWhatConfigure, this);
 
+    if (mAnalyticsItem != NULL) {
+        int32_t profile = 0;
+        if (format->findInt32("profile", &profile)) {
+            mAnalyticsItem->setInt32(kCodecProfile, profile);
+        }
+        int32_t level = 0;
+        if (format->findInt32("level", &level)) {
+            mAnalyticsItem->setInt32(kCodecLevel, level);
+        }
+    }
+
     if (mIsVideo) {
         format->findInt32("width", &mVideoWidth);
         format->findInt32("height", &mVideoHeight);
-        if (!format->findInt32(kCodecRotation, &mRotationDegrees)) {
+        if (!format->findInt32("rotation-degrees", &mRotationDegrees)) {
             mRotationDegrees = 0;
         }
 
@@ -711,6 +724,14 @@
             mAnalyticsItem->setInt32(kCodecWidth, mVideoWidth);
             mAnalyticsItem->setInt32(kCodecHeight, mVideoHeight);
             mAnalyticsItem->setInt32(kCodecRotation, mRotationDegrees);
+            int32_t maxWidth = 0;
+            if (format->findInt32("max-width", &maxWidth)) {
+                mAnalyticsItem->setInt32(kCodecMaxWidth, maxWidth);
+            }
+            int32_t maxHeight = 0;
+            if (format->findInt32("max-height", &maxHeight)) {
+                mAnalyticsItem->setInt32(kCodecMaxHeight, maxHeight);
+            }
         }
 
         // Prevent possible integer overflow in downstream code.
@@ -1417,6 +1438,12 @@
 
                         case CONFIGURING:
                         {
+                            if (actionCode == ACTION_CODE_FATAL) {
+                                mAnalyticsItem->setInt32(kCodecError, err);
+                                mAnalyticsItem->setInt32(kCodecErrorState, mState);
+                                flushAnalyticsItem();
+                                initAnalyticsItem();
+                            }
                             setState(actionCode == ACTION_CODE_FATAL ?
                                     UNINITIALIZED : INITIALIZED);
                             break;
@@ -1424,6 +1451,12 @@
 
                         case STARTING:
                         {
+                            if (actionCode == ACTION_CODE_FATAL) {
+                                mAnalyticsItem->setInt32(kCodecError, err);
+                                mAnalyticsItem->setInt32(kCodecErrorState, mState);
+                                flushAnalyticsItem();
+                                initAnalyticsItem();
+                            }
                             setState(actionCode == ACTION_CODE_FATAL ?
                                     UNINITIALIZED : CONFIGURED);
                             break;
@@ -1460,6 +1493,11 @@
                         case FLUSHING:
                         {
                             if (actionCode == ACTION_CODE_FATAL) {
+                                mAnalyticsItem->setInt32(kCodecError, err);
+                                mAnalyticsItem->setInt32(kCodecErrorState, mState);
+                                flushAnalyticsItem();
+                                initAnalyticsItem();
+
                                 setState(UNINITIALIZED);
                             } else {
                                 setState(
@@ -1488,6 +1526,10 @@
                                 setState(INITIALIZED);
                                 break;
                             default:
+                                mAnalyticsItem->setInt32(kCodecError, err);
+                                mAnalyticsItem->setInt32(kCodecErrorState, mState);
+                                flushAnalyticsItem();
+                                initAnalyticsItem();
                                 setState(UNINITIALIZED);
                                 break;
                             }
@@ -1592,6 +1634,19 @@
                     }
                     setState(CONFIGURED);
                     (new AMessage)->postReply(mReplyID);
+
+                    // augment our media metrics info, now that we know more things
+                    if (mAnalyticsItem != NULL) {
+                        sp<AMessage> format;
+                        if (mConfigureMsg != NULL &&
+                            mConfigureMsg->findMessage("format", &format)) {
+                                // format includes: mime
+                                AString mime;
+                                if (format->findString("mime", &mime)) {
+                                    mAnalyticsItem->setCString(kCodecMime, mime.c_str());
+                                }
+                            }
+                    }
                     break;
                 }
 
@@ -2817,6 +2872,9 @@
         Mutex::Autolock al(mBufferLock);
         info->mOwnedByClient = false;
         info->mData.clear();
+        if (mAnalyticsItem != NULL) {
+            mAnalyticsItem->addInt64(kCodecBytesIn, size);
+        }
     }
 
     return err;
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 1dcba29..32a9f0a 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -24,38 +24,37 @@
 
 #include <media/IMediaCodecList.h>
 #include <media/IMediaPlayerService.h>
-#include <media/IResourceManagerService.h>
+#include <media/IMediaCodecService.h>
 #include <media/MediaCodecInfo.h>
-#include <media/MediaResourcePolicy.h>
+#include <media/MediaDefs.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ACodec.h>
-#include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OmxInfoBuilder.h>
+#include <media/stagefright/omx/OMXUtils.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>
 
 namespace android {
 
-static Mutex sInitMutex;
+namespace {
 
-static bool parseBoolean(const char *s) {
-    if (!strcasecmp(s, "true") || !strcasecmp(s, "yes") || !strcasecmp(s, "y")) {
-        return true;
-    }
-    char *end;
-    unsigned long res = strtoul(s, &end, 10);
-    return *s != '\0' && *end == '\0' && res > 0;
-}
+Mutex sInitMutex;
 
-static bool isProfilingNeeded() {
+Mutex sRemoteInitMutex;
+
+constexpr const char* kProfilingResults =
+        MediaCodecsXmlParser::defaultProfilingResultsXmlPath;
+
+bool isProfilingNeeded() {
     int8_t value = property_get_bool("debug.stagefright.profilecodec", 0);
     if (value == 0) {
         return false;
@@ -78,6 +77,10 @@
     return profilingNeeded;
 }
 
+OmxInfoBuilder sOmxInfoBuilder;
+
+}  // unnamed namespace
+
 // static
 sp<IMediaCodecList> MediaCodecList::sCodecList;
 
@@ -86,42 +89,42 @@
     ALOGV("Enter profilerThreadWrapper.");
     remove(kProfilingResults);  // remove previous result so that it won't be loaded to
                                 // the new MediaCodecList
-    MediaCodecList *codecList = new MediaCodecList();
+    sp<MediaCodecList> codecList(new MediaCodecList(&sOmxInfoBuilder));
     if (codecList->initCheck() != OK) {
         ALOGW("Failed to create a new MediaCodecList, skipping codec profiling.");
-        delete codecList;
-        return NULL;
+        return nullptr;
     }
 
-    Vector<sp<MediaCodecInfo>> infos;
-    for (size_t i = 0; i < codecList->countCodecs(); ++i) {
-        infos.push_back(codecList->getCodecInfo(i));
-    }
+    const auto& infos = codecList->mCodecInfos;
     ALOGV("Codec profiling started.");
-    profileCodecs(infos);
+    profileCodecs(infos, kProfilingResults);
     ALOGV("Codec profiling completed.");
-    codecList->parseTopLevelXMLFile(kProfilingResults, true /* ignore_errors */);
+    codecList = new MediaCodecList(&sOmxInfoBuilder);
+    if (codecList->initCheck() != OK) {
+        ALOGW("Failed to parse profiling results.");
+        return nullptr;
+    }
 
     {
         Mutex::Autolock autoLock(sInitMutex);
         sCodecList = codecList;
     }
-    return NULL;
+    return nullptr;
 }
 
 // static
 sp<IMediaCodecList> MediaCodecList::getLocalInstance() {
     Mutex::Autolock autoLock(sInitMutex);
 
-    if (sCodecList == NULL) {
-        MediaCodecList *codecList = new MediaCodecList;
+    if (sCodecList == nullptr) {
+        MediaCodecList *codecList = new MediaCodecList(&sOmxInfoBuilder);
         if (codecList->initCheck() == OK) {
             sCodecList = codecList;
 
             if (isProfilingNeeded()) {
                 ALOGV("Codec profiling needed, will be run in separated thread.");
                 pthread_t profiler;
-                if (pthread_create(&profiler, NULL, profilerThreadWrapper, NULL) != 0) {
+                if (pthread_create(&profiler, nullptr, profilerThreadWrapper, nullptr) != 0) {
                     ALOGW("Failed to create thread for codec profiling.");
                 }
             }
@@ -134,8 +137,6 @@
     return sCodecList;
 }
 
-static Mutex sRemoteInitMutex;
-
 sp<IMediaCodecList> MediaCodecList::sRemoteList;
 
 sp<MediaCodecList::BinderDeathObserver> MediaCodecList::sBinderDeathObserver;
@@ -149,19 +150,19 @@
 // static
 sp<IMediaCodecList> MediaCodecList::getInstance() {
     Mutex::Autolock _l(sRemoteInitMutex);
-    if (sRemoteList == NULL) {
+    if (sRemoteList == nullptr) {
         sp<IBinder> binder =
             defaultServiceManager()->getService(String16("media.player"));
         sp<IMediaPlayerService> service =
             interface_cast<IMediaPlayerService>(binder);
-        if (service.get() != NULL) {
+        if (service.get() != nullptr) {
             sRemoteList = service->getCodecList();
-            if (sRemoteList != NULL) {
+            if (sRemoteList != nullptr) {
                 sBinderDeathObserver = new BinderDeathObserver();
                 binder->linkToDeath(sBinderDeathObserver.get());
             }
         }
-        if (sRemoteList == NULL) {
+        if (sRemoteList == nullptr) {
             // if failed to get remote list, create local list
             sRemoteList = getLocalInstance();
         }
@@ -169,175 +170,11 @@
     return sRemoteList;
 }
 
-// Treblized media codec list will be located in /odm/etc or /vendor/etc.
-static const char *kConfigLocationList[] =
-        {"/odm/etc", "/vendor/etc", "/etc"};
-static const int kConfigLocationListSize =
-        (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
-
-#define MEDIA_CODECS_CONFIG_FILE_PATH_MAX_LENGTH 128
-
-static bool findMediaCodecListFileFullPath(const char *file_name, char *out_path) {
-    for (int i = 0; i < kConfigLocationListSize; i++) {
-        snprintf(out_path,
-                 MEDIA_CODECS_CONFIG_FILE_PATH_MAX_LENGTH,
-                 "%s/%s",
-                 kConfigLocationList[i],
-                 file_name);
-        struct stat file_stat;
-        if (stat(out_path, &file_stat) == 0 && S_ISREG(file_stat.st_mode)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-MediaCodecList::MediaCodecList()
-    : mInitCheck(NO_INIT),
-      mUpdate(false),
-      mGlobalSettings(new AMessage()) {
-    char config_file_path[MEDIA_CODECS_CONFIG_FILE_PATH_MAX_LENGTH];
-    if (findMediaCodecListFileFullPath("media_codecs.xml", config_file_path)) {
-        parseTopLevelXMLFile(config_file_path);
-    }
-    if (findMediaCodecListFileFullPath("media_codecs_performance.xml",
-                                       config_file_path)) {
-        parseTopLevelXMLFile(config_file_path, true/* ignore_errors */);
-    }
-    parseTopLevelXMLFile(kProfilingResults, true/* ignore_errors */);
-}
-
-void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml, bool ignore_errors) {
-    // get href_base
-    const char *href_base_end = strrchr(codecs_xml, '/');
-    if (href_base_end != NULL) {
-        mHrefBase = AString(codecs_xml, href_base_end - codecs_xml + 1);
-    }
-
-    mInitCheck = OK; // keeping this here for safety
-    mCurrentSection = SECTION_TOPLEVEL;
-    mDepth = 0;
-
-    OMXClient client;
-    mInitCheck = client.connect();
-    if (mInitCheck != OK) {
-        return;  // this may fail if IMediaPlayerService is not available.
-    }
-    parseXMLFile(codecs_xml);
-
-    if (mInitCheck != OK) {
-        if (ignore_errors) {
-            mInitCheck = OK;
-            return;
-        }
-        mCodecInfos.clear();
-        return;
-    }
-
-    Vector<MediaResourcePolicy> policies;
-    AString value;
-    if (mGlobalSettings->findString(kPolicySupportsMultipleSecureCodecs, &value)) {
-        policies.push_back(
-                MediaResourcePolicy(
-                        String8(kPolicySupportsMultipleSecureCodecs),
-                        String8(value.c_str())));
-    }
-    if (mGlobalSettings->findString(kPolicySupportsSecureWithNonSecureCodec, &value)) {
-        policies.push_back(
-                MediaResourcePolicy(
-                        String8(kPolicySupportsSecureWithNonSecureCodec),
-                        String8(value.c_str())));
-    }
-    if (policies.size() > 0) {
-        sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder = sm->getService(String16("media.resource_manager"));
-        sp<IResourceManagerService> service = interface_cast<IResourceManagerService>(binder);
-        if (service == NULL) {
-            ALOGE("MediaCodecList: failed to get ResourceManagerService");
-        } else {
-            service->config(policies);
-        }
-    }
-
-    for (size_t i = mCodecInfos.size(); i > 0;) {
-        i--;
-        const MediaCodecInfo &info = *mCodecInfos.itemAt(i).get();
-        if (info.mCaps.size() == 0) {
-            // No types supported by this component???
-            ALOGW("Component %s does not support any type of media?",
-                  info.mName.c_str());
-
-            mCodecInfos.removeAt(i);
-#if LOG_NDEBUG == 0
-        } else {
-            for (size_t type_ix = 0; type_ix < info.mCaps.size(); ++type_ix) {
-                AString mime = info.mCaps.keyAt(type_ix);
-                const sp<MediaCodecInfo::Capabilities> &caps = info.mCaps.valueAt(type_ix);
-
-                ALOGV("%s codec info for %s: %s", info.mName.c_str(), mime.c_str(),
-                        caps->getDetails()->debugString().c_str());
-                ALOGV("    flags=%d", caps->getFlags());
-                {
-                    Vector<uint32_t> colorFormats;
-                    caps->getSupportedColorFormats(&colorFormats);
-                    AString nice;
-                    for (size_t ix = 0; ix < colorFormats.size(); ix++) {
-                        if (ix > 0) {
-                            nice.append(", ");
-                        }
-                        nice.append(colorFormats.itemAt(ix));
-                    }
-                    ALOGV("    colors=[%s]", nice.c_str());
-                }
-                {
-                    Vector<MediaCodecInfo::ProfileLevel> profileLevels;
-                    caps->getSupportedProfileLevels(&profileLevels);
-                    AString nice;
-                    for (size_t ix = 0; ix < profileLevels.size(); ix++) {
-                        if (ix > 0) {
-                            nice.append(", ");
-                        }
-                        const MediaCodecInfo::ProfileLevel &pl =
-                            profileLevels.itemAt(ix);
-                        nice.append(pl.mProfile);
-                        nice.append("/");
-                        nice.append(pl.mLevel);
-                    }
-                    ALOGV("    levels=[%s]", nice.c_str());
-                }
-                {
-                    AString quirks;
-                    for (size_t ix = 0; ix < info.mQuirks.size(); ix++) {
-                        if (ix > 0) {
-                            quirks.append(", ");
-                        }
-                        quirks.append(info.mQuirks[ix]);
-                    }
-                    ALOGV("    quirks=[%s]", quirks.c_str());
-                }
-            }
-#endif
-        }
-    }
-
-#if 0
-    for (size_t i = 0; i < mCodecInfos.size(); ++i) {
-        const CodecInfo &info = mCodecInfos.itemAt(i);
-
-        AString line = info.mName;
-        line.append(" supports ");
-        for (size_t j = 0; j < mTypes.size(); ++j) {
-            uint32_t value = mTypes.valueAt(j);
-
-            if (info.mTypes & (1ul << value)) {
-                line.append(mTypes.keyAt(j));
-                line.append(" ");
-            }
-        }
-
-        ALOGI("%s", line.c_str());
-    }
-#endif
+MediaCodecList::MediaCodecList(MediaCodecListBuilderBase* builder) {
+    mGlobalSettings = new AMessage();
+    mCodecInfos.clear();
+    MediaCodecListWriter writer(this);
+    mInitCheck = builder->buildMediaCodecList(&writer);
 }
 
 MediaCodecList::~MediaCodecList() {
@@ -347,531 +184,21 @@
     return mInitCheck;
 }
 
-void MediaCodecList::parseXMLFile(const char *path) {
-    FILE *file = fopen(path, "r");
-
-    if (file == NULL) {
-        ALOGW("unable to open media codecs configuration xml file: %s", path);
-        mInitCheck = NAME_NOT_FOUND;
-        return;
-    }
-
-    XML_Parser parser = ::XML_ParserCreate(NULL);
-    CHECK(parser != NULL);
-
-    ::XML_SetUserData(parser, this);
-    ::XML_SetElementHandler(
-            parser, StartElementHandlerWrapper, EndElementHandlerWrapper);
-
-    const int BUFF_SIZE = 512;
-    while (mInitCheck == OK) {
-        void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
-        if (buff == NULL) {
-            ALOGE("failed in call to XML_GetBuffer()");
-            mInitCheck = UNKNOWN_ERROR;
-            break;
-        }
-
-        int bytes_read = ::fread(buff, 1, BUFF_SIZE, file);
-        if (bytes_read < 0) {
-            ALOGE("failed in call to read");
-            mInitCheck = ERROR_IO;
-            break;
-        }
-
-        XML_Status status = ::XML_ParseBuffer(parser, bytes_read, bytes_read == 0);
-        if (status != XML_STATUS_OK) {
-            ALOGE("malformed (%s)", ::XML_ErrorString(::XML_GetErrorCode(parser)));
-            mInitCheck = ERROR_MALFORMED;
-            break;
-        }
-
-        if (bytes_read == 0) {
-            break;
-        }
-    }
-
-    ::XML_ParserFree(parser);
-
-    fclose(file);
-    file = NULL;
+MediaCodecListWriter::MediaCodecListWriter(MediaCodecList* list) :
+    mList(list) {
 }
 
-// static
-void MediaCodecList::StartElementHandlerWrapper(
-        void *me, const char *name, const char **attrs) {
-    static_cast<MediaCodecList *>(me)->startElementHandler(name, attrs);
+void MediaCodecListWriter::addGlobalSetting(
+        const char* key, const char* value) {
+    mList->mGlobalSettings->setString(key, value);
 }
 
-// static
-void MediaCodecList::EndElementHandlerWrapper(void *me, const char *name) {
-    static_cast<MediaCodecList *>(me)->endElementHandler(name);
-}
-
-status_t MediaCodecList::includeXMLFile(const char **attrs) {
-    const char *href = NULL;
-    size_t i = 0;
-    while (attrs[i] != NULL) {
-        if (!strcmp(attrs[i], "href")) {
-            if (attrs[i + 1] == NULL) {
-                return -EINVAL;
-            }
-            href = attrs[i + 1];
-            ++i;
-        } else {
-            return -EINVAL;
-        }
-        ++i;
-    }
-
-    // For security reasons and for simplicity, file names can only contain
-    // [a-zA-Z0-9_.] and must start with  media_codecs_ and end with .xml
-    for (i = 0; href[i] != '\0'; i++) {
-        if (href[i] == '.' || href[i] == '_' ||
-                (href[i] >= '0' && href[i] <= '9') ||
-                (href[i] >= 'A' && href[i] <= 'Z') ||
-                (href[i] >= 'a' && href[i] <= 'z')) {
-            continue;
-        }
-        ALOGE("invalid include file name: %s", href);
-        return -EINVAL;
-    }
-
-    AString filename = href;
-    if (!filename.startsWith("media_codecs_") ||
-        !filename.endsWith(".xml")) {
-        ALOGE("invalid include file name: %s", href);
-        return -EINVAL;
-    }
-    filename.insert(mHrefBase, 0);
-
-    parseXMLFile(filename.c_str());
-    return mInitCheck;
-}
-
-void MediaCodecList::startElementHandler(
-        const char *name, const char **attrs) {
-    if (mInitCheck != OK) {
-        return;
-    }
-
-    bool inType = true;
-
-    if (!strcmp(name, "Include")) {
-        mInitCheck = includeXMLFile(attrs);
-        if (mInitCheck == OK) {
-            mPastSections.push(mCurrentSection);
-            mCurrentSection = SECTION_INCLUDE;
-        }
-        ++mDepth;
-        return;
-    }
-
-    switch (mCurrentSection) {
-        case SECTION_TOPLEVEL:
-        {
-            if (!strcmp(name, "Decoders")) {
-                mCurrentSection = SECTION_DECODERS;
-            } else if (!strcmp(name, "Encoders")) {
-                mCurrentSection = SECTION_ENCODERS;
-            } else if (!strcmp(name, "Settings")) {
-                mCurrentSection = SECTION_SETTINGS;
-            }
-            break;
-        }
-
-        case SECTION_SETTINGS:
-        {
-            if (!strcmp(name, "Setting")) {
-                mInitCheck = addSettingFromAttributes(attrs);
-            }
-            break;
-        }
-
-        case SECTION_DECODERS:
-        {
-            if (!strcmp(name, "MediaCodec")) {
-                mInitCheck =
-                    addMediaCodecFromAttributes(false /* encoder */, attrs);
-
-                mCurrentSection = SECTION_DECODER;
-            }
-            break;
-        }
-
-        case SECTION_ENCODERS:
-        {
-            if (!strcmp(name, "MediaCodec")) {
-                mInitCheck =
-                    addMediaCodecFromAttributes(true /* encoder */, attrs);
-
-                mCurrentSection = SECTION_ENCODER;
-            }
-            break;
-        }
-
-        case SECTION_DECODER:
-        case SECTION_ENCODER:
-        {
-            if (!strcmp(name, "Quirk")) {
-                mInitCheck = addQuirk(attrs);
-            } else if (!strcmp(name, "Type")) {
-                mInitCheck = addTypeFromAttributes(attrs);
-                mCurrentSection =
-                    (mCurrentSection == SECTION_DECODER
-                            ? SECTION_DECODER_TYPE : SECTION_ENCODER_TYPE);
-            }
-        }
-        inType = false;
-        // fall through
-
-        case SECTION_DECODER_TYPE:
-        case SECTION_ENCODER_TYPE:
-        {
-            // ignore limits and features specified outside of type
-            bool outside = !inType && !mCurrentInfo->mHasSoleMime;
-            if (outside && (!strcmp(name, "Limit") || !strcmp(name, "Feature"))) {
-                ALOGW("ignoring %s specified outside of a Type", name);
-            } else if (!strcmp(name, "Limit")) {
-                mInitCheck = addLimit(attrs);
-            } else if (!strcmp(name, "Feature")) {
-                mInitCheck = addFeature(attrs);
-            }
-            break;
-        }
-
-        default:
-            break;
-    }
-
-    ++mDepth;
-}
-
-void MediaCodecList::endElementHandler(const char *name) {
-    if (mInitCheck != OK) {
-        return;
-    }
-
-    switch (mCurrentSection) {
-        case SECTION_SETTINGS:
-        {
-            if (!strcmp(name, "Settings")) {
-                mCurrentSection = SECTION_TOPLEVEL;
-            }
-            break;
-        }
-
-        case SECTION_DECODERS:
-        {
-            if (!strcmp(name, "Decoders")) {
-                mCurrentSection = SECTION_TOPLEVEL;
-            }
-            break;
-        }
-
-        case SECTION_ENCODERS:
-        {
-            if (!strcmp(name, "Encoders")) {
-                mCurrentSection = SECTION_TOPLEVEL;
-            }
-            break;
-        }
-
-        case SECTION_DECODER_TYPE:
-        case SECTION_ENCODER_TYPE:
-        {
-            if (!strcmp(name, "Type")) {
-                mCurrentSection =
-                    (mCurrentSection == SECTION_DECODER_TYPE
-                            ? SECTION_DECODER : SECTION_ENCODER);
-
-                mCurrentInfo->complete();
-            }
-            break;
-        }
-
-        case SECTION_DECODER:
-        {
-            if (!strcmp(name, "MediaCodec")) {
-                mCurrentSection = SECTION_DECODERS;
-                mCurrentInfo->complete();
-                mCurrentInfo = NULL;
-            }
-            break;
-        }
-
-        case SECTION_ENCODER:
-        {
-            if (!strcmp(name, "MediaCodec")) {
-                mCurrentSection = SECTION_ENCODERS;
-                mCurrentInfo->complete();;
-                mCurrentInfo = NULL;
-            }
-            break;
-        }
-
-        case SECTION_INCLUDE:
-        {
-            if (!strcmp(name, "Include") && mPastSections.size() > 0) {
-                mCurrentSection = mPastSections.top();
-                mPastSections.pop();
-            }
-            break;
-        }
-
-        default:
-            break;
-    }
-
-    --mDepth;
-}
-
-status_t MediaCodecList::addSettingFromAttributes(const char **attrs) {
-    const char *name = NULL;
-    const char *value = NULL;
-    const char *update = NULL;
-
-    size_t i = 0;
-    while (attrs[i] != NULL) {
-        if (!strcmp(attrs[i], "name")) {
-            if (attrs[i + 1] == NULL) {
-                return -EINVAL;
-            }
-            name = attrs[i + 1];
-            ++i;
-        } else if (!strcmp(attrs[i], "value")) {
-            if (attrs[i + 1] == NULL) {
-                return -EINVAL;
-            }
-            value = attrs[i + 1];
-            ++i;
-        } else if (!strcmp(attrs[i], "update")) {
-            if (attrs[i + 1] == NULL) {
-                return -EINVAL;
-            }
-            update = attrs[i + 1];
-            ++i;
-        } else {
-            return -EINVAL;
-        }
-
-        ++i;
-    }
-
-    if (name == NULL || value == NULL) {
-        return -EINVAL;
-    }
-
-    mUpdate = (update != NULL) && parseBoolean(update);
-    if (mUpdate != mGlobalSettings->contains(name)) {
-        return -EINVAL;
-    }
-
-    mGlobalSettings->setString(name, value);
-    return OK;
-}
-
-void MediaCodecList::setCurrentCodecInfo(bool encoder, const char *name, const char *type) {
-    for (size_t i = 0; i < mCodecInfos.size(); ++i) {
-        if (AString(name) == mCodecInfos[i]->getCodecName()) {
-            if (mCodecInfos[i]->getCapabilitiesFor(type) == NULL) {
-                ALOGW("Overrides with an unexpected mime %s", type);
-                // Create a new MediaCodecInfo (but don't add it to mCodecInfos) to hold the
-                // overrides we don't want.
-                mCurrentInfo = new MediaCodecInfo(name, encoder, type);
-            } else {
-                mCurrentInfo = mCodecInfos.editItemAt(i);
-                mCurrentInfo->updateMime(type);  // to set the current cap
-            }
-            return;
-        }
-    }
-    mCurrentInfo = new MediaCodecInfo(name, encoder, type);
-    // The next step involves trying to load the codec, which may
-    // fail.  Only list the codec if this succeeds.
-    // However, keep mCurrentInfo object around until parsing
-    // of full codec info is completed.
-    if (initializeCapabilities(type) == OK) {
-        mCodecInfos.push_back(mCurrentInfo);
-    }
-}
-
-status_t MediaCodecList::addMediaCodecFromAttributes(
-        bool encoder, const char **attrs) {
-    const char *name = NULL;
-    const char *type = NULL;
-    const char *update = NULL;
-
-    size_t i = 0;
-    while (attrs[i] != NULL) {
-        if (!strcmp(attrs[i], "name")) {
-            if (attrs[i + 1] == NULL) {
-                return -EINVAL;
-            }
-            name = attrs[i + 1];
-            ++i;
-        } else if (!strcmp(attrs[i], "type")) {
-            if (attrs[i + 1] == NULL) {
-                return -EINVAL;
-            }
-            type = attrs[i + 1];
-            ++i;
-        } else if (!strcmp(attrs[i], "update")) {
-            if (attrs[i + 1] == NULL) {
-                return -EINVAL;
-            }
-            update = attrs[i + 1];
-            ++i;
-        } else {
-            return -EINVAL;
-        }
-
-        ++i;
-    }
-
-    if (name == NULL) {
-        return -EINVAL;
-    }
-
-    mUpdate = (update != NULL) && parseBoolean(update);
-    ssize_t index = -1;
-    for (size_t i = 0; i < mCodecInfos.size(); ++i) {
-        if (AString(name) == mCodecInfos[i]->getCodecName()) {
-            index = i;
-        }
-    }
-    if (mUpdate != (index >= 0)) {
-        return -EINVAL;
-    }
-
-    if (index >= 0) {
-        // existing codec
-        mCurrentInfo = mCodecInfos.editItemAt(index);
-        if (type != NULL) {
-            // existing type
-            if (mCodecInfos[index]->getCapabilitiesFor(type) == NULL) {
-                return -EINVAL;
-            }
-            mCurrentInfo->updateMime(type);
-        }
-    } else {
-        // new codec
-        mCurrentInfo = new MediaCodecInfo(name, encoder, type);
-        // The next step involves trying to load the codec, which may
-        // fail.  Only list the codec if this succeeds.
-        // However, keep mCurrentInfo object around until parsing
-        // of full codec info is completed.
-        if (initializeCapabilities(type) == OK) {
-            mCodecInfos.push_back(mCurrentInfo);
-        }
-    }
-
-    return OK;
-}
-
-status_t MediaCodecList::initializeCapabilities(const char *type) {
-    if (type == NULL) {
-        return OK;
-    }
-
-    ALOGV("initializeCapabilities %s:%s",
-            mCurrentInfo->mName.c_str(), type);
-
-    sp<MediaCodecInfo::Capabilities> caps;
-    status_t err = MediaCodec::QueryCapabilities(
-            mCurrentInfo->mName,
-            type,
-            mCurrentInfo->mIsEncoder,
-            &caps);
-    if (err != OK) {
-        return err;
-    } else if (caps == NULL) {
-        ALOGE("MediaCodec::QueryCapabilities returned OK but no capabilities for '%s':'%s':'%s'",
-                mCurrentInfo->mName.c_str(), type,
-                mCurrentInfo->mIsEncoder ? "encoder" : "decoder");
-        return UNKNOWN_ERROR;
-    }
-
-    return mCurrentInfo->initializeCapabilities(caps);
-}
-
-status_t MediaCodecList::addQuirk(const char **attrs) {
-    const char *name = NULL;
-
-    size_t i = 0;
-    while (attrs[i] != NULL) {
-        if (!strcmp(attrs[i], "name")) {
-            if (attrs[i + 1] == NULL) {
-                return -EINVAL;
-            }
-            name = attrs[i + 1];
-            ++i;
-        } else {
-            return -EINVAL;
-        }
-
-        ++i;
-    }
-
-    if (name == NULL) {
-        return -EINVAL;
-    }
-
-    mCurrentInfo->addQuirk(name);
-    return OK;
-}
-
-status_t MediaCodecList::addTypeFromAttributes(const char **attrs) {
-    const char *name = NULL;
-    const char *update = NULL;
-
-    size_t i = 0;
-    while (attrs[i] != NULL) {
-        if (!strcmp(attrs[i], "name")) {
-            if (attrs[i + 1] == NULL) {
-                return -EINVAL;
-            }
-            name = attrs[i + 1];
-            ++i;
-        } else if (!strcmp(attrs[i], "update")) {
-            if (attrs[i + 1] == NULL) {
-                return -EINVAL;
-            }
-            update = attrs[i + 1];
-            ++i;
-        } else {
-            return -EINVAL;
-        }
-
-        ++i;
-    }
-
-    if (name == NULL) {
-        return -EINVAL;
-    }
-
-    bool isExistingType = (mCurrentInfo->getCapabilitiesFor(name) != NULL);
-    if (mUpdate != isExistingType) {
-        return -EINVAL;
-    }
-
-    status_t ret;
-    if (mUpdate) {
-        ret = mCurrentInfo->updateMime(name);
-    } else {
-        ret = mCurrentInfo->addMime(name);
-    }
-
-    if (ret != OK) {
-        return ret;
-    }
-
-    // The next step involves trying to load the codec, which may
-    // fail.  Handle this gracefully (by not reporting such mime).
-    if (!mUpdate && initializeCapabilities(name) != OK) {
-        mCurrentInfo->removeMime(name);
-    }
-    return OK;
+std::unique_ptr<MediaCodecInfoWriter>
+        MediaCodecListWriter::addMediaCodecInfo() {
+    sp<MediaCodecInfo> info = new MediaCodecInfo();
+    mList->mCodecInfos.push_back(info);
+    return std::unique_ptr<MediaCodecInfoWriter>(
+            new MediaCodecInfoWriter(info.get()));
 }
 
 // legacy method for non-advanced codecs
@@ -882,15 +209,15 @@
         "feature-tunneled-playback",
     };
 
-    size_t numCodecs = mCodecInfos.size();
-    for (; startIndex < numCodecs; ++startIndex) {
-        const MediaCodecInfo &info = *mCodecInfos.itemAt(startIndex).get();
+    size_t numCodecInfos = mCodecInfos.size();
+    for (; startIndex < numCodecInfos; ++startIndex) {
+        const MediaCodecInfo &info = *mCodecInfos[startIndex];
 
         if (info.isEncoder() != encoder) {
             continue;
         }
         sp<MediaCodecInfo::Capabilities> capabilities = info.getCapabilitiesFor(type);
-        if (capabilities == NULL) {
+        if (capabilities == nullptr) {
             continue;
         }
         const sp<AMessage> &details = capabilities->getDetails();
@@ -913,223 +240,9 @@
     return -ENOENT;
 }
 
-static status_t limitFoundMissingAttr(const AString &name, const char *attr, bool found = true) {
-    ALOGE("limit '%s' with %s'%s' attribute", name.c_str(),
-            (found ? "" : "no "), attr);
-    return -EINVAL;
-}
-
-static status_t limitError(const AString &name, const char *msg) {
-    ALOGE("limit '%s' %s", name.c_str(), msg);
-    return -EINVAL;
-}
-
-static status_t limitInvalidAttr(const AString &name, const char *attr, const AString &value) {
-    ALOGE("limit '%s' with invalid '%s' attribute (%s)", name.c_str(),
-            attr, value.c_str());
-    return -EINVAL;
-}
-
-status_t MediaCodecList::addLimit(const char **attrs) {
-    sp<AMessage> msg = new AMessage();
-
-    size_t i = 0;
-    while (attrs[i] != NULL) {
-        if (attrs[i + 1] == NULL) {
-            return -EINVAL;
-        }
-
-        // attributes with values
-        if (!strcmp(attrs[i], "name")
-                || !strcmp(attrs[i], "default")
-                || !strcmp(attrs[i], "in")
-                || !strcmp(attrs[i], "max")
-                || !strcmp(attrs[i], "min")
-                || !strcmp(attrs[i], "range")
-                || !strcmp(attrs[i], "ranges")
-                || !strcmp(attrs[i], "scale")
-                || !strcmp(attrs[i], "value")) {
-            msg->setString(attrs[i], attrs[i + 1]);
-            ++i;
-        } else {
-            return -EINVAL;
-        }
-        ++i;
-    }
-
-    AString name;
-    if (!msg->findString("name", &name)) {
-        ALOGE("limit with no 'name' attribute");
-        return -EINVAL;
-    }
-
-    // size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio,
-    // measured-frame-rate, measured-blocks-per-second: range
-    // quality: range + default + [scale]
-    // complexity: range + default
-    bool found;
-
-    if (name == "aspect-ratio" || name == "bitrate" || name == "block-count"
-            || name == "blocks-per-second" || name == "complexity"
-            || name == "frame-rate" || name == "quality" || name == "size"
-            || name == "measured-blocks-per-second" || name.startsWith("measured-frame-rate-")) {
-        AString min, max;
-        if (msg->findString("min", &min) && msg->findString("max", &max)) {
-            min.append("-");
-            min.append(max);
-            if (msg->contains("range") || msg->contains("value")) {
-                return limitError(name, "has 'min' and 'max' as well as 'range' or "
-                        "'value' attributes");
-            }
-            msg->setString("range", min);
-        } else if (msg->contains("min") || msg->contains("max")) {
-            return limitError(name, "has only 'min' or 'max' attribute");
-        } else if (msg->findString("value", &max)) {
-            min = max;
-            min.append("-");
-            min.append(max);
-            if (msg->contains("range")) {
-                return limitError(name, "has both 'range' and 'value' attributes");
-            }
-            msg->setString("range", min);
-        }
-
-        AString range, scale = "linear", def, in_;
-        if (!msg->findString("range", &range)) {
-            return limitError(name, "with no 'range', 'value' or 'min'/'max' attributes");
-        }
-
-        if ((name == "quality" || name == "complexity") ^
-                (found = msg->findString("default", &def))) {
-            return limitFoundMissingAttr(name, "default", found);
-        }
-        if (name != "quality" && msg->findString("scale", &scale)) {
-            return limitFoundMissingAttr(name, "scale");
-        }
-        if ((name == "aspect-ratio") ^ (found = msg->findString("in", &in_))) {
-            return limitFoundMissingAttr(name, "in", found);
-        }
-
-        if (name == "aspect-ratio") {
-            if (!(in_ == "pixels") && !(in_ == "blocks")) {
-                return limitInvalidAttr(name, "in", in_);
-            }
-            in_.erase(5, 1); // (pixel|block)-aspect-ratio
-            in_.append("-");
-            in_.append(name);
-            name = in_;
-        }
-        if (name == "quality") {
-            mCurrentInfo->addDetail("quality-scale", scale);
-        }
-        if (name == "quality" || name == "complexity") {
-            AString tag = name;
-            tag.append("-default");
-            mCurrentInfo->addDetail(tag, def);
-        }
-        AString tag = name;
-        tag.append("-range");
-        mCurrentInfo->addDetail(tag, range);
-    } else {
-        AString max, value, ranges;
-        if (msg->contains("default")) {
-            return limitFoundMissingAttr(name, "default");
-        } else if (msg->contains("in")) {
-            return limitFoundMissingAttr(name, "in");
-        } else if ((name == "channel-count" || name == "concurrent-instances") ^
-                (found = msg->findString("max", &max))) {
-            return limitFoundMissingAttr(name, "max", found);
-        } else if (msg->contains("min")) {
-            return limitFoundMissingAttr(name, "min");
-        } else if (msg->contains("range")) {
-            return limitFoundMissingAttr(name, "range");
-        } else if ((name == "sample-rate") ^
-                (found = msg->findString("ranges", &ranges))) {
-            return limitFoundMissingAttr(name, "ranges", found);
-        } else if (msg->contains("scale")) {
-            return limitFoundMissingAttr(name, "scale");
-        } else if ((name == "alignment" || name == "block-size") ^
-                (found = msg->findString("value", &value))) {
-            return limitFoundMissingAttr(name, "value", found);
-        }
-
-        if (max.size()) {
-            AString tag = "max-";
-            tag.append(name);
-            mCurrentInfo->addDetail(tag, max);
-        } else if (value.size()) {
-            mCurrentInfo->addDetail(name, value);
-        } else if (ranges.size()) {
-            AString tag = name;
-            tag.append("-ranges");
-            mCurrentInfo->addDetail(tag, ranges);
-        } else {
-            ALOGW("Ignoring unrecognized limit '%s'", name.c_str());
-        }
-    }
-    return OK;
-}
-
-status_t MediaCodecList::addFeature(const char **attrs) {
-    size_t i = 0;
-    const char *name = NULL;
-    int32_t optional = -1;
-    int32_t required = -1;
-    const char *value = NULL;
-
-    while (attrs[i] != NULL) {
-        if (attrs[i + 1] == NULL) {
-            return -EINVAL;
-        }
-
-        // attributes with values
-        if (!strcmp(attrs[i], "name")) {
-            name = attrs[i + 1];
-            ++i;
-        } else if (!strcmp(attrs[i], "optional") || !strcmp(attrs[i], "required")) {
-            int value = (int)parseBoolean(attrs[i + 1]);
-            if (!strcmp(attrs[i], "optional")) {
-                optional = value;
-            } else {
-                required = value;
-            }
-            ++i;
-        } else if (!strcmp(attrs[i], "value")) {
-            value = attrs[i + 1];
-            ++i;
-        } else {
-            return -EINVAL;
-        }
-        ++i;
-    }
-    if (name == NULL) {
-        ALOGE("feature with no 'name' attribute");
-        return -EINVAL;
-    }
-
-    if (optional == required && optional != -1) {
-        ALOGE("feature '%s' is both/neither optional and required", name);
-        return -EINVAL;
-    }
-
-    if ((optional != -1 || required != -1) && (value != NULL)) {
-        ALOGE("feature '%s' has both a value and optional/required attribute", name);
-        return -EINVAL;
-    }
-
-    if (value != NULL) {
-        mCurrentInfo->addFeature(name, value);
-    } else {
-        mCurrentInfo->addFeature(name, (required == 1) || (optional == 0));
-    }
-    return OK;
-}
-
 ssize_t MediaCodecList::findCodecByName(const char *name) const {
     for (size_t i = 0; i < mCodecInfos.size(); ++i) {
-        const MediaCodecInfo &info = *mCodecInfos.itemAt(i).get();
-
-        if (info.mName == name) {
+        if (strcmp(mCodecInfos[i]->getCodecName(), name) == 0) {
             return i;
         }
     }
@@ -1167,11 +280,15 @@
 
 //static
 void MediaCodecList::findMatchingCodecs(
-        const char *mime, bool encoder, uint32_t flags, Vector<AString> *matches) {
+        const char *mime, bool encoder, uint32_t flags,
+        Vector<AString> *matches, Vector<AString> *owners) {
     matches->clear();
+    if (owners != nullptr) {
+        owners->clear();
+    }
 
     const sp<IMediaCodecList> list = getInstance();
-    if (list == NULL) {
+    if (list == nullptr) {
         return;
     }
 
@@ -1187,45 +304,27 @@
         index = matchIndex + 1;
 
         const sp<MediaCodecInfo> info = list->getCodecInfo(matchIndex);
-        CHECK(info != NULL);
+        CHECK(info != nullptr);
         AString componentName = info->getCodecName();
 
         if ((flags & kHardwareCodecsOnly) && isSoftwareCodec(componentName)) {
             ALOGV("skipping SW codec '%s'", componentName.c_str());
         } else {
             matches->push(componentName);
+            if (owners != nullptr) {
+                owners->push(AString(info->getOwnerName()));
+            }
             ALOGV("matching '%s'", componentName.c_str());
         }
     }
 
-    if (flags & kPreferSoftwareCodecs || property_get_bool("debug.stagefright.swcodec", false)) {
+    if (flags & kPreferSoftwareCodecs ||
+            property_get_bool("debug.stagefright.swcodec", false)) {
         matches->sort(compareSoftwareCodecsFirst);
     }
 }
 
-// static
-uint32_t MediaCodecList::getQuirksFor(const char *componentName) {
-    const sp<IMediaCodecList> list = getInstance();
-    if (list == NULL) {
-        return 0;
-    }
-
-    ssize_t ix = list->findCodecByName(componentName);
-    if (ix < 0) {
-        return 0;
-    }
-
-    const sp<MediaCodecInfo> info = list->getCodecInfo(ix);
-
-    uint32_t quirks = 0;
-    if (info->hasQuirk("requires-allocate-on-input-ports")) {
-        quirks |= ACodec::kRequiresAllocateBufferOnInputPorts;
-    }
-    if (info->hasQuirk("requires-allocate-on-output-ports")) {
-        quirks |= ACodec::kRequiresAllocateBufferOnOutputPorts;
-    }
-
-    return quirks;
+MediaCodecListBuilderBase::~MediaCodecListBuilderBase() {
 }
 
 }  // namespace android
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index 095fc6a..6920e51 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -33,8 +33,6 @@
 
 namespace android {
 
-const char *kProfilingResults = "/data/misc/media/media_codecs_profiling_results.xml";
-
 AString getProfilingVersionString() {
     char val[PROPERTY_VALUE_MAX];
     if (property_get("ro.build.display.id", val, NULL) && (strlen(val) > 0)) {
@@ -205,24 +203,24 @@
     return true;
 }
 
-void profileCodecs(const Vector<sp<MediaCodecInfo>> &infos) {
+void profileCodecs(const std::vector<sp<MediaCodecInfo>> &infos,
+        const char* profilingResults) {
     CodecSettings global_results;
     KeyedVector<AString, CodecSettings> encoder_results;
     KeyedVector<AString, CodecSettings> decoder_results;
     profileCodecs(infos, &global_results, &encoder_results, &decoder_results);
-    exportResultsToXML(kProfilingResults, global_results, encoder_results, decoder_results);
+    exportResultsToXML(profilingResults, global_results, encoder_results, decoder_results);
 }
 
 void profileCodecs(
-        const Vector<sp<MediaCodecInfo>> &infos,
+        const std::vector<sp<MediaCodecInfo>> &infos,
         CodecSettings *global_results,
         KeyedVector<AString, CodecSettings> *encoder_results,
         KeyedVector<AString, CodecSettings> *decoder_results,
         bool forceToMeasure) {
     KeyedVector<AString, sp<MediaCodecInfo::Capabilities>> codecsNeedMeasure;
     AString supportMultipleSecureCodecs = "true";
-    for (size_t i = 0; i < infos.size(); ++i) {
-        const sp<MediaCodecInfo> info = infos[i];
+    for (const auto& info : infos) {
         AString name = info->getCodecName();
         if (name.startsWith("OMX.google.") ||
                 // TODO: reenable below codecs once fixed
diff --git a/media/libstagefright/MediaCodecListOverrides.h b/media/libstagefright/MediaCodecListOverrides.h
index d4bb225..4f8c2f5 100644
--- a/media/libstagefright/MediaCodecListOverrides.h
+++ b/media/libstagefright/MediaCodecListOverrides.h
@@ -23,12 +23,10 @@
 
 #include <utils/StrongPointer.h>
 #include <utils/KeyedVector.h>
+#include <vector>
 
 namespace android {
 
-extern const char *kProfilingVersionString;
-extern const char *kProfilingResults;
-
 struct MediaCodecInfo;
 
 AString getProfilingVersionString();
@@ -36,11 +34,12 @@
 bool splitString(const AString &s, const AString &delimiter, AString *s1, AString *s2);
 
 // profile codecs and save the result to xml file named kProfilingResults.
-void profileCodecs(const Vector<sp<MediaCodecInfo>> &infos);
+void profileCodecs(const std::vector<sp<MediaCodecInfo>> &infos,
+        const char* profilingResults);
 
 // profile codecs and save the result to global_results, encoder_results and decoder_results.
 void profileCodecs(
-        const Vector<sp<MediaCodecInfo>> &infos,
+        const std::vector<sp<MediaCodecInfo>> &infos,
         CodecSettings *global_results,
         KeyedVector<AString, CodecSettings> *encoder_results,
         KeyedVector<AString, CodecSettings> *decoder_results,
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index c91c82b..14e6251 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -43,7 +43,10 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/RemoteMediaExtractor.h>
+#include <media/IMediaExtractor.h>
 #include <media/IMediaExtractorService.h>
+#include <media/IMediaSource.h>
 #include <cutils/properties.h>
 #include <utils/String8.h>
 #include <private/android_filesystem_config.h>
@@ -92,6 +95,10 @@
     }
 }
 
+sp<IMediaExtractor> MediaExtractor::asIMediaExtractor() {
+    return RemoteMediaExtractor::wrap(sp<MediaExtractor>(this));
+}
+
 sp<MetaData> MediaExtractor::getMetaData() {
     return new MetaData;
 }
@@ -125,7 +132,8 @@
     if (!property_get_bool("media.stagefright.extractremote", true)) {
         // local extractor
         ALOGW("creating media extractor in calling process");
-        return CreateFromService(source, mime);
+        sp<MediaExtractor> extractor = CreateFromService(source, mime);
+        return (extractor.get() == nullptr) ? nullptr : extractor->asIMediaExtractor();
     } else {
         // remote extractor
         ALOGV("get service manager");
@@ -196,27 +204,27 @@
     }
 
     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);
+        // 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?
                 }
-                // what else is interesting and not already available?
-              }
-	  }
-       }
+            }
+        }
     }
 
     return ret;
diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
index a17757a..8b92a6b 100644
--- a/media/libstagefright/MediaSource.cpp
+++ b/media/libstagefright/MediaSource.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
+#include <media/stagefright/CallbackMediaSource.h>
 #include <media/stagefright/MediaSource.h>
+#include <media/stagefright/RemoteMediaSource.h>
 
 namespace android {
 
@@ -22,4 +24,16 @@
 
 MediaSource::~MediaSource() {}
 
+// static
+sp<MediaSource> MediaSource::CreateFromIMediaSource(const sp<IMediaSource> &source) {
+    if (source == nullptr) {
+        return nullptr;
+    }
+    return new CallbackMediaSource(source);
+}
+
+sp<IMediaSource> MediaSource::asIMediaSource() {
+    return RemoteMediaSource::wrap(sp<MediaSource>(this));
+}
+
 }  // namespace android
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/MidiExtractor.cpp b/media/libstagefright/MidiExtractor.cpp
index 7930bbb..89cfa3c 100644
--- a/media/libstagefright/MidiExtractor.cpp
+++ b/media/libstagefright/MidiExtractor.cpp
@@ -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;
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 5f9aa01..5f50e46 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -38,7 +38,7 @@
 }
 
 status_t OMXClient::connect() {
-    return connect(nullptr);
+    return connect("default", nullptr);
 }
 
 status_t OMXClient::connect(bool* trebleFlag) {
@@ -54,6 +54,19 @@
     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"));
@@ -73,9 +86,12 @@
     return OK;
 }
 
-status_t OMXClient::connectTreble() {
+status_t OMXClient::connectTreble(const char* name) {
     using namespace ::android::hardware::media::omx::V1_0;
-    sp<IOmx> tOmx = IOmx::getService("default");
+    if (name == nullptr) {
+        name = "default";
+    }
+    sp<IOmx> tOmx = IOmx::getService(name);
     if (tOmx.get() == nullptr) {
         ALOGE("Cannot obtain Treble IOmx.");
         return NO_INIT;
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 810b0d6..58467db 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -1123,6 +1123,7 @@
             mMeta->setData(kKeyVorbisInfo, 0, data, size);
             mMeta->setInt32(kKeySampleRate, mVi.rate);
             mMeta->setInt32(kKeyChannelCount, mVi.channels);
+            mMeta->setInt32(kKeyBitRate, mVi.bitrate_nominal);
 
             ALOGV("lower-bitrate = %ld", mVi.bitrate_lower);
             ALOGV("upper-bitrate = %ld", mVi.bitrate_upper);
@@ -1344,7 +1345,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;
     }
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
new file mode 100644
index 0000000..8717a79
--- /dev/null
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -0,0 +1,323 @@
+/*
+ * 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 "OmxInfoBuilder"
+
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
+#include <utils/Log.h>
+#include <cutils/properties.h>
+
+#include <binder/IServiceManager.h>
+#include <media/IMediaCodecService.h>
+#include <media/stagefright/OmxInfoBuilder.h>
+#include <media/stagefright/ACodec.h>
+
+#include <android/hardware/media/omx/1.0/IOmxStore.h>
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#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/openmax/OMX_Index.h>
+#include <media/openmax/OMX_IndexExt.h>
+#include <media/openmax/OMX_Audio.h>
+#include <media/openmax/OMX_AudioExt.h>
+#include <media/openmax/OMX_Video.h>
+#include <media/openmax/OMX_VideoExt.h>
+
+namespace android {
+
+namespace /* unnamed */ {
+
+status_t queryCapabilities(
+        const IOMXStore::NodeInfo& node, const char* mime, bool isEncoder,
+        MediaCodecInfo::CapabilitiesWriter* caps) {
+    sp<ACodec> codec = new ACodec();
+    status_t err = codec->queryCapabilities(
+            node.owner.c_str(), node.name.c_str(), mime, isEncoder, caps);
+    if (err != OK) {
+        return err;
+    }
+    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.
+            caps->addDetail(
+                    attribute.key.c_str(),
+                    attribute.value == "1" ? 1 : 0);
+        } else {
+            // Non-feature attributes
+            caps->addDetail(
+                    attribute.key.c_str(), attribute.value.c_str());
+        }
+    }
+    return OK;
+}
+
+}  // unnamed namespace
+
+OmxInfoBuilder::OmxInfoBuilder() {
+}
+
+status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
+    bool treble;
+    sp<IOMX> omx;
+    std::vector<IOMXStore::RoleInfo> roles;
+
+    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();
+        if (omxStore == nullptr) {
+            ALOGE("Cannot connect to an IOmxStore 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
+        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));
+                    }
+                });
+        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.");
+            return NO_INIT;
+        }
+    }
+
+    // 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;
+    // owner name -> MediaCodecInfo
+    // This map will be used to obtain the correct IOmx service(s) needed for
+    // creating IOmxNode instances and querying capabilities.
+    std::map<std::string, std::vector<sp<MediaCodecInfo> > >
+            owner2CodecInfo;
+
+    for (const auto& role : roles) {
+        const auto& typeName = role.type;
+        bool isEncoder = role.isEncoder;
+        bool preferPlatformNodes = role.preferPlatformNodes;
+        // 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;
+        for (const auto& node : role.nodes) {
+            const auto& nodeName = node.name;
+            bool isSoftware = nodeName.compare(0, 10, "OMX.google") == 0;
+            MediaCodecInfoWriter* info;
+            if (isSoftware) {
+                auto c2i = swCodecName2Info.find(nodeName);
+                if (c2i == swCodecName2Info.end()) {
+                    // Create a new MediaCodecInfo for a new node.
+                    c2i = swCodecName2Info.insert(std::make_pair(
+                            nodeName, writer->addMediaCodecInfo())).first;
+                    info = c2i->second.get();
+                    info->setName(nodeName.c_str());
+                    info->setOwner(node.owner.c_str());
+                    info->setEncoder(isEncoder);
+                } else {
+                    // The node has been seen before. Simply retrieve the
+                    // existing MediaCodecInfoWriter.
+                    info = c2i->second.get();
+                }
+            } else {
+                auto c2i = hwCodecName2Info.find(nodeName);
+                if (c2i == hwCodecName2Info.end()) {
+                    // Create a new MediaCodecInfo for a new node.
+                    if (!preferPlatformNodes) {
+                        c2i = hwCodecName2Info.insert(std::make_pair(
+                                nodeName, writer->addMediaCodecInfo())).first;
+                        info = c2i->second.get();
+                        info->setName(nodeName.c_str());
+                        info->setOwner(node.owner.c_str());
+                        info->setEncoder(isEncoder);
+                    } else {
+                        // If preferPlatformNodes is true, this node must be
+                        // added after all software nodes.
+                        hwCodecs.push_back(&node);
+                        continue;
+                    }
+                } else {
+                    // The node has been seen before. Simply retrieve the
+                    // existing MediaCodecInfoWriter.
+                    info = c2i->second.get();
+                }
+            }
+            std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
+                    info->addMime(typeName.c_str());
+            if (queryCapabilities(
+                    node, typeName.c_str(), isEncoder, caps.get()) != OK) {
+                ALOGW("Fail to add mime %s to codec %s",
+                        typeName.c_str(), nodeName.c_str());
+                info->removeMime(typeName.c_str());
+            }
+        }
+
+        // If preferPlatformNodes is true, hardware nodes will not have been
+        // added in the loop above, but rather saved in hwCodecs. They are
+        // going to be added here.
+        if (preferPlatformNodes) {
+            for (const auto& node : hwCodecs) {
+                MediaCodecInfoWriter* info;
+                const auto& nodeName = node->name;
+                auto c2i = hwCodecName2Info.find(nodeName);
+                if (c2i == hwCodecName2Info.end()) {
+                    // Create a new MediaCodecInfo for a new node.
+                    c2i = hwCodecName2Info.insert(std::make_pair(
+                            nodeName, writer->addMediaCodecInfo())).first;
+                    info = c2i->second.get();
+                    info->setName(nodeName.c_str());
+                    info->setOwner(node->owner.c_str());
+                    info->setEncoder(isEncoder);
+                } else {
+                    // The node has been seen before. Simply retrieve the
+                    // existing MediaCodecInfoWriter.
+                    info = c2i->second.get();
+                }
+                std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
+                        info->addMime(typeName.c_str());
+                if (queryCapabilities(
+                        *node, typeName.c_str(), isEncoder, caps.get()) != OK) {
+                    ALOGW("Fail to add mime %s to codec %s "
+                          "after software codecs",
+                          typeName.c_str(), nodeName.c_str());
+                    info->removeMime(typeName.c_str());
+                }
+            }
+        }
+    }
+    return OK;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
new file mode 100644
index 0000000..db2c20c
--- /dev/null
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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/RemoteMediaExtractor.h>
+#include <media/stagefright/MediaSource.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 : source->asIMediaSource();
+}
+
+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..4060526
--- /dev/null
+++ b/media/libstagefright/RemoteMediaSource.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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>
+
+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 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/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 4f31c5f..75f744d 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -172,7 +172,7 @@
         if (mSampleToChunkIndex + 1 < mTable->mNumSampleToChunkOffsets) {
             mStopChunk = entry[1].startChunk;
 
-            if (mStopChunk < mFirstChunk ||
+            if (mSamplesPerChunk == 0 || mStopChunk < mFirstChunk ||
                 (mStopChunk - mFirstChunk) > UINT32_MAX / mSamplesPerChunk ||
                 ((mStopChunk - mFirstChunk) * mSamplesPerChunk >
                  UINT32_MAX - mFirstChunkSampleIndex)) {
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 a53897f..103da95 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -60,6 +60,12 @@
 StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
     ALOGV("~StagefrightMetadataRetriever()");
     clearMetadata();
+    // Explicitly release extractor before continuing with the destructor,
+    // some extractors might need to callback to close off the DataSource
+    // and we need to make sure it's still there.
+    if (mExtractor != NULL) {
+        mExtractor->release();
+    }
     if (mSource != NULL) {
         mSource->close();
     }
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 780b746..18bf4ae 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -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;
     }
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index a745692..b75b468 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -200,10 +200,22 @@
              frame_crop_top_offset, frame_crop_bottom_offset,
              cropUnitX, cropUnitY);
 
-        *width -=
-            (frame_crop_left_offset + frame_crop_right_offset) * cropUnitX;
-        *height -=
-            (frame_crop_top_offset + frame_crop_bottom_offset) * cropUnitY;
+
+        // *width -= (frame_crop_left_offset + frame_crop_right_offset) * cropUnitX;
+        if(__builtin_add_overflow(frame_crop_left_offset, frame_crop_right_offset, &frame_crop_left_offset) ||
+            __builtin_mul_overflow(frame_crop_left_offset, cropUnitX, &frame_crop_left_offset) ||
+            __builtin_sub_overflow(*width, frame_crop_left_offset, width) ||
+            *width < 0) {
+            *width = 0;
+        }
+
+        //*height -= (frame_crop_top_offset + frame_crop_bottom_offset) * cropUnitY;
+        if(__builtin_add_overflow(frame_crop_top_offset, frame_crop_bottom_offset, &frame_crop_top_offset) ||
+            __builtin_mul_overflow(frame_crop_top_offset, cropUnitY, &frame_crop_top_offset) ||
+            __builtin_sub_overflow(*height, frame_crop_top_offset, height) ||
+            *height < 0) {
+            *height = 0;
+        }
     }
 
     if (sarWidth != NULL) {
diff --git a/media/libstagefright/codec2/include/C2Buffer.h b/media/libstagefright/codec2/include/C2Buffer.h
index 88f1db3..b5ea381 100644
--- a/media/libstagefright/codec2/include/C2Buffer.h
+++ b/media/libstagefright/codec2/include/C2Buffer.h
@@ -767,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
@@ -921,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;
@@ -961,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.
@@ -985,6 +1018,13 @@
      */
     C2Error error() const;
 
+protected:
+    C2GraphicView(
+            const _C2PlanarCapacityAspect *parent,
+            uint8_t *const *data,
+            const C2PlaneLayout& layout);
+    explicit C2GraphicView(C2Error error);
+
 private:
     class Impl;
     std::shared_ptr<Impl> mImpl;
@@ -1022,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;
 };
 
@@ -1050,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;
 };
 
 /// @}
@@ -1115,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);
 };
 
 /**
@@ -1171,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);
+    C2Error registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg = nullptr);
 
     /**
      * Unregisters a previously registered pre-destroy notification.
@@ -1183,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);
+    C2Error unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify);
 
     ///@}
 
@@ -1219,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;
 };
 
@@ -1451,10 +1507,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;
 };
 
 /**
diff --git a/media/libstagefright/codec2/include/C2Component.h b/media/libstagefright/codec2/include/C2Component.h
index f071423..94312fb 100644
--- a/media/libstagefright/codec2/include/C2Component.h
+++ b/media/libstagefright/codec2/include/C2Component.h
@@ -52,7 +52,7 @@
     // virtual void onComponentReleased(<id>) = 0;
 
 protected:
-    virtual ~C2ComponentListener();
+    virtual ~C2ComponentListener() = default;
 };
 
 /**
diff --git a/media/libstagefright/codec2/include/C2Work.h b/media/libstagefright/codec2/include/C2Work.h
index a42d11a..a378623 100644
--- a/media/libstagefright/codec2/include/C2Work.h
+++ b/media/libstagefright/codec2/include/C2Work.h
@@ -60,9 +60,9 @@
 typedef uint32_t node_id;
 
 enum flags_t : uint32_t {
-    BUFFERFLAG_CODEC_CONFIG,
-    BUFFERFLAG_DROP_FRAME,
-    BUFFERFLAG_END_OF_STREAM,
+    BUFFERFLAG_CODEC_CONFIG  = (1 << 0),
+    BUFFERFLAG_DROP_FRAME    = (1 << 1),
+    BUFFERFLAG_END_OF_STREAM = (1 << 2),
 };
 
 enum {
diff --git a/media/libstagefright/codec2/tests/Android.bp b/media/libstagefright/codec2/tests/Android.bp
index a8a6565..8a18f7d 100644
--- a/media/libstagefright/codec2/tests/Android.bp
+++ b/media/libstagefright/codec2/tests/Android.bp
@@ -15,14 +15,49 @@
     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",
-        "liblog",
-        "libstagefright_codec2",
-        "libcutils",
         "libhidlbase",
         "libion",
         "liblog",
diff --git a/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp b/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp
new file mode 100644
index 0000000..0c8ca3e
--- /dev/null
+++ b/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp
@@ -0,0 +1,708 @@
+/*
+ * 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 getSupportedValues() 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 status_t (e.g. C2_OK).
+    template <typename T> status_t queryOnStack(T *const p);
+
+    template <typename T>
+    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>
+    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, 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 std::vector<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> status_t C2CompIntfTest::queryOnStack(T *const p) {
+    std::vector<C2Param *const> stackParams{p};
+    return mIntf->query_nb(stackParams, {}, nullptr);
+}
+
+template <typename T>
+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>
+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, 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.
+    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 std::vector<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 std::vector<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[0];
+
+    switch (c2FSV.type) {
+    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) {
+    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.
+    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<C2FieldSupportedValues> validValueInfos;            \
+        ASSERT_EQ(C2_OK,                                                \
+                  mIntf->getSupportedValues(                            \
+                          {C2ParamField(param.get(), &field_type_name_::field_name_)}, \
+                          &validValueInfos));                           \
+        ASSERT_EQ(1u, validValueInfos.size());                          \
+        std::vector<decltype(param->field_name_)> validValues;          \
+        std::vector<decltype(param->field_name_)> invalidValues;        \
+        getTestValues(validValueInfos, &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->getSupportedParams(&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/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index 0ba3cad..97c4a7d 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -18,6 +18,7 @@
 
 #include <C2Buffer.h>
 #include <C2BufferPriv.h>
+#include <C2ParamDef.h>
 
 #include <system/graphics.h>
 
@@ -26,27 +27,28 @@
 class C2BufferTest : public ::testing::Test {
 public:
     C2BufferTest()
-        : mAllocator(std::make_shared<C2AllocatorIon>()),
+        : mLinearAllocator(std::make_shared<C2AllocatorIon>()),
           mSize(0u),
-          mAddr(nullptr) {
+          mAddr(nullptr),
+          mGraphicAllocator(std::make_shared<C2AllocatorGralloc>()) {
     }
 
     ~C2BufferTest() = default;
 
-    void allocate(size_t capacity) {
-        C2Error err = mAllocator->allocateLinearBuffer(
+    void allocateLinear(size_t capacity) {
+        C2Error err = mLinearAllocator->allocateLinearBuffer(
                 capacity,
                 { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
-                &mAllocation);
+                &mLinearAllocation);
         if (err != C2_OK) {
-            mAllocation.reset();
+            mLinearAllocation.reset();
             FAIL() << "C2Allocator::allocateLinearBuffer() failed: " << err;
         }
     }
 
-    void map(size_t offset, size_t size, uint8_t **addr) {
-        ASSERT_TRUE(mAllocation);
-        C2Error err = mAllocation->map(
+    void mapLinear(size_t offset, size_t size, uint8_t **addr) {
+        ASSERT_TRUE(mLinearAllocation);
+        C2Error err = mLinearAllocation->map(
                 offset,
                 size,
                 { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
@@ -62,45 +64,89 @@
         *addr = (uint8_t *)mAddr;
     }
 
-    void unmap() {
-        ASSERT_TRUE(mAllocation);
+    void unmapLinear() {
+        ASSERT_TRUE(mLinearAllocation);
         ASSERT_NE(nullptr, mAddr);
         ASSERT_NE(0u, mSize);
 
         // TODO: fence
-        ASSERT_EQ(C2_OK, mAllocation->unmap(mAddr, mSize, nullptr));
+        ASSERT_EQ(C2_OK, mLinearAllocation->unmap(mAddr, mSize, nullptr));
         mSize = 0u;
         mAddr = nullptr;
     }
 
-    std::shared_ptr<C2BlockAllocator> makeBlockAllocator() {
-        return std::make_shared<C2DefaultBlockAllocator>(mAllocator);
+    std::shared_ptr<C2BlockAllocator> makeLinearBlockAllocator() {
+        return std::make_shared<C2DefaultBlockAllocator>(mLinearAllocator);
+    }
+
+    void allocateGraphic(uint32_t width, uint32_t height) {
+        C2Error err = mGraphicAllocator->allocateGraphicBuffer(
+                width,
+                height,
+                HAL_PIXEL_FORMAT_YCBCR_420_888,
+                { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+                &mGraphicAllocation);
+        if (err != C2_OK) {
+            mGraphicAllocation.reset();
+            FAIL() << "C2Allocator::allocateLinearBuffer() failed: " << err;
+        }
+    }
+
+    void mapGraphic(C2Rect rect, C2PlaneLayout *layout, uint8_t **addr) {
+        ASSERT_TRUE(mGraphicAllocation);
+        C2Error 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<C2BlockAllocator> makeGraphicBlockAllocator() {
+        return std::make_shared<C2DefaultGraphicBlockAllocator>(mGraphicAllocator);
     }
 
 private:
-    std::shared_ptr<C2Allocator> mAllocator;
-    std::shared_ptr<C2LinearAllocation> mAllocation;
+    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;
 
-    allocate(kCapacity);
+    allocateLinear(kCapacity);
 
     uint8_t *addr = nullptr;
-    map(0u, kCapacity, &addr);
+    mapLinear(0u, kCapacity, &addr);
     ASSERT_NE(nullptr, addr);
 
     for (size_t i = 0; i < kCapacity; ++i) {
         addr[i] = i % 100u;
     }
 
-    unmap();
+    unmapLinear();
     addr = nullptr;
 
-    map(kCapacity / 3, kCapacity / 3, &addr);
+    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;
@@ -110,7 +156,7 @@
 TEST_F(C2BufferTest, BlockAllocatorTest) {
     constexpr size_t kCapacity = 1024u * 1024u;
 
-    std::shared_ptr<C2BlockAllocator> blockAllocator(makeBlockAllocator());
+    std::shared_ptr<C2BlockAllocator> blockAllocator(makeLinearBlockAllocator());
 
     std::shared_ptr<C2LinearBlock> block;
     ASSERT_EQ(C2_OK, blockAllocator->allocateLinearBlock(
@@ -161,4 +207,324 @@
     }
 }
 
+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, GraphicBlockAllocatorTest) {
+    constexpr uint32_t kWidth = 320;
+    constexpr uint32_t kHeight = 240;
+
+    std::shared_ptr<C2BlockAllocator> blockAllocator(makeGraphicBlockAllocator());
+
+    std::shared_ptr<C2GraphicBlock> block;
+    ASSERT_EQ(C2_OK, blockAllocator->allocateGraphicBlock(
+            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<C2BlockAllocator> linearBlockAllocator(makeLinearBlockAllocator());
+    std::shared_ptr<C2BlockAllocator> graphicBlockAllocator(makeGraphicBlockAllocator());
+
+    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, linearBlockAllocator->allocateLinearBlock(
+            kCapacity1,
+            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+            &linearBlock1));
+    ASSERT_EQ(C2_OK, linearBlockAllocator->allocateLinearBlock(
+            kCapacity2,
+            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+            &linearBlock2));
+    std::shared_ptr<C2GraphicBlock> graphicBlock1;
+    std::shared_ptr<C2GraphicBlock> graphicBlock2;
+    ASSERT_EQ(C2_OK, graphicBlockAllocator->allocateGraphicBlock(
+            kWidth1,
+            kHeight1,
+            HAL_PIXEL_FORMAT_YCBCR_420_888,
+            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
+            &graphicBlock1));
+    ASSERT_EQ(C2_OK, graphicBlockAllocator->allocateGraphicBlock(
+            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<C2BlockAllocator> alloc(makeLinearBlockAllocator());
+    constexpr size_t kCapacity = 1024u;
+    std::shared_ptr<C2LinearBlock> block;
+
+    ASSERT_EQ(C2_OK, alloc->allocateLinearBlock(
+            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_OK, buffer->unregisterOnDestroyNotify(&DestroyCallback));
+    EXPECT_FALSE(destroyed);
+    ASSERT_EQ(C2_NOT_FOUND, buffer->unregisterOnDestroyNotify(&DestroyCallback));
+    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
index 9426b4e..916a6a9 100644
--- a/media/libstagefright/codec2/vndk/Android.bp
+++ b/media/libstagefright/codec2/vndk/Android.bp
@@ -10,6 +10,8 @@
     ],
 
     shared_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
         "libbinder",
         "libcutils",
         "libdl",
@@ -19,6 +21,7 @@
         "liblog",
         "libmedia",
         "libstagefright_foundation",
+        "libui",
         "libutils",
     ],
 
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index ffb6c2e..1a0b55c 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -20,11 +20,25 @@
 
 #include <C2BufferPriv.h>
 
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+
 #include <ion/ion.h>
+#include <hardware/gralloc.h>
 #include <sys/mman.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;
+
 // standard ERRNO mappings
 template<int N> constexpr C2Error _c2_errno2error_impl();
 template<> constexpr C2Error _c2_errno2error_impl<0>()       { return C2_OK; }
@@ -95,6 +109,37 @@
     friend class ::android::C2DefaultBlockAllocator;
 };
 
+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::C2DefaultGraphicBlockAllocator;
+};
+
+class C2DefaultBufferData : public C2BufferData {
+    using C2BufferData::C2BufferData;
+    friend class ::android::C2Buffer;
+};
+
 }  // namespace
 
 /* ======================================= ION ALLOCATION ====================================== */
@@ -717,4 +762,680 @@
     return C2_OK;
 }
 
+/* ===================================== GRALLOC ALLOCATION ==================================== */
+
+static C2Error 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_UNSUPPORTED;
+    }
+    return C2_CORRUPTED;
+}
+
+class C2AllocationGralloc : public C2GraphicAllocation {
+public:
+    virtual ~C2AllocationGralloc();
+
+    virtual C2Error map(
+            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+            C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
+    virtual C2Error 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;
+    C2Error 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));
+}
+
+C2Error 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;
+    }
+
+    C2Error 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_UNSUPPORTED;
+    }
+    mLocked = true;
+
+    return C2_OK;
+}
+
+C2Error C2AllocationGralloc::unmap(C2Fence *fenceFd /* nullable */) {
+    // TODO: fence
+    C2Error 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();
+
+    C2Error allocateGraphicBuffer(
+            uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
+            std::shared_ptr<C2GraphicAllocation> *allocation);
+
+    C2Error recreateGraphicBuffer(
+            const C2Handle *handle,
+            std::shared_ptr<C2GraphicAllocation> *allocation);
+
+    C2Error status() const { return mInit; }
+
+private:
+    C2Error mInit;
+    sp<IAllocator> mAllocator;
+    sp<IMapper> mMapper;
+};
+
+C2AllocatorGralloc::Impl::Impl() : mInit(C2_OK) {
+    mAllocator = IAllocator::getService();
+    mMapper = IMapper::getService();
+    if (mAllocator == nullptr || mMapper == nullptr) {
+        mInit = C2_CORRUPTED;
+    }
+}
+
+C2Error C2AllocatorGralloc::Impl::allocateGraphicBuffer(
+        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,
+    };
+    C2Error 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;
+}
+
+C2Error C2AllocatorGralloc::Impl::recreateGraphicBuffer(
+        const C2Handle *handle,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    (void) handle;
+
+    // TODO: need to figure out BufferDescriptorInfo from the handle.
+    allocation->reset();
+    return C2_UNSUPPORTED;
+}
+
+C2AllocatorGralloc::C2AllocatorGralloc() : mImpl(new Impl) {}
+C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
+
+C2Error C2AllocatorGralloc::allocateGraphicBuffer(
+        uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    return mImpl->allocateGraphicBuffer(width, height, format, usage, allocation);
+}
+
+C2Error C2AllocatorGralloc::recreateGraphicBuffer(
+        const C2Handle *handle,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    return mImpl->recreateGraphicBuffer(handle, allocation);
+}
+
+C2Error C2AllocatorGralloc::status() const { return mImpl->status(); }
+
+/* ========================================== 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(C2Error error) : mData(nullptr), mError(error) {}
+
+    uint8_t *const *data() const { return mData; }
+    const C2PlaneLayout &layout() const { return mLayout; }
+    C2Error error() const { return mError; }
+
+private:
+    uint8_t *const *mData;
+    C2PlaneLayout mLayout;
+    C2Error mError;
+};
+
+C2GraphicView::C2GraphicView(
+        const _C2PlanarCapacityAspect *parent,
+        uint8_t *const *data,
+        const C2PlaneLayout& layout)
+    : _C2PlanarSection(parent), mImpl(new Impl(data, layout)) {}
+
+C2GraphicView::C2GraphicView(C2Error 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;
+}
+
+C2Error 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);
+        }
+    }
+
+    C2Error map(C2Rect rect) {
+        if (mData[0] != nullptr) {
+            // Already mapped.
+            return C2_OK;
+        }
+        C2Error 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 {
+    C2Error 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);
+        }
+    }
+
+    C2Error map(C2Rect rect) {
+        if (mData[0] != nullptr) {
+            // Already mapped.
+            return C2_OK;
+        }
+        uint8_t *data[C2PlaneLayout::MAX_NUM_PLANES];
+        C2Error 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() {
+    C2Error 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);
+}
+
+C2DefaultGraphicBlockAllocator::C2DefaultGraphicBlockAllocator(
+        const std::shared_ptr<C2Allocator> &allocator)
+  : mAllocator(allocator) {}
+
+C2Error C2DefaultGraphicBlockAllocator::allocateGraphicBlock(
+        uint32_t width,
+        uint32_t height,
+        uint32_t format,
+        C2MemoryUsage usage,
+        std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+    block->reset();
+
+    std::shared_ptr<C2GraphicAllocation> alloc;
+    C2Error err = mAllocator->allocateGraphicBuffer(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; }
+
+    C2Error registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg = nullptr) {
+        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;
+    }
+
+    C2Error unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify) {
+        auto it = std::find_if(
+                mNotify.begin(), mNotify.end(),
+                [onDestroyNotify] (const auto &pair) {
+                    return pair.first == onDestroyNotify;
+                });
+        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;
+    }
+
+    C2Error 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(); }
+
+C2Error C2Buffer::registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
+    return mImpl->registerOnDestroyNotify(onDestroyNotify, arg);
+}
+
+C2Error C2Buffer::unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify) {
+    return mImpl->unregisterOnDestroyNotify(onDestroyNotify);
+}
+
+const std::list<std::shared_ptr<const C2Info>> C2Buffer::infos() const {
+    return mImpl->infos();
+}
+
+C2Error 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/codec2/vndk/include/C2BufferPriv.h b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
index bfb069c..a536710 100644
--- a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
+++ b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
@@ -65,6 +65,49 @@
     const std::shared_ptr<C2Allocator> mAllocator;
 };
 
+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 C2Error allocateGraphicBuffer(
+            uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+            std::shared_ptr<C2GraphicAllocation> *allocation) override;
+
+    virtual C2Error recreateGraphicBuffer(
+            const C2Handle *handle,
+            std::shared_ptr<C2GraphicAllocation> *allocation) override;
+
+    C2AllocatorGralloc();
+
+    C2Error status() const;
+
+    virtual ~C2AllocatorGralloc();
+
+private:
+    class Impl;
+    Impl *mImpl;
+};
+
+class C2DefaultGraphicBlockAllocator : public C2BlockAllocator {
+public:
+    explicit C2DefaultGraphicBlockAllocator(const std::shared_ptr<C2Allocator> &allocator);
+
+    virtual ~C2DefaultGraphicBlockAllocator() = default;
+
+    virtual C2Error allocateGraphicBlock(
+            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;
+};
+
+
 #if 0
 class C2Allocation::Impl {
 public:
diff --git a/media/libstagefright/codecs/aacenc/Android.bp b/media/libstagefright/codecs/aacenc/Android.bp
index fb368c2..1b4e35c 100644
--- a/media/libstagefright/codecs/aacenc/Android.bp
+++ b/media/libstagefright/codecs/aacenc/Android.bp
@@ -56,7 +56,7 @@
 
             instruction_set: "arm",
 
-            armv7_a_neon: {
+            neon: {
                 exclude_srcs: [
                     "src/asm/ARMV5E/PrePostMDCT_v5.s",
                     "src/asm/ARMV5E/R4R8First_v5.s",
diff --git a/media/libstagefright/codecs/amrwbenc/Android.bp b/media/libstagefright/codecs/amrwbenc/Android.bp
index 8968991..b6f637f 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.bp
+++ b/media/libstagefright/codecs/amrwbenc/Android.bp
@@ -76,7 +76,7 @@
 
             instruction_set: "arm",
 
-            armv7_a_neon: {
+            neon: {
                 exclude_srcs: [
                     "src/asm/ARMV5E/convolve_opt.s",
                     "src/asm/ARMV5E/cor_h_vec_opt.s",
diff --git a/media/libstagefright/codecs/avcdec/Android.bp b/media/libstagefright/codecs/avcdec/Android.bp
index 1f43803..44c882c 100644
--- a/media/libstagefright/codecs/avcdec/Android.bp
+++ b/media/libstagefright/codecs/avcdec/Android.bp
@@ -36,3 +36,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: true,
+        diag: {
+            cfi: 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..3aa8c38
--- /dev/null
+++ b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp
@@ -0,0 +1,1409 @@
+/*
+ * 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 <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::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 {field, C2SettingResult::BAD_VALUE, 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 {field, C2SettingResult::BAD_VALUE, 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 {field, C2SettingResult::BAD_VALUE, 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 {C2ParamField(param, &T::m), C2SettingResult::BAD_VALUE, 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)::baseIndex: \
+        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 paramIndex) override {
+        constexpr C2SoftAvcDecIntf *component = nullptr;
+        switch (paramIndex.baseIndex()) {
+        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::baseIndex:
+            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, node_id 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;
+
+    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));
+}
+
+C2String C2SoftAvcDecIntf::getName() const {
+    return mName;
+}
+
+node_id C2SoftAvcDecIntf::getId() const {
+    return mId;
+}
+
+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)) {
+            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;
+}
+
+status_t C2SoftAvcDecIntf::config_nb(
+        const std::vector<C2Param* const> &params,
+        std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+    status_t err = C2_OK;
+    for (C2Param *param : params) {
+        uint32_t index = restoreIndex(param);
+        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;
+}
+
+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);
+}
+
+status_t C2SoftAvcDecIntf::createTunnel_sm(node_id targetComponent) {
+    // Tunneling is not supported
+    (void) targetComponent;
+    return C2_UNSUPPORTED;
+}
+
+status_t C2SoftAvcDecIntf::releaseTunnel_sm(node_id targetComponent) {
+    // Tunneling is not supported
+    (void) targetComponent;
+    return C2_UNSUPPORTED;
+}
+
+std::shared_ptr<C2ParamReflector> C2SoftAvcDecIntf::getParamReflector() const {
+    return mParamReflector;
+}
+
+status_t C2SoftAvcDecIntf::getSupportedParams(
+        std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const {
+    params->insert(params->begin(), mParamDescs.begin(), mParamDescs.end());
+    return C2_OK;
+}
+
+status_t C2SoftAvcDecIntf::getSupportedValues(
+        const std::vector<const C2ParamField> &fields,
+        std::vector<C2FieldSupportedValues>* const values) const {
+    for (const auto &field : fields) {
+        if (mSupportedValues.count(field) == 0) {
+            return BAD_VALUE;
+        }
+        values->push_back(mSupportedValues.at(field).supported);
+    }
+    return C2_OK;
+}
+
+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,
+        node_id id,
+        const std::shared_ptr<C2ComponentListener> &listener)
+    : mIntf(std::make_shared<C2SoftAvcDecIntf>(name, id)),
+      mListener(listener),
+      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);
+}
+
+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;
+}
+
+status_t C2SoftAvcDec::announce_nb(const std::vector<C2WorkOutline> &items) {
+    // Tunneling is not supported
+    (void) items;
+    return C2_UNSUPPORTED;
+}
+
+status_t C2SoftAvcDec::flush_sm(
+        bool flushThrough, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
+    // Tunneling is not supported
+    (void) flushThrough;
+
+    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;
+}
+
+status_t C2SoftAvcDec::drain_nb(bool drainThrough) {
+    // Tunneling is not supported
+    (void) drainThrough;
+
+    if (!mThread->isRunning()) {
+        return C2_CORRUPTED;
+    }
+    std::unique_lock<std::mutex> lock(mQueueLock);
+    if (!mQueue.empty()) {
+        C2BufferPack &lastInput = mQueue.back()->input;
+        lastInput.flags = (flags_t)(lastInput.flags | BUFFERFLAG_END_OF_STREAM);
+        mQueueCond.notify_all();
+    }
+    return C2_OK;
+}
+
+status_t C2SoftAvcDec::start() {
+    if (!mThread->isRunning()) {
+        mThread->start(shared_from_this());
+    }
+    return C2_OK;
+}
+
+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()) {
+        mListener->onWorkDone(shared_from_this(), std::move(done));
+    }
+}
+
+
+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(shared_from_this(), std::move(done));
+        if (!(work->input.flags & BUFFERFLAG_END_OF_STREAM)) {
+            return;
+        }
+
+        mReceivedEOS = true;
+        // TODO: flush
+    } else if (work->input.flags & BUFFERFLAG_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 };
+        (void) work->worklets.front()->allocators[0]->allocateGraphicBlock(
+                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(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;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/codecs/avcdec/C2SoftAvcDec.h b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.h
new file mode 100644
index 0000000..6a83d1d
--- /dev/null
+++ b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.h
@@ -0,0 +1,312 @@
+/*
+ * 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, node_id id);
+    virtual ~C2SoftAvcDecIntf() = default;
+
+    // From C2ComponentInterface
+    virtual C2String getName() const override;
+    virtual node_id getId() const override;
+    virtual 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 status_t config_nb(
+            const std::vector<C2Param* const> &params,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
+    virtual status_t commit_sm(
+            const std::vector<C2Param* const> &params,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
+    virtual status_t createTunnel_sm(node_id targetComponent) override;
+    virtual status_t releaseTunnel_sm(node_id targetComponent) override;
+    virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override;
+    virtual status_t getSupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override;
+    virtual status_t getSupportedValues(
+            const std::vector<const C2ParamField> &fields,
+            std::vector<C2FieldSupportedValues>* const values) const override;
+
+private:
+    class ParamReflector;
+
+    const C2String mName;
+    const node_id 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;
+    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();
+};
+
+class C2SoftAvcDec
+    : public C2Component,
+      public std::enable_shared_from_this<C2SoftAvcDec> {
+public:
+    C2SoftAvcDec(
+            const char *name, node_id id, const std::shared_ptr<C2ComponentListener> &listener);
+    virtual ~C2SoftAvcDec();
+
+    // From C2Component
+    virtual status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) override;
+    virtual status_t announce_nb(const std::vector<C2WorkOutline> &items) override;
+    virtual status_t flush_sm(
+            bool flushThrough, std::list<std::unique_ptr<C2Work>>* const flushedWork) override;
+    virtual status_t drain_nb(bool drainThrough) override;
+    virtual status_t start() override;
+    virtual 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;
+    const std::shared_ptr<C2ComponentListener> mListener;
+
+    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;
+    int32_t mWidth;
+    int32_t mHeight;
+    int32_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/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..ad4da9b
--- /dev/null
+++ b/media/libstagefright/codecs/cmds/codec2.cpp
@@ -0,0 +1,464 @@
+/*
+ * 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/ICrypto.h>
+#include <media/IMediaHTTPService.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/DataSource.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.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 <C2Work.h>
+
+#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<C2Allocator> mAllocGralloc;
+    std::shared_ptr<C2BlockAllocator> mLinearAlloc;
+    std::shared_ptr<C2BlockAllocator> mGraphicAlloc;
+
+    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 C2ComponentListener {
+public:
+    explicit Listener(SimplePlayer *thiz) : mThis(thiz) {}
+    virtual ~Listener() = default;
+
+    virtual void onWorkDone(std::weak_ptr<C2Component> component,
+                            std::vector<std::unique_ptr<C2Work>> workItems) override {
+        mThis->onWorkDone(component, std::move(workItems));
+    }
+
+    virtual void onTripped(std::weak_ptr<C2Component> component,
+                           std::vector<std::shared_ptr<C2SettingResult>> settingResult) override {
+        mThis->onTripped(component, settingResult);
+    }
+
+    virtual void onError(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),
+      mAllocIon(new C2AllocatorIon),
+      mAllocGralloc(new C2AllocatorGralloc),
+      mLinearAlloc(new C2DefaultBlockAllocator(mAllocIon)),
+      mGraphicAlloc(new C2DefaultGraphicBlockAllocator(mAllocGralloc)),
+      mComposerClient(new SurfaceComposerClient) {
+    CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
+
+    mControl = mComposerClient->createSurface(
+            String8("A Surface"),
+            1280,
+            800,
+            HAL_PIXEL_FORMAT_YV12);
+            //PIXEL_FORMAT_RGB_565);
+
+    CHECK(mControl != NULL);
+    CHECK(mControl->isValid());
+
+    SurfaceComposerClient::openGlobalTransaction();
+    CHECK_EQ(mControl->setLayer(INT_MAX), (status_t)OK);
+    CHECK_EQ(mControl->show(), (status_t)OK);
+    SurfaceComposerClient::closeGlobalTransaction();
+
+    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::shared_ptr<C2Component> component(std::make_shared<C2SoftAvcDec>("avc", 0, mListener));
+    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;
+    mLinearAlloc.reset(new C2DefaultBlockAllocator(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 = (flags_t)0;
+        work->input.ordinal.timestamp = timestamp;
+        work->input.ordinal.frame_index = numFrames;
+
+        std::shared_ptr<C2LinearBlock> block;
+        mLinearAlloc->allocateLinearBlock(
+                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);
+        work->worklets.front()->allocators.emplace_back(mGraphicAlloc);
+
+        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 =
+            DataSource::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 = MediaExtractor::Create(dataSource);
+
+        if (extractor == NULL) {
+            fprintf(stderr, "could not create extractor.\n");
+            return -1;
+        }
+
+        sp<MetaData> meta = extractor->getMetaData();
+
+        if (meta != NULL) {
+            const char *mime;
+            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/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
index cff4a33..4ab1ab2 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
@@ -126,6 +126,29 @@
         OMX_INDEXTYPE index, OMX_PTR params) {
     ALOGV("internalGetParameter: index(%x)", index);
     switch ((OMX_U32)index) {
+        case OMX_IndexParamAudioPortFormat:
+        {
+            OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (!isValidOMXParam(formatParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            formatParams->eEncoding =
+                (formatParams->nPortIndex == 0)
+                    ? OMX_AUDIO_CodingFLAC : OMX_AUDIO_CodingPCM;
+
+            return OMX_ErrorNone;
+        }
         case OMX_IndexParamAudioFlac:
         {
             OMX_AUDIO_PARAM_FLACTYPE *flacParams =
@@ -219,6 +242,29 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamAudioPortFormat:
+        {
+            const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (!isValidOMXParam(formatParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if ((formatParams->nPortIndex == 0
+                        && formatParams->eEncoding != OMX_AUDIO_CodingFLAC)
+                || (formatParams->nPortIndex == 1
+                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
         case OMX_IndexParamAudioPcm:
         {
             const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
@@ -256,10 +302,27 @@
     while (!inQueue.empty() && !outQueue.empty()) {
         BufferInfo *inInfo = *inQueue.begin();
         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
         uint8_t* inBuffer = inHeader->pBuffer + inHeader->nOffset;
         uint32_t inBufferLength = inHeader->nFilledLen;
         bool endOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0;
 
+        if (inHeader->nFilledLen == 0) {
+            if (endOfInput) {
+                outHeader->nFilledLen = 0;
+                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+                outInfo->mOwnedByUs = false;
+                outQueue.erase(outQueue.begin());
+                notifyFillBufferDone(outHeader);
+            } else {
+                ALOGE("onQueueFilled: emptyInputBuffer received");
+            }
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            notifyEmptyBufferDone(inHeader);
+            return;
+        }
         if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
             ALOGE("onQueueFilled: first buffer should have OMX_BUFFERFLAG_CODECCONFIG set");
             inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
@@ -297,8 +360,6 @@
             return;
         }
 
-        BufferInfo *outInfo = *outQueue.begin();
-        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
         short *outBuffer =
                 reinterpret_cast<short *>(outHeader->pBuffer + outHeader->nOffset);
         size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset;
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
index caceda9..56d2d69 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
@@ -154,6 +154,30 @@
     ALOGV("SoftFlacEncoder::internalGetParameter(index=0x%x)", index);
 
     switch (index) {
+        case OMX_IndexParamAudioPortFormat:
+        {
+            OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (!isValidOMXParam(formatParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            formatParams->eEncoding =
+                (formatParams->nPortIndex == 0)
+                    ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingFLAC;
+
+            return OMX_ErrorNone;
+        }
+
         case OMX_IndexParamAudioPcm:
         {
             OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
@@ -163,7 +187,7 @@
                 return OMX_ErrorBadParameter;
             }
 
-            if (pcmParams->nPortIndex > 1) {
+            if (pcmParams->nPortIndex != 0) {
                 return OMX_ErrorUndefined;
             }
 
@@ -189,6 +213,10 @@
                 return OMX_ErrorBadParameter;
             }
 
+            if (flacParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
             flacParams->nCompressionLevel = mCompressionLevel;
             flacParams->nChannels = mNumChannels;
             flacParams->nSampleRate = mSampleRate;
@@ -203,6 +231,29 @@
 OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter(
         OMX_INDEXTYPE index, const OMX_PTR params) {
     switch (index) {
+        case OMX_IndexParamAudioPortFormat:
+        {
+            const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (!isValidOMXParam(formatParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if ((formatParams->nPortIndex == 0
+                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
+                || (formatParams->nPortIndex == 1
+                        && formatParams->eEncoding != OMX_AUDIO_CodingFLAC)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
         case OMX_IndexParamAudioPcm:
         {
             ALOGV("SoftFlacEncoder::internalSetParameter(OMX_IndexParamAudioPcm)");
@@ -212,7 +263,7 @@
                 return OMX_ErrorBadParameter;
             }
 
-            if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) {
+            if (pcmParams->nPortIndex != 0) {
                 ALOGE("SoftFlacEncoder::internalSetParameter() Error #1");
                 return OMX_ErrorUndefined;
             }
@@ -258,6 +309,10 @@
                 return OMX_ErrorBadParameter;
             }
 
+            if (flacParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
             mCompressionLevel = flacParams->nCompressionLevel; // range clamping done inside encoder
             return OMX_ErrorNone;
         }
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.bp b/media/libstagefright/codecs/on2/h264dec/Android.bp
index 95c2075..6d558b6 100644
--- a/media/libstagefright/codecs/on2/h264dec/Android.bp
+++ b/media/libstagefright/codecs/on2/h264dec/Android.bp
@@ -35,7 +35,7 @@
         arm: {
             instruction_set: "arm",
 
-            armv7_a_neon: {
+            neon: {
                 cflags: [
                     "-DH264DEC_NEON",
                     "-DH264DEC_OMXDL",
diff --git a/media/libstagefright/codecs/tests/Android.mk b/media/libstagefright/codecs/tests/Android.mk
new file mode 100644
index 0000000..dcb86ba
--- /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 \
+	libmedia \
+	libstagefright_codec2 \
+	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..e59c03e
--- /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/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/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml
index a127843..829f403 100644
--- a/media/libstagefright/data/media_codecs_google_video.xml
+++ b/media/libstagefright/data/media_codecs_google_video.xml
@@ -35,10 +35,10 @@
         </MediaCodec>
         <MediaCodec name="OMX.google.h264.decoder" type="video/avc">
             <!-- profiles and levels:  ProfileHigh : Level52 -->
-            <Limit name="size" min="2x2" max="4096x4096" />
+            <Limit name="size" min="2x2" max="4080x4080" />
             <Limit name="alignment" value="2x2" />
             <Limit name="block-size" value="16x16" />
-            <Limit name="block-count" range="1-32768" /> <!-- max 4096x2048 -->
+            <Limit name="block-count" range="1-32768" /> <!-- max 4096x2048 equivalent -->
             <Limit name="blocks-per-second" range="1-1966080" />
             <Limit name="bitrate" range="1-48000000" />
             <Feature name="adaptive-playback" />
diff --git a/media/libstagefright/include/AACExtractor.h b/media/libstagefright/include/AACExtractor.h
index bd4c41c..91e2eed 100644
--- a/media/libstagefright/include/AACExtractor.h
+++ b/media/libstagefright/include/AACExtractor.h
@@ -32,7 +32,7 @@
     AACExtractor(const sp<DataSource> &source, const sp<AMessage> &meta);
 
     virtual size_t countTracks();
-    virtual sp<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/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
index 8abcb12..06cd387 100644
--- a/media/libstagefright/include/AMRExtractor.h
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -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/libstagefright/include/FLACExtractor.h b/media/libstagefright/include/FLACExtractor.h
index 51bc139..e945cf6 100644
--- a/media/libstagefright/include/FLACExtractor.h
+++ b/media/libstagefright/include/FLACExtractor.h
@@ -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/include/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
index 2fd04f2..2b16c24 100644
--- a/media/libstagefright/include/MP3Extractor.h
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -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/MPEG2PSExtractor.h b/media/libstagefright/include/MPEG2PSExtractor.h
index f5471b3..75e1346 100644
--- a/media/libstagefright/include/MPEG2PSExtractor.h
+++ b/media/libstagefright/include/MPEG2PSExtractor.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/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index ac93b5e..1702157 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.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/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index 4a4c538..bd404d2 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -56,12 +56,13 @@
     explicit MPEG4Extractor(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();
     virtual uint32_t flags() const;
     virtual const char * name() { return "MPEG4Extractor"; }
+    virtual void release();
 
     // for DRM
     virtual char* getDrmTrackInfo(size_t trackID, int *len);
@@ -85,6 +86,9 @@
         sp<SampleTable> sampleTable;
         bool includes_expensive_metadata;
         bool skipTrack;
+        bool has_elst;
+        int64_t elst_media_time;
+        uint64_t elst_segment_duration;
     };
 
     Vector<SidxEntry> mSidxEntries;
diff --git a/media/libstagefright/include/MidiExtractor.h b/media/libstagefright/include/MidiExtractor.h
index 94d2d08..87a4a02 100644
--- a/media/libstagefright/include/MidiExtractor.h
+++ b/media/libstagefright/include/MidiExtractor.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/include/OggExtractor.h b/media/libstagefright/include/OggExtractor.h
index 55aafed..c01850f 100644
--- a/media/libstagefright/include/OggExtractor.h
+++ b/media/libstagefright/include/OggExtractor.h
@@ -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();
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/libstagefright/include/WAVExtractor.h
index 12ad441..dbcbe86 100644
--- a/media/libstagefright/include/WAVExtractor.h
+++ b/media/libstagefright/include/WAVExtractor.h
@@ -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();
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 b9f48c4..424246d 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <android/native_window.h>
 #include <media/hardware/MetadataBufferType.h>
+#include <media/MediaCodecInfo.h>
 #include <media/IOMX.h>
 #include <media/stagefright/foundation/AHierarchicalStateMachine.h>
 #include <media/stagefright/CodecBase.h>
@@ -30,6 +31,8 @@
 #include <OMX_Audio.h>
 #include <hardware/gralloc.h>
 #include <nativebase/nativebase.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
 
 #define TRACK_BUFFER_TIMING     0
 
@@ -42,20 +45,6 @@
 struct DescribeColorFormat2Params;
 struct DataConverter;
 
-// Treble shared memory
-namespace hidl {
-namespace allocator {
-namespace V1_0 {
-struct IAllocator;
-} // V1_0
-} // allocator
-namespace memory {
-namespace V1_0 {
-struct IMemory;
-} // V1_0
-} // memory
-} // hidl
-
 typedef hidl::allocator::V1_0::IAllocator TAllocator;
 typedef hidl::memory::V1_0::IMemory TMemory;
 
@@ -72,9 +61,10 @@
     virtual void initiateStart();
     virtual void initiateShutdown(bool keepComponentAllocated = false);
 
-    virtual status_t queryCapabilities(
-            const AString &name, const AString &mime, bool isEncoder,
-            sp<MediaCodecInfo::Capabilities> *caps);
+    status_t queryCapabilities(
+            const char* owner, const char* name,
+            const char* mime, bool isEncoder,
+            MediaCodecInfo::CapabilitiesWriter* caps);
 
     virtual status_t setSurface(const sp<Surface> &surface);
 
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..581ead9 100644
--- a/media/libstagefright/include/media/stagefright/AudioPlayer.h
+++ b/media/libstagefright/include/media/stagefright/AudioPlayer.h
@@ -18,9 +18,9 @@
 
 #define AUDIO_PLAYER_H_
 
-#include <media/IMediaSource.h>
 #include <media/MediaPlayerInterface.h>
 #include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
 #include <utils/threads.h>
 
 namespace android {
@@ -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/CallbackMediaSource.h b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
new file mode 100644
index 0000000..17fca4e
--- /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/stagefright/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/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index 6245ccb..9197f7b 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -213,10 +213,6 @@
     // require an explicit message handler
     virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
 
-    virtual status_t queryCapabilities(
-            const AString& /*name*/, const AString& /*mime*/, bool /*isEncoder*/,
-            sp<MediaCodecInfo::Capabilities>* /*caps*/ /* nonnull */) { return INVALID_OPERATION; }
-
     virtual status_t setSurface(const sp<Surface>& /*surface*/) { return INVALID_OPERATION; }
 
     virtual void signalFlush() = 0;
diff --git a/media/libstagefright/include/media/stagefright/DataUriSource.h b/media/libstagefright/include/media/stagefright/DataUriSource.h
deleted file mode 100644
index d223c06..0000000
--- a/media/libstagefright/include/media/stagefright/DataUriSource.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DATA_URI_SOURCE_H_
-
-#define DATA_URI_SOURCE_H_
-
-#include <stdio.h>
-
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/foundation/AString.h>
-
-namespace android {
-
-class DataUriSource : public DataSource {
-public:
-    DataUriSource(const char *uri);
-
-    virtual status_t initCheck() const {
-        return mInited;
-    }
-
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-
-    virtual status_t getSize(off64_t *size) {
-        if (mInited != OK) {
-            return mInited;
-        }
-
-        *size = mData.size();
-        return OK;
-    }
-
-    virtual String8 getUri() {
-        return mDataUri;
-    }
-
-    virtual String8 getMIMEType() const {
-        return mMimeType;
-    }
-
-protected:
-    virtual ~DataUriSource() {
-        // Nothing to delete.
-    }
-
-private:
-    const String8 mDataUri;
-
-    String8 mMimeType;
-    // Use AString because individual bytes may not be valid UTF8 chars.
-    AString mData;
-    status_t mInited;
-
-    // Disallow copy and assign.
-    DataUriSource(const DataUriSource &);
-    DataUriSource &operator=(const DataUriSource &);
-};
-
-}  // namespace android
-
-#endif  // DATA_URI_SOURCE_H_
diff --git a/media/libstagefright/include/media/stagefright/FrameRenderTracker.h b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
index 044699c..c14755a 100644
--- a/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
+++ b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
@@ -23,6 +23,8 @@
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AString.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
 
 #include <list>
 
@@ -30,9 +32,6 @@
 
 namespace android {
 
-class Fence;
-class GraphicBuffer;
-
 // Tracks the render information about a frame. Frames go through several states while
 // the render information is tracked:
 //
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..eba3b32 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>
@@ -40,7 +39,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);
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/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 209fe12..1030407 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -87,11 +87,6 @@
 
     static sp<PersistentSurface> CreatePersistentInputSurface();
 
-    // utility method to query capabilities
-    static status_t QueryCapabilities(
-            const AString &name, const AString &mime, bool isEncoder,
-            sp<MediaCodecInfo::Capabilities> *caps /* nonnull */);
-
     status_t configure(
             const sp<AMessage> &format,
             const sp<Surface> &nativeWindow,
@@ -319,6 +314,8 @@
     SoftwareRenderer *mSoftRenderer;
 
     MediaAnalyticsItem *mAnalyticsItem;
+    void initAnalyticsItem();
+    void flushAnalyticsItem();
 
     sp<AMessage> mOutputFormat;
     sp<AMessage> mInputFormat;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecList.h b/media/libstagefright/include/media/stagefright/MediaCodecList.h
index 430bc16..f2bd496 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecList.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecList.h
@@ -21,7 +21,6 @@
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AString.h>
 #include <media/IMediaCodecList.h>
-#include <media/IOMX.h>
 #include <media/MediaCodecInfo.h>
 
 #include <sys/types.h>
@@ -36,6 +35,8 @@
 
 struct AMessage;
 
+struct MediaCodecListBuilderBase;
+
 struct MediaCodecList : public BnMediaCodecList {
     static sp<IMediaCodecList> getInstance();
 
@@ -51,7 +52,7 @@
             ALOGE("b/24445127");
             return NULL;
         }
-        return mCodecInfos.itemAt(index);
+        return mCodecInfos[index];
     }
 
     virtual const sp<AMessage> getGlobalSettings() const;
@@ -62,9 +63,6 @@
     // only to be used by getLocalInstance
     static void *profilerThreadWrapper(void * /*arg*/);
 
-    // only to be used by MediaPlayerService
-    void parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
-
     enum Flags {
         kPreferSoftwareCodecs   = 1,
         kHardwareCodecsOnly     = 2,
@@ -74,13 +72,11 @@
             const char *mime,
             bool createEncoder,
             uint32_t flags,
-            Vector<AString> *matching);
-
-    static uint32_t getQuirksFor(const char *mComponentName);
+            Vector<AString> *matchingCodecs,
+            Vector<AString> *owners = nullptr);
 
     static bool isSoftwareCodec(const AString &componentName);
 
-
 private:
     class BinderDeathObserver : public IBinder::DeathRecipient {
         void binderDied(const wp<IBinder> &the_late_who __unused);
@@ -88,64 +84,86 @@
 
     static sp<BinderDeathObserver> sBinderDeathObserver;
 
-    enum Section {
-        SECTION_TOPLEVEL,
-        SECTION_SETTINGS,
-        SECTION_DECODERS,
-        SECTION_DECODER,
-        SECTION_DECODER_TYPE,
-        SECTION_ENCODERS,
-        SECTION_ENCODER,
-        SECTION_ENCODER_TYPE,
-        SECTION_INCLUDE,
-    };
-
     static sp<IMediaCodecList> sCodecList;
     static sp<IMediaCodecList> sRemoteList;
 
     status_t mInitCheck;
-    Section mCurrentSection;
-    bool mUpdate;
-    Vector<Section> mPastSections;
-    int32_t mDepth;
-    AString mHrefBase;
 
     sp<AMessage> mGlobalSettings;
-    KeyedVector<AString, CodecSettings> mOverrides;
+    std::vector<sp<MediaCodecInfo> > mCodecInfos;
 
-    Vector<sp<MediaCodecInfo> > mCodecInfos;
-    sp<MediaCodecInfo> mCurrentInfo;
+    /**
+     * This constructor will call `buildMediaCodecList()` from the given
+     * `MediaCodecListBuilderBase` object.
+     */
+    MediaCodecList(MediaCodecListBuilderBase* builder);
 
-    MediaCodecList();
     ~MediaCodecList();
 
     status_t initCheck() const;
-    void parseXMLFile(const char *path);
 
-    static void StartElementHandlerWrapper(
-            void *me, const char *name, const char **attrs);
+    MediaCodecList(const MediaCodecList&) = delete;
+    MediaCodecList& operator=(const MediaCodecList&) = delete;
 
-    static void EndElementHandlerWrapper(void *me, const char *name);
+    friend MediaCodecListWriter;
+};
 
-    void startElementHandler(const char *name, const char **attrs);
-    void endElementHandler(const char *name);
+/**
+ * This class is to be used by a `MediaCodecListBuilderBase` instance to add
+ * information to the associated `MediaCodecList` object.
+ */
+struct MediaCodecListWriter {
+    /**
+     * Add a key-value pair to a `MediaCodecList`'s global settings.
+     *
+     * @param key Key.
+     * @param value Value.
+     */
+    void addGlobalSetting(const char* key, const char* value);
+    /**
+     * Create an add a new `MediaCodecInfo` object to a `MediaCodecList`, and
+     * return a `MediaCodecInfoWriter` object associated with the newly added
+     * `MediaCodecInfo`.
+     *
+     * @return The `MediaCodecInfoWriter` object associated with the newly
+     * added `MediaCodecInfo` object.
+     */
+    std::unique_ptr<MediaCodecInfoWriter> addMediaCodecInfo();
+private:
+    /**
+     * The associated `MediaCodecList` object.
+     */
+    MediaCodecList* mList;
 
-    status_t includeXMLFile(const char **attrs);
-    status_t addSettingFromAttributes(const char **attrs);
-    status_t addMediaCodecFromAttributes(bool encoder, const char **attrs);
-    void addMediaCodec(bool encoder, const char *name, const char *type = NULL);
+    /**
+     * Construct this writer object associated with the given `MediaCodecList`
+     * object.
+     *
+     * @param list The "base" `MediaCodecList` object.
+     */
+    MediaCodecListWriter(MediaCodecList* list);
 
-    void setCurrentCodecInfo(bool encoder, const char *name, const char *type);
+    friend MediaCodecList;
+};
 
-    status_t addQuirk(const char **attrs);
-    status_t addTypeFromAttributes(const char **attrs);
-    status_t addLimit(const char **attrs);
-    status_t addFeature(const char **attrs);
-    void addType(const char *name);
+/**
+ * This interface is to be used by `MediaCodecList` to fill its members with
+ * appropriate information. `buildMediaCodecList()` will be called from a
+ * `MediaCodecList` object during its construction.
+ */
+struct MediaCodecListBuilderBase {
+    /**
+     * Build the `MediaCodecList` via the given `MediaCodecListWriter` interface.
+     *
+     * @param writer The writer interface.
+     * @return The status of the construction. `NO_ERROR` means success.
+     */
+    virtual status_t buildMediaCodecList(MediaCodecListWriter* writer) = 0;
 
-    status_t initializeCapabilities(const char *type);
-
-    DISALLOW_EVIL_CONSTRUCTORS(MediaCodecList);
+    /**
+     * The default destructor does nothing.
+     */
+    virtual ~MediaCodecListBuilderBase();
 };
 
 }  // namespace android
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractor.h b/media/libstagefright/include/media/stagefright/MediaExtractor.h
index f12160b..f8eb7fd 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractor.h
@@ -19,15 +19,15 @@
 #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 {
+class MediaExtractor : public RefBase {
 public:
     static sp<IMediaExtractor> Create(
             const sp<DataSource> &source, const char *mime = NULL);
@@ -35,7 +35,7 @@
             const sp<DataSource> &source, const char *mime = NULL);
 
     virtual size_t countTracks() = 0;
-    virtual sp<IMediaSource> getTrack(size_t index) = 0;
+    virtual sp<MediaSource> getTrack(size_t index) = 0;
 
     enum GetTrackMetaDataFlags {
         kIncludeExtensiveMetaData = 1
@@ -60,18 +60,23 @@
     // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
     virtual uint32_t flags() const;
 
+    // Creates an IMediaExtractor wrapper to this MediaExtractor.
+    virtual sp<IMediaExtractor> asIMediaExtractor();
+
     // 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 {
+    virtual status_t setMediaCas(const HInterfaceToken &/*casToken*/) {
         return INVALID_OPERATION;
     }
 
     virtual const char * name() { return "<unspecified>"; }
 
+    virtual void release() {}
+
 protected:
     MediaExtractor();
     virtual ~MediaExtractor();
diff --git a/media/libstagefright/include/media/stagefright/MediaSource.h b/media/libstagefright/include/media/stagefright/MediaSource.h
index 14adb05..7e30e30 100644
--- a/media/libstagefright/include/media/stagefright/MediaSource.h
+++ b/media/libstagefright/include/media/stagefright/MediaSource.h
@@ -22,6 +22,7 @@
 
 #include <media/IMediaSource.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
 
@@ -29,8 +30,18 @@
 
 class MediaBuffer;
 class MetaData;
+class IMediaSource;
 
-struct MediaSource : public BnMediaSource {
+struct MediaSource : public virtual RefBase {
+    // TODO: Move ReadOptions implementation from IMediaSource to MediaSource
+    // once this class moves to a separate extractor lib on which both libmedia
+    // and libstagefright rely. For now, alias is added to avoid circular
+    // dependency.
+    using ReadOptions = IMediaSource::ReadOptions;
+
+    // Creates a MediaSource which wraps the given IMediaSource object.
+    static sp<MediaSource> CreateFromIMediaSource(const sp<IMediaSource> &source);
+
     MediaSource();
 
     // To be called before any other methods on this object, except
@@ -92,6 +103,9 @@
         return ERROR_UNSUPPORTED;
     }
 
+    // Creates an IMediaSource wrapper to this MediaSource.
+    virtual sp<IMediaSource> asIMediaSource();
+
 protected:
     virtual ~MediaSource();
 
diff --git a/media/libstagefright/include/media/stagefright/MediaWriter.h b/media/libstagefright/include/media/stagefright/MediaWriter.h
index cd4af4d..80c5358 100644
--- a/media/libstagefright/include/media/stagefright/MediaWriter.h
+++ b/media/libstagefright/include/media/stagefright/MediaWriter.h
@@ -20,7 +20,7 @@
 
 #include <utils/RefBase.h>
 #include <media/IMediaRecorderClient.h>
-#include <media/IMediaSource.h>
+#include <media/stagefright/MediaSource.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/OMXClient.h b/media/libstagefright/include/media/stagefright/OMXClient.h
index 203a181..2f159b0 100644
--- a/media/libstagefright/include/media/stagefright/OMXClient.h
+++ b/media/libstagefright/include/media/stagefright/OMXClient.h
@@ -28,9 +28,10 @@
 
     status_t connect();
     status_t connect(bool* trebleFlag);
+    status_t connect(const char* name, bool* trebleFlag = nullptr);
 
     status_t connectLegacy();
-    status_t connectTreble();
+    status_t connectTreble(const char* name = "default");
     void disconnect();
 
     sp<IOMX> interface() {
@@ -40,8 +41,8 @@
 private:
     sp<IOMX> mOMX;
 
-    OMXClient(const OMXClient &);
-    OMXClient &operator=(const OMXClient &);
+    OMXClient(const OMXClient &) = delete;
+    OMXClient &operator=(const OMXClient &) = delete;
 };
 
 }  // namespace android
diff --git a/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h b/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h
new file mode 100644
index 0000000..1b4d873
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h
@@ -0,0 +1,33 @@
+/*
+ * 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 OMX_INFO_BUILDER_H_
+#define OMX_INFO_BUILDER_H_
+
+#include <media/stagefright/MediaCodecList.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class OmxInfoBuilder : public MediaCodecListBuilderBase {
+public:
+    OmxInfoBuilder();
+    status_t buildMediaCodecList(MediaCodecListWriter* writer) override;
+};
+
+}  // namespace android
+
+#endif  // OMX_INFO_BUILDER_H_
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
new file mode 100644
index 0000000..96611d1
--- /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/stagefright/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..2731114
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -0,0 +1,50 @@
+/*
+ * 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/stagefright/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 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..b8d141a 100644
--- a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
+++ b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.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/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 813a257..487603c 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -140,6 +140,7 @@
     enum Type {
         AVC,
         AAC,
+        HEVC,
         OTHER
     };
 
@@ -148,7 +149,7 @@
     Type mType;
     bool mIsAudio;
     BlockIterator mBlockIter;
-    ssize_t mNALSizeLen;  // for type AVC
+    ssize_t mNALSizeLen;  // for type AVC or HEVC
 
     List<MediaBuffer *> mPendingFrames;
 
@@ -244,6 +245,19 @@
         } else {
             ALOGE("No mNALSizeLen");
         }
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+        mType = HEVC;
+
+        uint32_t dummy;
+        const uint8_t *hvcc;
+        size_t hvccSize;
+        if (meta->findData(kKeyHVCC, &dummy, (const void **)&hvcc, &hvccSize)
+                && hvccSize >= 22u) {
+            mNALSizeLen = 1 + (hvcc[14+7] & 3);
+            ALOGV("mNALSizeLen = %zu", mNALSizeLen);
+        } else {
+            ALOGE("No mNALSizeLen");
+        }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
         mType = AAC;
     }
@@ -692,7 +706,7 @@
     MediaBuffer *frame = *mPendingFrames.begin();
     mPendingFrames.erase(mPendingFrames.begin());
 
-    if (mType != AVC || mNALSizeLen == 0) {
+    if ((mType != AVC && mType != HEVC) || mNALSizeLen == 0) {
         if (targetSampleTimeUs >= 0ll) {
             frame->meta_data()->setInt64(
                     kKeyTargetTime, targetSampleTimeUs);
@@ -885,7 +899,7 @@
     return mTracks.size();
 }
 
-sp<IMediaSource> MatroskaExtractor::getTrack(size_t index) {
+sp<MediaSource> MatroskaExtractor::getTrack(size_t index) {
     if (index >= mTracks.size()) {
         return NULL;
     }
@@ -1293,6 +1307,14 @@
                 if (!strcmp("V_MPEG4/ISO/AVC", codecID)) {
                     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
                     meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize);
+                } else if (!strcmp("V_MPEGH/ISO/HEVC", codecID)) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
+                    if (codecPrivateSize > 0) {
+                        meta->setData(kKeyHVCC, kTypeHVCC, codecPrivate, codecPrivateSize);
+                    } else {
+                        ALOGW("HEVC is detected, but does not have configuration.");
+                        continue;
+                    }
                 } else if (!strcmp("V_MPEG4/ISO/ASP", codecID)) {
                     if (codecPrivateSize > 0) {
                         meta->setCString(
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index 19775ce..832463f 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.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/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
index 078a5f0..0f18fac 100644
--- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -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/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 9d684e0..b66af7b 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -129,7 +129,7 @@
     return mSourceImpls.size();
 }
 
-sp<IMediaSource> MPEG2TSExtractor::getTrack(size_t index) {
+sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) {
     if (index >= mSourceImpls.size()) {
         return NULL;
     }
diff --git a/media/libstagefright/omx/1.0/Omx.cpp b/media/libstagefright/omx/1.0/Omx.cpp
index 8f30a3d..fe50656 100644
--- a/media/libstagefright/omx/1.0/Omx.cpp
+++ b/media/libstagefright/omx/1.0/Omx.cpp
@@ -114,15 +114,23 @@
             return Void();
         }
         instance->setHandle(handle);
-        std::vector<AString> quirkVector;
-        if (mParser.getQuirks(name.c_str(), &quirkVector) == OK) {
+
+        // Find quirks from mParser
+        const auto& codec = mParser.getCodecMap().find(name.c_str());
+        if (codec == mParser.getCodecMap().cend()) {
+            LOG(WARNING) << "Failed to obtain quirks for omx component "
+                    "'" << name.c_str() << "' "
+                    "from XML files";
+        } else {
             uint32_t quirks = 0;
-            for (const AString& quirk : quirkVector) {
+            for (const auto& quirk : codec->second.quirkSet) {
                 if (quirk == "requires-allocate-on-input-ports") {
-                    quirks |= kRequiresAllocateBufferOnInputPorts;
+                    quirks |= OMXNodeInstance::
+                            kRequiresAllocateBufferOnInputPorts;
                 }
                 if (quirk == "requires-allocate-on-output-ports") {
-                    quirks |= kRequiresAllocateBufferOnOutputPorts;
+                    quirks |= OMXNodeInstance::
+                            kRequiresAllocateBufferOnOutputPorts;
                 }
             }
             instance->setQuirks(quirks);
diff --git a/media/libstagefright/omx/1.0/OmxStore.cpp b/media/libstagefright/omx/1.0/OmxStore.cpp
index a82625a..447af6f 100644
--- a/media/libstagefright/omx/1.0/OmxStore.cpp
+++ b/media/libstagefright/omx/1.0/OmxStore.cpp
@@ -21,6 +21,7 @@
 
 #include <media/stagefright/omx/1.0/Conversion.h>
 #include <media/stagefright/omx/1.0/OmxStore.h>
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
 
 namespace android {
 namespace hardware {
@@ -29,24 +30,87 @@
 namespace V1_0 {
 namespace implementation {
 
-OmxStore::OmxStore() {
+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 = toStatus(parser.getParsingStatus());
+
+    const auto& serviceAttributeMap = parser.getServiceAttributeMap();
+    mServiceAttributeList.resize(serviceAttributeMap.size());
+    size_t i = 0;
+    for (const auto& attributePair : serviceAttributeMap) {
+        ServiceAttribute attribute;
+        attribute.key = attributePair.first;
+        attribute.value = attributePair.second;
+        mServiceAttributeList[i] = std::move(attribute);
+        ++i;
+    }
+
+    const auto& roleMap = parser.getRoleMap();
+    mRoleList.resize(roleMap.size());
+    i = 0;
+    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;
+        hidl_vec<NodeInfo>& nodeList = role.nodes;
+        nodeList.resize(rolePair.second.nodeList.size());
+        size_t j = 0;
+        for (const auto& nodePair : rolePair.second.nodeList) {
+            NodeInfo node;
+            node.name = nodePair.second.name;
+            node.owner = owner;
+            hidl_vec<NodeAttribute>& attributeList = node.attributes;
+            attributeList.resize(nodePair.second.attributeList.size());
+            size_t k = 0;
+            for (const auto& attributePair : nodePair.second.attributeList) {
+                NodeAttribute attribute;
+                attribute.key = attributePair.first;
+                attribute.value = attributePair.second;
+                attributeList[k] = std::move(attribute);
+                ++k;
+            }
+            nodeList[j] = std::move(node);
+            ++j;
+        }
+        mRoleList[i] = std::move(role);
+        ++i;
+    }
+
+    mPrefix = parser.getCommonPrefix();
 }
 
 OmxStore::~OmxStore() {
 }
 
 Return<void> OmxStore::listServiceAttributes(listServiceAttributes_cb _hidl_cb) {
-    _hidl_cb(toStatus(NO_ERROR), hidl_vec<ServiceAttribute>());
+    if (mParsingStatus == Status::NO_ERROR) {
+        _hidl_cb(Status::NO_ERROR, mServiceAttributeList);
+    } else {
+        _hidl_cb(mParsingStatus, hidl_vec<ServiceAttribute>());
+    }
     return Void();
 }
 
 Return<void> OmxStore::getNodePrefix(getNodePrefix_cb _hidl_cb) {
-    _hidl_cb(hidl_string());
+    _hidl_cb(mPrefix);
     return Void();
 }
 
 Return<void> OmxStore::listRoles(listRoles_cb _hidl_cb) {
-    _hidl_cb(hidl_vec<RoleInfo>());
+    _hidl_cb(mRoleList);
     return Void();
 }
 
@@ -54,12 +118,6 @@
     return IOmx::tryGetService(omxName);
 }
 
-// Methods from ::android::hidl::base::V1_0::IBase follow.
-
-IOmxStore* HIDL_FETCH_IOmxStore(const char* /* name */) {
-    return new OmxStore();
-}
-
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace omx
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
index fcf1092..c4499dc 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
+++ b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
@@ -41,7 +41,9 @@
     sp<GraphicBuffer> buf;
     status_t status = mBase->requestBuffer(slot, &buf);
     AnwBuffer anwBuffer;
-    wrapAs(&anwBuffer, *buf);
+    if (buf != nullptr) {
+        wrapAs(&anwBuffer, *buf);
+    }
     _hidl_cb(static_cast<int32_t>(status), anwBuffer);
     return Void();
 }
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 46f2dd1..bec022a 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -10,6 +10,7 @@
         "GraphicBufferSource.cpp",
         "BWGraphicBufferSource.cpp",
         "OMX.cpp",
+        "OMXStore.cpp",
         "OMXMaster.cpp",
         "OMXNodeInstance.cpp",
         "OMXUtils.cpp",
@@ -32,15 +33,6 @@
         "include",
     ],
 
-    include_dirs: [
-        "frameworks/av/include/media/",
-        "frameworks/av/media/libstagefright",
-        "frameworks/av/media/libstagefright/include",
-        "frameworks/native/include", // for media/hardware/MetadataBufferType.h
-        "frameworks/native/include/media/hardware",
-        "frameworks/native/include/media/openmax",
-    ],
-
     header_libs: [
         "media_plugin_headers",
     ],
@@ -100,8 +92,12 @@
     },
 }
 
-cc_library_static {
+cc_library_shared {
     name: "libstagefright_omx_utils",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
     srcs: ["OMXUtils.cpp"],
     export_include_dirs: [
         "include",
@@ -113,10 +109,11 @@
         "media_plugin_headers",
     ],
     shared_libs: [
-        "libmedia",
+        "libmedia_omx",
+        "liblog",
     ],
     export_shared_lib_headers: [
-        "libmedia",
+        "libmedia_omx",
     ],
     sanitize: {
         misc_undefined: [
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 109460d..1917d2a 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -956,28 +956,40 @@
     Mutex::Autolock lock(mMutex);
 
     uint64_t slotMask;
-    if (mConsumer->getReleasedBuffers(&slotMask) != NO_ERROR) {
-        ALOGW("onBuffersReleased: unable to get released buffer set");
+    uint64_t releaseMask;
+    if (mConsumer->getReleasedBuffers(&releaseMask) != NO_ERROR) {
         slotMask = 0xffffffffffffffffULL;
+        ALOGW("onBuffersReleased: unable to get released buffer set");
+    } else {
+        slotMask = releaseMask;
+        ALOGV("onBuffersReleased: 0x%016" PRIx64, slotMask);
     }
 
-    ALOGV("onBuffersReleased: 0x%016" PRIx64, slotMask);
-
+    AString unpopulated;
     for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
         if ((slotMask & 0x01) != 0) {
-            discardBufferInSlot_l(i);
+            if (!discardBufferInSlot_l(i)) {
+                if (!unpopulated.empty()) {
+                    unpopulated.append(", ");
+                }
+                unpopulated.append(i);
+            }
         }
         slotMask >>= 1;
     }
+    if (!unpopulated.empty()) {
+        ALOGW("released unpopulated slots: [%s]", unpopulated.c_str());
+    }
 }
 
-void GraphicBufferSource::discardBufferInSlot_l(GraphicBufferSource::slot_id i) {
+bool GraphicBufferSource::discardBufferInSlot_l(GraphicBufferSource::slot_id i) {
     ssize_t bsi = mBufferSlots.indexOfKey(i);
     if (bsi < 0) {
-        ALOGW("releasing an unpopulated slot: %d", i);
+        return false;
     } else {
         discardBufferAtSlotIndex_l(bsi);
         mBufferSlots.removeItemsAt(bsi);
+        return true;
     }
 }
 
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 5388ba0..09c4019 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -115,15 +115,22 @@
         return StatusFromOMXError(err);
     }
     instance->setHandle(handle);
-    std::vector<AString> quirkVector;
-    if (mParser.getQuirks(name, &quirkVector) == OK) {
+
+    // 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 AString& quirk : quirkVector) {
+        for (const auto& quirk : codec->second.quirkSet) {
             if (quirk == "requires-allocate-on-input-ports") {
-                quirks |= kRequiresAllocateBufferOnInputPorts;
+                quirks |= OMXNodeInstance::
+                        kRequiresAllocateBufferOnInputPorts;
             }
             if (quirk == "requires-allocate-on-output-ports") {
-                quirks |= kRequiresAllocateBufferOnOutputPorts;
+                quirks |= OMXNodeInstance::
+                        kRequiresAllocateBufferOnOutputPorts;
             }
         }
         instance->setQuirks(quirks);
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index c749454..015a148 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -372,6 +372,8 @@
     mPortMode[1] = IOMX::kPortModePresetByteBuffer;
     mSecureBufferType[0] = kSecureBufferTypeUnknown;
     mSecureBufferType[1] = kSecureBufferTypeUnknown;
+    mGraphicBufferEnabled[0] = false;
+    mGraphicBufferEnabled[1] = false;
     mIsSecure = AString(name).endsWith(".secure");
     mLegacyAdaptiveExperiment = ADebug::isExperimentEnabled("legacy-adaptive");
 }
@@ -495,6 +497,9 @@
             LOG_ALWAYS_FATAL("unknown state %s(%#x).", asString(state), state);
             break;
     }
+
+    Mutex::Autolock _l(mLock);
+
     status_t err = mOwner->freeNode(this);
 
     mDispatcher.clear();
@@ -674,6 +679,11 @@
         return BAD_VALUE;
     }
 
+    if (mSailed || mNumPortBuffers[portIndex] > 0) {
+        android_errorWriteLog(0x534e4554, "29422020");
+        return INVALID_OPERATION;
+    }
+
     CLOG_CONFIG(setPortMode, "%s(%d), port %d", asString(mode), mode, portIndex);
 
     switch (mode) {
@@ -805,6 +815,12 @@
             } else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
                 mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
             }
+        } else {
+            if (err == OMX_ErrorNone) {
+                mGraphicBufferEnabled[portIndex] = enable;
+            } else if (enable) {
+                mGraphicBufferEnabled[portIndex] = false;
+            }
         }
     } else {
         CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
@@ -1073,6 +1089,12 @@
     OMX_ERRORTYPE err = OMX_ErrorNone;
     bool isMetadata = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
 
+    if (!isMetadata && mGraphicBufferEnabled[portIndex]) {
+        ALOGE("b/62948670");
+        android_errorWriteLog(0x534e4554, "62948670");
+        return INVALID_OPERATION;
+    }
+
     size_t paramsSize;
     void* paramsPointer;
     if (params != NULL && hParams != NULL) {
@@ -1258,6 +1280,13 @@
                 portIndex, graphicBuffer, buffer);
     }
 
+    if (!mGraphicBufferEnabled[portIndex]) {
+        // Report error if this is not in graphic buffer mode.
+        ALOGE("b/62948670");
+        android_errorWriteLog(0x534e4554, "62948670");
+        return INVALID_OPERATION;
+    }
+
     // See if the newer version of the extension is present.
     OMX_INDEXTYPE index;
     if (OMX_GetExtensionIndex(
diff --git a/media/libstagefright/omx/OMXStore.cpp b/media/libstagefright/omx/OMXStore.cpp
new file mode 100644
index 0000000..345336d
--- /dev/null
+++ b/media/libstagefright/omx/OMXStore.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 87c2411..1ba5852 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -458,7 +458,12 @@
         state = OMX_StateLoaded;
     }
 
-    CHECK_EQ((int)mState, (int)mTargetState);
+    if (mState != mTargetState) {
+        ALOGE("State change to state %d requested while still transitioning from state %d to %d",
+                state, mState, mTargetState);
+        notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+        return;
+    }
 
     switch (mState) {
         case OMX_StateLoaded:
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
index f319bdc..8d8a2d9 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
@@ -2064,8 +2064,10 @@
     int const* constFds = static_cast<int const*>(baseFds.get());
     numFds = baseNumFds;
     if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
-        native_handle_close(nh);
-        native_handle_delete(nh);
+        if (nh != nullptr) {
+            native_handle_close(nh);
+            native_handle_delete(nh);
+        }
         return false;
     }
 
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h
index f377f5a..006d2d9 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/OmxStore.h
@@ -21,6 +21,7 @@
 #include <hidl/Status.h>
 
 #include <android/hardware/media/omx/1.0/IOmxStore.h>
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
 
 namespace android {
 namespace hardware {
@@ -41,17 +42,31 @@
 using ::android::wp;
 
 struct OmxStore : public IOmxStore {
-    OmxStore();
+    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);
+
     virtual ~OmxStore();
 
-    // Methods from IOmx
+    // Methods from IOmxStore
     Return<void> listServiceAttributes(listServiceAttributes_cb) override;
     Return<void> getNodePrefix(getNodePrefix_cb) override;
     Return<void> listRoles(listRoles_cb) override;
     Return<sp<IOmx>> getOmx(hidl_string const&) override;
-};
 
-extern "C" IOmxStore* HIDL_FETCH_IOmxStore(const char* name);
+protected:
+    Status mParsingStatus;
+    hidl_string mPrefix;
+    hidl_vec<ServiceAttribute> mServiceAttributeList;
+    hidl_vec<RoleInfo> mRoleList;
+};
 
 }  // namespace implementation
 }  // namespace V1_0
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/GraphicBufferSource.h
index 29b51a8..84fee6f 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/GraphicBufferSource.h
@@ -22,7 +22,7 @@
 #include <gui/BufferQueue.h>
 #include <utils/RefBase.h>
 
-#include <VideoAPI.h>
+#include <media/hardware/VideoAPI.h>
 #include <media/IOMX.h>
 #include <media/OMXFenceParcelable.h>
 #include <media/stagefright/foundation/ABase.h>
@@ -264,8 +264,8 @@
     void onBufferAcquired_l(const VideoBuffer &buffer);
 
     // marks the buffer at the slot no longer cached, and accounts for the outstanding
-    // acquire count
-    void discardBufferInSlot_l(slot_id i);
+    // acquire count. Returns true if the slot was populated; otherwise, false.
+    bool discardBufferInSlot_l(slot_id i);
 
     // marks the buffer at the slot index no longer cached, and accounts for the outstanding
     // acquire count
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXMaster.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXMaster.h
index 3f9c0ca..897f287 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXMaster.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXMaster.h
@@ -18,7 +18,7 @@
 
 #define OMX_MASTER_H_
 
-#include <OMXPluginBase.h>
+#include <media/hardware/OMXPluginBase.h>
 
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
index 8e08d15..1065ca5 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
@@ -92,6 +92,15 @@
     status_t getExtensionIndex(
             const char *parameterName, OMX_INDEXTYPE *index);
 
+    // Quirk still supported, even though deprecated
+    enum Quirks {
+        kRequiresAllocateBufferOnInputPorts   = 1,
+        kRequiresAllocateBufferOnOutputPorts  = 2,
+
+        kQuirksMask = kRequiresAllocateBufferOnInputPorts
+                    | kRequiresAllocateBufferOnOutputPorts,
+    };
+
     status_t setQuirks(OMX_U32 quirks);
 
     bool isSecure() const {
@@ -143,7 +152,7 @@
 
     bool mLegacyAdaptiveExperiment;
     IOMX::PortMode mPortMode[2];
-    // metadata and secure buffer type tracking
+    // metadata and secure buffer types and graphic buffer mode tracking
     MetadataBufferType mMetadataType[2];
     enum SecureBufferType {
         kSecureBufferTypeUnknown,
@@ -151,6 +160,7 @@
         kSecureBufferTypeNativeHandle,
     };
     SecureBufferType mSecureBufferType[2];
+    bool mGraphicBufferEnabled[2];
 
     // Following are OMX parameters managed by us (instead of the component)
     // OMX_IndexParamMaxFrameDurationForBitrateControl
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h
new file mode 100644
index 0000000..e00d713
--- /dev/null
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h
@@ -0,0 +1,62 @@
+/*
+ * 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/include/media/stagefright/omx/SoftOMXPlugin.h b/media/libstagefright/omx/include/media/stagefright/omx/SoftOMXPlugin.h
index c89cd87..8ec717e 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/SoftOMXPlugin.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/SoftOMXPlugin.h
@@ -19,7 +19,7 @@
 #define SOFT_OMX_PLUGIN_H_
 
 #include <media/stagefright/foundation/ABase.h>
-#include <OMXPluginBase.h>
+#include <media/hardware/OMXPluginBase.h>
 
 namespace android {
 
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 3266439..4b624f2 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -543,7 +543,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 +564,7 @@
         CHECK(meta->findCString(kKeyMIMEType, &trackMime));
 
         if (!strcasecmp(mime, trackMime)) {
-            return extractor->getTrack(i);
+            return MediaSource::CreateFromIMediaSource(extractor->getTrack(i));
         }
     }
 
@@ -610,7 +610,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 +620,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/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 1f6b6f7..56c4aa6 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -104,7 +104,7 @@
     mFd = -1;
 }
 
-status_t ARTPWriter::addSource(const sp<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/tests/MediaCodecListOverrides_test.cpp b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
index 2599608..0c22a42 100644
--- a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
+++ b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
@@ -26,6 +26,8 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaCodecList.h>
 
+#include <vector>
+
 namespace android {
 
 static const char kTestOverridesStr[] =
@@ -117,7 +119,7 @@
 // TODO: the codec component never returns OMX_EventCmdComplete in unit test.
 TEST_F(MediaCodecListOverridesTest, DISABLED_profileCodecs) {
     sp<IMediaCodecList> list = MediaCodecList::getInstance();
-    Vector<sp<MediaCodecInfo>> infos;
+    std::vector<sp<MediaCodecInfo>> infos;
     for (size_t i = 0; i < list->countCodecs(); ++i) {
         infos.push_back(list->getCodecInfo(i));
     }
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..d65d9b7 100644
--- a/media/libstagefright/webm/WebmFrameThread.h
+++ b/media/libstagefright/webm/WebmFrameThread.h
@@ -123,7 +123,7 @@
 class WebmFrameMediaSourceThread: public WebmFrameSourceThread {
 public:
     WebmFrameMediaSourceThread(
-            const sp<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..ed5bc4c 100644
--- a/media/libstagefright/webm/WebmWriter.h
+++ b/media/libstagefright/webm/WebmWriter.h
@@ -40,7 +40,7 @@
     ~WebmWriter() { reset(); }
 
 
-    virtual status_t addSource(const sp<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 ab893de..3507284 100644
--- a/media/libstagefright/xmlparser/Android.bp
+++ b/media/libstagefright/xmlparser/Android.bp
@@ -9,11 +9,6 @@
         "MediaCodecsXmlParser.cpp",
     ],
 
-    include_dirs: [
-        "frameworks/av/media/libstagefright",
-        "frameworks/av/include",
-    ],
-
     export_include_dirs: [
         "include",
     ],
@@ -24,6 +19,7 @@
         "liblog",
         "libcutils",
         "libstagefright_foundation",
+        "libstagefright_omx_utils",
     ],
 
     cflags: [
@@ -38,6 +34,10 @@
             "unsigned-integer-overflow",
             "signed-integer-overflow",
         ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
     },
 
 }
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 4fdd107..ffd30ea 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -16,157 +16,190 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaCodecsXmlParser"
-#include <utils/Log.h>
 
 #include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
 
-#include <media/MediaCodecInfo.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/AUtils.h>
+#include <utils/Log.h>
 #include <media/stagefright/MediaErrors.h>
-
+#include <media/stagefright/omx/OMXUtils.h>
 #include <sys/stat.h>
-
 #include <expat.h>
-#include <string>
 
-#define MEDIA_CODECS_CONFIG_FILE_PATH_MAX_LENGTH 256
+#include <cctype>
+#include <algorithm>
 
 namespace android {
 
-namespace { // Local variables and functions
+namespace {
 
-const char *kProfilingResults =
-        "/data/misc/media/media_codecs_profiling_results.xml";
-
-// Treblized media codec list will be located in /odm/etc or /vendor/etc.
-const char *kConfigLocationList[] =
-        {"/odm/etc", "/vendor/etc", "/etc"};
-constexpr int kConfigLocationListSize =
-        (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
-
-bool findMediaCodecListFileFullPath(
-        const char *file_name, std::string *out_path) {
-    for (int i = 0; i < kConfigLocationListSize; i++) {
-        *out_path = std::string(kConfigLocationList[i]) + "/" + file_name;
-        struct stat file_stat;
-        if (stat(out_path->c_str(), &file_stat) == 0 &&
-                S_ISREG(file_stat.st_mode)) {
+/**
+ * Search for a file in a list of search directories.
+ *
+ * For each string `searchDir` in `searchDirs`, `searchDir/fileName` will be
+ * tested whether it is a valid file name or not. If it is a valid file name,
+ * the concatenated name (`searchDir/fileName`) will be stored in the output
+ * variable `outPath`, and the function will return `true`. Otherwise, the
+ * search continues until the `nullptr` element in `searchDirs` is reached, at
+ * which point the function returns `false`.
+ *
+ * \param[in] searchDirs Null-terminated array of search paths.
+ * \param[in] fileName Name of the file to search.
+ * \param[out] outPath Full path of the file. `outPath` will hold a valid file
+ * name if the return value of this function is `true`.
+ * \return `true` if some element in `searchDirs` combined with `fileName` is a
+ * valid file name; `false` otherwise.
+ */
+bool findFileInDirs(
+        const char* const* searchDirs,
+        const char *fileName,
+        std::string *outPath) {
+    for (; *searchDirs != nullptr; ++searchDirs) {
+        *outPath = std::string(*searchDirs) + "/" + fileName;
+        struct stat fileStat;
+        if (stat(outPath->c_str(), &fileStat) == 0 &&
+                S_ISREG(fileStat.st_mode)) {
             return true;
         }
     }
     return false;
 }
 
-// Find TypeInfo by name.
-std::vector<TypeInfo>::iterator findTypeInfo(
-        CodecInfo &codecInfo, const AString &typeName) {
-    return std::find_if(
-            codecInfo.mTypes.begin(), codecInfo.mTypes.end(),
-            [typeName](const auto &typeInfo) {
-                return typeInfo.mName == typeName;
-            });
+bool strnEq(const char* s1, const char* s2, size_t count) {
+    return strncmp(s1, s2, count) == 0;
 }
 
-// Convert a string into a boolean value.
-bool ParseBoolean(const char *s) {
-    if (!strcasecmp(s, "true") || !strcasecmp(s, "yes") || !strcasecmp(s, "y")) {
-        return true;
-    }
-    char *end;
-    unsigned long res = strtoul(s, &end, 10);
-    return *s != '\0' && *end == '\0' && res > 0;
+bool strEq(const char* s1, const char* s2) {
+    return strcmp(s1, s2) == 0;
 }
 
-} // unnamed namespace
+bool striEq(const char* s1, const char* s2) {
+    return strcasecmp(s1, s2) == 0;
+}
 
-MediaCodecsXmlParser::MediaCodecsXmlParser() :
-    mInitCheck(NO_INIT),
-    mUpdate(false) {
-    std::string config_file_path;
-    if (findMediaCodecListFileFullPath(
-            "media_codecs.xml", &config_file_path)) {
-        parseTopLevelXMLFile(config_file_path.c_str(), false);
+bool strHasPrefix(const char* test, const char* prefix) {
+    return strnEq(test, prefix, strlen(prefix));
+}
+
+bool parseBoolean(const char* s) {
+    return striEq(s, "y") ||
+            striEq(s, "yes") ||
+            striEq(s, "t") ||
+            striEq(s, "true") ||
+            striEq(s, "1");
+}
+
+status_t limitFoundMissingAttr(const char* name, const char *attr, bool found = true) {
+    ALOGE("limit '%s' with %s'%s' attribute", name,
+            (found ? "" : "no "), attr);
+    return -EINVAL;
+}
+
+status_t limitError(const char* name, const char *msg) {
+    ALOGE("limit '%s' %s", name, msg);
+    return -EINVAL;
+}
+
+status_t limitInvalidAttr(const char* name, const char* attr, const char* value) {
+    ALOGE("limit '%s' with invalid '%s' attribute (%s)", name,
+            attr, value);
+    return -EINVAL;
+}
+
+}; // unnamed namespace
+
+constexpr char const* MediaCodecsXmlParser::defaultSearchDirs[];
+constexpr char const* MediaCodecsXmlParser::defaultMainXmlName;
+constexpr char const* MediaCodecsXmlParser::defaultPerformanceXmlName;
+constexpr char const* MediaCodecsXmlParser::defaultProfilingResultsXmlPath;
+
+MediaCodecsXmlParser::MediaCodecsXmlParser(
+        const char* const* searchDirs,
+        const char* mainXmlName,
+        const char* performanceXmlName,
+        const char* profilingResultsXmlPath) :
+    mParsingStatus(NO_INIT),
+    mUpdate(false),
+    mCodecCounter(0) {
+    std::string path;
+    if (findFileInDirs(searchDirs, mainXmlName, &path)) {
+        parseTopLevelXMLFile(path.c_str(), false);
     } else {
-        mInitCheck = NAME_NOT_FOUND;
+        ALOGE("Cannot find %s", mainXmlName);
+        mParsingStatus = NAME_NOT_FOUND;
     }
-    if (findMediaCodecListFileFullPath(
-            "media_codecs_performance.xml", &config_file_path)) {
-        parseTopLevelXMLFile(config_file_path.c_str(), true);
+    if (findFileInDirs(searchDirs, performanceXmlName, &path)) {
+        parseTopLevelXMLFile(path.c_str(), true);
     }
-    parseTopLevelXMLFile(kProfilingResults, true);
+    if (profilingResultsXmlPath != nullptr) {
+        parseTopLevelXMLFile(profilingResultsXmlPath, true);
+    }
 }
 
-void MediaCodecsXmlParser::parseTopLevelXMLFile(
-        const char *codecs_xml, bool ignore_errors) {
+bool MediaCodecsXmlParser::parseTopLevelXMLFile(
+        const char *codecs_xml,
+        bool ignore_errors) {
     // get href_base
     const char *href_base_end = strrchr(codecs_xml, '/');
-    if (href_base_end != NULL) {
-        mHrefBase = AString(codecs_xml, href_base_end - codecs_xml + 1);
+    if (href_base_end != nullptr) {
+        mHrefBase = std::string(codecs_xml, href_base_end - codecs_xml + 1);
     }
 
-    mInitCheck = OK; // keeping this here for safety
+    mParsingStatus = OK; // keeping this here for safety
     mCurrentSection = SECTION_TOPLEVEL;
-    mDepth = 0;
 
     parseXMLFile(codecs_xml);
 
-    if (mInitCheck != OK) {
+    if (mParsingStatus != OK) {
+        ALOGW("parseTopLevelXMLFile(%s) failed", codecs_xml);
         if (ignore_errors) {
-            mInitCheck = OK;
-            return;
+            mParsingStatus = OK;
+            return false;
         }
-        mCodecInfos.clear();
-        return;
+        mCodecMap.clear();
+        return false;
     }
+    return true;
 }
 
 MediaCodecsXmlParser::~MediaCodecsXmlParser() {
 }
 
-status_t MediaCodecsXmlParser::initCheck() const {
-    return mInitCheck;
-}
-
 void MediaCodecsXmlParser::parseXMLFile(const char *path) {
     FILE *file = fopen(path, "r");
 
-    if (file == NULL) {
+    if (file == nullptr) {
         ALOGW("unable to open media codecs configuration xml file: %s", path);
-        mInitCheck = NAME_NOT_FOUND;
+        mParsingStatus = NAME_NOT_FOUND;
         return;
     }
 
-    ALOGV("Start parsing %s", path);
-    XML_Parser parser = ::XML_ParserCreate(NULL);
-    CHECK(parser != NULL);
+    XML_Parser parser = ::XML_ParserCreate(nullptr);
+    LOG_FATAL_IF(parser == nullptr, "XML_MediaCodecsXmlParserCreate() failed.");
 
     ::XML_SetUserData(parser, this);
     ::XML_SetElementHandler(
             parser, StartElementHandlerWrapper, EndElementHandlerWrapper);
 
-    const int BUFF_SIZE = 512;
-    while (mInitCheck == OK) {
+    static constexpr int BUFF_SIZE = 512;
+    while (mParsingStatus == OK) {
         void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
-        if (buff == NULL) {
+        if (buff == nullptr) {
             ALOGE("failed in call to XML_GetBuffer()");
-            mInitCheck = UNKNOWN_ERROR;
+            mParsingStatus = UNKNOWN_ERROR;
             break;
         }
 
         int bytes_read = ::fread(buff, 1, BUFF_SIZE, file);
         if (bytes_read < 0) {
             ALOGE("failed in call to read");
-            mInitCheck = ERROR_IO;
+            mParsingStatus = ERROR_IO;
             break;
         }
 
         XML_Status status = ::XML_ParseBuffer(parser, bytes_read, bytes_read == 0);
         if (status != XML_STATUS_OK) {
             ALOGE("malformed (%s)", ::XML_ErrorString(::XML_GetErrorCode(parser)));
-            mInitCheck = ERROR_MALFORMED;
+            mParsingStatus = ERROR_MALFORMED;
             break;
         }
 
@@ -178,30 +211,29 @@
     ::XML_ParserFree(parser);
 
     fclose(file);
-    file = NULL;
+    file = nullptr;
 }
 
 // static
 void MediaCodecsXmlParser::StartElementHandlerWrapper(
         void *me, const char *name, const char **attrs) {
-    static_cast<MediaCodecsXmlParser *>(me)->startElementHandler(name, attrs);
+    static_cast<MediaCodecsXmlParser*>(me)->startElementHandler(name, attrs);
 }
 
 // static
 void MediaCodecsXmlParser::EndElementHandlerWrapper(void *me, const char *name) {
-    static_cast<MediaCodecsXmlParser *>(me)->endElementHandler(name);
+    static_cast<MediaCodecsXmlParser*>(me)->endElementHandler(name);
 }
 
 status_t MediaCodecsXmlParser::includeXMLFile(const char **attrs) {
-    const char *href = NULL;
+    const char *href = nullptr;
     size_t i = 0;
-    while (attrs[i] != NULL) {
-        if (!strcmp(attrs[i], "href")) {
-            if (attrs[i + 1] == NULL) {
+    while (attrs[i] != nullptr) {
+        if (strEq(attrs[i], "href")) {
+            if (attrs[++i] == nullptr) {
                 return -EINVAL;
             }
-            href = attrs[i + 1];
-            ++i;
+            href = attrs[i];
         } else {
             ALOGE("includeXMLFile: unrecognized attribute: %s", attrs[i]);
             return -EINVAL;
@@ -222,44 +254,43 @@
         return -EINVAL;
     }
 
-    AString filename = href;
-    if (!filename.startsWith("media_codecs_") ||
-        !filename.endsWith(".xml")) {
+    std::string filename = href;
+    if (filename.compare(0, 13, "media_codecs_") != 0 ||
+            filename.compare(filename.size() - 4, 4, ".xml") != 0) {
         ALOGE("invalid include file name: %s", href);
         return -EINVAL;
     }
-    filename.insert(mHrefBase, 0);
+    filename.insert(0, mHrefBase);
 
     parseXMLFile(filename.c_str());
-    return mInitCheck;
+    return mParsingStatus;
 }
 
 void MediaCodecsXmlParser::startElementHandler(
         const char *name, const char **attrs) {
-    if (mInitCheck != OK) {
+    if (mParsingStatus != OK) {
         return;
     }
 
     bool inType = true;
 
-    if (!strcmp(name, "Include")) {
-        mInitCheck = includeXMLFile(attrs);
-        if (mInitCheck == OK) {
-            mPastSections.push(mCurrentSection);
+    if (strEq(name, "Include")) {
+        mParsingStatus = includeXMLFile(attrs);
+        if (mParsingStatus == OK) {
+            mSectionStack.push_back(mCurrentSection);
             mCurrentSection = SECTION_INCLUDE;
         }
-        ++mDepth;
         return;
     }
 
     switch (mCurrentSection) {
         case SECTION_TOPLEVEL:
         {
-            if (!strcmp(name, "Decoders")) {
+            if (strEq(name, "Decoders")) {
                 mCurrentSection = SECTION_DECODERS;
-            } else if (!strcmp(name, "Encoders")) {
+            } else if (strEq(name, "Encoders")) {
                 mCurrentSection = SECTION_ENCODERS;
-            } else if (!strcmp(name, "Settings")) {
+            } else if (strEq(name, "Settings")) {
                 mCurrentSection = SECTION_SETTINGS;
             }
             break;
@@ -267,16 +298,16 @@
 
         case SECTION_SETTINGS:
         {
-            if (!strcmp(name, "Setting")) {
-                mInitCheck = addSettingFromAttributes(attrs);
+            if (strEq(name, "Setting")) {
+                mParsingStatus = addSettingFromAttributes(attrs);
             }
             break;
         }
 
         case SECTION_DECODERS:
         {
-            if (!strcmp(name, "MediaCodec")) {
-                mInitCheck =
+            if (strEq(name, "MediaCodec")) {
+                mParsingStatus =
                     addMediaCodecFromAttributes(false /* encoder */, attrs);
 
                 mCurrentSection = SECTION_DECODER;
@@ -286,8 +317,8 @@
 
         case SECTION_ENCODERS:
         {
-            if (!strcmp(name, "MediaCodec")) {
-                mInitCheck =
+            if (strEq(name, "MediaCodec")) {
+                mParsingStatus =
                     addMediaCodecFromAttributes(true /* encoder */, attrs);
 
                 mCurrentSection = SECTION_ENCODER;
@@ -298,13 +329,14 @@
         case SECTION_DECODER:
         case SECTION_ENCODER:
         {
-            if (!strcmp(name, "Quirk")) {
-                mInitCheck = addQuirk(attrs);
-            } else if (!strcmp(name, "Type")) {
-                mInitCheck = addTypeFromAttributes(attrs, (mCurrentSection == SECTION_ENCODER));
+            if (strEq(name, "Quirk")) {
+                mParsingStatus = addQuirk(attrs);
+            } else if (strEq(name, "Type")) {
+                mParsingStatus = addTypeFromAttributes(attrs,
+                        (mCurrentSection == SECTION_ENCODER));
                 mCurrentSection =
-                    (mCurrentSection == SECTION_DECODER
-                            ? SECTION_DECODER_TYPE : SECTION_ENCODER_TYPE);
+                        (mCurrentSection == SECTION_DECODER ?
+                        SECTION_DECODER_TYPE : SECTION_ENCODER_TYPE);
             }
         }
         inType = false;
@@ -314,13 +346,15 @@
         case SECTION_ENCODER_TYPE:
         {
             // ignore limits and features specified outside of type
-            bool outside = !inType && mCurrentType == mCodecInfos[mCurrentName].mTypes.end();
-            if (outside && (!strcmp(name, "Limit") || !strcmp(name, "Feature"))) {
+            bool outside = !inType &&
+                    mCurrentType == mCurrentCodec->second.typeMap.end();
+            if (outside &&
+                    (strEq(name, "Limit") || strEq(name, "Feature"))) {
                 ALOGW("ignoring %s specified outside of a Type", name);
-            } else if (!strcmp(name, "Limit")) {
-                mInitCheck = addLimit(attrs);
-            } else if (!strcmp(name, "Feature")) {
-                mInitCheck = addFeature(attrs);
+            } else if (strEq(name, "Limit")) {
+                mParsingStatus = addLimit(attrs);
+            } else if (strEq(name, "Feature")) {
+                mParsingStatus = addFeature(attrs);
             }
             break;
         }
@@ -329,18 +363,17 @@
             break;
     }
 
-    ++mDepth;
 }
 
 void MediaCodecsXmlParser::endElementHandler(const char *name) {
-    if (mInitCheck != OK) {
+    if (mParsingStatus != OK) {
         return;
     }
 
     switch (mCurrentSection) {
         case SECTION_SETTINGS:
         {
-            if (!strcmp(name, "Settings")) {
+            if (strEq(name, "Settings")) {
                 mCurrentSection = SECTION_TOPLEVEL;
             }
             break;
@@ -348,7 +381,7 @@
 
         case SECTION_DECODERS:
         {
-            if (!strcmp(name, "Decoders")) {
+            if (strEq(name, "Decoders")) {
                 mCurrentSection = SECTION_TOPLEVEL;
             }
             break;
@@ -356,7 +389,7 @@
 
         case SECTION_ENCODERS:
         {
-            if (!strcmp(name, "Encoders")) {
+            if (strEq(name, "Encoders")) {
                 mCurrentSection = SECTION_TOPLEVEL;
             }
             break;
@@ -365,19 +398,19 @@
         case SECTION_DECODER_TYPE:
         case SECTION_ENCODER_TYPE:
         {
-            if (!strcmp(name, "Type")) {
+            if (strEq(name, "Type")) {
                 mCurrentSection =
-                    (mCurrentSection == SECTION_DECODER_TYPE
-                            ? SECTION_DECODER : SECTION_ENCODER);
+                        (mCurrentSection == SECTION_DECODER_TYPE ?
+                        SECTION_DECODER : SECTION_ENCODER);
 
-                mCurrentType = mCodecInfos[mCurrentName].mTypes.end();
+                mCurrentType = mCurrentCodec->second.typeMap.end();
             }
             break;
         }
 
         case SECTION_DECODER:
         {
-            if (!strcmp(name, "MediaCodec")) {
+            if (strEq(name, "MediaCodec")) {
                 mCurrentSection = SECTION_DECODERS;
                 mCurrentName.clear();
             }
@@ -386,7 +419,7 @@
 
         case SECTION_ENCODER:
         {
-            if (!strcmp(name, "MediaCodec")) {
+            if (strEq(name, "MediaCodec")) {
                 mCurrentSection = SECTION_ENCODERS;
                 mCurrentName.clear();
             }
@@ -395,9 +428,9 @@
 
         case SECTION_INCLUDE:
         {
-            if (!strcmp(name, "Include") && mPastSections.size() > 0) {
-                mCurrentSection = mPastSections.top();
-                mPastSections.pop();
+            if (strEq(name, "Include") && (mSectionStack.size() > 0)) {
+                mCurrentSection = mSectionStack.back();
+                mSectionStack.pop_back();
             }
             break;
         }
@@ -406,253 +439,282 @@
             break;
     }
 
-    --mDepth;
 }
 
 status_t MediaCodecsXmlParser::addSettingFromAttributes(const char **attrs) {
-    const char *name = NULL;
-    const char *value = NULL;
-    const char *update = NULL;
+    const char *name = nullptr;
+    const char *value = nullptr;
+    const char *update = nullptr;
 
     size_t i = 0;
-    while (attrs[i] != NULL) {
-        if (!strcmp(attrs[i], "name")) {
-            if (attrs[i + 1] == NULL) {
+    while (attrs[i] != nullptr) {
+        if (strEq(attrs[i], "name")) {
+            if (attrs[++i] == nullptr) {
                 ALOGE("addSettingFromAttributes: name is null");
                 return -EINVAL;
             }
-            name = attrs[i + 1];
-            ++i;
-        } else if (!strcmp(attrs[i], "value")) {
-            if (attrs[i + 1] == NULL) {
+            name = attrs[i];
+        } else if (strEq(attrs[i], "value")) {
+            if (attrs[++i] == nullptr) {
                 ALOGE("addSettingFromAttributes: value is null");
                 return -EINVAL;
             }
-            value = attrs[i + 1];
-            ++i;
-        } else if (!strcmp(attrs[i], "update")) {
-            if (attrs[i + 1] == NULL) {
+            value = attrs[i];
+        } else if (strEq(attrs[i], "update")) {
+            if (attrs[++i] == nullptr) {
                 ALOGE("addSettingFromAttributes: update is null");
                 return -EINVAL;
             }
-            update = attrs[i + 1];
-            ++i;
+            update = attrs[i];
         } else {
             ALOGE("addSettingFromAttributes: unrecognized attribute: %s", attrs[i]);
             return -EINVAL;
         }
-
         ++i;
     }
 
-    if (name == NULL || value == NULL) {
+    if (name == nullptr || value == nullptr) {
         ALOGE("addSettingFromAttributes: name or value unspecified");
         return -EINVAL;
     }
 
-    mUpdate = (update != NULL) && ParseBoolean(update);
-    if (mUpdate != (mGlobalSettings.count(name) > 0)) {
-        ALOGE("addSettingFromAttributes: updating non-existing setting");
-        return -EINVAL;
+    // Boolean values are converted to "0" or "1".
+    if (strHasPrefix(name, "supports-")) {
+        value = parseBoolean(value) ? "1" : "0";
     }
-    mGlobalSettings[name] = value;
+
+    mUpdate = (update != nullptr) && parseBoolean(update);
+    auto attribute = mServiceAttributeMap.find(name);
+    if (attribute == mServiceAttributeMap.end()) { // New attribute name
+        if (mUpdate) {
+            ALOGE("addSettingFromAttributes: updating non-existing setting");
+            return -EINVAL;
+        }
+        mServiceAttributeMap.insert(Attribute(name, value));
+    } else { // Existing attribute name
+        if (!mUpdate) {
+            ALOGE("addSettingFromAttributes: adding existing setting");
+        }
+        attribute->second = value;
+    }
 
     return OK;
 }
 
 status_t MediaCodecsXmlParser::addMediaCodecFromAttributes(
         bool encoder, const char **attrs) {
-    const char *name = NULL;
-    const char *type = NULL;
-    const char *update = NULL;
+    const char *name = nullptr;
+    const char *type = nullptr;
+    const char *update = nullptr;
 
     size_t i = 0;
-    while (attrs[i] != NULL) {
-        if (!strcmp(attrs[i], "name")) {
-            if (attrs[i + 1] == NULL) {
+    while (attrs[i] != nullptr) {
+        if (strEq(attrs[i], "name")) {
+            if (attrs[++i] == nullptr) {
                 ALOGE("addMediaCodecFromAttributes: name is null");
                 return -EINVAL;
             }
-            name = attrs[i + 1];
-            ++i;
-        } else if (!strcmp(attrs[i], "type")) {
-            if (attrs[i + 1] == NULL) {
+            name = attrs[i];
+        } else if (strEq(attrs[i], "type")) {
+            if (attrs[++i] == nullptr) {
                 ALOGE("addMediaCodecFromAttributes: type is null");
                 return -EINVAL;
             }
-            type = attrs[i + 1];
-            ++i;
-        } else if (!strcmp(attrs[i], "update")) {
-            if (attrs[i + 1] == NULL) {
+            type = attrs[i];
+        } else if (strEq(attrs[i], "update")) {
+            if (attrs[++i] == nullptr) {
                 ALOGE("addMediaCodecFromAttributes: update is null");
                 return -EINVAL;
             }
-            update = attrs[i + 1];
-            ++i;
+            update = attrs[i];
         } else {
             ALOGE("addMediaCodecFromAttributes: unrecognized attribute: %s", attrs[i]);
             return -EINVAL;
         }
-
         ++i;
     }
 
-    if (name == NULL) {
+    if (name == nullptr) {
         ALOGE("addMediaCodecFromAttributes: name not found");
         return -EINVAL;
     }
 
-    mUpdate = (update != NULL) && ParseBoolean(update);
-    if (mUpdate != (mCodecInfos.count(name) > 0)) {
-        ALOGE("addMediaCodecFromAttributes: updating non-existing codec or vice versa");
-        return -EINVAL;
-    }
-
-    CodecInfo *info = &mCodecInfos[name];
-    if (mUpdate) {
-        // existing codec
-        mCurrentName = name;
-        mCurrentType = info->mTypes.begin();
-        if (type != NULL) {
-            // existing type
-            mCurrentType = findTypeInfo(*info, type);
-            if (mCurrentType == info->mTypes.end()) {
+    mUpdate = (update != nullptr) && parseBoolean(update);
+    mCurrentCodec = mCodecMap.find(name);
+    if (mCurrentCodec == mCodecMap.end()) { // New codec name
+        if (mUpdate) {
+            ALOGE("addMediaCodecFromAttributes: updating non-existing codec");
+            return -EINVAL;
+        }
+        // Create a new codec in mCodecMap
+        mCurrentCodec = mCodecMap.insert(
+                Codec(name, CodecProperties())).first;
+        if (type != nullptr) {
+            mCurrentType = mCurrentCodec->second.typeMap.insert(
+                    Type(type, AttributeMap())).first;
+        } else {
+            mCurrentType = mCurrentCodec->second.typeMap.end();
+        }
+        mCurrentCodec->second.isEncoder = encoder;
+        mCurrentCodec->second.order = mCodecCounter++;
+    } else { // Existing codec name
+        if (!mUpdate) {
+            ALOGE("addMediaCodecFromAttributes: adding existing codec");
+            return -EINVAL;
+        }
+        if (type != nullptr) {
+            mCurrentType = mCurrentCodec->second.typeMap.find(type);
+            if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
                 ALOGE("addMediaCodecFromAttributes: updating non-existing type");
                 return -EINVAL;
             }
+        } else {
+            // This should happen only when the codec has at most one type.
+            mCurrentType = mCurrentCodec->second.typeMap.begin();
         }
-    } else {
-        // new codec
-        mCurrentName = name;
-        mQuirks[name].clear();
-        info->mTypes.clear();
-        info->mTypes.emplace_back();
-        mCurrentType = --info->mTypes.end();
-        mCurrentType->mName = type;
-        info->mIsEncoder = encoder;
     }
 
     return OK;
 }
 
 status_t MediaCodecsXmlParser::addQuirk(const char **attrs) {
-    const char *name = NULL;
+    const char *name = nullptr;
 
     size_t i = 0;
-    while (attrs[i] != NULL) {
-        if (!strcmp(attrs[i], "name")) {
-            if (attrs[i + 1] == NULL) {
+    while (attrs[i] != nullptr) {
+        if (strEq(attrs[i], "name")) {
+            if (attrs[++i] == nullptr) {
                 ALOGE("addQuirk: name is null");
                 return -EINVAL;
             }
-            name = attrs[i + 1];
-            ++i;
+            name = attrs[i];
         } else {
             ALOGE("addQuirk: unrecognized attribute: %s", attrs[i]);
             return -EINVAL;
         }
-
         ++i;
     }
 
-    if (name == NULL) {
+    if (name == nullptr) {
         ALOGE("addQuirk: name not found");
         return -EINVAL;
     }
 
-    mQuirks[mCurrentName].emplace_back(name);
+    mCurrentCodec->second.quirkSet.emplace(name);
     return OK;
 }
 
 status_t MediaCodecsXmlParser::addTypeFromAttributes(const char **attrs, bool encoder) {
-    const char *name = NULL;
-    const char *update = NULL;
+    const char *name = nullptr;
+    const char *update = nullptr;
 
     size_t i = 0;
-    while (attrs[i] != NULL) {
-        if (!strcmp(attrs[i], "name")) {
-            if (attrs[i + 1] == NULL) {
+    while (attrs[i] != nullptr) {
+        if (strEq(attrs[i], "name")) {
+            if (attrs[++i] == nullptr) {
                 ALOGE("addTypeFromAttributes: name is null");
                 return -EINVAL;
             }
-            name = attrs[i + 1];
-            ++i;
-        } else if (!strcmp(attrs[i], "update")) {
-            if (attrs[i + 1] == NULL) {
+            name = attrs[i];
+        } else if (strEq(attrs[i], "update")) {
+            if (attrs[++i] == nullptr) {
                 ALOGE("addTypeFromAttributes: update is null");
                 return -EINVAL;
             }
-            update = attrs[i + 1];
-            ++i;
+            update = attrs[i];
         } else {
             ALOGE("addTypeFromAttributes: unrecognized attribute: %s", attrs[i]);
             return -EINVAL;
         }
-
         ++i;
     }
 
-    if (name == NULL) {
+    if (name == nullptr) {
         return -EINVAL;
     }
 
-    CodecInfo *info = &mCodecInfos[mCurrentName];
-    info->mIsEncoder = encoder;
-    mCurrentType = findTypeInfo(*info, name);
+    mCurrentCodec->second.isEncoder = encoder;
+    mCurrentType = mCurrentCodec->second.typeMap.find(name);
     if (!mUpdate) {
-        if (mCurrentType != info->mTypes.end()) {
+        if (mCurrentType != mCurrentCodec->second.typeMap.end()) {
             ALOGE("addTypeFromAttributes: re-defining existing type without update");
             return -EINVAL;
         }
-        info->mTypes.emplace_back();
-        mCurrentType = --info->mTypes.end();
-    } else if (mCurrentType == info->mTypes.end()) {
+        mCurrentType = mCurrentCodec->second.typeMap.insert(
+                Type(name, AttributeMap())).first;
+    } else if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
         ALOGE("addTypeFromAttributes: updating non-existing type");
-        return -EINVAL;
     }
-
     return OK;
 }
 
-static status_t limitFoundMissingAttr(const AString &name, const char *attr, bool found = true) {
-    ALOGE("limit '%s' with %s'%s' attribute", name.c_str(),
-            (found ? "" : "no "), attr);
-    return -EINVAL;
-}
-
-static status_t limitError(const AString &name, const char *msg) {
-    ALOGE("limit '%s' %s", name.c_str(), msg);
-    return -EINVAL;
-}
-
-static status_t limitInvalidAttr(const AString &name, const char *attr, const AString &value) {
-    ALOGE("limit '%s' with invalid '%s' attribute (%s)", name.c_str(),
-            attr, value.c_str());
-    return -EINVAL;
-}
-
 status_t MediaCodecsXmlParser::addLimit(const char **attrs) {
-    sp<AMessage> msg = new AMessage();
+    const char* a_name = nullptr;
+    const char* a_default = nullptr;
+    const char* a_in = nullptr;
+    const char* a_max = nullptr;
+    const char* a_min = nullptr;
+    const char* a_range = nullptr;
+    const char* a_ranges = nullptr;
+    const char* a_scale = nullptr;
+    const char* a_value = nullptr;
 
     size_t i = 0;
-    while (attrs[i] != NULL) {
-        if (attrs[i + 1] == NULL) {
-            ALOGE("addLimit: limit is not given");
-            return -EINVAL;
-        }
-
-        // attributes with values
-        if (!strcmp(attrs[i], "name")
-                || !strcmp(attrs[i], "default")
-                || !strcmp(attrs[i], "in")
-                || !strcmp(attrs[i], "max")
-                || !strcmp(attrs[i], "min")
-                || !strcmp(attrs[i], "range")
-                || !strcmp(attrs[i], "ranges")
-                || !strcmp(attrs[i], "scale")
-                || !strcmp(attrs[i], "value")) {
-            msg->setString(attrs[i], attrs[i + 1]);
-            ++i;
+    while (attrs[i] != nullptr) {
+        if (strEq(attrs[i], "name")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addLimit: name is null");
+                return -EINVAL;
+            }
+            a_name = attrs[i];
+        } else if (strEq(attrs[i], "default")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addLimit: default is null");
+                return -EINVAL;
+            }
+            a_default = attrs[i];
+        } else if (strEq(attrs[i], "in")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addLimit: in is null");
+                return -EINVAL;
+            }
+            a_in = attrs[i];
+        } else if (strEq(attrs[i], "max")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addLimit: max is null");
+                return -EINVAL;
+            }
+            a_max = attrs[i];
+        } else if (strEq(attrs[i], "min")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addLimit: min is null");
+                return -EINVAL;
+            }
+            a_min = attrs[i];
+        } else if (strEq(attrs[i], "range")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addLimit: range is null");
+                return -EINVAL;
+            }
+            a_range = attrs[i];
+        } else if (strEq(attrs[i], "ranges")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addLimit: ranges is null");
+                return -EINVAL;
+            }
+            a_ranges = attrs[i];
+        } else if (strEq(attrs[i], "scale")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addLimit: scale is null");
+                return -EINVAL;
+            }
+            a_scale = attrs[i];
+        } else if (strEq(attrs[i], "value")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addLimit: value is null");
+                return -EINVAL;
+            }
+            a_value = attrs[i];
         } else {
             ALOGE("addLimit: unrecognized limit: %s", attrs[i]);
             return -EINVAL;
@@ -660,8 +722,7 @@
         ++i;
     }
 
-    AString name;
-    if (!msg->findString("name", &name)) {
+    if (a_name == nullptr) {
         ALOGE("limit with no 'name' attribute");
         return -EINVAL;
     }
@@ -670,109 +731,148 @@
     // measured-frame-rate, measured-blocks-per-second: range
     // quality: range + default + [scale]
     // complexity: range + default
-    bool found;
-    if (mCurrentType == mCodecInfos[mCurrentName].mTypes.end()) {
+    if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
         ALOGW("ignoring null type");
         return OK;
     }
 
-    if (name == "aspect-ratio" || name == "bitrate" || name == "block-count"
-            || name == "blocks-per-second" || name == "complexity"
-            || name == "frame-rate" || name == "quality" || name == "size"
-            || name == "measured-blocks-per-second" || name.startsWith("measured-frame-rate-")) {
-        AString min, max;
-        if (msg->findString("min", &min) && msg->findString("max", &max)) {
-            min.append("-");
-            min.append(max);
-            if (msg->contains("range") || msg->contains("value")) {
-                return limitError(name, "has 'min' and 'max' as well as 'range' or "
+    std::string range;
+    if (strEq(a_name, "aspect-ratio") ||
+            strEq(a_name, "bitrate") ||
+            strEq(a_name, "block-count") ||
+            strEq(a_name, "blocks-per-second") ||
+            strEq(a_name, "complexity") ||
+            strEq(a_name, "frame-rate") ||
+            strEq(a_name, "quality") ||
+            strEq(a_name, "size") ||
+            strEq(a_name, "measured-blocks-per-second") ||
+            strHasPrefix(a_name, "measured-frame-rate-")) {
+        // "range" is specified in exactly one of the following forms:
+        // 1) min-max
+        // 2) value-value
+        // 3) range
+        if (a_min != nullptr && a_max != nullptr) {
+            // min-max
+            if (a_range != nullptr || a_value != nullptr) {
+                return limitError(a_name, "has 'min' and 'max' as well as 'range' or "
                         "'value' attributes");
             }
-            msg->setString("range", min);
-        } else if (msg->contains("min") || msg->contains("max")) {
-            return limitError(name, "has only 'min' or 'max' attribute");
-        } else if (msg->findString("value", &max)) {
-            min = max;
-            min.append("-");
-            min.append(max);
-            if (msg->contains("range")) {
-                return limitError(name, "has both 'range' and 'value' attributes");
+            range = a_min;
+            range += '-';
+            range += a_max;
+        } else if (a_min != nullptr || a_max != nullptr) {
+            return limitError(a_name, "has only 'min' or 'max' attribute");
+        } else if (a_value != nullptr) {
+            // value-value
+            if (a_range != nullptr) {
+                return limitError(a_name, "has both 'range' and 'value' attributes");
             }
-            msg->setString("range", min);
-        }
-
-        AString range, scale = "linear", def, in_;
-        if (!msg->findString("range", &range)) {
-            return limitError(name, "with no 'range', 'value' or 'min'/'max' attributes");
-        }
-
-        if ((name == "quality" || name == "complexity") ^
-                (found = msg->findString("default", &def))) {
-            return limitFoundMissingAttr(name, "default", found);
-        }
-        if (name != "quality" && msg->findString("scale", &scale)) {
-            return limitFoundMissingAttr(name, "scale");
-        }
-        if ((name == "aspect-ratio") ^ (found = msg->findString("in", &in_))) {
-            return limitFoundMissingAttr(name, "in", found);
-        }
-
-        if (name == "aspect-ratio") {
-            if (!(in_ == "pixels") && !(in_ == "blocks")) {
-                return limitInvalidAttr(name, "in", in_);
-            }
-            in_.erase(5, 1); // (pixel|block)-aspect-ratio
-            in_.append("-");
-            in_.append(name);
-            name = in_;
-        }
-        if (name == "quality") {
-            mCurrentType->mDetails["quality-scale"] = scale;
-        }
-        if (name == "quality" || name == "complexity") {
-            AString tag = name;
-            tag.append("-default");
-            mCurrentType->mDetails[tag] = def;
-        }
-        AString tag = name;
-        tag.append("-range");
-        mCurrentType->mDetails[tag] = range;
-    } else {
-        AString max, value, ranges;
-        if (msg->contains("default")) {
-            return limitFoundMissingAttr(name, "default");
-        } else if (msg->contains("in")) {
-            return limitFoundMissingAttr(name, "in");
-        } else if ((name == "channel-count" || name == "concurrent-instances") ^
-                (found = msg->findString("max", &max))) {
-            return limitFoundMissingAttr(name, "max", found);
-        } else if (msg->contains("min")) {
-            return limitFoundMissingAttr(name, "min");
-        } else if (msg->contains("range")) {
-            return limitFoundMissingAttr(name, "range");
-        } else if ((name == "sample-rate") ^
-                (found = msg->findString("ranges", &ranges))) {
-            return limitFoundMissingAttr(name, "ranges", found);
-        } else if (msg->contains("scale")) {
-            return limitFoundMissingAttr(name, "scale");
-        } else if ((name == "alignment" || name == "block-size") ^
-                (found = msg->findString("value", &value))) {
-            return limitFoundMissingAttr(name, "value", found);
-        }
-
-        if (max.size()) {
-            AString tag = "max-";
-            tag.append(name);
-            mCurrentType->mDetails[tag] = max;
-        } else if (value.size()) {
-            mCurrentType->mDetails[name] = value;
-        } else if (ranges.size()) {
-            AString tag = name;
-            tag.append("-ranges");
-            mCurrentType->mDetails[tag] = ranges;
+            range = a_value;
+            range += '-';
+            range += a_value;
+        } else if (a_range == nullptr) {
+            return limitError(a_name, "with no 'range', 'value' or 'min'/'max' attributes");
         } else {
-            ALOGW("Ignoring unrecognized limit '%s'", name.c_str());
+            // range
+            range = a_range;
         }
+
+        // "aspect-ratio" requires some special treatment.
+        if (strEq(a_name, "aspect-ratio")) {
+            // "aspect-ratio" must have "in".
+            if (a_in == nullptr) {
+                return limitFoundMissingAttr(a_name, "in", false);
+            }
+            // "in" must be either "pixels" or "blocks".
+            if (!strEq(a_in, "pixels") && !strEq(a_in, "blocks")) {
+                return limitInvalidAttr(a_name, "in", a_in);
+            }
+            // name will be "pixel-aspect-ratio-range" or
+            // "block-aspect-ratio-range".
+            mCurrentType->second[
+                    std::string(a_in).substr(0, strlen(a_in) - 1) +
+                    "-aspect-ratio-range"] = range;
+        } else {
+            // For everything else (apart from "aspect-ratio"), simply append
+            // "-range" to the name for the range-type property.
+            mCurrentType->second[std::string(a_name) + "-range"] = range;
+
+            // Only "quality" may have "scale".
+            if (!strEq(a_name, "quality") && a_scale != nullptr) {
+                return limitFoundMissingAttr(a_name, "scale");
+            } else if (strEq(a_name, "quality")) {
+                // The default value of "quality-scale" is "linear".
+                mCurrentType->second["quality-scale"] = a_scale == nullptr ?
+                        "linear" : a_scale;
+            }
+
+            // "quality" and "complexity" must have "default".
+            // Other limits must not have "default".
+            if (strEq(a_name, "quality") || strEq(a_name, "complexity")) {
+                if (a_default == nullptr) {
+                    return limitFoundMissingAttr(a_name, "default", false);
+                }
+                // name will be "quality-default" or "complexity-default".
+                mCurrentType->second[std::string(a_name) + "-default"] = a_default;
+            } else if (a_default != nullptr) {
+                return limitFoundMissingAttr(a_name, "default", true);
+            }
+        }
+    } else {
+        if (a_default != nullptr) {
+            return limitFoundMissingAttr(a_name, "default");
+        }
+        if (a_in != nullptr) {
+            return limitFoundMissingAttr(a_name, "in");
+        }
+        if (a_scale != nullptr) {
+            return limitFoundMissingAttr(a_name, "scale");
+        }
+        if (a_range != nullptr) {
+            return limitFoundMissingAttr(a_name, "range");
+        }
+        if (a_min != nullptr) {
+            return limitFoundMissingAttr(a_name, "min");
+        }
+
+        if (a_max != nullptr) {
+            // "max" must exist if and only if name is "channel-count" or
+            // "concurrent-instances".
+            // "min" is not ncessary.
+            if (strEq(a_name, "channel-count") ||
+                    strEq(a_name, "concurrent-instances")) {
+                mCurrentType->second[std::string("max-") + a_name] = a_max;
+            } else {
+                return limitFoundMissingAttr(a_name, "max", false);
+            }
+        } else if (strEq(a_name, "channel-count") ||
+                strEq(a_name, "concurrent-instances")) {
+            return limitFoundMissingAttr(a_name, "max");
+        }
+
+        if (a_ranges != nullptr) {
+            // "ranges" must exist if and only if name is "sample-rate".
+            if (strEq(a_name, "sample-rate")) {
+                mCurrentType->second["sample-rate-ranges"] = a_ranges;
+            } else {
+                return limitFoundMissingAttr(a_name, "ranges", false);
+            }
+        } else if (strEq(a_name, "sample-rate")) {
+            return limitFoundMissingAttr(a_name, "ranges");
+        }
+
+        if (a_value != nullptr) {
+            // "value" must exist if and only if name is "alignment" or
+            // "block-size".
+            if (strEq(a_name, "alignment") || strEq(a_name, "block-size")) {
+                mCurrentType->second[a_name] = a_value;
+            } else {
+                return limitFoundMissingAttr(a_name, "value", false);
+            }
+        } else if (strEq(a_name, "alignment") || strEq(a_name, "block-size")) {
+            return limitFoundMissingAttr(a_name, "value", false);
+        }
+
     }
 
     return OK;
@@ -780,83 +880,175 @@
 
 status_t MediaCodecsXmlParser::addFeature(const char **attrs) {
     size_t i = 0;
-    const char *name = NULL;
+    const char *name = nullptr;
     int32_t optional = -1;
     int32_t required = -1;
-    const char *value = NULL;
+    const char *value = nullptr;
 
-    while (attrs[i] != NULL) {
-        if (attrs[i + 1] == NULL) {
-            ALOGE("addFeature: feature is not given");
-            return -EINVAL;
-        }
-
-        // attributes with values
-        if (!strcmp(attrs[i], "name")) {
-            name = attrs[i + 1];
-            ++i;
-        } else if (!strcmp(attrs[i], "optional") || !strcmp(attrs[i], "required")) {
-            int value = (int)ParseBoolean(attrs[i + 1]);
-            if (!strcmp(attrs[i], "optional")) {
-                optional = value;
-            } else {
-                required = value;
+    while (attrs[i] != nullptr) {
+        if (strEq(attrs[i], "name")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addFeature: name is null");
+                return -EINVAL;
             }
-            ++i;
-        } else if (!strcmp(attrs[i], "value")) {
-            value = attrs[i + 1];
-            ++i;
+            name = attrs[i];
+        } else if (strEq(attrs[i], "optional")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addFeature: optional is null");
+                return -EINVAL;
+            }
+            optional = parseBoolean(attrs[i]) ? 1 : 0;
+        } else if (strEq(attrs[i], "required")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addFeature: required is null");
+                return -EINVAL;
+            }
+            required = parseBoolean(attrs[i]) ? 1 : 0;
+        } else if (strEq(attrs[i], "value")) {
+            if (attrs[++i] == nullptr) {
+                ALOGE("addFeature: value is null");
+                return -EINVAL;
+            }
+            value = attrs[i];
         } else {
             ALOGE("addFeature: unrecognized attribute: %s", attrs[i]);
             return -EINVAL;
         }
         ++i;
     }
-    if (name == NULL) {
+
+    // Every feature must have a name.
+    if (name == nullptr) {
         ALOGE("feature with no 'name' attribute");
         return -EINVAL;
     }
 
-    if (optional == required && optional != -1) {
-        ALOGE("feature '%s' is both/neither optional and required", name);
-        return -EINVAL;
-    }
-
-    if (mCurrentType == mCodecInfos[mCurrentName].mTypes.end()) {
+    if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
         ALOGW("ignoring null type");
         return OK;
     }
-    if (value != NULL) {
-        mCurrentType->mStringFeatures[name] = value;
-    } else {
-        mCurrentType->mBoolFeatures[name] = (required == 1) || (optional == 0);
+
+    if ((optional != -1) || (required != -1)) {
+        if (optional == required) {
+            ALOGE("feature '%s' is both/neither optional and required", name);
+            return -EINVAL;
+        }
+        if ((optional == 1) || (required == 1)) {
+            if (value != nullptr) {
+                ALOGE("feature '%s' cannot have extra 'value'", name);
+                return -EINVAL;
+            }
+            mCurrentType->second[std::string("feature-") + name] =
+                    optional == 1 ? "0" : "1";
+            return OK;
+        }
     }
+    mCurrentType->second[std::string("feature-") + name] = value == nullptr ?
+            "0" : value;
     return OK;
 }
 
-void MediaCodecsXmlParser::getGlobalSettings(
-        std::map<AString, AString> *settings) const {
-    settings->clear();
-    settings->insert(mGlobalSettings.begin(), mGlobalSettings.end());
+const MediaCodecsXmlParser::AttributeMap&
+        MediaCodecsXmlParser::getServiceAttributeMap() const {
+    return mServiceAttributeMap;
 }
 
-status_t MediaCodecsXmlParser::getCodecInfo(const char *name, CodecInfo *info) const {
-    if (mCodecInfos.count(name) == 0) {
-        ALOGE("Codec not found with name '%s'", name);
-        return NAME_NOT_FOUND;
+const MediaCodecsXmlParser::CodecMap&
+        MediaCodecsXmlParser::getCodecMap() const {
+    return mCodecMap;
+}
+
+const MediaCodecsXmlParser::RoleMap&
+        MediaCodecsXmlParser::getRoleMap() const {
+    if (mRoleMap.empty()) {
+        generateRoleMap();
     }
-    *info = mCodecInfos.at(name);
-    return OK;
+    return mRoleMap;
 }
 
-status_t MediaCodecsXmlParser::getQuirks(const char *name, std::vector<AString> *quirks) const {
-    if (mQuirks.count(name) == 0) {
-        ALOGE("Codec not found with name '%s'", name);
-        return NAME_NOT_FOUND;
+const char* MediaCodecsXmlParser::getCommonPrefix() const {
+    if (mCommonPrefix.empty()) {
+        generateCommonPrefix();
     }
-    quirks->clear();
-    quirks->insert(quirks->end(), mQuirks.at(name).begin(), mQuirks.at(name).end());
-    return OK;
+    return mCommonPrefix.data();
 }
 
-}  // namespace android
+status_t MediaCodecsXmlParser::getParsingStatus() const {
+    return mParsingStatus;
+}
+
+void MediaCodecsXmlParser::generateRoleMap() const {
+    for (const auto& codec : mCodecMap) {
+        const auto& codecName = codec.first;
+        bool isEncoder = codec.second.isEncoder;
+        size_t order = codec.second.order;
+        const auto& typeMap = codec.second.typeMap;
+        for (const auto& type : typeMap) {
+            const auto& typeName = type.first;
+            const char* roleName = GetComponentRole(isEncoder, typeName.data());
+            if (roleName == nullptr) {
+                ALOGE("Cannot find the role for %s of type %s",
+                        isEncoder ? "an encoder" : "a decoder",
+                        typeName.data());
+                continue;
+            }
+            const auto& typeAttributeMap = type.second;
+
+            auto roleIterator = mRoleMap.find(roleName);
+            std::multimap<size_t, NodeInfo>* nodeList;
+            if (roleIterator == mRoleMap.end()) {
+                RoleProperties roleProperties;
+                roleProperties.type = typeName;
+                roleProperties.isEncoder = isEncoder;
+                auto insertResult = mRoleMap.insert(
+                        std::make_pair(roleName, roleProperties));
+                if (!insertResult.second) {
+                    ALOGE("Cannot add role %s", roleName);
+                    continue;
+                }
+                nodeList = &insertResult.first->second.nodeList;
+            } else {
+                if (roleIterator->second.type != typeName) {
+                    ALOGE("Role %s has mismatching types: %s and %s",
+                            roleName,
+                            roleIterator->second.type.data(),
+                            typeName.data());
+                    continue;
+                }
+                if (roleIterator->second.isEncoder != isEncoder) {
+                    ALOGE("Role %s cannot be both an encoder and a decoder",
+                            roleName);
+                    continue;
+                }
+                nodeList = &roleIterator->second.nodeList;
+            }
+
+            NodeInfo nodeInfo;
+            nodeInfo.name = codecName;
+            nodeInfo.attributeList.reserve(typeAttributeMap.size());
+            for (const auto& attribute : typeAttributeMap) {
+                nodeInfo.attributeList.push_back(
+                        Attribute{attribute.first, attribute.second});
+            }
+            nodeList->insert(std::make_pair(
+                    std::move(order), std::move(nodeInfo)));
+        }
+    }
+}
+
+void MediaCodecsXmlParser::generateCommonPrefix() const {
+    if (mCodecMap.empty()) {
+        return;
+    }
+    auto i = mCodecMap.cbegin();
+    auto first = i->first.cbegin();
+    auto last = i->first.cend();
+    for (++i; i != mCodecMap.cend(); ++i) {
+        last = std::mismatch(
+                first, last, i->first.cbegin(), i->first.cend()).first;
+    }
+    mCommonPrefix.insert(mCommonPrefix.begin(), first, last);
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
index b324cd8..cc69e52 100644
--- a/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
+++ b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
@@ -14,65 +14,107 @@
  * limitations under the License.
  */
 
-#ifndef MEDIA_CODECS_XML_PARSER_H_
-
-#define MEDIA_CODECS_XML_PARSER_H_
-
-#include <map>
-#include <vector>
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AString.h>
+#ifndef MEDIA_STAGEFRIGHT_XMLPARSER_H_
+#define MEDIA_STAGEFRIGHT_XMLPARSER_H_
 
 #include <sys/types.h>
 #include <utils/Errors.h>
 #include <utils/Vector.h>
 #include <utils/StrongPointer.h>
 
+#include <string>
+#include <set>
+#include <map>
+#include <vector>
+
 namespace android {
 
-struct AMessage;
-
-// Quirk still supported, even though deprecated
-enum Quirks {
-    kRequiresAllocateBufferOnInputPorts   = 1,
-    kRequiresAllocateBufferOnOutputPorts  = 2,
-
-    kQuirksMask = kRequiresAllocateBufferOnInputPorts
-                | kRequiresAllocateBufferOnOutputPorts,
-};
-
-// Lightweight struct for querying components.
-struct TypeInfo {
-    AString mName;
-    std::map<AString, AString> mStringFeatures;
-    std::map<AString, bool> mBoolFeatures;
-    std::map<AString, AString> mDetails;
-};
-
-struct ProfileLevel {
-    uint32_t mProfile;
-    uint32_t mLevel;
-};
-
-struct CodecInfo {
-    std::vector<TypeInfo> mTypes;
-    std::vector<ProfileLevel> mProfileLevels;
-    std::vector<uint32_t> mColorFormats;
-    uint32_t mFlags;
-    bool mIsEncoder;
-};
-
 class MediaCodecsXmlParser {
 public:
-    MediaCodecsXmlParser();
+
+    // Treblized media codec list will be located in /odm/etc or /vendor/etc.
+    static constexpr char const* defaultSearchDirs[] =
+            {"/odm/etc", "/vendor/etc", "/etc", nullptr};
+    static constexpr char const* defaultMainXmlName =
+            "media_codecs.xml";
+    static constexpr char const* defaultPerformanceXmlName =
+            "media_codecs_performance.xml";
+    static constexpr char const* defaultProfilingResultsXmlPath =
+            "/data/misc/media/media_codecs_profiling_results.xml";
+
+    MediaCodecsXmlParser(
+            const char* const* searchDirs = defaultSearchDirs,
+            const char* mainXmlName = defaultMainXmlName,
+            const char* performanceXmlName = defaultPerformanceXmlName,
+            const char* profilingResultsXmlPath = defaultProfilingResultsXmlPath);
     ~MediaCodecsXmlParser();
 
-    void getGlobalSettings(std::map<AString, AString> *settings) const;
+    typedef std::pair<std::string, std::string> Attribute;
+    typedef std::map<std::string, std::string> AttributeMap;
 
-    status_t getCodecInfo(const char *name, CodecInfo *info) const;
+    typedef std::pair<std::string, AttributeMap> Type;
+    typedef std::map<std::string, AttributeMap> TypeMap;
 
-    status_t getQuirks(const char *name, std::vector<AString> *quirks) const;
+    typedef std::set<std::string> QuirkSet;
+
+    /**
+     * Properties of a codec (node)
+     */
+    struct CodecProperties {
+        bool isEncoder;    ///< Whether this codec is an encoder or a decoder
+        size_t order;      ///< Order of appearance in the file (starting from 0)
+        QuirkSet quirkSet; ///< Set of quirks requested by this codec
+        TypeMap typeMap;   ///< Map of types supported by this codec
+    };
+
+    typedef std::pair<std::string, CodecProperties> Codec;
+    typedef std::map<std::string, CodecProperties> CodecMap;
+
+    /**
+     * Properties of a node (for IOmxStore)
+     */
+    struct NodeInfo {
+        std::string name;
+        std::vector<Attribute> attributeList;
+    };
+
+    /**
+     * Properties of a role (for IOmxStore)
+     */
+    struct RoleProperties {
+        std::string type;
+        bool isEncoder;
+        std::multimap<size_t, NodeInfo> nodeList;
+    };
+
+    typedef std::pair<std::string, RoleProperties> Role;
+    typedef std::map<std::string, RoleProperties> RoleMap;
+
+    /**
+     * Return a map for attributes that are service-specific.
+     */
+    const AttributeMap& getServiceAttributeMap() const;
+
+    /**
+     * Return a map for codecs and their properties.
+     */
+    const CodecMap& getCodecMap() const;
+
+    /**
+     * Return a map for roles and their properties.
+     * This map is generated from the CodecMap.
+     */
+    const RoleMap& getRoleMap() const;
+
+    /**
+     * Return a common prefix of all node names.
+     *
+     * The prefix is not provided in the xml, so it has to be computed by taking
+     * the longest common prefix of all node names.
+     */
+    const char* getCommonPrefix() const;
+
+    status_t getParsingStatus() const;
 
 private:
     enum Section {
@@ -87,23 +129,31 @@
         SECTION_INCLUDE,
     };
 
-    status_t mInitCheck;
+    status_t mParsingStatus;
     Section mCurrentSection;
     bool mUpdate;
-    Vector<Section> mPastSections;
-    int32_t mDepth;
-    AString mHrefBase;
+    std::vector<Section> mSectionStack;
+    std::string mHrefBase;
 
-    std::map<AString, AString> mGlobalSettings;
+    // Service attributes
+    AttributeMap mServiceAttributeMap;
 
-    // name -> CodecInfo
-    std::map<AString, CodecInfo> mCodecInfos;
-    std::map<AString, std::vector<AString>> mQuirks;
-    AString mCurrentName;
-    std::vector<TypeInfo>::iterator mCurrentType;
+    // Codec attributes
+    std::string mCurrentName;
+    std::set<std::string> mCodecSet;
+    Codec mCodecListTemp[2048];
+    CodecMap mCodecMap;
+    size_t mCodecCounter;
+    CodecMap::iterator mCurrentCodec;
+    TypeMap::iterator mCurrentType;
 
-    status_t initCheck() const;
-    void parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
+    // Role map
+    mutable RoleMap mRoleMap;
+
+    // Computed longest common prefix
+    mutable std::string mCommonPrefix;
+
+    bool parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
 
     void parseXMLFile(const char *path);
 
@@ -118,7 +168,8 @@
     status_t includeXMLFile(const char **attrs);
     status_t addSettingFromAttributes(const char **attrs);
     status_t addMediaCodecFromAttributes(bool encoder, const char **attrs);
-    void addMediaCodec(bool encoder, const char *name, const char *type = NULL);
+    void addMediaCodec(bool encoder, const char *name,
+            const char *type = nullptr);
 
     status_t addQuirk(const char **attrs);
     status_t addTypeFromAttributes(const char **attrs, bool encoder);
@@ -126,10 +177,14 @@
     status_t addFeature(const char **attrs);
     void addType(const char *name);
 
-    DISALLOW_EVIL_CONSTRUCTORS(MediaCodecsXmlParser);
+    void generateRoleMap() const;
+    void generateCommonPrefix() const;
+
+    MediaCodecsXmlParser(const MediaCodecsXmlParser&) = delete;
+    MediaCodecsXmlParser& operator=(const MediaCodecsXmlParser&) = delete;
 };
 
-}  // namespace android
+} // namespace android
 
-#endif  // MEDIA_CODECS_XML_PARSER_H_
+#endif // MEDIA_STAGEFRIGHT_XMLPARSER_H_
 
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index 4e6ac7a..c7021df 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -103,6 +103,9 @@
 
     virtual MtpProperty*            getDevicePropertyDesc(MtpDeviceProperty property) = 0;
 
+    virtual MtpResponseCode         moveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+                                            MtpString& newPath) = 0;
+
     virtual void                    sessionStarted() = 0;
 
     virtual void                    sessionEnded() = 0;
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 89b20e5..965985d 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -94,8 +94,11 @@
     __le32 fs_count;
     __le32 hs_count;
     __le32 ss_count;
+    __le32 os_count;
     struct func_desc fs_descs, hs_descs;
     struct ss_func_desc ss_descs;
+    struct usb_os_desc_header os_header;
+    struct usb_ext_compat_desc os_desc;
 } __attribute__((packed));
 
 const struct usb_interface_descriptor mtp_interface_desc = {
@@ -261,6 +264,31 @@
     },
 };
 
+struct usb_os_desc_header mtp_os_desc_header = {
+    .interface = htole32(1),
+    .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
+    .bcdVersion = htole16(1),
+    .wIndex = htole16(4),
+    .bCount = htole16(1),
+    .Reserved = htole16(0),
+};
+
+struct usb_ext_compat_desc mtp_os_desc_compat = {
+    .bFirstInterfaceNumber = 0,
+    .Reserved1 = htole32(1),
+    .CompatibleID = { 'M', 'T', 'P' },
+    .SubCompatibleID = {0},
+    .Reserved2 = {0},
+};
+
+struct usb_ext_compat_desc ptp_os_desc_compat = {
+    .bFirstInterfaceNumber = 0,
+    .Reserved1 = htole32(1),
+    .CompatibleID = { 'P', 'T', 'P' },
+    .SubCompatibleID = {0},
+    .Reserved2 = {0},
+};
+
 struct mtp_device_status {
     uint16_t  wLength;
     uint16_t  wCode;
@@ -336,13 +364,16 @@
     v2_descriptor.header.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
     v2_descriptor.header.length = htole32(sizeof(v2_descriptor));
     v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
-                                 FUNCTIONFS_HAS_SS_DESC;
+                                 FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
     v2_descriptor.fs_count = 4;
     v2_descriptor.hs_count = 4;
     v2_descriptor.ss_count = 7;
+    v2_descriptor.os_count = 1;
     v2_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
     v2_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
     v2_descriptor.ss_descs = mPtp ? ptp_ss_descriptors : mtp_ss_descriptors;
+    v2_descriptor.os_header = mtp_os_desc_header;
+    v2_descriptor.os_desc = mPtp ? ptp_os_desc_compat : mtp_os_desc_compat;
 
     if (mControl < 0) { // might have already done this before
         mControl.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP0, O_RDWR)));
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index e148b0c..236f3a9 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -67,8 +67,8 @@
     MTP_OPERATION_SET_DEVICE_PROP_VALUE,
     MTP_OPERATION_RESET_DEVICE_PROP_VALUE,
 //    MTP_OPERATION_TERMINATE_OPEN_CAPTURE,
-//    MTP_OPERATION_MOVE_OBJECT,
-//    MTP_OPERATION_COPY_OBJECT,
+    MTP_OPERATION_MOVE_OBJECT,
+    MTP_OPERATION_COPY_OBJECT,
     MTP_OPERATION_GET_PARTIAL_OBJECT,
 //    MTP_OPERATION_INITIATE_OPEN_CAPTURE,
     MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
@@ -437,6 +437,12 @@
         case MTP_OPERATION_DELETE_OBJECT:
             response = doDeleteObject();
             break;
+        case MTP_OPERATION_COPY_OBJECT:
+            response = doCopyObject();
+            break;
+        case MTP_OPERATION_MOVE_OBJECT:
+            response = doMoveObject();
+            break;
         case MTP_OPERATION_GET_OBJECT_PROP_DESC:
             response = doGetObjectPropDesc();
             break;
@@ -1020,6 +1026,137 @@
     return MTP_RESPONSE_OK;
 }
 
+MtpResponseCode MtpServer::doMoveObject() {
+    if (!hasStorage())
+        return MTP_RESPONSE_GENERAL_ERROR;
+    if (mRequest.getParameterCount() < 3)
+        return MTP_RESPONSE_INVALID_PARAMETER;
+    MtpObjectHandle objectHandle = mRequest.getParameter(1);
+    MtpStorageID storageID = mRequest.getParameter(2);
+    MtpStorage* storage = getStorage(storageID);
+    MtpObjectHandle parent = mRequest.getParameter(3);
+    if (!storage)
+        return MTP_RESPONSE_INVALID_STORAGE_ID;
+    MtpString path;
+    MtpResponseCode result;
+
+    MtpString fromPath;
+    int64_t fileLength;
+    MtpObjectFormat format;
+    MtpObjectInfo info(objectHandle);
+    result = mDatabase->getObjectInfo(objectHandle, info);
+    if (result != MTP_RESPONSE_OK)
+        return result;
+    result = mDatabase->getObjectFilePath(objectHandle, fromPath, fileLength, format);
+    if (result != MTP_RESPONSE_OK)
+        return result;
+
+    // special case the root
+    if (parent == 0) {
+        path = storage->getPath();
+    } else {
+        int64_t parentLength;
+        MtpObjectFormat parentFormat;
+        result = mDatabase->getObjectFilePath(parent, path, parentLength, parentFormat);
+        if (result != MTP_RESPONSE_OK)
+            return result;
+        if (parentFormat != MTP_FORMAT_ASSOCIATION)
+            return MTP_RESPONSE_INVALID_PARENT_OBJECT;
+    }
+
+    if (path[path.size() - 1] != '/')
+        path += "/";
+    path += info.mName;
+
+    result = mDatabase->moveObject(objectHandle, parent, path);
+    if (result != MTP_RESPONSE_OK)
+        return result;
+
+    if (info.mStorageID == storageID) {
+        ALOGV("Moving file from %s to %s", (const char*)fromPath, (const char*)path);
+        if (rename(fromPath, path)) {
+            ALOGE("rename() failed from %s to %s", (const char*)fromPath, (const char*)path);
+            result = MTP_RESPONSE_GENERAL_ERROR;
+        }
+    } else {
+        ALOGV("Moving across storages from %s to %s", (const char*)fromPath, (const char*)path);
+        if (copyFile(fromPath, path)) {
+            result = MTP_RESPONSE_GENERAL_ERROR;
+        } else {
+            deletePath(fromPath);
+        }
+    }
+
+    // If the move failed, undo the database change
+    if (result != MTP_RESPONSE_OK)
+        if (mDatabase->moveObject(objectHandle, info.mParent, fromPath) != MTP_RESPONSE_OK)
+            ALOGE("Couldn't undo failed move");
+
+    return result;
+}
+
+MtpResponseCode MtpServer::doCopyObject() {
+    if (!hasStorage())
+        return MTP_RESPONSE_GENERAL_ERROR;
+    MtpResponseCode result = MTP_RESPONSE_OK;
+    if (mRequest.getParameterCount() < 3)
+        return MTP_RESPONSE_INVALID_PARAMETER;
+    MtpObjectHandle objectHandle = mRequest.getParameter(1);
+    MtpStorageID storageID = mRequest.getParameter(2);
+    MtpStorage* storage = getStorage(storageID);
+    MtpObjectHandle parent = mRequest.getParameter(3);
+    if (!storage)
+        return MTP_RESPONSE_INVALID_STORAGE_ID;
+    MtpString path;
+
+    MtpString fromPath;
+    int64_t fileLength;
+    MtpObjectFormat format;
+    MtpObjectInfo info(objectHandle);
+    result = mDatabase->getObjectInfo(objectHandle, info);
+    if (result != MTP_RESPONSE_OK)
+        return result;
+    result = mDatabase->getObjectFilePath(objectHandle, fromPath, fileLength, format);
+    if (result != MTP_RESPONSE_OK)
+        return result;
+
+    // special case the root
+    if (parent == 0) {
+        path = storage->getPath();
+    } else {
+        int64_t parentLength;
+        MtpObjectFormat parentFormat;
+        result = mDatabase->getObjectFilePath(parent, path, parentLength, parentFormat);
+        if (result != MTP_RESPONSE_OK)
+            return result;
+        if (parentFormat != MTP_FORMAT_ASSOCIATION)
+            return MTP_RESPONSE_INVALID_PARENT_OBJECT;
+    }
+
+    // check space first
+    if ((uint64_t) fileLength > storage->getFreeSpace())
+        return MTP_RESPONSE_STORAGE_FULL;
+
+    if (path[path.size() - 1] != '/')
+        path += "/";
+    path += info.mName;
+
+    MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
+            format, parent, storageID, fileLength, info.mDateModified);
+    if (handle == kInvalidObjectHandle) {
+        return MTP_RESPONSE_GENERAL_ERROR;
+    }
+
+    ALOGV("Copying file from %s to %s", (const char*)fromPath, (const char*)path);
+    if (copyFile(fromPath, path)) {
+        result = MTP_RESPONSE_GENERAL_ERROR;
+    }
+
+    mDatabase->endSendObject(path, handle, format, result);
+    mResponse.setParameter(1, handle);
+    return result;
+}
+
 MtpResponseCode MtpServer::doSendObject() {
     if (!hasStorage())
         return MTP_RESPONSE_GENERAL_ERROR;
@@ -1124,65 +1261,6 @@
     return result;
 }
 
-static void deleteRecursive(const char* path) {
-    char pathbuf[PATH_MAX];
-    size_t pathLength = strlen(path);
-    if (pathLength >= sizeof(pathbuf) - 1) {
-        ALOGE("path too long: %s\n", path);
-    }
-    strcpy(pathbuf, path);
-    if (pathbuf[pathLength - 1] != '/') {
-        pathbuf[pathLength++] = '/';
-    }
-    char* fileSpot = pathbuf + pathLength;
-    int pathRemaining = sizeof(pathbuf) - pathLength - 1;
-
-    DIR* dir = opendir(path);
-    if (!dir) {
-        ALOGE("opendir %s failed: %s", path, strerror(errno));
-        return;
-    }
-
-    struct dirent* entry;
-    while ((entry = readdir(dir))) {
-        const char* name = entry->d_name;
-
-        // ignore "." and ".."
-        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
-            continue;
-        }
-
-        int nameLength = strlen(name);
-        if (nameLength > pathRemaining) {
-            ALOGE("path %s/%s too long\n", path, name);
-            continue;
-        }
-        strcpy(fileSpot, name);
-
-        if (entry->d_type == DT_DIR) {
-            deleteRecursive(pathbuf);
-            rmdir(pathbuf);
-        } else {
-            unlink(pathbuf);
-        }
-    }
-    closedir(dir);
-}
-
-static void deletePath(const char* path) {
-    struct stat statbuf;
-    if (stat(path, &statbuf) == 0) {
-        if (S_ISDIR(statbuf.st_mode)) {
-            deleteRecursive(path);
-            rmdir(path);
-        } else {
-            unlink(path);
-        }
-    } else {
-        ALOGE("deletePath stat failed for %s: %s", path, strerror(errno));
-    }
-}
-
 MtpResponseCode MtpServer::doDeleteObject() {
     if (!hasStorage())
         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 08a9e4a..aafc753 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -161,6 +161,8 @@
     MtpResponseCode     doSendObjectInfo();
     MtpResponseCode     doSendObject();
     MtpResponseCode     doDeleteObject();
+    MtpResponseCode     doMoveObject();
+    MtpResponseCode     doCopyObject();
     MtpResponseCode     doGetObjectPropDesc();
     MtpResponseCode     doGetDevicePropDesc();
     MtpResponseCode     doSendPartialObject();
diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp
index ebf3601..036ffe7 100644
--- a/media/mtp/MtpUtils.cpp
+++ b/media/mtp/MtpUtils.cpp
@@ -16,13 +16,23 @@
 
 #define LOG_TAG "MtpUtils"
 
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/sendfile.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <stdio.h>
 #include <time.h>
+#include <unistd.h>
 
 #include "MtpUtils.h"
 
 namespace android {
 
+constexpr unsigned long FILE_COPY_SIZE = 262144;
+
 /*
 DateTime strings follow a compatible subset of the definition found in ISO 8601, and
 take the form of a Unicode string formatted as: "YYYYMMDDThhmmss.s". In this
@@ -78,4 +88,101 @@
         tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
 }
 
+int copyFile(const char *fromPath, const char *toPath) {
+    auto start = std::chrono::steady_clock::now();
+
+    android::base::unique_fd fromFd(open(fromPath, O_RDONLY));
+    if (fromFd == -1) {
+        PLOG(ERROR) << "Failed to open copy from " << fromPath;
+        return -1;
+    }
+    android::base::unique_fd toFd(open(toPath, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR));
+    if (toFd == -1) {
+        PLOG(ERROR) << "Failed to open copy to " << toPath;
+        return -1;
+    }
+    off_t offset = 0;
+
+    struct stat sstat = {};
+    if (stat(fromPath, &sstat) == -1)
+        return -1;
+
+    off_t length = sstat.st_size;
+    int ret = 0;
+
+    while (offset < length) {
+        ssize_t transfer_length = std::min(length - offset, (off_t) FILE_COPY_SIZE);
+        ret = sendfile(toFd, fromFd, &offset, transfer_length);
+        if (ret != transfer_length) {
+            ret = -1;
+            PLOG(ERROR) << "Copying failed!";
+            break;
+        }
+    }
+    auto end = std::chrono::steady_clock::now();
+    std::chrono::duration<double> diff = end - start;
+    LOG(INFO) << "Copied a file with MTP. Time: " << diff.count() << " s, Size: " << length <<
+        ", Rate: " << ((double) length) / diff.count() << " bytes/s";
+    return ret == -1 ? -1 : 0;
+}
+
+void deleteRecursive(const char* path) {
+    char pathbuf[PATH_MAX];
+    size_t pathLength = strlen(path);
+    if (pathLength >= sizeof(pathbuf) - 1) {
+        LOG(ERROR) << "path too long: " << path;
+    }
+    strcpy(pathbuf, path);
+    if (pathbuf[pathLength - 1] != '/') {
+        pathbuf[pathLength++] = '/';
+    }
+    char* fileSpot = pathbuf + pathLength;
+    int pathRemaining = sizeof(pathbuf) - pathLength - 1;
+
+    DIR* dir = opendir(path);
+    if (!dir) {
+        PLOG(ERROR) << "opendir " << path << " failed";
+        return;
+    }
+
+    struct dirent* entry;
+    while ((entry = readdir(dir))) {
+        const char* name = entry->d_name;
+
+        // ignore "." and ".."
+        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+            continue;
+        }
+
+        int nameLength = strlen(name);
+        if (nameLength > pathRemaining) {
+            LOG(ERROR) << "path " << path << "/" << name << " too long";
+            continue;
+        }
+        strcpy(fileSpot, name);
+
+        if (entry->d_type == DT_DIR) {
+            deleteRecursive(pathbuf);
+            rmdir(pathbuf);
+        } else {
+            unlink(pathbuf);
+        }
+    }
+    closedir(dir);
+}
+
+void deletePath(const char* path) {
+    struct stat statbuf;
+    if (stat(path, &statbuf) == 0) {
+        if (S_ISDIR(statbuf.st_mode)) {
+            deleteRecursive(path);
+            rmdir(path);
+        } else {
+            unlink(path);
+        }
+    } else {
+        PLOG(ERROR) << "deletePath stat failed for " << path;;
+    }
+}
+
 }  // namespace android
diff --git a/media/mtp/MtpUtils.h b/media/mtp/MtpUtils.h
index 61f9055..a2bb7e1 100644
--- a/media/mtp/MtpUtils.h
+++ b/media/mtp/MtpUtils.h
@@ -24,6 +24,10 @@
 bool parseDateTime(const char* dateTime, time_t& outSeconds);
 void formatDateTime(time_t seconds, char* buffer, int bufferLength);
 
+int copyFile(const char *fromPath, const char *toPath);
+void deleteRecursive(const char* path);
+void deletePath(const char* path);
+
 }; // namespace android
 
 #endif // _MTP_UTILS_H
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 0d48de1..116f156 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -69,7 +69,6 @@
         "libmedia",
         "libmedia_jni",
         "libmediadrm",
-        "libskia",
         "libstagefright",
         "libstagefright_foundation",
         "liblog",
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 6d28d1b..87b649a 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -53,21 +53,25 @@
 
 void
 AImage::close(int releaseFenceFd) {
+    lockReader();
     Mutex::Autolock _l(mLock);
     if (mIsClosed) {
         return;
     }
     sp<AImageReader> reader = mReader.promote();
-    if (reader == nullptr) {
-        LOG_ALWAYS_FATAL("Error: AImage not closed before AImageReader close!");
-        return;
+    if (reader != nullptr) {
+        reader->releaseImageLocked(this, releaseFenceFd);
+    } else if (mBuffer != nullptr) {
+        LOG_ALWAYS_FATAL("%s: parent AImageReader closed without releasing image %p",
+                __FUNCTION__, this);
     }
-    reader->releaseImageLocked(this, releaseFenceFd);
+
     // Should have been set to nullptr in releaseImageLocked
     // Set to nullptr here for extra safety only
     mBuffer = nullptr;
     mLockedBuffer = nullptr;
     mIsClosed = true;
+    unlockReader();
 }
 
 void
@@ -618,9 +622,7 @@
 void AImage_deleteAsync(AImage* image, int releaseFenceFd) {
     ALOGV("%s", __FUNCTION__);
     if (image != nullptr) {
-        image->lockReader();
         image->close(releaseFenceFd);
-        image->unlockReader();
         if (!image->isClosed()) {
             LOG_ALWAYS_FATAL("Image close failed!");
         }
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index a450dd3..e90783d 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -349,6 +349,7 @@
     for (auto it = mAcquiredImages.begin();
               it != mAcquiredImages.end(); it++) {
         AImage* image = *it;
+        releaseImageLocked(image, /*releaseFenceFd*/-1);
         image->close();
     }
 
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 51143ac..eecc858 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -421,7 +421,7 @@
 
     for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
         keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
-        keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
+        keyValuePairs[i].mValue = mObj->mQueryResults.valueAt(i).string();
     }
     *numPairs = mObj->mQueryResults.size();
     return AMEDIA_OK;
diff --git a/media/ndk/include/media/NdkMediaCodec.h b/media/ndk/include/media/NdkMediaCodec.h
index 7e7e81e..faf2d14 100644
--- a/media/ndk/include/media/NdkMediaCodec.h
+++ b/media/ndk/include/media/NdkMediaCodec.h
@@ -39,6 +39,7 @@
 #endif
 
 struct ANativeWindow;
+typedef struct ANativeWindow ANativeWindow;
 
 #if __ANDROID_API__ >= 21
 
@@ -149,6 +150,7 @@
 
 #if (defined(__cplusplus) && __cplusplus >= 201103L) || \
     __STDC_VERSION__ >= 201112L
+#include <assert.h>
 static_assert(sizeof(_off_t_compat) == sizeof(long),
               "_off_t_compat does not match the NDK ABI. See "
               "https://github.com/android-ndk/ndk/issues/459.");
@@ -208,6 +210,8 @@
 media_status_t AMediaCodec_releaseOutputBufferAtTime(
         AMediaCodec *mData, size_t idx, int64_t timestampNs);
 
+#if __ANDROID_API__ >= 26
+
 /**
  * Creates a Surface that can be used as the input to encoder, in place of input buffers
  *
@@ -278,7 +282,7 @@
  */
 media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData);
 
-
+#endif /* __ANDROID_API__ >= 26 */
 
 typedef enum {
     AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index f906b6f..79e540a 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -329,6 +329,11 @@
         thread->configure(attr, streamType, sessionId, callback, *deviceId, portId);
         *handle = portId;
     } else {
+        if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
+            AudioSystem::releaseOutput(io, streamType, sessionId);
+        } else {
+            AudioSystem::releaseInput(io, sessionId);
+        }
         ret = NO_INIT;
     }
 
@@ -1397,11 +1402,11 @@
     // the config change is always sent from playback or record threads to avoid deadlock
     // with AudioSystem::gLock
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-        mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_OPENED, pid);
+        mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_REGISTERED, pid);
     }
 
     for (size_t i = 0; i < mRecordThreads.size(); i++) {
-        mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED, pid);
+        mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_REGISTERED, pid);
     }
 }
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 85d19cb..9544e5d 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1668,7 +1668,8 @@
         mScreenState(AudioFlinger::mScreenState),
         // index 0 is reserved for normal mixer's submix
         mFastTrackAvailMask(((1 << FastMixerState::sMaxFastTracks) - 1) & ~1),
-        mHwSupportsPause(false), mHwPaused(false), mFlushPending(false)
+        mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
+        mLeftVolFloat(-1.0), mRightVolFloat(-1.0)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
     mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
@@ -2253,6 +2254,7 @@
 
     switch (event) {
     case AUDIO_OUTPUT_OPENED:
+    case AUDIO_OUTPUT_REGISTERED:
     case AUDIO_OUTPUT_CONFIG_CHANGED:
         desc->mPatch = mPatch;
         desc->mChannelMask = mChannelMask;
@@ -4299,6 +4301,7 @@
                     param = AudioMixer::RAMP_VOLUME;
                 }
                 mAudioMixer->setParameter(name, AudioMixer::RESAMPLE, AudioMixer::RESET, NULL);
+                mLeftVolFloat = -1.0;
             // FIXME should not make a decision based on mServer
             } else if (cblk->mServer != 0) {
                 // If the track is stopped before the first frame was mixed,
@@ -4309,6 +4312,10 @@
             // compute volume for this track
             uint32_t vl, vr;       // in U8.24 integer format
             float vlf, vrf, vaf;   // in [0.0, 1.0] float format
+            // read original volumes with volume control
+            float typeVolume = mStreamTypes[track->streamType()].volume;
+            float v = masterVolume * typeVolume;
+
             if (track->isPausing() || mStreamTypes[track->streamType()].mute) {
                 vl = vr = 0;
                 vlf = vrf = vaf = 0.;
@@ -4316,10 +4323,6 @@
                     track->setPaused();
                 }
             } else {
-
-                // read original volumes with volume control
-                float typeVolume = mStreamTypes[track->streamType()].volume;
-                float v = masterVolume * typeVolume;
                 sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
                 gain_minifloat_packed_t vlr = proxy->getVolumeLR();
                 vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
@@ -4371,6 +4374,25 @@
                 track->mHasVolumeController = false;
             }
 
+            // For dedicated VoIP outputs, let the HAL apply the stream volume. Track volume is
+            // still applied by the mixer.
+            if ((mOutput->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) != 0) {
+                v = mStreamTypes[track->streamType()].mute ? 0.0f : v;
+                if (v != mLeftVolFloat) {
+                    status_t result = mOutput->stream->setVolume(v, v);
+                    ALOGE_IF(result != OK, "Error when setting output stream volume: %d", result);
+                    if (result == OK) {
+                        mLeftVolFloat = v;
+                    }
+                }
+                // if stream volume was successfully sent to the HAL, mLeftVolFloat == v here and we
+                // remove stream volume contribution from software volume.
+                if (v != 0.0f && mLeftVolFloat == v) {
+                   vlf = min(1.0f, vlf / v);
+                   vrf = min(1.0f, vrf / v);
+                   vaf = min(1.0f, vaf / v);
+               }
+            }
             // XXX: these things DON'T need to be done each time
             mAudioMixer->setBufferProvider(name, track);
             mAudioMixer->enable(name);
@@ -4812,7 +4834,6 @@
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
         AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, bool systemReady)
     :   PlaybackThread(audioFlinger, output, id, device, DIRECT, systemReady)
-        // mLeftVolFloat, mRightVolFloat
 {
 }
 
@@ -4820,7 +4841,6 @@
         AudioStreamOut* output, audio_io_handle_t id, uint32_t device,
         ThreadBase::type_t type, bool systemReady)
     :   PlaybackThread(audioFlinger, output, id, device, type, systemReady)
-        // mLeftVolFloat, mRightVolFloat
         , mVolumeShaperActive(false)
 {
 }
@@ -7247,6 +7267,7 @@
 
     switch (event) {
     case AUDIO_INPUT_OPENED:
+    case AUDIO_INPUT_REGISTERED:
     case AUDIO_INPUT_CONFIG_CHANGED:
         desc->mPatch = mPatch;
         desc->mChannelMask = mChannelMask;
@@ -7638,6 +7659,10 @@
         return NO_ERROR;
     }
 
+    if (!isOutput() && !recordingAllowed(client.packageName, client.clientPid, client.clientUid)) {
+        return PERMISSION_DENIED;
+    }
+
     audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
 
     audio_io_handle_t io = mId;
@@ -7914,8 +7939,10 @@
 
     switch (event) {
     case AUDIO_INPUT_OPENED:
+    case AUDIO_INPUT_REGISTERED:
     case AUDIO_INPUT_CONFIG_CHANGED:
     case AUDIO_OUTPUT_OPENED:
+    case AUDIO_OUTPUT_REGISTERED:
     case AUDIO_OUTPUT_CONFIG_CHANGED:
         desc->mPatch = mPatch;
         desc->mChannelMask = mChannelMask;
@@ -8126,10 +8153,8 @@
 
 void AudioFlinger::MmapThread::threadLoop_exit()
 {
-    sp<MmapStreamCallback> callback = mCallback.promote();
-    if (callback != 0) {
-        callback->onTearDown();
-    }
+    // Do not call callback->onTearDown() because it is redundant for thread exit
+    // and because it can cause a recursive mutex lock on stop().
 }
 
 status_t AudioFlinger::MmapThread::setSyncEvent(const sp<SyncEvent>& event __unused)
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index bfd9a3f..b685e1b 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1001,6 +1001,9 @@
                 bool        mHwSupportsPause;
                 bool        mHwPaused;
                 bool        mFlushPending;
+                // volumes last sent to audio HAL with stream->setVolume()
+                float mLeftVolFloat;
+                float mRightVolFloat;
 };
 
 class MixerThread : public PlaybackThread {
@@ -1118,9 +1121,6 @@
 
     virtual     void        onAddNewTrack_l();
 
-    // volumes last sent to audio HAL with stream->set_volume()
-    float mLeftVolFloat;
-    float mRightVolFloat;
     bool mVolumeShaperActive;
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
diff --git a/services/audiopolicy/config/primary_audio_policy_configuration.xml b/services/audiopolicy/config/primary_audio_policy_configuration.xml
index bf508ac..5b7ae7f 100644
--- a/services/audiopolicy/config/primary_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/primary_audio_policy_configuration.xml
@@ -13,7 +13,7 @@
         </mixPort>
         <mixPort name="primary input" role="sink">
             <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                     samplingRates="8000, 16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                     samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
         </mixPort>
    </mixPorts>
    <devicePorts>
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index d2a2855..906e05a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1444,62 +1444,13 @@
             "session %d, flags %#x",
           attr->source, config->sample_rate, config->format, config->channel_mask, session, flags);
 
-    // special case for mmap capture: if an input IO handle is specified, we reuse this input if
-    // possible
-    if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
-            *input != AUDIO_IO_HANDLE_NONE) {
-        ssize_t index = mInputs.indexOfKey(*input);
-        if (index < 0) {
-            ALOGW("getInputForAttr() unknown MMAP input %d", *input);
-            return BAD_VALUE;
-        }
-        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
-        sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
-        if (audioSession == 0) {
-            ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
-            return BAD_VALUE;
-        }
-        // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
-        // The second call is for the first active client and sets the UID. Any further call
-        // corresponds to a new client and is only permitted from the same UId.
-        if (audioSession->openCount() == 1) {
-            audioSession->setUid(uid);
-        } else if (audioSession->uid() != uid) {
-            ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
-                  uid, session, audioSession->uid());
-            return INVALID_OPERATION;
-        }
-        audioSession->changeOpenCount(1);
-        *inputType = API_INPUT_LEGACY;
-        if (*portId == AUDIO_PORT_HANDLE_NONE) {
-            *portId = AudioPort::getNextUniqueId();
-        }
-        DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
-        *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
-                : AUDIO_PORT_HANDLE_NONE;
-        ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
-        return NO_ERROR;
-    }
-
-    *input = AUDIO_IO_HANDLE_NONE;
-    *inputType = API_INPUT_INVALID;
-
-    audio_devices_t device;
+    status_t status = NO_ERROR;
     // handle legacy remote submix case where the address was not always specified
     String8 address = String8("");
-    audio_source_t inputSource = attr->source;
     audio_source_t halInputSource;
+    audio_source_t inputSource = attr->source;
     AudioMix *policyMix = NULL;
-
-    if (inputSource == AUDIO_SOURCE_DEFAULT) {
-        inputSource = AUDIO_SOURCE_MIC;
-    }
-    halInputSource = inputSource;
-
-    // TODO: check for existing client for this port ID
-    if (*portId == AUDIO_PORT_HANDLE_NONE) {
-        *portId = AudioPort::getNextUniqueId();
-    }
+    DeviceVector inputDevices;
 
     // Explicit routing?
     sp<DeviceDescriptor> deviceDesc;
@@ -1513,11 +1464,67 @@
     }
     mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);
 
+    // special case for mmap capture: if an input IO handle is specified, we reuse this input if
+    // possible
+    if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
+            *input != AUDIO_IO_HANDLE_NONE) {
+        ssize_t index = mInputs.indexOfKey(*input);
+        if (index < 0) {
+            ALOGW("getInputForAttr() unknown MMAP input %d", *input);
+            status = BAD_VALUE;
+            goto error;
+        }
+        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
+        sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
+        if (audioSession == 0) {
+            ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
+            status = BAD_VALUE;
+            goto error;
+        }
+        // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
+        // The second call is for the first active client and sets the UID. Any further call
+        // corresponds to a new client and is only permitted from the same UId.
+        if (audioSession->openCount() == 1) {
+            audioSession->setUid(uid);
+        } else if (audioSession->uid() != uid) {
+            ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
+                  uid, session, audioSession->uid());
+            status = INVALID_OPERATION;
+            goto error;
+        }
+        audioSession->changeOpenCount(1);
+        *inputType = API_INPUT_LEGACY;
+        if (*portId == AUDIO_PORT_HANDLE_NONE) {
+            *portId = AudioPort::getNextUniqueId();
+        }
+        inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
+        *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
+                : AUDIO_PORT_HANDLE_NONE;
+        ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
+
+        return NO_ERROR;
+    }
+
+    *input = AUDIO_IO_HANDLE_NONE;
+    *inputType = API_INPUT_INVALID;
+
+    if (inputSource == AUDIO_SOURCE_DEFAULT) {
+        inputSource = AUDIO_SOURCE_MIC;
+    }
+    halInputSource = inputSource;
+
+    // TODO: check for existing client for this port ID
+    if (*portId == AUDIO_PORT_HANDLE_NONE) {
+        *portId = AudioPort::getNextUniqueId();
+    }
+
+    audio_devices_t device;
+
     if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
             strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
-        status_t ret = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
-        if (ret != NO_ERROR) {
-            return ret;
+        status = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
+        if (status != NO_ERROR) {
+            goto error;
         }
         *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
         device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
@@ -1526,7 +1533,8 @@
         device = getDeviceAndMixForInputSource(inputSource, &policyMix);
         if (device == AUDIO_DEVICE_NONE) {
             ALOGW("getInputForAttr() could not find device for source %d", inputSource);
-            return BAD_VALUE;
+            status = BAD_VALUE;
+            goto error;
         }
         if (policyMix != NULL) {
             address = policyMix->mDeviceAddress;
@@ -1555,11 +1563,11 @@
                                config->sample_rate, config->format, config->channel_mask, flags,
                                policyMix);
     if (*input == AUDIO_IO_HANDLE_NONE) {
-        mInputRoutes.removeRoute(session);
-        return INVALID_OPERATION;
+        status = INVALID_OPERATION;
+        goto error;
     }
 
-    DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(device);
+    inputDevices = mAvailableInputDevices.getDevicesFromType(device);
     *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
             : AUDIO_PORT_HANDLE_NONE;
 
@@ -1567,6 +1575,10 @@
             *input, *inputType, *selectedDeviceId);
 
     return NO_ERROR;
+
+error:
+    mInputRoutes.removeRoute(session);
+    return status;
 }
 
 
@@ -4683,12 +4695,13 @@
     // scan the whole RouteMap, for each entry, convert the stream type to a strategy
     // (getStrategy(stream)).
     // if the strategy from the stream type in the RouteMap is the same as the argument above,
-    // and activity count is non-zero
-    // the device = the device from the descriptor in the RouteMap, and exit.
+    // and activity count is non-zero and the device in the route descriptor is available
+    // then select this device.
     for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {
         sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);
         routing_strategy routeStrategy = getStrategy(route->mStreamType);
-        if ((routeStrategy == strategy) && route->isActive()) {
+        if ((routeStrategy == strategy) && route->isActive() &&
+                (mAvailableOutputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
             return route->mDeviceDescriptor->type();
         }
     }
@@ -5083,9 +5096,15 @@
 
 audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
 {
+    // Routing
+    // Scan the whole RouteMap to see if we have an explicit route:
+    // if the input source in the RouteMap is the same as the argument above,
+    // and activity count is non-zero and the device in the route descriptor is available
+    // then select this device.
     for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) {
          sp<SessionRoute> route = mInputRoutes.valueAt(routeIndex);
-         if (inputSource == route->mSource && route->isActive()) {
+         if ((inputSource == route->mSource) && route->isActive() &&
+                 (mAvailableInputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
              return route->mDeviceDescriptor->type();
          }
      }
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 1d4386c..b7bce55 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -694,6 +694,7 @@
                                        audio_io_handle_t *ioHandle,
                                        audio_devices_t *device)
 {
+    Mutex::Autolock _l(mLock);
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
@@ -703,6 +704,7 @@
 
 status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session)
 {
+    Mutex::Autolock _l(mLock);
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index f1cdea3..7ec3ccb 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -77,7 +77,8 @@
     android.hardware.camera.common@1.0 \
     android.hardware.camera.provider@2.4 \
     android.hardware.camera.device@1.0 \
-    android.hardware.camera.device@3.2
+    android.hardware.camera.device@3.2 \
+    android.hardware.camera.device@3.3
 
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index a28518e..2cf648f 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -72,6 +72,20 @@
     return initializeImpl(manager);
 }
 
+bool Camera2Client::isZslEnabledInStillTemplate() {
+    bool zslEnabled = false;
+    CameraMetadata stillTemplate;
+    status_t res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_STILL_CAPTURE, &stillTemplate);
+    if (res == OK) {
+        camera_metadata_entry_t enableZsl = stillTemplate.find(ANDROID_CONTROL_ENABLE_ZSL);
+        if (enableZsl.count == 1) {
+            zslEnabled = (enableZsl.data.u8[0] == ANDROID_CONTROL_ENABLE_ZSL_TRUE);
+        }
+    }
+
+    return zslEnabled;
+}
+
 template<typename TProviderPtr>
 status_t Camera2Client::initializeImpl(TProviderPtr providerPtr)
 {
@@ -93,6 +107,8 @@
                     __FUNCTION__, mCameraId, strerror(-res), res);
             return NO_INIT;
         }
+
+        l.mParameters.isDeviceZslSupported = isZslEnabledInStillTemplate();
     }
 
     String8 threadName;
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 72315d4..5af74eb 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -224,6 +224,8 @@
 
     template<typename TProviderPtr>
     status_t initializeImpl(TProviderPtr providerPtr);
+
+    bool isZslEnabledInStillTemplate();
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
index 3f4017f..0d2dba1 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
@@ -121,18 +121,17 @@
 
     if (mCallbackStreamId != NO_STREAM) {
         // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight, currentFormat;
-        res = device->getStreamInfo(mCallbackStreamId,
-                &currentWidth, &currentHeight, &currentFormat, 0);
+        CameraDeviceBase::StreamInfo streamInfo;
+        res = device->getStreamInfo(mCallbackStreamId, &streamInfo);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying callback output stream info: "
                     "%s (%d)", __FUNCTION__, mId,
                     strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)params.previewWidth ||
-                currentHeight != (uint32_t)params.previewHeight ||
-                currentFormat != (uint32_t)callbackFormat) {
+        if (streamInfo.width != (uint32_t)params.previewWidth ||
+                streamInfo.height != (uint32_t)params.previewHeight ||
+                !streamInfo.matchFormat((uint32_t)callbackFormat)) {
             // Since size should only change while preview is not running,
             // assuming that all existing use of old callback stream is
             // completed.
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index 4981ce7..d1bbdaf 100755
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -136,17 +136,16 @@
 
     if (mCaptureStreamId != NO_STREAM) {
         // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight;
-        res = device->getStreamInfo(mCaptureStreamId,
-                &currentWidth, &currentHeight, 0, 0);
+        CameraDeviceBase::StreamInfo streamInfo;
+        res = device->getStreamInfo(mCaptureStreamId, &streamInfo);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying capture output stream info: "
                     "%s (%d)", __FUNCTION__,
                     mId, strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)params.pictureWidth ||
-                currentHeight != (uint32_t)params.pictureHeight) {
+        if (streamInfo.width != (uint32_t)params.pictureWidth ||
+                streamInfo.height != (uint32_t)params.pictureHeight) {
             ALOGV("%s: Camera %d: Deleting stream %d since the buffer dimensions changed",
                 __FUNCTION__, mId, mCaptureStreamId);
             res = device->deleteStream(mCaptureStreamId);
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 1addcdd..02a7616 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -954,7 +954,8 @@
         }
     }
 
-    if (slowJpegMode || property_get_bool("camera.disable_zsl_mode", false)) {
+    if (isDeviceZslSupported || slowJpegMode ||
+            property_get_bool("camera.disable_zsl_mode", false)) {
         ALOGI("Camera %d: Disabling ZSL mode", cameraId);
         allowZslMode = false;
     } else {
@@ -1997,7 +1998,8 @@
     if (previewFpsRange[1] > 1e9/minFrameDurationNs + FPS_MARGIN) {
         slowJpegMode = true;
     }
-    if (slowJpegMode || property_get_bool("camera.disable_zsl_mode", false)) {
+    if (isDeviceZslSupported || slowJpegMode ||
+            property_get_bool("camera.disable_zsl_mode", false)) {
         allowZslMode = false;
     } else {
         allowZslMode = isZslReprocessPresent;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index bea867a..17e3d75 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -175,6 +175,8 @@
     bool slowJpegMode;
     // Whether ZSL reprocess is supported by the device.
     bool isZslReprocessPresent;
+    // Whether the device supports enableZsl.
+    bool isDeviceZslSupported;
 
     // Overall camera state
     enum State {
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index d79e430..73dca73 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -161,18 +161,17 @@
 
     if (mPreviewStreamId != NO_STREAM) {
         // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight;
-        res = device->getStreamInfo(mPreviewStreamId,
-                &currentWidth, &currentHeight, 0, 0);
+        CameraDeviceBase::StreamInfo streamInfo;
+        res = device->getStreamInfo(mPreviewStreamId, &streamInfo);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying preview stream info: "
                     "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)params.previewWidth ||
-                currentHeight != (uint32_t)params.previewHeight) {
+        if (streamInfo.width != (uint32_t)params.previewWidth ||
+                streamInfo.height != (uint32_t)params.previewHeight) {
             ALOGV("%s: Camera %d: Preview size switch: %d x %d -> %d x %d",
-                    __FUNCTION__, mId, currentWidth, currentHeight,
+                    __FUNCTION__, mId, streamInfo.width, streamInfo.height,
                     params.previewWidth, params.previewHeight);
             res = device->waitUntilDrained();
             if (res != OK) {
@@ -312,10 +311,8 @@
         return INVALID_OPERATION;
     }
 
-    uint32_t currentWidth, currentHeight, currentFormat;
-    android_dataspace currentDataSpace;
-    res = device->getStreamInfo(mRecordingStreamId,
-            &currentWidth, &currentHeight, &currentFormat, &currentDataSpace);
+    CameraDeviceBase::StreamInfo streamInfo;
+    res = device->getStreamInfo(mRecordingStreamId, &streamInfo);
     if (res != OK) {
         ALOGE("%s: Camera %d: Error querying recording output stream info: "
                 "%s (%d)", __FUNCTION__, mId,
@@ -324,10 +321,10 @@
     }
 
     if (mRecordingWindow == nullptr ||
-            currentWidth != (uint32_t)params.videoWidth ||
-            currentHeight != (uint32_t)params.videoHeight ||
-            currentFormat != (uint32_t)params.videoFormat ||
-            currentDataSpace != params.videoDataSpace) {
+            streamInfo.width != (uint32_t)params.videoWidth ||
+            streamInfo.height != (uint32_t)params.videoHeight ||
+            !streamInfo.matchFormat((uint32_t)params.videoFormat) ||
+            !streamInfo.matchDataSpace(params.videoDataSpace)) {
         *needsUpdate = true;
         return res;
     }
@@ -348,22 +345,18 @@
 
     if (mRecordingStreamId != NO_STREAM) {
         // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight;
-        uint32_t currentFormat;
-        android_dataspace currentDataSpace;
-        res = device->getStreamInfo(mRecordingStreamId,
-                &currentWidth, &currentHeight,
-                &currentFormat, &currentDataSpace);
+        CameraDeviceBase::StreamInfo streamInfo;
+        res = device->getStreamInfo(mRecordingStreamId, &streamInfo);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying recording output stream info: "
                     "%s (%d)", __FUNCTION__, mId,
                     strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)params.videoWidth ||
-                currentHeight != (uint32_t)params.videoHeight ||
-                currentFormat != (uint32_t)params.videoFormat ||
-                currentDataSpace != params.videoDataSpace) {
+        if (streamInfo.width != (uint32_t)params.videoWidth ||
+                streamInfo.height != (uint32_t)params.videoHeight ||
+                !streamInfo.matchFormat((uint32_t)params.videoFormat) ||
+                !streamInfo.matchDataSpace(params.videoDataSpace)) {
             // TODO: Should wait to be sure previous recording has finished
             res = device->deleteStream(mRecordingStreamId);
 
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 9bc31b9..b0607fb 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -233,17 +233,16 @@
 
     if ((mZslStreamId != NO_STREAM) || (mInputStreamId != NO_STREAM)) {
         // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight;
-        res = device->getStreamInfo(mZslStreamId,
-                &currentWidth, &currentHeight, 0, 0);
+        CameraDeviceBase::StreamInfo streamInfo;
+        res = device->getStreamInfo(mZslStreamId, &streamInfo);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying capture output stream info: "
                     "%s (%d)", __FUNCTION__,
                     client->getCameraId(), strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)params.fastInfo.arrayWidth ||
-                currentHeight != (uint32_t)params.fastInfo.arrayHeight) {
+        if (streamInfo.width != (uint32_t)params.fastInfo.arrayWidth ||
+                streamInfo.height != (uint32_t)params.fastInfo.arrayHeight) {
             if (mZslStreamId != NO_STREAM) {
                 ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
                       "dimensions changed",
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 29bc21c..f985382 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -1354,7 +1354,7 @@
     sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
 
     if (remoteCb != 0) {
-        remoteCb->onRepeatingRequestError(lastFrameNumber);
+        remoteCb->onRepeatingRequestError(lastFrameNumber, mStreamingRequestId);
     }
 
     Mutex::Autolock idLock(mStreamingRequestIdLock);
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 54fcb0a..3919bfa 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -142,12 +142,51 @@
     virtual status_t createInputStream(uint32_t width, uint32_t height,
             int32_t format, /*out*/ int32_t *id) = 0;
 
+    struct StreamInfo {
+        uint32_t width;
+        uint32_t height;
+
+        uint32_t format;
+        bool formatOverridden;
+        uint32_t originalFormat;
+
+        android_dataspace dataSpace;
+        bool dataSpaceOverridden;
+        android_dataspace originalDataSpace;
+
+        StreamInfo() : width(0), height(0), format(0), formatOverridden(false), originalFormat(0),
+                dataSpace(HAL_DATASPACE_UNKNOWN), dataSpaceOverridden(false),
+                originalDataSpace(HAL_DATASPACE_UNKNOWN) {}
+        /**
+         * Check whether the format matches the current or the original one in case
+         * it got overridden.
+         */
+        bool matchFormat(uint32_t clientFormat) const {
+            if ((formatOverridden && (originalFormat == clientFormat)) ||
+                    (format == clientFormat)) {
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Check whether the dataspace matches the current or the original one in case
+         * it got overridden.
+         */
+        bool matchDataSpace(android_dataspace clientDataSpace) const {
+            if ((dataSpaceOverridden && (originalDataSpace == clientDataSpace)) ||
+                    (dataSpace == clientDataSpace)) {
+                return true;
+            }
+            return false;
+        }
+
+    };
+
     /**
      * Get information about a given stream.
      */
-    virtual status_t getStreamInfo(int id,
-            uint32_t *width, uint32_t *height,
-            uint32_t *format, android_dataspace *dataSpace) = 0;
+    virtual status_t getStreamInfo(int id, StreamInfo *streamInfo) = 0;
 
     /**
      * Set stream gralloc buffer transform
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 5addaf1..ae3bbc1 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -202,12 +202,17 @@
     for (auto& provider : mProviders) {
         auto deviceInfo = findDeviceInfoLocked(id);
         if (deviceInfo != nullptr) {
-            provider->mInterface->isSetTorchModeSupported(
+            auto ret = provider->mInterface->isSetTorchModeSupported(
                 [&support](auto status, bool supported) {
                     if (status == Status::OK) {
                         support = supported;
                     }
                 });
+            if (!ret.isOk()) {
+                ALOGE("%s: Transaction error checking torch mode support '%s': %s",
+                        __FUNCTION__, provider->mProviderName.c_str(), ret.description().c_str());
+            }
+            break;
         }
     }
     return support;
@@ -1339,7 +1344,7 @@
         desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
     }
 
-    descriptor = desc;
+    descriptor = std::move(desc);
     return OK;
 }
 
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
index 991b50f..522d521 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
@@ -97,58 +97,78 @@
         ALOGE("%s: CameraHeapMemory has FD %d (expect >= 0)", __FUNCTION__, memPoolId);
         return 0;
     }
+    std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
     mHidlMemPoolMap.insert(std::make_pair(memPoolId, mem));
     return memPoolId;
 }
 
 hardware::Return<void> CameraHardwareInterface::unregisterMemory(uint32_t memId) {
-    if (mHidlMemPoolMap.count(memId) == 0) {
-        ALOGE("%s: memory pool ID %d not found", __FUNCTION__, memId);
-        return hardware::Void();
+    camera_memory_t* mem = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+        if (mHidlMemPoolMap.count(memId) == 0) {
+            ALOGE("%s: memory pool ID %d not found", __FUNCTION__, memId);
+            return hardware::Void();
+        }
+        mem = mHidlMemPoolMap.at(memId);
+        mHidlMemPoolMap.erase(memId);
     }
-    camera_memory_t* mem = mHidlMemPoolMap.at(memId);
     sPutMemory(mem);
-    mHidlMemPoolMap.erase(memId);
     return hardware::Void();
 }
 
 hardware::Return<void> CameraHardwareInterface::dataCallback(
         DataCallbackMsg msgType, uint32_t data, uint32_t bufferIndex,
         const hardware::camera::device::V1_0::CameraFrameMetadata& metadata) {
-    if (mHidlMemPoolMap.count(data) == 0) {
-        ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
-        return hardware::Void();
+    camera_memory_t* mem = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+        if (mHidlMemPoolMap.count(data) == 0) {
+            ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
+            return hardware::Void();
+        }
+        mem = mHidlMemPoolMap.at(data);
     }
     camera_frame_metadata_t md;
     md.number_of_faces = metadata.faces.size();
     md.faces = (camera_face_t*) metadata.faces.data();
-    sDataCb((int32_t) msgType, mHidlMemPoolMap.at(data), bufferIndex, &md, this);
+    sDataCb((int32_t) msgType, mem, bufferIndex, &md, this);
     return hardware::Void();
 }
 
 hardware::Return<void> CameraHardwareInterface::dataCallbackTimestamp(
         DataCallbackMsg msgType, uint32_t data,
         uint32_t bufferIndex, int64_t timestamp) {
-    if (mHidlMemPoolMap.count(data) == 0) {
-        ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
-        return hardware::Void();
+    camera_memory_t* mem = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+        if (mHidlMemPoolMap.count(data) == 0) {
+            ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
+            return hardware::Void();
+        }
+        mem = mHidlMemPoolMap.at(data);
     }
-    sDataCbTimestamp(timestamp, (int32_t) msgType, mHidlMemPoolMap.at(data), bufferIndex, this);
+    sDataCbTimestamp(timestamp, (int32_t) msgType, mem, bufferIndex, this);
     return hardware::Void();
 }
 
 hardware::Return<void> CameraHardwareInterface::handleCallbackTimestamp(
         DataCallbackMsg msgType, const hidl_handle& frameData, uint32_t data,
         uint32_t bufferIndex, int64_t timestamp) {
-    if (mHidlMemPoolMap.count(data) == 0) {
-        ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
-        return hardware::Void();
+    camera_memory_t* mem = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+        if (mHidlMemPoolMap.count(data) == 0) {
+            ALOGE("%s: memory pool ID %d not found", __FUNCTION__, data);
+            return hardware::Void();
+        }
+        mem = mHidlMemPoolMap.at(data);
     }
-    sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(mHidlMemPoolMap.at(data)->handle));
+    sp<CameraHeapMemory> heapMem(static_cast<CameraHeapMemory *>(mem->handle));
     VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
-            mem->mBuffers[bufferIndex]->pointer();
+            heapMem->mBuffers[bufferIndex]->pointer();
     md->pHandle = const_cast<native_handle_t*>(frameData.getNativeHandle());
-    sDataCbTimestamp(timestamp, (int32_t) msgType, mHidlMemPoolMap.at(data), bufferIndex, this);
+    sDataCbTimestamp(timestamp, (int32_t) msgType, mem, bufferIndex, this);
     return hardware::Void();
 }
 
@@ -157,27 +177,28 @@
         const hardware::hidl_vec<hardware::camera::device::V1_0::HandleTimestampMessage>& messages) {
     std::vector<android::HandleTimestampMessage> msgs;
     msgs.reserve(messages.size());
+    {
+        std::lock_guard<std::mutex> lock(mHidlMemPoolMapLock);
+        for (const auto& hidl_msg : messages) {
+            if (mHidlMemPoolMap.count(hidl_msg.data) == 0) {
+                ALOGE("%s: memory pool ID %d not found", __FUNCTION__, hidl_msg.data);
+                return hardware::Void();
+            }
+            sp<CameraHeapMemory> mem(
+                    static_cast<CameraHeapMemory *>(mHidlMemPoolMap.at(hidl_msg.data)->handle));
 
-    for (const auto& hidl_msg : messages) {
-        if (mHidlMemPoolMap.count(hidl_msg.data) == 0) {
-            ALOGE("%s: memory pool ID %d not found", __FUNCTION__, hidl_msg.data);
-            return hardware::Void();
+            if (hidl_msg.bufferIndex >= mem->mNumBufs) {
+                ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
+                     hidl_msg.bufferIndex, mem->mNumBufs);
+                return hardware::Void();
+            }
+            VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
+                    mem->mBuffers[hidl_msg.bufferIndex]->pointer();
+            md->pHandle = const_cast<native_handle_t*>(hidl_msg.frameData.getNativeHandle());
+
+            msgs.push_back({hidl_msg.timestamp, mem->mBuffers[hidl_msg.bufferIndex]});
         }
-        sp<CameraHeapMemory> mem(
-                static_cast<CameraHeapMemory *>(mHidlMemPoolMap.at(hidl_msg.data)->handle));
-
-        if (hidl_msg.bufferIndex >= mem->mNumBufs) {
-            ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
-                 hidl_msg.bufferIndex, mem->mNumBufs);
-            return hardware::Void();
-        }
-        VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
-                mem->mBuffers[hidl_msg.bufferIndex]->pointer();
-        md->pHandle = const_cast<native_handle_t*>(hidl_msg.frameData.getNativeHandle());
-
-        msgs.push_back({hidl_msg.timestamp, mem->mBuffers[hidl_msg.bufferIndex]});
     }
-
     mDataCbTimestampBatch((int32_t) msgType, msgs, mCbUser);
     return hardware::Void();
 }
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 6a1b4fb..e519b04 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -479,6 +479,7 @@
     uint64_t mNextBufferId = 1;
     static const uint64_t BUFFER_ID_NO_BUFFER = 0;
 
+    std::mutex mHidlMemPoolMapLock; // protecting mHidlMemPoolMap
     std::unordered_map<int, camera_memory_t*> mHidlMemPoolMap;
 };
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 94e8f3b..ced1d3a 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -154,6 +154,15 @@
                 resultQueueRet.description().c_str());
         return DEAD_OBJECT;
     }
+    IF_ALOGV() {
+        session->interfaceChain([](
+            ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+                ALOGV("Session interface chain:");
+                for (auto iface : interfaceChain) {
+                    ALOGV("  %s", iface.c_str());
+                }
+            });
+    }
 
     mInterface = new HalInterface(session, queue);
     std::string providerType;
@@ -460,6 +469,11 @@
     return static_cast<uint32_t>(pixelFormat);
 }
 
+android_dataspace Camera3Device::mapToFrameworkDataspace(
+        DataspaceFlags dataSpace) {
+    return static_cast<android_dataspace>(dataSpace);
+}
+
 uint64_t Camera3Device::mapConsumerToFrameworkUsage(
         BufferUsageFlags usage) {
     return usage;
@@ -1345,10 +1359,11 @@
     return OK;
 }
 
-status_t Camera3Device::getStreamInfo(int id,
-        uint32_t *width, uint32_t *height,
-        uint32_t *format, android_dataspace *dataSpace) {
+status_t Camera3Device::getStreamInfo(int id, StreamInfo *streamInfo) {
     ATRACE_CALL();
+    if (nullptr == streamInfo) {
+        return BAD_VALUE;
+    }
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
 
@@ -1375,10 +1390,14 @@
         return idx;
     }
 
-    if (width) *width  = mOutputStreams[idx]->getWidth();
-    if (height) *height = mOutputStreams[idx]->getHeight();
-    if (format) *format = mOutputStreams[idx]->getFormat();
-    if (dataSpace) *dataSpace = mOutputStreams[idx]->getDataSpace();
+    streamInfo->width  = mOutputStreams[idx]->getWidth();
+    streamInfo->height = mOutputStreams[idx]->getHeight();
+    streamInfo->format = mOutputStreams[idx]->getFormat();
+    streamInfo->dataSpace = mOutputStreams[idx]->getDataSpace();
+    streamInfo->formatOverridden = mOutputStreams[idx]->isFormatOverridden();
+    streamInfo->originalFormat = mOutputStreams[idx]->getOriginalFormat();
+    streamInfo->dataSpaceOverridden = mOutputStreams[idx]->isDataSpaceOverridden();
+    streamInfo->originalDataSpace = mOutputStreams[idx]->getOriginalDataSpace();
     return OK;
 }
 
@@ -3193,17 +3212,51 @@
 
     // Invoke configureStreams
 
-    HalStreamConfiguration finalConfiguration;
+    device::V3_3::HalStreamConfiguration finalConfiguration;
     common::V1_0::Status status;
-    auto err = mHidlSession->configureStreams(requestedConfiguration,
+
+    // See if we have v3.3 HAL
+    sp<device::V3_3::ICameraDeviceSession> hidlSession_3_3;
+    auto castResult = device::V3_3::ICameraDeviceSession::castFrom(mHidlSession);
+    if (castResult.isOk()) {
+        hidlSession_3_3 = castResult;
+    } else {
+        ALOGE("%s: Transaction error when casting ICameraDeviceSession: %s", __FUNCTION__,
+                castResult.description().c_str());
+    }
+    if (hidlSession_3_3 != nullptr) {
+        // We do; use v3.3 for the call
+        ALOGV("%s: v3.3 device found", __FUNCTION__);
+        auto err = hidlSession_3_3->configureStreams_3_3(requestedConfiguration,
             [&status, &finalConfiguration]
-            (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
+            (common::V1_0::Status s, const device::V3_3::HalStreamConfiguration& halConfiguration) {
                 finalConfiguration = halConfiguration;
                 status = s;
             });
-    if (!err.isOk()) {
-        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
-        return DEAD_OBJECT;
+        if (!err.isOk()) {
+            ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+            return DEAD_OBJECT;
+        }
+    } else {
+        // We don't; use v3.2 call and construct a v3.3 HalStreamConfiguration
+        ALOGV("%s: v3.2 device found", __FUNCTION__);
+        HalStreamConfiguration finalConfiguration_3_2;
+        auto err = mHidlSession->configureStreams(requestedConfiguration,
+                [&status, &finalConfiguration_3_2]
+                (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
+                    finalConfiguration_3_2 = halConfiguration;
+                    status = s;
+                });
+        if (!err.isOk()) {
+            ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+            return DEAD_OBJECT;
+        }
+        finalConfiguration.streams.resize(finalConfiguration_3_2.streams.size());
+        for (size_t i = 0; i < finalConfiguration_3_2.streams.size(); i++) {
+            finalConfiguration.streams[i].v3_2 = finalConfiguration_3_2.streams[i];
+            finalConfiguration.streams[i].overrideDataSpace =
+                    requestedConfiguration.streams[i].dataSpace;
+        }
     }
 
     if (status != common::V1_0::Status::OK ) {
@@ -3220,7 +3273,7 @@
         size_t realIdx = i;
         bool found = false;
         for (size_t idx = 0; idx < finalConfiguration.streams.size(); idx++) {
-            if (finalConfiguration.streams[realIdx].id == streamId) {
+            if (finalConfiguration.streams[realIdx].v3_2.id == streamId) {
                 found = true;
                 break;
             }
@@ -3231,38 +3284,51 @@
                     __FUNCTION__, streamId);
             return INVALID_OPERATION;
         }
-        HalStream &src = finalConfiguration.streams[realIdx];
+        device::V3_3::HalStream &src = finalConfiguration.streams[realIdx];
 
-        int overrideFormat = mapToFrameworkFormat(src.overrideFormat);
+        Camera3Stream* dstStream = Camera3Stream::cast(dst);
+        dstStream->setFormatOverride(false);
+        dstStream->setDataSpaceOverride(false);
+        int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat);
+        android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
+
         if (dst->format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
             if (dst->format != overrideFormat) {
                 ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
                         streamId, dst->format);
             }
+            if (dst->data_space != overrideDataSpace) {
+                ALOGE("%s: Stream %d: DataSpace override not allowed for format 0x%x", __FUNCTION__,
+                        streamId, dst->format);
+            }
         } else {
+            dstStream->setFormatOverride((dst->format != overrideFormat) ? true : false);
+            dstStream->setDataSpaceOverride((dst->data_space != overrideDataSpace) ? true : false);
+
             // Override allowed with IMPLEMENTATION_DEFINED
             dst->format = overrideFormat;
+            dst->data_space = overrideDataSpace;
         }
 
         if (dst->stream_type == CAMERA3_STREAM_INPUT) {
-            if (src.producerUsage != 0) {
+            if (src.v3_2.producerUsage != 0) {
                 ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
                         __FUNCTION__, streamId);
                 return INVALID_OPERATION;
             }
-            Camera3Stream::cast(dst)->setUsage(
-                    mapConsumerToFrameworkUsage(src.consumerUsage));
+            dstStream->setUsage(
+                    mapConsumerToFrameworkUsage(src.v3_2.consumerUsage));
         } else {
             // OUTPUT
-            if (src.consumerUsage != 0) {
+            if (src.v3_2.consumerUsage != 0) {
                 ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
                         __FUNCTION__, streamId);
                 return INVALID_OPERATION;
             }
-            Camera3Stream::cast(dst)->setUsage(
-                    mapProducerToFrameworkUsage(src.producerUsage));
+            dstStream->setUsage(
+                    mapProducerToFrameworkUsage(src.v3_2.producerUsage));
         }
-        dst->max_buffers = src.maxBuffers;
+        dst->max_buffers = src.v3_2.maxBuffers;
     }
 
     return res;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 363bd88..fbbbd08 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -30,6 +30,7 @@
 
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/device/3.2/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.2/ICameraDeviceCallback.h>
 #include <fmq/MessageQueue.h>
 #include <hardware/camera3.h>
@@ -128,9 +129,7 @@
             uint32_t width, uint32_t height, int format,
             int *id) override;
 
-    status_t getStreamInfo(int id,
-            uint32_t *width, uint32_t *height,
-            uint32_t *format, android_dataspace *dataSpace) override;
+    status_t getStreamInfo(int id, StreamInfo *streamInfo) override;
     status_t setStreamTransform(int id, int transform) override;
 
     status_t deleteStream(int id) override;
@@ -597,6 +596,8 @@
             /*out*/ hardware::camera::device::V3_2::StreamConfigurationMode *mode);
     static camera3_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status);
     static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
+    static android_dataspace mapToFrameworkDataspace(
+            hardware::camera::device::V3_2::DataspaceFlags);
     static uint64_t mapConsumerToFrameworkUsage(
             hardware::camera::device::V3_2::BufferUsageFlags usage);
     static uint64_t mapProducerToFrameworkUsage(
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 25e44a5..fbe8f4f 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -62,7 +62,9 @@
     mPrepared(false),
     mPreparedBufferIdx(0),
     mLastMaxCount(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX),
-    mBufferLimitLatency(kBufferLimitLatencyBinSize) {
+    mBufferLimitLatency(kBufferLimitLatencyBinSize),
+    mFormatOverridden(false),
+    mOriginalFormat(-1) {
 
     camera3_stream::stream_type = type;
     camera3_stream::width = width;
@@ -112,6 +114,32 @@
     mUsage = usage;
 }
 
+void Camera3Stream::setFormatOverride(bool formatOverridden) {
+    mFormatOverridden = formatOverridden;
+    if (formatOverridden) mOriginalFormat = camera3_stream::format;
+}
+
+bool Camera3Stream::isFormatOverridden() const {
+    return mFormatOverridden;
+}
+
+int Camera3Stream::getOriginalFormat() const {
+    return mOriginalFormat;
+}
+
+void Camera3Stream::setDataSpaceOverride(bool dataSpaceOverridden) {
+    mDataSpaceOverridden = dataSpaceOverridden;
+    if (dataSpaceOverridden) mOriginalDataSpace = camera3_stream::data_space;
+}
+
+bool Camera3Stream::isDataSpaceOverridden() const {
+    return mDataSpaceOverridden;
+}
+
+android_dataspace Camera3Stream::getOriginalDataSpace() const {
+    return mOriginalDataSpace;
+}
+
 camera3_stream* Camera3Stream::startConfiguration() {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 9090f83..6e7912e 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -146,6 +146,12 @@
     android_dataspace getDataSpace() const;
     uint64_t          getUsage() const;
     void              setUsage(uint64_t usage);
+    void              setFormatOverride(bool formatOverriden);
+    bool              isFormatOverridden() const;
+    int               getOriginalFormat() const;
+    void              setDataSpaceOverride(bool dataSpaceOverriden);
+    bool              isDataSpaceOverridden() const;
+    android_dataspace getOriginalDataSpace() const;
 
     camera3_stream*   asHalStream() override {
         return this;
@@ -514,6 +520,15 @@
     // max_buffers.
     static const int32_t kBufferLimitLatencyBinSize = 33; //in ms
     CameraLatencyHistogram mBufferLimitLatency;
+
+    //Keep track of original format in case it gets overridden
+    bool mFormatOverridden;
+    int mOriginalFormat;
+
+    //Keep track of original dataSpace in case it gets overridden
+    bool mDataSpaceOverridden;
+    android_dataspace mOriginalDataSpace;
+
 }; // class Camera3Stream
 
 }; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 0544a1b..cc9bf8e 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -71,6 +71,12 @@
     virtual uint32_t getHeight() const = 0;
     virtual int      getFormat() const = 0;
     virtual android_dataspace getDataSpace() const = 0;
+    virtual void setFormatOverride(bool formatOverriden) = 0;
+    virtual bool isFormatOverridden() const = 0;
+    virtual int getOriginalFormat() const = 0;
+    virtual void setDataSpaceOverride(bool dataSpaceOverriden) = 0;
+    virtual bool isDataSpaceOverridden() const = 0;
+    virtual android_dataspace getOriginalDataSpace() const = 0;
 
     /**
      * Get a HAL3 handle for the stream, without starting stream configuration.
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 3c39883..c7f9270 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -222,6 +222,8 @@
 
     // we control these, generally not trusting user input
     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+    // round nsecs to seconds
+    now = ((now + 500000000) / 1000000000) * 1000000000;
     item->setTimestamp(now);
     int pid = IPCThreadState::self()->getCallingPid();
     int uid = IPCThreadState::self()->getCallingUid();
@@ -257,9 +259,22 @@
             break;
     }
 
-    item->setPkgName(getPkgName(item->getUid(), true));
-    item->setPkgVersionCode(0);
-    ALOGD("info is from uid %d pkg '%s', version %d", item->getUid(), item->getPkgName().c_str(), item->getPkgVersionCode());
+
+    // Overwrite package name and version if the caller was untrusted.
+    if (!isTrusted) {
+      setPkgInfo(item, item->getUid(), true, true);
+    } else if (item->getPkgName().empty()) {
+      // empty, so fill out both parts
+      setPkgInfo(item, item->getUid(), true, true);
+    } else {
+      // trusted, provided a package, do nothing
+    }
+
+    ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
+          "sanitized pkg version: %d",
+          uid_given, item->getUid(),
+          item->getPkgName().c_str(),
+          item->getPkgVersionCode());
 
     mItemsSubmitted++;
 
@@ -622,9 +637,6 @@
         while (l->size() > 0) {
             MediaAnalyticsItem * oitem = *(l->begin());
             nsecs_t when = oitem->getTimestamp();
-// DEBUGGING -- remove this ALOGD() call
-            if(0) ALOGD("@ now=%10" PRId64 " record when=%10" PRId64 "",
-                  now, when);
             // careful about timejumps too
             if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
                 // this (and the rest) are recent enough to keep
@@ -641,11 +653,6 @@
 // are they alike enough that nitem can be folded into oitem?
 static bool compatibleItems(MediaAnalyticsItem * oitem, MediaAnalyticsItem * nitem) {
 
-    if (0) {
-        ALOGD("Compare: o %s n %s",
-              oitem->toString().c_str(), nitem->toString().c_str());
-    }
-
     // general safety
     if (nitem->getUid() != oitem->getUid()) {
         return false;
@@ -796,85 +803,155 @@
 
 }
 
-// mapping uids to package names
+// how long we hold package info before we re-fetch it
+#define PKG_EXPIRATION_NS (30*60*1000000000ll)   // 30 minutes, in nsecs
 
 // give me the package name, perhaps going to find it
-AString MediaAnalyticsService::getPkgName(uid_t uid, bool addIfMissing) {
+void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion) {
+    ALOGV("asking for packagename to go with uid=%d", uid);
+
+    if (!setName && !setVersion) {
+        // setting nothing? strange
+        return;
+    }
+
+    nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+    struct UidToPkgMap mapping;
+    mapping.uid = (-1);
+
     ssize_t i = mPkgMappings.indexOfKey(uid);
     if (i >= 0) {
-        AString pkg = mPkgMappings.valueAt(i);
-        ALOGV("returning pkg '%s' for uid %d", pkg.c_str(), uid);
-        return pkg;
-    }
-
-    AString pkg;
-
-    if (addIfMissing == false) {
-        return pkg;
-    }
-
-    struct passwd *pw = getpwuid(uid);
-    if (pw) {
-        pkg = pw->pw_name;
-    } else {
-        pkg = "-";
-    }
-
-    // find the proper value
-
-    sp<IBinder> binder = NULL;
-    sp<IServiceManager> sm = defaultServiceManager();
-    if (sm == NULL) {
-        ALOGE("defaultServiceManager failed");
-    } else {
-        binder = sm->getService(String16("package_native"));
-        if (binder == NULL) {
-            ALOGE("getService package_native failed");
+        mapping = mPkgMappings.valueAt(i);
+        ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
+              uid, mapping.expiration, now);
+        if (mapping.expiration < now) {
+            // purge our current entry and re-query
+            ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
+            mPkgMappings.removeItemsAt(i, 1);
+            // could cheat and use a goto back to the top of the routine.
+            // a good compiler should recognize the local tail recursion...
+            return setPkgInfo(item, uid, setName, setVersion);
         }
-    }
+    } else {
+        AString pkg;
+        std::string installer = "";
+        int32_t versionCode = 0;
 
-    if (binder != NULL) {
-        sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
+        struct passwd *pw = getpwuid(uid);
+        if (pw) {
+            pkg = pw->pw_name;
+        }
 
-        std::vector<int> uids;
-        std::vector<std::string> names;
+        // find the proper value -- should we cache this binder??
 
-        uids.push_back(uid);
-
-        binder::Status status = package_mgr->getNamesForUids(uids, &names);
-        if (!status.isOk()) {
-            ALOGE("package_native::getNamesForUids failed: %s",
-                  status.exceptionMessage().c_str());
+        sp<IBinder> binder = NULL;
+        sp<IServiceManager> sm = defaultServiceManager();
+        if (sm == NULL) {
+            ALOGE("defaultServiceManager failed");
         } else {
-            if (!names[0].empty()) {
-                pkg = names[0].c_str();
+            binder = sm->getService(String16("package_native"));
+            if (binder == NULL) {
+                ALOGE("getService package_native failed");
+            }
+        }
+
+        if (binder != NULL) {
+            sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
+            binder::Status status;
+
+            std::vector<int> uids;
+            std::vector<std::string> names;
+
+            uids.push_back(uid);
+
+            status = package_mgr->getNamesForUids(uids, &names);
+            if (!status.isOk()) {
+                ALOGE("package_native::getNamesForUids failed: %s",
+                      status.exceptionMessage().c_str());
+            } else {
+                if (!names[0].empty()) {
+                    pkg = names[0].c_str();
+                }
+            }
+
+            // strip any leading "shared:" strings that came back
+            if (pkg.startsWith("shared:")) {
+                pkg.erase(0, 7);
+            }
+
+            // determine how pkg was installed and the versionCode
+            //
+            if (pkg.empty()) {
+                // no name for us to manage
+            } else if (strchr(pkg.c_str(), '.') == NULL) {
+                // not of form 'com.whatever...'; assume internal and ok
+            } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
+                // android.* packages are assumed fine
+            } else {
+                String16 pkgName16(pkg.c_str());
+                status = package_mgr->getInstallerForPackage(pkgName16, &installer);
+                if (!status.isOk()) {
+                    ALOGE("package_native::getInstallerForPackage failed: %s",
+                          status.exceptionMessage().c_str());
+                }
+
+                // skip if we didn't get an installer
+                if (status.isOk()) {
+                    status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
+                    if (!status.isOk()) {
+                        ALOGE("package_native::getVersionCodeForPackage failed: %s",
+                          status.exceptionMessage().c_str());
+                    }
+                }
+
+
+                ALOGV("package '%s' installed by '%s' versioncode %d / %08x",
+                      pkg.c_str(), installer.c_str(), versionCode, versionCode);
+
+                if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
+                        // from play store, we keep info
+                } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
+                        // some google source, we keep info
+                } else if (strcmp(installer.c_str(), "preload") == 0) {
+                        // preloads, we keep the info
+                } else if (installer.c_str()[0] == '\0') {
+                        // sideload (no installer); do not report
+                        pkg = "";
+                        versionCode = 0;
+                } else {
+                        // unknown installer; do not report
+                        pkg = "";
+                        versionCode = 0;
+                }
+            }
+        }
+
+        // add it to the map, to save a subsequent lookup
+        if (!pkg.empty()) {
+            Mutex::Autolock _l(mLock_mappings);
+            ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
+            ssize_t i = mPkgMappings.indexOfKey(uid);
+            if (i < 0) {
+                mapping.uid = uid;
+                mapping.pkg = pkg;
+                mapping.installer = installer.c_str();
+                mapping.versionCode = versionCode;
+                mapping.expiration = now + PKG_EXPIRATION_NS;
+                ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
+
+                mPkgMappings.add(uid, mapping);
             }
         }
     }
 
-    // XXX determine whether package was side-loaded or from playstore.
-    // for privacy, we only list apps loaded from playstore.
-
-    // Sanitize the package name for ":"
-    // as an example, we get "shared:android.uid.systemui"
-    // replace : with something benign (I'm going to use !)
-    if (!pkg.empty()) {
-        int n = pkg.size();
-        char *p = (char *) pkg.c_str();
-        for (int i = 0 ; i < n; i++) {
-            if (p[i] == ':') {
-                p[i] = '!';
-            }
+    if (mapping.uid != (uid_t)(-1)) {
+        if (setName) {
+            item->setPkgName(mapping.pkg);
+        }
+        if (setVersion) {
+            item->setPkgVersionCode(mapping.versionCode);
         }
     }
-
-    // add it to the map, to save a subsequent lookup
-    if (!pkg.empty()) {
-        ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
-        mPkgMappings.add(uid, pkg);
-    }
-
-    return pkg;
 }
 
 } // namespace android
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index 4fe2fb2..52e4631 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -62,6 +62,7 @@
     // partitioned a bit so we don't over serialize
     mutable Mutex           mLock;
     mutable Mutex           mLock_ids;
+    mutable Mutex           mLock_mappings;
 
     // limit how many records we'll retain
     // by count (in each queue (open, finalized))
@@ -135,10 +136,13 @@
     struct UidToPkgMap {
         uid_t uid;
         AString pkg;
+        AString installer;
+        int32_t versionCode;
+        nsecs_t expiration;
     };
 
-    KeyedVector<uid_t,AString>  mPkgMappings;
-    AString getPkgName(uid_t uid, bool addIfMissing);
+    KeyedVector<uid_t,struct UidToPkgMap>  mPkgMappings;
+    void setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion);
 
 };
 
diff --git a/services/mediaanalytics/MetricsSummarizerCodec.cpp b/services/mediaanalytics/MetricsSummarizerCodec.cpp
index 8c74782..6af3c9a 100644
--- a/services/mediaanalytics/MetricsSummarizerCodec.cpp
+++ b/services/mediaanalytics/MetricsSummarizerCodec.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "MetricsSummarizerCodec"
 #include <utils/Log.h>
 
+#include <stdint.h>
+#include <inttypes.h>
 
 #include <utils/threads.h>
 #include <utils/Errors.h>
@@ -40,5 +42,4 @@
     ALOGV("MetricsSummarizerCodec::MetricsSummarizerCodec");
 }
 
-
 } // namespace android
diff --git a/services/mediaanalytics/mediametrics.rc b/services/mediaanalytics/mediametrics.rc
index 3829f8c..1efde5e 100644
--- a/services/mediaanalytics/mediametrics.rc
+++ b/services/mediaanalytics/mediametrics.rc
@@ -1,5 +1,6 @@
 service mediametrics /system/bin/mediametrics
     class main
     user media
+    group media
     ioprio rt 4
     writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index 6997b5a..faeb0a7 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -9,13 +9,8 @@
     libgui \
     libutils \
     liblog \
-    libstagefright_omx
-LOCAL_C_INCLUDES := \
-    frameworks/av/include \
-    frameworks/av/media/libstagefright \
-    frameworks/av/media/libstagefright/include \
-    frameworks/native/include \
-    frameworks/native/include/media/openmax
+    libstagefright_omx \
+    libstagefright_xmlparser
 LOCAL_MODULE:= libmediacodecservice
 LOCAL_VENDOR_MODULE := true
 LOCAL_32_BIT_ONLY := true
@@ -38,15 +33,10 @@
     libhwbinder \
     libhidltransport \
     libstagefright_omx \
+    libstagefright_xmlparser \
     android.hardware.media.omx@1.0 \
     android.hidl.memory@1.0
 
-LOCAL_C_INCLUDES := \
-    frameworks/av/include \
-    frameworks/av/media/libstagefright \
-    frameworks/av/media/libstagefright/include \
-    frameworks/native/include \
-    frameworks/native/include/media/openmax
 LOCAL_MODULE := android.hardware.media.omx@1.0-service
 LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_VENDOR_MODULE := true
diff --git a/services/mediacodec/MediaCodecService.cpp b/services/mediacodec/MediaCodecService.cpp
index fc1e5d9..6b510c6 100644
--- a/services/mediacodec/MediaCodecService.cpp
+++ b/services/mediacodec/MediaCodecService.cpp
@@ -24,15 +24,25 @@
 
 sp<IOMX> MediaCodecService::getOMX() {
 
-    Mutex::Autolock autoLock(mLock);
+    Mutex::Autolock autoLock(mOMXLock);
 
     if (mOMX.get() == NULL) {
-        mOMX = new OMX;
+        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)
diff --git a/services/mediacodec/MediaCodecService.h b/services/mediacodec/MediaCodecService.h
index 0d2c9d8..9301135 100644
--- a/services/mediacodec/MediaCodecService.h
+++ b/services/mediacodec/MediaCodecService.h
@@ -20,10 +20,12 @@
 #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
+class MediaCodecService : public BinderService<MediaCodecService>,
+        public BnMediaCodecService
 {
     friend class BinderService<MediaCodecService>;    // for MediaCodecService()
 public:
@@ -31,16 +33,20 @@
     virtual ~MediaCodecService() { }
     virtual void onFirstRef() { }
 
-    static const char*  getServiceName() { return "media.codec"; }
+    static const char*    getServiceName() { return "media.codec"; }
 
-    virtual sp<IOMX>    getOMX();
+    virtual sp<IOMX>      getOMX();
 
-    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-                                uint32_t flags);
+    virtual sp<IOMXStore> getOMXStore();
+
+    virtual status_t      onTransact(uint32_t code, const Parcel& data,
+                                     Parcel* reply, uint32_t flags);
 
 private:
-    Mutex               mLock;
-    sp<IOMX>            mOMX;
+    Mutex                 mOMXLock;
+    sp<IOMX>              mOMX;
+    Mutex                 mOMXStoreLock;
+    sp<IOMXStore>         mOMXStore;
 };
 
 }   // namespace android
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/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index 4c4b594..a751b4c 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -53,6 +53,7 @@
 fstatat64: 1
 ugetrlimit: 1
 getdents64: 1
+getrandom: 1
 
 # for attaching to debuggerd on process crash
 sigaction: 1
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 08cbef6..50a4191 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -33,17 +33,18 @@
 
     sp<DataSource> localSource = DataSource::CreateFromIDataSource(remoteSource);
 
-    sp<IMediaExtractor> ret = MediaExtractor::CreateFromService(localSource, mime);
+    sp<MediaExtractor> extractor = MediaExtractor::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 = extractor->asIMediaExtractor();
         registerMediaExtractor(ret, localSource, mime);
+        return ret;
     }
-
-    return ret;
+    return nullptr;
 }
 
 sp<IDataSource> MediaExtractorService::makeIDataSource(int fd, int64_t offset, int64_t length)
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index e06ac8c..4fa69d7 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -39,6 +39,7 @@
 getegid32: 1
 getgroups32: 1
 nanosleep: 1
+getrandom: 1
 
 # for FileSource
 readlinkat: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index 4b51457..d1278a9 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -28,10 +28,10 @@
 rt_sigreturn: 1
 getrlimit: 1
 nanosleep: 1
+getrandom: 1
 
 # for FileSource
 readlinkat: 1
-_llseek: 1
 
 # for attaching to debuggerd on process crash
 tgkill: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index cdff4db..3b37f92 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -37,6 +37,7 @@
 getegid32: 1
 getgroups32: 1
 nanosleep: 1
+getrandom: 1
 
 # for FileSource
 readlinkat: 1
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index f41219e..f996f74 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -102,7 +102,7 @@
         }
     }
 
-    ALOGD("AAudioEndpointManager.findExclusiveEndpoint_l(), found %p for device = %d",
+    ALOGV("AAudioEndpointManager.findExclusiveEndpoint_l(), found %p for device = %d",
           endpoint.get(), configuration.getDeviceId());
     return endpoint;
 }
@@ -118,7 +118,7 @@
         }
     }
 
-    ALOGD("AAudioEndpointManager.findSharedEndpoint_l(), found %p for device = %d",
+    ALOGV("AAudioEndpointManager.findSharedEndpoint_l(), found %p for device = %d",
           endpoint.get(), configuration.getDeviceId());
     return endpoint;
 }
@@ -238,8 +238,6 @@
     std::lock_guard<std::mutex> lock(mExclusiveLock);
     int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
     serviceEndpoint->setOpenCount(newRefCount);
-    ALOGD("AAudioEndpointManager::closeExclusiveEndpoint(%p) newRefCount = %d",
-          serviceEndpoint.get(), newRefCount);
 
     // If no longer in use then close and delete it.
     if (newRefCount <= 0) {
@@ -262,8 +260,6 @@
     std::lock_guard<std::mutex> lock(mSharedLock);
     int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
     serviceEndpoint->setOpenCount(newRefCount);
-    ALOGD("AAudioEndpointManager::closeSharedEndpoint(%p) newRefCount = %d",
-          serviceEndpoint.get(), newRefCount);
 
     // If no longer in use then close and delete it.
     if (newRefCount <= 0) {
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 855ae69..5a3488d 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -18,9 +18,9 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <iomanip>
+#include <iostream>
 #include <sstream>
-//#include <time.h>
-//#include <pthread.h>
 
 #include <aaudio/AAudio.h>
 #include <mediautils/SchedulingPolicyService.h>
@@ -35,18 +35,13 @@
 #include "AAudioServiceStreamMMAP.h"
 #include "binding/IAAudioService.h"
 #include "ServiceUtilities.h"
-#include "utility/HandleTracker.h"
 
 using namespace android;
 using namespace aaudio;
 
 #define MAX_STREAMS_PER_PROCESS   8
 
-typedef enum
-{
-    AAUDIO_HANDLE_TYPE_STREAM
-} aaudio_service_handle_type_t;
-static_assert(AAUDIO_HANDLE_TYPE_STREAM < HANDLE_TRACKER_MAX_TYPES, "Too many handle types.");
+using android::AAudioService;
 
 android::AAudioService::AAudioService()
     : BnAAudioService() {
@@ -70,7 +65,8 @@
         result = ss.str();
         ALOGW("%s", result.c_str());
     } else {
-        result = mHandleTracker.dump()
+        result = "------------ AAudio Service ------------\n"
+                 + mStreamTracker.dump()
                  + AAudioClientTracker::getInstance().dump()
                  + AAudioEndpointManager::getInstance().dump();
     }
@@ -125,7 +121,7 @@
 
     // if SHARED requested or if EXCLUSIVE failed
     if (sharingMode == AAUDIO_SHARING_MODE_SHARED
-         || (serviceStream == nullptr && !sharingModeMatchRequired)) {
+         || (serviceStream.get() == nullptr && !sharingModeMatchRequired)) {
         serviceStream =  new AAudioServiceStreamShared(*this);
         result = serviceStream->open(request);
     }
@@ -136,18 +132,12 @@
               result, AAudio_convertResultToText(result));
         return result;
     } else {
-        aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream.get());
-        if (handle < 0) {
-            ALOGE("AAudioService::openStream(): handle table full");
-            serviceStream->close();
-            serviceStream.clear();
-        } else {
-            ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
-            serviceStream->setHandle(handle);
-            pid_t pid = request.getProcessId();
-            AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
-            configurationOutput.copyFrom(*serviceStream);
-        }
+        aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
+        ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
+        serviceStream->setHandle(handle);
+        pid_t pid = request.getProcessId();
+        AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
+        configurationOutput.copyFrom(*serviceStream);
         return handle;
     }
 }
@@ -155,30 +145,32 @@
 aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) {
     // Check permission and ownership first.
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
-        ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGE("AAudioService::closeStream(0x%0x), illegal stream handle", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 
     ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
     // Remove handle from tracker so that we cannot look up the raw address any more.
-    serviceStream = (AAudioServiceStreamBase *)
-            mHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM,
-                                  streamHandle);
-    if (serviceStream != nullptr) {
+    // removeStreamByHandle() uses a lock so that if there are two simultaneous closes
+    // then only one will get the pointer and do the close.
+    serviceStream = mStreamTracker.removeStreamByHandle(streamHandle);
+    if (serviceStream.get() != nullptr) {
         serviceStream->close();
         pid_t pid = serviceStream->getOwnerProcessId();
         AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
         return AAUDIO_OK;
+    } else {
+        ALOGW("AAudioService::closeStream(0x%0x) being handled by another thread", streamHandle);
+        return AAUDIO_ERROR_INVALID_HANDLE;
     }
-    return AAUDIO_ERROR_INVALID_HANDLE;
 }
 
-AAudioServiceStreamBase *AAudioService::convertHandleToServiceStream(
-        aaudio_handle_t streamHandle) const {
-    AAudioServiceStreamBase *serviceStream = (AAudioServiceStreamBase *)
-            mHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM, (aaudio_handle_t)streamHandle);
-    if (serviceStream != nullptr) {
+
+sp<AAudioServiceStreamBase> AAudioService::convertHandleToServiceStream(
+        aaudio_handle_t streamHandle) {
+    sp<AAudioServiceStreamBase> serviceStream = mStreamTracker.getStreamByHandle(streamHandle);
+    if (serviceStream.get() != nullptr) {
         // Only allow owner or the aaudio service to access the stream.
         const uid_t callingUserId = IPCThreadState::self()->getCallingUid();
         const uid_t ownerUserId = serviceStream->getOwnerUserId();
@@ -198,30 +190,30 @@
 aaudio_result_t AAudioService::getStreamDescription(
                 aaudio_handle_t streamHandle,
                 aaudio::AudioEndpointParcelable &parcelable) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
+
     aaudio_result_t result = serviceStream->getDescription(parcelable);
     // parcelable.dump();
     return result;
 }
 
 aaudio_result_t AAudioService::startStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
 
-    aaudio_result_t result = serviceStream->start();
-    return result;
+    return serviceStream->start();
 }
 
 aaudio_result_t AAudioService::pauseStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::pauseStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -230,9 +222,9 @@
 }
 
 aaudio_result_t AAudioService::stopStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
-        ALOGE("AAudioService::pauseStream(), illegal stream handle = 0x%0x", streamHandle);
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
+        ALOGE("AAudioService::stopStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
     aaudio_result_t result = serviceStream->stop();
@@ -240,8 +232,8 @@
 }
 
 aaudio_result_t AAudioService::flushStream(aaudio_handle_t streamHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::flushStream(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -251,8 +243,8 @@
 aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle,
                                                    pid_t clientThreadId,
                                                    int64_t periodNanoseconds) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
@@ -276,8 +268,8 @@
 
 aaudio_result_t AAudioService::unregisterAudioThread(aaudio_handle_t streamHandle,
                                                      pid_t clientThreadId) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::unregisterAudioThread(), illegal stream handle = 0x%0x",
               streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
@@ -293,8 +285,8 @@
 aaudio_result_t AAudioService::startClient(aaudio_handle_t streamHandle,
                                   const android::AudioClient& client,
                                   audio_port_handle_t *clientHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::startClient(), illegal stream handle = 0x%0x",
               streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
@@ -304,8 +296,8 @@
 
 aaudio_result_t AAudioService::stopClient(aaudio_handle_t streamHandle,
                                           audio_port_handle_t clientHandle) {
-    AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
-    if (serviceStream == nullptr) {
+    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+    if (serviceStream.get() == nullptr) {
         ALOGE("AAudioService::stopClient(), illegal stream handle = 0x%0x",
               streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index ffaf538..eef0824 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -24,13 +24,13 @@
 #include <media/AudioClient.h>
 
 #include <aaudio/AAudio.h>
-#include "utility/HandleTracker.h"
-#include "binding/IAAudioService.h"
-#include "binding/AAudioServiceInterface.h"
 
-namespace aaudio {
-    class AAudioServiceStreamBase;
-};
+#include "binding/AAudioCommon.h"
+#include "binding/AAudioServiceInterface.h"
+#include "binding/IAAudioService.h"
+
+#include "AAudioServiceStreamBase.h"
+#include "AAudioStreamTracker.h"
 
 namespace android {
 
@@ -51,45 +51,53 @@
 
     virtual void            registerClient(const sp<IAAudioClient>& client);
 
-    virtual aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
-                                     aaudio::AAudioStreamConfiguration &configurationOutput);
+    aaudio::aaudio_handle_t openStream(const aaudio::AAudioStreamRequest &request,
+                                       aaudio::AAudioStreamConfiguration &configurationOutput)
+                                       override;
 
-    virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle);
+    aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t getStreamDescription(
-                aaudio_handle_t streamHandle,
-                aaudio::AudioEndpointParcelable &parcelable);
+    aaudio_result_t getStreamDescription(
+                aaudio::aaudio_handle_t streamHandle,
+                aaudio::AudioEndpointParcelable &parcelable) override;
 
-    virtual aaudio_result_t startStream(aaudio_handle_t streamHandle);
+    aaudio_result_t startStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t pauseStream(aaudio_handle_t streamHandle);
+    aaudio_result_t pauseStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t stopStream(aaudio_handle_t streamHandle);
+    aaudio_result_t stopStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle);
+    aaudio_result_t flushStream(aaudio::aaudio_handle_t streamHandle) override;
 
-    virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
+    aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle,
                                                 pid_t tid,
-                                                int64_t periodNanoseconds) ;
+                                                int64_t periodNanoseconds) override;
 
-    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
-                                                  pid_t tid);
+    aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
+                                                  pid_t tid) override;
 
-    virtual aaudio_result_t startClient(aaudio_handle_t streamHandle,
+    aaudio_result_t startClient(aaudio::aaudio_handle_t streamHandle,
                                       const android::AudioClient& client,
-                                      audio_port_handle_t *clientHandle);
+                                      audio_port_handle_t *clientHandle) override;
 
-    virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle,
-                                       audio_port_handle_t clientHandle);
+    aaudio_result_t stopClient(aaudio::aaudio_handle_t streamHandle,
+                                       audio_port_handle_t clientHandle) override;
 
 private:
 
-    aaudio::AAudioServiceStreamBase *convertHandleToServiceStream(aaudio_handle_t streamHandle) const;
+    /**
+     * Lookup stream and then validate access to the stream.
+     * @param streamHandle
+     * @return
+     */
+    sp<aaudio::AAudioServiceStreamBase> convertHandleToServiceStream(
+            aaudio::aaudio_handle_t streamHandle);
 
-    HandleTracker mHandleTracker;
 
     android::AudioClient mAudioClient;
 
+    aaudio::AAudioStreamTracker                 mStreamTracker;
+
     enum constants {
         DEFAULT_AUDIO_PRIORITY = 2
     };
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index cba5bc8..3095bc9 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -60,7 +60,7 @@
     result << "    Reference Count:      " << mOpenCount << "\n";
     result << "    Requested Device Id:  " << mRequestedDeviceId << "\n";
     result << "    Device Id:            " << getDeviceId() << "\n";
-    result << "    Registered Streams:  " << "\n";
+    result << "    Registered Streams:" << "\n";
     result << AAudioServiceStreamShared::dumpHeader() << "\n";
     for (const auto stream : mRegisteredStreams) {
         result << stream->dump() << "\n";
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index 97558ca..c7d9b8e 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -84,30 +84,42 @@
             std::lock_guard <std::mutex> lock(mLockStreams);
             for (const auto clientStream : mRegisteredStreams) {
                 if (clientStream->isRunning()) {
-                    AAudioServiceStreamShared *streamShared =
+                    int64_t clientFramesWritten = 0;
+                    sp<AAudioServiceStreamShared> streamShared =
                             static_cast<AAudioServiceStreamShared *>(clientStream.get());
 
-                    FifoBuffer *fifo = streamShared->getDataFifoBuffer();
+                    {
+                        // Lock the AudioFifo to protect against close.
+                        std::lock_guard <std::mutex> lock(streamShared->getAudioDataQueueLock());
 
-                    // Determine offset between framePosition in client's stream vs the underlying
-                    // MMAP stream.
-                    int64_t clientFramesWritten = fifo->getWriteCounter();
-                    // There are two indices that refer to the same frame.
-                    int64_t positionOffset = mmapFramesRead - clientFramesWritten;
-                    streamShared->setTimestampPositionOffset(positionOffset);
+                        FifoBuffer *fifo = streamShared->getAudioDataFifoBuffer_l();
+                        if (fifo != nullptr) {
 
-                    if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
-                        getFramesPerBurst()) {
-                        underflowCount++;
-                    } else {
-                        fifo->write(mDistributionBuffer, getFramesPerBurst());
+                            // Determine offset between framePosition in client's stream
+                            // vs the underlying MMAP stream.
+                            clientFramesWritten = fifo->getWriteCounter();
+                            // There are two indices that refer to the same frame.
+                            int64_t positionOffset = mmapFramesRead - clientFramesWritten;
+                            streamShared->setTimestampPositionOffset(positionOffset);
+
+                            if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
+                                getFramesPerBurst()) {
+                                underflowCount++;
+                            } else {
+                                fifo->write(mDistributionBuffer, getFramesPerBurst());
+                            }
+                            clientFramesWritten = fifo->getWriteCounter();
+                        }
                     }
 
-                    // This timestamp represents the completion of data being written into the
-                    // client buffer. It is sent to the client and used in the timing model
-                    // to decide when data will be available to read.
-                    Timestamp timestamp(fifo->getWriteCounter(), AudioClock::getNanoseconds());
-                    streamShared->markTransferTime(timestamp);
+                    if (clientFramesWritten > 0) {
+                        // This timestamp represents the completion of data being written into the
+                        // client buffer. It is sent to the client and used in the timing model
+                        // to decide when data will be available to read.
+                        Timestamp timestamp(clientFramesWritten, AudioClock::getNanoseconds());
+                        streamShared->markTransferTime(timestamp);
+                    }
+
                 }
             }
         }
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 58213f8..4be25c8 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -250,6 +250,8 @@
 
 aaudio_result_t AAudioServiceEndpointMMAP::startStream(sp<AAudioServiceStreamBase> stream,
                                                    audio_port_handle_t *clientHandle) {
+    // Start the client on behalf of the AAudio service.
+    // Use the port handle that was provided by openMmapStream().
     return startClient(mMmapClient, &mPortHandle);
 }
 
@@ -262,11 +264,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))",
+          &client, client.clientUid, client.clientPid);
     audio_port_handle_t originalHandle =  *clientHandle;
-    aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->start(client,
-                                                                                    clientHandle));
-    ALOGD("AAudioServiceEndpointMMAP::startClient(%p(uid=%d, pid=%d), %d => %d) returns %d",
-          &client, client.clientUid, client.clientPid,
+    status_t status = mMmapStream->start(client, clientHandle);
+    aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
+    ALOGD("AAudioServiceEndpointMMAP::startClient() , %d => %d returns %d",
           originalHandle, *clientHandle, result);
     return result;
 }
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index c42a6e2..9b1833a 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -81,32 +81,44 @@
 
             std::lock_guard <std::mutex> lock(mLockStreams);
             for (const auto clientStream : mRegisteredStreams) {
+                int64_t clientFramesRead = 0;
+
                 if (!clientStream->isRunning()) {
                     continue;
                 }
 
-                AAudioServiceStreamShared *streamShared =
+                sp<AAudioServiceStreamShared> streamShared =
                         static_cast<AAudioServiceStreamShared *>(clientStream.get());
 
-                FifoBuffer *fifo = streamShared->getDataFifoBuffer();
-                // Determine offset between framePosition in client's stream vs the underlying
-                // MMAP stream.
-                int64_t clientFramesRead = fifo->getReadCounter();
-                // These two indices refer to the same frame.
-                int64_t positionOffset = mmapFramesWritten - clientFramesRead;
-                streamShared->setTimestampPositionOffset(positionOffset);
+                {
+                    // Lock the AudioFifo to protect against close.
+                    std::lock_guard <std::mutex> lock(streamShared->getAudioDataQueueLock());
 
-                float volume = 1.0; // to match legacy volume
-                bool underflowed = mMixer.mix(index, fifo, volume);
+                    FifoBuffer *fifo = streamShared->getAudioDataFifoBuffer_l();
+                    if (fifo != nullptr) {
 
-                // This timestamp represents the completion of data being read out of the
-                // client buffer. It is sent to the client and used in the timing model
-                // to decide when the client has room to write more data.
-                Timestamp timestamp(fifo->getReadCounter(), AudioClock::getNanoseconds());
-                streamShared->markTransferTime(timestamp);
+                        // Determine offset between framePosition in client's stream
+                        // vs the underlying MMAP stream.
+                        clientFramesRead = fifo->getReadCounter();
+                        // These two indices refer to the same frame.
+                        int64_t positionOffset = mmapFramesWritten - clientFramesRead;
+                        streamShared->setTimestampPositionOffset(positionOffset);
 
-                if (underflowed) {
-                    streamShared->incrementXRunCount();
+                        float volume = 1.0; // to match legacy volume
+                        bool underflowed = mMixer.mix(index, fifo, volume);
+                        if (underflowed) {
+                            streamShared->incrementXRunCount();
+                        }
+                        clientFramesRead = fifo->getReadCounter();
+                    }
+                }
+
+                if (clientFramesRead > 0) {
+                    // This timestamp represents the completion of data being read out of the
+                    // client buffer. It is sent to the client and used in the timing model
+                    // to decide when the client has room to write more data.
+                    Timestamp timestamp(clientFramesRead, AudioClock::getNanoseconds());
+                    streamShared->markTransferTime(timestamp);
                 }
 
                 index++; // just used for labelling tracks in systrace
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 43d73b7..cd40066 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -115,16 +115,33 @@
 aaudio_result_t AAudioServiceEndpointShared::startStream(sp<AAudioServiceStreamBase> sharedStream,
                                                          audio_port_handle_t *clientHandle) {
     aaudio_result_t result = AAUDIO_OK;
-    if (++mRunningStreamCount == 1) {
-        // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
+
+    {
         std::lock_guard<std::mutex> lock(mLockStreams);
-        result = getStreamInternal()->requestStart();
-        startSharingThread_l();
+        if (++mRunningStreamCount == 1) { // atomic
+            result = getStreamInternal()->requestStart();
+            if (result != AAUDIO_OK) {
+                --mRunningStreamCount;
+            } else {
+                result = startSharingThread_l();
+                if (result != AAUDIO_OK) {
+                    getStreamInternal()->requestStop();
+                    --mRunningStreamCount;
+                }
+            }
+        }
     }
+
     if (result == AAUDIO_OK) {
-        ALOGD("AAudioServiceEndpointShared::startStream() use shared stream client.");
         result = getStreamInternal()->startClient(sharedStream->getAudioClient(), clientHandle);
+        if (result != AAUDIO_OK) {
+            if (--mRunningStreamCount == 0) { // atomic
+                stopSharingThread();
+                getStreamInternal()->requestStop();
+            }
+        }
     }
+
     return result;
 }
 
@@ -142,7 +159,6 @@
     return AAUDIO_OK;
 }
 
-
 // Get timestamp that was written by the real-time service thread, eg. mixer.
 aaudio_result_t AAudioServiceEndpointShared::getFreeRunningPosition(int64_t *positionFrames,
                                                                   int64_t *timeNanos) {
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 2dc62a0..e670129 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -42,7 +42,7 @@
 
 AAudioServiceStreamBase::AAudioServiceStreamBase(AAudioService &audioService)
         : mUpMessageQueue(nullptr)
-        , mAAudioThread()
+        , mTimestampThread()
         , mAtomicTimestamp()
         , mAudioService(audioService) {
     mMmapClient.clientUid = -1;
@@ -54,10 +54,10 @@
     ALOGD("AAudioServiceStreamBase::~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(!(mState == AAUDIO_STREAM_STATE_CLOSED
-                        || mState == AAUDIO_STREAM_STATE_UNINITIALIZED
-                        || mState == AAUDIO_STREAM_STATE_DISCONNECTED),
-                        "service stream still open, state = %d", mState);
+    LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
+                        || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
+                        || getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
+                        "service stream still open, state = %d", getState());
 }
 
 std::string AAudioServiceStreamBase::dumpHeader() {
@@ -71,7 +71,7 @@
            << std::dec << std::setfill(' ') ;
     result << std::setw(6) << mMmapClient.clientUid;
     result << std::setw(4) << (isRunning() ? "yes" : " no");
-    result << std::setw(6) << mState;
+    result << std::setw(6) << getState();
     result << std::setw(7) << getFormat();
     result << std::setw(6) << mFramesPerBurst;
     result << std::setw(5) << getSamplesPerFrame();
@@ -124,7 +124,7 @@
 
 aaudio_result_t AAudioServiceStreamBase::close() {
     aaudio_result_t result = AAUDIO_OK;
-    if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+    if (getState() == AAUDIO_STREAM_STATE_CLOSED) {
         return AAUDIO_OK;
     }
 
@@ -146,37 +146,50 @@
         mUpMessageQueue = nullptr;
     }
 
-    mState = AAUDIO_STREAM_STATE_CLOSED;
+    setState(AAUDIO_STREAM_STATE_CLOSED);
     return result;
 }
 
+aaudio_result_t AAudioServiceStreamBase::startDevice() {
+    mClientHandle = AUDIO_PORT_HANDLE_NONE;
+    return mServiceEndpoint->startStream(this, &mClientHandle);
+}
+
 /**
  * Start the flow of audio data.
  *
  * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
  */
 aaudio_result_t AAudioServiceStreamBase::start() {
+    aaudio_result_t result = AAUDIO_OK;
     if (isRunning()) {
         return AAUDIO_OK;
     }
 
     if (mServiceEndpoint == nullptr) {
         ALOGE("AAudioServiceStreamBase::start() missing endpoint");
-        return AAUDIO_ERROR_INVALID_STATE;
+        result = AAUDIO_ERROR_INVALID_STATE;
+        goto error;
     }
+
+    // Start with fresh presentation timestamps.
+    mAtomicTimestamp.clear();
+
     mClientHandle = AUDIO_PORT_HANDLE_NONE;
-    aaudio_result_t result = mServiceEndpoint->startStream(this, &mClientHandle);
-    if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamBase::start() mServiceEndpoint returned %d", result);
-        disconnect();
-    } else {
-        if (result == AAUDIO_OK) {
-            sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED);
-            mState = AAUDIO_STREAM_STATE_STARTED;
-            mThreadEnabled.store(true);
-            result = mAAudioThread.start(this);
-        }
-    }
+    result = startDevice();
+    if (result != AAUDIO_OK) goto error;
+
+    // This should happen at the end of the start.
+    sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED);
+    setState(AAUDIO_STREAM_STATE_STARTED);
+    mThreadEnabled.store(true);
+    result = mTimestampThread.start(this);
+    if (result != AAUDIO_OK) goto error;
+
+    return result;
+
+error:
+    disconnect();
     return result;
 }
 
@@ -197,13 +210,13 @@
 
     sendCurrentTimestamp();
     mThreadEnabled.store(false);
-    result = mAAudioThread.stop();
+    result = mTimestampThread.stop();
     if (result != AAUDIO_OK) {
         disconnect();
         return result;
     }
     sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
-    mState = AAUDIO_STREAM_STATE_PAUSED;
+    setState(AAUDIO_STREAM_STATE_PAUSED);
     return result;
 }
 
@@ -234,7 +247,7 @@
     }
 
     sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
-    mState = AAUDIO_STREAM_STATE_STOPPED;
+    setState(AAUDIO_STREAM_STATE_STOPPED);
     return result;
 }
 
@@ -242,20 +255,20 @@
     aaudio_result_t result = AAUDIO_OK;
     // clear flag that tells thread to loop
     if (mThreadEnabled.exchange(false)) {
-        result = mAAudioThread.stop();
+        result = mTimestampThread.stop();
     }
     return result;
 }
 
 aaudio_result_t AAudioServiceStreamBase::flush() {
-    if (mState != AAUDIO_STREAM_STATE_PAUSED) {
+    if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
         ALOGE("AAudioServiceStreamBase::flush() stream not paused, state = %s",
               AAudio_convertStreamStateToText(mState));
         return AAUDIO_ERROR_INVALID_STATE;
     }
     // Data will get flushed when the client receives the FLUSHED event.
     sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
-    mState = AAUDIO_STREAM_STATE_FLUSHED;
+    setState(AAUDIO_STREAM_STATE_FLUSHED);
     return AAUDIO_OK;
 }
 
@@ -283,9 +296,9 @@
 }
 
 void AAudioServiceStreamBase::disconnect() {
-    if (mState != AAUDIO_STREAM_STATE_DISCONNECTED) {
+    if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
         sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
-        mState = AAUDIO_STREAM_STATE_DISCONNECTED;
+        setState(AAUDIO_STREAM_STATE_DISCONNECTED);
     }
 }
 
@@ -321,6 +334,9 @@
     aaudio_result_t result = getFreeRunningPosition(&command.timestamp.position,
                                                     &command.timestamp.timestamp);
     if (result == AAUDIO_OK) {
+        ALOGV("sendCurrentTimestamp() SERVICE  %8lld at %lld",
+              (long long) command.timestamp.position,
+              (long long) command.timestamp.timestamp);
         command.what = AAudioServiceMessage::code::TIMESTAMP_SERVICE;
         result = writeUpMessageQueue(&command);
 
@@ -329,13 +345,16 @@
             result = getHardwareTimestamp(&command.timestamp.position,
                                           &command.timestamp.timestamp);
             if (result == AAUDIO_OK) {
+                ALOGV("sendCurrentTimestamp() HARDWARE %8lld at %lld",
+                      (long long) command.timestamp.position,
+                      (long long) command.timestamp.timestamp);
                 command.what = AAudioServiceMessage::code::TIMESTAMP_HARDWARE;
                 result = writeUpMessageQueue(&command);
             }
         }
     }
 
-    if (result == AAUDIO_ERROR_UNAVAILABLE) {
+    if (result == AAUDIO_ERROR_UNAVAILABLE) { // TODO review best error code
         result = AAUDIO_OK; // just not available yet, try again later
     }
     return result;
@@ -346,10 +365,17 @@
  * used to communicate with the underlying HAL or Service.
  */
 aaudio_result_t AAudioServiceStreamBase::getDescription(AudioEndpointParcelable &parcelable) {
-    // Gather information on the message queue.
-    mUpMessageQueue->fillParcelable(parcelable,
-                                    parcelable.mUpMessageQueueParcelable);
-    return getDownDataDescription(parcelable);
+    {
+        std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
+        if (mUpMessageQueue == nullptr) {
+            ALOGE("getDescription(): mUpMessageQueue null! - stream not open");
+            return AAUDIO_ERROR_NULL;
+        }
+        // Gather information on the message queue.
+        mUpMessageQueue->fillParcelable(parcelable,
+                                        parcelable.mUpMessageQueueParcelable);
+    }
+    return getAudioDataDescription(parcelable);
 }
 
 void AAudioServiceStreamBase::onVolumeChanged(float volume) {
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 301795d..af435b4 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -32,7 +32,10 @@
 
 #include "SharedRingBuffer.h"
 #include "AAudioThread.h"
-#include "AAudioService.h"
+
+namespace android {
+    class AAudioService;
+}
 
 namespace aaudio {
 
@@ -191,6 +194,12 @@
         mState = state;
     }
 
+    /**
+     * Device specific startup.
+     * @return AAUDIO_OK or negative error.
+     */
+    virtual aaudio_result_t startDevice();
+
     aaudio_result_t writeUpMessageQueue(AAudioServiceMessage *command);
 
     aaudio_result_t sendCurrentTimestamp();
@@ -204,7 +213,7 @@
 
     virtual aaudio_result_t getHardwareTimestamp(int64_t *positionFrames, int64_t *timeNanos) = 0;
 
-    virtual aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) = 0;
+    virtual aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) = 0;
 
     aaudio_stream_state_t   mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
 
@@ -213,7 +222,7 @@
     SharedRingBuffer*       mUpMessageQueue;
     std::mutex              mUpMessageQueueLock;
 
-    AAudioThread            mAAudioThread;
+    AAudioThread            mTimestampThread;
     // This is used by one thread to tell another thread to exit. So it must be atomic.
     std::atomic<bool>       mThreadEnabled{false};
 
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 43595a4..44ba1ca 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -50,7 +50,7 @@
 }
 
 aaudio_result_t AAudioServiceStreamMMAP::close() {
-    if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+    if (getState() == AAUDIO_STREAM_STATE_CLOSED) {
         return AAUDIO_OK;
     }
 
@@ -67,7 +67,6 @@
     aaudio_result_t result = AAudioServiceStreamBase::open(request,
                                                            AAUDIO_SHARING_MODE_EXCLUSIVE);
     if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamBase open returned %d", result);
         return result;
     }
 
@@ -85,14 +84,11 @@
 /**
  * Start the flow of data.
  */
-aaudio_result_t AAudioServiceStreamMMAP::start() {
-    if (isRunning()) {
-        return AAUDIO_OK;
-    }
-
-    aaudio_result_t result = AAudioServiceStreamBase::start();
+aaudio_result_t AAudioServiceStreamMMAP::startDevice() {
+    aaudio_result_t result = AAudioServiceStreamBase::startDevice();
     if (!mInService && result == AAUDIO_OK) {
-        startClient(mMmapClient, &mClientHandle);
+        // Note that this can sometimes take 200 to 300 msec for a cold start!
+        result = startClient(mMmapClient, &mClientHandle);
     }
     return result;
 }
@@ -107,7 +103,7 @@
     aaudio_result_t result = AAudioServiceStreamBase::pause();
     // TODO put before base::pause()?
     if (!mInService) {
-        stopClient(mClientHandle);
+        (void) stopClient(mClientHandle);
     }
     return result;
 }
@@ -119,13 +115,14 @@
     aaudio_result_t result = AAudioServiceStreamBase::stop();
     // TODO put before base::stop()?
     if (!mInService) {
-        stopClient(mClientHandle);
+        (void) stopClient(mClientHandle);
     }
     return result;
 }
 
 aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
                                                        audio_port_handle_t *clientHandle) {
+    // Start the client on behalf of the application. Generate a new porthandle.
     aaudio_result_t result = mServiceEndpoint->startClient(client, clientHandle);
     return result;
 }
@@ -171,7 +168,8 @@
 /**
  * Get an immutable description of the data queue from the HAL.
  */
-aaudio_result_t AAudioServiceStreamMMAP::getDownDataDescription(AudioEndpointParcelable &parcelable)
+aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription(
+        AudioEndpointParcelable &parcelable)
 {
     sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP{
             static_cast<AAudioServiceEndpointMMAP *>(mServiceEndpoint.get())};
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index bf0aab3..e2415d0 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -53,14 +53,6 @@
     aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
 
     /**
-     * Start the flow of audio data.
-     *
-     * This is not guaranteed to be synchronous but it currently is.
-     * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
-     */
-    aaudio_result_t start() override;
-
-    /**
      * Stop the flow of data so that start() can resume without loss of data.
      *
      * This is not guaranteed to be synchronous but it currently is.
@@ -83,12 +75,18 @@
 
 protected:
 
-    aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override;
+    aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) override;
 
     aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
 
     aaudio_result_t getHardwareTimestamp(int64_t *positionFrames, int64_t *timeNanos) override;
 
+    /**
+     * Device specific startup.
+     * @return AAUDIO_OK or negative error.
+     */
+    aaudio_result_t startDevice() override;
+
 private:
 
     bool                     mInService = false;
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 834f39f..084f996 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -167,14 +167,17 @@
         goto error;
     }
 
-    // Create audio data shared memory buffer for client.
-    mAudioDataQueue = new SharedRingBuffer();
-    result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
-    if (result != AAUDIO_OK) {
-        ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
-              getBufferCapacity());
-        result = AAUDIO_ERROR_NO_MEMORY;
-        goto error;
+    {
+        std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+        // Create audio data shared memory buffer for client.
+        mAudioDataQueue = new SharedRingBuffer();
+        result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
+        if (result != AAUDIO_OK) {
+            ALOGE("AAudioServiceStreamShared::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",
@@ -197,8 +200,11 @@
 aaudio_result_t AAudioServiceStreamShared::close()  {
     aaudio_result_t result = AAudioServiceStreamBase::close();
 
-    delete mAudioDataQueue;
-    mAudioDataQueue = nullptr;
+    {
+        std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+        delete mAudioDataQueue;
+        mAudioDataQueue = nullptr;
+    }
 
     return result;
 }
@@ -206,8 +212,14 @@
 /**
  * Get an immutable description of the data queue created by this service.
  */
-aaudio_result_t AAudioServiceStreamShared::getDownDataDescription(AudioEndpointParcelable &parcelable)
+aaudio_result_t AAudioServiceStreamShared::getAudioDataDescription(
+        AudioEndpointParcelable &parcelable)
 {
+    std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+    if (mAudioDataQueue == nullptr) {
+        ALOGE("getAudioDataDescription(): mUpMessageQueue null! - stream not open");
+        return AAUDIO_ERROR_NULL;
+    }
     // Gather information on the data queue.
     mAudioDataQueue->fillParcelable(parcelable,
                                     parcelable.mDownDataQueueParcelable);
@@ -237,9 +249,15 @@
 aaudio_result_t AAudioServiceStreamShared::getHardwareTimestamp(int64_t *positionFrames,
                                                                 int64_t *timeNanos) {
 
-    aaudio_result_t result = mServiceEndpoint->getTimestamp(positionFrames, timeNanos);
+    int64_t position = 0;
+    aaudio_result_t result = mServiceEndpoint->getTimestamp(&position, timeNanos);
     if (result == AAUDIO_OK) {
-        *positionFrames -= mTimestampPositionOffset.load(); // Offset from shared MMAP stream
+        int64_t offset = mTimestampPositionOffset.load();
+        // TODO, do not go below starting value
+        position -= offset; // Offset from shared MMAP stream
+        ALOGV("getHardwareTimestamp() %8lld = %8lld - %8lld",
+              (long long) position, (long long) (position + offset), (long long) offset);
     }
+    *positionFrames = position;
     return result;
 }
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index bc86dcc..8499ea5 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -54,7 +54,21 @@
 
     aaudio_result_t close() override;
 
-    android::FifoBuffer *getDataFifoBuffer() { return mAudioDataQueue->getFifoBuffer(); }
+    /**
+     * This must be locked when calling getAudioDataFifoBuffer_l() and while
+     * using the FifoBuffer it returns.
+     */
+    std::mutex &getAudioDataQueueLock() {
+        return mAudioDataQueueLock;
+    }
+
+    /**
+     * This must only be call under getAudioDataQueueLock().
+     * @return
+     */
+    android::FifoBuffer *getAudioDataFifoBuffer_l() { return (mAudioDataQueue == nullptr)
+                                                      ? nullptr
+                                                      : mAudioDataQueue->getFifoBuffer(); }
 
     /* Keep a record of when a buffer transfer completed.
      * This allows for a more accurate timing model.
@@ -75,7 +89,7 @@
 
 protected:
 
-    aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override;
+    aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) override;
 
     aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
 
@@ -90,7 +104,8 @@
                                             int32_t framesPerBurst);
 
 private:
-    SharedRingBuffer        *mAudioDataQueue = nullptr;
+    SharedRingBuffer        *mAudioDataQueue = nullptr; // protected by mAudioDataQueueLock
+    std::mutex               mAudioDataQueueLock;
 
     std::atomic<int64_t>     mTimestampPositionOffset;
     std::atomic<int32_t>     mXRunCount;
diff --git a/services/oboeservice/AAudioStreamTracker.cpp b/services/oboeservice/AAudioStreamTracker.cpp
new file mode 100644
index 0000000..ef88b34
--- /dev/null
+++ b/services/oboeservice/AAudioStreamTracker.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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 "AAudioStreamTracker"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include <aaudio/AAudio.h>
+#include <utils/String16.h>
+
+#include "AAudioStreamTracker.h"
+
+using namespace android;
+using namespace aaudio;
+
+sp<AAudioServiceStreamBase> AAudioStreamTracker::removeStreamByHandle(
+        aaudio_handle_t streamHandle) {
+    std::lock_guard<std::mutex> lock(mHandleLock);
+    sp<AAudioServiceStreamBase> serviceStream;
+    auto it = mStreamsByHandle.find(streamHandle);
+    if (it != mStreamsByHandle.end()) {
+        serviceStream = it->second;
+        mStreamsByHandle.erase(it);
+    }
+    return serviceStream;
+}
+
+sp<AAudioServiceStreamBase> AAudioStreamTracker::getStreamByHandle(
+        aaudio_handle_t streamHandle) {
+    std::lock_guard<std::mutex> lock(mHandleLock);
+    sp<AAudioServiceStreamBase> serviceStream;
+    auto it = mStreamsByHandle.find(streamHandle);
+    if (it != mStreamsByHandle.end()) {
+        serviceStream = it->second;
+    }
+    return serviceStream;
+}
+
+// advance to next legal handle value
+__attribute__((no_sanitize("integer")))
+aaudio_handle_t AAudioStreamTracker::bumpHandle(aaudio_handle_t handle) {
+    handle++;
+    // Only use positive integers.
+    if (handle <= 0) {
+        handle = 1;
+    }
+    return handle;
+}
+
+aaudio_handle_t AAudioStreamTracker::addStreamForHandle(sp<AAudioServiceStreamBase> serviceStream) {
+    std::lock_guard<std::mutex> lock(mHandleLock);
+    aaudio_handle_t handle = mPreviousHandle.load();
+    // Assign a unique handle.
+    while (true) {
+        handle = bumpHandle(handle);
+        sp<AAudioServiceStreamBase> oldServiceStream = mStreamsByHandle[handle];
+        // Is this an unused handle? It would be extremely unlikely to wrap
+        // around and collide with a very old handle. But just in case.
+        if (oldServiceStream.get() == nullptr) {
+            mStreamsByHandle[handle] = serviceStream;
+            break;
+        }
+    }
+    mPreviousHandle.store(handle);
+    return handle;
+}
+
+std::string AAudioStreamTracker::dump() const {
+    std::stringstream result;
+    const bool isLocked = AAudio_tryUntilTrue(
+            [this]()->bool { return mHandleLock.try_lock(); } /* f */,
+            50 /* times */,
+            20 /* sleepMs */);
+    if (!isLocked) {
+        result << "AAudioStreamTracker may be deadlocked\n";
+    } else {
+        result << "Stream Handles:\n";
+        for (const auto&  it : mStreamsByHandle) {
+            aaudio_handle_t handle = it.second->getHandle();
+            result << "    0x" << std::setfill('0') << std::setw(8) << std::hex << handle
+                   << std::dec << std::setfill(' ') << "\n";
+        }
+
+        mHandleLock.unlock();
+    }
+    return result.str();
+}
diff --git a/services/oboeservice/AAudioStreamTracker.h b/services/oboeservice/AAudioStreamTracker.h
new file mode 100644
index 0000000..70d440d
--- /dev/null
+++ b/services/oboeservice/AAudioStreamTracker.h
@@ -0,0 +1,73 @@
+/*
+ * 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 AAUDIO_AAUDIO_STREAM_TRACKER_H
+#define AAUDIO_AAUDIO_STREAM_TRACKER_H
+
+#include <time.h>
+#include <pthread.h>
+
+#include <aaudio/AAudio.h>
+
+#include "binding/AAudioCommon.h"
+
+#include "AAudioServiceStreamBase.h"
+
+namespace aaudio {
+
+class AAudioStreamTracker {
+
+public:
+    /**
+     * Remove the stream associated with the handle.
+     * @param streamHandle
+     * @return strong pointer to the stream if found or to nullptr
+     */
+    android::sp<AAudioServiceStreamBase> removeStreamByHandle(aaudio_handle_t streamHandle);
+
+    /**
+     * Look up a stream based on the handle.
+     * @param streamHandle
+     * @return strong pointer to the stream if found or to nullptr
+     */
+    android::sp<aaudio::AAudioServiceStreamBase> getStreamByHandle(aaudio_handle_t streamHandle);
+
+    /**
+     * Store a strong pointer to the stream and return a unique handle for future reference.
+     * The handle is guaranteed not to collide with an existing stream.
+     * @param serviceStream
+     * @return handle for identifying the stream
+     */
+    aaudio_handle_t addStreamForHandle(android::sp<AAudioServiceStreamBase> serviceStream);
+
+    /**
+     * @return string that can be added to dumpsys
+     */
+    std::string dump() const;
+
+private:
+    static aaudio_handle_t bumpHandle(aaudio_handle_t handle);
+
+    // Track stream using a unique handle that wraps. Only use positive half.
+    mutable std::mutex                mHandleLock;
+    std::atomic<aaudio_handle_t>      mPreviousHandle{0};
+    std::map<aaudio_handle_t, android::sp<aaudio::AAudioServiceStreamBase>> mStreamsByHandle;
+};
+
+
+} /* namespace aaudio */
+
+#endif /* AAUDIO_AAUDIO_STREAM_TRACKER_H */
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index 1b74ad3..584b2ef 100644
--- a/services/oboeservice/Android.mk
+++ b/services/oboeservice/Android.mk
@@ -22,7 +22,6 @@
     $(TOP)/frameworks/av/media/libaaudio/src
 
 LOCAL_SRC_FILES += \
-    $(LIBAAUDIO_SRC_DIR)/utility/HandleTracker.cpp \
     SharedMemoryProxy.cpp \
     SharedRingBuffer.cpp \
     AAudioClientTracker.cpp \
@@ -37,6 +36,7 @@
     AAudioServiceStreamBase.cpp \
     AAudioServiceStreamMMAP.cpp \
     AAudioServiceStreamShared.cpp \
+    AAudioStreamTracker.cpp \
     TimestampScheduler.cpp \
     AAudioThread.cpp
 
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 8891aba..952acd7 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -840,7 +840,7 @@
         }
 
         const bool supports_stop_all =
-                (mHalInterface != 0) && (mHalInterface->stopAllRecognitions() == ENOSYS);
+                (mHalInterface != 0) && (mHalInterface->stopAllRecognitions() != -ENOSYS);
 
         for (size_t i = 0; i < mModels.size(); i++) {
             sp<Model> model = mModels.valueAt(i);