Merge changes from topic "aidl_audio_effect_8_config"

* changes:
  Add effect config xml parser in AIDL effect factory
  Support effect config parser in effect AIDL
This commit is contained in:
Shunkai Yao
2022-11-14 15:24:01 +00:00
committed by Gerrit Code Review
9 changed files with 504 additions and 41 deletions

View File

@@ -82,6 +82,7 @@ cc_defaults {
],
header_libs: [
"libaudioaidl_headers",
"libaudio_system_headers",
"libsystem_headers",
],
cflags: [
@@ -113,13 +114,15 @@ cc_binary {
"libhapticgeneratorsw",
"libloudnessenhancersw",
"libreverbsw",
"libtinyxml2",
"libvirtualizersw",
"libvisualizersw",
"libvolumesw",
],
srcs: [
"EffectMain.cpp",
"EffectConfig.cpp",
"EffectFactory.cpp",
"EffectMain.cpp",
],
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "AHAL_EffectConfig"
#include <android-base/logging.h>
#include "effectFactory-impl/EffectConfig.h"
using aidl::android::media::audio::common::AudioUuid;
namespace aidl::android::hardware::audio::effect {
EffectConfig::EffectConfig(const std::string& file) {
tinyxml2::XMLDocument doc;
doc.LoadFile(file.c_str());
LOG(DEBUG) << __func__ << " loading " << file;
// parse the xml file into maps
if (doc.Error()) {
LOG(ERROR) << __func__ << " tinyxml2 failed to load " << file
<< " error: " << doc.ErrorStr();
return;
}
auto registerFailure = [&](bool result) { mSkippedElements += result ? 0 : 1; };
for (auto& xmlConfig : getChildren(doc, "audio_effects_conf")) {
// Parse library
for (auto& xmlLibraries : getChildren(xmlConfig, "libraries")) {
for (auto& xmlLibrary : getChildren(xmlLibraries, "library")) {
registerFailure(parseLibrary(xmlLibrary));
}
}
// Parse effects
for (auto& xmlEffects : getChildren(xmlConfig, "effects")) {
for (auto& xmlEffect : getChildren(xmlEffects)) {
registerFailure(parseEffect(xmlEffect));
}
}
// Parse pre processing chains
for (auto& xmlPreprocess : getChildren(xmlConfig, "preprocess")) {
for (auto& xmlStream : getChildren(xmlPreprocess, "stream")) {
registerFailure(parseStream(xmlStream));
}
}
// Parse post processing chains
for (auto& xmlPostprocess : getChildren(xmlConfig, "postprocess")) {
for (auto& xmlStream : getChildren(xmlPostprocess, "stream")) {
registerFailure(parseStream(xmlStream));
}
}
}
LOG(DEBUG) << __func__ << " successfully parsed " << file << ", skipping " << mSkippedElements
<< " element(s)";
}
std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> EffectConfig::getChildren(
const tinyxml2::XMLNode& node, const char* childTag) {
std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> children;
for (auto* child = node.FirstChildElement(childTag); child != nullptr;
child = child->NextSiblingElement(childTag)) {
children.emplace_back(*child);
}
return children;
}
bool EffectConfig::parseLibrary(const tinyxml2::XMLElement& xml) {
const char* name = xml.Attribute("name");
RETURN_VALUE_IF(!name, false, "noNameAttribute");
const char* path = xml.Attribute("path");
RETURN_VALUE_IF(!path, false, "noPathAttribute");
mLibraryMap[name] = path;
LOG(DEBUG) << __func__ << " " << name << " : " << path;
return true;
}
bool EffectConfig::parseEffect(const tinyxml2::XMLElement& xml) {
struct EffectLibraries effectLibraries;
std::vector<LibraryUuid> libraryUuids;
std::string name = xml.Attribute("name");
RETURN_VALUE_IF(name == "", false, "effectsNoName");
LOG(DEBUG) << __func__ << dump(xml);
struct LibraryUuid libraryUuid;
if (std::strcmp(xml.Name(), "effectProxy") == 0) {
// proxy lib and uuid
RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid, true), false, "parseProxyLibFailed");
effectLibraries.proxyLibrary = libraryUuid;
// proxy effect libs and UUID
auto xmlProxyLib = xml.FirstChildElement();
RETURN_VALUE_IF(!xmlProxyLib, false, "noLibForProxy");
while (xmlProxyLib) {
struct LibraryUuid tempLibraryUuid;
RETURN_VALUE_IF(!parseLibraryUuid(*xmlProxyLib, tempLibraryUuid), false,
"parseEffectLibFailed");
libraryUuids.push_back(std::move(tempLibraryUuid));
xmlProxyLib = xmlProxyLib->NextSiblingElement();
}
} else {
// expect only one library if not proxy
RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid), false, "parseEffectLibFailed");
libraryUuids.push_back(std::move(libraryUuid));
}
effectLibraries.libraries = std::move(libraryUuids);
mEffectsMap[name] = std::move(effectLibraries);
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
if (!isProxy) {
const char* name = xml.Attribute("library");
RETURN_VALUE_IF(!name, false, "noLibraryAttribute");
libraryUuid.name = name;
}
const char* uuid = xml.Attribute("uuid");
RETURN_VALUE_IF(!uuid, false, "noUuidAttribute");
RETURN_VALUE_IF(!stringToUuid(uuid, &libraryUuid.uuid), false, "invalidUuidAttribute");
LOG(DEBUG) << __func__ << (isProxy ? " proxy " : libraryUuid.name) << " : "
<< libraryUuid.uuid.toString();
return true;
}
const char* EffectConfig::dump(const tinyxml2::XMLElement& element,
tinyxml2::XMLPrinter&& printer) const {
element.Accept(&printer);
return printer.CStr();
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -17,6 +17,7 @@
#define LOG_TAG "AHAL_EffectFactory"
#include <android-base/logging.h>
#include <dlfcn.h>
#include <unordered_set>
#include "effect-impl/EffectTypes.h"
#include "effect-impl/EffectUUID.h"
@@ -26,22 +27,9 @@ using aidl::android::media::audio::common::AudioUuid;
namespace aidl::android::hardware::audio::effect {
Factory::Factory() {
// TODO: get list of library UUID and name from audio_effect.xml.
openEffectLibrary(EqualizerTypeUUID, EqualizerSwImplUUID, std::nullopt, "libequalizersw.so");
openEffectLibrary(EqualizerTypeUUID, EqualizerBundleImplUUID, std::nullopt, "libbundleaidl.so");
openEffectLibrary(BassBoostTypeUUID, BassBoostSwImplUUID, std::nullopt, "libbassboostsw.so");
openEffectLibrary(DynamicsProcessingTypeUUID, DynamicsProcessingSwImplUUID, std::nullopt,
"libdynamicsprocessingsw.so");
openEffectLibrary(HapticGeneratorTypeUUID, HapticGeneratorSwImplUUID, std::nullopt,
"libhapticgeneratorsw.so");
openEffectLibrary(LoudnessEnhancerTypeUUID, LoudnessEnhancerSwImplUUID, std::nullopt,
"libloudnessenhancersw.so");
openEffectLibrary(ReverbTypeUUID, ReverbSwImplUUID, std::nullopt, "libreverbsw.so");
openEffectLibrary(VirtualizerTypeUUID, VirtualizerSwImplUUID, std::nullopt,
"libvirtualizersw.so");
openEffectLibrary(VisualizerTypeUUID, VisualizerSwImplUUID, std::nullopt, "libvisualizersw.so");
openEffectLibrary(VolumeTypeUUID, VolumeSwImplUUID, std::nullopt, "libvolumesw.so");
Factory::Factory(const std::string& file) : mConfig(EffectConfig(file)) {
LOG(DEBUG) << __func__ << " with config file: " << file;
loadEffectLibs();
}
Factory::~Factory() {
@@ -62,7 +50,7 @@ ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type
const std::optional<AudioUuid>& in_proxy_uuid,
std::vector<Descriptor::Identity>* _aidl_return) {
std::copy_if(
mIdentityList.begin(), mIdentityList.end(), std::back_inserter(*_aidl_return),
mIdentitySet.begin(), mIdentitySet.end(), std::back_inserter(*_aidl_return),
[&](auto& desc) {
return (!in_type_uuid.has_value() || in_type_uuid.value() == desc.type) &&
(!in_impl_uuid.has_value() || in_impl_uuid.value() == desc.uuid) &&
@@ -172,8 +160,7 @@ ndk::ScopedAStatus Factory::destroyEffect(const std::shared_ptr<IEffect>& in_han
return status;
}
void Factory::openEffectLibrary(const AudioUuid& type, const AudioUuid& impl,
const std::optional<AudioUuid>& proxy, const std::string& libName) {
void Factory::openEffectLibrary(const AudioUuid& impl, const std::string& libName) {
std::function<void(void*)> dlClose = [](void* handle) -> void {
if (handle && dlclose(handle)) {
LOG(ERROR) << "dlclose failed " << dlerror();
@@ -187,19 +174,51 @@ void Factory::openEffectLibrary(const AudioUuid& type, const AudioUuid& impl,
return;
}
LOG(DEBUG) << __func__ << " dlopen lib:" << libName << " for uuid:\ntype:" << type.toString()
<< "\nimpl:" << impl.toString()
<< "\nproxy:" << (proxy.has_value() ? proxy.value().toString() : "null")
LOG(DEBUG) << __func__ << " dlopen lib:" << libName << "\nimpl:" << impl.toString()
<< "\nhandle:" << libHandle;
mEffectLibMap.insert({impl, std::make_pair(std::move(libHandle), nullptr)});
}
Descriptor::Identity id;
id.type = type;
id.uuid = impl;
if (proxy.has_value()) {
id.proxy = proxy.value();
void Factory::createIdentityWithConfig(const EffectConfig::LibraryUuid& configLib,
const AudioUuid& typeUuid,
const std::optional<AudioUuid> proxyUuid) {
static const auto& libMap = mConfig.getLibraryMap();
const std::string& libName = configLib.name;
if (auto path = libMap.find(libName); path != libMap.end()) {
Descriptor::Identity id;
id.type = typeUuid;
id.uuid = configLib.uuid;
id.proxy = proxyUuid;
LOG(DEBUG) << __func__ << ": typeUuid " << id.type.toString() << "\nimplUuid "
<< id.uuid.toString() << " proxyUuid "
<< (proxyUuid.has_value() ? proxyUuid->toString() : "null");
openEffectLibrary(id.uuid, path->second);
mIdentitySet.insert(std::move(id));
} else {
LOG(ERROR) << __func__ << ": library " << libName << " not exist!";
return;
}
}
void Factory::loadEffectLibs() {
const auto& configEffectsMap = mConfig.getEffectsMap();
for (const auto& configEffects : configEffectsMap) {
if (auto typeUuid = kUuidNameTypeMap.find(configEffects.first /* effect name */);
typeUuid != kUuidNameTypeMap.end()) {
const auto& configLibs = configEffects.second;
std::optional<AudioUuid> proxyUuid;
if (configLibs.proxyLibrary.has_value()) {
const auto& proxyLib = configLibs.proxyLibrary.value();
proxyUuid = proxyLib.uuid;
}
for (const auto& configLib : configLibs.libraries) {
createIdentityWithConfig(configLib, typeUuid->second, proxyUuid);
}
} else {
LOG(ERROR) << __func__ << ": can not find type UUID for effect " << configEffects.first
<< " skipping!";
}
}
mIdentityList.push_back(id);
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -19,21 +19,31 @@
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <system/audio_config.h>
/** Default name of effect configuration file. */
static const char* kDefaultConfigName = "audio_effects_config.xml";
int main() {
// This is a debug implementation, always enable debug logging.
android::base::SetMinimumLogSeverity(::android::base::DEBUG);
ABinderProcess_setThreadPoolMaxThreadCount(0);
auto configFile = android::audio_find_readable_configuration_file(kDefaultConfigName);
if (configFile == "") {
LOG(ERROR) << __func__ << ": config file " << kDefaultConfigName << " not found!";
return EXIT_FAILURE;
}
LOG(DEBUG) << __func__ << ": start factory with configFile:" << configFile;
auto effectFactory =
ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>();
ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>(configFile);
std::string serviceName = std::string() + effectFactory->descriptor + "/default";
binder_status_t status =
AServiceManager_addService(effectFactory->asBinder().get(), serviceName.c_str());
CHECK_EQ(STATUS_OK, status);
LOG(DEBUG) << __func__ << ": effectFactoryName:" << serviceName;
LOG(DEBUG) << __func__ << ": effectFactory: " << serviceName << " start";
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<audio_effects_conf version="2.0" xmlns="http://schemas.android.com/audio/audio_effects_conf/v2_0">
<!-- Overview.
This example config file was copy from existing one: frameworks/av/media/libeffects/data/
audio_effects.xml, with effect library names updated to AIDL libraries we currently have.
All "library" attributes in "effect" element must must match a "library" element with the
same value of the "name" attribute.
All "effect" attributes in "preprocess" and "postprocess" element must match an "effect"
element with the same value of the "name" attribute.
AIDL EffectFactory are relying on the "name" attribute in "effect" element to identify the
effect type, so it's necessary to have the mapping from name to effect type UUID. Make
sure to either use existing effect name as key of
::android::hardware::audio::effect::kUuidNameTypeMap, or add a new {name, typeUUID} map
item to the kUuidNameTypeMap.
Existing audio_effects.xml should working without any change as long as:
1. "path" attribute of "library" element matches with the actual effect library name.
2. "name" attribute of "effect" and "effectProxy" element correctly added as key of
kUuidNameTypeMap, with value matches Identity.type in Descriptor.aidl.
3. "uuid" attribute of "effect" element matches Identity.uuid in Descriptor.aidl.
4. "uuid" attribute of "effectProxy" element matches Identity.proxy in Descriptor.aidl.
-->
<!-- List of effect libraries to load.
Each library element must contain a "name" attribute and a "path" attribute giving the
name of a library .so file on the target device.
-->
<libraries>
<library name="bassboostsw" path="libbassboostsw.so"/>
<library name="bundle" path="libbundleaidl.so"/>
<library name="dynamics_processingsw" path="libdynamicsprocessingsw.so"/>
<library name="equalizersw" path="libequalizersw.so"/>
<library name="haptic_generatorsw" path="libhapticgeneratorsw.so"/>
<library name="loudness_enhancersw" path="libloudnessenhancersw.so"/>
<library name="reverbsw" path="libreverbsw.so"/>
<library name="virtualizersw" path="libvirtualizersw.so"/>
<library name="visualizersw" path="libvisualizersw.so"/>
<library name="volumesw" path="libvolumesw.so"/>
</libraries>
<!-- list of effects to load.
Each "effect" element must contain a "name", "library" and a "uuid" attribute.
The value of the "library" attribute must correspond to the name of one library element in
the "libraries" element.
The "name" attribute used to specific effect type, and should be mapping to a key of
aidl::android::hardware::audio::effect::kUuidNameTypeMap.
The "uuid" attribute is the implementation specific UUID as specified by the effect vendor.
Effect proxy can be supported with "effectProxy" element, each sub-element should contain
"library" and "uuid" attribute, all other attributes were ignored. Framework side use
result of IFactory.queryEffects() to decide which effect implementation should be part of
proxy and which not.
Only "name", "library", and "uuid" attributes in "effects" element are meaningful and
parsed out by EffectConfig class, all other attributes are ignored.
Only "name" and "uuid" attributes in "effectProxy" element are meaningful and parsed out
by EffectConfig class, all other attributes are ignored.
-->
<effects>
<effect name="bassboost" library="bassboostsw" uuid="fa8181f2-588b-11ed-9b6a-0242ac120002"/>
<effect name="dynamics_processing" library="dynamics_processingsw" uuid="fa818d78-588b-11ed-9b6a-0242ac120002"/>
<effect name="haptic_generator" library="haptic_generatorsw" uuid="fa819110-588b-11ed-9b6a-0242ac120002"/>
<effect name="loudness_enhancer" library="loudness_enhancersw" uuid="fa819610-588b-11ed-9b6a-0242ac120002"/>
<effect name="reverb" library="reverbsw" uuid="fa8199c6-588b-11ed-9b6a-0242ac120002"/>
<effect name="virtualizer" library="virtualizersw" uuid="fa819d86-588b-11ed-9b6a-0242ac120002"/>
<effect name="visualizer" library="visualizersw" uuid="fa81a0f6-588b-11ed-9b6a-0242ac120002"/>
<effect name="volume" library="volumesw" uuid="fa81a718-588b-11ed-9b6a-0242ac120002"/>
<effectProxy name="equalizer" uuid="14804144-a5ee-4d24-aa88-0002a5d5c51b">
<libsw library="equalizersw" uuid="0bed4300-847d-11df-bb17-0002a5d5c51b"/>
<libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
</effectProxy>
</effects>
<!-- 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".
Each stream element has a "type" attribute corresponding to the input source used.
Valid types are these defined in system/hardware/interfaces/media/aidl/android/media/audio/
common/AudioSource.aidl.
Each "stream" element contains a list of "apply" elements indicating one effect to apply.
The effect to apply is designated by its name in the "effects" elements.
If there are more than one effect apply to one stream, the audio framework will apply them
in the same equence as they listed in "stream" element.
<preprocess>
<stream type="voice_communication">
<apply effect="aec"/>
<apply effect="ns"/>
</stream>
</preprocess>
-->
<!-- Audio post processor configurations.
The post processor configuration is described in a "postprocess" element and consists in a
list of elements each describing post processor settings for a given use case or "stream".
Each stream element has a "type" attribute corresponding to the stream type used.
Valid types are these defined in system/hardware/interfaces/media/aidl/android/media/audio/
common/AudioStreamType.aidl.
Each "stream" element contains a list of "apply" elements indicating one effect to apply.
The effect to apply is designated by its name in the "effects" elements.
If there are more than one effect apply to one stream, the audio framework will apply them
in the same equence as they listed in "stream" element.
<postprocess>
<stream type="music">
<apply effect="music_post_proc"/>
</stream>
<stream type="voice_call">
<apply effect="voice_post_proc"/>
</stream>
<stream type="notification">
<apply effect="notification_post_proc"/>
</stream>
</postprocess>
-->
</audio_effects_conf>

View File

@@ -19,6 +19,7 @@
#include <string>
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <android-base/logging.h>
typedef binder_exception_t (*EffectCreateFunctor)(
const ::aidl::android::media::audio::common::AudioUuid*,
@@ -101,4 +102,23 @@ inline std::ostream& operator<<(std::ostream& out, const RetCode& code) {
} \
} while (0)
static inline bool stringToUuid(const char* str,
::aidl::android::media::audio::common::AudioUuid* uuid) {
RETURN_VALUE_IF(!uuid || !str, false, "nullPtr");
uint32_t tmp[10];
if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", tmp, tmp + 1, tmp + 2, tmp + 3,
tmp + 4, tmp + 5, tmp + 6, tmp + 7, tmp + 8, tmp + 9) < 10) {
return false;
}
uuid->timeLow = (uint32_t)tmp[0];
uuid->timeMid = (uint16_t)tmp[1];
uuid->timeHiAndVersion = (uint16_t)tmp[2];
uuid->clockSeq = (uint16_t)tmp[3];
uuid->node.insert(uuid->node.end(), {(uint8_t)tmp[4], (uint8_t)tmp[5], (uint8_t)tmp[6],
(uint8_t)tmp[7], (uint8_t)tmp[8], (uint8_t)tmp[9]});
return true;
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -15,6 +15,8 @@
*/
#pragma once
#include <map>
#include <aidl/android/media/audio/common/AudioUuid.h>
namespace aidl::android::hardware::audio::effect {
@@ -39,14 +41,14 @@ static const AudioUuid EqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
0x8f34,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// Equalizer implementation UUID.
// 0bed4300-847d-11df-bb17-0002a5d5c51b
static const AudioUuid EqualizerSwImplUUID = {static_cast<int32_t>(0x0bed4300),
0x847d,
0x11df,
0xbb17,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// Equalizer bundle implementation UUID.
// ce772f20-847d-11df-bb17-0002a5d5c51b
static const AudioUuid EqualizerBundleImplUUID = {static_cast<int32_t>(0xce772f20),
0x847d,
0x11df,
@@ -166,4 +168,26 @@ static const AudioUuid VolumeSwImplUUID = {static_cast<int32_t>(0xfa81a718),
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
/**
* @brief A map between effect name and effect type UUID.
* All <name> attribution in effect/effectProxy of audio_effects.xml should be listed in this map.
* We need this map is because existing audio_effects.xml don't have a type UUID defined.
*/
static const std::map<const std::string /* effect type */, const AudioUuid&> kUuidNameTypeMap = {
{"bassboost", BassBoostTypeUUID},
{"downmix", DownmixTypeUUID},
{"dynamics_processing", DynamicsProcessingTypeUUID},
{"equalizer", EqualizerTypeUUID},
{"haptic_generator", HapticGeneratorTypeUUID},
{"loudness_enhancer", LoudnessEnhancerTypeUUID},
{"reverb", ReverbTypeUUID},
{"reverb_env_aux", ReverbTypeUUID},
{"reverb_env_ins", ReverbTypeUUID},
{"reverb_pre_aux", ReverbTypeUUID},
{"reverb_pre_ins", ReverbTypeUUID},
{"virtualizer", VirtualizerTypeUUID},
{"visualizer", VisualizerTypeUUID},
{"volume", VolumeTypeUUID},
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <cutils/properties.h>
#include <tinyxml2.h>
#include "effect-impl/EffectTypes.h"
namespace aidl::android::hardware::audio::effect {
/**
* Library contains a mapping from library name to path.
* Effect contains a mapping from effect name to Libraries and implementation UUID.
* Pre/post processor contains a mapping from processing name to effect names.
*/
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;
};
// <effects>
struct EffectLibraries {
std::optional<struct LibraryUuid> proxyLibrary;
std::vector<struct LibraryUuid> libraries;
};
int getSkippedElements() const { return mSkippedElements; }
const std::unordered_map<std::string, std::string> getLibraryMap() const { return mLibraryMap; }
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;
}
private:
int mSkippedElements;
/* Parsed Libraries result */
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;
/** @return all `node`s children that are elements and match the tag if provided. */
std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> getChildren(
const tinyxml2::XMLNode& node, const char* childTag = nullptr);
/** Parse a library xml note and push the result in mLibraryMap or return false on failure. */
bool parseLibrary(const tinyxml2::XMLElement& xml);
/** Parse an effect from an xml element describing it.
* @return true and pushes the effect in mEffectsMap on success, false on failure.
*/
bool parseEffect(const tinyxml2::XMLElement& xml);
bool parseStream(const tinyxml2::XMLElement& xml);
// Function to parse effect.library name and effect.uuid from xml
bool parseLibraryUuid(const tinyxml2::XMLElement& xml, struct LibraryUuid& libraryUuid,
bool isProxy = false);
const char* dump(const tinyxml2::XMLElement& element,
tinyxml2::XMLPrinter&& printer = {}) const;
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -19,15 +19,17 @@
#include <any>
#include <map>
#include <optional>
#include <set>
#include <vector>
#include <aidl/android/hardware/audio/effect/BnFactory.h>
#include "EffectConfig.h"
namespace aidl::android::hardware::audio::effect {
class Factory : public BnFactory {
public:
Factory();
explicit Factory(const std::string& file);
/**
* @brief Get identity of all effects supported by the device, with the optional filter by type
* and/or by instance UUID.
@@ -77,9 +79,10 @@ class Factory : public BnFactory {
override;
private:
const EffectConfig mConfig;
~Factory();
// List of effect descriptors supported by the devices.
std::vector<Descriptor::Identity> mIdentityList;
// Set of effect descriptors supported by the devices.
std::set<Descriptor::Identity> mIdentitySet;
std::map<aidl::android::media::audio::common::AudioUuid /* implementationUUID */,
std::pair<std::unique_ptr<void, std::function<void(void*)>> /* dlHandle */,
@@ -91,10 +94,13 @@ class Factory : public BnFactory {
ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle);
void cleanupEffectMap();
void openEffectLibrary(
const ::aidl::android::media::audio::common::AudioUuid& type,
const ::aidl::android::media::audio::common::AudioUuid& impl,
const std::optional<::aidl::android::media::audio::common::AudioUuid>& proxy,
const std::string& libName);
void openEffectLibrary(const ::aidl::android::media::audio::common::AudioUuid& impl,
const std::string& libName);
void createIdentityWithConfig(
const EffectConfig::LibraryUuid& configLib,
const ::aidl::android::media::audio::common::AudioUuid& typeUuid,
const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid);
void loadEffectLibs();
};
} // namespace aidl::android::hardware::audio::effect