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

Commit 1b4753ec authored by François Gaffie's avatar François Gaffie Committed by Eric Laurent
Browse files

audiopolicy: effects: preprocessing session not attached on right input



Bug: 267799634
Test: make

When an audio record is using a preferred device, and when it attaches
an effect to its session, the effect may not be attached to the right input.

Change-Id: I9e80cfde000a8a46fd21b19c4588c631f8512e3a
Signed-off-by: default avatarFrançois Gaffie <francois.gaffie@renault.com>
parent a2e985ba
Loading
Loading
Loading
Loading
+118 −12
Original line number Diff line number Diff line
@@ -2226,6 +2226,9 @@ void AudioFlinger::removeNotificationClient(pid_t pid)
        }
        if (removed) {
            removedEffects = purgeStaleEffects_l();
            std::vector< sp<IAfEffectModule> > removedOrphanEffects = purgeOrphanEffectChains_l();
            removedEffects.insert(removedEffects.end(), removedOrphanEffects.begin(),
                    removedOrphanEffects.end());
        }
    }
    for (auto& effect : removedEffects) {
@@ -3716,6 +3719,42 @@ std::vector<sp<IAfEffectModule>> AudioFlinger::purgeStaleEffects_l() {
    return removedEffects;
}

std::vector< sp<IAfEffectModule> > AudioFlinger::purgeOrphanEffectChains_l()
{
    ALOGV("purging stale effects from orphan chains");
    std::vector< sp<IAfEffectModule> > removedEffects;
    for (size_t index = 0; index < mOrphanEffectChains.size(); index++) {
        sp<IAfEffectChain> chain = mOrphanEffectChains.valueAt(index);
        audio_session_t session = mOrphanEffectChains.keyAt(index);
        if (session == AUDIO_SESSION_OUTPUT_MIX || session == AUDIO_SESSION_DEVICE
                || session == AUDIO_SESSION_OUTPUT_STAGE) {
            continue;
        }
        size_t numSessionRefs = mAudioSessionRefs.size();
        bool found = false;
        for (size_t k = 0; k < numSessionRefs; k++) {
            AudioSessionRef *ref = mAudioSessionRefs.itemAt(k);
            if (ref->mSessionid == session) {
                ALOGV(" session %d still exists for %d with %d refs", session, ref->mPid,
                        ref->mCnt);
                found = true;
                break;
            }
        }
        if (!found) {
            for (size_t i = 0; i < chain->numberOfEffects(); i++) {
                sp<IAfEffectModule> effect = chain->getEffectModule(i);
                removedEffects.push_back(effect);
            }
        }
    }
    for (auto& effect : removedEffects) {
        effect->unPin();
        updateOrphanEffectChains_l(effect);
    }
    return removedEffects;
}

// dumpToThreadLog_l() must be called with AudioFlinger::mLock held
void AudioFlinger::dumpToThreadLog_l(const sp<ThreadBase> &thread)
{
@@ -4449,24 +4488,42 @@ Exit:
    return lStatus;
}

status_t AudioFlinger::moveEffects(audio_session_t sessionId, audio_io_handle_t srcOutput,
        audio_io_handle_t dstOutput)
status_t AudioFlinger::moveEffects(audio_session_t sessionId, audio_io_handle_t srcIo,
        audio_io_handle_t dstIo)
NO_THREAD_SAFETY_ANALYSIS
{
    ALOGV("moveEffects() session %d, srcOutput %d, dstOutput %d",
            sessionId, srcOutput, dstOutput);
    ALOGV("%s() session %d, srcIo %d, dstIo %d", __func__, sessionId, srcIo, dstIo);
    Mutex::Autolock _l(mLock);
    if (srcOutput == dstOutput) {
        ALOGW("moveEffects() same dst and src outputs %d", dstOutput);
    if (srcIo == dstIo) {
        ALOGW("%s() same dst and src outputs %d", __func__, dstIo);
        return NO_ERROR;
    }
    PlaybackThread *srcThread = checkPlaybackThread_l(srcOutput);
    if (srcThread == NULL) {
        ALOGW("moveEffects() bad srcOutput %d", srcOutput);
    RecordThread *srcRecordThread = checkRecordThread_l(srcIo);
    RecordThread *dstRecordThread = checkRecordThread_l(dstIo);
    if (srcRecordThread != nullptr || dstRecordThread != nullptr) {
        if (srcRecordThread != nullptr) {
            srcRecordThread->mLock.lock();
        }
        if (dstRecordThread != nullptr) {
            dstRecordThread->mLock.lock();
        }
        status_t ret = moveEffectChain_l(sessionId, srcRecordThread, dstRecordThread);
        if (srcRecordThread != nullptr) {
            srcRecordThread->mLock.unlock();
        }
        if (dstRecordThread != nullptr) {
            dstRecordThread->mLock.unlock();
        }
        return ret;
    }
    PlaybackThread *srcThread = checkPlaybackThread_l(srcIo);
    if (srcThread == nullptr) {
        ALOGW("%s() bad srcIo %d", __func__, srcIo);
        return BAD_VALUE;
    }
    PlaybackThread *dstThread = checkPlaybackThread_l(dstOutput);
    if (dstThread == NULL) {
        ALOGW("moveEffects() bad dstOutput %d", dstOutput);
    PlaybackThread *dstThread = checkPlaybackThread_l(dstIo);
    if (dstThread == nullptr) {
        ALOGW("%s() bad dstIo %d", __func__, dstIo);
        return BAD_VALUE;
    }

@@ -4604,6 +4661,50 @@ NO_THREAD_SAFETY_ANALYSIS // requires srcThread and dstThread locks
    return status;
}


// moveEffectChain_l must be called with both srcThread (if not null) and dstThread (if not null)
// mLocks held
status_t AudioFlinger::moveEffectChain_l(audio_session_t sessionId,
                                         RecordThread *srcThread,
                                         RecordThread *dstThread)
NO_THREAD_SAFETY_ANALYSIS // requires srcThread and dstThread locks
{
    sp<IAfEffectChain> chain = nullptr;
    if (srcThread != 0) {
        Vector< sp<IAfEffectChain> > effectChains = srcThread->getEffectChains_l();
        for (size_t i = 0; i < effectChains.size(); i ++) {
             if (effectChains[i]->sessionId() == sessionId) {
                 chain = effectChains[i];
                 break;
             }
        }
        ALOGV_IF(effectChains.size() == 0, "%s: no effect chain on io=%d", __func__,
                srcThread->id());
        if (chain == nullptr) {
            ALOGE("%s wrong session id %d", __func__, sessionId);
            return BAD_VALUE;
        }
        ALOGV("%s: removing effect chain for session=%d io=%d", __func__, sessionId,
                srcThread->id());
        srcThread->removeEffectChain_l(chain);
    } else {
        chain = getOrphanEffectChain_l(sessionId);
        if (chain == nullptr) {
            ALOGE("%s: no orphan effect chain found for session=%d", __func__, sessionId);
            return BAD_VALUE;
        }
    }
    if (dstThread != 0) {
        ALOGV("%s: adding effect chain for session=%d on io=%d", __func__, sessionId,
                dstThread->id());
        dstThread->addEffectChain_l(chain);
        return NO_ERROR;
    }
    ALOGV("%s: parking to orphan effect chain for session=%d", __func__, sessionId);
    putOrphanEffectChain_l(chain);
    return NO_ERROR;
}

status_t AudioFlinger::moveAuxEffectToIo(int EffectId,
                                         const sp<PlaybackThread>& dstThread,
                                         sp<PlaybackThread> *srcThread)
@@ -4720,6 +4821,11 @@ sp<IAfEffectChain> AudioFlinger::getOrphanEffectChain_l(audio_session_t session)
bool AudioFlinger::updateOrphanEffectChains(const sp<IAfEffectModule>& effect)
{
    Mutex::Autolock _l(mLock);
    return updateOrphanEffectChains_l(effect);
}

bool AudioFlinger::updateOrphanEffectChains_l(const sp<IAfEffectModule>& effect)
{
    audio_session_t session = effect->sessionId();
    ssize_t index = mOrphanEffectChains.indexOfKey(session);
    ALOGV("updateOrphanEffectChains session %d index %zd", session, index);
+6 −0
Original line number Diff line number Diff line
@@ -791,6 +791,9 @@ private:
              status_t moveEffectChain_l(audio_session_t sessionId,
                                     PlaybackThread *srcThread,
                                     PlaybackThread *dstThread);
              status_t moveEffectChain_l(audio_session_t sessionId,
                                         RecordThread *srcThread,
                                         RecordThread *dstThread);

              status_t moveAuxEffectToIo(int EffectId,
                                         const sp<PlaybackThread>& dstThread,
@@ -840,6 +843,9 @@ public:
private:
                std::vector< sp<IAfEffectModule> > purgeStaleEffects_l();

                std::vector< sp<IAfEffectModule> > purgeOrphanEffectChains_l();
                bool updateOrphanEffectChains_l(const sp<IAfEffectModule>& effect);

                void broadcastParametersToRecordThreads_l(const String8& keyValuePairs);
                void updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices);
                void forwardParametersToDownstreamPatches_l(
+24 −2
Original line number Diff line number Diff line
@@ -25,6 +25,10 @@

namespace android {

class AudioInputCollection;
class AudioInputDescriptor;
class AudioPolicyClientInterface;

class EffectDescriptor : public RefBase
{
public:
@@ -40,6 +44,8 @@ public:

    int mId;                   // effect unique ID
    audio_io_handle_t mIo;     // io the effect is attached to
    bool mIsOrphan = false;    // on creation, effect is not yet attached but not yet orphan
    bool mEnabledWhenMoved = false;    // Backup enabled state before being moved
    audio_session_t mSession;  // audio session the effect is on
    effect_descriptor_t mDesc; // effect descriptor
    bool mEnabled;             // enabled state: CPU load being used or not
@@ -69,12 +75,28 @@ public:

    void moveEffects(audio_session_t session,
                     audio_io_handle_t srcOutput,
                     audio_io_handle_t dstOutput);
                     audio_io_handle_t dstOutput,
                     AudioPolicyClientInterface *clientInterface);
    void moveEffects(const std::vector<int>& ids, audio_io_handle_t dstOutput);
    void moveEffects(audio_session_t sessionId, audio_io_handle_t srcIo, audio_io_handle_t dstIo,
            const AudioInputCollection *inputs, AudioPolicyClientInterface *clientInterface);
    void moveEffectsForIo(audio_session_t sessionId, audio_io_handle_t dstIo,
            const AudioInputCollection *inputs, AudioPolicyClientInterface *mClientInterface);
    void putOrphanEffects(audio_session_t sessionId, audio_io_handle_t srcIo,
            const AudioInputCollection *inputs, AudioPolicyClientInterface *clientInterface);

    /**
     * @brief Checks if an effect session was already attached to an io handle and return it if
     * found. Check only for a given effect type if effectType is not null or for any effect
     * otherwise.
     * @param sessionId to consider.
     * @param effectType to consider.
     * @return ioHandle if found, AUDIO_IO_HANDLE_NONE otherwise.
     */
    audio_io_handle_t getIoForSession(audio_session_t sessionId,
                                      const effect_uuid_t *effectType = nullptr);

    bool hasOrphansForSession(audio_session_t sessionId);
    EffectDescriptorCollection getOrphanEffectsForSession(audio_session_t sessionId) const;
    void dump(String8 *dst, int spaces = 0, bool verbose = true) const;

private:
+105 −11
Original line number Diff line number Diff line
@@ -18,9 +18,15 @@
//#define LOG_NDEBUG 0

#include <android-base/stringprintf.h>

#include "AudioInputDescriptor.h"
#include "EffectDescriptor.h"
#include <utils/String8.h>

#include <AudioPolicyInterface.h>
#include "AudioPolicyMix.h"
#include "HwModule.h"

namespace android {

void EffectDescriptor::dump(String8 *dst, int spaces) const
@@ -175,30 +181,57 @@ uint32_t EffectDescriptorCollection::getMaxEffectsMemory() const
    return MAX_EFFECTS_MEMORY;
}

void EffectDescriptorCollection::moveEffects(audio_session_t session,
                                             audio_io_handle_t srcOutput,
                                             audio_io_handle_t dstOutput)
void EffectDescriptorCollection::moveEffects(audio_session_t sessionId, audio_io_handle_t srcIo,
                                             audio_io_handle_t dstIo,
                                             AudioPolicyClientInterface *clientInterface)
{
    ALOGV("%s session %d srcOutput %d dstOutput %d", __func__, session, srcOutput, dstOutput);
    ALOGV("%s session %d srcIo %d dstIo %d", __func__, sessionId, srcIo, dstIo);
    for (size_t i = 0; i < size(); i++) {
        sp<EffectDescriptor> effect = valueAt(i);
        if (effect->mSession == session && effect->mIo == srcOutput) {
            effect->mIo = dstOutput;
        if (effect->mSession == sessionId && effect->mIo == srcIo) {
            effect->mIo = dstIo;
            // Backup enable state before any updatePolicyState call
            effect->mIsOrphan = (dstIo == AUDIO_IO_HANDLE_NONE);
        }
    }
    clientInterface->moveEffects(sessionId, srcIo, dstIo);
}

void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids,
                                             audio_io_handle_t dstOutput)
void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids, audio_io_handle_t dstIo)
{
    ALOGV("%s num effects %zu, first ID %d, dstOutput %d",
        __func__, ids.size(), ids.size() ? ids[0] : 0, dstOutput);
    ALOGV("%s num effects %zu, first ID %d, dstIo %d",
        __func__, ids.size(), ids.size() ? ids[0] : 0, dstIo);
    for (size_t i = 0; i < size(); i++) {
        sp<EffectDescriptor> effect = valueAt(i);
        if (std::find(begin(ids), end(ids), effect->mId) != end(ids)) {
            effect->mIo = dstOutput;
            effect->mIo = dstIo;
            effect->mIsOrphan = (dstIo == AUDIO_IO_HANDLE_NONE);
        }
    }
}

bool EffectDescriptorCollection::hasOrphansForSession(audio_session_t sessionId)
{
    for (size_t i = 0; i < size(); ++i) {
        sp<EffectDescriptor> effect = valueAt(i);
        if (effect->mSession == sessionId && effect->mIsOrphan) {
            return true;
        }
    }
    return false;
}

EffectDescriptorCollection EffectDescriptorCollection::getOrphanEffectsForSession(
        audio_session_t sessionId) const
{
    EffectDescriptorCollection effects;
    for (size_t i = 0; i < size(); i++) {
        sp<EffectDescriptor> effect = valueAt(i);
        if (effect->mSession == sessionId && effect->mIsOrphan) {
            effects.add(keyAt(i), effect);
        }
    }
    return effects;
}

audio_io_handle_t EffectDescriptorCollection::getIoForSession(audio_session_t sessionId,
@@ -214,6 +247,67 @@ audio_io_handle_t EffectDescriptorCollection::getIoForSession(audio_session_t se
    return AUDIO_IO_HANDLE_NONE;
}

void EffectDescriptorCollection::moveEffectsForIo(audio_session_t session,
        audio_io_handle_t dstIo, const AudioInputCollection *inputs,
        AudioPolicyClientInterface *clientInterface)
{
    // No src io: try to find from effect session the src Io to move from
    audio_io_handle_t srcIo = getIoForSession(session);
    if (hasOrphansForSession(session) || (srcIo != AUDIO_IO_HANDLE_NONE && srcIo != dstIo)) {
        moveEffects(session, srcIo, dstIo, inputs, clientInterface);
    }
}

void EffectDescriptorCollection::moveEffects(audio_session_t session,
        audio_io_handle_t srcIo, audio_io_handle_t dstIo, const AudioInputCollection *inputs,
        AudioPolicyClientInterface *clientInterface)
{
    if ((srcIo != AUDIO_IO_HANDLE_NONE && srcIo == dstIo)
            || (srcIo == AUDIO_IO_HANDLE_NONE && !hasOrphansForSession(session))) {
        return;
    }
    // Either we may find orphan effects for given session or effects for this session might have
    // been assigned first to another input (it may happen when an input is released or recreated
    // after client sets its preferred device)
    EffectDescriptorCollection effectsToMove;
    if (srcIo == AUDIO_IO_HANDLE_NONE) {
        ALOGV("%s: restoring effects for session %d from orphan park to io=%d", __func__,
                session, dstIo);
        effectsToMove = getOrphanEffectsForSession(session);
    } else {
        ALOGV("%s: moving effects for session %d from io=%d to io=%d", __func__,
                session, srcIo, dstIo);
        sp<AudioInputDescriptor> previousInputDesc = inputs->valueFor(srcIo);
        effectsToMove = getEffectsForIo(srcIo);
        for (size_t i = 0; i < effectsToMove.size(); ++i) {
            sp<EffectDescriptor> effect = effectsToMove.valueAt(i);
            effect->mEnabledWhenMoved = effect->mEnabled;
            previousInputDesc->trackEffectEnabled(effect, false);
        }
    }
    moveEffects(session, srcIo, dstIo, clientInterface);

    if (dstIo != AUDIO_IO_HANDLE_NONE) {
        sp<AudioInputDescriptor> inputDesc = inputs->valueFor(dstIo);
        for (size_t i = 0; i < effectsToMove.size(); ++i) {
            sp<EffectDescriptor> effect = effectsToMove.valueAt(i);
            inputDesc->trackEffectEnabled(effect, effect->mEnabledWhenMoved);
        }
    }
}

void EffectDescriptorCollection::putOrphanEffects(audio_session_t session,
        audio_io_handle_t srcIo, const AudioInputCollection *inputs,
        AudioPolicyClientInterface *clientInterface)
{
    if (getIoForSession(session) != srcIo) {
       // Effect session not held by this client io handle
       return;
    }
    ALOGV("%s: park effects for session %d and io=%d to orphans", __func__, session, srcIo);
    moveEffects(session, srcIo, AUDIO_IO_HANDLE_NONE, inputs, clientInterface);
}

EffectDescriptorCollection EffectDescriptorCollection::getEffectsForIo(audio_io_handle_t io) const
{
    EffectDescriptorCollection effects;
+6 −3
Original line number Diff line number Diff line
@@ -2650,6 +2650,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
    sp<AudioPolicyMix> policyMix;
    sp<DeviceDescriptor> device;
    sp<AudioInputDescriptor> inputDesc;
    sp<AudioInputDescriptor> previousInputDesc;
    sp<RecordClientDescriptor> clientDesc;
    audio_port_handle_t requestedDeviceId = *selectedDeviceId;
    uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(attributionSource.uid));
@@ -2806,6 +2807,8 @@ exit:
                                            requestedDeviceId, attributes.source, flags,
                                            isSoundTrigger);
    inputDesc = mInputs.valueFor(*input);
    // Move (if found) effect for the client session to its input
    mEffects.moveEffectsForIo(session, *input, &mInputs, mpClientInterface);
    inputDesc->addClient(clientDesc);

    ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
@@ -3115,7 +3118,7 @@ void AudioPolicyManager::releaseInput(audio_port_handle_t portId)
    ALOGV("%s %d", __FUNCTION__, input);

    inputDesc->removeClient(portId);

    mEffects.putOrphanEffects(client->session(), input, &mInputs, mpClientInterface);
    if (inputDesc->getClientCount() > 0) {
        ALOGV("%s(%d) %zu clients remaining", __func__, portId, inputDesc->getClientCount());
        return;
@@ -3477,8 +3480,8 @@ audio_io_handle_t AudioPolicyManager::selectOutputForMusicEffects()
    }

    if (output != mMusicEffectOutput) {
        mEffects.moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output);
        mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output);
        mEffects.moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output,
                mpClientInterface);
        mMusicEffectOutput = output;
    }