Merge "AMediaDataSourceWrapper: keep DataSource sp alive"
diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk
index a5aab07..508f930 100644
--- a/camera/ndk/Android.mk
+++ b/camera/ndk/Android.mk
@@ -41,6 +41,8 @@
LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
LOCAL_CFLAGS += -Wall -Wextra -Werror
+LOCAL_LDFLAGS += -Wl,--version-script=$(LOCAL_PATH)/libcamera2ndk.map.txt
+
LOCAL_SHARED_LIBRARIES := \
libbinder \
liblog \
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp b/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp
index eaa3390..cb69f91 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyFetcher.cpp
@@ -89,7 +89,7 @@
// asset_id change. If it sends an EcmContainer with 2 Ecms with different
// asset_ids (old and new) then it might be best to prefetch the Emm.
if ((asset_.id() != 0) && (*asset_id != asset_.id())) {
- ALOGW("Asset_id change from %llu to %" PRIu64, asset_.id(), *asset_id);
+ ALOGW("Asset_id change from %" PRIu64 " to %" PRIu64, asset_.id(), *asset_id);
asset_.Clear();
}
diff --git a/drm/mediacas/plugins/clearkey/ecm.cpp b/drm/mediacas/plugins/clearkey/ecm.cpp
index 9fde13a..b3b5218 100644
--- a/drm/mediacas/plugins/clearkey/ecm.cpp
+++ b/drm/mediacas/plugins/clearkey/ecm.cpp
@@ -17,6 +17,8 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ecm"
+#include <inttypes.h>
+
#include "ecm.h"
#include "ecm_generator.h"
#include "protos/license_protos.pb.h"
@@ -76,7 +78,7 @@
return status;
}
if (asset.id() != asset_from_emm.id()) {
- ALOGE("Asset_id from Emm (%llu) does not match asset_id from Ecm (%llu).",
+ ALOGE("Asset_id from Emm (%" PRIu64 ") does not match asset_id from Ecm (%" PRIu64 ").",
asset_from_emm.id(), asset.id());
return CLEARKEY_STATUS_INVALID_PARAMETER;
}
diff --git a/media/bufferpool/2.0/Accessor.cpp b/media/bufferpool/2.0/Accessor.cpp
index 3eaea7c..f264501 100644
--- a/media/bufferpool/2.0/Accessor.cpp
+++ b/media/bufferpool/2.0/Accessor.cpp
@@ -117,19 +117,18 @@
Return<void> Accessor::connect(
const sp<::android::hardware::media::bufferpool::V2_0::IObserver>& observer,
connect_cb _hidl_cb) {
- (void)observer;
sp<Connection> connection;
ConnectionId connectionId;
+ uint32_t msgId;
const StatusDescriptor* fmqDesc;
+ const InvalidationDescriptor* invDesc;
- ResultStatus status = connect(&connection, &connectionId, &fmqDesc, false);
+ ResultStatus status = connect(
+ observer, false, &connection, &connectionId, &msgId, &fmqDesc, &invDesc);
if (status == ResultStatus::OK) {
- _hidl_cb(status, connection, connectionId, *fmqDesc,
- android::hardware::MQDescriptorUnsync<BufferInvalidationMessage>(
- std::vector<android::hardware::GrantorDescriptor>(),
- nullptr /* nhandle */, 0 /* size */));
+ _hidl_cb(status, connection, connectionId, msgId, *fmqDesc, *invDesc);
} else {
- _hidl_cb(status, nullptr, -1LL,
+ _hidl_cb(status, nullptr, -1LL, 0,
android::hardware::MQDescriptorSync<BufferStatusMessage>(
std::vector<android::hardware::GrantorDescriptor>(),
nullptr /* nhandle */, 0 /* size */),
@@ -147,7 +146,15 @@
}
bool Accessor::isValid() {
- return (bool)mImpl;
+ return (bool)mImpl && mImpl->isValid();
+}
+
+ResultStatus Accessor::flush() {
+ if (mImpl) {
+ mImpl->flush();
+ return ResultStatus::OK;
+ }
+ return ResultStatus::CRITICAL_ERROR;
}
ResultStatus Accessor::allocate(
@@ -170,10 +177,15 @@
}
ResultStatus Accessor::connect(
+ const sp<IObserver> &observer, bool local,
sp<Connection> *connection, ConnectionId *pConnectionId,
- const StatusDescriptor** fmqDescPtr, bool local) {
+ uint32_t *pMsgId,
+ const StatusDescriptor** statusDescPtr,
+ const InvalidationDescriptor** invDescPtr) {
if (mImpl) {
- ResultStatus status = mImpl->connect(this, connection, pConnectionId, fmqDescPtr);
+ ResultStatus status = mImpl->connect(
+ this, observer, connection, pConnectionId, pMsgId,
+ statusDescPtr, invDescPtr);
if (!local && status == ResultStatus::OK) {
sp<Accessor> accessor(this);
sConnectionDeathRecipient->add(*pConnectionId, accessor);
diff --git a/media/bufferpool/2.0/Accessor.h b/media/bufferpool/2.0/Accessor.h
index a718da1..4b5b17a 100644
--- a/media/bufferpool/2.0/Accessor.h
+++ b/media/bufferpool/2.0/Accessor.h
@@ -95,6 +95,9 @@
/** Returns whether the accessor is valid. */
bool isValid();
+ /** Invalidates all buffers which are owned by bufferpool */
+ ResultStatus flush();
+
/** Allocates a buffer from a buffer pool.
*
* @param connectionId the connection id of the client.
@@ -135,20 +138,28 @@
* created connection in order to communicate with the buffer pool. An
* FMQ for buffer status message is also created for the client.
*
- * @param connection created connection
- * @param pConnectionId the id of the created connection
- * @param fmqDescPtr FMQ descriptor for shared buffer status message
- * queue between a buffer pool and the client.
+ * @param observer client observer for buffer invalidation
* @param local true when a connection request comes from local process,
* false otherwise.
+ * @param connection created connection
+ * @param pConnectionId the id of the created connection
+ * @param pMsgId the id of the recent buffer pool message
+ * @param statusDescPtr FMQ descriptor for shared buffer status message
+ * queue between a buffer pool and the client.
+ * @param invDescPtr FMQ descriptor for buffer invalidation message
+ * queue from a buffer pool to the client.
*
* @return OK when a connection is successfully made.
* NO_MEMORY when there is no memory.
* CRITICAL_ERROR otherwise.
*/
ResultStatus connect(
+ const sp<IObserver>& observer,
+ bool local,
sp<Connection> *connection, ConnectionId *pConnectionId,
- const StatusDescriptor** fmqDescPtr, bool local);
+ uint32_t *pMsgId,
+ const StatusDescriptor** statusDescPtr,
+ const InvalidationDescriptor** invDescPtr);
/**
* Closes the specified connection to the client.
@@ -176,7 +187,7 @@
private:
class Impl;
- std::unique_ptr<Impl> mImpl;
+ std::shared_ptr<Impl> mImpl;
};
} // namespace implementation
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 0ba6600..4cc8abc 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -21,6 +21,7 @@
#include <time.h>
#include <unistd.h>
#include <utils/Log.h>
+#include <thread>
#include "AccessorImpl.h"
#include "Connection.h"
@@ -47,6 +48,7 @@
const std::shared_ptr<BufferPoolAllocation> mAllocation;
const size_t mAllocSize;
const std::vector<uint8_t> mConfig;
+ bool mInvalidated;
InternalBuffer(
BufferId id,
@@ -54,11 +56,16 @@
const size_t allocSize,
const std::vector<uint8_t> &allocConfig)
: mId(id), mOwnerCount(0), mTransactionCount(0),
- mAllocation(alloc), mAllocSize(allocSize), mConfig(allocConfig) {}
+ mAllocation(alloc), mAllocSize(allocSize), mConfig(allocConfig),
+ mInvalidated(false) {}
const native_handle_t *handle() {
return mAllocation->handle();
}
+
+ void invalidate() {
+ mInvalidated = true;
+ }
};
struct TransactionStatus {
@@ -138,21 +145,29 @@
}
ResultStatus Accessor::Impl::connect(
- const sp<Accessor> &accessor, sp<Connection> *connection,
- ConnectionId *pConnectionId, const StatusDescriptor** fmqDescPtr) {
+ const sp<Accessor> &accessor, const sp<IObserver> &observer,
+ sp<Connection> *connection,
+ ConnectionId *pConnectionId,
+ uint32_t *pMsgId,
+ const StatusDescriptor** statusDescPtr,
+ const InvalidationDescriptor** invDescPtr) {
sp<Connection> newConnection = new Connection();
ResultStatus status = ResultStatus::CRITICAL_ERROR;
{
std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
if (newConnection) {
ConnectionId id = (int64_t)sPid << 32 | sSeqId;
- status = mBufferPool.mObserver.open(id, fmqDescPtr);
+ status = mBufferPool.mObserver.open(id, statusDescPtr);
if (status == ResultStatus::OK) {
newConnection->initialize(accessor, id);
*connection = newConnection;
*pConnectionId = id;
+ *pMsgId = mBufferPool.mInvalidation.mInvalidationId;
+ mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
+ mBufferPool.mInvalidation.onConnect(id, observer);
++sSeqId;
}
+
}
mBufferPool.processStatusMessages();
mBufferPool.cleanUp();
@@ -165,6 +180,7 @@
mBufferPool.processStatusMessages();
mBufferPool.handleClose(connectionId);
mBufferPool.mObserver.close(connectionId);
+ mBufferPool.mInvalidation.onClose(connectionId);
// Since close# will be called after all works are finished, it is OK to
// evict unused buffers.
mBufferPool.cleanUp(true);
@@ -229,11 +245,30 @@
mBufferPool.cleanUp(clearCache);
}
+void Accessor::Impl::flush() {
+ std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+ mBufferPool.processStatusMessages();
+ mBufferPool.flush(shared_from_this());
+}
+
+void Accessor::Impl::handleInvalidateAck() {
+ std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+ mBufferPool.processStatusMessages();
+ mBufferPool.mInvalidation.onHandleAck();
+}
+
+bool Accessor::Impl::isValid() {
+ return mBufferPool.isValid();
+}
+
Accessor::Impl::Impl::BufferPool::BufferPool()
: mTimestampUs(getTimestampNow()),
mLastCleanUpUs(mTimestampUs),
mLastLogUs(mTimestampUs),
- mSeq(0) {}
+ mSeq(0),
+ mStartSeq(0) {
+ mValid = mInvalidationChannel.isValid();
+}
// Statistics helper
@@ -242,6 +277,8 @@
return int(total ? 0.5 + 100. * static_cast<S>(base) / total : 0);
}
+std::atomic<std::uint32_t> Accessor::Impl::BufferPool::Invalidation::sSeqId(0);
+
Accessor::Impl::Impl::BufferPool::~BufferPool() {
std::lock_guard<std::mutex> lock(mMutex);
ALOGD("Destruction - bufferpool %p "
@@ -255,6 +292,96 @@
percentage(mStats.mTotalTransfers - mStats.mTotalFetches, mStats.mTotalTransfers));
}
+void Accessor::Impl::BufferPool::Invalidation::onConnect(
+ ConnectionId conId, const sp<IObserver>& observer) {
+ mAcks[conId] = mInvalidationId; // starts from current invalidationId
+ mObservers.insert(std::make_pair(conId, observer));
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onClose(ConnectionId conId) {
+ mAcks.erase(conId);
+ mObservers.erase(conId);
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onAck(
+ ConnectionId conId,
+ uint32_t msgId) {
+ auto it = mAcks.find(conId);
+ if (it == mAcks.end() || isMessageLater(msgId, it->second)) {
+ mAcks[conId] = msgId;
+ }
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onBufferInvalidated(
+ BufferId bufferId,
+ BufferInvalidationChannel &channel) {
+ for (auto it = mPendings.begin(); it != mPendings.end();) {
+ if (it->invalidate(bufferId)) {
+ it = mPendings.erase(it);
+ uint32_t msgId = 0;
+ if (it->mNeedsAck) {
+ msgId = ++mInvalidationId;
+ if (msgId == 0) {
+ // wrap happens
+ msgId = ++mInvalidationId;
+ }
+ }
+ channel.postInvalidation(msgId, it->mFrom, it->mTo);
+ sInvalidator.addAccessor(mId, it->mImpl);
+ continue;
+ }
+ ++it;
+ }
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onInvalidationRequest(
+ bool needsAck,
+ uint32_t from,
+ uint32_t to,
+ size_t left,
+ BufferInvalidationChannel &channel,
+ const std::shared_ptr<Accessor::Impl> &impl) {
+ if (left == 0) {
+ uint32_t msgId = 0;
+ if (needsAck) {
+ msgId = ++mInvalidationId;
+ if (msgId == 0) {
+ // wrap happens
+ msgId = ++mInvalidationId;
+ }
+ }
+ channel.postInvalidation(msgId, from, to);
+ sInvalidator.addAccessor(mId, impl);
+ } else {
+ // TODO: sending hint message?
+ Pending pending(needsAck, from, to, left, impl);
+ mPendings.push_back(pending);
+ }
+}
+
+void Accessor::Impl::BufferPool::Invalidation::onHandleAck() {
+ if (mInvalidationId != 0) {
+ std::set<int> deads;
+ for (auto it = mAcks.begin(); it != mAcks.end(); ++it) {
+ if (it->second != mInvalidationId) {
+ const sp<IObserver> observer = mObservers[it->first].promote();
+ if (observer) {
+ observer->onMessage(it->first, mInvalidationId);
+ } else {
+ deads.insert(it->first);
+ }
+ }
+ }
+ if (deads.size() > 0) {
+ for (auto it = deads.begin(); it != deads.end(); ++it) {
+ onClose(*it);
+ }
+ }
+ }
+ // All invalidation Ids are synced.
+ sInvalidator.delAccessor(mId);
+}
+
bool Accessor::Impl::BufferPool::handleOwnBuffer(
ConnectionId connectionId, BufferId bufferId) {
@@ -275,8 +402,15 @@
iter->second->mOwnerCount--;
if (iter->second->mOwnerCount == 0 &&
iter->second->mTransactionCount == 0) {
- mStats.onBufferUnused(iter->second->mAllocSize);
- mFreeBuffers.insert(bufferId);
+ if (!iter->second->mInvalidated) {
+ mStats.onBufferUnused(iter->second->mAllocSize);
+ mFreeBuffers.insert(bufferId);
+ } else {
+ mStats.onBufferUnused(iter->second->mAllocSize);
+ mStats.onBufferEvicted(iter->second->mAllocSize);
+ mBuffers.erase(iter);
+ mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+ }
}
}
erase(&mUsingConnections, bufferId, connectionId);
@@ -352,8 +486,15 @@
bufferIter->second->mTransactionCount--;
if (bufferIter->second->mOwnerCount == 0
&& bufferIter->second->mTransactionCount == 0) {
- mStats.onBufferUnused(bufferIter->second->mAllocSize);
- mFreeBuffers.insert(message.bufferId);
+ if (!bufferIter->second->mInvalidated) {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mFreeBuffers.insert(message.bufferId);
+ } else {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+ mBuffers.erase(bufferIter);
+ mInvalidation.onBufferInvalidated(message.bufferId, mInvalidationChannel);
+ }
}
mTransactions.erase(found);
}
@@ -400,7 +541,7 @@
ret = handleTransferResult(message);
break;
case BufferStatus::INVALIDATION_ACK:
- // TODO
+ mInvalidation.onAck(message.connectionId, message.bufferId);
break;
}
if (ret == false) {
@@ -423,8 +564,15 @@
if (bufferIter->second->mOwnerCount == 0 &&
bufferIter->second->mTransactionCount == 0) {
// TODO: handle freebuffer insert fail
- mStats.onBufferUnused(bufferIter->second->mAllocSize);
- mFreeBuffers.insert(bufferId);
+ if (!bufferIter->second->mInvalidated) {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mFreeBuffers.insert(bufferId);
+ } else {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+ mBuffers.erase(bufferIter);
+ mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+ }
}
}
}
@@ -446,8 +594,15 @@
if (bufferIter->second->mOwnerCount == 0 &&
bufferIter->second->mTransactionCount == 0) {
// TODO: handle freebuffer insert fail
- mStats.onBufferUnused(bufferIter->second->mAllocSize);
- mFreeBuffers.insert(bufferId);
+ if (!bufferIter->second->mInvalidated) {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mFreeBuffers.insert(bufferId);
+ } else {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+ mBuffers.erase(bufferIter);
+ mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+ }
}
mTransactions.erase(iter);
}
@@ -538,6 +693,121 @@
}
}
+void Accessor::Impl::BufferPool::invalidate(
+ bool needsAck, BufferId from, BufferId to,
+ const std::shared_ptr<Accessor::Impl> &impl) {
+ for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
+ if (isBufferInRange(from, to, *freeIt)) {
+ auto it = mBuffers.find(*freeIt);
+ if (it != mBuffers.end() &&
+ it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
+ mStats.onBufferEvicted(it->second->mAllocSize);
+ mBuffers.erase(it);
+ freeIt = mFreeBuffers.erase(freeIt);
+ continue;
+ } else {
+ ALOGW("bufferpool inconsistent!");
+ }
+ }
+ ++freeIt;
+ }
+
+ size_t left = 0;
+ for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
+ if (isBufferInRange(from, to, it->first)) {
+ it->second->invalidate();
+ ++left;
+ }
+ }
+ mInvalidation.onInvalidationRequest(needsAck, from, to, left, mInvalidationChannel, impl);
+}
+
+void Accessor::Impl::BufferPool::flush(const std::shared_ptr<Accessor::Impl> &impl) {
+ BufferId from = mStartSeq;
+ BufferId to = mSeq;
+ mStartSeq = mSeq;
+ // TODO: needsAck params
+ if (from != to) {
+ invalidate(true, from, to, impl);
+ }
+}
+
+void Accessor::Impl::invalidatorThread(
+ std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> &accessors,
+ std::mutex &mutex,
+ std::condition_variable &cv,
+ bool &ready) {
+ while(true) {
+ std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> copied;
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ if (!ready) {
+ cv.wait(lock);
+ }
+ copied.insert(accessors.begin(), accessors.end());
+ }
+ std::list<ConnectionId> erased;
+ for (auto it = copied.begin(); it != copied.end(); ++it) {
+ const std::shared_ptr<Accessor::Impl> impl = it->second.lock();
+ if (!impl) {
+ erased.push_back(it->first);
+ } else {
+ impl->handleInvalidateAck();
+ }
+ }
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ for (auto it = erased.begin(); it != erased.end(); ++it) {
+ accessors.erase(*it);
+ }
+ if (accessors.size() == 0) {
+ ready = false;
+ } else {
+ // prevent draining cpu.
+ lock.unlock();
+ std::this_thread::yield();
+ }
+ }
+ }
+}
+
+Accessor::Impl::AccessorInvalidator::AccessorInvalidator() : mReady(false) {
+ std::thread invalidator(
+ invalidatorThread,
+ std::ref(mAccessors),
+ std::ref(mMutex),
+ std::ref(mCv),
+ std::ref(mReady));
+ invalidator.detach();
+}
+
+void Accessor::Impl::AccessorInvalidator::addAccessor(
+ uint32_t accessorId, const std::weak_ptr<Accessor::Impl> &impl) {
+ bool notify = false;
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (mAccessors.find(accessorId) == mAccessors.end()) {
+ if (!mReady) {
+ mReady = true;
+ notify = true;
+ }
+ mAccessors.insert(std::make_pair(accessorId, impl));
+ }
+ lock.unlock();
+ if (notify) {
+ mCv.notify_one();
+ }
+}
+
+void Accessor::Impl::AccessorInvalidator::delAccessor(uint32_t accessorId) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mAccessors.erase(accessorId);
+ if (mAccessors.size() == 0) {
+ mReady = false;
+ }
+}
+
+Accessor::Impl::AccessorInvalidator Accessor::Impl::sInvalidator;
+
} // namespace implementation
} // namespace V2_0
} // namespace bufferpool
diff --git a/media/bufferpool/2.0/AccessorImpl.h b/media/bufferpool/2.0/AccessorImpl.h
index 1d33880..6b03494 100644
--- a/media/bufferpool/2.0/AccessorImpl.h
+++ b/media/bufferpool/2.0/AccessorImpl.h
@@ -19,6 +19,7 @@
#include <map>
#include <set>
+#include <condition_variable>
#include "Accessor.h"
namespace android {
@@ -33,15 +34,20 @@
/**
* An implementation of a buffer pool accessor(or a buffer pool implementation.) */
-class Accessor::Impl {
+class Accessor::Impl
+ : public std::enable_shared_from_this<Accessor::Impl> {
public:
Impl(const std::shared_ptr<BufferPoolAllocator> &allocator);
~Impl();
ResultStatus connect(
- const sp<Accessor> &accessor, sp<Connection> *connection,
- ConnectionId *pConnectionId, const StatusDescriptor** fmqDescPtr);
+ const sp<Accessor> &accessor, const sp<IObserver> &observer,
+ sp<Connection> *connection,
+ ConnectionId *pConnectionId,
+ uint32_t *pMsgId,
+ const StatusDescriptor** statusDescPtr,
+ const InvalidationDescriptor** invDescPtr);
ResultStatus close(ConnectionId connectionId);
@@ -55,8 +61,14 @@
BufferId bufferId,
const native_handle_t** handle);
+ void flush();
+
void cleanUp(bool clearCache);
+ bool isValid();
+
+ void handleInvalidateAck();
+
private:
// ConnectionId = pid : (timestamp_created + seqId)
// in order to guarantee uniqueness for each connection
@@ -78,7 +90,10 @@
int64_t mLastCleanUpUs;
int64_t mLastLogUs;
BufferId mSeq;
+ BufferId mStartSeq;
+ bool mValid;
BufferStatusObserver mObserver;
+ BufferInvalidationChannel mInvalidationChannel;
std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
@@ -95,6 +110,54 @@
std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
std::set<BufferId> mFreeBuffers;
+ struct Invalidation {
+ static std::atomic<std::uint32_t> sSeqId;
+
+ struct Pending {
+ bool mNeedsAck;
+ uint32_t mFrom;
+ uint32_t mTo;
+ size_t mLeft;
+ const std::weak_ptr<Accessor::Impl> mImpl;
+ Pending(bool needsAck, uint32_t from, uint32_t to, size_t left,
+ const std::shared_ptr<Accessor::Impl> &impl)
+ : mNeedsAck(needsAck),
+ mFrom(from),
+ mTo(to),
+ mLeft(left),
+ mImpl(impl)
+ {}
+
+ bool invalidate(uint32_t bufferId) {
+ return isBufferInRange(mFrom, mTo, bufferId) && --mLeft == 0;
+ }
+ };
+
+ std::list<Pending> mPendings;
+ std::map<ConnectionId, uint32_t> mAcks;
+ std::map<ConnectionId, const wp<IObserver>> mObservers;
+ uint32_t mInvalidationId;
+ uint32_t mId;
+
+ Invalidation() : mInvalidationId(0), mId(sSeqId.fetch_add(1)) {}
+
+ void onConnect(ConnectionId conId, const sp<IObserver> &observer);
+
+ void onClose(ConnectionId conId);
+
+ void onAck(ConnectionId conId, uint32_t msgId);
+
+ void onBufferInvalidated(
+ BufferId bufferId,
+ BufferInvalidationChannel &channel);
+
+ void onInvalidationRequest(
+ bool needsAck, uint32_t from, uint32_t to, size_t left,
+ BufferInvalidationChannel &channel,
+ const std::shared_ptr<Accessor::Impl> &impl);
+
+ void onHandleAck();
+ } mInvalidation;
/// Buffer pool statistics which tracks allocation and transfer statistics.
struct Stats {
/// Total size of allocations which are used or available to use.
@@ -164,6 +227,13 @@
}
} mStats;
+ bool isValid() {
+ return mValid;
+ }
+
+ void invalidate(bool needsAck, BufferId from, BufferId to,
+ const std::shared_ptr<Accessor::Impl> &impl);
+
public:
/** Creates a buffer pool. */
BufferPool();
@@ -286,8 +356,33 @@
*/
void cleanUp(bool clearCache = false);
+ /**
+ * Processes pending buffer status messages and invalidate all current
+ * free buffers. Active buffers are invalidated after being inactive.
+ */
+ void flush(const std::shared_ptr<Accessor::Impl> &impl);
+
friend class Accessor::Impl;
} mBufferPool;
+
+ struct AccessorInvalidator {
+ std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> mAccessors;
+ std::mutex mMutex;
+ std::condition_variable mCv;
+ bool mReady;
+
+ AccessorInvalidator();
+ void addAccessor(uint32_t accessorId, const std::weak_ptr<Accessor::Impl> &impl);
+ void delAccessor(uint32_t accessorId);
+ };
+
+ static AccessorInvalidator sInvalidator;
+
+ static void invalidatorThread(
+ std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> &accessors,
+ std::mutex &mutex,
+ std::condition_variable &cv,
+ bool &ready);
};
} // namespace implementation
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
index 413125a..cd4e06e 100644
--- a/media/bufferpool/2.0/Android.bp
+++ b/media/bufferpool/2.0/Android.bp
@@ -8,6 +8,7 @@
"BufferStatus.cpp",
"ClientManager.cpp",
"Connection.cpp",
+ "Observer.cpp",
],
export_include_dirs: [
"include",
diff --git a/media/bufferpool/2.0/BufferPoolClient.cpp b/media/bufferpool/2.0/BufferPoolClient.cpp
index 0f763f7..c80beff 100644
--- a/media/bufferpool/2.0/BufferPoolClient.cpp
+++ b/media/bufferpool/2.0/BufferPoolClient.cpp
@@ -36,9 +36,9 @@
class BufferPoolClient::Impl
: public std::enable_shared_from_this<BufferPoolClient::Impl> {
public:
- explicit Impl(const sp<Accessor> &accessor);
+ explicit Impl(const sp<Accessor> &accessor, const sp<IObserver> &observer);
- explicit Impl(const sp<IAccessor> &accessor);
+ explicit Impl(const sp<IAccessor> &accessor, const sp<IObserver> &observer);
bool isValid() {
return mValid;
@@ -58,6 +58,10 @@
bool isActive(int64_t *lastTransactionUs, bool clearCache);
+ void receiveInvalidation(uint32_t msgID);
+
+ ResultStatus flush();
+
ResultStatus allocate(const std::vector<uint8_t> ¶ms,
native_handle_t **handle,
std::shared_ptr<BufferPoolData> *buffer);
@@ -83,10 +87,14 @@
void trySyncFromRemote();
- bool syncReleased();
+ bool syncReleased(uint32_t msgId = 0);
void evictCaches(bool clearCache = false);
+ void invalidateBuffer(BufferId id);
+
+ void invalidateRange(BufferId from, BufferId to);
+
ResultStatus allocateBufferHandle(
const std::vector<uint8_t>& params, BufferId *bufferId,
native_handle_t **handle);
@@ -106,6 +114,7 @@
uint32_t mSeqId;
ConnectionId mConnectionId;
int64_t mLastEvictCacheUs;
+ std::unique_ptr<BufferInvalidationListener> mInvalidationListener;
// CachedBuffers
struct BufferCache {
@@ -130,12 +139,16 @@
} mCache;
// FMQ - release notifier
- struct {
+ struct ReleaseCache {
std::mutex mLock;
// TODO: use only one list?(using one list may dealy sending messages?)
std::list<BufferId> mReleasingIds;
std::list<BufferId> mReleasedIds;
+ uint32_t mInvalidateId; // TODO: invalidation ACK to bufferpool
+ bool mInvalidateAck;
std::unique_ptr<BufferStatusChannel> mStatusChannel;
+
+ ReleaseCache() : mInvalidateId(0), mInvalidateAck(true) {}
} mReleasing;
// This lock is held during synchronization from remote side.
@@ -162,7 +175,6 @@
struct BufferPoolClient::Impl::ClientBuffer {
private:
- bool mInvalidated; // TODO: implement
int64_t mExpireUs;
bool mHasCache;
ConnectionId mConnectionId;
@@ -177,9 +189,8 @@
public:
ClientBuffer(
ConnectionId connectionId, BufferId id, native_handle_t *handle)
- : mInvalidated(false), mHasCache(false),
- mConnectionId(connectionId), mId(id), mHandle(handle) {
- (void)mInvalidated;
+ : mHasCache(false), mConnectionId(connectionId),
+ mId(id), mHandle(handle) {
mExpireUs = getTimestampNow() + kCacheTtlUs;
}
@@ -190,6 +201,10 @@
}
}
+ BufferId id() const {
+ return mId;
+ }
+
bool expire() const {
int64_t now = getTimestampNow();
return now >= mExpireUs;
@@ -244,41 +259,53 @@
}
};
-BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor)
+BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor, const sp<IObserver> &observer)
: mLocal(true), mValid(false), mAccessor(accessor), mSeqId(0),
mLastEvictCacheUs(getTimestampNow()) {
- const StatusDescriptor *fmqDesc;
+ const StatusDescriptor *statusDesc;
+ const InvalidationDescriptor *invDesc;
ResultStatus status = accessor->connect(
- &mLocalConnection, &mConnectionId, &fmqDesc, true);
+ observer, true,
+ &mLocalConnection, &mConnectionId, &mReleasing.mInvalidateId,
+ &statusDesc, &invDesc);
if (status == ResultStatus::OK) {
mReleasing.mStatusChannel =
- std::make_unique<BufferStatusChannel>(*fmqDesc);
+ std::make_unique<BufferStatusChannel>(*statusDesc);
+ mInvalidationListener =
+ std::make_unique<BufferInvalidationListener>(*invDesc);
mValid = mReleasing.mStatusChannel &&
- mReleasing.mStatusChannel->isValid();
+ mReleasing.mStatusChannel->isValid() &&
+ mInvalidationListener &&
+ mInvalidationListener->isValid();
}
}
-BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor)
+BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor, const sp<IObserver> &observer)
: mLocal(false), mValid(false), mAccessor(accessor), mSeqId(0),
mLastEvictCacheUs(getTimestampNow()) {
bool valid = false;
- sp<IObserver> observer; // TODO
sp<IConnection>& outConnection = mRemoteConnection;
ConnectionId& id = mConnectionId;
+ uint32_t& outMsgId = mReleasing.mInvalidateId;
std::unique_ptr<BufferStatusChannel>& outChannel =
mReleasing.mStatusChannel;
+ std::unique_ptr<BufferInvalidationListener>& outObserver =
+ mInvalidationListener;
Return<void> transResult = accessor->connect(
observer,
- [&valid, &outConnection, &id, &outChannel]
+ [&valid, &outConnection, &id, &outMsgId, &outChannel, &outObserver]
(ResultStatus status, sp<IConnection> connection,
- ConnectionId connectionId, const StatusDescriptor& desc,
+ ConnectionId connectionId, uint32_t msgId,
+ const StatusDescriptor& statusDesc,
const InvalidationDescriptor& invDesc) {
- (void) invDesc;
if (status == ResultStatus::OK) {
outConnection = connection;
id = connectionId;
- outChannel = std::make_unique<BufferStatusChannel>(desc);
- if (outChannel && outChannel->isValid()) {
+ outMsgId = msgId;
+ outChannel = std::make_unique<BufferStatusChannel>(statusDesc);
+ outObserver = std::make_unique<BufferInvalidationListener>(invDesc);
+ if (outChannel && outChannel->isValid() &&
+ outObserver && outObserver->isValid()) {
valid = true;
}
}
@@ -302,6 +329,24 @@
return active;
}
+void BufferPoolClient::Impl::receiveInvalidation(uint32_t messageId) {
+ std::lock_guard<std::mutex> lock(mCache.mLock);
+ syncReleased(messageId);
+ // TODO: evict cache required?
+}
+
+ResultStatus BufferPoolClient::Impl::flush() {
+ if (!mLocal || !mLocalConnection || !mValid) {
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ {
+ std::unique_lock<std::mutex> lock(mCache.mLock);
+ syncReleased();
+ evictCaches();
+ return mLocalConnection->flush();
+ }
+}
+
ResultStatus BufferPoolClient::Impl::allocate(
const std::vector<uint8_t> ¶ms,
native_handle_t **pHandle,
@@ -455,6 +500,11 @@
bool BufferPoolClient::Impl::postSend(
BufferId bufferId, ConnectionId receiver,
TransactionId *transactionId, int64_t *timestampUs) {
+ {
+ // TODO: don't need to call syncReleased every time
+ std::lock_guard<std::mutex> lock(mCache.mLock);
+ syncReleased();
+ }
bool ret = false;
bool needsSync = false;
{
@@ -538,34 +588,74 @@
}
// should have mCache.mLock
-bool BufferPoolClient::Impl::syncReleased() {
- std::lock_guard<std::mutex> lock(mReleasing.mLock);
- if (mReleasing.mReleasingIds.size() > 0) {
- mReleasing.mStatusChannel->postBufferRelease(
- mConnectionId, mReleasing.mReleasingIds,
- mReleasing.mReleasedIds);
- }
- if (mReleasing.mReleasedIds.size() > 0) {
- for (BufferId& id: mReleasing.mReleasedIds) {
- ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
- auto found = mCache.mBuffers.find(id);
- if (found != mCache.mBuffers.end()) {
- if (found->second->onCacheRelease()) {
- mCache.decActive_l();
+bool BufferPoolClient::Impl::syncReleased(uint32_t messageId) {
+ bool cleared = false;
+ {
+ std::lock_guard<std::mutex> lock(mReleasing.mLock);
+ if (mReleasing.mReleasingIds.size() > 0) {
+ mReleasing.mStatusChannel->postBufferRelease(
+ mConnectionId, mReleasing.mReleasingIds,
+ mReleasing.mReleasedIds);
+ }
+ if (mReleasing.mReleasedIds.size() > 0) {
+ for (BufferId& id: mReleasing.mReleasedIds) {
+ ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
+ auto found = mCache.mBuffers.find(id);
+ if (found != mCache.mBuffers.end()) {
+ if (found->second->onCacheRelease()) {
+ mCache.decActive_l();
+ } else {
+ // should not happen!
+ ALOGW("client %lld cache release status inconsitent!",
+ (long long)mConnectionId);
+ }
} else {
// should not happen!
- ALOGW("client %lld cache release status inconsitent!",
- (long long)mConnectionId);
+ ALOGW("client %lld cache status inconsitent!", (long long)mConnectionId);
}
+ }
+ mReleasing.mReleasedIds.clear();
+ cleared = true;
+ }
+ }
+ std::vector<BufferInvalidationMessage> invalidations;
+ mInvalidationListener->getInvalidations(invalidations);
+ uint32_t lastMsgId = 0;
+ if (invalidations.size() > 0) {
+ for (auto it = invalidations.begin(); it != invalidations.end(); ++it) {
+ if (it->messageId != 0) {
+ lastMsgId = it->messageId;
+ }
+ if (it->fromBufferId == it->toBufferId) {
+ // TODO: handle fromBufferId = UINT32_MAX
+ invalidateBuffer(it->fromBufferId);
} else {
- // should not happen!
- ALOGW("client %lld cache status inconsitent!", (long long)mConnectionId);
+ invalidateRange(it->fromBufferId, it->toBufferId);
}
}
- mReleasing.mReleasedIds.clear();
- return true;
}
- return false;
+ {
+ std::lock_guard<std::mutex> lock(mReleasing.mLock);
+ if (lastMsgId != 0) {
+ if (isMessageLater(lastMsgId, mReleasing.mInvalidateId)) {
+ mReleasing.mInvalidateId = lastMsgId;
+ mReleasing.mInvalidateAck = false;
+ }
+ } else if (messageId != 0) {
+ // messages are drained.
+ if (isMessageLater(messageId, mReleasing.mInvalidateId)) {
+ mReleasing.mInvalidateId = lastMsgId;
+ mReleasing.mInvalidateAck = true;
+ }
+ }
+ if (!mReleasing.mInvalidateAck) {
+ // post ACK
+ mReleasing.mStatusChannel->postBufferInvalidateAck(
+ mConnectionId,
+ mReleasing.mInvalidateId, &mReleasing.mInvalidateAck);
+ }
+ }
+ return cleared;
}
// should have mCache.mLock
@@ -587,6 +677,49 @@
}
}
+// should have mCache.mLock
+void BufferPoolClient::Impl::invalidateBuffer(BufferId id) {
+ for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end(); ++it) {
+ if (id == it->second->id()) {
+ if (!it->second->hasCache()) {
+ mCache.mBuffers.erase(it);
+ ALOGV("cache invalidated %lld : buffer %u",
+ (long long)mConnectionId, id);
+ } else {
+ ALOGW("Inconsitent invalidation %lld : activer buffer!! %u",
+ (long long)mConnectionId, (unsigned int)id);
+ }
+ break;
+ }
+ }
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::invalidateRange(BufferId from, BufferId to) {
+ size_t invalidated = 0;
+ for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
+ if (!it->second->hasCache()) {
+ BufferId bid = it->second->id();
+ if (from < to) {
+ if (from <= bid && bid < to) {
+ ++invalidated;
+ it = mCache.mBuffers.erase(it);
+ continue;
+ }
+ } else {
+ if (from <= bid || bid < to) {
+ ++invalidated;
+ it = mCache.mBuffers.erase(it);
+ continue;
+ }
+ }
+ }
+ ++it;
+ }
+ ALOGV("cache invalidated %lld : # of invalidated %zu",
+ (long long)mConnectionId, invalidated);
+}
+
ResultStatus BufferPoolClient::Impl::allocateBufferHandle(
const std::vector<uint8_t>& params, BufferId *bufferId,
native_handle_t** handle) {
@@ -629,12 +762,14 @@
}
-BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor) {
- mImpl = std::make_shared<Impl>(accessor);
+BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor,
+ const sp<IObserver> &observer) {
+ mImpl = std::make_shared<Impl>(accessor, observer);
}
-BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor) {
- mImpl = std::make_shared<Impl>(accessor);
+BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor,
+ const sp<IObserver> &observer) {
+ mImpl = std::make_shared<Impl>(accessor, observer);
}
BufferPoolClient::~BufferPoolClient() {
@@ -672,6 +807,19 @@
return ResultStatus::CRITICAL_ERROR;
}
+void BufferPoolClient::receiveInvalidation(uint32_t msgId) {
+ if (isValid()) {
+ mImpl->receiveInvalidation(msgId);
+ }
+}
+
+ResultStatus BufferPoolClient::flush() {
+ if (isValid()) {
+ return mImpl->flush();
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
ResultStatus BufferPoolClient::allocate(
const std::vector<uint8_t> ¶ms,
native_handle_t **handle,
diff --git a/media/bufferpool/2.0/BufferPoolClient.h b/media/bufferpool/2.0/BufferPoolClient.h
index 1889ea3..e8d9ae6 100644
--- a/media/bufferpool/2.0/BufferPoolClient.h
+++ b/media/bufferpool/2.0/BufferPoolClient.h
@@ -49,7 +49,8 @@
* Creates a buffer pool client from a local buffer pool
* (via ClientManager#create).
*/
- explicit BufferPoolClient(const sp<Accessor> &accessor);
+ explicit BufferPoolClient(const sp<Accessor> &accessor,
+ const sp<IObserver> &observer);
/**
* Creates a buffer pool client from a remote buffer pool
@@ -57,7 +58,8 @@
* Note: A buffer pool client created with remote buffer pool cannot
* allocate a buffer.
*/
- explicit BufferPoolClient(const sp<IAccessor> &accessor);
+ explicit BufferPoolClient(const sp<IAccessor> &accessor,
+ const sp<IObserver> &observer);
/** Destructs a buffer pool client. */
~BufferPoolClient();
@@ -73,6 +75,10 @@
ResultStatus getAccessor(sp<IAccessor> *accessor);
+ void receiveInvalidation(uint32_t msgId);
+
+ ResultStatus flush();
+
ResultStatus allocate(const std::vector<uint8_t> ¶ms,
native_handle_t **handle,
std::shared_ptr<BufferPoolData> *buffer);
@@ -92,6 +98,7 @@
std::shared_ptr<Impl> mImpl;
friend struct ClientManager;
+ friend struct Observer;
};
} // namespace implementation
diff --git a/media/bufferpool/2.0/BufferStatus.cpp b/media/bufferpool/2.0/BufferStatus.cpp
index 0d3f5a3..6937260 100644
--- a/media/bufferpool/2.0/BufferStatus.cpp
+++ b/media/bufferpool/2.0/BufferStatus.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "BufferPoolStatus"
//#define LOG_NDEBUG 0
+#include <thread>
#include <time.h>
#include "BufferStatus.h"
@@ -37,6 +38,18 @@
return stamp;
}
+bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId) {
+ return curMsgId != prevMsgId && curMsgId - prevMsgId < prevMsgId - curMsgId;
+}
+
+bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId) {
+ if (from < to) {
+ return from <= bufferId && bufferId < to;
+ } else { // wrap happens
+ return from <= bufferId || bufferId < to;
+ }
+}
+
static constexpr int kNumElementsInQueue = 1024*16;
static constexpr int kMinElementsToSyncInQueue = 128;
@@ -139,6 +152,29 @@
}
}
+void BufferStatusChannel::postBufferInvalidateAck(
+ ConnectionId connectionId,
+ uint32_t invalidateId,
+ bool *invalidated) {
+ if (mValid && !*invalidated) {
+ size_t avail = mBufferStatusQueue->availableToWrite();
+ if (avail > 0) {
+ BufferStatusMessage message;
+ message.newStatus = BufferStatus::INVALIDATION_ACK;
+ message.bufferId = invalidateId;
+ message.connectionId = connectionId;
+ if (!mBufferStatusQueue->write(&message, 1)) {
+ // Since avaliable # of writes are already confirmed,
+ // this should not happen.
+ // TODO: error handing?
+ ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+ return;
+ }
+ *invalidated = true;
+ }
+ }
+}
+
bool BufferStatusChannel::postBufferStatusMessage(
TransactionId transactionId, BufferId bufferId,
BufferStatus status, ConnectionId connectionId, ConnectionId targetId,
@@ -182,6 +218,83 @@
return false;
}
+BufferInvalidationListener::BufferInvalidationListener(
+ const InvalidationDescriptor &fmqDesc) {
+ std::unique_ptr<BufferInvalidationQueue> queue =
+ std::make_unique<BufferInvalidationQueue>(fmqDesc);
+ if (!queue || queue->isValid() == false) {
+ mValid = false;
+ return;
+ }
+ mValid = true;
+ mBufferInvalidationQueue = std::move(queue);
+ // drain previous messages
+ size_t avail = std::min(
+ mBufferInvalidationQueue->availableToRead(), (size_t) kNumElementsInQueue);
+ std::vector<BufferInvalidationMessage> temp(avail);
+ if (avail > 0) {
+ mBufferInvalidationQueue->read(temp.data(), avail);
+ }
+}
+
+void BufferInvalidationListener::getInvalidations(
+ std::vector<BufferInvalidationMessage> &messages) {
+ // Try twice in case of overflow.
+ // TODO: handling overflow though it may not happen.
+ for (int i = 0; i < 2; ++i) {
+ size_t avail = std::min(
+ mBufferInvalidationQueue->availableToRead(), (size_t) kNumElementsInQueue);
+ if (avail > 0) {
+ std::vector<BufferInvalidationMessage> temp(avail);
+ if (mBufferInvalidationQueue->read(temp.data(), avail)) {
+ messages.reserve(messages.size() + avail);
+ for (auto it = temp.begin(); it != temp.end(); ++it) {
+ messages.push_back(*it);
+ }
+ break;
+ }
+ } else {
+ return;
+ }
+ }
+}
+
+bool BufferInvalidationListener::isValid() {
+ return mValid;
+}
+
+BufferInvalidationChannel::BufferInvalidationChannel()
+ : mValid(true),
+ mBufferInvalidationQueue(
+ std::make_unique<BufferInvalidationQueue>(kNumElementsInQueue, true)) {
+ if (!mBufferInvalidationQueue || mBufferInvalidationQueue->isValid() == false) {
+ mValid = false;
+ }
+}
+
+bool BufferInvalidationChannel::isValid() {
+ return mValid;
+}
+
+void BufferInvalidationChannel::getDesc(const InvalidationDescriptor **fmqDescPtr) {
+ if (mValid) {
+ *fmqDescPtr = mBufferInvalidationQueue->getDesc();
+ } else {
+ *fmqDescPtr = nullptr;
+ }
+}
+
+void BufferInvalidationChannel::postInvalidation(
+ uint32_t msgId, BufferId fromId, BufferId toId) {
+ BufferInvalidationMessage message;
+
+ message.messageId = msgId;
+ message.fromBufferId = fromId;
+ message.toBufferId = toId;
+ // TODO: handle failure (it does not happen normally.)
+ mBufferInvalidationQueue->write(&message);
+}
+
} // namespace implementation
} // namespace V2_0
} // namespace bufferpool
diff --git a/media/bufferpool/2.0/BufferStatus.h b/media/bufferpool/2.0/BufferStatus.h
index 777a320..fa65838 100644
--- a/media/bufferpool/2.0/BufferStatus.h
+++ b/media/bufferpool/2.0/BufferStatus.h
@@ -37,9 +37,13 @@
/** Returns monotonic timestamp in Us since fixed point in time. */
int64_t getTimestampNow();
+bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId);
+
+bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId);
+
/**
- * A collection of FMQ for a buffer pool. buffer ownership/status change
- * messages are sent via the FMQs from the clients.
+ * A collection of buffer status message FMQ for a buffer pool. buffer
+ * ownership/status change messages are sent via the FMQs from the clients.
*/
class BufferStatusObserver {
private:
@@ -47,7 +51,8 @@
mBufferStatusQueues;
public:
- /** Creates an FMQ for the specified connection(client).
+ /** Creates a buffer status message FMQ for the specified
+ * connection(client).
*
* @param connectionId connection Id of the specified client.
* @param fmqDescPtr double ptr of created FMQ's descriptor.
@@ -58,7 +63,8 @@
*/
ResultStatus open(ConnectionId id, const StatusDescriptor** fmqDescPtr);
- /** Closes an FMQ for the specified connection(client).
+ /** Closes a buffer status message FMQ for the specified
+ * connection(client).
*
* @param connectionId connection Id of the specified client.
*
@@ -75,8 +81,8 @@
};
/**
- * An FMQ for a buffer pool client. Buffer ownership/status change messages
- * are sent via the fmq to the buffer pool.
+ * A buffer status message FMQ for a buffer pool client. Buffer ownership/status
+ * change messages are sent via the fmq to the buffer pool.
*/
class BufferStatusChannel {
private:
@@ -85,7 +91,8 @@
public:
/**
- * Connects to an FMQ from a descriptor of the created FMQ.
+ * Connects to a buffer status message FMQ from a descriptor of
+ * the created FMQ.
*
* @param fmqDesc Descriptor of the created FMQ.
*/
@@ -131,6 +138,86 @@
ConnectionId connectionId,
ConnectionId targetId,
std::list<BufferId> &pending, std::list<BufferId> &posted);
+
+ /**
+ * Posts a buffer invaliadation messge to the buffer pool.
+ *
+ * @param connectionId connection Id of the client.
+ * @param invalidateId invalidation ack to the buffer pool.
+ * if invalidation id is zero, the ack will not be
+ * posted.
+ * @param invalidated sets {@code true} only when the invalidation ack is
+ * posted.
+ */
+ void postBufferInvalidateAck(
+ ConnectionId connectionId,
+ uint32_t invalidateId,
+ bool *invalidated);
+};
+
+/**
+ * A buffer invalidation FMQ for a buffer pool client. Buffer invalidation
+ * messages are received via the fmq from the buffer pool. Buffer invalidation
+ * messages are handled as soon as possible.
+ */
+class BufferInvalidationListener {
+private:
+ bool mValid;
+ std::unique_ptr<BufferInvalidationQueue> mBufferInvalidationQueue;
+
+public:
+ /**
+ * Connects to a buffer invalidation FMQ from a descriptor of the created FMQ.
+ *
+ * @param fmqDesc Descriptor of the created FMQ.
+ */
+ BufferInvalidationListener(const InvalidationDescriptor &fmqDesc);
+
+ /** Retrieves all pending buffer invalidation messages from the buffer pool.
+ *
+ * @param messages retrieved pending messages.
+ */
+ void getInvalidations(std::vector<BufferInvalidationMessage> &messages);
+
+ /** Returns whether the FMQ is connected succesfully. */
+ bool isValid();
+};
+
+/**
+ * A buffer invalidation FMQ for a buffer pool. A buffer pool will send buffer
+ * invalidation messages to the clients via the FMQ. The FMQ is shared among
+ * buffer pool clients.
+ */
+class BufferInvalidationChannel {
+private:
+ bool mValid;
+ std::unique_ptr<BufferInvalidationQueue> mBufferInvalidationQueue;
+
+public:
+ /**
+ * Creates a buffer invalidation FMQ for a buffer pool.
+ */
+ BufferInvalidationChannel();
+
+ /** Returns whether the FMQ is connected succesfully. */
+ bool isValid();
+
+ /**
+ * Retrieves the descriptor of a buffer invalidation FMQ. the descriptor may
+ * be passed to the client for buffer invalidation handling.
+ *
+ * @param fmqDescPtr double ptr of created FMQ's descriptor.
+ */
+ void getDesc(const InvalidationDescriptor **fmqDescPtr);
+
+ /** Posts a buffer invalidation for invalidated buffers.
+ *
+ * @param msgId Invalidation message id which is used when clients send
+ * acks back via BufferStatusMessage
+ * @param fromId The start bufferid of the invalidated buffers(inclusive)
+ * @param toId The end bufferId of the invalidated buffers(inclusive)
+ */
+ void postInvalidation(uint32_t msgId, BufferId fromId, BufferId toId);
};
} // namespace implementation
diff --git a/media/bufferpool/2.0/ClientManager.cpp b/media/bufferpool/2.0/ClientManager.cpp
index eeaf093..f8531d8 100644
--- a/media/bufferpool/2.0/ClientManager.cpp
+++ b/media/bufferpool/2.0/ClientManager.cpp
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <utils/Log.h>
#include "BufferPoolClient.h"
+#include "Observer.h"
namespace android {
namespace hardware {
@@ -106,6 +107,8 @@
ResultStatus close(ConnectionId connectionId);
+ ResultStatus flush(ConnectionId connectionId);
+
ResultStatus allocate(ConnectionId connectionId,
const std::vector<uint8_t> ¶ms,
native_handle_t **handle,
@@ -153,10 +156,13 @@
mClients;
} mActive;
+ sp<Observer> mObserver;
+
ClientManagerCookieHolder mRemoteClientCookies;
};
-ClientManager::Impl::Impl() {}
+ClientManager::Impl::Impl()
+ : mObserver(new Observer()) {}
ResultStatus ClientManager::Impl::registerSender(
const sp<IAccessor> &accessor, ConnectionId *pConnectionId) {
@@ -185,7 +191,7 @@
lock.unlock();
ResultStatus result = ResultStatus::OK;
const std::shared_ptr<BufferPoolClient> client =
- std::make_shared<BufferPoolClient>(accessor);
+ std::make_shared<BufferPoolClient>(accessor, mObserver);
lock.lock();
if (!client) {
result = ResultStatus::NO_MEMORY;
@@ -197,6 +203,7 @@
const std::weak_ptr<BufferPoolClient> wclient = client;
mCache.mClients.push_back(std::make_pair(accessor, wclient));
ConnectionId conId = client->getConnectionId();
+ mObserver->addClient(conId, wclient);
{
std::lock_guard<std::mutex> lock(mActive.mMutex);
mActive.mClients.insert(std::make_pair(conId, client));
@@ -266,8 +273,9 @@
if (!accessor || !accessor->isValid()) {
return ResultStatus::CRITICAL_ERROR;
}
+ // TODO: observer is local. use direct call instead of hidl call.
std::shared_ptr<BufferPoolClient> client =
- std::make_shared<BufferPoolClient>(accessor);
+ std::make_shared<BufferPoolClient>(accessor, mObserver);
if (!client || !client->isValid()) {
return ResultStatus::CRITICAL_ERROR;
}
@@ -280,6 +288,7 @@
const std::weak_ptr<BufferPoolClient> wclient = client;
mCache.mClients.push_back(std::make_pair(accessor, wclient));
ConnectionId conId = client->getConnectionId();
+ mObserver->addClient(conId, wclient);
{
std::lock_guard<std::mutex> lock(mActive.mMutex);
mActive.mClients.insert(std::make_pair(conId, client));
@@ -291,12 +300,13 @@
}
ResultStatus ClientManager::Impl::close(ConnectionId connectionId) {
- std::lock_guard<std::mutex> lock1(mCache.mMutex);
- std::lock_guard<std::mutex> lock2(mActive.mMutex);
+ std::unique_lock<std::mutex> lock1(mCache.mMutex);
+ std::unique_lock<std::mutex> lock2(mActive.mMutex);
auto it = mActive.mClients.find(connectionId);
if (it != mActive.mClients.end()) {
sp<IAccessor> accessor;
it->second->getAccessor(&accessor);
+ std::shared_ptr<BufferPoolClient> closing = it->second;
mActive.mClients.erase(connectionId);
for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
// clean up dead client caches
@@ -307,11 +317,27 @@
cit++;
}
}
+ lock2.unlock();
+ lock1.unlock();
+ closing->flush();
return ResultStatus::OK;
}
return ResultStatus::NOT_FOUND;
}
+ResultStatus ClientManager::Impl::flush(ConnectionId connectionId) {
+ std::shared_ptr<BufferPoolClient> client;
+ {
+ std::lock_guard<std::mutex> lock(mActive.mMutex);
+ auto it = mActive.mClients.find(connectionId);
+ if (it == mActive.mClients.end()) {
+ return ResultStatus::NOT_FOUND;
+ }
+ client = it->second;
+ }
+ return client->flush();
+}
+
ResultStatus ClientManager::Impl::allocate(
ConnectionId connectionId, const std::vector<uint8_t> ¶ms,
native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
@@ -461,6 +487,13 @@
return ResultStatus::CRITICAL_ERROR;
}
+ResultStatus ClientManager::flush(ConnectionId connectionId) {
+ if (mImpl) {
+ return mImpl->flush(connectionId);
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
ResultStatus ClientManager::allocate(
ConnectionId connectionId, const std::vector<uint8_t> ¶ms,
native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
diff --git a/media/bufferpool/2.0/Connection.cpp b/media/bufferpool/2.0/Connection.cpp
index cd837a1..6bd0e79 100644
--- a/media/bufferpool/2.0/Connection.cpp
+++ b/media/bufferpool/2.0/Connection.cpp
@@ -60,6 +60,13 @@
}
}
+ResultStatus Connection::flush() {
+ if (mInitialized && mAccessor) {
+ return mAccessor->flush();
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
ResultStatus Connection::allocate(
const std::vector<uint8_t> ¶ms, BufferId *bufferId,
const native_handle_t **handle) {
diff --git a/media/bufferpool/2.0/Connection.h b/media/bufferpool/2.0/Connection.h
index e2b47f1..8507749 100644
--- a/media/bufferpool/2.0/Connection.h
+++ b/media/bufferpool/2.0/Connection.h
@@ -44,6 +44,11 @@
Return<void> fetch(uint64_t transactionId, uint32_t bufferId, fetch_cb _hidl_cb) override;
/**
+ * Invalidates all buffers which are active and/or are ready to be recycled.
+ */
+ ResultStatus flush();
+
+ /**
* Allocates a buffer using the specified parameters. Recycles a buffer if
* it is possible. The returned buffer can be transferred to other remote
* clients(Connection).
diff --git a/media/bufferpool/2.0/Observer.cpp b/media/bufferpool/2.0/Observer.cpp
new file mode 100644
index 0000000..5b23160
--- /dev/null
+++ b/media/bufferpool/2.0/Observer.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Observer.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+Observer::Observer() {
+}
+
+Observer::~Observer() {
+}
+
+// Methods from ::android::hardware::media::bufferpool::V2_0::IObserver follow.
+Return<void> Observer::onMessage(int64_t connectionId, uint32_t msgId) {
+ std::unique_lock<std::mutex> lock(mLock);
+ auto it = mClients.find(connectionId);
+ if (it != mClients.end()) {
+ const std::shared_ptr<BufferPoolClient> client = it->second.lock();
+ if (!client) {
+ mClients.erase(it);
+ } else {
+ lock.unlock();
+ client->receiveInvalidation(msgId);
+ }
+ }
+ return Void();
+}
+
+void Observer::addClient(ConnectionId connectionId,
+ const std::weak_ptr<BufferPoolClient> &wclient) {
+ std::lock_guard<std::mutex> lock(mLock);
+ for (auto it = mClients.begin(); it != mClients.end();) {
+ if (!it->second.lock() || it->first == connectionId) {
+ it = mClients.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ mClients.insert(std::make_pair(connectionId, wclient));
+
+}
+
+void Observer::delClient(ConnectionId connectionId) {
+ std::lock_guard<std::mutex> lock(mLock);
+ mClients.erase(connectionId);
+}
+
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace bufferpool
+} // namespace media
+} // namespace hardware
+} // namespace android
diff --git a/media/bufferpool/2.0/Observer.h b/media/bufferpool/2.0/Observer.h
new file mode 100644
index 0000000..42bd7c1
--- /dev/null
+++ b/media/bufferpool/2.0/Observer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_OBSERVER_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_OBSERVER_H
+
+#include <android/hardware/media/bufferpool/2.0/IObserver.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include "BufferPoolClient.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct Observer : public IObserver {
+ // Methods from ::android::hardware::media::bufferpool::V2_0::IObserver follow.
+ Return<void> onMessage(int64_t connectionId, uint32_t msgId) override;
+
+ ~Observer();
+
+ void addClient(ConnectionId connectionId,
+ const std::weak_ptr<BufferPoolClient> &wclient);
+
+ void delClient(ConnectionId connectionId);
+
+private:
+ Observer();
+
+ friend struct ClientManager;
+
+ std::mutex mLock;
+ std::map<ConnectionId, const std::weak_ptr<BufferPoolClient>> mClients;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace bufferpool
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_OBSERVER_H
diff --git a/media/bufferpool/2.0/include/bufferpool/ClientManager.h b/media/bufferpool/2.0/include/bufferpool/ClientManager.h
index cfc3bc3..953c304 100644
--- a/media/bufferpool/2.0/include/bufferpool/ClientManager.h
+++ b/media/bufferpool/2.0/include/bufferpool/ClientManager.h
@@ -92,6 +92,18 @@
ResultStatus close(ConnectionId connectionId);
/**
+ * Evicts cached allocations. If it's local connection, release the
+ * previous allocations and do not recycle current active allocations.
+ *
+ * @param connectionId The id of the connection.
+ *
+ * @return OK when the connection is resetted.
+ * NOT_FOUND when the specified connection was not found.
+ * CRITICAL_ERROR otherwise.
+ */
+ ResultStatus flush(ConnectionId connectionId);
+
+ /**
* Allocates a buffer from the specified connection.
*
* @param connectionId The id of the connection.
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index fcfdaff..be6d9fd 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -622,6 +622,8 @@
AMediaFormat_setInt32(mTrackMetadata,
AMEDIAFORMAT_KEY_SAMPLE_RATE, getSampleRate());
AMediaFormat_setInt32(mTrackMetadata,
+ AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, getBitsPerSample());
+ AMediaFormat_setInt32(mTrackMetadata,
AMEDIAFORMAT_KEY_PCM_ENCODING, kAudioEncodingPcm16bit);
// sample rate is non-zero, so division by zero not possible
AMediaFormat_setInt64(mTrackMetadata,
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index 9a329f1..ddc7031 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -311,6 +311,7 @@
AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mNumChannels);
AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_MASK, mChannelMask);
AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mSampleRate);
+ AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, mBitsPerSample);
AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_PCM_ENCODING,
kAudioEncodingPcm16bit);
diff --git a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
index ef9a753..64deb60 100644
--- a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
+++ b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
@@ -163,8 +163,7 @@
const float *needle, int needleSize,
LatencyReport *report) {
const double threshold = 0.1;
- printf("measureLatencyFromEchos: haystackSize = %d, needleSize = %d\n",
- haystackSize, needleSize);
+ // printf("%s: haystackSize = %d, needleSize = %d\n", __func__, haystackSize, needleSize);
// Find first peak
int first = (int) (findFirstMatch(haystack,
@@ -181,8 +180,6 @@
needle,
needleSize,
threshold) + 0.5);
-
- printf("measureLatencyFromEchos: first = %d, again at %d\n", first, again);
first = again;
// Allocate results array
@@ -199,7 +196,7 @@
// Add higher harmonics mapped onto lower harmonics.
// This reinforces the "fundamental" echo.
- const int numEchoes = 10;
+ const int numEchoes = 8;
for (int partial = 1; partial < numEchoes; partial++) {
for (int i = 0; i < numCorrelations; i++) {
harmonicSums[i / partial] += correlations[i] / partial;
@@ -216,7 +213,7 @@
maxCorrelation = harmonicSums[i];
sumOfPeaks += maxCorrelation;
peakIndex = i;
- printf("maxCorrelation = %f at %d\n", maxCorrelation, peakIndex);
+ // printf("maxCorrelation = %f at %d\n", maxCorrelation, peakIndex);
}
}
@@ -476,9 +473,13 @@
void report() override {
printf("EchoAnalyzer ---------------\n");
- printf(LOOPBACK_RESULT_TAG "measured.gain = %f\n", mMeasuredLoopGain);
- printf(LOOPBACK_RESULT_TAG "echo.gain = %f\n", mEchoGain);
- printf(LOOPBACK_RESULT_TAG "test.state = %d\n", mState);
+ printf(LOOPBACK_RESULT_TAG "measured.gain = %8f\n", mMeasuredLoopGain);
+ printf(LOOPBACK_RESULT_TAG "echo.gain = %8f\n", mEchoGain);
+ printf(LOOPBACK_RESULT_TAG "test.state = %8d\n", mState);
+ printf(LOOPBACK_RESULT_TAG "test.state.name = %8s\n", convertStateToText(mState));
+ if (mState == STATE_WAITING_FOR_SILENCE) {
+ printf("WARNING - Stuck waiting for silence. Input may be too noisy!\n");
+ }
if (mMeasuredLoopGain >= 0.9999) {
printf(" ERROR - clipping, turn down volume slightly\n");
} else {
@@ -491,9 +492,12 @@
printf(" ERROR - confidence too low = %f\n", mLatencyReport.confidence);
} else {
double latencyMillis = 1000.0 * mLatencyReport.latencyInFrames / getSampleRate();
- printf(LOOPBACK_RESULT_TAG "latency.frames = %8.2f\n", mLatencyReport.latencyInFrames);
- printf(LOOPBACK_RESULT_TAG "latency.msec = %8.2f\n", latencyMillis);
- printf(LOOPBACK_RESULT_TAG "latency.confidence = %8.6f\n", mLatencyReport.confidence);
+ printf(LOOPBACK_RESULT_TAG "latency.frames = %8.2f\n",
+ mLatencyReport.latencyInFrames);
+ printf(LOOPBACK_RESULT_TAG "latency.msec = %8.2f\n",
+ latencyMillis);
+ printf(LOOPBACK_RESULT_TAG "latency.confidence = %8.6f\n",
+ mLatencyReport.confidence);
}
}
}
@@ -527,7 +531,7 @@
int numWritten;
int numSamples;
- echo_state_t nextState = mState;
+ echo_state nextState = mState;
switch (mState) {
case STATE_INITIAL_SILENCE:
@@ -553,6 +557,7 @@
// mLoopCounter, peak);
mDownCounter = 8;
mMeasuredLoopGain = peak; // assumes original pulse amplitude is one
+ mSilenceThreshold = peak * 0.1; // scale silence to measured pulse
// Calculate gain that will give us a nice decaying echo.
mEchoGain = mDesiredEchoGain / mMeasuredLoopGain;
if (mEchoGain > MAX_ECHO_GAIN) {
@@ -638,7 +643,7 @@
private:
- enum echo_state_t {
+ enum echo_state {
STATE_INITIAL_SILENCE,
STATE_MEASURING_GAIN,
STATE_WAITING_FOR_SILENCE,
@@ -648,6 +653,35 @@
STATE_FAILED
};
+ const char *convertStateToText(echo_state state) {
+ const char *result = "Unknown";
+ switch(state) {
+ case STATE_INITIAL_SILENCE:
+ result = "INIT";
+ break;
+ case STATE_MEASURING_GAIN:
+ result = "GAIN";
+ break;
+ case STATE_WAITING_FOR_SILENCE:
+ result = "SILENCE";
+ break;
+ case STATE_SENDING_PULSE:
+ result = "PULSE";
+ break;
+ case STATE_GATHERING_ECHOS:
+ result = "ECHOS";
+ break;
+ case STATE_DONE:
+ result = "DONE";
+ break;
+ case STATE_FAILED:
+ result = "FAILED";
+ break;
+ }
+ return result;
+ }
+
+
int32_t mDownCounter = 500;
int32_t mLoopCounter = 0;
int32_t mSampleIndex = 0;
@@ -656,7 +690,7 @@
float mMeasuredLoopGain = 0.0f;
float mDesiredEchoGain = 0.95f;
float mEchoGain = 1.0f;
- echo_state_t mState = STATE_INITIAL_SILENCE;
+ echo_state mState = STATE_INITIAL_SILENCE;
AudioRecording mAudioRecording; // contains only the input after the gain detection burst
LatencyReport mLatencyReport;
@@ -680,21 +714,32 @@
void report() override {
printf("SineAnalyzer ------------------\n");
- printf(LOOPBACK_RESULT_TAG "peak.amplitude = %7.5f\n", mPeakAmplitude);
- printf(LOOPBACK_RESULT_TAG "sine.magnitude = %7.5f\n", mMagnitude);
- printf(LOOPBACK_RESULT_TAG "phase.offset = %7.5f\n", mPhaseOffset);
- printf(LOOPBACK_RESULT_TAG "ref.phase = %7.5f\n", mPhase);
- printf(LOOPBACK_RESULT_TAG "frames.accumulated = %6d\n", mFramesAccumulated);
- printf(LOOPBACK_RESULT_TAG "sine.period = %6d\n", mSinePeriod);
- printf(LOOPBACK_RESULT_TAG "test.state = %6d\n", mState);
- printf(LOOPBACK_RESULT_TAG "frame.count = %6d\n", mFrameCounter);
+ printf(LOOPBACK_RESULT_TAG "peak.amplitude = %8f\n", mPeakAmplitude);
+ printf(LOOPBACK_RESULT_TAG "sine.magnitude = %8f\n", mMagnitude);
+ printf(LOOPBACK_RESULT_TAG "peak.noise = %8f\n", mPeakNoise);
+ printf(LOOPBACK_RESULT_TAG "rms.noise = %8f\n", mRootMeanSquareNoise);
+ float amplitudeRatio = mMagnitude / mPeakNoise;
+ float signalToNoise = amplitudeRatio * amplitudeRatio;
+ printf(LOOPBACK_RESULT_TAG "signal.to.noise = %8.2f\n", signalToNoise);
+ float signalToNoiseDB = 10.0 * log(signalToNoise);
+ printf(LOOPBACK_RESULT_TAG "signal.to.noise.db = %8.2f\n", signalToNoiseDB);
+ if (signalToNoiseDB < MIN_SNRATIO_DB) {
+ printf("WARNING - signal to noise ratio is too low! < %d dB\n", MIN_SNRATIO_DB);
+ }
+ printf(LOOPBACK_RESULT_TAG "phase.offset = %8.5f\n", mPhaseOffset);
+ printf(LOOPBACK_RESULT_TAG "ref.phase = %8.5f\n", mPhase);
+ printf(LOOPBACK_RESULT_TAG "frames.accumulated = %8d\n", mFramesAccumulated);
+ printf(LOOPBACK_RESULT_TAG "sine.period = %8d\n", mSinePeriod);
+ printf(LOOPBACK_RESULT_TAG "test.state = %8d\n", mState);
+ printf(LOOPBACK_RESULT_TAG "frame.count = %8d\n", mFrameCounter);
// Did we ever get a lock?
bool gotLock = (mState == STATE_LOCKED) || (mGlitchCount > 0);
if (!gotLock) {
printf("ERROR - failed to lock on reference sine tone\n");
} else {
// Only print if meaningful.
- printf(LOOPBACK_RESULT_TAG "glitch.count = %6d\n", mGlitchCount);
+ printf(LOOPBACK_RESULT_TAG "glitch.count = %8d\n", mGlitchCount);
+ printf(LOOPBACK_RESULT_TAG "max.glitch = %8f\n", mMaxGlitchDelta);
}
}
@@ -732,15 +777,48 @@
}
for (int i = 0; i < numFrames; i++) {
+ bool sineEnabled = true;
float sample = inputData[i * inputChannelCount];
float sinOut = sinf(mPhase);
switch (mState) {
case STATE_IDLE:
- case STATE_IMMUNE:
- case STATE_WAITING_FOR_SIGNAL:
+ sineEnabled = false;
+ mDownCounter--;
+ if (mDownCounter <= 0) {
+ mState = STATE_MEASURE_NOISE;
+ mDownCounter = NOISE_FRAME_COUNT;
+ }
break;
+ case STATE_MEASURE_NOISE:
+ sineEnabled = false;
+ mPeakNoise = std::max(abs(sample), mPeakNoise);
+ mNoiseSumSquared += sample * sample;
+ mDownCounter--;
+ if (mDownCounter <= 0) {
+ mState = STATE_WAITING_FOR_SIGNAL;
+ mRootMeanSquareNoise = sqrt(mNoiseSumSquared / NOISE_FRAME_COUNT);
+ mTolerance = std::max(MIN_TOLERANCE, mPeakNoise * 2.0f);
+ mPhase = 0.0; // prevent spike at start
+ }
+ break;
+
+ case STATE_IMMUNE:
+ mDownCounter--;
+ if (mDownCounter <= 0) {
+ mState = STATE_WAITING_FOR_SIGNAL;
+ }
+ break;
+
+ case STATE_WAITING_FOR_SIGNAL:
+ if (peak > mThreshold) {
+ mState = STATE_WAITING_FOR_LOCK;
+ //printf("%5d: switch to STATE_WAITING_FOR_LOCK\n", mFrameCounter);
+ resetAccumulator();
+ }
+ break;
+
case STATE_WAITING_FOR_LOCK:
mSinAccumulator += sample * sinOut;
mCosAccumulator += sample * cosf(mPhase);
@@ -766,13 +844,14 @@
// printf(" predicted = %f, actual = %f\n", predicted, sample);
float diff = predicted - sample;
- if (fabs(diff) > mTolerance) {
+ float absDiff = fabs(diff);
+ mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
+ if (absDiff > mTolerance) {
mGlitchCount++;
//printf("%5d: Got a glitch # %d, predicted = %f, actual = %f\n",
// mFrameCounter, mGlitchCount, predicted, sample);
mState = STATE_IMMUNE;
- //printf("%5d: switch to STATE_IMMUNE\n", mFrameCounter);
- mDownCounter = mSinePeriod; // Set duration of IMMUNE state.
+ mDownCounter = mSinePeriod * PERIODS_IMMUNE;
}
// Track incoming signal and slowly adjust magnitude to account
@@ -792,44 +871,23 @@
} break;
}
+ float output = 0.0f;
// Output sine wave so we can measure it.
- outputData[i * outputChannelCount] = (sinOut * mOutputAmplitude)
- + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude);
- // printf("%5d: sin(%f) = %f, %f\n", i, mPhase, sinOut, mPhaseIncrement);
-
- // advance and wrap phase
- mPhase += mPhaseIncrement;
- if (mPhase > M_PI) {
- mPhase -= (2.0 * M_PI);
+ if (sineEnabled) {
+ output = (sinOut * mOutputAmplitude)
+ + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude);
+ // printf("%5d: sin(%f) = %f, %f\n", i, mPhase, sinOut, mPhaseIncrement);
+ // advance and wrap phase
+ mPhase += mPhaseIncrement;
+ if (mPhase > M_PI) {
+ mPhase -= (2.0 * M_PI);
+ }
}
+ outputData[i * outputChannelCount] = output;
+
mFrameCounter++;
}
-
- // Do these once per buffer.
- switch (mState) {
- case STATE_IDLE:
- mState = STATE_IMMUNE; // so we can tell when
- break;
- case STATE_IMMUNE:
- mDownCounter -= numFrames;
- if (mDownCounter <= 0) {
- mState = STATE_WAITING_FOR_SIGNAL;
- //printf("%5d: switch to STATE_WAITING_FOR_SIGNAL\n", mFrameCounter);
- }
- break;
- case STATE_WAITING_FOR_SIGNAL:
- if (peak > mThreshold) {
- mState = STATE_WAITING_FOR_LOCK;
- //printf("%5d: switch to STATE_WAITING_FOR_LOCK\n", mFrameCounter);
- resetAccumulator();
- }
- break;
- case STATE_WAITING_FOR_LOCK:
- case STATE_LOCKED:
- break;
- }
-
}
void resetAccumulator() {
@@ -840,18 +898,24 @@
void reset() override {
mGlitchCount = 0;
- mState = STATE_IMMUNE;
- mDownCounter = IMMUNE_FRAME_COUNT;
+ mState = STATE_IDLE;
+ mDownCounter = IDLE_FRAME_COUNT;
mPhaseIncrement = 2.0 * M_PI / mSinePeriod;
printf("phaseInc = %f for period %d\n", mPhaseIncrement, mSinePeriod);
resetAccumulator();
mProcessCount = 0;
+ mPeakNoise = 0.0f;
+ mNoiseSumSquared = 0.0;
+ mRootMeanSquareNoise = 0.0;
+ mPhase = 0.0f;
+ mMaxGlitchDelta = 0.0;
}
private:
enum sine_state_t {
STATE_IDLE,
+ STATE_MEASURE_NOISE,
STATE_IMMUNE,
STATE_WAITING_FOR_SIGNAL,
STATE_WAITING_FOR_LOCK,
@@ -859,10 +923,16 @@
};
enum constants {
- IMMUNE_FRAME_COUNT = 48 * 500,
- PERIODS_NEEDED_FOR_LOCK = 8
+ // Arbitrary durations, assuming 48000 Hz
+ IDLE_FRAME_COUNT = 48 * 100,
+ NOISE_FRAME_COUNT = 48 * 600,
+ PERIODS_NEEDED_FOR_LOCK = 8,
+ PERIODS_IMMUNE = 2,
+ MIN_SNRATIO_DB = 65
};
+ static constexpr float MIN_TOLERANCE = 0.01;
+
int mSinePeriod = 79;
double mPhaseIncrement = 0.0;
double mPhase = 0.0;
@@ -870,17 +940,23 @@
double mPreviousPhaseOffset = 0.0;
double mMagnitude = 0.0;
double mThreshold = 0.005;
- double mTolerance = 0.01;
+ double mTolerance = MIN_TOLERANCE;
int32_t mFramesAccumulated = 0;
int32_t mProcessCount = 0;
double mSinAccumulator = 0.0;
double mCosAccumulator = 0.0;
+ float mMaxGlitchDelta = 0.0f;
int32_t mGlitchCount = 0;
double mPeakAmplitude = 0.0;
- int mDownCounter = IMMUNE_FRAME_COUNT;
+ int mDownCounter = IDLE_FRAME_COUNT;
int32_t mFrameCounter = 0;
float mOutputAmplitude = 0.75;
+ // measure background noise
+ float mPeakNoise = 0.0f;
+ double mNoiseSumSquared = 0.0;
+ double mRootMeanSquareNoise = 0.0;
+
PseudoRandom mWhiteNoise;
float mNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC.
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 84f9c22..124efd8 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -37,13 +37,12 @@
// Tag for machine readable results as property = value pairs
#define RESULT_TAG "RESULT: "
-#define NUM_SECONDS 5
-#define PERIOD_MILLIS 1000
-#define NUM_INPUT_CHANNELS 1
#define FILENAME_ALL "/data/loopback_all.wav"
#define FILENAME_ECHOS "/data/loopback_echos.wav"
-#define APP_VERSION "0.2.04"
+#define APP_VERSION "0.3.00"
+constexpr int kLogPeriodMillis = 1000;
+constexpr int kNumInputChannels = 1;
constexpr int kNumCallbacksToDrain = 20;
constexpr int kNumCallbacksToDiscard = 20;
@@ -336,7 +335,7 @@
aaudio_result_t result = AAUDIO_OK;
aaudio_sharing_mode_t requestedInputSharingMode = AAUDIO_SHARING_MODE_SHARED;
- int requestedInputChannelCount = NUM_INPUT_CHANNELS;
+ int requestedInputChannelCount = kNumInputChannels;
aaudio_format_t requestedInputFormat = AAUDIO_FORMAT_UNSPECIFIED;
int32_t requestedInputCapacity = AAUDIO_UNSPECIFIED;
aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
@@ -459,7 +458,9 @@
argParser.setPerformanceMode(inputPerformanceLevel);
argParser.setChannelCount(requestedInputChannelCount);
argParser.setSharingMode(requestedInputSharingMode);
- // Warning! If you change input capacity then you may not get a FAST track on Legacy path.
+ if (requestedInputCapacity != AAUDIO_UNSPECIFIED) {
+ printf("Warning! If you set input capacity then maybe no FAST track on Legacy path!\n");
+ }
argParser.setBufferCapacity(requestedInputCapacity);
result = recorder.open(argParser);
@@ -510,15 +511,11 @@
// Start OUTPUT first so INPUT does not overflow.
result = player.start();
if (result != AAUDIO_OK) {
- printf("ERROR - AAudioStream_requestStart(output) returned %d = %s\n",
- result, AAudio_convertResultToText(result));
goto finish;
}
result = recorder.start();
if (result != AAUDIO_OK) {
- printf("ERROR - AAudioStream_requestStart(input) returned %d = %s\n",
- result, AAudio_convertResultToText(result));
goto finish;
}
@@ -561,7 +558,7 @@
AAudioStream_getXRunCount(outputStream)
);
}
- int32_t periodMillis = (timeMillis < 2000) ? PERIOD_MILLIS / 4 : PERIOD_MILLIS;
+ int32_t periodMillis = (timeMillis < 2000) ? kLogPeriodMillis / 4 : kLogPeriodMillis;
usleep(periodMillis * 1000);
timeMillis += periodMillis;
}
@@ -586,12 +583,12 @@
if (loopbackData.inputError == AAUDIO_OK) {
if (testMode == TEST_SINE_MAGNITUDE) {
printAudioGraph(loopbackData.audioRecording, 200);
+ // Print again so we don't have to scroll past waveform.
+ printf("OUTPUT Stream ----------------------------------------\n");
+ argParser.compareWithStream(outputStream);
+ printf("INPUT Stream ----------------------------------------\n");
+ argParser.compareWithStream(inputStream);
}
- // Print again so we don't have to scroll past waveform.
- printf("OUTPUT Stream ----------------------------------------\n");
- argParser.compareWithStream(outputStream);
- printf("INPUT Stream ----------------------------------------\n");
- argParser.compareWithStream(inputStream);
loopbackData.loopbackProcessor->report();
}
@@ -600,21 +597,21 @@
int32_t framesRead = AAudioStream_getFramesRead(inputStream);
int32_t framesWritten = AAudioStream_getFramesWritten(inputStream);
printf("Callback Results ---------------------------------------- INPUT\n");
- printf(" input overruns = %d\n", AAudioStream_getXRunCount(inputStream));
+ printf(" input overruns = %8d\n", AAudioStream_getXRunCount(inputStream));
printf(" framesWritten = %8d\n", framesWritten);
printf(" framesRead = %8d\n", framesRead);
printf(" myFramesRead = %8d\n", (int) loopbackData.framesReadTotal);
printf(" written - read = %8d\n", (int) (framesWritten - framesRead));
printf(" insufficient # = %8d\n", (int) loopbackData.insufficientReadCount);
if (loopbackData.insufficientReadCount > 0) {
- printf(" insufficient frames = %8d\n", (int) loopbackData.insufficientReadFrames);
+ printf(" insuffic. frames = %8d\n", (int) loopbackData.insufficientReadFrames);
}
}
{
int32_t framesRead = AAudioStream_getFramesRead(outputStream);
int32_t framesWritten = AAudioStream_getFramesWritten(outputStream);
printf("Callback Results ---------------------------------------- OUTPUT\n");
- printf(" output underruns = %d\n", AAudioStream_getXRunCount(outputStream));
+ printf(" output underruns = %8d\n", AAudioStream_getXRunCount(outputStream));
printf(" myFramesWritten = %8d\n", (int) loopbackData.framesWrittenTotal);
printf(" framesWritten = %8d\n", framesWritten);
printf(" framesRead = %8d\n", framesRead);
@@ -659,4 +656,3 @@
return EXIT_SUCCESS;
}
}
-
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 54b77ba..1645986 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -193,7 +193,7 @@
aaudio_result_t start() {
aaudio_result_t result = AAudioStream_requestStart(mStream);
if (result != AAUDIO_OK) {
- printf("ERROR - AAudioStream_requestStart() returned %d %s\n",
+ printf("ERROR - AAudioStream_requestStart(output) returned %d %s\n",
result, AAudio_convertResultToText(result));
}
return result;
@@ -203,7 +203,7 @@
aaudio_result_t stop() {
aaudio_result_t result = AAudioStream_requestStop(mStream);
if (result != AAUDIO_OK) {
- printf("ERROR - AAudioStream_requestStop() returned %d %s\n",
+ printf("ERROR - AAudioStream_requestStop(output) returned %d %s\n",
result, AAudio_convertResultToText(result));
}
int32_t xRunCount = AAudioStream_getXRunCount(mStream);
@@ -215,7 +215,7 @@
aaudio_result_t pause() {
aaudio_result_t result = AAudioStream_requestPause(mStream);
if (result != AAUDIO_OK) {
- printf("ERROR - AAudioStream_requestPause() returned %d %s\n",
+ printf("ERROR - AAudioStream_requestPause(output) returned %d %s\n",
result, AAudio_convertResultToText(result));
}
int32_t xRunCount = AAudioStream_getXRunCount(mStream);
@@ -223,11 +223,27 @@
return result;
}
+ aaudio_result_t waitUntilPaused() {
+ aaudio_result_t result = AAUDIO_OK;
+ aaudio_stream_state_t currentState = AAudioStream_getState(mStream);
+ aaudio_stream_state_t inputState = AAUDIO_STREAM_STATE_PAUSING;
+ while (result == AAUDIO_OK && currentState == AAUDIO_STREAM_STATE_PAUSING) {
+ result = AAudioStream_waitForStateChange(mStream, inputState,
+ ¤tState, NANOS_PER_SECOND);
+ inputState = currentState;
+ }
+ if (result != AAUDIO_OK) {
+ return result;
+ }
+ return (currentState == AAUDIO_STREAM_STATE_PAUSED)
+ ? AAUDIO_OK : AAUDIO_ERROR_INVALID_STATE;
+ }
+
// Flush the stream. AAudio will stop calling your callback function.
aaudio_result_t flush() {
aaudio_result_t result = AAudioStream_requestFlush(mStream);
if (result != AAUDIO_OK) {
- printf("ERROR - AAudioStream_requestFlush() returned %d %s\n",
+ printf("ERROR - AAudioStream_requestFlush(output) returned %d %s\n",
result, AAudio_convertResultToText(result));
}
return result;
diff --git a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
index 869fad0..246e2d7 100644
--- a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
+++ b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
@@ -201,8 +201,10 @@
aaudio_result_t start() {
aaudio_result_t result = AAudioStream_requestStart(mStream);
if (result != AAUDIO_OK) {
- fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d %s\n",
+ fprintf(stderr, "ERROR - AAudioStream_requestStart(input) returned %d %s\n",
result, AAudio_convertResultToText(result));
+ fprintf(stderr, " Did you remember to enter: adb root ????\n");
+
}
return result;
}
@@ -211,8 +213,9 @@
aaudio_result_t stop() {
aaudio_result_t result = AAudioStream_requestStop(mStream);
if (result != AAUDIO_OK) {
- fprintf(stderr, "ERROR - AAudioStream_requestStop() returned %d %s\n",
+ fprintf(stderr, "ERROR - AAudioStream_requestStop(input) returned %d %s\n",
result, AAudio_convertResultToText(result));
+
}
return result;
}
@@ -221,7 +224,7 @@
aaudio_result_t pause() {
aaudio_result_t result = AAudioStream_requestPause(mStream);
if (result != AAUDIO_OK) {
- fprintf(stderr, "ERROR - AAudioStream_requestPause() returned %d %s\n",
+ fprintf(stderr, "ERROR - AAudioStream_requestPause(input) returned %d %s\n",
result, AAudio_convertResultToText(result));
}
return result;
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index e33e9f8..7a48153 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -30,6 +30,8 @@
#include "AAudioSimplePlayer.h"
#include "AAudioArgsParser.h"
+#define APP_VERSION "0.1.5"
+
/**
* Open stream, play some sine waves, then close the stream.
*
@@ -109,13 +111,13 @@
startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
for (int second = 0; second < durationSeconds; second++) {
// Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
- long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
+ myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
int64_t millis =
(getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
result = myData.waker.get();
- printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
+ printf(" waker result = %d, at %6d millis"
", second = %3d, framesWritten = %8d, underruns = %d\n",
- ret, result, (int) millis,
+ result, (int) millis,
second,
(int) AAudioStream_getFramesWritten(player.getStream()),
(int) AAudioStream_getXRunCount(player.getStream()));
@@ -138,6 +140,10 @@
if (result != AAUDIO_OK) {
goto error;
}
+ result = player.waitUntilPaused();
+ if (result != AAUDIO_OK) {
+ goto error;
+ }
result = player.flush();
}
if (result != AAUDIO_OK) {
@@ -219,7 +225,7 @@
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Play a sine sweep using an AAudio callback V0.1.4\n", argv[0]);
+ printf("%s - Play a sine sweep using an AAudio callback V%s\n", argv[0], APP_VERSION);
for (int i = 1; i < argc; i++) {
const char *arg = argv[i];
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 8dc31d0..e272f2a 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -146,14 +146,14 @@
AAUDIO_API void AAudioStreamBuilder_setChannelCount(AAudioStreamBuilder* builder,
int32_t channelCount)
{
- AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
- streamBuilder->setSamplesPerFrame(channelCount);
+ AAudioStreamBuilder_setSamplesPerFrame(builder, channelCount);
}
AAUDIO_API void AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder* builder,
- int32_t channelCount)
+ int32_t samplesPerFrame)
{
- AAudioStreamBuilder_setChannelCount(builder, channelCount);
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ streamBuilder->setSamplesPerFrame(samplesPerFrame);
}
AAUDIO_API void AAudioStreamBuilder_setDirection(AAudioStreamBuilder* builder,
diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk
index 3534149..35e2f3d 100644
--- a/media/libeffects/visualizer/Android.mk
+++ b/media/libeffects/visualizer/Android.mk
@@ -9,6 +9,7 @@
LOCAL_CFLAGS+= -O2 -fvisibility=hidden
LOCAL_CFLAGS += -Wall -Werror
+LOCAL_CFLAGS += -DBUILD_FLOAT -DSUPPORT_MC
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index e2ccfb7..00bc371 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -32,8 +32,6 @@
#include <audio_effects/effect_visualizer.h>
#include <audio_utils/primitives.h>
-#define BUILD_FLOAT
-
#ifdef BUILD_FLOAT
static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_FLOAT;
@@ -157,7 +155,12 @@
if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
- if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
+ const uint32_t channelCount = audio_channel_count_from_out_mask(pConfig->inputCfg.channels);
+#ifdef SUPPORT_MC
+ if (channelCount < 1 || channelCount > FCC_8) return -EINVAL;
+#else
+ if (channelCount != FCC_2) return -EINVAL;
+#endif
if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
if (pConfig->inputCfg.format != kProcessFormat) return -EINVAL;
@@ -356,7 +359,7 @@
// store the measurement
pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mPeakU16 = (uint16_t)maxSample;
pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mRmsSquared =
- rmsSqAcc / (inBuffer->frameCount * pContext->mChannelCount);
+ rmsSqAcc / sampleLen;
pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mIsValid = true;
if (++pContext->mMeasurementBufferIdx >= pContext->mMeasurementWindowSizeInBuffers) {
pContext->mMeasurementBufferIdx = 0;
@@ -375,12 +378,17 @@
#ifdef BUILD_FLOAT
float maxSample = 0.f;
- for (size_t inIdx = 0; inIdx < sampleLen; ++inIdx) {
- maxSample = fmax(maxSample, fabs(inBuffer->f32[inIdx]));
+ for (size_t inIdx = 0; inIdx < sampleLen; ) {
+ // we reconstruct the actual summed value to ensure proper normalization
+ // for multichannel outputs (channels > 2 may often be 0).
+ float smp = 0.f;
+ for (int i = 0; i < pContext->mChannelCount; ++i) {
+ smp += inBuffer->f32[inIdx++];
+ }
+ maxSample = fmax(maxSample, fabs(smp));
}
if (maxSample > 0.f) {
- constexpr float halfish = 127.f / 256.f;
- fscale = halfish / maxSample;
+ fscale = 127.f / maxSample;
int exp; // unused
const float significand = frexp(fscale, &exp);
if (significand == 0.5f) {
@@ -412,7 +420,8 @@
} else {
assert(pContext->mScalingMode == VISUALIZER_SCALING_MODE_AS_PLAYED);
#ifdef BUILD_FLOAT
- fscale = 0.5f; // default divide by 2 to account for sum of L + R.
+ // Note: if channels are uncorrelated, 1/sqrt(N) could be used at the risk of clipping.
+ fscale = 1.f / pContext->mChannelCount; // account for summing all the channels together.
#else
shift = 9;
#endif // BUILD_FLOAT
@@ -422,17 +431,19 @@
uint32_t inIdx;
uint8_t *buf = pContext->mCaptureBuf;
for (inIdx = 0, captIdx = pContext->mCaptureIdx;
- inIdx < inBuffer->frameCount;
- inIdx++, captIdx++) {
- if (captIdx >= CAPTURE_BUF_SIZE) {
- // wrap around
- captIdx = 0;
- }
+ inIdx < sampleLen;
+ captIdx++) {
+ if (captIdx >= CAPTURE_BUF_SIZE) captIdx = 0; // wrap
+
#ifdef BUILD_FLOAT
- const float smp = (inBuffer->f32[2 * inIdx] + inBuffer->f32[2 * inIdx + 1]) * fscale;
- buf[captIdx] = clamp8_from_float(smp);
+ float smp = 0.f;
+ for (uint32_t i = 0; i < pContext->mChannelCount; ++i) {
+ smp += inBuffer->f32[inIdx++];
+ }
+ buf[captIdx] = clamp8_from_float(smp * fscale);
#else
- const int32_t smp = (inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1]) >> shift;
+ const int32_t smp = (inBuffer->s16[inIdx] + inBuffer->s16[inIdx + 1]) >> shift;
+ inIdx += FCC_2; // integer supports stereo only.
buf[captIdx] = ((uint8_t)smp)^0x80;
#endif // BUILD_FLOAT
}
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index 1e5fa07..d29e97d 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -71,6 +71,8 @@
METADATA_KEY_COLOR_STANDARD = 35,
METADATA_KEY_COLOR_TRANSFER = 36,
METADATA_KEY_COLOR_RANGE = 37,
+ METADATA_KEY_SAMPLERATE = 38,
+ METADATA_KEY_BITS_PER_SAMPLE = 39,
// Add more here...
};
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index a37973b..09b19d7 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -29,6 +29,7 @@
"libmediametrics",
"libmediautils",
"libmemunreachable",
+ "libnetd_client",
"libpowermanager",
"libstagefright",
"libstagefright_foundation",
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index 0f24329..03e0d12 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -114,30 +114,4 @@
mMaxBandwidthHistoryItems = numHistoryItems;
}
-// static
-void HTTPBase::RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag) {
- int res = qtaguid_tagSocket(sockfd, kTag, uid);
- if (res != 0) {
- ALOGE("Failed tagging socket %d for uid %d (My UID=%d)", sockfd, uid, geteuid());
- }
-}
-
-// static
-void HTTPBase::UnRegisterSocketUserTag(int sockfd) {
- int res = qtaguid_untagSocket(sockfd);
- if (res != 0) {
- ALOGE("Failed untagging socket %d (My UID=%d)", sockfd, geteuid());
- }
-}
-
-// static
-void HTTPBase::RegisterSocketUserMark(int sockfd, uid_t uid) {
- setNetworkForUser(uid, sockfd);
-}
-
-// static
-void HTTPBase::UnRegisterSocketUserMark(int sockfd) {
- RegisterSocketUserMark(sockfd, geteuid());
-}
-
} // namespace android
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index cdef3a5..f34d54c 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -545,6 +545,19 @@
if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
audioBitrate = -1;
}
+
+ int32_t bitsPerSample = -1;
+ int32_t sampleRate = -1;
+ trackMeta->findInt32(kKeyBitsPerSample, &bitsPerSample);
+ trackMeta->findInt32(kKeySampleRate, &sampleRate);
+ if (bitsPerSample >= 0) {
+ sprintf(tmp, "%d", bitsPerSample);
+ mMetaData.add(METADATA_KEY_BITS_PER_SAMPLE, String8(tmp));
+ }
+ if (sampleRate >= 0) {
+ sprintf(tmp, "%d", sampleRate);
+ mMetaData.add(METADATA_KEY_SAMPLERATE, String8(tmp));
+ }
} else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
hasVideo = true;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 53258ad..96993e9 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -787,6 +787,11 @@
msg->setInt32("channel-count", numChannels);
msg->setInt32("sample-rate", sampleRate);
+ int32_t bitsPerSample;
+ if (meta->findInt32(kKeyBitsPerSample, &bitsPerSample)) {
+ msg->setInt32("bits-per-sample", bitsPerSample);
+ }
+
int32_t channelMask;
if (meta->findInt32(kKeyChannelMask, &channelMask)) {
msg->setInt32("channel-mask", channelMask);
@@ -1526,6 +1531,10 @@
if (msg->findInt32("sample-rate", &sampleRate)) {
meta->setInt32(kKeySampleRate, sampleRate);
}
+ int32_t bitsPerSample;
+ if (msg->findInt32("bits-per-sample", &bitsPerSample)) {
+ meta->setInt32(kKeyBitsPerSample, bitsPerSample);
+ }
int32_t channelMask;
if (msg->findInt32("channel-mask", &channelMask)) {
meta->setInt32(kKeyChannelMask, channelMask);
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index a924197..8b20187 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -51,12 +51,6 @@
virtual void setBandwidthHistorySize(size_t numHistoryItems);
- static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag);
- static void UnRegisterSocketUserTag(int sockfd);
-
- static void RegisterSocketUserMark(int sockfd, uid_t uid);
- static void UnRegisterSocketUserMark(int sockfd);
-
virtual String8 toString() {
return mName;
}
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index fb498d4..3debe34 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -552,8 +552,10 @@
hasStreamCA = true;
streamCA.mSystemID = br->getBits(16);
streamCA.mPID = br->getBits(16) & 0x1fff;
- ES_info_length -= 4;
- streamCA.mPrivateData.assign(br->data(), br->data() + descriptor_length - 4);
+ ES_info_length -= descriptor_length;
+ descriptor_length -= 4;
+ streamCA.mPrivateData.assign(br->data(), br->data() + descriptor_length);
+ br->skipBits(descriptor_length * 8);
} else if (info.mType == STREAMTYPE_PES_PRIVATE_DATA &&
descriptor_tag == DESCRIPTOR_DVB_EXTENSION && descriptor_length >= 1) {
unsigned descTagExt = br->getBits(8);
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 5620cf8..33c1c18 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include "ARTSPConnection.h"
+#include "NetworkUtils.h"
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -59,8 +60,8 @@
if (mSocket >= 0) {
ALOGE("Connection is still open, closing the socket.");
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(mSocket);
- HTTPBase::UnRegisterSocketUserMark(mSocket);
+ NetworkUtils::UnRegisterSocketUserTag(mSocket);
+ NetworkUtils::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
@@ -214,8 +215,8 @@
if (mState != DISCONNECTED) {
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(mSocket);
- HTTPBase::UnRegisterSocketUserMark(mSocket);
+ NetworkUtils::UnRegisterSocketUserTag(mSocket);
+ NetworkUtils::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
@@ -266,9 +267,9 @@
mSocket = socket(AF_INET, SOCK_STREAM, 0);
if (mUIDValid) {
- HTTPBase::RegisterSocketUserTag(mSocket, mUID,
+ NetworkUtils::RegisterSocketUserTag(mSocket, mUID,
(uint32_t)*(uint32_t*) "RTSP");
- HTTPBase::RegisterSocketUserMark(mSocket, mUID);
+ NetworkUtils::RegisterSocketUserMark(mSocket, mUID);
}
MakeSocketBlocking(mSocket, false);
@@ -297,8 +298,8 @@
mState = DISCONNECTED;
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(mSocket);
- HTTPBase::UnRegisterSocketUserMark(mSocket);
+ NetworkUtils::UnRegisterSocketUserTag(mSocket);
+ NetworkUtils::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
@@ -315,8 +316,8 @@
void ARTSPConnection::performDisconnect() {
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(mSocket);
- HTTPBase::UnRegisterSocketUserMark(mSocket);
+ NetworkUtils::UnRegisterSocketUserTag(mSocket);
+ NetworkUtils::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
@@ -389,8 +390,8 @@
mState = DISCONNECTED;
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(mSocket);
- HTTPBase::UnRegisterSocketUserMark(mSocket);
+ NetworkUtils::UnRegisterSocketUserTag(mSocket);
+ NetworkUtils::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
diff --git a/media/libstagefright/rtsp/Android.bp b/media/libstagefright/rtsp/Android.bp
index debd07e..d1767d3 100644
--- a/media/libstagefright/rtsp/Android.bp
+++ b/media/libstagefright/rtsp/Android.bp
@@ -1,5 +1,5 @@
-cc_library_static {
- name: "libstagefright_rtsp",
+cc_defaults {
+ name: "libstagefright_rtsp_defaults",
srcs: [
"AAMRAssembler.cpp",
@@ -52,6 +52,21 @@
},
}
+cc_library_static {
+ name: "libstagefright_rtsp",
+
+ srcs: ["NetworkUtils.cpp"],
+ header_libs: ["libnetd_client_headers"],
+ defaults: ["libstagefright_rtsp_defaults"],
+}
+
+cc_library_static {
+ name: "libstagefright_rtsp_player2",
+
+ srcs: ["NetworkUtilsForAppProc.cpp"],
+ defaults: ["libstagefright_rtsp_defaults"],
+}
+
//###############################################################################
cc_test {
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index d183516..5d993db 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -31,6 +31,7 @@
#include "ARTPConnection.h"
#include "ARTSPConnection.h"
#include "ASessionDescription.h"
+#include "NetworkUtils.h"
#include <ctype.h>
#include <cutils/properties.h>
@@ -757,10 +758,10 @@
if (!track->mUsingInterleavedTCP) {
// Clear the tag
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(track->mRTPSocket);
- HTTPBase::UnRegisterSocketUserMark(track->mRTPSocket);
- HTTPBase::UnRegisterSocketUserTag(track->mRTCPSocket);
- HTTPBase::UnRegisterSocketUserMark(track->mRTCPSocket);
+ NetworkUtils::UnRegisterSocketUserTag(track->mRTPSocket);
+ NetworkUtils::UnRegisterSocketUserMark(track->mRTPSocket);
+ NetworkUtils::UnRegisterSocketUserTag(track->mRTCPSocket);
+ NetworkUtils::UnRegisterSocketUserMark(track->mRTCPSocket);
}
close(track->mRTPSocket);
@@ -886,10 +887,10 @@
// Clear the tag
if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(info->mRTPSocket);
- HTTPBase::UnRegisterSocketUserMark(info->mRTPSocket);
- HTTPBase::UnRegisterSocketUserTag(info->mRTCPSocket);
- HTTPBase::UnRegisterSocketUserMark(info->mRTCPSocket);
+ NetworkUtils::UnRegisterSocketUserTag(info->mRTPSocket);
+ NetworkUtils::UnRegisterSocketUserMark(info->mRTPSocket);
+ NetworkUtils::UnRegisterSocketUserTag(info->mRTCPSocket);
+ NetworkUtils::UnRegisterSocketUserMark(info->mRTCPSocket);
}
close(info->mRTPSocket);
@@ -1665,12 +1666,12 @@
&info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
if (mUIDValid) {
- HTTPBase::RegisterSocketUserTag(info->mRTPSocket, mUID,
- (uint32_t)*(uint32_t*) "RTP_");
- HTTPBase::RegisterSocketUserTag(info->mRTCPSocket, mUID,
- (uint32_t)*(uint32_t*) "RTP_");
- HTTPBase::RegisterSocketUserMark(info->mRTPSocket, mUID);
- HTTPBase::RegisterSocketUserMark(info->mRTCPSocket, mUID);
+ NetworkUtils::RegisterSocketUserTag(info->mRTPSocket, mUID,
+ (uint32_t)*(uint32_t*) "RTP_");
+ NetworkUtils::RegisterSocketUserTag(info->mRTCPSocket, mUID,
+ (uint32_t)*(uint32_t*) "RTP_");
+ NetworkUtils::RegisterSocketUserMark(info->mRTPSocket, mUID);
+ NetworkUtils::RegisterSocketUserMark(info->mRTCPSocket, mUID);
}
request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
diff --git a/media/libstagefright/rtsp/NetworkUtils.cpp b/media/libstagefright/rtsp/NetworkUtils.cpp
new file mode 100644
index 0000000..cc36b78
--- /dev/null
+++ b/media/libstagefright/rtsp/NetworkUtils.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NetworkUtils"
+#include <utils/Log.h>
+
+#include "NetworkUtils.h"
+#include <cutils/qtaguid.h>
+#include <NetdClient.h>
+
+namespace android {
+
+// static
+void NetworkUtils::RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag) {
+ int res = qtaguid_tagSocket(sockfd, kTag, uid);
+ if (res != 0) {
+ ALOGE("Failed tagging socket %d for uid %d (My UID=%d)", sockfd, uid, geteuid());
+ }
+}
+
+// static
+void NetworkUtils::UnRegisterSocketUserTag(int sockfd) {
+ int res = qtaguid_untagSocket(sockfd);
+ if (res != 0) {
+ ALOGE("Failed untagging socket %d (My UID=%d)", sockfd, geteuid());
+ }
+}
+
+// static
+void NetworkUtils::RegisterSocketUserMark(int sockfd, uid_t uid) {
+ setNetworkForUser(uid, sockfd);
+}
+
+// static
+void NetworkUtils::UnRegisterSocketUserMark(int sockfd) {
+ RegisterSocketUserMark(sockfd, geteuid());
+}
+
+} // namespace android
diff --git a/media/libstagefright/rtsp/NetworkUtils.h b/media/libstagefright/rtsp/NetworkUtils.h
new file mode 100644
index 0000000..e25ee46
--- /dev/null
+++ b/media/libstagefright/rtsp/NetworkUtils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NETWORK_UTILS_H_
+#define NETWORK_UTILS_H_
+
+namespace android {
+
+struct NetworkUtils {
+ static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag);
+ static void UnRegisterSocketUserTag(int sockfd);
+
+ static void RegisterSocketUserMark(int sockfd, uid_t uid);
+ static void UnRegisterSocketUserMark(int sockfd);
+};
+
+} // namespace android
+
+#endif // NETWORK_UTILS_H_
diff --git a/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp b/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp
new file mode 100644
index 0000000..662159c
--- /dev/null
+++ b/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NetworkUtils"
+#include <utils/Log.h>
+
+#include "NetworkUtils.h"
+
+// NetworkUtils implementation for application process.
+namespace android {
+
+// static
+void NetworkUtils::RegisterSocketUserTag(int, uid_t, uint32_t) {
+ // No op. Framework already handles the data usage billing for applications.
+}
+
+// static
+void NetworkUtils::UnRegisterSocketUserTag(int) {
+ // No op.
+}
+
+// static
+void NetworkUtils::RegisterSocketUserMark(int, uid_t) {
+ // No op. Framework already handles the data usage billing for applications.
+}
+
+// static
+void NetworkUtils::UnRegisterSocketUserMark(int) {
+ // No op.
+}
+
+} // namespace android
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index b95dcd0..6537ad1 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -276,6 +276,7 @@
EXPORT const char* AMEDIAFORMAT_KEY_AUTHOR = "author";
EXPORT const char* AMEDIAFORMAT_KEY_BITRATE_MODE = "bitrate-mode";
EXPORT const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate";
+EXPORT const char* AMEDIAFORMAT_KEY_BITS_PER_SAMPLE = "bits-per-sample";
EXPORT const char* AMEDIAFORMAT_KEY_CAPTURE_RATE = "capture-rate";
EXPORT const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER = "cdtracknum";
EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count";
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index b8047d9..3a3268c 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -181,6 +181,7 @@
extern const char* AMEDIAFORMAT_KEY_ALBUMARTIST __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_ARTIST __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_AUTHOR __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_BITS_PER_SAMPLE __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_COLOR_RANGE __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_COLOR_STANDARD __INTRODUCED_IN(29);