Implement AIDL effect IFacotry::queryProcessing
Bug: 281572768 Test: atest --test-mapping hardware/interfaces/audio/aidl/vts:presubmit Change-Id: I0166786d531437ef52690b92067766879b043a1d Merged-In: I0166786d531437ef52690b92067766879b043a1d
This commit is contained in:
parent
1d23120bad
commit
5824efbe84
6 changed files with 155 additions and 39 deletions
|
@ -14,12 +14,17 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#define LOG_TAG "AHAL_EffectConfig"
|
||||
#include <android-base/logging.h>
|
||||
#include <system/audio_effects/audio_effects_conf.h>
|
||||
#include <system/audio_effects/effect_uuid.h>
|
||||
|
||||
#include "effectFactory-impl/EffectConfig.h"
|
||||
|
||||
using aidl::android::media::audio::common::AudioSource;
|
||||
using aidl::android::media::audio::common::AudioStreamType;
|
||||
using aidl::android::media::audio::common::AudioUuid;
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
@ -55,14 +60,16 @@ EffectConfig::EffectConfig(const std::string& file) {
|
|||
// Parse pre processing chains
|
||||
for (auto& xmlPreprocess : getChildren(xmlConfig, "preprocess")) {
|
||||
for (auto& xmlStream : getChildren(xmlPreprocess, "stream")) {
|
||||
registerFailure(parseStream(xmlStream));
|
||||
// AudioSource
|
||||
registerFailure(parseProcessing(Processing::Type::source, xmlStream));
|
||||
}
|
||||
}
|
||||
|
||||
// Parse post processing chains
|
||||
for (auto& xmlPostprocess : getChildren(xmlConfig, "postprocess")) {
|
||||
for (auto& xmlStream : getChildren(xmlPostprocess, "stream")) {
|
||||
registerFailure(parseStream(xmlStream));
|
||||
// AudioStreamType
|
||||
registerFailure(parseProcessing(Processing::Type::streamType, xmlStream));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,21 +147,6 @@ bool EffectConfig::parseEffect(const tinyxml2::XMLElement& xml) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool EffectConfig::parseStream(const tinyxml2::XMLElement& xml) {
|
||||
LOG(DEBUG) << __func__ << dump(xml);
|
||||
const char* type = xml.Attribute("type");
|
||||
RETURN_VALUE_IF(!type, false, "noTypeInProcess");
|
||||
RETURN_VALUE_IF(0 != mProcessingMap.count(type), false, "duplicateType");
|
||||
|
||||
for (auto& apply : getChildren(xml, "apply")) {
|
||||
const char* name = apply.get().Attribute("effect");
|
||||
RETURN_VALUE_IF(!name, false, "noEffectAttribute");
|
||||
mProcessingMap[type].push_back(name);
|
||||
LOG(DEBUG) << __func__ << " " << type << " : " << name;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EffectConfig::parseLibraryUuid(const tinyxml2::XMLElement& xml,
|
||||
struct LibraryUuid& libraryUuid, bool isProxy) {
|
||||
// Retrieve library name only if not effectProxy element
|
||||
|
@ -174,6 +166,80 @@ bool EffectConfig::parseLibraryUuid(const tinyxml2::XMLElement& xml,
|
|||
return true;
|
||||
}
|
||||
|
||||
std::optional<Processing::Type> EffectConfig::stringToProcessingType(Processing::Type::Tag typeTag,
|
||||
const std::string& type) {
|
||||
// see list of audio stream types in audio_stream_type_t:
|
||||
// system/media/audio/include/system/audio_effects/audio_effects_conf.h
|
||||
// AUDIO_STREAM_DEFAULT_TAG is not listed here because according to SYS_RESERVED_DEFAULT in
|
||||
// AudioStreamType.aidl: "Value reserved for system use only. HALs must never return this value
|
||||
// to the system or accept it from the system".
|
||||
static const std::map<const std::string, AudioStreamType> sAudioStreamTypeTable = {
|
||||
{AUDIO_STREAM_VOICE_CALL_TAG, AudioStreamType::VOICE_CALL},
|
||||
{AUDIO_STREAM_SYSTEM_TAG, AudioStreamType::SYSTEM},
|
||||
{AUDIO_STREAM_RING_TAG, AudioStreamType::RING},
|
||||
{AUDIO_STREAM_MUSIC_TAG, AudioStreamType::MUSIC},
|
||||
{AUDIO_STREAM_ALARM_TAG, AudioStreamType::ALARM},
|
||||
{AUDIO_STREAM_NOTIFICATION_TAG, AudioStreamType::NOTIFICATION},
|
||||
{AUDIO_STREAM_BLUETOOTH_SCO_TAG, AudioStreamType::BLUETOOTH_SCO},
|
||||
{AUDIO_STREAM_ENFORCED_AUDIBLE_TAG, AudioStreamType::ENFORCED_AUDIBLE},
|
||||
{AUDIO_STREAM_DTMF_TAG, AudioStreamType::DTMF},
|
||||
{AUDIO_STREAM_TTS_TAG, AudioStreamType::TTS},
|
||||
{AUDIO_STREAM_ASSISTANT_TAG, AudioStreamType::ASSISTANT}};
|
||||
|
||||
// see list of audio sources in audio_source_t:
|
||||
// system/media/audio/include/system/audio_effects/audio_effects_conf.h
|
||||
static const std::map<const std::string, AudioSource> sAudioSourceTable = {
|
||||
{MIC_SRC_TAG, AudioSource::VOICE_CALL},
|
||||
{VOICE_UL_SRC_TAG, AudioSource::VOICE_CALL},
|
||||
{VOICE_DL_SRC_TAG, AudioSource::VOICE_CALL},
|
||||
{VOICE_CALL_SRC_TAG, AudioSource::VOICE_CALL},
|
||||
{CAMCORDER_SRC_TAG, AudioSource::VOICE_CALL},
|
||||
{VOICE_REC_SRC_TAG, AudioSource::VOICE_CALL},
|
||||
{VOICE_COMM_SRC_TAG, AudioSource::VOICE_CALL},
|
||||
{REMOTE_SUBMIX_SRC_TAG, AudioSource::VOICE_CALL},
|
||||
{UNPROCESSED_SRC_TAG, AudioSource::VOICE_CALL},
|
||||
{VOICE_PERFORMANCE_SRC_TAG, AudioSource::VOICE_CALL}};
|
||||
|
||||
if (typeTag == Processing::Type::streamType) {
|
||||
auto typeIter = sAudioStreamTypeTable.find(type);
|
||||
if (typeIter != sAudioStreamTypeTable.end()) {
|
||||
return typeIter->second;
|
||||
}
|
||||
} else if (typeTag == Processing::Type::source) {
|
||||
auto typeIter = sAudioSourceTable.find(type);
|
||||
if (typeIter != sAudioSourceTable.end()) {
|
||||
return typeIter->second;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool EffectConfig::parseProcessing(Processing::Type::Tag typeTag, const tinyxml2::XMLElement& xml) {
|
||||
LOG(DEBUG) << __func__ << dump(xml);
|
||||
const char* typeStr = xml.Attribute("type");
|
||||
auto aidlType = stringToProcessingType(typeTag, typeStr);
|
||||
RETURN_VALUE_IF(!aidlType.has_value(), false, "illegalStreamType");
|
||||
RETURN_VALUE_IF(0 != mProcessingMap.count(aidlType.value()), false, "duplicateStreamType");
|
||||
|
||||
for (auto& apply : getChildren(xml, "apply")) {
|
||||
const char* name = apply.get().Attribute("effect");
|
||||
if (mEffectsMap.find(name) == mEffectsMap.end()) {
|
||||
LOG(ERROR) << __func__ << " effect " << name << " doesn't exist, skipping";
|
||||
continue;
|
||||
}
|
||||
RETURN_VALUE_IF(!name, false, "noEffectAttribute");
|
||||
mProcessingMap[aidlType.value()].emplace_back(mEffectsMap[name]);
|
||||
LOG(WARNING) << __func__ << " " << typeStr << " : " << name;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::map<Processing::Type, std::vector<EffectConfig::EffectLibraries>>&
|
||||
EffectConfig::getProcessingMap() const {
|
||||
return mProcessingMap;
|
||||
}
|
||||
|
||||
bool EffectConfig::findUuid(const std::string& xmlEffectName, AudioUuid* uuid) {
|
||||
// Difference from EFFECT_TYPE_LIST_DEF, there could be multiple name mapping to same Effect Type
|
||||
#define EFFECT_XML_TYPE_LIST_DEF(V) \
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include <unordered_set>
|
||||
#define LOG_TAG "AHAL_EffectFactory"
|
||||
|
@ -52,6 +54,22 @@ Factory::~Factory() {
|
|||
}
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Factory::getDescriptorWithUuid(const AudioUuid& uuid, Descriptor* desc) {
|
||||
RETURN_IF(!desc, EX_NULL_POINTER, "nullDescriptor");
|
||||
|
||||
if (mEffectLibMap.count(uuid)) {
|
||||
auto& entry = mEffectLibMap[uuid];
|
||||
getDlSyms(entry);
|
||||
auto& libInterface = std::get<kMapEntryInterfaceIndex>(entry);
|
||||
RETURN_IF(!libInterface || !libInterface->queryEffectFunc, EX_NULL_POINTER,
|
||||
"dlNullQueryEffectFunc");
|
||||
RETURN_IF_BINDER_EXCEPTION(libInterface->queryEffectFunc(&uuid, desc));
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type_uuid,
|
||||
const std::optional<AudioUuid>& in_impl_uuid,
|
||||
const std::optional<AudioUuid>& in_proxy_uuid,
|
||||
|
@ -69,12 +87,7 @@ ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type
|
|||
for (const auto& id : idList) {
|
||||
if (mEffectLibMap.count(id.uuid)) {
|
||||
Descriptor desc;
|
||||
auto& entry = mEffectLibMap[id.uuid];
|
||||
getDlSyms(entry);
|
||||
auto& libInterface = std::get<kMapEntryInterfaceIndex>(entry);
|
||||
RETURN_IF(!libInterface || !libInterface->queryEffectFunc, EX_NULL_POINTER,
|
||||
"dlNullQueryEffectFunc");
|
||||
RETURN_IF_BINDER_EXCEPTION(libInterface->queryEffectFunc(&id.uuid, &desc));
|
||||
RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid(id.uuid, &desc), "getDescriptorFailed");
|
||||
// update proxy UUID with information from config xml
|
||||
desc.common.id.proxy = id.proxy;
|
||||
_aidl_return->emplace_back(std::move(desc));
|
||||
|
@ -85,12 +98,26 @@ ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type
|
|||
|
||||
ndk::ScopedAStatus Factory::queryProcessing(const std::optional<Processing::Type>& in_type,
|
||||
std::vector<Processing>* _aidl_return) {
|
||||
// TODO: implement this with audio_effect.xml.
|
||||
if (in_type.has_value()) {
|
||||
// return all matching process filter
|
||||
LOG(DEBUG) << __func__ << " process type: " << in_type.value().toString();
|
||||
const auto& processings = mConfig.getProcessingMap();
|
||||
// Processing stream type
|
||||
for (const auto& procIter : processings) {
|
||||
if (!in_type.has_value() || in_type.value() == procIter.first) {
|
||||
Processing process = {.type = procIter.first /* Processing::Type */};
|
||||
for (const auto& libs : procIter.second /* std::vector<struct EffectLibraries> */) {
|
||||
for (const auto& lib : libs.libraries /* std::vector<struct LibraryUuid> */) {
|
||||
Descriptor desc;
|
||||
if (libs.proxyLibrary.has_value()) {
|
||||
desc.common.id.proxy = libs.proxyLibrary.value().uuid;
|
||||
}
|
||||
RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid(lib.uuid, &desc),
|
||||
"getDescriptorFailed");
|
||||
process.ids.emplace_back(desc);
|
||||
}
|
||||
}
|
||||
_aidl_return->emplace_back(process);
|
||||
}
|
||||
}
|
||||
LOG(DEBUG) << __func__ << " return " << _aidl_return->size();
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
|
|
|
@ -95,8 +95,17 @@
|
|||
<libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
|
||||
</effectProxy>
|
||||
<effect name="extensioneffect" library="extensioneffect" uuid="fa81dd00-588b-11ed-9b6a-0242ac120002"/>
|
||||
<effect name="acoustic_echo_canceler" library="aecsw" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
|
||||
<effect name="noise_suppression" library="nssw" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
|
||||
</effects>
|
||||
|
||||
<preprocess>
|
||||
<stream type="voice_communication">
|
||||
<apply effect="acoustic_echo_canceler"/>
|
||||
<apply effect="noise_suppression"/>
|
||||
</stream>
|
||||
</preprocess>
|
||||
|
||||
<!-- Audio pre processor configurations.
|
||||
The pre processor configuration is described in a "preprocess" element and consists in a
|
||||
list of elements each describing pre processor settings for a given use case or "stream".
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <cutils/properties.h>
|
||||
#include <tinyxml2.h>
|
||||
|
||||
#include <aidl/android/hardware/audio/effect/Processing.h>
|
||||
#include "effect-impl/EffectTypes.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
@ -39,11 +40,6 @@ class EffectConfig {
|
|||
public:
|
||||
explicit EffectConfig(const std::string& file);
|
||||
|
||||
// <library>
|
||||
struct Library {
|
||||
std::string name;
|
||||
std::string path;
|
||||
};
|
||||
struct LibraryUuid {
|
||||
std::string name; // library name
|
||||
::aidl::android::media::audio::common::AudioUuid uuid;
|
||||
|
@ -59,13 +55,13 @@ class EffectConfig {
|
|||
const std::unordered_map<std::string, struct EffectLibraries> getEffectsMap() const {
|
||||
return mEffectsMap;
|
||||
}
|
||||
const std::unordered_map<std::string, std::vector<std::string>> getProcessingMap() const {
|
||||
return mProcessingMap;
|
||||
}
|
||||
|
||||
static bool findUuid(const std::string& xmlEffectName,
|
||||
::aidl::android::media::audio::common::AudioUuid* uuid);
|
||||
|
||||
using ProcessingLibrariesMap = std::map<Processing::Type, std::vector<struct EffectLibraries>>;
|
||||
const ProcessingLibrariesMap& getProcessingMap() const;
|
||||
|
||||
private:
|
||||
static constexpr const char* kEffectLibPath[] =
|
||||
#ifdef __LP64__
|
||||
|
@ -79,8 +75,11 @@ class EffectConfig {
|
|||
std::unordered_map<std::string, std::string> mLibraryMap;
|
||||
/* Parsed Effects result */
|
||||
std::unordered_map<std::string, struct EffectLibraries> mEffectsMap;
|
||||
/* Parsed pre/post processing result */
|
||||
std::unordered_map<std::string, std::vector<std::string>> mProcessingMap;
|
||||
/**
|
||||
* For parsed pre/post processing result: {key: AudioStreamType/AudioSource, value:
|
||||
* EffectLibraries}
|
||||
*/
|
||||
ProcessingLibrariesMap mProcessingMap;
|
||||
|
||||
/** @return all `node`s children that are elements and match the tag if provided. */
|
||||
std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> getChildren(
|
||||
|
@ -94,7 +93,7 @@ class EffectConfig {
|
|||
*/
|
||||
bool parseEffect(const tinyxml2::XMLElement& xml);
|
||||
|
||||
bool parseStream(const tinyxml2::XMLElement& xml);
|
||||
bool parseProcessing(Processing::Type::Tag typeTag, const tinyxml2::XMLElement& xml);
|
||||
|
||||
// Function to parse effect.library name and effect.uuid from xml
|
||||
bool parseLibraryUuid(const tinyxml2::XMLElement& xml, struct LibraryUuid& libraryUuid,
|
||||
|
@ -104,6 +103,9 @@ class EffectConfig {
|
|||
tinyxml2::XMLPrinter&& printer = {}) const;
|
||||
|
||||
bool resolveLibrary(const std::string& path, std::string* resolvedPath);
|
||||
|
||||
std::optional<Processing::Type> stringToProcessingType(Processing::Type::Tag typeTag,
|
||||
const std::string& type);
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
|
|
@ -107,6 +107,10 @@ class Factory : public BnFactory {
|
|||
const EffectConfig::LibraryUuid& configLib,
|
||||
const ::aidl::android::media::audio::common::AudioUuid& typeUuidStr,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid);
|
||||
|
||||
ndk::ScopedAStatus getDescriptorWithUuid(
|
||||
const aidl::android::media::audio::common::AudioUuid& uuid, Descriptor* desc);
|
||||
|
||||
void loadEffectLibs();
|
||||
/* Get effect_dl_interface_s from library handle */
|
||||
void getDlSyms(DlEntry& entry);
|
||||
|
|
|
@ -267,6 +267,7 @@ TEST_P(EffectFactoryTest, EffectInvalidAfterRestart) {
|
|||
TEST_P(EffectFactoryTest, QueryProcess) {
|
||||
std::vector<Processing> processing;
|
||||
EXPECT_IS_OK(mEffectFactory->queryProcessing(std::nullopt, &processing));
|
||||
std::set<Processing> processingSet(processing.begin(), processing.end());
|
||||
|
||||
Processing::Type streamType =
|
||||
Processing::Type::make<Processing::Type::streamType>(AudioStreamType::SYSTEM);
|
||||
|
@ -279,7 +280,14 @@ TEST_P(EffectFactoryTest, QueryProcess) {
|
|||
EXPECT_IS_OK(mEffectFactory->queryProcessing(source, &processingFilteredBySource));
|
||||
|
||||
EXPECT_TRUE(processing.size() >= processingFilteredByStream.size());
|
||||
EXPECT_TRUE(std::all_of(
|
||||
processingFilteredByStream.begin(), processingFilteredByStream.end(),
|
||||
[&](const auto& proc) { return processingSet.find(proc) != processingSet.end(); }));
|
||||
|
||||
EXPECT_TRUE(processing.size() >= processingFilteredBySource.size());
|
||||
EXPECT_TRUE(std::all_of(
|
||||
processingFilteredBySource.begin(), processingFilteredBySource.end(),
|
||||
[&](const auto& proc) { return processingSet.find(proc) != processingSet.end(); }));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactoryTest,
|
||||
|
|
Loading…
Reference in a new issue