AudioFlinger: mix track only when really ready (2)

This problem due to the way audio buffers are mixed when
low power mode is active was addressed by commits 19ddf0eb
and 8a04fe03 but only partially. As a matter of fact, when more
than one audio track is playing, the problem is still present.
This is most noticeable when playing music with screen off
and a notification or navigation instruction is played: in this case,
the music or notification is likely to skip.

The fix consists in declaring the mixer ready if all active tracks
are ready. Previous behavior was to declare ready if at least one track was
ready. To avoid that one application failing to fill the track buffer blocks other
tracks indefinitely, this condition is respected only if the mixer was ready
in the previous round.

Issue 5799167.

Change-Id: Iabd4ca08d3d45f563d9824c8a03c2c68a43ae179
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 060a632..133dabd 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1832,7 +1832,7 @@
 
 AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
     :   PlaybackThread(audioFlinger, output, id, device),
-        mAudioMixer(0)
+        mAudioMixer(0), mPrevMixerStatus(MIXER_IDLE)
 {
     mType = ThreadBase::MIXER;
     mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
@@ -1945,6 +1945,7 @@
                     LOGV("MixerThread %p TID %d waking up\n", this, gettid());
                     acquireWakeLock_l();
 
+                    mPrevMixerStatus = MIXER_IDLE;
                     if (mMasterMute == false) {
                         char value[PROPERTY_VALUE_MAX];
                         property_get("ro.audio.silent", value, "0");
@@ -2103,11 +2104,11 @@
         // make sure that we have enough frames to mix one full buffer.
         // enforce this condition only once to enable draining the buffer in case the client
         // app does not call stop() and relies on underrun to stop:
-        // hence the test on (track->mRetryCount >= kMaxTrackRetries) meaning the track was mixed
+        // hence the test on (mPrevMixerStatus == MIXER_TRACKS_READY) meaning the track was mixed
         // during last round
         uint32_t minFrames = 1;
         if (!track->isStopped() && !track->isPausing() &&
-                (track->mRetryCount >= kMaxTrackRetries)) {
+                (mPrevMixerStatus == MIXER_TRACKS_READY)) {
             if (t->sampleRate() == (int)mSampleRate) {
                 minFrames = mFrameCount;
             } else {
@@ -2229,7 +2230,13 @@
 
             // reset retry count
             track->mRetryCount = kMaxTrackRetries;
-            mixerStatus = MIXER_TRACKS_READY;
+            // If one track is ready, set the mixer ready if:
+            //  - the mixer was not ready during previous round OR
+            //  - no other track is not ready
+            if (mPrevMixerStatus != MIXER_TRACKS_READY ||
+                    mixerStatus != MIXER_TRACKS_ENABLED) {
+                mixerStatus = MIXER_TRACKS_READY;
+            }
         } else {
             //LOGV("track %d u=%08x, s=%08x [NOT READY] on thread %p", track->name(), cblk->user, cblk->server, this);
             if (track->isStopped()) {
@@ -2247,7 +2254,11 @@
                     tracksToRemove->add(track);
                     // indicate to client process that the track was disabled because of underrun
                     android_atomic_or(CBLK_DISABLED_ON, &cblk->flags);
-                } else if (mixerStatus != MIXER_TRACKS_READY) {
+                // If one track is not ready, mark the mixer also not ready if:
+                //  - the mixer was ready during previous round OR
+                //  - no other track is ready
+                } else if (mPrevMixerStatus == MIXER_TRACKS_READY ||
+                                mixerStatus != MIXER_TRACKS_READY) {
                     mixerStatus = MIXER_TRACKS_ENABLED;
                 }
             }
@@ -2281,6 +2292,7 @@
         memset(mMixBuffer, 0, mFrameCount * mChannelCount * sizeof(int16_t));
     }
 
+    mPrevMixerStatus = mixerStatus;
     return mixerStatus;
 }
 
@@ -3016,6 +3028,7 @@
                     LOGV("DuplicatingThread %p TID %d waking up\n", this, gettid());
                     acquireWakeLock_l();
 
+                    mPrevMixerStatus = MIXER_IDLE;
                     if (mMasterMute == false) {
                         char value[PROPERTY_VALUE_MAX];
                         property_get("ro.audio.silent", value, "0");
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 6cafa7e..9bd2c7f 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -836,7 +836,9 @@
         virtual     uint32_t    idleSleepTimeUs();
         virtual     uint32_t    suspendSleepTimeUs();
 
-        AudioMixer*                     mAudioMixer;
+                    AudioMixer* mAudioMixer;
+                    uint32_t    mPrevMixerStatus; // previous status (mixer_state) returned by
+                                                  // prepareTracks_l()
     };
 
     class DirectOutputThread : public PlaybackThread {