AIDL effect: Add Equalizer parameters implementation and vts
Bug: 238913361
Test: atest VtsHalAudioEffectTargetTest
atest VtsHalAudioEffectFactoryTargetTest
atest VtsHalEqualizerTargetTest
Change-Id: I94b2283ca2aa0e45715e1c9ac3ea6ad809ec2a2c
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 2baaad9..e64b90c 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -116,6 +116,6 @@
cc_library_headers {
name: "libaudioaidl_headers",
export_include_dirs: ["include"],
- vendor: true,
+ vendor_available: true,
host_supported: true,
}
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index 0ad9a14..80f120b 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -28,11 +28,11 @@
}
EffectThread::~EffectThread() {
- destroy();
+ destroyThread();
LOG(DEBUG) << __func__ << " done";
};
-RetCode EffectThread::create(const std::string& name, const int priority) {
+RetCode EffectThread::createThread(const std::string& name, const int priority) {
if (mThread.joinable()) {
LOG(WARNING) << __func__ << " thread already created, no-op";
return RetCode::SUCCESS;
@@ -44,7 +44,7 @@
return RetCode::SUCCESS;
}
-RetCode EffectThread::destroy() {
+RetCode EffectThread::destroyThread() {
{
std::lock_guard lg(mMutex);
mStop = mExit = true;
@@ -58,10 +58,10 @@
return RetCode::SUCCESS;
}
-RetCode EffectThread::start() {
+RetCode EffectThread::startThread() {
if (!mThread.joinable()) {
LOG(ERROR) << __func__ << " thread already destroyed";
- return RetCode::ERROR;
+ return RetCode::ERROR_THREAD;
}
{
@@ -78,10 +78,10 @@
return RetCode::SUCCESS;
}
-RetCode EffectThread::stop() {
+RetCode EffectThread::stopThread() {
if (!mThread.joinable()) {
LOG(ERROR) << __func__ << " thread already destroyed";
- return RetCode::ERROR;
+ return RetCode::ERROR_THREAD;
}
{
@@ -117,15 +117,4 @@
}
}
-std::string toString(RetCode& code) {
- switch (code) {
- case RetCode::SUCCESS:
- return "SUCCESS";
- case RetCode::ERROR:
- return "ERROR";
- default:
- return "EnumError";
- }
-}
-
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/Equalizer.cpp b/audio/aidl/default/equalizer/Equalizer.cpp
index 2e4e538..43fa206 100644
--- a/audio/aidl/default/equalizer/Equalizer.cpp
+++ b/audio/aidl/default/equalizer/Equalizer.cpp
@@ -16,10 +16,12 @@
#define LOG_TAG "AHAL_EqualizerSw"
#include <Utils.h>
-#include <android-base/logging.h>
+#include <algorithm>
#include <unordered_set>
-#include "effect-impl/EffectUUID.h"
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
#include "equalizer-impl/EqualizerSw.h"
using android::hardware::audio::common::getFrameSizeInBytes;
@@ -68,20 +70,26 @@
auto& output = common.output;
size_t inputFrameSize = getFrameSizeInBytes(input.base.format, input.base.channelMask);
size_t outputFrameSize = getFrameSizeInBytes(output.base.format, output.base.channelMask);
- if (!createFmq(1, input.frameCount * inputFrameSize, output.frameCount * outputFrameSize,
- _aidl_return)) {
+ 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 != mWorker->create(LOG_TAG)) {
+ if (RetCode::SUCCESS != createThread(LOG_TAG)) {
LOG(ERROR) << __func__ << " created worker thread failed";
- destroyFmq();
+ mContext.reset();
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_UNSUPPORTED_OPERATION,
- "FailedToCreateFmq");
+ "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();
}
@@ -98,8 +106,9 @@
// stop the worker thread
mState = State::INIT;
- mWorker->destroy();
- destroyFmq();
+ destroyThread();
+ mContext.reset();
+
LOG(DEBUG) << __func__;
return ndk::ScopedAStatus::ok();
}
@@ -121,19 +130,19 @@
case CommandId::START:
// start processing.
mState = State::PROCESSING;
- mWorker->start();
+ startThread();
LOG(DEBUG) << __func__ << " state: " << toString(mState);
return ndk::ScopedAStatus::ok();
case CommandId::STOP:
// stop processing.
mState = State::IDLE;
- mWorker->stop();
+ stopThread();
LOG(DEBUG) << __func__ << " state: " << toString(mState);
return ndk::ScopedAStatus::ok();
case CommandId::RESET:
// TODO: reset buffer status.
mState = State::IDLE;
- mWorker->stop();
+ stopThread();
LOG(DEBUG) << __func__ << " state: " << toString(mState);
return ndk::ScopedAStatus::ok();
default:
@@ -173,23 +182,27 @@
LOG(DEBUG) << __func__ << " get: " << _aidl_return->toString();
return ndk::ScopedAStatus::ok();
}
- case Parameter::Id::specificTag: {
- auto& id = in_paramId.get<Parameter::Id::specificTag>();
- if (id != Parameter::Specific::equalizer) {
- LOG(ERROR) << " unsupported parameter Id: " << in_paramId.toString();
- return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
- EX_ILLEGAL_ARGUMENT, "Parameter::IdNotSupported");
- }
+ case Parameter::Id::specificId: {
+ auto& id = in_paramId.get<Parameter::Id::specificId>();
Parameter::Specific specific;
- specific.set<Parameter::Specific::equalizer>(mEqualizerParam);
+ 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();
}
- default:
- return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
- "Parameter::IdNotSupported");
+ 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) {
@@ -198,35 +211,12 @@
}
/// Private methods.
-bool EqualizerSw::createFmq(int statusDepth, int inBufferSize, int outBufferSize,
- OpenEffectReturn* ret) {
- mStatusMQ = std::make_unique<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
- mInputMQ = std::make_unique<DataMQ>(inBufferSize);
- mOutputMQ = std::make_unique<DataMQ>(outBufferSize);
-
- if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
- LOG(ERROR) << __func__ << " created invalid FMQ";
- return false;
- }
- ret->statusMQ = mStatusMQ->dupeDesc();
- ret->inputDataMQ = mInputMQ->dupeDesc();
- ret->outputDataMQ = mOutputMQ->dupeDesc();
- return true;
-}
-
-void EqualizerSw::destroyFmq() {
- mStatusMQ.reset(nullptr);
- mInputMQ.reset(nullptr);
- mOutputMQ.reset(nullptr);
-}
-
ndk::ScopedAStatus EqualizerSw::setCommonParameter(const Parameter::Common& common) {
mCommonParam = common;
LOG(DEBUG) << __func__ << " set: " << mCommonParam.toString();
return ndk::ScopedAStatus::ok();
}
-// TODO: implementation need change to save all parameters.
ndk::ScopedAStatus EqualizerSw::setSpecificParameter(const Parameter::Specific& specific) {
if (Parameter::Specific::equalizer != specific.getTag()) {
LOG(ERROR) << " unsupported effect: " << specific.toString();
@@ -234,9 +224,76 @@
"EffectNotSupported");
}
- mEqualizerParam = specific.get<Parameter::Specific::equalizer>();
- LOG(DEBUG) << __func__ << mEqualizerParam.toString();
- return ndk::ScopedAStatus::ok();
+ 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 ndk::ScopedAStatus::ok();
+ }
+ case Equalizer::vendor: {
+ LOG(DEBUG) << __func__ << " noop for vendor tag now";
+ return ndk::ScopedAStatus::ok();
+ }
+ }
+
+ LOG(ERROR) << __func__ << " unsupported eq param tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "ParamNotSupported");
+}
+
+ndk::ScopedAStatus EqualizerSw::getSpecificParameter(Parameter::Specific::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");
+ }
+ auto eqTag = id.get<Parameter::Specific::Id::equalizerTag>();
+ switch (eqTag) {
+ case Equalizer::bandLevels: {
+ eqParam.set<Equalizer::bandLevels>(mBandLevels);
+ specific->set<Parameter::Specific::equalizer>(eqParam);
+ return ndk::ScopedAStatus::ok();
+ }
+ case Equalizer::preset: {
+ eqParam.set<Equalizer::preset>(mPreset);
+ LOG(DEBUG) << __func__ << " preset " << mPreset;
+ specific->set<Parameter::Specific::equalizer>(eqParam);
+ return ndk::ScopedAStatus::ok();
+ }
+ case Equalizer::vendor: {
+ LOG(DEBUG) << __func__ << " noop for vendor tag now";
+ return ndk::ScopedAStatus::ok();
+ }
+ }
+ LOG(ERROR) << __func__ << " unsupported eq param: " << toString(eqTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "ParamNotSupported");
}
void EqualizerSw::cleanUp() {
@@ -248,9 +305,18 @@
}
}
-// Processing method running in worker thread.
-void EqualizerSwWorker::process() {
- // TODO: add EQ processing with FMQ, should wait until data available before data processing.
+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;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status EqualizerSw::effectProcessImpl() {
+ // TODO: get data buffer and process.
+ return status(STATUS_OK, mContext->availableToRead(), mContext->availableToWrite());
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
new file mode 100644
index 0000000..36492ec
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -0,0 +1,65 @@
+/*
+ * 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 <cstdint>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectContext {
+ public:
+ typedef ::android::AidlMessageQueue<
+ IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ StatusMQ;
+ typedef ::android::AidlMessageQueue<
+ int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ DataMQ;
+
+ EffectContext(size_t statusDepth, size_t inBufferSize, size_t outBufferSize) {
+ mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
+ mInputMQ = std::make_shared<DataMQ>(inBufferSize);
+ mOutputMQ = std::make_shared<DataMQ>(outBufferSize);
+
+ if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
+ LOG(ERROR) << __func__ << " created invalid FMQ";
+ }
+ mWorkBuffer.reserve(std::max(inBufferSize, outBufferSize));
+ };
+
+ 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()); };
+ // TODO: update with actual available size
+ size_t availableToRead() { return mWorkBuffer.capacity(); };
+ size_t availableToWrite() { return mWorkBuffer.capacity(); };
+
+ private:
+ 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;
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectThread.h b/audio/aidl/default/include/effect-impl/EffectThread.h
index e831cea..09a0000 100644
--- a/audio/aidl/default/include/effect-impl/EffectThread.h
+++ b/audio/aidl/default/include/effect-impl/EffectThread.h
@@ -22,12 +22,10 @@
#include <android-base/thread_annotations.h>
#include <system/thread_defs.h>
+#include "effect-impl/EffectTypes.h"
+
namespace aidl::android::hardware::audio::effect {
-enum class RetCode { SUCCESS, ERROR };
-
-std::string toString(RetCode& code);
-
class EffectThread {
public:
// default priority is same as HIDL: ANDROID_PRIORITY_URGENT_AUDIO
@@ -35,10 +33,11 @@
virtual ~EffectThread();
// called by effect implementation.
- RetCode create(const std::string& name, const int priority = ANDROID_PRIORITY_URGENT_AUDIO);
- RetCode destroy();
- RetCode start();
- RetCode stop();
+ RetCode createThread(const std::string& name,
+ const int priority = ANDROID_PRIORITY_URGENT_AUDIO);
+ RetCode destroyThread();
+ RetCode startThread();
+ RetCode stopThread();
// Will call process() in a loop if the thread is running.
void threadLoop();
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
new file mode 100644
index 0000000..46cfc0c
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -0,0 +1,51 @@
+/*
+ * 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 <ostream>
+#include <string>
+
+namespace aidl::android::hardware::audio::effect {
+
+enum class RetCode {
+ SUCCESS,
+ ERROR_ILLEGAL_PARAMETER, /* Illegal parameter */
+ ERROR_THREAD, /* Effect thread error */
+ ERROR_NULL_POINTER, /* NULL pointer */
+ ERROR_ALIGNMENT_ERROR, /* Memory alignment error */
+ ERROR_BLOCK_SIZE_EXCEED /* Maximum block size exceeded */
+};
+
+inline std::ostream& operator<<(std::ostream& out, const RetCode& code) {
+ switch (code) {
+ case RetCode::SUCCESS:
+ return out << "SUCCESS";
+ case RetCode::ERROR_ILLEGAL_PARAMETER:
+ return out << "ERROR_ILLEGAL_PARAMETER";
+ case RetCode::ERROR_THREAD:
+ return out << "ERROR_THREAD";
+ case RetCode::ERROR_NULL_POINTER:
+ return out << "ERROR_NULL_POINTER";
+ case RetCode::ERROR_ALIGNMENT_ERROR:
+ return out << "ERROR_ALIGNMENT_ERROR";
+ case RetCode::ERROR_BLOCK_SIZE_EXCEED:
+ return out << "ERROR_BLOCK_SIZE_EXCEED";
+ }
+
+ return out << "EnumError: " << code;
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
index 99f6c24..48b7137 100644
--- a/audio/aidl/default/include/effect-impl/EffectUUID.h
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -21,6 +21,17 @@
using ::aidl::android::media::audio::common::AudioUuid;
+// Null UUID
+static const AudioUuid EffectNullUuid = {static_cast<int32_t>(0xec7178ec),
+ 0xe5e1,
+ 0x4432,
+ 0xa3f4,
+ {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
+
+// Zero UUID
+static const AudioUuid EffectZeroUuid = {
+ static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
+
// Equalizer type UUID.
static const AudioUuid EqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
0xddd6,
diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h
new file mode 100644
index 0000000..0fe69ff
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectWorker.h
@@ -0,0 +1,74 @@
+/*
+ * 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 <algorithm>
+#include <memory>
+#include <mutex>
+#include <string>
+
+#include "EffectContext.h"
+#include "EffectThread.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+std::string toString(RetCode& code);
+
+class EffectWorker : public EffectThread {
+ public:
+ // set effect context for worker, suppose to only happen once here
+ void setContext(std::shared_ptr<EffectContext> context) {
+ std::call_once(mOnceFlag, [&]() { mContext = context; });
+ };
+
+ // handle FMQ and call effect implemented virtual function
+ void process() override {
+ if (!mContext) {
+ LOG(ERROR) << __func__ << " invalid context!";
+ return;
+ }
+ 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 buffer = mContext->getWorkBuffer();
+ inputMQ->read(buffer, readSize);
+ IEffect::Status status = effectProcessImpl();
+ writeSize = std::min((int32_t)writeSize, status.fmqByteProduced);
+ outputMQ->write(buffer, writeSize);
+ statusMQ->writeBlocking(&status, 1);
+ LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqByteConsumed
+ << " produced " << status.fmqByteProduced;
+ } else {
+ // TODO: maybe add some sleep here to avoid busy waiting
+ }
+ }
+
+ // must implement by each effect implementation
+ virtual IEffect::Status effectProcessImpl() = 0;
+
+ private:
+ // make sure the context only set once.
+ std::once_flag mOnceFlag;
+ std::shared_ptr<EffectContext> mContext;
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/equalizer-impl/EqualizerSw.h b/audio/aidl/default/include/equalizer-impl/EqualizerSw.h
index 58ad1de..aa3a727 100644
--- a/audio/aidl/default/include/equalizer-impl/EqualizerSw.h
+++ b/audio/aidl/default/include/equalizer-impl/EqualizerSw.h
@@ -21,20 +21,29 @@
#include <cstdlib>
#include <memory>
-#include "effect-impl/EffectThread.h"
+#include "effect-impl/EffectContext.h"
+#include "effect-impl/EffectTypes.h"
+#include "effect-impl/EffectUUID.h"
+#include "effect-impl/EffectWorker.h"
namespace aidl::android::hardware::audio::effect {
-class EqualizerSwWorker : public EffectThread {
- // EqualizerSwWorker(const std::string name){EffectThread(name)};
- void process() override;
+class EqualizerSwContext : public EffectContext {
+ public:
+ EqualizerSwContext(int statusDepth, int inBufferSize, int outBufferSize)
+ : EffectContext(statusDepth, inBufferSize, outBufferSize) {
+ LOG(DEBUG) << __func__;
+ }
+
+ private:
+ // Add equalizer specific context for processing here
};
-class EqualizerSw : public BnEffect {
+class EqualizerSw : public BnEffect, EffectWorker {
public:
EqualizerSw() {
- // create the worker
- mWorker = std::make_unique<EqualizerSwWorker>();
+ Equalizer::Capability eqCap = {.bandFrequencies = mBandFrequency, .presets = mPresets};
+ mDesc.capability.set<Capability::equalizer>(eqCap);
LOG(DEBUG) << __func__;
};
~EqualizerSw() {
@@ -52,12 +61,11 @@
ndk::ScopedAStatus getParameter(const Parameter::Id& in_paramId,
Parameter* _aidl_return) override;
+ IEffect::Status effectProcessImpl() override;
+
private:
- // effect processing thread.
- std::unique_ptr<EqualizerSwWorker> mWorker;
// Effect descriptor.
- const Descriptor mDesc = {
- .common = {.id = {.type = EqualizerTypeUUID, .uuid = EqualizerSwImplUUID}}};
+ Descriptor mDesc = {.common = {.id = {.type = EqualizerTypeUUID, .uuid = EqualizerSwImplUUID}}};
// Parameters.
Parameter::Common mCommonParam;
@@ -66,21 +74,32 @@
// Instance state INIT by default.
State mState = State::INIT;
- typedef ::android::AidlMessageQueue<
- Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
- StatusMQ;
- typedef ::android::AidlMessageQueue<
- int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
- DataMQ;
+ int mPreset = PRESET_CUSTOM; // the current preset
+ 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;
- std::unique_ptr<StatusMQ> mStatusMQ;
- std::unique_ptr<DataMQ> mInputMQ;
- std::unique_ptr<DataMQ> mOutputMQ;
+ // Equalizer worker context
+ std::shared_ptr<EqualizerSwContext> mContext;
ndk::ScopedAStatus setCommonParameter(const Parameter::Common& common_param);
ndk::ScopedAStatus setSpecificParameter(const Parameter::Specific& specific);
- bool createFmq(int statusDepth, int inBufferSize, int outBufferSize, OpenEffectReturn* ret);
- void destroyFmq();
+ 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);
};
} // namespace aidl::android::hardware::audio::effect