Loading media/libaudiohal/impl/EffectConversionHelperAidl.cpp +25 −14 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * limitations under the License. */ #include <csignal> #include <cstddef> #include <cstdint> #include <cstring> Loading Loading @@ -194,11 +195,9 @@ status_t EffectConversionHelperAidl::handleSetConfig(uint32_t cmdSize, const voi statusTFromBinderStatus(mEffect->open(common, std::nullopt, &openReturn))); if (mIsProxyEffect) { const auto& ret = std::static_pointer_cast<EffectProxy>(mEffect)->getEffectReturnParam(); mStatusQ = std::make_shared<StatusMQ>(ret->statusMQ); mInputQ = std::make_shared<DataMQ>(ret->inputDataMQ); mOutputQ = std::make_shared<DataMQ>(ret->outputDataMQ); mStatusQ = std::static_pointer_cast<EffectProxy>(mEffect)->getStatusMQ(); mInputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getInputMQ(); mOutputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getOutputMQ(); } else { mStatusQ = std::make_shared<StatusMQ>(openReturn.statusMQ); mInputQ = std::make_shared<DataMQ>(openReturn.inputDataMQ); Loading @@ -206,6 +205,7 @@ status_t EffectConversionHelperAidl::handleSetConfig(uint32_t cmdSize, const voi } if (status_t status = updateEventFlags(); status != OK) { ALOGV("%s closing at status %d", __func__, status); mEffect->close(); return status; } Loading Loading @@ -353,14 +353,15 @@ status_t EffectConversionHelperAidl::handleSetOffload(uint32_t cmdSize, const vo ALOGI("%s offload param offload %s ioHandle %d", __func__, offload->isOffload ? "true" : "false", offload->ioHandle); mCommon.ioHandle = offload->ioHandle; RETURN_STATUS_IF_ERROR(statusTFromBinderStatus( std::static_pointer_cast<EffectProxy>(mEffect)->setOffloadParam(offload))); // update FMQs const auto& ret = std::static_pointer_cast<EffectProxy>(mEffect)->getEffectReturnParam(); mStatusQ = std::make_shared<StatusMQ>(ret->statusMQ); mInputQ = std::make_shared<DataMQ>(ret->inputDataMQ); mOutputQ = std::make_shared<DataMQ>(ret->outputDataMQ); RETURN_STATUS_IF_ERROR(updateEventFlags()); const auto& effectProxy = std::static_pointer_cast<EffectProxy>(mEffect); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(effectProxy->setOffloadParam(offload))); // update FMQs if the effect instance already open if (State state; effectProxy->getState(&state).isOk() && state != State::INIT) { mStatusQ = effectProxy->getStatusMQ(); mInputQ = effectProxy->getInputMQ(); mOutputQ = effectProxy->getOutputMQ(); updateEventFlags(); } } return *static_cast<int32_t*>(pReplyData) = OK; } Loading Loading @@ -408,17 +409,27 @@ status_t EffectConversionHelperAidl::handleVisualizerMeasure(uint32_t cmdSize __ status_t EffectConversionHelperAidl::updateEventFlags() { status_t status = BAD_VALUE; EventFlag* efGroup = nullptr; if (mStatusQ->isValid()) { if (mStatusQ && mStatusQ->isValid()) { status = EventFlag::createEventFlag(mStatusQ->getEventFlagWord(), &efGroup); if (status != OK || !efGroup) { ALOGE("%s: create EventFlagGroup failed, ret %d, egGroup %p", __func__, status, efGroup); status = (status == OK) ? BAD_VALUE : status; } } else if (isBypassing()) { // for effect with bypass (no processing) flag, it's okay to not have statusQ return OK; } mEfGroup.reset(efGroup, EventFlagDeleter()); return status; } bool EffectConversionHelperAidl::isBypassing() const { return mEffect && (mDesc.common.flags.bypass || (mIsProxyEffect && std::static_pointer_cast<EffectProxy>(mEffect)->isBypassing())); } } // namespace effect } // namespace android media/libaudiohal/impl/EffectConversionHelperAidl.h +1 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ class EffectConversionHelperAidl { std::shared_ptr<DataMQ> getInputMQ() { return mInputQ; } std::shared_ptr<DataMQ> getOutputMQ() { return mOutputQ; } std::shared_ptr<android::hardware::EventFlag> getEventFlagGroup() { return mEfGroup; } bool isBypassing() const; protected: const int32_t mSessionId; Loading media/libaudiohal/impl/EffectHalAidl.cpp +9 −3 Original line number Diff line number Diff line Loading @@ -74,9 +74,12 @@ EffectHalAidl::EffectHalAidl(const std::shared_ptr<IFactory>& factory, } EffectHalAidl::~EffectHalAidl() { if (mEffect) { mIsProxyEffect ? std::static_pointer_cast<EffectProxy>(mEffect)->destroy() : mFactory->destroyEffect(mEffect); if (mFactory && mEffect) { if (mIsProxyEffect) { std::static_pointer_cast<EffectProxy>(mEffect)->destroy(); } else { mFactory->destroyEffect(mEffect); } } } Loading Loading @@ -166,6 +169,9 @@ status_t EffectHalAidl::process() { auto inputQ = mConversion->getInputMQ(); auto outputQ = mConversion->getOutputMQ(); auto efGroup = mConversion->getEventFlagGroup(); if (mConversion->isBypassing()) { return OK; } if (!statusQ || !statusQ->isValid() || !inputQ || !inputQ->isValid() || !outputQ || !outputQ->isValid() || !efGroup) { ALOGE("%s invalid FMQ [Status %d I %d O %d] efGroup %p", __func__, Loading media/libaudiohal/impl/EffectProxy.cpp +133 −127 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ #include <algorithm> #include <iterator> #include <memory> #define LOG_TAG "EffectProxy" // #define LOG_NDEBUG 0 Loading @@ -25,6 +26,7 @@ #include "EffectProxy.h" using ::aidl::android::hardware::audio::effect::Capability; using ::aidl::android::hardware::audio::effect::CommandId; using ::aidl::android::hardware::audio::effect::Descriptor; using ::aidl::android::hardware::audio::effect::Flags; Loading @@ -33,89 +35,39 @@ using ::aidl::android::hardware::audio::effect::IFactory; using ::aidl::android::hardware::audio::effect::Parameter; using ::aidl::android::hardware::audio::effect::State; using ::aidl::android::media::audio::common::AudioUuid; using ::android::audio::utils::toString; namespace android { namespace effect { EffectProxy::EffectProxy(const Descriptor::Identity& id, const std::shared_ptr<IFactory>& factory) : mIdentity([](const Descriptor::Identity& subId) { // update EffectProxy implementation UUID to the sub-effect proxy UUID ALOG_ASSERT(subId.proxy.has_value(), "Sub-effect Identity must have valid proxy UUID"); Descriptor::Identity tempId = subId; tempId.uuid = subId.proxy.value(); return tempId; }(id)), mFactory(factory) {} EffectProxy::~EffectProxy() { close(); destroy(); mSubEffects.clear(); } // sub effect must have same proxy UUID as EffectProxy, and the type UUID must match. ndk::ScopedAStatus EffectProxy::addSubEffect(const Descriptor& sub) { ALOGV("%s: %s", __func__, toString(mIdentity.type).c_str()); if (0 != mSubEffects.count(sub.common.id) || !sub.common.id.proxy.has_value() || sub.common.id.proxy.value() != mIdentity.uuid) { ALOGE("%s sub effect already exist or mismatch %s", __func__, sub.toString().c_str()); return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "illegalSubEffect"); } // not create sub-effect yet std::get<SubEffectTupleIndex::HANDLE>(mSubEffects[sub.common.id]) = nullptr; std::get<SubEffectTupleIndex::DESCRIPTOR>(mSubEffects[sub.common.id]) = sub; // set the last added sub-effect to active before setOffloadParam() mActiveSub = sub.common.id; ALOGI("%s add %s to proxy %s flag %s", __func__, mActiveSub.toString().c_str(), mIdentity.toString().c_str(), sub.common.flags.toString().c_str()); if (sub.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL) { mSubFlags.hwAcceleratorMode = Flags::HardwareAccelerator::TUNNEL; } // initial flag values before we know which sub-effect to active (with setOffloadParam) // same as HIDL EffectProxy flags mSubFlags.type = Flags::Type::INSERT; mSubFlags.insert = Flags::Insert::LAST; mSubFlags.volume = Flags::Volume::CTRL; namespace android::effect { // set indication if any sub-effect indication was set mSubFlags.offloadIndication |= sub.common.flags.offloadIndication; mSubFlags.deviceIndication |= sub.common.flags.deviceIndication; mSubFlags.audioModeIndication |= sub.common.flags.audioModeIndication; mSubFlags.audioSourceIndication |= sub.common.flags.audioSourceIndication; // set bypass when all sub-effects are bypassing mSubFlags.bypass &= sub.common.flags.bypass; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus EffectProxy::create() { ALOGV("%s: %s", __func__, toString(mIdentity.type).c_str()); EffectProxy::EffectProxy(const AudioUuid& uuid, const std::vector<Descriptor>& descriptors, const std::shared_ptr<IFactory>& factory) : mDescriptorCommon(buildDescriptorCommon(uuid, descriptors)), mSubEffects( [](const std::vector<Descriptor>& descs, const std::shared_ptr<IFactory>& factory) { std::vector<SubEffect> subEffects; ALOG_ASSERT(factory, "invalid EffectFactory handle"); ndk::ScopedAStatus status = ndk::ScopedAStatus::ok(); for (auto& sub : mSubEffects) { auto& effectHandle = std::get<SubEffectTupleIndex::HANDLE>(sub.second); ALOGI("%s sub-effect %s", __func__, toString(sub.first.uuid).c_str()); status = mFactory->createEffect(sub.first.uuid, &effectHandle); if (!status.isOk() || !effectHandle) { ALOGE("%s sub-effect failed %s", __func__, toString(sub.first.uuid).c_str()); break; for (const auto& desc : descs) { SubEffect sub({.descriptor = desc}); status = factory->createEffect(desc.common.id.uuid, &sub.handle); if (!status.isOk() || !sub.handle) { ALOGW("%s create sub-effect %s failed", __func__, ::android::audio::utils::toString(desc.common.id.uuid).c_str()); } subEffects.emplace_back(sub); } return subEffects; }(descriptors, factory)), mFactory(factory) {} // destroy all created effects if failure if (!status.isOk()) { EffectProxy::~EffectProxy() { close(); destroy(); } return status; mSubEffects.clear(); } ndk::ScopedAStatus EffectProxy::destroy() { ALOGV("%s: %s", __func__, toString(mIdentity.type).c_str()); ALOGV("%s: %s", __func__, ::android::audio::utils::toString(mDescriptorCommon.id.type).c_str()); return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) { ndk::ScopedAStatus status = mFactory->destroyEffect(effect); if (status.isOk()) { Loading @@ -125,28 +77,24 @@ ndk::ScopedAStatus EffectProxy::destroy() { }); } const IEffect::OpenEffectReturn* EffectProxy::getEffectReturnParam() { return &std::get<SubEffectTupleIndex::RETURN>(mSubEffects[mActiveSub]); } 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 = std::get<SubEffectTupleIndex::DESCRIPTOR>(sub.second); ALOGI("%s: isOffload %d sub-effect: %s, flags %s", __func__, offload->isOffload, toString(desc.common.id.uuid).c_str(), desc.common.flags.toString().c_str()); const auto& desc = sub.descriptor; return offload->isOffload == (desc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL); }); if (itor == mSubEffects.end()) { ALOGE("%s no %soffload sub-effect found", __func__, offload->isOffload ? "" : "non-"); mActiveSubIdx = 0; return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER, "noActiveEffctFound"); } mActiveSub = itor->first; ALOGI("%s: active %soffload sub-effect: %s, flags %s", __func__, offload->isOffload ? "" : "non-", toString(mActiveSub.uuid).c_str(), std::get<SubEffectTupleIndex::DESCRIPTOR>(itor->second).common.flags.toString().c_str()); mActiveSubIdx = std::distance(mSubEffects.begin(), itor); ALOGV("%s: active %soffload sub-effect %zu descriptor: %s", __func__, offload->isOffload ? "" : "non-", mActiveSubIdx, ::android::audio::utils::toString(mSubEffects[mActiveSubIdx].descriptor.common.id.uuid) .c_str()); return ndk::ScopedAStatus::ok(); } Loading @@ -154,20 +102,24 @@ ndk::ScopedAStatus EffectProxy::setOffloadParam(const effect_offload_param_t* of ndk::ScopedAStatus EffectProxy::open(const Parameter::Common& common, const std::optional<Parameter::Specific>& specific, IEffect::OpenEffectReturn* ret __unused) { ALOGV("%s: %s", __func__, toString(mIdentity.type).c_str()); ndk::ScopedAStatus status = ndk::ScopedAStatus::fromExceptionCodeWithMessage( EX_ILLEGAL_ARGUMENT, "nullEffectHandle"); for (auto& sub : mSubEffects) { auto& effect = std::get<SubEffectTupleIndex::HANDLE>(sub.second); auto& openRet = std::get<SubEffectTupleIndex::RETURN>(sub.second); if (!effect || !(status = effect->open(common, specific, &openRet)).isOk()) { ALOGE("%s: failed to open UUID %s", __func__, toString(sub.first.uuid).c_str()); IEffect::OpenEffectReturn openReturn; if (!sub.handle || !(status = sub.handle->open(common, specific, &openReturn)).isOk()) { ALOGE("%s: failed to open %p UUID %s", __func__, sub.handle.get(), ::android::audio::utils::toString(sub.descriptor.common.id.uuid).c_str()); break; } sub.effectMq.statusQ = std::make_shared<StatusMQ>(openReturn.statusMQ); sub.effectMq.inputQ = std::make_shared<DataMQ>(openReturn.inputDataMQ); sub.effectMq.outputQ = std::make_shared<DataMQ>(openReturn.outputDataMQ); } // close all opened effects if failure if (!status.isOk()) { ALOGE("%s: closing all sub-effects with error %s", __func__, status.getDescription().c_str()); close(); } Loading @@ -175,38 +127,68 @@ ndk::ScopedAStatus EffectProxy::open(const Parameter::Common& common, } ndk::ScopedAStatus EffectProxy::close() { ALOGV("%s: %s", __func__, toString(mIdentity.type).c_str()); return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) { return effect->close(); }); } ndk::ScopedAStatus EffectProxy::getDescriptor(Descriptor* desc) { desc->common = mDescriptorCommon; desc->capability = mSubEffects[mActiveSubIdx].descriptor.capability; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus EffectProxy::buildDescriptor(const AudioUuid& uuid, const std::vector<Descriptor>& subEffectDescs, Descriptor* desc) { if (!desc) { ALOGE("%s: nuull descriptor pointer", __func__); ALOGE("%s: null descriptor pointer", __func__); return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER, "nullptr"); } auto& activeSubEffect = std::get<SubEffectTupleIndex::HANDLE>(mSubEffects[mActiveSub]); // return initial descriptor if no active sub-effect exist if (!activeSubEffect) { desc->common.id = mIdentity; desc->common.flags = mSubFlags; desc->common.name = "Proxy"; desc->common.implementor = "AOSP"; } else { *desc = std::get<SubEffectTupleIndex::DESCRIPTOR>(mSubEffects[mActiveSub]); desc->common.id = mIdentity; if (subEffectDescs.size() < 2) { ALOGE("%s: proxy need at least 2 sub-effects, got %zu", __func__, subEffectDescs.size()); return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "needMoreSubEffects"); } ALOGI("%s with %s", __func__, desc->toString().c_str()); desc->common = buildDescriptorCommon(uuid, subEffectDescs); return ndk::ScopedAStatus::ok(); } Descriptor::Common EffectProxy::buildDescriptorCommon( const AudioUuid& uuid, const std::vector<Descriptor>& subEffectDescs) { Descriptor::Common common; for (const auto& desc : subEffectDescs) { if (desc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL) { common.flags.hwAcceleratorMode = Flags::HardwareAccelerator::TUNNEL; } // initial flag values before we know which sub-effect to active (with setOffloadParam) // same as HIDL EffectProxy flags common.flags.type = Flags::Type::INSERT; common.flags.insert = Flags::Insert::LAST; common.flags.volume = Flags::Volume::CTRL; // 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; } // copy type UUID from any of sub-effects, all sub-effects should have same type common.id.type = subEffectDescs[0].common.id.type; // replace implementation UUID with proxy UUID. common.id.uuid = uuid; common.id.proxy = std::nullopt; common.name = "Proxy"; common.implementor = "AOSP"; return common; } // Handle with active sub-effect first, only send to other sub-effects when success ndk::ScopedAStatus EffectProxy::command(CommandId id) { ALOGV("%s: %s, command %s", __func__, toString(mIdentity.type).c_str(), android::internal::ToString(id).c_str()); return runWithActiveSubEffectThenOthers( [&](const std::shared_ptr<IEffect>& effect) -> ndk::ScopedAStatus { return effect->command(id); Loading Loading @@ -241,34 +223,30 @@ ndk::ScopedAStatus EffectProxy::runWithActiveSubEffectThenOthers( std::function<ndk::ScopedAStatus(const std::shared_ptr<IEffect>&)> const& func) { ndk::ScopedAStatus status = runWithActiveSubEffect(func); if (!status.isOk()) { return status; ALOGE("%s active sub-effect return error %s", __func__, status.getDescription().c_str()); } // proceed with others if active sub-effect success for (const auto& sub : mSubEffects) { auto& effect = std::get<SubEffectTupleIndex::HANDLE>(sub.second); if (sub.first != mActiveSub) { if (!effect) { // proceed with others for (size_t i = 0; i < mSubEffects.size() && i != mActiveSubIdx; i++) { if (!mSubEffects[i].handle) { ALOGE("%s null sub-effect interface for %s", __func__, sub.first.toString().c_str()); mSubEffects[i].descriptor.common.id.uuid.toString().c_str()); continue; } func(effect); } func(mSubEffects[i].handle); } return status; } ndk::ScopedAStatus EffectProxy::runWithActiveSubEffect( std::function<ndk::ScopedAStatus(const std::shared_ptr<IEffect>&)> const& func) { auto& effect = std::get<SubEffectTupleIndex::HANDLE>(mSubEffects[mActiveSub]); if (!effect) { if (!mSubEffects[mActiveSubIdx].handle) { ALOGE("%s null active sub-effect interface, active %s", __func__, mActiveSub.toString().c_str()); mSubEffects[mActiveSubIdx].descriptor.toString().c_str()); return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER, "activeSubEffectNull"); } return func(effect); return func(mSubEffects[mActiveSubIdx].handle); } ndk::ScopedAStatus EffectProxy::runWithAllSubEffects( Loading @@ -276,12 +254,11 @@ ndk::ScopedAStatus EffectProxy::runWithAllSubEffects( ndk::ScopedAStatus status = ndk::ScopedAStatus::ok(); // proceed with others if active sub-effect success for (auto& sub : mSubEffects) { auto& effect = std::get<SubEffectTupleIndex::HANDLE>(sub.second); if (!effect) { ALOGW("%s null sub-effect interface for %s", __func__, sub.first.toString().c_str()); if (!sub.handle) { ALOGW("%s null sub-effect interface %s", __func__, sub.descriptor.toString().c_str()); continue; } ndk::ScopedAStatus temp = func(effect); ndk::ScopedAStatus temp = func(sub.handle); if (!temp.isOk()) { status = ndk::ScopedAStatus::fromStatus(temp.getStatus()); } Loading @@ -289,5 +266,34 @@ ndk::ScopedAStatus EffectProxy::runWithAllSubEffects( return status; } } // namespace effect } // namespace android bool EffectProxy::isBypassing() const { return mSubEffects[mActiveSubIdx].descriptor.common.flags.bypass; } binder_status_t EffectProxy::dump(int fd, const char** args, uint32_t numArgs) { const std::string dumpString = toString(); write(fd, dumpString.c_str(), dumpString.size()); return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) { return ndk::ScopedAStatus::fromStatus(effect->dump(fd, args, numArgs)); }) .getStatus(); } std::string EffectProxy::toString(size_t level) const { std::string prefixSpace(level, ' '); std::string ss = prefixSpace + "EffectProxy:\n"; prefixSpace += " "; base::StringAppendF(&ss, "%sDescriptorCommon: %s\n", prefixSpace.c_str(), mDescriptorCommon.toString().c_str()); base::StringAppendF(&ss, "%sActiveSubIdx: %zu\n", prefixSpace.c_str(), mActiveSubIdx); base::StringAppendF(&ss, "%sAllSubEffects:\n", prefixSpace.c_str()); for (size_t i = 0; i < mSubEffects.size(); i++) { base::StringAppendF(&ss, "%s[%zu] - Handle: %p, %s\n", prefixSpace.c_str(), i, mSubEffects[i].handle ? mSubEffects[i].handle.get() : nullptr, mSubEffects[i].descriptor.toString().c_str()); } return ss; } } // namespace android::effect media/libaudiohal/impl/EffectProxy.h +62 −41 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
media/libaudiohal/impl/EffectConversionHelperAidl.cpp +25 −14 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * limitations under the License. */ #include <csignal> #include <cstddef> #include <cstdint> #include <cstring> Loading Loading @@ -194,11 +195,9 @@ status_t EffectConversionHelperAidl::handleSetConfig(uint32_t cmdSize, const voi statusTFromBinderStatus(mEffect->open(common, std::nullopt, &openReturn))); if (mIsProxyEffect) { const auto& ret = std::static_pointer_cast<EffectProxy>(mEffect)->getEffectReturnParam(); mStatusQ = std::make_shared<StatusMQ>(ret->statusMQ); mInputQ = std::make_shared<DataMQ>(ret->inputDataMQ); mOutputQ = std::make_shared<DataMQ>(ret->outputDataMQ); mStatusQ = std::static_pointer_cast<EffectProxy>(mEffect)->getStatusMQ(); mInputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getInputMQ(); mOutputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getOutputMQ(); } else { mStatusQ = std::make_shared<StatusMQ>(openReturn.statusMQ); mInputQ = std::make_shared<DataMQ>(openReturn.inputDataMQ); Loading @@ -206,6 +205,7 @@ status_t EffectConversionHelperAidl::handleSetConfig(uint32_t cmdSize, const voi } if (status_t status = updateEventFlags(); status != OK) { ALOGV("%s closing at status %d", __func__, status); mEffect->close(); return status; } Loading Loading @@ -353,14 +353,15 @@ status_t EffectConversionHelperAidl::handleSetOffload(uint32_t cmdSize, const vo ALOGI("%s offload param offload %s ioHandle %d", __func__, offload->isOffload ? "true" : "false", offload->ioHandle); mCommon.ioHandle = offload->ioHandle; RETURN_STATUS_IF_ERROR(statusTFromBinderStatus( std::static_pointer_cast<EffectProxy>(mEffect)->setOffloadParam(offload))); // update FMQs const auto& ret = std::static_pointer_cast<EffectProxy>(mEffect)->getEffectReturnParam(); mStatusQ = std::make_shared<StatusMQ>(ret->statusMQ); mInputQ = std::make_shared<DataMQ>(ret->inputDataMQ); mOutputQ = std::make_shared<DataMQ>(ret->outputDataMQ); RETURN_STATUS_IF_ERROR(updateEventFlags()); const auto& effectProxy = std::static_pointer_cast<EffectProxy>(mEffect); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(effectProxy->setOffloadParam(offload))); // update FMQs if the effect instance already open if (State state; effectProxy->getState(&state).isOk() && state != State::INIT) { mStatusQ = effectProxy->getStatusMQ(); mInputQ = effectProxy->getInputMQ(); mOutputQ = effectProxy->getOutputMQ(); updateEventFlags(); } } return *static_cast<int32_t*>(pReplyData) = OK; } Loading Loading @@ -408,17 +409,27 @@ status_t EffectConversionHelperAidl::handleVisualizerMeasure(uint32_t cmdSize __ status_t EffectConversionHelperAidl::updateEventFlags() { status_t status = BAD_VALUE; EventFlag* efGroup = nullptr; if (mStatusQ->isValid()) { if (mStatusQ && mStatusQ->isValid()) { status = EventFlag::createEventFlag(mStatusQ->getEventFlagWord(), &efGroup); if (status != OK || !efGroup) { ALOGE("%s: create EventFlagGroup failed, ret %d, egGroup %p", __func__, status, efGroup); status = (status == OK) ? BAD_VALUE : status; } } else if (isBypassing()) { // for effect with bypass (no processing) flag, it's okay to not have statusQ return OK; } mEfGroup.reset(efGroup, EventFlagDeleter()); return status; } bool EffectConversionHelperAidl::isBypassing() const { return mEffect && (mDesc.common.flags.bypass || (mIsProxyEffect && std::static_pointer_cast<EffectProxy>(mEffect)->isBypassing())); } } // namespace effect } // namespace android
media/libaudiohal/impl/EffectConversionHelperAidl.h +1 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ class EffectConversionHelperAidl { std::shared_ptr<DataMQ> getInputMQ() { return mInputQ; } std::shared_ptr<DataMQ> getOutputMQ() { return mOutputQ; } std::shared_ptr<android::hardware::EventFlag> getEventFlagGroup() { return mEfGroup; } bool isBypassing() const; protected: const int32_t mSessionId; Loading
media/libaudiohal/impl/EffectHalAidl.cpp +9 −3 Original line number Diff line number Diff line Loading @@ -74,9 +74,12 @@ EffectHalAidl::EffectHalAidl(const std::shared_ptr<IFactory>& factory, } EffectHalAidl::~EffectHalAidl() { if (mEffect) { mIsProxyEffect ? std::static_pointer_cast<EffectProxy>(mEffect)->destroy() : mFactory->destroyEffect(mEffect); if (mFactory && mEffect) { if (mIsProxyEffect) { std::static_pointer_cast<EffectProxy>(mEffect)->destroy(); } else { mFactory->destroyEffect(mEffect); } } } Loading Loading @@ -166,6 +169,9 @@ status_t EffectHalAidl::process() { auto inputQ = mConversion->getInputMQ(); auto outputQ = mConversion->getOutputMQ(); auto efGroup = mConversion->getEventFlagGroup(); if (mConversion->isBypassing()) { return OK; } if (!statusQ || !statusQ->isValid() || !inputQ || !inputQ->isValid() || !outputQ || !outputQ->isValid() || !efGroup) { ALOGE("%s invalid FMQ [Status %d I %d O %d] efGroup %p", __func__, Loading
media/libaudiohal/impl/EffectProxy.cpp +133 −127 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ #include <algorithm> #include <iterator> #include <memory> #define LOG_TAG "EffectProxy" // #define LOG_NDEBUG 0 Loading @@ -25,6 +26,7 @@ #include "EffectProxy.h" using ::aidl::android::hardware::audio::effect::Capability; using ::aidl::android::hardware::audio::effect::CommandId; using ::aidl::android::hardware::audio::effect::Descriptor; using ::aidl::android::hardware::audio::effect::Flags; Loading @@ -33,89 +35,39 @@ using ::aidl::android::hardware::audio::effect::IFactory; using ::aidl::android::hardware::audio::effect::Parameter; using ::aidl::android::hardware::audio::effect::State; using ::aidl::android::media::audio::common::AudioUuid; using ::android::audio::utils::toString; namespace android { namespace effect { EffectProxy::EffectProxy(const Descriptor::Identity& id, const std::shared_ptr<IFactory>& factory) : mIdentity([](const Descriptor::Identity& subId) { // update EffectProxy implementation UUID to the sub-effect proxy UUID ALOG_ASSERT(subId.proxy.has_value(), "Sub-effect Identity must have valid proxy UUID"); Descriptor::Identity tempId = subId; tempId.uuid = subId.proxy.value(); return tempId; }(id)), mFactory(factory) {} EffectProxy::~EffectProxy() { close(); destroy(); mSubEffects.clear(); } // sub effect must have same proxy UUID as EffectProxy, and the type UUID must match. ndk::ScopedAStatus EffectProxy::addSubEffect(const Descriptor& sub) { ALOGV("%s: %s", __func__, toString(mIdentity.type).c_str()); if (0 != mSubEffects.count(sub.common.id) || !sub.common.id.proxy.has_value() || sub.common.id.proxy.value() != mIdentity.uuid) { ALOGE("%s sub effect already exist or mismatch %s", __func__, sub.toString().c_str()); return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "illegalSubEffect"); } // not create sub-effect yet std::get<SubEffectTupleIndex::HANDLE>(mSubEffects[sub.common.id]) = nullptr; std::get<SubEffectTupleIndex::DESCRIPTOR>(mSubEffects[sub.common.id]) = sub; // set the last added sub-effect to active before setOffloadParam() mActiveSub = sub.common.id; ALOGI("%s add %s to proxy %s flag %s", __func__, mActiveSub.toString().c_str(), mIdentity.toString().c_str(), sub.common.flags.toString().c_str()); if (sub.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL) { mSubFlags.hwAcceleratorMode = Flags::HardwareAccelerator::TUNNEL; } // initial flag values before we know which sub-effect to active (with setOffloadParam) // same as HIDL EffectProxy flags mSubFlags.type = Flags::Type::INSERT; mSubFlags.insert = Flags::Insert::LAST; mSubFlags.volume = Flags::Volume::CTRL; namespace android::effect { // set indication if any sub-effect indication was set mSubFlags.offloadIndication |= sub.common.flags.offloadIndication; mSubFlags.deviceIndication |= sub.common.flags.deviceIndication; mSubFlags.audioModeIndication |= sub.common.flags.audioModeIndication; mSubFlags.audioSourceIndication |= sub.common.flags.audioSourceIndication; // set bypass when all sub-effects are bypassing mSubFlags.bypass &= sub.common.flags.bypass; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus EffectProxy::create() { ALOGV("%s: %s", __func__, toString(mIdentity.type).c_str()); EffectProxy::EffectProxy(const AudioUuid& uuid, const std::vector<Descriptor>& descriptors, const std::shared_ptr<IFactory>& factory) : mDescriptorCommon(buildDescriptorCommon(uuid, descriptors)), mSubEffects( [](const std::vector<Descriptor>& descs, const std::shared_ptr<IFactory>& factory) { std::vector<SubEffect> subEffects; ALOG_ASSERT(factory, "invalid EffectFactory handle"); ndk::ScopedAStatus status = ndk::ScopedAStatus::ok(); for (auto& sub : mSubEffects) { auto& effectHandle = std::get<SubEffectTupleIndex::HANDLE>(sub.second); ALOGI("%s sub-effect %s", __func__, toString(sub.first.uuid).c_str()); status = mFactory->createEffect(sub.first.uuid, &effectHandle); if (!status.isOk() || !effectHandle) { ALOGE("%s sub-effect failed %s", __func__, toString(sub.first.uuid).c_str()); break; for (const auto& desc : descs) { SubEffect sub({.descriptor = desc}); status = factory->createEffect(desc.common.id.uuid, &sub.handle); if (!status.isOk() || !sub.handle) { ALOGW("%s create sub-effect %s failed", __func__, ::android::audio::utils::toString(desc.common.id.uuid).c_str()); } subEffects.emplace_back(sub); } return subEffects; }(descriptors, factory)), mFactory(factory) {} // destroy all created effects if failure if (!status.isOk()) { EffectProxy::~EffectProxy() { close(); destroy(); } return status; mSubEffects.clear(); } ndk::ScopedAStatus EffectProxy::destroy() { ALOGV("%s: %s", __func__, toString(mIdentity.type).c_str()); ALOGV("%s: %s", __func__, ::android::audio::utils::toString(mDescriptorCommon.id.type).c_str()); return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) { ndk::ScopedAStatus status = mFactory->destroyEffect(effect); if (status.isOk()) { Loading @@ -125,28 +77,24 @@ ndk::ScopedAStatus EffectProxy::destroy() { }); } const IEffect::OpenEffectReturn* EffectProxy::getEffectReturnParam() { return &std::get<SubEffectTupleIndex::RETURN>(mSubEffects[mActiveSub]); } 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 = std::get<SubEffectTupleIndex::DESCRIPTOR>(sub.second); ALOGI("%s: isOffload %d sub-effect: %s, flags %s", __func__, offload->isOffload, toString(desc.common.id.uuid).c_str(), desc.common.flags.toString().c_str()); const auto& desc = sub.descriptor; return offload->isOffload == (desc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL); }); if (itor == mSubEffects.end()) { ALOGE("%s no %soffload sub-effect found", __func__, offload->isOffload ? "" : "non-"); mActiveSubIdx = 0; return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER, "noActiveEffctFound"); } mActiveSub = itor->first; ALOGI("%s: active %soffload sub-effect: %s, flags %s", __func__, offload->isOffload ? "" : "non-", toString(mActiveSub.uuid).c_str(), std::get<SubEffectTupleIndex::DESCRIPTOR>(itor->second).common.flags.toString().c_str()); mActiveSubIdx = std::distance(mSubEffects.begin(), itor); ALOGV("%s: active %soffload sub-effect %zu descriptor: %s", __func__, offload->isOffload ? "" : "non-", mActiveSubIdx, ::android::audio::utils::toString(mSubEffects[mActiveSubIdx].descriptor.common.id.uuid) .c_str()); return ndk::ScopedAStatus::ok(); } Loading @@ -154,20 +102,24 @@ ndk::ScopedAStatus EffectProxy::setOffloadParam(const effect_offload_param_t* of ndk::ScopedAStatus EffectProxy::open(const Parameter::Common& common, const std::optional<Parameter::Specific>& specific, IEffect::OpenEffectReturn* ret __unused) { ALOGV("%s: %s", __func__, toString(mIdentity.type).c_str()); ndk::ScopedAStatus status = ndk::ScopedAStatus::fromExceptionCodeWithMessage( EX_ILLEGAL_ARGUMENT, "nullEffectHandle"); for (auto& sub : mSubEffects) { auto& effect = std::get<SubEffectTupleIndex::HANDLE>(sub.second); auto& openRet = std::get<SubEffectTupleIndex::RETURN>(sub.second); if (!effect || !(status = effect->open(common, specific, &openRet)).isOk()) { ALOGE("%s: failed to open UUID %s", __func__, toString(sub.first.uuid).c_str()); IEffect::OpenEffectReturn openReturn; if (!sub.handle || !(status = sub.handle->open(common, specific, &openReturn)).isOk()) { ALOGE("%s: failed to open %p UUID %s", __func__, sub.handle.get(), ::android::audio::utils::toString(sub.descriptor.common.id.uuid).c_str()); break; } sub.effectMq.statusQ = std::make_shared<StatusMQ>(openReturn.statusMQ); sub.effectMq.inputQ = std::make_shared<DataMQ>(openReturn.inputDataMQ); sub.effectMq.outputQ = std::make_shared<DataMQ>(openReturn.outputDataMQ); } // close all opened effects if failure if (!status.isOk()) { ALOGE("%s: closing all sub-effects with error %s", __func__, status.getDescription().c_str()); close(); } Loading @@ -175,38 +127,68 @@ ndk::ScopedAStatus EffectProxy::open(const Parameter::Common& common, } ndk::ScopedAStatus EffectProxy::close() { ALOGV("%s: %s", __func__, toString(mIdentity.type).c_str()); return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) { return effect->close(); }); } ndk::ScopedAStatus EffectProxy::getDescriptor(Descriptor* desc) { desc->common = mDescriptorCommon; desc->capability = mSubEffects[mActiveSubIdx].descriptor.capability; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus EffectProxy::buildDescriptor(const AudioUuid& uuid, const std::vector<Descriptor>& subEffectDescs, Descriptor* desc) { if (!desc) { ALOGE("%s: nuull descriptor pointer", __func__); ALOGE("%s: null descriptor pointer", __func__); return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER, "nullptr"); } auto& activeSubEffect = std::get<SubEffectTupleIndex::HANDLE>(mSubEffects[mActiveSub]); // return initial descriptor if no active sub-effect exist if (!activeSubEffect) { desc->common.id = mIdentity; desc->common.flags = mSubFlags; desc->common.name = "Proxy"; desc->common.implementor = "AOSP"; } else { *desc = std::get<SubEffectTupleIndex::DESCRIPTOR>(mSubEffects[mActiveSub]); desc->common.id = mIdentity; if (subEffectDescs.size() < 2) { ALOGE("%s: proxy need at least 2 sub-effects, got %zu", __func__, subEffectDescs.size()); return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "needMoreSubEffects"); } ALOGI("%s with %s", __func__, desc->toString().c_str()); desc->common = buildDescriptorCommon(uuid, subEffectDescs); return ndk::ScopedAStatus::ok(); } Descriptor::Common EffectProxy::buildDescriptorCommon( const AudioUuid& uuid, const std::vector<Descriptor>& subEffectDescs) { Descriptor::Common common; for (const auto& desc : subEffectDescs) { if (desc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL) { common.flags.hwAcceleratorMode = Flags::HardwareAccelerator::TUNNEL; } // initial flag values before we know which sub-effect to active (with setOffloadParam) // same as HIDL EffectProxy flags common.flags.type = Flags::Type::INSERT; common.flags.insert = Flags::Insert::LAST; common.flags.volume = Flags::Volume::CTRL; // 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; } // copy type UUID from any of sub-effects, all sub-effects should have same type common.id.type = subEffectDescs[0].common.id.type; // replace implementation UUID with proxy UUID. common.id.uuid = uuid; common.id.proxy = std::nullopt; common.name = "Proxy"; common.implementor = "AOSP"; return common; } // Handle with active sub-effect first, only send to other sub-effects when success ndk::ScopedAStatus EffectProxy::command(CommandId id) { ALOGV("%s: %s, command %s", __func__, toString(mIdentity.type).c_str(), android::internal::ToString(id).c_str()); return runWithActiveSubEffectThenOthers( [&](const std::shared_ptr<IEffect>& effect) -> ndk::ScopedAStatus { return effect->command(id); Loading Loading @@ -241,34 +223,30 @@ ndk::ScopedAStatus EffectProxy::runWithActiveSubEffectThenOthers( std::function<ndk::ScopedAStatus(const std::shared_ptr<IEffect>&)> const& func) { ndk::ScopedAStatus status = runWithActiveSubEffect(func); if (!status.isOk()) { return status; ALOGE("%s active sub-effect return error %s", __func__, status.getDescription().c_str()); } // proceed with others if active sub-effect success for (const auto& sub : mSubEffects) { auto& effect = std::get<SubEffectTupleIndex::HANDLE>(sub.second); if (sub.first != mActiveSub) { if (!effect) { // proceed with others for (size_t i = 0; i < mSubEffects.size() && i != mActiveSubIdx; i++) { if (!mSubEffects[i].handle) { ALOGE("%s null sub-effect interface for %s", __func__, sub.first.toString().c_str()); mSubEffects[i].descriptor.common.id.uuid.toString().c_str()); continue; } func(effect); } func(mSubEffects[i].handle); } return status; } ndk::ScopedAStatus EffectProxy::runWithActiveSubEffect( std::function<ndk::ScopedAStatus(const std::shared_ptr<IEffect>&)> const& func) { auto& effect = std::get<SubEffectTupleIndex::HANDLE>(mSubEffects[mActiveSub]); if (!effect) { if (!mSubEffects[mActiveSubIdx].handle) { ALOGE("%s null active sub-effect interface, active %s", __func__, mActiveSub.toString().c_str()); mSubEffects[mActiveSubIdx].descriptor.toString().c_str()); return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER, "activeSubEffectNull"); } return func(effect); return func(mSubEffects[mActiveSubIdx].handle); } ndk::ScopedAStatus EffectProxy::runWithAllSubEffects( Loading @@ -276,12 +254,11 @@ ndk::ScopedAStatus EffectProxy::runWithAllSubEffects( ndk::ScopedAStatus status = ndk::ScopedAStatus::ok(); // proceed with others if active sub-effect success for (auto& sub : mSubEffects) { auto& effect = std::get<SubEffectTupleIndex::HANDLE>(sub.second); if (!effect) { ALOGW("%s null sub-effect interface for %s", __func__, sub.first.toString().c_str()); if (!sub.handle) { ALOGW("%s null sub-effect interface %s", __func__, sub.descriptor.toString().c_str()); continue; } ndk::ScopedAStatus temp = func(effect); ndk::ScopedAStatus temp = func(sub.handle); if (!temp.isOk()) { status = ndk::ScopedAStatus::fromStatus(temp.getStatus()); } Loading @@ -289,5 +266,34 @@ ndk::ScopedAStatus EffectProxy::runWithAllSubEffects( return status; } } // namespace effect } // namespace android bool EffectProxy::isBypassing() const { return mSubEffects[mActiveSubIdx].descriptor.common.flags.bypass; } binder_status_t EffectProxy::dump(int fd, const char** args, uint32_t numArgs) { const std::string dumpString = toString(); write(fd, dumpString.c_str(), dumpString.size()); return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) { return ndk::ScopedAStatus::fromStatus(effect->dump(fd, args, numArgs)); }) .getStatus(); } std::string EffectProxy::toString(size_t level) const { std::string prefixSpace(level, ' '); std::string ss = prefixSpace + "EffectProxy:\n"; prefixSpace += " "; base::StringAppendF(&ss, "%sDescriptorCommon: %s\n", prefixSpace.c_str(), mDescriptorCommon.toString().c_str()); base::StringAppendF(&ss, "%sActiveSubIdx: %zu\n", prefixSpace.c_str(), mActiveSubIdx); base::StringAppendF(&ss, "%sAllSubEffects:\n", prefixSpace.c_str()); for (size_t i = 0; i < mSubEffects.size(); i++) { base::StringAppendF(&ss, "%s[%zu] - Handle: %p, %s\n", prefixSpace.c_str(), i, mSubEffects[i].handle ? mSubEffects[i].handle.get() : nullptr, mSubEffects[i].descriptor.toString().c_str()); } return ss; } } // namespace android::effect
media/libaudiohal/impl/EffectProxy.h +62 −41 File changed.Preview size limit exceeded, changes collapsed. Show changes