diff options
55 files changed, 584 insertions, 275 deletions
diff --git a/camera/Android.bp b/camera/Android.bp index 22f1633dc5..4c5b16069c 100644 --- a/camera/Android.bp +++ b/camera/Android.bp @@ -46,6 +46,7 @@ license { aconfig_declarations { name: "camera_platform_flags", package: "com.android.internal.camera.flags", + container: "system", srcs: ["camera_platform.aconfig"], } diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig index 5d2a26346a..46a4cf2352 100644 --- a/camera/camera_platform.aconfig +++ b/camera/camera_platform.aconfig @@ -1,4 +1,5 @@ package: "com.android.internal.camera.flags" +container: "system" flag { namespace: "camera_platform" diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING index d38859693a..fd46b5ba32 100644 --- a/media/TEST_MAPPING +++ b/media/TEST_MAPPING @@ -48,7 +48,7 @@ // Postsubmit tests for TV devices "tv-postsubmit": [ { - "name": "DecoderRenderTest" + "name": "android.media.decoder.cts.DecoderRenderTest" } ] } diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig index b3c02ebcd9..9f64a2881a 100644 --- a/media/aconfig/codec_fwk.aconfig +++ b/media/aconfig/codec_fwk.aconfig @@ -101,7 +101,17 @@ flag { name: "set_state_early" namespace: "codec_fwk" description: "Bugfix flag for setting state early to avoid a race condition" - bug: "298613711" + bug: "298613712" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "stop_hal_before_surface" + namespace: "codec_fwk" + description: "Bugfix flag for setting state early to avoid a race condition" + bug: "339247977" metadata { purpose: PURPOSE_BUGFIX } diff --git a/media/audio/aconfig/Android.bp b/media/audio/aconfig/Android.bp index b1d4ad4b9e..2f659a223d 100644 --- a/media/audio/aconfig/Android.bp +++ b/media/audio/aconfig/Android.bp @@ -8,18 +8,21 @@ cc_defaults { aconfig_declarations { name: "com.android.media.audioserver-aconfig", package: "com.android.media.audioserver", + container: "system", srcs: ["audioserver.aconfig"], } aconfig_declarations { name: "com.android.media.audio-aconfig", package: "com.android.media.audio", + container: "system", srcs: ["audio.aconfig"], } aconfig_declarations { name: "com.android.media.aaudio-aconfig", package: "com.android.media.aaudio", + container: "system", srcs: ["aaudio.aconfig"], } @@ -63,6 +66,7 @@ java_aconfig_library { aconfig_declarations { name: "android.media.audio-aconfig", package: "android.media.audio", + container: "system", srcs: ["audio_framework.aconfig"], visibility: ["//visibility:private"], } @@ -70,6 +74,7 @@ aconfig_declarations { aconfig_declarations { name: "android.media.audiopolicy-aconfig", package: "android.media.audiopolicy", + container: "system", srcs: ["audiopolicy_framework.aconfig"], visibility: ["//visibility:private"], } @@ -77,6 +82,7 @@ aconfig_declarations { aconfig_declarations { name: "android.media.midi-aconfig", package: "android.media.midi", + container: "system", srcs: ["midi_flags.aconfig"], visibility: ["//visibility:private"], } diff --git a/media/audio/aconfig/aaudio.aconfig b/media/audio/aconfig/aaudio.aconfig index 7196525acd..c1601098b4 100644 --- a/media/audio/aconfig/aaudio.aconfig +++ b/media/audio/aconfig/aaudio.aconfig @@ -3,6 +3,7 @@ # Please add flags in alphabetical order. package: "com.android.media.aaudio" +container: "system" flag { name: "sample_rate_conversion" diff --git a/media/audio/aconfig/audio.aconfig b/media/audio/aconfig/audio.aconfig index 73cb8cad14..8ca4f9e5cc 100644 --- a/media/audio/aconfig/audio.aconfig +++ b/media/audio/aconfig/audio.aconfig @@ -3,6 +3,7 @@ # Please add flags in alphabetical order. package: "com.android.media.audio" +container: "system" flag { name: "alarm_min_volume_zero" diff --git a/media/audio/aconfig/audiopolicy_framework.aconfig b/media/audio/aconfig/audiopolicy_framework.aconfig index 833730a8ff..80e64adadf 100644 --- a/media/audio/aconfig/audiopolicy_framework.aconfig +++ b/media/audio/aconfig/audiopolicy_framework.aconfig @@ -4,6 +4,7 @@ # Please add flags in alphabetical order. package: "android.media.audiopolicy" +container: "system" flag { name: "audio_policy_update_mixing_rules_api" diff --git a/media/audio/aconfig/audioserver.aconfig b/media/audio/aconfig/audioserver.aconfig index 21ea1a2b18..5c6504f70b 100644 --- a/media/audio/aconfig/audioserver.aconfig +++ b/media/audio/aconfig/audioserver.aconfig @@ -3,6 +3,7 @@ # Please add flags in alphabetical order. package: "com.android.media.audioserver" +container: "system" flag { name: "direct_track_reprioritization" diff --git a/media/audio/aconfig/midi_flags.aconfig b/media/audio/aconfig/midi_flags.aconfig index ff9238a0f3..efb643f14e 100644 --- a/media/audio/aconfig/midi_flags.aconfig +++ b/media/audio/aconfig/midi_flags.aconfig @@ -4,6 +4,7 @@ # Please add flags in alphabetical order. package: "android.media.midi" +container: "system" flag { name: "virtual_ump" diff --git a/media/codec2/hal/aidl/Android.bp b/media/codec2/hal/aidl/Android.bp index 48b6e21535..e16e2b1726 100644 --- a/media/codec2/hal/aidl/Android.bp +++ b/media/codec2/hal/aidl/Android.bp @@ -8,6 +8,7 @@ cc_library { name: "libcodec2_aidl_client", defaults: [ + "aconfig_lib_cc_static_link.defaults", "libcodec2_hal_selection", ], @@ -65,6 +66,7 @@ cc_library { ], defaults: [ + "aconfig_lib_cc_static_link.defaults", "libcodec2_hal_selection", ], diff --git a/media/codec2/hal/client/GraphicsTracker.cpp b/media/codec2/hal/client/GraphicsTracker.cpp index 1c2a0fb7d8..dbbabfeb26 100644 --- a/media/codec2/hal/client/GraphicsTracker.cpp +++ b/media/codec2/hal/client/GraphicsTracker.cpp @@ -173,7 +173,7 @@ void GraphicsTracker::BufferCache::unblockSlot(int slot) { } GraphicsTracker::GraphicsTracker(int maxDequeueCount) - : mBufferCache(new BufferCache()), mMaxDequeue{maxDequeueCount}, + : mBufferCache(new BufferCache()), mNumDequeueing{0}, mMaxDequeue{maxDequeueCount}, mMaxDequeueCommitted{maxDequeueCount}, mDequeueable{maxDequeueCount}, mTotalDequeued{0}, mTotalCancelled{0}, mTotalDropped{0}, mTotalReleased{0}, @@ -235,6 +235,7 @@ c2_status_t GraphicsTracker::configureGraphics( const sp<IGraphicBufferProducer>& igbp, uint32_t generation) { // TODO: wait until operations to previous IGBP is completed. std::shared_ptr<BufferCache> prevCache; + int prevDequeueRequested = 0; int prevDequeueCommitted; std::unique_lock<std::mutex> cl(mConfigLock); @@ -243,6 +244,9 @@ c2_status_t GraphicsTracker::configureGraphics( mInConfig = true; prevCache = mBufferCache; prevDequeueCommitted = mMaxDequeueCommitted; + if (mMaxDequeueRequested.has_value()) { + prevDequeueRequested = mMaxDequeueRequested.value(); + } } // NOTE: Switching to the same surface is blocked from MediaCodec. // Switching to the same surface might not work if tried, since disconnect() @@ -263,6 +267,11 @@ c2_status_t GraphicsTracker::configureGraphics( mInConfig = false; return C2_BAD_VALUE; } + ALOGD("new surface in configuration: maxDequeueRequested(%d), maxDequeueCommitted(%d)", + prevDequeueRequested, prevDequeueCommitted); + if (prevDequeueRequested > 0 && prevDequeueRequested > prevDequeueCommitted) { + prevDequeueCommitted = prevDequeueRequested; + } if (igbp) { ret = igbp->setMaxDequeuedBufferCount(prevDequeueCommitted); if (ret != ::android::OK) { @@ -280,6 +289,34 @@ c2_status_t GraphicsTracker::configureGraphics( std::unique_lock<std::mutex> l(mLock); mInConfig = false; mBufferCache = newCache; + // {@code dequeued} is the number of currently dequeued buffers. + // {@code prevDequeueCommitted} is max dequeued buffer at any moment + // from the new surface. + // {@code newDequeueable} is hence the current # of dequeueable buffers + // if no change occurs. + int dequeued = mDequeued.size() + mNumDequeueing; + int newDequeueable = prevDequeueCommitted - dequeued; + if (newDequeueable < 0) { + // This will not happen. + // But if this happens, we respect the value and try to continue. + ALOGE("calculated new dequeueable is negative: %d max(%d),dequeued(%d)", + newDequeueable, prevDequeueCommitted, dequeued); + } + + if (mMaxDequeueRequested.has_value() && mMaxDequeueRequested == prevDequeueCommitted) { + mMaxDequeueRequested.reset(); + } + mMaxDequeue = mMaxDequeueCommitted = prevDequeueCommitted; + + int delta = newDequeueable - mDequeueable; + if (delta > 0) { + writeIncDequeueableLocked(delta); + } else if (delta < 0) { + drainDequeueableLocked(-delta); + } + ALOGV("new surfcace dequeueable %d(delta %d), maxDequeue %d", + newDequeueable, delta, mMaxDequeue); + mDequeueable = newDequeueable; } return C2_OK; } @@ -529,6 +566,7 @@ c2_status_t GraphicsTracker::requestAllocate(std::shared_ptr<BufferCache> *cache ALOGE("writing end for the waitable object seems to be closed"); return C2_BAD_STATE; } + mNumDequeueing++; mDequeueable--; *cache = mBufferCache; return C2_OK; @@ -543,6 +581,7 @@ void GraphicsTracker::commitAllocate(c2_status_t res, const std::shared_ptr<Buff bool cached, int slot, const sp<Fence> &fence, std::shared_ptr<BufferItem> *pBuffer, bool *updateDequeue) { std::unique_lock<std::mutex> l(mLock); + mNumDequeueing--; if (res == C2_OK) { if (cached) { auto it = cache->mBuffers.find(slot); @@ -655,7 +694,8 @@ c2_status_t GraphicsTracker::_allocate(const std::shared_ptr<BufferCache> &cache ALOGE("allocate by dequeueBuffer() successful, but requestBuffer() failed %d", status); igbp->cancelBuffer(slotId, fence); - return C2_CORRUPTED; + // This might be due to life-cycle end and/or surface switching. + return C2_BLOCKING; } *buffer = std::make_shared<BufferItem>(generation, slotId, realloced, fence); if (!*buffer) { diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h index dd6c8694ea..762030b3ed 100644 --- a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h +++ b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h @@ -234,6 +234,7 @@ private: // Maps bufferId to buffer std::map<uint64_t, std::shared_ptr<BufferItem>> mDequeued; std::set<uint64_t> mDeallocating; + int mNumDequeueing; // These member variables are read and modified accessed as follows. // 1. mConfigLock being held diff --git a/media/codec2/hal/common/Android.bp b/media/codec2/hal/common/Android.bp index 7d7b28545a..4c9da33c3c 100644 --- a/media/codec2/hal/common/Android.bp +++ b/media/codec2/hal/common/Android.bp @@ -31,6 +31,10 @@ cc_library { ], static_libs: ["aconfig_mediacodec_flags_c_lib"], + + defaults: [ + "aconfig_lib_cc_static_link.defaults", + ], } cc_library_static { diff --git a/media/codec2/hal/common/MultiAccessUnitHelper.cpp b/media/codec2/hal/common/MultiAccessUnitHelper.cpp index 8086ef20eb..b1fa82fe5f 100644 --- a/media/codec2/hal/common/MultiAccessUnitHelper.cpp +++ b/media/codec2/hal/common/MultiAccessUnitHelper.cpp @@ -27,6 +27,7 @@ #include <C2Debug.h> #include <C2PlatformSupport.h> +static inline constexpr uint32_t MAX_SUPPORTED_SIZE = ( 10 * 512000 * 8 * 2u); namespace android { static C2R MultiAccessUnitParamsSetter( @@ -39,8 +40,6 @@ static C2R MultiAccessUnitParamsSetter( res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.thresholdSize))); } else if (me.v.maxSize < me.v.thresholdSize) { me.set().maxSize = me.v.thresholdSize; - } else if (me.v.thresholdSize == 0 && me.v.maxSize > 0) { - me.set().thresholdSize = me.v.maxSize; } std::vector<std::unique_ptr<C2SettingResult>> failures; res.retrieveFailures(&failures); @@ -61,9 +60,9 @@ MultiAccessUnitInterface::MultiAccessUnitInterface( .withDefault(new C2LargeFrame::output(0u, 0, 0)) .withFields({ C2F(mLargeFrameParams, maxSize).inRange( - 0, c2_min(UINT_MAX, 10 * 512000 * 8 * 2u)), + 0, c2_min(UINT_MAX, MAX_SUPPORTED_SIZE)), C2F(mLargeFrameParams, thresholdSize).inRange( - 0, c2_min(UINT_MAX, 10 * 512000 * 8 * 2u)) + 0, c2_min(UINT_MAX, MAX_SUPPORTED_SIZE)) }) .withSetter(MultiAccessUnitParamsSetter) .build()); @@ -115,6 +114,18 @@ bool MultiAccessUnitInterface::getDecoderSampleRateAndChannelCount( return false; } +bool MultiAccessUnitInterface::getMaxInputSize( + C2StreamMaxBufferSizeInfo::input* const maxInputSize) const { + if (maxInputSize == nullptr || mC2ComponentIntf == nullptr) { + return false; + } + c2_status_t err = mC2ComponentIntf->query_vb({maxInputSize}, {}, C2_MAY_BLOCK, nullptr); + if (err != OK) { + return false; + } + return true; +} + //C2MultiAccessUnitBuffer class C2MultiAccessUnitBuffer : public C2Buffer { public: @@ -128,6 +139,7 @@ class C2MultiAccessUnitBuffer : public C2Buffer { MultiAccessUnitHelper::MultiAccessUnitHelper( const std::shared_ptr<MultiAccessUnitInterface>& intf, std::shared_ptr<C2BlockPool>& linearPool): + mMultiAccessOnOffAllowed(true), mInit(false), mInterface(intf), mLinearPool(linearPool) { @@ -152,6 +164,63 @@ bool MultiAccessUnitHelper::isEnabledOnPlatform() { return result; } +bool MultiAccessUnitHelper::tryReconfigure(const std::unique_ptr<C2Param> ¶m) { + C2LargeFrame::output *lfp = C2LargeFrame::output::From(param.get()); + if (lfp == nullptr) { + return false; + } + bool isDecoder = (mInterface->kind() == C2Component::KIND_DECODER) ? true : false; + if (!isDecoder) { + C2StreamMaxBufferSizeInfo::input maxInputSize(0); + if (!mInterface->getMaxInputSize(&maxInputSize)) { + LOG(ERROR) << "Error in reconfigure: " + << "Encoder failed to respond with a valid max input size"; + return false; + } + // This is assuming a worst case compression ratio of 1:1 + // In no case the encoder should give an output more than + // what is being provided to the encoder in a single call. + if (lfp->maxSize < maxInputSize.value) { + lfp->maxSize = maxInputSize.value; + } + } + lfp->maxSize = + (lfp->maxSize > MAX_SUPPORTED_SIZE) ? MAX_SUPPORTED_SIZE : + (lfp->maxSize < 0) ? 0 : lfp->maxSize; + lfp->thresholdSize = + (lfp->thresholdSize > MAX_SUPPORTED_SIZE) ? MAX_SUPPORTED_SIZE : + (lfp->thresholdSize < 0) ? 0 : lfp->thresholdSize; + C2LargeFrame::output currentConfig = mInterface->getLargeFrameParam(); + if ((currentConfig.maxSize == lfp->maxSize) + && (currentConfig.thresholdSize == lfp->thresholdSize)) { + // no need to update + return false; + } + if (isDecoder) { + bool isOnOffTransition = + (currentConfig.maxSize == 0 && lfp->maxSize != 0) + || (currentConfig.maxSize != 0 && lfp->maxSize == 0); + if (isOnOffTransition && !mMultiAccessOnOffAllowed) { + LOG(ERROR) << "Setting new configs not allowed" + << " MaxSize: " << lfp->maxSize + << " ThresholdSize: " << lfp->thresholdSize; + return false; + } + } + std::vector<C2Param*> config{lfp}; + std::vector<std::unique_ptr<C2SettingResult>> failures; + if (C2_OK != mInterface->config(config, C2_MAY_BLOCK, &failures)) { + LOG(ERROR) << "Dynamic config not applied for" + << " MaxSize: " << lfp->maxSize + << " ThresholdSize: " << lfp->thresholdSize; + return false; + } + LOG(DEBUG) << "Updated from param maxSize " + << lfp->maxSize + << " ThresholdSize " << lfp->thresholdSize; + return true; +} + std::shared_ptr<MultiAccessUnitInterface> MultiAccessUnitHelper::getInterface() { return mInterface; } @@ -163,6 +232,7 @@ bool MultiAccessUnitHelper::getStatus() { void MultiAccessUnitHelper::reset() { std::lock_guard<std::mutex> l(mLock); mFrameHolder.clear(); + mMultiAccessOnOffAllowed = true; } c2_status_t MultiAccessUnitHelper::error( @@ -181,6 +251,7 @@ c2_status_t MultiAccessUnitHelper::error( } } mFrameHolder.clear(); + mMultiAccessOnOffAllowed = true; return C2_OK; } @@ -232,16 +303,23 @@ c2_status_t MultiAccessUnitHelper::scatter( uint64_t newFrameIdx = mFrameIndex++; // TODO: Do not split buffers if component inherantly supports MultipleFrames. // if thats case, only replace frameindex. - auto cloneInputWork = [&newFrameIdx](std::unique_ptr<C2Work>& inWork, uint32_t flags) { + auto cloneInputWork = [&frameInfo, &newFrameIdx, this] + (std::unique_ptr<C2Work>& inWork, uint32_t flags) -> std::unique_ptr<C2Work> { std::unique_ptr<C2Work> newWork(new C2Work); newWork->input.flags = (C2FrameData::flags_t)flags; newWork->input.ordinal = inWork->input.ordinal; newWork->input.ordinal.frameIndex = newFrameIdx; if (!inWork->input.configUpdate.empty()) { for (std::unique_ptr<C2Param>& param : inWork->input.configUpdate) { - newWork->input.configUpdate.push_back( - std::move(C2Param::Copy(*(param.get())))); + if (param->index() == C2LargeFrame::output::PARAM_TYPE) { + if (tryReconfigure(param)) { + frameInfo.mConfigUpdate.push_back(std::move(param)); + } + } else { + newWork->input.configUpdate.push_back(std::move(param)); + } } + inWork->input.configUpdate.clear(); } newWork->input.infoBuffers = (inWork->input.infoBuffers); if (!inWork->worklets.empty() && inWork->worklets.front() != nullptr) { @@ -331,6 +409,7 @@ c2_status_t MultiAccessUnitHelper::scatter( frameInfo.mLargeFrameTuning = multiAccessParams; std::lock_guard<std::mutex> l(mLock); mFrameHolder.push_back(std::move(frameInfo)); + mMultiAccessOnOffAllowed = false; } } return C2_OK; @@ -360,6 +439,7 @@ c2_status_t MultiAccessUnitHelper::gather( std::list<MultiAccessUnitInfo>::iterator frame = mFrameHolder.begin(); while (!foundFrame && frame != mFrameHolder.end()) { + c2_status_t res = C2_OK; auto it = frame->mComponentFrameIds.find(thisFrameIndex); if (it != frame->mComponentFrameIds.end()) { foundFrame = true; @@ -369,8 +449,7 @@ c2_status_t MultiAccessUnitHelper::gather( if (work->result != C2_OK || work->worklets.empty() || !work->worklets.front() - || (frame->mLargeFrameTuning.thresholdSize == 0 - || frame->mLargeFrameTuning.maxSize == 0)) { + || frame->mLargeFrameTuning.maxSize == 0) { if (removeEntry) { frame->mComponentFrameIds.erase(it); removeEntry = false; @@ -388,10 +467,27 @@ c2_status_t MultiAccessUnitHelper::gather( addOutWork(frame->mLargeWork); frame->reset(); if (workResult != C2_OK) { - frame->mAccessUnitInfos.clear(); + frame->mComponentFrameIds.clear(); + removeEntry = false; } - } else if (C2_OK != processWorklets(*frame, work, addOutWork)) { - LOG(DEBUG) << "Error while processing work"; + } else if (C2_OK != (res = processWorklets(*frame, work, addOutWork))) { + // Upon error in processing worklets, we return the work with + // result set to the error. This should indicate the error to the + // framework and thus doing what is necessary to handle the + // error. + LOG(DEBUG) << "Error while processing worklets"; + if (frame->mLargeWork == nullptr) { + frame->mLargeWork.reset(new C2Work); + frame->mLargeWork->input.ordinal = frame->inOrdinal; + frame->mLargeWork->input.ordinal.frameIndex = + frame->inOrdinal.frameIndex; + } + frame->mLargeWork->result = res; + finalizeWork(*frame); + addOutWork(frame->mLargeWork); + frame->reset(); + frame->mComponentFrameIds.clear(); + removeEntry = false; } if (removeEntry) { LOG(DEBUG) << "Removing entry: " << thisFrameIndex @@ -528,9 +624,6 @@ c2_status_t MultiAccessUnitHelper::processWorklets(MultiAccessUnitInfo &frame, LOG(DEBUG) << "maxOutSize " << frame.mLargeFrameTuning.maxSize << " threshold " << frame.mLargeFrameTuning.thresholdSize; - if ((*worklet)->output.buffers.size() > 0) { - allocateWork(frame, true, true); - } LOG(DEBUG) << "This worklet has " << (*worklet)->output.buffers.size() << " buffers" << " ts: " << (*worklet)->output.ordinal.timestamp.peekull(); int64_t workletTimestamp = (*worklet)->output.ordinal.timestamp.peekull(); @@ -552,43 +645,39 @@ c2_status_t MultiAccessUnitHelper::processWorklets(MultiAccessUnitInfo &frame, inputSize -= (inputSize % frameSize); } while (inputOffset < inputSize) { - if (frame.mWview->offset() >= frame.mLargeFrameTuning.thresholdSize) { + if ((frame.mWview != nullptr) + && (frame.mWview->offset() >= frame.mLargeFrameTuning.thresholdSize)) { frame.mLargeWork->result = C2_OK; finalizeWork(frame, flagsForCopy); addWork(frame.mLargeWork); frame.reset(); - allocateWork(frame, true, true); } if (mInterface->kind() == C2Component::KIND_ENCODER) { if (inputSize > frame.mLargeFrameTuning.maxSize) { - LOG(ERROR) << "Enc: Output buffer too small for AU, configured with " - << frame.mLargeFrameTuning.maxSize - << " block size: " << blocks.front().size() - << "alloc size " << frame.mWview->size(); - if (frame.mLargeWork - && frame.mWview && frame.mWview->offset() > 0) { + LOG(WARNING) << "WARNING Encoder:" + << " Output buffer too small for configuration" + << " configured max size " << frame.mLargeFrameTuning.maxSize + << " access unit size " << inputSize; + if (frame.mLargeWork && (frame.mWview && frame.mWview->offset() > 0)) { + frame.mLargeWork->result = C2_OK; finalizeWork(frame, flagsForCopy); addWork(frame.mLargeWork); frame.reset(); - allocateWork(frame, true, false); } - frame.mLargeWork->result = C2_NO_MEMORY; - finalizeWork(frame, 0, true); - addWork(frame.mLargeWork); - frame.reset(); - return C2_NO_MEMORY; - } else if (inputSize > frame.mWview->size()) { + frame.mLargeFrameTuning.maxSize = inputSize; + } else if ((frame.mWview != nullptr) + && (inputSize > frame.mWview->size())) { LOG(DEBUG) << "Enc: Large frame hitting bufer limit, current size " << frame.mWview->offset(); - if (frame.mLargeWork - && frame.mWview && frame.mWview->offset() > 0) { + if (frame.mWview->offset() > 0) { + frame.mLargeWork->result = C2_OK; finalizeWork(frame, flagsForCopy); addWork(frame.mLargeWork); frame.reset(); - allocateWork(frame, true, true); } } } + allocateWork(frame, true, true); C2ReadView rView = blocks.front().map().get(); if (rView.error()) { LOG(ERROR) << "Buffer read view error"; @@ -683,26 +772,39 @@ c2_status_t MultiAccessUnitHelper::finalizeWork( frame.mWview->setOffset(0); std::shared_ptr<C2Buffer> c2Buffer = C2Buffer::CreateLinearBuffer( frame.mBlock->share(0, size, ::C2Fence())); - if (frame.mAccessUnitInfos.size() > 0) { - if (finalFlags & C2FrameData::FLAG_END_OF_STREAM) { - frame.mAccessUnitInfos.back().flags |= - C2FrameData::FLAG_END_OF_STREAM; + frame.mLargeWork->worklets.front()->output.buffers.push_back(std::move(c2Buffer)); + } + if (frame.mLargeWork->worklets.front()->output.buffers.size() > 0) { + std::shared_ptr<C2Buffer>& c2Buffer = + frame.mLargeWork->worklets.front()->output.buffers.front(); + if (c2Buffer != nullptr) { + if (frame.mAccessUnitInfos.size() > 0) { + if (finalFlags & C2FrameData::FLAG_END_OF_STREAM) { + frame.mAccessUnitInfos.back().flags |= C2FrameData::FLAG_END_OF_STREAM; + } + std::shared_ptr<C2AccessUnitInfos::output> largeFrame = + C2AccessUnitInfos::output::AllocShared( + frame.mAccessUnitInfos.size(), 0u, frame.mAccessUnitInfos); + frame.mInfos.push_back(largeFrame); + frame.mAccessUnitInfos.clear(); + } + for (auto &info : frame.mInfos) { + c2Buffer->setInfo(std::const_pointer_cast<C2Info>(info)); } - std::shared_ptr<C2AccessUnitInfos::output> largeFrame = - C2AccessUnitInfos::output::AllocShared( - frame.mAccessUnitInfos.size(), 0u, frame.mAccessUnitInfos); - frame.mInfos.push_back(largeFrame); - frame.mAccessUnitInfos.clear(); - } - for (auto &info : frame.mInfos) { - c2Buffer->setInfo(std::const_pointer_cast<C2Info>(info)); } - frame.mLargeWork->worklets.front()->output.buffers.push_back(std::move(c2Buffer)); - frame.mInfos.clear(); - frame.mBlock.reset(); - frame.mWview.reset(); + } + if (frame.mConfigUpdate.size() > 0) { + outFrameData.configUpdate.insert( + outFrameData.configUpdate.end(), + make_move_iterator(frame.mConfigUpdate.begin()), + make_move_iterator(frame.mConfigUpdate.end())); } } + frame.mConfigUpdate.clear(); + frame.mInfos.clear(); + frame.mBlock.reset(); + frame.mWview.reset(); + LOG(DEBUG) << "Multi access-unitflag setting as " << finalFlags; return C2_OK; } @@ -735,6 +837,7 @@ void MultiAccessUnitHelper::MultiAccessUnitInfo::reset() { mBlock.reset(); mWview.reset(); mInfos.clear(); + mConfigUpdate.clear(); mAccessUnitInfos.clear(); mLargeWork.reset(); } diff --git a/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h b/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h index bb4464c197..070a1f5fc1 100644 --- a/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h +++ b/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h @@ -46,6 +46,7 @@ struct MultiAccessUnitInterface : public C2InterfaceHelper { protected: bool getDecoderSampleRateAndChannelCount( uint32_t * const sampleRate_, uint32_t * const channelCount_) const; + bool getMaxInputSize(C2StreamMaxBufferSizeInfo::input* const maxInputSize) const; const std::shared_ptr<C2ComponentInterface> mC2ComponentIntf; std::shared_ptr<C2LargeFrame::output> mLargeFrameParams; C2ComponentKindSetting mKind; @@ -140,6 +141,11 @@ protected: std::vector<std::shared_ptr<const C2Info>> mInfos; /* + * Vector for holding config updates from the wrapper + */ + std::vector<std::unique_ptr<C2Param>> mConfigUpdate; + + /* * C2AccessUnitInfos for the current buffer */ std::vector<C2AccessUnitInfosStruct> mAccessUnitInfos; @@ -170,6 +176,11 @@ protected: }; /* + * Reconfigure helper + */ + bool tryReconfigure(const std::unique_ptr<C2Param> &p); + + /* * Creates a linear block to be used with work */ c2_status_t createLinearBlock(MultiAccessUnitInfo &frame); @@ -195,6 +206,14 @@ protected: uint32_t size, int64_t timestamp); + // Flag to allow dynamic on/off settings on this helper. + // Once enabled and buffers in transit, it is not possible + // to turn this module off by setting the max output value + // to 0. This is because the skip cut buffer expects the + // metadata to be always present along with a valid buffer. + // This flag is used to monitor that state of this module. + bool mMultiAccessOnOffAllowed; + bool mInit; // Interface of this module diff --git a/media/codec2/hal/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp index ab47b7c5d0..36907e1c69 100644 --- a/media/codec2/hal/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp +++ b/media/codec2/hal/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp @@ -263,9 +263,6 @@ TEST_P(Codec2ComponentHidlTest, Timeout) { ALOGV("mComponent->reset() timeConsumed=%" PRId64 " us", timeConsumed); ASSERT_EQ(err, C2_OK); - err = mComponent->start(); - ASSERT_EQ(err, C2_OK); - // Query supported params by the component std::vector<std::shared_ptr<C2ParamDescriptor>> params; startTime = getNowUs(); @@ -298,6 +295,9 @@ TEST_P(Codec2ComponentHidlTest, Timeout) { timeConsumed); } + err = mComponent->start(); + ASSERT_EQ(err, C2_OK); + std::list<std::unique_ptr<C2Work>> workList; startTime = getNowUs(); err = mComponent->queue(&workList); diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp index 362373e3cf..7076bacda9 100644 --- a/media/codec2/sfplugin/Android.bp +++ b/media/codec2/sfplugin/Android.bp @@ -91,6 +91,10 @@ cc_library_shared { "libcodec2_client", ], + defaults: [ + "aconfig_lib_cc_static_link.defaults", + ], + sanitize: { cfi: true, misc_undefined: [ diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp index 463b63fc7b..20b6d7f719 100644 --- a/media/codec2/sfplugin/CCodec.cpp +++ b/media/codec2/sfplugin/CCodec.cpp @@ -2227,8 +2227,17 @@ void CCodec::stop(bool pushBlankBuffer) { // 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(); + // + // The workaround is no longer needed with fetchGraphicBlock & C2Fence changes. + // so we are reverting back to the logical sequence of the operations. + status_t err = C2_OK; + if (android::media::codec::provider_->stop_hal_before_surface()) { + err = comp->stop(); + mChannel->stopUseOutputSurface(pushBlankBuffer); + } else { + mChannel->stopUseOutputSurface(pushBlankBuffer); + err = comp->stop(); + } if (err != C2_OK) { // TODO: convert err into status_t mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); @@ -2323,8 +2332,16 @@ void CCodec::release(bool sendCallback, bool pushBlankBuffer) { // So we reverse their order for stopUseOutputSurface() to notify C2Fence waiters // prior to comp->release(). // See also b/300350761. - mChannel->stopUseOutputSurface(pushBlankBuffer); - comp->release(); + // + // The workaround is no longer needed with fetchGraphicBlock & C2Fence changes. + // so we are reverting back to the logical sequence of the operations. + if (android::media::codec::provider_->stop_hal_before_surface()) { + comp->release(); + mChannel->stopUseOutputSurface(pushBlankBuffer); + } else { + mChannel->stopUseOutputSurface(pushBlankBuffer); + comp->release(); + } { Mutexed<State>::Locked state(mState); diff --git a/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp b/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp index 77a76e8584..7a33af4096 100644 --- a/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp +++ b/media/codec2/sfplugin/utils/Codec2CommonUtils.cpp @@ -32,10 +32,15 @@ namespace android { -static bool isAtLeast(int version, const char *codeName) { - char deviceCodeName[PROP_VALUE_MAX]; - __system_property_get("ro.build.version.codename", deviceCodeName); - return android_get_device_api_level() >= version || !strcmp(deviceCodeName, codeName); +static bool isAtLeast(int version, const std::string codeName) { + static std::once_flag sCheckOnce; + static std::string sDeviceCodeName; + static int sDeviceApiLevel; + std::call_once(sCheckOnce, [&](){ + sDeviceCodeName = base::GetProperty("ro.build.version.codename", ""); + sDeviceApiLevel = android_get_device_api_level(); + }); + return sDeviceApiLevel >= version || sDeviceCodeName == codeName; } bool isAtLeastT() { diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp index 9f57bfd1c2..dc06ee6400 100644 --- a/media/codec2/vndk/Android.bp +++ b/media/codec2/vndk/Android.bp @@ -53,6 +53,7 @@ cc_library { ], defaults: [ + "aconfig_lib_cc_static_link.defaults", "libcodec2_hal_selection", ], diff --git a/media/libaudioclient/aidl/fuzzer/Android.bp b/media/libaudioclient/aidl/fuzzer/Android.bp index 02c865d0d0..1071beb542 100644 --- a/media/libaudioclient/aidl/fuzzer/Android.bp +++ b/media/libaudioclient/aidl/fuzzer/Android.bp @@ -74,7 +74,7 @@ cc_defaults { ], fuzz_config: { cc: [ - "android-media-fuzzing-reports@google.com", + "android-audio-fuzzing-reports@google.com", ], componentid: 155276, hotlists: ["4593311"], diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp index c35a60edf0..3fe20464ea 100644 --- a/media/libaudiohal/impl/EffectHalAidl.cpp +++ b/media/libaudiohal/impl/EffectHalAidl.cpp @@ -57,7 +57,9 @@ using ::aidl::android::aidl_utils::statusTFromBinderStatus; using ::aidl::android::hardware::audio::effect::Descriptor; using ::aidl::android::hardware::audio::effect::IEffect; using ::aidl::android::hardware::audio::effect::IFactory; +using ::aidl::android::hardware::audio::effect::kEventFlagDataMqNotEmpty; using ::aidl::android::hardware::audio::effect::kEventFlagDataMqUpdate; +using ::aidl::android::hardware::audio::effect::kEventFlagNotEmpty; using ::aidl::android::hardware::audio::effect::kReopenSupportedVersion; using ::aidl::android::hardware::audio::effect::State; @@ -199,6 +201,7 @@ status_t EffectHalAidl::process() { efState & kEventFlagDataMqUpdate) { ALOGV("%s %s V%d receive dataMQUpdate eventFlag from HAL", __func__, effectName.c_str(), halVersion); + mConversion->reopen(); } auto statusQ = mConversion->getStatusMQ(); @@ -224,12 +227,22 @@ status_t EffectHalAidl::process() { floatsToWrite, mInBuffer->audioBuffer(), inputQ->availableToWrite()); return INVALID_OPERATION; } - efGroup->wake(aidl::android::hardware::audio::effect::kEventFlagNotEmpty); + + // for V2 audio effect HAL, expect different EventFlag to avoid bit conflict with FMQ_NOT_EMPTY + efGroup->wake(halVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty + : kEventFlagNotEmpty); IEffect::Status retStatus{}; - if (!statusQ->readBlocking(&retStatus, 1) || retStatus.status != OK || - (size_t)retStatus.fmqConsumed != floatsToWrite || retStatus.fmqProduced == 0) { - ALOGE("%s read status failed: %s", __func__, retStatus.toString().c_str()); + if (!statusQ->readBlocking(&retStatus, 1)) { + ALOGE("%s %s V%d read status from status FMQ failed", __func__, effectName.c_str(), + halVersion); + return INVALID_OPERATION; + } + if (retStatus.status != OK || (size_t)retStatus.fmqConsumed != floatsToWrite || + retStatus.fmqProduced == 0) { + ALOGE("%s read status failed: %s, consumed %d (of %zu) produced %d", __func__, + retStatus.toString().c_str(), retStatus.fmqConsumed, floatsToWrite, + retStatus.fmqProduced); return INVALID_OPERATION; } diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp index 9aa02e2fc1..fb4658f19d 100644 --- a/media/libaudiohal/impl/EffectProxy.cpp +++ b/media/libaudiohal/impl/EffectProxy.cpp @@ -82,8 +82,7 @@ ndk::ScopedAStatus EffectProxy::destroy() { ndk::ScopedAStatus EffectProxy::setOffloadParam(const effect_offload_param_t* offload) { const auto& itor = std::find_if(mSubEffects.begin(), mSubEffects.end(), [&](const auto& sub) { const auto& desc = sub.descriptor; - return offload->isOffload == - (desc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL); + return offload->isOffload == desc.common.flags.offloadIndication; }); if (itor == mSubEffects.end()) { ALOGE("%s no %soffload sub-effect found", __func__, offload->isOffload ? "" : "non-"); @@ -93,7 +92,7 @@ ndk::ScopedAStatus EffectProxy::setOffloadParam(const effect_offload_param_t* of } mActiveSubIdx = std::distance(mSubEffects.begin(), itor); - ALOGI("%s: active %soffload sub-effect %zu descriptor: %s", __func__, + ALOGI("%s: active %soffload sub-effect %zu: %s", __func__, offload->isOffload ? "" : "non-", mActiveSubIdx, ::android::audio::utils::toString(mSubEffects[mActiveSubIdx].descriptor.common.id.uuid) .c_str()); @@ -163,7 +162,7 @@ ndk::ScopedAStatus EffectProxy::close() { ndk::ScopedAStatus EffectProxy::getDescriptor(Descriptor* desc) { *desc = mSubEffects[mActiveSubIdx].descriptor; - desc->common.id.uuid = desc->common.id.proxy.value(); + desc->common = mDescriptorCommon; return ndk::ScopedAStatus::ok(); } @@ -185,42 +184,35 @@ ndk::ScopedAStatus EffectProxy::buildDescriptor(const AudioUuid& uuid, return ndk::ScopedAStatus::ok(); } +// Sub-effects are required to have identical features, so here we return the SW sub-effect +// descriptor, with the implementation UUID replaced with proxy UUID, and flags setting respect all +// sub-effects. Descriptor::Common EffectProxy::buildDescriptorCommon( const AudioUuid& uuid, const std::vector<Descriptor>& subEffectDescs) { - // initial flag values before we know which sub-effect to active (with setOffloadParam) - // align to HIDL EffectProxy flags - Descriptor::Common common = {.flags = {.type = Flags::Type::INSERT, - .insert = Flags::Insert::LAST, - .volume = Flags::Volume::CTRL}}; - + Descriptor::Common swCommon; + const Flags& firstFlag = subEffectDescs[0].common.flags; + bool offloadExist = false; for (const auto& desc : subEffectDescs) { - if (desc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL) { - common.flags.hwAcceleratorMode = Flags::HardwareAccelerator::TUNNEL; - } - - // set indication if any sub-effect indication was set - common.flags.offloadIndication |= desc.common.flags.offloadIndication; - common.flags.deviceIndication |= desc.common.flags.deviceIndication; - common.flags.audioModeIndication |= desc.common.flags.audioModeIndication; - common.flags.audioSourceIndication |= desc.common.flags.audioSourceIndication; - // Set to NONE if any sub-effect not supporting any Volume command - if (desc.common.flags.volume == Flags::Volume::NONE) { - common.flags.volume = Flags::Volume::NONE; + if (desc.common.flags.offloadIndication) { + offloadExist = true; + } else { + swCommon = desc.common; } - // set to AUXILIARY if any sub-effect is of AUXILIARY type - if (desc.common.flags.type == Flags::Type::AUXILIARY) { - common.flags.type = Flags::Type::AUXILIARY; + if (desc.common.flags.audioModeIndication != firstFlag.audioModeIndication || + desc.common.flags.audioSourceIndication != firstFlag.audioSourceIndication || + desc.common.flags.sinkMetadataIndication != firstFlag.sinkMetadataIndication || + desc.common.flags.sourceMetadataIndication != firstFlag.sourceMetadataIndication || + desc.common.flags.deviceIndication != firstFlag.deviceIndication) { + ALOGW("Inconsistent flags %s vs %s", desc.common.flags.toString().c_str(), + firstFlag.toString().c_str()); } } - // copy type UUID from any of sub-effects, all sub-effects should have same type - common.id.type = subEffectDescs[0].common.id.type; + swCommon.flags.offloadIndication = offloadExist; // replace implementation UUID with proxy UUID. - common.id.uuid = uuid; - common.id.proxy = std::nullopt; - common.name = "Proxy"; - common.implementor = "AOSP"; - return common; + swCommon.id.uuid = uuid; + swCommon.id.proxy = std::nullopt; + return swCommon; } // Handle with active sub-effect first, only send to other sub-effects when success diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp index 3b2f344fe8..64cc7ed3d8 100644 --- a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp +++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp @@ -188,7 +188,6 @@ status_t EffectsFactoryHalAidl::createEffect(const effect_uuid_t* uuid, int32_t aidlEffect = ndk::SharedRefBase::make<EffectProxy>( aidlUuid, mProxyUuidDescriptorMap.at(aidlUuid) /* sub-effect descriptor list */, mFactory); - mProxyList.emplace_back(std::static_pointer_cast<EffectProxy>(aidlEffect)); } else { RETURN_STATUS_IF_ERROR( statusTFromBinderStatus(mFactory->createEffect(aidlUuid, &aidlEffect))); @@ -205,15 +204,9 @@ status_t EffectsFactoryHalAidl::createEffect(const effect_uuid_t* uuid, int32_t } status_t EffectsFactoryHalAidl::dumpEffects(int fd) { - status_t ret = OK; - // record the error ret and continue dump as many effects as possible - for (const auto& proxy : mProxyList) { - if (status_t temp = BAD_VALUE; proxy && (temp = proxy->dump(fd, nullptr, 0)) != OK) { - ret = temp; - } - } + // TODO: b/333803769 improve the effect dump implementation RETURN_STATUS_IF_ERROR(mFactory->dump(fd, nullptr, 0)); - return ret; + return OK; } status_t EffectsFactoryHalAidl::allocateBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) { diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.h b/media/libaudiohal/impl/EffectsFactoryHalAidl.h index 73089b0088..3b8628c8fd 100644 --- a/media/libaudiohal/impl/EffectsFactoryHalAidl.h +++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.h @@ -84,9 +84,6 @@ class EffectsFactoryHalAidl final : public EffectsFactoryHalInterface { // Query result of pre and post processing from effect factory const std::vector<Processing> mAidlProcessings; - // list of the EffectProxy instances - std::list<std::shared_ptr<EffectProxy>> mProxyList; - virtual ~EffectsFactoryHalAidl() = default; status_t getHalDescriptorWithImplUuid( const ::aidl::android::media::audio::common::AudioUuid& uuid, diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp index 263e3e93d1..453f9e2113 100644 --- a/media/libaudiohal/impl/Hal2AidlMapper.cpp +++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp @@ -181,7 +181,9 @@ status_t Hal2AidlMapper::createOrUpdatePatch( }; // When looking up port configs, the destinationPortId is only used for mix ports. // Thus, we process device port configs first, and look up the destination port ID from them. - bool sourceIsDevice = std::any_of(sources.begin(), sources.end(), + const bool sourceIsDevice = std::any_of(sources.begin(), sources.end(), + [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; }); + const bool sinkIsDevice = std::any_of(sinks.begin(), sinks.end(), [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; }); const std::vector<AudioPortConfig>& devicePortConfigs = sourceIsDevice ? sources : sinks; @@ -202,7 +204,13 @@ status_t Hal2AidlMapper::createOrUpdatePatch( existingPatchIt->second = patch; } else { bool created = false; - RETURN_STATUS_IF_ERROR(findOrCreatePatch(patch, &patch, &created)); + // When the framework does not specify a patch ID, only the mix port config + // is used for finding an existing patch. That's because the framework assumes + // that there can only be one patch for an I/O thread. + PatchMatch match = sourceIsDevice && sinkIsDevice ? + MATCH_BOTH : (sourceIsDevice ? MATCH_SINKS : MATCH_SOURCES); + RETURN_STATUS_IF_ERROR(findOrCreatePatch(patch, match, + &patch, &created)); // No cleanup of the patch is needed, it is managed by the framework. *patchId = patch.id; if (!created) { @@ -274,18 +282,18 @@ void Hal2AidlMapper::eraseConnectedPort(int32_t portId) { } status_t Hal2AidlMapper::findOrCreatePatch( - const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) { + const AudioPatch& requestedPatch, PatchMatch match, AudioPatch* patch, bool* created) { std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(), requestedPatch.sourcePortConfigIds.end()); std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(), requestedPatch.sinkPortConfigIds.end()); - return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created); + return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, match, patch, created); } status_t Hal2AidlMapper::findOrCreatePatch( const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds, - AudioPatch* patch, bool* created) { - auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds); + PatchMatch match, AudioPatch* patch, bool* created) { + auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds, match); if (patchIt == mPatches.end()) { AudioPatch requestedPatch, appliedPatch; requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(), @@ -456,7 +464,8 @@ status_t Hal2AidlMapper::findPortConfig(const AudioDevice& device, AudioPortConf } Hal2AidlMapper::Patches::iterator Hal2AidlMapper::findPatch( - const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) { + const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds, + PatchMatch match) { return std::find_if(mPatches.begin(), mPatches.end(), [&](const auto& pair) { const auto& p = pair.second; @@ -464,7 +473,15 @@ Hal2AidlMapper::Patches::iterator Hal2AidlMapper::findPatch( p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end()); std::set<int32_t> patchSinks( p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end()); - return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; }); + switch (match) { + case MATCH_SOURCES: + return sourcePortConfigIds == patchSrcs; + case MATCH_SINKS: + return sinkPortConfigIds == patchSinks; + case MATCH_BOTH: + return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; + } + }); } Hal2AidlMapper::Ports::iterator Hal2AidlMapper::findPort(const AudioDevice& device) { @@ -816,10 +833,10 @@ status_t Hal2AidlMapper::prepareToOpenStreamHelper( } if (isInput) { RETURN_STATUS_IF_ERROR(findOrCreatePatch( - {devicePortConfigId}, {mixPortConfig->id}, patch, &created)); + {devicePortConfigId}, {mixPortConfig->id}, MATCH_BOTH, patch, &created)); } else { RETURN_STATUS_IF_ERROR(findOrCreatePatch( - {mixPortConfig->id}, {devicePortConfigId}, patch, &created)); + {mixPortConfig->id}, {devicePortConfigId}, MATCH_BOTH, patch, &created)); } if (created) { cleanups->add(&Hal2AidlMapper::resetPatch, patch->id); diff --git a/media/libaudiohal/impl/Hal2AidlMapper.h b/media/libaudiohal/impl/Hal2AidlMapper.h index f302c23cd3..c70c8af6c9 100644 --- a/media/libaudiohal/impl/Hal2AidlMapper.h +++ b/media/libaudiohal/impl/Hal2AidlMapper.h @@ -133,6 +133,8 @@ class Hal2AidlMapper { using Streams = std::map<wp<StreamHalInterface>, std::pair<int32_t /*mix port config ID*/, int32_t /*patch ID*/>>; + enum PatchMatch { MATCH_SOURCES, MATCH_SINKS, MATCH_BOTH }; + const std::string mInstance; const std::shared_ptr<::aidl::android::hardware::audio::core::IModule> mModule; @@ -150,11 +152,13 @@ class Hal2AidlMapper { ::aidl::android::media::audio::common::AudioPortConfig* result, bool *created); void eraseConnectedPort(int32_t portId); status_t findOrCreatePatch( - const std::set<int32_t>& sourcePortConfigIds, - const std::set<int32_t>& sinkPortConfigIds, + const std::set<int32_t>& sourcePortConfigIds, + const std::set<int32_t>& sinkPortConfigIds, + PatchMatch match, ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created); status_t findOrCreatePatch( const ::aidl::android::hardware::audio::core::AudioPatch& requestedPatch, + PatchMatch match, ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created); status_t findOrCreateDevicePortConfig( const ::aidl::android::media::audio::common::AudioDevice& device, @@ -175,7 +179,7 @@ class Hal2AidlMapper { const std::set<int32_t>& destinationPortIds, ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created); Patches::iterator findPatch(const std::set<int32_t>& sourcePortConfigIds, - const std::set<int32_t>& sinkPortConfigIds); + const std::set<int32_t>& sinkPortConfigIds, PatchMatch match); Ports::iterator findPort(const ::aidl::android::media::audio::common::AudioDevice& device); Ports::iterator findPort( const ::aidl::android::media::audio::common::AudioConfig& config, diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp index 97c9659a36..5d2f9e859b 100644 --- a/media/libaudiohal/impl/StreamHalAidl.cpp +++ b/media/libaudiohal/impl/StreamHalAidl.cpp @@ -200,8 +200,12 @@ status_t StreamHalAidl::standby() { StreamDescriptor::Reply reply; switch (state) { case StreamDescriptor::State::ACTIVE: + case StreamDescriptor::State::DRAINING: + case StreamDescriptor::State::TRANSFERRING: RETURN_STATUS_IF_ERROR(pause(&reply)); - if (reply.state != StreamDescriptor::State::PAUSED) { + if (reply.state != StreamDescriptor::State::PAUSED && + reply.state != StreamDescriptor::State::DRAIN_PAUSED && + reply.state != StreamDescriptor::State::TRANSFER_PAUSED) { ALOGE("%s: unexpected stream state: %s (expected PAUSED)", __func__, toString(reply.state).c_str()); return INVALID_OPERATION; @@ -209,6 +213,7 @@ status_t StreamHalAidl::standby() { FALLTHROUGH_INTENDED; case StreamDescriptor::State::PAUSED: case StreamDescriptor::State::DRAIN_PAUSED: + case StreamDescriptor::State::TRANSFER_PAUSED: if (mIsInput) return flush(); RETURN_STATUS_IF_ERROR(flush(&reply)); if (reply.state != StreamDescriptor::State::IDLE) { @@ -323,8 +328,11 @@ status_t StreamHalAidl::transfer(void *buffer, size_t bytes, size_t *transferred return INVALID_OPERATION; } } + StreamContextAidl::DataMQ::Error fmqError = StreamContextAidl::DataMQ::Error::NONE; + std::string fmqErrorMsg; if (!mIsInput) { - bytes = std::min(bytes, mContext.getDataMQ()->availableToWrite()); + bytes = std::min(bytes, + mContext.getDataMQ()->availableToWrite(&fmqError, &fmqErrorMsg)); } StreamDescriptor::Command burst = StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes); @@ -341,12 +349,14 @@ status_t StreamHalAidl::transfer(void *buffer, size_t bytes, size_t *transferred LOG_ALWAYS_FATAL_IF(*transferred > bytes, "%s: HAL module read %zu bytes, which exceeds requested count %zu", __func__, *transferred, bytes); - if (auto toRead = mContext.getDataMQ()->availableToRead(); + if (auto toRead = mContext.getDataMQ()->availableToRead(&fmqError, &fmqErrorMsg); toRead != 0 && !mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), toRead)) { ALOGE("%s: failed to read %zu bytes to data MQ", __func__, toRead); return NOT_ENOUGH_DATA; } } + LOG_ALWAYS_FATAL_IF(fmqError != StreamContextAidl::DataMQ::Error::NONE, + "%s", fmqErrorMsg.c_str()); mStreamPowerLog.log(buffer, *transferred); return OK; } @@ -379,10 +389,12 @@ status_t StreamHalAidl::resume(StreamDescriptor::Reply* reply) { return INVALID_OPERATION; } return OK; - } else if (state == StreamDescriptor::State::PAUSED) { + } else if (state == StreamDescriptor::State::PAUSED || + state == StreamDescriptor::State::TRANSFER_PAUSED || + state == StreamDescriptor::State::DRAIN_PAUSED) { return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply); } else { - ALOGE("%s: unexpected stream state: %s (expected IDLE or PAUSED)", + ALOGE("%s: unexpected stream state: %s (expected IDLE or one of *PAUSED states)", __func__, toString(state).c_str()); return INVALID_OPERATION; } @@ -618,7 +630,7 @@ status_t StreamOutHalAidl::getLatency(uint32_t *latency) { status_t StreamOutHalAidl::setVolume(float left, float right) { TIME_CHECK(); if (!mStream) return NO_INIT; - size_t channelCount = audio_channel_out_mask_from_count(mConfig.channel_mask); + size_t channelCount = audio_channel_count_from_out_mask(mConfig.channel_mask); if (channelCount == 0) channelCount = 2; std::vector<float> volumes(channelCount); if (channelCount == 1) { @@ -647,21 +659,16 @@ status_t StreamOutHalAidl::write(const void *buffer, size_t bytes, size_t *writt return transfer(const_cast<void*>(buffer), bytes, written); } -status_t StreamOutHalAidl::getRenderPosition(uint32_t *dspFrames) { +status_t StreamOutHalAidl::getRenderPosition(uint64_t *dspFrames) { if (dspFrames == nullptr) { return BAD_VALUE; } int64_t aidlFrames = 0, aidlTimestamp = 0; RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp)); - *dspFrames = static_cast<uint32_t>(aidlFrames); + *dspFrames = aidlFrames; return OK; } -status_t StreamOutHalAidl::getNextWriteTimestamp(int64_t *timestamp __unused) { - // Obsolete, use getPresentationPosition. - return INVALID_OPERATION; -} - status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) { ALOGD("%p %s", this, __func__); TIME_CHECK(); @@ -722,6 +729,11 @@ status_t StreamOutHalAidl::getPresentationPosition(uint64_t *frames, struct time return OK; } +status_t StreamOutHalAidl::presentationComplete() { + ALOGD("%p %s::%s", this, getClassName().c_str(), __func__); + return OK; +} + status_t StreamOutHalAidl::updateSourceMetadata( const StreamOutHalInterface::SourceMetadata& sourceMetadata) { TIME_CHECK(); diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h index b20eb00974..8a398d83d3 100644 --- a/media/libaudiohal/impl/StreamHalAidl.h +++ b/media/libaudiohal/impl/StreamHalAidl.h @@ -308,10 +308,7 @@ class StreamOutHalAidl : public virtual StreamOutHalInterface, // Return the number of audio frames written by the audio dsp to DAC since // the output has exited standby. - status_t getRenderPosition(uint32_t *dspFrames) override; - - // Get the local time at which the next write to the audio driver will be presented. - status_t getNextWriteTimestamp(int64_t *timestamp) override; + status_t getRenderPosition(uint64_t *dspFrames) override; // Set the callback for notifying completion of non-blocking write and drain. status_t setCallback(wp<StreamOutHalInterfaceCallback> callback) override; @@ -337,6 +334,9 @@ class StreamOutHalAidl : public virtual StreamOutHalInterface, // Return a recent count of the number of audio frames presented to an external observer. status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp) override; + // Notifies the HAL layer that the framework considers the current playback as completed. + status_t presentationComplete() override; + // Called when the metadata of the stream's source has been changed. status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) override; diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp index 77c75dbbe3..9e22700c4c 100644 --- a/media/libaudiohal/impl/StreamHalHidl.cpp +++ b/media/libaudiohal/impl/StreamHalHidl.cpp @@ -17,6 +17,8 @@ #define LOG_TAG "StreamHalHidl" //#define LOG_NDEBUG 0 +#include <cinttypes> + #include <android/hidl/manager/1.0/IServiceManager.h> #include <hwbinder/IPCThreadState.h> #include <media/AudioParameter.h> @@ -589,32 +591,39 @@ status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) { return OK; } -status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) { +status_t StreamOutHalHidl::getRenderPosition(uint64_t *dspFrames) { // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized. if (mStream == 0) return NO_INIT; Result retval; + uint32_t halPosition = 0; Return<void> ret = mStream->getRenderPosition( [&](Result r, uint32_t d) { retval = r; if (retval == Result::OK) { - *dspFrames = d; + halPosition = d; } }); - return processReturn("getRenderPosition", ret, retval); -} - -status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) { - TIME_CHECK(); - if (mStream == 0) return NO_INIT; - Result retval; - Return<void> ret = mStream->getNextWriteTimestamp( - [&](Result r, int64_t t) { - retval = r; - if (retval == Result::OK) { - *timestamp = t; - } - }); - return processReturn("getRenderPosition", ret, retval); + status_t status = processReturn("getRenderPosition", ret, retval); + if (status != OK) { + return status; + } + // Maintain a 64-bit render position using the 32-bit result from the HAL. + // This delta calculation relies on the arithmetic overflow behavior + // of integers. For example (100 - 0xFFFFFFF0) = 116. + std::lock_guard l(mPositionMutex); + const auto truncatedPosition = (uint32_t)mRenderPosition; + int32_t deltaHalPosition; // initialization not needed, overwitten by __builtin_sub_overflow() + (void) __builtin_sub_overflow(halPosition, truncatedPosition, &deltaHalPosition); + + if (deltaHalPosition >= 0) { + mRenderPosition += deltaHalPosition; + } else if (mExpectRetrograde) { + mExpectRetrograde = false; + mRenderPosition -= static_cast<uint64_t>(-deltaHalPosition); + ALOGW("Retrograde motion of %" PRId32 " frames", -deltaHalPosition); + } + *dspFrames = mRenderPosition; + return OK; } status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) { @@ -667,9 +676,23 @@ status_t StreamOutHalHidl::drain(bool earlyNotify) { status_t StreamOutHalHidl::flush() { TIME_CHECK(); if (mStream == 0) return NO_INIT; + { + std::lock_guard l(mPositionMutex); + mRenderPosition = 0; + mExpectRetrograde = false; + } return processReturn("pause", mStream->flush()); } +status_t StreamOutHalHidl::standby() { + { + std::lock_guard l(mPositionMutex); + mRenderPosition = 0; + mExpectRetrograde = false; + } + return StreamHalHidl::standby(); +} + status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) { // TIME_CHECK(); // TODO(b/243839867) reenable only when optimized. if (mStream == 0) return NO_INIT; @@ -696,6 +719,16 @@ status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct time } } +status_t StreamOutHalHidl::presentationComplete() { + // Avoid suppressing retrograde motion in mRenderPosition for gapless offload/direct when + // transitioning between tracks. + // The HAL resets the frame position without flush/stop being called, but calls back prior to + // this event. So, on the next occurrence of retrograde motion, we permit backwards movement of + // mRenderPosition. + mExpectRetrograde = true; + return OK; +} + #if MAJOR_VERSION == 2 status_t StreamOutHalHidl::updateSourceMetadata( const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) { diff --git a/media/libaudiohal/impl/StreamHalHidl.h b/media/libaudiohal/impl/StreamHalHidl.h index 48da633514..80379d059d 100644 --- a/media/libaudiohal/impl/StreamHalHidl.h +++ b/media/libaudiohal/impl/StreamHalHidl.h @@ -18,10 +18,12 @@ #define ANDROID_HARDWARE_STREAM_HAL_HIDL_H #include <atomic> +#include <mutex> #include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStream.h) #include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/IStreamIn.h) #include PATH(android/hardware/audio/FILE_VERSION/IStreamOut.h) +#include <android-base/thread_annotations.h> #include <fmq/EventFlag.h> #include <fmq/MessageQueue.h> #include <media/audiohal/EffectHalInterface.h> @@ -119,6 +121,9 @@ class StreamHalHidl : public virtual StreamHalInterface, public CoreConversionHe class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl { public: + // Put the audio hardware input/output into standby mode (from StreamHalInterface). + status_t standby() override; + // Return the frame size (number of bytes per sample) of a stream. virtual status_t getFrameSize(size_t *size); @@ -136,10 +141,7 @@ class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl { // Return the number of audio frames written by the audio dsp to DAC since // the output has exited standby. - virtual status_t getRenderPosition(uint32_t *dspFrames); - - // Get the local time at which the next write to the audio driver will be presented. - virtual status_t getNextWriteTimestamp(int64_t *timestamp); + virtual status_t getRenderPosition(uint64_t *dspFrames); // Set the callback for notifying completion of non-blocking write and drain. virtual status_t setCallback(wp<StreamOutHalInterfaceCallback> callback); @@ -165,6 +167,9 @@ class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl { // Return a recent count of the number of audio frames presented to an external observer. virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp); + // Notifies the HAL layer that the framework considers the current playback as completed. + status_t presentationComplete() override; + // Called when the metadata of the stream's source has been changed. status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) override; @@ -221,6 +226,10 @@ class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl { std::unique_ptr<StatusMQ> mStatusMQ; std::atomic<pid_t> mWriterClient; EventFlag* mEfGroup; + std::mutex mPositionMutex; + // Used to expand correctly the 32-bit position from the HAL. + uint64_t mRenderPosition GUARDED_BY(mPositionMutex) = 0; + bool mExpectRetrograde GUARDED_BY(mPositionMutex) = false; // See 'presentationComplete'. // Can not be constructed directly by clients. StreamOutHalHidl(const sp<::android::hardware::audio::CPP_VERSION::IStreamOut>& stream); diff --git a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h index 37615afd3f..eb14f6b1de 100644 --- a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h +++ b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h @@ -151,10 +151,7 @@ class StreamOutHalInterface : public virtual StreamHalInterface { // Return the number of audio frames written by the audio dsp to DAC since // the output has exited standby. - virtual status_t getRenderPosition(uint32_t *dspFrames) = 0; - - // Get the local time at which the next write to the audio driver will be presented. - virtual status_t getNextWriteTimestamp(int64_t *timestamp) = 0; + virtual status_t getRenderPosition(uint64_t *dspFrames) = 0; // Set the callback for notifying completion of non-blocking write and drain. // The callback must be owned by someone else. The output stream does not own it @@ -182,6 +179,9 @@ class StreamOutHalInterface : public virtual StreamHalInterface { // Return a recent count of the number of audio frames presented to an external observer. virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp) = 0; + // Notifies the HAL layer that the framework considers the current playback as completed. + virtual status_t presentationComplete() = 0; + struct SourceMetadata { std::vector<playback_track_metadata_v7_t> tracks; }; diff --git a/media/libeffects/data/Android.bp b/media/libeffects/data/Android.bp new file mode 100644 index 0000000000..2acf229d8e --- /dev/null +++ b/media/libeffects/data/Android.bp @@ -0,0 +1,19 @@ +// Copyright (C) 2024 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. + +prebuilt_etc { + name: "framework-audio_effects.xml", + src: "audio_effects.xml", + filename: "audio_effects.xml", +} diff --git a/media/libeffects/downmix/aidl/EffectDownmix.cpp b/media/libeffects/downmix/aidl/EffectDownmix.cpp index de60ca4921..883d41d629 100644 --- a/media/libeffects/downmix/aidl/EffectDownmix.cpp +++ b/media/libeffects/downmix/aidl/EffectDownmix.cpp @@ -177,7 +177,10 @@ void DownmixImpl::process() { * in the life cycle of workerThread (threadLoop). */ uint32_t efState = 0; - if (!mEventFlag || ::android::OK != mEventFlag->wait(kEventFlagNotEmpty, &efState)) { + if (!mEventFlag || + ::android::OK != mEventFlag->wait(mDataMqNotEmptyEf, &efState, 0 /* no timeout */, + true /* retry */) || + !(efState & mDataMqNotEmptyEf)) { LOG(ERROR) << getEffectName() << __func__ << ": StatusEventFlag invalid"; } diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp index fdc16e38d7..836e034c8a 100644 --- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp +++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp @@ -213,11 +213,12 @@ ndk::ScopedAStatus DynamicsProcessingImpl::open(const Parameter::Common& common, RETURN_OK_IF(mState != State::INIT); mImplContext = createContext(common); RETURN_IF(!mContext || !mImplContext, EX_NULL_POINTER, "createContextFailed"); - int version = 0; - RETURN_IF(!getInterfaceVersion(&version).isOk(), EX_UNSUPPORTED_OPERATION, + RETURN_IF(!getInterfaceVersion(&mVersion).isOk(), EX_UNSUPPORTED_OPERATION, "FailedToGetInterfaceVersion"); mImplContext->setVersion(version); mEventFlag = mImplContext->getStatusEventFlag(); + mDataMqNotEmptyEf = + mVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty : kEventFlagNotEmpty; if (specific.has_value()) { RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr"); @@ -231,8 +232,9 @@ ndk::ScopedAStatus DynamicsProcessingImpl::open(const Parameter::Common& common, mState = State::IDLE; mContext->dupeFmq(ret); - RETURN_IF(createThread(getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION, - "FailedToCreateWorker"); + RETURN_IF(createThread(getEffectNameWithVersion()) != RetCode::SUCCESS, + EX_UNSUPPORTED_OPERATION, "FailedToCreateWorker"); + LOG(INFO) << getEffectNameWithVersion() << __func__; return ndk::ScopedAStatus::ok(); } diff --git a/media/libeffects/visualizer/aidl/Visualizer.cpp b/media/libeffects/visualizer/aidl/Visualizer.cpp index 9c2b71ef13..9b493d43a8 100644 --- a/media/libeffects/visualizer/aidl/Visualizer.cpp +++ b/media/libeffects/visualizer/aidl/Visualizer.cpp @@ -72,7 +72,7 @@ const Descriptor VisualizerImpl::kDescriptor = { .uuid = getEffectImplUuidVisualizer(), .proxy = std::nullopt}, .flags = {.type = Flags::Type::INSERT, - .insert = Flags::Insert::LAST, + .insert = Flags::Insert::FIRST, .volume = Flags::Volume::NONE}, .name = VisualizerImpl::kEffectName, .implementor = "The Android Open Source Project"}, diff --git a/media/libheif/OWNERS b/media/libheif/OWNERS new file mode 100644 index 0000000000..a61ad21e7f --- /dev/null +++ b/media/libheif/OWNERS @@ -0,0 +1,2 @@ +include platform/frameworks/av:/media/janitors/avic_OWNERS +include platform/frameworks/av:/media/janitors/codec_OWNERS
\ No newline at end of file diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp index 886285e7c2..c9a2eea93d 100644 --- a/media/libstagefright/Android.bp +++ b/media/libstagefright/Android.bp @@ -318,6 +318,10 @@ cc_library { "aconfig_mediacodec_flags_c_lib", ], + defaults: [ + "aconfig_lib_cc_static_link.defaults", + ], + static_libs: [ "android.media.codec-aconfig-cc", "libstagefright_esds", diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp index 604dcb0f93..714e31265d 100644 --- a/media/libstagefright/SurfaceUtils.cpp +++ b/media/libstagefright/SurfaceUtils.cpp @@ -111,8 +111,9 @@ status_t setNativeWindowSizeFormatAndUsage( } } - int finalUsage = usage | consumerUsage; - ALOGV("gralloc usage: %#x(producer) + %#x(consumer) = %#x", usage, consumerUsage, finalUsage); + uint64_t finalUsage = (uint32_t) usage | (uint32_t) consumerUsage; + ALOGV("gralloc usage: %#x(producer) + %#x(consumer) = 0x%" PRIx64, + usage, consumerUsage, finalUsage); err = native_window_set_usage(nativeWindow, finalUsage); if (err != NO_ERROR) { ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); @@ -126,7 +127,7 @@ status_t setNativeWindowSizeFormatAndUsage( return err; } - ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage %#x", + ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage 0x%" PRIx64, nativeWindow, width, height, format, rotation, finalUsage); return NO_ERROR; } diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml index bfa361cd7e..d50bc1e643 100644 --- a/media/libstagefright/data/media_codecs_sw.xml +++ b/media/libstagefright/data/media_codecs_sw.xml @@ -139,6 +139,7 @@ <Limit name="bitrate" range="1-40000000" /> </Variant> <Feature name="adaptive-playback" /> + <Feature name="dynamic-color-aspects" /> <Attribute name="software-codec" /> </MediaCodec> <MediaCodec name="c2.android.hevc.decoder" type="video/hevc" variant="slow-cpu,!slow-cpu"> @@ -160,6 +161,7 @@ <Limit name="bitrate" range="1-5000000" /> </Variant> <Feature name="adaptive-playback" /> + <Feature name="dynamic-color-aspects" /> <Attribute name="software-codec" /> </MediaCodec> <MediaCodec name="c2.android.vp8.decoder" type="video/x-vnd.on2.vp8" variant="slow-cpu,!slow-cpu"> @@ -178,6 +180,7 @@ <Limit name="bitrate" range="1-40000000" /> </Variant> <Feature name="adaptive-playback" /> + <Feature name="dynamic-color-aspects" /> <Attribute name="software-codec" /> </MediaCodec> <MediaCodec name="c2.android.vp9.decoder" type="video/x-vnd.on2.vp9" variant="slow-cpu,!slow-cpu"> @@ -197,6 +200,7 @@ <Limit name="bitrate" range="1-5000000" /> </Variant> <Feature name="adaptive-playback" /> + <Feature name="dynamic-color-aspects" /> <Attribute name="software-codec" /> </MediaCodec> <MediaCodec name="c2.android.av1.decoder" type="video/av01" variant="slow-cpu,!slow-cpu"> @@ -216,6 +220,7 @@ <Limit name="bitrate" range="1-5000000" /> </Variant> <Feature name="adaptive-playback" /> + <Feature name="dynamic-color-aspects" /> <Feature name="low-latency" /> <Attribute name="software-codec" /> </MediaCodec> @@ -235,6 +240,7 @@ <Limit name="bitrate" range="1-5000000" /> </Variant> <Feature name="adaptive-playback" /> + <Feature name="dynamic-color-aspects" /> <Feature name="low-latency" /> <Attribute name="software-codec" /> </MediaCodec> diff --git a/media/libstagefright/rtsp/fuzzer/Android.bp b/media/libstagefright/rtsp/fuzzer/Android.bp index a2791ba77d..ff64af50eb 100644 --- a/media/libstagefright/rtsp/fuzzer/Android.bp +++ b/media/libstagefright/rtsp/fuzzer/Android.bp @@ -29,11 +29,19 @@ cc_defaults { header_libs: [ "libstagefright_rtsp_headers", ], - fuzz_config:{ + fuzz_config: { cc: [ - "android-media-fuzzing-reports@google.com", + "android-media-playback@google.com", ], componentid: 155276, + hotlists: [ + "4593311", + ], + description: "This fuzzer targets the APIs of libstagefright_rtsp", + vector: "local_privileges_required", + service_privilege: "privileged", + users: "multi_user", + fuzzed_code_usage: "shipped", }, } @@ -44,7 +52,7 @@ cc_fuzz { ], defaults: [ "libstagefright_rtsp_fuzzer_defaults", - ] + ], } cc_fuzz { @@ -55,7 +63,7 @@ cc_fuzz { defaults: [ "libstagefright_rtsp_fuzzer_defaults", ], - shared_libs:[ + shared_libs: [ "libandroid_net", "libbase", "libstagefright", diff --git a/media/module/bufferpool/2.0/AccessorImpl.cpp b/media/module/bufferpool/2.0/AccessorImpl.cpp index 1d2562e41d..202d8030a7 100644 --- a/media/module/bufferpool/2.0/AccessorImpl.cpp +++ b/media/module/bufferpool/2.0/AccessorImpl.cpp @@ -609,7 +609,7 @@ void Accessor::Impl::BufferPool::processStatusMessages() { } if (ret == false) { ALOGW("buffer status message processing failure - message : %d connection : %lld", - message.newStatus, (long long)message.connectionId); + (int)message.newStatus, (long long)message.connectionId); } } messages.clear(); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 1d7c356246..03d1935d6d 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -3357,9 +3357,9 @@ status_t PlaybackThread::getRenderPosition( return NO_ERROR; } else { status_t status; - uint32_t frames; + uint64_t frames = 0; status = mOutput->getRenderPosition(&frames); - *dspFrames = (size_t)frames; + *dspFrames = (uint32_t)frames; return status; } } @@ -5903,7 +5903,7 @@ PlaybackThread::mixer_state MixerThread::prepareTracks_l( vaf = v * sendLevel * (1. / MAX_GAIN_INT); } - track->setFinalVolume(vrf, vlf); + track->setFinalVolume(vlf, vrf); // Delegate volume control to effect in track effect chain if needed if (chain != 0 && chain->setVolume_l(&vl, &vr)) { diff --git a/services/audioflinger/datapath/AudioStreamIn.cpp b/services/audioflinger/datapath/AudioStreamIn.cpp index 76618f44b9..165ac255ec 100644 --- a/services/audioflinger/datapath/AudioStreamIn.cpp +++ b/services/audioflinger/datapath/AudioStreamIn.cpp @@ -58,7 +58,7 @@ status_t AudioStreamIn::getCapturePosition(int64_t* frames, int64_t* time) if (mHalFormatHasProportionalFrames && (flags & AUDIO_INPUT_FLAG_DIRECT) == AUDIO_INPUT_FLAG_DIRECT) { - // For DirectRecord reset timestamp to 0 on standby. + // For DirectRecord reset position to 0 on standby. const uint64_t adjustedPosition = (halPosition <= mFramesReadAtStandby) ? 0 : (halPosition - mFramesReadAtStandby); // Scale from HAL sample rate to application rate. diff --git a/services/audioflinger/datapath/AudioStreamOut.cpp b/services/audioflinger/datapath/AudioStreamOut.cpp index 9851f3a00d..a686ff625b 100644 --- a/services/audioflinger/datapath/AudioStreamOut.cpp +++ b/services/audioflinger/datapath/AudioStreamOut.cpp @@ -51,42 +51,17 @@ status_t AudioStreamOut::getRenderPosition(uint64_t *frames) return NO_INIT; } - uint32_t halPosition = 0; + uint64_t halPosition = 0; const status_t status = stream->getRenderPosition(&halPosition); if (status != NO_ERROR) { return status; } - - // Maintain a 64-bit render position using the 32-bit result from the HAL. - // This delta calculation relies on the arithmetic overflow behavior - // of integers. For example (100 - 0xFFFFFFF0) = 116. - const auto truncatedPosition = (uint32_t)mRenderPosition; - int32_t deltaHalPosition; // initialization not needed, overwitten by __builtin_sub_overflow() - (void) __builtin_sub_overflow(halPosition, truncatedPosition, &deltaHalPosition); - - if (deltaHalPosition > 0) { - mRenderPosition += deltaHalPosition; - } else if (mExpectRetrograde) { - mExpectRetrograde = false; - mRenderPosition -= static_cast<uint64_t>(-deltaHalPosition); - } // Scale from HAL sample rate to application rate. - *frames = mRenderPosition / mRateMultiplier; + *frames = halPosition / mRateMultiplier; return status; } -// return bottom 32-bits of the render position -status_t AudioStreamOut::getRenderPosition(uint32_t *frames) -{ - uint64_t position64 = 0; - const status_t status = getRenderPosition(&position64); - if (status == NO_ERROR) { - *frames = (uint32_t)position64; - } - return status; -} - status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) { if (stream == nullptr) { @@ -101,7 +76,7 @@ status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timesp if (mHalFormatHasProportionalFrames && (flags & AUDIO_OUTPUT_FLAG_DIRECT) == AUDIO_OUTPUT_FLAG_DIRECT) { - // For DirectTrack reset timestamp to 0 on standby. + // For DirectTrack reset position to 0 on standby. const uint64_t adjustedPosition = (halPosition <= mFramesWrittenAtStandby) ? 0 : (halPosition - mFramesWrittenAtStandby); // Scale from HAL sample rate to application rate. @@ -179,8 +154,6 @@ audio_config_base_t AudioStreamOut::getAudioProperties() const int AudioStreamOut::flush() { - mRenderPosition = 0; - mExpectRetrograde = false; mFramesWritten = 0; mFramesWrittenAtStandby = 0; const status_t result = stream->flush(); @@ -189,12 +162,14 @@ int AudioStreamOut::flush() int AudioStreamOut::standby() { - mRenderPosition = 0; - mExpectRetrograde = false; mFramesWrittenAtStandby = mFramesWritten; return stream->standby(); } +void AudioStreamOut::presentationComplete() { + stream->presentationComplete(); +} + ssize_t AudioStreamOut::write(const void *buffer, size_t numBytes) { size_t bytesWritten; diff --git a/services/audioflinger/datapath/AudioStreamOut.h b/services/audioflinger/datapath/AudioStreamOut.h index ea41bbab25..2c9fb3ead6 100644 --- a/services/audioflinger/datapath/AudioStreamOut.h +++ b/services/audioflinger/datapath/AudioStreamOut.h @@ -51,9 +51,6 @@ public: virtual ~AudioStreamOut(); - // Get the bottom 32-bits of the 64-bit render position. - status_t getRenderPosition(uint32_t *frames); - virtual status_t getRenderPosition(uint64_t *frames); virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp); @@ -91,21 +88,14 @@ public: virtual status_t flush(); virtual status_t standby(); - // Avoid suppressing retrograde motion in mRenderPosition for gapless offload/direct when - // transitioning between tracks. - // The HAL resets the frame position without flush/stop being called, but calls back prior to - // this event. So, on the next occurrence of retrograde motion, we permit backwards movement of - // mRenderPosition. - virtual void presentationComplete() { mExpectRetrograde = true; } + virtual void presentationComplete(); protected: uint64_t mFramesWritten = 0; // reset by flush uint64_t mFramesWrittenAtStandby = 0; - uint64_t mRenderPosition = 0; // reset by flush, standby, or presentation complete int mRateMultiplier = 1; bool mHalFormatHasProportionalFrames = false; size_t mHalFrameSize = 0; - bool mExpectRetrograde = false; // see presentationComplete }; } // namespace android diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp index d7eb2c8170..878e0e9021 100644 --- a/services/audiopolicy/engine/common/Android.bp +++ b/services/audiopolicy/engine/common/Android.bp @@ -61,4 +61,7 @@ cc_library_static { "com.android.media.audio-aconfig-cc", "server_configurable_flags", ], + defaults: [ + "aconfig_lib_cc_static_link.defaults", + ], } diff --git a/services/audiopolicy/engineconfigurable/Android.bp b/services/audiopolicy/engineconfigurable/Android.bp index aaf89a0380..2c3c4bee30 100644 --- a/services/audiopolicy/engineconfigurable/Android.bp +++ b/services/audiopolicy/engineconfigurable/Android.bp @@ -53,4 +53,7 @@ cc_library_shared { "libutils", "libxml2", ], + defaults: [ + "aconfig_lib_cc_static_link.defaults", + ], } diff --git a/services/audiopolicy/enginedefault/Android.bp b/services/audiopolicy/enginedefault/Android.bp index 1563d5f257..f5958bae02 100644 --- a/services/audiopolicy/enginedefault/Android.bp +++ b/services/audiopolicy/enginedefault/Android.bp @@ -40,4 +40,7 @@ cc_library_shared { "libutils", "libxml2", ], + defaults: [ + "aconfig_lib_cc_static_link.defaults", + ], } diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index d427de45a4..5c4ab7b1d9 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -6397,6 +6397,15 @@ void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices) if ((desc->mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0 && !isOutputOnlyAvailableRouteToSomeDevice(desc)) { outputsClosed.push_back(desc->mIoHandle); + nextAudioPortGeneration(); + ssize_t index = mAudioPatches.indexOfKey(desc->getPatchHandle()); + if (index >= 0) { + sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index); + (void) /*status_t status*/ mpClientInterface->releaseAudioPatch( + patchDesc->getAfHandle(), 0); + mAudioPatches.removeItemsAt(index); + mpClientInterface->onAudioPatchListUpdate(); + } desc->close(); } } diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 271860478d..58b3e510c9 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -3649,19 +3649,18 @@ bool Camera3Device::RequestThread::threadLoop() { cleanUpFailedRequests(/*sendRequestError*/ true); // Check if any stream is abandoned. checkAndStopRepeatingRequest(); + // Inform waitUntilRequestProcessed thread of a failed request ID + wakeupLatestRequest(/*failedRequestId*/true, latestRequestId); return true; } else if (res != OK) { cleanUpFailedRequests(/*sendRequestError*/ false); + // Inform waitUntilRequestProcessed thread of a failed request ID + wakeupLatestRequest(/*failedRequestId*/true, latestRequestId); return false; } // Inform waitUntilRequestProcessed thread of a new request ID - { - Mutex::Autolock al(mLatestRequestMutex); - - mLatestRequestId = latestRequestId; - mLatestRequestSignal.signal(); - } + wakeupLatestRequest(/*failedRequestId*/false, latestRequestId); // Submit a batch of requests to HAL. // Use flush lock only when submitting multilple requests in a batch. @@ -4393,12 +4392,7 @@ void Camera3Device::RequestThread::cleanUpFailedRequests(bool sendRequestError) hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST, captureRequest->mResultExtras); } - { - Mutex::Autolock al(mLatestRequestMutex); - - mLatestFailedRequestId = captureRequest->mResultExtras.requestId; - mLatestRequestSignal.signal(); - } + wakeupLatestRequest(/*failedRequestId*/true, captureRequest->mResultExtras.requestId); } // Remove yet-to-be submitted inflight request from inflightMap @@ -5060,6 +5054,20 @@ status_t Camera3Device::RequestThread::setHalInterface( return OK; } +void Camera3Device::RequestThread::wakeupLatestRequest( + bool latestRequestFailed, + int32_t latestRequestId) { + Mutex::Autolock al(mLatestRequestMutex); + + if (latestRequestFailed) { + mLatestFailedRequestId = latestRequestId; + } else { + mLatestRequestId = latestRequestId; + } + mLatestRequestSignal.signal(); +} + + /** * PreparerThread inner class methods */ diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 9a2f2b15c0..1820702349 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -1026,6 +1026,11 @@ class Camera3Device : const sp<CaptureRequest> &request, const CameraMetadata& injectedSessionParams); + /** + * signal mLatestRequestmutex + **/ + void wakeupLatestRequest(bool latestRequestFailed, int32_t latestRequestId); + protected: virtual bool threadLoop(); diff --git a/services/camera/virtualcamera/VirtualCameraStream.cc b/services/camera/virtualcamera/VirtualCameraStream.cc index 03da1716e0..fad6cac2f7 100644 --- a/services/camera/virtualcamera/VirtualCameraStream.cc +++ b/services/camera/virtualcamera/VirtualCameraStream.cc @@ -26,8 +26,6 @@ #include "EGL/egl.h" #include "aidl/android/hardware/camera/device/Stream.h" -#include "aidl/android/hardware/camera/device/StreamBuffer.h" -#include "aidl/android/hardware/graphics/common/PixelFormat.h" #include "aidlcommonsupport/NativeHandle.h" #include "android/hardware_buffer.h" #include "cutils/native_handle.h" @@ -39,52 +37,33 @@ namespace companion { namespace virtualcamera { using ::aidl::android::hardware::camera::device::Stream; -using ::aidl::android::hardware::camera::device::StreamBuffer; using ::aidl::android::hardware::common::NativeHandle; -using ::aidl::android::hardware::graphics::common::PixelFormat; namespace { -sp<GraphicBuffer> createBlobGraphicBuffer(GraphicBufferMapper& mapper, - buffer_handle_t bufferHandle) { - uint64_t allocationSize; - uint64_t usage; - uint64_t layerCount; - if (mapper.getAllocationSize(bufferHandle, &allocationSize) != NO_ERROR || - mapper.getUsage(bufferHandle, &usage) != NO_ERROR || - mapper.getLayerCount(bufferHandle, &layerCount) != NO_ERROR) { - ALOGE("Error fetching metadata for the imported BLOB buffer handle."); - return nullptr; - } - - return sp<GraphicBuffer>::make( - bufferHandle, GraphicBuffer::HandleWrapMethod::TAKE_HANDLE, - allocationSize, /*height=*/1, static_cast<int>(ui::PixelFormat::BLOB), - layerCount, usage, 0); -} - -sp<GraphicBuffer> createYCbCr420GraphicBuffer(GraphicBufferMapper& mapper, - buffer_handle_t bufferHandle) { +sp<GraphicBuffer> createGraphicBuffer(GraphicBufferMapper& mapper, + const buffer_handle_t bufferHandle) { uint64_t width; uint64_t height; uint64_t usage; uint64_t layerCount; + ui::PixelFormat pixelFormat; if (mapper.getWidth(bufferHandle, &width) != NO_ERROR || mapper.getHeight(bufferHandle, &height) != NO_ERROR || mapper.getUsage(bufferHandle, &usage) != NO_ERROR || - mapper.getLayerCount(bufferHandle, &layerCount) != NO_ERROR) { + mapper.getLayerCount(bufferHandle, &layerCount) != NO_ERROR || + mapper.getPixelFormatRequested(bufferHandle, &pixelFormat) != NO_ERROR) { ALOGE("Error fetching metadata for the imported YCbCr420 buffer handle."); return nullptr; } return sp<GraphicBuffer>::make( bufferHandle, GraphicBuffer::HandleWrapMethod::TAKE_HANDLE, width, height, - static_cast<int>(ui::PixelFormat::YCBCR_420_888), /*layers=*/1, usage, - width); + static_cast<int>(pixelFormat), layerCount, usage, width); } std::shared_ptr<AHardwareBuffer> importBufferInternal( - const NativeHandle& aidlHandle, const Stream& streamConfig) { + const NativeHandle& aidlHandle) { if (aidlHandle.fds.empty()) { ALOGE("Empty handle - nothing to import"); return nullptr; @@ -103,12 +82,9 @@ std::shared_ptr<AHardwareBuffer> importBufferInternal( return nullptr; } - sp<GraphicBuffer> buf = - streamConfig.format == PixelFormat::BLOB - ? createBlobGraphicBuffer(mapper, bufferHandle) - : createYCbCr420GraphicBuffer(mapper, bufferHandle); + sp<GraphicBuffer> buf = createGraphicBuffer(mapper, bufferHandle); - if (buf->initCheck() != NO_ERROR) { + if (buf == nullptr || buf->initCheck() != NO_ERROR) { ALOGE("Imported graphic buffer is not correcly initialized."); return nullptr; } @@ -128,7 +104,7 @@ VirtualCameraStream::VirtualCameraStream(const Stream& stream) std::shared_ptr<AHardwareBuffer> VirtualCameraStream::importBuffer( const ::aidl::android::hardware::camera::device::StreamBuffer& buffer) { - auto hwBufferPtr = importBufferInternal(buffer.buffer, mStreamConfig); + auto hwBufferPtr = importBufferInternal(buffer.buffer); if (hwBufferPtr != nullptr) { std::lock_guard<std::mutex> lock(mLock); mBuffers.emplace(std::piecewise_construct, diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp index 6a64823052..5dfec3050d 100644 --- a/services/mediaresourcemanager/test/Android.bp +++ b/services/mediaresourcemanager/test/Android.bp @@ -29,6 +29,9 @@ cc_test { "libactivitymanager_aidl", "server_configurable_flags", ], + defaults: [ + "aconfig_lib_cc_static_link.defaults", + ], include_dirs: [ "frameworks/av/include", "frameworks/av/services/mediaresourcemanager", |