Merge "Benchmark: Add test for Codec2 decoders"
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
index a5937fd..f56e1b5 100644
--- a/apex/ld.config.txt
+++ b/apex/ld.config.txt
@@ -37,12 +37,14 @@
 
 namespace.platform.isolated = true
 
-namespace.platform.search.paths = /system/${LIB}
+namespace.platform.search.paths  = /system/${LIB}
+namespace.platform.search.paths += /apex/com.android.runtime/${LIB}
 namespace.platform.asan.search.paths  = /data/asan/system/${LIB}
 namespace.platform.asan.search.paths +=           /system/${LIB}
+namespace.platform.asan.search.paths += /apex/com.android.runtime/${LIB}
 
 # /system/lib/libc.so, etc are symlinks to /apex/com.android.lib/lib/bionic/libc.so, etc.
-# Add /apex/... pat to the permitted paths because linker uses realpath(3)
+# Add /apex/... path to the permitted paths because linker uses realpath(3)
 # to check the accessibility of the lib. We could add this to search.paths
 # instead but that makes the resolution of bionic libs be dependent on
 # the order of /system/lib and /apex/... in search.paths. If /apex/...
@@ -129,3 +131,9 @@
 
 # Add a link for libz.so which is llndk on devices where VNDK is not enforced.
 namespace.sphal.link.platform.shared_libs += libz.so
+
+# With VNDK APEX, /system/${LIB}/vndk-sp${VNDK_VER} is a symlink to the following.
+# Add /apex/... path to the permitted paths because linker uses realpath(3)
+# to check the accessibility of the lib.
+namespace.sphal.permitted.paths += /apex/com.android.vndk.${VNDK_APEX_VER}/${LIB}
+namespace.sphal.asan.permitted.paths += /apex/com.android.vndk.${VNDK_APEX_VER}/${LIB}
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index 334f879..320c499 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -17,6 +17,10 @@
 
     srcs: ["main_cameraserver.cpp"],
 
+    header_libs: [
+        "libmedia_headers",
+    ],
+
     shared_libs: [
         "libcameraservice",
         "liblog",
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 0b882ee..7fc699e 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -139,6 +139,7 @@
 
   private:
     friend ACameraCaptureSession;
+    friend ACameraDevice;
 
     camera_status_t checkCameraClosedOrErrorLocked() const;
 
@@ -388,7 +389,6 @@
             mDevice(new android::acam::CameraDevice(id, cb, std::move(chars), this)) {}
 
     ~ACameraDevice();
-
     /*******************
      * NDK public APIs *
      *******************/
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 9ba6ee1..02ade94 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -304,7 +304,7 @@
             seekTimeUs = -1;
 
             if (shouldSeek) {
-                seekTimeUs = (rand() * (float)durationUs) / RAND_MAX;
+                seekTimeUs = (rand() * (float)durationUs) / (float)RAND_MAX;
                 options.setSeekTo(seekTimeUs);
 
                 printf("seeking to %" PRId64 " us (%.2f secs)\n",
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 39b048a..84f2f6d 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -35,6 +35,10 @@
         "include"
     ],
 
+    header_libs: [
+        "libmedia_headers",
+    ],
+
     shared_libs: [
         "libbinder",
         "libcutils",
@@ -75,6 +79,9 @@
         export_proto_headers: true,
         type: "lite",
     },
+    header_libs: [
+        "libmedia_headers",
+    ],
     shared_libs: [
         "android.hardware.drm@1.0",
         "android.hardware.drm@1.1",
@@ -110,6 +117,9 @@
         export_proto_headers: true,
         type: "full",
     },
+    header_libs: [
+        "libmedia_headers",
+    ],
     shared_libs: [
         "android.hardware.drm@1.0",
         "android.hardware.drm@1.1",
diff --git a/drm/libmediadrm/tests/Android.bp b/drm/libmediadrm/tests/Android.bp
index 873083b..2e39943 100644
--- a/drm/libmediadrm/tests/Android.bp
+++ b/drm/libmediadrm/tests/Android.bp
@@ -3,8 +3,8 @@
 cc_test {
     name: "CounterMetric_test",
     srcs: ["CounterMetric_test.cpp"],
+    header_libs: ["libmedia_headers"],
     shared_libs: ["libmediadrm"],
-    include_dirs: ["frameworks/av/include/media"],
     cflags: [
       "-Werror",
       "-Wall",
@@ -14,6 +14,9 @@
 cc_test {
     name: "DrmMetrics_test",
     srcs: ["DrmMetrics_test.cpp"],
+    header_libs: [
+        "libmedia_headers"
+    ],
     shared_libs: [
       "android.hardware.drm@1.0",
       "android.hardware.drm@1.1",
@@ -29,7 +32,6 @@
     static_libs: ["libgmock"],
     include_dirs: [
       "frameworks/av/drm/libmediadrm/include",
-      "frameworks/av/include/media",
     ],
     cflags: [
         // Suppress unused parameter and no error options. These cause problems
@@ -41,12 +43,14 @@
 cc_test {
     name: "EventMetric_test",
     srcs: ["EventMetric_test.cpp"],
+    header_libs: [
+        "libmedia_headers"
+    ],
     shared_libs: [
       "liblog",
       "libmediadrm",
       "libutils",
     ],
-    include_dirs: ["frameworks/av/include/media"],
     cflags: [
       "-Werror",
       "-Wall",
diff --git a/drm/libmediadrm/tests/CounterMetric_test.cpp b/drm/libmediadrm/tests/CounterMetric_test.cpp
index 6bca0da..c2becb4 100644
--- a/drm/libmediadrm/tests/CounterMetric_test.cpp
+++ b/drm/libmediadrm/tests/CounterMetric_test.cpp
@@ -16,7 +16,7 @@
 
 #include <gtest/gtest.h>
 
-#include "CounterMetric.h"
+#include <media/CounterMetric.h>
 
 namespace android {
 
diff --git a/drm/libmediadrm/tests/EventMetric_test.cpp b/drm/libmediadrm/tests/EventMetric_test.cpp
index eb6c4f6..b3c3f62 100644
--- a/drm/libmediadrm/tests/EventMetric_test.cpp
+++ b/drm/libmediadrm/tests/EventMetric_test.cpp
@@ -16,7 +16,7 @@
 
 #include <gtest/gtest.h>
 
-#include "EventMetric.h"
+#include <media/EventMetric.h>
 
 namespace android {
 
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
index bf35224..af7c367 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
@@ -97,7 +97,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 ClearKeyCasPlugin::ClearKeyCasPlugin(
         void *appData, CasPluginCallback callback)
-    : mCallback(callback), mCallbackExt(NULL), mAppData(appData) {
+    : mCallback(callback), mCallbackExt(NULL), mStatusCallback(NULL),
+    mAppData(appData) {
     ALOGV("CTOR");
 }
 
@@ -112,6 +113,13 @@
     ClearKeySessionLibrary::get()->destroyPlugin(this);
 }
 
+status_t ClearKeyCasPlugin::setStatusCallback(
+    CasPluginStatusCallback callback) {
+    ALOGV("setStatusCallback");
+    mStatusCallback = callback;
+    return OK;
+}
+
 status_t ClearKeyCasPlugin::setPrivateData(const CasData &/*data*/) {
     ALOGV("setPrivateData");
 
@@ -135,6 +143,19 @@
     return ClearKeySessionLibrary::get()->addSession(this, sessionId);
 }
 
+status_t ClearKeyCasPlugin::openSession(uint32_t intent, uint32_t mode,
+    CasSessionId* sessionId) {
+    ALOGV("openSession with intent=%d, mode=%d", intent, mode);
+    // Echo the received information to the callback.
+    // Clear key plugin doesn't use any event, echo'ing for testing only.
+    if (mStatusCallback != NULL) {
+        mStatusCallback((void*)mAppData, intent, mode);
+    }
+
+    // Clear key plugin doesn't use intent and mode.
+    return ClearKeySessionLibrary::get()->addSession(this, sessionId);
+}
+
 status_t ClearKeyCasPlugin::closeSession(const CasSessionId &sessionId) {
     ALOGV("closeSession: sessionId=%s", sessionIdToString(sessionId).string());
     std::shared_ptr<ClearKeyCasSession> session =
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
index f48d5b1..c6938e6 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
@@ -71,11 +71,17 @@
     ClearKeyCasPlugin(void *appData, CasPluginCallbackExt callback);
     virtual ~ClearKeyCasPlugin();
 
+    virtual status_t setStatusCallback(
+            CasPluginStatusCallback callback) override;
+
     virtual status_t setPrivateData(
             const CasData &data) override;
 
     virtual status_t openSession(CasSessionId *sessionId) override;
 
+    virtual status_t openSession(uint32_t intent, uint32_t mode,
+                                     CasSessionId *sessionId) override;
+
     virtual status_t closeSession(
             const CasSessionId &sessionId) override;
 
@@ -105,6 +111,7 @@
     std::unique_ptr<KeyFetcher> mKeyFetcher;
     CasPluginCallback mCallback;
     CasPluginCallbackExt mCallbackExt;
+    CasPluginStatusCallback mStatusCallback;
     void* mAppData;
 };
 
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.cpp b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
index 2964791..f8bab0a 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.cpp
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
@@ -111,6 +111,12 @@
     MockSessionLibrary::get()->destroyPlugin(this);
 }
 
+status_t MockCasPlugin::setStatusCallback(
+    CasPluginStatusCallback /*callback*/) {
+    ALOGV("setStatusCallback");
+    return OK;
+}
+
 status_t MockCasPlugin::setPrivateData(const CasData& /*data*/) {
     ALOGV("setPrivateData");
     return OK;
@@ -121,6 +127,13 @@
     return MockSessionLibrary::get()->addSession(this, sessionId);
 }
 
+status_t MockCasPlugin::openSession(uint32_t intent, uint32_t mode,
+    CasSessionId* sessionId) {
+    ALOGV("openSession with intent=%d, mode=%d", intent, mode);
+    // Clear key plugin doesn't use intent and mode.
+    return MockSessionLibrary::get()->addSession(this, sessionId);
+}
+
 status_t MockCasPlugin::closeSession(const CasSessionId &sessionId) {
     ALOGV("closeSession: sessionId=%s", arrayToString(sessionId).string());
     Mutex::Autolock lock(mLock);
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.h b/drm/mediacas/plugins/mock/MockCasPlugin.h
index 74b540c..660fd44 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.h
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.h
@@ -65,11 +65,17 @@
     MockCasPlugin();
     virtual ~MockCasPlugin();
 
+    virtual status_t setStatusCallback(
+            CasPluginStatusCallback callback) override;
+
     virtual status_t setPrivateData(
             const CasData &data) override;
 
     virtual status_t openSession(CasSessionId *sessionId) override;
 
+    virtual status_t openSession(uint32_t intent, uint32_t mode,
+                                     CasSessionId *sessionId) override;
+
     virtual status_t closeSession(
             const CasSessionId &sessionId) override;
 
diff --git a/include/drm/drm_framework_common.h b/include/drm/drm_framework_common.h
index d75f71c..d5f3ba2 100644
--- a/include/drm/drm_framework_common.h
+++ b/include/drm/drm_framework_common.h
@@ -317,14 +317,6 @@
     ~DecryptHandle() {
         delete decryptInfo; decryptInfo = NULL;
     }
-
-    bool operator<(const DecryptHandle& handle) const {
-        return (decryptId < handle.decryptId);
-    }
-
-    bool operator==(const DecryptHandle& handle) const {
-        return (decryptId == handle.decryptId);
-    }
 };
 
 };
diff --git a/include/media/BufferProviders.h b/include/media/BufferProviders.h
deleted file mode 120000
index 779bb15..0000000
--- a/include/media/BufferProviders.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/BufferProviders.h
\ No newline at end of file
diff --git a/include/media/CounterMetric.h b/include/media/CounterMetric.h
deleted file mode 120000
index baba043..0000000
--- a/include/media/CounterMetric.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/CounterMetric.h
\ No newline at end of file
diff --git a/include/media/EventMetric.h b/include/media/EventMetric.h
deleted file mode 120000
index 5707d9a..0000000
--- a/include/media/EventMetric.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/EventMetric.h
\ No newline at end of file
diff --git a/include/media/IDataSource.h b/include/media/IDataSource.h
deleted file mode 120000
index 41cdd8b..0000000
--- a/include/media/IDataSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IDataSource.h
\ No newline at end of file
diff --git a/include/media/IMediaLogService.h b/include/media/IMediaLogService.h
deleted file mode 120000
index 245a29d..0000000
--- a/include/media/IMediaLogService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaLogService.h
\ No newline at end of file
diff --git a/include/media/IMediaPlayerClient.h b/include/media/IMediaPlayerClient.h
deleted file mode 120000
index b6547ce..0000000
--- a/include/media/IMediaPlayerClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaPlayerClient.h
\ No newline at end of file
diff --git a/include/media/IMediaRecorderClient.h b/include/media/IMediaRecorderClient.h
deleted file mode 120000
index 89f4359..0000000
--- a/include/media/IMediaRecorderClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaRecorderClient.h
\ No newline at end of file
diff --git a/include/media/MemoryLeakTrackUtil.h b/include/media/MemoryLeakTrackUtil.h
deleted file mode 120000
index 504173e..0000000
--- a/include/media/MemoryLeakTrackUtil.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MemoryLeakTrackUtil.h
\ No newline at end of file
diff --git a/include/media/Metadata.h b/include/media/Metadata.h
deleted file mode 120000
index e421168..0000000
--- a/include/media/Metadata.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Metadata.h
\ No newline at end of file
diff --git a/include/media/MidiIoWrapper.h b/include/media/MidiIoWrapper.h
deleted file mode 120000
index 786ec3d..0000000
--- a/include/media/MidiIoWrapper.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MidiIoWrapper.h
\ No newline at end of file
diff --git a/include/media/Modulo.h b/include/media/Modulo.h
deleted file mode 120000
index 989c4cb..0000000
--- a/include/media/Modulo.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Modulo.h
\ No newline at end of file
diff --git a/include/media/PluginMetricsReporting.h b/include/media/PluginMetricsReporting.h
deleted file mode 120000
index 7d9a7a0..0000000
--- a/include/media/PluginMetricsReporting.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/PluginMetricsReporting.h
\ No newline at end of file
diff --git a/include/media/RingBuffer.h b/include/media/RingBuffer.h
deleted file mode 120000
index 9af28d5..0000000
--- a/include/media/RingBuffer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/RingBuffer.h
\ No newline at end of file
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index 3f3ef69..5484613 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -6,10 +6,10 @@
     capabilities BLOCK_SUSPEND
     ioprio rt 4
     writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
-    onrestart restart vendor.audio-hal-2-0
+    onrestart restart vendor.audio-hal
     onrestart restart vendor.audio-hal-4-0-msd
-    # Keep the original service name for backward compatibility when upgrading
-    # O-MR1 devices with framework-only.
+    # Keep the original service names for backward compatibility
+    onrestart restart vendor.audio-hal-2-0
     onrestart restart audio-hal-2-0
 
 on property:vts.native_server.on=1
diff --git a/media/bufferpool/1.0/AccessorImpl.cpp b/media/bufferpool/1.0/AccessorImpl.cpp
index fa17f15..a5366f6 100644
--- a/media/bufferpool/1.0/AccessorImpl.cpp
+++ b/media/bufferpool/1.0/AccessorImpl.cpp
@@ -151,6 +151,7 @@
                 newConnection->initialize(accessor, id);
                 *connection = newConnection;
                 *pConnectionId = id;
+                mBufferPool.mConnectionIds.insert(id);
                 ++sSeqId;
             }
         }
@@ -305,7 +306,12 @@
         found->second->mSenderValidated = true;
         return true;
     }
-    // TODO: verify there is target connection Id
+    if (mConnectionIds.find(message.targetConnectionId) == mConnectionIds.end()) {
+        // N.B: it could be fake or receive connection already closed.
+        ALOGD("bufferpool %p receiver connection %lld is no longer valid",
+              this, (long long)message.targetConnectionId);
+        return false;
+    }
     mStats.onBufferSent();
     mTransactions.insert(std::make_pair(
             message.transactionId,
@@ -450,6 +456,7 @@
             }
         }
     }
+    mConnectionIds.erase(connectionId);
     return true;
 }
 
diff --git a/media/bufferpool/1.0/AccessorImpl.h b/media/bufferpool/1.0/AccessorImpl.h
index c04dbf3..84cb685 100644
--- a/media/bufferpool/1.0/AccessorImpl.h
+++ b/media/bufferpool/1.0/AccessorImpl.h
@@ -94,6 +94,7 @@
 
         std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
         std::set<BufferId> mFreeBuffers;
+        std::set<ConnectionId> mConnectionIds;
 
         /// Buffer pool statistics which tracks allocation and transfer statistics.
         struct Stats {
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 94cf006..cacd465 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -163,6 +163,7 @@
                 *connection = newConnection;
                 *pConnectionId = id;
                 *pMsgId = mBufferPool.mInvalidation.mInvalidationId;
+                mBufferPool.mConnectionIds.insert(id);
                 mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
                 mBufferPool.mInvalidation.onConnect(id, observer);
                 ++sSeqId;
@@ -474,7 +475,12 @@
         found->second->mSenderValidated = true;
         return true;
     }
-    // TODO: verify there is target connection Id
+    if (mConnectionIds.find(message.targetConnectionId) == mConnectionIds.end()) {
+        // N.B: it could be fake or receive connection already closed.
+        ALOGD("bufferpool2 %p receiver connection %lld is no longer valid",
+              this, (long long)message.targetConnectionId);
+        return false;
+    }
     mStats.onBufferSent();
     mTransactions.insert(std::make_pair(
             message.transactionId,
@@ -644,6 +650,7 @@
             }
         }
     }
+    mConnectionIds.erase(connectionId);
     return true;
 }
 
@@ -774,11 +781,19 @@
             std::mutex &mutex,
             std::condition_variable &cv,
             bool &ready) {
+    constexpr uint32_t NUM_SPIN_TO_INCREASE_SLEEP = 1024;
+    constexpr uint32_t NUM_SPIN_TO_LOG = 1024*8;
+    constexpr useconds_t MAX_SLEEP_US = 10000;
+    uint32_t numSpin = 0;
+    useconds_t sleepUs = 1;
+
     while(true) {
         std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> copied;
         {
             std::unique_lock<std::mutex> lock(mutex);
             if (!ready) {
+                numSpin = 0;
+                sleepUs = 1;
                 cv.wait(lock);
             }
             copied.insert(accessors.begin(), accessors.end());
@@ -800,9 +815,20 @@
             if (accessors.size() == 0) {
                 ready = false;
             } else {
-                // prevent draining cpu.
+                // TODO Use an efficient way to wait over FMQ.
+                // N.B. Since there is not a efficient way to wait over FMQ,
+                // polling over the FMQ is the current way to prevent draining
+                // CPU.
                 lock.unlock();
-                std::this_thread::yield();
+                ++numSpin;
+                if (numSpin % NUM_SPIN_TO_INCREASE_SLEEP == 0 &&
+                    sleepUs < MAX_SLEEP_US) {
+                    sleepUs *= 10;
+                }
+                if (numSpin % NUM_SPIN_TO_LOG == 0) {
+                    ALOGW("invalidator thread spinning");
+                }
+                ::usleep(sleepUs);
             }
         }
     }
diff --git a/media/bufferpool/2.0/AccessorImpl.h b/media/bufferpool/2.0/AccessorImpl.h
index eea72b9..807e0f1 100644
--- a/media/bufferpool/2.0/AccessorImpl.h
+++ b/media/bufferpool/2.0/AccessorImpl.h
@@ -111,6 +111,7 @@
 
         std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
         std::set<BufferId> mFreeBuffers;
+        std::set<ConnectionId> mConnectionIds;
 
         struct Invalidation {
             static std::atomic<std::uint32_t> sInvSeqId;
diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp
index 8e3852c..1dc676b 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.cpp
+++ b/media/codec2/components/aac/C2SoftAacEnc.cpp
@@ -157,7 +157,7 @@
       mSentCodecSpecificData(false),
       mInputTimeSet(false),
       mInputSize(0),
-      mInputTimeUs(0),
+      mNextFrameTimestampUs(0),
       mSignalledError(false),
       mOutIndex(0u) {
 }
@@ -183,7 +183,7 @@
     mSentCodecSpecificData = false;
     mInputTimeSet = false;
     mInputSize = 0u;
-    mInputTimeUs = 0;
+    mNextFrameTimestampUs = 0;
     mSignalledError = false;
     return C2_OK;
 }
@@ -201,7 +201,7 @@
     mSentCodecSpecificData = false;
     mInputTimeSet = false;
     mInputSize = 0u;
-    mInputTimeUs = 0;
+    mNextFrameTimestampUs = 0;
     return C2_OK;
 }
 
@@ -365,17 +365,18 @@
         capacity = view.capacity();
     }
     if (!mInputTimeSet && capacity > 0) {
-        mInputTimeUs = work->input.ordinal.timestamp;
+        mNextFrameTimestampUs = work->input.ordinal.timestamp;
         mInputTimeSet = true;
     }
 
     size_t numFrames = (capacity + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0))
             / mNumBytesPerInputFrame;
-    ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu mNumBytesPerInputFrame = %u",
-          capacity, mInputSize, numFrames, mNumBytesPerInputFrame);
+    ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu "
+          "mNumBytesPerInputFrame = %u inputTS = %lld",
+          capacity, mInputSize, numFrames,
+          mNumBytesPerInputFrame, work->input.ordinal.timestamp.peekll());
 
     std::shared_ptr<C2LinearBlock> block;
-    std::shared_ptr<C2Buffer> buffer;
     std::unique_ptr<C2WriteView> wView;
     uint8_t *outPtr = temp;
     size_t outAvailable = 0u;
@@ -442,7 +443,11 @@
         const std::shared_ptr<C2Buffer> mBuffer;
     };
 
-    C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
+    struct OutputBuffer {
+        std::shared_ptr<C2Buffer> buffer;
+        c2_cntr64_t timestampUs;
+    };
+    std::list<OutputBuffer> outputBuffers;
 
     while (encoderErr == AACENC_OK && inargs.numInSamples > 0) {
         if (numFrames && !block) {
@@ -473,29 +478,22 @@
                                   &outargs);
 
         if (encoderErr == AACENC_OK) {
-            if (buffer) {
-                outOrdinal.frameIndex = mOutIndex++;
-                outOrdinal.timestamp = mInputTimeUs;
-                cloneAndSend(
-                        inputIndex,
-                        work,
-                        FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
-                buffer.reset();
-            }
-
             if (outargs.numOutBytes > 0) {
                 mInputSize = 0;
                 int consumed = (capacity / sizeof(int16_t)) - inargs.numInSamples
                         + outargs.numInSamples;
-                mInputTimeUs = work->input.ordinal.timestamp
+                c2_cntr64_t currentFrameTimestampUs = mNextFrameTimestampUs;
+                mNextFrameTimestampUs = work->input.ordinal.timestamp
                         + (consumed * 1000000ll / channelCount / sampleRate);
-                buffer = createLinearBuffer(block, 0, outargs.numOutBytes);
+                std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block, 0, outargs.numOutBytes);
 #if defined(LOG_NDEBUG) && !LOG_NDEBUG
                 hexdump(outPtr, std::min(outargs.numOutBytes, 256));
 #endif
                 outPtr = temp;
                 outAvailable = 0;
                 block.reset();
+
+                outputBuffers.push_back({buffer, currentFrameTimestampUs});
             } else {
                 mInputSize += outargs.numInSamples * sizeof(int16_t);
             }
@@ -506,8 +504,9 @@
                 inargs.numInSamples -= outargs.numInSamples;
             }
         }
-        ALOGV("encoderErr = %d mInputSize = %zu inargs.numInSamples = %d, mInputTimeUs = %lld",
-              encoderErr, mInputSize, inargs.numInSamples, mInputTimeUs.peekll());
+        ALOGV("encoderErr = %d mInputSize = %zu "
+              "inargs.numInSamples = %d, mNextFrameTimestampUs = %lld",
+              encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs.peekll());
     }
 
     if (eos && inBufferSize[0] > 0) {
@@ -542,10 +541,27 @@
                            &outargs);
     }
 
-    outOrdinal.frameIndex = mOutIndex++;
-    outOrdinal.timestamp = mInputTimeUs;
+    while (outputBuffers.size() > 1) {
+        const OutputBuffer& front = outputBuffers.front();
+        C2WorkOrdinalStruct ordinal = work->input.ordinal;
+        ordinal.frameIndex = mOutIndex++;
+        ordinal.timestamp = front.timestampUs;
+        cloneAndSend(
+                inputIndex,
+                work,
+                FillWork(C2FrameData::FLAG_INCOMPLETE, ordinal, front.buffer));
+        outputBuffers.pop_front();
+    }
+    std::shared_ptr<C2Buffer> buffer;
+    C2WorkOrdinalStruct ordinal = work->input.ordinal;
+    ordinal.frameIndex = mOutIndex++;
+    if (!outputBuffers.empty()) {
+        ordinal.timestamp = outputBuffers.front().timestampUs;
+        buffer = outputBuffers.front().buffer;
+    }
+    // Mark the end of frame
     FillWork((C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0),
-             outOrdinal, buffer)(work);
+             ordinal, buffer)(work);
 }
 
 c2_status_t C2SoftAacEnc::drain(
@@ -569,7 +585,7 @@
     mSentCodecSpecificData = false;
     mInputTimeSet = false;
     mInputSize = 0u;
-    mInputTimeUs = 0;
+    mNextFrameTimestampUs = 0;
 
     // TODO: we don't have any pending work at this time to drain.
     return C2_OK;
diff --git a/media/codec2/components/aac/C2SoftAacEnc.h b/media/codec2/components/aac/C2SoftAacEnc.h
index a38be19..2655039 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.h
+++ b/media/codec2/components/aac/C2SoftAacEnc.h
@@ -56,7 +56,7 @@
     bool mSentCodecSpecificData;
     bool mInputTimeSet;
     size_t mInputSize;
-    c2_cntr64_t mInputTimeUs;
+    c2_cntr64_t mNextFrameTimestampUs;
 
     bool mSignalledError;
     std::atomic_uint64_t mOutIndex;
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index 6dab70b..ebc7a8f 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -514,7 +514,7 @@
                         return;
                     }
                     vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, stride, vstride,
-                                 mStrideAlign, (uint8_t*)rView->data()[0]);
+                                 mStrideAlign, mConversionBuffer.data());
                     vpx_img_set_rect(&raw_frame, 0, 0, width, height);
                 } else {
                     ALOGE("Conversion buffer is too small: %u x %u for %zu",
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 9d1cc60..8223273 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -375,7 +375,11 @@
 
         // consumer usage is queried earlier.
 
-        ALOGD("ISConfig%s", status.str().c_str());
+        if (status.str().empty()) {
+            ALOGD("ISConfig not changed");
+        } else {
+            ALOGD("ISConfig%s", status.str().c_str());
+        }
         return err;
     }
 
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 8308292..0cbf62b 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -224,7 +224,7 @@
       mFirstValidFrameIndex(0u),
       mMetaMode(MODE_NONE),
       mInputMetEos(false) {
-    mOutputSurface.lock()->maxDequeueBuffers = kSmoothnessFactor + kRenderingDepth;
+    mOutputSurface.lock()->maxDequeueBuffers = 2 * kSmoothnessFactor + kRenderingDepth;
     {
         Mutexed<Input>::Locked input(mInput);
         input->buffers.reset(new DummyInputBuffers(""));
@@ -948,7 +948,8 @@
         uint32_t outputGeneration;
         {
             Mutexed<OutputSurface>::Locked output(mOutputSurface);
-            output->maxDequeueBuffers = numOutputSlots + reorderDepth.value + kRenderingDepth;
+            output->maxDequeueBuffers = numOutputSlots + numInputSlots +
+                    reorderDepth.value + kRenderingDepth;
             outputSurface = output->surface ?
                     output->surface->getIGraphicBufferProducer() : nullptr;
             if (outputSurface) {
@@ -1332,9 +1333,10 @@
                     ALOGV("[%s] onWorkDone: updated reorder depth to %u",
                           mName, reorderDepth.value);
                     size_t numOutputSlots = mOutput.lock()->numSlots;
+                    size_t numInputSlots = mInput.lock()->numSlots;
                     Mutexed<OutputSurface>::Locked output(mOutputSurface);
-                    output->maxDequeueBuffers =
-                        numOutputSlots + reorderDepth.value + kRenderingDepth;
+                    output->maxDequeueBuffers = numOutputSlots + numInputSlots +
+                            reorderDepth.value + kRenderingDepth;
                     if (output->surface) {
                         output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
                     }
@@ -1382,6 +1384,7 @@
 
                         bool outputBuffersChanged = false;
                         size_t numOutputSlots = 0;
+                        size_t numInputSlots = mInput.lock()->numSlots;
                         {
                             Mutexed<Output>::Locked output(mOutput);
                             output->outputDelay = outputDelay.value;
@@ -1406,7 +1409,8 @@
 
                         uint32_t depth = mReorderStash.lock()->depth();
                         Mutexed<OutputSurface>::Locked output(mOutputSurface);
-                        output->maxDequeueBuffers = numOutputSlots + depth + kRenderingDepth;
+                        output->maxDequeueBuffers = numOutputSlots + numInputSlots +
+                                depth + kRenderingDepth;
                         if (output->surface) {
                             output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
                         }
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 1cfdc19..5adcd94 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -235,7 +235,10 @@
     const std::vector<ConfigMapper> &getConfigMappersForSdkKey(std::string key) const {
         auto it = mConfigMappers.find(key);
         if (it == mConfigMappers.end()) {
-            ALOGD("no c2 equivalents for %s", key.c_str());
+            if (mComplained.count(key) == 0) {
+                ALOGD("no c2 equivalents for %s", key.c_str());
+                mComplained.insert(key);
+            }
             return NO_MAPPERS;
         }
         ALOGV("found %zu eqs for %s", it->second.size(), key.c_str());
@@ -304,6 +307,7 @@
 
 private:
     std::map<SdkKey, std::vector<ConfigMapper>> mConfigMappers;
+    mutable std::set<std::string> mComplained;
 };
 
 const std::vector<ConfigMapper> StandardParams::NO_MAPPERS;
@@ -508,7 +512,8 @@
                .limitTo(D::ENCODER & D::VIDEO));
     // convert to timestamp base
     add(ConfigMapper(KEY_I_FRAME_INTERVAL, C2_PARAMKEY_SYNC_FRAME_INTERVAL, "value")
-        .withMappers([](C2Value v) -> C2Value {
+        .limitTo(D::VIDEO & D::ENCODER & D::CONFIG)
+        .withMapper([](C2Value v) -> C2Value {
             // convert from i32 to float
             int32_t i32Value;
             float fpValue;
@@ -518,12 +523,6 @@
                 return int64_t(c2_min(1000000 * fpValue + 0.5, (double)INT64_MAX));
             }
             return C2Value();
-        }, [](C2Value v) -> C2Value {
-            int64_t i64;
-            if (v.get(&i64)) {
-                return float(i64) / 1000000;
-            }
-            return C2Value();
         }));
     // remove when codecs switch to proper coding.gop (add support for calculating gop)
     deprecated(ConfigMapper("i-frame-period", "coding.gop", "intra-period")
@@ -1033,7 +1032,25 @@
     }
 
     ReflectedParamUpdater::Dict reflected = mParamUpdater->getParams(paramPointers);
-    ALOGD("c2 config is %s", reflected.debugString().c_str());
+    std::string config = reflected.debugString();
+    std::set<std::string> configLines;
+    std::string diff;
+    for (size_t start = 0; start != std::string::npos; ) {
+        size_t end = config.find('\n', start);
+        size_t count = (end == std::string::npos)
+                ? std::string::npos
+                : end - start + 1;
+        std::string line = config.substr(start, count);
+        configLines.insert(line);
+        if (mLastConfig.count(line) == 0) {
+            diff.append(line);
+        }
+        start = (end == std::string::npos) ? std::string::npos : end + 1;
+    }
+    if (!diff.empty()) {
+        ALOGD("c2 config diff is %s", diff.c_str());
+    }
+    mLastConfig.swap(configLines);
 
     bool changed = false;
     if (domain & mInputDomain) {
diff --git a/media/codec2/sfplugin/CCodecConfig.h b/media/codec2/sfplugin/CCodecConfig.h
index 3bafe3f..a61c8b7 100644
--- a/media/codec2/sfplugin/CCodecConfig.h
+++ b/media/codec2/sfplugin/CCodecConfig.h
@@ -134,6 +134,8 @@
     /// For now support a validation function.
     std::map<C2Param::Index, LocalParamValidator> mLocalParams;
 
+    std::set<std::string> mLastConfig;
+
     CCodecConfig();
 
     /// initializes the members required to manage the format: descriptors, reflector,
diff --git a/media/codec2/sfplugin/PipelineWatcher.cpp b/media/codec2/sfplugin/PipelineWatcher.cpp
index 74d14e8..0ee9056 100644
--- a/media/codec2/sfplugin/PipelineWatcher.cpp
+++ b/media/codec2/sfplugin/PipelineWatcher.cpp
@@ -146,7 +146,7 @@
               std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count());
         durations.push_back(elapsed);
     }
-    std::nth_element(durations.begin(), durations.end(), durations.begin() + n,
+    std::nth_element(durations.begin(), durations.begin() + n, durations.end(),
                      std::greater<Clock::duration>());
     return durations[n];
 }
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index 7d42e70..d36cb49 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -6,6 +6,10 @@
         "frameworks/av/media/libstagefright/include",
     ],
 
+    header_libs: [
+        "libmedia_headers",
+    ],
+
     shared_libs: [
         "liblog",
         "libmediandk",
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index ee5d089..8173e3c 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -472,6 +472,8 @@
  * This is intended for developers to use when debugging.
  * It is not for display to users.
  *
+ * Available since API level 26.
+ *
  * @return pointer to a text representation of an AAudio result code.
  */
 AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode) __INTRODUCED_IN(26);
@@ -482,6 +484,8 @@
  * This is intended for developers to use when debugging.
  * It is not for display to users.
  *
+ * Available since API level 26.
+ *
  * @return pointer to a text representation of an AAudio state.
  */
 AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state)
@@ -502,6 +506,8 @@
  * chosen by the device when it is opened.
  *
  * AAudioStreamBuilder_delete() must be called when you are done using the builder.
+ *
+ * Available since API level 26.
  */
 AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder** builder)
         __INTRODUCED_IN(26);
@@ -513,6 +519,8 @@
  * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED},
  * in which case the primary device will be used.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param deviceId device identifier or {@link #AAUDIO_UNSPECIFIED}
  */
@@ -530,6 +538,8 @@
  * If an exact value is specified then an opened stream will use that value.
  * If a stream cannot be opened with the specified value then the open will fail.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param sampleRate frames per second. Common rates include 44100 and 48000 Hz.
  */
@@ -547,6 +557,8 @@
  * If an exact value is specified then an opened stream will use that value.
  * If a stream cannot be opened with the specified value then the open will fail.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param channelCount Number of channels desired.
  */
@@ -556,6 +568,8 @@
 /**
  * Identical to AAudioStreamBuilder_setChannelCount().
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param samplesPerFrame Number of samples in a frame.
  */
@@ -573,6 +587,8 @@
  * If an exact value is specified then an opened stream will use that value.
  * If a stream cannot be opened with the specified value then the open will fail.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param format common formats are {@link #AAUDIO_FORMAT_PCM_FLOAT} and
  *               {@link #AAUDIO_FORMAT_PCM_I16}.
@@ -588,6 +604,8 @@
  * The requested sharing mode may not be available.
  * The application can query for the actual mode after the stream is opened.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param sharingMode {@link #AAUDIO_SHARING_MODE_SHARED} or {@link #AAUDIO_SHARING_MODE_EXCLUSIVE}
  */
@@ -599,6 +617,8 @@
  *
  * The default, if you do not call this function, is {@link #AAUDIO_DIRECTION_OUTPUT}.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param direction {@link #AAUDIO_DIRECTION_OUTPUT} or {@link #AAUDIO_DIRECTION_INPUT}
  */
@@ -611,6 +631,8 @@
  *
  * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param numFrames the desired buffer capacity in frames or {@link #AAUDIO_UNSPECIFIED}
  */
@@ -629,6 +651,8 @@
  * You can call AAudioStream_getPerformanceMode()
  * to find out the final mode for the stream.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param mode the desired performance mode, eg. {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY}
  */
@@ -644,7 +668,7 @@
  *
  * The default, if you do not call this function, is {@link #AAUDIO_USAGE_MEDIA}.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param usage the desired usage, eg. {@link #AAUDIO_USAGE_GAME}
@@ -661,7 +685,7 @@
  *
  * The default, if you do not call this function, is {@link #AAUDIO_CONTENT_TYPE_MUSIC}.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param contentType the type of audio data, eg. {@link #AAUDIO_CONTENT_TYPE_SPEECH}
@@ -681,7 +705,7 @@
  * That is because VOICE_RECOGNITION is the preset with the lowest latency
  * on many platforms.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param inputPreset the desired configuration for recording
@@ -697,7 +721,7 @@
  * Note that an application can also set its global policy, in which case the most restrictive
  * policy is always applied. See {@link android.media.AudioAttributes#setAllowedCapturePolicy(int)}
  *
- * Added in API level 29.
+ * Available since API level 29.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param inputPreset the desired level of opt-out from being captured.
@@ -727,7 +751,7 @@
  *
  * Allocated session IDs will always be positive and nonzero.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param sessionId an allocated sessionID or {@link #AAUDIO_SESSION_ID_ALLOCATE}
@@ -826,6 +850,8 @@
  *
  * Note that the AAudio callbacks will never be called simultaneously from multiple threads.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param callback pointer to a function that will process audio data.
  * @param userData pointer to an application data structure that will be passed
@@ -854,6 +880,8 @@
  * If you do call this function then the requested size should be less than
  * half the buffer capacity, to allow double buffering.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param numFrames the desired buffer size in frames or {@link #AAUDIO_UNSPECIFIED}
  */
@@ -905,6 +933,8 @@
  *
  * Note that the AAudio callbacks will never be called simultaneously from multiple threads.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param callback pointer to a function that will be called if an error occurs.
  * @param userData pointer to an application data structure that will be passed
@@ -919,6 +949,8 @@
  * AAudioStream_close() must be called when finished with the stream to recover
  * the memory and to free the associated resources.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param stream pointer to a variable to receive the new stream reference
  * @return {@link #AAUDIO_OK} or a negative error.
@@ -929,6 +961,8 @@
 /**
  * Delete the resources associated with the StreamBuilder.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @return {@link #AAUDIO_OK} or a negative error.
  */
@@ -942,6 +976,8 @@
 /**
  * Free the resources associated with a stream created by AAudioStreamBuilder_openStream()
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return {@link #AAUDIO_OK} or a negative error.
  */
@@ -954,6 +990,8 @@
  * After this call the state will be in {@link #AAUDIO_STREAM_STATE_STARTING} or
  * {@link #AAUDIO_STREAM_STATE_STARTED}.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return {@link #AAUDIO_OK} or a negative error.
  */
@@ -969,6 +1007,8 @@
  * This will return {@link #AAUDIO_ERROR_UNIMPLEMENTED} for input streams.
  * For input streams use AAudioStream_requestStop().
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return {@link #AAUDIO_OK} or a negative error.
  */
@@ -984,6 +1024,8 @@
  *
  * This will return {@link #AAUDIO_ERROR_UNIMPLEMENTED} for input streams.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return {@link #AAUDIO_OK} or a negative error.
  */
@@ -995,6 +1037,8 @@
  * After this call the state will be in {@link #AAUDIO_STREAM_STATE_STOPPING} or
  * {@link #AAUDIO_STREAM_STATE_STOPPED}.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return {@link #AAUDIO_OK} or a negative error.
  */
@@ -1008,6 +1052,8 @@
  * call AAudioStream_waitForStateChange() with currentState
  * set to {@link #AAUDIO_STREAM_STATE_UNKNOWN} and a zero timeout.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  */
 AAUDIO_API aaudio_stream_state_t AAudioStream_getState(AAudioStream* stream) __INTRODUCED_IN(26);
@@ -1028,6 +1074,8 @@
  * }
  * </code></pre>
  *
+ * Available since API level 26.
+ *
  * @param stream A reference provided by AAudioStreamBuilder_openStream()
  * @param inputState The state we want to avoid.
  * @param nextState Pointer to a variable that will be set to the new state.
@@ -1056,6 +1104,8 @@
  *
  * If the call times out then zero or a partial frame count will be returned.
  *
+ * Available since API level 26.
+ *
  * @param stream A stream created using AAudioStreamBuilder_openStream().
  * @param buffer The address of the first sample.
  * @param numFrames Number of frames to read. Only complete frames will be written.
@@ -1079,6 +1129,8 @@
  *
  * If the call times out then zero or a partial frame count will be returned.
  *
+ * Available since API level 26.
+ *
  * @param stream A stream created using AAudioStreamBuilder_openStream().
  * @param buffer The address of the first sample.
  * @param numFrames Number of frames to write. Only complete frames will be written.
@@ -1104,6 +1156,8 @@
  * You can check the return value or call AAudioStream_getBufferSizeInFrames()
  * to see what the actual final size is.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @param numFrames requested number of frames that can be filled without blocking
  * @return actual buffer size in frames or a negative error
@@ -1114,6 +1168,8 @@
 /**
  * Query the maximum number of frames that can be filled without blocking.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return buffer size in frames.
  */
@@ -1129,6 +1185,8 @@
  * For some endpoints, the burst size can vary dynamically.
  * But these tend to be devices with high latency.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return burst size
  */
@@ -1137,6 +1195,8 @@
 /**
  * Query maximum buffer capacity in frames.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return  buffer capacity in frames
  */
@@ -1158,6 +1218,8 @@
  * {@link #AAUDIO_UNSPECIFIED} indicates that the callback buffer size for this stream
  * may vary from one dataProc callback to the next.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return callback buffer size in frames or {@link #AAUDIO_UNSPECIFIED}
  */
@@ -1175,12 +1237,16 @@
  * Note that some INPUT devices may not support this function.
  * In that case a 0 will always be returned.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return the underrun or overrun count
  */
 AAUDIO_API int32_t AAudioStream_getXRunCount(AAudioStream* stream) __INTRODUCED_IN(26);
 
 /**
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return actual sample rate
  */
@@ -1190,6 +1256,8 @@
  * A stream has one or more channels of data.
  * A frame will contain one sample for each channel.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return actual number of channels
  */
@@ -1198,18 +1266,24 @@
 /**
  * Identical to AAudioStream_getChannelCount().
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return actual number of samples frame
  */
 AAUDIO_API int32_t AAudioStream_getSamplesPerFrame(AAudioStream* stream) __INTRODUCED_IN(26);
 
 /**
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return actual device ID
  */
 AAUDIO_API int32_t AAudioStream_getDeviceId(AAudioStream* stream) __INTRODUCED_IN(26);
 
 /**
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return actual data format
  */
@@ -1217,6 +1291,9 @@
 
 /**
  * Provide actual sharing mode.
+ *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return  actual sharing mode
  */
@@ -1226,12 +1303,16 @@
 /**
  * Get the performance mode used by the stream.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  */
 AAUDIO_API aaudio_performance_mode_t AAudioStream_getPerformanceMode(AAudioStream* stream)
         __INTRODUCED_IN(26);
 
 /**
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return direction
  */
@@ -1245,6 +1326,8 @@
  *
  * The frame position is monotonically increasing.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return frames written
  */
@@ -1258,6 +1341,8 @@
  *
  * The frame position is monotonically increasing.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return frames read
  */
@@ -1281,7 +1366,7 @@
  *
  * The sessionID for a stream should not change once the stream has been opened.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return session ID or {@link #AAUDIO_SESSION_ID_NONE}
@@ -1304,6 +1389,8 @@
  *
  * The position and time passed back are monotonically increasing.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @param clockid CLOCK_MONOTONIC or CLOCK_BOOTTIME
  * @param framePosition pointer to a variable to receive the position
@@ -1316,7 +1403,7 @@
 /**
  * Return the use case for the stream.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return frames read
@@ -1326,7 +1413,7 @@
 /**
  * Return the content type for the stream.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return content type, for example {@link #AAUDIO_CONTENT_TYPE_MUSIC}
@@ -1337,7 +1424,7 @@
 /**
  * Return the input preset for the stream.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return input preset, for example {@link #AAUDIO_INPUT_PRESET_CAMCORDER}
@@ -1349,7 +1436,7 @@
  * Return the policy that determines whether the audio may or may not be captured
  * by other apps or the system.
  *
- * Added in API level 29.
+ * Available since API level 29.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return the allowed capture policy, for example {@link #AAUDIO_ALLOW_CAPTURE_BY_ALL}
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 56c0170..850b1d0 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -10,7 +10,9 @@
         "legacy",
         "utility",
     ],
-    header_libs: ["libaaudio_headers"],
+    header_libs: [
+        "libaaudio_headers",
+    ],
     export_header_lib_headers: ["libaaudio_headers"],
     version_script: "libaaudio.map.txt",
 
@@ -53,7 +55,10 @@
     ],
 
     export_include_dirs: ["."],
-    header_libs: ["libaaudio_headers"],
+    header_libs: [
+        "libaaudio_headers",
+        "libmedia_headers"
+    ],
     export_header_lib_headers: ["libaaudio_headers"],
 
     shared_libs: [
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 52eadd4..fb276c2 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -36,6 +36,7 @@
 #include "binding/AAudioStreamConfiguration.h"
 #include "binding/IAAudioService.h"
 #include "binding/AAudioServiceMessage.h"
+#include "core/AudioGlobal.h"
 #include "core/AudioStreamBuilder.h"
 #include "fifo/FifoBuffer.h"
 #include "utility/AudioClock.h"
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index a6cc45b..366cc87 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -89,7 +89,11 @@
     if (mAudioEndpoint.isFreeRunning()) {
         //ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter");
         // Update data queue based on the timing model.
-        int64_t estimatedRemoteCounter = mClockModel.convertTimeToPosition(currentNanoTime);
+        // Jitter in the DSP can cause late writes to the FIFO.
+        // This might be caused by resampling.
+        // We want to read the FIFO after the latest possible time
+        // that the DSP could have written the data.
+        int64_t estimatedRemoteCounter = mClockModel.convertLatestTimeToPosition(currentNanoTime);
         // TODO refactor, maybe use setRemoteCounter()
         mAudioEndpoint.setDataWriteCounter(estimatedRemoteCounter);
     }
@@ -139,7 +143,7 @@
                 // the writeCounter might have just advanced in the background,
                 // causing us to sleep until a later burst.
                 int64_t nextPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst;
-                wakeTime = mClockModel.convertPositionToTime(nextPosition);
+                wakeTime = mClockModel.convertPositionToLatestTime(nextPosition);
             }
                 break;
             default:
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index 747d0e1..9abdf53 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -19,12 +19,11 @@
 #include <log/log.h>
 
 #include <stdint.h>
+#include <algorithm>
 
 #include "utility/AudioClock.h"
 #include "IsochronousClockModel.h"
 
-#define MIN_LATENESS_NANOS (10 * AAUDIO_NANOS_PER_MICROSECOND)
-
 using namespace aaudio;
 
 IsochronousClockModel::IsochronousClockModel()
@@ -32,7 +31,7 @@
         , mMarkerNanoTime(0)
         , mSampleRate(48000)
         , mFramesPerBurst(64)
-        , mMaxLatenessInNanos(0)
+        , mMaxMeasuredLatenessNanos(0)
         , mState(STATE_STOPPED)
 {
 }
@@ -41,8 +40,7 @@
 }
 
 void IsochronousClockModel::setPositionAndTime(int64_t framePosition, int64_t nanoTime) {
-    ALOGV("setPositionAndTime(%lld, %lld)",
-          (long long) framePosition, (long long) nanoTime);
+    ALOGV("setPositionAndTime, %lld, %lld", (long long) framePosition, (long long) nanoTime);
     mMarkerFramePosition = framePosition;
     mMarkerNanoTime = nanoTime;
 }
@@ -54,7 +52,9 @@
 }
 
 void IsochronousClockModel::stop(int64_t nanoTime) {
-    ALOGV("stop(nanos = %lld)\n", (long long) nanoTime);
+    ALOGD("stop(nanos = %lld) max lateness = %d micros\n",
+        (long long) nanoTime,
+        (int) (mMaxMeasuredLatenessNanos / 1000));
     setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
     // TODO should we set position?
     mState = STATE_STOPPED;
@@ -69,9 +69,10 @@
 }
 
 void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nanoTime) {
-//    ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu",
-//         (long long)framePosition,
-//         (long long)nanoTime);
+    mTimestampCount++;
+// Log position and time in CSV format so we can import it easily into spreadsheets.
+    //ALOGD("%s() CSV, %d, %lld, %lld", __func__,
+          //mTimestampCount, (long long)framePosition, (long long)nanoTime);
     int64_t framesDelta = framePosition - mMarkerFramePosition;
     int64_t nanosDelta = nanoTime - mMarkerNanoTime;
     if (nanosDelta < 1000) {
@@ -108,17 +109,56 @@
     case STATE_RUNNING:
         if (nanosDelta < expectedNanosDelta) {
             // Earlier than expected timestamp.
-            // This data is probably more accurate so use it.
-            // or we may be drifting due to a slow HW clock.
-//            ALOGD("processTimestamp() - STATE_RUNNING - %d < %d micros - EARLY",
-//                 (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000));
+            // This data is probably more accurate, so use it.
+            // Or we may be drifting due to a fast HW clock.
+            //int microsDelta = (int) (nanosDelta / 1000);
+            //int expectedMicrosDelta = (int) (expectedNanosDelta / 1000);
+            //ALOGD("%s() - STATE_RUNNING - #%d, %4d micros EARLY",
+                //__func__, mTimestampCount, expectedMicrosDelta - microsDelta);
+
             setPositionAndTime(framePosition, nanoTime);
-        } else if (nanosDelta > (expectedNanosDelta + mMaxLatenessInNanos)) {
-            // Later than expected timestamp.
-//            ALOGD("processTimestamp() - STATE_RUNNING - %d > %d + %d micros - LATE",
-//                 (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000),
-//                 (int) (mMaxLatenessInNanos / 1000));
-            setPositionAndTime(framePosition - mFramesPerBurst,  nanoTime - mMaxLatenessInNanos);
+        } else if (nanosDelta > (expectedNanosDelta + (2 * mBurstPeriodNanos))) {
+            // In this case we do not update mMaxMeasuredLatenessNanos because it
+            // would force it too high.
+            // mMaxMeasuredLatenessNanos should range from 1 to 2 * mBurstPeriodNanos
+            //int32_t measuredLatenessNanos = (int32_t)(nanosDelta - expectedNanosDelta);
+            //ALOGD("%s() - STATE_RUNNING - #%d, lateness %d - max %d = %4d micros VERY LATE",
+                  //__func__,
+                  //mTimestampCount,
+                  //measuredLatenessNanos / 1000,
+                  //mMaxMeasuredLatenessNanos / 1000,
+                  //(measuredLatenessNanos - mMaxMeasuredLatenessNanos) / 1000
+                  //);
+
+            // This typically happens when we are modelling a service instead of a DSP.
+            setPositionAndTime(framePosition,  nanoTime - (2 * mBurstPeriodNanos));
+        } else if (nanosDelta > (expectedNanosDelta + mMaxMeasuredLatenessNanos)) {
+            //int32_t previousLatenessNanos = mMaxMeasuredLatenessNanos;
+            mMaxMeasuredLatenessNanos = (int32_t)(nanosDelta - expectedNanosDelta);
+
+            //ALOGD("%s() - STATE_RUNNING - #%d, newmax %d - oldmax %d = %4d micros LATE",
+                  //__func__,
+                  //mTimestampCount,
+                  //mMaxMeasuredLatenessNanos / 1000,
+                  //previousLatenessNanos / 1000,
+                  //(mMaxMeasuredLatenessNanos - previousLatenessNanos) / 1000
+                  //);
+
+            // When we are late, it may be because of preemption in the kernel,
+            // or timing jitter caused by resampling in the DSP,
+            // or we may be drifting due to a slow HW clock.
+            // We add slight drift value just in case there is actual long term drift
+            // forward caused by a slower clock.
+            // If the clock is faster than the model will get pushed earlier
+            // by the code in the preceding branch.
+            // The two opposing forces should allow the model to track the real clock
+            // over a long time.
+            int64_t driftingTime = mMarkerNanoTime + expectedNanosDelta + kDriftNanos;
+            setPositionAndTime(framePosition,  driftingTime);
+            //ALOGD("%s() - #%d, max lateness = %d micros",
+                  //__func__,
+                  //mTimestampCount,
+                  //(int) (mMaxMeasuredLatenessNanos / 1000));
         }
         break;
     default:
@@ -138,9 +178,12 @@
     update();
 }
 
+// Update expected lateness based on sampleRate and framesPerBurst
 void IsochronousClockModel::update() {
-    int64_t nanosLate = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate
-    mMaxLatenessInNanos = (nanosLate > MIN_LATENESS_NANOS) ? nanosLate : MIN_LATENESS_NANOS;
+    mBurstPeriodNanos = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate
+    // Timestamps may be late by up to a burst because we are randomly sampling the time period
+    // after the DSP position is actually updated.
+    mMaxMeasuredLatenessNanos = mBurstPeriodNanos;
 }
 
 int64_t IsochronousClockModel::convertDeltaPositionToTime(int64_t framesDelta) const {
@@ -183,11 +226,25 @@
     return position;
 }
 
+int32_t IsochronousClockModel::getLateTimeOffsetNanos() const {
+    // This will never be < 0 because mMaxLatenessNanos starts at
+    // mBurstPeriodNanos and only gets bigger.
+    return (mMaxMeasuredLatenessNanos - mBurstPeriodNanos) + kExtraLatenessNanos;
+}
+
+int64_t IsochronousClockModel::convertPositionToLatestTime(int64_t framePosition) const {
+    return convertPositionToTime(framePosition) + getLateTimeOffsetNanos();
+}
+
+int64_t IsochronousClockModel::convertLatestTimeToPosition(int64_t nanoTime) const {
+    return convertTimeToPosition(nanoTime - getLateTimeOffsetNanos());
+}
+
 void IsochronousClockModel::dump() const {
     ALOGD("mMarkerFramePosition = %lld", (long long) mMarkerFramePosition);
     ALOGD("mMarkerNanoTime      = %lld", (long long) mMarkerNanoTime);
     ALOGD("mSampleRate          = %6d", mSampleRate);
     ALOGD("mFramesPerBurst      = %6d", mFramesPerBurst);
-    ALOGD("mMaxLatenessInNanos  = %6d", mMaxLatenessInNanos);
+    ALOGD("mMaxMeasuredLatenessNanos = %6d", mMaxMeasuredLatenessNanos);
     ALOGD("mState               = %6d", mState);
 }
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 46ca48e..582bf4e 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -18,6 +18,7 @@
 #define ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
 
 #include <stdint.h>
+#include "utility/AudioClock.h"
 
 namespace aaudio {
 
@@ -79,6 +80,15 @@
     int64_t convertPositionToTime(int64_t framePosition) const;
 
     /**
+     * Calculate the latest estimated time that the stream will be at that position.
+     * The more jittery the clock is then the later this will be.
+     *
+     * @param framePosition
+     * @return time in nanoseconds
+     */
+    int64_t convertPositionToLatestTime(int64_t framePosition) const;
+
+    /**
      * Calculate an estimated position where the stream will be at the specified time.
      *
      * @param nanoTime time of interest
@@ -87,6 +97,18 @@
     int64_t convertTimeToPosition(int64_t nanoTime) const;
 
     /**
+     * Calculate the corresponding estimated position based on the specified time being
+     * the latest possible time.
+     *
+     * For the same nanoTime, this may return an earlier position than
+     * convertTimeToPosition().
+     *
+     * @param nanoTime
+     * @return position in frames
+     */
+    int64_t convertLatestTimeToPosition(int64_t nanoTime) const;
+
+    /**
      * @param framesDelta difference in frames
      * @return duration in nanoseconds
      */
@@ -101,6 +123,9 @@
     void dump() const;
 
 private:
+
+    int32_t getLateTimeOffsetNanos() const;
+
     enum clock_model_state_t {
         STATE_STOPPED,
         STATE_STARTING,
@@ -108,13 +133,23 @@
         STATE_RUNNING
     };
 
+    // Amount of time to drift forward when we get a late timestamp.
+    // This value was calculated to allow tracking of a clock with 50 ppm error.
+    static constexpr int32_t   kDriftNanos         =  10 * 1000;
+    // TODO review value of kExtraLatenessNanos
+    static constexpr int32_t   kExtraLatenessNanos = 100 * 1000;
+
     int64_t             mMarkerFramePosition;
     int64_t             mMarkerNanoTime;
     int32_t             mSampleRate;
     int32_t             mFramesPerBurst;
-    int32_t             mMaxLatenessInNanos;
+    int32_t             mBurstPeriodNanos;
+    // Includes mBurstPeriodNanos because we sample randomly over time.
+    int32_t             mMaxMeasuredLatenessNanos;
     clock_model_state_t mState;
 
+    int32_t             mTimestampCount = 0;
+
     void update();
 };
 
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index c516d20..32904bb 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -84,6 +84,7 @@
     header_libs: [
         "libaudioclient_headers",
         "libbase_headers",
+        "libmedia_headers",
     ],
     export_header_lib_headers: ["libaudioclient_headers"],
 
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 52bb2fb..d509be6 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -11,6 +11,9 @@
     defaults: ["libaudioclient_tests_defaults"],
     srcs: ["test_create_audiotrack.cpp",
            "test_create_utils.cpp"],
+    header_libs: [
+        "libmedia_headers",
+    ],
     shared_libs: [
         "libaudioclient",
         "libbinder",
@@ -25,6 +28,9 @@
     defaults: ["libaudioclient_tests_defaults"],
     srcs: ["test_create_audiorecord.cpp",
            "test_create_utils.cpp"],
+    header_libs: [
+        "libmedia_headers",
+    ],
     shared_libs: [
         "libaudioclient",
         "libbinder",
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
index 5e22322..74b48f3 100644
--- a/media/libaudiohal/Android.bp
+++ b/media/libaudiohal/Android.bp
@@ -13,20 +13,16 @@
     ],
 
     shared_libs: [
-        "android.hardware.audio.effect@2.0",
-        "android.hardware.audio.effect@4.0",
-        "android.hardware.audio.effect@5.0",
-        "android.hardware.audio@2.0",
-        "android.hardware.audio@4.0",
-        "android.hardware.audio@5.0",
         "libaudiohal@2.0",
         "libaudiohal@4.0",
         "libaudiohal@5.0",
+        "libaudiohal@6.0",
         "libutils",
     ],
 
     header_libs: [
-        "libaudiohal_headers"
+        "libaudiohal_headers",
+        "libbase_headers",
     ]
 }
 
diff --git a/media/libaudiohal/DevicesFactoryHalInterface.cpp b/media/libaudiohal/DevicesFactoryHalInterface.cpp
index f86009c..d5336fa 100644
--- a/media/libaudiohal/DevicesFactoryHalInterface.cpp
+++ b/media/libaudiohal/DevicesFactoryHalInterface.cpp
@@ -14,26 +14,16 @@
  * limitations under the License.
  */
 
-#include <android/hardware/audio/2.0/IDevicesFactory.h>
-#include <android/hardware/audio/4.0/IDevicesFactory.h>
-#include <android/hardware/audio/5.0/IDevicesFactory.h>
-
 #include <libaudiohal/FactoryHalHidl.h>
 
+#include <media/audiohal/DevicesFactoryHalInterface.h>
+
 namespace android {
 
 // static
 sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
-    if (hardware::audio::V5_0::IDevicesFactory::getService() != nullptr) {
-        return V5_0::createDevicesFactoryHal();
-    }
-    if (hardware::audio::V4_0::IDevicesFactory::getService() != nullptr) {
-        return V4_0::createDevicesFactoryHal();
-    }
-    if (hardware::audio::V2_0::IDevicesFactory::getService() != nullptr) {
-        return V2_0::createDevicesFactoryHal();
-    }
-    return nullptr;
+    return createPreferedImpl<DevicesFactoryHalInterface>();
 }
 
 } // namespace android
+
diff --git a/media/libaudiohal/EffectsFactoryHalInterface.cpp b/media/libaudiohal/EffectsFactoryHalInterface.cpp
index bd3ef61..d15b14e 100644
--- a/media/libaudiohal/EffectsFactoryHalInterface.cpp
+++ b/media/libaudiohal/EffectsFactoryHalInterface.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,26 +14,15 @@
  * limitations under the License.
  */
 
-#include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/5.0/IEffectsFactory.h>
-
 #include <libaudiohal/FactoryHalHidl.h>
 
+#include <media/audiohal/EffectsFactoryHalInterface.h>
+
 namespace android {
 
 // static
 sp<EffectsFactoryHalInterface> EffectsFactoryHalInterface::create() {
-    if (hardware::audio::effect::V5_0::IEffectsFactory::getService() != nullptr) {
-        return effect::V5_0::createEffectsFactoryHal();
-    }
-    if (hardware::audio::effect::V4_0::IEffectsFactory::getService() != nullptr) {
-        return effect::V4_0::createEffectsFactoryHal();
-    }
-    if (hardware::audio::effect::V2_0::IEffectsFactory::getService() != nullptr) {
-        return effect::V2_0::createEffectsFactoryHal();
-    }
-    return nullptr;
+    return createPreferedImpl<EffectsFactoryHalInterface>();
 }
 
 // static
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index a23d945..8669e2a 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -99,3 +99,20 @@
         "-include common/all-versions/VersionMacro.h",
     ]
 }
+
+cc_library_shared {
+    name: "libaudiohal@6.0",
+    defaults: ["libaudiohal_default"],
+    shared_libs: [
+        "android.hardware.audio.common@6.0",
+        "android.hardware.audio.common@6.0-util",
+        "android.hardware.audio.effect@6.0",
+        "android.hardware.audio@6.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=6",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ]
+}
+
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
index 5e01e42..1335a0c 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
@@ -35,13 +35,10 @@
 namespace android {
 namespace CPP_VERSION {
 
-DevicesFactoryHalHidl::DevicesFactoryHalHidl() {
-    sp<IDevicesFactory> defaultFactory{IDevicesFactory::getService()};
-    if (!defaultFactory) {
-        ALOGE("Failed to obtain IDevicesFactory/default service, terminating process.");
-        exit(1);
-    }
-    mDeviceFactories.push_back(defaultFactory);
+DevicesFactoryHalHidl::DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory) {
+    ALOG_ASSERT(devicesFactory != nullptr, "Provided IDevicesFactory service is NULL");
+
+    mDeviceFactories.push_back(devicesFactory);
     if (MAJOR_VERSION >= 4) {
         // The MSD factory is optional and only available starting at HAL 4.0
         sp<IDevicesFactory> msdFactory{IDevicesFactory::getService(AUDIO_HAL_SERVICE_NAME_MSD)};
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.h b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
index 27e0649..8775e7b 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
@@ -32,18 +32,14 @@
 class DevicesFactoryHalHidl : public DevicesFactoryHalInterface
 {
   public:
+    DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory);
+
     // Opens a device with the specified name. To close the device, it is
     // necessary to release references to the returned object.
     virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
-
   private:
-    friend class DevicesFactoryHalHybrid;
-
     std::vector<sp<IDevicesFactory>> mDeviceFactories;
 
-    // Can not be constructed directly by clients.
-    DevicesFactoryHalHidl();
-
     virtual ~DevicesFactoryHalHidl() = default;
 };
 
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
index f337a8b..0e1f1bb 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
@@ -17,16 +17,17 @@
 #define LOG_TAG "DevicesFactoryHalHybrid"
 //#define LOG_NDEBUG 0
 
+#include "DevicesFactoryHalHidl.h"
 #include "DevicesFactoryHalHybrid.h"
 #include "DevicesFactoryHalLocal.h"
-#include "DevicesFactoryHalHidl.h"
+#include <libaudiohal/FactoryHalHidl.h>
 
 namespace android {
 namespace CPP_VERSION {
 
-DevicesFactoryHalHybrid::DevicesFactoryHalHybrid()
+DevicesFactoryHalHybrid::DevicesFactoryHalHybrid(sp<IDevicesFactory> hidlFactory)
         : mLocalFactory(new DevicesFactoryHalLocal()),
-          mHidlFactory(new DevicesFactoryHalHidl()) {
+          mHidlFactory(new DevicesFactoryHalHidl(hidlFactory)) {
 }
 
 status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
@@ -36,6 +37,12 @@
     }
     return mLocalFactory->openDevice(name, device);
 }
-
 } // namespace CPP_VERSION
+
+template <>
+sp<DevicesFactoryHalInterface> createFactoryHal<AudioHALVersion::CPP_VERSION>() {
+    auto service = hardware::audio::CPP_VERSION::IDevicesFactory::getService();
+    return service ? new CPP_VERSION::DevicesFactoryHalHybrid(service) : nullptr;
+}
+
 } // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
index 5ac0d0d..545bb70 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
@@ -17,17 +17,20 @@
 #ifndef ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HYBRID_H
 #define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HYBRID_H
 
+#include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h)
 #include <media/audiohal/DevicesFactoryHalInterface.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
+using ::android::hardware::audio::CPP_VERSION::IDevicesFactory;
+
 namespace android {
 namespace CPP_VERSION {
 
 class DevicesFactoryHalHybrid : public DevicesFactoryHalInterface
 {
   public:
-    DevicesFactoryHalHybrid();
+    DevicesFactoryHalHybrid(sp<IDevicesFactory> hidlFactory);
 
     // Opens a device with the specified name. To close the device, it is
     // necessary to release references to the returned object.
@@ -38,10 +41,6 @@
     sp<DevicesFactoryHalInterface> mHidlFactory;
 };
 
-sp<DevicesFactoryHalInterface> createDevicesFactoryHal() {
-    return new DevicesFactoryHalHybrid();
-}
-
 } // namespace CPP_VERSION
 } // namespace android
 
diff --git a/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
index 7fd6bde..ba7b195 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
@@ -19,11 +19,12 @@
 
 #include <cutils/native_handle.h>
 
-#include "EffectsFactoryHalHidl.h"
 #include "ConversionHelperHidl.h"
 #include "EffectBufferHalHidl.h"
 #include "EffectHalHidl.h"
+#include "EffectsFactoryHalHidl.h"
 #include "HidlUtils.h"
+#include <libaudiohal/FactoryHalHidl.h>
 
 using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
 using ::android::hardware::Return;
@@ -35,12 +36,10 @@
 using namespace ::android::hardware::audio::common::CPP_VERSION;
 using namespace ::android::hardware::audio::effect::CPP_VERSION;
 
-EffectsFactoryHalHidl::EffectsFactoryHalHidl() : ConversionHelperHidl("EffectsFactory") {
-    mEffectsFactory = IEffectsFactory::getService();
-    if (mEffectsFactory == 0) {
-        ALOGE("Failed to obtain IEffectsFactory service, terminating process.");
-        exit(1);
-    }
+EffectsFactoryHalHidl::EffectsFactoryHalHidl(sp<IEffectsFactory> effectsFactory)
+        : ConversionHelperHidl("EffectsFactory") {
+    ALOG_ASSERT(effectsFactory != nullptr, "Provided IDevicesFactory service is NULL");
+    mEffectsFactory = effectsFactory;
 }
 
 status_t EffectsFactoryHalHidl::queryAllDescriptors() {
@@ -147,4 +146,11 @@
 
 } // namespace CPP_VERSION
 } // namespace effect
+
+template<>
+sp<EffectsFactoryHalInterface> createFactoryHal<AudioHALVersion::CPP_VERSION>() {
+    auto service = hardware::audio::effect::CPP_VERSION::IEffectsFactory::getService();
+    return service ? new effect::CPP_VERSION::EffectsFactoryHalHidl(service) : nullptr;
+}
+
 } // namespace android
diff --git a/media/libaudiohal/impl/EffectsFactoryHalHidl.h b/media/libaudiohal/impl/EffectsFactoryHalHidl.h
index 01178ff..2828513 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalHidl.h
+++ b/media/libaudiohal/impl/EffectsFactoryHalHidl.h
@@ -18,7 +18,6 @@
 #define ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_HIDL_H
 
 #include PATH(android/hardware/audio/effect/FILE_VERSION/IEffectsFactory.h)
-#include PATH(android/hardware/audio/effect/FILE_VERSION/types.h)
 #include <media/audiohal/EffectsFactoryHalInterface.h>
 
 #include "ConversionHelperHidl.h"
@@ -34,7 +33,7 @@
 class EffectsFactoryHalHidl : public EffectsFactoryHalInterface, public ConversionHelperHidl
 {
   public:
-    EffectsFactoryHalHidl();
+    EffectsFactoryHalHidl(sp<IEffectsFactory> effectsFactory);
 
     // Returns the number of different effects in all loaded libraries.
     virtual status_t queryNumberEffects(uint32_t *pNumEffects);
@@ -66,10 +65,6 @@
     status_t queryAllDescriptors();
 };
 
-sp<EffectsFactoryHalInterface> createEffectsFactoryHal() {
-    return new EffectsFactoryHalHidl();
-}
-
 } // namespace CPP_VERSION
 } // namespace effect
 } // namespace android
diff --git a/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h b/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
index c7319d0..271bafc 100644
--- a/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
+++ b/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
@@ -23,33 +23,43 @@
 #include <media/audiohal/EffectsFactoryHalInterface.h>
 #include <utils/StrongPointer.h>
 
+#include <array>
+#include <utility>
+
 namespace android {
 
-namespace effect {
-namespace V2_0 {
-sp<EffectsFactoryHalInterface> createEffectsFactoryHal();
-} // namespace V2_0
+/** Supported HAL versions, in order of preference.
+ * Implementation should use specialize the `create*FactoryHal` for their version.
+ * Client should use `createPreferedImpl<*FactoryHal>()` to instantiate
+ * the preferred available impl.
+ */
+enum class AudioHALVersion {
+    V6_0,
+    V5_0,
+    V4_0,
+    V2_0,
+    end, // used for iterating over supported versions
+};
 
-namespace V4_0 {
-sp<EffectsFactoryHalInterface> createEffectsFactoryHal();
-} // namespace V4_0
+/** Template function to fully specialized for each version and each Interface. */
+template <AudioHALVersion, class Interface>
+sp<Interface> createFactoryHal();
 
-namespace V5_0 {
-sp<EffectsFactoryHalInterface> createEffectsFactoryHal();
-} // namespace V5_0
-} // namespace effect
+/** @Return the preferred available implementation or nullptr if none are available. */
+template <class Interface, AudioHALVersion version = AudioHALVersion{}>
+static sp<Interface> createPreferedImpl() {
+    if constexpr (version == AudioHALVersion::end) {
+        return nullptr; // tried all version, all returned nullptr
+    } else {
+        if (auto created = createFactoryHal<version, Interface>(); created != nullptr) {
+           return created;
+        }
 
-namespace V2_0 {
-sp<DevicesFactoryHalInterface> createDevicesFactoryHal();
-} // namespace V2_0
+        using Raw = std::underlying_type_t<AudioHALVersion>; // cast as enum class do not support ++
+        return createPreferedImpl<Interface, AudioHALVersion(Raw(version) + 1)>();
+    }
+}
 
-namespace V4_0 {
-sp<DevicesFactoryHalInterface> createDevicesFactoryHal();
-} // namespace V4_0
-
-namespace V5_0 {
-sp<DevicesFactoryHalInterface> createDevicesFactoryHal();
-} // namespace V5_0
 
 } // namespace android
 
diff --git a/media/libaudioprocessing/Android.bp b/media/libaudioprocessing/Android.bp
index e8aa700..9b5d58c 100644
--- a/media/libaudioprocessing/Android.bp
+++ b/media/libaudioprocessing/Android.bp
@@ -33,6 +33,7 @@
 
     header_libs: [
         "libbase_headers",
+        "libmedia_headers"
     ],
 
     shared_libs: [
diff --git a/media/libaudioprocessing/tests/Android.bp b/media/libaudioprocessing/tests/Android.bp
index f4e497b..20c2c2c 100644
--- a/media/libaudioprocessing/tests/Android.bp
+++ b/media/libaudioprocessing/tests/Android.bp
@@ -3,7 +3,11 @@
 cc_defaults {
     name: "libaudioprocessing_test_defaults",
 
-    header_libs: ["libbase_headers"],
+    header_libs: [
+        "libbase_headers",
+        "libmedia_headers",
+    ],
+
     shared_libs: [
         "libaudioclient",
         "libaudioprocessing",
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 3fbbc09..10dda19 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -302,6 +302,8 @@
         for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
             pContext->pBundledContext->bandGaindB[i] = EQNB_5BandSoftPresets[i];
         }
+        pContext->pBundledContext->effectProcessCalled      = 0;
+        pContext->pBundledContext->effectInDrain            = 0;
 
         ALOGV("\tEffectCreate - Calling LvmBundle_init");
         ret = LvmBundle_init(pContext);
@@ -394,6 +396,8 @@
 
     // Clear the instantiated flag for the effect
     // protect agains the case where an effect is un-instantiated without being disabled
+
+    int &effectInDrain = pContext->pBundledContext->effectInDrain;
     if(pContext->EffectType == LVM_BASS_BOOST) {
         ALOGV("\tEffectRelease LVM_BASS_BOOST Clearing global intstantiated flag");
         pSessionContext->bBassInstantiated = LVM_FALSE;
@@ -418,12 +422,16 @@
     } else if(pContext->EffectType == LVM_VOLUME) {
         ALOGV("\tEffectRelease LVM_VOLUME Clearing global intstantiated flag");
         pSessionContext->bVolumeInstantiated = LVM_FALSE;
-        if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE){
+        // There is no samplesToExitCount for volume so we also use the drain flag to check
+        // if we should decrement the effects enabled.
+        if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE
+                || (effectInDrain & 1 << LVM_VOLUME) != 0) {
             pContext->pBundledContext->NumberEffectsEnabled--;
         }
     } else {
         ALOGV("\tLVM_ERROR : EffectRelease : Unsupported effect\n\n\n\n\n\n\n");
     }
+    effectInDrain &= ~(1 << pContext->EffectType); // no need to drain if released
 
     // Disable effect, in this case ignore errors (return codes)
     // if an effect has already been disabled
@@ -3124,8 +3132,9 @@
 
 int Effect_setEnabled(EffectContext *pContext, bool enabled)
 {
-    ALOGV("\tEffect_setEnabled() type %d, enabled %d", pContext->EffectType, enabled);
-
+    ALOGV("%s effectType %d, enabled %d, currently enabled %d", __func__,
+            pContext->EffectType, enabled, pContext->pBundledContext->NumberEffectsEnabled);
+    int &effectInDrain = pContext->pBundledContext->effectInDrain;
     if (enabled) {
         // Bass boost or Virtualizer can be temporarily disabled if playing over device speaker due
         // to their nature.
@@ -3139,6 +3148,7 @@
                 if(pContext->pBundledContext->SamplesToExitCountBb <= 0){
                     pContext->pBundledContext->NumberEffectsEnabled++;
                 }
+                effectInDrain &= ~(1 << LVM_BASS_BOOST);
                 pContext->pBundledContext->SamplesToExitCountBb =
                      (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
                 pContext->pBundledContext->bBassEnabled = LVM_TRUE;
@@ -3152,6 +3162,7 @@
                 if(pContext->pBundledContext->SamplesToExitCountEq <= 0){
                     pContext->pBundledContext->NumberEffectsEnabled++;
                 }
+                effectInDrain &= ~(1 << LVM_EQUALIZER);
                 pContext->pBundledContext->SamplesToExitCountEq =
                      (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
                 pContext->pBundledContext->bEqualizerEnabled = LVM_TRUE;
@@ -3164,6 +3175,7 @@
                 if(pContext->pBundledContext->SamplesToExitCountVirt <= 0){
                     pContext->pBundledContext->NumberEffectsEnabled++;
                 }
+                effectInDrain &= ~(1 << LVM_VIRTUALIZER);
                 pContext->pBundledContext->SamplesToExitCountVirt =
                      (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
                 pContext->pBundledContext->bVirtualizerEnabled = LVM_TRUE;
@@ -3174,7 +3186,10 @@
                     ALOGV("\tEffect_setEnabled() LVM_VOLUME is already enabled");
                     return -EINVAL;
                 }
-                pContext->pBundledContext->NumberEffectsEnabled++;
+                if ((effectInDrain & 1 << LVM_VOLUME) == 0) {
+                    pContext->pBundledContext->NumberEffectsEnabled++;
+                }
+                effectInDrain &= ~(1 << LVM_VOLUME);
                 pContext->pBundledContext->bVolumeEnabled = LVM_TRUE;
                 break;
             default:
@@ -3192,6 +3207,7 @@
                     return -EINVAL;
                 }
                 pContext->pBundledContext->bBassEnabled = LVM_FALSE;
+                effectInDrain |= 1 << LVM_BASS_BOOST;
                 break;
             case LVM_EQUALIZER:
                 if (pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE) {
@@ -3199,6 +3215,7 @@
                     return -EINVAL;
                 }
                 pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE;
+                effectInDrain |= 1 << LVM_EQUALIZER;
                 break;
             case LVM_VIRTUALIZER:
                 if (pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE) {
@@ -3206,6 +3223,7 @@
                     return -EINVAL;
                 }
                 pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE;
+                effectInDrain |= 1 << LVM_VIRTUALIZER;
                 break;
             case LVM_VOLUME:
                 if (pContext->pBundledContext->bVolumeEnabled == LVM_FALSE) {
@@ -3213,6 +3231,7 @@
                     return -EINVAL;
                 }
                 pContext->pBundledContext->bVolumeEnabled = LVM_FALSE;
+                effectInDrain |= 1 << LVM_VOLUME;
                 break;
             default:
                 ALOGV("\tEffect_setEnabled() invalid effect type");
@@ -3283,6 +3302,38 @@
         ALOGV("\tLVM_ERROR : Effect_process() ERROR NULL INPUT POINTER OR FRAME COUNT IS WRONG");
         return -EINVAL;
     }
+
+    int &effectProcessCalled = pContext->pBundledContext->effectProcessCalled;
+    int &effectInDrain = pContext->pBundledContext->effectInDrain;
+    if ((effectProcessCalled & 1 << pContext->EffectType) != 0) {
+        ALOGW("Effect %d already called", pContext->EffectType);
+        const int undrainedEffects = effectInDrain & ~effectProcessCalled;
+        if ((undrainedEffects & 1 << LVM_BASS_BOOST) != 0) {
+            ALOGW("Draining BASS_BOOST");
+            pContext->pBundledContext->SamplesToExitCountBb = 0;
+            --pContext->pBundledContext->NumberEffectsEnabled;
+            effectInDrain &= ~(1 << LVM_BASS_BOOST);
+        }
+        if ((undrainedEffects & 1 << LVM_EQUALIZER) != 0) {
+            ALOGW("Draining EQUALIZER");
+            pContext->pBundledContext->SamplesToExitCountEq = 0;
+            --pContext->pBundledContext->NumberEffectsEnabled;
+            effectInDrain &= ~(1 << LVM_EQUALIZER);
+        }
+        if ((undrainedEffects & 1 << LVM_VIRTUALIZER) != 0) {
+            ALOGW("Draining VIRTUALIZER");
+            pContext->pBundledContext->SamplesToExitCountVirt = 0;
+            --pContext->pBundledContext->NumberEffectsEnabled;
+            effectInDrain &= ~(1 << LVM_VIRTUALIZER);
+        }
+        if ((undrainedEffects & 1 << LVM_VOLUME) != 0) {
+            ALOGW("Draining VOLUME");
+            --pContext->pBundledContext->NumberEffectsEnabled;
+            effectInDrain &= ~(1 << LVM_VOLUME);
+        }
+    }
+    effectProcessCalled |= 1 << pContext->EffectType;
+
     if ((pContext->pBundledContext->bBassEnabled == LVM_FALSE)&&
         (pContext->EffectType == LVM_BASS_BOOST)){
         //ALOGV("\tEffect_process() LVM_BASS_BOOST Effect is not enabled");
@@ -3291,9 +3342,12 @@
             //ALOGV("\tEffect_process: Waiting to turn off BASS_BOOST, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountBb);
         }
-        if(pContext->pBundledContext->SamplesToExitCountBb <= 0) {
+        if (pContext->pBundledContext->SamplesToExitCountBb <= 0) {
             status = -ENODATA;
-            pContext->pBundledContext->NumberEffectsEnabled--;
+            if ((effectInDrain & 1 << LVM_BASS_BOOST) != 0) {
+                pContext->pBundledContext->NumberEffectsEnabled--;
+                effectInDrain &= ~(1 << LVM_BASS_BOOST);
+            }
             ALOGV("\tEffect_process() this is the last frame for LVM_BASS_BOOST");
         }
     }
@@ -3301,7 +3355,10 @@
         (pContext->EffectType == LVM_VOLUME)){
         //ALOGV("\tEffect_process() LVM_VOLUME Effect is not enabled");
         status = -ENODATA;
-        pContext->pBundledContext->NumberEffectsEnabled--;
+        if ((effectInDrain & 1 << LVM_VOLUME) != 0) {
+            pContext->pBundledContext->NumberEffectsEnabled--;
+            effectInDrain &= ~(1 << LVM_VOLUME);
+        }
     }
     if ((pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE)&&
         (pContext->EffectType == LVM_EQUALIZER)){
@@ -3311,9 +3368,12 @@
             //ALOGV("\tEffect_process: Waiting to turn off EQUALIZER, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountEq);
         }
-        if(pContext->pBundledContext->SamplesToExitCountEq <= 0) {
+        if (pContext->pBundledContext->SamplesToExitCountEq <= 0) {
             status = -ENODATA;
-            pContext->pBundledContext->NumberEffectsEnabled--;
+            if ((effectInDrain & 1 << LVM_EQUALIZER) != 0) {
+                pContext->pBundledContext->NumberEffectsEnabled--;
+                effectInDrain &= ~(1 << LVM_EQUALIZER);
+            }
             ALOGV("\tEffect_process() this is the last frame for LVM_EQUALIZER");
         }
     }
@@ -3326,9 +3386,12 @@
             //ALOGV("\tEffect_process: Waiting for to turn off VIRTUALIZER, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountVirt);
         }
-        if(pContext->pBundledContext->SamplesToExitCountVirt <= 0) {
+        if (pContext->pBundledContext->SamplesToExitCountVirt <= 0) {
             status = -ENODATA;
-            pContext->pBundledContext->NumberEffectsEnabled--;
+            if ((effectInDrain & 1 << LVM_VIRTUALIZER) != 0) {
+                pContext->pBundledContext->NumberEffectsEnabled--;
+                effectInDrain &= ~(1 << LVM_VIRTUALIZER);
+            }
             ALOGV("\tEffect_process() this is the last frame for LVM_VIRTUALIZER");
         }
     }
@@ -3337,8 +3400,18 @@
         pContext->pBundledContext->NumberEffectsCalled++;
     }
 
-    if(pContext->pBundledContext->NumberEffectsCalled ==
-       pContext->pBundledContext->NumberEffectsEnabled){
+    if (pContext->pBundledContext->NumberEffectsCalled >=
+            pContext->pBundledContext->NumberEffectsEnabled) {
+
+        // We expect the # effects called to be equal to # effects enabled in sequence (including
+        // draining effects).  Warn if this is not the case due to inconsistent calls.
+        ALOGW_IF(pContext->pBundledContext->NumberEffectsCalled >
+                pContext->pBundledContext->NumberEffectsEnabled,
+                "%s Number of effects called %d is greater than number of effects enabled %d",
+                __func__, pContext->pBundledContext->NumberEffectsCalled,
+                pContext->pBundledContext->NumberEffectsEnabled);
+        effectProcessCalled = 0; // reset our consistency check.
+
         //ALOGV("\tEffect_process     Calling process with %d effects enabled, %d called: Effect %d",
         //pContext->pBundledContext->NumberEffectsEnabled,
         //pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType);
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index 6af4554..e4aacd0 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -110,6 +110,14 @@
 #ifdef SUPPORT_MC
     LVM_INT32                       ChMask;
 #endif
+
+    /* Bitmask whether drain is in progress due to disabling the effect.
+       The corresponding bit to an effect is set by 1 << lvm_effect_en. */
+    int                             effectInDrain;
+
+    /* Bitmask whether process() was called for a particular effect.
+       The corresponding bit to an effect is set by 1 << lvm_effect_en. */
+    int                             effectProcessCalled;
 };
 
 /* SessionContext : One session */
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index ec4751c..b49df9e 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -197,6 +197,7 @@
     ],
 
     header_libs: [
+        "libmedia_headers",
         "media_ndk_headers",
     ],
 
@@ -292,7 +293,6 @@
         "MediaProfiles.cpp",
         "MediaResource.cpp",
         "MediaResourcePolicy.cpp",
-        "Visualizer.cpp",
         "StringArray.cpp",
         "NdkMediaFormatPriv.cpp",
         "NdkMediaErrorPriv.cpp",
@@ -328,7 +328,6 @@
         "libstagefright_foundation",
         "libgui",
         "libdl",
-        "libaudioutils",
         "libaudioclient",
         "libmedia_codeclist",
         "libmedia_omx",
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
deleted file mode 100644
index cb8d375..0000000
--- a/media/libmedia/Visualizer.cpp
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
-**
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Visualizer"
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <limits.h>
-
-#include <media/Visualizer.h>
-#include <audio_utils/fixedfft.h>
-#include <utils/Thread.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-Visualizer::Visualizer (const String16& opPackageName,
-         int32_t priority,
-         effect_callback_t cbf,
-         void* user,
-         audio_session_t sessionId)
-    :   AudioEffect(SL_IID_VISUALIZATION, opPackageName, NULL, priority, cbf, user, sessionId),
-        mCaptureRate(CAPTURE_RATE_DEF),
-        mCaptureSize(CAPTURE_SIZE_DEF),
-        mSampleRate(44100000),
-        mScalingMode(VISUALIZER_SCALING_MODE_NORMALIZED),
-        mMeasurementMode(MEASUREMENT_MODE_NONE),
-        mCaptureCallBack(NULL),
-        mCaptureCbkUser(NULL)
-{
-    initCaptureSize();
-}
-
-Visualizer::~Visualizer()
-{
-    ALOGV("Visualizer::~Visualizer()");
-    setEnabled(false);
-    setCaptureCallBack(NULL, NULL, 0, 0);
-}
-
-void Visualizer::release()
-{
-    ALOGV("Visualizer::release()");
-    setEnabled(false);
-    Mutex::Autolock _l(mCaptureLock);
-
-    mCaptureThread.clear();
-    mCaptureCallBack = NULL;
-    mCaptureCbkUser = NULL;
-    mCaptureFlags = 0;
-    mCaptureRate = 0;
-}
-
-status_t Visualizer::setEnabled(bool enabled)
-{
-    Mutex::Autolock _l(mCaptureLock);
-
-    sp<CaptureThread> t = mCaptureThread;
-    if (t != 0) {
-        if (enabled) {
-            if (t->exitPending()) {
-                if (t->requestExitAndWait() == WOULD_BLOCK) {
-                    ALOGE("Visualizer::enable() called from thread");
-                    return INVALID_OPERATION;
-                }
-            }
-        }
-        t->mLock.lock();
-    }
-
-    status_t status = AudioEffect::setEnabled(enabled);
-
-    if (t != 0) {
-        if (enabled && status == NO_ERROR) {
-            t->run("Visualizer");
-        } else {
-            t->requestExit();
-        }
-    }
-
-    if (t != 0) {
-        t->mLock.unlock();
-    }
-
-    return status;
-}
-
-status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags,
-        uint32_t rate)
-{
-    if (rate > CAPTURE_RATE_MAX) {
-        return BAD_VALUE;
-    }
-    Mutex::Autolock _l(mCaptureLock);
-
-    if (mEnabled) {
-        return INVALID_OPERATION;
-    }
-
-    if (mCaptureThread != 0) {
-        mCaptureLock.unlock();
-        mCaptureThread->requestExitAndWait();
-        mCaptureLock.lock();
-    }
-
-    mCaptureThread.clear();
-    mCaptureCallBack = cbk;
-    mCaptureCbkUser = user;
-    mCaptureFlags = flags;
-    mCaptureRate = rate;
-
-    if (cbk != NULL) {
-        mCaptureThread = new CaptureThread(this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
-    }
-    ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
-            rate, mCaptureThread.get(), mCaptureFlags);
-    return NO_ERROR;
-}
-
-status_t Visualizer::setCaptureSize(uint32_t size)
-{
-    if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
-        size < VISUALIZER_CAPTURE_SIZE_MIN ||
-        popcount(size) != 1) {
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock _l(mCaptureLock);
-    if (mEnabled) {
-        return INVALID_OPERATION;
-    }
-
-    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
-    effect_param_t *p = (effect_param_t *)buf32;
-
-    p->psize = sizeof(uint32_t);
-    p->vsize = sizeof(uint32_t);
-    *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
-    *((int32_t *)p->data + 1)= size;
-    status_t status = setParameter(p);
-
-    ALOGV("setCaptureSize size %d  status %d p->status %d", size, status, p->status);
-
-    if (status == NO_ERROR) {
-        status = p->status;
-        if (status == NO_ERROR) {
-            mCaptureSize = size;
-        }
-    }
-
-    return status;
-}
-
-status_t Visualizer::setScalingMode(uint32_t mode) {
-    if ((mode != VISUALIZER_SCALING_MODE_NORMALIZED)
-            && (mode != VISUALIZER_SCALING_MODE_AS_PLAYED)) {
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock _l(mCaptureLock);
-
-    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
-    effect_param_t *p = (effect_param_t *)buf32;
-
-    p->psize = sizeof(uint32_t);
-    p->vsize = sizeof(uint32_t);
-    *(int32_t *)p->data = VISUALIZER_PARAM_SCALING_MODE;
-    *((int32_t *)p->data + 1)= mode;
-    status_t status = setParameter(p);
-
-    ALOGV("setScalingMode mode %d  status %d p->status %d", mode, status, p->status);
-
-    if (status == NO_ERROR) {
-        status = p->status;
-        if (status == NO_ERROR) {
-            mScalingMode = mode;
-        }
-    }
-
-    return status;
-}
-
-status_t Visualizer::setMeasurementMode(uint32_t mode) {
-    if ((mode != MEASUREMENT_MODE_NONE)
-            //Note: needs to be handled as a mask when more measurement modes are added
-            && ((mode & MEASUREMENT_MODE_PEAK_RMS) != mode)) {
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock _l(mCaptureLock);
-
-    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
-    effect_param_t *p = (effect_param_t *)buf32;
-
-    p->psize = sizeof(uint32_t);
-    p->vsize = sizeof(uint32_t);
-    *(int32_t *)p->data = VISUALIZER_PARAM_MEASUREMENT_MODE;
-    *((int32_t *)p->data + 1)= mode;
-    status_t status = setParameter(p);
-
-    ALOGV("setMeasurementMode mode %d  status %d p->status %d", mode, status, p->status);
-
-    if (status == NO_ERROR) {
-        status = p->status;
-        if (status == NO_ERROR) {
-            mMeasurementMode = mode;
-        }
-    }
-    return status;
-}
-
-status_t Visualizer::getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements) {
-    if (mMeasurementMode == MEASUREMENT_MODE_NONE) {
-        ALOGE("Cannot retrieve int measurements, no measurement mode set");
-        return INVALID_OPERATION;
-    }
-    if (!(mMeasurementMode & type)) {
-        // measurement type has not been set on this Visualizer
-        ALOGE("Cannot retrieve int measurements, requested measurement mode 0x%x not set(0x%x)",
-                type, mMeasurementMode);
-        return INVALID_OPERATION;
-    }
-    // only peak+RMS measurement supported
-    if ((type != MEASUREMENT_MODE_PEAK_RMS)
-            // for peak+RMS measurement, the results are 2 int32_t values
-            || (number != 2)) {
-        ALOGE("Cannot retrieve int measurements, MEASUREMENT_MODE_PEAK_RMS returns 2 ints, not %d",
-                        number);
-        return BAD_VALUE;
-    }
-
-    status_t status = NO_ERROR;
-    if (mEnabled) {
-        uint32_t replySize = number * sizeof(int32_t);
-        status = command(VISUALIZER_CMD_MEASURE,
-                sizeof(uint32_t)  /*cmdSize*/,
-                &type /*cmdData*/,
-                &replySize, measurements);
-        ALOGV("getMeasurements() command returned %d", status);
-        if ((status == NO_ERROR) && (replySize == 0)) {
-            status = NOT_ENOUGH_DATA;
-        }
-    } else {
-        ALOGV("getMeasurements() disabled");
-        return INVALID_OPERATION;
-    }
-    return status;
-}
-
-status_t Visualizer::getWaveForm(uint8_t *waveform)
-{
-    if (waveform == NULL) {
-        return BAD_VALUE;
-    }
-    if (mCaptureSize == 0) {
-        return NO_INIT;
-    }
-
-    status_t status = NO_ERROR;
-    if (mEnabled) {
-        uint32_t replySize = mCaptureSize;
-        status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform);
-        ALOGV("getWaveForm() command returned %d", status);
-        if ((status == NO_ERROR) && (replySize == 0)) {
-            status = NOT_ENOUGH_DATA;
-        }
-    } else {
-        ALOGV("getWaveForm() disabled");
-        memset(waveform, 0x80, mCaptureSize);
-    }
-    return status;
-}
-
-status_t Visualizer::getFft(uint8_t *fft)
-{
-    if (fft == NULL) {
-        return BAD_VALUE;
-    }
-    if (mCaptureSize == 0) {
-        return NO_INIT;
-    }
-
-    status_t status = NO_ERROR;
-    if (mEnabled) {
-        uint8_t buf[mCaptureSize];
-        status = getWaveForm(buf);
-        if (status == NO_ERROR) {
-            status = doFft(fft, buf);
-        }
-    } else {
-        memset(fft, 0, mCaptureSize);
-    }
-    return status;
-}
-
-status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
-{
-    int32_t workspace[mCaptureSize >> 1];
-    int32_t nonzero = 0;
-
-    for (uint32_t i = 0; i < mCaptureSize; i += 2) {
-        workspace[i >> 1] =
-                ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
-        nonzero |= workspace[i >> 1];
-    }
-
-    if (nonzero) {
-        fixed_fft_real(mCaptureSize >> 1, workspace);
-    }
-
-    for (uint32_t i = 0; i < mCaptureSize; i += 2) {
-        short tmp = workspace[i >> 1] >> 21;
-        while (tmp > 127 || tmp < -128) tmp >>= 1;
-        fft[i] = tmp;
-        tmp = workspace[i >> 1];
-        tmp >>= 5;
-        while (tmp > 127 || tmp < -128) tmp >>= 1;
-        fft[i + 1] = tmp;
-    }
-
-    return NO_ERROR;
-}
-
-void Visualizer::periodicCapture()
-{
-    Mutex::Autolock _l(mCaptureLock);
-    ALOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
-            this, mCaptureCallBack, mCaptureFlags);
-    if (mCaptureCallBack != NULL &&
-        (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
-        mCaptureSize != 0) {
-        uint8_t waveform[mCaptureSize];
-        status_t status = getWaveForm(waveform);
-        if (status != NO_ERROR) {
-            return;
-        }
-        uint8_t fft[mCaptureSize];
-        if (mCaptureFlags & CAPTURE_FFT) {
-            status = doFft(fft, waveform);
-        }
-        if (status != NO_ERROR) {
-            return;
-        }
-        uint8_t *wavePtr = NULL;
-        uint8_t *fftPtr = NULL;
-        uint32_t waveSize = 0;
-        uint32_t fftSize = 0;
-        if (mCaptureFlags & CAPTURE_WAVEFORM) {
-            wavePtr = waveform;
-            waveSize = mCaptureSize;
-        }
-        if (mCaptureFlags & CAPTURE_FFT) {
-            fftPtr = fft;
-            fftSize = mCaptureSize;
-        }
-        mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
-    }
-}
-
-uint32_t Visualizer::initCaptureSize()
-{
-    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
-    effect_param_t *p = (effect_param_t *)buf32;
-
-    p->psize = sizeof(uint32_t);
-    p->vsize = sizeof(uint32_t);
-    *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
-    status_t status = getParameter(p);
-
-    if (status == NO_ERROR) {
-        status = p->status;
-    }
-
-    uint32_t size = 0;
-    if (status == NO_ERROR) {
-        size = *((int32_t *)p->data + 1);
-    }
-    mCaptureSize = size;
-
-    ALOGV("initCaptureSize size %d status %d", mCaptureSize, status);
-
-    return size;
-}
-
-void Visualizer::controlStatusChanged(bool controlGranted) {
-    if (controlGranted) {
-        // this Visualizer instance regained control of the effect, reset the scaling mode
-        //   and capture size as has been cached through it.
-        ALOGV("controlStatusChanged(true) causes effect parameter reset:");
-        ALOGV("    scaling mode reset to %d", mScalingMode);
-        setScalingMode(mScalingMode);
-        ALOGV("    capture size reset to %d", mCaptureSize);
-        setCaptureSize(mCaptureSize);
-    }
-    AudioEffect::controlStatusChanged(controlGranted);
-}
-
-//-------------------------------------------------------------------------
-
-Visualizer::CaptureThread::CaptureThread(Visualizer* receiver, uint32_t captureRate,
-        bool bCanCallJava)
-    : Thread(bCanCallJava), mReceiver(receiver)
-{
-    mSleepTimeUs = 1000000000 / captureRate;
-    ALOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
-}
-
-bool Visualizer::CaptureThread::threadLoop()
-{
-    ALOGV("CaptureThread %p enter", this);
-    sp<Visualizer> receiver = mReceiver.promote();
-    if (receiver == NULL) {
-        return false;
-    }
-    while (!exitPending())
-    {
-        usleep(mSleepTimeUs);
-        receiver->periodicCapture();
-    }
-    ALOGV("CaptureThread %p exiting", this);
-    return false;
-}
-
-} // namespace android
diff --git a/media/libmedia/include/media/Visualizer.h b/media/libmedia/include/media/Visualizer.h
deleted file mode 100644
index 8078e36..0000000
--- a/media/libmedia/include/media/Visualizer.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIA_VISUALIZER_H
-#define ANDROID_MEDIA_VISUALIZER_H
-
-#include <media/AudioEffect.h>
-#include <system/audio_effects/effect_visualizer.h>
-#include <utils/Thread.h>
-
-/**
- * The Visualizer class enables application to retrieve part of the currently playing audio for
- * visualization purpose. It is not an audio recording interface and only returns partial and low
- * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use
- * of the visualizer requires the permission android.permission.RECORD_AUDIO.
- * The audio session ID passed to the constructor indicates which audio content should be
- * visualized:
- * - If the session is 0, the audio output mix is visualized
- * - If the session is not 0, the audio from a particular MediaPlayer or AudioTrack
- *   using this audio session is visualized
- * Two types of representation of audio content can be captured:
- * - Waveform data: consecutive 8-bit (unsigned) mono samples by using the getWaveForm() method
- * - Frequency data: 8-bit magnitude FFT by using the getFft() method
- *
- * The length of the capture can be retrieved or specified by calling respectively
- * getCaptureSize() and setCaptureSize() methods. Note that the size of the FFT
- * is half of the specified capture size but both sides of the spectrum are returned yielding in a
- * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
- * returned by getMinCaptureSize() and getMaxCaptureSize().
- * In addition to the polling capture mode, a callback mode is also available by installing a
- * callback function by use of the setCaptureCallBack() method. The rate at which the callback
- * is called as well as the type of data returned is specified.
- * Before capturing data, the Visualizer must be enabled by calling the setEnabled() method.
- * When data capture is not needed any more, the Visualizer should be disabled.
- */
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class Visualizer: public AudioEffect {
-public:
-
-    enum callback_flags {
-        CAPTURE_WAVEFORM = 0x00000001,  // capture callback returns a PCM wave form
-        CAPTURE_FFT = 0x00000002,       // apture callback returns a frequency representation
-        CAPTURE_CALL_JAVA = 0x00000004  // the callback thread can call java
-    };
-
-
-    /* Constructor.
-     * See AudioEffect constructor for details on parameters.
-     */
-                        Visualizer(const String16& opPackageName,
-                                   int32_t priority = 0,
-                                   effect_callback_t cbf = NULL,
-                                   void* user = NULL,
-                                   audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX);
-
-                        ~Visualizer();
-
-    virtual status_t    setEnabled(bool enabled);
-
-    // maximum capture size in samples
-    static uint32_t getMaxCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MAX; }
-    // minimum capture size in samples
-    static uint32_t getMinCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MIN; }
-    // maximum capture rate in millihertz
-    static uint32_t getMaxCaptureRate() { return CAPTURE_RATE_MAX; }
-
-    // callback used to return periodic PCM or FFT captures to the application. Either one or both
-    // types of data are returned (PCM and FFT) according to flags indicated when installing the
-    // callback. When a type of data is not present, the corresponding size (waveformSize or
-    // fftSize) is 0.
-    typedef void (*capture_cbk_t)(void* user,
-                                    uint32_t waveformSize,
-                                    uint8_t *waveform,
-                                    uint32_t fftSize,
-                                    uint8_t *fft,
-                                    uint32_t samplingrate);
-
-    // install a callback to receive periodic captures. The capture rate is specified in milliHertz
-    // and the capture format is according to flags  (see callback_flags).
-    status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate);
-
-    // set the capture size capture size must be a power of two in the range
-    // [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN]
-    // must be called when the visualizer is not enabled
-    status_t setCaptureSize(uint32_t size);
-    uint32_t getCaptureSize() { return mCaptureSize; }
-
-    // returns the capture rate indicated when installing the callback
-    uint32_t getCaptureRate() { return mCaptureRate; }
-
-    // returns the sampling rate of the audio being captured
-    uint32_t getSamplingRate() { return mSampleRate; }
-
-    // set the way volume affects the captured data
-    // mode must one of VISUALIZER_SCALING_MODE_NORMALIZED,
-    //  VISUALIZER_SCALING_MODE_AS_PLAYED
-    status_t setScalingMode(uint32_t mode);
-    uint32_t getScalingMode() { return mScalingMode; }
-
-    // set which measurements are done on the audio buffers processed by the effect.
-    // valid measurements (mask): MEASUREMENT_MODE_PEAK_RMS
-    status_t setMeasurementMode(uint32_t mode);
-    uint32_t getMeasurementMode() { return mMeasurementMode; }
-
-    // return a set of int32_t measurements
-    status_t getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements);
-
-    // return a capture in PCM 8 bit unsigned format. The size of the capture is equal to
-    // getCaptureSize()
-    status_t getWaveForm(uint8_t *waveform);
-
-    // return a capture in FFT 8 bit signed format. The size of the capture is equal to
-    // getCaptureSize() but the length of the FFT is half of the size (both parts of the spectrum
-    // are returned
-    status_t getFft(uint8_t *fft);
-    void release();
-
-protected:
-    // from IEffectClient
-    virtual void controlStatusChanged(bool controlGranted);
-
-private:
-
-    static const uint32_t CAPTURE_RATE_MAX = 20000;
-    static const uint32_t CAPTURE_RATE_DEF = 10000;
-    static const uint32_t CAPTURE_SIZE_DEF = VISUALIZER_CAPTURE_SIZE_MAX;
-
-    /* internal class to handle the callback */
-    class CaptureThread : public Thread
-    {
-    public:
-        CaptureThread(Visualizer* visualizer, uint32_t captureRate, bool bCanCallJava = false);
-
-    private:
-        friend class Visualizer;
-        virtual bool        threadLoop();
-        wp<Visualizer> mReceiver;
-        Mutex       mLock;
-        uint32_t mSleepTimeUs;
-    };
-
-    status_t doFft(uint8_t *fft, uint8_t *waveform);
-    void periodicCapture();
-    uint32_t initCaptureSize();
-
-    Mutex mCaptureLock;
-    uint32_t mCaptureRate;
-    uint32_t mCaptureSize;
-    uint32_t mSampleRate;
-    uint32_t mScalingMode;
-    uint32_t mMeasurementMode;
-    capture_cbk_t mCaptureCallBack;
-    void *mCaptureCbkUser;
-    sp<CaptureThread> mCaptureThread;
-    uint32_t mCaptureFlags;
-};
-
-
-}; // namespace android
-
-#endif // ANDROID_MEDIA_VISUALIZER_H
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index f17520a..00e3443 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -784,7 +784,7 @@
         return;
     }
 
-    int64_t nextSubTimeUs;
+    int64_t nextSubTimeUs = 0;
     readBuffer(type, -1, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, &nextSubTimeUs);
 
     sp<ABuffer> buffer;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index d198d39..d1b96e3 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2403,7 +2403,7 @@
         }
         rate = (OMX_U32)(rateFloat * 65536.0f + 0.5f);
     } else {
-        if (rateFloat > UINT_MAX) {
+        if (rateFloat > static_cast<float>(UINT_MAX)) {
             return BAD_VALUE;
         }
         rate = (OMX_U32)(rateFloat);
@@ -3309,6 +3309,7 @@
     { MEDIA_MIMETYPE_VIDEO_VP9, OMX_VIDEO_CodingVP9 },
     { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, OMX_VIDEO_CodingDolbyVision },
     { MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, OMX_VIDEO_CodingImageHEIC },
+    { MEDIA_MIMETYPE_VIDEO_AV1, OMX_VIDEO_CodingAV1 },
 };
 
 static status_t GetVideoCodingTypeFromMime(
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 9e5a779..08f690b 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -725,12 +725,6 @@
     }
     converter.setSrcColorSpace(standard, range, transfer);
 
-    int32_t dstLeft, dstTop, dstRight, dstBottom;
-    dstLeft = mTilesDecoded % mGridCols * width;
-    dstTop = mTilesDecoded / mGridCols * height;
-    dstRight = dstLeft + width - 1;
-    dstBottom = dstTop + height - 1;
-
     int32_t crop_left, crop_top, crop_right, crop_bottom;
     if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
         crop_left = crop_top = 0;
@@ -738,15 +732,25 @@
         crop_bottom = height - 1;
     }
 
+    int32_t crop_width, crop_height;
+    crop_width = crop_right - crop_left + 1;
+    crop_height = crop_bottom - crop_top + 1;
+
+    int32_t dstLeft, dstTop, dstRight, dstBottom;
+    dstLeft = mTilesDecoded % mGridCols * crop_width;
+    dstTop = mTilesDecoded / mGridCols * crop_height;
+    dstRight = dstLeft + crop_width - 1;
+    dstBottom = dstTop + crop_height - 1;
+
     // apply crop on bottom-right
     // TODO: need to move this into the color converter itself.
     if (dstRight >= mWidth) {
-        crop_right = mWidth - dstLeft - 1;
-        dstRight = dstLeft + crop_right;
+        crop_right = crop_left + mWidth - dstLeft - 1;
+        dstRight = mWidth - 1;
     }
     if (dstBottom >= mHeight) {
-        crop_bottom = mHeight - dstTop - 1;
-        dstBottom = dstTop + crop_bottom;
+        crop_bottom = crop_top + mHeight - dstTop - 1;
+        dstBottom = mHeight - 1;
     }
 
     *done = (++mTilesDecoded >= mTargetTiles);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 2f13dc9..f130c9b 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1635,8 +1635,13 @@
         return BAD_VALUE;
     }
 
+    // Increase moovExtraSize once only irrespective of how many times
+    // setCaptureRate is called.
+    bool containsCaptureFps = mMetaKeys->contains(kMetaKey_CaptureFps);
     mMetaKeys->setFloat(kMetaKey_CaptureFps, captureFps);
-    mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32;
+    if (!containsCaptureFps) {
+        mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32;
+    }
 
     return OK;
 }
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
index 4f9bc6d..24608a7 100644
--- a/media/libstagefright/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -281,7 +281,7 @@
             it = mTimers.erase(it);
         } else {
             if (mPlaybackRate != 0.0
-                && (double)diffMediaUs < INT64_MAX * (double)mPlaybackRate) {
+                && (double)diffMediaUs < (double)INT64_MAX * (double)mPlaybackRate) {
                 int64_t targetRealUs = diffMediaUs / (double)mPlaybackRate;
                 if (targetRealUs < nextLapseRealUs) {
                     nextLapseRealUs = targetRealUs;
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index 9ba2add..7ebdb1a 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -96,10 +96,18 @@
 
     sp<MediaAdapter> newTrack = new MediaAdapter(trackMeta);
     status_t result = mWriter->addSource(newTrack);
-    if (result == OK) {
-        return mTrackList.add(newTrack);
+    if (result != OK) {
+        return -1;
     }
-    return -1;
+    float captureFps = -1.0;
+    if (format->findAsFloat("time-lapse-fps", &captureFps)) {
+        ALOGV("addTrack() time-lapse-fps: %f", captureFps);
+        result = mWriter->setCaptureRate(captureFps);
+        if (result != OK) {
+            ALOGW("addTrack() setCaptureRate failed :%d", result);
+        }
+    }
+    return mTrackList.add(newTrack);
 }
 
 status_t MediaMuxer::setOrientationHint(int degrees) {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index bda6053..02e8ab5 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -689,6 +689,7 @@
         { "temporal-layer-id", kKeyTemporalLayerId },
         { "thumbnail-width", kKeyThumbnailWidth },
         { "thumbnail-height", kKeyThumbnailHeight },
+        { "track-id", kKeyTrackID },
         { "valid-samples", kKeyValidSamples },
     }
 };
@@ -896,12 +897,6 @@
         msg->setInt32("is-sync-frame", 1);
     }
 
-    // this only needs to be translated from meta to message as it is an extractor key
-    int32_t trackID;
-    if (meta->findInt32(kKeyTrackID, &trackID)) {
-        msg->setInt32("track-id", trackID);
-    }
-
     const char *lang;
     if (meta->findCString(kKeyMediaLanguage, &lang)) {
         msg->setString("language", lang);
@@ -1806,7 +1801,7 @@
     if (msg->findInt32("frame-rate", &fps) && fps > 0) {
         meta->setInt32(kKeyFrameRate, fps);
     } else if (msg->findFloat("frame-rate", &fpsFloat)
-            && fpsFloat >= 1 && fpsFloat <= INT32_MAX) {
+            && fpsFloat >= 1 && static_cast<int32_t>(fpsFloat) <= INT32_MAX) {
         // truncate values to distinguish between e.g. 24 vs 23.976 fps
         meta->setInt32(kKeyFrameRate, (int32_t)fpsFloat);
     }
diff --git a/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h b/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
index adb0dd4..f9d91b1 100644
--- a/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
+++ b/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
@@ -44,7 +44,7 @@
 #endif
 
 #include "pvmp3_audio_type_defs.h"
-#define Qfmt_31(a)   (Int32)((float)(a)*0x7FFFFFFF)
+#define Qfmt_31(a)   (Int32)((float)(a)*(float)0x7FFFFFFF)
 
 #define Qfmt15(x)   (Int16)((x)*((Int32)1<<15) + ((x)>=0?0.5F:-0.5F))
 
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
index af738ba..a4f798e 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
@@ -169,7 +169,7 @@
 
     int32 i, j;
 
-    *used_freq_lines = fxp_mul32_Q32(*used_freq_lines << 16, (int32)(0x7FFFFFFF / (float)18 - 1.0f)) >> 15;
+    *used_freq_lines = fxp_mul32_Q32(*used_freq_lines << 16, (int32)((float)0x7FFFFFFF / 18.0f - 1.0f)) >> 15;
 
 
     if (gr_info->window_switching_flag &&  gr_info->block_type == 2)
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
index bbb247d..9cd0e91 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
@@ -77,7 +77,7 @@
 ; Include all pre-processor statements here. Include conditional
 ; compile variables also.
 ----------------------------------------------------------------------------*/
-#define Qfmt31(a)   (int32)((a)*(0x7FFFFFFF))
+#define Qfmt31(a)   (int32)((a)*((float)0x7FFFFFFF))
 
 #define cos_pi_9    Qfmt31( 0.93969262078591f)
 #define cos_2pi_9   Qfmt31( 0.76604444311898f)
diff --git a/media/libstagefright/id3/Android.bp b/media/libstagefright/id3/Android.bp
index d9704a6..c8173cf 100644
--- a/media/libstagefright/id3/Android.bp
+++ b/media/libstagefright/id3/Android.bp
@@ -4,6 +4,7 @@
     srcs: ["ID3.cpp"],
 
     header_libs: [
+        "libmedia_headers",
         "media_ndk_headers",
     ],
 
diff --git a/media/libstagefright/include/media/stagefright/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h
index 09639e2..6f48c5d 100644
--- a/media/libstagefright/include/media/stagefright/MediaErrors.h
+++ b/media/libstagefright/include/media/stagefright/MediaErrors.h
@@ -99,7 +99,13 @@
     ERROR_CAS_DEVICE_REVOKED                 = CAS_ERROR_BASE - 9,
     ERROR_CAS_RESOURCE_BUSY                  = CAS_ERROR_BASE - 10,
     ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = CAS_ERROR_BASE - 11,
-    ERROR_CAS_LAST_USED_ERRORCODE            = CAS_ERROR_BASE - 11,
+    ERROR_CAS_NEED_ACTIVATION                = CAS_ERROR_BASE - 12,
+    ERROR_CAS_NEED_PAIRING                   = CAS_ERROR_BASE - 13,
+    ERROR_CAS_NO_CARD                        = CAS_ERROR_BASE - 14,
+    ERROR_CAS_CARD_MUTE                      = CAS_ERROR_BASE - 15,
+    ERROR_CAS_CARD_INVALID                   = CAS_ERROR_BASE - 16,
+    ERROR_CAS_BLACKOUT                       = CAS_ERROR_BASE - 17,
+    ERROR_CAS_LAST_USED_ERRORCODE            = CAS_ERROR_BASE - 17,
 
     ERROR_CAS_VENDOR_MAX                     = CAS_ERROR_BASE - 500,
     ERROR_CAS_VENDOR_MIN                     = CAS_ERROR_BASE - 999,
diff --git a/media/libstagefright/include/media/stagefright/MediaWriter.h b/media/libstagefright/include/media/stagefright/MediaWriter.h
index 2c12a87..972ae1d 100644
--- a/media/libstagefright/include/media/stagefright/MediaWriter.h
+++ b/media/libstagefright/include/media/stagefright/MediaWriter.h
@@ -35,6 +35,10 @@
     virtual status_t start(MetaData *params = NULL) = 0;
     virtual status_t stop() = 0;
     virtual status_t pause() = 0;
+    virtual status_t setCaptureRate(float /* captureFps */) {
+        ALOGW("setCaptureRate unsupported");
+        return ERROR_UNSUPPORTED;
+    }
 
     virtual void setMaxFileSize(int64_t bytes) { mMaxFileSizeLimitBytes = bytes; }
     virtual void setMaxFileDuration(int64_t durationUs) { mMaxFileDurationLimitUs = durationUs; }
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index cac1af9..bb66f4c 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -954,7 +954,7 @@
     CHECK_GE(space2, 0);
 
     method->setTo(request, 0, space1);
-    url->setTo(request, space1 + 1, space2 - space1);
+    url->setTo(request, space1 + 1, space2 - space1 - 1);
 }
 
 void ARTSPConnection::addAuthentication(AString *request) {
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index 9f3e807..2cebe8f 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -34,6 +34,7 @@
     ],
 
     header_libs: [
+        "libmedia_headers",
         "media_ndk_headers",
     ],
 }
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 61f9014..aac6d71 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -149,6 +149,10 @@
         "-Wall",
     ],
 
+    header_libs: [
+        "libmedia_headers",
+    ],
+
     shared_libs: [
     ],
 
diff --git a/media/ndk/include/media/NdkImage.h b/media/ndk/include/media/NdkImage.h
index 3e60de0..62b8624 100644
--- a/media/ndk/include/media/NdkImage.h
+++ b/media/ndk/include/media/NdkImage.h
@@ -570,6 +570,8 @@
  * return {@link AMEDIA_ERROR_INVALID_OBJECT}. Application still needs to call this method on those
  * {@link AImage} objects to fully delete the {@link AImage} object from memory.</p>
  *
+ * Available since API level 24.
+ *
  * @param image The {@link AImage} to be deleted.
  */
 void AImage_delete(AImage* image) __INTRODUCED_IN(24);
@@ -577,6 +579,8 @@
 /**
  * Query the width of the input {@link AImage}.
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param width the width of the image will be filled here if the method call succeeeds.
  *
@@ -591,6 +595,8 @@
 /**
  * Query the height of the input {@link AImage}.
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param height the height of the image will be filled here if the method call succeeeds.
  *
@@ -607,6 +613,8 @@
  *
  * <p>The format value will be one of AIMAGE_FORMAT_* enum value.</p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param format the format of the image will be filled here if the method call succeeeds.
  *
@@ -624,6 +632,8 @@
  * <p>The crop rectangle specifies the region of valid pixels in the image, using coordinates in the
  * largest-resolution plane.</p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param rect the cropped rectangle of the image will be filled here if the method call succeeeds.
  *
@@ -648,6 +658,8 @@
  * {@link ACameraCaptureSession_captureCallbacks#onCaptureCompleted} callback.
  * </p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param timestampNs the timestamp of the image will be filled here if the method call succeeeds.
  *
@@ -665,6 +677,8 @@
  * <p>The number of plane of an {@link AImage} is determined by its format, which can be queried by
  * {@link AImage_getFormat} method.</p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param numPlanes the number of planes of the image will be filled here if the method call
  *         succeeeds.
@@ -687,6 +701,8 @@
  * being returned.
  * For formats where pixel stride is well defined, the pixel stride is always greater than 0.</p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param planeIdx the index of the plane. Must be less than the number of planes of input image.
  * @param pixelStride the pixel stride of the image will be filled here if the method call succeeeds.
@@ -714,6 +730,8 @@
  * being returned.
  * For formats where row stride is well defined, the row stride is always greater than 0.</p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param planeIdx the index of the plane. Must be less than the number of planes of input image.
  * @param rowStride the row stride of the image will be filled here if the method call succeeeds.
@@ -739,6 +757,8 @@
  * pointer from previous AImage_getPlaneData call becomes invalid. Do NOT use it after the
  * {@link AImage} or the parent {@link AImageReader} is deleted.</p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param planeIdx the index of the plane. Must be less than the number of planes of input image.
  * @param data the data pointer of the image will be filled here if the method call succeeeds.
@@ -769,6 +789,8 @@
  * signal the release of the hardware buffer back to the {@link AImageReader}'s queue using
  * releaseFenceFd.</p>
  *
+ * Available since API level 26.
+ *
  * @param image The {@link AImage} to be deleted.
  * @param releaseFenceFd A sync fence fd defined in {@link sync.h}, which signals the release of
  *         underlying {@link AHardwareBuffer}.
@@ -794,6 +816,8 @@
  * {@link AImageReader_setBufferRemovedListener} to be notified when the buffer is no longer used
  * by {@link AImageReader}.</p>
  *
+ * Available since API level 26.
+ *
  * @param image the {@link AImage} of interest.
  * @param outBuffer The memory area pointed to by buffer will contain the acquired AHardwareBuffer
  *         handle.
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index e5d863c..600ffc9 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -67,6 +67,8 @@
  * The valid sizes and formats depend on the source of the image data.
  * </p>
  *
+ * Available since API level 24.
+ *
  * @param width The default width in pixels of the Images that this reader will produce.
  * @param height The default height in pixels of the Images that this reader will produce.
  * @param format The format of the Image that this reader will produce. This must be one of the
@@ -101,6 +103,8 @@
  * making any of data pointers obtained from {@link AImage_getPlaneData} invalid. Do NOT access
  * the reader object or any of those data pointers after this method returns.</p>
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader to be deleted.
  */
 void AImageReader_delete(AImageReader* reader) __INTRODUCED_IN(24);
@@ -108,6 +112,8 @@
 /**
  * Get a {@link ANativeWindow} that can be used to produce {@link AImage} for this image reader.
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param window The output {@link ANativeWindow} will be filled here if the method call succeeds.
  *                The {@link ANativeWindow} is managed by this image reader. Do NOT call
@@ -126,6 +132,8 @@
  * {@link ANativeWindow}. If so, the actual width of the images can be found using
  * {@link AImage_getWidth}.</p>
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param width the default width of the reader will be filled here if the method call succeeeds.
  *
@@ -142,6 +150,8 @@
  * {@link ANativeWindow}. If so, the actual height of the images can be found using
  * {@link AImage_getHeight}.</p>
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param height the default height of the reader will be filled here if the method call succeeeds.
  *
@@ -154,6 +164,8 @@
 /**
  * Query the format of the {@link AImage} generated by this reader.
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param format the fromat of the reader will be filled here if the method call succeeeds. The
  *                value will be one of the AIMAGE_FORMAT_* enum value defiend in {@link NdkImage.h}.
@@ -167,6 +179,8 @@
 /**
  * Query the maximum number of concurrently acquired {@link AImage}s of this reader.
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param maxImages the maximum number of concurrently acquired images of the reader will be filled
  *                here if the method call succeeeds.
@@ -197,6 +211,8 @@
  * {@link AImage_delete}.
  * </p>
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param image the acquired {@link AImage} will be filled here if the method call succeeeds.
  *
@@ -214,7 +230,6 @@
 media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) __INTRODUCED_IN(24);
 
 /**
-
  * Acquire the latest {@link AImage} from the image reader's queue, dropping older images.
  *
  * <p>
@@ -241,6 +256,8 @@
  * {@link AImage_delete}.
  * </p>
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param image the acquired {@link AImage} will be filled here if the method call succeeeds.
  *
@@ -290,6 +307,8 @@
  *
  * Calling this method will replace previously registered listeners.
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param listener The {@link AImageReader_ImageListener} to be registered. Set this to NULL if
  *                 the application no longer needs to listen to new images.
@@ -356,6 +375,9 @@
  *   {@link AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE}, or combined</td>
  * </tr>
  * </table>
+ *
+ * Available since API level 26.
+ *
  * @return <ul>
  *         <li>{@link AMEDIA_OK} if the method call succeeds.</li>
  *         <li>{@link AMEDIA_ERROR_INVALID_PARAMETER} if reader is NULL, or one or more of width,
@@ -377,6 +399,8 @@
  * additional parameter for the sync fence. All other parameters and the return values are
  * identical to those passed to {@link AImageReader_acquireNextImage}.</p>
  *
+ * Available since API level 26.
+ *
  * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
  *         buffer is ready to consume. When synchronization fence is not needed, fence will be set
  *         to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
@@ -397,6 +421,8 @@
  * additional parameter for the sync fence. All other parameters and the return values are
  * identical to those passed to {@link AImageReader_acquireLatestImage}.</p>
  *
+ * Available since API level 26.
+ *
  * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
  *         buffer is ready to consume. When synchronization fence is not needed, fence will be set
  *         to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
@@ -408,6 +434,7 @@
  */
 media_status_t AImageReader_acquireLatestImageAsync(
         AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) __INTRODUCED_IN(26);
+
 /**
  * Signature of the callback which is called when {@link AImageReader} is about to remove a buffer.
  *
@@ -451,6 +478,8 @@
  *
  * <p>Note that calling this method will replace previously registered listeners.</p>
  *
+ * Available since API level 26.
+ *
  * @param reader The image reader of interest.
  * @param listener the {@link AImageReader_BufferRemovedListener} to be registered. Set this to
  * NULL if application no longer needs to listen to buffer removed events.
diff --git a/media/ndk/include/media/NdkMediaCodec.h b/media/ndk/include/media/NdkMediaCodec.h
index b3ee853..1823fbc 100644
--- a/media/ndk/include/media/NdkMediaCodec.h
+++ b/media/ndk/include/media/NdkMediaCodec.h
@@ -127,27 +127,37 @@
  * Create codec by name. Use this if you know the exact codec you want to use.
  * When configuring, you will need to specify whether to use the codec as an
  * encoder or decoder.
+ *
+ * Available since API level 21.
  */
 AMediaCodec* AMediaCodec_createCodecByName(const char *name) __INTRODUCED_IN(21);
 
 /**
  * Create codec by mime type. Most applications will use this, specifying a
  * mime type obtained from media extractor.
+ *
+ * Available since API level 21.
  */
 AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) __INTRODUCED_IN(21);
 
 /**
  * Create encoder by name.
+ *
+ * Available since API level 21.
  */
 AMediaCodec* AMediaCodec_createEncoderByType(const char *mime_type) __INTRODUCED_IN(21);
 
 /**
- * delete the codec and free its resources
+ * Delete the codec and free its resources.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_delete(AMediaCodec*) __INTRODUCED_IN(21);
 
 /**
  * Configure the codec. For decoding you would typically get the format from an extractor.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_configure(
         AMediaCodec*,
@@ -159,29 +169,39 @@
 /**
  * Start the codec. A codec must be configured before it can be started, and must be started
  * before buffers can be sent to it.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_start(AMediaCodec*) __INTRODUCED_IN(21);
 
 /**
  * Stop the codec.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_stop(AMediaCodec*) __INTRODUCED_IN(21);
 
 /*
  * Flush the codec's input and output. All indices previously returned from calls to
  * AMediaCodec_dequeueInputBuffer and AMediaCodec_dequeueOutputBuffer become invalid.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_flush(AMediaCodec*) __INTRODUCED_IN(21);
 
 /**
  * Get an input buffer. The specified buffer index must have been previously obtained from
  * dequeueInputBuffer, and not yet queued.
+ *
+ * Available since API level 21.
  */
 uint8_t* AMediaCodec_getInputBuffer(AMediaCodec*, size_t idx, size_t *out_size) __INTRODUCED_IN(21);
 
 /**
  * Get an output buffer. The specified buffer index must have been previously obtained from
  * dequeueOutputBuffer, and not yet queued.
+ *
+ * Available since API level 21.
  */
 uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec*, size_t idx, size_t *out_size) __INTRODUCED_IN(21);
 
@@ -189,6 +209,8 @@
  * Get the index of the next available input buffer. An app will typically use this with
  * getInputBuffer() to get a pointer to the buffer, then copy the data to be encoded or decoded
  * into the buffer before passing it to the codec.
+ *
+ * Available since API level 21.
  */
 ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec*, int64_t timeoutUs) __INTRODUCED_IN(21);
 
@@ -218,6 +240,8 @@
 
 /**
  * Send the specified buffer to the codec for processing.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_queueInputBuffer(AMediaCodec*, size_t idx,
                                             _off_t_compat offset, size_t size,
@@ -225,6 +249,8 @@
 
 /**
  * Send the specified buffer to the codec for processing.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_queueSecureInputBuffer(AMediaCodec*, size_t idx,
                                                   _off_t_compat offset,
@@ -235,15 +261,23 @@
 
 /**
  * Get the index of the next available buffer of processed data.
+ *
+ * Available since API level 21.
  */
 ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec*, AMediaCodecBufferInfo *info,
         int64_t timeoutUs) __INTRODUCED_IN(21);
+
+/**
+ * Available since API level 21.
+ */
 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec*) __INTRODUCED_IN(21);
 
 /**
  * If you are done with a buffer, use this call to return the buffer to
  * the codec. If you previously specified a surface when configuring this
  * video decoder you can optionally render the buffer.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render) __INTRODUCED_IN(21);
 
@@ -256,6 +290,8 @@
  *  to ImageReader (software readable) output.
  *
  * For more details, see the Java documentation for MediaCodec.setOutputSurface.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_setOutputSurface(AMediaCodec*, ANativeWindow* surface) __INTRODUCED_IN(21);
 
@@ -266,6 +302,8 @@
  * this call will simply return the buffer to the codec.
  *
  * For more details, see the Java documentation for MediaCodec.releaseOutputBuffer.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_releaseOutputBufferAtTime(
         AMediaCodec *mData, size_t idx, int64_t timestampNs) __INTRODUCED_IN(21);
@@ -282,6 +320,8 @@
  * ANativeWindow_release() when done.
  *
  * For more details, see the Java documentation for MediaCodec.createInputSurface.
+ *
+ * Available since API level 26.
  */
 media_status_t AMediaCodec_createInputSurface(
         AMediaCodec *mData, ANativeWindow **surface) __INTRODUCED_IN(26);
@@ -298,6 +338,8 @@
  * ANativeWindow_release() when done.
  *
  * For more details, see the Java documentation for MediaCodec.createPersistentInputSurface.
+ *
+ * Available since API level 26.
  */
 media_status_t AMediaCodec_createPersistentInputSurface(
         ANativeWindow **surface) __INTRODUCED_IN(26);
@@ -311,6 +353,8 @@
  * AMediaCodec_configure(..); and before AMediaCodec_start() has been called.
  *
  * For more details, see the Java documentation for MediaCodec.setInputSurface.
+ *
+ * Available since API level 26.
  */
 media_status_t AMediaCodec_setInputSurface(
         AMediaCodec *mData, ANativeWindow *surface) __INTRODUCED_IN(26);
@@ -322,6 +366,8 @@
  * after AMediaCodec_start() has been called.
  *
  * NOTE: Some of these parameter changes may silently fail to apply.
+ *
+ * Available since API level 26.
  */
 media_status_t AMediaCodec_setParameters(
         AMediaCodec *mData, const AMediaFormat* params) __INTRODUCED_IN(26);
@@ -339,6 +385,8 @@
  * Returns AMEDIA_OK when completed succesfully.
  *
  * For more details, see the Java documentation for MediaCodec.signalEndOfInputStream.
+ *
+ * Available since API level 26.
  */
 media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData) __INTRODUCED_IN(26);
 
@@ -349,6 +397,8 @@
 /**
  * Get format of the buffer. The specified buffer index must have been previously obtained from
  * dequeueOutputBuffer.
+ *
+ * Available since API level 28.
  */
 AMediaFormat* AMediaCodec_getBufferFormat(AMediaCodec*, size_t index) __INTRODUCED_IN(28);
 
@@ -356,11 +406,15 @@
  * Get the component name. If the codec was created by createDecoderByType
  * or createEncoderByType, what component is chosen is not known beforehand.
  * Caller shall call AMediaCodec_releaseName to free the returned pointer.
+ *
+ * Available since API level 28.
  */
 media_status_t AMediaCodec_getName(AMediaCodec*, char** out_name) __INTRODUCED_IN(28);
 
 /**
  * Free the memory pointed by name which is returned by AMediaCodec_getName.
+ *
+ * Available since API level 28.
  */
 void AMediaCodec_releaseName(AMediaCodec*, char* name) __INTRODUCED_IN(28);
 
@@ -382,6 +436,8 @@
  * All callbacks are fired on one NDK internal thread.
  * AMediaCodec_setAsyncNotifyCallback should not be called on the callback thread.
  * No heavy duty task should be performed on callback thread.
+ *
+ * Available since API level 28.
  */
 media_status_t AMediaCodec_setAsyncNotifyCallback(
         AMediaCodec*,
@@ -390,6 +446,8 @@
 
 /**
  * Release the crypto if applicable.
+ *
+ * Available since API level 28.
  */
 media_status_t AMediaCodec_releaseCrypto(AMediaCodec*) __INTRODUCED_IN(28);
 
@@ -397,12 +455,16 @@
  * Call this after AMediaCodec_configure() returns successfully to get the input
  * format accepted by the codec. Do this to determine what optional configuration
  * parameters were supported by the codec.
+ *
+ * Available since API level 28.
  */
 AMediaFormat* AMediaCodec_getInputFormat(AMediaCodec*) __INTRODUCED_IN(28);
 
 /**
  * Returns true if the codec cannot proceed further, but can be recovered by stopping,
  * configuring, and starting again.
+ *
+ * Available since API level 28.
  */
 bool AMediaCodecActionCode_isRecoverable(int32_t actionCode) __INTRODUCED_IN(28);
 
@@ -410,6 +472,8 @@
  * Returns true if the codec error is a transient issue, perhaps due to
  * resource constraints, and that the method (or encoding/decoding) may be
  * retried at a later time.
+ *
+ * Available since API level 28.
  */
 bool AMediaCodecActionCode_isTransient(int32_t actionCode) __INTRODUCED_IN(28);
 
@@ -440,6 +504,8 @@
  * numBytesOfClearData can be null to indicate that all data is encrypted.
  * This information encapsulates per-sample metadata as outlined in
  * ISO/IEC FDIS 23001-7:2011 "Common encryption in ISO base media file format files".
+ *
+ * Available since API level 21.
  */
 AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
         int numsubsamples,
@@ -450,13 +516,17 @@
         size_t *encryptedbytes) __INTRODUCED_IN(21);
 
 /**
- * delete an AMediaCodecCryptoInfo created previously with AMediaCodecCryptoInfo_new, or
- * obtained from AMediaExtractor
+ * Delete an AMediaCodecCryptoInfo created previously with AMediaCodecCryptoInfo_new, or
+ * obtained from AMediaExtractor.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*) __INTRODUCED_IN(21);
 
 /**
- * Set the crypto pattern on an AMediaCryptoInfo object
+ * Set the crypto pattern on an AMediaCryptoInfo object.
+ *
+ * Available since API level 21.
  */
 void AMediaCodecCryptoInfo_setPattern(
         AMediaCodecCryptoInfo *info,
@@ -464,32 +534,44 @@
 
 /**
  * The number of subsamples that make up the buffer's contents.
+ *
+ * Available since API level 21.
  */
 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo*) __INTRODUCED_IN(21);
 
 /**
- * A 16-byte opaque key
+ * A 16-byte opaque key.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo*, uint8_t *dst) __INTRODUCED_IN(21);
 
 /**
- * A 16-byte initialization vector
+ * A 16-byte initialization vector.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo*, uint8_t *dst) __INTRODUCED_IN(21);
 
 /**
  * The type of encryption that has been applied,
  * one of AMEDIACODECRYPTOINFO_MODE_CLEAR or AMEDIACODECRYPTOINFO_MODE_AES_CTR.
+ *
+ * Available since API level 21.
  */
 cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo*) __INTRODUCED_IN(21);
 
 /**
  * The number of leading unencrypted bytes in each subsample.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo*, size_t *dst) __INTRODUCED_IN(21);
 
 /**
  * The number of trailing encrypted bytes in each subsample.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo*, size_t *dst) __INTRODUCED_IN(21);
 
diff --git a/media/ndk/include/media/NdkMediaCrypto.h b/media/ndk/include/media/NdkMediaCrypto.h
index bcdf9a0..3fa07c7 100644
--- a/media/ndk/include/media/NdkMediaCrypto.h
+++ b/media/ndk/include/media/NdkMediaCrypto.h
@@ -49,12 +49,24 @@
 
 #if __ANDROID_API__ >= 21
 
+/**
+ * Available since API level 21.
+ */
 bool AMediaCrypto_isCryptoSchemeSupported(const AMediaUUID uuid) __INTRODUCED_IN(21);
 
+/**
+ * Available since API level 21.
+ */
 bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime) __INTRODUCED_IN(21);
 
+/**
+ * Available since API level 21.
+ */
 AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *initData, size_t initDataSize) __INTRODUCED_IN(21);
 
+/**
+ * Available since API level 21.
+ */
 void AMediaCrypto_delete(AMediaCrypto* crypto) __INTRODUCED_IN(21);
 
 #endif /* __ANDROID_API__ >= 21 */
diff --git a/media/ndk/include/media/NdkMediaDataSource.h b/media/ndk/include/media/NdkMediaDataSource.h
index 16b1eb3..0577df2 100644
--- a/media/ndk/include/media/NdkMediaDataSource.h
+++ b/media/ndk/include/media/NdkMediaDataSource.h
@@ -88,6 +88,8 @@
 /**
  * Create new media data source. Returns NULL if memory allocation
  * for the new data source object fails.
+ *
+ * Available since API level 28.
  */
 AMediaDataSource* AMediaDataSource_new() __INTRODUCED_IN(28);
 
@@ -116,6 +118,7 @@
  * ...
  * key_values[(numheaders - 1) * 2]:key_values[(numheaders - 1) * 2 + 1]
  *
+ * Available since API level 29.
  */
 AMediaDataSource* AMediaDataSource_newUri(const char *uri,
         int numheaders,
@@ -125,12 +128,16 @@
 
 /**
  * Delete a previously created media data source.
+ *
+ * Available since API level 28.
  */
 void AMediaDataSource_delete(AMediaDataSource*) __INTRODUCED_IN(28);
 
 /**
  * Set an user provided opaque handle. This opaque handle is passed as
  * the first argument to the data source callbacks.
+ *
+ * Available since API level 28.
  */
 void AMediaDataSource_setUserdata(
         AMediaDataSource*, void *userdata) __INTRODUCED_IN(28);
@@ -145,6 +152,8 @@
  *
  * Please refer to the definition of AMediaDataSourceReadAt for
  * additional details.
+ *
+ * Available since API level 28.
  */
 void AMediaDataSource_setReadAt(
         AMediaDataSource*,
@@ -156,6 +165,8 @@
  *
  * Please refer to the definition of AMediaDataSourceGetSize for
  * additional details.
+ *
+ * Available since API level 28.
  */
 void AMediaDataSource_setGetSize(
         AMediaDataSource*,
@@ -167,6 +178,8 @@
  *
  * Please refer to the definition of AMediaDataSourceClose for
  * additional details.
+ *
+ * Available since API level 28.
  */
 void AMediaDataSource_setClose(
         AMediaDataSource*,
@@ -181,6 +194,8 @@
  *
  * Please refer to the definition of AMediaDataSourceClose for
  * additional details.
+ *
+ * Available since API level 29.
  */
 void AMediaDataSource_close(AMediaDataSource*) __INTRODUCED_IN(29);
 
@@ -191,6 +206,8 @@
  *
  * Please refer to the definition of AMediaDataSourceGetAvailableSize
  * for additional details.
+ *
+ * Available since API level 29.
  */
 void AMediaDataSource_setGetAvailableSize(
         AMediaDataSource*,
diff --git a/media/ndk/include/media/NdkMediaDrm.h b/media/ndk/include/media/NdkMediaDrm.h
index 2e438d9..31f5c7d 100644
--- a/media/ndk/include/media/NdkMediaDrm.h
+++ b/media/ndk/include/media/NdkMediaDrm.h
@@ -174,41 +174,53 @@
  * uuid identifies the universal unique ID of the crypto scheme. uuid must be 16 bytes.
  * mimeType is the MIME type of the media container, e.g. "video/mp4".  If mimeType
  * is not known or required, it can be provided as NULL.
+ *
+ * Available since API level 21.
  */
 bool AMediaDrm_isCryptoSchemeSupported(const uint8_t *uuid,
         const char *mimeType) __INTRODUCED_IN(21);
 
 /**
- * Create a MediaDrm instance from a UUID
+ * Create a MediaDrm instance from a UUID.
  * uuid identifies the universal unique ID of the crypto scheme. uuid must be 16 bytes.
+ *
+ * Available since API level 21.
  */
 AMediaDrm* AMediaDrm_createByUUID(const uint8_t *uuid) __INTRODUCED_IN(21);
 
 /**
- * Release a MediaDrm object
+ * Release a MediaDrm object.
+ *
+ * Available since API level 21.
  */
 void AMediaDrm_release(AMediaDrm *) __INTRODUCED_IN(21);
 
 /**
- * Register a callback to be invoked when an event occurs
+ * Register a callback to be invoked when an event occurs.
  *
- * listener is the callback that will be invoked on event
+ * listener is the callback that will be invoked on event.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_setOnEventListener(AMediaDrm *,
         AMediaDrmEventListener listener) __INTRODUCED_IN(21);
 
 /**
- * Register a callback to be invoked when an expiration update event occurs
+ * Register a callback to be invoked when an expiration update event occurs.
  *
- * listener is the callback that will be invoked on event
+ * listener is the callback that will be invoked on event.
+ *
+ * Available since API level 29.
  */
 media_status_t AMediaDrm_setOnExpirationUpdateListener(AMediaDrm *,
         AMediaDrmExpirationUpdateListener listener) __INTRODUCED_IN(29);
 
 /**
- * Register a callback to be invoked when a key status change event occurs
+ * Register a callback to be invoked when a key status change event occurs.
  *
- * listener is the callback that will be invoked on event
+ * listener is the callback that will be invoked on event.
+ *
+ * Available since API level 29.
  */
 media_status_t AMediaDrm_setOnKeysChangeListener(AMediaDrm *,
         AMediaDrmKeysChangeListener listener) __INTRODUCED_IN(29);
@@ -216,8 +228,10 @@
 /**
  * Open a new session with the MediaDrm object.  A session ID is returned.
  *
- * returns MEDIADRM_NOT_PROVISIONED_ERROR if provisioning is needed
- * returns MEDIADRM_RESOURCE_BUSY_ERROR if required resources are in use
+ * Returns MEDIADRM_NOT_PROVISIONED_ERROR if provisioning is needed.
+ * Returns MEDIADRM_RESOURCE_BUSY_ERROR if required resources are in use.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_openSession(AMediaDrm *,
         AMediaDrmSessionId *sessionId) __INTRODUCED_IN(21);
@@ -225,6 +239,8 @@
 /**
  * Close a session on the MediaDrm object that was previously opened
  * with AMediaDrm_openSession.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_closeSession(AMediaDrm *,
         const AMediaDrmSessionId *sessionId) __INTRODUCED_IN(21);
@@ -272,9 +288,11 @@
  *       MediaDrm object is released.
  *   2. keyRequestSize will be set to the size of the request
  *
- * returns MEDIADRM_NOT_PROVISIONED_ERROR if reprovisioning is needed, due to a
+ * Returns MEDIADRM_NOT_PROVISIONED_ERROR if reprovisioning is needed, due to a
  * problem with the device certificate.
-*/
+ *
+ * Available since API level 21.
+ */
 media_status_t AMediaDrm_getKeyRequest(AMediaDrm *, const AMediaDrmScope *scope,
         const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
         const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
@@ -295,8 +313,9 @@
  *
  * response points to the opaque response from the server
  * responseSize should be set to the size of the response in bytes
+ *
+ * Available since API level 21.
  */
-
 media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *, const AMediaDrmScope *scope,
         const uint8_t *response, size_t responseSize,
         AMediaDrmKeySetId *keySetId) __INTRODUCED_IN(21);
@@ -305,8 +324,10 @@
  * Restore persisted offline keys into a new session.  keySetId identifies the
  * keys to load, obtained from a prior call to AMediaDrm_provideKeyResponse.
  *
- * sessionId is the session ID for the DRM session
- * keySetId identifies the saved key set to restore
+ * sessionId is the session ID for the DRM session.
+ * keySetId identifies the saved key set to restore.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_restoreKeys(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const AMediaDrmKeySetId *keySetId) __INTRODUCED_IN(21);
@@ -314,7 +335,9 @@
 /**
  * Remove the current keys from a session.
  *
- * keySetId identifies keys to remove
+ * keySetId identifies keys to remove.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_removeKeys(AMediaDrm *,
         const AMediaDrmSessionId *keySetId) __INTRODUCED_IN(21);
@@ -331,6 +354,8 @@
  * to the number of entries written to the array.  If the number of {key, value} pairs
  * to be returned is greater than *numPairs, MEDIADRM_SHORT_BUFFER will be returned
  * and numPairs will be set to the number of pairs available.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) __INTRODUCED_IN(21);
@@ -350,6 +375,8 @@
  *    3. serverUrl will reference a NULL terminated string containing the URL
  *       the provisioning request should be sent to.  It will remain accessible until
  *       the next call to getProvisionRequest.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *, const uint8_t **provisionRequest,
         size_t *provisionRequestSize, const char **serverUrl) __INTRODUCED_IN(21);
@@ -363,8 +390,10 @@
  *   DRM engine plugin.
  * responseSize is the length of the provisioning response in bytes.
  *
- * returns MEDIADRM_DEVICE_REVOKED_ERROR if the response indicates that the
+ * Returns MEDIADRM_DEVICE_REVOKED_ERROR if the response indicates that the
  * server rejected the request
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *,
         const uint8_t *response, size_t responseSize) __INTRODUCED_IN(21);
@@ -390,6 +419,8 @@
  * If *numSecureStops is too small for the number of secure stops available,
  * MEDIADRM_SHORT_BUFFER will be returned and *numSecureStops will be set to the
  * number required.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_getSecureStops(AMediaDrm *,
         AMediaDrmSecureStop *secureStops, size_t *numSecureStops) __INTRODUCED_IN(21);
@@ -399,6 +430,8 @@
  * the message, remove the SecureStops identified in the response.
  *
  * ssRelease is the server response indicating which secure stops to release
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *,
         const AMediaDrmSecureStop *ssRelease) __INTRODUCED_IN(21);
@@ -432,6 +465,8 @@
  * On return, propertyValue will be set to point to the property value.  The
  * memory that the value resides in is owned by the NDK MediaDrm API and
  * will remain valid until the next call to AMediaDrm_getPropertyString.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_getPropertyString(AMediaDrm *, const char *propertyName,
         const char **propertyValue) __INTRODUCED_IN(21);
@@ -447,18 +482,24 @@
  * On return, *propertyValue will be set to point to the property value.  The
  * memory that the value resides in is owned by the NDK MediaDrm API and
  * will remain valid until the next call to AMediaDrm_getPropertyByteArray.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *, const char *propertyName,
         AMediaDrmByteArray *propertyValue) __INTRODUCED_IN(21);
 
 /**
  * Set a DRM engine plugin String property value.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_setPropertyString(AMediaDrm *, const char *propertyName,
         const char *value) __INTRODUCED_IN(21);
 
 /**
  * Set a DRM engine plugin byte array property value.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *, const char *propertyName,
         const uint8_t *value, size_t valueSize) __INTRODUCED_IN(21);
@@ -487,6 +528,8 @@
  * ensure that the output buffer is large enough to accept dataSize bytes. The key
  * to use is identified by the 16 byte keyId.  The key must have been loaded into
  * the session using provideKeyResponse.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_encrypt(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
@@ -498,6 +541,8 @@
  * ensure that the output buffer is large enough to accept dataSize bytes.  The key
  * to use is identified by the 16 byte keyId.  The key must have been loaded into
  * the session using provideKeyResponse.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_decrypt(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
@@ -511,6 +556,8 @@
  * *signatureSize is set to the buffer size required.  The key to use is identified
  * by the 16 byte keyId.  The key must have been loaded into the session using
  * provideKeyResponse.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_sign(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
@@ -522,6 +569,8 @@
  * if the signature matches, otherwise MEDAIDRM_VERIFY_FAILED is returned. The key to
  * use is identified by the 16 byte keyId.  The key must have been loaded into the
  * session using provideKeyResponse.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_verify(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
diff --git a/media/ndk/include/media/NdkMediaExtractor.h b/media/ndk/include/media/NdkMediaExtractor.h
index e3d9fe6..14319c4 100644
--- a/media/ndk/include/media/NdkMediaExtractor.h
+++ b/media/ndk/include/media/NdkMediaExtractor.h
@@ -52,23 +52,31 @@
 #if __ANDROID_API__ >= 21
 
 /**
- * Create new media extractor
+ * Create new media extractor.
+ *
+ * Available since API level 21.
  */
 AMediaExtractor* AMediaExtractor_new() __INTRODUCED_IN(21);
 
 /**
- * Delete a previously created media extractor
+ * Delete a previously created media extractor.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaExtractor_delete(AMediaExtractor*) __INTRODUCED_IN(21);
 
 /**
- *  Set the file descriptor from which the extractor will read.
+ * Set the file descriptor from which the extractor will read.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor*, int fd, off64_t offset,
         off64_t length) __INTRODUCED_IN(21);
 
 /**
  * Set the URI from which the extractor will read.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaExtractor_setDataSource(AMediaExtractor*,
         const char *location) __INTRODUCED_IN(21);
@@ -77,6 +85,8 @@
 
 /**
  * Set the custom data source implementation from which the extractor will read.
+ *
+ * Available since API level 28.
  */
 media_status_t AMediaExtractor_setDataSourceCustom(AMediaExtractor*,
         AMediaDataSource *src) __INTRODUCED_IN(28);
@@ -85,11 +95,15 @@
 
 /**
  * Return the number of tracks in the previously specified media file
+ *
+ * Available since API level 21.
  */
 size_t AMediaExtractor_getTrackCount(AMediaExtractor*) __INTRODUCED_IN(21);
 
 /**
  * Return the format of the specified track. The caller must free the returned format
+ *
+ * Available since API level 21.
  */
 AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor*, size_t idx) __INTRODUCED_IN(21);
 
@@ -98,41 +112,55 @@
  * getSampleTime only retrieve information for the subset of tracks selected.
  * Selecting the same track multiple times has no effect, the track is
  * only selected once.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaExtractor_selectTrack(AMediaExtractor*, size_t idx) __INTRODUCED_IN(21);
 
 /**
  * Unselect the specified track. Subsequent calls to readSampleData, getSampleTrackIndex and
- * getSampleTime only retrieve information for the subset of tracks selected..
+ * getSampleTime only retrieve information for the subset of tracks selected.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaExtractor_unselectTrack(AMediaExtractor*, size_t idx) __INTRODUCED_IN(21);
 
 /**
  * Read the current sample.
+ *
+ * Available since API level 21.
  */
 ssize_t AMediaExtractor_readSampleData(AMediaExtractor*,
         uint8_t *buffer, size_t capacity) __INTRODUCED_IN(21);
 
 /**
  * Read the current sample's flags.
+ *
+ * Available since API level 21.
  */
 uint32_t AMediaExtractor_getSampleFlags(AMediaExtractor*) __INTRODUCED_IN(21);
 
 /**
  * Returns the track index the current sample originates from (or -1
  * if no more samples are available)
+ *
+ * Available since API level 21.
  */
 int AMediaExtractor_getSampleTrackIndex(AMediaExtractor*) __INTRODUCED_IN(21);
 
 /**
  * Returns the current sample's presentation time in microseconds.
  * or -1 if no more samples are available.
+ *
+ * Available since API level 21.
  */
 int64_t AMediaExtractor_getSampleTime(AMediaExtractor*) __INTRODUCED_IN(21);
 
 /**
  * Advance to the next sample. Returns false if no more sample data
  * is available (end of stream).
+ *
+ * Available since API level 21.
  */
 bool AMediaExtractor_advance(AMediaExtractor*) __INTRODUCED_IN(21);
 
@@ -143,7 +171,7 @@
 } SeekMode;
 
 /**
- *
+ * Available since API level 21.
  */
 media_status_t AMediaExtractor_seekTo(AMediaExtractor*,
         int64_t seekPosUs, SeekMode mode) __INTRODUCED_IN(21);
@@ -167,10 +195,14 @@
 
 /**
  * Get the PSSH info if present.
+ *
+ * Available since API level 21.
  */
 PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor*) __INTRODUCED_IN(21);
 
-
+/**
+ * Available since API level 21.
+ */
 AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *) __INTRODUCED_IN(21);
 
 enum {
@@ -186,6 +218,8 @@
  *
  * This function will always return a format; however, the format could be empty
  * (no key-value pairs) if the media container does not provide format information.
+ *
+ * Available since API level 28.
  */
 AMediaFormat* AMediaExtractor_getFileFormat(AMediaExtractor*) __INTRODUCED_IN(28);
 
@@ -198,6 +232,7 @@
  * uint8_t *buf = new uint8_t[sampleSize];
  * AMediaExtractor_readSampleData(ex, buf, sampleSize);
  *
+ * Available since API level 28.
  */
 ssize_t AMediaExtractor_getSampleSize(AMediaExtractor*) __INTRODUCED_IN(28);
 
@@ -211,6 +246,8 @@
  * Returns -1 when the extractor is not reading from a network data source, or when the
  * cached duration cannot be calculated (bitrate, duration, and file size information
  * not available).
+ *
+ * Available since API level 28.
  */
 int64_t AMediaExtractor_getCachedDuration(AMediaExtractor *) __INTRODUCED_IN(28);
 
@@ -222,6 +259,8 @@
  * Returns AMEDIA_OK on success or AMEDIA_ERROR_* to indicate failure reason.
  * Existing key-value pairs in |fmt| would be removed if this API returns AMEDIA_OK.
  * The contents of |fmt| is undefined if this API returns AMEDIA_ERROR_*.
+ *
+ * Available since API level 28.
  */
 media_status_t AMediaExtractor_getSampleFormat(AMediaExtractor *ex,
         AMediaFormat *fmt) __INTRODUCED_IN(28);
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index fd43f36..41c2378 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -48,40 +48,78 @@
 
 #if __ANDROID_API__ >= 21
 
+/**
+ * Available since API level 21.
+ */
 AMediaFormat *AMediaFormat_new() __INTRODUCED_IN(21);
+
+/**
+ * Available since API level 21.
+ */
 media_status_t AMediaFormat_delete(AMediaFormat*) __INTRODUCED_IN(21);
 
 /**
  * Human readable representation of the format. The returned string is owned by the format,
  * and remains valid until the next call to toString, or until the format is deleted.
+ *
+ * Available since API level 21.
  */
 const char* AMediaFormat_toString(AMediaFormat*) __INTRODUCED_IN(21);
 
+/**
+ * Available since API level 21.
+ */
 bool AMediaFormat_getInt32(AMediaFormat*, const char *name, int32_t *out) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
 bool AMediaFormat_getInt64(AMediaFormat*, const char *name, int64_t *out) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
 bool AMediaFormat_getFloat(AMediaFormat*, const char *name, float *out) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
 bool AMediaFormat_getSize(AMediaFormat*, const char *name, size_t *out) __INTRODUCED_IN(21);
 /**
  * The returned data is owned by the format and remains valid as long as the named entry
  * is part of the format.
+ *
+ * Available since API level 21.
  */
 bool AMediaFormat_getBuffer(AMediaFormat*, const char *name, void** data, size_t *size) __INTRODUCED_IN(21);
 /**
  * The returned string is owned by the format, and remains valid until the next call to getString,
  * or until the format is deleted.
+ *
+ * Available since API level 21.
  */
 bool AMediaFormat_getString(AMediaFormat*, const char *name, const char **out) __INTRODUCED_IN(21);
 
 
+/**
+ * Available since API level 21.
+ */
 void AMediaFormat_setInt32(AMediaFormat*, const char* name, int32_t value) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
 void AMediaFormat_setInt64(AMediaFormat*, const char* name, int64_t value) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
 void AMediaFormat_setFloat(AMediaFormat*, const char* name, float value) __INTRODUCED_IN(21);
 /**
  * The provided string is copied into the format.
+ *
+ * Available since API level 21.
  */
 void AMediaFormat_setString(AMediaFormat*, const char* name, const char* value) __INTRODUCED_IN(21);
 /**
  * The provided data is copied into the format.
+ *
+ * Available since API level 21.
  */
 void AMediaFormat_setBuffer(AMediaFormat*, const char* name, const void* data, size_t size) __INTRODUCED_IN(21);
 
@@ -155,24 +193,43 @@
 #endif /* __ANDROID_API__ >= 21 */
 
 #if __ANDROID_API__ >= 28
+/**
+ * Available since API level 28.
+ */
 bool AMediaFormat_getDouble(AMediaFormat*, const char *name, double *out) __INTRODUCED_IN(28);
+/**
+ * Available since API level 28.
+ */
 bool AMediaFormat_getRect(AMediaFormat*, const char *name,
         int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) __INTRODUCED_IN(28);
 
+/**
+ * Available since API level 28.
+ */
 void AMediaFormat_setDouble(AMediaFormat*, const char* name, double value) __INTRODUCED_IN(28);
+/**
+ * Available since API level 28.
+ */
 void AMediaFormat_setSize(AMediaFormat*, const char* name, size_t value) __INTRODUCED_IN(28);
+/**
+ * Available since API level 28.
+ */
 void AMediaFormat_setRect(AMediaFormat*, const char* name,
         int32_t left, int32_t top, int32_t right, int32_t bottom) __INTRODUCED_IN(28);
 #endif /* __ANDROID_API__ >= 28 */
 
 #if __ANDROID_API__ >= 29
 /**
- * remove all key/value pairs from the given AMediaFormat
+ * Remove all key/value pairs from the given AMediaFormat.
+ *
+ * Available since API level 29.
  */
 void AMediaFormat_clear(AMediaFormat*) __INTRODUCED_IN(29);
 
 /**
- * copy one AMediaFormat to another
+ * Copy one AMediaFormat to another.
+ *
+ * Available since API level 29.
  */
 media_status_t AMediaFormat_copy(AMediaFormat *to, AMediaFormat *from) __INTRODUCED_IN(29);
 
diff --git a/media/ndk/include/media/NdkMediaMuxer.h b/media/ndk/include/media/NdkMediaMuxer.h
index 7393867..3fdeea4 100644
--- a/media/ndk/include/media/NdkMediaMuxer.h
+++ b/media/ndk/include/media/NdkMediaMuxer.h
@@ -56,12 +56,16 @@
 #if __ANDROID_API__ >= 21
 
 /**
- * Create new media muxer
+ * Create new media muxer.
+ *
+ * Available since API level 21.
  */
 AMediaMuxer* AMediaMuxer_new(int fd, OutputFormat format) __INTRODUCED_IN(21);
 
 /**
- * Delete a previously created media muxer
+ * Delete a previously created media muxer.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaMuxer_delete(AMediaMuxer*) __INTRODUCED_IN(21);
 
@@ -75,6 +79,8 @@
  * Both values are specified in degrees.
  * Latitude must be in the range [-90, 90].
  * Longitude must be in the range [-180, 180].
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaMuxer_setLocation(AMediaMuxer*,
         float latitude, float longitude) __INTRODUCED_IN(21);
@@ -90,6 +96,8 @@
  * during playback.
  * The angle is specified in degrees, clockwise.
  * The supported angles are 0, 90, 180, and 270 degrees.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaMuxer_setOrientationHint(AMediaMuxer*, int degrees) __INTRODUCED_IN(21);
 
@@ -97,18 +105,24 @@
  * Adds a track with the specified format.
  * Returns the index of the new track or a negative value in case of failure,
  * which can be interpreted as a media_status_t.
+ *
+ * Available since API level 21.
  */
 ssize_t AMediaMuxer_addTrack(AMediaMuxer*, const AMediaFormat* format) __INTRODUCED_IN(21);
 
 /**
  * Start the muxer. Should be called after AMediaMuxer_addTrack and
  * before AMediaMuxer_writeSampleData.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaMuxer_start(AMediaMuxer*) __INTRODUCED_IN(21);
 
 /**
  * Stops the muxer.
  * Once the muxer stops, it can not be restarted.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaMuxer_stop(AMediaMuxer*) __INTRODUCED_IN(21);
 
@@ -118,6 +132,8 @@
  * the right tracks. Also, it needs to make sure the samples for each track
  * are written in chronological order (e.g. in the order they are provided
  * by the encoder.)
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaMuxer_writeSampleData(AMediaMuxer *muxer,
         size_t trackIdx, const uint8_t *data,
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index f666ad0..7531578 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -4,7 +4,7 @@
     AImageReader_acquireLatestImageAsync; # introduced=26
     AImageReader_acquireNextImage; # introduced=24
     AImageReader_acquireNextImageAsync; # introduced=26
-    AImageReader_getWindowNativeHandle; #vndk
+    AImageReader_getWindowNativeHandle; # llndk
     AImageReader_delete; # introduced=24
     AImageReader_getFormat; # introduced=24
     AImageReader_getHeight; # introduced=24
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index 2dbc476..63437da 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -47,6 +47,7 @@
 
     header_libs: [
         "bionic_libc_platform_headers",
+        "libmedia_headers",
     ],
 
     local_include_dirs: ["include"],
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9b0872e..9497416 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1570,7 +1570,7 @@
     proposed.format = format;
 
     sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
-    size_t frames;
+    size_t frames = 0;
     for (;;) {
         // Note: config is currently a const parameter for get_input_buffer_size()
         // but we use a copy from proposed in case config changes from the call.
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 3c4fbba..13152d0 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -24,6 +24,7 @@
 #include "Configuration.h"
 #include <utils/Log.h>
 #include <system/audio_effects/effect_aec.h>
+#include <system/audio_effects/effect_dynamicsprocessing.h>
 #include <system/audio_effects/effect_ns.h>
 #include <system/audio_effects/effect_visualizer.h>
 #include <audio_utils/channels.h>
@@ -2569,7 +2570,8 @@
     if ((mSessionId == AUDIO_SESSION_OUTPUT_MIX) &&
         (((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) ||
          (memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) ||
-         (memcmp(&desc.type, SL_IID_VOLUME, sizeof(effect_uuid_t)) == 0))) {
+         (memcmp(&desc.type, SL_IID_VOLUME, sizeof(effect_uuid_t)) == 0) ||
+         (memcmp(&desc.type, SL_IID_DYNAMICSPROCESSING, sizeof(effect_uuid_t)) == 0))) {
         return false;
     }
     return true;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a021866..73292d3 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3958,6 +3958,32 @@
     return INVALID_OPERATION;
 }
 
+// For dedicated VoIP outputs, let the HAL apply the stream volume. Track volume is
+// still applied by the mixer.
+// All tracks attached to a mixer with flag VOIP_RX are tied to the same
+// stream type STREAM_VOICE_CALL so this will only change the HAL volume once even
+// if more than one track are active
+status_t AudioFlinger::PlaybackThread::handleVoipVolume_l(float *volume)
+{
+    status_t result = NO_ERROR;
+    if ((mOutput->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) != 0) {
+        if (*volume != mLeftVolFloat) {
+            result = mOutput->stream->setVolume(*volume, *volume);
+            ALOGE_IF(result != OK,
+                     "Error when setting output stream volume: %d", result);
+            if (result == NO_ERROR) {
+                mLeftVolFloat = *volume;
+            }
+        }
+        // if stream volume was successfully sent to the HAL, mLeftVolFloat == v here and we
+        // remove stream volume contribution from software volume.
+        if (mLeftVolFloat == *volume) {
+            *volume = 1.0f;
+        }
+    }
+    return result;
+}
+
 status_t AudioFlinger::MixerThread::createAudioPatch_l(const struct audio_patch *patch,
                                                           audio_patch_handle_t *handle)
 {
@@ -4760,22 +4786,25 @@
                     // no acknowledgement required for newly active tracks
                 }
                 sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
+                float volume;
+                if (track->isPlaybackRestricted() || mStreamTypes[track->streamType()].mute) {
+                    volume = 0.f;
+                } else {
+                    volume = masterVolume * mStreamTypes[track->streamType()].volume;
+                }
+
+                handleVoipVolume_l(&volume);
+
                 // cache the combined master volume and stream type volume for fast mixer; this
                 // lacks any synchronization or barrier so VolumeProvider may read a stale value
                 const float vh = track->getVolumeHandler()->getVolume(
-                        proxy->framesReleased()).first;
-                float volume;
-                if (track->isPlaybackRestricted()) {
-                    volume = 0.f;
-                } else {
-                    volume = masterVolume
-                        * mStreamTypes[track->streamType()].volume
-                        * vh;
-                }
+                    proxy->framesReleased()).first;
+                volume *= vh;
                 track->mCachedVolume = volume;
                 gain_minifloat_packed_t vlr = proxy->getVolumeLR();
                 float vlf = volume * float_from_gain(gain_minifloat_unpack_left(vlr));
                 float vrf = volume * float_from_gain(gain_minifloat_unpack_right(vlr));
+
                 track->setFinalVolume((vlf + vrf) / 2.f);
                 ++fastTracks;
             } else {
@@ -4918,20 +4947,22 @@
             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;
+            float v = masterVolume * mStreamTypes[track->streamType()].volume;
             // Always fetch volumeshaper volume to ensure state is updated.
             const sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
             const float vh = track->getVolumeHandler()->getVolume(
                     track->mAudioTrackServerProxy->framesReleased()).first;
 
-            if (track->isPausing() || mStreamTypes[track->streamType()].mute
-                    || track->isPlaybackRestricted()) {
+            if (mStreamTypes[track->streamType()].mute || track->isPlaybackRestricted()) {
+                v = 0;
+            }
+
+            handleVoipVolume_l(&v);
+
+            if (track->isPausing()) {
                 vl = vr = 0;
                 vlf = vrf = vaf = 0.;
-                if (track->isPausing()) {
-                    track->setPaused();
-                }
+                track->setPaused();
             } else {
                 gain_minifloat_packed_t vlr = proxy->getVolumeLR();
                 vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
@@ -4983,25 +5014,6 @@
                 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(trackId, track);
             mAudioMixer->enable(trackId);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 31e10a3..acb1370 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -747,6 +747,7 @@
                 // is safe to do so. That will drop the final ref count and destroy the tracks.
     virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove) = 0;
                 void        removeTracks_l(const Vector< sp<Track> >& tracksToRemove);
+                status_t    handleVoipVolume_l(float *volume);
 
     // StreamOutHalInterfaceCallback implementation
     virtual     void        onWriteReady();
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 83ae35e..b0b63d9 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1086,8 +1086,9 @@
     }
 
     audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
+        .channel_mask = config->channel_mask,
         .format = config->format,
-        .channel_mask = config->channel_mask };
+    };
     *portId = AudioPort::getNextUniqueId();
 
     sp<TrackClientDescriptor> clientDesc =
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index bdeb273..c70513c 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1169,6 +1169,8 @@
                 clientPid,
                 states[states.size() - 1]);
 
+        resource_policy::ClientPriority clientPriority = clientDescriptor->getPriority();
+
         // Find clients that would be evicted
         auto evicted = mActiveClientManager.wouldEvict(clientDescriptor);
 
@@ -1186,8 +1188,7 @@
             String8 msg = String8::format("%s : DENIED connect device %s client for package %s "
                     "(PID %d, score %d state %d) due to eviction policy", curTime.string(),
                     cameraId.string(), packageName.string(), clientPid,
-                    priorityScores[priorityScores.size() - 1],
-                    states[states.size() - 1]);
+                    clientPriority.getScore(), clientPriority.getState());
 
             for (auto& i : incompatibleClients) {
                 msg.appendFormat("\n   - Blocked by existing device %s client for package %s"
@@ -1232,9 +1233,8 @@
                     i->getKey().string(), String8{clientSp->getPackageName()}.string(),
                     i->getOwnerId(), i->getPriority().getScore(),
                     i->getPriority().getState(), cameraId.string(),
-                    packageName.string(), clientPid,
-                    priorityScores[priorityScores.size() - 1],
-                    states[states.size() - 1]));
+                    packageName.string(), clientPid, clientPriority.getScore(),
+                    clientPriority.getState()));
 
             // Notify the client of disconnection
             clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
@@ -1368,14 +1368,19 @@
     Status ret = Status::ok();
     String8 id = String8(cameraId);
     sp<CameraDeviceClient> client = nullptr;
-
+    String16 clientPackageNameAdj = clientPackageName;
+    if (hardware::IPCThreadState::self()->isServingCall()) {
+        std::string vendorClient =
+                StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid());
+        clientPackageNameAdj = String16(vendorClient.c_str());
+    }
     ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
             /*api1CameraId*/-1,
-            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
+            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageNameAdj,
             clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client);
 
     if(!ret.isOk()) {
-        logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
+        logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageNameAdj),
                 ret.toString8());
         return ret;
     }
@@ -2397,11 +2402,7 @@
         }
         mClientPackageName = packages[0];
     }
-    if (hardware::IPCThreadState::self()->isServingCall()) {
-        std::string vendorClient =
-                StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid());
-        mClientPackageName = String16(vendorClient.c_str());
-    } else {
+    if (!hardware::IPCThreadState::self()->isServingCall()) {
         mAppOpsManager = std::make_unique<AppOpsManager>();
     }
 }
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 7f94e55..cb2c324 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -2087,6 +2087,13 @@
     return OK;
 }
 bool CameraProviderManager::ProviderInfo::DeviceInfo3::isAPI1Compatible() const {
+    // Do not advertise NIR cameras to API1 camera app.
+    camera_metadata_ro_entry cfa = mCameraCharacteristics.find(
+            ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT);
+    if (cfa.count == 1 && cfa.data.u8[0] == ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR) {
+        return false;
+    }
+
     bool isBackwardCompatible = false;
     camera_metadata_ro_entry_t caps = mCameraCharacteristics.find(
             ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
diff --git a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
index 3c90de0..94541d8 100644
--- a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
+++ b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
@@ -419,7 +419,7 @@
 
     std::vector<std::unique_ptr<Item>> items;
     std::vector<std::unique_ptr<Camera>> cameraList;
-    auto image = Image::FromDataForPrimaryImage("android/mainimage", &items);
+    auto image = Image::FromDataForPrimaryImage("image/jpeg", &items);
     std::unique_ptr<CameraParams> cameraParams(new CameraParams(std::move(image)));
     if (cameraParams == nullptr) {
         ALOGE("%s: Failed to initialize camera parameters", __FUNCTION__);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index a8e80fa..4227a3b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -29,6 +29,9 @@
 #define CLOGE(fmt, ...) ALOGE("Camera %s: %s: " fmt, mId.string(), __FUNCTION__, \
             ##__VA_ARGS__)
 
+#define CLOGW(fmt, ...) ALOGW("Camera %s: %s: " fmt, mId.string(), __FUNCTION__, \
+            ##__VA_ARGS__)
+
 // Convenience macros for transitioning to the error state
 #define SET_ERR(fmt, ...) setErrorState(   \
     "%s: " fmt, __FUNCTION__,              \
@@ -3267,14 +3270,19 @@
         ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
      }
 
-    // Sanity check - if we have too many in-flight frames, something has
-    // likely gone wrong
-    if (!mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() > kInFlightWarnLimit) {
-        CLOGE("In-flight list too large: %zu", mInFlightMap.size());
-    } else if (mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() >
-            kInFlightWarnLimitHighSpeed) {
-        CLOGE("In-flight list too large for high speed configuration: %zu",
-                mInFlightMap.size());
+    // Sanity check - if we have too many in-flight frames with long total inflight duration,
+    // something has likely gone wrong. This might still be legit only if application send in
+    // a long burst of long exposure requests.
+    if (mExpectedInflightDuration > kMinWarnInflightDuration) {
+        if (!mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() > kInFlightWarnLimit) {
+            CLOGW("In-flight list too large: %zu, total inflight duration %" PRIu64,
+                    mInFlightMap.size(), mExpectedInflightDuration);
+        } else if (mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() >
+                kInFlightWarnLimitHighSpeed) {
+            CLOGW("In-flight list too large for high speed configuration: %zu,"
+                    "total inflight duration %" PRIu64,
+                    mInFlightMap.size(), mExpectedInflightDuration);
+        }
     }
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 6e8ac84..cae34ce 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -227,6 +227,7 @@
     static const size_t        kDumpLockAttempts  = 10;
     static const size_t        kDumpSleepDuration = 100000; // 0.10 sec
     static const nsecs_t       kActiveTimeout     = 500000000;  // 500 ms
+    static const nsecs_t       kMinWarnInflightDuration = 5000000000; // 5 s
     static const size_t        kInFlightWarnLimit = 30;
     static const size_t        kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8
     static const nsecs_t       kDefaultExpectedDuration = 100000000; // 100 ms
diff --git a/services/mediaanalytics/statsd_audiopolicy.cpp b/services/mediaanalytics/statsd_audiopolicy.cpp
index 06c4dde..95cb274 100644
--- a/services/mediaanalytics/statsd_audiopolicy.cpp
+++ b/services/mediaanalytics/statsd_audiopolicy.cpp
@@ -60,14 +60,14 @@
         metrics_proto.set_status(status);
     }
     //string char kAudioPolicyRqstSrc[] = "android.media.audiopolicy.rqst.src";
-    char *rqst_src = NULL;
-    if (item->getCString("android.media.audiopolicy.rqst.src", &rqst_src)) {
-        metrics_proto.set_request_source(rqst_src);
+    std::string rqst_src;
+    if (item->getString("android.media.audiopolicy.rqst.src", &rqst_src)) {
+        metrics_proto.set_request_source(std::move(rqst_src));
     }
     //string char kAudioPolicyRqstPkg[] = "android.media.audiopolicy.rqst.pkg";
-    char *rqst_pkg = NULL;
-    if (item->getCString("android.media.audiopolicy.rqst.pkg", &rqst_pkg)) {
-        metrics_proto.set_request_package(rqst_pkg);
+    std::string rqst_pkg;
+    if (item->getString("android.media.audiopolicy.rqst.pkg", &rqst_pkg)) {
+        metrics_proto.set_request_package(std::move(rqst_pkg));
     }
     //int32 char kAudioPolicyRqstSession[] = "android.media.audiopolicy.rqst.session";
     int32_t rqst_session = -1;
@@ -75,20 +75,20 @@
         metrics_proto.set_request_session(rqst_session);
     }
     //string char kAudioPolicyRqstDevice[] = "android.media.audiopolicy.rqst.device";
-    char *rqst_device = NULL;
-    if (item->getCString("android.media.audiopolicy.rqst.device", &rqst_device)) {
-        metrics_proto.set_request_device(rqst_device);
+    std::string rqst_device;
+    if (item->getString("android.media.audiopolicy.rqst.device", &rqst_device)) {
+        metrics_proto.set_request_device(std::move(rqst_device));
     }
 
     //string char kAudioPolicyActiveSrc[] = "android.media.audiopolicy.active.src";
-    char *active_src = NULL;
-    if (item->getCString("android.media.audiopolicy.active.src", &active_src)) {
-        metrics_proto.set_active_source(active_src);
+    std::string active_src;
+    if (item->getString("android.media.audiopolicy.active.src", &active_src)) {
+        metrics_proto.set_active_source(std::move(active_src));
     }
     //string char kAudioPolicyActivePkg[] = "android.media.audiopolicy.active.pkg";
-    char *active_pkg = NULL;
-    if (item->getCString("android.media.audiopolicy.active.pkg", &active_pkg)) {
-        metrics_proto.set_active_package(active_pkg);
+    std::string active_pkg;
+    if (item->getString("android.media.audiopolicy.active.pkg", &active_pkg)) {
+        metrics_proto.set_active_package(std::move(active_pkg));
     }
     //int32 char kAudioPolicyActiveSession[] = "android.media.audiopolicy.active.session";
     int32_t active_session = -1;
@@ -96,9 +96,9 @@
         metrics_proto.set_active_session(active_session);
     }
     //string char kAudioPolicyActiveDevice[] = "android.media.audiopolicy.active.device";
-    char *active_device = NULL;
-    if (item->getCString("android.media.audiopolicy.active.device", &active_device)) {
-        metrics_proto.set_active_device(active_device);
+    std::string active_device;
+    if (item->getString("android.media.audiopolicy.active.device", &active_device)) {
+        metrics_proto.set_active_device(std::move(active_device));
     }
 
 
@@ -119,14 +119,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(rqst_src);
-    free(rqst_pkg);
-    free(rqst_device);
-    free(active_src);
-    free(active_pkg);
-    free(active_device);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_audiorecord.cpp b/services/mediaanalytics/statsd_audiorecord.cpp
index c9edb27..7c7a62c 100644
--- a/services/mediaanalytics/statsd_audiorecord.cpp
+++ b/services/mediaanalytics/statsd_audiorecord.cpp
@@ -54,14 +54,14 @@
 
     // flesh out the protobuf we'll hand off with our data
     //
-    char *encoding = NULL;
-    if (item->getCString("android.media.audiorecord.encoding", &encoding)) {
-        metrics_proto.set_encoding(encoding);
+    std::string encoding;
+    if (item->getString("android.media.audiorecord.encoding", &encoding)) {
+        metrics_proto.set_encoding(std::move(encoding));
     }
 
-    char *source = NULL;
-    if (item->getCString("android.media.audiorecord.source", &source)) {
-        metrics_proto.set_source(source);
+    std::string source;
+    if (item->getString("android.media.audiorecord.source", &source)) {
+        metrics_proto.set_source(std::move(source));
     }
 
     int32_t latency = -1;
@@ -101,11 +101,11 @@
         metrics_proto.set_error_code(errcode);
     }
 
-    char *errfunc = NULL;
-    if (item->getCString("android.media.audiorecord.errfunc", &errfunc)) {
-        metrics_proto.set_error_function(errfunc);
-    } else if (item->getCString("android.media.audiorecord.lastError.at", &errfunc)) {
-        metrics_proto.set_error_function(errfunc);
+    std::string errfunc;
+    if (item->getString("android.media.audiorecord.errfunc", &errfunc)) {
+        metrics_proto.set_error_function(std::move(errfunc));
+    } else if (item->getString("android.media.audiorecord.lastError.at", &errfunc)) {
+        metrics_proto.set_error_function(std::move(errfunc));
     }
 
     // portId (int32)
@@ -119,9 +119,9 @@
         metrics_proto.set_frame_count(frameCount);
     }
     // attributes (string)
-    char *attributes = NULL;
-    if (item->getCString("android.media.audiorecord.attributes", &attributes)) {
-        metrics_proto.set_attributes(attributes);
+    std::string attributes;
+    if (item->getString("android.media.audiorecord.attributes", &attributes)) {
+        metrics_proto.set_attributes(std::move(attributes));
     }
     // channelMask (int64)
     int64_t channelMask = -1;
@@ -152,12 +152,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(encoding);
-    free(source);
-    free(errfunc);
-    free(attributes);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_audiothread.cpp b/services/mediaanalytics/statsd_audiothread.cpp
index 8232424..e9d6b17 100644
--- a/services/mediaanalytics/statsd_audiothread.cpp
+++ b/services/mediaanalytics/statsd_audiothread.cpp
@@ -56,9 +56,9 @@
 
     // flesh out the protobuf we'll hand off with our data
     //
-    char *mytype = NULL;
-    if (item->getCString(MM_PREFIX "type", &mytype)) {
-        metrics_proto.set_type(mytype);
+    std::string mytype;
+    if (item->getString(MM_PREFIX "type", &mytype)) {
+        metrics_proto.set_type(std::move(mytype));
     }
     int32_t framecount = -1;
     if (item->getInt32(MM_PREFIX "framecount", &framecount)) {
@@ -68,17 +68,17 @@
     if (item->getInt32(MM_PREFIX "samplerate", &samplerate)) {
         metrics_proto.set_samplerate(samplerate);
     }
-    char *workhist = NULL;
-    if (item->getCString(MM_PREFIX "workMs.hist", &workhist)) {
-        metrics_proto.set_work_millis_hist(workhist);
+    std::string workhist;
+    if (item->getString(MM_PREFIX "workMs.hist", &workhist)) {
+        metrics_proto.set_work_millis_hist(std::move(workhist));
     }
-    char *latencyhist = NULL;
-    if (item->getCString(MM_PREFIX "latencyMs.hist", &latencyhist)) {
-        metrics_proto.set_latency_millis_hist(latencyhist);
+    std::string latencyhist;
+    if (item->getString(MM_PREFIX "latencyMs.hist", &latencyhist)) {
+        metrics_proto.set_latency_millis_hist(std::move(latencyhist));
     }
-    char *warmuphist = NULL;
-    if (item->getCString(MM_PREFIX "warmupMs.hist", &warmuphist)) {
-        metrics_proto.set_warmup_millis_hist(warmuphist);
+    std::string warmuphist;
+    if (item->getString(MM_PREFIX "warmupMs.hist", &warmuphist)) {
+        metrics_proto.set_warmup_millis_hist(std::move(warmuphist));
     }
     int64_t underruns = -1;
     if (item->getInt64(MM_PREFIX "underruns", &underruns)) {
@@ -108,9 +108,9 @@
         metrics_proto.set_port_id(port_id);
     }
     // item->setCString(MM_PREFIX "type", threadTypeToString(mType));
-    char *type = NULL;
-    if (item->getCString(MM_PREFIX "type", &type)) {
-        metrics_proto.set_type(type);
+    std::string type;
+    if (item->getString(MM_PREFIX "type", &type)) {
+        metrics_proto.set_type(std::move(type));
     }
     // item->setInt32(MM_PREFIX "sampleRate", (int32_t)mSampleRate);
     int32_t sample_rate = -1;
@@ -123,9 +123,9 @@
         metrics_proto.set_channel_mask(channel_mask);
     }
     // item->setCString(MM_PREFIX "encoding", toString(mFormat).c_str());
-    char *encoding = NULL;
-    if (item->getCString(MM_PREFIX "encoding", &encoding)) {
-        metrics_proto.set_encoding(encoding);
+    std::string encoding;
+    if (item->getString(MM_PREFIX "encoding", &encoding)) {
+        metrics_proto.set_encoding(std::move(encoding));
     }
     // item->setInt32(MM_PREFIX "frameCount", (int32_t)mFrameCount);
     int32_t frame_count = -1;
@@ -133,14 +133,14 @@
         metrics_proto.set_frame_count(frame_count);
     }
     // item->setCString(MM_PREFIX "outDevice", toString(mOutDevice).c_str());
-    char *outDevice = NULL;
-    if (item->getCString(MM_PREFIX "outDevice", &outDevice)) {
-        metrics_proto.set_output_device(outDevice);
+    std::string outDevice;
+    if (item->getString(MM_PREFIX "outDevice", &outDevice)) {
+        metrics_proto.set_output_device(std::move(outDevice));
     }
     // item->setCString(MM_PREFIX "inDevice", toString(mInDevice).c_str());
-    char *inDevice = NULL;
-    if (item->getCString(MM_PREFIX "inDevice", &inDevice)) {
-        metrics_proto.set_input_device(inDevice);
+    std::string inDevice;
+    if (item->getString(MM_PREFIX "inDevice", &inDevice)) {
+        metrics_proto.set_input_device(std::move(inDevice));
     }
     // item->setDouble(MM_PREFIX "ioJitterMs.mean", mIoJitterMs.getMean());
     double iojitters_ms_mean = -1;
@@ -201,16 +201,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(mytype);
-    free(workhist);
-    free(latencyhist);
-    free(warmuphist);
-    free(type);
-    free(encoding);
-    free(inDevice);
-    free(outDevice);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_audiotrack.cpp b/services/mediaanalytics/statsd_audiotrack.cpp
index f250ced..57cda99 100644
--- a/services/mediaanalytics/statsd_audiotrack.cpp
+++ b/services/mediaanalytics/statsd_audiotrack.cpp
@@ -57,23 +57,23 @@
 
     // static constexpr char kAudioTrackStreamType[] = "android.media.audiotrack.streamtype";
     // optional string streamType;
-    char *streamtype = NULL;
-    if (item->getCString("android.media.audiotrack.streamtype", &streamtype)) {
-        metrics_proto.set_stream_type(streamtype);
+    std::string streamtype;
+    if (item->getString("android.media.audiotrack.streamtype", &streamtype)) {
+        metrics_proto.set_stream_type(std::move(streamtype));
     }
 
     // static constexpr char kAudioTrackContentType[] = "android.media.audiotrack.type";
     // optional string contentType;
-    char *contenttype = NULL;
-    if (item->getCString("android.media.audiotrack.type", &contenttype)) {
-        metrics_proto.set_content_type(contenttype);
+    std::string contenttype;
+    if (item->getString("android.media.audiotrack.type", &contenttype)) {
+        metrics_proto.set_content_type(std::move(contenttype));
     }
 
     // static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
     // optional string trackUsage;
-    char *trackusage = NULL;
-    if (item->getCString("android.media.audiotrack.usage", &trackusage)) {
-        metrics_proto.set_track_usage(trackusage);
+    std::string trackusage;
+    if (item->getString("android.media.audiotrack.usage", &trackusage)) {
+        metrics_proto.set_track_usage(std::move(trackusage));
     }
 
     // static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
@@ -111,9 +111,9 @@
         metrics_proto.set_port_id(port_id);
     }
     // encoding (string)
-    char *encoding = NULL;
-    if (item->getCString("android.media.audiotrack.encoding", &encoding)) {
-        metrics_proto.set_encoding(encoding);
+    std::string encoding;
+    if (item->getString("android.media.audiotrack.encoding", &encoding)) {
+        metrics_proto.set_encoding(std::move(encoding));
     }
     // frameCount (int32)
     int32_t frame_count = -1;
@@ -121,9 +121,9 @@
         metrics_proto.set_frame_count(frame_count);
     }
     // attributes (string)
-    char *attributes = NULL;
-    if (item->getCString("android.media.audiotrack.attributes", &attributes)) {
-        metrics_proto.set_attributes(attributes);
+    std::string attributes;
+    if (item->getString("android.media.audiotrack.attributes", &attributes)) {
+        metrics_proto.set_attributes(std::move(attributes));
     }
 
     std::string serialized;
@@ -143,13 +143,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(streamtype);
-    free(contenttype);
-    free(trackusage);
-    free(encoding);
-    free(attributes);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_codec.cpp b/services/mediaanalytics/statsd_codec.cpp
index dc8e4ef..bf82e50 100644
--- a/services/mediaanalytics/statsd_codec.cpp
+++ b/services/mediaanalytics/statsd_codec.cpp
@@ -55,19 +55,19 @@
     // flesh out the protobuf we'll hand off with our data
     //
     // android.media.mediacodec.codec   string
-    char *codec = NULL;
-    if (item->getCString("android.media.mediacodec.codec", &codec)) {
-        metrics_proto.set_codec(codec);
+    std::string codec;
+    if (item->getString("android.media.mediacodec.codec", &codec)) {
+        metrics_proto.set_codec(std::move(codec));
     }
     // android.media.mediacodec.mime    string
-    char *mime = NULL;
-    if (item->getCString("android.media.mediacodec.mime", &mime)) {
-        metrics_proto.set_mime(mime);
+    std::string mime;
+    if (item->getString("android.media.mediacodec.mime", &mime)) {
+        metrics_proto.set_mime(std::move(mime));
     }
     // android.media.mediacodec.mode    string
-    char *mode = NULL;
-    if ( item->getCString("android.media.mediacodec.mode", &mode)) {
-        metrics_proto.set_mode(mode);
+    std::string mode;
+    if ( item->getString("android.media.mediacodec.mode", &mode)) {
+        metrics_proto.set_mode(std::move(mode));
     }
     // android.media.mediacodec.encoder int32
     int32_t encoder = -1;
@@ -125,9 +125,9 @@
         metrics_proto.set_error_code(errcode);
     }
     // android.media.mediacodec.errstate        string
-    char *errstate = NULL;
-    if ( item->getCString("android.media.mediacodec.errstate", &errstate)) {
-        metrics_proto.set_error_state(errstate);
+    std::string errstate;
+    if ( item->getString("android.media.mediacodec.errstate", &errstate)) {
+        metrics_proto.set_error_state(std::move(errstate));
     }
     // android.media.mediacodec.latency.max  int64
     int64_t latency_max = -1;
@@ -173,12 +173,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(codec);
-    free(mime);
-    free(mode);
-    free(errstate);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_extractor.cpp b/services/mediaanalytics/statsd_extractor.cpp
index 395c912..d84930c 100644
--- a/services/mediaanalytics/statsd_extractor.cpp
+++ b/services/mediaanalytics/statsd_extractor.cpp
@@ -56,14 +56,14 @@
     //
 
     // android.media.mediaextractor.fmt         string
-    char *fmt = NULL;
-    if (item->getCString("android.media.mediaextractor.fmt", &fmt)) {
-        metrics_proto.set_format(fmt);
+    std::string fmt;
+    if (item->getString("android.media.mediaextractor.fmt", &fmt)) {
+        metrics_proto.set_format(std::move(fmt));
     }
     // android.media.mediaextractor.mime        string
-    char *mime = NULL;
-    if (item->getCString("android.media.mediaextractor.mime", &mime)) {
-        metrics_proto.set_mime(mime);
+    std::string mime;
+    if (item->getString("android.media.mediaextractor.mime", &mime)) {
+        metrics_proto.set_mime(std::move(mime));
     }
     // android.media.mediaextractor.ntrk        int32
     int32_t ntrk = -1;
@@ -88,10 +88,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(fmt);
-    free(mime);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_nuplayer.cpp b/services/mediaanalytics/statsd_nuplayer.cpp
index 5ec118a..e6e0f2c 100644
--- a/services/mediaanalytics/statsd_nuplayer.cpp
+++ b/services/mediaanalytics/statsd_nuplayer.cpp
@@ -62,13 +62,13 @@
     // differentiate between nuplayer and nuplayer2
     metrics_proto.set_whichplayer(item->getKey().c_str());
 
-    char *video_mime = NULL;
-    if (item->getCString("android.media.mediaplayer.video.mime", &video_mime)) {
-        metrics_proto.set_video_mime(video_mime);
+    std::string video_mime;
+    if (item->getString("android.media.mediaplayer.video.mime", &video_mime)) {
+        metrics_proto.set_video_mime(std::move(video_mime));
     }
-    char *video_codec = NULL;
-    if (item->getCString("android.media.mediaplayer.video.codec", &video_codec)) {
-        metrics_proto.set_video_codec(video_codec);
+    std::string video_codec;
+    if (item->getString("android.media.mediaplayer.video.codec", &video_codec)) {
+        metrics_proto.set_video_codec(std::move(video_codec));
     }
 
     int32_t width = -1;
@@ -97,13 +97,13 @@
         metrics_proto.set_framerate(fps);
     }
 
-    char *audio_mime = NULL;
-    if (item->getCString("android.media.mediaplayer.audio.mime", &audio_mime)) {
-        metrics_proto.set_audio_mime(audio_mime);
+    std::string audio_mime;
+    if (item->getString("android.media.mediaplayer.audio.mime", &audio_mime)) {
+        metrics_proto.set_audio_mime(std::move(audio_mime));
     }
-    char *audio_codec = NULL;
-    if (item->getCString("android.media.mediaplayer.audio.codec", &audio_codec)) {
-        metrics_proto.set_audio_codec(audio_codec);
+    std::string audio_codec;
+    if (item->getString("android.media.mediaplayer.audio.codec", &audio_codec)) {
+        metrics_proto.set_audio_codec(std::move(audio_codec));
     }
 
     int64_t duration_ms = -1;
@@ -123,14 +123,14 @@
     if (item->getInt32("android.media.mediaplayer.errcode", &error_code)) {
         metrics_proto.set_error_code(error_code);
     }
-    char *error_state = NULL;
-    if (item->getCString("android.media.mediaplayer.errstate", &error_state)) {
-        metrics_proto.set_error_state(error_state);
+    std::string error_state;
+    if (item->getString("android.media.mediaplayer.errstate", &error_state)) {
+        metrics_proto.set_error_state(std::move(error_state));
     }
 
-    char *data_source_type = NULL;
-    if (item->getCString("android.media.mediaplayer.dataSource", &data_source_type)) {
-        metrics_proto.set_data_source_type(data_source_type);
+    std::string data_source_type;
+    if (item->getString("android.media.mediaplayer.dataSource", &data_source_type)) {
+        metrics_proto.set_data_source_type(std::move(data_source_type));
     }
 
     int64_t rebufferingMs = -1;
@@ -164,14 +164,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(video_mime);
-    free(video_codec);
-    free(audio_mime);
-    free(audio_codec);
-    free(error_state);
-    free(data_source_type);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_recorder.cpp b/services/mediaanalytics/statsd_recorder.cpp
index 4d981b4..d286f00 100644
--- a/services/mediaanalytics/statsd_recorder.cpp
+++ b/services/mediaanalytics/statsd_recorder.cpp
@@ -56,14 +56,14 @@
     //
 
     // string kRecorderAudioMime = "android.media.mediarecorder.audio.mime";
-    char *audio_mime = NULL;
-    if (item->getCString("android.media.mediarecorder.audio.mime", &audio_mime)) {
-        metrics_proto.set_audio_mime(audio_mime);
+    std::string audio_mime;
+    if (item->getString("android.media.mediarecorder.audio.mime", &audio_mime)) {
+        metrics_proto.set_audio_mime(std::move(audio_mime));
     }
     // string kRecorderVideoMime = "android.media.mediarecorder.video.mime";
-    char *video_mime = NULL;
-    if (item->getCString("android.media.mediarecorder.video.mime", &video_mime)) {
-        metrics_proto.set_video_mime(video_mime);
+    std::string video_mime;
+    if (item->getString("android.media.mediarecorder.video.mime", &video_mime)) {
+        metrics_proto.set_video_mime(std::move(video_mime));
     }
     // int32 kRecorderVideoProfile = "android.media.mediarecorder.video-encoder-profile";
     int32_t videoProfile = -1;
@@ -183,10 +183,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(audio_mime);
-    free(video_mime);
-
     return true;
 }
 
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index f668c33..6a82b1b 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -21,6 +21,7 @@
 #include "minijail.h"
 
 #include <binder/ProcessState.h>
+#include <cutils/properties.h>
 #include <hidl/HidlTransportSupport.h>
 #include <media/stagefright/omx/1.0/Omx.h>
 #include <media/stagefright/omx/1.0/OmxStore.h>
@@ -57,7 +58,8 @@
     } else {
         LOG(INFO) << "IOmx HAL service created.";
     }
-    sp<IOmxStore> omxStore = new implementation::OmxStore(omx);
+    sp<IOmxStore> omxStore = new implementation::OmxStore(
+            property_get_int64("vendor.media.omx", 1) ? omx : nullptr);
     if (omxStore == nullptr) {
         LOG(ERROR) << "Cannot create IOmxStore HAL service.";
     } else if (omxStore->registerAsService() != OK) {
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index d4bb48a..9f03964 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -21,6 +21,7 @@
     main_mediadrmserver.cpp
 
 LOCAL_HEADER_LIBRARIES:= \
+    libmedia_headers \
     libmediadrm_headers
 
 LOCAL_SHARED_LIBRARIES:= \
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
index bee5d25..74b63d5 100644
--- a/services/medialog/Android.bp
+++ b/services/medialog/Android.bp
@@ -6,6 +6,10 @@
         "MediaLogService.cpp",
     ],
 
+    header_libs: [
+        "libmedia_headers",
+    ],
+
     shared_libs: [
         "libaudioutils",
         "libbinder",