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

Commit 10cbff13 authored by Andy Hung's avatar Andy Hung
Browse files

VolumeShaper: Enable for offload and direct tracks

Test: Play Music in offload mode
Bug: 31015569
Change-Id: I00bb59e3e6809d4682f42057b1cc083f4fa9b9d1
parent 1e50d1da
Loading
Loading
Loading
Loading
+51 −44
Original line number Diff line number Diff line
@@ -94,6 +94,14 @@ public:
            , mId(-1) {
        }

        Configuration(const Configuration &configuration)
            : Interpolator<S, T>(*static_cast<const Interpolator<S, T> *>(&configuration))
            , mType(configuration.mType)
            , mOptionFlags(configuration.mOptionFlags)
            , mDurationMs(configuration.mDurationMs)
            , mId(configuration.mId) {
        }

        Type getType() const {
            return mType;
        }
@@ -493,13 +501,8 @@ public:
        return new VolumeShaper::State(mLastVolume, mXOffset);
    }

    std::pair<T, bool> getVolume(int64_t trackFrameCount, double trackSampleRate) {
        if (mConfiguration.get() == nullptr || mConfiguration->empty()) {
            ALOGE("nonexistent VolumeShaper, removing");
            mLastVolume = T(1);
            mXOffset = 0.f;
            return std::make_pair(T(1), true);
        }
    std::pair<T /* volume */, bool /* active */> getVolume(
            int64_t trackFrameCount, double trackSampleRate) {
        if ((getFlags() & VolumeShaper::Operation::FLAG_DELAY) != 0) {
            VS_LOG("delayed VolumeShaper, ignoring");
            mLastVolume = T(1);
@@ -534,13 +537,13 @@ public:
            if (x > mConfiguration->last().first) {
                mXOffset = 0.f;
                mLastVolume = 1.f;
                return std::make_pair(T(1), false); // too early
                return std::make_pair(T(1), true); // too early
            }
        } else {
            if (x < mConfiguration->first().first) {
                mXOffset = 0.f;
                mLastVolume = 1.f;
                return std::make_pair(T(1), false); // too early
                return std::make_pair(T(1), true); // too early
            }
            if (x > mConfiguration->last().first) {
                mXOffset = 1.f;
@@ -558,7 +561,7 @@ public:
        const T volume = mConfiguration->adjustVolume(volumeChange);
        VS_LOG("volume: %f  unscaled: %f", volume, unscaledVolume);
        mLastVolume = volume;
        return std::make_pair(volume, false);
        return std::make_pair(volume, true);
    }

    std::string toString() const {
@@ -597,6 +600,8 @@ public:
    VolumeShaper::Status applyVolumeShaper(
            const sp<VolumeShaper::Configuration> &configuration,
            const sp<VolumeShaper::Operation> &operation) {
        VS_LOG("applyVolumeShaper:configuration: %s", configuration->toString().c_str());
        VS_LOG("applyVolumeShaper:operation: %s", operation->toString().c_str());
        AutoMutex _l(mLock);
        if (configuration == nullptr) {
            ALOGE("null configuration");
@@ -614,34 +619,6 @@ public:
        VS_LOG("applyVolumeShaper id: %d", id);

        switch (configuration->getType()) {
        case VolumeShaper::Configuration::TYPE_ID: {
            VS_LOG("trying to find id: %d", id);
            auto it = findId_l(id);
            if (it == mVolumeShapers.end()) {
                VS_LOG("couldn't find id: %d\n%s", id, this->toString().c_str());
                return VolumeShaper::Status(INVALID_OPERATION);
            }
            if ((it->getFlags() & VolumeShaper::Operation::FLAG_TERMINATE) != 0) {
                VS_LOG("terminate id: %d", id);
                mVolumeShapers.erase(it);
                break;
            }
            if ((it->getFlags() & VolumeShaper::Operation::FLAG_REVERSE) !=
                    (operation->getFlags() & VolumeShaper::Operation::FLAG_REVERSE)) {
                const S x = it->mXTranslate((T)mLastFrame);
                VS_LOG("translation: %f", x);
                // reflect position
                S target = 1.f - x;
                if (target < it->mConfiguration->first().first) {
                    VS_LOG("clamp to start - begin immediately");
                    target = 0.;
                }
                VS_LOG("target: %f", target);
                it->mXTranslate.setOffset(it->mXTranslate.getOffset()
                        + (x - target) / it->mXTranslate.getScale());
            }
            it->mOperation = operation; // replace the operation
        } break;
        case VolumeShaper::Configuration::TYPE_SCALE: {
            const int replaceId = operation->getReplaceId();
            if (replaceId >= 0) {
@@ -670,6 +647,38 @@ public:
            }
            // create new VolumeShaper
            mVolumeShapers.emplace_back(configuration, operation);
        }
        // fall through to handle the operation
        case VolumeShaper::Configuration::TYPE_ID: {
            VS_LOG("trying to find id: %d", id);
            auto it = findId_l(id);
            if (it == mVolumeShapers.end()) {
                VS_LOG("couldn't find id: %d", id);
                return VolumeShaper::Status(INVALID_OPERATION);
            }
            if ((it->getFlags() & VolumeShaper::Operation::FLAG_TERMINATE) != 0) {
                VS_LOG("terminate id: %d", id);
                mVolumeShapers.erase(it);
                break;
            }
            const bool clockTime = (it->mConfiguration->getOptionFlags()
                    & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0;
            if ((it->getFlags() & VolumeShaper::Operation::FLAG_REVERSE) !=
                    (operation->getFlags() & VolumeShaper::Operation::FLAG_REVERSE)) {
                const int64_t frameCount = clockTime ? VolumeShaper::getNowUs() : mLastFrame;
                const S x = it->mXTranslate((T)frameCount);
                VS_LOG("reverse translation: %f", x);
                // reflect position
                S target = 1.f - x;
                if (target < it->mConfiguration->first().first) {
                    VS_LOG("clamp to start - begin immediately");
                    target = 0.;
                }
                VS_LOG("target reverse: %f", target);
                it->mXTranslate.setOffset(it->mXTranslate.getOffset()
                        + (x - target) / it->mXTranslate.getScale());
            }
            it->mOperation = operation; // replace the operation
        } break;
        }
        return VolumeShaper::Status(id);
@@ -684,21 +693,19 @@ public:
        return it->getState();
    }

    T getVolume(int64_t trackFrameCount) {
    std::pair<T /* volume */, bool /* active */> getVolume(int64_t trackFrameCount) {
        AutoMutex _l(mLock);
        mLastFrame = trackFrameCount;
        T volume(1);
        size_t activeCount = 0;
        for (auto it = mVolumeShapers.begin(); it != mVolumeShapers.end();) {
            std::pair<T, bool> shaperVolume =
                    it->getVolume(trackFrameCount, mSampleRate);
            volume *= shaperVolume.first;
            if (shaperVolume.second) {
                it = mVolumeShapers.erase(it);
                continue;
            }
            activeCount += shaperVolume.second;
            ++it;
        }
        return volume;
        return std::make_pair(volume, activeCount != 0);
    }

    std::string toString() const {
+4 −0
Original line number Diff line number Diff line
@@ -59,6 +59,10 @@ public:
            bool        isOffloaded() const
                                { return (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0; }
            bool        isDirect() const { return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
            bool        isOffloadedOrDirect() const { return (mFlags
                            & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
                                    | AUDIO_OUTPUT_FLAG_DIRECT)) != 0; }

            status_t    setParameters(const String8& keyValuePairs);
            status_t    attachAuxEffect(int EffectId);
            void        setAuxBuffer(int EffectId, int32_t *buffer);
+22 −10
Original line number Diff line number Diff line
@@ -3063,8 +3063,13 @@ bool AudioFlinger::PlaybackThread::threadLoop()
                    releaseWakeLock_l();
                    released = true;
                }
                ALOGV("wait async completion");
                mWaitWorkCV.wait(mLock);

                const int64_t waitNs = computeWaitTimeNs_l();
                ALOGV("wait async completion (wait time: %lld)", (long long)waitNs);
                status_t status = mWaitWorkCV.waitRelative(mLock, waitNs);
                if (status == TIMED_OUT) {
                    mSignalPending = true; // if timeout recheck everything
                }
                ALOGV("async completion/wake");
                if (released) {
                    acquireWakeLock_l();
@@ -4131,7 +4136,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
                // cache the combined master volume and stream type volume for fast mixer; this
                // lacks any synchronization or barrier so VolumeProvider may read a stale value
                const float vh = track->getVolumeHandler()->getVolume(
                        track->mAudioTrackServerProxy->framesReleased());
                        track->mAudioTrackServerProxy->framesReleased()).first;
                track->mCachedVolume = masterVolume
                        * mStreamTypes[track->streamType()].volume
                        * vh;
@@ -4277,7 +4282,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
                    vrf = GAIN_FLOAT_UNITY;
                }
                const float vh = track->getVolumeHandler()->getVolume(
                        track->mAudioTrackServerProxy->framesReleased());
                        track->mAudioTrackServerProxy->framesReleased()).first;
                // now apply the master volume and stream type volume and shaper volume
                vlf *= v * vh;
                vrf *= v * vh;
@@ -4756,6 +4761,7 @@ AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& aud
        ThreadBase::type_t type, bool systemReady)
    :   PlaybackThread(audioFlinger, output, id, device, type, systemReady)
        // mLeftVolFloat, mRightVolFloat
        , mVolumeShaperActive(false)
{
}

@@ -4774,13 +4780,12 @@ void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTr
        float v = mMasterVolume * typeVolume;
        sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;

        if (audio_is_linear_pcm(mFormat) && !usesHwAvSync()) {
            const float vh = track->getVolumeHandler()->getVolume(
        // Get volumeshaper scaling
        std::pair<float /* volume */, bool /* active */>
            vh = track->getVolumeHandler()->getVolume(
                    track->mAudioTrackServerProxy->framesReleased());
            v *= vh;
        } else {
            // TODO: implement volume scaling in HW
        }
        v *= vh.first;
        mVolumeShaperActive = vh.second;

        gain_minifloat_packed_t vlr = proxy->getVolumeLR();
        left = float_from_gain(gain_minifloat_unpack_left(vlr));
@@ -5238,6 +5243,13 @@ void AudioFlinger::DirectOutputThread::flushHw_l()
    mFlushPending = false;
}

int64_t AudioFlinger::DirectOutputThread::computeWaitTimeNs_l() const {
    // If a VolumeShaper is active, we must wake up periodically to update volume.
    const int64_t NS_PER_MS = 1000000;
    return mVolumeShaperActive ?
            kMinNormalSinkBufferSizeMs * NS_PER_MS : PlaybackThread::computeWaitTimeNs_l();
}

// ----------------------------------------------------------------------------

AudioFlinger::AsyncCallbackThread::AsyncCallbackThread(
+6 −0
Original line number Diff line number Diff line
@@ -757,6 +757,9 @@ public:

    virtual     void        getAudioPortConfig(struct audio_port_config *config);

                // Return the asynchronous signal wait time.
    virtual     int64_t     computeWaitTimeNs_l() const { return INT64_MAX; }

protected:
    // updated by readOutputParameters_l()
    size_t                          mNormalFrameCount;  // normal mixer and effects
@@ -1174,6 +1177,7 @@ protected:
    // volumes last sent to audio HAL with stream->set_volume()
    float mLeftVolFloat;
    float mRightVolFloat;
    bool mVolumeShaperActive;

    DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
                        audio_io_handle_t id, uint32_t device, ThreadBase::type_t type,
@@ -1187,6 +1191,8 @@ protected:

public:
    virtual     bool        hasFastMixer() const { return false; }

    virtual     int64_t     computeWaitTimeNs_l() const override;
};

class OffloadThread : public DirectOutputThread {
+26 −3
Original line number Diff line number Diff line
@@ -905,10 +905,33 @@ VolumeShaper::Status AudioFlinger::PlaybackThread::Track::applyVolumeShaper(
        const sp<VolumeShaper::Configuration>& configuration,
        const sp<VolumeShaper::Operation>& operation)
{
    // Note: We don't check if Thread exists.
    sp<VolumeShaper::Configuration> newConfiguration;

    if (isOffloadedOrDirect()) {
        const VolumeShaper::Configuration::OptionFlag optionFlag
            = configuration->getOptionFlags();
        if ((optionFlag & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) == 0) {
            ALOGW("%s tracks do not support frame counted VolumeShaper,"
                    " using clock time instead", isOffloaded() ? "Offload" : "Direct");
            newConfiguration = new VolumeShaper::Configuration(*configuration);
            newConfiguration->setOptionFlags(
                VolumeShaper::Configuration::OptionFlag(optionFlag
                        | VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME));
        }
    }

    VolumeShaper::Status status = mVolumeHandler->applyVolumeShaper(
            (newConfiguration.get() != nullptr ? newConfiguration : configuration), operation);

    // mVolumeHandler is thread-safe.
    return mVolumeHandler->applyVolumeShaper(configuration, operation);
    if (isOffloadedOrDirect()) {
        // Signal thread to fetch new volume.
        sp<ThreadBase> thread = mThread.promote();
        if (thread != 0) {
             Mutex::Autolock _l(thread->mLock);
            thread->broadcast_l();
        }
    }
    return status;
}

sp<VolumeShaper::State> AudioFlinger::PlaybackThread::Track::getVolumeShaperState(int id)