From 95a3c3f7c2f22314bf835db69c4c3dd7622210b1 Mon Sep 17 00:00:00 2001 From: Iscle Date: Tue, 22 Apr 2025 01:16:20 +0200 Subject: [PATCH] Builds 3 versions with aosp build system --- Android.bp | 52 ++++- src/EffectThread.cpp | 130 +++++++++++ src/ViPER4Aidl.cpp | 539 +++++++++++++++++++++++++------------------ src/ViPER4Aidl.h | 153 +++--------- 4 files changed, 526 insertions(+), 348 deletions(-) create mode 100644 src/EffectThread.cpp diff --git a/Android.bp b/Android.bp index a6e3ac3..c707935 100644 --- a/Android.bp +++ b/Android.bp @@ -5,6 +5,9 @@ cc_defaults { // Main "src/viper/ViPER.cpp", "src/ViperContext.cpp", + "src/ViPER4Aidl.cpp", + "src/ViPER4Android.cpp", + "src/EffectThread.cpp", // Effects "src/viper/effects/AnalogX.cpp", "src/viper/effects/ColorfulMusic.cpp", @@ -60,29 +63,66 @@ cc_defaults { "-DVIPER_VERSION=20240314", "-Wno-unused-parameter", + "-DBACKEND_NDK", ], cppflags: [ "-Wno-unused-parameter", ], shared_libs: [ + "libaudioaidlcommon", + "libaudioutils", + "libbase", + "libbinder_ndk", + "libcutils", + "libfmq", "liblog", + "libutils", ], header_libs: [ "libaudioeffects", "libaudioutils_headers", + "libaudioaidl_headers", + "libaudio_system_headers", + "libsystem_headers", ], relative_install_path: "soundfx", } cc_library_shared { - name: "libv4a_re", + name: "libv4a_re-V1", defaults: [ - "aidlaudioeffectservice_defaults", "v4a_defaults", ], - srcs: [ - ":effectCommonFile", - "src/ViPER4Aidl.cpp", - "src/ViPER4Android.cpp", + shared_libs: [ + "android.hardware.audio.effect-V1-ndk", + ], + cflags: [ + "-DVIPER_AIDL_VERSION=1", + ], +} + +cc_library_shared { + name: "libv4a_re-V2", + defaults: [ + "v4a_defaults", + ], + shared_libs: [ + "android.hardware.audio.effect-V2-ndk", + ], + cflags: [ + "-DVIPER_AIDL_VERSION=2", + ], +} + +cc_library_shared { + name: "libv4a_re-V3", + defaults: [ + "v4a_defaults", + ], + shared_libs: [ + "android.hardware.audio.effect-V3-ndk", + ], + cflags: [ + "-DVIPER_AIDL_VERSION=3", ], } diff --git a/src/EffectThread.cpp b/src/EffectThread.cpp new file mode 100644 index 0000000..1a52c13 --- /dev/null +++ b/src/EffectThread.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#define LOG_TAG "AHAL_EffectThread" +#include +#include +#include + +#include "effect-impl/EffectThread.h" +#include "effect-impl/EffectTypes.h" + +namespace aidl::android::hardware::audio::effect { + +EffectThread::~EffectThread() { + destroyThread(); +} + +RetCode EffectThread::createThread(const std::string& name, int priority) { + if (mThread.joinable()) { + LOG(WARNING) << mName << __func__ << " thread already created, no-op"; + return RetCode::SUCCESS; + } + + mName = name; + mPriority = priority; + { + std::lock_guard lg(mThreadMutex); + mStop = true; + mExit = false; + } + + mThread = std::thread(&EffectThread::threadLoop, this); + LOG(VERBOSE) << mName << __func__ << " priority " << mPriority << " done"; + return RetCode::SUCCESS; +} + +RetCode EffectThread::destroyThread() { + { + std::lock_guard lg(mThreadMutex); + mStop = mExit = true; + } + + mCv.notify_one(); + if (mThread.joinable()) { + mThread.join(); + } + + LOG(VERBOSE) << mName << __func__; + return RetCode::SUCCESS; +} + +RetCode EffectThread::startThread() { + { + std::lock_guard lg(mThreadMutex); + if (mDraining) { + mDraining = false; + } else { + mStop = false; + } + mCv.notify_one(); + } + + LOG(VERBOSE) << mName << __func__; + return RetCode::SUCCESS; +} + +RetCode EffectThread::stopThread() { + { + std::lock_guard lg(mThreadMutex); + mStop = true; + mCv.notify_one(); + } + + LOG(VERBOSE) << mName << __func__; + return RetCode::SUCCESS; +} + +RetCode EffectThread::startDraining() { + std::lock_guard lg(mThreadMutex); + mDraining = true; + mCv.notify_one(); + + LOG(VERBOSE) << mName << __func__; + return RetCode::SUCCESS; +} + +RetCode EffectThread::finishDraining() { + std::lock_guard lg(mThreadMutex); + mDraining = false; + mStop = true; + mCv.notify_one(); + + LOG(VERBOSE) << mName << __func__; + return RetCode::SUCCESS; +} + +void EffectThread::threadLoop() { + pthread_setname_np(pthread_self(), mName.substr(0, kMaxTaskNameLen - 1).c_str()); + setpriority(PRIO_PROCESS, 0, mPriority); + while (true) { + { + std::unique_lock l(mThreadMutex); + ::android::base::ScopedLockAssertion lock_assertion(mThreadMutex); + mCv.wait(l, [&]() REQUIRES(mThreadMutex) { return mExit || !mStop; }); + if (mExit) { + LOG(VERBOSE) << mName << " threadLoop EXIT!"; + return; + } + } + process(); + } +} + +} // namespace aidl::android::hardware::audio::effect diff --git a/src/ViPER4Aidl.cpp b/src/ViPER4Aidl.cpp index c621762..d345b58 100644 --- a/src/ViPER4Aidl.cpp +++ b/src/ViPER4Aidl.cpp @@ -1,244 +1,335 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * 2025 anonymix007 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#define LOG_TAG "ViPER4Aidl" -#include - -#include -#include -#include -#include - -#include #include "ViPER4Aidl.h" +#include +#include +using aidl::android::hardware::audio::effect::CommandId; using aidl::android::hardware::audio::effect::Descriptor; -using aidl::android::hardware::audio::effect::DefaultExtension; -using aidl::android::hardware::audio::effect::ViperAidl; -using aidl::android::hardware::audio::effect::getEffectImplUuidViper; -using aidl::android::hardware::audio::effect::getEffectTypeUuidViper; +using aidl::android::hardware::audio::effect::Flags; using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::hardware::audio::effect::Parameter; +using aidl::android::hardware::audio::effect::RetCode; using aidl::android::hardware::audio::effect::State; -using aidl::android::hardware::audio::effect::VendorExtension; using aidl::android::media::audio::common::AudioUuid; +using aidl::android::media::audio::common::PcmType; +using android::hardware::EventFlag; -extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, - std::shared_ptr* instanceSpp) { - if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidViper()) { - LOG(ERROR) << __func__ << "uuid not supported"; - return EX_ILLEGAL_ARGUMENT; - } - if (instanceSpp) { - *instanceSpp = ndk::SharedRefBase::make(); - LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created"; - return EX_NONE; - } else { - LOG(ERROR) << __func__ << " invalid input parameter!"; - return EX_ILLEGAL_ARGUMENT; +/** + * EventFlag to indicate that the data FMQ is not Empty after a write. + * TODO: b/277900230, Define in future AIDL version. + */ +static constexpr uint32_t kEventFlagDataMqNotEmpty = 0x1 << 11; + +inline AudioUuid stringToUuid(const char* str) { + AudioUuid uuid{}; + uint32_t tmp[10]; + if (!str || sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", tmp, + tmp + 1, tmp + 2, tmp + 3, tmp + 4, tmp + 5, tmp + 6, + tmp + 7, tmp + 8, tmp + 9) < 10) { + return uuid; } + + uuid.timeLow = (uint32_t)tmp[0]; + uuid.timeMid = (uint16_t)tmp[1]; + uuid.timeHiAndVersion = (uint16_t)tmp[2]; + uuid.clockSeq = (uint16_t)tmp[3]; + uuid.node.insert(uuid.node.end(), {(uint8_t)tmp[4], (uint8_t)tmp[5], (uint8_t)tmp[6], + (uint8_t)tmp[7], (uint8_t)tmp[8], (uint8_t)tmp[9]}); + return uuid; } -extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) { - if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidViper()) { - LOG(ERROR) << __func__ << "uuid not supported"; +const AudioUuid kType = stringToUuid("b9bc100c-26cd-42e6-acb6-cad8c3f778de"); +const AudioUuid kUuid = stringToUuid("90380da3-8536-4744-a6a3-5731970e640f"); +const Descriptor kDescriptor = { + .common = { + .id = { + .type = kType, + .uuid = kUuid, + .proxy = std::nullopt + }, + .flags = { + .type = Flags::Type::INSERT, + .insert = Flags::Insert::LAST, + .volume = Flags::Volume::NONE + }, + .name = "ViPER4Android", + .implementor = "Iscle", + }, +}; + +constexpr size_t getPcmSampleSizeInBytes(::aidl::android::media::audio::common::PcmType pcm) { + using ::aidl::android::media::audio::common::PcmType; + switch (pcm) { + case PcmType::UINT_8_BIT: + return 1; + case PcmType::INT_16_BIT: + return 2; + case PcmType::INT_32_BIT: + return 4; + case PcmType::FIXED_Q_8_24: + return 4; + case PcmType::FLOAT_32_BIT: + return 4; + case PcmType::INT_24_BIT: + return 3; + } + return 0; +} + +constexpr size_t getChannelCount( + const ::aidl::android::media::audio::common::AudioChannelLayout& layout, + int32_t mask = std::numeric_limits::max()) { + using Tag = ::aidl::android::media::audio::common::AudioChannelLayout::Tag; + switch (layout.getTag()) { + case Tag::none: + return 0; + case Tag::invalid: + return 0; + case Tag::indexMask: + return __builtin_popcount(layout.get() & mask); + case Tag::layoutMask: + return __builtin_popcount(layout.get() & mask); + case Tag::voiceMask: + return __builtin_popcount(layout.get() & mask); + } + return 0; +} + +constexpr size_t getFrameSizeInBytes( + const ::aidl::android::media::audio::common::AudioFormatDescription& format, + const ::aidl::android::media::audio::common::AudioChannelLayout& layout) { + if (format == ::aidl::android::media::audio::common::AudioFormatDescription{}) { + // Unspecified format. + return 0; + } + using ::aidl::android::media::audio::common::AudioFormatType; + if (format.type == AudioFormatType::PCM) { + return getPcmSampleSizeInBytes(format.pcm) * getChannelCount(layout); + } else if (format.type == AudioFormatType::NON_PCM) { + // For non-PCM formats always use the underlying PCM size. The default value for + // PCM is "UINT_8_BIT", thus non-encapsulated streams have the frame size of 1. + return getPcmSampleSizeInBytes(format.pcm); + } + // Something unexpected. + return 0; +} + +//int ViPER4AndroidAIDL::notifyEventFlag(uint32_t flag) { +// if (!mEventFlag) { +// ALOGE("notifyEventFlag: StatusEventFlag invalid"); +// return -1; +// } +// if (const auto ret = mEventFlag->wake(flag); ret != ::android::OK) { +// ALOGE("notifyEventFlag: wake failure with ret %d", ret); +// return -1; +// } +// return 0; +//} + +ndk::ScopedAStatus ViPER4AndroidAIDL::open(const Parameter::Common &common, + const std::optional &specific, + IEffect::OpenEffectReturn *ret) { + ALOGD("open called"); + if (common.input.base.format.pcm != PcmType::FLOAT_32_BIT || + common.output.base.format.pcm != PcmType::FLOAT_32_BIT) { + ALOGE("open called with invalid PCM type"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + std::lock_guard lg(mImplMutex); + + ALOGD("mImplMutex locked"); + + if (mState != State::INIT) { + ALOGD("open: already opened"); + return ndk::ScopedAStatus::ok(); + } + + size_t mInputFrameSize = getFrameSizeInBytes( + common.input.base.format, common.input.base.channelMask); + size_t mOutputFrameSize = getFrameSizeInBytes( + common.output.base.format, common.output.base.channelMask); + + size_t inBufferSizeInFloat = common.input.frameCount * mInputFrameSize / sizeof(float); + size_t outBufferSizeInFloat = common.output.frameCount * mOutputFrameSize / sizeof(float); + + ALOGD("open: inBufferSizeInFloat %zu, outBufferSizeInFloat %zu", inBufferSizeInFloat, + outBufferSizeInFloat); + + // only status FMQ use the EventFlag + mStatusMQ = std::make_shared(1, true /*configureEventFlagWord*/); + mInputMQ = std::make_shared(inBufferSizeInFloat); + mOutputMQ = std::make_shared(outBufferSizeInFloat); + + if (!mStatusMQ || !mInputMQ || !mOutputMQ) { + ALOGE("open: failed to create message queues"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + + ALOGD("message queues created"); + ALOGD("open: mStatusMQ %p, mInputMQ %p, mOutputMQ %p", mStatusMQ.get(), mInputMQ.get(), + mOutputMQ.get()); + + if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) { + ALOGE("open: failed to create message queues"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + + android::status_t status = EventFlag::createEventFlag( + mStatusMQ->getEventFlagWord(), &mEventFlag); + if (status != android::OK || mEventFlag == nullptr) { + ALOGE("open: failed to create event flag"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + + ALOGD("open: event flag created"); + + mWorkBuffer.resize(std::max(inBufferSizeInFloat, outBufferSizeInFloat)); + + ALOGD("open: work buffer size %zu", mWorkBuffer.size()); + + if (specific.has_value()) { + ALOGD("open: specific parameters provided, ignoring for now..."); + } + + mState = State::IDLE; + + ALOGD("open: state set to IDLE"); + + ret->statusMQ = mStatusMQ->dupeDesc(); + ret->inputDataMQ = mInputMQ->dupeDesc(); + ret->outputDataMQ = mOutputMQ->dupeDesc(); + + ALOGD("open: mq descriptors set"); + + if (createThread("ViPER4Android") != RetCode::SUCCESS) { + ALOGE("open: failed to create thread"); + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + + ALOGD("open: thread created"); + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus ViPER4AndroidAIDL::close() { + ALOGD("close called"); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus +ViPER4AndroidAIDL::getDescriptor(Descriptor *descriptor) { + ALOGD("getDescriptor: returning descriptor"); + *descriptor = kDescriptor; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus ViPER4AndroidAIDL::command(CommandId id) { + std::lock_guard lg(mImplMutex); + if (mState == State::INIT) { + ALOGE("command: instance not open"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + + switch (id) { + case CommandId::START: { + ALOGD("command: START"); + + if (mState == State::PROCESSING) { + return ndk::ScopedAStatus::ok(); + } + mState = State::PROCESSING; + +// if (notifyEventFlag() != 0) { +// ALOGE("id: failed to notify event flag"); +// return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); +// } + startThread(); + break; + } + case CommandId::STOP: { + ALOGD("command: STOP"); + + if (mState == State::IDLE) { + return ndk::ScopedAStatus::ok(); + } + mState = State::IDLE; + + stopThread(); + break; + } + case CommandId::RESET: { + ALOGD("command: RESET"); + mState = State::IDLE; + stopThread(); + break; + } + default: + ALOGE("command: unknown command %d", static_cast(id)); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus ViPER4AndroidAIDL::getState(State *state) { + ALOGD("getState: returning state"); + *state = mState; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus +ViPER4AndroidAIDL::setParameter(const Parameter ¶meter) { + ALOGD("setParameter called"); + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus +ViPER4AndroidAIDL::getParameter(const Parameter::Id &id, Parameter *param) { + ALOGD("getParameter called"); + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +#if VIPER_AIDL_VERSION >= 2 +ndk::ScopedAStatus +ViPER4AndroidAIDL::reopen(IEffect::OpenEffectReturn *open_effect_return) { + std::lock_guard lg(mImplMutex); + if (mState == State::INIT) { + ALOGE("reopen: already closed"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + // TODO + return ndk::ScopedAStatus::ok(); +} +#endif + +void ViPER4AndroidAIDL::process() { + ALOGD("process called"); +} + +extern "C" binder_exception_t createEffect(const AudioUuid *audio_uuid, std::shared_ptr *instance) { + if (audio_uuid == nullptr || instance == nullptr) { + ALOGE("createEffect called with null arguments"); return EX_ILLEGAL_ARGUMENT; } - *_aidl_return = ViperAidl::kDesc; + ALOGD("createEffect: creating effect instance"); + *instance = ndk::SharedRefBase::make(); return EX_NONE; } -namespace aidl::android::hardware::audio::effect { - -const std::string ViperAidl::kEffectName = VIPER_NAME; - -const Descriptor ViperAidl::kDesc = {.common = {.id = {.type = getEffectTypeUuidViper(), - .uuid = getEffectImplUuidViper()}, - .flags = {.type = Flags::Type::INSERT, - .insert = Flags::Insert::LAST, - .volume = Flags::Volume::CTRL}, - .name = ViperAidl::kEffectName, - .implementor = VIPER_AUTHORS}}; - -ndk::ScopedAStatus ViperAidl::getDescriptor(Descriptor* _aidl_return) { - LOG(DEBUG) << __func__ << kDesc.toString(); - *_aidl_return = kDesc; - return ndk::ScopedAStatus::ok(); +extern "C" binder_exception_t destroyEffect(const std::shared_ptr &instance) { + ALOGD("destroyEffect called"); + return EX_ILLEGAL_STATE; } -ndk::ScopedAStatus ViperAidl::setParameterSpecific(const Parameter::Specific& specific) { - LOG(DEBUG) << __func__ << ": " << specific.toString(); - RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext"); - RETURN_IF(Parameter::Specific::vendorEffect != specific.getTag(), EX_ILLEGAL_ARGUMENT, "EffectNotSupported"); - auto& vendorEffect = specific.get(); - std::optional defaultExt; - RETURN_IF(STATUS_OK != vendorEffect.extension.getParcelable(&defaultExt), EX_ILLEGAL_ARGUMENT, "getParcelableFailed"); - RETURN_IF(!defaultExt.has_value(), EX_ILLEGAL_ARGUMENT, "parcelableNull"); - -#ifdef AIDL_DEBUG - LOG(DEBUG) << __func__ << ": defaultExt: " << defaultExt->toString(); -#endif - - int32_t ret = 0; - uint32_t ret_size = sizeof(ret); - RETURN_IF(mContext->handleCommand(EFFECT_CMD_SET_PARAM, defaultExt->bytes.size(), defaultExt->bytes.data(), &ret_size, &ret) != 0, EX_ILLEGAL_ARGUMENT, "handleCommandFailed"); - RETURN_IF(ret != 0, EX_ILLEGAL_ARGUMENT, "handleCommandInternalFailed"); - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus ViperAidl::getParameterSpecific(const Parameter::Id& id, - Parameter::Specific* specific) { - LOG(DEBUG) << __func__ << ": " << specific->toString(); - RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext"); - RETURN_IF(Parameter::Id::vendorEffectTag != id.getTag(), EX_ILLEGAL_ARGUMENT, "wrongIdTag"); - auto extensionId = id.get(); - std::optional defaultIdExt; - RETURN_IF(STATUS_OK != extensionId.extension.getParcelable(&defaultIdExt), EX_ILLEGAL_ARGUMENT, "getIdParcelableFailed"); - RETURN_IF(!defaultIdExt.has_value(), EX_ILLEGAL_ARGUMENT, "parcelableIdNull"); - -#ifdef AIDL_DEBUG - LOG(DEBUG) << __func__ << ": defaultIdExt: " << defaultIdExt->toString(); -#endif - - VendorExtension extension; - DefaultExtension defaultExt; - defaultExt.bytes.resize(sizeof(effect_param_t) + 2 * sizeof(int32_t)); - uint32_t data_size = defaultExt.bytes.size(); - RETURN_IF(mContext->handleCommand(EFFECT_CMD_GET_PARAM, defaultIdExt->bytes.size(), defaultIdExt->bytes.data(), &data_size, defaultExt.bytes.data()) != 0, EX_ILLEGAL_ARGUMENT, "handleCommandFailed"); - assert(data_size <= defaultExt.bytes.size()); - defaultExt.bytes.resize(data_size); - -#ifdef AIDL_DEBUG - LOG(DEBUG) << __func__ << ": defaultExt: " << defaultExt.toString(); -#endif - - RETURN_IF(STATUS_OK != extension.extension.setParcelable(defaultExt), EX_ILLEGAL_ARGUMENT, "setParcelableFailed"); - specific->set(extension); - return ndk::ScopedAStatus::ok(); -} - -std::shared_ptr ViperAidl::createContext(const Parameter::Common& common) { - if (mContext) { - LOG(DEBUG) << __func__ << " context already exists"; - } else { - mContext = std::make_shared(1 /* statusFmqDepth */, common); - int32_t ret = 0; - uint32_t ret_size = sizeof(ret); - int32_t status = mContext->handleCommand(EFFECT_CMD_INIT, 0, NULL, &ret_size, &ret); - if (status < 0) { - LOG(ERROR) << __func__ << ": ViperContext::handleCommand failed: " << status; - mContext = nullptr; - return mContext; - } - if (ret < 0) { - LOG(ERROR) << __func__ << ": ViperContext::handleCommand failed (internal): " << ret; - mContext = nullptr; - return mContext; - } - ret = 0; - ret_size = sizeof(ret); - effect_config_t conf; - - if (!aidl2legacy_ParameterCommon_effect_config_t(common, conf)) { - LOG(ERROR) << __func__ << ": JamesDSPAIDL::createContext: aidl2legacy_ParameterCommon_effect_config_t failed"; - mContext = nullptr; - return mContext; - } - - status = mContext->handleCommand(EFFECT_CMD_SET_CONFIG, sizeof(conf), &conf, &ret_size, &ret); - if (status < 0) { - LOG(ERROR) << __func__ << ": ViperContext::handleCommand failed: " << status; - mContext = nullptr; - return mContext; - } - if (ret < 0) { - LOG(ERROR) << __func__ << ": ViperContext::handleCommand failed (internal): " << ret; - mContext = nullptr; - return mContext; - } +extern "C" binder_exception_t queryEffect(const AudioUuid *audio_uuid, Descriptor *descriptor) { + if (audio_uuid == nullptr || descriptor == nullptr) { + ALOGE("queryEffect called with null arguments"); + return EX_ILLEGAL_ARGUMENT; } - - return mContext; -} - -ndk::ScopedAStatus ViperAidl::commandImpl(CommandId command) { - RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext"); - int32_t ret = 0; - uint32_t ret_size = sizeof(ret); - switch (command) { - case CommandId::START: - RETURN_IF(mContext->handleCommand(EFFECT_CMD_ENABLE, 0, NULL, &ret_size, &ret) != 0, EX_ILLEGAL_ARGUMENT, "handleCommandFailed"); - RETURN_IF(ret != 0, EX_ILLEGAL_ARGUMENT, "handleCommandInternalFailed"); - break; - case CommandId::STOP: - RETURN_IF(mContext->handleCommand(EFFECT_CMD_DISABLE, 0, NULL, &ret_size, &ret) != 0, EX_ILLEGAL_ARGUMENT, "handleCommandFailed"); - RETURN_IF(ret != 0, EX_ILLEGAL_ARGUMENT, "handleCommandInternalFailed"); - break; - case CommandId::RESET: - mImplContext->resetBuffer(); - break; - default: - break; + if (*audio_uuid != kUuid) { + ALOGE("queryEffect called with invalid uuid"); + return EX_ILLEGAL_ARGUMENT; } - return ndk::ScopedAStatus::ok(); + ALOGD("queryEffect: returning descriptor"); + *descriptor = kDescriptor; + return EX_NONE; } - - -RetCode ViperAidl::releaseContext() { - if (mContext) { - int32_t ret = 0; - uint32_t ret_size = sizeof(ret); - int32_t status = mContext->handleCommand(EFFECT_CMD_RESET, 0, NULL, &ret_size, &ret); - if (status < 0) { - LOG(ERROR) << __func__ << ": ViperContext::handleCommand failed: " << status; - return RetCode::ERROR_ILLEGAL_PARAMETER; - } - if (ret < 0) { - LOG(ERROR) << __func__ << ": ViperContext::handleCommand failed (internal): " << ret; - return RetCode::ERROR_ILLEGAL_PARAMETER; - } - mContext.reset(); - } - return RetCode::SUCCESS; -} - -// Processing method running in EffectWorker thread. -IEffect::Status ViperAidl::effectProcessImpl(float* in_, float* out_, int samples) { - size_t frames = static_cast(samples) / 2; - audio_buffer_t in{frames, {in_}}, out{frames, {out_}}; - -#ifdef AIDL_DEBUG - LOG(DEBUG) << __func__ << " in " << in_ << " out " << out_ << " samples " << samples; -#endif - int32_t ret = mContext->process(&in, &out); -#ifdef AIDL_DEBUG - LOG(DEBUG) << __func__ << ": mContext->process: " << ret; -#endif - - switch(ret) { - case 0: - return {STATUS_OK, samples, samples}; - case -ENODATA: - return {STATUS_NOT_ENOUGH_DATA, 0, 0}; - default: - return {STATUS_INVALID_OPERATION, 0, 0}; - } -} - -} // namespace aidl::android::hardware::audio::effect diff --git a/src/ViPER4Aidl.h b/src/ViPER4Aidl.h index 54f46e2..5c5934d 100644 --- a/src/ViPER4Aidl.h +++ b/src/ViPER4Aidl.h @@ -1,128 +1,45 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * 2025 anonymix007 - * - * 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. - */ - #pragma once +#include +#include #include #include -#include -#include +#include -#include "effect-impl/EffectImpl.h" +using aidl::android::hardware::common::fmq::SynchronizedReadWrite; +using aidl::android::hardware::audio::effect::BnEffect; +using aidl::android::hardware::audio::effect::CommandId; +using aidl::android::hardware::audio::effect::Descriptor; +using aidl::android::hardware::audio::effect::EffectThread; +using aidl::android::hardware::audio::effect::Parameter; +using aidl::android::hardware::audio::effect::State; -#include "ViperContext.h" +class ViPER4AndroidAIDL : public BnEffect, public EffectThread { +public: + // BnEffect + ndk::ScopedAStatus open(const Parameter::Common &common, const std::optional &specific, IEffect::OpenEffectReturn *ret) override; + ndk::ScopedAStatus close() override; + ndk::ScopedAStatus getDescriptor(Descriptor *_aidl_return) override; + ndk::ScopedAStatus command(CommandId id) override; + ndk::ScopedAStatus getState(State *_aidl_return) override; + ndk::ScopedAStatus setParameter(const Parameter &in_param) override; + ndk::ScopedAStatus getParameter(const Parameter::Id &in_paramId, Parameter *_aidl_return) override; +#if VIPER_AIDL_VERSION >= 2 + ndk::ScopedAStatus reopen(IEffect::OpenEffectReturn *_aidl_return) override; +#endif -namespace aidl::android::hardware::audio::effect { + // EffectThread + void process() override; +private: + typedef android::AidlMessageQueue StatusMQ; + typedef android::AidlMessageQueue DataMQ; -static inline bool aidl2legacy_ParameterCommon_effect_config_t(const Parameter::Common& common, effect_config_t &conf) { - // FIXME: This shouldn't be false - auto tmp = ::aidl::android::aidl2legacy_AudioConfig_buffer_config_t(common.input, false); - if (tmp.ok()) { - conf.inputCfg = tmp.value(); - } else { - return false; - } + std::mutex mImplMutex; + State mState = State::INIT; - tmp = ::aidl::android::aidl2legacy_AudioConfig_buffer_config_t(common.output, false); - if (tmp.ok()) { - conf.outputCfg = tmp.value(); - } else {; - return false; - } - - return true; -} - -class ViperAidlContext final : public EffectContext, public ViperContext { - public: - ViperAidlContext(int statusDepth, const Parameter::Common& common) - : EffectContext(statusDepth, common), - ViperContext() { - LOG(DEBUG) << __func__; - } - - RetCode setCommon(const Parameter::Common& common) override { - if (auto ret = EffectContext::setCommon(common); ret != RetCode::SUCCESS) { - return ret; - } - - int32_t ret = 0; - uint32_t ret_size = sizeof(ret); - effect_config_t conf; - - if (!aidl2legacy_ParameterCommon_effect_config_t(common, conf)) { - LOG(ERROR) << __func__ << ": ViperAidlContext::setCommon: aidl2legacy_ParameterCommon_effect_config_t failed"; - return RetCode::ERROR_ILLEGAL_PARAMETER; - } - - int32_t status = handleCommand(EFFECT_CMD_SET_CONFIG, sizeof(conf), &conf, &ret_size, &ret); - if (status < 0) { - LOG(ERROR) << __func__ << ": ViperAidlContext::handleCommand SET CONFIG failed: " << status; - return RetCode::ERROR_ILLEGAL_PARAMETER; - } - if (ret < 0) { - LOG(ERROR) << __func__ << ": ViperAidlContext::handleCommand SET CONFIG failed (internal): " << ret; - return RetCode::ERROR_ILLEGAL_PARAMETER; - } - return RetCode::SUCCESS; - } + std::shared_ptr mStatusMQ; + std::shared_ptr mInputMQ; + std::shared_ptr mOutputMQ; + android::hardware::EventFlag *mEventFlag; + std::vector mWorkBuffer; }; - -class ViperAidl final : public EffectImpl { - public: - static const std::string kEffectName; - static const Capability kEqCap; - static const Descriptor kDesc; - - ViperAidl() { LOG(DEBUG) << __func__; } - ~ViperAidl() { - cleanUp(); - LOG(DEBUG) << __func__; - } - - ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; - ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) - REQUIRES(mImplMutex) override; - ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific) - REQUIRES(mImplMutex) override; - - std::shared_ptr createContext(const Parameter::Common& common) - REQUIRES(mImplMutex) override; - ndk::ScopedAStatus commandImpl(CommandId id) REQUIRES(mImplMutex); - - RetCode releaseContext() REQUIRES(mImplMutex) override; - - IEffect::Status effectProcessImpl(float* in, float* out, int samples) - REQUIRES(mImplMutex) override; - std::string getEffectName() override { return kEffectName; } - - private: - std::shared_ptr mContext; -}; - -constexpr char kEffectImplUuidViper[] = "90380da3-8536-4744-a6a3-5731970e640f"; -inline const AudioUuid& getEffectImplUuidViper() { - static const ::android::base::NoDestructor uuid(stringToUuid(kEffectImplUuidViper)); - return *uuid; -} - -constexpr char kEffectTypeUuidViper[] = "b9bc100c-26cd-42e6-acb6-cad8c3f778de"; -inline const AudioUuid& getEffectTypeUuidViper() { - static const ::android::base::NoDestructor uuid(stringToUuid(kEffectTypeUuidViper)); - return *uuid; -} -} // namespace aidl::android::hardware::audio::effect