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(¶m);
+ param.nPortIndex = kPortIndexOutput;
+
+ status_t err = mOMXNode->getParameter(
+ (OMX_INDEXTYPE)OMX_IndexParamVideoAndroidRequiresSwRenderer,
+ ¶m, 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())