[audioeffect] add support of device effect in config parser

Bug: 136294538
Test: build

Change-Id: I2c75b4bf6a4346362044696feabb35822c860efa
Merged-In: I2c75b4bf6a4346362044696feabb35822c860efa
Signed-off-by: François Gaffie <francois.gaffie@renault.com>
diff --git a/media/libeffects/config/Android.bp b/media/libeffects/config/Android.bp
index 5fa9da9..8476f82 100644
--- a/media/libeffects/config/Android.bp
+++ b/media/libeffects/config/Android.bp
@@ -13,6 +13,8 @@
     shared_libs: [
         "liblog",
         "libtinyxml2",
+        "libutils",
+        "libmedia_helper",
     ],
 
     header_libs: ["libaudio_system_headers"],
diff --git a/media/libeffects/config/include/media/EffectsConfig.h b/media/libeffects/config/include/media/EffectsConfig.h
index fa0415b..ef10e0d 100644
--- a/media/libeffects/config/include/media/EffectsConfig.h
+++ b/media/libeffects/config/include/media/EffectsConfig.h
@@ -76,6 +76,10 @@
 using OutputStream = Stream<audio_stream_type_t>;
 using InputStream = Stream<audio_source_t>;
 
+struct DeviceEffects : Stream<audio_devices_t> {
+    std::string address;
+};
+
 /** Parsed configuration.
  * Intended to be a transient structure only used for deserialization.
  * Note: Everything is copied in the configuration from the xml dom.
@@ -89,6 +93,7 @@
     Effects effects;
     std::vector<OutputStream> postprocess;
     std::vector<InputStream> preprocess;
+    std::vector<DeviceEffects> deviceprocess;
 };
 
 /** Result of `parse(const char*)` */
diff --git a/media/libeffects/config/src/EffectsConfig.cpp b/media/libeffects/config/src/EffectsConfig.cpp
index 90a4fbb..85fbf11 100644
--- a/media/libeffects/config/src/EffectsConfig.cpp
+++ b/media/libeffects/config/src/EffectsConfig.cpp
@@ -26,6 +26,7 @@
 #include <log/log.h>
 
 #include <media/EffectsConfig.h>
+#include <media/TypeConverter.h>
 
 using namespace tinyxml2;
 
@@ -134,6 +135,11 @@
     return false;
 }
 
+template <>
+bool stringToStreamType(const char *streamName, audio_devices_t* type) {
+    return deviceFromString(streamName, *type);
+}
+
 /** Parse a library xml note and push the result in libraries or return false on failure. */
 bool parseLibrary(const XMLElement& xmlLibrary, Libraries* libraries) {
     const char* name = xmlLibrary.Attribute("name");
@@ -221,7 +227,7 @@
     return true;
 }
 
-/** Parse an stream from an xml element describing it.
+/** Parse an <Output|Input>stream or a device from an xml element describing it.
  * @return true and pushes the stream in streams on success,
  *         false on failure. */
 template <class Stream>
@@ -233,14 +239,14 @@
     }
     Stream stream;
     if (!stringToStreamType(streamType, &stream.type)) {
-        ALOGE("Invalid stream type %s: %s", streamType, dump(xmlStream));
+        ALOGE("Invalid <stream|device> type %s: %s", streamType, dump(xmlStream));
         return false;
     }
 
     for (auto& xmlApply : getChildren(xmlStream, "apply")) {
         const char* effectName = xmlApply.get().Attribute("effect");
         if (effectName == nullptr) {
-            ALOGE("stream/apply must have reference an effect: %s", dump(xmlApply));
+            ALOGE("<stream|device>/apply must have reference an effect: %s", dump(xmlApply));
             return false;
         }
         auto* effect = findByName(effectName, effects);
@@ -254,6 +260,21 @@
     return true;
 }
 
+bool parseDeviceEffects(
+        const XMLElement& xmlDevice, Effects& effects, std::vector<DeviceEffects>* deviceEffects) {
+
+    const char* address = xmlDevice.Attribute("address");
+    if (address == nullptr) {
+        ALOGE("device must have an address: %s", dump(xmlDevice));
+        return false;
+    }
+    if (!parseStream(xmlDevice, effects, deviceEffects)) {
+        return false;
+    }
+    deviceEffects->back().address = address;
+    return true;
+}
+
 /** Internal version of the public parse(const char* path) where path always exist. */
 ParsingResult parseWithPath(std::string&& path) {
     XMLDocument doc;
@@ -298,6 +319,14 @@
                 registerFailure(parseStream(xmlStream, config->effects, &config->postprocess));
             }
         }
+
+        // Parse device effect chains
+        for (auto& xmlDeviceEffects : getChildren(xmlConfig, "deviceEffects")) {
+            for (auto& xmlDevice : getChildren(xmlDeviceEffects, "devicePort")) {
+                registerFailure(
+                            parseDeviceEffects(xmlDevice, config->effects, &config->deviceprocess));
+            }
+        }
     }
     return {std::move(config), nbSkippedElements, std::move(path)};
 }
diff --git a/media/libeffects/data/audio_effects.xml b/media/libeffects/data/audio_effects.xml
index 3f85052..2e5f529 100644
--- a/media/libeffects/data/audio_effects.xml
+++ b/media/libeffects/data/audio_effects.xml
@@ -99,4 +99,31 @@
         </postprocess>
     -->
 
+     <!-- Device pre/post processor configurations.
+          The device pre/post processor configuration is described in a deviceEffects element and
+          consists in a list of elements each describing pre/post proecessor settings for a given
+          device or "devicePort".
+          Each devicePort element has a "type" attribute corresponding to the device type (e.g.
+          speaker, bus), an "address" attribute corresponding to the device address and contains a
+          list of "apply" elements indicating one effect to apply.
+          If the device is a source, only pre processing effects are expected, if the
+          device is a sink, only post processing effects are expected.
+          The effect to apply is designated by its name in the "effects" elements.
+          The effect will be enabled by default and the audio framework will automatically add
+          and activate the effect if the given port is involved in an audio patch.
+          If the patch is "HW", the effect must be HW accelerated.
+
+        <deviceEffects>
+            <devicePort type="AUDIO_DEVICE_OUT_BUS" address="BUS00_USAGE_MAIN">
+                <apply effect="equalizer"/>
+            </devicePort>
+            <devicePort type="AUDIO_DEVICE_OUT_BUS" address="BUS04_USAGE_VOICE">
+                <apply effect="volume"/>
+            </devicePort>
+            <devicePort type="AUDIO_DEVICE_IN_BUILTIN_MIC" address="bottom">
+                <apply effect="agc"/>
+            </devicePort>
+        </deviceEffects>
+    -->
+
 </audio_effects_conf>