Merge "audioflinger: implement pause/resume for direct outputs" into lmp-mr1-dev
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index d9c3177..389aacc 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -335,6 +335,11 @@
                 ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST);
     }
 
+    // force direct flag if HW A/V sync requested
+    if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) {
+        flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
+    }
+
     if (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
         if (audio_is_linear_pcm(format)) {
             mFrameSize = channelCount * audio_bytes_per_sample(format);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 87f636c..dacb12c 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1197,6 +1197,7 @@
         mScreenState(AudioFlinger::mScreenState),
         // index 0 is reserved for normal mixer's submix
         mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1),
+        mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
         // mLatchD, mLatchQ,
         mLatchDValid(false), mLatchQValid(false)
 {
@@ -1847,6 +1848,19 @@
         }
     }
 
+    mHwSupportsPause = false;
+    if (mOutput->flags & AUDIO_OUTPUT_FLAG_DIRECT) {
+        if (mOutput->stream->pause != NULL) {
+            if (mOutput->stream->resume != NULL) {
+                mHwSupportsPause = true;
+            } else {
+                ALOGW("direct output implements pause but not resume");
+            }
+        } else if (mOutput->stream->resume != NULL) {
+            ALOGW("direct output implements resume but not pause");
+        }
+    }
+
     // Calculate size of normal sink buffer relative to the HAL output buffer size
     double multiplier = 1.0;
     if (mType == MIXER && (kUseFastMixer == FastMixer_Static ||
@@ -3078,6 +3092,7 @@
         mCallbackThread->setWriteBlocked(mWriteAckSequence);
         mCallbackThread->setDraining(mDrainSequence);
     }
+    mHwPaused = false;
 }
 
 void AudioFlinger::PlaybackThread::onAddNewTrack_l()
@@ -3990,6 +4005,9 @@
 {
     size_t count = mActiveTracks.size();
     mixer_state mixerStatus = MIXER_IDLE;
+    bool doHwPause = false;
+    bool doHwResume = false;
+    bool flushPending = false;
 
     // find out which tracks need to be processed
     for (size_t i = 0; i < count; i++) {
@@ -4008,6 +4026,28 @@
         sp<Track> l = mLatestActiveTrack.promote();
         bool last = l.get() == track;
 
+        if (mHwSupportsPause && track->isPausing()) {
+            track->setPaused();
+            if (last && !mHwPaused) {
+                doHwPause = true;
+                mHwPaused = true;
+            }
+            tracksToRemove->add(track);
+        } else if (track->isFlushPending()) {
+            track->flushAck();
+            if (last) {
+                flushPending = true;
+            }
+        } else if (mHwSupportsPause && track->isResumePending()){
+            track->resumeAck();
+            if (last) {
+                if (mHwPaused) {
+                    doHwResume = true;
+                    mHwPaused = false;
+                }
+            }
+        }
+
         // The first time a track is added we wait
         // for all its buffers to be filled before processing it.
         // Allow draining the buffer in case the client
@@ -4031,8 +4071,8 @@
                 track->mFillingUpStatus = Track::FS_ACTIVE;
                 // make sure processVolume_l() will apply new volume even if 0
                 mLeftVolFloat = mRightVolFloat = -1.0;
-                if (track->mState == TrackBase::RESUMING) {
-                    track->mState = TrackBase::ACTIVE;
+                if (!mHwSupportsPause) {
+                    track->resumeAck();
                 }
             }
 
@@ -4095,6 +4135,30 @@
         }
     }
 
+    // if an active track did not command a flush, check for pending flush on stopped tracks
+    if (!flushPending) {
+        for (size_t i = 0; i < mTracks.size(); i++) {
+            if (mTracks[i]->isFlushPending()) {
+                mTracks[i]->flushAck();
+                flushPending = true;
+            }
+        }
+    }
+
+    // make sure the pause/flush/resume sequence is executed in the right order.
+    // If a flush is pending and a track is active but the HW is not paused, force a HW pause
+    // before flush and then resume HW. This can happen in case of pause/flush/resume
+    // if resume is received before pause is executed.
+    if (mHwSupportsPause && !mStandby &&
+            (doHwPause || (flushPending && !mHwPaused && (count != 0)))) {
+        mOutput->stream->pause(mOutput->stream);
+    }
+    if (flushPending) {
+        flushHw_l();
+    }
+    if (mHwSupportsPause && !mStandby && doHwResume) {
+        mOutput->stream->resume(mOutput->stream);
+    }
     // remove all the tracks that need to be...
     removeTracks_l(*tracksToRemove);
 
@@ -4127,6 +4191,11 @@
 
 void AudioFlinger::DirectOutputThread::threadLoop_sleepTime()
 {
+    // do not write to HAL when paused
+    if (mHwPaused) {
+        sleepTime = idleSleepTime;
+        return;
+    }
     if (sleepTime == 0) {
         if (mMixerStatus == MIXER_TRACKS_ENABLED) {
             sleepTime = activeSleepTime;
@@ -4139,6 +4208,38 @@
     }
 }
 
+void AudioFlinger::DirectOutputThread::threadLoop_exit()
+{
+    {
+        Mutex::Autolock _l(mLock);
+        bool flushPending = false;
+        for (size_t i = 0; i < mTracks.size(); i++) {
+            if (mTracks[i]->isFlushPending()) {
+                mTracks[i]->flushAck();
+                flushPending = true;
+            }
+        }
+        if (flushPending) {
+            flushHw_l();
+        }
+    }
+    PlaybackThread::threadLoop_exit();
+}
+
+// must be called with thread mutex locked
+bool AudioFlinger::DirectOutputThread::shouldStandby_l()
+{
+    bool trackPaused = false;
+
+    // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack
+    // after a timeout and we will enter standby then.
+    if (mTracks.size() > 0) {
+        trackPaused = mTracks[mTracks.size() - 1]->isPaused();
+    }
+
+    return !mStandby && !trackPaused;
+}
+
 // getTrackName_l() must be called with ThreadBase::mLock held
 int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused,
         audio_format_t format __unused, int sessionId __unused)
@@ -4248,8 +4349,10 @@
 
 void AudioFlinger::DirectOutputThread::flushHw_l()
 {
-    if (mOutput->stream->flush != NULL)
+    if (mOutput->stream->flush != NULL) {
         mOutput->stream->flush(mOutput->stream);
+    }
+    mHwPaused = false;
 }
 
 // ----------------------------------------------------------------------------
@@ -4358,8 +4461,6 @@
 AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
         AudioStreamOut* output, audio_io_handle_t id, uint32_t device)
     :   DirectOutputThread(audioFlinger, output, id, device, OFFLOAD),
-        mHwPaused(false),
-        mFlushPending(false),
         mPausedBytesRemaining(0)
 {
     //FIXME: mStandby should be set to true by ThreadBase constructor
@@ -4596,21 +4697,6 @@
     return false;
 }
 
-// must be called with thread mutex locked
-bool AudioFlinger::OffloadThread::shouldStandby_l()
-{
-    bool trackPaused = false;
-
-    // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack
-    // after a timeout and we will enter standby then.
-    if (mTracks.size() > 0) {
-        trackPaused = mTracks[mTracks.size() - 1]->isPaused();
-    }
-
-    return !mStandby && !trackPaused;
-}
-
-
 bool AudioFlinger::OffloadThread::waitingAsyncCallback()
 {
     Mutex::Autolock _l(mLock);
@@ -4625,7 +4711,6 @@
     mBytesRemaining = 0;
     mPausedWriteLength = 0;
     mPausedBytesRemaining = 0;
-    mHwPaused = false;
 
     if (mUseAsyncWrite) {
         // discard any pending drain or write ack by incrementing sequence
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 119e495..f5d0e27 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -809,7 +809,9 @@
 protected:
                 // accessed by both binder threads and within threadLoop(), lock on mutex needed
                 unsigned    mFastTrackAvailMask;    // bit i set if fast track [i] is available
-
+                bool        mHwSupportsPause;
+                bool        mHwPaused;
+                bool        mFlushPending;
 private:
     // timestamp latch:
     //  D input is written by threadLoop_write while mutex is unlocked, and read while locked
@@ -910,6 +912,8 @@
     virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
     virtual     void        threadLoop_mix();
     virtual     void        threadLoop_sleepTime();
+    virtual     void        threadLoop_exit();
+    virtual     bool        shouldStandby_l();
 
     // volumes last sent to audio HAL with stream->set_volume()
     float mLeftVolFloat;
@@ -940,12 +944,9 @@
 
     virtual     bool        waitingAsyncCallback();
     virtual     bool        waitingAsyncCallback_l();
-    virtual     bool        shouldStandby_l();
     virtual     void        onAddNewTrack_l();
 
 private:
-    bool        mHwPaused;
-    bool        mFlushPending;
     size_t      mPausedWriteLength;     // length in bytes of write interrupted by pause
     size_t      mPausedBytesRemaining;  // bytes still waiting in mixbuffer after resume
     wp<Track>   mPreviousTrack;         // used to detect track switch
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index fcbf8f8..e970036 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -823,12 +823,11 @@
             // this will be done by prepareTracks_l() when the track is stopped.
             // prepareTracks_l() will see mState == FLUSHED, then
             // remove from active track list, reset(), and trigger presentation complete
+            if (isDirect()) {
+                mFlushHwPending = true;
+            }
             if (playbackThread->mActiveTracks.indexOf(this) < 0) {
                 reset();
-                if (thread->type() == ThreadBase::DIRECT) {
-                    DirectOutputThread *t = (DirectOutputThread *)playbackThread;
-                    t->flushHw_l();
-                }
             }
         }
         // Prevent flush being lost if the track is flushed and then resumed
@@ -841,7 +840,7 @@
 // must be called with thread lock held
 void AudioFlinger::PlaybackThread::Track::flushAck()
 {
-    if (!isOffloaded())
+    if (!isOffloaded() && !isDirect())
         return;
 
     mFlushHwPending = false;