AIDL effect: Add all aosp effects default implementation

Bug: 238913361
Test: atest VtsHalAudioEffectTargetTest
atest VtsHalAudioEffectFactoryTargetTest
atest VtsHalEqualizerTargetTest

Change-Id: I6825ba77ae0707f97e852f0faa52ce3486ba2af5
This commit is contained in:
Shunkai Yao
2022-10-26 22:47:20 +00:00
parent 82a6f7a8ad
commit 6afc855087
41 changed files with 2851 additions and 472 deletions

View File

@@ -68,10 +68,20 @@ cc_defaults {
],
vendor: true,
shared_libs: [
"libaudioaidlcommon",
"libbase",
"libbinder_ndk",
"libcutils",
"libfmq",
"liblog",
"libutils",
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
"android.hardware.audio.effect-V1-ndk",
"libequalizer",
],
header_libs: [
"libaudioaidl_headers",
"libsystem_headers",
],
cflags: [
"-Wall",
@@ -81,24 +91,12 @@ cc_defaults {
],
}
cc_library_static {
name: "libaudioeffectserviceexampleimpl",
defaults: ["aidlaudioeffectservice_defaults"],
export_include_dirs: ["include"],
srcs: [
"EffectFactory.cpp",
],
header_libs: [
"libsystem_headers",
],
visibility: [
":__subpackages__",
],
}
filegroup {
name: "effectCommonFile",
srcs: ["EffectThread.cpp"],
srcs: [
"EffectThread.cpp",
"EffectImpl.cpp",
],
}
cc_binary {
@@ -107,10 +105,21 @@ cc_binary {
init_rc: ["android.hardware.audio.effect.service-aidl.example.rc"],
vintf_fragments: ["android.hardware.audio.effect.service-aidl.xml"],
defaults: ["aidlaudioeffectservice_defaults"],
static_libs: [
"libaudioeffectserviceexampleimpl",
shared_libs: [
"libbassboostsw",
"libdynamicsprocessingsw",
"libequalizersw",
"libhapticgeneratorsw",
"libloudnessenhancersw",
"libreverbsw",
"libvirtualizersw",
"libvisualizersw",
"libvolumesw",
],
srcs: [
"EffectMain.cpp",
"EffectFactory.cpp",
],
srcs: ["EffectMain.cpp"],
}
cc_library_headers {

View File

@@ -18,6 +18,7 @@
#include <android-base/logging.h>
#include <dlfcn.h>
#include "effect-impl/EffectTypes.h"
#include "effect-impl/EffectUUID.h"
#include "effectFactory-impl/EffectFactory.h"
@@ -26,27 +27,21 @@ using aidl::android::media::audio::common::AudioUuid;
namespace aidl::android::hardware::audio::effect {
Factory::Factory() {
std::function<void(void*)> dlClose = [](void* handle) -> void {
if (handle && dlclose(handle)) {
LOG(ERROR) << "dlclose failed " << dlerror();
}
};
// TODO: implement this with audio_effect.xml.
auto libHandle =
std::unique_ptr<void, decltype(dlClose)>{dlopen("libequalizer.so", RTLD_LAZY), dlClose};
if (!libHandle) {
LOG(ERROR) << __func__ << ": dlopen failed, err: " << dlerror();
return;
}
LOG(DEBUG) << __func__ << " dlopen uuid: " << EqualizerSwImplUUID.toString() << " handle "
<< libHandle;
mEffectLibMap.insert({EqualizerSwImplUUID, std::make_pair(std::move(libHandle), nullptr)});
Descriptor::Identity id;
id.type = EqualizerTypeUUID;
id.uuid = EqualizerSwImplUUID;
mIdentityList.push_back(id);
// TODO: get list of library UUID and name from audio_effect.xml.
openEffectLibrary(EqualizerTypeUUID, EqualizerSwImplUUID, std::nullopt, "libequalizersw.so");
openEffectLibrary(EqualizerTypeUUID, EqualizerBundleImplUUID, std::nullopt, "libbundleaidl.so");
openEffectLibrary(BassBoostTypeUUID, BassBoostSwImplUUID, std::nullopt, "libbassboostsw.so");
openEffectLibrary(DynamicsProcessingTypeUUID, DynamicsProcessingSwImplUUID, std::nullopt,
"libdynamicsprocessingsw.so");
openEffectLibrary(HapticGeneratorTypeUUID, HapticGeneratorSwImplUUID, std::nullopt,
"libhapticgeneratorsw.so");
openEffectLibrary(LoudnessEnhancerTypeUUID, LoudnessEnhancerSwImplUUID, std::nullopt,
"libloudnessenhancersw.so");
openEffectLibrary(ReverbTypeUUID, ReverbSwImplUUID, std::nullopt, "libreverbsw.so");
openEffectLibrary(VirtualizerTypeUUID, VirtualizerSwImplUUID, std::nullopt,
"libvirtualizersw.so");
openEffectLibrary(VisualizerTypeUUID, VisualizerSwImplUUID, std::nullopt, "libvisualizersw.so");
openEffectLibrary(VolumeTypeUUID, VolumeSwImplUUID, std::nullopt, "libvolumesw.so");
}
Factory::~Factory() {
@@ -64,12 +59,16 @@ Factory::~Factory() {
ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type_uuid,
const std::optional<AudioUuid>& in_impl_uuid,
const std::optional<AudioUuid>& in_proxy_uuid,
std::vector<Descriptor::Identity>* _aidl_return) {
std::copy_if(mIdentityList.begin(), mIdentityList.end(), std::back_inserter(*_aidl_return),
[&](auto& desc) {
return (!in_type_uuid.has_value() || in_type_uuid.value() == desc.type) &&
(!in_impl_uuid.has_value() || in_impl_uuid.value() == desc.uuid);
});
std::copy_if(
mIdentityList.begin(), mIdentityList.end(), std::back_inserter(*_aidl_return),
[&](auto& desc) {
return (!in_type_uuid.has_value() || in_type_uuid.value() == desc.type) &&
(!in_impl_uuid.has_value() || in_impl_uuid.value() == desc.uuid) &&
(!in_proxy_uuid.has_value() ||
(desc.proxy.has_value() && in_proxy_uuid.value() == desc.proxy.value()));
});
return ndk::ScopedAStatus::ok();
}
@@ -96,43 +95,37 @@ ndk::ScopedAStatus Factory::queryProcessing(const std::optional<Processing::Type
ndk::ScopedAStatus Factory::createEffect(const AudioUuid& in_impl_uuid,
std::shared_ptr<IEffect>* _aidl_return) {
LOG(DEBUG) << __func__ << ": UUID " << in_impl_uuid.toString();
if (in_impl_uuid == EqualizerSwImplUUID) {
if (mEffectLibMap.count(in_impl_uuid)) {
auto& lib = mEffectLibMap[in_impl_uuid];
// didn't do dlsym yet
if (nullptr == lib.second) {
void* libHandle = lib.first.get();
struct effect_interface_s intf = {
.createEffectFunc = (EffectCreateFunctor)dlsym(libHandle, "createEffect"),
.destroyEffectFunc =
(EffectDestroyFunctor)dlsym(libHandle, "destroyEffect")};
auto dlInterface = std::make_unique<struct effect_interface_s>(intf);
if (!dlInterface->createEffectFunc || !dlInterface->destroyEffectFunc) {
LOG(ERROR) << __func__
<< ": create or destroy symbol not exist in library: " << libHandle
<< "!";
return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
}
lib.second = std::move(dlInterface);
}
auto& libInterface = lib.second;
std::shared_ptr<IEffect> effectSp;
RETURN_IF_BINDER_EXCEPTION(libInterface->createEffectFunc(&effectSp));
if (!effectSp) {
LOG(ERROR) << __func__ << ": library created null instance without return error!";
if (mEffectLibMap.count(in_impl_uuid)) {
auto& lib = mEffectLibMap[in_impl_uuid];
// didn't do dlsym yet
if (nullptr == lib.second) {
void* libHandle = lib.first.get();
auto dlInterface = std::make_unique<struct effect_dl_interface_s>();
dlInterface->createEffectFunc = (EffectCreateFunctor)dlsym(libHandle, "createEffect");
dlInterface->destroyEffectFunc =
(EffectDestroyFunctor)dlsym(libHandle, "destroyEffect");
if (!dlInterface->createEffectFunc || !dlInterface->destroyEffectFunc) {
LOG(ERROR) << __func__
<< ": create or destroy symbol not exist in library: " << libHandle
<< " with dlerror: " << dlerror();
return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
}
*_aidl_return = effectSp;
mEffectUuidMap[std::weak_ptr<IEffect>(effectSp)] = in_impl_uuid;
LOG(DEBUG) << __func__ << ": instance " << effectSp.get() << " created successfully";
return ndk::ScopedAStatus::ok();
} else {
LOG(ERROR) << __func__ << ": library doesn't exist";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
lib.second = std::move(dlInterface);
}
auto& libInterface = lib.second;
std::shared_ptr<IEffect> effectSp;
RETURN_IF_BINDER_EXCEPTION(libInterface->createEffectFunc(&in_impl_uuid, &effectSp));
if (!effectSp) {
LOG(ERROR) << __func__ << ": library created null instance without return error!";
return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
}
*_aidl_return = effectSp;
mEffectUuidMap[std::weak_ptr<IEffect>(effectSp)] = in_impl_uuid;
LOG(DEBUG) << __func__ << ": instance " << effectSp.get() << " created successfully";
return ndk::ScopedAStatus::ok();
} else {
LOG(ERROR) << __func__ << ": UUID not supported";
LOG(ERROR) << __func__ << ": library doesn't exist";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
return ndk::ScopedAStatus::ok();
@@ -179,4 +172,34 @@ ndk::ScopedAStatus Factory::destroyEffect(const std::shared_ptr<IEffect>& in_han
return status;
}
void Factory::openEffectLibrary(const AudioUuid& type, const AudioUuid& impl,
const std::optional<AudioUuid>& proxy, const std::string& libName) {
std::function<void(void*)> dlClose = [](void* handle) -> void {
if (handle && dlclose(handle)) {
LOG(ERROR) << "dlclose failed " << dlerror();
}
};
auto libHandle =
std::unique_ptr<void, decltype(dlClose)>{dlopen(libName.c_str(), RTLD_LAZY), dlClose};
if (!libHandle) {
LOG(ERROR) << __func__ << ": dlopen failed, err: " << dlerror();
return;
}
LOG(DEBUG) << __func__ << " dlopen lib:" << libName << " for uuid:\ntype:" << type.toString()
<< "\nimpl:" << impl.toString()
<< "\nproxy:" << (proxy.has_value() ? proxy.value().toString() : "null")
<< "\nhandle:" << libHandle;
mEffectLibMap.insert({impl, std::make_pair(std::move(libHandle), nullptr)});
Descriptor::Identity id;
id.type = type;
id.uuid = impl;
if (proxy.has_value()) {
id.proxy = proxy.value();
}
mIdentityList.push_back(id);
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,256 @@
/*
* 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.
*/
#define LOG_TAG "AHAL_EffectImpl"
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectTypes.h"
#include "include/effect-impl/EffectTypes.h"
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus EffectImpl::open(const Parameter::Common& common,
const std::optional<Parameter::Specific>& specific,
OpenEffectReturn* ret) {
LOG(DEBUG) << __func__;
{
std::lock_guard lg(mMutex);
RETURN_OK_IF(mState != State::INIT);
mContext = createContext(common);
RETURN_IF(!mContext, EX_ILLEGAL_ARGUMENT, "createContextFailed");
setContext(mContext);
}
RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
if (specific.has_value()) {
RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
}
RETURN_IF(createThread(LOG_TAG) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
"FailedToCreateWorker");
{
std::lock_guard lg(mMutex);
mContext->dupeFmq(ret);
mState = State::IDLE;
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EffectImpl::close() {
std::lock_guard lg(mMutex);
RETURN_OK_IF(mState == State::INIT);
RETURN_IF(mState == State::PROCESSING, EX_ILLEGAL_STATE, "closeAtProcessing");
// stop the worker thread, ignore the return code
RETURN_IF(destroyThread() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
"FailedToDestroyWorker");
RETURN_IF(releaseContext() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
"FailedToCreateWorker");
mState = State::INIT;
LOG(DEBUG) << __func__;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) {
LOG(DEBUG) << __func__ << " with: " << param.toString();
auto tag = param.getTag();
switch (tag) {
case Parameter::common:
case Parameter::deviceDescription:
case Parameter::mode:
case Parameter::source:
FALLTHROUGH_INTENDED;
case Parameter::volumeStereo:
return setParameterCommon(param);
case Parameter::specific: {
return setParameterSpecific(param.get<Parameter::specific>());
}
default: {
LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"ParameterNotSupported");
}
}
}
ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter* param) {
LOG(DEBUG) << __func__ << id.toString();
auto tag = id.getTag();
switch (tag) {
case Parameter::Id::commonTag: {
RETURN_IF_ASTATUS_NOT_OK(getParameterCommon(id.get<Parameter::Id::commonTag>(), param),
"CommonParamNotSupported");
break;
}
case Parameter::Id::vendorEffectTag: {
LOG(DEBUG) << __func__ << " noop for vendor tag";
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"vendortagNotSupported");
}
default: {
Parameter::Specific specific;
RETURN_IF_ASTATUS_NOT_OK(getParameterSpecific(id, &specific), "SpecParamNotSupported");
param->set<Parameter::specific>(specific);
break;
}
}
LOG(DEBUG) << __func__ << param->toString();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
auto tag = param.getTag();
switch (tag) {
case Parameter::common:
RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setCommFailed");
break;
case Parameter::deviceDescription:
RETURN_IF(mContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
break;
case Parameter::mode:
RETURN_IF(mContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setModeFailed");
break;
case Parameter::source:
RETURN_IF(mContext->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setSourceFailed");
break;
case Parameter::volumeStereo:
RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
break;
default: {
LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"commonParamNotSupported");
}
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Parameter* param) {
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
switch (tag) {
case Parameter::common: {
param->set<Parameter::common>(mContext->getCommon());
break;
}
case Parameter::deviceDescription: {
param->set<Parameter::deviceDescription>(mContext->getOutputDevice());
break;
}
case Parameter::mode: {
param->set<Parameter::mode>(mContext->getAudioMode());
break;
}
case Parameter::source: {
param->set<Parameter::source>(mContext->getAudioSource());
break;
}
case Parameter::volumeStereo: {
param->set<Parameter::volumeStereo>(mContext->getVolumeStereo());
break;
}
default: {
LOG(DEBUG) << __func__ << " unsupported tag " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"tagNotSupported");
}
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EffectImpl::getState(State* state) {
std::lock_guard lg(mMutex);
*state = mState;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EffectImpl::command(CommandId command) {
std::lock_guard lg(mMutex);
LOG(DEBUG) << __func__ << ": receive command: " << toString(command) << " at state "
<< toString(mState);
RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
switch (command) {
case CommandId::START:
RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
RETURN_OK_IF(mState == State::PROCESSING);
RETURN_IF_ASTATUS_NOT_OK(commandStart(), "commandStartFailed");
mState = State::PROCESSING;
startThread();
return ndk::ScopedAStatus::ok();
case CommandId::STOP:
RETURN_OK_IF(mState == State::IDLE);
mState = State::IDLE;
RETURN_IF_ASTATUS_NOT_OK(commandStop(), "commandStopFailed");
stopThread();
return ndk::ScopedAStatus::ok();
case CommandId::RESET:
RETURN_OK_IF(mState == State::IDLE);
mState = State::IDLE;
RETURN_IF_ASTATUS_NOT_OK(commandStop(), "commandStopFailed");
stopThread();
mContext->resetBuffer();
return ndk::ScopedAStatus::ok();
default:
LOG(ERROR) << __func__ << " instance still processing";
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"CommandIdNotSupported");
}
LOG(DEBUG) << __func__ << " transfer to state: " << toString(mState);
return ndk::ScopedAStatus::ok();
}
void EffectImpl::cleanUp() {
command(CommandId::STOP);
close();
}
IEffect::Status EffectImpl::status(binder_status_t status, size_t consumed, size_t produced) {
IEffect::Status ret;
ret.status = status;
ret.fmqConsumed = consumed;
ret.fmqProduced = produced;
return ret;
}
// A placeholder processing implementation to copy samples from input to output
IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int processSamples) {
// lock before access context/parameters
std::lock_guard lg(mMutex);
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
RETURN_VALUE_IF(!mContext, status, "nullContext");
auto frameSize = mContext->getInputFrameSize();
RETURN_VALUE_IF(0 == frameSize, status, "frameSizeIs0");
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << processSamples
<< " frames " << processSamples * sizeof(float) / frameSize;
for (int i = 0; i < processSamples; i++) {
*out++ = *in++;
}
LOG(DEBUG) << __func__ << " done processing " << processSamples << " samples";
return {STATUS_OK, processSamples, processSamples};
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,40 @@
/*
* 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.
*/
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_shared {
name: "libbassboostsw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"BassBoostSw.cpp",
":effectCommonFile",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
}

View File

@@ -0,0 +1,118 @@
/*
* 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 <cstddef>
#define LOG_TAG "AHAL_BassBoostSw"
#include <Utils.h>
#include <algorithm>
#include <unordered_set>
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "BassBoostSw.h"
using aidl::android::hardware::audio::effect::BassBoostSw;
using aidl::android::hardware::audio::effect::BassBoostSwImplUUID;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != BassBoostSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<BassBoostSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
LOG(ERROR) << __func__ << " invalid input parameter!";
return EX_ILLEGAL_ARGUMENT;
}
}
extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
if (!instanceSp) {
return EX_NONE;
}
State state;
ndk::ScopedAStatus status = instanceSp->getState(&state);
if (!status.isOk() || State::INIT != state) {
LOG(ERROR) << __func__ << " instance " << instanceSp.get()
<< " in state: " << toString(state) << ", status: " << status.getDescription();
return EX_ILLEGAL_STATE;
}
LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus BassBoostSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus BassBoostSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::bassBoost != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::bassBoost>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus BassBoostSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::bassBoostTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
specific->set<Parameter::Specific::bassBoost>(mSpecificParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> BassBoostSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
return mContext;
}
mContext = std::make_shared<BassBoostSwContext>(1 /* statusFmqDepth */, common);
return mContext;
}
RetCode BassBoostSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status BassBoostSw::effectProcessImpl(float* in, float* out, int process) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
for (int i = 0; i < process; i++) {
*out++ = *in++;
}
return {STATUS_OK, process, process};
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,72 @@
/*
* 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.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
namespace aidl::android::hardware::audio::effect {
class BassBoostSwContext : public EffectContext {
public:
BassBoostSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
// TODO: add specific context here
};
class BassBoostSw : public EffectImpl {
public:
BassBoostSw() { LOG(DEBUG) << __func__; }
~BassBoostSw() {
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
RetCode releaseContext() override;
private:
std::shared_ptr<BassBoostSwContext> mContext;
/* capabilities */
const BassBoost::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = BassBoostTypeUUID,
.uuid = BassBoostSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "BassBoostSw"},
.capability = Capability::make<Capability::bassBoost>(kCapability)};
/* parameters */
BassBoost mSpecificParam;
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,40 @@
/*
* 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.
*/
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_shared {
name: "libdynamicsprocessingsw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"DynamicsProcessingSw.cpp",
":effectCommonFile",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
}

View File

@@ -0,0 +1,119 @@
/*
* 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 <cstddef>
#define LOG_TAG "AHAL_DynamicsProcessingSw"
#include <Utils.h>
#include <algorithm>
#include <unordered_set>
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "DynamicsProcessingSw.h"
using aidl::android::hardware::audio::effect::DynamicsProcessingSw;
using aidl::android::hardware::audio::effect::DynamicsProcessingSwImplUUID;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != DynamicsProcessingSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<DynamicsProcessingSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
LOG(ERROR) << __func__ << " invalid input parameter!";
return EX_ILLEGAL_ARGUMENT;
}
}
extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
if (!instanceSp) {
return EX_NONE;
}
State state;
ndk::ScopedAStatus status = instanceSp->getState(&state);
if (!status.isOk() || State::INIT != state) {
LOG(ERROR) << __func__ << " instance " << instanceSp.get()
<< " in state: " << toString(state) << ", status: " << status.getDescription();
return EX_ILLEGAL_STATE;
}
LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus DynamicsProcessingSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus DynamicsProcessingSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::dynamicsProcessing>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus DynamicsProcessingSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
specific->set<Parameter::Specific::dynamicsProcessing>(mSpecificParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> DynamicsProcessingSw::createContext(
const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
return mContext;
}
mContext = std::make_shared<DynamicsProcessingSwContext>(1 /* statusFmqDepth */, common);
return mContext;
}
RetCode DynamicsProcessingSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, int process) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
for (int i = 0; i < process; i++) {
*out++ = *in++;
}
return {STATUS_OK, process, process};
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,72 @@
/*
* 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.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
namespace aidl::android::hardware::audio::effect {
class DynamicsProcessingSwContext : public EffectContext {
public:
DynamicsProcessingSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
// TODO: add specific context here
};
class DynamicsProcessingSw : public EffectImpl {
public:
DynamicsProcessingSw() { LOG(DEBUG) << __func__; }
~DynamicsProcessingSw() {
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
RetCode releaseContext() override;
private:
std::shared_ptr<DynamicsProcessingSwContext> mContext;
/* capabilities */
const DynamicsProcessing::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = DynamicsProcessingTypeUUID,
.uuid = DynamicsProcessingSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "DynamicsProcessingSw"},
.capability = Capability::make<Capability::dynamicsProcessing>(kCapability)};
/* parameters */
DynamicsProcessing mSpecificParam;
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -24,15 +24,9 @@ package {
}
cc_library_shared {
name: "libequalizer",
vendor: true,
shared_libs: [
"libaudioaidlcommon",
"libbase",
"android.hardware.common-V2-ndk",
],
name: "libequalizersw",
defaults: [
"aidlaudioservice_defaults",
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
@@ -40,12 +34,6 @@ cc_library_shared {
"Equalizer.cpp",
":effectCommonFile",
],
cflags: [
"-Wall",
"-Wextra",
"-Werror",
"-Wthread-safety",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],

View File

@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <cstddef>
#define LOG_TAG "AHAL_EqualizerSw"
#include <Utils.h>
#include <algorithm>
@@ -24,11 +25,18 @@
#include "equalizer-impl/EqualizerSw.h"
using android::hardware::audio::common::getFrameSizeInBytes;
using aidl::android::hardware::audio::effect::EqualizerSw;
using aidl::android::hardware::audio::effect::EqualizerSwImplUUID;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
namespace aidl::android::hardware::audio::effect {
extern "C" binder_exception_t createEffect(std::shared_ptr<IEffect>* instanceSpp) {
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != EqualizerSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<EqualizerSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
@@ -51,212 +59,39 @@ extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& inst
return EX_NONE;
}
ndk::ScopedAStatus EqualizerSw::open(const Parameter::Common& common,
const Parameter::Specific& specific,
OpenEffectReturn* _aidl_return) {
LOG(DEBUG) << __func__;
if (mState != State::INIT) {
LOG(WARNING) << __func__ << " eq already open";
return ndk::ScopedAStatus::ok();
}
// Set essential parameters before create worker thread.
setCommonParameter(common);
setSpecificParameter(specific);
LOG(DEBUG) << " common: " << common.toString() << " specific " << specific.toString();
auto& input = common.input;
auto& output = common.output;
size_t inputFrameSize = getFrameSizeInBytes(input.base.format, input.base.channelMask);
size_t outputFrameSize = getFrameSizeInBytes(output.base.format, output.base.channelMask);
mContext = std::make_shared<EqualizerSwContext>(1, input.frameCount * inputFrameSize,
output.frameCount * outputFrameSize);
if (!mContext) {
LOG(ERROR) << __func__ << " created EqualizerSwContext failed";
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_UNSUPPORTED_OPERATION,
"FailedToCreateFmq");
}
setContext(mContext);
// create the worker thread
if (RetCode::SUCCESS != createThread(LOG_TAG)) {
LOG(ERROR) << __func__ << " created worker thread failed";
mContext.reset();
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_UNSUPPORTED_OPERATION,
"FailedToCreateWorker");
}
_aidl_return->statusMQ = mContext->getStatusFmq()->dupeDesc();
_aidl_return->inputDataMQ = mContext->getInputDataFmq()->dupeDesc();
_aidl_return->outputDataMQ = mContext->getOutputDataFmq()->dupeDesc();
mState = State::IDLE;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EqualizerSw::close() {
if (mState == State::INIT) {
LOG(WARNING) << __func__ << " instance already closed";
return ndk::ScopedAStatus::ok();
} else if (mState == State::PROCESSING) {
LOG(ERROR) << __func__ << " instance still processing";
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
"EqInstanceProcessing");
}
// stop the worker thread
mState = State::INIT;
destroyThread();
mContext.reset();
LOG(DEBUG) << __func__;
return ndk::ScopedAStatus::ok();
}
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus EqualizerSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << mDesc.toString();
*_aidl_return = mDesc;
LOG(DEBUG) << __func__ << kDesc.toString();
*_aidl_return = kDesc;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EqualizerSw::command(CommandId in_commandId) {
LOG(DEBUG) << __func__ << ": receive command:" << toString(in_commandId);
if (mState == State::INIT) {
LOG(ERROR) << __func__ << ": instance not open yet";
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
"CommandStateError");
}
switch (in_commandId) {
case CommandId::START:
// start processing.
mState = State::PROCESSING;
startThread();
LOG(DEBUG) << __func__ << " state: " << toString(mState);
return ndk::ScopedAStatus::ok();
case CommandId::STOP:
// stop processing.
mState = State::IDLE;
stopThread();
LOG(DEBUG) << __func__ << " state: " << toString(mState);
return ndk::ScopedAStatus::ok();
case CommandId::RESET:
// TODO: reset buffer status.
mState = State::IDLE;
stopThread();
LOG(DEBUG) << __func__ << " state: " << toString(mState);
return ndk::ScopedAStatus::ok();
default:
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"CommandIdNotSupported");
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EqualizerSw::setParameter(const Parameter& in_param) {
if (mState == State::INIT) {
LOG(ERROR) << __func__ << ": instance not open yet";
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, "StateError");
}
LOG(DEBUG) << __func__ << " with: " << in_param.toString();
auto tag = in_param.getTag();
switch (tag) {
case Parameter::common: {
return setCommonParameter(in_param.get<Parameter::common>());
}
case Parameter::specific: {
return setSpecificParameter(in_param.get<Parameter::specific>());
}
default:
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"ParameterNotSupported");
}
}
ndk::ScopedAStatus EqualizerSw::getParameter(const Parameter::Id& in_paramId,
Parameter* _aidl_return) {
LOG(DEBUG) << __func__ << in_paramId.toString();
auto tag = in_paramId.getTag();
switch (tag) {
case Parameter::Id::commonTag: {
_aidl_return->set<Parameter::common>(mCommonParam);
LOG(DEBUG) << __func__ << " get: " << _aidl_return->toString();
return ndk::ScopedAStatus::ok();
}
case Parameter::Id::specificId: {
auto& id = in_paramId.get<Parameter::Id::specificId>();
Parameter::Specific specific;
ndk::ScopedAStatus status = getSpecificParameter(id, &specific);
if (!status.isOk()) {
LOG(ERROR) << __func__
<< " getSpecificParameter error: " << status.getDescription();
return status;
}
_aidl_return->set<Parameter::specific>(specific);
LOG(DEBUG) << __func__ << _aidl_return->toString();
return ndk::ScopedAStatus::ok();
}
case Parameter::Id::vendorTag: {
LOG(DEBUG) << __func__ << " noop for vendor tag now";
return ndk::ScopedAStatus::ok();
}
}
LOG(ERROR) << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"Parameter:IdNotSupported");
}
ndk::ScopedAStatus EqualizerSw::getState(State* _aidl_return) {
*_aidl_return = mState;
return ndk::ScopedAStatus::ok();
}
/// Private methods.
ndk::ScopedAStatus EqualizerSw::setCommonParameter(const Parameter::Common& common) {
mCommonParam = common;
LOG(DEBUG) << __func__ << " set: " << mCommonParam.toString();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EqualizerSw::setSpecificParameter(const Parameter::Specific& specific) {
if (Parameter::Specific::equalizer != specific.getTag()) {
LOG(ERROR) << " unsupported effect: " << specific.toString();
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
}
ndk::ScopedAStatus EqualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::equalizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
auto& eqParam = specific.get<Parameter::Specific::equalizer>();
auto tag = eqParam.getTag();
switch (tag) {
case Equalizer::bandLevels: {
auto& bandLevels = eqParam.get<Equalizer::bandLevels>();
const auto& [minItem, maxItem] = std::minmax_element(
bandLevels.begin(), bandLevels.end(),
[](const auto& a, const auto& b) { return a.index < b.index; });
if (bandLevels.size() >= NUM_OF_BANDS || minItem->index < 0 ||
maxItem->index >= NUM_OF_BANDS) {
LOG(ERROR) << " bandLevels " << bandLevels.size() << "minIndex " << minItem->index
<< "maxIndex " << maxItem->index << " illegal ";
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"ExceedMaxBandNum");
}
mBandLevels = bandLevels;
return ndk::ScopedAStatus::ok();
}
case Equalizer::preset: {
int preset = eqParam.get<Equalizer::preset>();
if (preset < 0 || preset >= NUM_OF_PRESETS) {
LOG(ERROR) << " preset: " << preset << " invalid";
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"ExceedMaxBandNum");
}
mPreset = preset;
LOG(DEBUG) << __func__ << " preset set to " << mPreset;
RETURN_IF(mContext->setEqPreset(eqParam.get<Equalizer::preset>()) != RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setBandLevelsFailed");
return ndk::ScopedAStatus::ok();
}
case Equalizer::vendor: {
LOG(DEBUG) << __func__ << " noop for vendor tag now";
case Equalizer::bandLevels: {
RETURN_IF(mContext->setEqBandLevels(eqParam.get<Equalizer::bandLevels>()) !=
RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setBandLevelsFailed");
return ndk::ScopedAStatus::ok();
}
default: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"EqTagNotSupported");
}
}
LOG(ERROR) << __func__ << " unsupported eq param tag: " << toString(tag);
@@ -264,59 +99,72 @@ ndk::ScopedAStatus EqualizerSw::setSpecificParameter(const Parameter::Specific&
"ParamNotSupported");
}
ndk::ScopedAStatus EqualizerSw::getSpecificParameter(Parameter::Specific::Id id,
ndk::ScopedAStatus EqualizerSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
Equalizer eqParam;
auto tag = id.getTag();
if (tag != Parameter::Specific::Id::equalizerTag) {
LOG(ERROR) << " invalid tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"UnsupportedTag");
RETURN_IF(Parameter::Id::equalizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
auto eqId = id.get<Parameter::Id::equalizerTag>();
auto eqIdTag = eqId.getTag();
switch (eqIdTag) {
case Equalizer::Id::commonTag:
return getParameterEqualizer(eqId.get<Equalizer::Id::commonTag>(), specific);
default:
LOG(ERROR) << __func__ << " tag " << toString(eqIdTag) << " not supported";
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"EqualizerTagNotSupported");
}
auto eqTag = id.get<Parameter::Specific::Id::equalizerTag>();
switch (eqTag) {
}
ndk::ScopedAStatus EqualizerSw::getParameterEqualizer(const Equalizer::Tag& tag,
Parameter::Specific* specific) {
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
Equalizer eqParam;
switch (tag) {
case Equalizer::bandLevels: {
eqParam.set<Equalizer::bandLevels>(mBandLevels);
specific->set<Parameter::Specific::equalizer>(eqParam);
return ndk::ScopedAStatus::ok();
eqParam.set<Equalizer::bandLevels>(mContext->getEqBandLevels());
break;
}
case Equalizer::preset: {
eqParam.set<Equalizer::preset>(mPreset);
LOG(DEBUG) << __func__ << " preset " << mPreset;
specific->set<Parameter::Specific::equalizer>(eqParam);
return ndk::ScopedAStatus::ok();
eqParam.set<Equalizer::preset>(mContext->getEqPreset());
break;
}
case Equalizer::vendor: {
LOG(DEBUG) << __func__ << " noop for vendor tag now";
return ndk::ScopedAStatus::ok();
default: {
LOG(ERROR) << __func__ << " not handled tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"unsupportedTag");
}
}
LOG(ERROR) << __func__ << " unsupported eq param: " << toString(eqTag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"ParamNotSupported");
specific->set<Parameter::Specific::equalizer>(eqParam);
return ndk::ScopedAStatus::ok();
}
void EqualizerSw::cleanUp() {
if (State::PROCESSING == mState) {
command(CommandId::STOP);
}
if (State::INIT != mState) {
close();
std::shared_ptr<EffectContext> EqualizerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
return mContext;
}
mContext = std::make_shared<EqualizerSwContext>(1 /* statusFmqDepth */, common);
return mContext;
}
IEffect::Status EqualizerSw::status(binder_status_t status, size_t consumed, size_t produced) {
IEffect::Status ret;
ret.status = status;
ret.fmqByteConsumed = consumed;
ret.fmqByteProduced = produced;
return ret;
RetCode EqualizerSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status EqualizerSw::effectProcessImpl() {
IEffect::Status EqualizerSw::effectProcessImpl(float* in, float* out, int process) {
// TODO: get data buffer and process.
return status(STATUS_OK, mContext->availableToRead(), mContext->availableToWrite());
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
for (int i = 0; i < process; i++) {
*out++ = *in++;
}
return {STATUS_OK, process, process};
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,40 @@
/*
* 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.
*/
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_shared {
name: "libhapticgeneratorsw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"HapticGeneratorSw.cpp",
":effectCommonFile",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
}

View File

@@ -0,0 +1,118 @@
/*
* 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 <cstddef>
#define LOG_TAG "AHAL_HapticGeneratorSw"
#include <Utils.h>
#include <algorithm>
#include <unordered_set>
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "HapticGeneratorSw.h"
using aidl::android::hardware::audio::effect::HapticGeneratorSw;
using aidl::android::hardware::audio::effect::HapticGeneratorSwImplUUID;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != HapticGeneratorSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<HapticGeneratorSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
LOG(ERROR) << __func__ << " invalid input parameter!";
return EX_ILLEGAL_ARGUMENT;
}
}
extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
if (!instanceSp) {
return EX_NONE;
}
State state;
ndk::ScopedAStatus status = instanceSp->getState(&state);
if (!status.isOk() || State::INIT != state) {
LOG(ERROR) << __func__ << " instance " << instanceSp.get()
<< " in state: " << toString(state) << ", status: " << status.getDescription();
return EX_ILLEGAL_STATE;
}
LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus HapticGeneratorSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus HapticGeneratorSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::hapticGenerator != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::hapticGenerator>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus HapticGeneratorSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::hapticGeneratorTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
specific->set<Parameter::Specific::hapticGenerator>(mSpecificParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> HapticGeneratorSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
return mContext;
}
mContext = std::make_shared<HapticGeneratorSwContext>(1 /* statusFmqDepth */, common);
return mContext;
}
RetCode HapticGeneratorSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status HapticGeneratorSw::effectProcessImpl(float* in, float* out, int process) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
for (int i = 0; i < process; i++) {
*out++ = *in++;
}
return {STATUS_OK, process, process};
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,72 @@
/*
* 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.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
namespace aidl::android::hardware::audio::effect {
class HapticGeneratorSwContext : public EffectContext {
public:
HapticGeneratorSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
// TODO: add specific context here
};
class HapticGeneratorSw : public EffectImpl {
public:
HapticGeneratorSw() { LOG(DEBUG) << __func__; }
~HapticGeneratorSw() {
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
RetCode releaseContext() override;
private:
std::shared_ptr<HapticGeneratorSwContext> mContext;
/* capabilities */
const HapticGenerator::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = HapticGeneratorTypeUUID,
.uuid = HapticGeneratorSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "HapticGeneratorSw"},
.capability = Capability::make<Capability::hapticGenerator>(kCapability)};
/* parameters */
HapticGenerator mSpecificParam;
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -15,6 +15,10 @@
*/
#pragma once
#include <Utils.h>
#include <android-base/logging.h>
#include <utils/Log.h>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <utility>
@@ -22,6 +26,7 @@
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include "EffectTypes.h"
namespace aidl::android::hardware::audio::effect {
@@ -31,35 +36,122 @@ class EffectContext {
IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
StatusMQ;
typedef ::android::AidlMessageQueue<
int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
DataMQ;
EffectContext(size_t statusDepth, size_t inBufferSize, size_t outBufferSize) {
EffectContext(size_t statusDepth, const Parameter::Common& common) {
mSessionId = common.session;
auto& input = common.input;
auto& output = common.output;
LOG_ALWAYS_FATAL_IF(
input.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
"inputFormatNotFloat");
LOG_ALWAYS_FATAL_IF(output.base.format.pcm !=
aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
"outputFormatNotFloat");
mInputFrameSize = ::android::hardware::audio::common::getFrameSizeInBytes(
input.base.format, input.base.channelMask);
mOutputFrameSize = ::android::hardware::audio::common::getFrameSizeInBytes(
output.base.format, output.base.channelMask);
// in/outBuffer size in float (FMQ data format defined for DataMQ)
size_t inBufferSizeInFloat = input.frameCount * mInputFrameSize / sizeof(float);
size_t outBufferSizeInFloat = output.frameCount * mOutputFrameSize / sizeof(float);
mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
mInputMQ = std::make_shared<DataMQ>(inBufferSize);
mOutputMQ = std::make_shared<DataMQ>(outBufferSize);
mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
LOG(ERROR) << __func__ << " created invalid FMQ";
}
mWorkBuffer.reserve(std::max(inBufferSize, outBufferSize));
};
mWorkBuffer.reserve(std::max(inBufferSizeInFloat, outBufferSizeInFloat));
}
virtual ~EffectContext() {}
std::shared_ptr<StatusMQ> getStatusFmq() { return mStatusMQ; };
std::shared_ptr<DataMQ> getInputDataFmq() { return mInputMQ; };
std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; };
std::shared_ptr<StatusMQ> getStatusFmq() { return mStatusMQ; }
std::shared_ptr<DataMQ> getInputDataFmq() { return mInputMQ; }
std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; }
int8_t* getWorkBuffer() { return static_cast<int8_t*>(mWorkBuffer.data()); };
float* getWorkBuffer() { return static_cast<float*>(mWorkBuffer.data()); }
// TODO: update with actual available size
size_t availableToRead() { return mWorkBuffer.capacity(); };
size_t availableToWrite() { return mWorkBuffer.capacity(); };
size_t availableToRead() { return mWorkBuffer.capacity(); }
size_t availableToWrite() { return mWorkBuffer.capacity(); }
// reset buffer status by abandon all data and status in FMQ
void resetBuffer() {
auto buffer = getWorkBuffer();
std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
mInputMQ->read(buffer, mInputMQ->availableToRead());
mOutputMQ->read(buffer, mOutputMQ->availableToRead());
mStatusMQ->read(status.data(), mStatusMQ->availableToRead());
}
void dupeFmq(IEffect::OpenEffectReturn* effectRet) {
if (effectRet) {
effectRet->statusMQ = getStatusFmq()->dupeDesc();
effectRet->inputDataMQ = getInputDataFmq()->dupeDesc();
effectRet->outputDataMQ = getOutputDataFmq()->dupeDesc();
}
}
size_t getInputFrameSize() { return mInputFrameSize; }
size_t getOutputFrameSize() { return mOutputFrameSize; }
int getSessionId() { return mSessionId; }
virtual RetCode setOutputDevice(
const aidl::android::media::audio::common::AudioDeviceDescription& device) {
mOutputDevice = device;
return RetCode::SUCCESS;
}
virtual aidl::android::media::audio::common::AudioDeviceDescription getOutputDevice() {
return mOutputDevice;
}
virtual RetCode setAudioMode(const aidl::android::media::audio::common::AudioMode& mode) {
mMode = mode;
return RetCode::SUCCESS;
}
virtual aidl::android::media::audio::common::AudioMode getAudioMode() { return mMode; }
virtual RetCode setAudioSource(const aidl::android::media::audio::common::AudioSource& source) {
mSource = source;
return RetCode::SUCCESS;
}
virtual aidl::android::media::audio::common::AudioSource getAudioSource() { return mSource; }
virtual RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) {
mVolumeStereo = volumeStereo;
return RetCode::SUCCESS;
}
virtual Parameter::VolumeStereo getVolumeStereo() { return mVolumeStereo; }
virtual RetCode setCommon(const Parameter::Common& common) {
mCommon = common;
LOG(ERROR) << __func__ << mCommon.toString();
return RetCode::SUCCESS;
}
virtual Parameter::Common getCommon() {
LOG(ERROR) << __func__ << mCommon.toString();
return mCommon;
}
protected:
// common parameters
int mSessionId = INVALID_AUDIO_SESSION_ID;
size_t mInputFrameSize, mOutputFrameSize;
Parameter::Common mCommon;
aidl::android::media::audio::common::AudioDeviceDescription mOutputDevice;
aidl::android::media::audio::common::AudioMode mMode;
aidl::android::media::audio::common::AudioSource mSource;
Parameter::VolumeStereo mVolumeStereo;
private:
// fmq and buffers
std::shared_ptr<StatusMQ> mStatusMQ;
std::shared_ptr<DataMQ> mInputMQ;
std::shared_ptr<DataMQ> mOutputMQ;
// TODO handle effect process input and output
// work buffer set by effect instances, the access and update are in same thread
std::vector<int8_t> mWorkBuffer;
std::vector<float> mWorkBuffer;
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,86 @@
/*
* 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.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include <mutex>
#include "EffectTypes.h"
#include "effect-impl/EffectContext.h"
#include "effect-impl/EffectTypes.h"
#include "effect-impl/EffectWorker.h"
namespace aidl::android::hardware::audio::effect {
class EffectImpl : public BnEffect, public EffectWorker {
public:
EffectImpl() { LOG(DEBUG) << __func__; }
~EffectImpl() {
cleanUp();
LOG(DEBUG) << __func__;
}
/**
* Each effect implementation CAN override these methods if necessary
* If you would like implement IEffect::open completely, override EffectImpl::open(), if you
* want to keep most of EffectImpl logic but have a little customize, try override openImpl().
* openImpl() will be called at the beginning of EffectImpl::open() without lock protection.
*
* Same for closeImpl().
*/
virtual ndk::ScopedAStatus open(const Parameter::Common& common,
const std::optional<Parameter::Specific>& specific,
OpenEffectReturn* ret) override;
virtual ndk::ScopedAStatus close() override;
virtual ndk::ScopedAStatus command(CommandId id) override;
virtual ndk::ScopedAStatus commandStart() { return ndk::ScopedAStatus::ok(); }
virtual ndk::ScopedAStatus commandStop() { return ndk::ScopedAStatus::ok(); }
virtual ndk::ScopedAStatus commandReset() { return ndk::ScopedAStatus::ok(); }
virtual ndk::ScopedAStatus getState(State* state) override;
virtual ndk::ScopedAStatus setParameter(const Parameter& param) override;
virtual ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter* param) override;
virtual IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param);
virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param);
/* Methods MUST be implemented by each effect instances */
virtual ndk::ScopedAStatus getDescriptor(Descriptor* desc) = 0;
virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) = 0;
virtual ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) = 0;
virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) = 0;
virtual RetCode releaseContext() = 0;
protected:
/*
* Lock is required if effectProcessImpl (which is running in an independent thread) needs to
* access state and parameters.
*/
std::mutex mMutex;
State mState GUARDED_BY(mMutex) = State::INIT;
IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
private:
void cleanUp();
std::shared_ptr<EffectContext> mContext GUARDED_BY(mMutex);
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -18,6 +18,19 @@
#include <ostream>
#include <string>
#include <aidl/android/hardware/audio/effect/BnEffect.h>
typedef binder_exception_t (*EffectCreateFunctor)(
const ::aidl::android::media::audio::common::AudioUuid*,
std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>*);
typedef binder_exception_t (*EffectDestroyFunctor)(
const std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>&);
struct effect_dl_interface_s {
EffectCreateFunctor createEffectFunc;
EffectDestroyFunctor destroyEffectFunc;
};
namespace aidl::android::hardware::audio::effect {
enum class RetCode {
@@ -26,9 +39,12 @@ enum class RetCode {
ERROR_THREAD, /* Effect thread error */
ERROR_NULL_POINTER, /* NULL pointer */
ERROR_ALIGNMENT_ERROR, /* Memory alignment error */
ERROR_BLOCK_SIZE_EXCEED /* Maximum block size exceeded */
ERROR_BLOCK_SIZE_EXCEED, /* Maximum block size exceeded */
ERROR_EFFECT_LIB_ERROR
};
static const int INVALID_AUDIO_SESSION_ID = -1;
inline std::ostream& operator<<(std::ostream& out, const RetCode& code) {
switch (code) {
case RetCode::SUCCESS:
@@ -43,9 +59,46 @@ inline std::ostream& operator<<(std::ostream& out, const RetCode& code) {
return out << "ERROR_ALIGNMENT_ERROR";
case RetCode::ERROR_BLOCK_SIZE_EXCEED:
return out << "ERROR_BLOCK_SIZE_EXCEED";
case RetCode::ERROR_EFFECT_LIB_ERROR:
return out << "ERROR_EFFECT_LIB_ERROR";
}
return out << "EnumError: " << code;
}
#define RETURN_IF_ASTATUS_NOT_OK(status, message) \
do { \
const ::ndk::ScopedAStatus curr_status = (status); \
if (!curr_status.isOk()) { \
LOG(ERROR) << __func__ << ":" << __LINE__ \
<< "return with status: " << curr_status.getDescription() << (message); \
return ndk::ScopedAStatus::fromExceptionCodeWithMessage( \
curr_status.getExceptionCode(), (message)); \
} \
} while (0)
#define RETURN_IF(expr, exception, message) \
do { \
if (expr) { \
LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr " << #expr; \
return ndk::ScopedAStatus::fromExceptionCodeWithMessage((exception), (message)); \
} \
} while (0)
#define RETURN_OK_IF(expr) \
do { \
if (expr) { \
LOG(INFO) << __func__ << ":" << __LINE__ << " return with expr " << #expr; \
return ndk::ScopedAStatus::ok(); \
} \
} while (0)
#define RETURN_VALUE_IF(expr, ret, log) \
do { \
if (expr) { \
LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr " << #expr << (log); \
return ret; \
} \
} while (0)
} // namespace aidl::android::hardware::audio::effect

View File

@@ -46,11 +46,124 @@ static const AudioUuid EqualizerSwImplUUID = {static_cast<int32_t>(0x0bed4300),
0xbb17,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// Visualizer type UUID.
static const AudioUuid VisualizerTypeUUID = {static_cast<int32_t>(0x1d4033c0),
0x8557,
0x11df,
0x9f2d,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// Equalizer bundle implementation UUID.
static const AudioUuid EqualizerBundleImplUUID = {static_cast<int32_t>(0xce772f20),
0x847d,
0x11df,
0xbb17,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// fa8184a4-588b-11ed-9b6a-0242ac120002
static const AudioUuid BassBoostTypeUUID = {static_cast<int32_t>(0xfa8184a4),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa8181f2-588b-11ed-9b6a-0242ac120002
static const AudioUuid BassBoostSwImplUUID = {static_cast<int32_t>(0xfa8181f2),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa81862a-588b-11ed-9b6a-0242ac120002
static const AudioUuid DownmixTypeUUID = {static_cast<int32_t>(0xfa81862a),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa8187ba-588b-11ed-9b6a-0242ac120002
static const AudioUuid DownmixSwImplUUID = {static_cast<int32_t>(0xfa8187ba),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa818954-588b-11ed-9b6a-0242ac120002
static const AudioUuid DynamicsProcessingTypeUUID = {static_cast<int32_t>(0xfa818954),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa818d78-588b-11ed-9b6a-0242ac120002
static const AudioUuid DynamicsProcessingSwImplUUID = {static_cast<int32_t>(0xfa818d78),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa818f62-588b-11ed-9b6a-0242ac120002
static const AudioUuid HapticGeneratorTypeUUID = {static_cast<int32_t>(0xfa818f62),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819110-588b-11ed-9b6a-0242ac120002
static const AudioUuid HapticGeneratorSwImplUUID = {static_cast<int32_t>(0xfa819110),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa8194a8-588b-11ed-9b6a-0242ac120002
static const AudioUuid LoudnessEnhancerTypeUUID = {static_cast<int32_t>(0xfa8194a8),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819610-588b-11ed-9b6a-0242ac120002
static const AudioUuid LoudnessEnhancerSwImplUUID = {static_cast<int32_t>(0xfa819610),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819886-588b-11ed-9b6a-0242ac120002
static const AudioUuid ReverbTypeUUID = {static_cast<int32_t>(0xfa819886),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa8199c6-588b-11ed-9b6a-0242ac120002
static const AudioUuid ReverbSwImplUUID = {static_cast<int32_t>(0xfa8199c6),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819af2-588b-11ed-9b6a-0242ac120002
static const AudioUuid VirtualizerTypeUUID = {static_cast<int32_t>(0xfa819af2),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819d86-588b-11ed-9b6a-0242ac120002
static const AudioUuid VirtualizerSwImplUUID = {static_cast<int32_t>(0xfa819d86),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819f3e-588b-11ed-9b6a-0242ac120002
static const AudioUuid VisualizerTypeUUID = {static_cast<int32_t>(0xfa819f3e),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa81a0f6-588b-11ed-9b6a-0242ac120002
static const AudioUuid VisualizerSwImplUUID = {static_cast<int32_t>(0xfa81a0f6),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa81a2b8-588b-11ed-9b6a-0242ac120002
static const AudioUuid VolumeTypeUUID = {static_cast<int32_t>(0xfa81a2b8),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa81a718-588b-11ed-9b6a-0242ac120002
static const AudioUuid VolumeSwImplUUID = {static_cast<int32_t>(0xfa81a718),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -36,34 +36,33 @@ class EffectWorker : public EffectThread {
// handle FMQ and call effect implemented virtual function
void process() override {
if (!mContext) {
LOG(ERROR) << __func__ << " invalid context!";
return;
}
RETURN_VALUE_IF(!mContext, void(), "nullContext");
std::shared_ptr<EffectContext::StatusMQ> statusMQ = mContext->getStatusFmq();
std::shared_ptr<EffectContext::DataMQ> inputMQ = mContext->getInputDataFmq();
std::shared_ptr<EffectContext::DataMQ> outputMQ = mContext->getOutputDataFmq();
// Only this worker will read from input data MQ and write to output data MQ.
auto readSize = inputMQ->availableToRead(), writeSize = outputMQ->availableToWrite();
if (readSize && writeSize) {
LOG(DEBUG) << __func__ << " available to read " << readSize << " available to write "
<< writeSize;
auto readSamples = inputMQ->availableToRead(), writeSamples = outputMQ->availableToWrite();
if (readSamples && writeSamples) {
auto processSamples = std::min(readSamples, writeSamples);
LOG(DEBUG) << __func__ << " available to read " << readSamples << " available to write "
<< writeSamples << " process " << processSamples;
auto buffer = mContext->getWorkBuffer();
inputMQ->read(buffer, readSize);
IEffect::Status status = effectProcessImpl();
writeSize = std::min((int32_t)writeSize, status.fmqByteProduced);
outputMQ->write(buffer, writeSize);
inputMQ->read(buffer, processSamples);
IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
outputMQ->write(buffer, status.fmqProduced);
statusMQ->writeBlocking(&status, 1);
LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqByteConsumed
<< " produced " << status.fmqByteProduced;
LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqConsumed
<< " produced " << status.fmqProduced;
} else {
// TODO: maybe add some sleep here to avoid busy waiting
}
}
// must implement by each effect implementation
virtual IEffect::Status effectProcessImpl() = 0;
virtual IEffect::Status effectProcessImpl(float* in, float* out, int processSamples) = 0;
private:
// make sure the context only set once.

View File

@@ -34,12 +34,14 @@ class Factory : public BnFactory {
*
* @param in_type Type UUID.
* @param in_instance Instance UUID.
* @param in_proxy Proxy UUID.
* @param out_descriptor List of identities .
* @return ndk::ScopedAStatus
*/
ndk::ScopedAStatus queryEffects(
const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_type,
const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_instance,
const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_proxy,
std::vector<Descriptor::Identity>* out_descriptor) override;
/**
@@ -79,16 +81,9 @@ class Factory : public BnFactory {
// List of effect descriptors supported by the devices.
std::vector<Descriptor::Identity> mIdentityList;
typedef binder_exception_t (*EffectCreateFunctor)(std::shared_ptr<IEffect>*);
typedef binder_exception_t (*EffectDestroyFunctor)(const std::shared_ptr<IEffect>&);
struct effect_interface_s {
EffectCreateFunctor createEffectFunc;
EffectDestroyFunctor destroyEffectFunc;
};
std::map<aidl::android::media::audio::common::AudioUuid /* implementationUUID */,
std::pair<std::unique_ptr<void, std::function<void(void*)>> /* dlHandle */,
std::unique_ptr<struct effect_interface_s>>>
std::unique_ptr<struct effect_dl_interface_s>>>
mEffectLibMap;
std::map<std::weak_ptr<IEffect>, aidl::android::media::audio::common::AudioUuid,
std::owner_less<>>
@@ -96,5 +91,10 @@ class Factory : public BnFactory {
ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle);
void cleanupEffectMap();
void openEffectLibrary(
const ::aidl::android::media::audio::common::AudioUuid& type,
const ::aidl::android::media::audio::common::AudioUuid& impl,
const std::optional<::aidl::android::media::audio::common::AudioUuid>& proxy,
const std::string& libName);
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -21,85 +21,104 @@
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectContext.h"
#include "effect-impl/EffectTypes.h"
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
#include "effect-impl/EffectWorker.h"
namespace aidl::android::hardware::audio::effect {
class EqualizerSwContext : public EffectContext {
public:
EqualizerSwContext(int statusDepth, int inBufferSize, int outBufferSize)
: EffectContext(statusDepth, inBufferSize, outBufferSize) {
EqualizerSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
RetCode setEqPreset(const int& presetIdx) {
if (presetIdx < 0 || presetIdx >= NUM_OF_PRESETS) {
return RetCode::ERROR_ILLEGAL_PARAMETER;
}
mPreset = presetIdx;
return RetCode::SUCCESS;
}
int getEqPreset() { return mPreset; }
RetCode setEqBandLevels(const std::vector<Equalizer::BandLevel>& bandLevels) {
if (bandLevels.size() > NUM_OF_BANDS) {
LOG(ERROR) << __func__ << " return because size exceed " << NUM_OF_BANDS;
return RetCode::ERROR_ILLEGAL_PARAMETER;
}
RetCode ret = RetCode::SUCCESS;
for (auto& it : bandLevels) {
if (it.index >= NUM_OF_BANDS || it.index < 0) {
LOG(ERROR) << __func__ << " index illegal, skip: " << it.index << " - "
<< it.levelMb;
ret = RetCode::ERROR_ILLEGAL_PARAMETER;
}
mBandLevels[it.index] = it.levelMb;
}
return ret;
}
std::vector<Equalizer::BandLevel> getEqBandLevels() {
std::vector<Equalizer::BandLevel> bandLevels;
for (int i = 0; i < NUM_OF_BANDS; i++) {
bandLevels.push_back({i, mBandLevels[i]});
}
return bandLevels;
}
private:
static const int NUM_OF_BANDS = 5;
static const int NUM_OF_PRESETS = 10;
static const int PRESET_CUSTOM = -1;
// preset band level
int mPreset = PRESET_CUSTOM;
int32_t mBandLevels[NUM_OF_BANDS] = {3, 0, 0, 0, 3};
// Add equalizer specific context for processing here
};
class EqualizerSw : public BnEffect, EffectWorker {
class EqualizerSw : public EffectImpl {
public:
EqualizerSw() {
Equalizer::Capability eqCap = {.bandFrequencies = mBandFrequency, .presets = mPresets};
mDesc.capability.set<Capability::equalizer>(eqCap);
LOG(DEBUG) << __func__;
};
EqualizerSw() { LOG(DEBUG) << __func__; }
~EqualizerSw() {
cleanUp();
LOG(DEBUG) << __func__;
};
ndk::ScopedAStatus open(const Parameter::Common& common, const Parameter::Specific& specific,
OpenEffectReturn* _aidl_return) override;
ndk::ScopedAStatus close() override;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus getState(State* _aidl_return) override;
ndk::ScopedAStatus command(CommandId in_commandId) override;
ndk::ScopedAStatus setParameter(const Parameter& in_param) override;
ndk::ScopedAStatus getParameter(const Parameter::Id& in_paramId,
Parameter* _aidl_return) override;
IEffect::Status effectProcessImpl() override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
RetCode releaseContext() override;
private:
// Effect descriptor.
Descriptor mDesc = {.common = {.id = {.type = EqualizerTypeUUID, .uuid = EqualizerSwImplUUID}}};
// Parameters.
Parameter::Common mCommonParam;
Equalizer mEqualizerParam; // TODO: the equalizer parameter needs to update
// Instance state INIT by default.
State mState = State::INIT;
int mPreset = PRESET_CUSTOM; // the current preset
std::shared_ptr<EqualizerSwContext> mContext;
/* capabilities */
const std::vector<Equalizer::BandFrequency> mBandFrequency = {{0, 30000, 120000},
{1, 120001, 460000},
{2, 460001, 1800000},
{3, 1800001, 7000000},
{4, 7000001, 20000000}};
// preset band level
std::vector<Equalizer::BandLevel> mBandLevels = {{0, 3}, {1, 0}, {2, 0}, {3, 0}, {4, 3}};
// presets supported by the device
const std::vector<Equalizer::Preset> mPresets = {
{0, "Normal"}, {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
{5, "Heavy Metal"}, {6, "Hip Hop"}, {7, "Jazz"}, {8, "Pop"}, {9, "Rock"}};
static const int NUM_OF_BANDS = 5;
static const int NUM_OF_PRESETS = 10;
static const int PRESET_CUSTOM = -1;
// Equalizer worker context
std::shared_ptr<EqualizerSwContext> mContext;
const Equalizer::Capability kEqCap = {.bandFrequencies = mBandFrequency, .presets = mPresets};
// Effect descriptor.
const Descriptor kDesc = {.common = {.id = {.type = EqualizerTypeUUID,
.uuid = EqualizerSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "EqualizerSw"},
.capability = Capability::make<Capability::equalizer>(kEqCap)};
ndk::ScopedAStatus setCommonParameter(const Parameter::Common& common_param);
ndk::ScopedAStatus setSpecificParameter(const Parameter::Specific& specific);
ndk::ScopedAStatus getSpecificParameter(Parameter::Specific::Id id,
Parameter::Specific* specific);
void cleanUp();
IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Tag& tag,
Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,40 @@
/*
* 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.
*/
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_shared {
name: "libloudnessenhancersw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"LoudnessEnhancerSw.cpp",
":effectCommonFile",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
}

View File

@@ -0,0 +1,118 @@
/*
* 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 <cstddef>
#define LOG_TAG "AHAL_LoudnessEnhancerSw"
#include <Utils.h>
#include <algorithm>
#include <unordered_set>
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "LoudnessEnhancerSw.h"
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::LoudnessEnhancerSw;
using aidl::android::hardware::audio::effect::LoudnessEnhancerSwImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != LoudnessEnhancerSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<LoudnessEnhancerSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
LOG(ERROR) << __func__ << " invalid input parameter!";
return EX_ILLEGAL_ARGUMENT;
}
}
extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
if (!instanceSp) {
return EX_NONE;
}
State state;
ndk::ScopedAStatus status = instanceSp->getState(&state);
if (!status.isOk() || State::INIT != state) {
LOG(ERROR) << __func__ << " instance " << instanceSp.get()
<< " in state: " << toString(state) << ", status: " << status.getDescription();
return EX_ILLEGAL_STATE;
}
LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus LoudnessEnhancerSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus LoudnessEnhancerSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::loudnessEnhancer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::loudnessEnhancer>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus LoudnessEnhancerSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::loudnessEnhancerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
specific->set<Parameter::Specific::loudnessEnhancer>(mSpecificParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> LoudnessEnhancerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
return mContext;
}
mContext = std::make_shared<LoudnessEnhancerSwContext>(1 /* statusFmqDepth */, common);
return mContext;
}
RetCode LoudnessEnhancerSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status LoudnessEnhancerSw::effectProcessImpl(float* in, float* out, int process) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
for (int i = 0; i < process; i++) {
*out++ = *in++;
}
return {STATUS_OK, process, process};
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,72 @@
/*
* 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.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
namespace aidl::android::hardware::audio::effect {
class LoudnessEnhancerSwContext : public EffectContext {
public:
LoudnessEnhancerSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
// TODO: add specific context here
};
class LoudnessEnhancerSw : public EffectImpl {
public:
LoudnessEnhancerSw() { LOG(DEBUG) << __func__; }
~LoudnessEnhancerSw() {
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
RetCode releaseContext() override;
private:
std::shared_ptr<LoudnessEnhancerSwContext> mContext;
/* capabilities */
const LoudnessEnhancer::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = LoudnessEnhancerTypeUUID,
.uuid = LoudnessEnhancerSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "LoudnessEnhancerSw"},
.capability = Capability::make<Capability::loudnessEnhancer>(kCapability)};
/* parameters */
LoudnessEnhancer mSpecificParam;
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,40 @@
/*
* 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.
*/
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_shared {
name: "libreverbsw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"ReverbSw.cpp",
":effectCommonFile",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
}

View File

@@ -0,0 +1,118 @@
/*
* 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 <cstddef>
#define LOG_TAG "AHAL_ReverbSw"
#include <Utils.h>
#include <algorithm>
#include <unordered_set>
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "ReverbSw.h"
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::ReverbSw;
using aidl::android::hardware::audio::effect::ReverbSwImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != ReverbSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<ReverbSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
LOG(ERROR) << __func__ << " invalid input parameter!";
return EX_ILLEGAL_ARGUMENT;
}
}
extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
if (!instanceSp) {
return EX_NONE;
}
State state;
ndk::ScopedAStatus status = instanceSp->getState(&state);
if (!status.isOk() || State::INIT != state) {
LOG(ERROR) << __func__ << " instance " << instanceSp.get()
<< " in state: " << toString(state) << ", status: " << status.getDescription();
return EX_ILLEGAL_STATE;
}
LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus ReverbSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::reverb>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ReverbSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
specific->set<Parameter::Specific::reverb>(mSpecificParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> ReverbSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
return mContext;
}
mContext = std::make_shared<ReverbSwContext>(1 /* statusFmqDepth */, common);
return mContext;
}
RetCode ReverbSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status ReverbSw::effectProcessImpl(float* in, float* out, int process) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
for (int i = 0; i < process; i++) {
*out++ = *in++;
}
return {STATUS_OK, process, process};
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,72 @@
/*
* 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.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
namespace aidl::android::hardware::audio::effect {
class ReverbSwContext : public EffectContext {
public:
ReverbSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
// TODO: add specific context here
};
class ReverbSw : public EffectImpl {
public:
ReverbSw() { LOG(DEBUG) << __func__; }
~ReverbSw() {
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
RetCode releaseContext() override;
private:
std::shared_ptr<ReverbSwContext> mContext;
/* capabilities */
const Reverb::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = ReverbTypeUUID,
.uuid = ReverbSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "ReverbSw"},
.capability = Capability::make<Capability::reverb>(kCapability)};
/* parameters */
Reverb mSpecificParam;
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,40 @@
/*
* 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.
*/
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_shared {
name: "libvirtualizersw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"VirtualizerSw.cpp",
":effectCommonFile",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
}

View File

@@ -0,0 +1,118 @@
/*
* 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 <cstddef>
#define LOG_TAG "AHAL_VirtualizerSw"
#include <Utils.h>
#include <algorithm>
#include <unordered_set>
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "VirtualizerSw.h"
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::State;
using aidl::android::hardware::audio::effect::VirtualizerSw;
using aidl::android::hardware::audio::effect::VirtualizerSwImplUUID;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != VirtualizerSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<VirtualizerSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
LOG(ERROR) << __func__ << " invalid input parameter!";
return EX_ILLEGAL_ARGUMENT;
}
}
extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
if (!instanceSp) {
return EX_NONE;
}
State state;
ndk::ScopedAStatus status = instanceSp->getState(&state);
if (!status.isOk() || State::INIT != state) {
LOG(ERROR) << __func__ << " instance " << instanceSp.get()
<< " in state: " << toString(state) << ", status: " << status.getDescription();
return EX_ILLEGAL_STATE;
}
LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus VirtualizerSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus VirtualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::virtualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::virtualizer>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus VirtualizerSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::virtualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
specific->set<Parameter::Specific::virtualizer>(mSpecificParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> VirtualizerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
return mContext;
}
mContext = std::make_shared<VirtualizerSwContext>(1 /* statusFmqDepth */, common);
return mContext;
}
RetCode VirtualizerSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status VirtualizerSw::effectProcessImpl(float* in, float* out, int process) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
for (int i = 0; i < process; i++) {
*out++ = *in++;
}
return {STATUS_OK, process, process};
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,72 @@
/*
* 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.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
namespace aidl::android::hardware::audio::effect {
class VirtualizerSwContext : public EffectContext {
public:
VirtualizerSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
// TODO: add specific context here
};
class VirtualizerSw : public EffectImpl {
public:
VirtualizerSw() { LOG(DEBUG) << __func__; }
~VirtualizerSw() {
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
RetCode releaseContext() override;
private:
std::shared_ptr<VirtualizerSwContext> mContext;
/* capabilities */
const Virtualizer::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = VirtualizerTypeUUID,
.uuid = VirtualizerSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "VirtualizerSw"},
.capability = Capability::make<Capability::virtualizer>(kCapability)};
/* parameters */
Virtualizer mSpecificParam;
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,40 @@
/*
* 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.
*/
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_shared {
name: "libvisualizersw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"VisualizerSw.cpp",
":effectCommonFile",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
}

View File

@@ -0,0 +1,118 @@
/*
* 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 <cstddef>
#define LOG_TAG "AHAL_VisualizerSw"
#include <Utils.h>
#include <algorithm>
#include <unordered_set>
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "VisualizerSw.h"
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::State;
using aidl::android::hardware::audio::effect::VisualizerSw;
using aidl::android::hardware::audio::effect::VisualizerSwImplUUID;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != VisualizerSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<VisualizerSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
LOG(ERROR) << __func__ << " invalid input parameter!";
return EX_ILLEGAL_ARGUMENT;
}
}
extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
if (!instanceSp) {
return EX_NONE;
}
State state;
ndk::ScopedAStatus status = instanceSp->getState(&state);
if (!status.isOk() || State::INIT != state) {
LOG(ERROR) << __func__ << " instance " << instanceSp.get()
<< " in state: " << toString(state) << ", status: " << status.getDescription();
return EX_ILLEGAL_STATE;
}
LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus VisualizerSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus VisualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::visualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::visualizer>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus VisualizerSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::visualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
specific->set<Parameter::Specific::visualizer>(mSpecificParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> VisualizerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
return mContext;
}
mContext = std::make_shared<VisualizerSwContext>(1 /* statusFmqDepth */, common);
return mContext;
}
RetCode VisualizerSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status VisualizerSw::effectProcessImpl(float* in, float* out, int process) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
for (int i = 0; i < process; i++) {
*out++ = *in++;
}
return {STATUS_OK, process, process};
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,72 @@
/*
* 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.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
namespace aidl::android::hardware::audio::effect {
class VisualizerSwContext : public EffectContext {
public:
VisualizerSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
// TODO: add specific context here
};
class VisualizerSw : public EffectImpl {
public:
VisualizerSw() { LOG(DEBUG) << __func__; }
~VisualizerSw() {
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
RetCode releaseContext() override;
private:
std::shared_ptr<VisualizerSwContext> mContext;
/* capabilities */
const Visualizer::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = VisualizerTypeUUID,
.uuid = VisualizerSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "VisualizerSw"},
.capability = Capability::make<Capability::visualizer>(kCapability)};
/* parameters */
Visualizer mSpecificParam;
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,40 @@
/*
* 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.
*/
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_shared {
name: "libvolumesw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"VolumeSw.cpp",
":effectCommonFile",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
}

View File

@@ -0,0 +1,118 @@
/*
* 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 <cstddef>
#define LOG_TAG "AHAL_VolumeSw"
#include <Utils.h>
#include <algorithm>
#include <unordered_set>
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "VolumeSw.h"
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::State;
using aidl::android::hardware::audio::effect::VolumeSw;
using aidl::android::hardware::audio::effect::VolumeSwImplUUID;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != VolumeSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<VolumeSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
LOG(ERROR) << __func__ << " invalid input parameter!";
return EX_ILLEGAL_ARGUMENT;
}
}
extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
if (!instanceSp) {
return EX_NONE;
}
State state;
ndk::ScopedAStatus status = instanceSp->getState(&state);
if (!status.isOk() || State::INIT != state) {
LOG(ERROR) << __func__ << " instance " << instanceSp.get()
<< " in state: " << toString(state) << ", status: " << status.getDescription();
return EX_ILLEGAL_STATE;
}
LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus VolumeSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus VolumeSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::volume != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::volume>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus VolumeSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::volumeTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
specific->set<Parameter::Specific::volume>(mSpecificParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> VolumeSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
return mContext;
}
mContext = std::make_shared<VolumeSwContext>(1 /* statusFmqDepth */, common);
return mContext;
}
RetCode VolumeSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status VolumeSw::effectProcessImpl(float* in, float* out, int process) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
for (int i = 0; i < process; i++) {
*out++ = *in++;
}
return {STATUS_OK, process, process};
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,72 @@
/*
* 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.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
namespace aidl::android::hardware::audio::effect {
class VolumeSwContext : public EffectContext {
public:
VolumeSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
// TODO: add specific context here
};
class VolumeSw : public EffectImpl {
public:
VolumeSw() { LOG(DEBUG) << __func__; }
~VolumeSw() {
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
RetCode releaseContext() override;
private:
std::shared_ptr<VolumeSwContext> mContext;
/* capabilities */
const Volume::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = VolumeTypeUUID,
.uuid = VolumeSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "VolumeSw"},
.capability = Capability::make<Capability::volume>(kCapability)};
/* parameters */
Volume mSpecificParam;
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -53,9 +53,10 @@ class EffectFactoryHelper {
void QueryEffects(const std::optional<AudioUuid>& in_type,
const std::optional<AudioUuid>& in_instance,
const std::optional<AudioUuid>& in_proxy,
std::vector<Descriptor::Identity>* _aidl_return) {
ASSERT_NE(mEffectFactory, nullptr);
EXPECT_IS_OK(mEffectFactory->queryEffects(in_type, in_instance, _aidl_return));
EXPECT_IS_OK(mEffectFactory->queryEffects(in_type, in_instance, in_proxy, _aidl_return));
mIds = *_aidl_return;
}
@@ -85,9 +86,10 @@ class EffectFactoryHelper {
ASSERT_NE(mEffectFactory, nullptr);
if (type == EffectNullUuid) {
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, &ids));
EXPECT_IS_OK(
mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
} else {
EXPECT_IS_OK(mEffectFactory->queryEffects(type, std::nullopt, &ids));
EXPECT_IS_OK(mEffectFactory->queryEffects(type, std::nullopt, std::nullopt, &ids));
}
for (const auto& id : ids) {
ASSERT_EQ(id.type, type);
@@ -121,7 +123,8 @@ class EffectFactoryHelper {
void QueryAndCreateAllEffects() {
ASSERT_NE(mEffectFactory, nullptr);
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, &mCompleteIds));
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt,
&mCompleteIds));
for (const auto& id : mCompleteIds) {
std::shared_ptr<IEffect> effect;
EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));

View File

@@ -49,7 +49,7 @@ using aidl::android::media::audio::common::AudioUuid;
using aidl::android::media::audio::common::PcmType;
const AudioFormatDescription DefaultFormat = {
.type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT, .encoding = ""};
.type = AudioFormatType::PCM, .pcm = PcmType::FLOAT_32_BIT, .encoding = ""};
class EffectHelper {
public:
@@ -59,6 +59,7 @@ class EffectHelper {
void OpenEffects(const AudioUuid& type = EffectNullUuid) {
auto open = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
IEffect::OpenEffectReturn ret;
EXPECT_IS_OK(effect->open(mCommon, mSpecific, &ret));
EffectParam params;
@@ -72,6 +73,7 @@ class EffectHelper {
void CloseEffects(const binder_status_t status = EX_NONE) {
auto close = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
EXPECT_STATUS(status, effect->close());
};
@@ -97,6 +99,7 @@ class EffectHelper {
void GetEffectDescriptors() {
auto get = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
Descriptor desc;
EXPECT_IS_OK(effect->getDescriptor(&desc));
mEffectDescriptors.push_back(std::move(desc));
@@ -106,6 +109,7 @@ class EffectHelper {
void CommandEffects(CommandId command) {
auto close = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
EXPECT_IS_OK(effect->command(command));
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
@@ -113,6 +117,7 @@ class EffectHelper {
void CommandEffectsExpectStatus(CommandId command, const binder_status_t status) {
auto func = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
EXPECT_STATUS(status, effect->command(command));
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
@@ -120,6 +125,7 @@ class EffectHelper {
void ExpectState(State expected) {
auto get = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
State state = State::INIT;
EXPECT_IS_OK(effect->getState(&state));
EXPECT_EQ(expected, state);
@@ -129,6 +135,7 @@ class EffectHelper {
void SetParameter() {
auto func = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
Parameter param;
param.set<Parameter::common>(mCommon);
EXPECT_IS_OK(effect->setParameter(param));
@@ -138,9 +145,10 @@ class EffectHelper {
void VerifyParameters() {
auto func = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
Parameter paramCommonGet = Parameter(), paramCommonExpect = Parameter();
Parameter::Id id;
id.set<Parameter::Id::commonTag>(0);
id.set<Parameter::Id::commonTag>(Parameter::common);
paramCommonExpect.set<Parameter::common>(mCommon);
EXPECT_IS_OK(effect->getParameter(id, &paramCommonGet));
EXPECT_EQ(paramCommonExpect, paramCommonGet)
@@ -151,8 +159,9 @@ class EffectHelper {
void QueryEffects(const std::optional<AudioUuid>& in_type,
const std::optional<AudioUuid>& in_instance,
const std::optional<AudioUuid>& in_proxy,
std::vector<Descriptor::Identity>* _aidl_return) {
mFactoryHelper.QueryEffects(in_type, in_instance, _aidl_return);
mFactoryHelper.QueryEffects(in_type, in_instance, in_proxy, _aidl_return);
}
template <typename Functor>
@@ -173,7 +182,7 @@ class EffectHelper {
}
}
static const size_t mWriteMQSize = 0x400;
static const size_t mWriteMQBytes = 0x400;
enum class IO : char { INPUT = 0, OUTPUT = 1, INOUT = 2 };
@@ -204,7 +213,7 @@ class EffectHelper {
mCommon.output.frameCount = frameCount;
}
}
void initParamCommon(int session = -1, int ioHandle = -1, int iSampleRate = 48000,
void initParamCommon(int session = 0, int ioHandle = -1, int iSampleRate = 48000,
int oSampleRate = 48000, long iFrameCount = 0x100,
long oFrameCount = 0x100) {
mCommon.session = session;
@@ -215,10 +224,12 @@ class EffectHelper {
input.base.sampleRate = iSampleRate;
input.base.channelMask = mInputChannelLayout;
input.frameCount = iFrameCount;
input.base.format = DefaultFormat;
output.base.sampleRate = oSampleRate;
output.base.channelMask = mOutputChannelLayout;
output.base.format = DefaultFormat;
output.frameCount = oFrameCount;
output.base.format = DefaultFormat;
inputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
input.base.format, input.base.channelMask);
outputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
@@ -228,45 +239,45 @@ class EffectHelper {
void setSpecific(Parameter::Specific& specific) { mSpecific = specific; }
// usually this function only call once.
void PrepareInputData(size_t s = mWriteMQSize) {
size_t maxInputSize = s;
void PrepareInputData(size_t bytes = mWriteMQBytes) {
size_t maxInputBytes = mWriteMQBytes;
for (auto& it : mEffectParams) {
auto& mq = it.inputMQ;
EXPECT_NE(nullptr, mq);
EXPECT_TRUE(mq->isValid());
const size_t bytesToWrite = mq->availableToWrite();
const size_t bytesToWrite = mq->availableToWrite() * sizeof(float);
EXPECT_EQ(inputFrameSize * mCommon.input.frameCount, bytesToWrite);
EXPECT_NE(0UL, bytesToWrite);
EXPECT_TRUE(s <= bytesToWrite);
maxInputSize = std::max(maxInputSize, bytesToWrite);
EXPECT_TRUE(bytes <= bytesToWrite);
maxInputBytes = std::max(maxInputBytes, bytesToWrite);
}
mInputBuffer.resize(maxInputSize);
mInputBuffer.resize(maxInputBytes / sizeof(float));
std::fill(mInputBuffer.begin(), mInputBuffer.end(), 0x5a);
}
void writeToFmq(size_t s = mWriteMQSize) {
void writeToFmq(size_t bytes = mWriteMQBytes) {
for (auto& it : mEffectParams) {
auto& mq = it.inputMQ;
EXPECT_NE(nullptr, mq);
const size_t bytesToWrite = mq->availableToWrite();
const size_t bytesToWrite = mq->availableToWrite() * sizeof(float);
EXPECT_NE(0Ul, bytesToWrite);
EXPECT_TRUE(s <= bytesToWrite);
EXPECT_TRUE(mq->write(mInputBuffer.data(), s));
EXPECT_TRUE(bytes <= bytesToWrite);
EXPECT_TRUE(mq->write(mInputBuffer.data(), bytes / sizeof(float)));
}
}
void readFromFmq(size_t expectSize = mWriteMQSize) {
void readFromFmq(size_t expectBytes = mWriteMQBytes) {
for (auto& it : mEffectParams) {
IEffect::Status status{};
auto& statusMq = it.statusMQ;
EXPECT_NE(nullptr, statusMq);
EXPECT_TRUE(statusMq->readBlocking(&status, 1));
EXPECT_EQ(STATUS_OK, status.status);
EXPECT_EQ(expectSize, (unsigned)status.fmqByteProduced);
EXPECT_EQ(expectBytes, (unsigned)status.fmqProduced * sizeof(float));
auto& outputMq = it.outputMQ;
EXPECT_NE(nullptr, outputMq);
EXPECT_EQ(expectSize, outputMq->availableToRead());
EXPECT_EQ(expectBytes, outputMq->availableToRead() * sizeof(float));
}
}
@@ -288,16 +299,16 @@ class EffectHelper {
AudioChannelLayout::LAYOUT_STEREO);
Parameter::Common mCommon;
Parameter::Specific mSpecific;
std::optional<Parameter::Specific> mSpecific = std::nullopt;
size_t inputFrameSize, outputFrameSize;
std::vector<int8_t> mInputBuffer; // reuse same buffer for all effects testing
std::vector<float> mInputBuffer; // reuse same buffer for all effects testing
typedef ::android::AidlMessageQueue<
IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
StatusMQ;
typedef ::android::AidlMessageQueue<
int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
DataMQ;
class EffectParam {

View File

@@ -66,13 +66,13 @@ TEST_P(EffectFactoryTest, CanBeRestarted) {
TEST_P(EffectFactoryTest, QueriedDescriptorList) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
EXPECT_NE(descriptors.size(), 0UL);
}
TEST_P(EffectFactoryTest, DescriptorUUIDNotNull) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
// TODO: Factory eventually need to return the full list of MUST supported AOSP effects.
for (auto& desc : descriptors) {
EXPECT_NE(desc.type, EffectNullUuid);
@@ -82,19 +82,19 @@ TEST_P(EffectFactoryTest, DescriptorUUIDNotNull) {
TEST_P(EffectFactoryTest, QueriedDescriptorNotExistType) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(EffectNullUuid, std::nullopt, &descriptors);
mFactory.QueryEffects(EffectNullUuid, std::nullopt, std::nullopt, &descriptors);
EXPECT_EQ(descriptors.size(), 0UL);
}
TEST_P(EffectFactoryTest, QueriedDescriptorNotExistInstance) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, EffectNullUuid, &descriptors);
mFactory.QueryEffects(std::nullopt, EffectNullUuid, std::nullopt, &descriptors);
EXPECT_EQ(descriptors.size(), 0UL);
}
TEST_P(EffectFactoryTest, CreateAndDestroyOnce) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
auto numIds = mFactory.GetEffectIds().size();
EXPECT_NE(numIds, 0UL);
@@ -108,7 +108,7 @@ TEST_P(EffectFactoryTest, CreateAndDestroyOnce) {
TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
auto numIds = mFactory.GetEffectIds().size();
EXPECT_NE(numIds, 0UL);
@@ -128,7 +128,7 @@ TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
TEST_P(EffectFactoryTest, CreateMultipleInstanceOfSameEffect) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
auto numIds = mFactory.GetEffectIds().size();
EXPECT_NE(numIds, 0UL);
@@ -167,7 +167,7 @@ TEST_P(EffectFactoryTest, DestroyWithInvalidInterface) {
TEST_P(EffectFactoryTest, CreateAndRemoveReference) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
auto numIds = mFactory.GetEffectIds().size();
EXPECT_NE(numIds, 0UL);
@@ -182,7 +182,7 @@ TEST_P(EffectFactoryTest, CreateAndRemoveReference) {
TEST_P(EffectFactoryTest, CreateRemoveReferenceAndCreateDestroy) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
auto numIds = mFactory.GetEffectIds().size();
EXPECT_NE(numIds, 0UL);
@@ -203,7 +203,7 @@ TEST_P(EffectFactoryTest, CreateRemoveReferenceAndCreateDestroy) {
TEST_P(EffectFactoryTest, CreateRestartAndCreateDestroy) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
auto numIds = mFactory.GetEffectIds().size();
auto& effectMap = mFactory.GetEffectMap();
mFactory.CreateEffects();

View File

@@ -59,7 +59,6 @@ class AudioEffectTest : public testing::TestWithParam<std::string>, public Effec
CreateEffects();
initParamCommonFormat();
initParamCommon();
// initParamSpecific();
}
void TearDown() override {
@@ -105,8 +104,9 @@ TEST_P(AudioEffectTest, DescriptorIdExistAndUnique) {
Descriptor desc;
std::vector<Descriptor::Identity> idList;
EXPECT_IS_OK(effect->getDescriptor(&desc));
QueryEffects(desc.common.id.type, desc.common.id.uuid, &idList);
EXPECT_EQ(idList.size(), 1UL);
QueryEffects(desc.common.id.type, desc.common.id.uuid, desc.common.id.proxy, &idList);
// Must have at least one instance.
EXPECT_NE(idList.size(), 0UL);
};
ForEachEffect(checker);
@@ -117,7 +117,7 @@ TEST_P(AudioEffectTest, DescriptorIdExistAndUnique) {
auto vec = GetCompleteEffectIdList();
std::unordered_set<Descriptor::Identity, decltype(stringHash)> idSet(0, stringHash);
for (auto it : vec) {
EXPECT_EQ(idSet.count(it), 0UL);
EXPECT_EQ(idSet.count(it), 0UL) << it.toString();
idSet.insert(it);
}
}
@@ -256,7 +256,8 @@ TEST_P(AudioEffectTest, DestroyOpenEffects) {
// open effects, destroy without close, expect to get EX_ILLEGAL_STATE status.
CreateEffects();
OpenEffects();
DestroyEffects(EX_ILLEGAL_STATE, 1);
auto vec = GetCompleteEffectIdList();
DestroyEffects(EX_ILLEGAL_STATE, vec.size());
CloseEffects();
}
@@ -310,9 +311,11 @@ TEST_P(AudioEffectTest, ResetAndVerifyParameter) {
CloseEffects();
}
// TODO: need a way to support setting different sessionId to different effect instances
#if 0
// Multiple instances of same implementation running.
TEST_P(AudioEffectTest, MultipleInstancesRunning) {
CreateEffects(3);
TEST_P(AudioEffectTest, MultipleInstancesRunningWithDiffSessionId) {
CreateEffects();
ExpectState(State::INIT);
OpenEffects();
ExpectState(State::IDLE);
@@ -327,15 +330,16 @@ TEST_P(AudioEffectTest, MultipleInstancesRunning) {
VerifyParameters();
CloseEffects();
}
#endif
// Send data to effects and expect it to consume by check statusMQ.
TEST_P(AudioEffectTest, ExpectEffectsToConsumeDataInMQ) {
OpenEffects();
PrepareInputData(mWriteMQSize);
PrepareInputData(mWriteMQBytes);
CommandEffects(CommandId::START);
writeToFmq(mWriteMQSize);
readFromFmq(mWriteMQSize);
writeToFmq(mWriteMQBytes);
readFromFmq(mWriteMQBytes);
ExpectState(State::PROCESSING);
CommandEffects(CommandId::STOP);

View File

@@ -95,9 +95,9 @@ class EqualizerParamTest : public ::testing::TestWithParam<EqualizerParamTestPar
CleanUp();
}
const int mParamPresetIndex;
const int mParamBandIndex;
const int mParamBandLevel;
int mParamPresetIndex = 0;
int mParamBandIndex = 0;
int mParamBandLevel = 0;
void SetAndGetEqualizerParameters() {
auto functor = [&](const std::shared_ptr<IEffect>& effect) {
@@ -122,19 +122,54 @@ class EqualizerParamTest : public ::testing::TestWithParam<EqualizerParamTestPar
// only get if parameter in range and set success
if (expected == EX_NONE) {
Parameter getParam;
Parameter::Specific::Id id;
id.set<Parameter::Specific::Id::equalizerTag>(tag);
Parameter::Id id;
Equalizer::Id eqId;
eqId.set<Equalizer::Id::commonTag>(tag);
id.set<Parameter::Id::equalizerTag>(eqId);
// if set success, then get should match
EXPECT_STATUS(expected, effect->getParameter(id, &getParam));
EXPECT_EQ(expectParam, getParam) << "\n"
<< expectParam.toString() << "\n"
<< getParam.toString();
EXPECT_TRUE(isEqParameterExpected(expectParam, getParam));
}
}
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(functor));
}
bool isEqParameterExpected(const Parameter& expect, const Parameter& target) {
// if parameter same, then for sure matched
if (expect == target) return true;
// if not, see if target include the expect parameter, and others all default (0).
/*
This is verify the case of client setParameter to a single bandLevel ({3, -1} for
example), and return of getParameter must be [{0, 0}, {1, 0}, {2, 0}, {3, -1}, {4, 0}]
*/
EXPECT_EQ(expect.getTag(), Parameter::specific);
EXPECT_EQ(target.getTag(), Parameter::specific);
Parameter::Specific expectSpec = expect.get<Parameter::specific>(),
targetSpec = target.get<Parameter::specific>();
EXPECT_EQ(expectSpec.getTag(), Parameter::Specific::equalizer);
EXPECT_EQ(targetSpec.getTag(), Parameter::Specific::equalizer);
Equalizer expectEq = expectSpec.get<Parameter::Specific::equalizer>(),
targetEq = targetSpec.get<Parameter::Specific::equalizer>();
EXPECT_EQ(expectEq.getTag(), targetEq.getTag());
auto eqTag = targetEq.getTag();
switch (eqTag) {
case Equalizer::bandLevels: {
auto expectBl = expectEq.get<Equalizer::bandLevels>();
auto targetBl = targetEq.get<Equalizer::bandLevels>();
return std::includes(targetBl.begin(), targetBl.end(), expectBl.begin(),
expectBl.end());
}
default:
return false;
}
return false;
}
void addPresetParam(int preset) {
Equalizer eq;
eq.set<Equalizer::preset>(preset);
@@ -189,7 +224,6 @@ class EqualizerParamTest : public ::testing::TestWithParam<EqualizerParamTestPar
}
private:
Equalizer::VendorExtension mVendorExtension;
std::vector<std::pair<Equalizer::Tag, std::unique_ptr<Equalizer>>> mTags;
bool validCapabilityTag(Capability& cap) { return cap.getTag() == Capability::equalizer; }
@@ -211,8 +245,8 @@ TEST_P(EqualizerParamTest, SetAndGetPreset) {
}
TEST_P(EqualizerParamTest, SetAndGetSingleBand) {
Equalizer::BandLevel bandLevel = {mParamBandIndex, mParamBandLevel};
std::vector<Equalizer::BandLevel> bandLevels;
Equalizer::BandLevel bandLevel = {mParamBandIndex, mParamBandLevel};
bandLevels.push_back(bandLevel);
EXPECT_NO_FATAL_FAILURE(addBandLevelsParam(bandLevels));
SetAndGetEqualizerParameters();