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

Commit 8f194f19 authored by ziyangch's avatar ziyangch
Browse files

Prevent offload underrun during active playback.

Bug: 177944032

Test:Start playback in Youtube app.

Change-Id: Ib60b7d049e159d0f32daa5e586ff92dc0bfd48ee
parent 513278bf
Loading
Loading
Loading
Loading
+35 −29
Original line number Diff line number Diff line
@@ -5889,6 +5889,20 @@ uint32_t AudioFlinger::PlaybackThread::trackCountForUid_l(uid_t uid) const
    return trackCount;
}

bool AudioFlinger::PlaybackThread::checkRunningTimestamp()
{
    uint64_t position = 0;
    struct timespec unused;
    const status_t ret = mOutput->getPresentationPosition(&position, &unused);
    if (ret == NO_ERROR) {
        if (position != mLastCheckedTimestampPosition) {
            mLastCheckedTimestampPosition = position;
            return true;
        }
    }
    return false;
}

// isTrackAllowed_l() must be called with ThreadBase::mLock held
bool AudioFlinger::MixerThread::isTrackAllowed_l(
        audio_channel_mask_t channelMask, audio_format_t format,
@@ -6317,10 +6331,14 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
                // fill a buffer, then remove it from active list.
                // Only consider last track started for mixer state control
                if (--(track->mRetryCount) <= 0) {
                    const bool running = checkRunningTimestamp();
                    if (running) { // still running, give us more time.
                        track->mRetryCount = kMaxTrackRetriesOffload;
                    } else {
                        ALOGV("BUFFER TIMEOUT: remove track(%d) from active list", trackId);
                        tracksToRemove->add(track);
                    // indicate to client process that the track was disabled because of underrun;
                    // it will then automatically call start() when data is available
                        // indicate to client process that the track was disabled because of
                        // underrun; it will then automatically call start() when data is available
                        track->disable();
                        // only do hw pause when track is going to be removed due to BUFFER TIMEOUT.
                        // unlike mixerthread, HAL can be paused for direct output
@@ -6331,6 +6349,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
                            doHwPause = true;
                            mHwPaused = true;
                        }
                    }
                } else if (last) {
                    mixerStatus = MIXER_TRACKS_ENABLED;
                }
@@ -6540,6 +6559,7 @@ void AudioFlinger::DirectOutputThread::cacheParameters_l()

void AudioFlinger::DirectOutputThread::flushHw_l()
{
    PlaybackThread::flushHw_l();
    mOutput->flush();
    mHwPaused = false;
    mFlushPending = false;
@@ -6675,8 +6695,7 @@ void AudioFlinger::AsyncCallbackThread::setAsyncError()
AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
        AudioStreamOut* output, audio_io_handle_t id, bool systemReady)
    :   DirectOutputThread(audioFlinger, output, id, OFFLOAD, systemReady),
        mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true),
        mOffloadUnderrunPosition(~0LL)
        mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true)
{
    //FIXME: mStandby should be set to true by ThreadBase constructo
    mStandby = true;
@@ -6893,19 +6912,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
                // No buffers for this track. Give it a few chances to
                // fill a buffer, then remove it from active list.
                if (--(track->mRetryCount) <= 0) {
                    bool running = false;
                    uint64_t position = 0;
                    struct timespec unused;
                    // The running check restarts the retry counter at least once.
                    status_t ret = mOutput->stream->getPresentationPosition(&position, &unused);
                    if (ret == NO_ERROR && position != mOffloadUnderrunPosition) {
                        running = true;
                        mOffloadUnderrunPosition = position;
                    }
                    if (ret == NO_ERROR) {
                        ALOGVV("underrun counter, running(%d): %lld vs %lld", running,
                                (long long)position, (long long)mOffloadUnderrunPosition);
                    }
                    const bool running = checkRunningTimestamp();
                    if (running) { // still running, give us more time.
                        track->mRetryCount = kMaxTrackRetriesOffload;
                    } else {
@@ -6976,7 +6983,6 @@ void AudioFlinger::OffloadThread::flushHw_l()
    mPausedBytesRemaining = 0;
    // reset bytes written count to reflect that DSP buffers are empty after flush.
    mBytesWritten = 0;
    mOffloadUnderrunPosition = ~0LL;

    if (mUseAsyncWrite) {
        // discard any pending drain or write ack by incrementing sequence
+10 −6
Original line number Diff line number Diff line
@@ -1376,6 +1376,14 @@ protected:
                struct audio_patch mDownStreamPatch;

                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();

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

class MixerThread : public PlaybackThread {
@@ -1493,7 +1501,7 @@ public:
    virtual     bool        checkForNewParameter_l(const String8& keyValuePair,
                                                   status_t& status);

    virtual     void        flushHw_l();
                void        flushHw_l() override;

                void        setMasterBalance(float balance) override;

@@ -1558,7 +1566,7 @@ public:
    OffloadThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
                  audio_io_handle_t id, bool systemReady);
    virtual                 ~OffloadThread() {};
    virtual     void        flushHw_l();
                void        flushHw_l() override;

protected:
    // threadLoop snippets
@@ -1575,10 +1583,6 @@ private:
    size_t      mPausedWriteLength;     // length in bytes of write interrupted by pause
    size_t      mPausedBytesRemaining;  // bytes still waiting in mixbuffer after resume
    bool        mKeepWakeLock;          // keep wake lock while waiting for write callback
    uint64_t    mOffloadUnderrunPosition; // Current frame position for offloaded playback
                                          // used and valid only during underrun.  ~0 if
                                          // no underrun has occurred during playback and
                                          // is not reset on standby.
};

class AsyncCallbackThread : public Thread {