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

Commit e265cf94 authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "AudioFlinger: Make Direct AudioTrack behavior more flexible for underrun" into sc-dev

parents f3d086f2 455982fd
Loading
Loading
Loading
Loading
+28 −6
Original line number Original line Diff line number Diff line
@@ -124,12 +124,26 @@ using media::permission::Identity;
// 50 * ~20msecs = 1 second
// 50 * ~20msecs = 1 second
static const int8_t kMaxTrackRetries = 50;
static const int8_t kMaxTrackRetries = 50;
static const int8_t kMaxTrackStartupRetries = 50;
static const int8_t kMaxTrackStartupRetries = 50;

// allow less retry attempts on direct output thread.
// allow less retry attempts on direct output thread.
// direct outputs can be a scarce resource in audio hardware and should
// direct outputs can be a scarce resource in audio hardware and should
// be released as quickly as possible.
// be released as quickly as possible.
static const int8_t kMaxTrackRetriesDirect = 2;
// Notes:

// 1) The retry duration kMaxTrackRetriesDirectMs may be increased

//    in case the data write is bursty for the AudioTrack.  The application
//    should endeavor to write at least once every kMaxTrackRetriesDirectMs
//    to prevent an underrun situation.  If the data is bursty, then
//    the application can also throttle the data sent to be even.
// 2) For compressed audio data, any data present in the AudioTrack buffer
//    will be sent and reset the retry count.  This delivers data as
//    it arrives, with approximately kDirectMinSleepTimeUs = 10ms checking interval.
// 3) For linear PCM or proportional PCM, we wait one period for a period's worth
//    of data to be available, then any remaining data is delivered.
//    This is required to ensure the last bit of data is delivered before underrun.
//
// Sleep time per cycle is kDirectMinSleepTimeUs for compressed tracks
// or the size of the HAL period for proportional / linear PCM tracks.
static const int32_t kMaxTrackRetriesDirectMs = 200;


// don't warn about blocked writes or record buffer overflows more often than this
// don't warn about blocked writes or record buffer overflows more often than this
static const nsecs_t kWarningThrottleNs = seconds(5);
static const nsecs_t kWarningThrottleNs = seconds(5);
@@ -5931,11 +5945,19 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
        // Allow draining the buffer in case the client
        // Allow draining the buffer in case the client
        // app does not call stop() and relies on underrun to stop:
        // app does not call stop() and relies on underrun to stop:
        // hence the test on (track->mRetryCount > 1).
        // hence the test on (track->mRetryCount > 1).
        // If retryCount<=1 then track is about to underrun and be removed.
        // If track->mRetryCount <= 1 then track is about to be disabled, paused, removed,
        // so we accept any nonzero amount of data delivered by the AudioTrack (which will
        // reset the retry counter).
        // Do not use a high threshold for compressed audio.
        // Do not use a high threshold for compressed audio.

        // target retry count that we will use is based on the time we wait for retries.
        const int32_t targetRetryCount = kMaxTrackRetriesDirectMs * 1000 / mActiveSleepTimeUs;
        // the retry threshold is when we accept any size for PCM data.  This is slightly
        // smaller than the retry count so we can push small bits of data without a glitch.
        const int32_t retryThreshold = targetRetryCount > 2 ? targetRetryCount - 1 : 1;
        uint32_t minFrames;
        uint32_t minFrames;
        if ((track->sharedBuffer() == 0) && !track->isStopping_1() && !track->isPausing()
        if ((track->sharedBuffer() == 0) && !track->isStopping_1() && !track->isPausing()
            && (track->mRetryCount > 1) && audio_has_proportional_frames(mFormat)) {
            && (track->mRetryCount > retryThreshold) && audio_has_proportional_frames(mFormat)) {
            minFrames = mNormalFrameCount;
            minFrames = mNormalFrameCount;
        } else {
        } else {
            minFrames = 1;
            minFrames = 1;
@@ -5979,7 +6001,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
                mPreviousTrack = track;
                mPreviousTrack = track;


                // reset retry count
                // reset retry count
                track->mRetryCount = kMaxTrackRetriesDirect;
                track->mRetryCount = targetRetryCount;
                mActiveTrack = t;
                mActiveTrack = t;
                mixerStatus = MIXER_TRACKS_READY;
                mixerStatus = MIXER_TRACKS_READY;
                if (mHwPaused) {
                if (mHwPaused) {