From 24628310591c3b4d9701ebad9df7f5750dc599b2 Mon Sep 17 00:00:00 2001 From: Ari Hausman-Cohen Date: Mon, 13 Aug 2018 15:01:09 -0700 Subject: [PATCH] Add dynamic source default effects Allows runtime modification of what effects should be default attached to sources of different types. 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 source effect, tested both media on the specified source and on a different source. Also tested by Android Things integration tests. Change-Id: I4da15787278c79d80043e172f4f81d3b2a139f44 --- media/libaudioclient/AudioEffect.cpp | 40 ++++++++ media/libaudioclient/IAudioPolicyService.cpp | 76 +++++++++++++- .../include/media/AudioEffect.h | 53 ++++++++++ .../include/media/IAudioPolicyService.h | 7 ++ .../service/AudioPolicyEffects.cpp | 99 +++++++++++++++++++ .../audiopolicy/service/AudioPolicyEffects.h | 13 ++- .../service/AudioPolicyInterfaceImpl.cpp | 75 +++++++++----- .../audiopolicy/service/AudioPolicyService.h | 9 ++ 8 files changed, 347 insertions(+), 25 deletions(-) diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp index 0641b6ead6..0ae2738138 100644 --- a/media/libaudioclient/AudioEffect.cpp +++ b/media/libaudioclient/AudioEffect.cpp @@ -456,6 +456,38 @@ status_t AudioEffect::newEffectUniqueId(audio_unique_id_t* id) return NO_ERROR; } +status_t AudioEffect::addSourceDefaultEffect(const char *typeStr, + const String16& opPackageName, + const char *uuidStr, + int32_t priority, + audio_source_t source, + audio_unique_id_t *id) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + + if (typeStr == NULL && uuidStr == NULL) return BAD_VALUE; + + // Convert type & uuid from string to effect_uuid_t. + effect_uuid_t type; + if (typeStr != NULL) { + status_t res = stringToGuid(typeStr, &type); + if (res != OK) return res; + } else { + type = *EFFECT_UUID_NULL; + } + + effect_uuid_t uuid; + if (uuidStr != NULL) { + status_t res = stringToGuid(uuidStr, &uuid); + if (res != OK) return res; + } else { + uuid = *EFFECT_UUID_NULL; + } + + return aps->addSourceDefaultEffect(&type, opPackageName, &uuid, priority, source, id); +} + status_t AudioEffect::addStreamDefaultEffect(const char *typeStr, const String16& opPackageName, const char *uuidStr, @@ -488,6 +520,14 @@ status_t AudioEffect::addStreamDefaultEffect(const char *typeStr, return aps->addStreamDefaultEffect(&type, opPackageName, &uuid, priority, usage, id); } +status_t AudioEffect::removeSourceDefaultEffect(audio_unique_id_t id) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + + return aps->removeSourceDefaultEffect(id); +} + status_t AudioEffect::removeStreamDefaultEffect(audio_unique_id_t id) { const sp& aps = AudioSystem::get_audio_policy_service(); diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp index abf74f80e4..32a71f3b6a 100644 --- a/media/libaudioclient/IAudioPolicyService.cpp +++ b/media/libaudioclient/IAudioPolicyService.cpp @@ -83,7 +83,9 @@ enum { GET_SURROUND_FORMATS, SET_SURROUND_FORMAT_ENABLED, ADD_STREAM_DEFAULT_EFFECT, - REMOVE_STREAM_DEFAULT_EFFECT + REMOVE_STREAM_DEFAULT_EFFECT, + ADD_SOURCE_DEFAULT_EFFECT, + REMOVE_SOURCE_DEFAULT_EFFECT }; #define MAX_ITEMS_PER_LIST 1024 @@ -904,6 +906,41 @@ public: return static_cast (reply.readInt32()); } + virtual status_t addSourceDefaultEffect(const effect_uuid_t *type, + const String16& opPackageName, + const effect_uuid_t *uuid, + int32_t priority, + audio_source_t source, + audio_unique_id_t* id) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(type, sizeof(effect_uuid_t)); + data.writeString16(opPackageName); + data.write(uuid, sizeof(effect_uuid_t)); + data.writeInt32(priority); + data.writeInt32((int32_t) source); + status_t status = remote()->transact(ADD_SOURCE_DEFAULT_EFFECT, data, &reply); + if (status != NO_ERROR) { + return status; + } + status = static_cast (reply.readInt32()); + *id = reply.readInt32(); + return status; + } + + virtual status_t removeSourceDefaultEffect(audio_unique_id_t id) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(id); + status_t status = remote()->transact(REMOVE_SOURCE_DEFAULT_EFFECT, data, &reply); + if (status != NO_ERROR) { + return status; + } + return static_cast (reply.readInt32()); + } + }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -1636,6 +1673,43 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } + case ADD_SOURCE_DEFAULT_EFFECT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + effect_uuid_t type; + status_t status = data.read(&type, sizeof(effect_uuid_t)); + if (status != NO_ERROR) { + return status; + } + String16 opPackageName; + status = data.readString16(&opPackageName); + if (status != NO_ERROR) { + return status; + } + effect_uuid_t uuid; + status = data.read(&uuid, sizeof(effect_uuid_t)); + if (status != NO_ERROR) { + return status; + } + int32_t priority = data.readInt32(); + audio_source_t source = (audio_source_t) data.readInt32(); + audio_unique_id_t id = 0; + reply->writeInt32(static_cast (addSourceDefaultEffect(&type, + opPackageName, + &uuid, + priority, + source, + &id))); + reply->writeInt32(id); + return NO_ERROR; + } + + case REMOVE_SOURCE_DEFAULT_EFFECT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + audio_unique_id_t id = static_cast(data.readInt32()); + reply->writeInt32(static_cast (removeSourceDefaultEffect(id))); + return NO_ERROR; + } + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h index c97f7838a3..0de58b85a5 100644 --- a/media/libaudioclient/include/media/AudioEffect.h +++ b/media/libaudioclient/include/media/AudioEffect.h @@ -169,6 +169,44 @@ public: * Static methods for adding/removing system-wide effects. */ + /* + * Adds an effect to the list of default output effects for a given source type. + * + * If the effect is no longer available when a source of the given type + * is created, the system will continue without adding it. + * + * Parameters: + * typeStr: Type uuid of effect to be a default: can be null if uuidStr is specified. + * This may correspond to the OpenSL ES interface implemented by this effect, + * or could be some vendor-defined type. + * opPackageName: The package name used for app op checks. + * uuidStr: Uuid of effect to be a default: can be null if type is specified. + * This uuid corresponds to a particular implementation of an effect type. + * Note if both uuidStr and typeStr are specified, typeStr is ignored. + * priority: Requested priority for effect control: the priority level corresponds to the + * value of priority parameter: negative values indicate lower priorities, positive + * values higher priorities, 0 being the normal priority. + * source: The source this effect should be a default for. + * id: Address where the system-wide unique id of the default effect should be returned. + * + * Returned status (from utils/Errors.h) can be: + * NO_ERROR successful operation. + * PERMISSION_DENIED could not get AudioFlinger interface + * or caller lacks required permissions. + * NO_INIT effect library failed to initialize. + * BAD_VALUE invalid source, type uuid or implementation uuid. + * NAME_NOT_FOUND no effect with this uuid or type found. + * + * Returned value + * *id: The system-wide unique id of the added default effect. + */ + static status_t addSourceDefaultEffect(const char* typeStr, + const String16& opPackageName, + const char* uuidStr, + int32_t priority, + audio_source_t source, + audio_unique_id_t* id); + /* * Adds an effect to the list of default output effects for a given stream type. * @@ -208,6 +246,21 @@ public: audio_usage_t usage, audio_unique_id_t* id); + /* + * Removes an effect from the list of default output effects for a given source type. + * + * Parameters: + * id: The system-wide unique id of the effect that should no longer be a default. + * + * Returned status (from utils/Errors.h) can be: + * NO_ERROR successful operation. + * PERMISSION_DENIED could not get AudioFlinger interface + * or caller lacks required permissions. + * NO_INIT effect library failed to initialize. + * BAD_VALUE invalid id. + */ + static status_t removeSourceDefaultEffect(audio_unique_id_t id); + /* * Removes an effect from the list of default output effects for a given stream type. * diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h index c2899f83e0..fdd8d57969 100644 --- a/media/libaudioclient/include/media/IAudioPolicyService.h +++ b/media/libaudioclient/include/media/IAudioPolicyService.h @@ -109,12 +109,19 @@ public: virtual status_t queryDefaultPreProcessing(audio_session_t audioSession, effect_descriptor_t *descriptors, uint32_t *count) = 0; + virtual status_t addSourceDefaultEffect(const effect_uuid_t *type, + const String16& opPackageName, + const effect_uuid_t *uuid, + int32_t priority, + audio_source_t source, + audio_unique_id_t* id) = 0; 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) = 0; + virtual status_t removeSourceDefaultEffect(audio_unique_id_t id) = 0; virtual status_t removeStreamDefaultEffect(audio_unique_id_t id) = 0; // Check if offload is possible for given format, stream type, sample rate, // bit rate, duration, video and streaming or offload property is enabled diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp index 2858aadb2d..b3d564aaf3 100644 --- a/services/audiopolicy/service/AudioPolicyEffects.cpp +++ b/services/audiopolicy/service/AudioPolicyEffects.cpp @@ -318,6 +318,74 @@ status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t outpu return status; } +status_t AudioPolicyEffects::addSourceDefaultEffect(const effect_uuid_t *type, + const String16& opPackageName, + const effect_uuid_t *uuid, + int32_t priority, + audio_source_t source, + audio_unique_id_t* id) +{ + if (uuid == NULL || type == NULL) { + ALOGE("addSourceDefaultEffect(): Null uuid or type uuid pointer"); + return BAD_VALUE; + } + + // HOTWORD and FM_TUNER are two special case sources > MAX. + if (source < AUDIO_SOURCE_DEFAULT || + (source > AUDIO_SOURCE_MAX && + source != AUDIO_SOURCE_HOTWORD && + source != AUDIO_SOURCE_FM_TUNER)) { + ALOGE("addSourceDefaultEffect(): Unsupported source type %d", source); + 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_PRE_PROC, &descriptor); + if (res != OK) { + ALOGE("addSourceDefaultEffect(): Failed to find effect descriptor matching uuid/type."); + return res; + } + + // Only pre-processing effects can be added dynamically as source defaults. + if ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC) { + ALOGE("addSourceDefaultEffect(): Desired effect cannot be attached " + "as a source default effect."); + return BAD_VALUE; + } + + Mutex::Autolock _l(mLock); + + // Find the EffectDescVector for the given source type, or create a new one if necessary. + ssize_t index = mInputSources.indexOfKey(source); + EffectDescVector *desc = NULL; + if (index < 0) { + // No effects for this source type yet. + desc = new EffectDescVector(); + mInputSources.add(source, desc); + } else { + desc = mInputSources.valueAt(index); + } + + // Create a new effect and add it to the vector. + res = AudioEffect::newEffectUniqueId(id); + if (res != OK) { + ALOGE("addSourceDefaultEffect(): 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 sources of the given type. + // This requires tracking the source type of each session id in addition to what is + // already being tracked. + + return NO_ERROR; +} + status_t AudioPolicyEffects::addStreamDefaultEffect(const effect_uuid_t *type, const String16& opPackageName, const effect_uuid_t *uuid, @@ -384,6 +452,37 @@ status_t AudioPolicyEffects::addStreamDefaultEffect(const effect_uuid_t *type, return NO_ERROR; } +status_t AudioPolicyEffects::removeSourceDefaultEffect(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 source type. + size_t numSources = mInputSources.size(); + for (size_t i = 0; i < numSources; ++i) { + // Check each effect for each source. + EffectDescVector* descVector = mInputSources[i]; + for (auto desc = descVector->mEffects.begin(); desc != descVector->mEffects.end(); ++desc) { + if ((*desc)->mId == id) { + // Found it! + // TODO(b/71814300): Remove from any sources 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; +} + status_t AudioPolicyEffects::removeStreamDefaultEffect(audio_unique_id_t id) { if (id == AUDIO_UNIQUE_ID_ALLOCATE) { diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h index 69367b1dc0..6ad01f7611 100644 --- a/services/audiopolicy/service/AudioPolicyEffects.h +++ b/services/audiopolicy/service/AudioPolicyEffects.h @@ -81,7 +81,15 @@ public: audio_stream_type_t stream, audio_session_t audioSession); - // Add the effect to the list of default effects for streams of type |stream|. + // Add the effect to the list of default effects for sources of type |source|. + status_t addSourceDefaultEffect(const effect_uuid_t *type, + const String16& opPackageName, + const effect_uuid_t *uuid, + int32_t priority, + audio_source_t source, + audio_unique_id_t* id); + + // Add the effect to the list of default effects for streams of a given usage. status_t addStreamDefaultEffect(const effect_uuid_t *type, const String16& opPackageName, const effect_uuid_t *uuid, @@ -89,6 +97,9 @@ public: audio_usage_t usage, audio_unique_id_t* id); + // Remove the default source effect from wherever it's attached. + status_t removeSourceDefaultEffect(audio_unique_id_t id); + // Remove the default stream effect from wherever it's attached. status_t removeStreamDefaultEffect(audio_unique_id_t id); diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 3439c9bcda..02ab07fbed 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -829,67 +829,96 @@ bool AudioPolicyService::isSourceActive(audio_source_t source) const return mAudioPolicyManager->isSourceActive(source); } -status_t AudioPolicyService::queryDefaultPreProcessing(audio_session_t audioSession, - effect_descriptor_t *descriptors, - uint32_t *count) +status_t AudioPolicyService::getAudioPolicyEffects(sp& audioPolicyEffects) { if (mAudioPolicyManager == NULL) { - *count = 0; return NO_INIT; } - spaudioPolicyEffects; { Mutex::Autolock _l(mLock); audioPolicyEffects = mAudioPolicyEffects; } if (audioPolicyEffects == 0) { - *count = 0; return NO_INIT; } + + return OK; +} + +status_t AudioPolicyService::queryDefaultPreProcessing(audio_session_t audioSession, + effect_descriptor_t *descriptors, + uint32_t *count) +{ + spaudioPolicyEffects; + status_t status = getAudioPolicyEffects(audioPolicyEffects); + if (status != OK) { + *count = 0; + return status; + } return audioPolicyEffects->queryDefaultInputEffects( (audio_session_t)audioSession, descriptors, count); } -status_t AudioPolicyService::addStreamDefaultEffect(const effect_uuid_t *type, +status_t AudioPolicyService::addSourceDefaultEffect(const effect_uuid_t *type, const String16& opPackageName, const effect_uuid_t *uuid, int32_t priority, - audio_usage_t usage, + audio_source_t source, audio_unique_id_t* id) { - if (mAudioPolicyManager == NULL) { - return NO_INIT; + spaudioPolicyEffects; + status_t status = getAudioPolicyEffects(audioPolicyEffects); + if (status != OK) { + return status; } if (!modifyDefaultAudioEffectsAllowed()) { return PERMISSION_DENIED; } + return audioPolicyEffects->addSourceDefaultEffect( + type, opPackageName, uuid, priority, source, id); +} + +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) +{ spaudioPolicyEffects; - { - Mutex::Autolock _l(mLock); - audioPolicyEffects = mAudioPolicyEffects; + status_t status = getAudioPolicyEffects(audioPolicyEffects); + if (status != OK) { + return status; } - if (audioPolicyEffects == 0) { - return NO_INIT; + if (!modifyDefaultAudioEffectsAllowed()) { + return PERMISSION_DENIED; } return audioPolicyEffects->addStreamDefaultEffect( type, opPackageName, uuid, priority, usage, id); } -status_t AudioPolicyService::removeStreamDefaultEffect(audio_unique_id_t id) +status_t AudioPolicyService::removeSourceDefaultEffect(audio_unique_id_t id) { - if (mAudioPolicyManager == NULL) { - return NO_INIT; + spaudioPolicyEffects; + status_t status = getAudioPolicyEffects(audioPolicyEffects); + if (status != OK) { + return status; } if (!modifyDefaultAudioEffectsAllowed()) { return PERMISSION_DENIED; } + return audioPolicyEffects->removeSourceDefaultEffect(id); +} + +status_t AudioPolicyService::removeStreamDefaultEffect(audio_unique_id_t id) +{ spaudioPolicyEffects; - { - Mutex::Autolock _l(mLock); - audioPolicyEffects = mAudioPolicyEffects; + status_t status = getAudioPolicyEffects(audioPolicyEffects); + if (status != OK) { + return status; } - if (audioPolicyEffects == 0) { - return NO_INIT; + if (!modifyDefaultAudioEffectsAllowed()) { + return PERMISSION_DENIED; } return audioPolicyEffects->removeStreamDefaultEffect(id); } diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h index 44c0347f7f..6c5564728a 100644 --- a/services/audiopolicy/service/AudioPolicyService.h +++ b/services/audiopolicy/service/AudioPolicyService.h @@ -126,12 +126,19 @@ public: virtual status_t queryDefaultPreProcessing(audio_session_t audioSession, effect_descriptor_t *descriptors, uint32_t *count); + virtual status_t addSourceDefaultEffect(const effect_uuid_t *type, + const String16& opPackageName, + const effect_uuid_t *uuid, + int32_t priority, + audio_source_t source, + audio_unique_id_t* id); 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 removeSourceDefaultEffect(audio_unique_id_t id); virtual status_t removeStreamDefaultEffect(audio_unique_id_t id); virtual status_t onTransact( @@ -259,6 +266,8 @@ private: std::string getDeviceTypeStrForPortId(audio_port_handle_t portId); + status_t getAudioPolicyEffects(sp& audioPolicyEffects); + // If recording we need to make sure the UID is allowed to do that. If the UID is idle // then it cannot record and gets buffers with zeros - silence. As soon as the UID // transitions to an active state we will start reporting buffers with data. This approach