Merge "audio flinger: add support for effects without process function" into nyc-mr1-dev
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
index 40275cf..d27956c 100644
--- a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
@@ -24,6 +24,7 @@
 
 #include "DrmPlugin.h"
 #include "ClearKeyUUID.h"
+#include "MimeType.h"
 #include "SessionLibrary.h"
 
 namespace clearkeydrm {
@@ -32,10 +33,14 @@
     return isClearKeyUUID(uuid);
 }
 
-bool DrmFactory::isContentTypeSupported(const android::String8 &initDataType) {
+bool DrmFactory::isContentTypeSupported(const android::String8 &type) {
     // This should match the types handed by InitDataParser.
-    return initDataType == "cenc" ||
-           initDataType == "webm";
+    return type == kIsoBmffVideoMimeType ||
+        type == kIsoBmffAudioMimeType ||
+        type == kCencInitDataFormat ||
+        type == kWebmVideoMimeType ||
+        type == kWebmAudioMimeType ||
+        type == kWebmInitDataFormat;
 }
 
 android::status_t DrmFactory::createDrmPlugin(
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.h b/drm/mediadrm/plugins/clearkey/DrmFactory.h
index 164d3d0..87db982 100644
--- a/drm/mediadrm/plugins/clearkey/DrmFactory.h
+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.h
@@ -32,7 +32,7 @@
 
     virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
 
-    virtual bool isContentTypeSupported(const android::String8 &initDataType);
+    virtual bool isContentTypeSupported(const android::String8 &mimeType);
 
     virtual android::status_t createDrmPlugin(
             const uint8_t uuid[16], android::DrmPlugin** plugin);
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
index e5ee403..86bf047 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
@@ -46,7 +46,7 @@
 status_t DrmPlugin::getKeyRequest(
         const Vector<uint8_t>& scope,
         const Vector<uint8_t>& initData,
-        const String8& initDataType,
+        const String8& mimeType,
         KeyType keyType,
         const KeyedVector<String8, String8>& optionalParameters,
         Vector<uint8_t>& request,
@@ -62,7 +62,7 @@
     if (!session.get()) {
         return android::ERROR_DRM_SESSION_NOT_OPENED;
     }
-    return session->getKeyRequest(initData, initDataType, &request);
+    return session->getKeyRequest(initData, mimeType, &request);
 }
 
 status_t DrmPlugin::provideKeyResponse(
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index 9095045..efb9f8b 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -49,7 +49,7 @@
 
     virtual status_t getKeyRequest(
             const Vector<uint8_t>& scope,
-            const Vector<uint8_t>& initData,
+            const Vector<uint8_t>& mimeType,
             const String8& initDataType,
             KeyType keyType,
             const KeyedVector<String8, String8>& optionalParameters,
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
index c22d73a..0216b8d 100644
--- a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
@@ -27,6 +27,7 @@
 #include "InitDataParser.h"
 
 #include "ClearKeyUUID.h"
+#include "MimeType.h"
 #include "Utils.h"
 
 namespace clearkeydrm {
@@ -41,16 +42,20 @@
 }
 
 android::status_t InitDataParser::parse(const Vector<uint8_t>& initData,
-        const String8& initDataType,
+        const String8& type,
         Vector<uint8_t>* licenseRequest) {
     // Build a list of the key IDs
     Vector<const uint8_t*> keyIds;
-    if (initDataType == "cenc") {
+    if (type == kIsoBmffVideoMimeType ||
+        type == kIsoBmffAudioMimeType ||
+        type == kCencInitDataFormat) {
         android::status_t res = parsePssh(initData, &keyIds);
         if (res != android::OK) {
             return res;
         }
-    } else if (initDataType == "webm") {
+    } else if (type == kWebmVideoMimeType ||
+        type == kWebmAudioMimeType ||
+        type == kWebmInitDataFormat) {
         // WebM "init data" is just a single key ID
         if (initData.size() != kKeyIdSize) {
             return android::ERROR_DRM_CANNOT_HANDLE;
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.h b/drm/mediadrm/plugins/clearkey/InitDataParser.h
index 9505d2a..a9707bf 100644
--- a/drm/mediadrm/plugins/clearkey/InitDataParser.h
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.h
@@ -29,7 +29,7 @@
     InitDataParser() {}
 
     android::status_t parse(const android::Vector<uint8_t>& initData,
-            const android::String8& initDataType,
+            const android::String8& type,
             android::Vector<uint8_t>* licenseRequest);
 
 private:
diff --git a/drm/mediadrm/plugins/clearkey/MimeType.h b/drm/mediadrm/plugins/clearkey/MimeType.h
new file mode 100644
index 0000000..085f17a
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/MimeType.h
@@ -0,0 +1,15 @@
+#ifndef CLEARKEY_MIMETYPE_H_
+#define CLEARKEY_MIMETYPE_H_
+
+#include <utils/String8.h>
+
+namespace {
+    const android::String8 kCencInitDataFormat("cenc");
+    const android::String8 kIsoBmffAudioMimeType("audio/mp4");
+    const android::String8 kIsoBmffVideoMimeType("video/mp4");
+    const android::String8 kWebmInitDataFormat("webm");
+    const android::String8 kWebmAudioMimeType("audio/webm");
+    const android::String8 kWebmVideoMimeType("video/webm");
+}
+
+#endif // CLEARKEY_MIMETYPE_H_
diff --git a/drm/mediadrm/plugins/clearkey/Session.cpp b/drm/mediadrm/plugins/clearkey/Session.cpp
index 95016f5..d210f5e 100644
--- a/drm/mediadrm/plugins/clearkey/Session.cpp
+++ b/drm/mediadrm/plugins/clearkey/Session.cpp
@@ -36,10 +36,10 @@
 
 status_t Session::getKeyRequest(
         const Vector<uint8_t>& initData,
-        const String8& initDataType,
+        const String8& mimeType,
         Vector<uint8_t>* keyRequest) const {
     InitDataParser parser;
-    return parser.parse(initData, initDataType, keyRequest);
+    return parser.parse(initData, mimeType, keyRequest);
 }
 
 status_t Session::provideKeyResponse(const Vector<uint8_t>& response) {
diff --git a/drm/mediadrm/plugins/clearkey/Session.h b/drm/mediadrm/plugins/clearkey/Session.h
index cab0dc3..0933506 100644
--- a/drm/mediadrm/plugins/clearkey/Session.h
+++ b/drm/mediadrm/plugins/clearkey/Session.h
@@ -38,7 +38,7 @@
     const android::Vector<uint8_t>& sessionId() const { return mSessionId; }
 
     android::status_t getKeyRequest(
-            const android::Vector<uint8_t>& initData,
+            const android::Vector<uint8_t>& mimeType,
             const android::String8& initDataType,
             android::Vector<uint8_t>* keyRequest) const;
 
diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
index 4ba65ed..e275108 100644
--- a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
@@ -30,27 +30,27 @@
 
 namespace {
     const size_t kKeyIdSize = 16;
-    const String8 kCencType("cenc");
-    const String8 kWebMType("webm");
+    const String8 kCencMimeType("video/mp4");
+    const String8 kWebmMimeType("video/webm");
     const String8 kBase64Padding("=");
 }
 
 class InitDataParserTest : public ::testing::Test {
   protected:
     status_t attemptParse(const Vector<uint8_t>& initData,
-                          const String8& initDataType,
+                          const String8& mimeType,
                           Vector<uint8_t>* licenseRequest) {
         InitDataParser parser;
-        return parser.parse(initData, initDataType, licenseRequest);
+        return parser.parse(initData, mimeType, licenseRequest);
     }
 
     void attemptParseExpectingSuccess(const Vector<uint8_t>& initData,
-                                      const String8& initDataType,
+                                      const String8& mimeType,
                                       const Vector<String8>& expectedKeys) {
         const String8 kRequestPrefix("{\"kids\":[");
         const String8 kRequestSuffix("],\"type\":\"temporary\"}");
         Vector<uint8_t> request;
-        ASSERT_EQ(android::OK, attemptParse(initData, initDataType, &request));
+        ASSERT_EQ(android::OK, attemptParse(initData, mimeType, &request));
 
         String8 requestString(reinterpret_cast<const char*>(request.array()),
                               request.size());
@@ -68,9 +68,9 @@
     }
 
     void attemptParseExpectingFailure(const Vector<uint8_t>& initData,
-                                      const String8& initDataType) {
+                                      const String8& mimeType) {
         Vector<uint8_t> request;
-        ASSERT_NE(android::OK, attemptParse(initData, initDataType, &request));
+        ASSERT_NE(android::OK, attemptParse(initData, mimeType, &request));
         EXPECT_EQ(0, request.size());
     }
 };
@@ -93,7 +93,7 @@
     Vector<String8> expectedKeys;
     expectedKeys.push(String8("01234567890ABCDE"));
 
-    attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
+    attemptParseExpectingSuccess(initData, kCencMimeType, expectedKeys);
 }
 
 TEST_F(InitDataParserTest, ParsesMultipleKeyPssh) {
@@ -120,7 +120,7 @@
     expectedKeys.push(String8("ClearKeyClearKey"));
     expectedKeys.push(String8(" GOOGLE  GOOGLE "));
 
-    attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
+    attemptParseExpectingSuccess(initData, kCencMimeType, expectedKeys);
 }
 
 TEST_F(InitDataParserTest, ParsesWebM) {
@@ -134,7 +134,7 @@
     Vector<String8> expectedKeys;
     expectedKeys.push(String8("01234567890ABCDE"));
 
-    attemptParseExpectingSuccess(initData, kWebMType, expectedKeys);
+    attemptParseExpectingSuccess(initData, kWebmMimeType, expectedKeys);
 }
 
 TEST_F(InitDataParserTest, FailsForPsshTooSmall) {
@@ -147,7 +147,7 @@
     Vector<uint8_t> initData;
     initData.appendArray(pssh, 16);
 
-    attemptParseExpectingFailure(initData, kCencType);
+    attemptParseExpectingFailure(initData, kCencMimeType);
 }
 
 TEST_F(InitDataParserTest, FailsForWebMTooSmall) {
@@ -157,7 +157,7 @@
     Vector<uint8_t> initData;
     initData.appendArray(initDataRaw, 8);
 
-    attemptParseExpectingFailure(initData, kWebMType);
+    attemptParseExpectingFailure(initData, kWebmMimeType);
 }
 
 TEST_F(InitDataParserTest, FailsForPsshBadSystemId) {
@@ -175,7 +175,7 @@
     Vector<uint8_t> initData;
     initData.appendArray(pssh, 52);
 
-    attemptParseExpectingFailure(initData, kCencType);
+    attemptParseExpectingFailure(initData, kCencMimeType);
 }
 
 TEST_F(InitDataParserTest, FailsForPsshBadSize) {
@@ -193,7 +193,7 @@
     Vector<uint8_t> initData;
     initData.appendArray(pssh, 52);
 
-    attemptParseExpectingFailure(initData, kCencType);
+    attemptParseExpectingFailure(initData, kCencMimeType);
 }
 
 TEST_F(InitDataParserTest, FailsForPsshWrongVersion) {
@@ -211,7 +211,7 @@
     Vector<uint8_t> initData;
     initData.appendArray(pssh, 52);
 
-    attemptParseExpectingFailure(initData, kCencType);
+    attemptParseExpectingFailure(initData, kCencMimeType);
 }
 
 TEST_F(InitDataParserTest, FailsForPsshBadKeyCount) {
@@ -229,7 +229,7 @@
     Vector<uint8_t> initData;
     initData.appendArray(pssh, 52);
 
-    attemptParseExpectingFailure(initData, kCencType);
+    attemptParseExpectingFailure(initData, kCencMimeType);
 }
 
 }  // namespace clearkeydrm
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
index ec0dad5..7bb9e8b 100644
--- a/include/media/Visualizer.h
+++ b/include/media/Visualizer.h
@@ -95,8 +95,7 @@
 
     // 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,
-                                bool force = false);
+    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]
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index ffdb9b5..7becf57 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -522,6 +522,12 @@
         mTimestampMutator.push(timestamp);
     }
 
+    // Flushes the shared ring buffer if the client had requested it using mStreaming.mFlush.
+    // If flush occurs then:
+    //   cblk->u.mStreaming.mFront, ServerProxy::mFlush and ServerProxy::mFlushed will be modified
+    //   client will be notified via Futex
+    virtual void    flushBufferIfNeeded();
+
     // Total count of the number of flushed frames since creation (never reset).
     virtual int64_t     framesFlushed() const { return mFlushed; }
 
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 7119517..846f8b8 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -622,6 +622,56 @@
 }
 
 __attribute__((no_sanitize("integer")))
+void ServerProxy::flushBufferIfNeeded()
+{
+    audio_track_cblk_t* cblk = mCblk;
+    // The acquire_load is not really required. But since the write is a release_store in the
+    // client, using acquire_load here makes it easier for people to maintain the code,
+    // and the logic for communicating ipc variables seems somewhat standard,
+    // and there really isn't much penalty for 4 or 8 byte atomics.
+    int32_t flush = android_atomic_acquire_load(&cblk->u.mStreaming.mFlush);
+    if (flush != mFlush) {
+        ALOGV("ServerProxy::flushBufferIfNeeded() mStreaming.mFlush = 0x%x, mFlush = 0x%0x",
+                flush, mFlush);
+        int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
+        int32_t front = cblk->u.mStreaming.mFront;
+
+        // effectively obtain then release whatever is in the buffer
+        const size_t overflowBit = mFrameCountP2 << 1;
+        const size_t mask = overflowBit - 1;
+        int32_t newFront = (front & ~mask) | (flush & mask);
+        ssize_t filled = rear - newFront;
+        if (filled >= (ssize_t)overflowBit) {
+            // front and rear offsets span the overflow bit of the p2 mask
+            // so rebasing newFront on the front offset is off by the overflow bit.
+            // adjust newFront to match rear offset.
+            ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
+            newFront += overflowBit;
+            filled -= overflowBit;
+        }
+        // Rather than shutting down on a corrupt flush, just treat it as a full flush
+        if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
+            ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "
+                    "filled %zd=%#x",
+                    mFlush, flush, front, rear,
+                    (unsigned)mask, newFront, filled, (unsigned)filled);
+            newFront = rear;
+        }
+        mFlush = flush;
+        android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
+        // There is no danger from a false positive, so err on the side of caution
+        if (true /*front != newFront*/) {
+            int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
+            if (!(old & CBLK_FUTEX_WAKE)) {
+                (void) syscall(__NR_futex, &cblk->mFutex,
+                        mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
+            }
+        }
+        mFlushed += (newFront - front) & mask;
+    }
+}
+
+__attribute__((no_sanitize("integer")))
 status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
 {
     LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
@@ -636,44 +686,9 @@
     int32_t rear;
     // See notes on barriers at ClientProxy::obtainBuffer()
     if (mIsOut) {
-        int32_t flush = cblk->u.mStreaming.mFlush;
+        flushBufferIfNeeded(); // might modify mFront
         rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
         front = cblk->u.mStreaming.mFront;
-        if (flush != mFlush) {
-            // effectively obtain then release whatever is in the buffer
-            const size_t overflowBit = mFrameCountP2 << 1;
-            const size_t mask = overflowBit - 1;
-            int32_t newFront = (front & ~mask) | (flush & mask);
-            ssize_t filled = rear - newFront;
-            if (filled >= (ssize_t)overflowBit) {
-                // front and rear offsets span the overflow bit of the p2 mask
-                // so rebasing newFront on the front offset is off by the overflow bit.
-                // adjust newFront to match rear offset.
-                ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
-                newFront += overflowBit;
-                filled -= overflowBit;
-            }
-            // Rather than shutting down on a corrupt flush, just treat it as a full flush
-            if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
-                ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "
-                        "filled %zd=%#x",
-                        mFlush, flush, front, rear,
-                        (unsigned)mask, newFront, filled, (unsigned)filled);
-                newFront = rear;
-            }
-            mFlush = flush;
-            android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
-            // There is no danger from a false positive, so err on the side of caution
-            if (true /*front != newFront*/) {
-                int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
-                if (!(old & CBLK_FUTEX_WAKE)) {
-                    (void) syscall(__NR_futex, &cblk->mFutex,
-                            mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
-                }
-            }
-            mFlushed += (newFront - front) & mask;
-            front = newFront;
-        }
     } else {
         front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
         rear = cblk->u.mStreaming.mRear;
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index 31e310b..37bf0bd 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -55,7 +55,7 @@
 {
     ALOGV("Visualizer::~Visualizer()");
     setEnabled(false);
-    setCaptureCallBack(NULL, NULL, 0, 0, true);
+    setCaptureCallBack(NULL, NULL, 0, 0);
 }
 
 status_t Visualizer::setEnabled(bool enabled)
@@ -77,13 +77,11 @@
 
     status_t status = AudioEffect::setEnabled(enabled);
 
-    if (status == NO_ERROR) {
-        if (t != 0) {
-            if (enabled) {
-                t->run("Visualizer");
-            } else {
-                t->requestExit();
-            }
+    if (t != 0) {
+        if (enabled && status == NO_ERROR) {
+            t->run("Visualizer");
+        } else {
+            t->requestExit();
         }
     }
 
@@ -95,14 +93,14 @@
 }
 
 status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags,
-        uint32_t rate, bool force)
+        uint32_t rate)
 {
     if (rate > CAPTURE_RATE_MAX) {
         return BAD_VALUE;
     }
     Mutex::Autolock _l(mCaptureLock);
 
-    if (force || mEnabled) {
+    if (mEnabled) {
         return INVALID_OPERATION;
     }
 
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index a669dca..276d731 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -305,7 +305,10 @@
 
     sp<IMediaSource> source = mImpl->getTrack(index);
 
-    CHECK_EQ((status_t)OK, source->start());
+    status_t ret = source->start();
+    if (ret != OK) {
+        return ret;
+    }
 
     mSelectedTracks.push();
     TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1);
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp
index 76ec625..5b18814 100644
--- a/media/libstagefright/http/MediaHTTP.cpp
+++ b/media/libstagefright/http/MediaHTTP.cpp
@@ -58,15 +58,19 @@
         extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
     }
 
-    bool success = mHTTPConnection->connect(uri, &extHeaders);
+    mLastURI = uri;
+    // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
+    // as part of the above assignment. Ensure no accidental later use.
+    uri = NULL;
+
+    bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
 
     mLastHeaders = extHeaders;
-    mLastURI = uri;
 
     mCachedSizeValid = false;
 
     if (success) {
-        AString sanitized = uriDebugString(uri);
+        AString sanitized = uriDebugString(mLastURI);
         mName = String8::format("MediaHTTP(%s)", sanitized.c_str());
     }
 
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 26b41d0..93d6584 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -139,7 +139,6 @@
     mRepeatLastFrameTimestamp(-1ll),
     mLatestBufferId(-1),
     mLatestBufferFrameNum(0),
-    mLatestBufferUseCount(0),
     mLatestBufferFence(Fence::NO_FENCE),
     mRepeatBufferDeferred(false),
     mTimePerCaptureUs(-1ll),
@@ -398,12 +397,16 @@
     sp<Fence> fence = new Fence(fenceFd);
     if (mBufferSlot[id] != NULL &&
         mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
-        ALOGV("cbi %d matches bq slot %d, handle=%p",
-                cbi, id, mBufferSlot[id]->handle);
+        mBufferUseCount[id]--;
 
-        if (id == mLatestBufferId) {
-            CHECK_GT(mLatestBufferUseCount--, 0);
-        } else {
+        ALOGV("codecBufferEmptied: slot=%d, cbi=%d, useCount=%d, handle=%p",
+                id, cbi, mBufferUseCount[id], mBufferSlot[id]->handle);
+
+        if (mBufferUseCount[id] < 0) {
+            ALOGW("mBufferUseCount for bq slot %d < 0 (=%d)", id, mBufferUseCount[id]);
+            mBufferUseCount[id] = 0;
+        }
+        if (id != mLatestBufferId && mBufferUseCount[id] == 0) {
             releaseBuffer(id, codecBuffer.mFrameNumber, mBufferSlot[id], fence);
         }
     } else {
@@ -614,6 +617,7 @@
     if (item.mGraphicBuffer != NULL) {
         ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mSlot);
         mBufferSlot[item.mSlot] = item.mGraphicBuffer;
+        mBufferUseCount[item.mSlot] = 0;
     }
 
     if (item.mDataSpace != mLastDataSpace) {
@@ -699,7 +703,7 @@
         return false;
     }
 
-    ++mLatestBufferUseCount;
+    ++mBufferUseCount[item.mSlot];
 
     /* repeat last frame up to kRepeatLastFrameCount times.
      * in case of static scene, a single repeat might not get rid of encoder
@@ -720,10 +724,8 @@
 
 void GraphicBufferSource::setLatestBuffer_l(
         const BufferItem &item, bool dropped) {
-    ALOGV("setLatestBuffer_l");
-
     if (mLatestBufferId >= 0) {
-        if (mLatestBufferUseCount == 0) {
+        if (mBufferUseCount[mLatestBufferId] == 0) {
             releaseBuffer(mLatestBufferId, mLatestBufferFrameNum,
                     mBufferSlot[mLatestBufferId], mLatestBufferFence);
             // mLatestBufferFence will be set to new fence just below
@@ -734,7 +736,13 @@
     mLatestBufferFrameNum = item.mFrameNumber;
     mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
 
-    mLatestBufferUseCount = dropped ? 0 : 1;
+    if (!dropped) {
+        ++mBufferUseCount[item.mSlot];
+    }
+
+    ALOGV("setLatestBuffer_l: slot=%d, useCount=%d",
+            item.mSlot, mBufferUseCount[item.mSlot]);
+
     mRepeatBufferDeferred = false;
     mRepeatLastFrameCount = kRepeatLastFrameCount;
     mLatestBufferFence = item.mFence;
@@ -842,7 +850,7 @@
 }
 
 status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
-    ALOGV("submitBuffer_l cbi=%d", cbi);
+    ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
 
     int64_t timeUs = getTimestamp(item);
     if (timeUs < 0ll) {
@@ -935,6 +943,7 @@
 void GraphicBufferSource::releaseBuffer(
         int &id, uint64_t frameNum,
         const sp<GraphicBuffer> buffer, const sp<Fence> &fence) {
+    ALOGV("releaseBuffer: slot=%d", id);
     if (mIsPersistent) {
         mConsumer->detachBuffer(id);
         mBufferSlot[id] = NULL;
@@ -978,6 +987,7 @@
             if (item.mGraphicBuffer != NULL) {
                 ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mSlot);
                 mBufferSlot[item.mSlot] = item.mGraphicBuffer;
+                mBufferUseCount[item.mSlot] = 0;
             }
 
             releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -1011,6 +1021,7 @@
     for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
         if ((slotMask & 0x01) != 0) {
             mBufferSlot[i] = NULL;
+            mBufferUseCount[i] = 0;
         }
         slotMask >>= 1;
     }
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 30bfddb..aa4ceb3 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -295,6 +295,7 @@
     // is done processing a GraphicBuffer, we can use this to map back
     // to a slot number.
     sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
+    int32_t mBufferUseCount[BufferQueue::NUM_BUFFER_SLOTS];
 
     // Tracks codec buffers.
     Vector<CodecBuffer> mCodecBuffers;
@@ -327,7 +328,6 @@
 
     int mLatestBufferId;
     uint64_t mLatestBufferFrameNum;
-    int32_t mLatestBufferUseCount;
     sp<Fence> mLatestBufferFence;
 
     // The previous buffer should've been repeated but
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 35d5de6..e9ed570 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -372,8 +372,7 @@
 status_t OMXNodeInstance::sendCommand(
         OMX_COMMANDTYPE cmd, OMX_S32 param) {
     if (cmd == OMX_CommandStateSet) {
-        // We do not support returning from unloaded state, so there are no configurations past
-        // first StateSet command.
+        // There are no configurations past first StateSet command.
         mSailed = true;
     }
     const sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
@@ -531,6 +530,12 @@
 
 status_t OMXNodeInstance::enableNativeBuffers(
         OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable) {
+    if (portIndex >= NELEM(mSecureBufferType)) {
+        ALOGE("b/31385713, portIndex(%u)", portIndex);
+        android_errorWriteLog(0x534e4554, "31385713");
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock autoLock(mLock);
     CLOG_CONFIG(enableNativeBuffers, "%s:%u%s, %d", portString(portIndex), portIndex,
                 graphic ? ", graphic" : "", enable);
@@ -811,7 +816,7 @@
                 params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data);
     } else {
         buffer_meta = new BufferMeta(
-                params, portIndex, false /* copyFromOmx */, false /* copyToOmx */, NULL);
+                params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, NULL);
     }
 
     OMX_BUFFERHEADERTYPE *header;
@@ -1039,7 +1044,7 @@
     }
 
     BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
-    // update backup buffer for input, codec buffer for output
+    // update backup buffer
     sp<ABuffer> data = bufferMeta->getBuffer(
             header, false /* backup */, false /* limit */);
     bufferMeta->setNativeHandle(nativeHandle);
@@ -1217,6 +1222,12 @@
         return BAD_VALUE;
     }
 
+    if (portIndex >= NELEM(mSecureBufferType)) {
+        ALOGE("b/31385713, portIndex(%u)", portIndex);
+        android_errorWriteLog(0x534e4554, "31385713");
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock autoLock(mLock);
 
     BufferMeta *buffer_meta = new BufferMeta(size, portIndex);
@@ -1393,23 +1404,11 @@
     }
     BufferMeta *buffer_meta =
         static_cast<BufferMeta *>(header->pAppPrivate);
-    sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
-    sp<ABuffer> codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */);
 
-    // convert incoming ANW meta buffers if component is configured for gralloc metadata mode
-    // ignore rangeOffset in this case
-    if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource
-            && backup->capacity() >= sizeof(VideoNativeMetadata)
-            && codec->capacity() >= sizeof(VideoGrallocMetadata)
-            && ((VideoNativeMetadata *)backup->base())->eType
-                    == kMetadataBufferTypeANWBuffer) {
-        VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base();
-        VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base();
-        CLOG_BUFFER(emptyBuffer, "converting ANWB %p to handle %p",
-                backupMeta.pBuffer, backupMeta.pBuffer->handle);
-        codecMeta.pHandle = backupMeta.pBuffer != NULL ? backupMeta.pBuffer->handle : NULL;
-        codecMeta.eType = kMetadataBufferTypeGrallocSource;
-        header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0;
+    // set up proper filled length if component is configured for gralloc metadata mode
+    // ignore rangeOffset in this case (as client may be assuming ANW meta buffers).
+    if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
+        header->nFilledLen = rangeLength ? sizeof(VideoGrallocMetadata) : 0;
         header->nOffset = 0;
     } else {
         // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
@@ -1844,6 +1843,13 @@
             && arg2 == OMX_StateExecuting) {
         bufferSource->omxExecuting();
     }
+
+    // allow configuration if we return to the loaded state
+    if (event == OMX_EventCmdComplete
+            && arg1 == OMX_CommandStateSet
+            && arg2 == OMX_StateLoaded) {
+        mSailed = false;
+    }
 }
 
 // static
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b387af3..3cca054 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -777,6 +777,13 @@
         Mutex::Autolock _l(thread->mLock);
         PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
 
+        // Flush the ring buffer now if the track is not active in the PlaybackThread.
+        // Otherwise the flush would not be done until the track is resumed.
+        // Requires FastTrack removal be BLOCK_UNTIL_ACKED
+        if (playbackThread->mActiveTracks.indexOf(this) < 0) {
+            (void)mServerProxy->flushBufferIfNeeded();
+        }
+
         if (isOffloaded()) {
             // If offloaded we allow flush during any state except terminated
             // and keep the track active to avoid problems if user is seeking
@@ -828,6 +835,10 @@
     if (!isOffloaded() && !isDirect())
         return;
 
+    // Clear the client ring buffer so that the app can prime the buffer while paused.
+    // Otherwise it might not get cleared until playback is resumed and obtainBuffer() is called.
+    mServerProxy->flushBufferIfNeeded();
+
     mFlushHwPending = false;
 }
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 1ddfb4d..9095cde 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -4939,6 +4939,18 @@
                                         audio_devices_t device)
 {
     float volumeDB = mVolumeCurves->volIndexToDb(stream, Volume::getDeviceCategory(device), index);
+
+    // handle the case of accessibility active while a ringtone is playing: if the ringtone is much
+    // louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
+    // exploration of the dialer UI. In this situation, bring the accessibility volume closer to
+    // the ringtone volume
+    if ((stream == AUDIO_STREAM_ACCESSIBILITY)
+            && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState())
+            && isStreamActive(AUDIO_STREAM_RING, 0)) {
+        const float ringVolumeDB = computeVolume(AUDIO_STREAM_RING, index, device);
+        return ringVolumeDB - 4 > volumeDB ? ringVolumeDB - 4 : volumeDB;
+    }
+
     // if a headset is connected, apply the following rules to ring tones and notifications
     // to avoid sound level bursts in user's ears:
     // - always attenuate notifications volume by 6dB