Add dynamic stream default effects
Allows runtime modification of what effects should be default
attached to streams of different types/usages. The core functionality
was already in the AudioPolicyEffects system, this allows
the dynamic modification of the lists.
Bug: 78527120
Test: Builds, manually tested an app adding a stream effect,
tested both media on the specified stream and on a different stream.
Also tested by Android Things integration tests.
Change-Id: Ie0426b17ff7daece58b8c85d72fbef620844325b
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index fdae23b..2858aad 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -23,6 +23,7 @@
#include <memory>
#include <cutils/misc.h>
#include <media/AudioEffect.h>
+#include <media/AudioPolicyHelper.h>
#include <media/EffectsConfig.h>
#include <mediautils/ServiceUtilities.h>
#include <system/audio.h>
@@ -317,6 +318,102 @@
return status;
}
+status_t AudioPolicyEffects::addStreamDefaultEffect(const effect_uuid_t *type,
+ const String16& opPackageName,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ audio_usage_t usage,
+ audio_unique_id_t* id)
+{
+ if (uuid == NULL || type == NULL) {
+ ALOGE("addStreamDefaultEffect(): Null uuid or type uuid pointer");
+ return BAD_VALUE;
+ }
+
+ audio_stream_type_t stream = audio_usage_to_stream_type(usage);
+
+ if (stream < AUDIO_STREAM_MIN || stream >= AUDIO_STREAM_PUBLIC_CNT) {
+ ALOGE("addStreamDefaultEffect(): Unsupported stream type %d", stream);
+ return BAD_VALUE;
+ }
+
+ // Check that |uuid| or |type| corresponds to an effect on the system.
+ effect_descriptor_t descriptor = {};
+ status_t res = AudioEffect::getEffectDescriptor(
+ uuid, type, EFFECT_FLAG_TYPE_INSERT, &descriptor);
+ if (res != OK) {
+ ALOGE("addStreamDefaultEffect(): Failed to find effect descriptor matching uuid/type.");
+ return res;
+ }
+
+ // Only insert effects can be added dynamically as stream defaults.
+ if ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_INSERT) {
+ ALOGE("addStreamDefaultEffect(): Desired effect cannot be attached "
+ "as a stream default effect.");
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mLock);
+
+ // Find the EffectDescVector for the given stream type, or create a new one if necessary.
+ ssize_t index = mOutputStreams.indexOfKey(stream);
+ EffectDescVector *desc = NULL;
+ if (index < 0) {
+ // No effects for this stream type yet.
+ desc = new EffectDescVector();
+ mOutputStreams.add(stream, desc);
+ } else {
+ desc = mOutputStreams.valueAt(index);
+ }
+
+ // Create a new effect and add it to the vector.
+ res = AudioEffect::newEffectUniqueId(id);
+ if (res != OK) {
+ ALOGE("addStreamDefaultEffect(): failed to get new unique id.");
+ return res;
+ }
+ EffectDesc *effect = new EffectDesc(
+ descriptor.name, *type, opPackageName, *uuid, priority, *id);
+ desc->mEffects.add(effect);
+ // TODO(b/71813697): Support setting params as well.
+
+ // TODO(b/71814300): Retroactively attach to any existing streams of the given type.
+ // This requires tracking the stream type of each session id in addition to what is
+ // already being tracked.
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyEffects::removeStreamDefaultEffect(audio_unique_id_t id)
+{
+ if (id == AUDIO_UNIQUE_ID_ALLOCATE) {
+ // ALLOCATE is not a unique identifier, but rather a reserved value indicating
+ // a real id has not been assigned. For default effects, this value is only used
+ // by system-owned defaults from the loaded config, which cannot be removed.
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mLock);
+
+ // Check each stream type.
+ size_t numStreams = mOutputStreams.size();
+ for (size_t i = 0; i < numStreams; ++i) {
+ // Check each effect for each stream.
+ EffectDescVector* descVector = mOutputStreams[i];
+ for (auto desc = descVector->mEffects.begin(); desc != descVector->mEffects.end(); ++desc) {
+ if ((*desc)->mId == id) {
+ // Found it!
+ // TODO(b/71814300): Remove from any streams the effect was attached to.
+ descVector->mEffects.erase(desc);
+ // Handles are unique; there can only be one match, so return early.
+ return NO_ERROR;
+ }
+ }
+ }
+
+ // Effect wasn't found, so it's been trivially removed successfully.
+ return NO_ERROR;
+}
void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled)
{
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 623180e..69367b1 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -64,7 +64,6 @@
status_t releaseInputEffects(audio_io_handle_t input,
audio_session_t audioSession);
-
// Return a list of effect descriptors for default output effects
// associated with audioSession
status_t queryDefaultOutputSessionEffects(audio_session_t audioSession,
@@ -82,18 +81,49 @@
audio_stream_type_t stream,
audio_session_t audioSession);
+ // Add the effect to the list of default effects for streams of type |stream|.
+ status_t addStreamDefaultEffect(const effect_uuid_t *type,
+ const String16& opPackageName,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ audio_usage_t usage,
+ audio_unique_id_t* id);
+
+ // Remove the default stream effect from wherever it's attached.
+ status_t removeStreamDefaultEffect(audio_unique_id_t id);
+
private:
// class to store the description of an effects and its parameters
// as defined in audio_effects.conf
class EffectDesc {
public:
- EffectDesc(const char *name, const effect_uuid_t& uuid) :
+ EffectDesc(const char *name,
+ const effect_uuid_t& typeUuid,
+ const String16& opPackageName,
+ const effect_uuid_t& uuid,
+ uint32_t priority,
+ audio_unique_id_t id) :
mName(strdup(name)),
- mUuid(uuid) { }
+ mTypeUuid(typeUuid),
+ mOpPackageName(opPackageName),
+ mUuid(uuid),
+ mPriority(priority),
+ mId(id) { }
+ EffectDesc(const char *name, const effect_uuid_t& uuid) :
+ EffectDesc(name,
+ *EFFECT_UUID_NULL,
+ String16(""),
+ uuid,
+ 0,
+ AUDIO_UNIQUE_ID_ALLOCATE) { }
EffectDesc(const EffectDesc& orig) :
mName(strdup(orig.mName)),
- mUuid(orig.mUuid) {
+ mTypeUuid(orig.mTypeUuid),
+ mOpPackageName(orig.mOpPackageName),
+ mUuid(orig.mUuid),
+ mPriority(orig.mPriority),
+ mId(orig.mId) {
// deep copy mParams
for (size_t k = 0; k < orig.mParams.size(); k++) {
effect_param_t *origParam = orig.mParams[k];
@@ -116,7 +146,11 @@
}
}
char *mName;
+ effect_uuid_t mTypeUuid;
+ String16 mOpPackageName;
effect_uuid_t mUuid;
+ int32_t mPriority;
+ audio_unique_id_t mId;
Vector <effect_param_t *> mParams;
};
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index dbfda44..d29f637 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -859,6 +859,50 @@
(audio_session_t)audioSession, descriptors, count);
}
+status_t AudioPolicyService::addStreamDefaultEffect(const effect_uuid_t *type,
+ const String16& opPackageName,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ audio_usage_t usage,
+ audio_unique_id_t* id)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!modifyDefaultAudioEffectsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ sp<AudioPolicyEffects>audioPolicyEffects;
+ {
+ Mutex::Autolock _l(mLock);
+ audioPolicyEffects = mAudioPolicyEffects;
+ }
+ if (audioPolicyEffects == 0) {
+ return NO_INIT;
+ }
+ return audioPolicyEffects->addStreamDefaultEffect(
+ type, opPackageName, uuid, priority, usage, id);
+}
+
+status_t AudioPolicyService::removeStreamDefaultEffect(audio_unique_id_t id)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!modifyDefaultAudioEffectsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ sp<AudioPolicyEffects>audioPolicyEffects;
+ {
+ Mutex::Autolock _l(mLock);
+ audioPolicyEffects = mAudioPolicyEffects;
+ }
+ if (audioPolicyEffects == 0) {
+ return NO_INIT;
+ }
+ return audioPolicyEffects->removeStreamDefaultEffect(id);
+}
+
bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
{
if (mAudioPolicyManager == NULL) {
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 6a25668..44c0347 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -126,6 +126,14 @@
virtual status_t queryDefaultPreProcessing(audio_session_t audioSession,
effect_descriptor_t *descriptors,
uint32_t *count);
+ virtual status_t addStreamDefaultEffect(const effect_uuid_t *type,
+ const String16& opPackageName,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ audio_usage_t usage,
+ audio_unique_id_t* id);
+ virtual status_t removeStreamDefaultEffect(audio_unique_id_t id);
+
virtual status_t onTransact(
uint32_t code,
const Parcel& data,