audio policy: concurrent capture effects
Add pre processing effect management for concurrent capture scenarii.
When several clients on the same input stream have enabled audio effects,
only the effects attached to the top priotity client are active.
Other effects are suspended.
Add AudioFlinger API to suspend/restore audio effects build on top
of exisiting internal effect suspend mechanism.
RecordThread now supports more than one effect chain.
AOSP pre processing implementation supports more than one effect session
per input.
Refactor AudioPolicyManager::closeAllInputs() to call closeInput() on
all inputs instead of partially duplicated code.
Bug: 128419018
Test: make
Change-Id: I685286da4c2905a8894a4354679f9787b1400621
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 825cd4e..dd95e34 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -89,6 +89,7 @@
GET_MICROPHONES,
SET_MASTER_BALANCE,
GET_MASTER_BALANCE,
+ SET_EFFECT_SUSPENDED,
};
#define MAX_ITEMS_PER_LIST 1024
@@ -718,6 +719,18 @@
return reply.readInt32();
}
+ virtual void setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(effectId);
+ data.writeInt32(sessionId);
+ data.writeInt32(suspended ? 1 : 0);
+ remote()->transact(SET_EFFECT_SUSPENDED, data, &reply);
+ }
+
virtual audio_module_handle_t loadHwModule(const char *name)
{
Parcel data, reply;
@@ -913,6 +926,7 @@
case INVALIDATE_STREAM:
case SET_VOICE_VOLUME:
case MOVE_EFFECTS:
+ case SET_EFFECT_SUSPENDED:
case LOAD_HW_MODULE:
case LIST_AUDIO_PORTS:
case GET_AUDIO_PORT:
@@ -926,6 +940,7 @@
// return status only for non void methods
switch (code) {
case SET_RECORD_SILENCED:
+ case SET_EFFECT_SUSPENDED:
break;
default:
reply->writeInt32(static_cast<int32_t> (INVALID_OPERATION));
@@ -1371,6 +1386,14 @@
reply->writeInt32(moveEffects(session, srcOutput, dstOutput));
return NO_ERROR;
} break;
+ case SET_EFFECT_SUSPENDED: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int effectId = data.readInt32();
+ audio_session_t sessionId = (audio_session_t) data.readInt32();
+ bool suspended = data.readInt32() == 1;
+ setEffectSuspended(effectId, sessionId, suspended);
+ return NO_ERROR;
+ } break;
case LOAD_HW_MODULE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
reply->writeInt32(loadHwModule(data.readCString()));
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index ef0ed0c..dcc18b6 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -457,6 +457,10 @@
virtual status_t moveEffects(audio_session_t session, audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput) = 0;
+ virtual void setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended) = 0;
+
virtual audio_module_handle_t loadHwModule(const char *name) = 0;
// helpers for android.media.AudioManager.getProperty(), see description there for meaning
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 50c33c6..5fab5be 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -926,7 +926,7 @@
delete session->revBuf;
session->revBuf = NULL;
- session->io = 0;
+ session->id = 0;
}
return 0;
@@ -1155,7 +1155,7 @@
{
size_t i;
for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
- if (sSessions[i].io == ioId) {
+ if (sSessions[i].id == sessionId) {
if (sSessions[i].createdMsk & (1 << procId)) {
return NULL;
}
@@ -1163,7 +1163,7 @@
}
}
for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
- if (sSessions[i].io == 0) {
+ if (sSessions[i].id == 0) {
sSessions[i].id = sessionId;
sSessions[i].io = ioId;
return &sSessions[i];
@@ -1915,7 +1915,7 @@
status = Session_CreateEffect(session, procId, pInterface);
if (status < 0 && session->createdMsk == 0) {
- session->io = 0;
+ session->id = 0;
}
return status;
}
@@ -1929,7 +1929,7 @@
preproc_effect_t *fx = (preproc_effect_t *)interface;
- if (fx->session->io == 0) {
+ if (fx->session->id == 0) {
return -EINVAL;
}
return Session_ReleaseEffect(fx->session, fx);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 4b31816..809d16d 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1699,18 +1699,35 @@
}
// getEffectThread_l() must be called with AudioFlinger::mLock held
-sp<AudioFlinger::PlaybackThread> AudioFlinger::getEffectThread_l(audio_session_t sessionId,
- int EffectId)
+sp<AudioFlinger::ThreadBase> AudioFlinger::getEffectThread_l(audio_session_t sessionId,
+ int effectId)
{
- sp<PlaybackThread> thread;
+ sp<ThreadBase> thread;
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- if (mPlaybackThreads.valueAt(i)->getEffect(sessionId, EffectId) != 0) {
+ if (mPlaybackThreads.valueAt(i)->getEffect(sessionId, effectId) != 0) {
ALOG_ASSERT(thread == 0);
thread = mPlaybackThreads.valueAt(i);
}
}
-
+ if (thread != nullptr) {
+ return thread;
+ }
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ if (mRecordThreads.valueAt(i)->getEffect(sessionId, effectId) != 0) {
+ ALOG_ASSERT(thread == 0);
+ thread = mRecordThreads.valueAt(i);
+ }
+ }
+ if (thread != nullptr) {
+ return thread;
+ }
+ for (size_t i = 0; i < mMmapThreads.size(); i++) {
+ if (mMmapThreads.valueAt(i)->getEffect(sessionId, effectId) != 0) {
+ ALOG_ASSERT(thread == 0);
+ thread = mMmapThreads.valueAt(i);
+ }
+ }
return thread;
}
@@ -3464,6 +3481,23 @@
return moveEffectChain_l(sessionId, srcThread, dstThread);
}
+
+void AudioFlinger::setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended)
+{
+ Mutex::Autolock _l(mLock);
+
+ sp<ThreadBase> thread = getEffectThread_l(sessionId, effectId);
+ if (thread == nullptr) {
+ return;
+ }
+ Mutex::Autolock _sl(thread->mLock);
+ sp<EffectModule> effect = thread->getEffect_l(sessionId, effectId);
+ thread->setEffectSuspended_l(&effect->desc().type, suspended, sessionId);
+}
+
+
// moveEffectChain_l must be called with both srcThread and dstThread mLocks held
status_t AudioFlinger::moveEffectChain_l(audio_session_t sessionId,
AudioFlinger::PlaybackThread *srcThread,
@@ -3541,7 +3575,8 @@
{
status_t status = NO_ERROR;
Mutex::Autolock _l(mLock);
- sp<PlaybackThread> thread = getEffectThread_l(AUDIO_SESSION_OUTPUT_MIX, EffectId);
+ sp<PlaybackThread> thread =
+ static_cast<PlaybackThread *>(getEffectThread_l(AUDIO_SESSION_OUTPUT_MIX, EffectId).get());
if (EffectId != 0 && thread != 0 && dstThread != thread.get()) {
Mutex::Autolock _dl(dstThread->mLock);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 8bf89c8..72e669a 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -239,6 +239,10 @@
virtual status_t moveEffects(audio_session_t sessionId, audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput);
+ void setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended) override;
+
virtual audio_module_handle_t loadHwModule(const char *name);
virtual uint32_t getPrimaryOutputSamplingRate();
@@ -708,7 +712,7 @@
// return the playback thread with smallest HAL buffer size, and prefer fast
PlaybackThread *fastPlaybackThread_l() const;
- sp<PlaybackThread> getEffectThread_l(audio_session_t sessionId, int EffectId);
+ sp<ThreadBase> getEffectThread_l(audio_session_t sessionId, int effectId);
void removeClient_l(pid_t pid);
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 50ab634..3c4fbba 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1488,9 +1488,10 @@
result.append("\t\tCould not lock Fx mutex:\n");
}
- result.append("\t\tSession Status State Engine:\n");
- result.appendFormat("\t\t%05d %03d %03d %p\n",
- mSessionId, mStatus, mState, mEffectInterface.get());
+ result.append("\t\tSession Status State Registered Enabled Suspended Engine:\n");
+ result.appendFormat("\t\t%05d %03d %03d %s %s %s %p\n",
+ mSessionId, mStatus, mState, mPolicyRegistered ? "y" : "n", mPolicyEnabled ? "y" : "n",
+ mSuspended ? "y" : "n", mEffectInterface.get());
result.append("\t\tDescriptor:\n");
char uuidStr[64];
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index e71f0c6..59ced26 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -8248,11 +8248,6 @@
status_t AudioFlinger::RecordThread::addEffectChain_l(const sp<EffectChain>& chain)
{
- // only one chain per input thread
- if (!mEffectChains.isEmpty()) {
- ALOGW("addEffectChain_l() already one chain %p on thread %p", chain.get(), this);
- return INVALID_OPERATION;
- }
ALOGV("addEffectChain_l() %p on thread %p", chain.get(), this);
chain->setThread(this);
chain->setInBuffer(NULL);
@@ -8272,13 +8267,14 @@
size_t AudioFlinger::RecordThread::removeEffectChain_l(const sp<EffectChain>& chain)
{
ALOGV("removeEffectChain_l() %p from thread %p", chain.get(), this);
- ALOGW_IF(mEffectChains.size() != 1,
- "removeEffectChain_l() %p invalid chain size %zu on thread %p",
- chain.get(), mEffectChains.size(), this);
- if (mEffectChains.size() == 1) {
- mEffectChains.removeAt(0);
+
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ if (chain == mEffectChains[i]) {
+ mEffectChains.removeAt(i);
+ break;
+ }
}
- return 0;
+ return mEffectChains.size();
}
status_t AudioFlinger::RecordThread::createAudioPatch_l(const struct audio_patch *patch,
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index caf0d7e..4b56a46 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -348,6 +348,10 @@
audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput) = 0;
+ virtual void setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended) = 0;
+
/* Create a patch between several source and sink ports */
virtual status_t createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index e071fe0..37f9d14 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -68,11 +68,13 @@
bool isSourceActive(audio_source_t source) const;
audio_source_t source() const;
bool isSoundTrigger() const;
+ sp<RecordClientDescriptor> getHighestPriorityClient() const;
audio_attributes_t getHighestPriorityAttributes() const;
void setClientActive(const sp<RecordClientDescriptor>& client, bool active);
int32_t activeCount() { return mGlobalActiveCount; }
void trackEffectEnabled(const sp<EffectDescriptor> &effect, bool enabled);
EffectDescriptorCollection getEnabledEffects() const;
+ EffectDescriptorCollection getActiveEffects() const; // enabled and not suspended
// implementation of AudioIODescriptorInterface
audio_config_base_t getConfig() const override;
audio_patch_handle_t getPatchHandle() const override;
@@ -100,6 +102,10 @@
// implementation of ClientMapHandler<RecordClientDescriptor>
void addClient(const sp<RecordClientDescriptor> &client) override;
+ // Go over all active clients and suspend or restore effects according highest priority
+ // active use case
+ void checkSuspendEffects();
+
private:
void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);
diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
index c729ef9..c4eab30 100644
--- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
@@ -29,8 +29,8 @@
{
public:
EffectDescriptor(const effect_descriptor_t *desc, bool isMusicEffect,
- int id, int io, int session) :
- mId(id), mIo(io), mSession(session), mEnabled(false),
+ int id, audio_io_handle_t io, audio_session_t session) :
+ mId(id), mIo(io), mSession(session), mEnabled(false), mSuspended(false),
mIsMusicEffect(isMusicEffect)
{
memcpy (&mDesc, desc, sizeof(effect_descriptor_t));
@@ -38,11 +38,12 @@
void dump(String8 *dst, int spaces = 0) const;
- int mId; // effect unique ID
- int mIo; // io the effect is attached to
- int mSession; // audio session the effect is on
- effect_descriptor_t mDesc; // effect descriptor
- bool mEnabled; // enabled state: CPU load being used or not
+ int mId; // effect unique ID
+ audio_io_handle_t mIo; // io the effect is attached to
+ 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
+ bool mSuspended; // enabled but suspended by concurent capture policy
bool isMusicEffect() const { return mIsMusicEffect; }
@@ -59,6 +60,7 @@
int session, int id, bool isMusicEffect);
status_t unregisterEffect(int id);
sp<EffectDescriptor> getEffect(int id) const;
+ EffectDescriptorCollection getEffectsForIo(audio_io_handle_t io) const;
status_t setEffectEnabled(int id, bool enabled);
bool isEffectEnabled(int id) const;
uint32_t getMaxEffectsCpuLoad() const;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 5b4e2eb..58683be 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -128,6 +128,13 @@
audio_attributes_t AudioInputDescriptor::getHighestPriorityAttributes() const
{
audio_attributes_t attributes = { .source = AUDIO_SOURCE_DEFAULT };
+ sp<RecordClientDescriptor> topClient = getHighestPriorityClient();
+ return topClient ? topClient->attributes() : attributes;
+}
+
+sp<RecordClientDescriptor> AudioInputDescriptor::getHighestPriorityClient() const
+{
+ sp<RecordClientDescriptor> topClient;
for (bool activeOnly : { true, false }) {
int32_t topPriority = -1;
@@ -139,18 +146,18 @@
app_state_t curState = client->appState();
if (curState >= topState) {
int32_t curPriority = source_priority(client->source());
- if (curPriority > topPriority) {
- attributes = client->attributes();
+ if (curPriority >= topPriority) {
+ topClient = client;
topPriority = curPriority;
}
topState = curState;
}
}
- if (attributes.source != AUDIO_SOURCE_DEFAULT) {
+ if (topClient != nullptr) {
break;
}
}
- return attributes;
+ return topClient;
}
bool AudioInputDescriptor::isSoundTrigger() const {
@@ -326,9 +333,10 @@
client->setActive(active);
+ checkSuspendEffects();
+
int event = active ? RECORD_CONFIG_EVENT_START : RECORD_CONFIG_EVENT_STOP;
updateClientRecordingConfiguration(event, client);
-
}
void AudioInputDescriptor::updateClientRecordingConfiguration(
@@ -397,44 +405,90 @@
mEnabledEffects.replaceValueFor(effect->mId, effect);
} else {
mEnabledEffects.removeItem(effect->mId);
+ // always exit from suspend when disabling an effect as only enabled effects
+ // are managed by checkSuspendEffects()
+ if (effect->mSuspended) {
+ effect->mSuspended = false;
+ mClientInterface->setEffectSuspended(effect->mId, effect->mSession, effect->mSuspended);
+ }
}
RecordClientVector clients = getClientsForSession((audio_session_t)effect->mSession);
+ RecordClientVector updatedClients;
+
for (const auto& client : clients) {
sp<EffectDescriptor> clientEffect = client->getEnabledEffects().getEffect(effect->mId);
bool changed = (enabled && clientEffect == nullptr)
|| (!enabled && clientEffect != nullptr);
client->trackEffectEnabled(effect, enabled);
if (changed && client->active()) {
- updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+ updatedClients.push_back(client);
}
}
+
+ checkSuspendEffects();
+
+ for (const auto& client : updatedClients) {
+ updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+ }
}
EffectDescriptorCollection AudioInputDescriptor::getEnabledEffects() const
{
- EffectDescriptorCollection enabledEffects;
// report effects for highest priority active source as applied to all clients
- RecordClientVector clients =
- clientsList(true /*activeOnly*/, source(), false /*preferredDeviceOnly*/);
- if (clients.size() > 0) {
- enabledEffects = clients[0]->getEnabledEffects();
+ EffectDescriptorCollection enabledEffects;
+ sp<RecordClientDescriptor> topClient = getHighestPriorityClient();
+ if (topClient != nullptr) {
+ enabledEffects = topClient->getEnabledEffects();
}
return enabledEffects;
}
-void AudioInputDescriptor::setAppState(uid_t uid, app_state_t state) {
+void AudioInputDescriptor::setAppState(uid_t uid, app_state_t state)
+{
RecordClientVector clients = clientsList(false /*activeOnly*/);
+ RecordClientVector updatedClients;
for (const auto& client : clients) {
if (uid == client->uid()) {
bool wasSilenced = client->isSilenced();
client->setAppState(state);
if (client->active() && wasSilenced != client->isSilenced()) {
- updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+ updatedClients.push_back(client);
}
}
}
+
+ checkSuspendEffects();
+
+ for (const auto& client : updatedClients) {
+ updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
+ }
+}
+
+void AudioInputDescriptor::checkSuspendEffects()
+{
+ sp<RecordClientDescriptor> topClient = getHighestPriorityClient();
+ if (topClient == nullptr) {
+ return;
+ }
+
+ for (size_t i = 0; i < mEnabledEffects.size(); i++) {
+ sp<EffectDescriptor> effect = mEnabledEffects.valueAt(i);
+ if (effect->mSession == topClient->session()) {
+ if (effect->mSuspended) {
+ effect->mSuspended = false;
+ mClientInterface->setEffectSuspended(effect->mId,
+ effect->mSession,
+ effect->mSuspended);
+ }
+ } else if (!effect->mSuspended) {
+ effect->mSuspended = true;
+ mClientInterface->setEffectSuspended(effect->mId,
+ effect->mSession,
+ effect->mSuspended);
+ }
+ }
}
void AudioInputDescriptor::dump(String8 *dst) const
@@ -444,7 +498,7 @@
dst->appendFormat(" Format: %d\n", mFormat);
dst->appendFormat(" Channels: %08x\n", mChannelMask);
dst->appendFormat(" Devices %s\n", mDevice->toString().c_str());
- getEnabledEffects().dump(dst, 1 /*spaces*/, false /*verbose*/);
+ mEnabledEffects.dump(dst, 1 /*spaces*/, false /*verbose*/);
dst->append(" AudioRecord Clients:\n");
ClientMapHandler<RecordClientDescriptor>::dump(dst);
dst->append("\n");
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
index 627fa8d..415962a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -30,6 +30,7 @@
dst->appendFormat("%*sSession: %d\n", spaces, "", mSession);
dst->appendFormat("%*sName: %s\n", spaces, "", mDesc.name);
dst->appendFormat("%*s%s\n", spaces, "", mEnabled ? "Enabled" : "Disabled");
+ dst->appendFormat("%*s%s\n", spaces, "", mSuspended ? "Suspended" : "Active");
}
EffectDescriptorCollection::EffectDescriptorCollection() :
@@ -63,7 +64,8 @@
desc->name, io, session, id);
ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
- sp<EffectDescriptor> effectDesc = new EffectDescriptor(desc, isMusicEffect, id, io, session);
+ sp<EffectDescriptor> effectDesc =
+ new EffectDescriptor(desc, isMusicEffect, id, io, (audio_session_t)session);
add(id, effectDesc);
return NO_ERROR;
@@ -200,6 +202,17 @@
}
}
+EffectDescriptorCollection EffectDescriptorCollection::getEffectsForIo(audio_io_handle_t io) const
+{
+ EffectDescriptorCollection effects;
+ for (size_t i = 0; i < size(); i++) {
+ if (valueAt(i)->mIo == io) {
+ effects.add(keyAt(i), valueAt(i));
+ }
+ }
+ return effects;
+}
+
void EffectDescriptorCollection::dump(String8 *dst, int spaces, bool verbose) const
{
if (verbose) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index d8fbc38..c6d55bc 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2361,25 +2361,8 @@
}
void AudioPolicyManager::closeAllInputs() {
- bool patchRemoved = false;
-
- for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
- sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(input_index);
- ssize_t patch_index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
- if (patch_index >= 0) {
- sp<AudioPatch> patchDesc = mAudioPatches.valueAt(patch_index);
- (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
- mAudioPatches.removeItemsAt(patch_index);
- patchRemoved = true;
- }
- inputDesc->close();
- }
- mInputs.clear();
- SoundTrigger::setCaptureState(false);
- nextAudioPortGeneration();
-
- if (patchRemoved) {
- mpClientInterface->onAudioPatchListUpdate();
+ while (mInputs.size() != 0) {
+ closeInput(mInputs.keyAt(0));
}
}
@@ -2713,7 +2696,6 @@
if (mEffects.getEffect(id) == nullptr) {
return INVALID_OPERATION;
}
-
if (mEffects.isEffectEnabled(id)) {
ALOGW("%s effect %d enabled", __FUNCTION__, id);
setEffectEnabled(id, false);
@@ -2721,6 +2703,16 @@
return mEffects.unregisterEffect(id);
}
+void AudioPolicyManager::cleanUpEffectsForIo(audio_io_handle_t io)
+{
+ EffectDescriptorCollection effects = mEffects.getEffectsForIo(io);
+ for (size_t i = 0; i < effects.size(); i++) {
+ ALOGW("%s removing stale effect %s, id %d on closed IO %d",
+ __func__, effects.valueAt(i)->mDesc.name, effects.keyAt(i), io);
+ unregisterEffect(effects.keyAt(i));
+ }
+}
+
status_t AudioPolicyManager::setEffectEnabled(int id, bool enabled)
{
sp<EffectDescriptor> effect = mEffects.getEffect(id);
@@ -4113,15 +4105,8 @@
void AudioPolicyManager::setAppState(uid_t uid, app_state_t state)
{
ALOGV("%s(uid:%d, state:%d)", __func__, uid, state);
-
for (size_t i = 0; i < mInputs.size(); i++) {
- sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
- RecordClientVector clients = inputDesc->clientsList(false /*activeOnly*/);
- for (const auto& client : clients) {
- if (uid == client->uid()) {
- client->setAppState(state);
- }
- }
+ mInputs.valueAt(i)->setAppState(uid, state);
}
}
@@ -4932,6 +4917,8 @@
setMsdPatch();
}
}
+
+ cleanUpEffectsForIo(output);
}
void AudioPolicyManager::closeInput(audio_io_handle_t input)
@@ -4963,6 +4950,8 @@
mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
SoundTrigger::setCaptureState(false);
}
+
+ cleanUpEffectsForIo(input);
}
SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevices(
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index fd88841..587f2b8 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -870,6 +870,8 @@
int delayMs,
uid_t uid,
sp<AudioPatch> *patchDescPtr);
+
+ void cleanUpEffectsForIo(audio_io_handle_t io);
};
};
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 5748334..d51cc6e 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -172,6 +172,13 @@
return af->moveEffects(session, src_output, dst_output);
}
+void AudioPolicyService::AudioPolicyClient::setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended)
+{
+ mAudioPolicyService->setEffectSuspended(effectId, sessionId, suspended);
+}
+
status_t AudioPolicyService::AudioPolicyClient::createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
int delayMs)
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index f63fa81..5389c08 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -1196,6 +1196,17 @@
data->mPatchHandle, data->mSource);
mLock.lock();
} break;
+ case SET_EFFECT_SUSPENDED: {
+ SetEffectSuspendedData *data = (SetEffectSuspendedData *)command->mParam.get();
+ ALOGV("AudioCommandThread() processing set effect suspended");
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af != 0) {
+ mLock.unlock();
+ af->setEffectSuspended(data->mEffectId, data->mSessionId, data->mSuspended);
+ mLock.lock();
+ }
+ } break;
+
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
}
@@ -1327,6 +1338,23 @@
return sendCommand(command, delayMs);
}
+void AudioPolicyService::AudioCommandThread::setEffectSuspendedCommand(int effectId,
+ audio_session_t sessionId,
+ bool suspended)
+{
+ sp<AudioCommand> command = new AudioCommand();
+ command->mCommand = SET_EFFECT_SUSPENDED;
+ sp<SetEffectSuspendedData> data = new SetEffectSuspendedData();
+ data->mEffectId = effectId;
+ data->mSessionId = sessionId;
+ data->mSuspended = suspended;
+ command->mParam = data;
+ ALOGV("AudioCommandThread() adding set suspended effectId %d sessionId %d suspended %d",
+ effectId, sessionId, suspended);
+ sendCommand(command);
+}
+
+
void AudioPolicyService::AudioCommandThread::stopOutputCommand(audio_port_handle_t portId)
{
sp<AudioCommand> command = new AudioCommand();
@@ -1707,6 +1735,14 @@
return (int)mAudioCommandThread->voiceVolumeCommand(volume, delayMs);
}
+void AudioPolicyService::setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended)
+{
+ mAudioCommandThread->setEffectSuspendedCommand(effectId, sessionId, suspended);
+}
+
+
extern "C" {
audio_module_handle_t aps_load_hw_module(void *service __unused,
const char *name);
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 0842649..6c19912 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -293,6 +293,9 @@
void onAudioVolumeGroupChanged(volume_group_t group, int flags);
void doOnAudioVolumeGroupChanged(volume_group_t group, int flags);
+ void setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended);
private:
AudioPolicyService() ANDROID_API;
@@ -427,7 +430,8 @@
CHANGED_AUDIOVOLUMEGROUP,
SET_AUDIOPORT_CONFIG,
DYN_POLICY_MIX_STATE_UPDATE,
- RECORDING_CONFIGURATION_UPDATE
+ RECORDING_CONFIGURATION_UPDATE,
+ SET_EFFECT_SUSPENDED,
};
AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -470,6 +474,9 @@
std::vector<effect_descriptor_t> effects,
audio_patch_handle_t patchHandle,
audio_source_t source);
+ void setEffectSuspendedCommand(int effectId,
+ audio_session_t sessionId,
+ bool suspended);
void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
class AudioCommandData;
@@ -567,6 +574,13 @@
audio_source_t mSource;
};
+ class SetEffectSuspendedData : public AudioCommandData {
+ public:
+ int mEffectId;
+ audio_session_t mSessionId;
+ bool mSuspended;
+ };
+
Mutex mLock;
Condition mWaitWorkCV;
Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
@@ -652,6 +666,10 @@
audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput);
+ void setEffectSuspended(int effectId,
+ audio_session_t sessionId,
+ bool suspended) override;
+
/* Create a patch between several source and sink ports */
virtual status_t createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 8854eb2..e4c64e5 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -84,6 +84,9 @@
std::vector<effect_descriptor_t> effects __unused,
audio_patch_handle_t patchHandle __unused,
audio_source_t source __unused) override { }
+ void setEffectSuspended(int effectId __unused,
+ audio_session_t sessionId __unused,
+ bool suspended __unused) {}
};
} // namespace android