audiopolicy: effects: preprocessing session not attached on right input
Bug: 267799634
Test: make
When an audio record is using a preferred device, and when it attaches
an effect to its session, the effect may not be attached to the right input.
Change-Id: I9e80cfde000a8a46fd21b19c4588c631f8512e3a
Signed-off-by: François Gaffie <francois.gaffie@renault.com>
diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
index 59eee52..d40bbcb 100644
--- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
@@ -25,6 +25,10 @@
namespace android {
+class AudioInputCollection;
+class AudioInputDescriptor;
+class AudioPolicyClientInterface;
+
class EffectDescriptor : public RefBase
{
public:
@@ -40,6 +44,8 @@
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
@@ -69,12 +75,28 @@
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:
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
index 3f9c8b0..216d2eb 100644
--- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -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
@@ -175,30 +181,57 @@
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 dstIo)
+{
+ 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 = dstIo;
+ effect->mIsOrphan = (dstIo == AUDIO_IO_HANDLE_NONE);
}
}
}
-void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids,
- audio_io_handle_t dstOutput)
+bool EffectDescriptorCollection::hasOrphansForSession(audio_session_t sessionId)
{
- ALOGV("%s num effects %zu, first ID %d, dstOutput %d",
- __func__, ids.size(), ids.size() ? ids[0] : 0, dstOutput);
- for (size_t i = 0; i < size(); i++) {
+ 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;
+ 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,
@@ -214,6 +247,67 @@
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;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0e971b0..92b58ec 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2650,6 +2650,7 @@
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));
@@ -2806,6 +2807,8 @@
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",
@@ -3115,7 +3118,7 @@
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;
@@ -3477,8 +3480,8 @@
}
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;
}