audio flinger: fix AEC and NS suspend logic
Make sure we suspend/restore AEC and NS only when the suspend condition
actually changes to avoid mismatch in number of suspends/restores
causing the ref counting mechanism to leave the effects in suspend mode
while they should not.
Also clear the suspend state on an effect session before parking it in
the orphan chains list so that it is in default state whne attached to a
new record thread.
Bug: 63015903
Test: verify that switching BT SCO on/off with Duo enables or disables
AEC and NS accordingly
Change-Id: I4d0f0bf818deca3952da3c67bb7e83cb500429c7
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 38c9687..0df9a39 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1193,25 +1193,10 @@
String8 value;
if (param.get(String8(AudioParameter::keyBtNrec), value) == NO_ERROR) {
bool btNrecIsOff = (value == AudioParameter::valueOff);
- if (mBtNrecIsOff != btNrecIsOff) {
+ if (mBtNrecIsOff.exchange(btNrecIsOff) != btNrecIsOff) {
for (size_t i = 0; i < mRecordThreads.size(); i++) {
- sp<RecordThread> thread = mRecordThreads.valueAt(i);
- audio_devices_t device = thread->inDevice();
- bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff;
- // collect all of the thread's session IDs
- KeyedVector<audio_session_t, bool> ids = thread->sessionIds();
- // suspend effects associated with those session IDs
- for (size_t j = 0; j < ids.size(); ++j) {
- audio_session_t sessionId = ids.keyAt(j);
- thread->setEffectSuspended(FX_IID_AEC,
- suspend,
- sessionId);
- thread->setEffectSuspended(FX_IID_NS,
- suspend,
- sessionId);
- }
+ mRecordThreads.valueAt(i)->checkBtNrec();
}
- mBtNrecIsOff = btNrecIsOff;
}
}
String8 screenState;
@@ -3214,6 +3199,11 @@
status_t AudioFlinger::putOrphanEffectChain_l(const sp<AudioFlinger::EffectChain>& chain)
{
+ // clear possible suspended state before parking the chain so that it starts in default state
+ // when attached to a new record thread
+ chain->setEffectSuspended_l(FX_IID_AEC, false);
+ chain->setEffectSuspended_l(FX_IID_NS, false);
+
audio_session_t session = chain->sessionId();
ssize_t index = mOrphanEffectChains.indexOfKey(session);
ALOGV("putOrphanEffectChain_l session %d index %zd", session, index);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 8a96c1d..9023b2d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -350,12 +350,13 @@
sync_event_callback_t callBack,
const wp<RefBase>& cookie);
+ bool btNrecIsOff() const { return mBtNrecIsOff.load(); }
+
+
private:
audio_mode_t getMode() const { return mMode; }
- bool btNrecIsOff() const { return mBtNrecIsOff; }
-
AudioFlinger() ANDROID_API;
virtual ~AudioFlinger();
@@ -781,7 +782,7 @@
volatile atomic_uint_fast32_t mNextUniqueIds[AUDIO_UNIQUE_ID_USE_MAX];
audio_mode_t mMode;
- bool mBtNrecIsOff;
+ std::atomic_bool mBtNrecIsOff;
// protected by mLock
Vector<AudioSessionRef*> mAudioSessionRefs;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index f4428fe..f2c1c4f 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -21,10 +21,12 @@
#include "Configuration.h"
#include <utils/Log.h>
+#include <system/audio_effects/effect_aec.h>
+#include <system/audio_effects/effect_ns.h>
+#include <system/audio_effects/effect_visualizer.h>
#include <audio_utils/primitives.h>
#include <media/audiohal/EffectHalInterface.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
-#include <system/audio_effects/effect_visualizer.h>
#include "AudioFlinger.h"
#include "ServiceUtilities.h"
@@ -1809,6 +1811,7 @@
idx_insert);
}
effect->configure();
+
return NO_ERROR;
}
@@ -2030,6 +2033,7 @@
mSuspendedEffects.add(type->timeLow, desc);
ALOGV("setEffectSuspended_l() add entry for %08x", type->timeLow);
}
+
if (desc->mRefCount++ == 0) {
sp<EffectModule> effect = getEffectIfEnabled(type);
if (effect != 0) {
@@ -2045,7 +2049,8 @@
desc = mSuspendedEffects.valueAt(index);
if (desc->mRefCount <= 0) {
ALOGW("setEffectSuspended_l() restore refcount should not be 0 %d", desc->mRefCount);
- desc->mRefCount = 1;
+ desc->mRefCount = 0;
+ return;
}
if (--desc->mRefCount == 0) {
ALOGV("setEffectSuspended_l() remove entry for %08x", mSuspendedEffects.keyAt(index));
@@ -2123,6 +2128,17 @@
const effect_uuid_t * const SL_IID_VOLUME = &SL_IID_VOLUME_;
#endif //OPENSL_ES_H_
+/* static */
+bool AudioFlinger::EffectChain::isEffectEligibleForBtNrecSuspend(const effect_uuid_t *type)
+{
+ // Only NS and AEC are suspended when BtNRec is off
+ if ((memcmp(type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) ||
+ (memcmp(type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) {
+ return true;
+ }
+ return false;
+}
+
bool AudioFlinger::EffectChain::isEffectEligibleForSuspend(const effect_descriptor_t& desc)
{
// auxiliary effects and visualizer are never suspended on output mix
@@ -2177,7 +2193,7 @@
ALOGV("checkSuspendOnEffectEnabled() enable suspending fx %08x",
effect->desc().type.timeLow);
sp<SuspendedEffectDesc> desc = mSuspendedEffects.valueAt(index);
- // if effect is requested to suspended but was not yet enabled, supend it now.
+ // if effect is requested to suspended but was not yet enabled, suspend it now.
if (desc->mEffect == 0) {
desc->mEffect = effect;
effect->setEnabled(false);
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index e37529e..e29798b 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -331,7 +331,8 @@
void setStrategy(uint32_t strategy)
{ mStrategy = strategy; }
- // suspend effect of the given type
+ // suspend or restore effects of the specified type. The number of suspend requests is counted
+ // and restore occurs once all suspend requests are cancelled.
void setEffectSuspended_l(const effect_uuid_t *type,
bool suspend);
// suspend all eligible effects
@@ -372,7 +373,7 @@
public:
SuspendedEffectDesc() : mRefCount(0) {}
- int mRefCount;
+ int mRefCount; // > 0 when suspended
effect_uuid_t mType;
wp<EffectModule> mEffect;
};
@@ -388,6 +389,8 @@
// types or implementations from the suspend/restore mechanism.
bool isEffectEligibleForSuspend(const effect_descriptor_t& desc);
+ static bool isEffectEligibleForBtNrecSuspend(const effect_uuid_t *type);
+
void clearInputBuffer_l(const sp<ThreadBase>& thread);
void setThread(const sp<ThreadBase>& thread);
@@ -414,6 +417,6 @@
// mSuspendedEffects lists all effects currently suspended in the chain.
// Use effect type UUID timelow field as key. There is no real risk of identical
// timeLow fields among effect type UUIDs.
- // Updated by updateSuspendedSessions_l() only.
+ // Updated by setEffectSuspended_l() and setEffectSuspendedAll_l() only.
KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
};
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d932483..a67acd6 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -991,13 +991,6 @@
ALOGW("power manager service died !!!");
}
-void AudioFlinger::ThreadBase::setEffectSuspended(
- const effect_uuid_t *type, bool suspend, audio_session_t sessionId)
-{
- Mutex::Autolock _l(mLock);
- setEffectSuspended_l(type, suspend, sessionId);
-}
-
void AudioFlinger::ThreadBase::setEffectSuspended_l(
const effect_uuid_t *type, bool suspend, audio_session_t sessionId)
{
@@ -1451,6 +1444,7 @@
effect->setDevice(mInDevice);
effect->setMode(mAudioFlinger->getMode());
effect->setAudioSource(mAudioSource);
+
return NO_ERROR;
}
@@ -5947,6 +5941,7 @@
// mPipeMemory
// mFastCaptureNBLogWriter
, mFastTrackAvail(false)
+ , mBtNrecSuspended(false)
{
snprintf(mThreadName, kThreadNameLength, "AudioIn_%X", id);
mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
@@ -6711,12 +6706,6 @@
}
mTracks.add(track);
- // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
- bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
- mAudioFlinger->btNrecIsOff();
- setEffectSuspended_l(FX_IID_AEC, suspend, sessionId);
- setEffectSuspended_l(FX_IID_NS, suspend, sessionId);
-
if ((*flags & AUDIO_INPUT_FLAG_FAST) && (tid != -1)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
// we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
@@ -7079,6 +7068,26 @@
buffer->frameCount = 0;
}
+void AudioFlinger::RecordThread::checkBtNrec()
+{
+ Mutex::Autolock _l(mLock);
+ checkBtNrec_l();
+}
+
+void AudioFlinger::RecordThread::checkBtNrec_l()
+{
+ // disable AEC and NS if the device is a BT SCO headset supporting those
+ // pre processings
+ bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
+ mAudioFlinger->btNrecIsOff();
+ if (mBtNrecSuspended.exchange(suspend) != suspend) {
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ setEffectSuspended_l(FX_IID_AEC, suspend, mEffectChains[i]->sessionId());
+ setEffectSuspended_l(FX_IID_NS, suspend, mEffectChains[i]->sessionId());
+ }
+ }
+}
+
bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValuePair,
status_t& status)
@@ -7151,17 +7160,7 @@
if (value != AUDIO_DEVICE_NONE) {
mPrevInDevice = value;
}
- // disable AEC and NS if the device is a BT SCO headset supporting those
- // pre processings
- if (mTracks.size() > 0) {
- bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
- mAudioFlinger->btNrecIsOff();
- for (size_t i = 0; i < mTracks.size(); i++) {
- sp<RecordTrack> track = mTracks[i];
- setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
- setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
- }
- }
+ checkBtNrec_l();
}
}
if (param.getInt(String8(AudioParameter::keyInputSource), value) == NO_ERROR &&
@@ -7394,17 +7393,7 @@
mEffectChains[i]->setDevice_l(mInDevice);
}
- // disable AEC and NS if the device is a BT SCO headset supporting those
- // pre processings
- if (mTracks.size() > 0) {
- bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
- mAudioFlinger->btNrecIsOff();
- for (size_t i = 0; i < mTracks.size(); i++) {
- sp<RecordTrack> track = mTracks[i];
- setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
- setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
- }
- }
+ checkBtNrec_l();
// store new source and send to effects
if (mAudioSource != patch->sinks[0].ext.mix.usecase.source) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 65266b0..062bad6 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -361,11 +361,6 @@
virtual uint32_t getStrategyForSession_l(audio_session_t sessionId __unused)
{ return 0; }
- // suspend or restore effect according to the type of effect passed. a NULL
- // type pointer means suspend all effects in the session
- void setEffectSuspended(const effect_uuid_t *type,
- bool suspend,
- audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX);
// check if some effects must be suspended/restored when an effect is enabled
// or disabled
void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
@@ -417,10 +412,13 @@
void releaseWakeLock_l();
void updateWakeLockUids_l(const SortedVector<uid_t> &uids);
void getPowerManager_l();
+ // suspend or restore effects of the specified type (or all if type is NULL)
+ // on a given session. The number of suspend requests is counted and restore
+ // occurs when all suspend requests are cancelled.
void setEffectSuspended_l(const effect_uuid_t *type,
bool suspend,
audio_session_t sessionId);
- // updated mSuspendedSessions when an effect suspended or restored
+ // updated mSuspendedSessions when an effect is suspended or restored
void updateSuspendedSessions_l(const effect_uuid_t *type,
bool suspend,
audio_session_t sessionId);
@@ -484,6 +482,7 @@
const sp<PMDeathRecipient> mDeathRecipient;
// list of suspended effects per session and per type. The first (outer) vector is
// keyed by session ID, the second (inner) by type UUID timeLow field
+ // Updated by updateSuspendedSessions_l() only.
KeyedVector< audio_session_t, KeyedVector< int, sp<SuspendedSessionDesc> > >
mSuspendedSessions;
static const size_t kLogSize = 4 * 1024;
@@ -1387,6 +1386,8 @@
}
virtual bool isOutput() const override { return false; }
+ void checkBtNrec();
+
private:
// Enter standby if not already in standby, and set mStandby flag
void standbyIfNotAlreadyInStandby();
@@ -1394,6 +1395,8 @@
// Call the HAL standby method unconditionally, and don't change mStandby flag
void inputStandBy();
+ void checkBtNrec_l();
+
AudioStreamIn *mInput;
SortedVector < sp<RecordTrack> > mTracks;
// mActiveTracks has dual roles: it indicates the current active track(s), and
@@ -1453,6 +1456,8 @@
sp<NBLog::Writer> mFastCaptureNBLogWriter;
bool mFastTrackAvail; // true if fast track available
+ // common state to all record threads
+ std::atomic_bool mBtNrecSuspended;
};
class MmapThread : public ThreadBase