diff options
author | Eric Laurent <elaurent@google.com> | 2011-08-30 10:18:54 -0700 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2011-08-30 10:19:38 -0700 |
commit | 05ce0941649c3cdd7f8034496719e607977fc005 (patch) | |
tree | 1e507788895e36bcd18b37cd109ec90e7c46d90c | |
parent | 2c5423da4e3b23c0381952da2671f05a7501f9af (diff) | |
download | frameworks_base-05ce0941649c3cdd7f8034496719e607977fc005.zip frameworks_base-05ce0941649c3cdd7f8034496719e607977fc005.tar.gz frameworks_base-05ce0941649c3cdd7f8034496719e607977fc005.tar.bz2 |
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
-rw-r--r-- | include/media/AudioSystem.h | 7 | ||||
-rw-r--r-- | media/libmedia/AudioSystem.cpp | 8 | ||||
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 4 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 20 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 6 |
5 files changed, 43 insertions, 2 deletions
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index e0d7898..6a15f6e 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -185,6 +185,10 @@ public: static status_t unregisterEffect(int id); static status_t setEffectEnabled(int id, bool enabled); + // clear stream to output mapping cache (gStreamOutputMap) + // and output configuration cache (gOutputs) + static void clearAudioConfigCache(); + static const sp<IAudioPolicyService>& get_audio_policy_service(); // ---------------------------------------------------------------------------- @@ -236,7 +240,8 @@ private: // mapping between stream types and outputs static DefaultKeyedVector<int, audio_io_handle_t> gStreamOutputMap; - // list of output descritor containing cached parameters (sampling rate, framecount, channel count...) + // list of output descriptors containing cached parameters + // (sampling rate, framecount, channel count...) static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs; }; diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index bb91fa9..853a5f6 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -727,6 +727,14 @@ status_t AudioSystem::isStreamActive(int stream, bool* state, uint32_t inPastMs) } +void AudioSystem::clearAudioConfigCache() +{ + Mutex::Autolock _l(gLock); + LOGV("clearAudioConfigCache()"); + gStreamOutputMap.clear(); + gOutputs.clear(); +} + // --------------------------------------------------------------------------- void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) { diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index cecedb5..3b6c64d 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1164,6 +1164,10 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) cblk->cv.broadcast(); cblk->lock.unlock(); + // refresh the audio configuration cache in this process to make sure we get new + // output parameters in getOutput_l() and createTrack_l() + AudioSystem::clearAudioConfigCache(); + // if the new IAudioTrack is created, createTrack_l() will modify the // following member variables: mAudioTrack, mCblkMemory and mCblk. // It will also delete the strong references on previous IAudioTrack and IMemory 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<AudioFlinger>& 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::Track> 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: |