Merge "audioflinger: refactor EffectModule class"

am: 186f9ccf66

Change-Id: Ia37d6ef261c2d8f2c90c0268211b2b8fa419d981
gugelfrei
Eric Laurent 5 years ago committed by android-build-merger
commit c69cab48b3

@ -3507,7 +3507,7 @@ sp<IEffect> AudioFlinger::createEffect(
if (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS) {
// Check CPU and memory usage
sp<EffectModule> effect = handle->effect().promote();
sp<EffectBase> effect = handle->effect().promote();
if (effect != nullptr) {
status_t rStatus = effect->updatePolicyState();
if (rStatus != NO_ERROR) {

@ -533,6 +533,7 @@ private:
class AsyncCallbackThread;
class Track;
class RecordTrack;
class EffectBase;
class EffectModule;
class EffectHandle;
class EffectChain;

@ -58,71 +58,115 @@
namespace android {
// ----------------------------------------------------------------------------
// EffectModule implementation
// EffectBase implementation
// ----------------------------------------------------------------------------
#undef LOG_TAG
#define LOG_TAG "AudioFlinger::EffectModule"
#define LOG_TAG "AudioFlinger::EffectBase"
AudioFlinger::EffectModule::EffectModule(const sp<AudioFlinger::EffectCallbackInterface>& callback,
AudioFlinger::EffectBase::EffectBase(const sp<AudioFlinger::EffectCallbackInterface>& callback,
effect_descriptor_t *desc,
int id,
audio_session_t sessionId,
bool pinned)
: mPinned(pinned),
mCallback(callback), mId(id), mSessionId(sessionId),
mDescriptor(*desc),
// clear mConfig to ensure consistent initial value of buffer framecount
// in case buffers are associated by setInBuffer() or setOutBuffer()
// prior to configure().
mConfig{{}, {}},
mStatus(NO_INIT), mState(IDLE),
mMaxDisableWaitCnt(1), // set by configure(), should be >= 1
mDisableWaitCnt(0), // set by process() and updateState()
mSuspended(false),
mOffloaded(false)
#ifdef FLOAT_EFFECT_CHAIN
, mSupportsFloat(false)
#endif
mDescriptor(*desc)
{
ALOGV("Constructor %p pinned %d", this, pinned);
int lStatus;
}
// create effect engine from effect factory
mStatus = callback->createEffectHal(
&desc->uuid, sessionId, AUDIO_PORT_HANDLE_NONE, &mEffectInterface);
if (mStatus != NO_ERROR) {
return;
}
lStatus = init();
if (lStatus < 0) {
mStatus = lStatus;
goto Error;
}
// must be called with EffectModule::mLock held
status_t AudioFlinger::EffectBase::setEnabled_l(bool enabled)
{
setOffloaded(callback->isOffload(), callback->io());
ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface.get());
ALOGV("setEnabled %p enabled %d", this, enabled);
return;
Error:
mEffectInterface.clear();
ALOGV("Constructor Error %d", mStatus);
if (enabled != isEnabled()) {
switch (mState) {
// going from disabled to enabled
case IDLE:
mState = STARTING;
break;
case STOPPED:
mState = RESTART;
break;
case STOPPING:
mState = ACTIVE;
break;
// going from enabled to disabled
case RESTART:
mState = STOPPED;
break;
case STARTING:
mState = IDLE;
break;
case ACTIVE:
mState = STOPPING;
break;
case DESTROYED:
return NO_ERROR; // simply ignore as we are being destroyed
}
for (size_t i = 1; i < mHandles.size(); i++) {
EffectHandle *h = mHandles[i];
if (h != NULL && !h->disconnected()) {
h->setEnabled(enabled);
}
}
}
return NO_ERROR;
}
AudioFlinger::EffectModule::~EffectModule()
status_t AudioFlinger::EffectBase::setEnabled(bool enabled, bool fromHandle)
{
ALOGV("Destructor %p", this);
if (mEffectInterface != 0) {
char uuidStr[64];
AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
ALOGW("EffectModule %p destructor called with unreleased interface, effect %s",
this, uuidStr);
release_l();
status_t status;
{
Mutex::Autolock _l(mLock);
status = setEnabled_l(enabled);
}
if (fromHandle) {
if (enabled) {
if (status != NO_ERROR) {
mCallback->checkSuspendOnEffectEnabled(this, false, false /*threadLocked*/);
} else {
mCallback->onEffectEnable(this);
}
} else {
mCallback->onEffectDisable(this);
}
}
return status;
}
bool AudioFlinger::EffectBase::isEnabled() const
{
switch (mState) {
case RESTART:
case STARTING:
case ACTIVE:
return true;
case IDLE:
case STOPPING:
case STOPPED:
case DESTROYED:
default:
return false;
}
}
void AudioFlinger::EffectBase::setSuspended(bool suspended)
{
Mutex::Autolock _l(mLock);
mSuspended = suspended;
}
status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle)
bool AudioFlinger::EffectBase::suspended() const
{
Mutex::Autolock _l(mLock);
return mSuspended;
}
status_t AudioFlinger::EffectBase::addHandle(EffectHandle *handle)
{
status_t status;
@ -161,7 +205,7 @@ status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle)
return status;
}
status_t AudioFlinger::EffectModule::updatePolicyState()
status_t AudioFlinger::EffectBase::updatePolicyState()
{
status_t status = NO_ERROR;
bool doRegister = false;
@ -217,13 +261,13 @@ status_t AudioFlinger::EffectModule::updatePolicyState()
}
ssize_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle)
ssize_t AudioFlinger::EffectBase::removeHandle(EffectHandle *handle)
{
Mutex::Autolock _l(mLock);
return removeHandle_l(handle);
}
ssize_t AudioFlinger::EffectModule::removeHandle_l(EffectHandle *handle)
ssize_t AudioFlinger::EffectBase::removeHandle_l(EffectHandle *handle)
{
size_t size = mHandles.size();
size_t i;
@ -247,19 +291,15 @@ ssize_t AudioFlinger::EffectModule::removeHandle_l(EffectHandle *handle)
}
}
// Prevent calls to process() and other functions on effect interface from now on.
// The effect engine will be released by the destructor when the last strong reference on
// this object is released which can happen after next process is called.
if (mHandles.size() == 0 && !mPinned) {
mState = DESTROYED;
mEffectInterface->close();
}
return mHandles.size();
}
// must be called with EffectModule::mLock held
AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l()
AudioFlinger::EffectHandle *AudioFlinger::EffectBase::controlHandle_l()
{
// the first valid handle in the list has control over the module
for (size_t i = 0; i < mHandles.size(); i++) {
@ -273,21 +313,268 @@ AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l()
}
// unsafe method called when the effect parent thread has been destroyed
ssize_t AudioFlinger::EffectModule::disconnectHandle(EffectHandle *handle, bool unpinIfLast)
ssize_t AudioFlinger::EffectBase::disconnectHandle(EffectHandle *handle, bool unpinIfLast)
{
ALOGV("disconnect() %p handle %p", this, handle);
if (mCallback->disconnectEffectHandle(handle, unpinIfLast)) {
return mHandles.size();
}
Mutex::Autolock _l(mLock);
ssize_t numHandles = removeHandle_l(handle);
if ((numHandles == 0) && (!mPinned || unpinIfLast)) {
mLock.unlock();
mCallback->updateOrphanEffectChains(this);
mLock.lock();
}
return numHandles;
}
bool AudioFlinger::EffectBase::purgeHandles()
{
bool enabled = false;
Mutex::Autolock _l(mLock);
EffectHandle *handle = controlHandle_l();
if (handle != NULL) {
enabled = handle->enabled();
}
mHandles.clear();
return enabled;
}
void AudioFlinger::EffectBase::checkSuspendOnEffectEnabled(bool enabled, bool threadLocked) {
mCallback->checkSuspendOnEffectEnabled(this, enabled, threadLocked);
}
static String8 effectFlagsToString(uint32_t flags) {
String8 s;
s.append("conn. mode: ");
switch (flags & EFFECT_FLAG_TYPE_MASK) {
case EFFECT_FLAG_TYPE_INSERT: s.append("insert"); break;
case EFFECT_FLAG_TYPE_AUXILIARY: s.append("auxiliary"); break;
case EFFECT_FLAG_TYPE_REPLACE: s.append("replace"); break;
case EFFECT_FLAG_TYPE_PRE_PROC: s.append("preproc"); break;
case EFFECT_FLAG_TYPE_POST_PROC: s.append("postproc"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
s.append("insert pref: ");
switch (flags & EFFECT_FLAG_INSERT_MASK) {
case EFFECT_FLAG_INSERT_ANY: s.append("any"); break;
case EFFECT_FLAG_INSERT_FIRST: s.append("first"); break;
case EFFECT_FLAG_INSERT_LAST: s.append("last"); break;
case EFFECT_FLAG_INSERT_EXCLUSIVE: s.append("exclusive"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
s.append("volume mgmt: ");
switch (flags & EFFECT_FLAG_VOLUME_MASK) {
case EFFECT_FLAG_VOLUME_NONE: s.append("none"); break;
case EFFECT_FLAG_VOLUME_CTRL: s.append("implements control"); break;
case EFFECT_FLAG_VOLUME_IND: s.append("requires indication"); break;
case EFFECT_FLAG_VOLUME_MONITOR: s.append("monitors volume"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
uint32_t devind = flags & EFFECT_FLAG_DEVICE_MASK;
if (devind) {
s.append("device indication: ");
switch (devind) {
case EFFECT_FLAG_DEVICE_IND: s.append("requires updates"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
}
s.append("input mode: ");
switch (flags & EFFECT_FLAG_INPUT_MASK) {
case EFFECT_FLAG_INPUT_DIRECT: s.append("direct"); break;
case EFFECT_FLAG_INPUT_PROVIDER: s.append("provider"); break;
case EFFECT_FLAG_INPUT_BOTH: s.append("direct+provider"); break;
default: s.append("not set"); break;
}
s.append(", ");
s.append("output mode: ");
switch (flags & EFFECT_FLAG_OUTPUT_MASK) {
case EFFECT_FLAG_OUTPUT_DIRECT: s.append("direct"); break;
case EFFECT_FLAG_OUTPUT_PROVIDER: s.append("provider"); break;
case EFFECT_FLAG_OUTPUT_BOTH: s.append("direct+provider"); break;
default: s.append("not set"); break;
}
s.append(", ");
uint32_t accel = flags & EFFECT_FLAG_HW_ACC_MASK;
if (accel) {
s.append("hardware acceleration: ");
switch (accel) {
case EFFECT_FLAG_HW_ACC_SIMPLE: s.append("non-tunneled"); break;
case EFFECT_FLAG_HW_ACC_TUNNEL: s.append("tunneled"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
}
uint32_t modeind = flags & EFFECT_FLAG_AUDIO_MODE_MASK;
if (modeind) {
s.append("mode indication: ");
switch (modeind) {
case EFFECT_FLAG_AUDIO_MODE_IND: s.append("required"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
}
uint32_t srcind = flags & EFFECT_FLAG_AUDIO_SOURCE_MASK;
if (srcind) {
s.append("source indication: ");
switch (srcind) {
case EFFECT_FLAG_AUDIO_SOURCE_IND: s.append("required"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
}
if (flags & EFFECT_FLAG_OFFLOAD_MASK) {
s.append("offloadable, ");
}
int len = s.length();
if (s.length() > 2) {
(void) s.lockBuffer(len);
s.unlockBuffer(len - 2);
}
return s;
}
void AudioFlinger::EffectBase::dump(int fd, const Vector<String16>& args __unused)
{
String8 result;
result.appendFormat("\tEffect ID %d:\n", mId);
bool locked = AudioFlinger::dumpTryLock(mLock);
// failed to lock - AudioFlinger is probably deadlocked
if (!locked) {
result.append("\t\tCould not lock Fx mutex:\n");
}
result.append("\t\tSession State Registered Enabled Suspended:\n");
result.appendFormat("\t\t%05d %03d %s %s %s\n",
mSessionId, mState, mPolicyRegistered ? "y" : "n",
mPolicyEnabled ? "y" : "n", mSuspended ? "y" : "n");
result.append("\t\tDescriptor:\n");
char uuidStr[64];
AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
result.appendFormat("\t\t- UUID: %s\n", uuidStr);
AudioEffect::guidToString(&mDescriptor.type, uuidStr, sizeof(uuidStr));
result.appendFormat("\t\t- TYPE: %s\n", uuidStr);
result.appendFormat("\t\t- apiVersion: %08X\n\t\t- flags: %08X (%s)\n",
mDescriptor.apiVersion,
mDescriptor.flags,
effectFlagsToString(mDescriptor.flags).string());
result.appendFormat("\t\t- name: %s\n",
mDescriptor.name);
result.appendFormat("\t\t- implementor: %s\n",
mDescriptor.implementor);
result.appendFormat("\t\t%zu Clients:\n", mHandles.size());
result.append("\t\t\t Pid Priority Ctrl Locked client server\n");
char buffer[256];
for (size_t i = 0; i < mHandles.size(); ++i) {
EffectHandle *handle = mHandles[i];
if (handle != NULL && !handle->disconnected()) {
handle->dumpToBuffer(buffer, sizeof(buffer));
result.append(buffer);
}
}
if (locked) {
mLock.unlock();
}
write(fd, result.string(), result.length());
}
// ----------------------------------------------------------------------------
// EffectModule implementation
// ----------------------------------------------------------------------------
#undef LOG_TAG
#define LOG_TAG "AudioFlinger::EffectModule"
AudioFlinger::EffectModule::EffectModule(const sp<AudioFlinger::EffectCallbackInterface>& callback,
effect_descriptor_t *desc,
int id,
audio_session_t sessionId,
bool pinned)
: EffectBase(callback, desc, id, sessionId, pinned),
// clear mConfig to ensure consistent initial value of buffer framecount
// in case buffers are associated by setInBuffer() or setOutBuffer()
// prior to configure().
mConfig{{}, {}},
mStatus(NO_INIT),
mMaxDisableWaitCnt(1), // set by configure(), should be >= 1
mDisableWaitCnt(0), // set by process() and updateState()
mOffloaded(false)
#ifdef FLOAT_EFFECT_CHAIN
, mSupportsFloat(false)
#endif
{
ALOGV("Constructor %p pinned %d", this, pinned);
int lStatus;
// create effect engine from effect factory
mStatus = callback->createEffectHal(
&desc->uuid, sessionId, AUDIO_PORT_HANDLE_NONE, &mEffectInterface);
if (mStatus != NO_ERROR) {
return;
}
lStatus = init();
if (lStatus < 0) {
mStatus = lStatus;
goto Error;
}
setOffloaded(callback->isOffload(), callback->io());
ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface.get());
return;
Error:
mEffectInterface.clear();
ALOGV("Constructor Error %d", mStatus);
}
AudioFlinger::EffectModule::~EffectModule()
{
ALOGV("Destructor %p", this);
if (mEffectInterface != 0) {
char uuidStr[64];
AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
ALOGW("EffectModule %p destructor called with unreleased interface, effect %s",
this, uuidStr);
release_l();
}
}
ssize_t AudioFlinger::EffectModule::removeHandle_l(EffectHandle *handle)
{
ALOGV("disconnect() %p handle %p", this, handle);
if (mCallback->disconnectEffectHandle(handle, unpinIfLast)) {
return mHandles.size();
}
ssize_t status = EffectBase::removeHandle_l(handle);
Mutex::Autolock _l(mLock);
ssize_t numHandles = removeHandle_l(handle);
if ((numHandles == 0) && (!mPinned || unpinIfLast)) {
mLock.unlock();
mCallback->updateOrphanEffectChains(this);
mLock.lock();
// Prevent calls to process() and other functions on effect interface from now on.
// The effect engine will be released by the destructor when the last strong reference on
// this object is released which can happen after next process is called.
if (status == 0 && !mPinned) {
mEffectInterface->close();
}
return numHandles;
return status;
}
bool AudioFlinger::EffectModule::updateState() {
@ -950,89 +1237,6 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode,
return status;
}
void AudioFlinger::EffectModule::checkSuspendOnEffectEnabled(bool enabled, bool threadLocked) {
mCallback->checkSuspendOnEffectEnabled(this, enabled, threadLocked);
}
status_t AudioFlinger::EffectModule::setEnabled(bool enabled, bool fromHandle)
{
status_t status;
{
Mutex::Autolock _l(mLock);
status = setEnabled_l(enabled);
}
if (fromHandle) {
if (enabled) {
if (status != NO_ERROR) {
mCallback->checkSuspendOnEffectEnabled(this, false, false /*threadLocked*/);
} else {
mCallback->onEffectEnable(this);
}
} else {
mCallback->onEffectDisable(this);
}
}
return status;
}
// must be called with EffectModule::mLock held
status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled)
{
ALOGV("setEnabled %p enabled %d", this, enabled);
if (enabled != isEnabled()) {
switch (mState) {
// going from disabled to enabled
case IDLE:
mState = STARTING;
break;
case STOPPED:
mState = RESTART;
break;
case STOPPING:
mState = ACTIVE;
break;
// going from enabled to disabled
case RESTART:
mState = STOPPED;
break;
case STARTING:
mState = IDLE;
break;
case ACTIVE:
mState = STOPPING;
break;
case DESTROYED:
return NO_ERROR; // simply ignore as we are being destroyed
}
for (size_t i = 1; i < mHandles.size(); i++) {
EffectHandle *h = mHandles[i];
if (h != NULL && !h->disconnected()) {
h->setEnabled(enabled);
}
}
}
return NO_ERROR;
}
bool AudioFlinger::EffectModule::isEnabled() const
{
switch (mState) {
case RESTART:
case STARTING:
case ACTIVE:
return true;
case IDLE:
case STOPPING:
case STOPPED:
case DESTROYED:
default:
return false;
}
}
bool AudioFlinger::EffectModule::isProcessEnabled() const
{
if (mStatus != NO_ERROR) {
@ -1274,30 +1478,6 @@ status_t AudioFlinger::EffectModule::setAudioSource(audio_source_t source)
return status;
}
void AudioFlinger::EffectModule::setSuspended(bool suspended)
{
Mutex::Autolock _l(mLock);
mSuspended = suspended;
}
bool AudioFlinger::EffectModule::suspended() const
{
Mutex::Autolock _l(mLock);
return mSuspended;
}
bool AudioFlinger::EffectModule::purgeHandles()
{
bool enabled = false;
Mutex::Autolock _l(mLock);
EffectHandle *handle = controlHandle_l();
if (handle != NULL) {
enabled = handle->enabled();
}
mHandles.clear();
return enabled;
}
status_t AudioFlinger::EffectModule::setOffloaded(bool offloaded, audio_io_handle_t io)
{
Mutex::Autolock _l(mLock);
@ -1337,111 +1517,6 @@ bool AudioFlinger::EffectModule::isOffloaded() const
return mOffloaded;
}
String8 effectFlagsToString(uint32_t flags) {
String8 s;
s.append("conn. mode: ");
switch (flags & EFFECT_FLAG_TYPE_MASK) {
case EFFECT_FLAG_TYPE_INSERT: s.append("insert"); break;
case EFFECT_FLAG_TYPE_AUXILIARY: s.append("auxiliary"); break;
case EFFECT_FLAG_TYPE_REPLACE: s.append("replace"); break;
case EFFECT_FLAG_TYPE_PRE_PROC: s.append("preproc"); break;
case EFFECT_FLAG_TYPE_POST_PROC: s.append("postproc"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
s.append("insert pref: ");
switch (flags & EFFECT_FLAG_INSERT_MASK) {
case EFFECT_FLAG_INSERT_ANY: s.append("any"); break;
case EFFECT_FLAG_INSERT_FIRST: s.append("first"); break;
case EFFECT_FLAG_INSERT_LAST: s.append("last"); break;
case EFFECT_FLAG_INSERT_EXCLUSIVE: s.append("exclusive"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
s.append("volume mgmt: ");
switch (flags & EFFECT_FLAG_VOLUME_MASK) {
case EFFECT_FLAG_VOLUME_NONE: s.append("none"); break;
case EFFECT_FLAG_VOLUME_CTRL: s.append("implements control"); break;
case EFFECT_FLAG_VOLUME_IND: s.append("requires indication"); break;
case EFFECT_FLAG_VOLUME_MONITOR: s.append("monitors volume"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
uint32_t devind = flags & EFFECT_FLAG_DEVICE_MASK;
if (devind) {
s.append("device indication: ");
switch (devind) {
case EFFECT_FLAG_DEVICE_IND: s.append("requires updates"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
}
s.append("input mode: ");
switch (flags & EFFECT_FLAG_INPUT_MASK) {
case EFFECT_FLAG_INPUT_DIRECT: s.append("direct"); break;
case EFFECT_FLAG_INPUT_PROVIDER: s.append("provider"); break;
case EFFECT_FLAG_INPUT_BOTH: s.append("direct+provider"); break;
default: s.append("not set"); break;
}
s.append(", ");
s.append("output mode: ");
switch (flags & EFFECT_FLAG_OUTPUT_MASK) {
case EFFECT_FLAG_OUTPUT_DIRECT: s.append("direct"); break;
case EFFECT_FLAG_OUTPUT_PROVIDER: s.append("provider"); break;
case EFFECT_FLAG_OUTPUT_BOTH: s.append("direct+provider"); break;
default: s.append("not set"); break;
}
s.append(", ");
uint32_t accel = flags & EFFECT_FLAG_HW_ACC_MASK;
if (accel) {
s.append("hardware acceleration: ");
switch (accel) {
case EFFECT_FLAG_HW_ACC_SIMPLE: s.append("non-tunneled"); break;
case EFFECT_FLAG_HW_ACC_TUNNEL: s.append("tunneled"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
}
uint32_t modeind = flags & EFFECT_FLAG_AUDIO_MODE_MASK;
if (modeind) {
s.append("mode indication: ");
switch (modeind) {
case EFFECT_FLAG_AUDIO_MODE_IND: s.append("required"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
}
uint32_t srcind = flags & EFFECT_FLAG_AUDIO_SOURCE_MASK;
if (srcind) {
s.append("source indication: ");
switch (srcind) {
case EFFECT_FLAG_AUDIO_SOURCE_IND: s.append("required"); break;
default: s.append("unknown/reserved"); break;
}
s.append(", ");
}
if (flags & EFFECT_FLAG_OFFLOAD_MASK) {
s.append("offloadable, ");
}
int len = s.length();
if (s.length() > 2) {
(void) s.lockBuffer(len);
s.unlockBuffer(len - 2);
}
return s;
}
static std::string dumpInOutBuffer(bool isInput, const sp<EffectBufferHalInterface> &buffer) {
std::stringstream ss;
@ -1457,38 +1532,16 @@ static std::string dumpInOutBuffer(bool isInput, const sp<EffectBufferHalInterfa
return ss.str();
}
void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args __unused)
void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
{
String8 result;
result.appendFormat("\tEffect ID %d:\n", mId);
EffectBase::dump(fd, args);
String8 result;
bool locked = AudioFlinger::dumpTryLock(mLock);
// failed to lock - AudioFlinger is probably deadlocked
if (!locked) {
result.append("\t\tCould not lock Fx mutex:\n");
}
result.append("\t\tSession Status State Registered Enabled Suspended Engine:\n");
result.appendFormat("\t\t%05d %03d %03d %s %s %s %p\n",
mSessionId, mStatus, mState, mPolicyRegistered ? "y" : "n", mPolicyEnabled ? "y" : "n",
mSuspended ? "y" : "n", mEffectInterface.get());
result.append("\t\tDescriptor:\n");
char uuidStr[64];
AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
result.appendFormat("\t\t- UUID: %s\n", uuidStr);
AudioEffect::guidToString(&mDescriptor.type, uuidStr, sizeof(uuidStr));
result.appendFormat("\t\t- TYPE: %s\n", uuidStr);
result.appendFormat("\t\t- apiVersion: %08X\n\t\t- flags: %08X (%s)\n",
mDescriptor.apiVersion,
mDescriptor.flags,
effectFlagsToString(mDescriptor.flags).string());
result.appendFormat("\t\t- name: %s\n",
mDescriptor.name);
result.appendFormat("\t\t- implementor: %s\n",
mDescriptor.implementor);
result.append("\t\tStatus Engine:\n");
result.appendFormat("\t\t%03d %p\n",
mStatus, mEffectInterface.get());
result.appendFormat("\t\t- data: %s\n", mSupportsFloat ? "float" : "int16");
@ -1522,17 +1575,6 @@ void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args __unu
dumpInOutBuffer(false /* isInput */, mOutConversionBuffer).c_str());
#endif
result.appendFormat("\t\t%zu Clients:\n", mHandles.size());
result.append("\t\t\t Pid Priority Ctrl Locked client server\n");
char buffer[256];
for (size_t i = 0; i < mHandles.size(); ++i) {
EffectHandle *handle = mHandles[i];
if (handle != NULL && !handle->disconnected()) {
handle->dumpToBuffer(buffer, sizeof(buffer));
result.append(buffer);
}
}
write(fd, result.string(), result.length());
if (mEffectInterface != 0) {
@ -1552,7 +1594,7 @@ void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args __unu
#undef LOG_TAG
#define LOG_TAG "AudioFlinger::EffectHandle"
AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect,
AudioFlinger::EffectHandle::EffectHandle(const sp<EffectBase>& effect,
const sp<AudioFlinger::Client>& client,
const sp<IEffectClient>& effectClient,
int32_t priority)
@ -1593,7 +1635,7 @@ status_t AudioFlinger::EffectHandle::enable()
{
AutoMutex _l(mLock);
ALOGV("enable %p", this);
sp<EffectModule> effect = mEffect.promote();
sp<EffectBase> effect = mEffect.promote();
if (effect == 0 || mDisconnected) {
return DEAD_OBJECT;
}
@ -1631,7 +1673,7 @@ status_t AudioFlinger::EffectHandle::disable()
{
ALOGV("disable %p", this);
AutoMutex _l(mLock);
sp<EffectModule> effect = mEffect.promote();
sp<EffectBase> effect = mEffect.promote();
if (effect == 0 || mDisconnected) {
return DEAD_OBJECT;
}
@ -1672,7 +1714,7 @@ void AudioFlinger::EffectHandle::disconnect(bool unpinIfLast)
}
mDisconnected = true;
{
sp<EffectModule> effect = mEffect.promote();
sp<EffectBase> effect = mEffect.promote();
if (effect != 0) {
if (effect->disconnectHandle(this, unpinIfLast) > 0) {
ALOGW("%s Effect handle %p disconnected after thread destruction",
@ -1740,7 +1782,7 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode,
}
AutoMutex _l(mLock);
sp<EffectModule> effect = mEffect.promote();
sp<EffectBase> effect = mEffect.promote();
if (effect == 0 || mDisconnected) {
return DEAD_OBJECT;
}
@ -2671,12 +2713,13 @@ status_t AudioFlinger::EffectChain::EffectCallback::createEffectHal(
}
bool AudioFlinger::EffectChain::EffectCallback::updateOrphanEffectChains(
const sp<AudioFlinger::EffectModule>& effect) {
const sp<AudioFlinger::EffectBase>& effect) {
sp<AudioFlinger> af = mAudioFlinger.promote();
if (af == nullptr) {
return false;
}
return af->updateOrphanEffectChains(effect);
// in EffectChain context, an EffectBase is always from an EffectModule so static cast is safe
return af->updateOrphanEffectChains(effect->asEffectModule());
}
status_t AudioFlinger::EffectChain::EffectCallback::allocateHalBuffer(
@ -2807,7 +2850,7 @@ void AudioFlinger::EffectChain::EffectCallback::setVolumeForOutput(float left, f
}
void AudioFlinger::EffectChain::EffectCallback::checkSuspendOnEffectEnabled(
const sp<EffectModule>& effect, bool enabled, bool threadLocked) {
const sp<EffectBase>& effect, bool enabled, bool threadLocked) {
sp<ThreadBase> t = mThread.promote();
if (t == nullptr) {
return;
@ -2818,18 +2861,20 @@ void AudioFlinger::EffectChain::EffectCallback::checkSuspendOnEffectEnabled(
if (c == nullptr) {
return;
}
c->checkSuspendOnEffectEnabled(effect, enabled);
// in EffectChain context, an EffectBase is always from an EffectModule so static cast is safe
c->checkSuspendOnEffectEnabled(effect->asEffectModule(), enabled);
}
void AudioFlinger::EffectChain::EffectCallback::onEffectEnable(const sp<EffectModule>& effect) {
void AudioFlinger::EffectChain::EffectCallback::onEffectEnable(const sp<EffectBase>& effect) {
sp<ThreadBase> t = mThread.promote();
if (t == nullptr) {
return;
}
t->onEffectEnable(effect);
// in EffectChain context, an EffectBase is always from an EffectModule so static cast is safe
t->onEffectEnable(effect->asEffectModule());
}
void AudioFlinger::EffectChain::EffectCallback::onEffectDisable(const sp<EffectModule>& effect) {
void AudioFlinger::EffectChain::EffectCallback::onEffectDisable(const sp<EffectBase>& effect) {
checkSuspendOnEffectEnabled(effect, false, false /*threadLocked*/);
sp<ThreadBase> t = mThread.promote();

@ -45,17 +45,17 @@ public:
virtual status_t removeEffectFromHal(sp<EffectHalInterface> effect) = 0;
virtual void setVolumeForOutput(float left, float right) const = 0;
virtual bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) = 0;
virtual void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
virtual void checkSuspendOnEffectEnabled(const sp<EffectBase>& effect,
bool enabled,
bool threadLocked) = 0;
virtual void onEffectEnable(const sp<EffectModule>& effect) = 0;
virtual void onEffectDisable(const sp<EffectModule>& effect) = 0;
virtual void onEffectEnable(const sp<EffectBase>& effect) = 0;
virtual void onEffectDisable(const sp<EffectBase>& effect) = 0;
// Methods usually implemented with help from AudioFlinger: pay attention to mutex locking order
virtual status_t createEffectHal(const effect_uuid_t *pEffectUuid,
int32_t sessionId, int32_t deviceId, sp<EffectHalInterface> *effect) = 0;
virtual status_t allocateHalBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) = 0;
virtual bool updateOrphanEffectChains(const sp<EffectModule>& effect) = 0;
virtual bool updateOrphanEffectChains(const sp<EffectBase>& effect) = 0;
// Methods usually implemented with help from EffectChain: pay attention to mutex locking order
virtual uint32_t strategy() const = 0;
@ -65,11 +65,11 @@ public:
virtual wp<EffectChain> chain() const = 0;
};
// EffectModule and EffectChain classes both have their own mutex to protect
// EffectBase(EffectModule) and EffectChain classes both have their own mutex to protect
// state changes or resource modifications. Always respect the following order
// if multiple mutexes must be acquired to avoid cross deadlock:
// AudioFlinger -> ThreadBase -> EffectChain -> EffectModule
// AudioHandle -> ThreadBase -> EffectChain -> EffectModule
// AudioFlinger -> ThreadBase -> EffectChain -> EffectBase(EffectModule)
// AudioHandle -> ThreadBase -> EffectChain -> EffectBase(EffectModule)
// NOTE: When implementing the EffectCallbackInterface, in an EffectChain or other, it is important
// to pay attention to this locking order as some callback methods can be called from a state where
@ -80,6 +80,116 @@ public:
// Threadbase mutex locked to avoid cross deadlock with other clients calling AudioPolicyService
// methods that in turn call AudioFlinger thus locking the same mutexes in the reverse order.
// The EffectBase class contains common properties, state and behavior for and EffectModule or
// other derived classes managing an audio effect instance within the effect framework.
// It also contains the class mutex (see comment on locking order above).
class EffectBase : public RefBase {
public:
EffectBase(const sp<EffectCallbackInterface>& callback,
effect_descriptor_t *desc,
int id,
audio_session_t sessionId,
bool pinned);
~EffectBase() override = default;
enum effect_state {
IDLE,
RESTART,
STARTING,
ACTIVE,
STOPPING,
STOPPED,
DESTROYED
};
int id() const { return mId; }
effect_state state() const {
return mState;
}
audio_session_t sessionId() const {
return mSessionId;
}
const effect_descriptor_t& desc() const { return mDescriptor; }
bool isOffloadable() const
{ return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; }
bool isImplementationSoftware() const
{ return (mDescriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0; }
bool isProcessImplemented() const
{ return (mDescriptor.flags & EFFECT_FLAG_NO_PROCESS) == 0; }
bool isVolumeControl() const
{ return (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK)
== EFFECT_FLAG_VOLUME_CTRL; }
bool isVolumeMonitor() const
{ return (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK)
== EFFECT_FLAG_VOLUME_MONITOR; }
virtual status_t setEnabled(bool enabled, bool fromHandle);
status_t setEnabled_l(bool enabled);
bool isEnabled() const;
void setSuspended(bool suspended);
bool suspended() const;
virtual status_t command(uint32_t cmdCode __unused,
uint32_t cmdSize __unused,
void *pCmdData __unused,
uint32_t *replySize __unused,
void *pReplyData __unused) { return NO_ERROR; };
void setCallback(const sp<EffectCallbackInterface>& callback) { mCallback = callback; }
sp<EffectCallbackInterface>& callback() { return mCallback; }
status_t addHandle(EffectHandle *handle);
ssize_t disconnectHandle(EffectHandle *handle, bool unpinIfLast);
ssize_t removeHandle(EffectHandle *handle);
virtual ssize_t removeHandle_l(EffectHandle *handle);
EffectHandle* controlHandle_l();
bool purgeHandles();
void checkSuspendOnEffectEnabled(bool enabled, bool threadLocked);
bool isPinned() const { return mPinned; }
void unPin() { mPinned = false; }
void lock() { mLock.lock(); }
void unlock() { mLock.unlock(); }
status_t updatePolicyState();
virtual sp<EffectModule> asEffectModule() { return nullptr; }
void dump(int fd, const Vector<String16>& args);
private:
friend class AudioFlinger; // for mHandles
bool mPinned = false;
DISALLOW_COPY_AND_ASSIGN(EffectBase);
mutable Mutex mLock; // mutex for process, commands and handles list protection
sp<EffectCallbackInterface> mCallback; // parent effect chain
const int mId; // this instance unique ID
const audio_session_t mSessionId; // audio session ID
const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
effect_state mState = IDLE; // current activation state
bool mSuspended; // effect is suspended: temporarily disabled by framework
Vector<EffectHandle *> mHandles; // list of client handles
// First handle in mHandles has highest priority and controls the effect module
// Audio policy effect state management
// Mutex protecting transactions with audio policy manager as mLock cannot
// be held to avoid cross deadlocks with audio policy mutex
Mutex mPolicyLock;
// Effect is registered in APM or not
bool mPolicyRegistered = false;
// Effect enabled state communicated to APM. Enabled state corresponds to
// state requested by the EffectHandle with control
bool mPolicyEnabled = false;
};
// The EffectModule class is a wrapper object controlling the effect engine implementation
// in the effect library. It prevents concurrent calls to process() and command() functions
// from different client threads. It keeps a list of EffectHandle objects corresponding
@ -89,49 +199,31 @@ public:
// ramping when effects are activated/deactivated.
// When controlling an auxiliary effect, the EffectModule also provides an input buffer used by
// the attached track(s) to accumulate their auxiliary channel.
class EffectModule : public RefBase {
class EffectModule : public EffectBase {
public:
EffectModule(const sp<EffectCallbackInterface>& chain,
EffectModule(const sp<EffectCallbackInterface>& callabck,
effect_descriptor_t *desc,
int id,
audio_session_t sessionId,
bool pinned);
virtual ~EffectModule();
enum effect_state {
IDLE,
RESTART,
STARTING,
ACTIVE,
STOPPING,
STOPPED,
DESTROYED
};
int id() const { return mId; }
void process();
bool updateState();
status_t command(uint32_t cmdCode,
uint32_t cmdSize,
void *pCmdData,
uint32_t *replySize,
void *pReplyData);
void *pReplyData) override;
void reset_l();
status_t configure();
status_t init();
effect_state state() const {
return mState;
}
uint32_t status() {
return mStatus;
}
audio_session_t sessionId() const {
return mSessionId;
}
status_t setEnabled(bool enabled, bool fromHandle);
status_t setEnabled_l(bool enabled);
bool isEnabled() const;
bool isProcessEnabled() const;
bool isOffloadedOrDirect() const;
bool isVolumeControlEnabled() const;
@ -144,15 +236,8 @@ public:
int16_t *outBuffer() const {
return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
}
void setCallback(const sp<EffectCallbackInterface>& callback) { mCallback = callback; }
status_t addHandle(EffectHandle *handle);
ssize_t disconnectHandle(EffectHandle *handle, bool unpinIfLast);
ssize_t removeHandle(EffectHandle *handle);
ssize_t removeHandle_l(EffectHandle *handle);
const effect_descriptor_t& desc() const { return mDescriptor; }
sp<EffectCallbackInterface>& callback() { return mCallback; }
ssize_t removeHandle_l(EffectHandle *handle) override;
status_t setDevices(const AudioDeviceTypeAddrVector &devices);
status_t setInputDevice(const AudioDeviceTypeAddr &device);
@ -161,41 +246,18 @@ public:
status_t setAudioSource(audio_source_t source);
status_t start();
status_t stop();
void setSuspended(bool suspended);
bool suspended() const;
EffectHandle* controlHandle_l();
bool isPinned() const { return mPinned; }
void unPin() { mPinned = false; }
bool purgeHandles();
void lock() { mLock.lock(); }
void unlock() { mLock.unlock(); }
bool isOffloadable() const
{ return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; }
bool isImplementationSoftware() const
{ return (mDescriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0; }
bool isProcessImplemented() const
{ return (mDescriptor.flags & EFFECT_FLAG_NO_PROCESS) == 0; }
bool isVolumeControl() const
{ return (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK)
== EFFECT_FLAG_VOLUME_CTRL; }
bool isVolumeMonitor() const
{ return (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK)
== EFFECT_FLAG_VOLUME_MONITOR; }
status_t setOffloaded(bool offloaded, audio_io_handle_t io);
bool isOffloaded() const;
void addEffectToHal_l();
void release_l();
status_t updatePolicyState();
void checkSuspendOnEffectEnabled(bool enabled, bool threadLocked);
sp<EffectModule> asEffectModule() override { return this; }
void dump(int fd, const Vector<String16>& args);
private:
friend class AudioFlinger; // for mHandles
bool mPinned;
// Maximum time allocated to effect engines to complete the turn off sequence
static const uint32_t MAX_DISABLE_TIME_MS = 10000;
@ -207,23 +269,15 @@ private:
status_t removeEffectFromHal_l();
status_t sendSetAudioDevicesCommand(const AudioDeviceTypeAddrVector &devices, uint32_t cmdCode);
mutable Mutex mLock; // mutex for process, commands and handles list protection
sp<EffectCallbackInterface> mCallback; // parent effect chain
const int mId; // this instance unique ID
const audio_session_t mSessionId; // audio session ID
const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
effect_config_t mConfig; // input and output audio configuration
sp<EffectHalInterface> mEffectInterface; // Effect module HAL
sp<EffectBufferHalInterface> mInBuffer; // Buffers for interacting with HAL
sp<EffectBufferHalInterface> mOutBuffer;
status_t mStatus; // initialization status
effect_state mState; // current activation state
Vector<EffectHandle *> mHandles; // list of client handles
// First handle in mHandles has highest priority and controls the effect module
uint32_t mMaxDisableWaitCnt; // maximum grace period before forcing an effect off after
// sending disable command.
uint32_t mDisableWaitCnt; // current process() calls count during disable period.
bool mSuspended; // effect is suspended: temporarily disabled by framework
bool mOffloaded; // effect is currently offloaded to the audio DSP
#ifdef FLOAT_EFFECT_CHAIN
@ -251,16 +305,6 @@ mutable Mutex mLock; // mutex for process, commands and handl
static constexpr pid_t INVALID_PID = (pid_t)-1;
// this tid is allowed to call setVolume() without acquiring the mutex.
pid_t mSetVolumeReentrantTid = INVALID_PID;
// Audio policy effect state management
// Mutex protecting transactions with audio policy manager as mLock cannot
// be held to avoid cross deadlocks with audio policy mutex
Mutex mPolicyLock;
// Effect is registered in APM or not
bool mPolicyRegistered = false;
// Effect enabled state communicated to APM. Enabled state corresponds to
// state requested by the EffectHandle with control
bool mPolicyEnabled = false;
};
// The EffectHandle class implements the IEffect interface. It provides resources
@ -272,7 +316,7 @@ mutable Mutex mLock; // mutex for process, commands and handl
class EffectHandle: public android::BnEffect {
public:
EffectHandle(const sp<EffectModule>& effect,
EffectHandle(const sp<EffectBase>& effect,
const sp<AudioFlinger::Client>& client,
const sp<IEffectClient>& effectClient,
int32_t priority);
@ -310,9 +354,9 @@ public:
bool enabled() const { return mEnabled; }
// Getters
wp<EffectModule> effect() const { return mEffect; }
wp<EffectBase> effect() const { return mEffect; }
int id() const {
sp<EffectModule> effect = mEffect.promote();
sp<EffectBase> effect = mEffect.promote();
if (effect == 0) {
return 0;
}
@ -329,7 +373,7 @@ private:
DISALLOW_COPY_AND_ASSIGN(EffectHandle);
Mutex mLock; // protects IEffect method calls
wp<EffectModule> mEffect; // pointer to controlled EffectModule
wp<EffectBase> mEffect; // pointer to controlled EffectModule
sp<IEffectClient> mEffectClient; // callback interface for client notifications
/*const*/ sp<Client> mClient; // client for shared memory allocation, see disconnect()
sp<IMemory> mCblkMemory; // shared memory for control block
@ -472,7 +516,7 @@ private:
status_t createEffectHal(const effect_uuid_t *pEffectUuid,
int32_t sessionId, int32_t deviceId, sp<EffectHalInterface> *effect) override;
status_t allocateHalBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) override;
bool updateOrphanEffectChains(const sp<EffectModule>& effect) override;
bool updateOrphanEffectChains(const sp<EffectBase>& effect) override;
audio_io_handle_t io() const override;
bool isOutput() const override;
@ -492,13 +536,13 @@ private:
void setVolumeForOutput(float left, float right) const override;
// check if effects should be suspended/restored when a given effect is enable/disabled
void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
void checkSuspendOnEffectEnabled(const sp<EffectBase>& effect,
bool enabled, bool threadLocked) override;
void resetVolume() override;
uint32_t strategy() const override;
int32_t activeTrackCnt() const override;
void onEffectEnable(const sp<EffectModule>& effect) override;
void onEffectDisable(const sp<EffectModule>& effect) override;
void onEffectEnable(const sp<EffectBase>& effect) override;
void onEffectDisable(const sp<EffectBase>& effect) override;
wp<EffectChain> chain() const override { return mChain; }

@ -1419,11 +1419,11 @@ void AudioFlinger::ThreadBase::disconnectEffectHandle(EffectHandle *handle,
sp<EffectModule> effect;
{
Mutex::Autolock _l(mLock);
effect = handle->effect().promote();
if (effect == nullptr) {
sp<EffectBase> effectBase = handle->effect().promote();
if (effectBase == nullptr) {
return;
}
effect = static_cast<EffectModule *>(effectBase.get());
// restore suspended effects if the disconnected handle was enabled and the last one.
remove = (effect->removeHandle(handle) == 0) && (!effect->isPinned() || unpinIfLast);
if (remove) {

Loading…
Cancel
Save