diff options
author | Eric Laurent <elaurent@google.com> | 2014-12-17 18:08:04 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-12-17 18:08:04 +0000 |
commit | 23c8dc13787186dc98731055858b2fba3aedc105 (patch) | |
tree | 08ed5ebd4244095641a3d7494e9dab6b6d471eb5 /services/audioflinger/Threads.cpp | |
parent | c30943f7485fa84a32e7d070234b3def692d9d16 (diff) | |
parent | 85aca658ac7d20584b0647427256df50a5f243ef (diff) | |
download | frameworks_av-23c8dc13787186dc98731055858b2fba3aedc105.zip frameworks_av-23c8dc13787186dc98731055858b2fba3aedc105.tar.gz frameworks_av-23c8dc13787186dc98731055858b2fba3aedc105.tar.bz2 |
am 85aca658: am d33712d7: am 145cf5d8: Merge "audioflinger: implement pause/resume for direct outputs" into lmp-mr1-dev
* commit '85aca658ac7d20584b0647427256df50a5f243ef':
audioflinger: implement pause/resume for direct outputs
Diffstat (limited to 'services/audioflinger/Threads.cpp')
-rw-r--r-- | services/audioflinger/Threads.cpp | 127 |
1 files changed, 106 insertions, 21 deletions
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index f93a2c5..984f8b7 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -1256,6 +1256,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) { @@ -1910,6 +1911,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 || @@ -3145,6 +3159,7 @@ void AudioFlinger::PlaybackThread::threadLoop_standby() mCallbackThread->setWriteBlocked(mWriteAckSequence); mCallbackThread->setDraining(mDrainSequence); } + mHwPaused = false; } void AudioFlinger::PlaybackThread::onAddNewTrack_l() @@ -4074,6 +4089,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++) { @@ -4092,6 +4110,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 @@ -4115,8 +4155,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(); } } @@ -4179,6 +4219,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); @@ -4211,6 +4275,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; @@ -4223,6 +4292,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) @@ -4332,8 +4433,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; } // ---------------------------------------------------------------------------- @@ -4442,8 +4545,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 @@ -4680,21 +4781,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); @@ -4709,7 +4795,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 |