AIDL Effect: Update locking in EffectImpl
Avoid locking for all EffectContext calls. Locking inside context seems not necessary for now as all binder calls already serialized. Add BassBoost AIDL placeholder implementation. Bug: 261646550 Test: atest VtsHalAudioEffectTargetTest Change-Id: Iaa41f013d5756801553e20b995aab5ddc845cf32
This commit is contained in:
parent
f0803cd8d5
commit
f627d80d37
27 changed files with 599 additions and 222 deletions
|
@ -25,41 +25,33 @@ 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_OK_IF(mState != State::INIT);
|
||||
auto context = createContext(common);
|
||||
RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
|
||||
|
||||
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,
|
||||
mState = State::IDLE;
|
||||
context->dupeFmq(ret);
|
||||
RETURN_IF(createThread(context, getEffectName()) != 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");
|
||||
mState = State::INIT;
|
||||
RETURN_IF(releaseContext() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
|
||||
"FailedToCreateWorker");
|
||||
mState = State::INIT;
|
||||
|
||||
LOG(DEBUG) << __func__;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
@ -113,29 +105,30 @@ ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter*
|
|||
}
|
||||
|
||||
ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
|
||||
std::lock_guard lg(mMutex);
|
||||
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
|
||||
auto context = getContext();
|
||||
RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
|
||||
|
||||
auto tag = param.getTag();
|
||||
switch (tag) {
|
||||
case Parameter::common:
|
||||
RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
|
||||
RETURN_IF(context->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
|
||||
EX_ILLEGAL_ARGUMENT, "setCommFailed");
|
||||
break;
|
||||
case Parameter::deviceDescription:
|
||||
RETURN_IF(mContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
|
||||
RETURN_IF(context->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,
|
||||
RETURN_IF(context->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,
|
||||
RETURN_IF(context->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
|
||||
EX_ILLEGAL_ARGUMENT, "setSourceFailed");
|
||||
break;
|
||||
case Parameter::volumeStereo:
|
||||
RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
|
||||
RETURN_IF(context->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
|
||||
RetCode::SUCCESS,
|
||||
EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
|
||||
break;
|
||||
|
@ -149,27 +142,28 @@ ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
|
|||
}
|
||||
|
||||
ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Parameter* param) {
|
||||
std::lock_guard lg(mMutex);
|
||||
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
|
||||
auto context = getContext();
|
||||
RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
|
||||
|
||||
switch (tag) {
|
||||
case Parameter::common: {
|
||||
param->set<Parameter::common>(mContext->getCommon());
|
||||
param->set<Parameter::common>(context->getCommon());
|
||||
break;
|
||||
}
|
||||
case Parameter::deviceDescription: {
|
||||
param->set<Parameter::deviceDescription>(mContext->getOutputDevice());
|
||||
param->set<Parameter::deviceDescription>(context->getOutputDevice());
|
||||
break;
|
||||
}
|
||||
case Parameter::mode: {
|
||||
param->set<Parameter::mode>(mContext->getAudioMode());
|
||||
param->set<Parameter::mode>(context->getAudioMode());
|
||||
break;
|
||||
}
|
||||
case Parameter::source: {
|
||||
param->set<Parameter::source>(mContext->getAudioSource());
|
||||
param->set<Parameter::source>(context->getAudioSource());
|
||||
break;
|
||||
}
|
||||
case Parameter::volumeStereo: {
|
||||
param->set<Parameter::volumeStereo>(mContext->getVolumeStereo());
|
||||
param->set<Parameter::volumeStereo>(context->getVolumeStereo());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -182,39 +176,30 @@ ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Par
|
|||
}
|
||||
|
||||
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);
|
||||
RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
|
||||
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;
|
||||
RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
|
||||
startThread();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
mState = State::PROCESSING;
|
||||
break;
|
||||
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();
|
||||
RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
|
||||
mState = State::IDLE;
|
||||
break;
|
||||
default:
|
||||
LOG(ERROR) << __func__ << " instance still processing";
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
|
@ -224,6 +209,15 @@ ndk::ScopedAStatus EffectImpl::command(CommandId command) {
|
|||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EffectImpl::commandImpl(CommandId command) {
|
||||
auto context = getContext();
|
||||
RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
|
||||
if (command == CommandId::RESET) {
|
||||
context->resetBuffer();
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
void EffectImpl::cleanUp() {
|
||||
command(CommandId::STOP);
|
||||
close();
|
||||
|
@ -238,19 +232,12 @@ IEffect::Status EffectImpl::status(binder_status_t status, size_t consumed, size
|
|||
}
|
||||
|
||||
// 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++) {
|
||||
IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int samples) {
|
||||
for (int i = 0; i < samples; i++) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
LOG(DEBUG) << __func__ << " done processing " << processSamples << " samples";
|
||||
return {STATUS_OK, processSamples, processSamples};
|
||||
LOG(DEBUG) << __func__ << " done processing " << samples << " samples";
|
||||
return {STATUS_OK, samples, samples};
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#define LOG_TAG "AHAL_EffectThread"
|
||||
#include <android-base/logging.h>
|
||||
#include <pthread.h>
|
||||
|
@ -32,13 +33,18 @@ EffectThread::~EffectThread() {
|
|||
LOG(DEBUG) << __func__ << " done";
|
||||
};
|
||||
|
||||
RetCode EffectThread::createThread(const std::string& name, const int priority) {
|
||||
RetCode EffectThread::createThread(std::shared_ptr<EffectContext> context, const std::string& name,
|
||||
const int priority) {
|
||||
if (mThread.joinable()) {
|
||||
LOG(WARNING) << __func__ << " thread already created, no-op";
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
mName = name;
|
||||
mPriority = priority;
|
||||
{
|
||||
std::lock_guard lg(mThreadMutex);
|
||||
mThreadContext = std::move(context);
|
||||
}
|
||||
mThread = std::thread(&EffectThread::threadLoop, this);
|
||||
LOG(DEBUG) << __func__ << " " << name << " priority " << mPriority << " done";
|
||||
return RetCode::SUCCESS;
|
||||
|
@ -46,7 +52,7 @@ RetCode EffectThread::createThread(const std::string& name, const int priority)
|
|||
|
||||
RetCode EffectThread::destroyThread() {
|
||||
{
|
||||
std::lock_guard lg(mMutex);
|
||||
std::lock_guard lg(mThreadMutex);
|
||||
mStop = mExit = true;
|
||||
}
|
||||
mCv.notify_one();
|
||||
|
@ -54,6 +60,11 @@ RetCode EffectThread::destroyThread() {
|
|||
if (mThread.joinable()) {
|
||||
mThread.join();
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard lg(mThreadMutex);
|
||||
mThreadContext.reset();
|
||||
}
|
||||
LOG(DEBUG) << __func__ << " done";
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
|
@ -65,7 +76,7 @@ RetCode EffectThread::startThread() {
|
|||
}
|
||||
|
||||
{
|
||||
std::lock_guard lg(mMutex);
|
||||
std::lock_guard lg(mThreadMutex);
|
||||
if (!mStop) {
|
||||
LOG(WARNING) << __func__ << " already start";
|
||||
return RetCode::SUCCESS;
|
||||
|
@ -85,7 +96,7 @@ RetCode EffectThread::stopThread() {
|
|||
}
|
||||
|
||||
{
|
||||
std::lock_guard lg(mMutex);
|
||||
std::lock_guard lg(mThreadMutex);
|
||||
if (mStop) {
|
||||
LOG(WARNING) << __func__ << " already stop";
|
||||
return RetCode::SUCCESS;
|
||||
|
@ -97,13 +108,13 @@ RetCode EffectThread::stopThread() {
|
|||
}
|
||||
|
||||
void EffectThread::threadLoop() {
|
||||
pthread_setname_np(pthread_self(), mName.substr(0, MAX_TASK_COMM_LEN - 1).c_str());
|
||||
pthread_setname_np(pthread_self(), mName.substr(0, kMaxTaskNameLen - 1).c_str());
|
||||
setpriority(PRIO_PROCESS, 0, mPriority);
|
||||
while (true) {
|
||||
bool needExit = false;
|
||||
{
|
||||
std::unique_lock l(mMutex);
|
||||
mCv.wait(l, [&]() REQUIRES(mMutex) {
|
||||
std::unique_lock l(mThreadMutex);
|
||||
mCv.wait(l, [&]() REQUIRES(mThreadMutex) {
|
||||
needExit = mExit;
|
||||
return mExit || !mStop;
|
||||
});
|
||||
|
@ -112,9 +123,41 @@ void EffectThread::threadLoop() {
|
|||
LOG(WARNING) << __func__ << " EXIT!";
|
||||
return;
|
||||
}
|
||||
// process without lock
|
||||
|
||||
process();
|
||||
}
|
||||
}
|
||||
|
||||
void EffectThread::process() {
|
||||
std::shared_ptr<EffectContext> context;
|
||||
{
|
||||
std::lock_guard lg(mThreadMutex);
|
||||
context = mThreadContext;
|
||||
RETURN_VALUE_IF(!context, void(), "nullContext");
|
||||
}
|
||||
std::shared_ptr<EffectContext::StatusMQ> statusMQ = context->getStatusFmq();
|
||||
std::shared_ptr<EffectContext::DataMQ> inputMQ = context->getInputDataFmq();
|
||||
std::shared_ptr<EffectContext::DataMQ> outputMQ = context->getOutputDataFmq();
|
||||
auto buffer = context->getWorkBuffer();
|
||||
|
||||
// Only this worker will read from input data MQ and write to output data MQ.
|
||||
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;
|
||||
|
||||
inputMQ->read(buffer, processSamples);
|
||||
|
||||
// call effectProcessImpl without lock
|
||||
IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
|
||||
outputMQ->write(buffer, status.fmqProduced);
|
||||
statusMQ->writeBlocking(&status, 1);
|
||||
LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqConsumed
|
||||
<< " produced " << status.fmqProduced;
|
||||
} else {
|
||||
// TODO: maybe add some sleep here to avoid busy waiting
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -14,10 +14,11 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#define LOG_TAG "AHAL_BassBoostSw"
|
||||
#include <Utils.h>
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
@ -73,28 +74,74 @@ ndk::ScopedAStatus BassBoostSw::getDescriptor(Descriptor* _aidl_return) {
|
|||
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();
|
||||
auto& bbParam = specific.get<Parameter::Specific::bassBoost>();
|
||||
auto tag = bbParam.getTag();
|
||||
|
||||
switch (tag) {
|
||||
case BassBoost::strengthPm: {
|
||||
RETURN_IF(!mStrengthSupported, EX_ILLEGAL_ARGUMENT, "SettingStrengthNotSupported");
|
||||
|
||||
RETURN_IF(mContext->setBbStrengthPm(bbParam.get<BassBoost::strengthPm>()) !=
|
||||
RetCode::SUCCESS,
|
||||
EX_ILLEGAL_ARGUMENT, "strengthPmNotSupported");
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
default: {
|
||||
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"BassBoostTagNotSupported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
auto bbId = id.get<Parameter::Id::bassBoostTag>();
|
||||
auto bbIdTag = bbId.getTag();
|
||||
switch (bbIdTag) {
|
||||
case BassBoost::Id::commonTag:
|
||||
return getParameterBassBoost(bbId.get<BassBoost::Id::commonTag>(), specific);
|
||||
default:
|
||||
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"BassBoostTagNotSupported");
|
||||
}
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus BassBoostSw::getParameterBassBoost(const BassBoost::Tag& tag,
|
||||
Parameter::Specific* specific) {
|
||||
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
|
||||
BassBoost bbParam;
|
||||
switch (tag) {
|
||||
case BassBoost::strengthPm: {
|
||||
bbParam.set<BassBoost::strengthPm>(mContext->getBbStrengthPm());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"BassBoostTagNotSupported");
|
||||
}
|
||||
}
|
||||
|
||||
specific->set<Parameter::Specific::bassBoost>(bbParam);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> BassBoostSw::createContext(const Parameter::Common& common) {
|
||||
if (mContext) {
|
||||
LOG(DEBUG) << __func__ << " context already exist";
|
||||
return mContext;
|
||||
} else {
|
||||
mContext = std::make_shared<BassBoostSwContext>(1 /* statusFmqDepth */, common);
|
||||
}
|
||||
mContext = std::make_shared<BassBoostSwContext>(1 /* statusFmqDepth */, common);
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> BassBoostSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
|
@ -106,13 +153,13 @@ RetCode BassBoostSw::releaseContext() {
|
|||
}
|
||||
|
||||
// Processing method running in EffectWorker thread.
|
||||
IEffect::Status BassBoostSw::effectProcessImpl(float* in, float* out, int process) {
|
||||
IEffect::Status BassBoostSw::effectProcessImpl(float* in, float* out, int samples) {
|
||||
// TODO: get data buffer and process.
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
|
||||
for (int i = 0; i < process; i++) {
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
return {STATUS_OK, process, process};
|
||||
return {STATUS_OK, samples, samples};
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -32,7 +32,21 @@ class BassBoostSwContext final : public EffectContext {
|
|||
: EffectContext(statusDepth, common) {
|
||||
LOG(DEBUG) << __func__;
|
||||
}
|
||||
// TODO: add specific context here
|
||||
|
||||
RetCode setBbStrengthPm(int strength) {
|
||||
if (strength < BassBoost::MIN_PER_MILLE_STRENGTH ||
|
||||
strength > BassBoost::MAX_PER_MILLE_STRENGTH) {
|
||||
LOG(ERROR) << __func__ << " invalid strength: " << strength;
|
||||
return RetCode::ERROR_ILLEGAL_PARAMETER;
|
||||
}
|
||||
// TODO : Add implementation to apply new strength
|
||||
mStrength = strength;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
int getBbStrengthPm() const { return mStrength; }
|
||||
|
||||
private:
|
||||
int mStrength;
|
||||
};
|
||||
|
||||
class BassBoostSw final : public EffectImpl {
|
||||
|
@ -47,14 +61,20 @@ class BassBoostSw final : public EffectImpl {
|
|||
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;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
|
||||
std::string getEffectName() override { return kEffectName; };
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
|
||||
private:
|
||||
const std::string kEffectName = "BassBoostSw";
|
||||
std::shared_ptr<BassBoostSwContext> mContext;
|
||||
/* capabilities */
|
||||
const BassBoost::Capability kCapability;
|
||||
const bool mStrengthSupported = true;
|
||||
const BassBoost::Capability kCapability = {.strengthSupported = mStrengthSupported};
|
||||
/* Effect descriptor */
|
||||
const Descriptor kDescriptor = {
|
||||
.common = {.id = {.type = kBassBoostTypeUUID,
|
||||
|
@ -63,11 +83,11 @@ class BassBoostSw final : public EffectImpl {
|
|||
.flags = {.type = Flags::Type::INSERT,
|
||||
.insert = Flags::Insert::FIRST,
|
||||
.volume = Flags::Volume::CTRL},
|
||||
.name = "BassBoostSw",
|
||||
.name = kEffectName,
|
||||
.implementor = "The Android Open Source Project"},
|
||||
.capability = Capability::make<Capability::bassBoost>(kCapability)};
|
||||
|
||||
/* parameters */
|
||||
BassBoost mSpecificParam;
|
||||
ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -73,8 +73,6 @@ ndk::ScopedAStatus DynamicsProcessingSw::getDescriptor(Descriptor* _aidl_return)
|
|||
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();
|
||||
|
@ -93,9 +91,13 @@ std::shared_ptr<EffectContext> DynamicsProcessingSw::createContext(
|
|||
const Parameter::Common& common) {
|
||||
if (mContext) {
|
||||
LOG(DEBUG) << __func__ << " context already exist";
|
||||
return mContext;
|
||||
} else {
|
||||
mContext = std::make_shared<DynamicsProcessingSwContext>(1 /* statusFmqDepth */, common);
|
||||
}
|
||||
mContext = std::make_shared<DynamicsProcessingSwContext>(1 /* statusFmqDepth */, common);
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> DynamicsProcessingSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
|
@ -107,13 +109,13 @@ RetCode DynamicsProcessingSw::releaseContext() {
|
|||
}
|
||||
|
||||
// Processing method running in EffectWorker thread.
|
||||
IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, int process) {
|
||||
IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, int samples) {
|
||||
// TODO: get data buffer and process.
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
|
||||
for (int i = 0; i < process; i++) {
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
return {STATUS_OK, process, process};
|
||||
return {STATUS_OK, samples, samples};
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -47,11 +47,16 @@ class DynamicsProcessingSw final : public EffectImpl {
|
|||
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;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
std::string getEffectName() override { return kEffectName; };
|
||||
|
||||
private:
|
||||
const std::string kEffectName = "DynamicsProcessingSw";
|
||||
std::shared_ptr<DynamicsProcessingSwContext> mContext;
|
||||
/* capabilities */
|
||||
const DynamicsProcessing::Capability kCapability;
|
||||
|
@ -63,7 +68,7 @@ class DynamicsProcessingSw final : public EffectImpl {
|
|||
.flags = {.type = Flags::Type::INSERT,
|
||||
.insert = Flags::Insert::FIRST,
|
||||
.volume = Flags::Volume::CTRL},
|
||||
.name = "DynamicsProcessingSw",
|
||||
.name = kEffectName,
|
||||
.implementor = "The Android Open Source Project"},
|
||||
.capability = Capability::make<Capability::dynamicsProcessing>(kCapability)};
|
||||
|
||||
|
|
|
@ -73,8 +73,6 @@ ndk::ScopedAStatus EnvReverbSw::getDescriptor(Descriptor* _aidl_return) {
|
|||
ndk::ScopedAStatus EnvReverbSw::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();
|
||||
|
@ -92,9 +90,14 @@ ndk::ScopedAStatus EnvReverbSw::getParameterSpecific(const Parameter::Id& id,
|
|||
std::shared_ptr<EffectContext> EnvReverbSw::createContext(const Parameter::Common& common) {
|
||||
if (mContext) {
|
||||
LOG(DEBUG) << __func__ << " context already exist";
|
||||
return mContext;
|
||||
} else {
|
||||
mContext = std::make_shared<EnvReverbSwContext>(1 /* statusFmqDepth */, common);
|
||||
}
|
||||
mContext = std::make_shared<EnvReverbSwContext>(1 /* statusFmqDepth */, common);
|
||||
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> EnvReverbSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
|
@ -106,13 +109,13 @@ RetCode EnvReverbSw::releaseContext() {
|
|||
}
|
||||
|
||||
// Processing method running in EffectWorker thread.
|
||||
IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int process) {
|
||||
IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int samples) {
|
||||
// TODO: get data buffer and process.
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
|
||||
for (int i = 0; i < process; i++) {
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
return {STATUS_OK, process, process};
|
||||
return {STATUS_OK, samples, samples};
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -47,11 +47,16 @@ class EnvReverbSw final : public EffectImpl {
|
|||
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;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
const std::string kEffectName = "EnvReverbSw";
|
||||
std::shared_ptr<EnvReverbSwContext> mContext;
|
||||
/* capabilities */
|
||||
const Reverb::Capability kCapability;
|
||||
|
@ -63,7 +68,7 @@ class EnvReverbSw final : public EffectImpl {
|
|||
.flags = {.type = Flags::Type::INSERT,
|
||||
.insert = Flags::Insert::FIRST,
|
||||
.volume = Flags::Volume::CTRL},
|
||||
.name = "EnvReverbSw",
|
||||
.name = kEffectName,
|
||||
.implementor = "The Android Open Source Project"},
|
||||
.capability = Capability::make<Capability::reverb>(kCapability)};
|
||||
|
||||
|
|
|
@ -70,7 +70,6 @@ ndk::ScopedAStatus EqualizerSw::getDescriptor(Descriptor* _aidl_return) {
|
|||
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>();
|
||||
|
@ -117,7 +116,6 @@ ndk::ScopedAStatus EqualizerSw::getParameterSpecific(const Parameter::Id& id,
|
|||
|
||||
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;
|
||||
|
@ -144,9 +142,14 @@ ndk::ScopedAStatus EqualizerSw::getParameterEqualizer(const Equalizer::Tag& tag,
|
|||
std::shared_ptr<EffectContext> EqualizerSw::createContext(const Parameter::Common& common) {
|
||||
if (mContext) {
|
||||
LOG(DEBUG) << __func__ << " context already exist";
|
||||
return mContext;
|
||||
} else {
|
||||
mContext = std::make_shared<EqualizerSwContext>(1 /* statusFmqDepth */, common);
|
||||
}
|
||||
mContext = std::make_shared<EqualizerSwContext>(1 /* statusFmqDepth */, common);
|
||||
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> EqualizerSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
|
@ -158,13 +161,13 @@ RetCode EqualizerSw::releaseContext() {
|
|||
}
|
||||
|
||||
// Processing method running in EffectWorker thread.
|
||||
IEffect::Status EqualizerSw::effectProcessImpl(float* in, float* out, int process) {
|
||||
IEffect::Status EqualizerSw::effectProcessImpl(float* in, float* out, int samples) {
|
||||
// TODO: get data buffer and process.
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
|
||||
for (int i = 0; i < process; i++) {
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
return {STATUS_OK, process, process};
|
||||
return {STATUS_OK, samples, samples};
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -90,11 +90,16 @@ class EqualizerSw final : public EffectImpl {
|
|||
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;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
const std::string kEffectName = "EqualizerSw";
|
||||
std::shared_ptr<EqualizerSwContext> mContext;
|
||||
/* capabilities */
|
||||
const std::vector<Equalizer::BandFrequency> mBandFrequency = {{0, 30000, 120000},
|
||||
|
@ -115,7 +120,7 @@ class EqualizerSw final : public EffectImpl {
|
|||
.flags = {.type = Flags::Type::INSERT,
|
||||
.insert = Flags::Insert::FIRST,
|
||||
.volume = Flags::Volume::CTRL},
|
||||
.name = "EqualizerSw",
|
||||
.name = kEffectName,
|
||||
.implementor = "The Android Open Source Project"},
|
||||
.capability = Capability::make<Capability::equalizer>(kEqCap)};
|
||||
|
||||
|
|
|
@ -73,9 +73,6 @@ ndk::ScopedAStatus HapticGeneratorSw::getDescriptor(Descriptor* _aidl_return) {
|
|||
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();
|
||||
|
@ -92,9 +89,14 @@ ndk::ScopedAStatus HapticGeneratorSw::getParameterSpecific(const Parameter::Id&
|
|||
std::shared_ptr<EffectContext> HapticGeneratorSw::createContext(const Parameter::Common& common) {
|
||||
if (mContext) {
|
||||
LOG(DEBUG) << __func__ << " context already exist";
|
||||
return mContext;
|
||||
} else {
|
||||
mContext = std::make_shared<HapticGeneratorSwContext>(1 /* statusFmqDepth */, common);
|
||||
}
|
||||
mContext = std::make_shared<HapticGeneratorSwContext>(1 /* statusFmqDepth */, common);
|
||||
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> HapticGeneratorSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
|
@ -106,13 +108,13 @@ RetCode HapticGeneratorSw::releaseContext() {
|
|||
}
|
||||
|
||||
// Processing method running in EffectWorker thread.
|
||||
IEffect::Status HapticGeneratorSw::effectProcessImpl(float* in, float* out, int process) {
|
||||
IEffect::Status HapticGeneratorSw::effectProcessImpl(float* in, float* out, int samples) {
|
||||
// TODO: get data buffer and process.
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
|
||||
for (int i = 0; i < process; i++) {
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
return {STATUS_OK, process, process};
|
||||
return {STATUS_OK, samples, samples};
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -47,11 +47,16 @@ class HapticGeneratorSw final : public EffectImpl {
|
|||
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;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
const std::string kEffectName = "HapticGeneratorSw";
|
||||
std::shared_ptr<HapticGeneratorSwContext> mContext;
|
||||
/* capabilities */
|
||||
const HapticGenerator::Capability kCapability;
|
||||
|
@ -63,7 +68,7 @@ class HapticGeneratorSw final : public EffectImpl {
|
|||
.flags = {.type = Flags::Type::INSERT,
|
||||
.insert = Flags::Insert::FIRST,
|
||||
.volume = Flags::Volume::CTRL},
|
||||
.name = "HapticGeneratorSw",
|
||||
.name = kEffectName,
|
||||
.implementor = "The Android Open Source Project"},
|
||||
.capability = Capability::make<Capability::hapticGenerator>(kCapability)};
|
||||
|
||||
|
|
|
@ -16,16 +16,13 @@
|
|||
|
||||
#pragma once
|
||||
#include <Utils.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <utils/Log.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <aidl/android/hardware/audio/effect/BnEffect.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
|
||||
#include <aidl/android/hardware/audio/effect/BnEffect.h>
|
||||
#include "EffectTypes.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
@ -74,13 +71,10 @@ class EffectContext {
|
|||
std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; }
|
||||
|
||||
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(); }
|
||||
|
||||
// reset buffer status by abandon all data and status in FMQ
|
||||
void resetBuffer() {
|
||||
auto buffer = getWorkBuffer();
|
||||
auto buffer = static_cast<float*>(mWorkBuffer.data());
|
||||
std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
|
||||
mInputMQ->read(buffer, mInputMQ->availableToRead());
|
||||
mOutputMQ->read(buffer, mOutputMQ->availableToRead());
|
||||
|
@ -89,9 +83,9 @@ class EffectContext {
|
|||
|
||||
void dupeFmq(IEffect::OpenEffectReturn* effectRet) {
|
||||
if (effectRet) {
|
||||
effectRet->statusMQ = getStatusFmq()->dupeDesc();
|
||||
effectRet->inputDataMQ = getInputDataFmq()->dupeDesc();
|
||||
effectRet->outputDataMQ = getOutputDataFmq()->dupeDesc();
|
||||
effectRet->statusMQ = mStatusMQ->dupeDesc();
|
||||
effectRet->inputDataMQ = mInputMQ->dupeDesc();
|
||||
effectRet->outputDataMQ = mOutputMQ->dupeDesc();
|
||||
}
|
||||
}
|
||||
size_t getInputFrameSize() { return mInputFrameSize; }
|
||||
|
@ -138,7 +132,8 @@ class EffectContext {
|
|||
protected:
|
||||
// common parameters
|
||||
int mSessionId = INVALID_AUDIO_SESSION_ID;
|
||||
size_t mInputFrameSize, mOutputFrameSize;
|
||||
size_t mInputFrameSize;
|
||||
size_t mOutputFrameSize;
|
||||
Parameter::Common mCommon;
|
||||
aidl::android::media::audio::common::AudioDeviceDescription mOutputDevice;
|
||||
aidl::android::media::audio::common::AudioMode mMode;
|
||||
|
|
|
@ -15,45 +15,35 @@
|
|||
*/
|
||||
|
||||
#pragma once
|
||||
#include <aidl/android/hardware/audio/effect/BnEffect.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include <aidl/android/hardware/audio/effect/BnEffect.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
|
||||
#include "EffectContext.h"
|
||||
#include "EffectThread.h"
|
||||
#include "EffectTypes.h"
|
||||
#include "effect-impl/EffectContext.h"
|
||||
#include "effect-impl/EffectThread.h"
|
||||
#include "effect-impl/EffectTypes.h"
|
||||
#include "effect-impl/EffectWorker.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
class EffectImpl : public BnEffect, public EffectWorker {
|
||||
class EffectImpl : public BnEffect, public EffectThread {
|
||||
public:
|
||||
EffectImpl() = default;
|
||||
virtual ~EffectImpl() = default;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
@ -63,21 +53,32 @@ class EffectImpl : public BnEffect, public EffectWorker {
|
|||
virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) = 0;
|
||||
virtual ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) = 0;
|
||||
|
||||
virtual std::string getEffectName() = 0;
|
||||
virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
|
||||
/**
|
||||
* Effect context methods must be implemented by each effect.
|
||||
* Each effect can derive from EffectContext and define its own context, but must upcast to
|
||||
* EffectContext for EffectImpl to use.
|
||||
*/
|
||||
virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) = 0;
|
||||
virtual std::shared_ptr<EffectContext> getContext() = 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;
|
||||
State mState = State::INIT;
|
||||
|
||||
IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
|
||||
void cleanUp();
|
||||
|
||||
private:
|
||||
std::shared_ptr<EffectContext> mContext GUARDED_BY(mMutex);
|
||||
/**
|
||||
* Optional CommandId handling methods for effects to override.
|
||||
* For CommandId::START, EffectImpl call commandImpl before starting the EffectThread
|
||||
* processing.
|
||||
* For CommandId::STOP and CommandId::RESET, EffectImpl call commandImpl after stop the
|
||||
* EffectThread processing.
|
||||
*/
|
||||
virtual ndk::ScopedAStatus commandImpl(CommandId id);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <android-base/thread_annotations.h>
|
||||
#include <system/thread_defs.h>
|
||||
|
||||
#include "effect-impl/EffectContext.h"
|
||||
#include "effect-impl/EffectTypes.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
@ -33,7 +34,7 @@ class EffectThread {
|
|||
virtual ~EffectThread();
|
||||
|
||||
// called by effect implementation.
|
||||
RetCode createThread(const std::string& name,
|
||||
RetCode createThread(std::shared_ptr<EffectContext> context, const std::string& name,
|
||||
const int priority = ANDROID_PRIORITY_URGENT_AUDIO);
|
||||
RetCode destroyThread();
|
||||
RetCode startThread();
|
||||
|
@ -42,15 +43,43 @@ class EffectThread {
|
|||
// Will call process() in a loop if the thread is running.
|
||||
void threadLoop();
|
||||
|
||||
// User of EffectThread must implement the effect processing logic in this method.
|
||||
virtual void process() = 0;
|
||||
const int MAX_TASK_COMM_LEN = 15;
|
||||
/**
|
||||
* @brief effectProcessImpl is running in worker thread which created in EffectThread.
|
||||
*
|
||||
* Effect implementation should think about concurrency in the implementation if necessary.
|
||||
* Parameter setting usually implemented in context (derived from EffectContext), and some
|
||||
* parameter maybe used in the processing, then effect implementation should consider using a
|
||||
* mutex to protect these parameter.
|
||||
*
|
||||
* EffectThread will make sure effectProcessImpl only be called after startThread() successful
|
||||
* and before stopThread() successful.
|
||||
*
|
||||
* @param in address of input float buffer.
|
||||
* @param out address of output float buffer.
|
||||
* @param samples number of samples to process.
|
||||
* @return IEffect::Status
|
||||
*/
|
||||
virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
|
||||
|
||||
/**
|
||||
* The default EffectThread::process() implementation doesn't need to lock. It will only
|
||||
* access the FMQ and mWorkBuffer in EffectContext, since they will only be changed in
|
||||
* EffectImpl IEffect::open() (in this case EffectThread just created and not running yet) and
|
||||
* IEffect::command(CommandId::RESET) (in this case EffectThread already stopped).
|
||||
*
|
||||
* process() call effectProcessImpl for effect processing, and because effectProcessImpl is
|
||||
* implemented by effects, process() must not hold lock before call into effectProcessImpl to
|
||||
* avoid deadlock.
|
||||
*/
|
||||
virtual void process();
|
||||
|
||||
private:
|
||||
std::mutex mMutex;
|
||||
const int kMaxTaskNameLen = 15;
|
||||
std::mutex mThreadMutex;
|
||||
std::condition_variable mCv;
|
||||
bool mExit GUARDED_BY(mMutex) = false;
|
||||
bool mStop GUARDED_BY(mMutex) = true;
|
||||
bool mExit GUARDED_BY(mThreadMutex) = false;
|
||||
bool mStop GUARDED_BY(mThreadMutex) = true;
|
||||
std::shared_ptr<EffectContext> mThreadContext GUARDED_BY(mThreadMutex);
|
||||
std::thread mThread;
|
||||
int mPriority;
|
||||
std::string mName;
|
||||
|
|
|
@ -63,7 +63,7 @@ class EffectWorker : public EffectThread {
|
|||
|
||||
// must implement by each effect implementation
|
||||
// TODO: consider if this interface need adjustment to handle in-place processing
|
||||
virtual IEffect::Status effectProcessImpl(float* in, float* out, int processSamples) = 0;
|
||||
virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
|
||||
|
||||
private:
|
||||
// make sure the context only set once.
|
||||
|
|
|
@ -73,7 +73,6 @@ ndk::ScopedAStatus LoudnessEnhancerSw::getDescriptor(Descriptor* _aidl_return) {
|
|||
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");
|
||||
|
||||
auto& leParam = specific.get<Parameter::Specific::loudnessEnhancer>();
|
||||
|
@ -113,7 +112,6 @@ ndk::ScopedAStatus LoudnessEnhancerSw::getParameterSpecific(const Parameter::Id&
|
|||
|
||||
ndk::ScopedAStatus LoudnessEnhancerSw::getParameterLoudnessEnhancer(
|
||||
const LoudnessEnhancer::Tag& tag, Parameter::Specific* specific) {
|
||||
std::lock_guard lg(mMutex);
|
||||
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
|
||||
|
||||
LoudnessEnhancer leParam;
|
||||
|
@ -136,9 +134,14 @@ ndk::ScopedAStatus LoudnessEnhancerSw::getParameterLoudnessEnhancer(
|
|||
std::shared_ptr<EffectContext> LoudnessEnhancerSw::createContext(const Parameter::Common& common) {
|
||||
if (mContext) {
|
||||
LOG(DEBUG) << __func__ << " context already exist";
|
||||
return mContext;
|
||||
} else {
|
||||
mContext = std::make_shared<LoudnessEnhancerSwContext>(1 /* statusFmqDepth */, common);
|
||||
}
|
||||
mContext = std::make_shared<LoudnessEnhancerSwContext>(1 /* statusFmqDepth */, common);
|
||||
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> LoudnessEnhancerSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
|
@ -150,13 +153,13 @@ RetCode LoudnessEnhancerSw::releaseContext() {
|
|||
}
|
||||
|
||||
// Processing method running in EffectWorker thread.
|
||||
IEffect::Status LoudnessEnhancerSw::effectProcessImpl(float* in, float* out, int process) {
|
||||
IEffect::Status LoudnessEnhancerSw::effectProcessImpl(float* in, float* out, int samples) {
|
||||
// TODO: get data buffer and process.
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
|
||||
for (int i = 0; i < process; i++) {
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
return {STATUS_OK, process, process};
|
||||
return {STATUS_OK, samples, samples};
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -56,11 +56,16 @@ class LoudnessEnhancerSw final : public EffectImpl {
|
|||
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;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
const std::string kEffectName = "LoudnessEnhancerSw";
|
||||
std::shared_ptr<LoudnessEnhancerSwContext> mContext;
|
||||
/* capabilities */
|
||||
const LoudnessEnhancer::Capability kCapability;
|
||||
|
@ -72,7 +77,7 @@ class LoudnessEnhancerSw final : public EffectImpl {
|
|||
.flags = {.type = Flags::Type::INSERT,
|
||||
.insert = Flags::Insert::FIRST,
|
||||
.volume = Flags::Volume::CTRL},
|
||||
.name = "LoudnessEnhancerSw",
|
||||
.name = kEffectName,
|
||||
.implementor = "The Android Open Source Project"},
|
||||
.capability = Capability::make<Capability::loudnessEnhancer>(kCapability)};
|
||||
|
||||
|
|
|
@ -73,8 +73,6 @@ ndk::ScopedAStatus PresetReverbSw::getDescriptor(Descriptor* _aidl_return) {
|
|||
ndk::ScopedAStatus PresetReverbSw::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();
|
||||
|
@ -92,9 +90,14 @@ ndk::ScopedAStatus PresetReverbSw::getParameterSpecific(const Parameter::Id& id,
|
|||
std::shared_ptr<EffectContext> PresetReverbSw::createContext(const Parameter::Common& common) {
|
||||
if (mContext) {
|
||||
LOG(DEBUG) << __func__ << " context already exist";
|
||||
return mContext;
|
||||
} else {
|
||||
mContext = std::make_shared<PresetReverbSwContext>(1 /* statusFmqDepth */, common);
|
||||
}
|
||||
mContext = std::make_shared<PresetReverbSwContext>(1 /* statusFmqDepth */, common);
|
||||
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> PresetReverbSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
|
@ -106,13 +109,13 @@ RetCode PresetReverbSw::releaseContext() {
|
|||
}
|
||||
|
||||
// Processing method running in EffectWorker thread.
|
||||
IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int process) {
|
||||
IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int samples) {
|
||||
// TODO: get data buffer and process.
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
|
||||
for (int i = 0; i < process; i++) {
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
return {STATUS_OK, process, process};
|
||||
return {STATUS_OK, samples, samples};
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -47,11 +47,16 @@ class PresetReverbSw final : public EffectImpl {
|
|||
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;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
const std::string kEffectName = "PresetReverbSw";
|
||||
std::shared_ptr<PresetReverbSwContext> mContext;
|
||||
/* capabilities */
|
||||
const Reverb::Capability kCapability;
|
||||
|
@ -63,7 +68,7 @@ class PresetReverbSw final : public EffectImpl {
|
|||
.flags = {.type = Flags::Type::INSERT,
|
||||
.insert = Flags::Insert::FIRST,
|
||||
.volume = Flags::Volume::CTRL},
|
||||
.name = "PresetReverbSw",
|
||||
.name = kEffectName,
|
||||
.implementor = "The Android Open Source Project"},
|
||||
.capability = Capability::make<Capability::reverb>(kCapability)};
|
||||
|
||||
|
|
|
@ -73,8 +73,6 @@ ndk::ScopedAStatus VirtualizerSw::getDescriptor(Descriptor* _aidl_return) {
|
|||
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();
|
||||
|
@ -92,9 +90,14 @@ ndk::ScopedAStatus VirtualizerSw::getParameterSpecific(const Parameter::Id& id,
|
|||
std::shared_ptr<EffectContext> VirtualizerSw::createContext(const Parameter::Common& common) {
|
||||
if (mContext) {
|
||||
LOG(DEBUG) << __func__ << " context already exist";
|
||||
return mContext;
|
||||
} else {
|
||||
mContext = std::make_shared<VirtualizerSwContext>(1 /* statusFmqDepth */, common);
|
||||
}
|
||||
mContext = std::make_shared<VirtualizerSwContext>(1 /* statusFmqDepth */, common);
|
||||
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> VirtualizerSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
|
@ -106,13 +109,13 @@ RetCode VirtualizerSw::releaseContext() {
|
|||
}
|
||||
|
||||
// Processing method running in EffectWorker thread.
|
||||
IEffect::Status VirtualizerSw::effectProcessImpl(float* in, float* out, int process) {
|
||||
IEffect::Status VirtualizerSw::effectProcessImpl(float* in, float* out, int samples) {
|
||||
// TODO: get data buffer and process.
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
|
||||
for (int i = 0; i < process; i++) {
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
return {STATUS_OK, process, process};
|
||||
return {STATUS_OK, samples, samples};
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -47,11 +47,16 @@ class VirtualizerSw final : public EffectImpl {
|
|||
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;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
const std::string kEffectName = "VirtualizerSw";
|
||||
std::shared_ptr<VirtualizerSwContext> mContext;
|
||||
/* capabilities */
|
||||
const Virtualizer::Capability kCapability;
|
||||
|
@ -63,7 +68,7 @@ class VirtualizerSw final : public EffectImpl {
|
|||
.flags = {.type = Flags::Type::INSERT,
|
||||
.insert = Flags::Insert::FIRST,
|
||||
.volume = Flags::Volume::CTRL},
|
||||
.name = "VirtualizerSw",
|
||||
.name = kEffectName,
|
||||
.implementor = "The Android Open Source Project"},
|
||||
.capability = Capability::make<Capability::virtualizer>(kCapability)};
|
||||
|
||||
|
|
|
@ -73,8 +73,6 @@ ndk::ScopedAStatus VisualizerSw::getDescriptor(Descriptor* _aidl_return) {
|
|||
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();
|
||||
|
@ -92,9 +90,14 @@ ndk::ScopedAStatus VisualizerSw::getParameterSpecific(const Parameter::Id& id,
|
|||
std::shared_ptr<EffectContext> VisualizerSw::createContext(const Parameter::Common& common) {
|
||||
if (mContext) {
|
||||
LOG(DEBUG) << __func__ << " context already exist";
|
||||
return mContext;
|
||||
} else {
|
||||
mContext = std::make_shared<VisualizerSwContext>(1 /* statusFmqDepth */, common);
|
||||
}
|
||||
mContext = std::make_shared<VisualizerSwContext>(1 /* statusFmqDepth */, common);
|
||||
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> VisualizerSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
|
@ -106,13 +109,13 @@ RetCode VisualizerSw::releaseContext() {
|
|||
}
|
||||
|
||||
// Processing method running in EffectWorker thread.
|
||||
IEffect::Status VisualizerSw::effectProcessImpl(float* in, float* out, int process) {
|
||||
IEffect::Status VisualizerSw::effectProcessImpl(float* in, float* out, int samples) {
|
||||
// TODO: get data buffer and process.
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
|
||||
for (int i = 0; i < process; i++) {
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
return {STATUS_OK, process, process};
|
||||
return {STATUS_OK, samples, samples};
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -47,11 +47,16 @@ class VisualizerSw final : public EffectImpl {
|
|||
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;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
const std::string kEffectName = "VisualizerSw";
|
||||
std::shared_ptr<VisualizerSwContext> mContext;
|
||||
/* capabilities */
|
||||
const Visualizer::Capability kCapability;
|
||||
|
@ -63,7 +68,7 @@ class VisualizerSw final : public EffectImpl {
|
|||
.flags = {.type = Flags::Type::INSERT,
|
||||
.insert = Flags::Insert::FIRST,
|
||||
.volume = Flags::Volume::CTRL},
|
||||
.name = "VisualizerSw",
|
||||
.name = kEffectName,
|
||||
.implementor = "The Android Open Source Project"},
|
||||
.capability = Capability::make<Capability::visualizer>(kCapability)};
|
||||
|
||||
|
|
|
@ -73,8 +73,6 @@ ndk::ScopedAStatus VolumeSw::getDescriptor(Descriptor* _aidl_return) {
|
|||
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();
|
||||
|
@ -92,9 +90,14 @@ ndk::ScopedAStatus VolumeSw::getParameterSpecific(const Parameter::Id& id,
|
|||
std::shared_ptr<EffectContext> VolumeSw::createContext(const Parameter::Common& common) {
|
||||
if (mContext) {
|
||||
LOG(DEBUG) << __func__ << " context already exist";
|
||||
return mContext;
|
||||
} else {
|
||||
mContext = std::make_shared<VolumeSwContext>(1 /* statusFmqDepth */, common);
|
||||
}
|
||||
mContext = std::make_shared<VolumeSwContext>(1 /* statusFmqDepth */, common);
|
||||
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> VolumeSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
|
@ -106,13 +109,13 @@ RetCode VolumeSw::releaseContext() {
|
|||
}
|
||||
|
||||
// Processing method running in EffectWorker thread.
|
||||
IEffect::Status VolumeSw::effectProcessImpl(float* in, float* out, int process) {
|
||||
IEffect::Status VolumeSw::effectProcessImpl(float* in, float* out, int samples) {
|
||||
// TODO: get data buffer and process.
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
|
||||
for (int i = 0; i < process; i++) {
|
||||
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
return {STATUS_OK, process, process};
|
||||
return {STATUS_OK, samples, samples};
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -47,11 +47,16 @@ class VolumeSw final : public EffectImpl {
|
|||
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;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
const std::string kEffectName = "VolumeSw";
|
||||
std::shared_ptr<VolumeSwContext> mContext;
|
||||
/* capabilities */
|
||||
const Volume::Capability kCapability;
|
||||
|
@ -63,7 +68,7 @@ class VolumeSw final : public EffectImpl {
|
|||
.flags = {.type = Flags::Type::INSERT,
|
||||
.insert = Flags::Insert::FIRST,
|
||||
.volume = Flags::Volume::CTRL},
|
||||
.name = "VolumeSw",
|
||||
.name = kEffectName,
|
||||
.implementor = "The Android Open Source Project"},
|
||||
.capability = Capability::make<Capability::volume>(kCapability)};
|
||||
|
||||
|
|
185
audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
Normal file
185
audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* 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 "VtsHalBassBoostTest"
|
||||
|
||||
#include <Utils.h>
|
||||
#include <aidl/Vintf.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "EffectHelper.h"
|
||||
|
||||
using namespace android;
|
||||
|
||||
using aidl::android::hardware::audio::effect::BassBoost;
|
||||
using aidl::android::hardware::audio::effect::Capability;
|
||||
using aidl::android::hardware::audio::effect::Descriptor;
|
||||
using aidl::android::hardware::audio::effect::IEffect;
|
||||
using aidl::android::hardware::audio::effect::IFactory;
|
||||
using aidl::android::hardware::audio::effect::kBassBoostTypeUUID;
|
||||
using aidl::android::hardware::audio::effect::Parameter;
|
||||
|
||||
/**
|
||||
* Here we focus on specific parameter checking, general IEffect interfaces testing performed in
|
||||
* VtsAudioEffectTargetTest.
|
||||
*/
|
||||
enum ParamName { PARAM_INSTANCE_NAME, PARAM_STRENGTH };
|
||||
using BassBoostParamTestParam =
|
||||
std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
|
||||
|
||||
/*
|
||||
* Testing parameter range, assuming the parameter supported by effect is in this range.
|
||||
* Parameter should be within the valid range defined in the documentation,
|
||||
* for any supported value test expects EX_NONE from IEffect.setParameter(),
|
||||
* otherwise expect EX_ILLEGAL_ARGUMENT.
|
||||
*/
|
||||
|
||||
const std::vector<int> kStrengthValues = {
|
||||
std::numeric_limits<int>::min(),
|
||||
BassBoost::MIN_PER_MILLE_STRENGTH - 1,
|
||||
BassBoost::MIN_PER_MILLE_STRENGTH,
|
||||
(BassBoost::MIN_PER_MILLE_STRENGTH + BassBoost::MAX_PER_MILLE_STRENGTH) >> 1,
|
||||
BassBoost::MAX_PER_MILLE_STRENGTH,
|
||||
BassBoost::MAX_PER_MILLE_STRENGTH + 2,
|
||||
std::numeric_limits<int>::max()};
|
||||
|
||||
class BassBoostParamTest : public ::testing::TestWithParam<BassBoostParamTestParam>,
|
||||
public EffectHelper {
|
||||
public:
|
||||
BassBoostParamTest() : mParamStrength(std::get<PARAM_STRENGTH>(GetParam())) {
|
||||
std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
ASSERT_NE(nullptr, mFactory);
|
||||
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
|
||||
|
||||
Parameter::Specific specific = getDefaultParamSpecific();
|
||||
Parameter::Common common = EffectHelper::createParamCommon(
|
||||
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
|
||||
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
|
||||
IEffect::OpenEffectReturn ret;
|
||||
ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
|
||||
ASSERT_NE(nullptr, mEffect);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
ASSERT_NO_FATAL_FAILURE(close(mEffect));
|
||||
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
|
||||
}
|
||||
|
||||
Parameter::Specific getDefaultParamSpecific() {
|
||||
BassBoost bb = BassBoost::make<BassBoost::strengthPm>(BassBoost::MIN_PER_MILLE_STRENGTH);
|
||||
Parameter::Specific specific =
|
||||
Parameter::Specific::make<Parameter::Specific::bassBoost>(bb);
|
||||
return specific;
|
||||
}
|
||||
|
||||
static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
|
||||
std::shared_ptr<IFactory> mFactory;
|
||||
std::shared_ptr<IEffect> mEffect;
|
||||
Descriptor::Identity mIdentity;
|
||||
int mParamStrength = BassBoost::MIN_PER_MILLE_STRENGTH;
|
||||
|
||||
void SetAndGetBassBoostParameters() {
|
||||
for (auto& it : mTags) {
|
||||
auto& tag = it.first;
|
||||
auto& bb = it.second;
|
||||
|
||||
// validate parameter
|
||||
Descriptor desc;
|
||||
ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
|
||||
const bool valid = isTagInRange(it.first, it.second, desc);
|
||||
const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
|
||||
|
||||
// set parameter
|
||||
Parameter expectParam;
|
||||
Parameter::Specific specific;
|
||||
specific.set<Parameter::Specific::bassBoost>(bb);
|
||||
expectParam.set<Parameter::specific>(specific);
|
||||
EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
|
||||
|
||||
// only get if parameter in range and set success
|
||||
if (expected == EX_NONE) {
|
||||
Parameter getParam;
|
||||
Parameter::Id id;
|
||||
BassBoost::Id bbId;
|
||||
bbId.set<BassBoost::Id::commonTag>(tag);
|
||||
id.set<Parameter::Id::bassBoostTag>(bbId);
|
||||
// if set success, then get should match
|
||||
EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
|
||||
EXPECT_EQ(expectParam, getParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addStrengthParam(int strength) {
|
||||
BassBoost bb;
|
||||
bb.set<BassBoost::strengthPm>(strength);
|
||||
mTags.push_back({BassBoost::strengthPm, bb});
|
||||
}
|
||||
|
||||
bool isTagInRange(const BassBoost::Tag& tag, const BassBoost& bb,
|
||||
const Descriptor& desc) const {
|
||||
const BassBoost::Capability& bbCap = desc.capability.get<Capability::bassBoost>();
|
||||
switch (tag) {
|
||||
case BassBoost::strengthPm: {
|
||||
int strength = bb.get<BassBoost::strengthPm>();
|
||||
return isStrengthInRange(bbCap, strength);
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isStrengthInRange(const BassBoost::Capability& cap, int strength) const {
|
||||
return cap.strengthSupported && strength >= BassBoost::MIN_PER_MILLE_STRENGTH &&
|
||||
strength <= BassBoost::MAX_PER_MILLE_STRENGTH;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<BassBoost::Tag, BassBoost>> mTags;
|
||||
void CleanUp() { mTags.clear(); }
|
||||
};
|
||||
|
||||
TEST_P(BassBoostParamTest, SetAndGetStrength) {
|
||||
EXPECT_NO_FATAL_FAILURE(addStrengthParam(mParamStrength));
|
||||
SetAndGetBassBoostParameters();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BassBoostTest, BassBoostParamTest,
|
||||
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
|
||||
IFactory::descriptor, kBassBoostTypeUUID)),
|
||||
testing::ValuesIn(kStrengthValues)),
|
||||
[](const testing::TestParamInfo<BassBoostParamTest::ParamType>& info) {
|
||||
auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
|
||||
std::string strength = std::to_string(std::get<PARAM_STRENGTH>(info.param));
|
||||
std::string name = instance.second.uuid.toString() + "_strength_" + strength;
|
||||
std::replace_if(
|
||||
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
|
||||
return name;
|
||||
});
|
||||
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BassBoostParamTest);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(1);
|
||||
ABinderProcess_startThreadPool();
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
Loading…
Reference in a new issue