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

Commit 6a00616d authored by Brian Lindahl's avatar Brian Lindahl Committed by Automerger Merge Worker
Browse files

Merge "Pause faster during audio underrun" into tm-qpr-dev am: b127211d am: d5a85fa3

parents cfa01a51 d5a85fa3
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);
@@ -5910,18 +5916,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
@@ -6356,9 +6379,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);
@@ -6939,9 +6962,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
@@ -1409,13 +1409,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 {