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

Commit 82aaf94a authored by Glenn Kasten's avatar Glenn Kasten
Browse files

Report underruns for fast tracks also

This fixes a regression that was introduced earlier
by commit 9f80dd22
called "New control block for AudioTrack and AudioRecord".
That commit broke underrun reporting for fast tracks.

Also remove Track::mUnderrunCount, which counted the number of underrun
events, and was only used by dumpsys media.audio_flinger.

Now dumpsys media.audio_flinger reports the number of underrun frames,

Isolated underrun-related control block accesses via the proxy, so that
the server is not directly poking around in the control block.

The new proxy APIs are AudioTrackServerProxy::getUnderrunFrames() and
AudioTrackServerProxy::tallyUnderrunFrames().  getUnderrunFrames() returns
a rolling counter for streaming tracks, or zero for static buffer tracks
which never underrun, but do a kind of 'pause' at end of buffer.
tallyUnderrunFrames() increments the counter by a specified number of frames.

Change-Id: Ib31fd73eb17cbb23888ce3af8ff29f471f5bd5a2
parent b08ab81b
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -415,6 +415,13 @@ public:
    virtual void        framesReadyIsCalledByMultipleThreads() { }

    bool     setStreamEndDone();    // and return previous value

    // Add to the tally of underrun frames, and inform client of underrun
    virtual void        tallyUnderrunFrames(uint32_t frameCount);

    // Return the total number of frames which AudioFlinger desired but were unavailable,
    // and thus which resulted in an underrun.
    virtual uint32_t    getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; }
};

class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
@@ -429,6 +436,8 @@ public:
    virtual void        framesReadyIsCalledByMultipleThreads();
    virtual status_t    obtainBuffer(Buffer* buffer);
    virtual void        releaseBuffer(Buffer* buffer);
    virtual void        tallyUnderrunFrames(uint32_t frameCount);
    virtual uint32_t    getUnderrunFrames() const { return 0; }

private:
    ssize_t             pollPosition(); // poll for state queue update, and return current position
+19 −0
Original line number Diff line number Diff line
@@ -661,6 +661,14 @@ bool AudioTrackServerProxy::setStreamEndDone() {
    return old;
}

void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
{
    mCblk->u.mStreaming.mUnderrunFrames += frameCount;

    // FIXME also wake futex so that underrun is noticed more quickly
    (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
}

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

StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers,
@@ -817,6 +825,17 @@ void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
    buffer->mNonContig = 0;
}

void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
{
    // Unlike AudioTrackServerProxy::tallyUnderrunFrames() used for streaming tracks,
    // we don't have a location to count underrun frames.  The underrun frame counter
    // only exists in AudioTrackSharedStreaming.  Fortunately, underruns are not
    // possible for static buffer tracks other than at end of buffer, so this is not a loss.

    // FIXME also wake futex so that underrun is noticed more quickly
    (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
}

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

}   // namespace android
+0 −1
Original line number Diff line number Diff line
@@ -140,7 +140,6 @@ private:
                                    // but the slot is only used if track is active
    FastTrackUnderruns  mObservedUnderruns; // Most recently observed value of
                                    // mFastMixerDumpState.mTracks[mFastIndex].mUnderruns
    uint32_t            mUnderrunCount; // Counter of total number of underruns, never reset
    volatile float      mCachedVolume;  // combined master volume and stream type volume;
                                        // 'volatile' means accessed without lock or
                                        // barrier, but is read/written atomically
+5 −8
Original line number Diff line number Diff line
@@ -2739,8 +2739,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
            track->mObservedUnderruns = underruns;
            // don't count underruns that occur while stopping or pausing
            // or stopped which can occur when flush() is called while active
            if (!(track->isStopping() || track->isPausing() || track->isStopped())) {
                track->mUnderrunCount += recentUnderruns;
            if (!(track->isStopping() || track->isPausing() || track->isStopped()) &&
                    recentUnderruns > 0) {
                // FIXME fast mixer will pull & mix partial buffers, but we count as a full underrun
                track->mAudioTrackServerProxy->tallyUnderrunFrames(recentUnderruns * mFrameCount);
            }

            // This is similar to the state machine for normal tracks,
@@ -3056,12 +3058,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
                mixerStatus = MIXER_TRACKS_READY;
            }
        } else {
            // only implemented for normal tracks, not fast tracks
            if (framesReady < desiredFrames && !track->isStopped() && !track->isPaused()) {
                // we missed desiredFrames whatever the actual number of frames missing was
                cblk->u.mStreaming.mUnderrunFrames += desiredFrames;
                // FIXME also wake futex so that underrun is noticed more quickly
                (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
                track->mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
            }
            // clear effect chain input buffer if an active track underruns to avoid sending
            // previous audio buffer again to effects
@@ -3086,7 +3084,6 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
                    tracksToRemove->add(track);
                }
            } else {
                track->mUnderrunCount++;
                // No buffers for this track. Give it a few chances to
                // fill a buffer, then remove it from active list.
                if (--(track->mRetryCount) <= 0) {
+3 −7
Original line number Diff line number Diff line
@@ -316,7 +316,6 @@ AudioFlinger::PlaybackThread::Track::Track(
    mPresentationCompleteFrames(0),
    mFlags(flags),
    mFastIndex(-1),
    mUnderrunCount(0),
    mCachedVolume(1.0),
    mIsInvalid(false),
    mAudioTrackServerProxy(NULL),
@@ -389,7 +388,7 @@ void AudioFlinger::PlaybackThread::Track::destroy()
/*static*/ void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result)
{
    result.append("   Name Client Type Fmt Chn mask Session fCount S F SRate  "
                  "L dB  R dB    Server Main buf  Aux Buf Flags Underruns\n");
                  "L dB  R dB    Server Main buf  Aux Buf Flags UndFrmCnt\n");
}

void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
@@ -470,7 +469,7 @@ void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
            (int)mMainBuffer,
            (int)mAuxBuffer,
            mCblk->mFlags,
            mUnderrunCount,
            mAudioTrackServerProxy->getUnderrunFrames(),
            nowInUnderrun);
}

@@ -489,10 +488,7 @@ status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(
    buffer->frameCount = buf.mFrameCount;
    buffer->raw = buf.mRaw;
    if (buf.mFrameCount == 0) {
        // only implemented so far for normal tracks, not fast tracks
        mCblk->u.mStreaming.mUnderrunFrames += desiredFrames;
        // FIXME also wake futex so that underrun is noticed more quickly
        (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
        mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
    }
    return status;
}