audio_utils::lock_guard _l(mutex()); const sp threadBase = getEffectThread_l(AUDIO_SESSION_OUTPUT_MIX, EffectId); const sp thread = threadBase ? threadBase->asIAfPlaybackThread() : nullptr; if (EffectId != 0 && thread != 0 && dstThread != thread.get()) { audio_utils::scoped_lock _ll(dstThread->mutex(), thread->mutex()); sp srcChain = thread->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX); sp dstChain; if (srcChain == 0) { return INVALID_OPERATION; } sp effect = srcChain->getEffectFromId_l(EffectId); if (effect == 0) { return INVALID_OPERATION; } thread->removeEffect_l(effect); status = dstThread->addEffect_ll(effect); if (status != NO_ERROR) { thread->addEffect_ll(effect); status = INVALID_OPERATION; goto Exit; } dstChain = effect->getCallback()->chain().promote(); if (dstChain == 0) { thread->addEffect_ll(effect); status = INVALID_OPERATION; } Exit: // removeEffect_l() has stopped the effect if it was active so it must be restarted if (effect->state() == IAfEffectModule::ACTIVE || effect->state() == IAfEffectModule::STOPPING) { effect->start_l(); } } if (status == NO_ERROR && srcThread != nullptr) { *srcThread = thread; } return status; } bool AudioFlinger::isNonOffloadableGlobalEffectEnabled_l() const { for (const auto& [_, thread] : mPlaybackThreads) { audio_utils::lock_guard l(thread->mutex()); const sp ec = thread->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX); if (ec != 0 && ec->isNonOffloadableEnabled()) { return true; } } return false; } void AudioFlinger::onNonOffloadableGlobalEffectEnable() { audio_utils::lock_guard _l(mutex()); for (const auto& [_, thread] : mPlaybackThreads) { if (thread->type() == IAfThreadBase::OFFLOAD) { // we could invalidate based on session id, but offload threads // are based on single client access, so we invalidate everything. thread->invalidateTracks(); } } } status_t AudioFlinger::putOrphanEffectChain_l(const sp& 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(); ALOGV("%s: session %d", __func__, session); if (auto it = mOrphanEffectChains.find(session); it != mOrphanEffectChains.end()) { ALOGW("%s: chain for session %d already present", __func__, session); return ALREADY_EXISTS; } mOrphanEffectChains[session] = chain; return NO_ERROR; } sp AudioFlinger::getOrphanEffectChain_l(audio_session_t session) { ALOGV("%s: session %d", __func__, session); if (auto it = mOrphanEffectChains.find(session); it != mOrphanEffectChains.end()) { sp chain = it->second; mOrphanEffectChains.erase(it); return chain; } else { return {}; } } bool AudioFlinger::updateOrphanEffectChains(const sp& effect) { audio_utils::lock_guard _l(mutex()); return updateOrphanEffectChains_l(effect); } bool AudioFlinger::updateOrphanEffectChains_l(const sp& effect) { audio_session_t session = effect->sessionId(); ALOGV("%s: session %d", __func__, session);