summaryrefslogtreecommitdiffstats
path: root/services/audioflinger
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2013-09-19 14:37:46 -0700
committerEric Laurent <elaurent@google.com>2013-09-19 15:53:20 -0700
commitede6c3b8b1147bc425f7b923882f559a513fe23b (patch)
treeac3986f0521aa4a5af705299ab423ec9d5e98bfa /services/audioflinger
parent5baf2af52cd186633b7173196c1e4a4cd3435f22 (diff)
downloadframeworks_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.cpp59
-rw-r--r--services/audioflinger/Threads.h4
-rw-r--r--services/audioflinger/Tracks.cpp4
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();
}
}