mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:50:18 +00:00
Effect AIDL: implement IEffect.reopen
- add IEffect.reopen implementation - now data MQs can update at runtime, sync EffectContext access - add clang thread annotation Bug: 302036943 Test: atest VtsHalAudioEffectTargetTest Test: build and test audio effect on Pixel Change-Id: I3e9fdc2d5eb50b8c1377e0da75573f0eba7ea3f1
This commit is contained in:
@@ -230,6 +230,7 @@ cc_defaults {
|
||||
filegroup {
|
||||
name: "effectCommonFile",
|
||||
srcs: [
|
||||
"EffectContext.cpp",
|
||||
"EffectThread.cpp",
|
||||
"EffectImpl.cpp",
|
||||
],
|
||||
|
||||
227
audio/aidl/default/EffectContext.cpp
Normal file
227
audio/aidl/default/EffectContext.cpp
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#define LOG_TAG "AHAL_EffectContext"
|
||||
#include "effect-impl/EffectContext.h"
|
||||
#include "include/effect-impl/EffectTypes.h"
|
||||
|
||||
using aidl::android::hardware::audio::common::getChannelCount;
|
||||
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
|
||||
using aidl::android::hardware::audio::effect::IEffect;
|
||||
using aidl::android::media::audio::common::PcmType;
|
||||
using ::android::hardware::EventFlag;
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
EffectContext::EffectContext(size_t statusDepth, const Parameter::Common& common) {
|
||||
LOG_ALWAYS_FATAL_IF(RetCode::SUCCESS != setCommon(common), "illegalCommonParameter");
|
||||
|
||||
// in/outBuffer size in float (FMQ data format defined for DataMQ)
|
||||
size_t inBufferSizeInFloat = common.input.frameCount * mInputFrameSize / sizeof(float);
|
||||
size_t outBufferSizeInFloat = common.output.frameCount * mOutputFrameSize / sizeof(float);
|
||||
|
||||
// only status FMQ use the EventFlag
|
||||
mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
|
||||
mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
|
||||
mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
|
||||
|
||||
if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
|
||||
LOG(ERROR) << __func__ << " created invalid FMQ";
|
||||
}
|
||||
|
||||
::android::status_t status =
|
||||
EventFlag::createEventFlag(mStatusMQ->getEventFlagWord(), &mEfGroup);
|
||||
LOG_ALWAYS_FATAL_IF(status != ::android::OK || !mEfGroup, " create EventFlagGroup failed ");
|
||||
mWorkBuffer.reserve(std::max(inBufferSizeInFloat, outBufferSizeInFloat));
|
||||
}
|
||||
|
||||
// reset buffer status by abandon input data in FMQ
|
||||
void EffectContext::resetBuffer() {
|
||||
auto buffer = static_cast<float*>(mWorkBuffer.data());
|
||||
std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
|
||||
if (mInputMQ) {
|
||||
mInputMQ->read(buffer, mInputMQ->availableToRead());
|
||||
}
|
||||
}
|
||||
|
||||
void EffectContext::dupeFmqWithReopen(IEffect::OpenEffectReturn* effectRet) {
|
||||
if (!mInputMQ) {
|
||||
mInputMQ = std::make_shared<DataMQ>(mCommon.input.frameCount * mInputFrameSize /
|
||||
sizeof(float));
|
||||
}
|
||||
if (!mOutputMQ) {
|
||||
mOutputMQ = std::make_shared<DataMQ>(mCommon.output.frameCount * mOutputFrameSize /
|
||||
sizeof(float));
|
||||
}
|
||||
dupeFmq(effectRet);
|
||||
}
|
||||
|
||||
void EffectContext::dupeFmq(IEffect::OpenEffectReturn* effectRet) {
|
||||
if (effectRet) {
|
||||
effectRet->statusMQ = mStatusMQ->dupeDesc();
|
||||
effectRet->inputDataMQ = mInputMQ->dupeDesc();
|
||||
effectRet->outputDataMQ = mOutputMQ->dupeDesc();
|
||||
}
|
||||
}
|
||||
|
||||
float* EffectContext::getWorkBuffer() {
|
||||
return static_cast<float*>(mWorkBuffer.data());
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext::StatusMQ> EffectContext::getStatusFmq() const {
|
||||
return mStatusMQ;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext::DataMQ> EffectContext::getInputDataFmq() const {
|
||||
return mInputMQ;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext::DataMQ> EffectContext::getOutputDataFmq() const {
|
||||
return mOutputMQ;
|
||||
}
|
||||
|
||||
size_t EffectContext::getInputFrameSize() const {
|
||||
return mInputFrameSize;
|
||||
}
|
||||
|
||||
size_t EffectContext::getOutputFrameSize() const {
|
||||
return mOutputFrameSize;
|
||||
}
|
||||
|
||||
int EffectContext::getSessionId() const {
|
||||
return mCommon.session;
|
||||
}
|
||||
|
||||
int EffectContext::getIoHandle() const {
|
||||
return mCommon.ioHandle;
|
||||
}
|
||||
|
||||
RetCode EffectContext::setOutputDevice(
|
||||
const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& device) {
|
||||
mOutputDevice = device;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
|
||||
std::vector<aidl::android::media::audio::common::AudioDeviceDescription>
|
||||
EffectContext::getOutputDevice() {
|
||||
return mOutputDevice;
|
||||
}
|
||||
|
||||
RetCode EffectContext::setAudioMode(const aidl::android::media::audio::common::AudioMode& mode) {
|
||||
mMode = mode;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
aidl::android::media::audio::common::AudioMode EffectContext::getAudioMode() {
|
||||
return mMode;
|
||||
}
|
||||
|
||||
RetCode EffectContext::setAudioSource(
|
||||
const aidl::android::media::audio::common::AudioSource& source) {
|
||||
mSource = source;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
|
||||
aidl::android::media::audio::common::AudioSource EffectContext::getAudioSource() {
|
||||
return mSource;
|
||||
}
|
||||
|
||||
RetCode EffectContext::setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) {
|
||||
mVolumeStereo = volumeStereo;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
|
||||
Parameter::VolumeStereo EffectContext::getVolumeStereo() {
|
||||
return mVolumeStereo;
|
||||
}
|
||||
|
||||
RetCode EffectContext::setCommon(const Parameter::Common& common) {
|
||||
LOG(VERBOSE) << __func__ << common.toString();
|
||||
auto& input = common.input;
|
||||
auto& output = common.output;
|
||||
|
||||
if (input.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT ||
|
||||
output.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT) {
|
||||
LOG(ERROR) << __func__ << " illegal IO, input "
|
||||
<< ::android::internal::ToString(input.base.format) << ", output "
|
||||
<< ::android::internal::ToString(output.base.format);
|
||||
return RetCode::ERROR_ILLEGAL_PARAMETER;
|
||||
}
|
||||
|
||||
if (auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
mInputChannelCount = getChannelCount(input.base.channelMask);
|
||||
mOutputChannelCount = getChannelCount(output.base.channelMask);
|
||||
if (mInputChannelCount == 0 || mOutputChannelCount == 0) {
|
||||
LOG(ERROR) << __func__ << " illegal channel count input " << mInputChannelCount
|
||||
<< ", output " << mOutputChannelCount;
|
||||
return RetCode::ERROR_ILLEGAL_PARAMETER;
|
||||
}
|
||||
|
||||
mCommon = common;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
|
||||
Parameter::Common EffectContext::getCommon() {
|
||||
LOG(VERBOSE) << __func__ << mCommon.toString();
|
||||
return mCommon;
|
||||
}
|
||||
|
||||
EventFlag* EffectContext::getStatusEventFlag() {
|
||||
return mEfGroup;
|
||||
}
|
||||
|
||||
RetCode EffectContext::updateIOFrameSize(const Parameter::Common& common) {
|
||||
const auto iFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
|
||||
common.input.base.format, common.input.base.channelMask);
|
||||
const auto oFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
|
||||
common.output.base.format, common.output.base.channelMask);
|
||||
|
||||
bool needUpdateMq = false;
|
||||
if (mInputMQ &&
|
||||
(mInputFrameSize != iFrameSize || mCommon.input.frameCount != common.input.frameCount)) {
|
||||
mInputMQ.reset();
|
||||
needUpdateMq = true;
|
||||
}
|
||||
if (mOutputMQ &&
|
||||
(mOutputFrameSize != oFrameSize || mCommon.output.frameCount != common.output.frameCount)) {
|
||||
mOutputMQ.reset();
|
||||
needUpdateMq = true;
|
||||
}
|
||||
mInputFrameSize = iFrameSize;
|
||||
mOutputFrameSize = oFrameSize;
|
||||
if (needUpdateMq) {
|
||||
return notifyDataMqUpdate();
|
||||
}
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
|
||||
RetCode EffectContext::notifyDataMqUpdate() {
|
||||
if (!mEfGroup) {
|
||||
LOG(ERROR) << __func__ << ": invalid EventFlag group";
|
||||
return RetCode::ERROR_EVENT_FLAG_ERROR;
|
||||
}
|
||||
|
||||
if (const auto ret = mEfGroup->wake(kEventFlagDataMqUpdate); ret != ::android::OK) {
|
||||
LOG(ERROR) << __func__ << ": wake failure with ret " << ret;
|
||||
return RetCode::ERROR_EVENT_FLAG_ERROR;
|
||||
}
|
||||
LOG(DEBUG) << __func__ << " : signal client for reopen";
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#define LOG_TAG "AHAL_EffectImpl"
|
||||
#include "effect-impl/EffectImpl.h"
|
||||
#include "effect-impl/EffectTypes.h"
|
||||
@@ -22,6 +23,7 @@
|
||||
using aidl::android::hardware::audio::effect::IEffect;
|
||||
using aidl::android::hardware::audio::effect::State;
|
||||
using aidl::android::media::audio::common::PcmType;
|
||||
using ::android::hardware::EventFlag;
|
||||
|
||||
extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
|
||||
State state;
|
||||
@@ -45,50 +47,62 @@ ndk::ScopedAStatus EffectImpl::open(const Parameter::Common& common,
|
||||
RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
|
||||
common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
|
||||
EX_ILLEGAL_ARGUMENT, "dataMustBe32BitsFloat");
|
||||
std::lock_guard lg(mImplMutex);
|
||||
RETURN_OK_IF(mState != State::INIT);
|
||||
auto context = createContext(common);
|
||||
RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
|
||||
mImplContext = createContext(common);
|
||||
RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
|
||||
mEventFlag = mImplContext->getStatusEventFlag();
|
||||
|
||||
if (specific.has_value()) {
|
||||
RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
|
||||
}
|
||||
|
||||
mState = State::IDLE;
|
||||
context->dupeFmq(ret);
|
||||
RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
|
||||
mImplContext->dupeFmq(ret);
|
||||
RETURN_IF(createThread(getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
|
||||
"FailedToCreateWorker");
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EffectImpl::reopen(OpenEffectReturn* ret) {
|
||||
std::lock_guard lg(mImplMutex);
|
||||
RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "alreadyClosed");
|
||||
|
||||
// TODO: b/302036943 add reopen implementation
|
||||
auto context = getContext();
|
||||
RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
|
||||
context->dupeFmq(ret);
|
||||
RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
|
||||
mImplContext->dupeFmqWithReopen(ret);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EffectImpl::close() {
|
||||
RETURN_OK_IF(mState == State::INIT);
|
||||
RETURN_IF(mState == State::PROCESSING, EX_ILLEGAL_STATE, "closeAtProcessing");
|
||||
{
|
||||
std::lock_guard lg(mImplMutex);
|
||||
RETURN_OK_IF(mState == State::INIT);
|
||||
RETURN_IF(mState == State::PROCESSING, EX_ILLEGAL_STATE, "closeAtProcessing");
|
||||
mState = State::INIT;
|
||||
}
|
||||
|
||||
RETURN_IF(notifyEventFlag(kEventFlagNotEmpty) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
|
||||
"notifyEventFlagFailed");
|
||||
// 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");
|
||||
|
||||
{
|
||||
std::lock_guard lg(mImplMutex);
|
||||
releaseContext();
|
||||
mImplContext.reset();
|
||||
}
|
||||
|
||||
LOG(DEBUG) << getEffectName() << __func__;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) {
|
||||
std::lock_guard lg(mImplMutex);
|
||||
LOG(VERBOSE) << getEffectName() << __func__ << " with: " << param.toString();
|
||||
|
||||
const auto tag = param.getTag();
|
||||
const auto& tag = param.getTag();
|
||||
switch (tag) {
|
||||
case Parameter::common:
|
||||
case Parameter::deviceDescription:
|
||||
@@ -110,8 +124,8 @@ ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter* param) {
|
||||
auto tag = id.getTag();
|
||||
switch (tag) {
|
||||
std::lock_guard lg(mImplMutex);
|
||||
switch (id.getTag()) {
|
||||
case Parameter::Id::commonTag: {
|
||||
RETURN_IF_ASTATUS_NOT_OK(getParameterCommon(id.get<Parameter::Id::commonTag>(), param),
|
||||
"CommonParamNotSupported");
|
||||
@@ -131,30 +145,30 @@ ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter*
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
|
||||
auto context = getContext();
|
||||
RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
|
||||
RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
|
||||
|
||||
auto tag = param.getTag();
|
||||
const auto& tag = param.getTag();
|
||||
switch (tag) {
|
||||
case Parameter::common:
|
||||
RETURN_IF(context->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
|
||||
RETURN_IF(mImplContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
|
||||
EX_ILLEGAL_ARGUMENT, "setCommFailed");
|
||||
break;
|
||||
case Parameter::deviceDescription:
|
||||
RETURN_IF(context->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
|
||||
RETURN_IF(mImplContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
|
||||
RetCode::SUCCESS,
|
||||
EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
|
||||
break;
|
||||
case Parameter::mode:
|
||||
RETURN_IF(context->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
|
||||
RETURN_IF(mImplContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
|
||||
EX_ILLEGAL_ARGUMENT, "setModeFailed");
|
||||
break;
|
||||
case Parameter::source:
|
||||
RETURN_IF(context->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
|
||||
RETURN_IF(mImplContext->setAudioSource(param.get<Parameter::source>()) !=
|
||||
RetCode::SUCCESS,
|
||||
EX_ILLEGAL_ARGUMENT, "setSourceFailed");
|
||||
break;
|
||||
case Parameter::volumeStereo:
|
||||
RETURN_IF(context->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
|
||||
RETURN_IF(mImplContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
|
||||
RetCode::SUCCESS,
|
||||
EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
|
||||
break;
|
||||
@@ -169,28 +183,27 @@ ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Parameter* param) {
|
||||
auto context = getContext();
|
||||
RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
|
||||
RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
|
||||
|
||||
switch (tag) {
|
||||
case Parameter::common: {
|
||||
param->set<Parameter::common>(context->getCommon());
|
||||
param->set<Parameter::common>(mImplContext->getCommon());
|
||||
break;
|
||||
}
|
||||
case Parameter::deviceDescription: {
|
||||
param->set<Parameter::deviceDescription>(context->getOutputDevice());
|
||||
param->set<Parameter::deviceDescription>(mImplContext->getOutputDevice());
|
||||
break;
|
||||
}
|
||||
case Parameter::mode: {
|
||||
param->set<Parameter::mode>(context->getAudioMode());
|
||||
param->set<Parameter::mode>(mImplContext->getAudioMode());
|
||||
break;
|
||||
}
|
||||
case Parameter::source: {
|
||||
param->set<Parameter::source>(context->getAudioSource());
|
||||
param->set<Parameter::source>(mImplContext->getAudioSource());
|
||||
break;
|
||||
}
|
||||
case Parameter::volumeStereo: {
|
||||
param->set<Parameter::volumeStereo>(context->getVolumeStereo());
|
||||
param->set<Parameter::volumeStereo>(mImplContext->getVolumeStereo());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -202,30 +215,34 @@ ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Par
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EffectImpl::getState(State* state) {
|
||||
ndk::ScopedAStatus EffectImpl::getState(State* state) NO_THREAD_SAFETY_ANALYSIS {
|
||||
*state = mState;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EffectImpl::command(CommandId command) {
|
||||
RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
|
||||
std::lock_guard lg(mImplMutex);
|
||||
RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
|
||||
LOG(DEBUG) << getEffectName() << __func__ << ": receive command: " << toString(command)
|
||||
<< " at state " << toString(mState);
|
||||
|
||||
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(commandImpl(command), "commandImplFailed");
|
||||
startThread();
|
||||
mState = State::PROCESSING;
|
||||
RETURN_IF(notifyEventFlag(kEventFlagNotEmpty) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
|
||||
"notifyEventFlagFailed");
|
||||
startThread();
|
||||
break;
|
||||
case CommandId::STOP:
|
||||
case CommandId::RESET:
|
||||
RETURN_OK_IF(mState == State::IDLE);
|
||||
mState = State::IDLE;
|
||||
RETURN_IF(notifyEventFlag(kEventFlagNotEmpty) != RetCode::SUCCESS, EX_ILLEGAL_STATE,
|
||||
"notifyEventFlagFailed");
|
||||
stopThread();
|
||||
RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
|
||||
mState = State::IDLE;
|
||||
break;
|
||||
default:
|
||||
LOG(ERROR) << getEffectName() << __func__ << " instance still processing";
|
||||
@@ -237,19 +254,41 @@ ndk::ScopedAStatus EffectImpl::command(CommandId command) {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EffectImpl::commandImpl(CommandId command) {
|
||||
auto context = getContext();
|
||||
RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
|
||||
RETURN_IF(!mImplContext, EX_NULL_POINTER, "nullContext");
|
||||
if (command == CommandId::RESET) {
|
||||
context->resetBuffer();
|
||||
mImplContext->resetBuffer();
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> EffectImpl::createContext(const Parameter::Common& common) {
|
||||
return std::make_shared<EffectContext>(1 /* statusMqDepth */, common);
|
||||
}
|
||||
|
||||
RetCode EffectImpl::releaseContext() {
|
||||
if (mImplContext) {
|
||||
mImplContext.reset();
|
||||
}
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
|
||||
void EffectImpl::cleanUp() {
|
||||
command(CommandId::STOP);
|
||||
close();
|
||||
}
|
||||
|
||||
RetCode EffectImpl::notifyEventFlag(uint32_t flag) {
|
||||
if (!mEventFlag) {
|
||||
LOG(ERROR) << getEffectName() << __func__ << ": StatusEventFlag invalid";
|
||||
return RetCode::ERROR_EVENT_FLAG_ERROR;
|
||||
}
|
||||
if (const auto ret = mEventFlag->wake(flag); ret != ::android::OK) {
|
||||
LOG(ERROR) << getEffectName() << __func__ << ": wake failure with ret " << ret;
|
||||
return RetCode::ERROR_EVENT_FLAG_ERROR;
|
||||
}
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
|
||||
IEffect::Status EffectImpl::status(binder_status_t status, size_t consumed, size_t produced) {
|
||||
IEffect::Status ret;
|
||||
ret.status = status;
|
||||
@@ -258,6 +297,48 @@ IEffect::Status EffectImpl::status(binder_status_t status, size_t consumed, size
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EffectImpl::process() {
|
||||
/**
|
||||
* wait for the EventFlag without lock, it's ok because the mEfGroup pointer will not change
|
||||
* in the life cycle of workerThread (threadLoop).
|
||||
*/
|
||||
uint32_t efState = 0;
|
||||
if (!mEventFlag ||
|
||||
::android::OK != mEventFlag->wait(kEventFlagNotEmpty, &efState, 0 /* no timeout */,
|
||||
true /* retry */) ||
|
||||
!(efState & kEventFlagNotEmpty)) {
|
||||
LOG(ERROR) << getEffectName() << __func__ << ": StatusEventFlag - " << mEventFlag
|
||||
<< " efState - " << std::hex << efState;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard lg(mImplMutex);
|
||||
if (mState != State::PROCESSING) {
|
||||
LOG(DEBUG) << getEffectName() << " skip process in state: " << toString(mState);
|
||||
return;
|
||||
}
|
||||
RETURN_VALUE_IF(!mImplContext, void(), "nullContext");
|
||||
auto statusMQ = mImplContext->getStatusFmq();
|
||||
auto inputMQ = mImplContext->getInputDataFmq();
|
||||
auto outputMQ = mImplContext->getOutputDataFmq();
|
||||
auto buffer = mImplContext->getWorkBuffer();
|
||||
if (!inputMQ || !outputMQ) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto processSamples = inputMQ->availableToRead();
|
||||
if (processSamples) {
|
||||
inputMQ->read(buffer, processSamples);
|
||||
IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
|
||||
outputMQ->write(buffer, status.fmqProduced);
|
||||
statusMQ->writeBlocking(&status, 1);
|
||||
LOG(VERBOSE) << getEffectName() << __func__ << ": done processing, effect consumed "
|
||||
<< status.fmqConsumed << " produced " << status.fmqProduced;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A placeholder processing implementation to copy samples from input to output
|
||||
IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int samples) {
|
||||
for (int i = 0; i < samples; i++) {
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include "effect-impl/EffectThread.h"
|
||||
#include "effect-impl/EffectTypes.h"
|
||||
|
||||
using ::android::hardware::EventFlag;
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
EffectThread::EffectThread() {
|
||||
@@ -38,31 +36,18 @@ EffectThread::~EffectThread() {
|
||||
LOG(DEBUG) << __func__ << " done";
|
||||
}
|
||||
|
||||
RetCode EffectThread::createThread(std::shared_ptr<EffectContext> context, const std::string& name,
|
||||
int priority) {
|
||||
RetCode EffectThread::createThread(const std::string& name, int priority) {
|
||||
if (mThread.joinable()) {
|
||||
LOG(WARNING) << mName << __func__ << " thread already created, no-op";
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
|
||||
mName = name;
|
||||
mPriority = priority;
|
||||
{
|
||||
std::lock_guard lg(mThreadMutex);
|
||||
mStop = true;
|
||||
mExit = false;
|
||||
mThreadContext = std::move(context);
|
||||
auto statusMQ = mThreadContext->getStatusFmq();
|
||||
EventFlag* efGroup = nullptr;
|
||||
::android::status_t status =
|
||||
EventFlag::createEventFlag(statusMQ->getEventFlagWord(), &efGroup);
|
||||
if (status != ::android::OK || !efGroup) {
|
||||
LOG(ERROR) << mName << __func__ << " create EventFlagGroup failed " << status
|
||||
<< " efGroup " << efGroup;
|
||||
return RetCode::ERROR_THREAD;
|
||||
}
|
||||
mEfGroup.reset(efGroup);
|
||||
// kickoff and wait for commands (CommandId::START/STOP) or IEffect.close from client
|
||||
mEfGroup->wake(kEventFlagNotEmpty);
|
||||
}
|
||||
|
||||
mThread = std::thread(&EffectThread::threadLoop, this);
|
||||
@@ -75,16 +60,12 @@ RetCode EffectThread::destroyThread() {
|
||||
std::lock_guard lg(mThreadMutex);
|
||||
mStop = mExit = true;
|
||||
}
|
||||
mCv.notify_one();
|
||||
|
||||
mCv.notify_one();
|
||||
if (mThread.joinable()) {
|
||||
mThread.join();
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard lg(mThreadMutex);
|
||||
mThreadContext.reset();
|
||||
}
|
||||
LOG(DEBUG) << mName << __func__;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
@@ -96,7 +77,6 @@ RetCode EffectThread::startThread() {
|
||||
mCv.notify_one();
|
||||
}
|
||||
|
||||
mEfGroup->wake(kEventFlagNotEmpty);
|
||||
LOG(DEBUG) << mName << __func__;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
@@ -108,7 +88,6 @@ RetCode EffectThread::stopThread() {
|
||||
mCv.notify_one();
|
||||
}
|
||||
|
||||
mEfGroup->wake(kEventFlagNotEmpty);
|
||||
LOG(DEBUG) << mName << __func__;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
@@ -117,13 +96,6 @@ void EffectThread::threadLoop() {
|
||||
pthread_setname_np(pthread_self(), mName.substr(0, kMaxTaskNameLen - 1).c_str());
|
||||
setpriority(PRIO_PROCESS, 0, mPriority);
|
||||
while (true) {
|
||||
/**
|
||||
* wait for the EventFlag without lock, it's ok because the mEfGroup pointer will not change
|
||||
* in the life cycle of workerThread (threadLoop).
|
||||
*/
|
||||
uint32_t efState = 0;
|
||||
mEfGroup->wait(kEventFlagNotEmpty, &efState);
|
||||
|
||||
{
|
||||
std::unique_lock l(mThreadMutex);
|
||||
::android::base::ScopedLockAssertion lock_assertion(mThreadMutex);
|
||||
@@ -132,27 +104,8 @@ void EffectThread::threadLoop() {
|
||||
LOG(INFO) << __func__ << " EXIT!";
|
||||
return;
|
||||
}
|
||||
process_l();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EffectThread::process_l() {
|
||||
RETURN_VALUE_IF(!mThreadContext, void(), "nullContext");
|
||||
|
||||
auto statusMQ = mThreadContext->getStatusFmq();
|
||||
auto inputMQ = mThreadContext->getInputDataFmq();
|
||||
auto outputMQ = mThreadContext->getOutputDataFmq();
|
||||
auto buffer = mThreadContext->getWorkBuffer();
|
||||
|
||||
auto processSamples = inputMQ->availableToRead();
|
||||
if (processSamples) {
|
||||
inputMQ->read(buffer, processSamples);
|
||||
IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
|
||||
outputMQ->write(buffer, status.fmqProduced);
|
||||
statusMQ->writeBlocking(&status, 1);
|
||||
LOG(VERBOSE) << mName << __func__ << ": done processing, effect consumed "
|
||||
<< status.fmqConsumed << " produced " << status.fmqProduced;
|
||||
process();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -168,10 +168,6 @@ std::shared_ptr<EffectContext> AcousticEchoCancelerSw::createContext(
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> AcousticEchoCancelerSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode AcousticEchoCancelerSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -52,21 +52,23 @@ class AcousticEchoCancelerSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
std::string getEffectName() override { return kEffectName; };
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
|
||||
private:
|
||||
static const std::vector<Range::AcousticEchoCancelerRange> kRanges;
|
||||
std::shared_ptr<AcousticEchoCancelerSwContext> mContext;
|
||||
std::shared_ptr<AcousticEchoCancelerSwContext> mContext GUARDED_BY(mImplMutex);
|
||||
ndk::ScopedAStatus getParameterAcousticEchoCanceler(const AcousticEchoCanceler::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -177,10 +177,6 @@ std::shared_ptr<EffectContext> AutomaticGainControlV1Sw::createContext(
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> AutomaticGainControlV1Sw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode AutomaticGainControlV1Sw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -53,21 +53,24 @@ class AutomaticGainControlV1Sw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
std::string getEffectName() override { return kEffectName; };
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
private:
|
||||
static const std::vector<Range::AutomaticGainControlV1Range> kRanges;
|
||||
std::shared_ptr<AutomaticGainControlV1SwContext> mContext;
|
||||
std::shared_ptr<AutomaticGainControlV1SwContext> mContext GUARDED_BY(mImplMutex);
|
||||
ndk::ScopedAStatus getParameterAutomaticGainControlV1(const AutomaticGainControlV1::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -180,10 +180,6 @@ std::shared_ptr<EffectContext> AutomaticGainControlV2Sw::createContext(
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> AutomaticGainControlV2Sw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode AutomaticGainControlV2Sw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -59,21 +59,24 @@ class AutomaticGainControlV2Sw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
std::string getEffectName() override { return kEffectName; };
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
private:
|
||||
static const std::vector<Range::AutomaticGainControlV2Range> kRanges;
|
||||
std::shared_ptr<AutomaticGainControlV2SwContext> mContext;
|
||||
std::shared_ptr<AutomaticGainControlV2SwContext> mContext GUARDED_BY(mImplMutex);
|
||||
ndk::ScopedAStatus getParameterAutomaticGainControlV2(const AutomaticGainControlV2::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -151,10 +151,6 @@ std::shared_ptr<EffectContext> BassBoostSw::createContext(const Parameter::Commo
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> BassBoostSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode BassBoostSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -51,21 +51,23 @@ class BassBoostSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
std::string getEffectName() override { return kEffectName; };
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
private:
|
||||
static const std::vector<Range::BassBoostRange> kRanges;
|
||||
std::shared_ptr<BassBoostSwContext> mContext;
|
||||
std::shared_ptr<BassBoostSwContext> mContext GUARDED_BY(mImplMutex);
|
||||
ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific) REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -144,10 +144,6 @@ std::shared_ptr<EffectContext> DownmixSw::createContext(const Parameter::Common&
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> DownmixSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode DownmixSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -55,20 +55,23 @@ class DownmixSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
std::string getEffectName() override { return kEffectName; };
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int sample) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int sample)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<DownmixSwContext> mContext;
|
||||
std::shared_ptr<DownmixSwContext> mContext GUARDED_BY(mImplMutex);
|
||||
|
||||
ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific);
|
||||
ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -260,10 +260,6 @@ std::shared_ptr<EffectContext> DynamicsProcessingSw::createContext(
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> DynamicsProcessingSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode DynamicsProcessingSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
@@ -282,6 +278,9 @@ IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, i
|
||||
}
|
||||
|
||||
RetCode DynamicsProcessingSwContext::setCommon(const Parameter::Common& common) {
|
||||
if (auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
mCommon = common;
|
||||
mChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
|
||||
common.input.base.channelMask);
|
||||
|
||||
@@ -113,15 +113,17 @@ class DynamicsProcessingSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
std::string getEffectName() override { return kEffectName; };
|
||||
|
||||
private:
|
||||
@@ -130,9 +132,10 @@ class DynamicsProcessingSw final : public EffectImpl {
|
||||
static const Range::DynamicsProcessingRange kPreEqBandRange;
|
||||
static const Range::DynamicsProcessingRange kPostEqBandRange;
|
||||
static const std::vector<Range::DynamicsProcessingRange> kRanges;
|
||||
std::shared_ptr<DynamicsProcessingSwContext> mContext;
|
||||
std::shared_ptr<DynamicsProcessingSwContext> mContext GUARDED_BY(mImplMutex);
|
||||
ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex);
|
||||
|
||||
}; // DynamicsProcessingSw
|
||||
|
||||
|
||||
@@ -267,10 +267,6 @@ std::shared_ptr<EffectContext> EnvReverbSw::createContext(const Parameter::Commo
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> EnvReverbSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode EnvReverbSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -100,21 +100,23 @@ class EnvReverbSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
static const std::vector<Range::EnvironmentalReverbRange> kRanges;
|
||||
std::shared_ptr<EnvReverbSwContext> mContext;
|
||||
std::shared_ptr<EnvReverbSwContext> mContext GUARDED_BY(mImplMutex);
|
||||
ndk::ScopedAStatus getParameterEnvironmentalReverb(const EnvironmentalReverb::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -198,10 +198,6 @@ std::shared_ptr<EffectContext> EqualizerSw::createContext(const Parameter::Commo
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> EqualizerSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode EqualizerSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -97,15 +97,17 @@ class EqualizerSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
@@ -113,7 +115,7 @@ class EqualizerSw final : public EffectImpl {
|
||||
static const std::vector<Equalizer::Preset> kPresets;
|
||||
static const std::vector<Range::EqualizerRange> kRanges;
|
||||
ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific) REQUIRES(mImplMutex);
|
||||
std::shared_ptr<EqualizerSwContext> mContext;
|
||||
};
|
||||
|
||||
|
||||
@@ -123,10 +123,6 @@ std::shared_ptr<EffectContext> ExtensionEffect::createContext(const Parameter::C
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> ExtensionEffect::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode ExtensionEffect::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -54,18 +54,20 @@ class ExtensionEffect final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
std::string getEffectName() override { return kEffectName; };
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<ExtensionEffectContext> mContext;
|
||||
std::shared_ptr<ExtensionEffectContext> mContext GUARDED_BY(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -158,10 +158,6 @@ std::shared_ptr<EffectContext> HapticGeneratorSw::createContext(const Parameter:
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> HapticGeneratorSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode HapticGeneratorSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -67,21 +67,24 @@ class HapticGeneratorSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<HapticGeneratorSwContext> mContext;
|
||||
std::shared_ptr<HapticGeneratorSwContext> mContext GUARDED_BY(mImplMutex);
|
||||
|
||||
ndk::ScopedAStatus getParameterHapticGenerator(const HapticGenerator::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <Utils.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
#include <fmq/EventFlag.h>
|
||||
|
||||
#include <aidl/android/hardware/audio/effect/BnEffect.h>
|
||||
#include "EffectTypes.h"
|
||||
@@ -36,127 +37,73 @@ class EffectContext {
|
||||
float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
|
||||
DataMQ;
|
||||
|
||||
EffectContext(size_t statusDepth, const Parameter::Common& common) {
|
||||
auto& input = common.input;
|
||||
auto& output = common.output;
|
||||
|
||||
LOG_ALWAYS_FATAL_IF(
|
||||
input.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
|
||||
"inputFormatNotFloat");
|
||||
LOG_ALWAYS_FATAL_IF(output.base.format.pcm !=
|
||||
aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
|
||||
"outputFormatNotFloat");
|
||||
|
||||
size_t inputChannelCount =
|
||||
::aidl::android::hardware::audio::common::getChannelCount(input.base.channelMask);
|
||||
LOG_ALWAYS_FATAL_IF(inputChannelCount == 0, "inputChannelCountNotValid");
|
||||
size_t outputChannelCount =
|
||||
::aidl::android::hardware::audio::common::getChannelCount(output.base.channelMask);
|
||||
LOG_ALWAYS_FATAL_IF(outputChannelCount == 0, "outputChannelCountNotValid");
|
||||
|
||||
mInputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
|
||||
input.base.format, input.base.channelMask);
|
||||
mOutputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
|
||||
output.base.format, output.base.channelMask);
|
||||
// in/outBuffer size in float (FMQ data format defined for DataMQ)
|
||||
size_t inBufferSizeInFloat = input.frameCount * mInputFrameSize / sizeof(float);
|
||||
size_t outBufferSizeInFloat = output.frameCount * mOutputFrameSize / sizeof(float);
|
||||
|
||||
// only status FMQ use the EventFlag
|
||||
mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
|
||||
mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
|
||||
mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
|
||||
|
||||
if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
|
||||
LOG(ERROR) << __func__ << " created invalid FMQ";
|
||||
EffectContext(size_t statusDepth, const Parameter::Common& common);
|
||||
virtual ~EffectContext() {
|
||||
if (mEfGroup) {
|
||||
::android::hardware::EventFlag::deleteEventFlag(&mEfGroup);
|
||||
}
|
||||
mWorkBuffer.reserve(std::max(inBufferSizeInFloat, outBufferSizeInFloat));
|
||||
mCommon = common;
|
||||
}
|
||||
virtual ~EffectContext() {}
|
||||
|
||||
std::shared_ptr<StatusMQ> getStatusFmq() { return mStatusMQ; }
|
||||
std::shared_ptr<DataMQ> getInputDataFmq() { return mInputMQ; }
|
||||
std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; }
|
||||
std::shared_ptr<StatusMQ> getStatusFmq() const;
|
||||
std::shared_ptr<DataMQ> getInputDataFmq() const;
|
||||
std::shared_ptr<DataMQ> getOutputDataFmq() const;
|
||||
|
||||
float* getWorkBuffer() { return static_cast<float*>(mWorkBuffer.data()); }
|
||||
float* getWorkBuffer();
|
||||
|
||||
// reset buffer status by abandon input data in FMQ
|
||||
void resetBuffer() {
|
||||
auto buffer = static_cast<float*>(mWorkBuffer.data());
|
||||
std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
|
||||
mInputMQ->read(buffer, mInputMQ->availableToRead());
|
||||
}
|
||||
void resetBuffer();
|
||||
void dupeFmq(IEffect::OpenEffectReturn* effectRet);
|
||||
size_t getInputFrameSize() const;
|
||||
size_t getOutputFrameSize() const;
|
||||
int getSessionId() const;
|
||||
int getIoHandle() const;
|
||||
|
||||
void dupeFmq(IEffect::OpenEffectReturn* effectRet) {
|
||||
if (effectRet) {
|
||||
effectRet->statusMQ = mStatusMQ->dupeDesc();
|
||||
effectRet->inputDataMQ = mInputMQ->dupeDesc();
|
||||
effectRet->outputDataMQ = mOutputMQ->dupeDesc();
|
||||
}
|
||||
}
|
||||
size_t getInputFrameSize() { return mInputFrameSize; }
|
||||
size_t getOutputFrameSize() { return mOutputFrameSize; }
|
||||
int getSessionId() { return mCommon.session; }
|
||||
int getIoHandle() { return mCommon.ioHandle; }
|
||||
virtual void dupeFmqWithReopen(IEffect::OpenEffectReturn* effectRet);
|
||||
|
||||
virtual RetCode setOutputDevice(
|
||||
const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>&
|
||||
device) {
|
||||
mOutputDevice = device;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& device);
|
||||
|
||||
virtual std::vector<aidl::android::media::audio::common::AudioDeviceDescription>
|
||||
getOutputDevice() {
|
||||
return mOutputDevice;
|
||||
}
|
||||
getOutputDevice();
|
||||
|
||||
virtual RetCode setAudioMode(const aidl::android::media::audio::common::AudioMode& mode) {
|
||||
mMode = mode;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
virtual aidl::android::media::audio::common::AudioMode getAudioMode() { return mMode; }
|
||||
virtual RetCode setAudioMode(const aidl::android::media::audio::common::AudioMode& mode);
|
||||
virtual aidl::android::media::audio::common::AudioMode getAudioMode();
|
||||
|
||||
virtual RetCode setAudioSource(const aidl::android::media::audio::common::AudioSource& source) {
|
||||
mSource = source;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
virtual aidl::android::media::audio::common::AudioSource getAudioSource() { return mSource; }
|
||||
virtual RetCode setAudioSource(const aidl::android::media::audio::common::AudioSource& source);
|
||||
virtual aidl::android::media::audio::common::AudioSource getAudioSource();
|
||||
|
||||
virtual RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) {
|
||||
mVolumeStereo = volumeStereo;
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
virtual Parameter::VolumeStereo getVolumeStereo() { return mVolumeStereo; }
|
||||
virtual RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo);
|
||||
virtual Parameter::VolumeStereo getVolumeStereo();
|
||||
|
||||
virtual RetCode setCommon(const Parameter::Common& common) {
|
||||
mCommon = common;
|
||||
LOG(VERBOSE) << __func__ << mCommon.toString();
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
virtual Parameter::Common getCommon() {
|
||||
LOG(VERBOSE) << __func__ << mCommon.toString();
|
||||
return mCommon;
|
||||
}
|
||||
virtual RetCode setCommon(const Parameter::Common& common);
|
||||
virtual Parameter::Common getCommon();
|
||||
|
||||
virtual ::android::hardware::EventFlag* getStatusEventFlag();
|
||||
|
||||
protected:
|
||||
// common parameters
|
||||
size_t mInputFrameSize;
|
||||
size_t mOutputFrameSize;
|
||||
Parameter::Common mCommon;
|
||||
std::vector<aidl::android::media::audio::common::AudioDeviceDescription> mOutputDevice;
|
||||
aidl::android::media::audio::common::AudioMode mMode;
|
||||
aidl::android::media::audio::common::AudioSource mSource;
|
||||
Parameter::VolumeStereo mVolumeStereo;
|
||||
size_t mInputChannelCount;
|
||||
size_t mOutputChannelCount;
|
||||
Parameter::Common mCommon = {};
|
||||
std::vector<aidl::android::media::audio::common::AudioDeviceDescription> mOutputDevice = {};
|
||||
aidl::android::media::audio::common::AudioMode mMode =
|
||||
aidl::android::media::audio::common::AudioMode::SYS_RESERVED_INVALID;
|
||||
aidl::android::media::audio::common::AudioSource mSource =
|
||||
aidl::android::media::audio::common::AudioSource::SYS_RESERVED_INVALID;
|
||||
Parameter::VolumeStereo mVolumeStereo = {};
|
||||
RetCode updateIOFrameSize(const Parameter::Common& common);
|
||||
RetCode notifyDataMqUpdate();
|
||||
|
||||
private:
|
||||
// fmq and buffers
|
||||
std::shared_ptr<StatusMQ> mStatusMQ;
|
||||
std::shared_ptr<DataMQ> mInputMQ;
|
||||
std::shared_ptr<DataMQ> mOutputMQ;
|
||||
// TODO handle effect process input and output
|
||||
// std::shared_ptr<IEffect::OpenEffectReturn> mRet;
|
||||
// work buffer set by effect instances, the access and update are in same thread
|
||||
std::vector<float> mWorkBuffer;
|
||||
|
||||
::android::hardware::EventFlag* mEfGroup;
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -49,33 +49,54 @@ class EffectImpl : public BnEffect, public EffectThread {
|
||||
virtual ndk::ScopedAStatus setParameter(const Parameter& param) override;
|
||||
virtual ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter* param) override;
|
||||
|
||||
virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param);
|
||||
virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param);
|
||||
virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param) REQUIRES(mImplMutex);
|
||||
virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param)
|
||||
REQUIRES(mImplMutex);
|
||||
|
||||
/* Methods MUST be implemented by each effect instances */
|
||||
virtual ndk::ScopedAStatus getDescriptor(Descriptor* desc) = 0;
|
||||
virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) = 0;
|
||||
virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) = 0;
|
||||
virtual ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) = 0;
|
||||
Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) = 0;
|
||||
|
||||
virtual std::string getEffectName() = 0;
|
||||
virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex);
|
||||
virtual RetCode releaseContext() REQUIRES(mImplMutex) = 0;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @brief effectProcessImpl is running in worker thread which created in EffectThread.
|
||||
*
|
||||
* EffectThread will make sure effectProcessImpl only be called after startThread() successful
|
||||
* and before stopThread() successful.
|
||||
*
|
||||
* effectProcessImpl implementation must not call any EffectThread interface, otherwise it will
|
||||
* cause deadlock.
|
||||
*
|
||||
* @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 std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) = 0;
|
||||
virtual std::shared_ptr<EffectContext> getContext() = 0;
|
||||
virtual RetCode releaseContext() = 0;
|
||||
virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
|
||||
|
||||
/**
|
||||
* process() get data from data MQs, and call effectProcessImpl() for effect data processing.
|
||||
* Its important for the implementation to use mImplMutex for context synchronization.
|
||||
*/
|
||||
void process() override;
|
||||
|
||||
protected:
|
||||
State mState = State::INIT;
|
||||
State mState GUARDED_BY(mImplMutex) = State::INIT;
|
||||
|
||||
IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
|
||||
void cleanUp();
|
||||
|
||||
std::mutex mImplMutex;
|
||||
std::shared_ptr<EffectContext> mImplContext GUARDED_BY(mImplMutex);
|
||||
|
||||
/**
|
||||
* Optional CommandId handling methods for effects to override.
|
||||
* For CommandId::START, EffectImpl call commandImpl before starting the EffectThread
|
||||
@@ -83,6 +104,9 @@ class EffectImpl : public BnEffect, public EffectThread {
|
||||
* For CommandId::STOP and CommandId::RESET, EffectImpl call commandImpl after stop the
|
||||
* EffectThread processing.
|
||||
*/
|
||||
virtual ndk::ScopedAStatus commandImpl(CommandId id);
|
||||
virtual ndk::ScopedAStatus commandImpl(CommandId id) REQUIRES(mImplMutex);
|
||||
|
||||
RetCode notifyEventFlag(uint32_t flag);
|
||||
::android::hardware::EventFlag* mEventFlag;
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -36,8 +36,7 @@ class EffectThread {
|
||||
virtual ~EffectThread();
|
||||
|
||||
// called by effect implementation.
|
||||
RetCode createThread(std::shared_ptr<EffectContext> context, const std::string& name,
|
||||
int priority = ANDROID_PRIORITY_URGENT_AUDIO);
|
||||
RetCode createThread(const std::string& name, int priority = ANDROID_PRIORITY_URGENT_AUDIO);
|
||||
RetCode destroyThread();
|
||||
RetCode startThread();
|
||||
RetCode stopThread();
|
||||
@@ -45,33 +44,12 @@ class EffectThread {
|
||||
// Will call process() in a loop if the thread is running.
|
||||
void threadLoop();
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* effectProcessImpl implementation must not call any EffectThread interface, otherwise it will
|
||||
* cause deadlock.
|
||||
*
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* process() call effectProcessImpl() for effect data processing, it is necessary for the
|
||||
* processing to be called under Effect thread mutex mThreadMutex, to avoid the effect state
|
||||
* change before/during data processing, and keep the thread and effect state consistent.
|
||||
*/
|
||||
virtual void process_l() REQUIRES(mThreadMutex);
|
||||
virtual void process() = 0;
|
||||
|
||||
private:
|
||||
static constexpr int kMaxTaskNameLen = 15;
|
||||
@@ -80,16 +58,7 @@ class EffectThread {
|
||||
std::condition_variable mCv;
|
||||
bool mStop GUARDED_BY(mThreadMutex) = true;
|
||||
bool mExit GUARDED_BY(mThreadMutex) = false;
|
||||
std::shared_ptr<EffectContext> mThreadContext GUARDED_BY(mThreadMutex);
|
||||
|
||||
struct EventFlagDeleter {
|
||||
void operator()(::android::hardware::EventFlag* flag) const {
|
||||
if (flag) {
|
||||
::android::hardware::EventFlag::deleteEventFlag(&flag);
|
||||
}
|
||||
}
|
||||
};
|
||||
std::unique_ptr<::android::hardware::EventFlag, EventFlagDeleter> mEfGroup;
|
||||
std::thread mThread;
|
||||
int mPriority;
|
||||
std::string mName;
|
||||
|
||||
@@ -46,7 +46,8 @@ enum class RetCode {
|
||||
ERROR_NULL_POINTER, /* NULL pointer */
|
||||
ERROR_ALIGNMENT_ERROR, /* Memory alignment error */
|
||||
ERROR_BLOCK_SIZE_EXCEED, /* Maximum block size exceeded */
|
||||
ERROR_EFFECT_LIB_ERROR
|
||||
ERROR_EFFECT_LIB_ERROR, /* Effect implementation library error */
|
||||
ERROR_EVENT_FLAG_ERROR /* Error with effect event flags */
|
||||
};
|
||||
|
||||
static const int INVALID_AUDIO_SESSION_ID = -1;
|
||||
@@ -67,6 +68,8 @@ inline std::ostream& operator<<(std::ostream& out, const RetCode& code) {
|
||||
return out << "ERROR_BLOCK_SIZE_EXCEED";
|
||||
case RetCode::ERROR_EFFECT_LIB_ERROR:
|
||||
return out << "ERROR_EFFECT_LIB_ERROR";
|
||||
case RetCode::ERROR_EVENT_FLAG_ERROR:
|
||||
return out << "ERROR_EVENT_FLAG_ERROR";
|
||||
}
|
||||
|
||||
return out << "EnumError: " << code;
|
||||
|
||||
@@ -147,10 +147,6 @@ std::shared_ptr<EffectContext> LoudnessEnhancerSw::createContext(const Parameter
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> LoudnessEnhancerSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode LoudnessEnhancerSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -54,20 +54,23 @@ class LoudnessEnhancerSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<LoudnessEnhancerSwContext> mContext;
|
||||
std::shared_ptr<LoudnessEnhancerSwContext> mContext GUARDED_BY(mImplMutex);
|
||||
ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -155,10 +155,6 @@ std::shared_ptr<EffectContext> NoiseSuppressionSw::createContext(const Parameter
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> NoiseSuppressionSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode NoiseSuppressionSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -55,20 +55,23 @@ class NoiseSuppressionSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
std::string getEffectName() override { return kEffectName; };
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<NoiseSuppressionSwContext> mContext;
|
||||
std::shared_ptr<NoiseSuppressionSwContext> mContext GUARDED_BY(mImplMutex);
|
||||
ndk::ScopedAStatus getParameterNoiseSuppression(const NoiseSuppression::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -161,10 +161,6 @@ std::shared_ptr<EffectContext> PresetReverbSw::createContext(const Parameter::Co
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> PresetReverbSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode PresetReverbSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -56,21 +56,23 @@ class PresetReverbSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<PresetReverbSwContext> mContext;
|
||||
std::shared_ptr<PresetReverbSwContext> mContext GUARDED_BY(mImplMutex);
|
||||
|
||||
ndk::ScopedAStatus getParameterPresetReverb(const PresetReverb::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific) REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -141,10 +141,6 @@ std::shared_ptr<EffectContext> SpatializerSw::createContext(const Parameter::Com
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> SpatializerSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode SpatializerSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -50,19 +50,21 @@ class SpatializerSw final : public EffectImpl {
|
||||
~SpatializerSw();
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
std::string getEffectName() override { return kEffectName; };
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
private:
|
||||
static const std::vector<Range::SpatializerRange> kRanges;
|
||||
std::shared_ptr<SpatializerSwContext> mContext = nullptr;
|
||||
std::shared_ptr<SpatializerSwContext> mContext GUARDED_BY(mImplMutex) = nullptr;
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -203,10 +203,6 @@ std::shared_ptr<EffectContext> VirtualizerSw::createContext(const Parameter::Com
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> VirtualizerSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode VirtualizerSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -59,24 +59,25 @@ class VirtualizerSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
static const std::vector<Range::VirtualizerRange> kRanges;
|
||||
std::shared_ptr<VirtualizerSwContext> mContext;
|
||||
std::shared_ptr<VirtualizerSwContext> mContext GUARDED_BY(mImplMutex);
|
||||
|
||||
ndk::ScopedAStatus getParameterVirtualizer(const Virtualizer::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific) REQUIRES(mImplMutex);
|
||||
ndk::ScopedAStatus getSpeakerAngles(const Virtualizer::SpeakerAnglesPayload payload,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific) REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -190,10 +190,6 @@ std::shared_ptr<EffectContext> VisualizerSw::createContext(const Parameter::Comm
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> VisualizerSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode VisualizerSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -72,21 +72,23 @@ class VisualizerSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
static const std::vector<Range::VisualizerRange> kRanges;
|
||||
std::shared_ptr<VisualizerSwContext> mContext;
|
||||
std::shared_ptr<VisualizerSwContext> mContext GUARDED_BY(mImplMutex);
|
||||
ndk::ScopedAStatus getParameterVisualizer(const Visualizer::Tag& tag,
|
||||
Parameter::Specific* specific);
|
||||
Parameter::Specific* specific) REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -160,10 +160,6 @@ std::shared_ptr<EffectContext> VolumeSw::createContext(const Parameter::Common&
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::shared_ptr<EffectContext> VolumeSw::getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
RetCode VolumeSw::releaseContext() {
|
||||
if (mContext) {
|
||||
mContext.reset();
|
||||
|
||||
@@ -57,21 +57,24 @@ class VolumeSw final : public EffectImpl {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
|
||||
Parameter::Specific* specific) override;
|
||||
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex) override;
|
||||
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
|
||||
std::shared_ptr<EffectContext> getContext() override;
|
||||
RetCode releaseContext() override;
|
||||
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
|
||||
REQUIRES(mImplMutex) override;
|
||||
RetCode releaseContext() REQUIRES(mImplMutex) override;
|
||||
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
|
||||
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
|
||||
REQUIRES(mImplMutex) override;
|
||||
std::string getEffectName() override { return kEffectName; }
|
||||
|
||||
private:
|
||||
static const std::vector<Range::VolumeRange> kRanges;
|
||||
std::shared_ptr<VolumeSwContext> mContext;
|
||||
std::shared_ptr<VolumeSwContext> mContext GUARDED_BY(mImplMutex);
|
||||
|
||||
ndk::ScopedAStatus getParameterVolume(const Volume::Tag& tag, Parameter::Specific* specific);
|
||||
ndk::ScopedAStatus getParameterVolume(const Volume::Tag& tag, Parameter::Specific* specific)
|
||||
REQUIRES(mImplMutex);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -43,6 +43,7 @@ using namespace android;
|
||||
using aidl::android::hardware::audio::effect::CommandId;
|
||||
using aidl::android::hardware::audio::effect::Descriptor;
|
||||
using aidl::android::hardware::audio::effect::IEffect;
|
||||
using aidl::android::hardware::audio::effect::kEventFlagDataMqUpdate;
|
||||
using aidl::android::hardware::audio::effect::kEventFlagNotEmpty;
|
||||
using aidl::android::hardware::audio::effect::Parameter;
|
||||
using aidl::android::hardware::audio::effect::Range;
|
||||
@@ -191,6 +192,16 @@ class EffectHelper {
|
||||
ASSERT_TRUE(dataMq->read(buffer.data(), expectFloats));
|
||||
}
|
||||
}
|
||||
static void expectDataMqUpdateEventFlag(std::unique_ptr<StatusMQ>& statusMq) {
|
||||
EventFlag* efGroup;
|
||||
ASSERT_EQ(::android::OK,
|
||||
EventFlag::createEventFlag(statusMq->getEventFlagWord(), &efGroup));
|
||||
ASSERT_NE(nullptr, efGroup);
|
||||
uint32_t efState = 0;
|
||||
EXPECT_EQ(::android::OK, efGroup->wait(kEventFlagDataMqUpdate, &efState, 1'000'000 /*1ms*/,
|
||||
true /* retry */));
|
||||
EXPECT_TRUE(efState & kEventFlagDataMqUpdate);
|
||||
}
|
||||
static Parameter::Common createParamCommon(
|
||||
int session = 0, int ioHandle = -1, int iSampleRate = 48000, int oSampleRate = 48000,
|
||||
long iFrameCount = 0x100, long oFrameCount = 0x100,
|
||||
|
||||
@@ -609,6 +609,49 @@ TEST_P(AudioEffectTest, SetAndGetParameterVolume) {
|
||||
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
|
||||
}
|
||||
|
||||
// Verify Parameters kept after reset.
|
||||
TEST_P(AudioEffectTest, SetCommonParameterAndReopen) {
|
||||
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
|
||||
|
||||
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, std::nullopt /* specific */, &ret, EX_NONE));
|
||||
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
|
||||
ASSERT_TRUE(statusMQ->isValid());
|
||||
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
|
||||
ASSERT_TRUE(inputMQ->isValid());
|
||||
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
|
||||
ASSERT_TRUE(outputMQ->isValid());
|
||||
|
||||
Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common);
|
||||
common.input.frameCount++;
|
||||
ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
|
||||
ASSERT_TRUE(statusMQ->isValid());
|
||||
expectDataMqUpdateEventFlag(statusMQ);
|
||||
EXPECT_IS_OK(mEffect->reopen(&ret));
|
||||
inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
|
||||
outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
|
||||
ASSERT_TRUE(statusMQ->isValid());
|
||||
ASSERT_TRUE(inputMQ->isValid());
|
||||
ASSERT_TRUE(outputMQ->isValid());
|
||||
|
||||
common.output.frameCount++;
|
||||
ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
|
||||
ASSERT_TRUE(statusMQ->isValid());
|
||||
expectDataMqUpdateEventFlag(statusMQ);
|
||||
EXPECT_IS_OK(mEffect->reopen(&ret));
|
||||
inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
|
||||
outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
|
||||
ASSERT_TRUE(statusMQ->isValid());
|
||||
ASSERT_TRUE(inputMQ->isValid());
|
||||
ASSERT_TRUE(outputMQ->isValid());
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(close(mEffect));
|
||||
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
|
||||
}
|
||||
|
||||
/// Data processing test
|
||||
// Send data to effects and expect it to be consumed by checking statusMQ.
|
||||
// Effects exposing bypass flags or operating in offload mode will be skipped.
|
||||
@@ -684,6 +727,59 @@ TEST_P(AudioEffectDataPathTest, ConsumeDataAfterRestart) {
|
||||
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
|
||||
}
|
||||
|
||||
// Send data to effects and expect it to be consumed after effect reopen (IO AudioConfig change).
|
||||
// Effects exposing bypass flags or operating in offload mode will be skipped.
|
||||
TEST_P(AudioEffectDataPathTest, ConsumeDataAfterReopen) {
|
||||
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
|
||||
|
||||
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, std::nullopt /* specific */, &ret, EX_NONE));
|
||||
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
|
||||
ASSERT_TRUE(statusMQ->isValid());
|
||||
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
|
||||
ASSERT_TRUE(inputMQ->isValid());
|
||||
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
|
||||
ASSERT_TRUE(outputMQ->isValid());
|
||||
|
||||
std::vector<float> buffer;
|
||||
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
|
||||
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
|
||||
EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
|
||||
EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
|
||||
|
||||
// set a new common parameter with different IO frameCount, reopen
|
||||
Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common);
|
||||
common.input.frameCount += 4;
|
||||
common.output.frameCount += 4;
|
||||
ASSERT_NO_FATAL_FAILURE(setAndGetParameter(id, Parameter::make<Parameter::common>(common)));
|
||||
ASSERT_TRUE(statusMQ->isValid());
|
||||
expectDataMqUpdateEventFlag(statusMQ);
|
||||
EXPECT_IS_OK(mEffect->reopen(&ret));
|
||||
inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
|
||||
outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
|
||||
ASSERT_TRUE(statusMQ->isValid());
|
||||
ASSERT_TRUE(inputMQ->isValid());
|
||||
ASSERT_TRUE(outputMQ->isValid());
|
||||
|
||||
// verify data consume again
|
||||
EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
|
||||
EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(statusMQ, inputMQ, buffer));
|
||||
EXPECT_NO_FATAL_FAILURE(
|
||||
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
|
||||
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
|
||||
EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(close(mEffect));
|
||||
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
|
||||
}
|
||||
|
||||
// Send data to IDLE effects and expect it to be consumed after effect start.
|
||||
// Effects exposing bypass flags or operating in offload mode will be skipped.
|
||||
TEST_P(AudioEffectDataPathTest, SendDataAtIdleAndConsumeDataInProcessing) {
|
||||
|
||||
Reference in New Issue
Block a user