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

Commit 1990bd40 authored by Tomoharu Kasahara's avatar Tomoharu Kasahara
Browse files

Set volume for output when effect is enabled/disabled.

Even though effect module has "EFFECT_FLAG_VOLUME_CTRL" flag,
there is some case where volume setting is not sent to offload thread.
That leads to sudden increase of audio volume or too low volume.
This change is to support delegation of volume control completely
for offload audio effect.

Bug: 37443095
Test: Enable/Disable Audio effects during offload playback
Change-Id: I7033071edc99fadc519efd7adc895dc10f7b9d86
parent 34affaed
Loading
Loading
Loading
Loading
+39 −4
Original line number Diff line number Diff line
@@ -263,7 +263,9 @@ bool AudioFlinger::EffectModule::updateState() {
        }
        break;
    case STOPPING:
        if (stop_l() == NO_ERROR) {
        // volume control for offload and direct threads must take effect immediately.
        if (stop_l() == NO_ERROR
            && !(isVolumeControl() && isOffloadedOrDirect())) {
            mDisableWaitCnt = mMaxDisableWaitCnt;
        } else {
            mDisableWaitCnt = 1; // will cause immediate transition to IDLE
@@ -778,6 +780,16 @@ status_t AudioFlinger::EffectModule::stop_l()
    }
    status_t cmdStatus = NO_ERROR;
    uint32_t size = sizeof(status_t);

    if (isVolumeControl() && isOffloadedOrDirect()) {
        sp<EffectChain>chain = mChain.promote();
        // We have the EffectChain and EffectModule lock, permit a reentrant call to setVolume:
        // resetVolume_l --> setVolume_l --> EffectModule::setVolume
        mSetVolumeReentrantTid = gettid();
        chain->resetVolume_l();
        mSetVolumeReentrantTid = INVALID_PID;
    }

    status_t status = mEffectInterface->command(EFFECT_CMD_DISABLE,
                                                0,
                                                NULL,
@@ -993,6 +1005,16 @@ bool AudioFlinger::EffectModule::isProcessEnabled() const
    }
}

bool AudioFlinger::EffectModule::isOffloadedOrDirect() const
{
    return (mThreadType == ThreadBase::OFFLOAD || mThreadType == ThreadBase::DIRECT);
}

bool AudioFlinger::EffectModule::isVolumeControlEnabled() const
{
    return (isVolumeControl() && (isOffloadedOrDirect() ? isEnabled() : isProcessEnabled()));
}

void AudioFlinger::EffectModule::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
    ALOGVV("setInBuffer %p",(&buffer));

@@ -1091,7 +1113,7 @@ void AudioFlinger::EffectModule::setOutBuffer(const sp<EffectBufferHalInterface>

status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
{
    Mutex::Autolock _l(mLock);
    AutoLockReentrant _l(mLock, mSetVolumeReentrantTid);
    if (mStatus != NO_ERROR) {
        return mStatus;
    }
@@ -1122,6 +1144,18 @@ status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right,
    return status;
}

void AudioFlinger::EffectChain::setVolumeForOutput_l(uint32_t left, uint32_t right)
{
    sp<ThreadBase> thread = mThread.promote();
    if (thread != 0 &&
        (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::DIRECT)) {
        PlaybackThread *t = (PlaybackThread *)thread.get();
        float vol_l = (float)left / (1 << 24);
        float vol_r = (float)right / (1 << 24);
        t->setVolumeForOutput_l(vol_l, vol_r);
    }
}

status_t AudioFlinger::EffectModule::setDevice(audio_devices_t device)
{
    if (device == AUDIO_DEVICE_NONE) {
@@ -2200,8 +2234,7 @@ bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right, boo

    // first update volume controller
    for (size_t i = size; i > 0; i--) {
        if (mEffects[i - 1]->isProcessEnabled() &&
            (mEffects[i - 1]->desc().flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL) {
        if (mEffects[i - 1]->isVolumeControlEnabled()) {
            ctrlIdx = i - 1;
            hasControl = true;
            break;
@@ -2247,6 +2280,8 @@ bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right, boo
    *left = newLeft;
    *right = newRight;

    setVolumeForOutput_l(*left, *right);

    return hasControl;
}

+28 −1
Original line number Diff line number Diff line
@@ -85,6 +85,8 @@ public:
    status_t    setEnabled_l(bool enabled);
    bool isEnabled() const;
    bool isProcessEnabled() const;
    bool isOffloadedOrDirect() const;
    bool isVolumeControlEnabled() const;

    void        setInBuffer(const sp<EffectBufferHalInterface>& buffer);
    int16_t     *inBuffer() const {
@@ -95,7 +97,8 @@ public:
        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; }
    void        setThread(const wp<ThreadBase>& thread)
                    { mThread = thread; mThreadType = thread.promote()->type(); }
    const wp<ThreadBase>& thread() { return mThread; }

    status_t addHandle(EffectHandle *handle);
@@ -128,6 +131,9 @@ public:
                        { return (mDescriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0; }
    bool             isProcessImplemented() const
                        { return (mDescriptor.flags & EFFECT_FLAG_NO_PROCESS) == 0; }
    bool             isVolumeControl() const
                        { return (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK)
                            == EFFECT_FLAG_VOLUME_CTRL; }
    status_t         setOffloaded(bool offloaded, audio_io_handle_t io);
    bool             isOffloaded() const;
    void             addEffectToHal_l();
@@ -150,6 +156,7 @@ private:

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
    const int           mId;        // this instance unique ID
    const audio_session_t mSessionId; // audio session ID
@@ -176,6 +183,24 @@ mutable Mutex mLock; // mutex for process, commands and handl
    uint32_t mInChannelCountRequested;
    uint32_t mOutChannelCountRequested;
#endif

    class AutoLockReentrant {
    public:
        AutoLockReentrant(Mutex& mutex, pid_t allowedTid)
            : mMutex(gettid() == allowedTid ? nullptr : &mutex)
        {
            if (mMutex != nullptr) mMutex->lock();
        }
        ~AutoLockReentrant() {
            if (mMutex != nullptr) mMutex->unlock();
        }
    private:
        Mutex * const mMutex;
    };

    static constexpr pid_t INVALID_PID = (pid_t)-1;
    // this tid is allowed to call setVolume() without acquiring the mutex.
    pid_t mSetVolumeReentrantTid = INVALID_PID;
};

// The EffectHandle class implements the IEffect interface. It provides resources
@@ -403,6 +428,8 @@ private:

    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
+14 −9
Original line number Diff line number Diff line
@@ -2286,6 +2286,11 @@ float AudioFlinger::PlaybackThread::streamVolume(audio_stream_type_t stream) con
    return mStreamTypes[stream].volume;
}

void AudioFlinger::PlaybackThread::setVolumeForOutput_l(float left, float right) const
{
    mOutput->stream->setVolume(left, right);
}

// addTrack_l() must be called with ThreadBase::mLock held
status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
@@ -5142,20 +5147,20 @@ void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTr
            mLeftVolFloat = left;
            mRightVolFloat = right;

            // Convert volumes from float to 8.24
            uint32_t vl = (uint32_t)(left * (1 << 24));
            uint32_t vr = (uint32_t)(right * (1 << 24));

            // Delegate volume control to effect in track effect chain if needed
            // only one effect chain can be present on DirectOutputThread, so if
            // there is one, the track is connected to it
            if (!mEffectChains.isEmpty()) {
                mEffectChains[0]->setVolume_l(&vl, &vr);
                left = (float)vl / (1 << 24);
                right = (float)vr / (1 << 24);
                // if effect chain exists, volume is handled by it.
                // Convert volumes from float to 8.24
                uint32_t vl = (uint32_t)(left * (1 << 24));
                uint32_t vr = (uint32_t)(right * (1 << 24));
                // Direct/Offload effect chains set output volume in setVolume_l().
                (void)mEffectChains[0]->setVolume_l(&vl, &vr);
            } else {
                // otherwise we directly set the volume.
                setVolumeForOutput_l(left, right);
            }
            status_t result = mOutput->stream->setVolume(left, right);
            ALOGE_IF(result != OK, "Error when setting output stream volume: %d", result);
        }
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -712,6 +712,8 @@ 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;

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