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

Commit c0abc623 authored by Eric Laurent's avatar Eric Laurent
Browse files

Audio effects: define interface between EffectModule and audio framework

This is in preparation of the addition of audio effects attached to a
specific audio device that will not be attached to a particular
ThreadBase or Effectchain.

Create an clean callback interface used by the EffectModule to interact
with the rest of the audio framework. This callback must be implemented
by the EffectModule parent (e.g an EfffectChain).

Als refactor EffectHandle enabled(), disable() and disconnect methods()
to avoid dealing with the ThreadBase directly.

Bug: 136294538
Test: make
Change-Id: I9160f88f7fbb0447b5e679260bf0401d3af591d2
parent 880971c8
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -2996,7 +2996,7 @@ std::vector<sp<AudioFlinger::EffectModule>> AudioFlinger::purgeStaleEffects_l()
    for (size_t i = 0; i < chains.size(); i++) {
        sp<EffectChain> ec = chains[i];
        int sessionid = ec->sessionId();
        sp<ThreadBase> t = ec->mThread.promote();
        sp<ThreadBase> t = ec->thread().promote();
        if (t == 0) {
            continue;
        }
@@ -3019,7 +3019,7 @@ std::vector<sp<AudioFlinger::EffectModule>> AudioFlinger::purgeStaleEffects_l()
                effect->unPin();
                t->removeEffect_l(effect, /*release*/ true);
                if (effect->purgeHandles()) {
                    t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId());
                    effect->checkSuspendOnEffectEnabled(false, true /*threadLocked*/);
                }
                removedEffects.push_back(effect);
            }
@@ -3642,7 +3642,7 @@ status_t AudioFlinger::moveEffectChain_l(audio_session_t sessionId,
        // if the move request is not received from audio policy manager, the effect must be
        // re-registered with the new strategy and output
        if (dstChain == 0) {
            dstChain = effect->chain().promote();
            dstChain = effect->callback()->chain().promote();
            if (dstChain == 0) {
                ALOGW("moveEffectChain_l() cannot get chain from effect %p", effect.get());
                status = NO_INIT;
@@ -3692,7 +3692,7 @@ status_t AudioFlinger::moveAuxEffectToIo(int EffectId,
            goto Exit;
        }

        dstChain = effect->chain().promote();
        dstChain = effect->callback()->chain().promote();
        if (dstChain == 0) {
            thread->addEffect_l(effect);
            status = INVALID_OPERATION;
+303 −170

File changed.

Preview size limit exceeded, changes collapsed.

+113 −19
Original line number Diff line number Diff line
@@ -21,11 +21,61 @@

//--- Audio Effect Management

// Interface implemented by the EffectModule parent or owner (e.g an EffectChain) to abstract
// interactions between the EffectModule and the reset of the audio framework.
class EffectCallbackInterface : public RefBase {
public:
            ~EffectCallbackInterface() override = default;


    // Trivial methods usually implemented with help from ThreadBase
    virtual audio_io_handle_t io() const = 0;
    virtual bool isOutput() const = 0;
    virtual bool isOffload() const = 0;
    virtual bool isOffloadOrDirect() const = 0;
    virtual bool isOffloadOrMmap() const = 0;
    virtual uint32_t  sampleRate() const = 0;
    virtual audio_channel_mask_t channelMask() const = 0;
    virtual uint32_t channelCount() const = 0;
    virtual size_t frameCount() const = 0;

    // Non trivial methods usually implemented with help from ThreadBase:
    //   pay attention to mutex locking order
    virtual uint32_t latency() const { return 0; }
    virtual status_t addEffectToHal(sp<EffectHalInterface> effect) = 0;
    virtual status_t removeEffectFromHal(sp<EffectHalInterface> effect) = 0;
    virtual void setVolumeForOutput(float left, float right) const;
    virtual bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) = 0;
    virtual void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
                                             bool enabled,
                                             bool threadLocked) = 0;
    virtual void onEffectEnable(const sp<EffectModule>& effect) = 0;
    virtual void onEffectDisable(const sp<EffectModule>& effect) = 0;

    // Methods usually implemented with help from AudioFlinger: pay attention to mutex locking order
    virtual status_t createEffectHal(const effect_uuid_t *pEffectUuid,
                    int32_t sessionId, int32_t deviceId, sp<EffectHalInterface> *effect) = 0;
    virtual status_t allocateHalBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) = 0;
    virtual bool updateOrphanEffectChains(const sp<EffectModule>& effect) = 0;

    // Methods usually implemented with help from EffectChain: pay attention to mutex locking order
    virtual uint32_t strategy() const = 0;
    virtual int32_t activeTrackCnt() const = 0;
    virtual void resetVolume() = 0;

    virtual wp<EffectChain> chain() const = 0;
};

// EffectModule and EffectChain classes both have their own mutex to protect
// state changes or resource modifications. Always respect the following order
// if multiple mutexes must be acquired to avoid cross deadlock:
// AudioFlinger -> ThreadBase -> EffectChain -> EffectModule
// AudioHandle -> ThreadBase -> EffectChain -> EffectModule

// NOTE: When implementing the EffectCallbackInterface, in an EffectChain or other, it is important
// to pay attention to this locking order as some callback methods can be called from a state where
// EffectModule and/or EffectChain mutexes are held.

// In addition, methods that lock the AudioPolicyService mutex (getOutputForEffect(),
// startOutput(), getInputForAttr(), releaseInput()...) should never be called with AudioFlinger or
// Threadbase mutex locked to avoid cross deadlock with other clients calling AudioPolicyService
@@ -42,8 +92,7 @@
// the attached track(s) to accumulate their auxiliary channel.
class EffectModule : public RefBase {
public:
    EffectModule(ThreadBase *thread,
                    const wp<AudioFlinger::EffectChain>& chain,
    EffectModule(const sp<EffectCallbackInterface>& chain,
                    effect_descriptor_t *desc,
                    int id,
                    audio_session_t sessionId,
@@ -81,7 +130,7 @@ public:
    audio_session_t sessionId() const {
        return mSessionId;
    }
    status_t    setEnabled(bool enabled);
    status_t    setEnabled(bool enabled, bool fromHandle);
    status_t    setEnabled_l(bool enabled);
    bool isEnabled() const;
    bool isProcessEnabled() const;
@@ -96,10 +145,7 @@ public:
    int16_t     *outBuffer() const {
        return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
    }
    void        setChain(const wp<EffectChain>& chain) { mChain = chain; }
    void        setThread(const wp<ThreadBase>& thread)
                    { mThread = thread; mThreadType = thread.promote()->type(); }
    const wp<ThreadBase>& thread() { return mThread; }
    void        setCallback(const sp<EffectCallbackInterface>& callback) { mCallback = callback; }

    status_t addHandle(EffectHandle *handle);
    ssize_t  disconnectHandle(EffectHandle *handle, bool unpinIfLast);
@@ -107,7 +153,7 @@ public:
    ssize_t removeHandle_l(EffectHandle *handle);

    const effect_descriptor_t& desc() const { return mDescriptor; }
    wp<EffectChain>&     chain() { return mChain; }
    sp<EffectCallbackInterface>&     callback() { return mCallback; }

    status_t         setDevices(const AudioDeviceTypeAddrVector &devices);
    status_t         setInputDevice(const AudioDeviceTypeAddr &device);
@@ -144,6 +190,7 @@ public:
    void             release_l();

    status_t         updatePolicyState();
    void             checkSuspendOnEffectEnabled(bool enabled, bool threadLocked);

    void             dump(int fd, const Vector<String16>& args);

@@ -158,13 +205,11 @@ private:

    status_t start_l();
    status_t stop_l();
    status_t remove_effect_from_hal_l();
    status_t removeEffectFromHal_l();
    status_t sendSetAudioDevicesCommand(const AudioDeviceTypeAddrVector &devices, uint32_t cmdCode);

mutable Mutex               mLock;      // mutex for process, commands and handles list protection
    wp<ThreadBase>      mThread;    // parent thread
    ThreadBase::type_t  mThreadType; // parent thread type
    wp<EffectChain>     mChain;     // parent effect chain
    sp<EffectCallbackInterface>     mCallback;     // parent effect chain
    const int           mId;        // this instance unique ID
    const audio_session_t mSessionId; // audio session ID
    const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
@@ -181,7 +226,6 @@ mutable Mutex mLock; // mutex for process, commands and handl
    uint32_t mDisableWaitCnt;       // current process() calls count during disable period.
    bool     mSuspended;            // effect is suspended: temporarily disabled by framework
    bool     mOffloaded;            // effect is currently offloaded to the audio DSP
    wp<AudioFlinger>    mAudioFlinger;

#ifdef FLOAT_EFFECT_CHAIN
    bool    mSupportsFloat;         // effect supports float processing
@@ -333,7 +377,6 @@ public:
    }

    status_t createEffect_l(sp<EffectModule>& effect,
                            ThreadBase *thread,
                            effect_descriptor_t *desc,
                            int id,
                            audio_session_t sessionId,
@@ -389,9 +432,8 @@ public:
                              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
    void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
                                          bool enabled);
    // check if effects should be suspended or restored when a given effect is enable or disabled
    void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect, bool enabled);

    void clearInputBuffer();

@@ -416,9 +458,60 @@ public:
    // isCompatibleWithThread_l() must be called with thread->mLock held
    bool isCompatibleWithThread_l(const sp<ThreadBase>& thread) const;

    sp<EffectCallbackInterface> effectCallback() const { return mEffectCallback; }
    wp<ThreadBase> thread() const { return mEffectCallback->thread(); }

    void dump(int fd, const Vector<String16>& args);

private:

    class EffectCallback :  public EffectCallbackInterface {
    public:
        EffectCallback(EffectChain *chain, ThreadBase *thread, AudioFlinger *audioFlinger)
            : mChain(chain), mThread(thread), mAudioFlinger(audioFlinger) {}

        status_t createEffectHal(const effect_uuid_t *pEffectUuid,
               int32_t sessionId, int32_t deviceId, sp<EffectHalInterface> *effect) override;
        status_t allocateHalBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) override;
        bool updateOrphanEffectChains(const sp<EffectModule>& effect) override;

        audio_io_handle_t io() const override;
        bool isOutput() const override;
        bool isOffload() const override;
        bool isOffloadOrDirect() const override;
        bool isOffloadOrMmap() const override;

        uint32_t sampleRate() const override;
        audio_channel_mask_t channelMask() const override;
        uint32_t channelCount() const override;
        size_t frameCount() const override;
        uint32_t latency() const override;

        status_t addEffectToHal(sp<EffectHalInterface> effect) override;
        status_t removeEffectFromHal(sp<EffectHalInterface> effect) override;
        bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) override;
        void setVolumeForOutput(float left, float right) const override;

        // check if effects should be suspended/restored when a given effect is enable/disabled
        void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
                              bool enabled, bool threadLocked) override;
        void resetVolume() override;
        uint32_t strategy() const override;
        int32_t activeTrackCnt() const override;
        void onEffectEnable(const sp<EffectModule>& effect) override;
        void onEffectDisable(const sp<EffectModule>& effect) override;

        wp<EffectChain> chain() const override { return mChain; }

        wp<ThreadBase> thread() { return mThread; }
        void setThread(ThreadBase *thread) { mThread = thread; };

    private:
        wp<EffectChain> mChain;
        wp<ThreadBase> mThread;
        wp<AudioFlinger> mAudioFlinger;
    };

    friend class AudioFlinger;  // for mThread, mEffects
    DISALLOW_COPY_AND_ASSIGN(EffectChain);

@@ -444,13 +537,12 @@ private:

    static bool isEffectEligibleForBtNrecSuspend(const effect_uuid_t *type);

    void clearInputBuffer_l(const sp<ThreadBase>& thread);
    void clearInputBuffer_l();

    void setThread(const sp<ThreadBase>& thread);

    void setVolumeForOutput_l(uint32_t left, uint32_t right);

             wp<ThreadBase> mThread;     // parent mixer thread
    mutable  Mutex mLock;        // mutex protecting effect list
             Vector< sp<EffectModule> > mEffects; // list of effect modules
             audio_session_t mSessionId; // audio session ID
@@ -474,4 +566,6 @@ private:
             // timeLow fields among effect type UUIDs.
             // Updated by setEffectSuspended_l() and setEffectSuspendedAll_l() only.
             KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;

             const sp<EffectCallback> mEffectCallback;
};
+35 −18
Original line number Diff line number Diff line
@@ -1146,18 +1146,13 @@ void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *ty
    }
}

void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
                                                            bool enabled,
                                                            audio_session_t sessionId)
{
    Mutex::Autolock _l(mLock);
    checkSuspendOnEffectEnabled_l(effect, enabled, sessionId);
void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(bool enabled,
                                                           audio_session_t sessionId,
                                                           bool threadLocked) {
    if (!threadLocked) {
        mLock.lock();
    }

void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const sp<EffectModule>& effect,
                                                            bool enabled,
                                                            audio_session_t sessionId)
{
    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
@@ -1169,9 +1164,8 @@ void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const sp<EffectModu
        }
    }

    sp<EffectChain> chain = getEffectChain_l(sessionId);
    if (chain != 0) {
        chain->checkSuspendOnEffectEnabled(effect, enabled);
    if (!threadLocked) {
        mLock.unlock();
    }
}

@@ -1379,7 +1373,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
        if (effect == 0) {
            effectId = mAudioFlinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
            // create a new effect module if none present in the chain
            lStatus = chain->createEffect_l(effect, this, desc, effectId, sessionId, pinned);
            lStatus = chain->createEffect_l(effect, desc, effectId, sessionId, pinned);
            if (lStatus != NO_ERROR) {
                goto Exit;
            }
@@ -1427,7 +1421,7 @@ void AudioFlinger::ThreadBase::disconnectEffectHandle(EffectHandle *handle,
        Mutex::Autolock _l(mLock);

        effect = handle->effect().promote();
        if (effect == 0) {
        if (effect == nullptr) {
            return;
        }
        // restore suspended effects if the disconnected handle was enabled and the last one.
@@ -1439,9 +1433,32 @@ void AudioFlinger::ThreadBase::disconnectEffectHandle(EffectHandle *handle,
    if (remove) {
        mAudioFlinger->updateOrphanEffectChains(effect);
        if (handle->enabled()) {
            checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
            effect->checkSuspendOnEffectEnabled(false, false /*threadLocked*/);
        }
    }
}

void AudioFlinger::ThreadBase::onEffectEnable(const sp<EffectModule>& effect) {
    if (mType == OFFLOAD || mType == MMAP) {
        Mutex::Autolock _l(mLock);
        broadcast_l();
    }
    if (!effect->isOffloadable()) {
        if (mType == ThreadBase::OFFLOAD) {
            PlaybackThread *t = (PlaybackThread *)this;
            t->invalidateTracks(AUDIO_STREAM_MUSIC);
        }
        if (effect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) {
            mAudioFlinger->onNonOffloadableGlobalEffectEnable();
        }
    }
}

void AudioFlinger::ThreadBase::onEffectDisable() {
    if (mType == OFFLOAD || mType == MMAP) {
        Mutex::Autolock _l(mLock);
        broadcast_l();
    }
}

sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect(audio_session_t sessionId,
@@ -1519,7 +1536,7 @@ void AudioFlinger::ThreadBase::removeEffect_l(const sp<EffectModule>& effect, bo
        detachAuxEffect_l(effect->id());
    }

    sp<EffectChain> chain = effect->chain().promote();
    sp<EffectChain> chain = effect->callback()->chain().promote();
    if (chain != 0) {
        // remove effect chain if removing last effect
        if (chain->removeEffect_l(effect, release) == 0) {
+10 −10
Original line number Diff line number Diff line
@@ -271,6 +271,8 @@ public:
                // Called by AudioFlinger::frameCount(audio_io_handle_t output) and effects,
                // and returns the [normal mix] buffer's frame count.
    virtual     size_t      frameCount() const = 0;
    virtual     uint32_t    latency_l() const { return 0; }
    virtual     void        setVolumeForOutput_l(float left __unused, float right __unused) const {}

                // Return's the HAL's frame count i.e. fast mixer buffer size.
                size_t      frameCountHAL() const { return mFrameCount; }
@@ -424,14 +426,9 @@ public:

                // check if some effects must be suspended/restored when an effect is enabled
                // or disabled
                void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
                                                 bool enabled,
                                                 audio_session_t sessionId =
                                                        AUDIO_SESSION_OUTPUT_MIX);
                void checkSuspendOnEffectEnabled_l(const sp<EffectModule>& effect,
                                                   bool enabled,
                                                   audio_session_t sessionId =
                                                        AUDIO_SESSION_OUTPUT_MIX);
                void checkSuspendOnEffectEnabled(bool enabled,
                                                 audio_session_t sessionId,
                                                 bool threadLocked);

                virtual status_t    setSyncEvent(const sp<SyncEvent>& event) = 0;
                virtual bool        isValidSyncEvent(const sp<SyncEvent>& event) const = 0;
@@ -465,6 +462,9 @@ public:

    mutable     Mutex                   mLock;

                void onEffectEnable(const sp<EffectModule>& effect);
                void onEffectDisable();

protected:

                // entry describing an effect being suspended in mSuspendedSessions keyed vector
@@ -814,7 +814,7 @@ public:
                // return estimated latency in milliseconds, as reported by HAL
                uint32_t    latency() const;
                // same, but lock must already be held
                uint32_t    latency_l() const;
                uint32_t    latency_l() const override;

                // VolumeInterface
    virtual     void        setMasterVolume(float value);
@@ -824,7 +824,7 @@ public:
    virtual     void        setStreamMute(audio_stream_type_t stream, bool muted);
    virtual     float       streamVolume(audio_stream_type_t stream) const;

                void        setVolumeForOutput_l(float left, float right) const;
                void        setVolumeForOutput_l(float left, float right) const override;

                sp<Track>   createTrack_l(
                                const sp<AudioFlinger::Client>& client,