Loading services/audioflinger/AudioFlinger.cpp +118 −12 Original line number Diff line number Diff line Loading @@ -2226,6 +2226,9 @@ void AudioFlinger::removeNotificationClient(pid_t pid) } if (removed) { removedEffects = purgeStaleEffects_l(); std::vector< sp<IAfEffectModule> > removedOrphanEffects = purgeOrphanEffectChains_l(); removedEffects.insert(removedEffects.end(), removedOrphanEffects.begin(), removedOrphanEffects.end()); } } for (auto& effect : removedEffects) { Loading Loading @@ -3716,6 +3719,42 @@ std::vector<sp<IAfEffectModule>> AudioFlinger::purgeStaleEffects_l() { return removedEffects; } std::vector< sp<IAfEffectModule> > AudioFlinger::purgeOrphanEffectChains_l() { ALOGV("purging stale effects from orphan chains"); std::vector< sp<IAfEffectModule> > removedEffects; for (size_t index = 0; index < mOrphanEffectChains.size(); index++) { sp<IAfEffectChain> chain = mOrphanEffectChains.valueAt(index); audio_session_t session = mOrphanEffectChains.keyAt(index); if (session == AUDIO_SESSION_OUTPUT_MIX || session == AUDIO_SESSION_DEVICE || session == AUDIO_SESSION_OUTPUT_STAGE) { continue; } size_t numSessionRefs = mAudioSessionRefs.size(); bool found = false; for (size_t k = 0; k < numSessionRefs; k++) { AudioSessionRef *ref = mAudioSessionRefs.itemAt(k); if (ref->mSessionid == session) { ALOGV(" session %d still exists for %d with %d refs", session, ref->mPid, ref->mCnt); found = true; break; } } if (!found) { for (size_t i = 0; i < chain->numberOfEffects(); i++) { sp<IAfEffectModule> effect = chain->getEffectModule(i); removedEffects.push_back(effect); } } } for (auto& effect : removedEffects) { effect->unPin(); updateOrphanEffectChains_l(effect); } return removedEffects; } // dumpToThreadLog_l() must be called with AudioFlinger::mLock held void AudioFlinger::dumpToThreadLog_l(const sp<ThreadBase> &thread) { Loading Loading @@ -4449,24 +4488,42 @@ Exit: return lStatus; } status_t AudioFlinger::moveEffects(audio_session_t sessionId, audio_io_handle_t srcOutput, audio_io_handle_t dstOutput) status_t AudioFlinger::moveEffects(audio_session_t sessionId, audio_io_handle_t srcIo, audio_io_handle_t dstIo) NO_THREAD_SAFETY_ANALYSIS { ALOGV("moveEffects() session %d, srcOutput %d, dstOutput %d", sessionId, srcOutput, dstOutput); ALOGV("%s() session %d, srcIo %d, dstIo %d", __func__, sessionId, srcIo, dstIo); Mutex::Autolock _l(mLock); if (srcOutput == dstOutput) { ALOGW("moveEffects() same dst and src outputs %d", dstOutput); if (srcIo == dstIo) { ALOGW("%s() same dst and src outputs %d", __func__, dstIo); return NO_ERROR; } PlaybackThread *srcThread = checkPlaybackThread_l(srcOutput); if (srcThread == NULL) { ALOGW("moveEffects() bad srcOutput %d", srcOutput); RecordThread *srcRecordThread = checkRecordThread_l(srcIo); RecordThread *dstRecordThread = checkRecordThread_l(dstIo); if (srcRecordThread != nullptr || dstRecordThread != nullptr) { if (srcRecordThread != nullptr) { srcRecordThread->mLock.lock(); } if (dstRecordThread != nullptr) { dstRecordThread->mLock.lock(); } status_t ret = moveEffectChain_l(sessionId, srcRecordThread, dstRecordThread); if (srcRecordThread != nullptr) { srcRecordThread->mLock.unlock(); } if (dstRecordThread != nullptr) { dstRecordThread->mLock.unlock(); } return ret; } PlaybackThread *srcThread = checkPlaybackThread_l(srcIo); if (srcThread == nullptr) { ALOGW("%s() bad srcIo %d", __func__, srcIo); return BAD_VALUE; } PlaybackThread *dstThread = checkPlaybackThread_l(dstOutput); if (dstThread == NULL) { ALOGW("moveEffects() bad dstOutput %d", dstOutput); PlaybackThread *dstThread = checkPlaybackThread_l(dstIo); if (dstThread == nullptr) { ALOGW("%s() bad dstIo %d", __func__, dstIo); return BAD_VALUE; } Loading Loading @@ -4604,6 +4661,50 @@ NO_THREAD_SAFETY_ANALYSIS // requires srcThread and dstThread locks return status; } // moveEffectChain_l must be called with both srcThread (if not null) and dstThread (if not null) // mLocks held status_t AudioFlinger::moveEffectChain_l(audio_session_t sessionId, RecordThread *srcThread, RecordThread *dstThread) NO_THREAD_SAFETY_ANALYSIS // requires srcThread and dstThread locks { sp<IAfEffectChain> chain = nullptr; if (srcThread != 0) { Vector< sp<IAfEffectChain> > effectChains = srcThread->getEffectChains_l(); for (size_t i = 0; i < effectChains.size(); i ++) { if (effectChains[i]->sessionId() == sessionId) { chain = effectChains[i]; break; } } ALOGV_IF(effectChains.size() == 0, "%s: no effect chain on io=%d", __func__, srcThread->id()); if (chain == nullptr) { ALOGE("%s wrong session id %d", __func__, sessionId); return BAD_VALUE; } ALOGV("%s: removing effect chain for session=%d io=%d", __func__, sessionId, srcThread->id()); srcThread->removeEffectChain_l(chain); } else { chain = getOrphanEffectChain_l(sessionId); if (chain == nullptr) { ALOGE("%s: no orphan effect chain found for session=%d", __func__, sessionId); return BAD_VALUE; } } if (dstThread != 0) { ALOGV("%s: adding effect chain for session=%d on io=%d", __func__, sessionId, dstThread->id()); dstThread->addEffectChain_l(chain); return NO_ERROR; } ALOGV("%s: parking to orphan effect chain for session=%d", __func__, sessionId); putOrphanEffectChain_l(chain); return NO_ERROR; } status_t AudioFlinger::moveAuxEffectToIo(int EffectId, const sp<PlaybackThread>& dstThread, sp<PlaybackThread> *srcThread) Loading Loading @@ -4720,6 +4821,11 @@ sp<IAfEffectChain> AudioFlinger::getOrphanEffectChain_l(audio_session_t session) bool AudioFlinger::updateOrphanEffectChains(const sp<IAfEffectModule>& effect) { Mutex::Autolock _l(mLock); return updateOrphanEffectChains_l(effect); } bool AudioFlinger::updateOrphanEffectChains_l(const sp<IAfEffectModule>& effect) { audio_session_t session = effect->sessionId(); ssize_t index = mOrphanEffectChains.indexOfKey(session); ALOGV("updateOrphanEffectChains session %d index %zd", session, index); Loading services/audioflinger/AudioFlinger.h +6 −0 Original line number Diff line number Diff line Loading @@ -791,6 +791,9 @@ private: status_t moveEffectChain_l(audio_session_t sessionId, PlaybackThread *srcThread, PlaybackThread *dstThread); status_t moveEffectChain_l(audio_session_t sessionId, RecordThread *srcThread, RecordThread *dstThread); status_t moveAuxEffectToIo(int EffectId, const sp<PlaybackThread>& dstThread, Loading Loading @@ -840,6 +843,9 @@ public: private: std::vector< sp<IAfEffectModule> > purgeStaleEffects_l(); std::vector< sp<IAfEffectModule> > purgeOrphanEffectChains_l(); bool updateOrphanEffectChains_l(const sp<IAfEffectModule>& effect); void broadcastParametersToRecordThreads_l(const String8& keyValuePairs); void updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices); void forwardParametersToDownstreamPatches_l( Loading services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h +24 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,10 @@ namespace android { class AudioInputCollection; class AudioInputDescriptor; class AudioPolicyClientInterface; class EffectDescriptor : public RefBase { public: Loading @@ -40,6 +44,8 @@ public: int mId; // effect unique ID audio_io_handle_t mIo; // io the effect is attached to bool mIsOrphan = false; // on creation, effect is not yet attached but not yet orphan bool mEnabledWhenMoved = false; // Backup enabled state before being moved audio_session_t mSession; // audio session the effect is on effect_descriptor_t mDesc; // effect descriptor bool mEnabled; // enabled state: CPU load being used or not Loading Loading @@ -69,12 +75,28 @@ public: void moveEffects(audio_session_t session, audio_io_handle_t srcOutput, audio_io_handle_t dstOutput); audio_io_handle_t dstOutput, AudioPolicyClientInterface *clientInterface); void moveEffects(const std::vector<int>& ids, audio_io_handle_t dstOutput); void moveEffects(audio_session_t sessionId, audio_io_handle_t srcIo, audio_io_handle_t dstIo, const AudioInputCollection *inputs, AudioPolicyClientInterface *clientInterface); void moveEffectsForIo(audio_session_t sessionId, audio_io_handle_t dstIo, const AudioInputCollection *inputs, AudioPolicyClientInterface *mClientInterface); void putOrphanEffects(audio_session_t sessionId, audio_io_handle_t srcIo, const AudioInputCollection *inputs, AudioPolicyClientInterface *clientInterface); /** * @brief Checks if an effect session was already attached to an io handle and return it if * found. Check only for a given effect type if effectType is not null or for any effect * otherwise. * @param sessionId to consider. * @param effectType to consider. * @return ioHandle if found, AUDIO_IO_HANDLE_NONE otherwise. */ audio_io_handle_t getIoForSession(audio_session_t sessionId, const effect_uuid_t *effectType = nullptr); bool hasOrphansForSession(audio_session_t sessionId); EffectDescriptorCollection getOrphanEffectsForSession(audio_session_t sessionId) const; void dump(String8 *dst, int spaces = 0, bool verbose = true) const; private: Loading services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp +105 −11 Original line number Diff line number Diff line Loading @@ -18,9 +18,15 @@ //#define LOG_NDEBUG 0 #include <android-base/stringprintf.h> #include "AudioInputDescriptor.h" #include "EffectDescriptor.h" #include <utils/String8.h> #include <AudioPolicyInterface.h> #include "AudioPolicyMix.h" #include "HwModule.h" namespace android { void EffectDescriptor::dump(String8 *dst, int spaces) const Loading Loading @@ -175,30 +181,57 @@ uint32_t EffectDescriptorCollection::getMaxEffectsMemory() const return MAX_EFFECTS_MEMORY; } void EffectDescriptorCollection::moveEffects(audio_session_t session, audio_io_handle_t srcOutput, audio_io_handle_t dstOutput) void EffectDescriptorCollection::moveEffects(audio_session_t sessionId, audio_io_handle_t srcIo, audio_io_handle_t dstIo, AudioPolicyClientInterface *clientInterface) { ALOGV("%s session %d srcOutput %d dstOutput %d", __func__, session, srcOutput, dstOutput); ALOGV("%s session %d srcIo %d dstIo %d", __func__, sessionId, srcIo, dstIo); for (size_t i = 0; i < size(); i++) { sp<EffectDescriptor> effect = valueAt(i); if (effect->mSession == session && effect->mIo == srcOutput) { effect->mIo = dstOutput; if (effect->mSession == sessionId && effect->mIo == srcIo) { effect->mIo = dstIo; // Backup enable state before any updatePolicyState call effect->mIsOrphan = (dstIo == AUDIO_IO_HANDLE_NONE); } } clientInterface->moveEffects(sessionId, srcIo, dstIo); } void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids, audio_io_handle_t dstOutput) void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids, audio_io_handle_t dstIo) { ALOGV("%s num effects %zu, first ID %d, dstOutput %d", __func__, ids.size(), ids.size() ? ids[0] : 0, dstOutput); ALOGV("%s num effects %zu, first ID %d, dstIo %d", __func__, ids.size(), ids.size() ? ids[0] : 0, dstIo); for (size_t i = 0; i < size(); i++) { sp<EffectDescriptor> effect = valueAt(i); if (std::find(begin(ids), end(ids), effect->mId) != end(ids)) { effect->mIo = dstOutput; effect->mIo = dstIo; effect->mIsOrphan = (dstIo == AUDIO_IO_HANDLE_NONE); } } } bool EffectDescriptorCollection::hasOrphansForSession(audio_session_t sessionId) { for (size_t i = 0; i < size(); ++i) { sp<EffectDescriptor> effect = valueAt(i); if (effect->mSession == sessionId && effect->mIsOrphan) { return true; } } return false; } EffectDescriptorCollection EffectDescriptorCollection::getOrphanEffectsForSession( audio_session_t sessionId) const { EffectDescriptorCollection effects; for (size_t i = 0; i < size(); i++) { sp<EffectDescriptor> effect = valueAt(i); if (effect->mSession == sessionId && effect->mIsOrphan) { effects.add(keyAt(i), effect); } } return effects; } audio_io_handle_t EffectDescriptorCollection::getIoForSession(audio_session_t sessionId, Loading @@ -214,6 +247,67 @@ audio_io_handle_t EffectDescriptorCollection::getIoForSession(audio_session_t se return AUDIO_IO_HANDLE_NONE; } void EffectDescriptorCollection::moveEffectsForIo(audio_session_t session, audio_io_handle_t dstIo, const AudioInputCollection *inputs, AudioPolicyClientInterface *clientInterface) { // No src io: try to find from effect session the src Io to move from audio_io_handle_t srcIo = getIoForSession(session); if (hasOrphansForSession(session) || (srcIo != AUDIO_IO_HANDLE_NONE && srcIo != dstIo)) { moveEffects(session, srcIo, dstIo, inputs, clientInterface); } } void EffectDescriptorCollection::moveEffects(audio_session_t session, audio_io_handle_t srcIo, audio_io_handle_t dstIo, const AudioInputCollection *inputs, AudioPolicyClientInterface *clientInterface) { if ((srcIo != AUDIO_IO_HANDLE_NONE && srcIo == dstIo) || (srcIo == AUDIO_IO_HANDLE_NONE && !hasOrphansForSession(session))) { return; } // Either we may find orphan effects for given session or effects for this session might have // been assigned first to another input (it may happen when an input is released or recreated // after client sets its preferred device) EffectDescriptorCollection effectsToMove; if (srcIo == AUDIO_IO_HANDLE_NONE) { ALOGV("%s: restoring effects for session %d from orphan park to io=%d", __func__, session, dstIo); effectsToMove = getOrphanEffectsForSession(session); } else { ALOGV("%s: moving effects for session %d from io=%d to io=%d", __func__, session, srcIo, dstIo); sp<AudioInputDescriptor> previousInputDesc = inputs->valueFor(srcIo); effectsToMove = getEffectsForIo(srcIo); for (size_t i = 0; i < effectsToMove.size(); ++i) { sp<EffectDescriptor> effect = effectsToMove.valueAt(i); effect->mEnabledWhenMoved = effect->mEnabled; previousInputDesc->trackEffectEnabled(effect, false); } } moveEffects(session, srcIo, dstIo, clientInterface); if (dstIo != AUDIO_IO_HANDLE_NONE) { sp<AudioInputDescriptor> inputDesc = inputs->valueFor(dstIo); for (size_t i = 0; i < effectsToMove.size(); ++i) { sp<EffectDescriptor> effect = effectsToMove.valueAt(i); inputDesc->trackEffectEnabled(effect, effect->mEnabledWhenMoved); } } } void EffectDescriptorCollection::putOrphanEffects(audio_session_t session, audio_io_handle_t srcIo, const AudioInputCollection *inputs, AudioPolicyClientInterface *clientInterface) { if (getIoForSession(session) != srcIo) { // Effect session not held by this client io handle return; } ALOGV("%s: park effects for session %d and io=%d to orphans", __func__, session, srcIo); moveEffects(session, srcIo, AUDIO_IO_HANDLE_NONE, inputs, clientInterface); } EffectDescriptorCollection EffectDescriptorCollection::getEffectsForIo(audio_io_handle_t io) const { EffectDescriptorCollection effects; Loading services/audiopolicy/managerdefault/AudioPolicyManager.cpp +6 −3 Original line number Diff line number Diff line Loading @@ -2650,6 +2650,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, sp<AudioPolicyMix> policyMix; sp<DeviceDescriptor> device; sp<AudioInputDescriptor> inputDesc; sp<AudioInputDescriptor> previousInputDesc; sp<RecordClientDescriptor> clientDesc; audio_port_handle_t requestedDeviceId = *selectedDeviceId; uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(attributionSource.uid)); Loading Loading @@ -2806,6 +2807,8 @@ exit: requestedDeviceId, attributes.source, flags, isSoundTrigger); inputDesc = mInputs.valueFor(*input); // Move (if found) effect for the client session to its input mEffects.moveEffectsForIo(session, *input, &mInputs, mpClientInterface); inputDesc->addClient(clientDesc); ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d", Loading Loading @@ -3115,7 +3118,7 @@ void AudioPolicyManager::releaseInput(audio_port_handle_t portId) ALOGV("%s %d", __FUNCTION__, input); inputDesc->removeClient(portId); mEffects.putOrphanEffects(client->session(), input, &mInputs, mpClientInterface); if (inputDesc->getClientCount() > 0) { ALOGV("%s(%d) %zu clients remaining", __func__, portId, inputDesc->getClientCount()); return; Loading Loading @@ -3477,8 +3480,8 @@ audio_io_handle_t AudioPolicyManager::selectOutputForMusicEffects() } if (output != mMusicEffectOutput) { mEffects.moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output); mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output); mEffects.moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output, mpClientInterface); mMusicEffectOutput = output; } Loading Loading
services/audioflinger/AudioFlinger.cpp +118 −12 Original line number Diff line number Diff line Loading @@ -2226,6 +2226,9 @@ void AudioFlinger::removeNotificationClient(pid_t pid) } if (removed) { removedEffects = purgeStaleEffects_l(); std::vector< sp<IAfEffectModule> > removedOrphanEffects = purgeOrphanEffectChains_l(); removedEffects.insert(removedEffects.end(), removedOrphanEffects.begin(), removedOrphanEffects.end()); } } for (auto& effect : removedEffects) { Loading Loading @@ -3716,6 +3719,42 @@ std::vector<sp<IAfEffectModule>> AudioFlinger::purgeStaleEffects_l() { return removedEffects; } std::vector< sp<IAfEffectModule> > AudioFlinger::purgeOrphanEffectChains_l() { ALOGV("purging stale effects from orphan chains"); std::vector< sp<IAfEffectModule> > removedEffects; for (size_t index = 0; index < mOrphanEffectChains.size(); index++) { sp<IAfEffectChain> chain = mOrphanEffectChains.valueAt(index); audio_session_t session = mOrphanEffectChains.keyAt(index); if (session == AUDIO_SESSION_OUTPUT_MIX || session == AUDIO_SESSION_DEVICE || session == AUDIO_SESSION_OUTPUT_STAGE) { continue; } size_t numSessionRefs = mAudioSessionRefs.size(); bool found = false; for (size_t k = 0; k < numSessionRefs; k++) { AudioSessionRef *ref = mAudioSessionRefs.itemAt(k); if (ref->mSessionid == session) { ALOGV(" session %d still exists for %d with %d refs", session, ref->mPid, ref->mCnt); found = true; break; } } if (!found) { for (size_t i = 0; i < chain->numberOfEffects(); i++) { sp<IAfEffectModule> effect = chain->getEffectModule(i); removedEffects.push_back(effect); } } } for (auto& effect : removedEffects) { effect->unPin(); updateOrphanEffectChains_l(effect); } return removedEffects; } // dumpToThreadLog_l() must be called with AudioFlinger::mLock held void AudioFlinger::dumpToThreadLog_l(const sp<ThreadBase> &thread) { Loading Loading @@ -4449,24 +4488,42 @@ Exit: return lStatus; } status_t AudioFlinger::moveEffects(audio_session_t sessionId, audio_io_handle_t srcOutput, audio_io_handle_t dstOutput) status_t AudioFlinger::moveEffects(audio_session_t sessionId, audio_io_handle_t srcIo, audio_io_handle_t dstIo) NO_THREAD_SAFETY_ANALYSIS { ALOGV("moveEffects() session %d, srcOutput %d, dstOutput %d", sessionId, srcOutput, dstOutput); ALOGV("%s() session %d, srcIo %d, dstIo %d", __func__, sessionId, srcIo, dstIo); Mutex::Autolock _l(mLock); if (srcOutput == dstOutput) { ALOGW("moveEffects() same dst and src outputs %d", dstOutput); if (srcIo == dstIo) { ALOGW("%s() same dst and src outputs %d", __func__, dstIo); return NO_ERROR; } PlaybackThread *srcThread = checkPlaybackThread_l(srcOutput); if (srcThread == NULL) { ALOGW("moveEffects() bad srcOutput %d", srcOutput); RecordThread *srcRecordThread = checkRecordThread_l(srcIo); RecordThread *dstRecordThread = checkRecordThread_l(dstIo); if (srcRecordThread != nullptr || dstRecordThread != nullptr) { if (srcRecordThread != nullptr) { srcRecordThread->mLock.lock(); } if (dstRecordThread != nullptr) { dstRecordThread->mLock.lock(); } status_t ret = moveEffectChain_l(sessionId, srcRecordThread, dstRecordThread); if (srcRecordThread != nullptr) { srcRecordThread->mLock.unlock(); } if (dstRecordThread != nullptr) { dstRecordThread->mLock.unlock(); } return ret; } PlaybackThread *srcThread = checkPlaybackThread_l(srcIo); if (srcThread == nullptr) { ALOGW("%s() bad srcIo %d", __func__, srcIo); return BAD_VALUE; } PlaybackThread *dstThread = checkPlaybackThread_l(dstOutput); if (dstThread == NULL) { ALOGW("moveEffects() bad dstOutput %d", dstOutput); PlaybackThread *dstThread = checkPlaybackThread_l(dstIo); if (dstThread == nullptr) { ALOGW("%s() bad dstIo %d", __func__, dstIo); return BAD_VALUE; } Loading Loading @@ -4604,6 +4661,50 @@ NO_THREAD_SAFETY_ANALYSIS // requires srcThread and dstThread locks return status; } // moveEffectChain_l must be called with both srcThread (if not null) and dstThread (if not null) // mLocks held status_t AudioFlinger::moveEffectChain_l(audio_session_t sessionId, RecordThread *srcThread, RecordThread *dstThread) NO_THREAD_SAFETY_ANALYSIS // requires srcThread and dstThread locks { sp<IAfEffectChain> chain = nullptr; if (srcThread != 0) { Vector< sp<IAfEffectChain> > effectChains = srcThread->getEffectChains_l(); for (size_t i = 0; i < effectChains.size(); i ++) { if (effectChains[i]->sessionId() == sessionId) { chain = effectChains[i]; break; } } ALOGV_IF(effectChains.size() == 0, "%s: no effect chain on io=%d", __func__, srcThread->id()); if (chain == nullptr) { ALOGE("%s wrong session id %d", __func__, sessionId); return BAD_VALUE; } ALOGV("%s: removing effect chain for session=%d io=%d", __func__, sessionId, srcThread->id()); srcThread->removeEffectChain_l(chain); } else { chain = getOrphanEffectChain_l(sessionId); if (chain == nullptr) { ALOGE("%s: no orphan effect chain found for session=%d", __func__, sessionId); return BAD_VALUE; } } if (dstThread != 0) { ALOGV("%s: adding effect chain for session=%d on io=%d", __func__, sessionId, dstThread->id()); dstThread->addEffectChain_l(chain); return NO_ERROR; } ALOGV("%s: parking to orphan effect chain for session=%d", __func__, sessionId); putOrphanEffectChain_l(chain); return NO_ERROR; } status_t AudioFlinger::moveAuxEffectToIo(int EffectId, const sp<PlaybackThread>& dstThread, sp<PlaybackThread> *srcThread) Loading Loading @@ -4720,6 +4821,11 @@ sp<IAfEffectChain> AudioFlinger::getOrphanEffectChain_l(audio_session_t session) bool AudioFlinger::updateOrphanEffectChains(const sp<IAfEffectModule>& effect) { Mutex::Autolock _l(mLock); return updateOrphanEffectChains_l(effect); } bool AudioFlinger::updateOrphanEffectChains_l(const sp<IAfEffectModule>& effect) { audio_session_t session = effect->sessionId(); ssize_t index = mOrphanEffectChains.indexOfKey(session); ALOGV("updateOrphanEffectChains session %d index %zd", session, index); Loading
services/audioflinger/AudioFlinger.h +6 −0 Original line number Diff line number Diff line Loading @@ -791,6 +791,9 @@ private: status_t moveEffectChain_l(audio_session_t sessionId, PlaybackThread *srcThread, PlaybackThread *dstThread); status_t moveEffectChain_l(audio_session_t sessionId, RecordThread *srcThread, RecordThread *dstThread); status_t moveAuxEffectToIo(int EffectId, const sp<PlaybackThread>& dstThread, Loading Loading @@ -840,6 +843,9 @@ public: private: std::vector< sp<IAfEffectModule> > purgeStaleEffects_l(); std::vector< sp<IAfEffectModule> > purgeOrphanEffectChains_l(); bool updateOrphanEffectChains_l(const sp<IAfEffectModule>& effect); void broadcastParametersToRecordThreads_l(const String8& keyValuePairs); void updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices); void forwardParametersToDownstreamPatches_l( Loading
services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h +24 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,10 @@ namespace android { class AudioInputCollection; class AudioInputDescriptor; class AudioPolicyClientInterface; class EffectDescriptor : public RefBase { public: Loading @@ -40,6 +44,8 @@ public: int mId; // effect unique ID audio_io_handle_t mIo; // io the effect is attached to bool mIsOrphan = false; // on creation, effect is not yet attached but not yet orphan bool mEnabledWhenMoved = false; // Backup enabled state before being moved audio_session_t mSession; // audio session the effect is on effect_descriptor_t mDesc; // effect descriptor bool mEnabled; // enabled state: CPU load being used or not Loading Loading @@ -69,12 +75,28 @@ public: void moveEffects(audio_session_t session, audio_io_handle_t srcOutput, audio_io_handle_t dstOutput); audio_io_handle_t dstOutput, AudioPolicyClientInterface *clientInterface); void moveEffects(const std::vector<int>& ids, audio_io_handle_t dstOutput); void moveEffects(audio_session_t sessionId, audio_io_handle_t srcIo, audio_io_handle_t dstIo, const AudioInputCollection *inputs, AudioPolicyClientInterface *clientInterface); void moveEffectsForIo(audio_session_t sessionId, audio_io_handle_t dstIo, const AudioInputCollection *inputs, AudioPolicyClientInterface *mClientInterface); void putOrphanEffects(audio_session_t sessionId, audio_io_handle_t srcIo, const AudioInputCollection *inputs, AudioPolicyClientInterface *clientInterface); /** * @brief Checks if an effect session was already attached to an io handle and return it if * found. Check only for a given effect type if effectType is not null or for any effect * otherwise. * @param sessionId to consider. * @param effectType to consider. * @return ioHandle if found, AUDIO_IO_HANDLE_NONE otherwise. */ audio_io_handle_t getIoForSession(audio_session_t sessionId, const effect_uuid_t *effectType = nullptr); bool hasOrphansForSession(audio_session_t sessionId); EffectDescriptorCollection getOrphanEffectsForSession(audio_session_t sessionId) const; void dump(String8 *dst, int spaces = 0, bool verbose = true) const; private: Loading
services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp +105 −11 Original line number Diff line number Diff line Loading @@ -18,9 +18,15 @@ //#define LOG_NDEBUG 0 #include <android-base/stringprintf.h> #include "AudioInputDescriptor.h" #include "EffectDescriptor.h" #include <utils/String8.h> #include <AudioPolicyInterface.h> #include "AudioPolicyMix.h" #include "HwModule.h" namespace android { void EffectDescriptor::dump(String8 *dst, int spaces) const Loading Loading @@ -175,30 +181,57 @@ uint32_t EffectDescriptorCollection::getMaxEffectsMemory() const return MAX_EFFECTS_MEMORY; } void EffectDescriptorCollection::moveEffects(audio_session_t session, audio_io_handle_t srcOutput, audio_io_handle_t dstOutput) void EffectDescriptorCollection::moveEffects(audio_session_t sessionId, audio_io_handle_t srcIo, audio_io_handle_t dstIo, AudioPolicyClientInterface *clientInterface) { ALOGV("%s session %d srcOutput %d dstOutput %d", __func__, session, srcOutput, dstOutput); ALOGV("%s session %d srcIo %d dstIo %d", __func__, sessionId, srcIo, dstIo); for (size_t i = 0; i < size(); i++) { sp<EffectDescriptor> effect = valueAt(i); if (effect->mSession == session && effect->mIo == srcOutput) { effect->mIo = dstOutput; if (effect->mSession == sessionId && effect->mIo == srcIo) { effect->mIo = dstIo; // Backup enable state before any updatePolicyState call effect->mIsOrphan = (dstIo == AUDIO_IO_HANDLE_NONE); } } clientInterface->moveEffects(sessionId, srcIo, dstIo); } void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids, audio_io_handle_t dstOutput) void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids, audio_io_handle_t dstIo) { ALOGV("%s num effects %zu, first ID %d, dstOutput %d", __func__, ids.size(), ids.size() ? ids[0] : 0, dstOutput); ALOGV("%s num effects %zu, first ID %d, dstIo %d", __func__, ids.size(), ids.size() ? ids[0] : 0, dstIo); for (size_t i = 0; i < size(); i++) { sp<EffectDescriptor> effect = valueAt(i); if (std::find(begin(ids), end(ids), effect->mId) != end(ids)) { effect->mIo = dstOutput; effect->mIo = dstIo; effect->mIsOrphan = (dstIo == AUDIO_IO_HANDLE_NONE); } } } bool EffectDescriptorCollection::hasOrphansForSession(audio_session_t sessionId) { for (size_t i = 0; i < size(); ++i) { sp<EffectDescriptor> effect = valueAt(i); if (effect->mSession == sessionId && effect->mIsOrphan) { return true; } } return false; } EffectDescriptorCollection EffectDescriptorCollection::getOrphanEffectsForSession( audio_session_t sessionId) const { EffectDescriptorCollection effects; for (size_t i = 0; i < size(); i++) { sp<EffectDescriptor> effect = valueAt(i); if (effect->mSession == sessionId && effect->mIsOrphan) { effects.add(keyAt(i), effect); } } return effects; } audio_io_handle_t EffectDescriptorCollection::getIoForSession(audio_session_t sessionId, Loading @@ -214,6 +247,67 @@ audio_io_handle_t EffectDescriptorCollection::getIoForSession(audio_session_t se return AUDIO_IO_HANDLE_NONE; } void EffectDescriptorCollection::moveEffectsForIo(audio_session_t session, audio_io_handle_t dstIo, const AudioInputCollection *inputs, AudioPolicyClientInterface *clientInterface) { // No src io: try to find from effect session the src Io to move from audio_io_handle_t srcIo = getIoForSession(session); if (hasOrphansForSession(session) || (srcIo != AUDIO_IO_HANDLE_NONE && srcIo != dstIo)) { moveEffects(session, srcIo, dstIo, inputs, clientInterface); } } void EffectDescriptorCollection::moveEffects(audio_session_t session, audio_io_handle_t srcIo, audio_io_handle_t dstIo, const AudioInputCollection *inputs, AudioPolicyClientInterface *clientInterface) { if ((srcIo != AUDIO_IO_HANDLE_NONE && srcIo == dstIo) || (srcIo == AUDIO_IO_HANDLE_NONE && !hasOrphansForSession(session))) { return; } // Either we may find orphan effects for given session or effects for this session might have // been assigned first to another input (it may happen when an input is released or recreated // after client sets its preferred device) EffectDescriptorCollection effectsToMove; if (srcIo == AUDIO_IO_HANDLE_NONE) { ALOGV("%s: restoring effects for session %d from orphan park to io=%d", __func__, session, dstIo); effectsToMove = getOrphanEffectsForSession(session); } else { ALOGV("%s: moving effects for session %d from io=%d to io=%d", __func__, session, srcIo, dstIo); sp<AudioInputDescriptor> previousInputDesc = inputs->valueFor(srcIo); effectsToMove = getEffectsForIo(srcIo); for (size_t i = 0; i < effectsToMove.size(); ++i) { sp<EffectDescriptor> effect = effectsToMove.valueAt(i); effect->mEnabledWhenMoved = effect->mEnabled; previousInputDesc->trackEffectEnabled(effect, false); } } moveEffects(session, srcIo, dstIo, clientInterface); if (dstIo != AUDIO_IO_HANDLE_NONE) { sp<AudioInputDescriptor> inputDesc = inputs->valueFor(dstIo); for (size_t i = 0; i < effectsToMove.size(); ++i) { sp<EffectDescriptor> effect = effectsToMove.valueAt(i); inputDesc->trackEffectEnabled(effect, effect->mEnabledWhenMoved); } } } void EffectDescriptorCollection::putOrphanEffects(audio_session_t session, audio_io_handle_t srcIo, const AudioInputCollection *inputs, AudioPolicyClientInterface *clientInterface) { if (getIoForSession(session) != srcIo) { // Effect session not held by this client io handle return; } ALOGV("%s: park effects for session %d and io=%d to orphans", __func__, session, srcIo); moveEffects(session, srcIo, AUDIO_IO_HANDLE_NONE, inputs, clientInterface); } EffectDescriptorCollection EffectDescriptorCollection::getEffectsForIo(audio_io_handle_t io) const { EffectDescriptorCollection effects; Loading
services/audiopolicy/managerdefault/AudioPolicyManager.cpp +6 −3 Original line number Diff line number Diff line Loading @@ -2650,6 +2650,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, sp<AudioPolicyMix> policyMix; sp<DeviceDescriptor> device; sp<AudioInputDescriptor> inputDesc; sp<AudioInputDescriptor> previousInputDesc; sp<RecordClientDescriptor> clientDesc; audio_port_handle_t requestedDeviceId = *selectedDeviceId; uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(attributionSource.uid)); Loading Loading @@ -2806,6 +2807,8 @@ exit: requestedDeviceId, attributes.source, flags, isSoundTrigger); inputDesc = mInputs.valueFor(*input); // Move (if found) effect for the client session to its input mEffects.moveEffectsForIo(session, *input, &mInputs, mpClientInterface); inputDesc->addClient(clientDesc); ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d", Loading Loading @@ -3115,7 +3118,7 @@ void AudioPolicyManager::releaseInput(audio_port_handle_t portId) ALOGV("%s %d", __FUNCTION__, input); inputDesc->removeClient(portId); mEffects.putOrphanEffects(client->session(), input, &mInputs, mpClientInterface); if (inputDesc->getClientCount() > 0) { ALOGV("%s(%d) %zu clients remaining", __func__, portId, inputDesc->getClientCount()); return; Loading Loading @@ -3477,8 +3480,8 @@ audio_io_handle_t AudioPolicyManager::selectOutputForMusicEffects() } if (output != mMusicEffectOutput) { mEffects.moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output); mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output); mEffects.moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output, mpClientInterface); mMusicEffectOutput = output; } Loading