summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorMarco Nelissen <marcone@google.com>2011-08-02 13:33:41 -0700
committerMarco Nelissen <marcone@google.com>2011-08-09 10:21:10 -0700
commit3a34befc6fb04a4945a849e8bda8b84e4bf973fe (patch)
tree80dee67385fb78763b2c25f6dce9ed122bfd9aee /services
parenta1f10e8959cd4656aedb2613e855342102e59555 (diff)
downloadframeworks_av-3a34befc6fb04a4945a849e8bda8b84e4bf973fe.zip
frameworks_av-3a34befc6fb04a4945a849e8bda8b84e4bf973fe.tar.gz
frameworks_av-3a34befc6fb04a4945a849e8bda8b84e4bf973fe.tar.bz2
Keep effects sessions active when the caller dies.
Don't remove effects until the session they are in goes away or all AudioEffects have been explicitly released. This allows the control panel process to die without stopping the effects. Change-Id: I4496e5df080230ca1af149dec95c1309ab8ea888
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioFlinger.cpp189
-rw-r--r--services/audioflinger/AudioFlinger.h31
2 files changed, 192 insertions, 28 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e201b17..d6bfda6 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -264,6 +264,14 @@ status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
}
}
}
+
+ result.append("Global session refs:\n");
+ result.append(" session pid cnt\n");
+ for (size_t i = 0; i < mAudioSessionRefs.size(); i++) {
+ AudioSessionRef *r = mAudioSessionRefs[i];
+ snprintf(buffer, SIZE, " %7d %3d %3d\n", r->sessionid, r->pid, r->cnt);
+ result.append(buffer);
+ }
write(fd, result.string(), result.size());
return NO_ERROR;
}
@@ -892,6 +900,25 @@ void AudioFlinger::removeNotificationClient(pid_t pid)
LOGV("removeNotificationClient() %p, pid %d", client.get(), pid);
mNotificationClients.removeItem(pid);
}
+
+ LOGV("%d died, releasing its sessions", pid);
+ int num = mAudioSessionRefs.size();
+ bool removed = false;
+ for (int i = 0; i< num; i++) {
+ AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
+ LOGV(" pid %d @ %d", ref->pid, i);
+ if (ref->pid == pid) {
+ LOGV(" removing entry for pid %d session %d", pid, ref->sessionid);
+ mAudioSessionRefs.removeAt(i);
+ delete ref;
+ removed = true;
+ i--;
+ num--;
+ }
+ }
+ if (removed) {
+ purgeStaleEffects_l();
+ }
}
// audioConfigChanged_l() must be called with AudioFlinger::mLock held
@@ -5042,6 +5069,109 @@ int AudioFlinger::newAudioSessionId()
return nextUniqueId();
}
+void AudioFlinger::acquireAudioSessionId(int audioSession)
+{
+ Mutex::Autolock _l(mLock);
+ int caller = IPCThreadState::self()->getCallingPid();
+ LOGV("acquiring %d from %d", audioSession, caller);
+ int num = mAudioSessionRefs.size();
+ for (int i = 0; i< num; i++) {
+ AudioSessionRef *ref = mAudioSessionRefs.editItemAt(i);
+ if (ref->sessionid == audioSession && ref->pid == caller) {
+ ref->cnt++;
+ LOGV(" incremented refcount to %d", ref->cnt);
+ return;
+ }
+ }
+ AudioSessionRef *ref = new AudioSessionRef();
+ ref->sessionid = audioSession;
+ ref->pid = caller;
+ ref->cnt = 1;
+ mAudioSessionRefs.push(ref);
+ LOGV(" added new entry for %d", ref->sessionid);
+}
+
+void AudioFlinger::releaseAudioSessionId(int audioSession)
+{
+ Mutex::Autolock _l(mLock);
+ int caller = IPCThreadState::self()->getCallingPid();
+ LOGV("releasing %d from %d", audioSession, caller);
+ int num = mAudioSessionRefs.size();
+ for (int i = 0; i< num; i++) {
+ AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
+ if (ref->sessionid == audioSession && ref->pid == caller) {
+ ref->cnt--;
+ LOGV(" decremented refcount to %d", ref->cnt);
+ if (ref->cnt == 0) {
+ mAudioSessionRefs.removeAt(i);
+ delete ref;
+ purgeStaleEffects_l();
+ }
+ return;
+ }
+ }
+ LOGW("session id %d not found for pid %d", audioSession, caller);
+}
+
+void AudioFlinger::purgeStaleEffects_l() {
+
+ LOGV("purging stale effects");
+
+ Vector< sp<EffectChain> > chains;
+
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
+ for (size_t j = 0; j < t->mEffectChains.size(); j++) {
+ sp<EffectChain> ec = t->mEffectChains[j];
+ chains.push(ec);
+ }
+ }
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ sp<RecordThread> t = mRecordThreads.valueAt(i);
+ for (size_t j = 0; j < t->mEffectChains.size(); j++) {
+ sp<EffectChain> ec = t->mEffectChains[j];
+ chains.push(ec);
+ }
+ }
+
+ for (size_t i = 0; i < chains.size(); i++) {
+ sp<EffectChain> ec = chains[i];
+ int sessionid = ec->sessionId();
+ sp<ThreadBase> t = ec->mThread.promote();
+ if (t == 0) {
+ continue;
+ }
+ size_t numsessionrefs = mAudioSessionRefs.size();
+ bool found = false;
+ for (size_t k = 0; k < numsessionrefs; k++) {
+ AudioSessionRef *ref = mAudioSessionRefs.itemAt(k);
+ if (ref->sessionid == sessionid) {
+ LOGV(" session %d still exists for %d with %d refs",
+ sessionid, ref->pid, ref->cnt);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // remove all effects from the chain
+ while (ec->mEffects.size()) {
+ sp<EffectModule> effect = ec->mEffects[0];
+ effect->unPin();
+ Mutex::Autolock _l (t->mLock);
+ t->removeEffect_l(effect);
+ for (size_t j = 0; j < effect->mHandles.size(); j++) {
+ sp<EffectHandle> handle = effect->mHandles[j].promote();
+ if (handle != 0) {
+ handle->mEffect.clear();
+ }
+ }
+ AudioSystem::unregisterEffect(effect->id());
+ }
+ }
+ }
+ return;
+}
+
// checkPlaybackThread_l() must be called with AudioFlinger::mLock held
AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const
{
@@ -5199,6 +5329,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
}
uint32_t numEffects = 0;
effect_descriptor_t d;
+ d.flags = 0; // prevent compiler warning
bool found = false;
lStatus = EffectQueryNumberEffects(&numEffects);
@@ -5302,7 +5433,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
mClients.add(pid, client);
}
- // create effect on selected output trhead
+ // create effect on selected output thread
handle = thread->createEffect_l(client, effectClient, priority, sessionId,
&desc, enabled, &lStatus);
if (handle != 0 && id != NULL) {
@@ -5344,7 +5475,7 @@ status_t AudioFlinger::moveEffects(int sessionId, int srcOutput, int dstOutput)
return NO_ERROR;
}
-// moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held
+// moveEffectChain_l must be called with both srcThread and dstThread mLocks held
status_t AudioFlinger::moveEffectChain_l(int sessionId,
AudioFlinger::PlaybackThread *srcThread,
AudioFlinger::PlaybackThread *dstThread,
@@ -5370,7 +5501,7 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId,
// correct buffer sizes and audio parameters and effect engines reconfigured accordingly
int dstOutput = dstThread->id();
sp<EffectChain> dstChain;
- uint32_t strategy;
+ uint32_t strategy = 0; // prevent compiler warning
sp<EffectModule> effect = chain->getEffectFromId_l(0);
while (effect != 0) {
srcThread->removeEffect_l(effect);
@@ -5632,14 +5763,17 @@ void AudioFlinger::ThreadBase::setMode(uint32_t mode)
}
void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
- const wp<EffectHandle>& handle) {
+ const wp<EffectHandle>& handle,
+ bool unpiniflast) {
Mutex::Autolock _l(mLock);
LOGV("disconnectEffect() %p effect %p", this, effect.get());
// delete the effect module if removing last handle on it
if (effect->removeHandle(handle) == 0) {
- removeEffect_l(effect);
- AudioSystem::unregisterEffect(effect->id());
+ if (!effect->isPinned() || unpiniflast) {
+ removeEffect_l(effect);
+ AudioSystem::unregisterEffect(effect->id());
+ }
}
}
@@ -5847,6 +5981,9 @@ AudioFlinger::EffectModule::EffectModule(const wp<ThreadBase>& wThread,
goto Error;
}
+ if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) {
+ mPinned = true;
+ }
LOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface);
return;
Error:
@@ -5938,7 +6075,7 @@ size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle)
// Prevent calls to process() and other functions on effect interface from now on.
// The effect engine will be released by the destructor when the last strong reference on
// this object is released which can happen after next process is called.
- if (size == 0) {
+ if (size == 0 && !mPinned) {
mState = DESTROYED;
}
@@ -5955,9 +6092,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::EffectModule::controlHandle()
return handle;
}
-
-
-void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle)
+void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpiniflast)
{
LOGV("disconnect() %p handle %p ", this, handle.unsafe_get());
// keep a strong reference on this EffectModule to avoid calling the
@@ -5966,7 +6101,7 @@ void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle)
{
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
- thread->disconnectEffect(keep, handle);
+ thread->disconnectEffect(keep, handle, unpiniflast);
}
}
}
@@ -6533,11 +6668,14 @@ AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect,
const sp<IEffectClient>& effectClient,
int32_t priority)
: BnEffect(),
- mEffect(effect), mEffectClient(effectClient), mClient(client),
+ mEffect(effect), mEffectClient(effectClient), mClient(client), mCblk(NULL),
mPriority(priority), mHasControl(false), mEnabled(false)
{
LOGV("constructor %p", this);
+ if (client == 0) {
+ return;
+ }
int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
mCblkMemory = client->heap()->allocate(EFFECT_PARAM_BUFFER_SIZE + bufOffset);
if (mCblkMemory != 0) {
@@ -6556,7 +6694,7 @@ AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect,
AudioFlinger::EffectHandle::~EffectHandle()
{
LOGV("Destructor %p", this);
- disconnect();
+ disconnect(false);
LOGV("Destructor DONE %p", this);
}
@@ -6605,12 +6743,16 @@ status_t AudioFlinger::EffectHandle::disable()
void AudioFlinger::EffectHandle::disconnect()
{
- LOGV("disconnect %p", this);
+ disconnect(true);
+}
+
+void AudioFlinger::EffectHandle::disconnect(bool unpiniflast)
+{
+ LOGV("disconnect(%s)", unpiniflast ? "true" : "false");
if (mEffect == 0) {
return;
}
-
- mEffect->disconnect(this);
+ mEffect->disconnect(this, unpiniflast);
sp<ThreadBase> thread = mEffect->thread().promote();
if (thread != 0) {
@@ -6619,11 +6761,11 @@ void AudioFlinger::EffectHandle::disconnect()
// release sp on module => module destructor can be called now
mEffect.clear();
- if (mCblk) {
- mCblk->~effect_param_cblk_t(); // destroy our shared-structure.
- }
- mCblkMemory.clear(); // and free the shared memory
if (mClient != 0) {
+ if (mCblk) {
+ mCblk->~effect_param_cblk_t(); // destroy our shared-structure.
+ }
+ mCblkMemory.clear(); // and free the shared memory
Mutex::Autolock _l(mClient->audioFlinger()->mLock);
mClient.clear();
}
@@ -6643,6 +6785,7 @@ status_t AudioFlinger::EffectHandle::command(uint32_t cmdCode,
return INVALID_OPERATION;
}
if (mEffect == 0) return DEAD_OBJECT;
+ if (mClient == 0) return INVALID_OPERATION;
// handle commands that are not forwarded transparently to effect engine
if (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) {
@@ -6749,15 +6892,15 @@ status_t AudioFlinger::EffectHandle::onTransact(
void AudioFlinger::EffectHandle::dump(char* buffer, size_t size)
{
- bool locked = tryLock(mCblk->lock);
+ bool locked = mCblk ? tryLock(mCblk->lock) : false;
snprintf(buffer, size, "\t\t\t%05d %05d %01u %01u %05u %05u\n",
(mClient == NULL) ? getpid() : mClient->pid(),
mPriority,
mHasControl,
!locked,
- mCblk->clientIndex,
- mCblk->serverIndex
+ mCblk ? mCblk->clientIndex : 0,
+ mCblk ? mCblk->serverIndex : 0
);
if (locked) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 4fa70a2..3a0aac9 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -149,6 +149,10 @@ public:
virtual int newAudioSessionId();
+ virtual void acquireAudioSessionId(int audioSession);
+
+ virtual void releaseAudioSessionId(int audioSession);
+
virtual status_t queryNumberEffects(uint32_t *numEffects);
virtual status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor);
@@ -215,6 +219,7 @@ private:
status_t initCheck() const;
virtual void onFirstRef();
audio_hw_device_t* findSuitableHwDev_l(uint32_t devices);
+ void purgeStaleEffects_l();
// Internal dump utilites.
status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
@@ -436,7 +441,8 @@ private:
int *enabled,
status_t *status);
void disconnectEffect(const sp< EffectModule>& effect,
- const wp<EffectHandle>& handle);
+ const wp<EffectHandle>& handle,
+ bool unpiniflast);
// return values for hasAudioSession (bit field)
enum effect_state {
@@ -519,6 +525,7 @@ private:
// updated mSuspendedSessions when an effect chain is removed
void updateSuspendedSessionsOnRemoveEffectChain_l(const sp<EffectChain>& chain);
+ friend class AudioFlinger;
friend class Track;
friend class TrackBase;
friend class PlaybackThread;
@@ -607,7 +614,6 @@ private:
protected:
friend class ThreadBase;
- friend class AudioFlinger;
friend class TrackHandle;
friend class PlaybackThread;
friend class MixerThread;
@@ -1100,7 +1106,7 @@ private:
wp<ThreadBase>& thread() { return mThread; }
status_t addHandle(sp<EffectHandle>& handle);
- void disconnect(const wp<EffectHandle>& handle);
+ void disconnect(const wp<EffectHandle>& handle, bool unpiniflast);
size_t removeHandle (const wp<EffectHandle>& handle);
effect_descriptor_t& desc() { return mDescriptor; }
@@ -1115,9 +1121,15 @@ private:
sp<EffectHandle> controlHandle();
+ bool isPinned() { return mPinned; }
+ void unPin() { mPinned = false; }
+
status_t dump(int fd, const Vector<String16>& args);
protected:
+ friend class EffectHandle;
+ friend class AudioFlinger;
+ bool mPinned;
// Maximum time allocated to effect engines to complete the turn off sequence
static const uint32_t MAX_DISABLE_TIME_MS = 10000;
@@ -1169,6 +1181,7 @@ private:
uint32_t *replySize,
void *pReplyData);
virtual void disconnect();
+ virtual void disconnect(bool unpiniflast);
virtual sp<IMemory> getCblk() const;
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
@@ -1196,7 +1209,8 @@ private:
void dump(char* buffer, size_t size);
protected:
-
+ friend class AudioFlinger;
+ friend class EffectModule;
EffectHandle(const EffectHandle&);
EffectHandle& operator =(const EffectHandle&);
@@ -1288,7 +1302,7 @@ private:
status_t dump(int fd, const Vector<String16>& args);
protected:
-
+ friend class AudioFlinger;
EffectChain(const EffectChain&);
EffectChain& operator =(const EffectChain&);
@@ -1344,6 +1358,12 @@ private:
hwDev(dev), stream(in) {}
};
+ struct AudioSessionRef {
+ int sessionid;
+ pid_t pid;
+ int cnt;
+ };
+
friend class RecordThread;
friend class PlaybackThread;
@@ -1369,6 +1389,7 @@ private:
uint32_t mMode;
bool mBtNrec;
+ Vector<AudioSessionRef*> mAudioSessionRefs;
};