audio flinger: fix offload track underrun

Fix offload track underrun detection causing early disabling
of offloaded audio tracks.

Optimize sleep time in case of underrun to avoid spinning while
waiting for new data.

Re-enable offload when streaming

Bug: 26668110

Change-Id: I874728c69647ac05e1effb84c48700a6d0ac7435
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9397729..5980b58 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1819,7 +1819,8 @@
 
         PlaybackThread *thread;
         if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
-            thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
+            thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady,
+                                       config->offload_info.bit_rate);
             ALOGV("openOutput_l() created offload output: ID %d thread %p", *output, thread);
         } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
                 || !isValidPcmSinkFormat(config->format)
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 2bc3596..96c5f59 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -108,6 +108,13 @@
 // direct outputs can be a scarce resource in audio hardware and should
 // be released as quickly as possible.
 static const int8_t kMaxTrackRetriesDirect = 2;
+// retry count before removing active track in case of underrun on offloaded thread:
+// we need to make sure that AudioTrack client has enough time to send large buffers
+//FIXME may be more appropriate if expressed in time units. Need to revise how underrun is handled
+// for offloaded tracks
+static const int8_t kMaxTrackRetriesOffload = 10;
+static const int8_t kMaxTrackStartupRetriesOffload = 100;
+
 
 // don't warn about blocked writes or record buffer overflows more often than this
 static const nsecs_t kWarningThrottleNs = seconds(5);
@@ -136,6 +143,14 @@
 // Offloaded output thread standby delay: allows track transition without going to standby
 static const nsecs_t kOffloadStandbyDelayNs = seconds(1);
 
+// Direct output thread minimum sleep time in idle or active(underrun) state
+static const nsecs_t kDirectMinSleepTimeUs = 10000;
+
+// Offloaded output bit rate in bits per second when unknown.
+// Used for sleep time calculation, so use a high default bitrate to be conservative on sleep time.
+static const uint32_t kOffloadDefaultBitRateBps = 1500000;
+
+
 // Whether to use fast mixer
 static const enum {
     FastMixer_Never,    // never initialize or use: for debugging only
@@ -1553,7 +1568,8 @@
                                              audio_io_handle_t id,
                                              audio_devices_t device,
                                              type_t type,
-                                             bool systemReady)
+                                             bool systemReady,
+                                             uint32_t bitRate)
     :   ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type, systemReady),
         mNormalFrameCount(0), mSinkBuffer(NULL),
         mMixerBufferEnabled(AudioFlinger::kEnableExtendedPrecision),
@@ -1616,6 +1632,13 @@
         mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream);
         mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream);
     }
+
+    if (audio_has_proportional_frames(mFormat)) {
+        mBufferDurationUs = (uint32_t)((mNormalFrameCount * 1000000LL) / mSampleRate);
+    } else {
+        bitRate = bitRate != 0 ? bitRate : kOffloadDefaultBitRateBps;
+        mBufferDurationUs = (uint32_t)((mBufferSize * 8 * 1000000LL) / bitRate);
+    }
 }
 
 AudioFlinger::PlaybackThread::~PlaybackThread()
@@ -2008,8 +2031,6 @@
 {
     status_t status = ALREADY_EXISTS;
 
-    // set retry count for buffer fill
-    track->mRetryCount = kMaxTrackStartupRetries;
     if (mActiveTracks.indexOf(track) < 0) {
         // the track is newly added, make sure it fills up all its
         // buffers before playing. This is to ensure the client will
@@ -2040,6 +2061,13 @@
 #endif
         }
 
+        // set retry count for buffer fill
+        if (track->isOffloaded()) {
+            track->mRetryCount = kMaxTrackStartupRetriesOffload;
+        } else {
+            track->mRetryCount = kMaxTrackStartupRetries;
+        }
+
         track->mFillingUpStatus = track->sharedBuffer() != 0 ? Track::FS_FILLED : Track::FS_FILLING;
         track->mResetDone = false;
         track->mPresentationCompleteFrames = 0;
@@ -2572,6 +2600,7 @@
         // FIXME We should have an implementation of timestamps for direct output threads.
         // They are used e.g for multichannel PCM playback over HDMI.
         bytesWritten = mOutput->write((char *)mSinkBuffer + offset, mBytesRemaining);
+
         if (mUseAsyncWrite &&
                 ((bytesWritten < 0) || (bytesWritten == (ssize_t)mBytesRemaining))) {
             // do not wait for async callback in case of error of full write
@@ -3137,7 +3166,30 @@
 
             } else {
                 ATRACE_BEGIN("sleep");
-                usleep(mSleepTimeUs);
+                if ((mType == OFFLOAD) && !audio_has_proportional_frames(mFormat)) {
+                    Mutex::Autolock _l(mLock);
+                    if (!mSignalPending && !exitPending()) {
+                        // Do not sleep more than one buffer duration since last write and not
+                        // less than kDirectMinSleepTimeUs
+                        // Wake up if a command is received
+                        nsecs_t now = systemTime();
+                        uint32_t deltaUs = (uint32_t)((now - mLastWriteTime) / 1000);
+                        uint32_t timeoutUs = mSleepTimeUs;
+                        if (timeoutUs + deltaUs > mBufferDurationUs) {
+                            if (mBufferDurationUs > deltaUs) {
+                                timeoutUs = mBufferDurationUs - deltaUs;
+                                if (timeoutUs < kDirectMinSleepTimeUs) {
+                                    timeoutUs = kDirectMinSleepTimeUs;
+                                }
+                            } else {
+                                timeoutUs = kDirectMinSleepTimeUs;
+                            }
+                        }
+                        mWaitWorkCV.waitRelative(mLock, microseconds((nsecs_t)timeoutUs));
+                    }
+                } else {
+                    usleep(mSleepTimeUs);
+                }
                 ATRACE_END();
             }
         }
@@ -4583,16 +4635,17 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
-        AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, bool systemReady)
-    :   PlaybackThread(audioFlinger, output, id, device, DIRECT, systemReady)
+        AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, bool systemReady,
+        uint32_t bitRate)
+    :   PlaybackThread(audioFlinger, output, id, device, DIRECT, systemReady, bitRate)
         // mLeftVolFloat, mRightVolFloat
 {
 }
 
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
         AudioStreamOut* output, audio_io_handle_t id, uint32_t device,
-        ThreadBase::type_t type, bool systemReady)
-    :   PlaybackThread(audioFlinger, output, id, device, type, systemReady)
+        ThreadBase::type_t type, bool systemReady, uint32_t bitRate)
+    :   PlaybackThread(audioFlinger, output, id, device, type, systemReady, bitRate)
         // mLeftVolFloat, mRightVolFloat
 {
 }
@@ -4871,7 +4924,10 @@
         buffer.frameCount = frameCount;
         status_t status = mActiveTrack->getNextBuffer(&buffer);
         if (status != NO_ERROR || buffer.raw == NULL) {
-            memset(curBuf, 0, frameCount * mFrameSize);
+            // no need to pad with 0 for compressed audio
+            if (audio_has_proportional_frames(mFormat)) {
+                memset(curBuf, 0, frameCount * mFrameSize);
+            }
             break;
         }
         memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize);
@@ -4894,7 +4950,14 @@
     }
     if (mSleepTimeUs == 0) {
         if (mMixerStatus == MIXER_TRACKS_ENABLED) {
-            mSleepTimeUs = mActiveSleepTimeUs;
+            // For compressed offload, use faster sleep time when underruning until more than an
+            // entire buffer was written to the audio HAL
+            if (!audio_has_proportional_frames(mFormat) &&
+                    (mType == OFFLOAD) && (mBytesWritten < mBufferSize)) {
+                mSleepTimeUs = kDirectMinSleepTimeUs;
+            } else {
+                mSleepTimeUs = mActiveSleepTimeUs;
+            }
         } else {
             mSleepTimeUs = mIdleSleepTimeUs;
         }
@@ -5008,7 +5071,7 @@
     if (audio_has_proportional_frames(mFormat)) {
         time = PlaybackThread::activeSleepTimeUs();
     } else {
-        time = 10000;
+        time = kDirectMinSleepTimeUs;
     }
     return time;
 }
@@ -5019,7 +5082,7 @@
     if (audio_has_proportional_frames(mFormat)) {
         time = (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000) / 2;
     } else {
-        time = 10000;
+        time = kDirectMinSleepTimeUs;
     }
     return time;
 }
@@ -5030,7 +5093,7 @@
     if (audio_has_proportional_frames(mFormat)) {
         time = (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000);
     } else {
-        time = 10000;
+        time = kDirectMinSleepTimeUs;
     }
     return time;
 }
@@ -5162,8 +5225,9 @@
 
 // ----------------------------------------------------------------------------
 AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
-        AudioStreamOut* output, audio_io_handle_t id, uint32_t device, bool systemReady)
-    :   DirectOutputThread(audioFlinger, output, id, device, OFFLOAD, systemReady),
+        AudioStreamOut* output, audio_io_handle_t id, uint32_t device, bool systemReady,
+        uint32_t bitRate)
+    :   DirectOutputThread(audioFlinger, output, id, device, OFFLOAD, systemReady, bitRate),
         mPausedBytesRemaining(0)
 {
     //FIXME: mStandby should be set to true by ThreadBase constructor
@@ -5244,6 +5308,7 @@
             }
             tracksToRemove->add(track);
         } else if (track->isFlushPending()) {
+            track->mRetryCount = kMaxTrackRetriesOffload;
             track->flushAck();
             if (last) {
                 mFlushPending = true;
@@ -5424,6 +5489,20 @@
     }
 }
 
+uint32_t AudioFlinger::OffloadThread::activeSleepTimeUs() const
+{
+    uint32_t time;
+    if (audio_has_proportional_frames(mFormat)) {
+        time = PlaybackThread::activeSleepTimeUs();
+    } else {
+        // sleep time is half the duration of an audio HAL buffer.
+        // Note: This can be problematic in case of underrun with variable bit rate and
+        // current rate is much less than initial rate.
+        time = (uint32_t)max(kDirectMinSleepTimeUs, mBufferDurationUs / 2);
+    }
+    return time;
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 42b3266..d1613db 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -479,14 +479,9 @@
         // suspend by audio policy manager is orthogonal to mixer state
     };
 
-    // retry count before removing active track in case of underrun on offloaded thread:
-    // we need to make sure that AudioTrack client has enough time to send large buffers
-//FIXME may be more appropriate if expressed in time units. Need to revise how underrun is handled
-    // for offloaded tracks
-    static const int8_t kMaxTrackRetriesOffload = 20;
-
     PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                   audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady);
+                   audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady,
+                   uint32_t bitRate = 0);
     virtual             ~PlaybackThread();
 
                 void        dump(int fd, const Vector<String16>& args);
@@ -841,6 +836,8 @@
                 bool        mHwSupportsPause;
                 bool        mHwPaused;
                 bool        mFlushPending;
+                uint32_t    mBufferDurationUs;      // estimated duration of an audio HAL buffer
+                                                    // based on initial bit rate (offload only)
 };
 
 class MixerThread : public PlaybackThread {
@@ -931,7 +928,8 @@
 public:
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                       audio_io_handle_t id, audio_devices_t device, bool systemReady);
+                       audio_io_handle_t id, audio_devices_t device, bool systemReady,
+                       uint32_t bitRate = 0);
     virtual                 ~DirectOutputThread();
 
     // Thread virtuals
@@ -964,7 +962,7 @@
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
                         audio_io_handle_t id, uint32_t device, ThreadBase::type_t type,
-                        bool systemReady);
+                        bool systemReady, uint32_t bitRate = 0);
     void processVolume_l(Track *track, bool lastTrack);
 
     // prepareTracks_l() tells threadLoop_mix() the name of the single active track
@@ -980,7 +978,8 @@
 public:
 
     OffloadThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                        audio_io_handle_t id, uint32_t device, bool systemReady);
+                        audio_io_handle_t id, uint32_t device,
+                        bool systemReady, uint32_t bitRate);
     virtual                 ~OffloadThread() {};
     virtual     void        flushHw_l();
 
@@ -989,6 +988,8 @@
     virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
     virtual     void        threadLoop_exit();
 
+    virtual     uint32_t    activeSleepTimeUs() const;
+
     virtual     bool        waitingAsyncCallback();
     virtual     bool        waitingAsyncCallback_l();
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index e684fc2..8b49062 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -792,11 +792,6 @@
                 mState = ACTIVE;
             }
 
-            if (mState == ACTIVE) {
-                ALOGV("flush called in active state, resetting buffer time out retry count");
-                mRetryCount = PlaybackThread::kMaxTrackRetriesOffload;
-            }
-
             mFlushHwPending = true;
             mResumeToStopping = false;
         } else {