summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2012-06-29 16:36:52 -0700
committerEric Laurent <elaurent@google.com>2012-06-29 17:03:53 -0700
commit717e128691f083a9469a1d0e363ac6ecd5c65d58 (patch)
tree70761520a17703d543262ebe7778f51a360d7923
parent33e28dd3c033641f4db9d1b99c7c88d6d08c61f7 (diff)
audioflinger: fix auxiliary effect attachment
Auxiliary effects (Reverb) are global effects and as such follow the default rule which is to attach them to the output thread that handles music streams by default. This causes a problem when several threads are eligible to handle music streams as tracks can be attached to either thread based on criteria unknown when teh effect is created. The fix consists in moving the auxiliary effect if necessary when an AudioTrack is attached to it and this track is not on the same output thread. Bug 6608561. Change-Id: Ib32c3cabc731b2046aba728be1771982999c6069
-rw-r--r--services/audioflinger/AudioFlinger.cpp61
-rw-r--r--services/audioflinger/AudioFlinger.h4
2 files changed, 65 insertions, 0 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b78c6d11..abe02932 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1106,6 +1106,20 @@ void AudioFlinger::removeClient_l(pid_t pid)
mClients.removeItem(pid);
}
+// getEffectThread_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::PlaybackThread> AudioFlinger::getEffectThread_l(int sessionId, int EffectId)
+{
+ sp<PlaybackThread> thread;
+
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads.valueAt(i)->getEffect(sessionId, EffectId) != 0) {
+ ALOG_ASSERT(thread == 0);
+ thread = mPlaybackThreads.valueAt(i);
+ }
+ }
+
+ return thread;
+}
// ----------------------------------------------------------------------------
@@ -4677,6 +4691,47 @@ status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId)
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ sp<AudioFlinger> af = mClient->audioFlinger();
+
+ Mutex::Autolock _l(af->mLock);
+
+ sp<PlaybackThread> srcThread = af->getEffectThread_l(AUDIO_SESSION_OUTPUT_MIX, EffectId);
+ if (srcThread == 0) {
+ return INVALID_OPERATION;
+ }
+
+ if (EffectId != 0 && playbackThread != srcThread.get()) {
+ Mutex::Autolock _dl(playbackThread->mLock);
+ Mutex::Autolock _sl(srcThread->mLock);
+ sp<EffectChain> chain = srcThread->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
+ if (chain == 0) {
+ return INVALID_OPERATION;
+ }
+
+ sp<EffectModule> effect = chain->getEffectFromId_l(EffectId);
+ if (effect == 0) {
+ return INVALID_OPERATION;
+ }
+ srcThread->removeEffect_l(effect);
+ playbackThread->addEffect_l(effect);
+ // removeEffect_l() has stopped the effect if it was active so it must be restarted
+ if (effect->state() == EffectModule::ACTIVE ||
+ effect->state() == EffectModule::STOPPING) {
+ effect->start();
+ }
+
+ sp<EffectChain> dstChain = effect->chain().promote();
+ if (dstChain == 0) {
+ srcThread->addEffect_l(effect);
+ return INVALID_OPERATION;
+ }
+ AudioSystem::unregisterEffect(effect->id());
+ AudioSystem::registerEffect(&effect->desc(),
+ srcThread->id(),
+ dstChain->strategy(),
+ AUDIO_SESSION_OUTPUT_MIX,
+ effect->id());
+ }
status = playbackThread->attachAuxEffect(this, EffectId);
}
return status;
@@ -7645,6 +7700,12 @@ Exit:
return handle;
}
+sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect(int sessionId, int effectId)
+{
+ Mutex::Autolock _l(mLock);
+ return getEffect_l(sessionId, effectId);
+}
+
sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect_l(int sessionId, int effectId)
{
sp<EffectChain> chain = getEffectChain_l(sessionId);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 384306ca..cfd718f4 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -253,6 +253,7 @@ public:
int listenerSession,
sync_event_callback_t callBack,
void *cookie);
+
private:
audio_mode_t getMode() const { return mMode; }
@@ -543,6 +544,7 @@ private:
// set audio mode to all effect chains
void setMode(audio_mode_t mode);
// get effect module with corresponding ID on specified audio session
+ sp<AudioFlinger::EffectModule> getEffect(int sessionId, int effectId);
sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId);
// add and effect module. Also creates the effect chain is none exists for
// the effects audio session
@@ -1287,6 +1289,8 @@ private:
PlaybackThread *primaryPlaybackThread_l() const;
uint32_t primaryOutputDevice_l() const;
+ sp<PlaybackThread> getEffectThread_l(int sessionId, int EffectId);
+
// server side of the client's IAudioTrack
class TrackHandle : public android::BnAudioTrack {
public: