Issue 3032913: improve AudioTrack recovery time

This issue showed that when an AudioTrack underruns during a too long period
of time and is therefore disabled by audioflinger mixer, it takes an additional
delay of up to 3 seconds to recover.
This fix adds a simple mechanism to recover immediately when the client application
is ready to write data again in the AudioTrack buffer

Also throttle warnings on record overflows

Change-Id: I8b2c71578dd134b9e60a15ee4d91b70f3799cb3d
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 1510f87..c6990bf 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -42,8 +42,11 @@
 #define CBLK_FORCEREADY_ON      0x0004  // track is considered ready immediately by AudioFlinger
 #define CBLK_FORCEREADY_OFF     0x0000  // track is ready when buffer full
 #define CBLK_INVALID_MSK        0x0008
-#define CBLK_INVALID_ON         0x0008  // track buffer is invalidated by AudioFlinger: must be re-created
-#define CBLK_INVALID_OFF        0x0000
+#define CBLK_INVALID_ON         0x0008  // track buffer is invalidated by AudioFlinger:
+#define CBLK_INVALID_OFF        0x0000  // must be re-created
+#define CBLK_DISABLED_MSK       0x0010
+#define CBLK_DISABLED_ON        0x0010  // track disabled by AudioFlinger due to underrun:
+#define CBLK_DISABLED_OFF       0x0000  // must be re-started
 
 struct audio_track_cblk_t
 {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 890786e..587c8ff 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -316,6 +316,7 @@
         mNewPosition = mCblk->server + mUpdatePeriod;
         mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
         mCblk->waitTimeMs = 0;
+        mCblk->flags &= ~CBLK_DISABLED_ON;
         if (t != 0) {
            t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
         } else {
@@ -842,6 +843,13 @@
         cblk->lock.unlock();
     }
 
+    // restart track if it was disabled by audioflinger due to previous underrun
+    if (cblk->flags & CBLK_DISABLED_MSK) {
+        cblk->flags &= ~CBLK_DISABLED_ON;
+        LOGW("obtainBuffer() track %p disabled, restarting", this);
+        mAudioTrack->start();
+    }
+
     cblk->waitTimeMs = 0;
 
     if (framesReq > framesAvail) {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 97b8086..8527059 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1856,6 +1856,8 @@
                 if (--(track->mRetryCount) <= 0) {
                     LOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", track->name(), this);
                     tracksToRemove->add(track);
+                    // indicate to client process that the track was disabled because of underrun
+                    cblk->flags |= CBLK_DISABLED_ON;
                 } else if (mixerStatus != MIXER_TRACKS_READY) {
                     mixerStatus = MIXER_TRACKS_ENABLED;
                 }
@@ -2790,7 +2792,7 @@
                     mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
                     memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
                     // Force underrun condition to avoid false underrun callback until first data is
-                    // written to buffer
+                    // written to buffer (other flags are cleared)
                     mCblk->flags = CBLK_UNDERRUN_ON;
                 } else {
                     mBuffer = sharedBuffer->pointer();
@@ -2813,7 +2815,7 @@
            mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
            memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
            // Force underrun condition to avoid false underrun callback until first data is
-           // written to buffer
+           // written to buffer (other flags are cleared)
            mCblk->flags = CBLK_UNDERRUN_ON;
            mBufferEnd = (uint8_t *)mBuffer + bufferSize;
        }
@@ -3794,6 +3796,8 @@
     AudioBufferProvider::Buffer buffer;
     sp<RecordTrack> activeTrack;
 
+    nsecs_t lastWarning = 0;
+
     // start recording
     while (!exitPending()) {
 
@@ -3935,8 +3939,13 @@
             }
             // client isn't retrieving buffers fast enough
             else {
-                if (!mActiveTrack->setOverflow())
-                    LOGW("RecordThread: buffer overflow");
+                if (!mActiveTrack->setOverflow()) {
+                    nsecs_t now = systemTime();
+                    if ((now - lastWarning) > kWarningThrottle) {
+                        LOGW("RecordThread: buffer overflow");
+                        lastWarning = now;
+                    }
+                }
                 // Release the processor for a while before asking for a new buffer.
                 // This will give the application more chance to read from the buffer and
                 // clear the overflow.