Modifications in audio effect engine state management.
- Separate the updating of effect engine state from the process call in EffectModule so that the state
of all effects in the same effect chain is updated simultaneusly before all process functions are called.
- Added a mechanism for the effect engine to continue being called for processing after receiving the disable
commands untils it considers that the framework can stop calling the process function without causing
a glitch or loosing some effect tail.
- Updated test reverb and equalizer to support this new feature
Change-Id: Icb56ae2c84c076d4dbad6cf733b1a62f823febe7
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index e6f46ce..97eb6c0 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -17,8 +17,7 @@
#define LOG_TAG "AudioFlinger"
-//
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#include <math.h>
#include <signal.h>
@@ -5085,15 +5084,53 @@
}
}
+void AudioFlinger::EffectModule::updateState() {
+ Mutex::Autolock _l(mLock);
+
+ switch (mState) {
+ case RESTART:
+ reset_l();
+ // FALL THROUGH
+
+ case STARTING:
+ // clear auxiliary effect input buffer for next accumulation
+ if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+ memset(mConfig.inputCfg.buffer.raw,
+ 0,
+ mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
+ }
+ start_l();
+ mState = ACTIVE;
+ break;
+ case STOPPING:
+ stop_l();
+ mDisableWaitCnt = mMaxDisableWaitCnt;
+ mState = STOPPED;
+ break;
+ case STOPPED:
+ // mDisableWaitCnt is forced to 1 by process() when the engine indicates the end of the
+ // turn off sequence.
+ if (--mDisableWaitCnt == 0) {
+ reset_l();
+ mState = IDLE;
+ }
+ break;
+ default: //IDLE , ACTIVE
+ break;
+ }
+}
+
void AudioFlinger::EffectModule::process()
{
Mutex::Autolock _l(mLock);
- if (mEffectInterface == NULL || mConfig.inputCfg.buffer.raw == NULL || mConfig.outputCfg.buffer.raw == NULL) {
+ if (mEffectInterface == NULL ||
+ mConfig.inputCfg.buffer.raw == NULL ||
+ mConfig.outputCfg.buffer.raw == NULL) {
return;
}
- if (mState != IDLE) {
+ if (mState == ACTIVE || mState == STOPPING || mState == STOPPED) {
// do 32 bit to 16 bit conversion for auxiliary effect input buffer
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
@@ -5101,33 +5138,15 @@
mConfig.inputCfg.buffer.frameCount);
}
- // TODO: handle effects with buffer provider
- if (mState != ACTIVE) {
- switch (mState) {
- case RESET:
- reset_l();
- mState = STARTING;
- // clear auxiliary effect input buffer for next accumulation
- if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
- memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
- }
- return;
- case STARTING:
- start_l();
- mState = ACTIVE;
- break;
- case STOPPING:
- mState = STOPPED;
- break;
- case STOPPED:
- stop_l();
- mState = IDLE;
- return;
- }
- }
-
// do the actual processing in the effect engine
- (*mEffectInterface)->process(mEffectInterface, &mConfig.inputCfg.buffer, &mConfig.outputCfg.buffer);
+ int ret = (*mEffectInterface)->process(mEffectInterface,
+ &mConfig.inputCfg.buffer,
+ &mConfig.outputCfg.buffer);
+
+ // force transition to IDLE state when engine is ready
+ if (mState == STOPPED && ret == -ENODATA) {
+ mDisableWaitCnt = 1;
+ }
// clear auxiliary effect input buffer for next accumulation
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
@@ -5216,6 +5235,10 @@
if (status == 0) {
status = cmdStatus;
}
+
+ mMaxDisableWaitCnt = (MAX_DISABLE_TIME_MS * mConfig.outputCfg.samplingRate) /
+ (1000 * mConfig.outputCfg.buffer.frameCount);
+
return status;
}
@@ -5292,21 +5315,19 @@
switch (mState) {
// going from disabled to enabled
case IDLE:
- mState = RESET;
+ mState = STARTING;
+ break;
+ case STOPPED:
+ mState = RESTART;
break;
case STOPPING:
mState = ACTIVE;
break;
- case STOPPED:
- mState = STARTING;
- break;
// going from enabled to disabled
- case RESET:
- mState = IDLE;
- break;
+ case RESTART:
case STARTING:
- mState = STOPPED;
+ mState = IDLE;
break;
case ACTIVE:
mState = STOPPING;
@@ -5325,7 +5346,7 @@
bool AudioFlinger::EffectModule::isEnabled()
{
switch (mState) {
- case RESET:
+ case RESTART:
case STARTING:
case ACTIVE:
return true;
@@ -5772,6 +5793,9 @@
for (size_t i = 0; i < size; i++) {
mEffects[i]->process();
}
+ for (size_t i = 0; i < size; i++) {
+ mEffects[i]->updateState();
+ }
// if no track is active, input buffer must be cleared here as the mixer process
// will not do it
if (mSessionId > 0 && activeTracks() == 0) {