diff options
author | Eric Laurent <elaurent@google.com> | 2013-09-19 14:37:46 -0700 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2013-09-19 15:53:20 -0700 |
commit | ede6c3b8b1147bc425f7b923882f559a513fe23b (patch) | |
tree | ac3986f0521aa4a5af705299ab423ec9d5e98bfa /services/audioflinger | |
parent | 5baf2af52cd186633b7173196c1e4a4cd3435f22 (diff) | |
download | frameworks_av-ede6c3b8b1147bc425f7b923882f559a513fe23b.zip frameworks_av-ede6c3b8b1147bc425f7b923882f559a513fe23b.tar.gz frameworks_av-ede6c3b8b1147bc425f7b923882f559a513fe23b.tar.bz2 |
audioflinger: fix lost offload thread resume event
It was possible that a resume request signaled by addTrack_l()
while waiting for an async write callback is lost. This is because
mSignalPending was not set and waitingAsyncCallback_l() would pause the
thread loop before executing prepareTracks_l().
The fix consists in using signal_l() method to wake the thread
loop o that mSignalPending is set.
Also make sure that sleepTime is reset to 0 when resuming to make sure
that we write any remaining bytes to the HAL.
Bug: 10810347.
Change-Id: If9a3b22cc3b9e6eb384a56c48c40e6258d0896ad
Diffstat (limited to 'services/audioflinger')
-rw-r--r-- | services/audioflinger/Threads.cpp | 59 | ||||
-rw-r--r-- | services/audioflinger/Threads.h | 4 | ||||
-rw-r--r-- | services/audioflinger/Tracks.cpp | 4 |
3 files changed, 37 insertions, 30 deletions
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 7d0ecac..9210330 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -960,6 +960,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge mUseAsyncWrite(false), mWriteAckSequence(0), mDrainSequence(0), + mSignalPending(false), mScreenState(AudioFlinger::mScreenState), // index 0 is reserved for normal mixer's submix mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1), @@ -1348,14 +1349,14 @@ void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, f { Mutex::Autolock _l(mLock); mStreamTypes[stream].volume = value; - signal_l(); + broadcast_l(); } void AudioFlinger::PlaybackThread::setStreamMute(audio_stream_type_t stream, bool muted) { Mutex::Autolock _l(mLock); mStreamTypes[stream].mute = muted; - signal_l(); + broadcast_l(); } float AudioFlinger::PlaybackThread::streamVolume(audio_stream_type_t stream) const @@ -1413,8 +1414,8 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track) status = NO_ERROR; } - ALOGV("mWaitWorkCV.broadcast"); - mWaitWorkCV.broadcast(); + ALOGV("signal playback thread"); + broadcast_l(); return status; } @@ -1455,14 +1456,14 @@ void AudioFlinger::PlaybackThread::removeTrack_l(const sp<Track>& track) } } -void AudioFlinger::PlaybackThread::signal_l() +void AudioFlinger::PlaybackThread::broadcast_l() { // Thread could be blocked waiting for async // so signal it to handle state changes immediately // If threadLoop is currently unlocked a signal of mWaitWorkCV will // be lost so we also flag to prevent it blocking on mWaitWorkCV mSignalPending = true; - mWaitWorkCV.signal(); + mWaitWorkCV.broadcast(); } String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys) @@ -2143,7 +2144,6 @@ bool AudioFlinger::PlaybackThread::threadLoop() } saveOutputTracks(); - if (mSignalPending) { // A signal was raised while we were unlocked mSignalPending = false; @@ -2158,10 +2158,10 @@ bool AudioFlinger::PlaybackThread::threadLoop() acquireWakeLock_l(); standbyTime = systemTime() + standbyDelay; sleepTime = 0; - if (exitPending()) { - break; - } - } else if ((!mActiveTracks.size() && systemTime() > standbyTime) || + + continue; + } + if ((!mActiveTracks.size() && systemTime() > standbyTime) || isSuspended()) { // put audio hardware into standby after short delay if (shouldStandby_l()) { @@ -2203,7 +2203,6 @@ bool AudioFlinger::PlaybackThread::threadLoop() continue; } } - // mMixerStatusIgnoringFastTracks is also updated internally mMixerStatus = prepareTracks_l(&tracksToRemove); @@ -3855,13 +3854,14 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr Vector< sp<Track> > *tracksToRemove ) { - ALOGV("OffloadThread::prepareTracks_l"); size_t count = mActiveTracks.size(); mixer_state mixerStatus = MIXER_IDLE; bool doHwPause = false; bool doHwResume = false; + ALOGV("OffloadThread::prepareTracks_l active tracks %d", count); + // find out which tracks need to be processed for (size_t i = 0; i < count; i++) { sp<Track> t = mActiveTracks[i].promote(); @@ -3915,23 +3915,27 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr // make sure processVolume_l() will apply new volume even if 0 mLeftVolFloat = mRightVolFloat = -1.0; if (track->mState == TrackBase::RESUMING) { - if (mPausedBytesRemaining) { - // Need to continue write that was interrupted - mCurrentWriteLength = mPausedWriteLength; - mBytesRemaining = mPausedBytesRemaining; - mPausedBytesRemaining = 0; - } track->mState = TrackBase::ACTIVE; + if (last) { + if (mPausedBytesRemaining) { + // Need to continue write that was interrupted + mCurrentWriteLength = mPausedWriteLength; + mBytesRemaining = mPausedBytesRemaining; + mPausedBytesRemaining = 0; + } + if (mHwPaused) { + doHwResume = true; + mHwPaused = false; + // threadLoop_mix() will handle the case that we need to + // resume an interrupted write + } + // enable write to audio HAL + sleepTime = 0; + } } } if (last) { - if (mHwPaused) { - doHwResume = true; - mHwPaused = false; - // threadLoop_mix() will handle the case that we need to - // resume an interrupted write - } // reset retry count track->mRetryCount = kMaxTrackRetriesOffload; mActiveTrack = t; @@ -3948,9 +3952,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr // has been written ALOGV("OffloadThread: underrun and STOPPING_1 -> draining, STOPPING_2"); track->mState = TrackBase::STOPPING_2; // so presentation completes after drain - sleepTime = 0; - standbyTime = systemTime() + standbyDelay; if (last) { + sleepTime = 0; + standbyTime = systemTime() + standbyDelay; mixerStatus = MIXER_DRAIN_TRACK; mDrainSequence += 2; if (mHwPaused) { @@ -4337,6 +4341,7 @@ bool AudioFlinger::RecordThread::threadLoop() mStandby = false; } } + lockEffectChains_l(effectChains); } diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 3fe470c..b3d88e3 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -526,7 +526,7 @@ private: status_t addTrack_l(const sp<Track>& track); bool destroyTrack_l(const sp<Track>& track); void removeTrack_l(const sp<Track>& track); - void signal_l(); + void broadcast_l(); void readOutputParameters(); @@ -590,6 +590,8 @@ private: // Bit 0 is reset by the async callback thread calling resetDraining(). Out of sequence // callbacks are ignored. uint32_t mDrainSequence; + // A condition that must be evaluated by prepareTrack_l() has changed and we must not wait + // for async write callback in the thread loop before evaluating it bool mSignalPending; sp<AsyncCallbackThread> mCallbackThread; diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 57aad1e..2b8f0ab 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -651,7 +651,7 @@ void AudioFlinger::PlaybackThread::Track::pause() case RESUMING: mState = PAUSING; ALOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get()); - playbackThread->signal_l(); + playbackThread->broadcast_l(); break; default: @@ -711,7 +711,7 @@ void AudioFlinger::PlaybackThread::Track::flush() // before mixer thread can run. This is important when offloading // because the hardware buffer could hold a large amount of audio playbackThread->flushOutput_l(); - playbackThread->signal_l(); + playbackThread->broadcast_l(); } } |