diff options
Diffstat (limited to 'services/audioflinger')
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 494 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 94 |
2 files changed, 550 insertions, 38 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" diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 80a9945..4fa70a2 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -165,7 +165,7 @@ public: int *id, int *enabled); - virtual status_t moveEffects(int session, int srcOutput, int dstOutput); + virtual status_t moveEffects(int sessionId, int srcOutput, int dstOutput); enum hardware_call_state { AUDIO_HW_IDLE = 0, @@ -206,6 +206,8 @@ public: uint32_t getMode() { return mMode; } + bool btNrec() { return mBtNrec; } + private: AudioFlinger(); virtual ~AudioFlinger(); @@ -477,14 +479,45 @@ private: // strategy is only meaningful for PlaybackThread which implements this method virtual uint32_t getStrategyForSession_l(int sessionId) { 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, + int sessionId = AUDIO_SESSION_OUTPUT_MIX); + // check if some effects must be suspended/restored when an effect is enabled + // or disabled + virtual void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect, + bool enabled, + int sessionId = AUDIO_SESSION_OUTPUT_MIX); + mutable Mutex mLock; protected: + // entry describing an effect being suspended in mSuspendedSessions keyed vector + class SuspendedSessionDesc : public RefBase { + public: + SuspendedSessionDesc() : mRefCount(0) {} + + int mRefCount; // number of active suspend requests + effect_uuid_t mType; // effect type UUID + }; + void acquireWakeLock(); void acquireWakeLock_l(); void releaseWakeLock(); void releaseWakeLock_l(); + void setEffectSuspended_l(const effect_uuid_t *type, + bool suspend, + int sessionId = AUDIO_SESSION_OUTPUT_MIX); + // updated mSuspendedSessions when an effect suspended or restored + void updateSuspendedSessions_l(const effect_uuid_t *type, + bool suspend, + int sessionId); + // check if some effects must be suspended when an effect chain is added + void checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain); + // updated mSuspendedSessions when an effect chain is removed + void updateSuspendedSessionsOnRemoveEffectChain_l(const sp<EffectChain>& chain); friend class Track; friend class TrackBase; @@ -519,6 +552,9 @@ private: sp<IPowerManager> mPowerManager; sp<IBinder> mWakeLockToken; sp<PMDeathRecipient> mDeathRecipient; + // list of suspended effects per session and per type. The first vector is + // keyed by session ID, the second by type UUID timeLow field + KeyedVector< int, KeyedVector< int, sp<SuspendedSessionDesc> > > mSuspendedSessions; }; // --- PlaybackThread --- @@ -849,7 +885,7 @@ private: void audioConfigChanged_l(int event, int ioHandle, void *param2); uint32_t nextUniqueId(); - status_t moveEffectChain_l(int session, + status_t moveEffectChain_l(int sessionId, AudioFlinger::PlaybackThread *srcThread, AudioFlinger::PlaybackThread *dstThread, bool reRegister); @@ -909,6 +945,7 @@ private: bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; } void dump(char* buffer, size_t size); + private: friend class AudioFlinger; friend class RecordThread; @@ -952,8 +989,6 @@ private: AudioStreamIn* clearInput(); virtual audio_stream_t* stream(); - - void setTrack(RecordTrack *recordTrack) { mTrack = recordTrack; } virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer); virtual bool checkForNewParameters_l(); @@ -965,6 +1000,7 @@ private: virtual status_t addEffectChain_l(const sp<EffectChain>& chain); virtual size_t removeEffectChain_l(const sp<EffectChain>& chain); virtual uint32_t hasAudioSession(int sessionId); + RecordTrack* track(); private: RecordThread(); @@ -1061,6 +1097,7 @@ private: int16_t *outBuffer() { return mConfig.outputCfg.buffer.s16; } void setChain(const wp<EffectChain>& chain) { mChain = chain; } void setThread(const wp<ThreadBase>& thread) { mThread = thread; } + wp<ThreadBase>& thread() { return mThread; } status_t addHandle(sp<EffectHandle>& handle); void disconnect(const wp<EffectHandle>& handle); @@ -1073,6 +1110,10 @@ private: status_t setVolume(uint32_t *left, uint32_t *right, bool controller); status_t setMode(uint32_t mode); status_t stop(); + void setSuspended(bool suspended); + bool suspended(); + + sp<EffectHandle> controlHandle(); status_t dump(int fd, const Vector<String16>& args); @@ -1101,6 +1142,7 @@ private: 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 }; // The EffectHandle class implements the IEffect interface. It provides resources @@ -1133,13 +1175,17 @@ private: // Give or take control of effect module - void setControl(bool hasControl, bool signal); + // - hasControl: true if control is given, false if removed + // - signal: true client app should be signaled of change, false otherwise + // - enabled: state of the effect when control is passed + void setControl(bool hasControl, bool signal, bool enabled); void commandExecuted(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData, uint32_t replySize, void *pReplyData); void setEnabled(bool enabled); + bool enabled() { return mEnabled; } // Getters int id() { return mEffect->id(); } @@ -1162,6 +1208,8 @@ private: uint8_t* mBuffer; // pointer to parameter area in shared memory int mPriority; // client application priority to control the effect bool mHasControl; // true if this handle is controlling the effect + bool mEnabled; // cached enable state: needed when the effect is + // restored after being suspended }; // the EffectChain class represents a group of effects associated to one audio session. @@ -1176,6 +1224,10 @@ private: EffectChain(const wp<ThreadBase>& wThread, int sessionId); ~EffectChain(); + // special key used for an entry in mSuspendedEffects keyed vector + // corresponding to a suspend all request. + static const int kKeyForSuspendAll = 0; + void process_l(); void lock() { @@ -1193,6 +1245,7 @@ private: sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor); sp<EffectModule> getEffectFromId_l(int id); + sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type); bool setVolume_l(uint32_t *left, uint32_t *right); void setDevice_l(uint32_t device); void setMode_l(uint32_t mode); @@ -1223,6 +1276,15 @@ private: void setStrategy(uint32_t strategy) { mStrategy = strategy; } + // suspend effect of the given type + void setEffectSuspended_l(const effect_uuid_t *type, + bool suspend); + // suspend all eligible effects + void setEffectSuspendedAll_l(bool suspend); + // check if effects should be suspend or restored when a given effect is enable or disabled + virtual void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect, + bool enabled); + status_t dump(int fd, const Vector<String16>& args); protected: @@ -1230,6 +1292,21 @@ private: EffectChain(const EffectChain&); EffectChain& operator =(const EffectChain&); + class SuspendedEffectDesc : public RefBase { + public: + SuspendedEffectDesc() : mRefCount(0) {} + + int mRefCount; + effect_uuid_t mType; + wp<EffectModule> mEffect; + }; + + // get a list of effect modules to suspend when an effect of the type + // passed is enabled. + Vector< sp<EffectModule> > getSuspendEligibleEffects(); + // get an effect module if it is currently enable + sp<EffectModule> getEffectIfEnabled(const effect_uuid_t *type); + wp<ThreadBase> mThread; // parent mixer thread Mutex mLock; // mutex protecting effect list Vector<sp<EffectModule> > mEffects; // list of effect modules @@ -1245,6 +1322,10 @@ private: uint32_t mNewLeftVolume; // new volume on left channel uint32_t mNewRightVolume; // new volume on right channel uint32_t mStrategy; // strategy for this effect chain + // mSuspendedEffects lists all effect 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. + KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects; }; struct AudioStreamOut { @@ -1285,7 +1366,8 @@ private: DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients; volatile int32_t mNextUniqueId; - uint32_t mMode; + uint32_t mMode; + bool mBtNrec; }; |