Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6752ec80 authored by Eric Laurent's avatar Eric Laurent
Browse files

Audio effects: track CPU and memory use separately

Before this change, CPU and memory usage for an audio effect were
registered and checked against the limit by audio policy manager
upon effect instantiation. Even if an effect was not enabled
it would prevent another effect to be created if the CPU load budget
was exceeded, which was too restrictive.

This change adds a method to register/unregister CPU load only when
an effect is enabled or disabled.
It also adds a mechanism to place all effects on the global output mix
in suspend state (disabled) when an effect is enabled on a specific session.
This will allow applications using session effects to have the priority
over others using global effects.

Also fixes some issues with suspend/restore mechanism:
- avoid taking actions when an effect is disconnected and was not enabled.
- do not remove a session from the suspended sessions list when corresponding
effect chain is destroyed.

Change-Id: I5225278aba1ae13d0d0997bfe26a0c9fb46b17d3
parent 246ae501
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -183,6 +183,7 @@ public:
                                    int session,
                                    int id);
    static status_t unregisterEffect(int id);
    static status_t setEffectEnabled(int id, bool enabled);

    static const sp<IAudioPolicyService>& get_audio_policy_service();

+1 −0
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ public:
                                    int session,
                                    int id) = 0;
    virtual status_t unregisterEffect(int id) = 0;
    virtual status_t setEffectEnabled(int id, bool enabled) = 0;
    virtual bool     isStreamActive(int stream, uint32_t inPastMs = 0) const = 0;
    virtual status_t queryDefaultPreProcessing(int audioSession,
                                              effect_descriptor_t *descriptors,
+7 −0
Original line number Diff line number Diff line
@@ -710,6 +710,13 @@ status_t AudioSystem::unregisterEffect(int id)
    return aps->unregisterEffect(id);
}

status_t AudioSystem::setEffectEnabled(int id, bool enabled)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    if (aps == 0) return PERMISSION_DENIED;
    return aps->setEffectEnabled(id, enabled);
}

status_t AudioSystem::isStreamActive(int stream, bool* state, uint32_t inPastMs)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+20 −1
Original line number Diff line number Diff line
@@ -53,7 +53,8 @@ enum {
    UNREGISTER_EFFECT,
    IS_STREAM_ACTIVE,
    GET_DEVICES_FOR_STREAM,
    QUERY_DEFAULT_PRE_PROCESSING
    QUERY_DEFAULT_PRE_PROCESSING,
    SET_EFFECT_ENABLED
};

class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
@@ -313,6 +314,16 @@ public:
        return static_cast <status_t> (reply.readInt32());
    }

    virtual status_t setEffectEnabled(int id, bool enabled)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
        data.writeInt32(id);
        data.writeInt32(enabled);
        remote()->transact(SET_EFFECT_ENABLED, data, &reply);
        return static_cast <status_t> (reply.readInt32());
    }

    virtual bool isStreamActive(int stream, uint32_t inPastMs) const
    {
        Parcel data, reply;
@@ -577,6 +588,14 @@ status_t BnAudioPolicyService::onTransact(
            return NO_ERROR;
        } break;

        case SET_EFFECT_ENABLED: {
            CHECK_INTERFACE(IAudioPolicyService, data, reply);
            int id = data.readInt32();
            bool enabled = static_cast <bool>(data.readInt32());
            reply->writeInt32(static_cast <int32_t>(setEffectEnabled(id, enabled)));
            return NO_ERROR;
        } break;

        case IS_STREAM_ACTIVE: {
            CHECK_INTERFACE(IAudioPolicyService, data, reply);
            int stream = data.readInt32();
+53 −24
Original line number Diff line number Diff line
@@ -1232,18 +1232,6 @@ void AudioFlinger::ThreadBase::checkSuspendOnAddEffectChain_l(const sp<EffectCha
    }
}

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)
@@ -1311,7 +1299,14 @@ void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(const sp<EffectModule
{
    Mutex::Autolock _l(mLock);

    // TODO: implement PlaybackThread or RecordThread specific behavior here
    if (mType != RECORD) {
        // suspend all effects in AUDIO_SESSION_OUTPUT_MIX when enabling any effect on
        // another session. This gives the priority to well behaved effect control panels
        // and applications not using global effects.
        if (sessionId != AUDIO_SESSION_OUTPUT_MIX) {
            setEffectSuspended_l(NULL, enabled, AUDIO_SESSION_OUTPUT_MIX);
        }
    }

    sp<EffectChain> chain = getEffectChain_l(sessionId);
    if (chain != 0) {
@@ -5847,7 +5842,6 @@ 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) {
@@ -5939,7 +5933,6 @@ 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;
@@ -6393,10 +6386,16 @@ status_t AudioFlinger::EffectModule::command(uint32_t cmdCode,

status_t AudioFlinger::EffectModule::setEnabled(bool enabled)
{

    Mutex::Autolock _l(mLock);
    LOGV("setEnabled %p enabled %d", this, enabled);

    if (enabled != isEnabled()) {
        status_t status = AudioSystem::setEffectEnabled(mId, enabled);
        if (enabled && status != NO_ERROR) {
            return status;
        }

        switch (mState) {
        // going from disabled to enabled
        case IDLE:
@@ -6704,6 +6703,10 @@ status_t AudioFlinger::EffectHandle::enable()
    if (!mHasControl) return INVALID_OPERATION;
    if (mEffect == 0) return DEAD_OBJECT;

    if (mEnabled) {
        return NO_ERROR;
    }

    mEnabled = true;

    sp<ThreadBase> thread = mEffect->thread().promote();
@@ -6716,7 +6719,14 @@ status_t AudioFlinger::EffectHandle::enable()
        return NO_ERROR;
    }

    return mEffect->setEnabled(true);
    status_t status = mEffect->setEnabled(true);
    if (status != NO_ERROR) {
        if (thread != 0) {
            thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
        }
        mEnabled = false;
    }
    return status;
}

status_t AudioFlinger::EffectHandle::disable()
@@ -6725,6 +6735,9 @@ status_t AudioFlinger::EffectHandle::disable()
    if (!mHasControl) return INVALID_OPERATION;
    if (mEffect == 0) return DEAD_OBJECT;

    if (!mEnabled) {
        return NO_ERROR;
    }
    mEnabled = false;

    if (mEffect->suspended()) {
@@ -6754,10 +6767,12 @@ void AudioFlinger::EffectHandle::disconnect(bool unpiniflast)
    }
    mEffect->disconnect(this, unpiniflast);

    if (mEnabled) {
        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();
@@ -7367,15 +7382,22 @@ void AudioFlinger::EffectChain::setEffectSuspendedAll_l(bool suspend)
    }
}

bool AudioFlinger::EffectChain::isEffectEligibleForSuspend(const effect_descriptor_t& desc)
{
    // auxiliary effects and visualizer 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))) {
        return false;
    }
    return true;
}

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))) {
        if (!isEffectEligibleForSuspend(mEffects[i]->desc())) {
            continue;
        }
        effects.add(mEffects[i]);
@@ -7405,8 +7427,15 @@ void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModul
            if (index < 0) {
                return;
            }
            if (!isEffectEligibleForSuspend(effect->desc())) {
                return;
            }
            setEffectSuspended_l(&effect->desc().type, enabled);
            index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
            if (index < 0) {
                LOGW("checkSuspendOnEffectEnabled() Fx should be suspended here!");
                return;
            }
        }
        LOGV("checkSuspendOnEffectEnabled() enable suspending fx %08x",
             effect->desc().type.timeLow);
Loading