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

Commit daa3ff8b authored by Andy Hung's avatar Andy Hung Committed by Gerrit Code Review
Browse files

Merge "Pause faster during audio underrun"

parents 8a4e9b2b 9e661ad8
Loading
Loading
Loading
Loading
+34 −11
Original line number Diff line number Diff line
@@ -178,6 +178,11 @@ static const nsecs_t kOffloadStandbyDelayNs = seconds(1);
// Direct output thread minimum sleep time in idle or active(underrun) state
static const nsecs_t kDirectMinSleepTimeUs = 10000;

// Minimum amount of time between checking to see if the timestamp is advancing
// for underrun detection. If we check too frequently, we may not detect a
// timestamp update and will falsely detect underrun.
static const nsecs_t kMinimumTimeBetweenTimestampChecksNs = 150 /* ms */ * 1000;

// The universal constant for ubiquitous 20ms value. The value of 20ms seems to provide a good
// balance between power consumption and latency, and allows threads to be scheduled reliably
// by the CFS scheduler.
@@ -2040,7 +2045,8 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
        mFastTrackAvailMask(((1 << FastMixerState::sMaxFastTracks) - 1) & ~1),
        mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
        mLeftVolFloat(-1.0), mRightVolFloat(-1.0),
        mDownStreamPatch{}
        mDownStreamPatch{},
        mIsTimestampAdvancing(kMinimumTimeBetweenTimestampChecksNs)
{
    snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
    mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
@@ -5902,18 +5908,35 @@ uint32_t AudioFlinger::PlaybackThread::trackCountForUid_l(uid_t uid) const
    return trackCount;
}

bool AudioFlinger::PlaybackThread::checkRunningTimestamp()
bool AudioFlinger::PlaybackThread::IsTimestampAdvancing::check(AudioStreamOut * output)
{
    // Check the timestamp to see if it's advancing once every 150ms. If we check too frequently, we
    // could falsely detect that the frame position has stalled due to underrun because we haven't
    // given the Audio HAL enough time to update.
    const nsecs_t nowNs = systemTime();
    if (nowNs - mPreviousNs < mMinimumTimeBetweenChecksNs) {
        return mLatchedValue;
    }
    mPreviousNs = nowNs;
    mLatchedValue = false;
    // Determine if the presentation position is still advancing.
    uint64_t position = 0;
    struct timespec unused;
    const status_t ret = mOutput->getPresentationPosition(&position, &unused);
    const status_t ret = output->getPresentationPosition(&position, &unused);
    if (ret == NO_ERROR) {
        if (position != mLastCheckedTimestampPosition) {
            mLastCheckedTimestampPosition = position;
            return true;
        if (position != mPreviousPosition) {
            mPreviousPosition = position;
            mLatchedValue = true;
        }
    }
    return false;
    return mLatchedValue;
}

void AudioFlinger::PlaybackThread::IsTimestampAdvancing::clear()
{
    mLatchedValue = true;
    mPreviousPosition = 0;
    mPreviousNs = 0;
}

// isTrackAllowed_l() must be called with ThreadBase::mLock held
@@ -6348,9 +6371,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
                // No buffers for this track. Give it a few chances to
                // fill a buffer, then remove it from active list.
                // Only consider last track started for mixer state control
                bool isTimestampAdvancing = mIsTimestampAdvancing.check(mOutput);
                if (--(track->mRetryCount) <= 0) {
                    const bool running = checkRunningTimestamp();
                    if (running) { // still running, give us more time.
                    if (isTimestampAdvancing) { // HAL is still playing audio, give us more time.
                        track->mRetryCount = kMaxTrackRetriesOffload;
                    } else {
                        ALOGV("BUFFER TIMEOUT: remove track(%d) from active list", trackId);
@@ -6931,9 +6954,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
            } else {
                // No buffers for this track. Give it a few chances to
                // fill a buffer, then remove it from active list.
                bool isTimestampAdvancing = mIsTimestampAdvancing.check(mOutput);
                if (--(track->mRetryCount) <= 0) {
                    const bool running = checkRunningTimestamp();
                    if (running) { // still running, give us more time.
                    if (isTimestampAdvancing) { // HAL is still playing audio, give us more time.
                        track->mRetryCount = kMaxTrackRetriesOffload;
                    } else {
                        ALOGV("OffloadThread: BUFFER TIMEOUT: remove track(%d) from active list",
+30 −5
Original line number Diff line number Diff line
@@ -1403,13 +1403,38 @@ protected:

                std::atomic_bool mCheckOutputStageEffects{};

                // A differential check on the timestamps to see if there is a change in the
                // timestamp frame position between the last call to checkRunningTimestamp.
                uint64_t mLastCheckedTimestampPosition = ~0LL;

                bool checkRunningTimestamp();
                // Provides periodic checking for timestamp advancement for underrun detection.
                class IsTimestampAdvancing {
                public:
                    // The timestamp will not be checked any faster than the specified time.
                    IsTimestampAdvancing(nsecs_t minimumTimeBetweenChecksNs)
                        :   mMinimumTimeBetweenChecksNs(minimumTimeBetweenChecksNs)
                    {
                        clear();
                    }
                    // Check if the presentation position has advanced in the last periodic time.
                    bool check(AudioStreamOut * output);
                    // Clear the internal state when the playback state changes for the output
                    // stream.
                    void clear();
                private:
                    // The minimum time between timestamp checks.
                    const nsecs_t mMinimumTimeBetweenChecksNs;
                    // Add differential check on the timestamps to see if there is a change in the
                    // timestamp frame position between the last call to check.
                    uint64_t mPreviousPosition;
                    // The time at which the last check occurred, to ensure we don't check too
                    // frequently, giving the Audio HAL enough time to update its timestamps.
                    nsecs_t mPreviousNs;
                    // The valued is latched so we don't check timestamps too frequently.
                    bool mLatchedValue;
                };
                IsTimestampAdvancing mIsTimestampAdvancing;

    virtual     void flushHw_l() { mLastCheckedTimestampPosition = ~0LL; }
    virtual     void flushHw_l() {
                    mIsTimestampAdvancing.clear();
                }
};

class MixerThread : public PlaybackThread {