Merge "audio policy: allow direct outputs for dynamic audio policies" into rvc-dev
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
index ccc73b6..1ce8269 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
@@ -91,6 +91,19 @@
     return Void();
 }
 
+Return<void> DrmFactory::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /*args*/) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+        ALOGE("%s: missing fd for writing", __FUNCTION__);
+        return Void();
+    }
+
+    FILE* out = fdopen(dup(fd->data[0]), "w");
+    uint32_t currentSessions = SessionLibrary::get()->numOpenSessions();
+    fprintf(out, "current open sessions: %u\n", currentSessions);
+    fclose(out);
+    return Void();
+}
+
 } // namespace clearkey
 } // namespace V1_3
 } // namespace drm
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
index 403a8ec..63234cf 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
@@ -30,6 +30,7 @@
 
 using ::android::hardware::drm::V1_1::SecurityLevel;
 using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::hardware::Return;
 
@@ -55,6 +56,8 @@
     Return<void> getSupportedCryptoSchemes(
             getSupportedCryptoSchemes_cb _hidl_cb) override;
 
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args);
+
 private:
     CLEARKEY_DISALLOW_COPY_AND_ASSIGN(DrmFactory);
 };
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 6b389d5..e2be991 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -127,97 +127,6 @@
     count->value = -1;
 }
 
-// CCodecBufferChannel::ReorderStash
-
-CCodecBufferChannel::ReorderStash::ReorderStash() {
-    clear();
-}
-
-void CCodecBufferChannel::ReorderStash::clear() {
-    mPending.clear();
-    mStash.clear();
-    mDepth = 0;
-    mKey = C2Config::ORDINAL;
-}
-
-void CCodecBufferChannel::ReorderStash::flush() {
-    mPending.clear();
-    mStash.clear();
-}
-
-void CCodecBufferChannel::ReorderStash::setDepth(uint32_t depth) {
-    mPending.splice(mPending.end(), mStash);
-    mDepth = depth;
-}
-
-void CCodecBufferChannel::ReorderStash::setKey(C2Config::ordinal_key_t key) {
-    mPending.splice(mPending.end(), mStash);
-    mKey = key;
-}
-
-bool CCodecBufferChannel::ReorderStash::pop(Entry *entry) {
-    if (mPending.empty()) {
-        return false;
-    }
-    entry->buffer     = mPending.front().buffer;
-    entry->timestamp  = mPending.front().timestamp;
-    entry->flags      = mPending.front().flags;
-    entry->ordinal    = mPending.front().ordinal;
-    mPending.pop_front();
-    return true;
-}
-
-void CCodecBufferChannel::ReorderStash::emplace(
-        const std::shared_ptr<C2Buffer> &buffer,
-        int64_t timestamp,
-        int32_t flags,
-        const C2WorkOrdinalStruct &ordinal) {
-    bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
-    if (!buffer && eos) {
-        // TRICKY: we may be violating ordering of the stash here. Because we
-        // don't expect any more emplace() calls after this, the ordering should
-        // not matter.
-        mStash.emplace_back(buffer, timestamp, flags, ordinal);
-    } else {
-        flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
-        auto it = mStash.begin();
-        for (; it != mStash.end(); ++it) {
-            if (less(ordinal, it->ordinal)) {
-                break;
-            }
-        }
-        mStash.emplace(it, buffer, timestamp, flags, ordinal);
-        if (eos) {
-            mStash.back().flags = mStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
-        }
-    }
-    while (!mStash.empty() && mStash.size() > mDepth) {
-        mPending.push_back(mStash.front());
-        mStash.pop_front();
-    }
-}
-
-void CCodecBufferChannel::ReorderStash::defer(
-        const CCodecBufferChannel::ReorderStash::Entry &entry) {
-    mPending.push_front(entry);
-}
-
-bool CCodecBufferChannel::ReorderStash::hasPending() const {
-    return !mPending.empty();
-}
-
-bool CCodecBufferChannel::ReorderStash::less(
-        const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) {
-    switch (mKey) {
-        case C2Config::ORDINAL:   return o1.frameIndex < o2.frameIndex;
-        case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
-        case C2Config::CUSTOM:    return o1.customOrdinal < o2.customOrdinal;
-        default:
-            ALOGD("Unrecognized key; default to timestamp");
-            return o1.frameIndex < o2.frameIndex;
-    }
-}
-
 // Input
 
 CCodecBufferChannel::Input::Input() : extraBuffers("extra") {}
@@ -707,7 +616,7 @@
 
 void CCodecBufferChannel::feedInputBufferIfAvailableInternal() {
     if (mInputMetEos ||
-           mReorderStash.lock()->hasPending() ||
+           mOutput.lock()->buffers->hasPending() ||
            mPipelineWatcher.lock()->pipelineFull()) {
         return;
     } else {
@@ -980,17 +889,6 @@
         return UNKNOWN_ERROR;
     }
 
-    {
-        Mutexed<ReorderStash>::Locked reorder(mReorderStash);
-        reorder->clear();
-        if (reorderDepth) {
-            reorder->setDepth(reorderDepth.value);
-        }
-        if (reorderKey) {
-            reorder->setKey(reorderKey.value);
-        }
-    }
-
     uint32_t inputDelayValue = inputDelay ? inputDelay.value : 0;
     uint32_t pipelineDelayValue = pipelineDelay ? pipelineDelay.value : 0;
     uint32_t outputDelayValue = outputDelay ? outputDelay.value : 0;
@@ -1259,6 +1157,13 @@
         }
         output->buffers->setFormat(outputFormat);
 
+        output->buffers->clearStash();
+        if (reorderDepth) {
+            output->buffers->setReorderDepth(reorderDepth.value);
+        }
+        if (reorderKey) {
+            output->buffers->setReorderKey(reorderKey.value);
+        }
 
         // Try to set output surface to created block pool if given.
         if (outputSurface) {
@@ -1426,8 +1331,8 @@
     {
         Mutexed<Output>::Locked output(mOutput);
         output->buffers->flush(flushedWork);
+        output->buffers->flushStash();
     }
-    mReorderStash.lock()->flush();
     mPipelineWatcher.lock()->flush();
 }
 
@@ -1463,45 +1368,34 @@
         std::unique_ptr<C2Work> work,
         const sp<AMessage> &outputFormat,
         const C2StreamInitDataInfo::output *initData) {
-    if (outputFormat != nullptr) {
-        Mutexed<Output>::Locked output(mOutput);
-        ALOGD("[%s] onWorkDone: output format changed to %s",
-                mName, outputFormat->debugString().c_str());
-        output->buffers->setFormat(outputFormat);
+    // Whether the output buffer should be reported to the client or not.
+    bool notifyClient = false;
 
-        AString mediaType;
-        if (outputFormat->findString(KEY_MIME, &mediaType)
-                && mediaType == MIMETYPE_AUDIO_RAW) {
-            int32_t channelCount;
-            int32_t sampleRate;
-            if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
-                    && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
-                output->buffers->updateSkipCutBuffer(sampleRate, channelCount);
-            }
-        }
+    if (work->result == C2_OK){
+        notifyClient = true;
+    } else if (work->result == C2_NOT_FOUND) {
+        ALOGD("[%s] flushed work; ignored.", mName);
+    } else {
+        // C2_OK and C2_NOT_FOUND are the only results that we accept for processing
+        // the config update.
+        ALOGD("[%s] work failed to complete: %d", mName, work->result);
+        mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
+        return false;
     }
 
-    if ((work->input.ordinal.frameIndex - mFirstValidFrameIndex.load()).peek() < 0) {
+    if ((work->input.ordinal.frameIndex -
+            mFirstValidFrameIndex.load()).peek() < 0) {
         // Discard frames from previous generation.
         ALOGD("[%s] Discard frames from previous generation.", mName);
-        return false;
+        notifyClient = false;
     }
 
     if (mInputSurface == nullptr && (work->worklets.size() != 1u
             || !work->worklets.front()
-            || !(work->worklets.front()->output.flags & C2FrameData::FLAG_INCOMPLETE))) {
-        mPipelineWatcher.lock()->onWorkDone(work->input.ordinal.frameIndex.peeku());
-    }
-
-    if (work->result == C2_NOT_FOUND) {
-        ALOGD("[%s] flushed work; ignored.", mName);
-        return true;
-    }
-
-    if (work->result != C2_OK) {
-        ALOGD("[%s] work failed to complete: %d", mName, work->result);
-        mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
-        return false;
+            || !(work->worklets.front()->output.flags &
+                 C2FrameData::FLAG_INCOMPLETE))) {
+        mPipelineWatcher.lock()->onWorkDone(
+                work->input.ordinal.frameIndex.peeku());
     }
 
     // NOTE: MediaCodec usage supposedly have only one worklet
@@ -1537,8 +1431,10 @@
             case C2PortReorderBufferDepthTuning::CORE_INDEX: {
                 C2PortReorderBufferDepthTuning::output reorderDepth;
                 if (reorderDepth.updateFrom(*param)) {
-                    bool secure = mComponent->getName().find(".secure") != std::string::npos;
-                    mReorderStash.lock()->setDepth(reorderDepth.value);
+                    bool secure = mComponent->getName().find(".secure") !=
+                                  std::string::npos;
+                    mOutput.lock()->buffers->setReorderDepth(
+                            reorderDepth.value);
                     ALOGV("[%s] onWorkDone: updated reorder depth to %u",
                           mName, reorderDepth.value);
                     size_t numOutputSlots = mOutput.lock()->numSlots;
@@ -1550,17 +1446,19 @@
                         output->maxDequeueBuffers += numInputSlots;
                     }
                     if (output->surface) {
-                        output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
+                        output->surface->setMaxDequeuedBufferCount(
+                                output->maxDequeueBuffers);
                     }
                 } else {
-                    ALOGD("[%s] onWorkDone: failed to read reorder depth", mName);
+                    ALOGD("[%s] onWorkDone: failed to read reorder depth",
+                          mName);
                 }
                 break;
             }
             case C2PortReorderKeySetting::CORE_INDEX: {
                 C2PortReorderKeySetting::output reorderKey;
                 if (reorderKey.updateFrom(*param)) {
-                    mReorderStash.lock()->setKey(reorderKey.value);
+                    mOutput.lock()->buffers->setReorderKey(reorderKey.value);
                     ALOGV("[%s] onWorkDone: updated reorder key to %u",
                           mName, reorderKey.value);
                 } else {
@@ -1575,7 +1473,8 @@
                         ALOGV("[%s] onWorkDone: updating pipeline delay %u",
                               mName, pipelineDelay.value);
                         newPipelineDelay = pipelineDelay.value;
-                        (void)mPipelineWatcher.lock()->pipelineDelay(pipelineDelay.value);
+                        (void)mPipelineWatcher.lock()->pipelineDelay(
+                                pipelineDelay.value);
                     }
                 }
                 if (param->forInput()) {
@@ -1584,7 +1483,8 @@
                         ALOGV("[%s] onWorkDone: updating input delay %u",
                               mName, inputDelay.value);
                         newInputDelay = inputDelay.value;
-                        (void)mPipelineWatcher.lock()->inputDelay(inputDelay.value);
+                        (void)mPipelineWatcher.lock()->inputDelay(
+                                inputDelay.value);
                     }
                 }
                 if (param->forOutput()) {
@@ -1592,8 +1492,10 @@
                     if (outputDelay.updateFrom(*param)) {
                         ALOGV("[%s] onWorkDone: updating output delay %u",
                               mName, outputDelay.value);
-                        bool secure = mComponent->getName().find(".secure") != std::string::npos;
-                        (void)mPipelineWatcher.lock()->outputDelay(outputDelay.value);
+                        bool secure = mComponent->getName().find(".secure") !=
+                                      std::string::npos;
+                        (void)mPipelineWatcher.lock()->outputDelay(
+                                outputDelay.value);
 
                         bool outputBuffersChanged = false;
                         size_t numOutputSlots = 0;
@@ -1601,7 +1503,8 @@
                         {
                             Mutexed<Output>::Locked output(mOutput);
                             output->outputDelay = outputDelay.value;
-                            numOutputSlots = outputDelay.value + kSmoothnessFactor;
+                            numOutputSlots = outputDelay.value +
+                                             kSmoothnessFactor;
                             if (output->numSlots < numOutputSlots) {
                                 output->numSlots = numOutputSlots;
                                 if (output->buffers->isArrayMode()) {
@@ -1620,7 +1523,7 @@
                             mCCodecCallback->onOutputBuffersChanged();
                         }
 
-                        uint32_t depth = mReorderStash.lock()->depth();
+                        uint32_t depth = mOutput.lock()->buffers->getReorderDepth();
                         Mutexed<OutputSurface>::Locked output(mOutputSurface);
                         output->maxDequeueBuffers = numOutputSlots + depth + kRenderingDepth;
                         if (!secure) {
@@ -1664,9 +1567,6 @@
         ALOGV("[%s] onWorkDone: output EOS", mName);
     }
 
-    sp<MediaCodecBuffer> outBuffer;
-    size_t index;
-
     // WORKAROUND: adjust output timestamp based on client input timestamp and codec
     // input timestamp. Codec output timestamp (in the timestamp field) shall correspond to
     // the codec input timestamp, but client output timestamp should (reported in timeUs)
@@ -1687,8 +1587,18 @@
           worklet->output.ordinal.timestamp.peekll(),
           timestamp.peekll());
 
+    // csd cannot be re-ordered and will always arrive first.
     if (initData != nullptr) {
         Mutexed<Output>::Locked output(mOutput);
+        if (outputFormat) {
+            output->buffers->updateSkipCutBuffer(outputFormat);
+            output->buffers->setFormat(outputFormat);
+        }
+        if (!notifyClient) {
+            return false;
+        }
+        size_t index;
+        sp<MediaCodecBuffer> outBuffer;
         if (output->buffers->registerCsd(initData, &index, &outBuffer) == OK) {
             outBuffer->meta()->setInt64("timeUs", timestamp.peek());
             outBuffer->meta()->setInt32("flags", MediaCodec::BUFFER_FLAG_CODECCONFIG);
@@ -1704,10 +1614,10 @@
         }
     }
 
-    if (!buffer && !flags) {
+    if (notifyClient && !buffer && !flags) {
         ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
               mName, work->input.ordinal.frameIndex.peekull());
-        return true;
+        notifyClient = false;
     }
 
     if (buffer) {
@@ -1726,63 +1636,60 @@
     }
 
     {
-        Mutexed<ReorderStash>::Locked reorder(mReorderStash);
-        reorder->emplace(buffer, timestamp.peek(), flags, worklet->output.ordinal);
-        if (flags & MediaCodec::BUFFER_FLAG_EOS) {
-            // Flush reorder stash
-            reorder->setDepth(0);
-        }
+        Mutexed<Output>::Locked output(mOutput);
+        output->buffers->pushToStash(
+                buffer,
+                notifyClient,
+                timestamp.peek(),
+                flags,
+                outputFormat,
+                worklet->output.ordinal);
     }
     sendOutputBuffers();
     return true;
 }
 
 void CCodecBufferChannel::sendOutputBuffers() {
-    ReorderStash::Entry entry;
-    sp<MediaCodecBuffer> outBuffer;
+    OutputBuffers::BufferAction action;
     size_t index;
+    sp<MediaCodecBuffer> outBuffer;
+    std::shared_ptr<C2Buffer> c2Buffer;
 
     while (true) {
-        Mutexed<ReorderStash>::Locked reorder(mReorderStash);
-        if (!reorder->hasPending()) {
-            break;
-        }
-        if (!reorder->pop(&entry)) {
-            break;
-        }
-
         Mutexed<Output>::Locked output(mOutput);
-        status_t err = output->buffers->registerBuffer(entry.buffer, &index, &outBuffer);
-        if (err != OK) {
-            bool outputBuffersChanged = false;
-            if (err != WOULD_BLOCK) {
-                if (!output->buffers->isArrayMode()) {
-                    output->buffers = output->buffers->toArrayMode(output->numSlots);
-                }
-                OutputBuffersArray *array = (OutputBuffersArray *)output->buffers.get();
-                array->realloc(entry.buffer);
-                outputBuffersChanged = true;
-            }
-            ALOGV("[%s] sendOutputBuffers: unable to register output buffer", mName);
-            reorder->defer(entry);
-
+        action = output->buffers->popFromStashAndRegister(
+                &c2Buffer, &index, &outBuffer);
+        switch (action) {
+        case OutputBuffers::SKIP:
+            return;
+        case OutputBuffers::DISCARD:
+            break;
+        case OutputBuffers::NOTIFY_CLIENT:
             output.unlock();
-            reorder.unlock();
-
-            if (outputBuffersChanged) {
+            mCallback->onOutputBufferAvailable(index, outBuffer);
+            break;
+        case OutputBuffers::REALLOCATE: {
+                if (!output->buffers->isArrayMode()) {
+                    output->buffers =
+                        output->buffers->toArrayMode(output->numSlots);
+                }
+                static_cast<OutputBuffersArray*>(output->buffers.get())->
+                        realloc(c2Buffer);
+                output.unlock();
                 mCCodecCallback->onOutputBuffersChanged();
             }
             return;
+        case OutputBuffers::RETRY:
+            ALOGV("[%s] sendOutputBuffers: unable to register output buffer",
+                  mName);
+            return;
+        default:
+            LOG_ALWAYS_FATAL("[%s] sendOutputBuffers: "
+                    "corrupted BufferAction value (%d) "
+                    "returned from popFromStashAndRegister.",
+                    mName, int(action));
+            return;
         }
-        output.unlock();
-        reorder.unlock();
-
-        outBuffer->meta()->setInt64("timeUs", entry.timestamp);
-        outBuffer->meta()->setInt32("flags", entry.flags);
-        ALOGV("[%s] sendOutputBuffers: out buffer index = %zu [%p] => %p + %zu (%lld)",
-                mName, index, outBuffer.get(), outBuffer->data(), outBuffer->size(),
-                (long long)entry.timestamp);
-        mCallback->onOutputBufferAvailable(index, outBuffer);
     }
 }
 
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 0263211..da15724 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -296,48 +296,6 @@
 
     Mutexed<PipelineWatcher> mPipelineWatcher;
 
-    class ReorderStash {
-    public:
-        struct Entry {
-            inline Entry() : buffer(nullptr), timestamp(0), flags(0), ordinal({0, 0, 0}) {}
-            inline Entry(
-                    const std::shared_ptr<C2Buffer> &b,
-                    int64_t t,
-                    int32_t f,
-                    const C2WorkOrdinalStruct &o)
-                : buffer(b), timestamp(t), flags(f), ordinal(o) {}
-            std::shared_ptr<C2Buffer> buffer;
-            int64_t timestamp;
-            int32_t flags;
-            C2WorkOrdinalStruct ordinal;
-        };
-
-        ReorderStash();
-
-        void clear();
-        void flush();
-        void setDepth(uint32_t depth);
-        void setKey(C2Config::ordinal_key_t key);
-        bool pop(Entry *entry);
-        void emplace(
-                const std::shared_ptr<C2Buffer> &buffer,
-                int64_t timestamp,
-                int32_t flags,
-                const C2WorkOrdinalStruct &ordinal);
-        void defer(const Entry &entry);
-        bool hasPending() const;
-        uint32_t depth() const { return mDepth; }
-
-    private:
-        std::list<Entry> mPending;
-        std::list<Entry> mStash;
-        uint32_t mDepth;
-        C2Config::ordinal_key_t mKey;
-
-        bool less(const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2);
-    };
-    Mutexed<ReorderStash> mReorderStash;
-
     std::atomic_bool mInputMetEos;
     std::once_flag mRenderWarningFlag;
 
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index d7cc175..4ce13aa 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -21,6 +21,7 @@
 #include <C2PlatformSupport.h>
 
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/SkipCutBuffer.h>
 
@@ -149,16 +150,29 @@
     setSkipCutBuffer(delay, padding);
 }
 
+void OutputBuffers::updateSkipCutBuffer(
+        const sp<AMessage> &format, bool notify) {
+    AString mediaType;
+    if (format->findString(KEY_MIME, &mediaType)
+            && mediaType == MIMETYPE_AUDIO_RAW) {
+        int32_t channelCount;
+        int32_t sampleRate;
+        if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
+                && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
+            updateSkipCutBuffer(sampleRate, channelCount);
+        }
+    }
+    if (notify) {
+        mUnreportedFormat = nullptr;
+    }
+}
+
 void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
     if (mSkipCutBuffer != nullptr) {
         mSkipCutBuffer->submit(buffer);
     }
 }
 
-void OutputBuffers::transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
-    mSkipCutBuffer = scb;
-}
-
 void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
     if (mSkipCutBuffer != nullptr) {
         size_t prevSize = mSkipCutBuffer->size();
@@ -169,6 +183,175 @@
     mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
 }
 
+void OutputBuffers::clearStash() {
+    mPending.clear();
+    mReorderStash.clear();
+    mDepth = 0;
+    mKey = C2Config::ORDINAL;
+    mUnreportedFormat = nullptr;
+}
+
+void OutputBuffers::flushStash() {
+    for (StashEntry& e : mPending) {
+        e.notify = false;
+    }
+    for (StashEntry& e : mReorderStash) {
+        e.notify = false;
+    }
+}
+
+uint32_t OutputBuffers::getReorderDepth() const {
+    return mDepth;
+}
+
+void OutputBuffers::setReorderDepth(uint32_t depth) {
+    mPending.splice(mPending.end(), mReorderStash);
+    mDepth = depth;
+}
+
+void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
+    mPending.splice(mPending.end(), mReorderStash);
+    mKey = key;
+}
+
+void OutputBuffers::pushToStash(
+        const std::shared_ptr<C2Buffer>& buffer,
+        bool notify,
+        int64_t timestamp,
+        int32_t flags,
+        const sp<AMessage>& format,
+        const C2WorkOrdinalStruct& ordinal) {
+    bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
+    if (!buffer && eos) {
+        // TRICKY: we may be violating ordering of the stash here. Because we
+        // don't expect any more emplace() calls after this, the ordering should
+        // not matter.
+        mReorderStash.emplace_back(
+                buffer, notify, timestamp, flags, format, ordinal);
+    } else {
+        flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
+        auto it = mReorderStash.begin();
+        for (; it != mReorderStash.end(); ++it) {
+            if (less(ordinal, it->ordinal)) {
+                break;
+            }
+        }
+        mReorderStash.emplace(it,
+                buffer, notify, timestamp, flags, format, ordinal);
+        if (eos) {
+            mReorderStash.back().flags =
+                mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
+        }
+    }
+    while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
+        mPending.push_back(mReorderStash.front());
+        mReorderStash.pop_front();
+    }
+    ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
+}
+
+OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
+        std::shared_ptr<C2Buffer>* c2Buffer,
+        size_t* index,
+        sp<MediaCodecBuffer>* outBuffer) {
+    if (mPending.empty()) {
+        return SKIP;
+    }
+
+    // Retrieve the first entry.
+    StashEntry &entry = mPending.front();
+
+    *c2Buffer = entry.buffer;
+    sp<AMessage> outputFormat = entry.format;
+
+    // The output format can be processed without a registered slot.
+    if (outputFormat) {
+        ALOGD("[%s] popFromStashAndRegister: output format changed to %s",
+                mName, outputFormat->debugString().c_str());
+        updateSkipCutBuffer(outputFormat, entry.notify);
+    }
+
+    if (entry.notify) {
+        if (outputFormat) {
+            setFormat(outputFormat);
+        } else if (mUnreportedFormat) {
+            outputFormat = mUnreportedFormat->dup();
+            setFormat(outputFormat);
+        }
+        mUnreportedFormat = nullptr;
+    } else {
+        if (outputFormat) {
+            mUnreportedFormat = outputFormat;
+        } else if (!mUnreportedFormat) {
+            mUnreportedFormat = mFormat;
+        }
+    }
+
+    // Flushing mReorderStash because no other buffers should come after output
+    // EOS.
+    if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
+        // Flush reorder stash
+        setReorderDepth(0);
+    }
+
+    if (!entry.notify) {
+        mPending.pop_front();
+        return DISCARD;
+    }
+
+    // Try to register the buffer.
+    status_t err = registerBuffer(*c2Buffer, index, outBuffer);
+    if (err != OK) {
+        if (err != WOULD_BLOCK) {
+            return REALLOCATE;
+        }
+        return RETRY;
+    }
+
+    // Append information from the front stash entry to outBuffer.
+    (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
+    (*outBuffer)->meta()->setInt32("flags", entry.flags);
+    ALOGV("[%s] popFromStashAndRegister: "
+          "out buffer index = %zu [%p] => %p + %zu (%lld)",
+          mName, *index, outBuffer->get(),
+          (*outBuffer)->data(), (*outBuffer)->size(),
+          (long long)entry.timestamp);
+
+    // The front entry of mPending will be removed now that the registration
+    // succeeded.
+    mPending.pop_front();
+    return NOTIFY_CLIENT;
+}
+
+bool OutputBuffers::popPending(StashEntry *entry) {
+    if (mPending.empty()) {
+        return false;
+    }
+    *entry = mPending.front();
+    mPending.pop_front();
+    return true;
+}
+
+void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
+    mPending.push_front(entry);
+}
+
+bool OutputBuffers::hasPending() const {
+    return !mPending.empty();
+}
+
+bool OutputBuffers::less(
+        const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
+    switch (mKey) {
+        case C2Config::ORDINAL:   return o1.frameIndex < o2.frameIndex;
+        case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
+        case C2Config::CUSTOM:    return o1.customOrdinal < o2.customOrdinal;
+        default:
+            ALOGD("Unrecognized key; default to timestamp");
+            return o1.frameIndex < o2.frameIndex;
+    }
+}
+
 // LocalBufferPool
 
 std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
@@ -968,6 +1151,16 @@
     mImpl.grow(newSize, mAlloc);
 }
 
+void OutputBuffersArray::transferFrom(OutputBuffers* source) {
+    mFormat = source->mFormat;
+    mSkipCutBuffer = source->mSkipCutBuffer;
+    mUnreportedFormat = source->mUnreportedFormat;
+    mPending = std::move(source->mPending);
+    mReorderStash = std::move(source->mReorderStash);
+    mDepth = source->mDepth;
+    mKey = source->mKey;
+}
+
 // FlexOutputBuffers
 
 status_t FlexOutputBuffers::registerBuffer(
@@ -1010,13 +1203,12 @@
     // track of the flushed work.
 }
 
-std::unique_ptr<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) {
+std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
     std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
-    array->setFormat(mFormat);
-    array->transferSkipCutBuffer(mSkipCutBuffer);
+    array->transferFrom(this);
     std::function<sp<Codec2Buffer>()> alloc = getAlloc();
     array->initialize(mImpl, size, alloc);
-    return std::move(array);
+    return array;
 }
 
 size_t FlexOutputBuffers::numClientBuffers() const {
diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h
index 85ca5d5..cadc4d8 100644
--- a/media/codec2/sfplugin/CCodecBuffers.h
+++ b/media/codec2/sfplugin/CCodecBuffers.h
@@ -154,6 +154,8 @@
     DISALLOW_EVIL_CONSTRUCTORS(InputBuffers);
 };
 
+class OutputBuffersArray;
+
 class OutputBuffers : public CCodecBuffers {
 public:
     OutputBuffers(const char *componentName, const char *name = "Output")
@@ -162,8 +164,12 @@
 
     /**
      * Register output C2Buffer from the component and obtain corresponding
-     * index and MediaCodecBuffer object. Returns false if registration
-     * fails.
+     * index and MediaCodecBuffer object.
+     *
+     * Returns:
+     *   OK if registration succeeds.
+     *   NO_MEMORY if all buffers are available but not compatible.
+     *   WOULD_BLOCK if there are compatible buffers, but they are all in use.
      */
     virtual status_t registerBuffer(
             const std::shared_ptr<C2Buffer> &buffer,
@@ -198,7 +204,7 @@
      * shall retain the internal state so that it will honor index and
      * buffer from previous calls of registerBuffer().
      */
-    virtual std::unique_ptr<OutputBuffers> toArrayMode(size_t size) = 0;
+    virtual std::unique_ptr<OutputBuffersArray> toArrayMode(size_t size) = 0;
 
     /**
      * Initialize SkipCutBuffer object.
@@ -207,6 +213,164 @@
             int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount);
 
     /**
+     * Update SkipCutBuffer from format. The @p format must not be null.
+     * @p notify determines whether the format comes with a buffer that should
+     * be reported to the client or not.
+     */
+    void updateSkipCutBuffer(const sp<AMessage> &format, bool notify = true);
+
+    /**
+     * Output Stash
+     * ============
+     *
+     * The output stash is a place to hold output buffers temporarily before
+     * they are registered to output slots. It has 2 main functions:
+     * 1. Allow reordering of output frames as the codec may produce frames in a
+     *    different order.
+     * 2. Act as a "buffer" between the codec and the client because the codec
+     *    may produce more buffers than available slots. This excess of codec's
+     *    output buffers should be registered to slots later, after the client
+     *    has released some slots.
+     *
+     * The stash consists of 2 lists of buffers: mPending and mReorderStash.
+     * mPending is a normal FIFO queue with not size limit, while mReorderStash
+     * is a sorted list with size limit mDepth.
+     *
+     * The normal flow of a non-csd output buffer is as follows:
+     *
+     *           |----------------OutputBuffers---------------|
+     *           |----------Output stash----------|           |
+     *   Codec --|-> mReorderStash --> mPending --|-> slots --|-> client
+     *           |                                |           |
+     *     pushToStash()                    popFromStashAndRegister()
+     *
+     * The buffer that comes from the codec first enters mReorderStash. The
+     * first buffer in mReorderStash gets moved to mPending when mReorderStash
+     * overflows. Buffers in mPending are registered to slots and given to the
+     * client as soon as slots are available.
+     *
+     * Every output buffer that is not a csd buffer should be put on the stash
+     * by calling pushToStash(), then later registered to a slot by calling
+     * popFromStashAndRegister() before notifying the client with
+     * onOutputBufferAvailable().
+     *
+     * Reordering
+     * ==========
+     *
+     * mReorderStash is a sorted list with a specified size limit. The size
+     * limit can be set by calling setReorderDepth().
+     *
+     * Every buffer in mReorderStash has a C2WorkOrdinalStruct, which contains 3
+     * members, all of which are comparable. Which member of C2WorkOrdinalStruct
+     * should be used for reordering can be chosen by calling setReorderKey().
+     */
+
+    /**
+     * Return the reorder depth---the size of mReorderStash.
+     */
+    uint32_t getReorderDepth() const;
+
+    /**
+     * Set the reorder depth.
+     */
+    void setReorderDepth(uint32_t depth);
+
+    /**
+     * Set the type of "key" to use in comparisons.
+     */
+    void setReorderKey(C2Config::ordinal_key_t key);
+
+    /**
+     * Return whether the output stash has any pending buffers.
+     */
+    bool hasPending() const;
+
+    /**
+     * Flush the stash and reset the depth and the key to their default values.
+     */
+    void clearStash();
+
+    /**
+     * Flush the stash.
+     */
+    void flushStash();
+
+    /**
+     * Push a buffer to the reorder stash.
+     *
+     * @param buffer    C2Buffer object from the returned work.
+     * @param notify    Whether the returned work contains a buffer that should
+     *                  be reported to the client. This may be false if the
+     *                  caller wants to process the buffer without notifying the
+     *                  client.
+     * @param timestamp Buffer timestamp to report to the client.
+     * @param flags     Buffer flags to report to the client.
+     * @param format    Buffer format to report to the client.
+     * @param ordinal   Ordinal used in reordering. This determines when the
+     *                  buffer will be popped from the output stash by
+     *                  `popFromStashAndRegister()`.
+     */
+    void pushToStash(
+            const std::shared_ptr<C2Buffer>& buffer,
+            bool notify,
+            int64_t timestamp,
+            int32_t flags,
+            const sp<AMessage>& format,
+            const C2WorkOrdinalStruct& ordinal);
+
+    enum BufferAction : int {
+        SKIP,
+        DISCARD,
+        NOTIFY_CLIENT,
+        REALLOCATE,
+        RETRY,
+    };
+
+    /**
+     * Try to atomically pop the first buffer from the reorder stash and
+     * register it to an output slot. The function returns a value that
+     * indicates a recommended course of action for the caller.
+     *
+     * If the stash is empty, the function will return `SKIP`.
+     *
+     * If the stash is not empty, the function will peek at the first (oldest)
+     * entry in mPending process the buffer in the entry as follows:
+     * - If the buffer should not be sent to the client, the function will
+     *   return `DISCARD`. The stash entry will be removed.
+     * - If the buffer should be sent to the client, the function will attempt
+     *   to register the buffer to a slot. The registration may have 3 outcomes
+     *   corresponding to the following return values:
+     *   - `NOTIFY_CLIENT`: The buffer is successfully registered to a slot. The
+     *     output arguments @p index and @p outBuffer will contain valid values
+     *     that the caller can use to call onOutputBufferAvailable(). The stash
+     *     entry will be removed.
+     *   - `REALLOCATE`: The buffer is not registered because it is not
+     *     compatible with the current slots (which are available). The caller
+     *     should reallocate the OutputBuffers with slots that can fit the
+     *     returned @p c2Buffer. The stash entry will not be removed
+     *   - `RETRY`: All slots are currently occupied by the client. The caller
+     *     should try to call this function again after the client has released
+     *     some slots.
+     *
+     * @return What the caller should do afterwards.
+     *
+     * @param[out] c2Buffer   Underlying C2Buffer associated to the first buffer
+     *                        on the stash. This value is guaranteed to be valid
+     *                        unless the return value is `SKIP`.
+     * @param[out] index      Slot index. This value is valid only if the return
+     *                        value is `NOTIFY_CLIENT`.
+     * @param[out] outBuffer  Registered buffer. This value is valid only if the
+     *                        return valu is `NOTIFY_CLIENT`.
+     */
+    BufferAction popFromStashAndRegister(
+            std::shared_ptr<C2Buffer>* c2Buffer,
+            size_t* index,
+            sp<MediaCodecBuffer>* outBuffer);
+
+protected:
+    sp<SkipCutBuffer> mSkipCutBuffer;
+
+    /**
      * Update the SkipCutBuffer object. No-op if it's never initialized.
      */
     void updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount);
@@ -216,15 +380,8 @@
      */
     void submit(const sp<MediaCodecBuffer> &buffer);
 
-    /**
-     * Transfer SkipCutBuffer object to the other Buffers object.
-     */
-    void transferSkipCutBuffer(const sp<SkipCutBuffer> &scb);
-
-protected:
-    sp<SkipCutBuffer> mSkipCutBuffer;
-
 private:
+    // SkipCutBuffer
     int32_t mDelay;
     int32_t mPadding;
     int32_t mSampleRate;
@@ -232,7 +389,78 @@
 
     void setSkipCutBuffer(int32_t skip, int32_t cut);
 
+    // Output stash
+
+    // Output format that has not been made available to the client.
+    sp<AMessage> mUnreportedFormat;
+
+    // Struct for an entry in the output stash (mPending and mReorderStash)
+    struct StashEntry {
+        inline StashEntry()
+            : buffer(nullptr),
+              notify(false),
+              timestamp(0),
+              flags(0),
+              format(),
+              ordinal({0, 0, 0}) {}
+        inline StashEntry(
+                const std::shared_ptr<C2Buffer> &b,
+                bool n,
+                int64_t t,
+                int32_t f,
+                const sp<AMessage> &fmt,
+                const C2WorkOrdinalStruct &o)
+            : buffer(b),
+              notify(n),
+              timestamp(t),
+              flags(f),
+              format(fmt),
+              ordinal(o) {}
+        std::shared_ptr<C2Buffer> buffer;
+        bool notify;
+        int64_t timestamp;
+        int32_t flags;
+        sp<AMessage> format;
+        C2WorkOrdinalStruct ordinal;
+    };
+
+    /**
+     * FIFO queue of stash entries.
+     */
+    std::list<StashEntry> mPending;
+    /**
+     * Sorted list of stash entries.
+     */
+    std::list<StashEntry> mReorderStash;
+    /**
+     * Size limit of mReorderStash.
+     */
+    uint32_t mDepth{0};
+    /**
+     * Choice of key to use in ordering of stash entries in mReorderStash.
+     */
+    C2Config::ordinal_key_t mKey{C2Config::ORDINAL};
+
+    /**
+     * Return false if mPending is empty; otherwise, pop the first entry from
+     * mPending and return true.
+     */
+    bool popPending(StashEntry *entry);
+
+    /**
+     * Push an entry as the first entry of mPending.
+     */
+    void deferPending(const StashEntry &entry);
+
+    /**
+     * Comparison of C2WorkOrdinalStruct based on mKey.
+     */
+    bool less(const C2WorkOrdinalStruct &o1,
+              const C2WorkOrdinalStruct &o2) const;
+
     DISALLOW_EVIL_CONSTRUCTORS(OutputBuffers);
+
+    friend OutputBuffersArray;
 };
 
 /**
@@ -772,7 +1000,7 @@
 
     bool isArrayMode() const final { return true; }
 
-    std::unique_ptr<OutputBuffers> toArrayMode(size_t) final {
+    std::unique_ptr<OutputBuffersArray> toArrayMode(size_t) final {
         return nullptr;
     }
 
@@ -811,6 +1039,12 @@
      */
     void grow(size_t newSize);
 
+    /**
+     * Transfer the SkipCutBuffer and the output stash from another
+     * OutputBuffers.
+     */
+    void transferFrom(OutputBuffers* source);
+
 private:
     BuffersArrayImpl mImpl;
     std::function<sp<Codec2Buffer>()> mAlloc;
@@ -839,7 +1073,7 @@
     void flush(
             const std::list<std::unique_ptr<C2Work>> &flushedWork) override;
 
-    std::unique_ptr<OutputBuffers> toArrayMode(size_t size) override;
+    std::unique_ptr<OutputBuffersArray> toArrayMode(size_t size) override;
 
     size_t numClientBuffers() const final;
 
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index bdb724b..b8255fc 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -10,7 +10,7 @@
 
     static_libs: [
         "libmedia_midiiowrapper",
-        "libsonivox",
+        "libsonivoxwithoutjet",
         "libstagefright_foundation",
         "libwatchdog",
     ],
diff --git a/media/extractors/tests/Android.bp b/media/extractors/tests/Android.bp
index fa39b64..b3afe2f 100644
--- a/media/extractors/tests/Android.bp
+++ b/media/extractors/tests/Android.bp
@@ -45,7 +45,7 @@
         "libstagefright_metadatautils",
 
         "libmedia_midiiowrapper",
-        "libsonivox",
+        "libsonivoxwithoutjet",
         "libvorbisidec",
         "libwebm",
         "libFLAC",
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h
index cd5eb5a..9c24b2b 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.h
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h
@@ -129,6 +129,7 @@
     }
 
     // This is used for exact matching by MediaMetrics. So do not change it.
+    // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_AAUDIO
     static constexpr char     kCallerName[] = "aaudio";
 
     MonotonicCounter           mFramesWritten;
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 1fb03bc..0bbceef 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -172,7 +172,7 @@
         .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
         .set(AMEDIAMETRICS_PROP_CALLERNAME,
                 mCallerName.empty()
-                ? AMEDIAMETRICS_PROP_VALUE_UNKNOWN
+                ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
                 : mCallerName.c_str())
         .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
         .record();
@@ -400,6 +400,10 @@
     status_t status = NO_ERROR;
     mediametrics::Defer defer([&] {
         mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_CALLERNAME,
+                    mCallerName.empty()
+                    ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
+                    : mCallerName.c_str())
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
             .set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index a5bb908..ca80dc4 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -303,7 +303,7 @@
         .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
         .set(AMEDIAMETRICS_PROP_CALLERNAME,
                 mCallerName.empty()
-                ? AMEDIAMETRICS_PROP_VALUE_UNKNOWN
+                ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
                 : mCallerName.c_str())
         .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
         .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
@@ -645,6 +645,10 @@
     status_t status = NO_ERROR; // logged: make sure to set this before returning.
     mediametrics::Defer defer([&] {
         mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_CALLERNAME,
+                    mCallerName.empty()
+                    ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
+                    : mCallerName.c_str())
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
             .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
@@ -879,7 +883,7 @@
 {
     const int64_t beginNs = systemTime();
     AutoMutex lock(mLock);
-    mediametrics::Defer([&]() {
+    mediametrics::Defer defer([&]() {
         mediametrics::LogItem(mMetricsId)
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
@@ -2433,7 +2437,7 @@
 {
     status_t result = NO_ERROR;  // logged: make sure to set this before returning.
     const int64_t beginNs = systemTime();
-    mediametrics::Defer([&] {
+    mediametrics::Defer defer([&] {
         mediametrics::LogItem(mMetricsId)
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index 536b00d..050ad65 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -1262,7 +1262,9 @@
             AUDIO_UID_INVALID,
             -1,
             &attr);
-
+    // Set caller name so it can be logged in destructor.
+    // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_TONEGENERATOR
+    mpAudioTrack->setCallerName("tonegenerator");
     if (status != NO_ERROR) {
         ALOGE("AudioTrack(%p) set failed with error %d", mpAudioTrack.get(), status);
         mpAudioTrack.clear();
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 62a86e7..be3f995 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -187,7 +187,7 @@
     srcs: ["MidiIoWrapper.cpp"],
 
     static_libs: [
-        "libsonivox",
+        "libsonivoxwithoutjet",
     ],
 
     header_libs: [
@@ -312,7 +312,7 @@
         "libutils",
         "libbinder",
         "libbinder_ndk",
-        "libsonivox",
+        //"libsonivox",
         "libandroidicu",
         "libexpat",
         "libcamera_client",
@@ -328,7 +328,7 @@
         "libaudioclient",
         "libbinder",
         "libandroidicu",
-        "libsonivox",
+        //"libsonivox",
         "libmedia_omx",
     ],
 
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 315ad62..00da69a 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -86,6 +86,7 @@
 // of suppressed in the Time Machine.
 #define AMEDIAMETRICS_PROP_SUFFIX_CHAR_DUPLICATES_ALLOWED '#'
 
+#define AMEDIAMETRICS_PROP_ALLOWUID       "_allowUid"      // int32_t, allow client uid to post
 #define AMEDIAMETRICS_PROP_AUXEFFECTID    "auxEffectId"    // int32 (AudioTrack)
 #define AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES "bufferSizeFrames" // int32
 #define AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES "bufferCapacityFrames" // int32
@@ -133,8 +134,6 @@
 #define AMEDIAMETRICS_PROP_VOLUME_RIGHT   "volume.right"   // double (AudioTrack)
 #define AMEDIAMETRICS_PROP_WHERE          "where"          // string value
 
-#define AMEDIAMETRICS_PROP_VALUE_UNKNOWN  "unknown"         // string for callerName
-
 // Timing values: millisecond values are suffixed with MS and the type is double
 // nanosecond values are suffixed with NS and the type is int64.
 
@@ -159,4 +158,16 @@
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_STOP       "stop"   // AudioTrack, AudioRecord
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN   "underrun" // from Thread
 
+// Possible values for AMEDIAMETRICS_PROP_CALLERNAME
+// Check within the framework for these strings as this header file may not be explicitly
+// included to avoid unnecessary cross-project dependencies.
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_AAUDIO        "aaudio"         // Native AAudio
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_JAVA          "java"           // Java API layer
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA         "media"          // libmedia
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_OPENSLES      "opensles"       // Open SLES
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_RTP           "rtp"            // RTP communication
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_SOUNDPOOL     "soundpool"      // SoundPool
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_TONEGENERATOR "tonegenerator"  // dial tones
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN       "unknown"        // callerName not set
+
 #endif // ANDROID_MEDIA_MEDIAMETRICSCONSTANTS_H
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 42a0622..c0da0ce 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -2206,7 +2206,9 @@
                     targetSpeed,
                     mSelectedDeviceId);
         }
-
+        // Set caller name so it can be logged in destructor.
+        // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA
+        t->setCallerName("media");
         if ((t == 0) || (t->initCheck() != NO_ERROR)) {
             ALOGE("Unable to create audio track");
             delete newcbd;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 73d3a0b..63ab654 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2053,17 +2053,34 @@
     if (mIsVideo || mIsImage) {
         // determine need for software renderer
         bool usingSwRenderer = false;
-        if (haveNativeWindow && mComponentName.startsWith("OMX.google.")) {
-            usingSwRenderer = true;
-            haveNativeWindow = false;
-            (void)setPortMode(kPortIndexOutput, IOMX::kPortModePresetByteBuffer);
-        } else if (haveNativeWindow && !storingMetadataInDecodedBuffers()) {
-            err = setPortMode(kPortIndexOutput, IOMX::kPortModePresetANWBuffer);
-            if (err != OK) {
-                return err;
+        if (haveNativeWindow) {
+            bool requiresSwRenderer = false;
+            OMX_PARAM_U32TYPE param;
+            InitOMXParams(&param);
+            param.nPortIndex = kPortIndexOutput;
+
+            status_t err = mOMXNode->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamVideoAndroidRequiresSwRenderer,
+                    &param, sizeof(param));
+
+            if (err == OK && param.nU32 == 1) {
+                requiresSwRenderer = true;
             }
+
+            if (mComponentName.startsWith("OMX.google.") || requiresSwRenderer) {
+                usingSwRenderer = true;
+                haveNativeWindow = false;
+                (void)setPortMode(kPortIndexOutput, IOMX::kPortModePresetByteBuffer);
+            } else if (!storingMetadataInDecodedBuffers()) {
+                err = setPortMode(kPortIndexOutput, IOMX::kPortModePresetANWBuffer);
+                if (err != OK) {
+                    return err;
+                }
+            }
+
         }
 
+
         if (encoder) {
             err = setupVideoEncoder(mime, msg, outputFormat, inputFormat);
         } else {
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 00c5b40..4bc861e 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -108,6 +108,9 @@
                     selectedDeviceId,
                     selectedMicDirection,
                     selectedMicFieldDimension);
+        // Set caller name so it can be logged in destructor.
+        // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA
+        mRecord->setCallerName("media");
         mInitCheck = mRecord->initCheck();
         if (mInitCheck != OK) {
             mRecord.clear();
diff --git a/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp b/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp
index ddc818e..c9c1cd4 100644
--- a/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp
+++ b/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp
@@ -337,7 +337,10 @@
     st = (Decoder_State *) spd_state;
 
     /* mode verification */
-
+    if (mode < 0 || mode >= NUM_OF_MODES)
+    {
+        return (-1);
+    }
     nb_bits = AMR_WB_COMPRESSED[mode];
 
     *frame_length = AMR_WB_PCM_FRAME;
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index f5687e0..784e802 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -126,12 +126,20 @@
     }
     header->num_streams = data[kOpusHeaderNumStreamsOffset];
     header->num_coupled = data[kOpusHeaderNumCoupledStreamsOffset];
-    if (header->num_streams + header->num_coupled != header->channels) {
-        ALOGV("Inconsistent channel mapping.");
+    if (header->num_coupled > header->num_streams ||
+        header->num_streams + header->num_coupled != header->channels) {
+        ALOGV("Inconsistent channel mapping, streams: %d coupled: %d channels: %d",
+        header->num_streams, header->num_coupled, header->channels);
         return false;
     }
-    for (int i = 0; i < header->channels; ++i)
-        header->stream_map[i] = data[kOpusHeaderStreamMapOffset + i];
+    for (int i = 0; i < header->channels; ++i) {
+        uint8_t value = data[kOpusHeaderStreamMapOffset + i];
+        if (value != 255 && value >= header->channels) {
+            ALOGV("Invalid channel mapping for index %i : %d", i, value);
+            return false;
+        }
+        header->stream_map[i] = value;
+    }
     return true;
 }
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 23d8329..4898d37 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -605,6 +605,7 @@
     mediametrics::LogItem(mMetricsId)
         .setPid(creatorPid)
         .setUid(uid)
+        .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)uid)
         .set(AMEDIAMETRICS_PROP_EVENT,
                 AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
         .record();
@@ -2165,6 +2166,7 @@
     mediametrics::LogItem(mMetricsId)
         .setPid(creatorPid)
         .setUid(uid)
+        .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)uid)
         .set(AMEDIAMETRICS_PROP_EVENT, "server." AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
         .record();
 }
diff --git a/services/mediametrics/TimeMachine.h b/services/mediametrics/TimeMachine.h
index 6861c78..c82778b 100644
--- a/services/mediametrics/TimeMachine.h
+++ b/services/mediametrics/TimeMachine.h
@@ -75,21 +75,30 @@
     class KeyHistory  {
     public:
         template <typename T>
-        KeyHistory(T key, pid_t pid, uid_t uid, int64_t time)
+        KeyHistory(T key, uid_t allowUid, int64_t time)
             : mKey(key)
-            , mPid(pid)
-            , mUid(uid)
+            , mAllowUid(allowUid)
             , mCreationTime(time)
             , mLastModificationTime(time)
         {
-            putValue(BUNDLE_PID, (int32_t)pid, time);
-            putValue(BUNDLE_UID, (int32_t)uid, time);
+            // allowUid allows an untrusted client with a matching uid to set properties
+            // in this key.
+            // If allowUid == (uid_t)-1, no untrusted client may set properties in the key.
+            if (allowUid != (uid_t)-1) {
+                // Set ALLOWUID property here; does not change after key creation.
+                putValue(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)allowUid, time);
+            }
         }
 
         KeyHistory(const KeyHistory &other) = default;
 
+        // Return NO_ERROR only if the passed in uidCheck is -1 or matches
+        // the internal mAllowUid.
+        // An external submit will always have a valid uidCheck parameter.
+        // An internal get request within mediametrics will have a uidCheck == -1 which
+        // we allow to proceed.
         status_t checkPermission(uid_t uidCheck) const {
-            return uidCheck != (uid_t)-1 && uidCheck != mUid ? PERMISSION_DENIED : NO_ERROR;
+            return uidCheck != (uid_t)-1 && uidCheck != mAllowUid ? PERMISSION_DENIED : NO_ERROR;
         }
 
         template <typename T>
@@ -199,8 +208,7 @@
         }
 
         const std::string mKey;
-        const pid_t mPid __unused;
-        const uid_t mUid;
+        const uid_t mAllowUid;
         const int64_t mCreationTime __unused;
 
         int64_t mLastModificationTime;
@@ -276,10 +284,13 @@
 
                 (void)gc(garbage);
 
+                // We set the allowUid for client access on key creation.
+                int32_t allowUid = -1;
+                (void)item->get(AMEDIAMETRICS_PROP_ALLOWUID, &allowUid);
                 // no keylock needed here as we are sole owner
                 // until placed on mHistory.
                 keyHistory = std::make_shared<KeyHistory>(
-                    key, item->getPid(), item->getUid(), time);
+                    key, allowUid, time);
                 mHistory[key] = keyHistory;
             } else {
                 keyHistory = it->second;
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
index 78eb71c..cf0dceb 100644
--- a/services/mediametrics/tests/mediametrics_tests.cpp
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -813,6 +813,42 @@
   ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
 }
 
+TEST(mediametrics_tests, audio_analytics_permission2) {
+  constexpr int32_t transactionUid = 1010; // arbitrary
+  auto item = std::make_shared<mediametrics::Item>("audio.1");
+  (*item).set("one", (int32_t)1)
+         .set("two", (int32_t)2)
+         .set(AMEDIAMETRICS_PROP_ALLOWUID, transactionUid)
+         .setTimestamp(10);
+
+  // item2 submitted untrusted
+  auto item2 = std::make_shared<mediametrics::Item>("audio.1");
+  (*item2).set("three", (int32_t)3)
+         .setUid(transactionUid)
+         .setTimestamp(11);
+
+  auto item3 = std::make_shared<mediametrics::Item>("audio.2");
+  (*item3).set("four", (int32_t)4)
+          .setTimestamp(12);
+
+  android::mediametrics::AudioAnalytics audioAnalytics;
+
+  // untrusted entities cannot create a new key.
+  ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item, false /* isTrusted */));
+  ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item2, false /* isTrusted */));
+
+  // TODO: Verify contents of AudioAnalytics.
+  // Currently there is no getter API in AudioAnalytics besides dump.
+  ASSERT_EQ(9, audioAnalytics.dump(1000).second /* lines */);
+
+  ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
+  // untrusted entities can add to an existing key
+  ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
+
+  // Check that we have some info in the dump.
+  ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
+}
+
 TEST(mediametrics_tests, audio_analytics_dump) {
   auto item = std::make_shared<mediametrics::Item>("audio.1");
   (*item).set("one", (int32_t)1)
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 044c361..dba9fb9 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -105,6 +105,7 @@
     mediametrics::LogItem(mMetricsId)
         .setPid(getOwnerProcessId())
         .setUid(getOwnerUserId())
+        .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)getOwnerUserId())
         .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_OPEN)
         // the following are immutable
         .set(AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, (int32_t)getBufferCapacity())