diff options
-rw-r--r-- | include/media/AudioSystem.h | 2 | ||||
-rw-r--r-- | include/media/IAudioFlinger.h | 3 | ||||
-rw-r--r-- | media/libmedia/AudioRecord.cpp | 3 | ||||
-rw-r--r-- | media/libmedia/AudioSystem.cpp | 14 | ||||
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 2 | ||||
-rw-r--r-- | media/libmedia/IAudioFlinger.cpp | 32 | ||||
-rw-r--r-- | media/libmedia/mediaplayer.cpp | 8 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 189 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 31 |
9 files changed, 254 insertions, 30 deletions
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index f20e234..eb22e32 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -108,6 +108,8 @@ public: static unsigned int getInputFramesLost(audio_io_handle_t ioHandle); static int newAudioSessionId(); + static void acquireAudioSessionId(int audioSession); + static void releaseAudioSessionId(int audioSession); // types of io configuration change events received with ioConfigChanged() enum io_config_event { diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h index 4037c46..9e3cb7f 100644 --- a/include/media/IAudioFlinger.h +++ b/include/media/IAudioFlinger.h @@ -139,6 +139,9 @@ public: virtual int newAudioSessionId() = 0; + virtual void acquireAudioSessionId(int audioSession) = 0; + virtual void releaseAudioSessionId(int audioSession) = 0; + virtual status_t queryNumberEffects(uint32_t *numEffects) = 0; virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) = 0; diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 16554c2..e5062ab 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -114,6 +114,7 @@ AudioRecord::~AudioRecord() } mAudioRecord.clear(); IPCThreadState::self()->flushCommands(); + AudioSystem::releaseAudioSessionId(mSessionId); } } @@ -233,6 +234,7 @@ status_t AudioRecord::set( mInputSource = (uint8_t)inputSource; mFlags = flags; mInput = input; + AudioSystem::acquireAudioSessionId(mSessionId); return NO_ERROR; } @@ -465,6 +467,7 @@ status_t AudioRecord::openRecord_l( ((uint16_t)flags) << 16, &mSessionId, &status); + if (record == 0) { LOGE("AudioFlinger could not create record track, status: %d", status); return status; diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 5009957..b26ed71 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -356,6 +356,20 @@ int AudioSystem::newAudioSessionId() { return af->newAudioSessionId(); } +void AudioSystem::acquireAudioSessionId(int audioSession) { + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af != 0) { + af->acquireAudioSessionId(audioSession); + } +} + +void AudioSystem::releaseAudioSessionId(int audioSession) { + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af != 0) { + af->releaseAudioSessionId(audioSession); + } +} + // --------------------------------------------------------------------------- void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) { diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 31eb97a..3949c39 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -134,6 +134,7 @@ AudioTrack::~AudioTrack() } mAudioTrack.clear(); IPCThreadState::self()->flushCommands(); + AudioSystem::releaseAudioSessionId(mSessionId); } } @@ -259,6 +260,7 @@ status_t AudioTrack::set( mNewPosition = 0; mUpdatePeriod = 0; mFlags = flags; + AudioSystem::acquireAudioSessionId(mSessionId); return NO_ERROR; } diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 4a12962..d58834b 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -1,4 +1,4 @@ -/* //device/extlibs/pv/android/IAudioflinger.cpp +/* ** ** Copyright 2007, The Android Open Source Project ** @@ -63,6 +63,8 @@ enum { GET_RENDER_POSITION, GET_INPUT_FRAMES_LOST, NEW_AUDIO_SESSION_ID, + ACQUIRE_AUDIO_SESSION_ID, + RELEASE_AUDIO_SESSION_ID, QUERY_NUM_EFFECTS, QUERY_EFFECT, GET_EFFECT_DESCRIPTOR, @@ -526,6 +528,22 @@ public: return id; } + virtual void acquireAudioSessionId(int audioSession) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(audioSession); + remote()->transact(ACQUIRE_AUDIO_SESSION_ID, data, &reply); + } + + virtual void releaseAudioSessionId(int audioSession) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(audioSession); + remote()->transact(RELEASE_AUDIO_SESSION_ID, data, &reply); + } + virtual status_t queryNumberEffects(uint32_t *numEffects) { Parcel data, reply; @@ -919,6 +937,18 @@ status_t BnAudioFlinger::onTransact( reply->writeInt32(newAudioSessionId()); return NO_ERROR; } break; + case ACQUIRE_AUDIO_SESSION_ID: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int audioSession = data.readInt32(); + acquireAudioSessionId(audioSession); + return NO_ERROR; + } break; + case RELEASE_AUDIO_SESSION_ID: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int audioSession = data.readInt32(); + releaseAudioSessionId(audioSession); + return NO_ERROR; + } break; case QUERY_NUM_EFFECTS: { CHECK_INTERFACE(IAudioFlinger, data, reply); uint32_t numEffects; diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 3dd9249..67a66a2 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -61,12 +61,14 @@ MediaPlayer::MediaPlayer() mVideoWidth = mVideoHeight = 0; mLockThreadId = 0; mAudioSessionId = AudioSystem::newAudioSessionId(); + AudioSystem::acquireAudioSessionId(mAudioSessionId); mSendLevel = 0; } MediaPlayer::~MediaPlayer() { LOGV("destructor"); + AudioSystem::releaseAudioSessionId(mAudioSessionId); disconnect(); IPCThreadState::self()->flushCommands(); } @@ -618,7 +620,11 @@ status_t MediaPlayer::setAudioSessionId(int sessionId) if (sessionId < 0) { return BAD_VALUE; } - mAudioSessionId = sessionId; + if (sessionId != mAudioSessionId) { + AudioSystem::releaseAudioSessionId(mAudioSessionId); + AudioSystem::acquireAudioSessionId(sessionId); + mAudioSessionId = sessionId; + } return NO_ERROR; } 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; }; |