diff options
author | Eric Laurent <elaurent@google.com> | 2014-12-17 18:04:15 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-12-17 18:04:15 +0000 |
commit | 85aca658ac7d20584b0647427256df50a5f243ef (patch) | |
tree | 0a368cd14a99953de3943fa6f43334a8aea9f19f /services/audioflinger | |
parent | 22dfb93254de370d401706728aba1f032ef1b172 (diff) | |
parent | d33712d7ec5dcf427cc0be9b7d2ca1c99823c8e6 (diff) | |
download | frameworks_av-85aca658ac7d20584b0647427256df50a5f243ef.zip frameworks_av-85aca658ac7d20584b0647427256df50a5f243ef.tar.gz frameworks_av-85aca658ac7d20584b0647427256df50a5f243ef.tar.bz2 |
am d33712d7: am 145cf5d8: Merge "audioflinger: implement pause/resume for direct outputs" into lmp-mr1-dev
* commit 'd33712d7ec5dcf427cc0be9b7d2ca1c99823c8e6':
audioflinger: implement pause/resume for direct outputs
Diffstat (limited to 'services/audioflinger')
-rw-r--r-- | services/audioflinger/Threads.cpp | 127 | ||||
-rw-r--r-- | services/audioflinger/Threads.h | 9 | ||||
-rw-r--r-- | services/audioflinger/Tracks.cpp | 9 |
3 files changed, 115 insertions, 30 deletions
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index b20b238..d5bb0af 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -1197,6 +1197,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge 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 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l() } } + 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 @@ void AudioFlinger::PlaybackThread::threadLoop_standby() mCallbackThread->setWriteBlocked(mWriteAckSequence); mCallbackThread->setDraining(mDrainSequence); } + mHwPaused = false; } void AudioFlinger::PlaybackThread::onAddNewTrack_l() @@ -3990,6 +4005,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep { 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 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep 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 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep 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 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep } } + // 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_mix() 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_sleepTime() } } +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::cacheParameters_l() 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 @@ void AudioFlinger::AsyncCallbackThread::resetDraining() 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 @@ bool AudioFlinger::OffloadThread::waitingAsyncCallback_l() 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 @@ void AudioFlinger::OffloadThread::flushHw_l() 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 @@ public: 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 @@ protected: 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 @@ protected: 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 @@ void AudioFlinger::PlaybackThread::Track::flush() // 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 @@ void AudioFlinger::PlaybackThread::Track::flush() // must be called with thread lock held void AudioFlinger::PlaybackThread::Track::flushAck() { - if (!isOffloaded()) + if (!isOffloaded() && !isDirect()) return; mFlushHwPending = false; |