From 9f6530f53ae9eda43f4e7c1cb30d2379db00aa00 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 30 Aug 2011 10:18:54 -0700 Subject: 226483: A2DP connected, but music out to speaker When the A2DP headset is connected, there is a possible race condition when the audio tracks are moved from the mixer thread attached to the speaker output to the thread attached to A2DP output. As the request to clear the stream type to output mapping cache in the client process is asynchronous, it is possible that the flag indicating to the client audio track to re-create the IAudioTrack on the new thread is processed before the cache is invalidated. In this case, the track will be attached to the old thread and music will continue playing over the device speaker instead of being redirected to A2DP headset. Change-Id: Ib2ce1eb5320eaff83287b93779061bf4e7a330df --- services/audioflinger/AudioFlinger.cpp | 20 ++++++++++++++++++++ services/audioflinger/AudioFlinger.h | 6 +++++- 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'services') diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 744fa50..2260091 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1362,6 +1362,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp& audioFlinge for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) { mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream); mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream); + mStreamTypes[stream].valid = true; } } @@ -1530,6 +1531,14 @@ sp AudioFlinger::PlaybackThread::createTra chain->setStrategy(AudioSystem::getStrategyForStream((audio_stream_type_t)track->type())); chain->incTrackCnt(); } + + // invalidate track immediately if the stream type was moved to another thread since + // createTrack() was called by the client process. + if (!mStreamTypes[streamType].valid) { + LOGW("createTrack_l() on thread %p: invalidating track on stream %d", + this, streamType); + android_atomic_or(CBLK_INVALID_ON, &track->mCblk->flags); + } } lStatus = NO_ERROR; @@ -2219,6 +2228,14 @@ void AudioFlinger::MixerThread::invalidateTracks(int streamType) } } +void AudioFlinger::PlaybackThread::setStreamValid(int streamType, bool valid) +{ + LOGV ("PlaybackThread::setStreamValid() thread %p, streamType %d, valid %d", + this, streamType, valid); + Mutex::Autolock _l(mLock); + + mStreamTypes[streamType].valid = valid; +} // getTrackName_l() must be called with ThreadBase::mLock held int AudioFlinger::MixerThread::getTrackName_l() @@ -5074,11 +5091,14 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output) LOGV("setStreamOutput() stream %d to output %d", stream, output); audioConfigChanged_l(AudioSystem::STREAM_CONFIG_CHANGED, output, &stream); + dstThread->setStreamValid(stream, true); + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); if (thread != dstThread && thread->type() != ThreadBase::DIRECT) { MixerThread *srcThread = (MixerThread *)thread; + srcThread->setStreamValid(stream, false); srcThread->invalidateTracks(stream); } } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 1141f6c..c64fd4f 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -751,14 +751,18 @@ private: virtual uint32_t hasAudioSession(int sessionId); virtual uint32_t getStrategyForSession_l(int sessionId); + void setStreamValid(int streamType, bool valid); + struct stream_type_t { stream_type_t() : volume(1.0f), - mute(false) + mute(false), + valid(true) { } float volume; bool mute; + bool valid; }; protected: -- cgit v1.1