Merge "[SAFE CHANGE] Audio OWNERS fixup" into main
diff --git a/drm/libmediadrm/fuzzer/Android.bp b/drm/libmediadrm/fuzzer/Android.bp
index deda9ef..adc33d5 100644
--- a/drm/libmediadrm/fuzzer/Android.bp
+++ b/drm/libmediadrm/fuzzer/Android.bp
@@ -65,8 +65,16 @@
],
fuzz_config: {
cc: [
- "android-media-fuzzing-reports@google.com",
+ "android-drm-team@google.com",
],
- componentid: 155276,
+ componentid: 49079,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libmediadrm",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index 3e4247b..f056759 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "C2SoftGav1Dec"
#include "C2SoftGav1Dec.h"
+#include <android-base/properties.h>
#include <C2Debug.h>
#include <C2PlatformSupport.h>
#include <Codec2BufferUtils.h>
@@ -39,6 +40,9 @@
namespace android {
+// Property used to control the number of threads used in the gav1 decoder.
+constexpr char kNumThreadsProperty[] = "debug.c2.gav1.numthreads";
+
// codecname set and passed in as a compile flag from Android.bp
constexpr char COMPONENT_NAME[] = CODECNAME;
@@ -506,6 +510,10 @@
libgav1::DecoderSettings settings = {};
settings.threads = GetCPUCoreCount();
+ int32_t numThreads = android::base::GetIntProperty(kNumThreadsProperty, 0);
+ if (numThreads > 0 && numThreads < settings.threads) {
+ settings.threads = numThreads;
+ }
ALOGV("Using libgav1 AV1 software decoder.");
Libgav1StatusCode status = mCodecCtx->Init(&settings);
diff --git a/media/codec2/hal/aidl/Android.bp b/media/codec2/hal/aidl/Android.bp
index 44f85fd..73cae93 100644
--- a/media/codec2/hal/aidl/Android.bp
+++ b/media/codec2/hal/aidl/Android.bp
@@ -174,5 +174,6 @@
cc: [
"wonsik@google.com",
],
+ triage_assignee: "waghpawan@google.com",
},
}
diff --git a/media/codec2/hal/client/GraphicBufferAllocator.cpp b/media/codec2/hal/client/GraphicBufferAllocator.cpp
index 7045537..8f489ec 100644
--- a/media/codec2/hal/client/GraphicBufferAllocator.cpp
+++ b/media/codec2/hal/client/GraphicBufferAllocator.cpp
@@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-GraphicBufferAllocator"
+
#include <gui/IProducerListener.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/codec2/hal/client/GraphicsTracker.cpp b/media/codec2/hal/client/GraphicsTracker.cpp
index 573ded8..0848fc6 100644
--- a/media/codec2/hal/client/GraphicsTracker.cpp
+++ b/media/codec2/hal/client/GraphicsTracker.cpp
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "GraphicsTracker"
#include <fcntl.h>
#include <unistd.h>
@@ -73,11 +75,19 @@
}
GraphicsTracker::BufferItem::BufferItem(
- uint32_t generation,
- AHardwareBuffer_Desc *desc, AHardwareBuffer *pBuf) :
+ uint32_t generation, AHardwareBuffer *pBuf, uint64_t usage) :
mInit{true}, mGeneration{generation}, mSlot{-1},
- mBuf{pBuf}, mUsage{::android::AHardwareBuffer_convertToGrallocUsageBits(desc->usage)},
+ mBuf{pBuf}, mUsage{usage},
mFence{Fence::NO_FENCE} {
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ int ret = AHardwareBuffer_getId(mBuf, &mId);
+ if (ret != ::android::OK) {
+ mInit = false;
+ mBuf = nullptr;
+ return;
+ }
+ }
+ AHardwareBuffer_acquire(mBuf);
}
GraphicsTracker::BufferItem::~BufferItem() {
@@ -86,7 +96,8 @@
}
}
-sp<GraphicBuffer> GraphicsTracker::BufferItem::updateBuffer(
+
+std::shared_ptr<GraphicsTracker::BufferItem> GraphicsTracker::BufferItem::migrateBuffer(
uint64_t newUsage, uint32_t newGeneration) {
if (!mInit) {
return nullptr;
@@ -111,21 +122,28 @@
return nullptr;
}
- GraphicBuffer *gb = ::android::AHardwareBuffer_to_GraphicBuffer(newBuf);
- if (!gb) {
- AHardwareBuffer_release(newBuf);
+ std::shared_ptr<BufferItem> newBuffer =
+ std::make_shared<BufferItem>(newGeneration, newBuf, newUsage);
+ AHardwareBuffer_release(newBuf);
+ return newBuffer;
+}
+
+sp<GraphicBuffer> GraphicsTracker::BufferItem::getGraphicBuffer() {
+ if (!mInit) {
return nullptr;
}
-
- gb->setGenerationNumber(newGeneration);
- mUsage = newUsage;
- mGeneration = newGeneration;
- AHardwareBuffer_release(mBuf);
- // acquire is already done when creating.
- mBuf = newBuf;
+ GraphicBuffer *gb = ::android::AHardwareBuffer_to_GraphicBuffer(mBuf);
+ if (!gb) {
+ return nullptr;
+ }
+ gb->setGenerationNumber(mGeneration);
return gb;
}
+GraphicsTracker::BufferCache::~BufferCache() {
+ ALOGV("BufferCache destruction: generation(%d), igbp(%d)", mGeneration, (bool)mIgbp);
+}
+
void GraphicsTracker::BufferCache::waitOnSlot(int slot) {
// TODO: log
CHECK(0 <= slot && slot < kNumSlots);
@@ -138,6 +156,7 @@
void GraphicsTracker::BufferCache::blockSlot(int slot) {
CHECK(0 <= slot && slot < kNumSlots);
+ ALOGV("block slot %d", slot);
BlockedSlot *p = &mBlockedSlots[slot];
std::unique_lock<std::mutex> l(p->l);
p->blocked = true;
@@ -145,6 +164,7 @@
void GraphicsTracker::BufferCache::unblockSlot(int slot) {
CHECK(0 <= slot && slot < kNumSlots);
+ ALOGV("unblock slot %d", slot);
BlockedSlot *p = &mBlockedSlots[slot];
std::unique_lock<std::mutex> l(p->l);
p->blocked = false;
@@ -153,7 +173,8 @@
}
GraphicsTracker::GraphicsTracker(int maxDequeueCount)
- : mMaxDequeue{maxDequeueCount}, mMaxDequeueRequested{maxDequeueCount},
+ : mBufferCache(new BufferCache()), mMaxDequeue{maxDequeueCount},
+ mMaxDequeueRequested{maxDequeueCount},
mMaxDequeueCommitted{maxDequeueCount},
mMaxDequeueRequestedSeqId{0UL}, mMaxDequeueCommittedSeqId{0ULL},
mDequeueable{maxDequeueCount},
@@ -177,6 +198,7 @@
mWritePipeFd.reset(pipefd[1]);
mEventQueueThread = std::thread([this](){processEvent();});
+ writeIncDequeueable(mDequeueable);
CHECK(ret >= 0);
CHECK(mEventQueueThread.joinable());
@@ -185,9 +207,6 @@
GraphicsTracker::~GraphicsTracker() {
stop();
if (mEventQueueThread.joinable()) {
- std::unique_lock<std::mutex> l(mEventLock);
- l.unlock();
- mEventCv.notify_one();
mEventQueueThread.join();
}
}
@@ -327,6 +346,7 @@
void GraphicsTracker::updateDequeueConf() {
std::shared_ptr<BufferCache> cache;
int dequeueCommit;
+ ALOGV("trying to update max dequeue count");
std::unique_lock<std::mutex> cl(mConfigLock);
{
std::unique_lock<std::mutex> l(mLock);
@@ -374,6 +394,11 @@
}
+int GraphicsTracker::getCurDequeueable() {
+ std::unique_lock<std::mutex> l(mLock);
+ return mDequeueable;
+}
+
void GraphicsTracker::stop() {
bool expected = false;
std::unique_lock<std::mutex> l(mEventLock);
@@ -381,6 +406,9 @@
if (updated) {
int writeFd = mWritePipeFd.release();
::close(writeFd);
+ int readFd = mReadPipeFd.release();
+ ::close(readFd);
+ mEventCv.notify_one();
}
}
@@ -470,6 +498,7 @@
}
if (ret == 0) {
// writing end is closed
+ ALOGE("writing end for the waitable object seems to be closed");
return C2_BAD_STATE;
}
mDequeueable--;
@@ -492,6 +521,7 @@
CHECK(it != cache->mBuffers.end());
it->second->mFence = fence;
*pBuffer = it->second;
+ ALOGV("an allocated buffer already cached, updated Fence");
} else if (cache.get() == mBufferCache.get() && mBufferCache->mIgbp) {
// Cache the buffer if it is allocated from the current IGBP
CHECK(slot >= 0);
@@ -499,6 +529,7 @@
if (!ret.second) {
ret.first->second = *pBuffer;
}
+ ALOGV("an allocated buffer not cached from the current IGBP");
}
uint64_t bid = (*pBuffer)->mId;
auto mapRet = mDequeued.emplace(bid, *pBuffer);
@@ -520,7 +551,7 @@
// retrieved by commitAllocate();
c2_status_t GraphicsTracker::_allocate(const std::shared_ptr<BufferCache> &cache,
uint32_t width, uint32_t height, PixelFormat format,
- int64_t usage,
+ uint64_t usage,
bool *cached,
int *rSlotId,
sp<Fence> *rFence,
@@ -545,11 +576,21 @@
return ret == ::android::NO_MEMORY ? C2_NO_MEMORY : C2_CORRUPTED;
}
*cached = false;
- *buffer = std::make_shared<BufferItem>(generation, &desc, buf);
+ *rSlotId = -1;
+ *rFence = Fence::NO_FENCE;
+ *buffer = std::make_shared<BufferItem>(generation, buf, usage);
+ AHardwareBuffer_release(buf); // remove an acquire count from
+ // AHwb_allocate().
if (!*buffer) {
- AHardwareBuffer_release(buf);
+ ALOGE("direct allocation of AHB successful, but failed to create BufferItem");
return C2_NO_MEMORY;
}
+ if (!(*buffer)->mInit) {
+ ALOGE("direct allocation of AHB successful, but BufferItem init failed");
+ buffer->reset();
+ return C2_CORRUPTED;
+ }
+ ALOGV("allocate: direct allocate without igbp");
return C2_OK;
}
@@ -578,19 +619,29 @@
sp<GraphicBuffer> realloced;
status = igbp->requestBuffer(slotId, &realloced);
if (status != ::android::OK) {
+ ALOGE("allocate by dequeueBuffer() successful, but requestBuffer() failed %d",
+ status);
igbp->cancelBuffer(slotId, fence);
return C2_CORRUPTED;
}
*buffer = std::make_shared<BufferItem>(generation, slotId, realloced, fence);
+ if (!*buffer) {
+ ALOGE("allocate by dequeueBuffer() successful, but creating BufferItem failed");
+ igbp->cancelBuffer(slotId, fence);
+ return C2_NO_MEMORY;
+ }
if (!(*buffer)->mInit) {
+ ALOGE("allocate by dequeueBuffer() successful, but BufferItem init failed");
buffer->reset();
igbp->cancelBuffer(slotId, fence);
return C2_CORRUPTED;
}
*cached = false;
- return C2_OK;
+ } else {
+ *cached = true;
}
- *cached = true;
+ ALOGV("allocate: a new allocated buffer from igbp cached %d, slot: %d",
+ *cached, slotId);
*rSlotId = slotId;
*rFence = fence;
return C2_OK;
@@ -600,6 +651,7 @@
uint32_t width, uint32_t height, PixelFormat format, uint64_t usage,
AHardwareBuffer **buf, sp<Fence> *rFence) {
if (mStopped.load() == true) {
+ ALOGE("cannot allocate due to being stopped");
return C2_BAD_STATE;
}
std::shared_ptr<BufferCache> cache;
@@ -607,6 +659,7 @@
if (res != C2_OK) {
return res;
}
+ ALOGV("allocatable or dequeueable");
bool cached = false;
int slotId;
@@ -616,6 +669,8 @@
res = _allocate(cache, width, height, format, usage, &cached, &slotId, &fence, &buffer);
commitAllocate(res, cache, cached, slotId, fence, &buffer, &updateDequeue);
if (res == C2_OK) {
+ ALOGV("allocated a buffer width:%u height:%u pixelformat:%d usage:%llu",
+ width, height, format, (unsigned long long)usage);
*buf = buffer->mBuf;
*rFence = buffer->mFence;
// *buf should be valid even if buffer is dtor-ed.
@@ -668,14 +723,16 @@
void GraphicsTracker::commitDeallocate(
std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid) {
- std::lock_guard<std::mutex> l(mLock);
+ std::unique_lock<std::mutex> l(mLock);
size_t del1 = mDequeued.erase(bid);
size_t del2 = mDeallocating.erase(bid);
CHECK(del1 > 0 && del2 > 0);
- mDequeueable++;
if (cache) {
cache->unblockSlot(slotId);
}
+ mDequeueable++;
+ l.unlock();
+ writeIncDequeueable(1);
}
@@ -707,6 +764,7 @@
c2_status_t GraphicsTracker::requestRender(uint64_t bid, std::shared_ptr<BufferCache> *cache,
std::shared_ptr<BufferItem> *pBuffer,
+ bool *fromCache,
bool *updateDequeue) {
std::unique_lock<std::mutex> l(mLock);
if (mDeallocating.find(bid) != mDeallocating.end()) {
@@ -737,23 +795,35 @@
auto it = mBufferCache->mBuffers.find(buffer->mSlot);
CHECK(it != mBufferCache->mBuffers.end() && it->second.get() == buffer.get());
mBufferCache->blockSlot(buffer->mSlot);
+ *fromCache = true;
+ } else {
+ *fromCache = false;
}
*pBuffer = buffer;
mDeallocating.emplace(bid);
return C2_OK;
}
-void GraphicsTracker::commitRender(uint64_t origBid,
- const std::shared_ptr<BufferCache> &cache,
+void GraphicsTracker::commitRender(const std::shared_ptr<BufferCache> &cache,
const std::shared_ptr<BufferItem> &buffer,
+ const std::shared_ptr<BufferItem> &oldBuffer,
+ bool bufferReplaced,
bool *updateDequeue) {
std::unique_lock<std::mutex> l(mLock);
- uint64_t bid = buffer->mId;
+ uint64_t origBid = oldBuffer ? oldBuffer->mId : buffer->mId;
- if (cache.get() != mBufferCache.get()) {
+ if (cache) {
+ cache->unblockSlot(buffer->mSlot);
+ if (oldBuffer) {
+ // migrated, register the new buffer to the cache.
+ cache->mBuffers.emplace(buffer->mSlot, buffer);
+ }
+ }
+ mDeallocating.erase(origBid);
+ mDequeued.erase(origBid);
+
+ if (cache.get() != mBufferCache.get() || bufferReplaced) {
// Surface changed, no need to wait for buffer being released.
- mDeallocating.erase(bid);
- mDequeued.erase(bid);
if (adjustDequeueConfLocked(updateDequeue)) {
return;
}
@@ -762,13 +832,6 @@
writeIncDequeueable(1);
return;
}
-
- if (origBid != bid) {
- // migration happened, need to register the buffer to Cache
- mBufferCache->mBuffers.emplace(buffer->mSlot, buffer);
- }
- mDeallocating.erase(bid);
- mDequeued.erase(bid);
}
c2_status_t GraphicsTracker::render(const C2ConstGraphicBlock& blk,
@@ -782,57 +845,60 @@
}
std::shared_ptr<BufferCache> cache;
std::shared_ptr<BufferItem> buffer;
+ std::shared_ptr<BufferItem> oldBuffer;
bool updateDequeue = false;
- res = requestRender(bid, &cache, &buffer, &updateDequeue);
+ bool fromCache = false;
+ res = requestRender(bid, &cache, &buffer, &fromCache, &updateDequeue);
if (res != C2_OK) {
if (updateDequeue) {
updateDequeueConf();
}
return res;
}
- ::android::status_t migrateRes = ::android::OK;
- ::android::status_t renderRes = ::android::OK;
- if (cache->mGeneration != buffer->mGeneration) {
+ int cacheSlotId = fromCache ? buffer->mSlot : -1;
+ ALOGV("render prepared: igbp(%d) slot(%d)", bool(cache->mIgbp), cacheSlotId);
+ if (!fromCache) {
+ // The buffer does not come from the current cache.
+ // The buffer is needed to be migrated(attached).
uint64_t newUsage = 0ULL;
- int slotId = -1;;
(void) cache->mIgbp->getConsumerUsage(&newUsage);
- sp<GraphicBuffer> gb = buffer->updateBuffer(newUsage, cache->mGeneration);
- if (gb) {
- migrateRes = cache->mIgbp->attachBuffer(&(buffer->mSlot), gb);
- } else {
- ALOGW("realloc-ing a new buffer for migration failed");
- migrateRes = ::android::INVALID_OPERATION;
- }
- }
- if (migrateRes == ::android::OK) {
- renderRes = cache->mIgbp->queueBuffer(buffer->mSlot, input, output);
- if (renderRes != ::android::OK) {
- CHECK(renderRes != ::android::BAD_VALUE);
- }
- }
- if (migrateRes != ::android::OK || renderRes != ::android::OK) {
- // since it is not renderable, just de-allocate
- if (migrateRes != ::android::OK) {
+ std::shared_ptr<BufferItem> newBuffer =
+ buffer->migrateBuffer(newUsage, cache->mGeneration);
+ sp<GraphicBuffer> gb = newBuffer ? newBuffer->getGraphicBuffer() : nullptr;
+
+ if (!gb) {
+ ALOGE("render: realloc-ing a new buffer for migration failed");
std::shared_ptr<BufferCache> nullCache;
commitDeallocate(nullCache, -1, bid);
- } else {
- (void) cache->mIgbp->cancelBuffer(buffer->mSlot, input.fence);
- commitDeallocate(cache, buffer->mSlot, bid);
+ return C2_REFUSED;
}
- ALOGE("migration error(%d), render error(%d)", (int)migrateRes, (int)renderRes);
+ if (cache->mIgbp->attachBuffer(&(newBuffer->mSlot), gb) != ::android::OK) {
+ ALOGE("render: attaching a new buffer to IGBP failed");
+ std::shared_ptr<BufferCache> nullCache;
+ commitDeallocate(nullCache, -1, bid);
+ return C2_REFUSED;
+ }
+ cache->waitOnSlot(newBuffer->mSlot);
+ cache->blockSlot(newBuffer->mSlot);
+ oldBuffer = buffer;
+ buffer = newBuffer;
+ }
+ ::android::status_t renderRes = cache->mIgbp->queueBuffer(buffer->mSlot, input, output);
+ ALOGV("render done: migration(%d), render(err = %d)", !fromCache, renderRes);
+ if (renderRes != ::android::OK) {
+ CHECK(renderRes != ::android::BAD_VALUE);
+ ALOGE("render: failed to queueBuffer() err = %d", renderRes);
+ (void) cache->mIgbp->cancelBuffer(buffer->mSlot, input.fence);
+ commitDeallocate(cache, buffer->mSlot, bid);
return C2_REFUSED;
}
updateDequeue = false;
- commitRender(bid, cache, buffer, &updateDequeue);
+ commitRender(cache, buffer, oldBuffer, output->bufferReplaced, &updateDequeue);
if (updateDequeue) {
updateDequeueConf();
}
- if (output->bufferReplaced) {
- // in case of buffer drop during render
- onReleased(cache->mGeneration);
- }
return C2_OK;
}
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index ab6505e..1e9aa7f 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -16,8 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Codec2Client"
+#define ATRACE_TAG ATRACE_TAG_VIDEO
#include <android-base/logging.h>
-
+#include <utils/Trace.h>
#include <codec2/hidl/client.h>
#include <C2Debug.h>
#include <C2BufferPriv.h>
@@ -2324,6 +2325,7 @@
const C2ConstGraphicBlock& block,
const QueueBufferInput& input,
QueueBufferOutput* output) {
+ ScopedTrace trace(ATRACE_TAG,"Codec2Client::Component::queueToOutputSurface");
return mOutputBufferQueue->outputBuffer(block, input, output);
}
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
index 1fd9049..4640243 100644
--- a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
@@ -153,6 +153,11 @@
c2_status_t getWaitableFd(int *pipeFd);
/**
+ * Get the current max allocatable/dequeueable buffer count without de-allocating.
+ */
+ int getCurDequeueable();
+
+ /**
* Ends to use the class. after the call, allocate will fail.
*/
void stop();
@@ -177,12 +182,15 @@
// Create from an AHB (no slot information)
// Should be attached to IGBP for rendering
BufferItem(uint32_t generation,
- AHardwareBuffer_Desc *desc,
- AHardwareBuffer *pBuf);
+ AHardwareBuffer *pBuf,
+ uint64_t usage);
~BufferItem();
- sp<GraphicBuffer> updateBuffer(uint64_t newUsage, uint32_t newGeneration);
+ std::shared_ptr<BufferItem> migrateBuffer(uint64_t newUsage, uint32_t newGeneration);
+
+ sp<GraphicBuffer> getGraphicBuffer();
+
};
struct BufferCache {
@@ -212,6 +220,8 @@
BufferCache(uint64_t bqId, uint32_t generation, const sp<IGraphicBufferProducer>& igbp) :
mBqId{bqId}, mGeneration{generation}, mIgbp{igbp} {}
+ ~BufferCache();
+
void waitOnSlot(int slot);
void blockSlot(int slot);
@@ -287,6 +297,7 @@
sp<Fence> *rFence);
c2_status_t requestRender(uint64_t bid, std::shared_ptr<BufferCache> *cache,
std::shared_ptr<BufferItem> *pBuffer,
+ bool *fromCache,
bool *updateDequeue);
void commitAllocate(c2_status_t res,
@@ -295,14 +306,15 @@
std::shared_ptr<BufferItem> *buffer,
bool *updateDequeue);
void commitDeallocate(std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid);
- void commitRender(uint64_t origBid,
- const std::shared_ptr<BufferCache> &cache,
+ void commitRender(const std::shared_ptr<BufferCache> &cache,
const std::shared_ptr<BufferItem> &buffer,
+ const std::shared_ptr<BufferItem> &oldBuffer,
+ bool bufferReplaced,
bool *updateDequeue);
c2_status_t _allocate(
const std::shared_ptr<BufferCache> &cache,
- uint32_t width, uint32_t height, PixelFormat format, int64_t usage,
+ uint32_t width, uint32_t height, PixelFormat format, uint64_t usage,
bool *cached, int *rSlotId, sp<Fence> *rFence,
std::shared_ptr<BufferItem> *buffer);
diff --git a/media/codec2/hal/client/output.cpp b/media/codec2/hal/client/output.cpp
index 4eebd1c..f86e048 100644
--- a/media/codec2/hal/client/output.cpp
+++ b/media/codec2/hal/client/output.cpp
@@ -16,7 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Codec2-OutputBufferQueue"
+#define ATRACE_TAG ATRACE_TAG_VIDEO
#include <android-base/logging.h>
+#include <utils/Trace.h>
#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
#include <codec2/hidl/output.h>
@@ -336,9 +338,25 @@
}
void OutputBufferQueue::stop() {
- std::scoped_lock<std::mutex> l(mMutex);
- mStopped = true;
- mOwner.reset(); // destructor of the block will not triger IGBP::cancel()
+ std::shared_ptr<C2SurfaceSyncMemory> oldMem;
+ {
+ std::scoped_lock<std::mutex> l(mMutex);
+ if (mStopped) {
+ return;
+ }
+ mStopped = true;
+ mOwner.reset(); // destructor of the block will not trigger IGBP::cancel()
+ // basically configuring null surface
+ oldMem = mSyncMem;
+ mSyncMem.reset();
+ mIgbp.clear();
+ mGeneration = 0;
+ mBqId = 0;
+ }
+ {
+ std::scoped_lock<std::mutex> l(mOldMutex);
+ mOldMem = oldMem;
+ }
}
bool OutputBufferQueue::registerBuffer(const C2ConstGraphicBlock& block) {
@@ -388,6 +406,7 @@
uint32_t generation;
uint64_t bqId;
int32_t bqSlot;
+ ScopedTrace trace(ATRACE_TAG,"Codec2-OutputBufferQueue::outputBuffer");
bool display = V1_0::utils::displayBufferQueueBlock(block);
if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot) ||
bqId == 0) {
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 86fd8ab..8082dd7 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1915,8 +1915,16 @@
}
comp = state->comp;
}
- status_t err = comp->stop();
+
+ // Note: Logically mChannel->stopUseOutputSurface() should be after comp->stop().
+ // But in the case some HAL implementations hang forever on comp->stop().
+ // (HAL is waiting for C2Fence until fetchGraphicBlock unblocks and not
+ // completing stop()).
+ // So we reverse their order for stopUseOutputSurface() to notify C2Fence waiters
+ // prior to comp->stop().
+ // See also b/300350761.
mChannel->stopUseOutputSurface(pushBlankBuffer);
+ status_t err = comp->stop();
if (err != C2_OK) {
// TODO: convert err into status_t
mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
@@ -2004,8 +2012,15 @@
}
comp = state->comp;
}
- comp->release();
+ // Note: Logically mChannel->stopUseOutputSurface() should be after comp->release().
+ // But in the case some HAL implementations hang forever on comp->release().
+ // (HAL is waiting for C2Fence until fetchGraphicBlock unblocks and not
+ // completing release()).
+ // So we reverse their order for stopUseOutputSurface() to notify C2Fence waiters
+ // prior to comp->release().
+ // See also b/300350761.
mChannel->stopUseOutputSurface(pushBlankBuffer);
+ comp->release();
{
Mutexed<State>::Locked state(mState);
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index c93b7d0..bddf3cb 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -598,6 +598,8 @@
size_t bufferSize = 0;
c2_status_t blockRes = C2_OK;
bool copied = false;
+ ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
+ "CCodecBufferChannel::decrypt(%s)", mName).c_str());
if (mSendEncryptedInfoBuffer) {
static const C2MemoryUsage kDefaultReadWriteUsage{
C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
diff --git a/media/codec2/vndk/C2Buffer.cpp b/media/codec2/vndk/C2Buffer.cpp
index 018e269..a56a216 100644
--- a/media/codec2/vndk/C2Buffer.cpp
+++ b/media/codec2/vndk/C2Buffer.cpp
@@ -16,7 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "C2Buffer"
+#define ATRACE_TAG ATRACE_TAG_VIDEO
#include <utils/Log.h>
+#include <utils/Trace.h>
#include <list>
#include <map>
@@ -33,6 +35,7 @@
namespace {
+using android::ScopedTrace;
using android::C2AllocatorBlob;
using android::C2AllocatorGralloc;
using android::C2AllocatorIon;
@@ -1159,6 +1162,7 @@
uint32_t capacity,
C2MemoryUsage usage,
std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+ ScopedTrace trace(ATRACE_TAG,"C2PooledBlockPool::fetchLinearBlock");
if (mBufferPoolVer == VER_HIDL && mImpl) {
return mImpl->fetchLinearBlock(capacity, usage, block);
}
@@ -1174,6 +1178,7 @@
uint32_t format,
C2MemoryUsage usage,
std::shared_ptr<C2GraphicBlock> *block) {
+ ScopedTrace trace(ATRACE_TAG,"C2PooledBlockPool::fetchGraphicBlock");
if (mBufferPoolVer == VER_HIDL && mImpl) {
return mImpl->fetchGraphicBlock(width, height, format, usage, block);
}
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 5fb0c8f..960fa79 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -16,8 +16,10 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "C2BqBuffer"
+#define ATRACE_TAG ATRACE_TAG_VIDEO
#include <android/hardware_buffer.h>
#include <utils/Log.h>
+#include <utils/Trace.h>
#include <ui/BufferQueueDefs.h>
#include <ui/GraphicBuffer.h>
@@ -37,6 +39,7 @@
#include <map>
#include <mutex>
+using ::android::ScopedTrace;
using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS;
using ::android::C2AllocatorGralloc;
using ::android::C2AndroidMemoryUsage;
@@ -1063,6 +1066,7 @@
uint32_t format,
C2MemoryUsage usage,
std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+ ScopedTrace trace(ATRACE_TAG,"C2BufferQueueBlockPool::fetchGraphicBlock");
if (mImpl) {
return mImpl->fetchGraphicBlock(width, height, format, usage, block, nullptr);
}
diff --git a/media/janitors/media_reliability_OWNERS b/media/janitors/media_reliability_OWNERS
new file mode 100644
index 0000000..cced19c
--- /dev/null
+++ b/media/janitors/media_reliability_OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 1051309
+# go/android-media-reliability
+
+essick@google.com
+nchalko@google.com
diff --git a/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp b/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
index 0233ee1..e1ff3eb 100644
--- a/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
+++ b/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
@@ -20,7 +20,7 @@
#include <fuzzer/FuzzedDataProvider.h>
constexpr int32_t kRandomStringLength = 256;
-
+constexpr int32_t kMaxRuns = 100;
constexpr int64_t kNanosPerMillisecond = 1000 * 1000;
constexpr aaudio_direction_t kDirections[] = {
@@ -97,6 +97,7 @@
public:
~LibAaudioFuzzer() { deInit(); }
bool init();
+ void invokeAAudioSetAPIs(FuzzedDataProvider &fdp);
void process(const uint8_t *data, size_t size);
void deInit();
@@ -113,160 +114,208 @@
return true;
}
-void LibAaudioFuzzer::process(const uint8_t *data, size_t size) {
- FuzzedDataProvider fdp(data, size);
- aaudio_performance_mode_t mode =
- fdp.PickValueInArray({fdp.PickValueInArray(kPerformanceModes),
- fdp.ConsumeIntegral<int32_t>()});
+void LibAaudioFuzzer::invokeAAudioSetAPIs(FuzzedDataProvider &fdp){
+ aaudio_performance_mode_t mode = fdp.PickValueInArray(
+ {fdp.PickValueInArray(kPerformanceModes), fdp.ConsumeIntegral<int32_t>()});
AAudioStreamBuilder_setPerformanceMode(mAaudioBuilder, mode);
- int32_t deviceId = fdp.PickValueInArray(
- {AAUDIO_UNSPECIFIED, fdp.ConsumeIntegral<int32_t>()});
+ int32_t deviceId = fdp.PickValueInArray({AAUDIO_UNSPECIFIED, fdp.ConsumeIntegral<int32_t>()});
AAudioStreamBuilder_setDeviceId(mAaudioBuilder, deviceId);
- std::string packageName = fdp.PickValueInArray<std::string>(
- {"android.nativemedia.aaudio", "android.app.appops.cts",
- fdp.ConsumeRandomLengthString(kRandomStringLength)});
+ std::string packageName =
+ fdp.PickValueInArray<std::string>({"android.nativemedia.aaudio", "android.app.appops.cts",
+ fdp.ConsumeRandomLengthString(kRandomStringLength)});
AAudioStreamBuilder_setPackageName(mAaudioBuilder, packageName.c_str());
- std::string attributionTag =
- fdp.ConsumeRandomLengthString(kRandomStringLength);
+ std::string attributionTag = fdp.ConsumeRandomLengthString(kRandomStringLength);
AAudioStreamBuilder_setAttributionTag(mAaudioBuilder, attributionTag.c_str());
int32_t sampleRate = fdp.PickValueInArray(kSampleRates);
AAudioStreamBuilder_setSampleRate(mAaudioBuilder, sampleRate);
- int32_t channelCount = fdp.PickValueInArray(
- {AAUDIO_UNSPECIFIED, fdp.ConsumeIntegral<int32_t>()});
+ int32_t channelCount = fdp.PickValueInArray({AAUDIO_UNSPECIFIED, fdp.ConsumeIntegral<int32_t>()});
AAudioStreamBuilder_setChannelCount(mAaudioBuilder, channelCount);
- aaudio_direction_t direction = fdp.PickValueInArray(
- {fdp.PickValueInArray(kDirections), fdp.ConsumeIntegral<int32_t>()});
+ aaudio_direction_t direction =
+ fdp.PickValueInArray({fdp.PickValueInArray(kDirections), fdp.ConsumeIntegral<int32_t>()});
AAudioStreamBuilder_setDirection(mAaudioBuilder, direction);
- aaudio_format_t format = fdp.PickValueInArray(
- {fdp.PickValueInArray(kFormats), fdp.ConsumeIntegral<int32_t>()});
+ aaudio_format_t format =
+ fdp.PickValueInArray({fdp.PickValueInArray(kFormats), fdp.ConsumeIntegral<int32_t>()});
AAudioStreamBuilder_setFormat(mAaudioBuilder, format);
aaudio_sharing_mode_t sharingMode = fdp.PickValueInArray(
- {fdp.PickValueInArray(kSharingModes), fdp.ConsumeIntegral<int32_t>()});
+ {fdp.PickValueInArray(kSharingModes), fdp.ConsumeIntegral<int32_t>()});
AAudioStreamBuilder_setSharingMode(mAaudioBuilder, sharingMode);
- aaudio_usage_t usage = fdp.PickValueInArray(
- {fdp.PickValueInArray(kUsages), fdp.ConsumeIntegral<int32_t>()});
+ aaudio_usage_t usage =
+ fdp.PickValueInArray({fdp.PickValueInArray(kUsages), fdp.ConsumeIntegral<int32_t>()});
AAudioStreamBuilder_setUsage(mAaudioBuilder, usage);
aaudio_content_type_t contentType = fdp.PickValueInArray(
- {fdp.PickValueInArray(kContentTypes), fdp.ConsumeIntegral<int32_t>()});
+ {fdp.PickValueInArray(kContentTypes), fdp.ConsumeIntegral<int32_t>()});
AAudioStreamBuilder_setContentType(mAaudioBuilder, contentType);
aaudio_input_preset_t inputPreset = fdp.PickValueInArray(
- {fdp.PickValueInArray(kInputPresets), fdp.ConsumeIntegral<int32_t>()});
+ {fdp.PickValueInArray(kInputPresets), fdp.ConsumeIntegral<int32_t>()});
AAudioStreamBuilder_setInputPreset(mAaudioBuilder, inputPreset);
bool privacySensitive = fdp.ConsumeBool();
AAudioStreamBuilder_setPrivacySensitive(mAaudioBuilder, privacySensitive);
- int32_t frames = fdp.PickValueInArray(
- {AAUDIO_UNSPECIFIED, fdp.ConsumeIntegral<int32_t>()});
+ int32_t frames = fdp.PickValueInArray({AAUDIO_UNSPECIFIED, fdp.ConsumeIntegral<int32_t>()});
AAudioStreamBuilder_setBufferCapacityInFrames(mAaudioBuilder, frames);
- aaudio_allowed_capture_policy_t allowedCapturePolicy =
- fdp.PickValueInArray({fdp.PickValueInArray(kAllowedCapturePolicies),
- fdp.ConsumeIntegral<int32_t>()});
- AAudioStreamBuilder_setAllowedCapturePolicy(mAaudioBuilder,
- allowedCapturePolicy);
+ aaudio_allowed_capture_policy_t allowedCapturePolicy = fdp.PickValueInArray(
+ {fdp.PickValueInArray(kAllowedCapturePolicies), fdp.ConsumeIntegral<int32_t>()});
+ AAudioStreamBuilder_setAllowedCapturePolicy(mAaudioBuilder, allowedCapturePolicy);
- aaudio_session_id_t sessionId = fdp.PickValueInArray(
- {fdp.PickValueInArray(kSessionIds), fdp.ConsumeIntegral<int32_t>()});
+ aaudio_session_id_t sessionId =
+ fdp.PickValueInArray({fdp.PickValueInArray(kSessionIds), fdp.ConsumeIntegral<int32_t>()});
AAudioStreamBuilder_setSessionId(mAaudioBuilder, sessionId);
AAudioStreamBuilder_setDataCallback(mAaudioBuilder, nullptr, nullptr);
AAudioStreamBuilder_setErrorCallback(mAaudioBuilder, nullptr, nullptr);
- int32_t framesPerDataCallback = fdp.PickValueInArray(
- {AAUDIO_UNSPECIFIED, fdp.ConsumeIntegral<int32_t>()});
- AAudioStreamBuilder_setFramesPerDataCallback(mAaudioBuilder,
- framesPerDataCallback);
+ int32_t framesPerDataCallback =
+ fdp.PickValueInArray({AAUDIO_UNSPECIFIED, fdp.ConsumeIntegral<int32_t>()});
+ AAudioStreamBuilder_setFramesPerDataCallback(mAaudioBuilder, framesPerDataCallback);
- aaudio_policy_t policy = fdp.PickValueInArray(
- {fdp.PickValueInArray(kPolicies), fdp.ConsumeIntegral<int32_t>()});
+ aaudio_policy_t policy =
+ fdp.PickValueInArray({fdp.PickValueInArray(kPolicies), fdp.ConsumeIntegral<int32_t>()});
AAudio_setMMapPolicy(policy);
- (void)AAudio_getMMapPolicy();
+}
- aaudio_result_t result =
- AAudioStreamBuilder_openStream(mAaudioBuilder, &mAaudioStream);
+void LibAaudioFuzzer::process(const uint8_t *data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ int32_t maxFrames = 0;
+ int32_t count = 0;
+ aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNKNOWN;
+
+ invokeAAudioSetAPIs(fdp);
+
+ aaudio_result_t result = AAudioStreamBuilder_openStream(mAaudioBuilder, &mAaudioStream);
if ((result != AAUDIO_OK) || (!mAaudioStream)) {
return;
}
+ /* The 'runs' variable serves to set an upper limit on the loop iterations, preventing excessive
+ * execution.
+ */
+ int32_t runs = kMaxRuns;
+ while (fdp.remaining_bytes() > 0 && --runs) {
+ auto AAudioapi = fdp.PickValueInArray<const std::function<void()>>({
+ [&]() { (void)AAudio_getMMapPolicy(); },
- int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mAaudioStream);
- uint8_t numberOfBursts = fdp.ConsumeIntegral<uint8_t>();
- int32_t maxFrames = numberOfBursts * framesPerBurst;
- int32_t requestedBufferSize =
- fdp.ConsumeIntegral<uint16_t>() * framesPerBurst;
- AAudioStream_setBufferSizeInFrames(mAaudioStream, requestedBufferSize);
+ [&]() {
+ int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mAaudioStream);
+ uint8_t numberOfBursts = fdp.ConsumeIntegral<uint8_t>();
+ maxFrames = numberOfBursts * framesPerBurst;
+ int32_t requestedBufferSize = fdp.ConsumeIntegral<uint16_t>() * framesPerBurst;
+ AAudioStream_setBufferSizeInFrames(mAaudioStream, requestedBufferSize);
+ },
+ [&]() {
+ int64_t position = 0, nanoseconds = 0;
+ AAudioStream_getTimestamp(mAaudioStream, CLOCK_MONOTONIC, &position, &nanoseconds);
+ },
+ [&]() {
+ AAudioStream_requestStart(mAaudioStream);
+ },
+ [&]() {
+ AAudioStream_requestPause(mAaudioStream);
+ },
+ [&]() {
+ AAudioStream_requestFlush(mAaudioStream);
+ },
+ [&]() {
+ AAudioStream_requestStop(mAaudioStream);
+ },
+ [&]() {
+ aaudio_format_t actualFormat = AAudioStream_getFormat(mAaudioStream);
+ int32_t actualChannelCount = AAudioStream_getChannelCount(mAaudioStream);
- int64_t position = 0, nanoseconds = 0;
- AAudioStream_getTimestamp(mAaudioStream, CLOCK_MONOTONIC, &position,
- &nanoseconds);
+ count = fdp.ConsumeIntegral<int32_t>();
+ aaudio_direction_t direction = AAudioStream_getDirection(mAaudioStream);
- AAudioStream_requestStart(mAaudioStream);
-
- aaudio_format_t actualFormat = AAudioStream_getFormat(mAaudioStream);
- int32_t actualChannelCount = AAudioStream_getChannelCount(mAaudioStream);
-
- int32_t count = fdp.ConsumeIntegral<int32_t>();
- direction = AAudioStream_getDirection(mAaudioStream);
-
- if (actualFormat == AAUDIO_FORMAT_PCM_I16) {
- std::vector<int16_t> inputShortData(maxFrames * actualChannelCount, 0x0);
- if (direction == AAUDIO_DIRECTION_INPUT) {
- AAudioStream_read(mAaudioStream, inputShortData.data(), maxFrames,
- count * kNanosPerMillisecond);
- } else if (direction == AAUDIO_DIRECTION_OUTPUT) {
- AAudioStream_write(mAaudioStream, inputShortData.data(), maxFrames,
- count * kNanosPerMillisecond);
- }
- } else if (actualFormat == AAUDIO_FORMAT_PCM_FLOAT) {
- std::vector<float> inputFloatData(maxFrames * actualChannelCount, 0x0);
- if (direction == AAUDIO_DIRECTION_INPUT) {
- AAudioStream_read(mAaudioStream, inputFloatData.data(), maxFrames,
- count * kNanosPerMillisecond);
- } else if (direction == AAUDIO_DIRECTION_OUTPUT) {
- AAudioStream_write(mAaudioStream, inputFloatData.data(), maxFrames,
- count * kNanosPerMillisecond);
- }
+ if (actualFormat == AAUDIO_FORMAT_PCM_I16) {
+ std::vector<int16_t> inputShortData(maxFrames * actualChannelCount, 0x0);
+ if (direction == AAUDIO_DIRECTION_INPUT) {
+ AAudioStream_read(mAaudioStream, inputShortData.data(), maxFrames,
+ count * kNanosPerMillisecond);
+ } else if (direction == AAUDIO_DIRECTION_OUTPUT) {
+ AAudioStream_write(mAaudioStream, inputShortData.data(), maxFrames,
+ count * kNanosPerMillisecond);
+ }
+ } else if (actualFormat == AAUDIO_FORMAT_PCM_FLOAT) {
+ std::vector<float> inputFloatData(maxFrames * actualChannelCount, 0x0);
+ if (direction == AAUDIO_DIRECTION_INPUT) {
+ AAudioStream_read(mAaudioStream, inputFloatData.data(), maxFrames,
+ count * kNanosPerMillisecond);
+ } else if (direction == AAUDIO_DIRECTION_OUTPUT) {
+ AAudioStream_write(mAaudioStream, inputFloatData.data(), maxFrames,
+ count * kNanosPerMillisecond);
+ }
+ }
+ },
+ [&]() {
+ AAudioStream_waitForStateChange(mAaudioStream, AAUDIO_STREAM_STATE_UNKNOWN, &state,
+ count * kNanosPerMillisecond);
+ },
+ [&]() { (void)AAudio_convertStreamStateToText(state); },
+ [&]() {
+ (void)AAudioStream_getState(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getUsage(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getSamplesPerFrame(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getContentType(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getInputPreset(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_isPrivacySensitive(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getAllowedCapturePolicy(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getPerformanceMode(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getDeviceId(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getSharingMode(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getSessionId(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getFramesRead(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getXRunCount(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getFramesWritten(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getBufferCapacityInFrames(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_getBufferSizeInFrames(mAaudioStream);
+ },
+ [&]() {
+ (void)AAudioStream_isMMapUsed(mAaudioStream);
+ },
+ });
+ AAudioapi();
}
-
- aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNKNOWN;
- AAudioStream_waitForStateChange(mAaudioStream, AAUDIO_STREAM_STATE_UNKNOWN,
- &state, count * kNanosPerMillisecond);
- (void)AAudio_convertStreamStateToText(state);
-
- (void)AAudioStream_getUsage(mAaudioStream);
- (void)AAudioStream_getSampleRate(mAaudioStream);
- (void)AAudioStream_getState(mAaudioStream);
- (void)AAudioStream_getSamplesPerFrame(mAaudioStream);
- (void)AAudioStream_getContentType(mAaudioStream);
- (void)AAudioStream_getInputPreset(mAaudioStream);
- (void)AAudioStream_isPrivacySensitive(mAaudioStream);
- (void)AAudioStream_getAllowedCapturePolicy(mAaudioStream);
- (void)AAudioStream_getPerformanceMode(mAaudioStream);
- (void)AAudioStream_getDeviceId(mAaudioStream);
- (void)AAudioStream_getSharingMode(mAaudioStream);
- (void)AAudioStream_getSessionId(mAaudioStream);
- (void)AAudioStream_getFramesRead(mAaudioStream);
- (void)AAudioStream_getFramesWritten(mAaudioStream);
- (void)AAudioStream_getXRunCount(mAaudioStream);
- (void)AAudioStream_getBufferCapacityInFrames(mAaudioStream);
- (void)AAudioStream_getBufferSizeInFrames(mAaudioStream);
- (void)AAudioStream_isMMapUsed(mAaudioStream);
-
- AAudioStream_requestPause(mAaudioStream);
- AAudioStream_requestFlush(mAaudioStream);
AAudioStream_release(mAaudioStream);
- AAudioStream_requestStop(mAaudioStream);
}
void LibAaudioFuzzer::deInit() {
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 6616197..5b94845 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -108,7 +108,7 @@
}
// establish binder interface to AudioFlinger service
-const sp<IAudioFlinger> AudioSystem::get_audio_flinger() {
+const sp<IAudioFlinger> AudioSystem::getAudioFlingerImpl(bool canStartThreadPool = true) {
sp<IAudioFlinger> af;
sp<AudioFlingerClient> afc;
bool reportNoError = false;
@@ -147,7 +147,9 @@
afc = gAudioFlingerClient;
af = gAudioFlinger;
// Make sure callbacks can be received by gAudioFlingerClient
- ProcessState::self()->startThreadPool();
+ if(canStartThreadPool) {
+ ProcessState::self()->startThreadPool();
+ }
}
const int64_t token = IPCThreadState::self()->clearCallingIdentity();
af->registerClient(afc);
@@ -156,6 +158,14 @@
return af;
}
+const sp<IAudioFlinger> AudioSystem:: get_audio_flinger() {
+ return getAudioFlingerImpl();
+}
+
+const sp<IAudioFlinger> AudioSystem:: get_audio_flinger_for_fuzzer() {
+ return getAudioFlingerImpl(false);
+}
+
const sp<AudioSystem::AudioFlingerClient> AudioSystem::getAudioFlingerClient() {
// calling get_audio_flinger() will initialize gAudioFlingerClient if needed
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 4bd12b8..01edf72 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -898,6 +898,22 @@
return NO_ERROR;
}
+status_t AudioFlingerClientAdapter::getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) const {
+ if (devicePort == nullptr || mixPort == nullptr) {
+ return BAD_VALUE;
+ }
+ media::AudioPortFw devicePortAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_port_v7_AudioPortFw(*devicePort));
+ media::AudioPortFw mixPortAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_port_v7_AudioPortFw(*mixPort));
+ media::AudioPortFw aidlRet;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mDelegate->getAudioMixPort(devicePortAidl, mixPortAidl, &aidlRet)));
+ *mixPort = VALUE_OR_RETURN_STATUS(aidl2legacy_AudioPortFw_audio_port_v7(aidlRet));
+ return OK;
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// AudioFlingerServerAdapter
AudioFlingerServerAdapter::AudioFlingerServerAdapter(
@@ -1444,4 +1460,16 @@
return Status::fromStatusT(mDelegate->getAudioPolicyConfig(_aidl_return));
}
+Status AudioFlingerServerAdapter::getAudioMixPort(const media::AudioPortFw &devicePort,
+ const media::AudioPortFw &mixPort,
+ media::AudioPortFw *_aidl_return) {
+ audio_port_v7 devicePortLegacy = VALUE_OR_RETURN_BINDER(
+ aidl2legacy_AudioPortFw_audio_port_v7(devicePort));
+ audio_port_v7 mixPortLegacy = VALUE_OR_RETURN_BINDER(
+ aidl2legacy_AudioPortFw_audio_port_v7(mixPort));
+ RETURN_BINDER_IF_ERROR(mDelegate->getAudioMixPort(&devicePortLegacy, &mixPortLegacy));
+ *_aidl_return = VALUE_OR_RETURN_BINDER(legacy2aidl_audio_port_v7_AudioPortFw(mixPortLegacy));
+ return Status::ok();
+}
+
} // namespace android
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index 6412810..31d3af5 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -288,6 +288,11 @@
*/
AudioPolicyConfig getAudioPolicyConfig();
+ /**
+ * Get the attributes of the mix port when connecting to the given device port.
+ */
+ AudioPortFw getAudioMixPort(in AudioPortFw devicePort, in AudioPortFw mixPort);
+
// When adding a new method, please review and update
// IAudioFlinger.h AudioFlingerServerAdapter::Delegate::TransactionCode
// AudioFlinger.cpp AudioFlinger::onTransactWrapper()
diff --git a/media/libaudioclient/aidl/fuzzer/Android.bp b/media/libaudioclient/aidl/fuzzer/Android.bp
new file mode 100644
index 0000000..6093933
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/Android.bp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+cc_defaults {
+ name: "libaudioclient_aidl_fuzzer_defaults",
+ static_libs: [
+ "android.hardware.audio.common@7.0-enums",
+ "effect-aidl-cpp",
+ "libcgrouprc",
+ "libcgrouprc_format",
+ "libfakeservicemanager",
+ "libjsoncpp",
+ "liblog",
+ "libmediametricsservice",
+ "libmedia_helper",
+ "libprocessgroup",
+ "shared-file-region-aidl-cpp",
+ ],
+ shared_libs: [
+ "android.hardware.audio.common-util",
+ "audioclient-types-aidl-cpp",
+ "audiopolicy-aidl-cpp",
+ "audiopolicy-types-aidl-cpp",
+ "av-types-aidl-cpp",
+ "capture_state_listener-aidl-cpp",
+ "framework-permission-aidl-cpp",
+ "libaudioclient",
+ "audioflinger-aidl-cpp",
+ "libaudioflinger",
+ "libaudioclient_aidl_conversion",
+ "libaudiofoundation",
+ "libaudiomanager",
+ "libaudiopolicy",
+ "libaudioutils",
+ "libaudiopolicyservice",
+ "libaudiopolicymanagerdefault",
+ "libaudiohal",
+ "libaudioprocessing",
+ "libactivitymanager_aidl",
+ "libdl",
+ "libheadtracking",
+ "libmediautils",
+ "libmediametrics",
+ "libnblog",
+ "libnbaio",
+ "libpowermanager",
+ "libvibrator",
+ "libvndksupport",
+ "libxml2",
+ "mediametricsservice-aidl-cpp",
+ "packagemanager_aidl-cpp",
+ ],
+ header_libs: [
+ "libaudiopolicymanager_interface_headers",
+ "libaudiofoundation_headers",
+ "libaudiohal_headers",
+ "libaudioflinger_headers",
+ "libbinder_headers",
+ "libmedia_headers",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ hotlists: ["4593311"],
+ description: "The fuzzer targets the APIs of libaudioflinger",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
+ },
+}
+
+cc_fuzz {
+ name: "audioflinger_aidl_fuzzer",
+ srcs: ["audioflinger_aidl_fuzzer.cpp"],
+ defaults: [
+ "libaudioclient_aidl_fuzzer_defaults",
+ "service_fuzzer_defaults"
+ ],
+}
diff --git a/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp b/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp
new file mode 100644
index 0000000..f99cc3b
--- /dev/null
+++ b/media/libaudioclient/aidl/fuzzer/audioflinger_aidl_fuzzer.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 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 <AudioFlinger.h>
+#include <android-base/logging.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_process.h>
+#include <android/media/IAudioPolicyService.h>
+#include <fakeservicemanager/FakeServiceManager.h>
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzbinder/random_binder.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <media/IAudioFlinger.h>
+#include <service/AudioPolicyService.h>
+
+using namespace android;
+using namespace android::binder;
+using android::fuzzService;
+
+[[clang::no_destroy]] static std::once_flag gSmOnce;
+sp<FakeServiceManager> gFakeServiceManager;
+
+bool addService(const String16& serviceName, const sp<FakeServiceManager>& fakeServiceManager,
+ FuzzedDataProvider& fdp) {
+ sp<IBinder> binder = getRandomBinder(&fdp);
+ if (binder == nullptr) {
+ return false;
+ }
+ CHECK_EQ(NO_ERROR, fakeServiceManager->addService(serviceName, binder));
+ return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+
+ std::call_once(gSmOnce, [&] {
+ /* Create a FakeServiceManager instance and add required services */
+ gFakeServiceManager = sp<FakeServiceManager>::make();
+ setDefaultServiceManager(gFakeServiceManager);
+ });
+ gFakeServiceManager->clear();
+
+ for (const char* service :
+ {"activity", "sensor_privacy", "permission", "scheduling_policy",
+ "android.hardware.audio.core.IConfig", "batterystats", "media.metrics"}) {
+ if (!addService(String16(service), gFakeServiceManager, fdp)) {
+ return 0;
+ }
+ }
+
+ const auto audioFlinger = sp<AudioFlinger>::make();
+ const auto afAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
+
+ CHECK_EQ(NO_ERROR,
+ gFakeServiceManager->addService(
+ String16(IAudioFlinger::DEFAULT_SERVICE_NAME), IInterface::asBinder(afAdapter),
+ false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+
+ AudioSystem::get_audio_flinger_for_fuzzer();
+ const auto audioPolicyService = sp<AudioPolicyService>::make();
+
+ CHECK_EQ(NO_ERROR,
+ gFakeServiceManager->addService(String16("media.audio_policy"), audioPolicyService,
+ false /* allowIsolated */,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+
+ sp<IBinder> audioFlingerServiceBinder =
+ gFakeServiceManager->getService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME));
+ sp<media::IAudioFlingerService> audioFlingerService =
+ interface_cast<media::IAudioFlingerService>(audioFlingerServiceBinder);
+
+ fuzzService(media::IAudioFlingerService::asBinder(audioFlingerService), std::move(fdp));
+
+ return 0;
+}
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 8f8c9dd..0215f3c 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -178,6 +178,7 @@
// helper function to obtain AudioFlinger service handle
static const sp<IAudioFlinger> get_audio_flinger();
+ static const sp<IAudioFlinger> get_audio_flinger_for_fuzzer();
static float linearToLog(int volume);
static int logToLinear(float volume);
@@ -876,6 +877,7 @@
static audio_io_handle_t getOutput(audio_stream_type_t stream);
static const sp<AudioFlingerClient> getAudioFlingerClient();
static sp<AudioIoDescriptor> getIoDescriptor(audio_io_handle_t ioHandle);
+ static const sp<IAudioFlinger> getAudioFlingerImpl(bool canStartThreadPool);
// Invokes all registered error callbacks with the given error code.
static void reportError(status_t err);
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 3c96862..eb27e25 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -384,6 +384,9 @@
virtual status_t supportsBluetoothVariableLatency(bool* support) const = 0;
virtual status_t getAudioPolicyConfig(media::AudioPolicyConfig* output) = 0;
+
+ virtual status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) const = 0;
};
/**
@@ -498,6 +501,8 @@
sp<media::ISoundDose>* soundDose) const override;
status_t invalidateTracks(const std::vector<audio_port_handle_t>& portIds) override;
status_t getAudioPolicyConfig(media::AudioPolicyConfig* output) override;
+ status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) const override;
private:
const sp<media::IAudioFlingerService> mDelegate;
@@ -599,6 +604,7 @@
INVALIDATE_TRACKS = media::BnAudioFlingerService::TRANSACTION_invalidateTracks,
GET_AUDIO_POLICY_CONFIG =
media::BnAudioFlingerService::TRANSACTION_getAudioPolicyConfig,
+ GET_AUDIO_MIX_PORT = media::BnAudioFlingerService::TRANSACTION_getAudioMixPort,
};
protected:
@@ -732,6 +738,9 @@
sp<media::ISoundDose>* _aidl_return) override;
Status invalidateTracks(const std::vector<int32_t>& portIds) override;
Status getAudioPolicyConfig(media::AudioPolicyConfig* _aidl_return) override;
+ Status getAudioMixPort(const media::AudioPortFw& devicePort,
+ const media::AudioPortFw& mixPort,
+ media::AudioPortFw* _aidl_return) override;
private:
const sp<AudioFlingerServerAdapter::Delegate> mDelegate;
};
diff --git a/media/libaudioclient/tests/audioeffect_tests.cpp b/media/libaudioclient/tests/audioeffect_tests.cpp
index e6149e4..26121cd 100644
--- a/media/libaudioclient/tests/audioeffect_tests.cpp
+++ b/media/libaudioclient/tests/audioeffect_tests.cpp
@@ -250,8 +250,10 @@
if (!isEffectDefaultOnRecord(&descriptors[i].type, &descriptors[i].uuid,
capture->getAudioRecordHandle())) {
selectedEffect = i;
+ EXPECT_EQ(OK, capture->stop());
break;
}
+ EXPECT_EQ(OK, capture->stop());
}
}
if (selectedEffect == -1) GTEST_SKIP() << " expected at least one preprocessing effect";
diff --git a/media/libaudiofoundation/AudioContainers.cpp b/media/libaudiofoundation/AudioContainers.cpp
index 202a400..e1265cf 100644
--- a/media/libaudiofoundation/AudioContainers.cpp
+++ b/media/libaudiofoundation/AudioContainers.cpp
@@ -119,4 +119,115 @@
return ss.str();
}
+std::string dumpMixerBehaviors(const MixerBehaviorSet& mixerBehaviors) {
+ std::stringstream ss;
+ for (auto it = mixerBehaviors.begin(); it != mixerBehaviors.end(); ++it) {
+ if (it != mixerBehaviors.begin()) {
+ ss << ", ";
+ }
+ ss << (*it);
+ }
+ return ss.str();
+}
+
+AudioProfileAttributesMultimap createAudioProfilesAttrMap(audio_profile profiles[],
+ uint32_t first,
+ uint32_t last) {
+ AudioProfileAttributesMultimap result;
+ for (uint32_t i = first; i < last; ++i) {
+ SampleRateSet sampleRates(profiles[i].sample_rates,
+ profiles[i].sample_rates + profiles[i].num_sample_rates);
+ ChannelMaskSet channelMasks(profiles[i].channel_masks,
+ profiles[i].channel_masks + profiles[i].num_channel_masks);
+ result.emplace(profiles[i].format, std::make_pair(sampleRates, channelMasks));
+ }
+ return result;
+}
+
+namespace {
+
+void populateAudioProfile(audio_format_t format,
+ const ChannelMaskSet& channelMasks,
+ const SampleRateSet& samplingRates,
+ audio_profile* profile) {
+ profile->format = format;
+ profile->num_channel_masks = 0;
+ for (auto it = channelMasks.begin();
+ it != channelMasks.end() && profile->num_channel_masks < AUDIO_PORT_MAX_CHANNEL_MASKS;
+ ++it) {
+ profile->channel_masks[profile->num_channel_masks++] = *it;
+ }
+ profile->num_sample_rates = 0;
+ for (auto it = samplingRates.begin();
+ it != samplingRates.end() && profile->num_sample_rates < AUDIO_PORT_MAX_SAMPLING_RATES;
+ ++it) {
+ profile->sample_rates[profile->num_sample_rates++] = *it;
+ }
+}
+
+} // namespace
+
+void populateAudioProfiles(const AudioProfileAttributesMultimap& profileAttrs,
+ audio_format_t format,
+ ChannelMaskSet allChannelMasks,
+ SampleRateSet allSampleRates,
+ audio_profile audioProfiles[],
+ uint32_t* numAudioProfiles,
+ uint32_t maxAudioProfiles) {
+ if (*numAudioProfiles >= maxAudioProfiles) {
+ return;
+ }
+
+ const auto lower= profileAttrs.lower_bound(format);
+ const auto upper = profileAttrs.upper_bound(format);
+ SampleRateSet sampleRatesPresent;
+ ChannelMaskSet channelMasksPresent;
+ for (auto it = lower; it != upper && *numAudioProfiles < maxAudioProfiles; ++it) {
+ SampleRateSet srs;
+ std::set_intersection(it->second.first.begin(), it->second.first.end(),
+ allSampleRates.begin(), allSampleRates.end(),
+ std::inserter(srs, srs.begin()));
+ if (srs.empty()) {
+ continue;
+ }
+ ChannelMaskSet cms;
+ std::set_intersection(it->second.second.begin(), it->second.second.end(),
+ allChannelMasks.begin(), allChannelMasks.end(),
+ std::inserter(cms, cms.begin()));
+ if (cms.empty()) {
+ continue;
+ }
+ sampleRatesPresent.insert(srs.begin(), srs.end());
+ channelMasksPresent.insert(cms.begin(), cms.end());
+ populateAudioProfile(it->first, cms, srs,
+ &audioProfiles[(*numAudioProfiles)++]);
+ }
+ if (*numAudioProfiles >= maxAudioProfiles) {
+ ALOGW("%s, too many audio profiles", __func__);
+ return;
+ }
+
+ SampleRateSet srs;
+ std::set_difference(allSampleRates.begin(), allSampleRates.end(),
+ sampleRatesPresent.begin(), sampleRatesPresent.end(),
+ std::inserter(srs, srs.begin()));
+ if (!srs.empty()) {
+ populateAudioProfile(format, allChannelMasks, srs,
+ &audioProfiles[(*numAudioProfiles)++]);
+ }
+ if (*numAudioProfiles >= maxAudioProfiles) {
+ ALOGW("%s, too many audio profiles", __func__);
+ return;
+ }
+ ChannelMaskSet cms;
+ std::set_difference(allChannelMasks.begin(), allChannelMasks.end(),
+ channelMasksPresent.begin(), channelMasksPresent.end(),
+ std::inserter(cms, cms.begin()));
+ if (!cms.empty()) {
+ populateAudioProfile(format, cms, allSampleRates,
+ &audioProfiles[(*numAudioProfiles)++]);
+ }
+
+}
+
} // namespace android
diff --git a/media/libaudiofoundation/AudioProfile.cpp b/media/libaudiofoundation/AudioProfile.cpp
index 999e263..4a5fb96 100644
--- a/media/libaudiofoundation/AudioProfile.cpp
+++ b/media/libaudiofoundation/AudioProfile.cpp
@@ -383,6 +383,16 @@
}
}
+ChannelMaskSet AudioProfileVector::getSupportedChannelMasks() const {
+ ChannelMaskSet channelMasks;
+ for (const auto& profile : *this) {
+ if (profile->isValid()) {
+ channelMasks.insert(profile->getChannels().begin(), profile->getChannels().end());
+ }
+ }
+ return channelMasks;
+}
+
ConversionResult<AudioProfileVector>
aidl2legacy_AudioProfileVector(const AudioProfileVector::Aidl& aidl, bool isInput) {
return convertContainers<AudioProfileVector>(aidl.first, aidl.second,
diff --git a/media/libaudiofoundation/TEST_MAPPING b/media/libaudiofoundation/TEST_MAPPING
index a4e271e..f7e5b12 100644
--- a/media/libaudiofoundation/TEST_MAPPING
+++ b/media/libaudiofoundation/TEST_MAPPING
@@ -20,5 +20,10 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "audiofoundation_containers_test"
+ }
]
}
diff --git a/media/libaudiofoundation/include/media/AudioContainers.h b/media/libaudiofoundation/include/media/AudioContainers.h
index 88dcee9..46fd620 100644
--- a/media/libaudiofoundation/include/media/AudioContainers.h
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -19,6 +19,7 @@
#include <algorithm>
#include <functional>
#include <iterator>
+#include <map>
#include <set>
#include <vector>
@@ -34,6 +35,8 @@
using MixerBehaviorSet = std::set<audio_mixer_behavior_t>;
using FormatVector = std::vector<audio_format_t>;
+using AudioProfileAttributesMultimap =
+ std::multimap<audio_format_t, std::pair<SampleRateSet, ChannelMaskSet>>;
const DeviceTypeSet& getAudioDeviceOutAllSet();
const DeviceTypeSet& getAudioDeviceOutAllA2dpSet();
@@ -126,6 +129,8 @@
std::string dumpDeviceTypes(const DeviceTypeSet& deviceTypes);
+std::string dumpMixerBehaviors(const MixerBehaviorSet& mixerBehaviors);
+
/**
* Return human readable string for device types.
*/
@@ -133,5 +138,49 @@
return deviceTypesToString(deviceTypes);
}
+/**
+ * Create audio profile attributes map by given audio profile array from the range of [first, last).
+ *
+ * @param profiles the array of audio profiles.
+ * @param first the first index of the profile.
+ * @param last the last index of the profile.
+ * @return a multipmap of audio format to pair of corresponding sample rates and channel masks set.
+ */
+AudioProfileAttributesMultimap createAudioProfilesAttrMap(audio_profile profiles[],
+ uint32_t first,
+ uint32_t last);
+
+/**
+ * Populate audio profiles according to given profile attributes, format, channel masks and
+ * sample rates.
+ *
+ * The function will first go over all pairs of channel masks and sample rates that are present in
+ * the profile attributes of the given map. Note that the channel masks and the sample rates that
+ * are not present in the collections of all valid channel masks and all valid sample rates will be
+ * excluded. After that, if there are channel masks and sample rates that present in the all values
+ * collection but not in profile attributes, they will also be place in a new audio profile in the
+ * profile array.
+ *
+ * Note that if the resulting index of the audio profile exceeds the maximum, no new audio profiles
+ * will be placed in the array.
+ *
+ * @param profileAttrs a multimap that contains format and its corresponding channel masks and
+ * sample rates.
+ * @param format the targeted audio format.
+ * @param allChannelMasks all valid channel masks for the format.
+ * @param allSampleRates all valid sample rates for the format.
+ * @param audioProfiles the audio profile array.
+ * @param numAudioProfiles the start index to put audio profile in the array. The value will be
+ * updated if there is new audio profile placed.
+ * @param maxAudioProfiles the maximum number of audio profile.
+ */
+void populateAudioProfiles(const AudioProfileAttributesMultimap& profileAttrs,
+ audio_format_t format,
+ ChannelMaskSet allChannelMasks,
+ SampleRateSet allSampleRates,
+ audio_profile audioProfiles[],
+ uint32_t* numAudioProfiles,
+ uint32_t maxAudioProfiles = AUDIO_PORT_MAX_AUDIO_PROFILES);
+
} // namespace android
diff --git a/media/libaudiofoundation/include/media/AudioProfile.h b/media/libaudiofoundation/include/media/AudioProfile.h
index a668afe..bcde1fe 100644
--- a/media/libaudiofoundation/include/media/AudioProfile.h
+++ b/media/libaudiofoundation/include/media/AudioProfile.h
@@ -149,6 +149,8 @@
bool equals(const AudioProfileVector& other) const;
void addAllValidProfiles(const AudioProfileVector& audioProfiles);
+ ChannelMaskSet getSupportedChannelMasks() const;
+
using Aidl = std::pair<
std::vector<media::audio::common::AudioProfile>,
std::vector<media::AudioProfileSys>>;
diff --git a/media/libaudiofoundation/tests/Android.bp b/media/libaudiofoundation/tests/Android.bp
index 2f4aee0..82c7db7 100644
--- a/media/libaudiofoundation/tests/Android.bp
+++ b/media/libaudiofoundation/tests/Android.bp
@@ -43,3 +43,30 @@
test_suites: ["device-tests"],
}
+
+cc_test {
+ name: "audiofoundation_containers_test",
+
+ shared_libs: [
+ "liblog",
+ ],
+
+ static_libs: [
+ "libaudiofoundation",
+ ],
+
+ header_libs: [
+ "libaudio_system_headers",
+ ],
+
+ srcs: [
+ "audiofoundation_containers_test.cpp",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ test_suites: ["device-tests"],
+}
diff --git a/media/libaudiofoundation/tests/audiofoundation_containers_test.cpp b/media/libaudiofoundation/tests/audiofoundation_containers_test.cpp
new file mode 100644
index 0000000..967e2ee
--- /dev/null
+++ b/media/libaudiofoundation/tests/audiofoundation_containers_test.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 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 <gtest/gtest.h>
+
+#include <media/AudioContainers.h>
+
+namespace android {
+
+const static AudioProfileAttributesMultimap AUDIO_PROFILE_ATTRIBUTES = {
+ {AUDIO_FORMAT_PCM_16_BIT, {{44100, 48000},
+ {AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1}}},
+ {AUDIO_FORMAT_PCM_16_BIT, {{96000},
+ {AUDIO_CHANNEL_OUT_STEREO}}},
+ {AUDIO_FORMAT_PCM_8_24_BIT, {{48000},
+ {AUDIO_CHANNEL_OUT_STEREO}}}
+};
+
+TEST(PopulateAudioProfilesTest, AllAttributesMatches) {
+ const AudioProfileAttributesMultimap expected = {
+ {AUDIO_FORMAT_PCM_16_BIT, {{44100, 48000},
+ {AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1}}},
+ {AUDIO_FORMAT_PCM_16_BIT, {{96000},
+ {AUDIO_CHANNEL_OUT_STEREO}}}
+ };
+ const audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
+ const SampleRateSet allSampleRates = {44100, 48000, 96000};
+ const ChannelMaskSet allChannelMasks = {AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1};
+
+ audio_profile profiles[AUDIO_PORT_MAX_AUDIO_PROFILES];
+ uint32_t numProfiles = 0;
+ populateAudioProfiles(AUDIO_PROFILE_ATTRIBUTES, format, allChannelMasks, allSampleRates,
+ profiles, &numProfiles);
+ ASSERT_EQ(expected, createAudioProfilesAttrMap(profiles, 0, numProfiles));
+}
+
+TEST(PopulateAudioProfilesTest, AttributesNotInAllValues) {
+ const AudioProfileAttributesMultimap expected = {
+ {AUDIO_FORMAT_PCM_16_BIT, {{48000},
+ {AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1}}},
+ {AUDIO_FORMAT_PCM_16_BIT, {{96000},
+ {AUDIO_CHANNEL_OUT_STEREO}}}
+ };
+ const audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
+ const SampleRateSet allSampleRates = {48000, 96000};
+ const ChannelMaskSet allChannelMasks = {AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1};
+
+ audio_profile profiles[AUDIO_PORT_MAX_AUDIO_PROFILES];
+ uint32_t numProfiles = 0;
+ populateAudioProfiles(AUDIO_PROFILE_ATTRIBUTES, format, allChannelMasks, allSampleRates,
+ profiles, &numProfiles);
+ ASSERT_EQ(expected, createAudioProfilesAttrMap(profiles, 0, numProfiles));
+}
+
+TEST(PopulateAudioProfilesTest, AllValuesNotInAttributes) {
+ const AudioProfileAttributesMultimap expected = {
+ {AUDIO_FORMAT_PCM_16_BIT, {{48000},
+ {AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1}}},
+ {AUDIO_FORMAT_PCM_16_BIT, {{96000},
+ {AUDIO_CHANNEL_OUT_STEREO}}},
+ {AUDIO_FORMAT_PCM_16_BIT, {{88200},
+ {AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO,
+ AUDIO_CHANNEL_OUT_7POINT1}}},
+ {AUDIO_FORMAT_PCM_16_BIT, {{48000, 88200, 96000},
+ {AUDIO_CHANNEL_OUT_MONO}}}
+ };
+ const audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
+ const SampleRateSet allSampleRates = {48000, 88200, 96000};
+ const ChannelMaskSet allChannelMasks =
+ {AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1};
+
+ audio_profile profiles[AUDIO_PORT_MAX_AUDIO_PROFILES];
+ uint32_t numProfiles = 0;
+ populateAudioProfiles(AUDIO_PROFILE_ATTRIBUTES, format, allChannelMasks, allSampleRates,
+ profiles, &numProfiles);
+ ASSERT_EQ(expected, createAudioProfilesAttrMap(profiles, 0, numProfiles));
+}
+
+TEST(PopulateAudioProfilesTest, NoOverflow) {
+ const audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
+ const SampleRateSet allSampleRates = {48000, 88200, 96000};
+ const ChannelMaskSet allChannelMasks =
+ {AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1};
+
+ audio_profile profiles[AUDIO_PORT_MAX_AUDIO_PROFILES];
+ const uint32_t expectedNumProfiles = 4;
+ for (uint32_t i = 0; i <= AUDIO_PORT_MAX_AUDIO_PROFILES; ++i) {
+ uint32_t numProfiles = 0;
+ populateAudioProfiles(AUDIO_PROFILE_ATTRIBUTES, format, allChannelMasks, allSampleRates,
+ profiles, &numProfiles, i);
+ ASSERT_EQ(std::min(i, expectedNumProfiles), numProfiles);
+ }
+}
+
+} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index b18e64b..e2233c7 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -836,6 +836,33 @@
return OK;
}
+status_t DeviceHalAidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ if (devicePort->type != AUDIO_PORT_TYPE_DEVICE) {
+ return BAD_VALUE;
+ }
+ if (mixPort->type != AUDIO_PORT_TYPE_MIX) {
+ return BAD_VALUE;
+ }
+ const int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(mixPort->ext.mix.handle));
+ auto it = findPortConfig(std::nullopt /*config*/, std::nullopt/*flags*/, aidlHandle);
+ if (it == mPortConfigs.end()) {
+ ALOGE("%s, cannot find mix port config for handle=%u", __func__, aidlHandle);
+ return BAD_VALUE;
+ }
+ AudioPort port;
+ if (status_t status = getAudioPort(it->second.portId, &port); status != NO_ERROR) {
+ return status;
+ }
+ const bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
+ mixPort->role, mixPort->type)) == ::aidl::android::AudioPortDirection::INPUT;
+ *mixPort = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
+ port, isInput));
+ return NO_ERROR;
+}
+
status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
@@ -1010,7 +1037,7 @@
return mModule->dump(fd, Args(args).args(), args.size());
}
-int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
+status_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports) {
TIME_CHECK();
if (!mModule) return NO_INIT;
if (supports == nullptr) {
@@ -1194,10 +1221,15 @@
TIME_CHECK();
if (String8 key = String8(AudioParameter::keyReconfigA2dpSupported); keys.containsKey(key)) {
keys.remove(key);
- bool supports;
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
- mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
- result->addInt(key, supports ? 1 : 0);
+ if (mBluetoothA2dp != nullptr) {
+ bool supports;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mBluetoothA2dp->supportsOffloadReconfiguration(&supports)));
+ result->addInt(key, supports ? 1 : 0);
+ } else {
+ ALOGI("%s: no IBluetoothA2dp on %s", __func__, mInstance.c_str());
+ result->addInt(key, 0);
+ }
}
return OK;
}
@@ -1702,7 +1734,9 @@
}
DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
- const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
+ const std::optional<AudioConfig>& config,
+ const std::optional<AudioIoFlags>& flags,
+ int32_t ioHandle) {
using Tag = AudioPortExt::Tag;
return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
[&](const auto& pair) {
@@ -1713,7 +1747,8 @@
"%s: stored mix port config is not fully specified: %s",
__func__, p.toString().c_str());
return p.ext.getTag() == Tag::mix &&
- isConfigEqualToPortConfig(config, p) &&
+ (!config.has_value() ||
+ isConfigEqualToPortConfig(config.value(), p)) &&
(!flags.has_value() || p.flags.value() == flags.value()) &&
p.ext.template get<Tag::mix>().handle == ioHandle; });
}
@@ -1840,6 +1875,25 @@
return OK;
}
+status_t DeviceHalAidl::getAudioPort(int32_t portId, AudioPort* port) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mModule) {
+ return NO_INIT;
+ }
+ const status_t status = statusTFromBinderStatus(mModule->getAudioPort(portId, port));
+ if (status == OK) {
+ auto portIt = mPorts.find(portId);
+ if (portIt != mPorts.end()) {
+ portIt->second = *port;
+ } else {
+ ALOGW("%s, port(%d) returned successfully from the HAL but not it is not cached",
+ __func__, portId);
+ }
+ }
+ return status;
+}
+
void DeviceHalAidl::clearCallbacks(void* cookie) {
std::lock_guard l(mLock);
mCallbacks.erase(cookie);
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index 20cf88c..e1fe4d1 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -165,7 +165,7 @@
error::Result<audio_hw_sync_t> getHwAvSync() override;
- int32_t supportsBluetoothVariableLatency(bool* supports __unused) override;
+ status_t supportsBluetoothVariableLatency(bool* supports __unused) override;
status_t getSoundDoseInterface(const std::string& module,
::ndk::SpAIBinder* soundDoseBinder) override;
@@ -176,6 +176,9 @@
status_t setSimulateDeviceConnections(bool enabled) override;
+ status_t getAudioMixPort(const struct audio_port_v7* devicePort,
+ struct audio_port_v7* mixPort) override;
+
status_t dump(int __unused, const Vector<String16>& __unused) override;
private:
@@ -260,7 +263,7 @@
PortConfigs::iterator findPortConfig(
const ::aidl::android::media::audio::common::AudioDevice& device);
PortConfigs::iterator findPortConfig(
- const ::aidl::android::media::audio::common::AudioConfig& config,
+ const std::optional<::aidl::android::media::audio::common::AudioConfig>& config,
const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
int32_t ioHandle);
bool isPortHeldByAStream(int32_t portId);
@@ -280,6 +283,7 @@
void resetUnusedPatchesAndPortConfigs();
void resetUnusedPortConfigs();
status_t updateRoutes();
+ status_t getAudioPort(int32_t portId, ::aidl::android::media::audio::common::AudioPort* port);
// CallbackBroker implementation
void clearCallbacks(void* cookie) override;
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index f96d419..e8e1f46 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -304,7 +304,12 @@
}
HidlUtils::audioConfigToHal(suggestedConfig, config);
});
- return processReturn("openOutputStream", ret, retval);
+ const status_t status = processReturn("openOutputStream", ret, retval);
+ cleanupStreams();
+ if (status == NO_ERROR) {
+ mStreams.insert({handle, *outStream});
+ }
+ return status;
}
status_t DeviceHalHidl::openInputStream(
@@ -377,7 +382,12 @@
}
HidlUtils::audioConfigToHal(suggestedConfig, config);
});
- return processReturn("openInputStream", ret, retval);
+ const status_t status = processReturn("openInputStream", ret, retval);
+ cleanupStreams();
+ if (status == NO_ERROR) {
+ mStreams.insert({handle, *inStream});
+ }
+ return status;
}
status_t DeviceHalHidl::supportsAudioPatches(bool *supportsPatches) {
@@ -684,4 +694,148 @@
}
#endif
+status_t DeviceHalHidl::supportsBluetoothVariableLatency(bool* supports) {
+ if (supports == nullptr) {
+ return BAD_VALUE;
+ }
+ *supports = false;
+
+ String8 reply;
+ status_t status = getParameters(
+ String8(AUDIO_PARAMETER_BT_VARIABLE_LATENCY_SUPPORTED), &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ AudioParameter replyParams(reply);
+ String8 trueOrFalse;
+ status = replyParams.get(
+ String8(AUDIO_PARAMETER_BT_VARIABLE_LATENCY_SUPPORTED), trueOrFalse);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ *supports = trueOrFalse == AudioParameter::valueTrue;
+ return NO_ERROR;
+}
+
+namespace {
+
+status_t getParametersFromStream(
+ sp<StreamHalInterface> stream,
+ const char* parameters,
+ const char* extraParameters,
+ String8* reply) {
+ String8 request(parameters);
+ if (extraParameters != nullptr) {
+ request.append(";");
+ request.append(extraParameters);
+ }
+ status_t status = stream->getParameters(request, reply);
+ if (status != NO_ERROR) {
+ ALOGW("%s, failed to query %s, status=%d", __func__, parameters, status);
+ return status;
+ }
+ AudioParameter repliedParameters(*reply);
+ status = repliedParameters.get(String8(parameters), *reply);
+ if (status != NO_ERROR) {
+ ALOGW("%s: failed to retrieve %s, bailing out", __func__, parameters);
+ }
+ return status;
+}
+
+} // namespace
+
+status_t DeviceHalHidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) {
+ // For HIDL HAL, querying mix port information is not supported. If the HAL supports
+ // `getAudioPort` API to query the device port attributes, use the structured audio profiles
+ // that have the same attributes reported by the `getParameters` API. Otherwise, only use
+ // the attributes reported by `getParameters` API.
+ struct audio_port_v7 temp = *devicePort;
+ AudioProfileAttributesMultimap attrsFromDevice;
+ status_t status = getAudioPort(&temp);
+ if (status == NO_ERROR) {
+ attrsFromDevice = createAudioProfilesAttrMap(temp.audio_profiles, 0 /*first*/,
+ temp.num_audio_profiles);
+ }
+ auto streamIt = mStreams.find(mixPort->ext.mix.handle);
+ if (streamIt == mStreams.end()) {
+ return BAD_VALUE;
+ }
+ auto stream = streamIt->second.promote();
+ if (stream == nullptr) {
+ return BAD_VALUE;
+ }
+
+ String8 formatsStr;
+ status = getParametersFromStream(
+ stream, AudioParameter::keyStreamSupportedFormats, nullptr /*extraParameters*/,
+ &formatsStr);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FormatVector formats = formatsFromString(formatsStr.c_str());
+
+ mixPort->num_audio_profiles = 0;
+ for (audio_format_t format : formats) {
+ if (mixPort->num_audio_profiles >= AUDIO_PORT_MAX_AUDIO_PROFILES) {
+ ALOGW("%s, too many audio profiles", __func__);
+ break;
+ }
+ AudioParameter formatParameter;
+ formatParameter.addInt(String8(AudioParameter::keyFormat), format);
+
+ String8 samplingRatesStr;
+ status = getParametersFromStream(
+ stream, AudioParameter::keyStreamSupportedSamplingRates,
+ formatParameter.toString(), &samplingRatesStr);
+ if (status != NO_ERROR) {
+ // Failed to query supported sample rate for current format, may succeed with
+ // other formats.
+ ALOGW("Skip adding format=%#x, status=%d", format, status);
+ continue;
+ }
+ SampleRateSet sampleRatesFromStream = samplingRatesFromString(samplingRatesStr.c_str());
+ if (sampleRatesFromStream.empty()) {
+ ALOGW("Skip adding format=%#x as the returned sampling rates are empty", format);
+ continue;
+ }
+ String8 channelMasksStr;
+ status = getParametersFromStream(
+ stream, AudioParameter::keyStreamSupportedChannels,
+ formatParameter.toString(), &channelMasksStr);
+ if (status != NO_ERROR) {
+ // Failed to query supported channel masks for current format, may succeed with
+ // other formats.
+ ALOGW("Skip adding format=%#x, status=%d", format, status);
+ continue;
+ }
+ ChannelMaskSet channelMasksFromStream = channelMasksFromString(channelMasksStr.c_str());
+ if (channelMasksFromStream.empty()) {
+ ALOGW("Skip adding format=%#x as the returned channel masks are empty", format);
+ continue;
+ }
+
+ // For an audio format, all audio profiles from the device port with the same format will
+ // be added to mix port after filtering sample rates, channel masks according to the reply
+ // of getParameters API. If there is any sample rate or channel mask reported by
+ // getParameters API but not reported by the device, additional audio profiles will be
+ // added.
+ populateAudioProfiles(attrsFromDevice, format, channelMasksFromStream,
+ sampleRatesFromStream, mixPort->audio_profiles,
+ &mixPort->num_audio_profiles);
+ }
+
+ return NO_ERROR;
+}
+
+void DeviceHalHidl::cleanupStreams() {
+ for (auto it = mStreams.begin(); it != mStreams.end();) {
+ if (it->second.promote() == nullptr) {
+ it = mStreams.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index 989c1f5..7a712df 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -21,6 +21,7 @@
#include PATH(android/hardware/audio/FILE_VERSION/IPrimaryDevice.h)
#include <media/audiohal/DeviceHalInterface.h>
#include <media/audiohal/EffectHalInterface.h>
+#include <media/audiohal/StreamHalInterface.h>
#include "CoreConversionHelperHidl.h"
@@ -127,10 +128,7 @@
return INVALID_OPERATION;
}
- int32_t supportsBluetoothVariableLatency(bool* supports __unused) override {
- // TODO: Implement the HAL query when moving to AIDL HAL.
- return INVALID_OPERATION;
- }
+ status_t supportsBluetoothVariableLatency(bool* supports) override;
status_t setConnectedState(const struct audio_port_v7 *port, bool connected) override;
@@ -148,6 +146,9 @@
status_t prepareToDisconnectExternalDevice(const struct audio_port_v7* port) override;
+ status_t getAudioMixPort(const struct audio_port_v7* devicePort,
+ struct audio_port_v7* mixPort) override;
+
private:
friend class DevicesFactoryHalHidl;
sp<::android::hardware::audio::CPP_VERSION::IDevice> mDevice;
@@ -157,12 +158,15 @@
class SoundDoseWrapper;
const std::unique_ptr<SoundDoseWrapper> mSoundDoseWrapper;
std::set<audio_port_handle_t> mDeviceDisconnectionNotified;
+ std::map<audio_io_handle_t, wp<StreamHalInterface>> mStreams;
// Can not be constructed directly by clients.
explicit DeviceHalHidl(const sp<::android::hardware::audio::CPP_VERSION::IDevice>& device);
explicit DeviceHalHidl(
const sp<::android::hardware::audio::CPP_VERSION::IPrimaryDevice>& device);
+ void cleanupStreams();
+
// The destructor automatically closes the device.
virtual ~DeviceHalHidl();
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
index 87aaeac..7d807b2 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
@@ -243,7 +243,7 @@
[&](const auto& desc) { return desc.common.id.uuid == uuid; });
if (matchIt == list.end()) {
ALOGE("%s UUID not found in HAL and proxy list %s", __func__, toString(uuid).c_str());
- return BAD_VALUE;
+ return NAME_NOT_FOUND;
}
ALOGI("%s UUID impl found %s", __func__, toString(uuid).c_str());
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index a965709..bb5f851 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -142,7 +142,7 @@
virtual int32_t getAAudioMixerBurstCount() = 0;
virtual int32_t getAAudioHardwareBurstMinUsec() = 0;
- virtual int32_t supportsBluetoothVariableLatency(bool* supports) = 0;
+ virtual status_t supportsBluetoothVariableLatency(bool* supports) = 0;
// Update the connection status of an external device.
virtual status_t setConnectedState(const struct audio_port_v7* port, bool connected) = 0;
@@ -160,6 +160,9 @@
virtual status_t prepareToDisconnectExternalDevice(const struct audio_port_v7* port) = 0;
+ virtual status_t getAudioMixPort(const struct audio_port_v7* devicePort,
+ struct audio_port_v7* mixPort) = 0;
+
protected:
// Subclasses can not be constructed directly by clients.
DeviceHalInterface() {}
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index b5bd975..57937f9 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -16,7 +16,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "FrameDecoder"
-
+#define ATRACE_TAG ATRACE_TAG_VIDEO
#include "include/FrameDecoder.h"
#include "include/FrameCaptureLayer.h"
#include "include/HevcUtils.h"
@@ -41,6 +41,7 @@
#include <media/stagefright/Utils.h>
#include <private/media/VideoFrame.h>
#include <utils/Log.h>
+#include <utils/Trace.h>
namespace android {
@@ -340,6 +341,7 @@
}
sp<IMemory> FrameDecoder::extractFrame(FrameRect *rect) {
+ ScopedTrace trace(ATRACE_TAG, "FrameDecoder::ExtractFrame");
status_t err = onExtractRect(rect);
if (err == OK) {
err = extractInternal();
@@ -713,6 +715,7 @@
}
converter.setSrcColorSpace(standard, range, transfer);
if (converter.isValid()) {
+ ScopedTrace trace(ATRACE_TAG, "FrameDecoder::ColorConverter");
converter.convert(
(const uint8_t *)videoFrameBuffer->data(),
width, height, stride,
diff --git a/media/mtp/tests/MtpFuzzer/Android.bp b/media/mtp/tests/MtpFuzzer/Android.bp
index 9e41680..acae06a 100644
--- a/media/mtp/tests/MtpFuzzer/Android.bp
+++ b/media/mtp/tests/MtpFuzzer/Android.bp
@@ -38,11 +38,19 @@
],
fuzz_config: {
- cc: ["jameswei@google.com"],
- componentid: 1344,
+ cc: ["android-usb@google.com"],
+ componentid: 1407286,
acknowledgement: [
"Grant Hernandez of Google",
],
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libmtp library",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
cc_fuzz {
diff --git a/media/ndk/include/media/NdkMediaDataSource.h b/media/ndk/include/media/NdkMediaDataSource.h
index 4158a97..197e202 100644
--- a/media/ndk/include/media/NdkMediaDataSource.h
+++ b/media/ndk/include/media/NdkMediaDataSource.h
@@ -14,6 +14,14 @@
* limitations under the License.
*/
+/**
+ * @addtogroup Media
+ * @{
+ */
+
+/**
+ * @file NdkMediaDataSource.h
+ */
/*
* This file defines an NDK API.
diff --git a/media/ndk/include/media/NdkMediaExtractor.h b/media/ndk/include/media/NdkMediaExtractor.h
index e429820..af30b8b 100644
--- a/media/ndk/include/media/NdkMediaExtractor.h
+++ b/media/ndk/include/media/NdkMediaExtractor.h
@@ -221,9 +221,9 @@
* available (end of stream). This API can be used in in conjunction with
* AMediaExtractor_readSampleData:
*
- * ssize_t sampleSize = AMediaExtractor_getSampleSize(ex);
+ * <pre>ssize_t sampleSize = AMediaExtractor_getSampleSize(ex);
* uint8_t *buf = new uint8_t[sampleSize];
- * AMediaExtractor_readSampleData(ex, buf, sampleSize);
+ * AMediaExtractor_readSampleData(ex, buf, sampleSize);</pre>
*
* Available since API level 28.
*/
@@ -245,13 +245,13 @@
int64_t AMediaExtractor_getCachedDuration(AMediaExtractor *) __INTRODUCED_IN(28);
/**
- * Read the current sample's metadata format into |fmt|. Examples of sample metadata are
+ * Read the current sample's metadata format into `fmt`. Examples of sample metadata are
* SEI (supplemental enhancement information) and MPEG user data, both of which can embed
* closed-caption data.
*
* Returns AMEDIA_OK on success or AMEDIA_ERROR_* to indicate failure reason.
- * Existing key-value pairs in |fmt| would be removed if this API returns AMEDIA_OK.
- * The contents of |fmt| is undefined if this API returns AMEDIA_ERROR_*.
+ * Existing key-value pairs in `fmt` would be removed if this API returns AMEDIA_OK.
+ * The contents of `fmt` is undefined if this API returns AMEDIA_ERROR_*.
*
* Available since API level 28.
*/
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 0d539c0..29c6845 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -189,6 +189,7 @@
BINDER_METHOD_ENTRY(supportsBluetoothVariableLatency) \
BINDER_METHOD_ENTRY(getSoundDoseInterface) \
BINDER_METHOD_ENTRY(getAudioPolicyConfig) \
+BINDER_METHOD_ENTRY(getAudioMixPort) \
// singleton for Binder Method Statistics for IAudioFlinger
static auto& getIAudioFlingerStatistics() {
@@ -4269,7 +4270,7 @@
response->id = idOut;
response->enabled = enabledOut != 0;
- response->effect = handle->asIEffect();
+ response->effect = handle.get() ? handle->asIEffect() : nullptr;
response->desc = VALUE_OR_RETURN_STATUS(
legacy2aidl_effect_descriptor_t_EffectDescriptor(descOut));
@@ -4607,6 +4608,24 @@
return mPatchPanel->listAudioPatches_l(num_patches, patches);
}
+/**
+ * Get the attributes of the mix port when connecting to the given device port.
+ */
+status_t AudioFlinger::getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) const {
+ if (status_t status = AudioValidator::validateAudioPort(*devicePort); status != NO_ERROR) {
+ ALOGE("%s, invalid device port, status=%d", __func__, status);
+ return status;
+ }
+ if (status_t status = AudioValidator::validateAudioPort(*mixPort); status != NO_ERROR) {
+ ALOGE("%s, invalid mix port, status=%d", __func__, status);
+ return status;
+ }
+
+ audio_utils::lock_guard _l(mutex());
+ return mPatchPanel->getAudioMixPort_l(devicePort, mixPort);
+}
+
// ----------------------------------------------------------------------------
status_t AudioFlinger::onTransactWrapper(TransactionCode code,
@@ -4640,6 +4659,7 @@
case TransactionCode::GET_SUPPORTED_LATENCY_MODES:
case TransactionCode::INVALIDATE_TRACKS:
case TransactionCode::GET_AUDIO_POLICY_CONFIG:
+ case TransactionCode::GET_AUDIO_MIX_PORT:
ALOGW("%s: transaction %d received from PID %d",
__func__, code, IPCThreadState::self()->getCallingPid());
// return status only for non void methods
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 2c34144..e7f9255 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -255,6 +255,10 @@
status_t getAudioPolicyConfig(media::AudioPolicyConfig* config) final
EXCLUDES_AudioFlinger_Mutex;
+ // Get the attributes of the mix port when connecting to the given device port.
+ status_t getAudioMixPort(const struct audio_port_v7* devicePort,
+ struct audio_port_v7* mixPort) const final EXCLUDES_AudioFlinger_Mutex;
+
status_t onTransactWrapper(TransactionCode code, const Parcel& data, uint32_t flags,
const std::function<status_t()>& delegate) final EXCLUDES_AudioFlinger_Mutex;
diff --git a/services/audioflinger/IAfPatchPanel.h b/services/audioflinger/IAfPatchPanel.h
index 5a6621e..6110e4c 100644
--- a/services/audioflinger/IAfPatchPanel.h
+++ b/services/audioflinger/IAfPatchPanel.h
@@ -302,6 +302,13 @@
virtual void closeThreadInternal_l(const sp<IAfThreadBase>& thread) const
REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
+
+ /**
+ * Get the attributes of the mix port when connecting to the given device port.
+ */
+ virtual status_t getAudioMixPort_l(
+ const struct audio_port_v7* devicePort,
+ struct audio_port_v7* mixPort) REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
};
} // namespace android
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 7d3900b..17591dd 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -447,6 +447,24 @@
return status;
}
+status_t PatchPanel::getAudioMixPort_l(const audio_port_v7 *devicePort,
+ audio_port_v7 *mixPort) {
+ if (devicePort->type != AUDIO_PORT_TYPE_DEVICE) {
+ ALOGE("%s the type of given device port is not DEVICE", __func__);
+ return INVALID_OPERATION;
+ }
+ if (mixPort->type != AUDIO_PORT_TYPE_MIX) {
+ ALOGE("%s the type of given mix port is not MIX", __func__);
+ return INVALID_OPERATION;
+ }
+ AudioHwDevice* hwDevice = findAudioHwDeviceByModule_l(devicePort->ext.device.hw_module);
+ if (hwDevice == nullptr) {
+ ALOGW("%s cannot find hw module %d", __func__, devicePort->ext.device.hw_module);
+ return BAD_VALUE;
+ }
+ return hwDevice->getAudioMixPort(devicePort, mixPort);
+}
+
PatchPanel::Patch::~Patch()
{
ALOGE_IF(isSoftware(), "Software patch connections leaked %d %d",
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index 1ff8fff..b107eb0 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -73,6 +73,12 @@
void closeThreadInternal_l(const sp<IAfThreadBase>& thread) const final
REQUIRES(audio_utils::AudioFlinger_Mutex);
+ /**
+ * Get the attributes of the mix port when connecting to the given device port
+ */
+ status_t getAudioMixPort_l(const audio_port_v7* devicePort, audio_port_v7* mixPort) final
+ REQUIRES(audio_utils::AudioFlinger_Mutex);
+
private:
AudioHwDevice* findAudioHwDeviceByModule_l(audio_module_handle_t module)
REQUIRES(audio_utils::AudioFlinger_Mutex);
diff --git a/services/audioflinger/datapath/AudioHwDevice.cpp b/services/audioflinger/datapath/AudioHwDevice.cpp
index 9ff316c..67e9991 100644
--- a/services/audioflinger/datapath/AudioHwDevice.cpp
+++ b/services/audioflinger/datapath/AudioHwDevice.cpp
@@ -118,5 +118,10 @@
return mHwDevice->getAAudioHardwareBurstMinUsec();
}
+status_t AudioHwDevice::getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) const {
+ return mHwDevice->getAudioMixPort(devicePort, mixPort);
+}
+
}; // namespace android
diff --git a/services/audioflinger/datapath/AudioHwDevice.h b/services/audioflinger/datapath/AudioHwDevice.h
index f9cb80e..cfb6fbd 100644
--- a/services/audioflinger/datapath/AudioHwDevice.h
+++ b/services/audioflinger/datapath/AudioHwDevice.h
@@ -101,6 +101,9 @@
[[nodiscard]] int32_t getAAudioHardwareBurstMinUsec() const;
+ [[nodiscard]] status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) const;
+
private:
const audio_module_handle_t mHandle;
const char * const mModuleName;
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index da0df5f..d49a002 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -574,6 +574,10 @@
media::DeviceConnectedState state) = 0;
virtual status_t invalidateTracks(const std::vector<audio_port_handle_t>& portIds) = 0;
+
+ // Get the attributes of the mix port when connecting to the given device port.
+ virtual status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) = 0;
};
// These are the signatures of createAudioPolicyManager/destroyAudioPolicyManager
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index c489eed..f3a9518 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -63,13 +63,7 @@
if (getRole() == AUDIO_PORT_ROLE_SINK && (flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
maxActiveCount = 0;
}
- if (getRole() == AUDIO_PORT_ROLE_SOURCE) {
- mMixerBehaviors.clear();
- mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_DEFAULT);
- if (mFlags.output & AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
- mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_BIT_PERFECT);
- }
- }
+ refreshMixerBehaviors();
}
const MixerBehaviorSet& getMixerBehaviors() const {
@@ -222,6 +216,10 @@
void toSupportedMixerAttributes(std::vector<audio_mixer_attributes_t>* mixerAttributes) const;
+ status_t readFromParcelable(const media::AudioPortFw& parcelable);
+
+ void importAudioPort(const audio_port_v7& port) override;
+
// Number of streams currently opened for this profile.
uint32_t curOpenCount;
// Number of streams currently active for this profile. This is not the number of active clients
@@ -229,6 +227,8 @@
uint32_t curActiveCount;
private:
+ void refreshMixerBehaviors();
+
DeviceVector mSupportedDevices; // supported devices: this input/output can be routed from/to
MixerBehaviorSet mMixerBehaviors;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 4877166..475059c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -322,7 +322,7 @@
mOutput1(0), mOutput2(0), mDirectOpenCount(0),
mDirectClientSession(AUDIO_SESSION_NONE)
{
- if (profile != NULL) {
+ if (profile != nullptr) {
// By default, opening the output without immutable flags, the bit-perfect flags should be
// applied when the apps explicitly request.
mFlags = (audio_output_flags_t)(profile->getFlags() & (~AUDIO_OUTPUT_FLAG_BIT_PERFECT));
@@ -376,7 +376,10 @@
supportedDevices.merge(mOutput2->supportedDevices());
return supportedDevices;
}
- return mProfile->getSupportedDevices();
+ if (mProfile != nullptr) {
+ return mProfile->getSupportedDevices();
+ }
+ return DeviceVector();
}
bool SwAudioOutputDescriptor::supportsDevice(const sp<DeviceDescriptor> &device) const
@@ -407,9 +410,10 @@
if (isDuplicated()) {
return (mOutput1->devicesSupportEncodedFormats(deviceTypes)
|| mOutput2->devicesSupportEncodedFormats(deviceTypes));
- } else {
+ } else if (mProfile != nullptr) {
return mProfile->devicesSupportEncodedFormats(deviceTypes);
}
+ return false;
}
bool SwAudioOutputDescriptor::containsSingleDeviceSupportingEncodedFormats(
@@ -419,7 +423,10 @@
return (mOutput1->containsSingleDeviceSupportingEncodedFormats(device) &&
mOutput2->containsSingleDeviceSupportingEncodedFormats(device));
}
- return mProfile->containsSingleDeviceSupportingEncodedFormats(device);
+ if (mProfile != nullptr) {
+ return mProfile->containsSingleDeviceSupportingEncodedFormats(device);
+ }
+ return false;
}
uint32_t SwAudioOutputDescriptor::latency()
@@ -578,6 +585,11 @@
"with the requested devices, all device types: %s",
__func__, dumpDeviceTypes(devices.types()).c_str());
+ if (mProfile == nullptr) {
+ ALOGE("%s : Cannot open descriptor without a profile ", __func__);
+ return INVALID_OPERATION;
+ }
+
audio_config_t lHalConfig;
if (halConfig == nullptr) {
lHalConfig = AUDIO_CONFIG_INITIALIZER;
@@ -662,7 +674,7 @@
}
return NO_ERROR;
}
- if (!isActive()) {
+ if (mProfile != nullptr && !isActive()) {
if (!mProfile->canStartNewIo()) {
return INVALID_OPERATION;
}
@@ -679,7 +691,7 @@
return;
}
- if (!isActive()) {
+ if (mProfile != nullptr && !isActive()) {
LOG_ALWAYS_FATAL_IF(mProfile->curActiveCount < 1,
"%s invalid profile active count %u",
__func__, mProfile->curActiveCount);
@@ -702,10 +714,11 @@
}
mClientInterface->closeOutput(mIoHandle);
-
- LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < 1, "%s profile open count %u",
- __FUNCTION__, mProfile->curOpenCount);
- mProfile->curOpenCount--;
+ if (mProfile != nullptr) {
+ LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < 1, "%s profile open count %u",
+ __FUNCTION__, mProfile->curOpenCount);
+ mProfile->curOpenCount--;
+ }
mIoHandle = AUDIO_IO_HANDLE_NONE;
}
}
@@ -740,7 +753,10 @@
return std::max(mOutput1->getRecommendedMuteDurationMs(),
mOutput2->getRecommendedMuteDurationMs());
}
- return mProfile->recommendedMuteDurationMs;
+ if (mProfile != nullptr) {
+ return mProfile->recommendedMuteDurationMs;
+ }
+ return 0;
}
void SwAudioOutputDescriptor::setTracksInvalidatedStatusByStrategy(product_strategy_t strategy) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index 03ab3f8..dd222de 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -171,6 +171,49 @@
}
}
+void IOProfile::refreshMixerBehaviors() {
+ if (getRole() == AUDIO_PORT_ROLE_SOURCE) {
+ mMixerBehaviors.clear();
+ mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_DEFAULT);
+ if (mFlags.output & AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
+ mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_BIT_PERFECT);
+ }
+ }
+}
+
+status_t IOProfile::readFromParcelable(const media::AudioPortFw &parcelable) {
+ status_t status = AudioPort::readFromParcelable(parcelable);
+ if (status == OK) {
+ refreshMixerBehaviors();
+ }
+ return status;
+}
+
+void IOProfile::importAudioPort(const audio_port_v7 &port) {
+ if (mProfiles.hasDynamicFormat()) {
+ std::set<audio_format_t> formats;
+ for (size_t i = 0; i < port.num_audio_profiles; ++i) {
+ formats.insert(port.audio_profiles[i].format);
+ }
+ addProfilesForFormats(mProfiles, FormatVector(formats.begin(), formats.end()));
+ }
+ for (audio_format_t format : mProfiles.getSupportedFormats()) {
+ for (size_t i = 0; i < port.num_audio_profiles; ++i) {
+ if (port.audio_profiles[i].format == format) {
+ ChannelMaskSet channelMasks(port.audio_profiles[i].channel_masks,
+ port.audio_profiles[i].channel_masks +
+ port.audio_profiles[i].num_channel_masks);
+ SampleRateSet sampleRates(port.audio_profiles[i].sample_rates,
+ port.audio_profiles[i].sample_rates +
+ port.audio_profiles[i].num_sample_rates);
+ addDynamicAudioProfileAndSort(
+ mProfiles, sp<AudioProfile>::make(
+ format, channelMasks, sampleRates));
+ }
+ }
+ }
+}
+
void IOProfile::dump(String8 *dst, int spaces) const
{
String8 extraInfo;
@@ -195,6 +238,10 @@
spaces - 2, "", maxActiveCount, curActiveCount);
dst->appendFormat("%*s- recommendedMuteDurationMs: %u ms\n",
spaces - 2, "", recommendedMuteDurationMs);
+ if (hasDynamicAudioProfile() && !mMixerBehaviors.empty()) {
+ dst->appendFormat("%*s- mixerBehaviors: %s\n",
+ spaces - 2, "", dumpMixerBehaviors(mMixerBehaviors).c_str());
+ }
}
void IOProfile::log()
diff --git a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
index 93122e0..fcf410b 100644
--- a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
+++ b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
@@ -79,6 +79,7 @@
case AUDIO_DEVICE_OUT_USB_ACCESSORY:
case AUDIO_DEVICE_OUT_USB_DEVICE:
case AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET:
+ case AUDIO_DEVICE_OUT_AUX_DIGITAL:
return GROUP_WIRED;
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 15f7842..e06bbb3 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -296,7 +296,8 @@
// excluding HEARING_AID and BLE_HEADSET because Dialer uses
// setCommunicationDevice to select them explicitly
AUDIO_DEVICE_OUT_HEARING_AID,
- AUDIO_DEVICE_OUT_BLE_HEADSET
+ AUDIO_DEVICE_OUT_BLE_HEADSET,
+ AUDIO_DEVICE_OUT_AUX_DIGITAL
}));
if (!devices.isEmpty()) break;
devices = availableOutputDevices.getFirstDevicesFromTypes({
@@ -399,20 +400,21 @@
}
if (devices2.isEmpty() && (getLastRemovableMediaDevices().size() > 0)) {
+ std::vector<audio_devices_t> excludedDevices;
+ // no sonification on aux digital (e.g. HDMI)
+ if (strategy == STRATEGY_SONIFICATION) {
+ excludedDevices.push_back(AUDIO_DEVICE_OUT_AUX_DIGITAL);
+ }
if ((getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
// Get the last connected device of wired and bluetooth a2dp
devices2 = availableOutputDevices.getFirstDevicesFromTypes(
- getLastRemovableMediaDevices());
+ getLastRemovableMediaDevices(GROUP_NONE, excludedDevices));
} else {
// Get the last connected device of wired except bluetooth a2dp
devices2 = availableOutputDevices.getFirstDevicesFromTypes(
- getLastRemovableMediaDevices(GROUP_WIRED));
+ getLastRemovableMediaDevices(GROUP_WIRED, excludedDevices));
}
}
- if ((devices2.isEmpty()) && (strategy != STRATEGY_SONIFICATION)) {
- // no sonification on aux digital (e.g. HDMI)
- devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_AUX_DIGITAL);
- }
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK) == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
devices2 = availableOutputDevices.getDevicesFromType(
diff --git a/services/audiopolicy/fuzzer/aidl/Android.bp b/services/audiopolicy/fuzzer/aidl/Android.bp
new file mode 100644
index 0000000..38a2cde
--- /dev/null
+++ b/services/audiopolicy/fuzzer/aidl/Android.bp
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2023 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.
+ *
+ ******************************************************************************/
+
+cc_defaults {
+ name: "audiopolicy_aidl_fuzzer_defaults",
+ shared_libs: [
+ "audiopolicy-aidl-cpp",
+ "audiopolicy-types-aidl-cpp",
+ "framework-permission-aidl-cpp",
+ "libaudiopolicy",
+ "libaudiopolicymanagerdefault",
+ "libactivitymanager_aidl",
+ "libaudiohal",
+ "libaudiopolicyservice",
+ "libaudioflinger",
+ "libaudioclient",
+ "libaudioprocessing",
+ "libhidlbase",
+ "liblog",
+ "libmediautils",
+ "libnblog",
+ "libnbaio",
+ "libpowermanager",
+ "libvibrator",
+ "packagemanager_aidl-cpp",
+ ],
+ static_libs: [
+ "libfakeservicemanager",
+ "libmediaplayerservice",
+ ],
+ header_libs: [
+ "libaudiohal_headers",
+ "libaudioflinger_headers",
+ "libaudiopolicymanager_interface_headers",
+ "libbinder_headers",
+ "libmedia_headers",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ hotlists: ["4593311"],
+ description: "The fuzzer targets the APIs of libaudiopolicy",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
+ },
+}
+
+cc_fuzz {
+ name: "audiopolicy_aidl_fuzzer",
+ srcs: ["audiopolicy_aidl_fuzzer.cpp"],
+ defaults: [
+ "audiopolicy_aidl_fuzzer_defaults",
+ "service_fuzzer_defaults",
+ ],
+}
diff --git a/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp b/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
new file mode 100644
index 0000000..ca79c49
--- /dev/null
+++ b/services/audiopolicy/fuzzer/aidl/audiopolicy_aidl_fuzzer.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 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 <AudioFlinger.h>
+#include <android-base/logging.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_process.h>
+#include <android/media/IAudioPolicyService.h>
+#include <fakeservicemanager/FakeServiceManager.h>
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzbinder/random_binder.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <media/IAudioFlinger.h>
+#include <service/AudioPolicyService.h>
+
+using namespace android;
+using namespace android::binder;
+using namespace android::hardware;
+using android::fuzzService;
+
+[[clang::no_destroy]] static std::once_flag gSmOnce;
+sp<FakeServiceManager> gFakeServiceManager;
+
+bool addService(const String16& serviceName, const sp<FakeServiceManager>& fakeServiceManager,
+ FuzzedDataProvider& fdp) {
+ sp<IBinder> binder = getRandomBinder(&fdp);
+ if (binder == nullptr) {
+ return false;
+ }
+ CHECK_EQ(NO_ERROR, fakeServiceManager->addService(serviceName, binder));
+ return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+
+ std::call_once(gSmOnce, [&] {
+ /* Create a FakeServiceManager instance and add required services */
+ gFakeServiceManager = sp<FakeServiceManager>::make();
+ setDefaultServiceManager(gFakeServiceManager);
+ });
+ gFakeServiceManager->clear();
+
+ for (const char* service :
+ {"activity", "sensor_privacy", "permission", "scheduling_policy",
+ "android.hardware.audio.core.IConfig", "batterystats", "media.metrics"}) {
+ if (!addService(String16(service), gFakeServiceManager, fdp)) {
+ return 0;
+ }
+ }
+
+ const auto audioFlinger = sp<AudioFlinger>::make();
+ const auto afAdapter = sp<AudioFlingerServerAdapter>::make(audioFlinger);
+
+ CHECK_EQ(NO_ERROR,
+ gFakeServiceManager->addService(
+ String16(IAudioFlinger::DEFAULT_SERVICE_NAME), IInterface::asBinder(afAdapter),
+ false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+
+ AudioSystem::get_audio_flinger_for_fuzzer();
+ const auto audioPolicyService = sp<AudioPolicyService>::make();
+
+ CHECK_EQ(NO_ERROR,
+ gFakeServiceManager->addService(String16("media.audio_policy"), audioPolicyService,
+ false /* allowIsolated */,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT));
+
+ fuzzService(media::IAudioPolicyService::asBinder(audioPolicyService),
+ FuzzedDataProvider(data, size));
+
+ return 0;
+}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index cc32aec..e70af52 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1736,7 +1736,8 @@
// Compressed formats for MSD module, ordered from most preferred to least preferred.
static const std::vector<audio_format_t> formatsOrder = {{
AUDIO_FORMAT_IEC60958, AUDIO_FORMAT_MAT_2_1, AUDIO_FORMAT_MAT_2_0, AUDIO_FORMAT_E_AC3,
- AUDIO_FORMAT_AC3, AUDIO_FORMAT_PCM_16_BIT }};
+ AUDIO_FORMAT_AC3, AUDIO_FORMAT_PCM_FLOAT, AUDIO_FORMAT_PCM_32_BIT,
+ AUDIO_FORMAT_PCM_8_24_BIT, AUDIO_FORMAT_PCM_24_BIT_PACKED, AUDIO_FORMAT_PCM_16_BIT }};
static const std::vector<audio_channel_mask_t> channelMasksOrder = [](){
// Channel position masks for MSD module, 3D > 2D > 1D ordering (most preferred to least
// preferred).
@@ -6519,7 +6520,7 @@
mpClientInterface->setParameters(input, String8(param));
free(param);
}
- updateAudioProfiles(device, input, profile->getAudioProfiles());
+ updateAudioProfiles(device, input, profile);
if (!profile->hasValidAudioProfile()) {
ALOGW("checkInputsForDevice() direct input missing param");
desc->close();
@@ -8049,77 +8050,54 @@
void AudioPolicyManager::updateAudioProfiles(const sp<DeviceDescriptor>& devDesc,
audio_io_handle_t ioHandle,
- AudioProfileVector &profiles)
-{
- String8 reply;
- audio_devices_t device = devDesc->type();
-
- // Format MUST be checked first to update the list of AudioProfile
- if (profiles.hasDynamicFormat()) {
- reply = mpClientInterface->getParameters(
- ioHandle, String8(AudioParameter::keyStreamSupportedFormats));
- ALOGV("%s: supported formats %d, %s", __FUNCTION__, ioHandle, reply.c_str());
- AudioParameter repliedParameters(reply);
- FormatVector formats;
- if (repliedParameters.get(
- String8(AudioParameter::keyStreamSupportedFormats), reply) == NO_ERROR) {
- formats = formatsFromString(reply.c_str());
- } else if (devDesc->hasValidAudioProfile()) {
- ALOGD("%s: using the device profiles", __func__);
- formats = devDesc->getAudioProfiles().getSupportedFormats();
- } else {
- ALOGE("%s: failed to retrieve format, bailing out", __func__);
- return;
- }
- mReportedFormatsMap[devDesc] = formats;
- if (device == AUDIO_DEVICE_OUT_HDMI
- || isDeviceOfModule(devDesc, AUDIO_HARDWARE_MODULE_ID_MSD)) {
- modifySurroundFormats(devDesc, &formats);
- }
- addProfilesForFormats(profiles, formats);
+ const sp<IOProfile>& profile) {
+ if (!profile->hasDynamicAudioProfile()) {
+ return;
}
- for (audio_format_t format : profiles.getSupportedFormats()) {
- std::optional<ChannelMaskSet> channelMasks;
- SampleRateSet samplingRates;
- AudioParameter requestedParameters;
- requestedParameters.addInt(String8(AudioParameter::keyFormat), format);
+ audio_port_v7 devicePort;
+ devDesc->toAudioPort(&devicePort);
- if (profiles.hasDynamicRateFor(format)) {
- reply = mpClientInterface->getParameters(
- ioHandle,
- requestedParameters.toString() + ";" +
- AudioParameter::keyStreamSupportedSamplingRates);
- ALOGV("%s: supported sampling rates %s", __FUNCTION__, reply.c_str());
- AudioParameter repliedParameters(reply);
- if (repliedParameters.get(
- String8(AudioParameter::keyStreamSupportedSamplingRates), reply) == NO_ERROR) {
- samplingRates = samplingRatesFromString(reply.c_str());
- } else {
- samplingRates = devDesc->getAudioProfiles().getSampleRatesFor(format);
- }
- }
- if (profiles.hasDynamicChannelsFor(format)) {
- reply = mpClientInterface->getParameters(ioHandle,
- requestedParameters.toString() + ";" +
- AudioParameter::keyStreamSupportedChannels);
- ALOGV("%s: supported channel masks %s", __FUNCTION__, reply.c_str());
- AudioParameter repliedParameters(reply);
- if (repliedParameters.get(
- String8(AudioParameter::keyStreamSupportedChannels), reply) == NO_ERROR) {
- channelMasks = channelMasksFromString(reply.c_str());
- } else {
- channelMasks = devDesc->getAudioProfiles().getChannelMasksFor(format);
- }
- if (channelMasks.has_value() && (device == AUDIO_DEVICE_OUT_HDMI
- || isDeviceOfModule(devDesc, AUDIO_HARDWARE_MODULE_ID_MSD))) {
- modifySurroundChannelMasks(&channelMasks.value());
- }
- }
- addDynamicAudioProfileAndSort(
- profiles, new AudioProfile(
- format, channelMasks.value_or(ChannelMaskSet()), samplingRates));
+ audio_port_v7 mixPort;
+ profile->toAudioPort(&mixPort);
+ mixPort.ext.mix.handle = ioHandle;
+
+ status_t status = mpClientInterface->getAudioMixPort(&devicePort, &mixPort);
+ if (status != NO_ERROR) {
+ ALOGE("%s failed to query the attributes of the mix port", __func__);
+ return;
}
+
+ std::set<audio_format_t> supportedFormats;
+ for (size_t i = 0; i < mixPort.num_audio_profiles; ++i) {
+ supportedFormats.insert(mixPort.audio_profiles[i].format);
+ }
+ FormatVector formats(supportedFormats.begin(), supportedFormats.end());
+ mReportedFormatsMap[devDesc] = formats;
+
+ if (devDesc->type() == AUDIO_DEVICE_OUT_HDMI ||
+ isDeviceOfModule(devDesc,AUDIO_HARDWARE_MODULE_ID_MSD)) {
+ modifySurroundFormats(devDesc, &formats);
+ size_t modifiedNumProfiles = 0;
+ for (size_t i = 0; i < mixPort.num_audio_profiles; ++i) {
+ if (std::find(formats.begin(), formats.end(), mixPort.audio_profiles[i].format) ==
+ formats.end()) {
+ // Skip the format that is not present after modifying surround formats.
+ continue;
+ }
+ memcpy(&mixPort.audio_profiles[modifiedNumProfiles], &mixPort.audio_profiles[i],
+ sizeof(struct audio_profile));
+ ChannelMaskSet channels(mixPort.audio_profiles[modifiedNumProfiles].channel_masks,
+ mixPort.audio_profiles[modifiedNumProfiles].channel_masks +
+ mixPort.audio_profiles[modifiedNumProfiles].num_channel_masks);
+ modifySurroundChannelMasks(&channels);
+ std::copy(channels.begin(), channels.end(),
+ std::begin(mixPort.audio_profiles[modifiedNumProfiles].channel_masks));
+ mixPort.audio_profiles[modifiedNumProfiles++].num_channel_masks = channels.size();
+ }
+ mixPort.num_audio_profiles = modifiedNumProfiles;
+ }
+ profile->importAudioPort(mixPort);
}
status_t AudioPolicyManager::installPatch(const char *caller,
@@ -8246,7 +8224,7 @@
mpClientInterface->setParameters(output, String8(param));
free(param);
}
- updateAudioProfiles(device, output, profile->getAudioProfiles());
+ updateAudioProfiles(device, output, profile);
if (!profile->hasValidAudioProfile()) {
ALOGW("%s() missing param", __func__);
desc->close();
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 88bafef..440fd01 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -1040,9 +1040,9 @@
void modifySurroundFormats(const sp<DeviceDescriptor>& devDesc, FormatVector *formatsPtr);
void modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr);
- // If any, resolve any "dynamic" fields of an Audio Profiles collection
+ // If any, resolve any "dynamic" fields of the Audio Profiles collection of and IOProfile
void updateAudioProfiles(const sp<DeviceDescriptor>& devDesc, audio_io_handle_t ioHandle,
- AudioProfileVector &profiles);
+ const sp<IOProfile> &profiles);
// Notify the policy client to prepare for disconnecting external device.
void prepareToDisconnectExternalDevice(const sp<DeviceDescriptor> &device);
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 2874824..7584632 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -340,4 +340,14 @@
return af->invalidateTracks(portIds);
}
+status_t AudioPolicyService::AudioPolicyClient::getAudioMixPort(
+ const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *port) {
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ return PERMISSION_DENIED;
+ }
+ return af->getAudioMixPort(devicePort, port);
+}
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index d0cde64..8d5628f 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -856,6 +856,9 @@
status_t invalidateTracks(const std::vector<audio_port_handle_t>& portIds) override;
+ status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *port) override;
+
private:
AudioPolicyService *mAudioPolicyService;
};
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index 3629c16..7ef0266 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -201,6 +201,26 @@
return mAudioParameters.toString();
}
+ status_t getAudioMixPort(const struct audio_port_v7 *devicePort __unused,
+ struct audio_port_v7 *mixPort) override {
+ mixPort->num_audio_profiles = 0;
+ for (auto format : mSupportedFormats) {
+ const int i = mixPort->num_audio_profiles;
+ mixPort->audio_profiles[i].format = format;
+ mixPort->audio_profiles[i].num_sample_rates = 1;
+ mixPort->audio_profiles[i].sample_rates[0] = 48000;
+ mixPort->audio_profiles[i].num_channel_masks = 0;
+ for (const auto& cm : mSupportedChannelMasks) {
+ if (audio_channel_mask_is_valid(cm)) {
+ mixPort->audio_profiles[i].channel_masks[
+ mixPort->audio_profiles[i].num_channel_masks++] = cm;
+ }
+ }
+ mixPort->num_audio_profiles++;
+ }
+ return NO_ERROR;
+ }
+
void addSupportedFormat(audio_format_t format) {
mSupportedFormats.insert(format);
}
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 2ae0e97..e55e935 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -106,6 +106,10 @@
status_t invalidateTracks(const std::vector<audio_port_handle_t>& /*portIds*/) override {
return NO_INIT;
}
+ status_t getAudioMixPort(const struct audio_port_v7 *devicePort __unused,
+ struct audio_port_v7 *mixPort __unused) override {
+ return INVALID_OPERATION;
+ }
};
} // namespace android
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 5e58dbb..378255d 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -1423,6 +1423,7 @@
ASSERT_NO_FATAL_FAILURE(AudioPolicyManagerTest::SetUp());
mClient->addSupportedFormat(AUDIO_FORMAT_AC3);
mClient->addSupportedFormat(AUDIO_FORMAT_E_AC3);
+ mClient->addSupportedChannelMask(AUDIO_CHANNEL_OUT_STEREO);
mManager->setDeviceConnectionState(
AUDIO_DEVICE_OUT_HDMI, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
"" /*address*/, "" /*name*/, AUDIO_FORMAT_DEFAULT);
@@ -1548,13 +1549,13 @@
mManager->setForceUse(
AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND, AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL);
- ASSERT_EQ(NO_ERROR, mManager->setSurroundFormatEnabled(GetParam(), false /*enabled*/));
- auto formats = getFormatsFromPorts();
- ASSERT_EQ(0, formats.count(GetParam()));
-
ASSERT_EQ(NO_ERROR, mManager->setSurroundFormatEnabled(GetParam(), true /*enabled*/));
- formats = getFormatsFromPorts();
+ auto formats = getFormatsFromPorts();
ASSERT_EQ(1, formats.count(GetParam()));
+
+ ASSERT_EQ(NO_ERROR, mManager->setSurroundFormatEnabled(GetParam(), false /*enabled*/));
+ formats = getFormatsFromPorts();
+ ASSERT_EQ(0, formats.count(GetParam()));
}
TEST_P(AudioPolicyManagerTestForHdmi,