diff options
Diffstat (limited to 'services/audioflinger/AudioFlinger.cpp')
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 494 |
1 files changed, 462 insertions, 32 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index b11ec63..e201b17 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -51,6 +51,8 @@ #include <media/EffectsFactoryApi.h> #include <audio_effects/effect_visualizer.h> +#include <audio_effects/effect_ns.h> +#include <audio_effects/effect_aec.h> #include <cpustats/ThreadCpuUsage.h> #include <powermanager/PowerManager.h> @@ -148,7 +150,8 @@ static const char *audio_interfaces[] = { AudioFlinger::AudioFlinger() : BnAudioFlinger(), - mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1) + mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1), + mBtNrec(false) { } @@ -717,6 +720,31 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs) final_result = result ?: final_result; } mHardwareStatus = AUDIO_HW_IDLE; + // disable AEC and NS if the device is a BT SCO headset supporting those pre processings + AudioParameter param = AudioParameter(keyValuePairs); + String8 value; + if (param.get(String8(AUDIO_PARAMETER_KEY_BT_NREC), value) == NO_ERROR) { + Mutex::Autolock _l(mLock); + bool btNrec = (value == AUDIO_PARAMETER_VALUE_ON); + if (mBtNrec != btNrec) { + for (size_t i = 0; i < mRecordThreads.size(); i++) { + sp<RecordThread> thread = mRecordThreads.valueAt(i); + RecordThread::RecordTrack *track = thread->track(); + if (track != NULL) { + audio_devices_t device = (audio_devices_t)( + thread->device() & AUDIO_DEVICE_IN_ALL); + bool suspend = audio_is_bluetooth_sco_device(device) && btNrec; + thread->setEffectSuspended(FX_IID_AEC, + suspend, + track->sessionId()); + thread->setEffectSuspended(FX_IID_NS, + suspend, + track->sessionId()); + } + } + mBtNrec = btNrec; + } + } return final_result; } @@ -1130,6 +1158,140 @@ void AudioFlinger::ThreadBase::PMDeathRecipient::binderDied(const wp<IBinder>& w LOGW("power manager service died !!!"); } +void AudioFlinger::ThreadBase::setEffectSuspended( + const effect_uuid_t *type, bool suspend, int sessionId) +{ + Mutex::Autolock _l(mLock); + setEffectSuspended_l(type, suspend, sessionId); +} + +void AudioFlinger::ThreadBase::setEffectSuspended_l( + const effect_uuid_t *type, bool suspend, int sessionId) +{ + sp<EffectChain> chain; + chain = getEffectChain_l(sessionId); + if (chain != 0) { + if (type != NULL) { + chain->setEffectSuspended_l(type, suspend); + } else { + chain->setEffectSuspendedAll_l(suspend); + } + } + + updateSuspendedSessions_l(type, suspend, sessionId); +} + +void AudioFlinger::ThreadBase::checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain) +{ + int index = mSuspendedSessions.indexOfKey(chain->sessionId()); + if (index < 0) { + return; + } + + KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects = + mSuspendedSessions.editValueAt(index); + + for (size_t i = 0; i < sessionEffects.size(); i++) { + sp <SuspendedSessionDesc> desc = sessionEffects.valueAt(i); + for (int j = 0; j < desc->mRefCount; j++) { + if (sessionEffects.keyAt(i) == EffectChain::kKeyForSuspendAll) { + chain->setEffectSuspendedAll_l(true); + } else { + LOGV("checkSuspendOnAddEffectChain_l() suspending effects %08x", + desc->mType.timeLow); + chain->setEffectSuspended_l(&desc->mType, true); + } + } + } +} + +void AudioFlinger::ThreadBase::updateSuspendedSessionsOnRemoveEffectChain_l( + const sp<EffectChain>& chain) +{ + int index = mSuspendedSessions.indexOfKey(chain->sessionId()); + if (index < 0) { + return; + } + LOGV("updateSuspendedSessionsOnRemoveEffectChain_l() removed suspended session %d", + chain->sessionId()); + mSuspendedSessions.removeItemsAt(index); +} + +void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *type, + bool suspend, + int sessionId) +{ + int index = mSuspendedSessions.indexOfKey(sessionId); + + KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects; + + if (suspend) { + if (index >= 0) { + sessionEffects = mSuspendedSessions.editValueAt(index); + } else { + mSuspendedSessions.add(sessionId, sessionEffects); + } + } else { + if (index < 0) { + return; + } + sessionEffects = mSuspendedSessions.editValueAt(index); + } + + + int key = EffectChain::kKeyForSuspendAll; + if (type != NULL) { + key = type->timeLow; + } + index = sessionEffects.indexOfKey(key); + + sp <SuspendedSessionDesc> desc; + if (suspend) { + if (index >= 0) { + desc = sessionEffects.valueAt(index); + } else { + desc = new SuspendedSessionDesc(); + if (type != NULL) { + memcpy(&desc->mType, type, sizeof(effect_uuid_t)); + } + sessionEffects.add(key, desc); + LOGV("updateSuspendedSessions_l() suspend adding effect %08x", key); + } + desc->mRefCount++; + } else { + if (index < 0) { + return; + } + desc = sessionEffects.valueAt(index); + if (--desc->mRefCount == 0) { + LOGV("updateSuspendedSessions_l() restore removing effect %08x", key); + sessionEffects.removeItemsAt(index); + if (sessionEffects.isEmpty()) { + LOGV("updateSuspendedSessions_l() restore removing session %d", + sessionId); + mSuspendedSessions.removeItem(sessionId); + } + } + } + if (!sessionEffects.isEmpty()) { + mSuspendedSessions.replaceValueFor(sessionId, sessionEffects); + } +} + +void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect, + bool enabled, + int sessionId) +{ + Mutex::Autolock _l(mLock); + + // TODO: implement PlaybackThread or RecordThread specific behavior here + + sp<EffectChain> chain = getEffectChain_l(sessionId); + if (chain != 0) { + chain->checkSuspendOnEffectEnabled(effect, enabled); + } +} + // ---------------------------------------------------------------------------- AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, @@ -4180,7 +4342,11 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createR } mTrack = track.get(); - + // disable AEC and NS if the device is a BT SCO headset supporting those pre processings + bool suspend = audio_is_bluetooth_sco_device( + (audio_devices_t)(mDevice & AUDIO_DEVICE_IN_ALL)) && mAudioFlinger->btNrec(); + setEffectSuspended_l(FX_IID_AEC, suspend, sessionId); + setEffectSuspended_l(FX_IID_NS, suspend, sessionId); } lStatus = NO_ERROR; @@ -4400,6 +4566,13 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l() status = BAD_VALUE; } else { mDevice &= (uint32_t)~(value & AUDIO_DEVICE_IN_ALL); + // disable AEC and NS if the device is a BT SCO headset supporting those pre processings + if (mTrack != NULL) { + bool suspend = audio_is_bluetooth_sco_device( + (audio_devices_t)value) && mAudioFlinger->btNrec(); + setEffectSuspended_l(FX_IID_AEC, suspend, mTrack->sessionId()); + setEffectSuspended_l(FX_IID_NS, suspend, mTrack->sessionId()); + } } mDevice |= (uint32_t)value; } @@ -4537,6 +4710,12 @@ uint32_t AudioFlinger::RecordThread::hasAudioSession(int sessionId) return result; } +AudioFlinger::RecordThread::RecordTrack* AudioFlinger::RecordThread::track() +{ + Mutex::Autolock _l(mLock); + return mTrack; +} + AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::getInput() { Mutex::Autolock _l(mLock); @@ -4948,10 +5127,6 @@ status_t AudioFlinger::getEffectDescriptor(effect_uuid_t *pUuid, effect_descript } -// this UUID must match the one defined in media/libeffects/EffectVisualizer.cpp -static const effect_uuid_t VISUALIZATION_UUID_ = - {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}; - sp<IEffect> AudioFlinger::createEffect(pid_t pid, effect_descriptor_t *pDesc, const sp<IEffectClient>& effectClient, @@ -4989,14 +5164,6 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, goto Exit; } - // check recording permission for visualizer - if ((memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 || - memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) && - !recordingAllowed()) { - lStatus = PERMISSION_DENIED; - goto Exit; - } - if (io == 0) { if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) { // output must be specified by AudioPolicyManager when using session @@ -5077,6 +5244,13 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, goto Exit; } + // check recording permission for visualizer + if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) && + !recordingAllowed()) { + lStatus = PERMISSION_DENIED; + goto Exit; + } + // return effect descriptor memcpy(pDesc, &desc, sizeof(effect_descriptor_t)); @@ -5143,10 +5317,10 @@ Exit: return handle; } -status_t AudioFlinger::moveEffects(int session, int srcOutput, int dstOutput) +status_t AudioFlinger::moveEffects(int sessionId, int srcOutput, int dstOutput) { LOGV("moveEffects() session %d, srcOutput %d, dstOutput %d", - session, srcOutput, dstOutput); + sessionId, srcOutput, dstOutput); Mutex::Autolock _l(mLock); if (srcOutput == dstOutput) { LOGW("moveEffects() same dst and src outputs %d", dstOutput); @@ -5165,24 +5339,24 @@ status_t AudioFlinger::moveEffects(int session, int srcOutput, int dstOutput) Mutex::Autolock _dl(dstThread->mLock); Mutex::Autolock _sl(srcThread->mLock); - moveEffectChain_l(session, srcThread, dstThread, false); + moveEffectChain_l(sessionId, srcThread, dstThread, false); return NO_ERROR; } // moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held -status_t AudioFlinger::moveEffectChain_l(int session, +status_t AudioFlinger::moveEffectChain_l(int sessionId, AudioFlinger::PlaybackThread *srcThread, AudioFlinger::PlaybackThread *dstThread, bool reRegister) { LOGV("moveEffectChain_l() session %d from thread %p to thread %p", - session, srcThread, dstThread); + sessionId, srcThread, dstThread); - sp<EffectChain> chain = srcThread->getEffectChain_l(session); + sp<EffectChain> chain = srcThread->getEffectChain_l(sessionId); if (chain == 0) { LOGW("moveEffectChain_l() effect chain for session %d not on source thread %p", - session, srcThread); + sessionId, srcThread); return INVALID_OPERATION; } @@ -5217,7 +5391,7 @@ status_t AudioFlinger::moveEffectChain_l(int session, AudioSystem::registerEffect(&effect->desc(), dstOutput, strategy, - session, + sessionId, effect->id()); } effect = chain->getEffectFromId_l(0); @@ -5459,6 +5633,7 @@ void AudioFlinger::ThreadBase::setMode(uint32_t mode) void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect, const wp<EffectHandle>& handle) { + Mutex::Autolock _l(mLock); LOGV("disconnectEffect() %p effect %p", this, effect.get()); // delete the effect module if removing last handle on it @@ -5525,6 +5700,7 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& c if (mEffectChains[i]->sessionId() < session) break; } mEffectChains.insertAt(chain, i); + checkSuspendOnAddEffectChain_l(chain); return NO_ERROR; } @@ -5537,6 +5713,7 @@ size_t AudioFlinger::PlaybackThread::removeEffectChain_l(const sp<EffectChain>& for (size_t i = 0; i < mEffectChains.size(); i++) { if (chain == mEffectChains[i]) { + updateSuspendedSessionsOnRemoveEffectChain_l(chain); mEffectChains.removeAt(i); // detach all active tracks from the chain for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) { @@ -5614,6 +5791,8 @@ status_t AudioFlinger::RecordThread::addEffectChain_l(const sp<EffectChain>& cha chain->setInBuffer(NULL); chain->setOutBuffer(NULL); + checkSuspendOnAddEffectChain_l(chain); + mEffectChains.add(chain); return NO_ERROR; @@ -5626,6 +5805,7 @@ size_t AudioFlinger::RecordThread::removeEffectChain_l(const sp<EffectChain>& ch "removeEffectChain_l() %p invalid chain size %d on thread %p", chain.get(), mEffectChains.size(), this); if (mEffectChains.size() == 1) { + updateSuspendedSessionsOnRemoveEffectChain_l(chain); mEffectChains.removeAt(0); } return 0; @@ -5644,7 +5824,7 @@ AudioFlinger::EffectModule::EffectModule(const wp<ThreadBase>& wThread, int id, int sessionId) : mThread(wThread), mChain(chain), mId(id), mSessionId(sessionId), mEffectInterface(NULL), - mStatus(NO_INIT), mState(IDLE) + mStatus(NO_INIT), mState(IDLE), mSuspended(false) { LOGV("Constructor %p", this); int lStatus; @@ -5711,14 +5891,17 @@ status_t AudioFlinger::EffectModule::addHandle(sp<EffectHandle>& handle) } // if inserted in first place, move effect control from previous owner to this handle if (i == 0) { + bool enabled = false; if (h != 0) { - h->setControl(false, true); + enabled = h->enabled(); + h->setControl(false/*hasControl*/, true /*signal*/, enabled /*enabled*/); } - handle->setControl(true, false); + handle->setControl(true /*hasControl*/, false /*signal*/, enabled /*enabled*/); status = NO_ERROR; } else { status = ALREADY_EXISTS; } + LOGV("addHandle() %p added handle %p in position %d", this, handle.get(), i); mHandles.insertAt(handle, i); return status; } @@ -5734,13 +5917,21 @@ size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle) if (i == size) { return size; } + LOGV("removeHandle() %p removed handle %p in position %d", this, handle.unsafe_get(), i); + + bool enabled = false; + EffectHandle *hdl = handle.unsafe_get(); + if (hdl) { + LOGV("removeHandle() unsafe_get OK"); + enabled = hdl->enabled(); + } mHandles.removeAt(i); size = mHandles.size(); // if removed from first place, move effect control from this handle to next in line if (i == 0 && size != 0) { sp<EffectHandle> h = mHandles[0].promote(); if (h != 0) { - h->setControl(true, true); + h->setControl(true /*hasControl*/, true /*signal*/ , enabled /*enabled*/); } } @@ -5754,8 +5945,21 @@ size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle) return size; } +sp<AudioFlinger::EffectHandle> AudioFlinger::EffectModule::controlHandle() +{ + Mutex::Autolock _l(mLock); + sp<EffectHandle> handle; + if (mHandles.size() != 0) { + handle = mHandles[0].promote(); + } + return handle; +} + + + void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle) { + LOGV("disconnect() %p handle %p ", this, handle.unsafe_get()); // keep a strong reference on this EffectModule to avoid calling the // destructor before we exit sp<EffectModule> keep(this); @@ -6222,6 +6426,17 @@ status_t AudioFlinger::EffectModule::setMode(uint32_t mode) return status; } +void AudioFlinger::EffectModule::setSuspended(bool suspended) +{ + Mutex::Autolock _l(mLock); + mSuspended = suspended; +} +bool AudioFlinger::EffectModule::suspended() +{ + Mutex::Autolock _l(mLock); + return mSuspended; +} + status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args) { const size_t SIZE = 256; @@ -6318,7 +6533,8 @@ AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect, const sp<IEffectClient>& effectClient, int32_t priority) : BnEffect(), - mEffect(effect), mEffectClient(effectClient), mClient(client), mPriority(priority), mHasControl(false) + mEffect(effect), mEffectClient(effectClient), mClient(client), + mPriority(priority), mHasControl(false), mEnabled(false) { LOGV("constructor %p", this); @@ -6341,30 +6557,66 @@ AudioFlinger::EffectHandle::~EffectHandle() { LOGV("Destructor %p", this); disconnect(); + LOGV("Destructor DONE %p", this); } status_t AudioFlinger::EffectHandle::enable() { + LOGV("enable %p", this); if (!mHasControl) return INVALID_OPERATION; if (mEffect == 0) return DEAD_OBJECT; + mEnabled = true; + + sp<ThreadBase> thread = mEffect->thread().promote(); + if (thread != 0) { + thread->checkSuspendOnEffectEnabled(mEffect, true, mEffect->sessionId()); + } + + // checkSuspendOnEffectEnabled() can suspend this same effect when enabled + if (mEffect->suspended()) { + return NO_ERROR; + } + return mEffect->setEnabled(true); } status_t AudioFlinger::EffectHandle::disable() { + LOGV("disable %p", this); if (!mHasControl) return INVALID_OPERATION; - if (mEffect == NULL) return DEAD_OBJECT; + if (mEffect == 0) return DEAD_OBJECT; + + mEnabled = false; + + if (mEffect->suspended()) { + return NO_ERROR; + } + + status_t status = mEffect->setEnabled(false); + + sp<ThreadBase> thread = mEffect->thread().promote(); + if (thread != 0) { + thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId()); + } - return mEffect->setEnabled(false); + return status; } void AudioFlinger::EffectHandle::disconnect() { + LOGV("disconnect %p", this); if (mEffect == 0) { return; } + mEffect->disconnect(this); + + sp<ThreadBase> thread = mEffect->thread().promote(); + if (thread != 0) { + thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId()); + } + // release sp on module => module destructor can be called now mEffect.clear(); if (mCblk) { @@ -6456,11 +6708,13 @@ sp<IMemory> AudioFlinger::EffectHandle::getCblk() const { return mCblkMemory; } -void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal) +void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal, bool enabled) { LOGV("setControl %p control %d", this, hasControl); mHasControl = hasControl; + mEnabled = enabled; + if (signal && mEffectClient != 0) { mEffectClient->controlStatusChanged(hasControl); } @@ -6531,7 +6785,7 @@ AudioFlinger::EffectChain::~EffectChain() } -// getEffectFromDesc_l() must be called with PlaybackThread::mLock held +// getEffectFromDesc_l() must be called with ThreadBase::mLock held sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromDesc_l(effect_descriptor_t *descriptor) { sp<EffectModule> effect; @@ -6546,7 +6800,7 @@ sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromDesc_l(ef return effect; } -// getEffectFromId_l() must be called with PlaybackThread::mLock held +// getEffectFromId_l() must be called with ThreadBase::mLock held sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int id) { sp<EffectModule> effect; @@ -6562,6 +6816,22 @@ sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int return effect; } +// getEffectFromType_l() must be called with ThreadBase::mLock held +sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromType_l( + const effect_uuid_t *type) +{ + sp<EffectModule> effect; + size_t size = mEffects.size(); + + for (size_t i = 0; i < size; i++) { + if (memcmp(&mEffects[i]->desc().type, type, sizeof(effect_uuid_t)) == 0) { + effect = mEffects[i]; + break; + } + } + return effect; +} + // Must be called with EffectChain::mLock locked void AudioFlinger::EffectChain::process_l() { @@ -6856,6 +7126,166 @@ status_t AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args) return NO_ERROR; } +// must be called with ThreadBase::mLock held +void AudioFlinger::EffectChain::setEffectSuspended_l( + const effect_uuid_t *type, bool suspend) +{ + sp<SuspendedEffectDesc> desc; + // use effect type UUID timelow as key as there is no real risk of identical + // timeLow fields among effect type UUIDs. + int index = mSuspendedEffects.indexOfKey(type->timeLow); + if (suspend) { + if (index >= 0) { + desc = mSuspendedEffects.valueAt(index); + } else { + desc = new SuspendedEffectDesc(); + memcpy(&desc->mType, type, sizeof(effect_uuid_t)); + mSuspendedEffects.add(type->timeLow, desc); + LOGV("setEffectSuspended_l() add entry for %08x", type->timeLow); + } + if (desc->mRefCount++ == 0) { + sp<EffectModule> effect = getEffectIfEnabled(type); + if (effect != 0) { + desc->mEffect = effect; + effect->setSuspended(true); + effect->setEnabled(false); + } + } + } else { + if (index < 0) { + return; + } + desc = mSuspendedEffects.valueAt(index); + if (desc->mRefCount <= 0) { + LOGW("setEffectSuspended_l() restore refcount should not be 0 %d", desc->mRefCount); + desc->mRefCount = 1; + } + if (--desc->mRefCount == 0) { + LOGV("setEffectSuspended_l() remove entry for %08x", mSuspendedEffects.keyAt(index)); + if (desc->mEffect != 0) { + sp<EffectModule> effect = desc->mEffect.promote(); + if (effect != 0) { + effect->setSuspended(false); + sp<EffectHandle> handle = effect->controlHandle(); + if (handle != 0) { + effect->setEnabled(handle->enabled()); + } + } + desc->mEffect.clear(); + } + mSuspendedEffects.removeItemsAt(index); + } + } +} + +// must be called with ThreadBase::mLock held +void AudioFlinger::EffectChain::setEffectSuspendedAll_l(bool suspend) +{ + sp<SuspendedEffectDesc> desc; + + int index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll); + if (suspend) { + if (index >= 0) { + desc = mSuspendedEffects.valueAt(index); + } else { + desc = new SuspendedEffectDesc(); + mSuspendedEffects.add((int)kKeyForSuspendAll, desc); + LOGV("setEffectSuspendedAll_l() add entry for 0"); + } + if (desc->mRefCount++ == 0) { + Vector< sp<EffectModule> > effects = getSuspendEligibleEffects(); + for (size_t i = 0; i < effects.size(); i++) { + setEffectSuspended_l(&effects[i]->desc().type, true); + } + } + } else { + if (index < 0) { + return; + } + desc = mSuspendedEffects.valueAt(index); + if (desc->mRefCount <= 0) { + LOGW("setEffectSuspendedAll_l() restore refcount should not be 0 %d", desc->mRefCount); + desc->mRefCount = 1; + } + if (--desc->mRefCount == 0) { + Vector<const effect_uuid_t *> types; + for (size_t i = 0; i < mSuspendedEffects.size(); i++) { + if (mSuspendedEffects.keyAt(i) == (int)kKeyForSuspendAll) { + continue; + } + types.add(&mSuspendedEffects.valueAt(i)->mType); + } + for (size_t i = 0; i < types.size(); i++) { + setEffectSuspended_l(types[i], false); + } + LOGV("setEffectSuspendedAll_l() remove entry for %08x", mSuspendedEffects.keyAt(index)); + mSuspendedEffects.removeItem((int)kKeyForSuspendAll); + } + } +} + +Vector< sp<AudioFlinger::EffectModule> > AudioFlinger::EffectChain::getSuspendEligibleEffects() +{ + Vector< sp<EffectModule> > effects; + for (size_t i = 0; i < mEffects.size(); i++) { + effect_descriptor_t desc = mEffects[i]->desc(); + // auxiliary effects and vizualizer are never suspended on output mix + if ((mSessionId == AUDIO_SESSION_OUTPUT_MIX) && ( + ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) || + (memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0))) { + continue; + } + effects.add(mEffects[i]); + } + return effects; +} + +sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectIfEnabled( + const effect_uuid_t *type) +{ + sp<EffectModule> effect; + effect = getEffectFromType_l(type); + if (effect != 0 && !effect->isEnabled()) { + effect.clear(); + } + return effect; +} + +void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect, + bool enabled) +{ + int index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow); + if (enabled) { + if (index < 0) { + // if the effect is not suspend check if all effects are suspended + index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll); + if (index < 0) { + return; + } + setEffectSuspended_l(&effect->desc().type, enabled); + index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow); + } + LOGV("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 (desc->mEffect == 0) { + desc->mEffect = effect; + effect->setEnabled(false); + effect->setSuspended(true); + } + } else { + if (index < 0) { + return; + } + LOGV("checkSuspendOnEffectEnabled() disable restoring fx %08x", + effect->desc().type.timeLow); + sp<SuspendedEffectDesc> desc = mSuspendedEffects.valueAt(index); + desc->mEffect.clear(); + effect->setSuspended(false); + } +} + #undef LOG_TAG #define LOG_TAG "AudioFlinger" |