diff options
| -rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 445 | ||||
| -rw-r--r-- | services/audioflinger/AudioFlinger.h | 88 | 
2 files changed, 498 insertions, 35 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index ec45530..0dc1eb8 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1130,6 +1130,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, @@ -4874,10 +5008,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, @@ -4915,14 +5045,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 @@ -5003,6 +5125,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)); @@ -5069,10 +5198,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); @@ -5091,24 +5220,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;      } @@ -5143,7 +5272,7 @@ status_t AudioFlinger::moveEffectChain_l(int session,              AudioSystem::registerEffect(&effect->desc(),                                          dstOutput,                                          strategy, -                                        session, +                                        sessionId,                                          effect->id());          }          effect = chain->getEffectFromId_l(0); @@ -5385,6 +5514,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 @@ -5451,6 +5581,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;  } @@ -5463,6 +5594,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) { @@ -5540,6 +5672,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; @@ -5552,6 +5686,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; @@ -5570,7 +5705,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; @@ -5634,14 +5769,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;  } @@ -5657,13 +5795,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*/);          }      } @@ -5677,8 +5823,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); @@ -6139,6 +6298,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; @@ -6235,7 +6405,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); @@ -6258,30 +6429,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; -    return mEffect->setEnabled(false); +    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 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) { @@ -6373,11 +6580,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);      } @@ -6448,7 +6657,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; @@ -6463,7 +6672,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; @@ -6479,6 +6688,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()  { @@ -6773,6 +6998,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 7b6215f..440cd34 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, @@ -477,14 +477,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 +550,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 --- @@ -848,7 +882,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); @@ -908,6 +942,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; @@ -950,8 +985,6 @@ private:                  AudioStreamIn* getInput() { return mInput; }                  virtual audio_stream_t* stream() { return &mInput->stream->common; } - -                void        setTrack(RecordTrack *recordTrack) { mTrack = recordTrack; }          virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer);          virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);          virtual bool        checkForNewParameters_l(); @@ -1059,6 +1092,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); @@ -1071,6 +1105,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); @@ -1099,6 +1137,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 @@ -1131,13 +1170,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(); } @@ -1160,6 +1203,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. @@ -1174,6 +1219,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() { @@ -1191,6 +1240,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); @@ -1221,6 +1271,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: @@ -1228,6 +1287,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 @@ -1243,6 +1317,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 {  | 
