audiopolicy: Move surround configuration to xml

Move the configuration for supported surround formats
into APM xml config file.

Bug: 116356348
Test: on elfin
Change-Id: Ifba218fa2c03136a3a59eeee8077b00fba77c069
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 78e7ec9..d1a0f9b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -16,6 +16,9 @@
 
 #pragma once
 
+#include <unordered_map>
+#include <unordered_set>
+
 #include <AudioGain.h>
 #include <VolumeCurve.h>
 #include <AudioPort.h>
@@ -145,6 +148,35 @@
         inProfile->addAudioProfile(micProfile);
         inProfile->addSupportedDevice(defaultInputDevice);
         module->addInputProfile(inProfile);
+
+        setDefaultSurroundFormats();
+    }
+
+    // Surround formats, with an optional list of subformats that are equivalent from users' POV.
+    using SurroundFormats = std::unordered_map<audio_format_t, std::unordered_set<audio_format_t>>;
+
+    const SurroundFormats &getSurroundFormats() const
+    {
+        return mSurroundFormats;
+    }
+
+    void setSurroundFormats(const SurroundFormats &surroundFormats)
+    {
+        mSurroundFormats = surroundFormats;
+    }
+
+    void setDefaultSurroundFormats()
+    {
+        mSurroundFormats = {
+            {AUDIO_FORMAT_AC3, {}},
+            {AUDIO_FORMAT_E_AC3, {}},
+            {AUDIO_FORMAT_DTS, {}},
+            {AUDIO_FORMAT_DTS_HD, {}},
+            {AUDIO_FORMAT_AAC_LC, {
+                    AUDIO_FORMAT_AAC_HE_V1, AUDIO_FORMAT_AAC_HE_V2, AUDIO_FORMAT_AAC_ELD,
+                    AUDIO_FORMAT_AAC_XHE}},
+            {AUDIO_FORMAT_DOLBY_TRUEHD, {}},
+            {AUDIO_FORMAT_E_AC3_JOC, {}}};
     }
 
 private:
@@ -158,6 +190,7 @@
     // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
     // Note: remove also speaker_drc_enabled from global configuration of XML config file.
     bool mIsSpeakerDrcEnabled;
+    SurroundFormats mSurroundFormats;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 19eac26..59db81c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -407,6 +407,8 @@
 
     config.setHwModules(hwModules);
 
+    config.setDefaultSurroundFormats();
+
     config_free(root);
     free(root);
     free(data);
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index d5a09fe..179a678 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -19,6 +19,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include <hidl/Status.h>
 #include <libxml/parser.h>
@@ -41,7 +42,7 @@
 using utilities::convertTo;
 
 template<typename E, typename C>
-struct BaseSerializerTraits {
+struct AndroidCollectionTraits {
     typedef sp<E> Element;
     typedef C Collection;
     typedef void* PtrSerializingCtx;
@@ -51,7 +52,19 @@
     }
 };
 
-struct AudioGainTraits : public BaseSerializerTraits<AudioGain, AudioGainCollection>
+template<typename C>
+struct StdCollectionTraits {
+    typedef C Collection;
+    typedef typename C::value_type Element;
+    typedef void* PtrSerializingCtx;
+
+    static status_t addElementToCollection(const Element &element, Collection *collection) {
+        auto pair = collection->insert(element);
+        return pair.second ? NO_ERROR : BAD_VALUE;
+    }
+};
+
+struct AudioGainTraits : public AndroidCollectionTraits<AudioGain, AudioGainCollection>
 {
     static constexpr const char *tag = "gain";
     static constexpr const char *collectionTag = "gains";
@@ -79,7 +92,7 @@
 
 // A profile section contains a name,  one audio format and the list of supported sampling rates
 // and channel masks for this format
-struct AudioProfileTraits : public BaseSerializerTraits<AudioProfile, AudioProfileVector>
+struct AudioProfileTraits : public AndroidCollectionTraits<AudioProfile, AudioProfileVector>
 {
     static constexpr const char *tag = "profile";
     static constexpr const char *collectionTag = "profiles";
@@ -94,7 +107,7 @@
     static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
 };
 
-struct MixPortTraits : public BaseSerializerTraits<IOProfile, IOProfileCollection>
+struct MixPortTraits : public AndroidCollectionTraits<IOProfile, IOProfileCollection>
 {
     static constexpr const char *tag = "mixPort";
     static constexpr const char *collectionTag = "mixPorts";
@@ -113,7 +126,7 @@
     // Children: GainTraits
 };
 
-struct DevicePortTraits : public BaseSerializerTraits<DeviceDescriptor, DeviceVector>
+struct DevicePortTraits : public AndroidCollectionTraits<DeviceDescriptor, DeviceVector>
 {
     static constexpr const char *tag = "devicePort";
     static constexpr const char *collectionTag = "devicePorts";
@@ -133,7 +146,7 @@
     // Children: GainTraits (optional)
 };
 
-struct RouteTraits : public BaseSerializerTraits<AudioRoute, AudioRouteVector>
+struct RouteTraits : public AndroidCollectionTraits<AudioRoute, AudioRouteVector>
 {
     static constexpr const char *tag = "route";
     static constexpr const char *collectionTag = "routes";
@@ -152,7 +165,7 @@
     static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
 };
 
-struct ModuleTraits : public BaseSerializerTraits<HwModule, HwModuleCollection>
+struct ModuleTraits : public AndroidCollectionTraits<HwModule, HwModuleCollection>
 {
     static constexpr const char *tag = "module";
     static constexpr const char *collectionTag = "modules";
@@ -186,7 +199,7 @@
     static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
 };
 
-struct VolumeTraits : public BaseSerializerTraits<VolumeCurve, VolumeCurvesCollection>
+struct VolumeTraits : public AndroidCollectionTraits<VolumeCurve, VolumeCurvesCollection>
 {
     static constexpr const char *tag = "volume";
     static constexpr const char *collectionTag = "volumes";
@@ -205,6 +218,28 @@
     // No Children
 };
 
+struct SurroundSoundTraits
+{
+    static constexpr const char *tag = "surroundSound";
+
+    static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
+    // Children: SurroundSoundFormatTraits
+};
+
+struct SurroundSoundFormatTraits : public StdCollectionTraits<AudioPolicyConfig::SurroundFormats>
+{
+    static constexpr const char *tag = "format";
+    static constexpr const char *collectionTag = "formats";
+
+    struct Attributes
+    {
+        static constexpr const char *name = "name";
+        static constexpr const char *subformats = "subformats";
+    };
+
+    static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+};
+
 class PolicySerializer
 {
 public:
@@ -224,7 +259,7 @@
 
     const std::string mVersion;
 
-    // Children: ModulesTraits, VolumeTraits
+    // Children: ModulesTraits, VolumeTraits, SurroundSoundTraits (optional)
 };
 
 template <class T>
@@ -721,6 +756,52 @@
     return volCurve;
 }
 
+status_t SurroundSoundTraits::deserialize(const xmlNode *root, AudioPolicyConfig *config)
+{
+    config->setDefaultSurroundFormats();
+
+    for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
+        if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(tag))) {
+            AudioPolicyConfig::SurroundFormats formats;
+            status_t status = deserializeCollection<SurroundSoundFormatTraits>(
+                    cur, &formats, nullptr);
+            if (status == NO_ERROR) {
+                config->setSurroundFormats(formats);
+            }
+            return NO_ERROR;
+        }
+    }
+    return NO_ERROR;
+}
+
+Return<SurroundSoundFormatTraits::Element> SurroundSoundFormatTraits::deserialize(
+        const xmlNode *cur, PtrSerializingCtx /*serializingContext*/)
+{
+    std::string formatLiteral = getXmlAttribute(cur, Attributes::name);
+    if (formatLiteral.empty()) {
+        ALOGE("%s: No %s found for a surround format", __func__, Attributes::name);
+        return Status::fromStatusT(BAD_VALUE);
+    }
+    audio_format_t format = formatFromString(formatLiteral);
+    if (format == AUDIO_FORMAT_DEFAULT) {
+        ALOGE("%s: Unrecognized format %s", __func__, formatLiteral.c_str());
+        return Status::fromStatusT(BAD_VALUE);
+    }
+    Element pair = std::make_pair(format, Collection::mapped_type{});
+
+    std::string subformatsLiteral = getXmlAttribute(cur, Attributes::subformats);
+    if (subformatsLiteral.empty()) return pair;
+    FormatVector subformats = formatsFromString(subformatsLiteral, " ");
+    for (const auto& subformat : subformats) {
+        auto result = pair.second.insert(subformat);
+        if (!result.second) {
+            ALOGE("%s: could not add subformat %x to collection", __func__, subformat);
+            return Status::fromStatusT(BAD_VALUE);
+        }
+    }
+    return pair;
+}
+
 status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config)
 {
     auto doc = make_xmlUnique(xmlParseFile(configFile));
@@ -773,6 +854,9 @@
     // Global Configuration
     GlobalConfigTraits::deserialize(root, config);
 
+    // Surround configuration
+    SurroundSoundTraits::deserialize(root, config);
+
     return android::OK;
 }
 
diff --git a/services/audiopolicy/config/audio_policy_configuration.xml b/services/audiopolicy/config/audio_policy_configuration.xml
index 9381f1f..1d037c3 100644
--- a/services/audiopolicy/config/audio_policy_configuration.xml
+++ b/services/audiopolicy/config/audio_policy_configuration.xml
@@ -198,4 +198,26 @@
 
     <!-- End of Volume section -->
 
+    <?disabledUntilHalV4_1
+    <!-- Surround configuration -->
+
+    <surroundSound>
+      <!-- Each of the listed formats gets an entry in Surround Settings dialog.
+           There must be a corresponding Java ENCODING_... contant defined in AudioFormat.java,
+           and a display name defined in AudioFormat.toDisplayName. For the formats that don't
+           need a dedicated Surrond Settings dialog entry, a subformats list should be used. -->
+      <formats>
+        <format name="AUDIO_FORMAT_AC3" />
+        <format name="AUDIO_FORMAT_E_AC3" />
+        <format name="AUDIO_FORMAT_E_AC3_JOC" />
+        <format name="AUDIO_FORMAT_DOLBY_TRUEHD" />
+        <format name="AUDIO_FORMAT_DTS" />
+        <format name="AUDIO_FORMAT_DTS_HD" />
+        <format name="AUDIO_FORMAT_AAC_LC" subformats="AUDIO_FORMAT_AAC_HE_V1 AUDIO_FORMAT_AAC_HE_V2 AUDIO_FORMAT_AAC_ELD AUDIO_FORMAT_AAC_XHE" />
+      </formats>
+    </surroundSound>
+
+    <!-- End of Surround configuration -->
+    ?>
+
 </audioPolicyConfiguration>
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 42777f6..e28ab68 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -62,26 +62,6 @@
 // media / notification / system volume.
 constexpr float IN_CALL_EARPIECE_HEADROOM_DB = 3.f;
 
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-// Array of all surround formats.
-static const audio_format_t SURROUND_FORMATS[] = {
-    AUDIO_FORMAT_AC3,
-    AUDIO_FORMAT_E_AC3,
-    AUDIO_FORMAT_DTS,
-    AUDIO_FORMAT_DTS_HD,
-    AUDIO_FORMAT_AAC_LC,
-    AUDIO_FORMAT_DOLBY_TRUEHD,
-    AUDIO_FORMAT_E_AC3_JOC,
-};
-// Array of all AAC formats. When AAC is enabled by users, all AAC formats should be enabled.
-static const audio_format_t AAC_FORMATS[] = {
-    AUDIO_FORMAT_AAC_LC,
-    AUDIO_FORMAT_AAC_HE_V1,
-    AUDIO_FORMAT_AAC_HE_V2,
-    AUDIO_FORMAT_AAC_ELD,
-    AUDIO_FORMAT_AAC_XHE,
-};
-
 // Compressed formats for MSD module, ordered from most preferred to least preferred.
 static const std::vector<audio_format_t> compressedFormatsOrder = {{
         AUDIO_FORMAT_MAT_2_1, AUDIO_FORMAT_MAT_2_0, AUDIO_FORMAT_E_AC3,
@@ -3606,35 +3586,38 @@
              FormatVector supportedFormats =
                  hdmiOutputDevs[i]->getAudioPort()->getAudioProfiles().getSupportedFormats();
              for (size_t j = 0; j < supportedFormats.size(); j++) {
-                 if (std::find(std::begin(SURROUND_FORMATS),
-                                 std::end(SURROUND_FORMATS),
-                                 supportedFormats[j]) != std::end(SURROUND_FORMATS)) {
+                 if (mConfig.getSurroundFormats().count(supportedFormats[j]) != 0) {
                      formats.insert(supportedFormats[j]);
-                 } else if (std::find(std::begin(AAC_FORMATS),
-                                 std::end(AAC_FORMATS),
-                                 supportedFormats[j]) != std::end(AAC_FORMATS)) {
-                     // if any format in AAC_FORMATS is reported, insert AUDIO_FORMAT_AAC_LC as this
-                     // is the only AAC format used in the TvSettings UI for all AAC formats.
-                     formats.insert(AUDIO_FORMAT_AAC_LC);
+                 } else {
+                     for (const auto& pair : mConfig.getSurroundFormats()) {
+                         if (pair.second.count(supportedFormats[j]) != 0) {
+                             formats.insert(pair.first);
+                             break;
+                         }
+                     }
                  }
              }
         }
     } else {
-        for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
-            formats.insert(SURROUND_FORMATS[i]);
+        for (const auto& pair : mConfig.getSurroundFormats()) {
+            formats.insert(pair.first);
         }
     }
     for (const auto& format: formats) {
         if (formatsWritten < formatsMax) {
             surroundFormats[formatsWritten] = format;
             bool formatEnabled = false;
-            if (format == AUDIO_FORMAT_AAC_LC) {
-                for (size_t j = 0; j < ARRAY_SIZE(AAC_FORMATS) && !formatEnabled; j++) {
-                    formatEnabled =
-                            mSurroundFormats.find(AAC_FORMATS[j]) != mSurroundFormats.end();
+            if (mConfig.getSurroundFormats().count(format) == 0) {
+                // Check sub-formats
+                for (const auto& pair : mConfig.getSurroundFormats()) {
+                    for (const auto& subformat : pair.second) {
+                        formatEnabled = mSurroundFormats.count(subformat) != 0;
+                        if (formatEnabled) break;
+                    }
+                    if (formatEnabled) break;
                 }
             } else {
-                formatEnabled = mSurroundFormats.find(format) != mSurroundFormats.end();
+                formatEnabled = mSurroundFormats.count(format) != 0;
             }
             surroundFormatsEnabled[formatsWritten++] = formatEnabled;
         }
@@ -3647,14 +3630,8 @@
 {
     ALOGV("%s() format 0x%X enabled %d", __func__, audioFormat, enabled);
     // Check if audio format is a surround formats.
-    bool isSurroundFormat = false;
-    for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
-        if (audioFormat == SURROUND_FORMATS[i]) {
-            isSurroundFormat = true;
-            break;
-        }
-    }
-    if (!isSurroundFormat) {
+    const auto& formatIter = mConfig.getSurroundFormats().find(audioFormat);
+    if (formatIter == mConfig.getSurroundFormats().end()) {
         ALOGW("%s() format 0x%X is not a known surround format", __func__, audioFormat);
         return BAD_VALUE;
     }
@@ -3667,8 +3644,7 @@
         return INVALID_OPERATION;
     }
 
-    if ((mSurroundFormats.find(audioFormat) != mSurroundFormats.end() && enabled)
-            || (mSurroundFormats.find(audioFormat) == mSurroundFormats.end() && !enabled)) {
+    if ((mSurroundFormats.count(audioFormat) != 0) == enabled) {
         return NO_ERROR;
     }
 
@@ -3680,20 +3656,14 @@
 
     std::unordered_set<audio_format_t> surroundFormatsBackup(mSurroundFormats);
     if (enabled) {
-        if (audioFormat == AUDIO_FORMAT_AAC_LC) {
-            for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
-                mSurroundFormats.insert(AAC_FORMATS[i]);
-            }
-        } else {
-            mSurroundFormats.insert(audioFormat);
+        mSurroundFormats.insert(audioFormat);
+        for (const auto& subFormat : formatIter->second) {
+            mSurroundFormats.insert(subFormat);
         }
     } else {
-        if (audioFormat == AUDIO_FORMAT_AAC_LC) {
-            for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
-                mSurroundFormats.erase(AAC_FORMATS[i]);
-            }
-        } else {
-            mSurroundFormats.erase(audioFormat);
+        mSurroundFormats.erase(audioFormat);
+        for (const auto& subFormat : formatIter->second) {
+            mSurroundFormats.erase(subFormat);
         }
     }
 
@@ -3738,7 +3708,6 @@
         profileUpdated |= (status == NO_ERROR);
     }
 
-    // Undo the surround formats change due to no audio profiles updated.
     if (!profileUpdated) {
         ALOGW("%s() no audio profiles updated, undoing surround formats change", __func__);
         mSurroundFormats = std::move(surroundFormatsBackup);