blob: 3d5c1d2e4205a2afb28fef489ea402eb2a4a7dad [file] [log] [blame]
François Gaffief4ad6e52015-11-19 16:59:57 +01001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "APM::Serializer"
18//#define LOG_NDEBUG 0
19
Mikhail Naganova289aea2018-09-17 15:26:23 -070020#include <memory>
21#include <string>
Mikhail Naganov778bc1f2018-09-14 16:28:52 -070022#include <utility>
Mikhail Naganov6ef1b952021-02-25 18:22:02 -080023#include <variant>
Mikhail Naganova289aea2018-09-17 15:26:23 -070024
François Gaffief4ad6e52015-11-19 16:59:57 +010025#include <libxml/parser.h>
26#include <libxml/xinclude.h>
Mikhail Naganova289aea2018-09-17 15:26:23 -070027#include <media/convert.h>
28#include <utils/Log.h>
29#include <utils/StrongPointer.h>
30#include <utils/Errors.h>
31#include <utils/RefBase.h>
Mikhail Naganov68e3f642023-04-28 13:06:32 -070032#include "IOProfile.h"
Mikhail Naganova289aea2018-09-17 15:26:23 -070033#include "Serializer.h"
34#include "TypeConverter.h"
François Gaffief4ad6e52015-11-19 16:59:57 +010035
36namespace android {
37
Mikhail Naganova289aea2018-09-17 15:26:23 -070038namespace {
François Gaffief4ad6e52015-11-19 16:59:57 +010039
40using utilities::convertTo;
41
Mikhail Naganov6ef1b952021-02-25 18:22:02 -080042static inline bool maybeVendorExtension(const std::string& s) {
43 // Only checks whether the string starts with the "vendor prefix".
44 static const std::string vendorPrefix = "VX_";
45 return s.size() > vendorPrefix.size() && s.substr(0, vendorPrefix.size()) == vendorPrefix;
46}
47
Mikhail Naganova289aea2018-09-17 15:26:23 -070048template<typename E, typename C>
Mikhail Naganov778bc1f2018-09-14 16:28:52 -070049struct AndroidCollectionTraits {
Mikhail Naganov43c386c2018-09-19 12:38:29 -070050 typedef sp<E> Element;
Mikhail Naganova289aea2018-09-17 15:26:23 -070051 typedef C Collection;
52 typedef void* PtrSerializingCtx;
Mikhail Naganov43c386c2018-09-19 12:38:29 -070053
54 static status_t addElementToCollection(const Element &element, Collection *collection) {
55 return collection->add(element) >= 0 ? NO_ERROR : BAD_VALUE;
56 }
Mikhail Naganova289aea2018-09-17 15:26:23 -070057};
François Gaffiec9d7c4e2016-01-22 13:54:30 +010058
Mikhail Naganov778bc1f2018-09-14 16:28:52 -070059template<typename C>
60struct StdCollectionTraits {
61 typedef C Collection;
62 typedef typename C::value_type Element;
63 typedef void* PtrSerializingCtx;
64
65 static status_t addElementToCollection(const Element &element, Collection *collection) {
66 auto pair = collection->insert(element);
67 return pair.second ? NO_ERROR : BAD_VALUE;
68 }
69};
70
François Gaffie43c73442018-11-08 08:21:55 +010071struct AudioGainTraits : public AndroidCollectionTraits<AudioGain, AudioGains>
François Gaffiec9d7c4e2016-01-22 13:54:30 +010072{
Mikhail Naganova289aea2018-09-17 15:26:23 -070073 static constexpr const char *tag = "gain";
74 static constexpr const char *collectionTag = "gains";
75
76 struct Attributes
77 {
78 /** gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
79 static constexpr const char *mode = "mode";
80 /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
81 static constexpr const char *channelMask = "channel_mask";
82 static constexpr const char *minValueMB = "minValueMB"; /**< min value in millibel. */
83 static constexpr const char *maxValueMB = "maxValueMB"; /**< max value in millibel. */
84 /** default value in millibel. */
85 static constexpr const char *defaultValueMB = "defaultValueMB";
86 static constexpr const char *stepValueMB = "stepValueMB"; /**< step value in millibel. */
87 /** needed if mode AUDIO_GAIN_MODE_RAMP. */
88 static constexpr const char *minRampMs = "minRampMs";
89 /** needed if mode AUDIO_GAIN_MODE_RAMP. */
90 static constexpr const char *maxRampMs = "maxRampMs";
François Gaffie43c73442018-11-08 08:21:55 +010091 /** needed to allow use setPortGain instead of setStreamVolume. */
92 static constexpr const char *useForVolume = "useForVolume";
93
Mikhail Naganova289aea2018-09-17 15:26:23 -070094 };
95
Mikhail Naganova289aea2018-09-17 15:26:23 -070096 // No children
97};
98
99// A profile section contains a name, one audio format and the list of supported sampling rates
100// and channel masks for this format
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700101struct AudioProfileTraits : public AndroidCollectionTraits<AudioProfile, AudioProfileVector>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700102{
103 static constexpr const char *tag = "profile";
104 static constexpr const char *collectionTag = "profiles";
105
106 struct Attributes
107 {
108 static constexpr const char *samplingRates = "samplingRates";
109 static constexpr const char *format = "format";
110 static constexpr const char *channelMasks = "channelMasks";
111 };
Mikhail Naganova289aea2018-09-17 15:26:23 -0700112};
113
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700114struct MixPortTraits : public AndroidCollectionTraits<IOProfile, IOProfileCollection>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700115{
116 static constexpr const char *tag = "mixPort";
117 static constexpr const char *collectionTag = "mixPorts";
118
119 struct Attributes
120 {
121 static constexpr const char *name = "name";
122 static constexpr const char *role = "role";
123 static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
124 static constexpr const char *flags = "flags";
125 static constexpr const char *maxOpenCount = "maxOpenCount";
126 static constexpr const char *maxActiveCount = "maxActiveCount";
Jasmine Chaf6074fe2021-08-17 13:44:31 +0800127 static constexpr const char *recommendedMuteDurationMs = "recommendedMuteDurationMs";
Mikhail Naganova289aea2018-09-17 15:26:23 -0700128 };
129
Mikhail Naganova289aea2018-09-17 15:26:23 -0700130 // Children: GainTraits
131};
132
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700133struct DevicePortTraits : public AndroidCollectionTraits<DeviceDescriptor, DeviceVector>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700134{
135 static constexpr const char *tag = "devicePort";
136 static constexpr const char *collectionTag = "devicePorts";
137
138 struct Attributes
139 {
140 /** <device tag name>: any string without space. */
141 static constexpr const char *tagName = "tagName";
142 static constexpr const char *type = "type"; /**< <device type>. */
143 static constexpr const char *role = "role"; /**< <device role: sink or source>. */
144 static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
145 /** optional: device address, char string less than 64. */
146 static constexpr const char *address = "address";
Aniket Kumar Lata4e464702019-01-10 23:38:46 -0800147 /** optional: the list of encoded audio formats that are known to be supported. */
148 static constexpr const char *encodedFormats = "encodedFormats";
Mikhail Naganova289aea2018-09-17 15:26:23 -0700149 };
150
Mikhail Naganova289aea2018-09-17 15:26:23 -0700151 // Children: GainTraits (optional)
152};
153
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700154struct RouteTraits : public AndroidCollectionTraits<AudioRoute, AudioRouteVector>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700155{
156 static constexpr const char *tag = "route";
157 static constexpr const char *collectionTag = "routes";
158
159 struct Attributes
160 {
161 static constexpr const char *type = "type"; /**< <route type>: mix or mux. */
162 static constexpr const char *typeMix = "mix"; /**< type attribute mix value. */
163 static constexpr const char *sink = "sink"; /**< <sink: involved in this route>. */
164 /** sources: all source that can be involved in this route. */
165 static constexpr const char *sources = "sources";
166 };
167
168 typedef HwModule *PtrSerializingCtx;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700169};
170
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700171struct ModuleTraits : public AndroidCollectionTraits<HwModule, HwModuleCollection>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700172{
173 static constexpr const char *tag = "module";
174 static constexpr const char *collectionTag = "modules";
175
176 static constexpr const char *childAttachedDevicesTag = "attachedDevices";
177 static constexpr const char *childAttachedDeviceTag = "item";
178 static constexpr const char *childDefaultOutputDeviceTag = "defaultOutputDevice";
179
180 struct Attributes
181 {
182 static constexpr const char *name = "name";
183 static constexpr const char *version = "halVersion";
184 };
185
186 typedef AudioPolicyConfig *PtrSerializingCtx;
187
Mikhail Naganova289aea2018-09-17 15:26:23 -0700188 // Children: mixPortTraits, devicePortTraits, and routeTraits
189 // Need to call deserialize on each child
190};
191
192struct GlobalConfigTraits
193{
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800194 typedef std::monostate Element;
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000195
Mikhail Naganova289aea2018-09-17 15:26:23 -0700196 static constexpr const char *tag = "globalConfiguration";
197
198 struct Attributes
199 {
Eric Laurent8340e672019-11-06 11:01:08 -0800200 static constexpr const char *callScreenModeSupported= "call_screen_mode_supported";
François Gaffie8475ae52019-11-19 09:50:48 +0100201 static constexpr const char *engineLibrarySuffix = "engine_library";
Mikhail Naganova289aea2018-09-17 15:26:23 -0700202 };
203
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000204 typedef AudioPolicyConfig *PtrSerializingCtx;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700205};
206
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700207struct SurroundSoundTraits
208{
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800209 typedef std::monostate Element;
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000210
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700211 static constexpr const char *tag = "surroundSound";
212
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000213 typedef AudioPolicyConfig *PtrSerializingCtx;
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700214 // Children: SurroundSoundFormatTraits
215};
216
217struct SurroundSoundFormatTraits : public StdCollectionTraits<AudioPolicyConfig::SurroundFormats>
218{
219 static constexpr const char *tag = "format";
220 static constexpr const char *collectionTag = "formats";
221
222 struct Attributes
223 {
224 static constexpr const char *name = "name";
225 static constexpr const char *subformats = "subformats";
226 };
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700227};
228
Mikhail Naganova289aea2018-09-17 15:26:23 -0700229class PolicySerializer
230{
231public:
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800232 status_t deserialize(const char *configFile, AudioPolicyConfig *config,
233 bool ignoreVendorExtensions = false);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700234
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000235 template <class Trait>
236 status_t deserializeCollection(const xmlNode *cur,
237 typename Trait::Collection *collection,
238 typename Trait::PtrSerializingCtx serializingContext);
239 template <class Trait>
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800240 std::variant<status_t, typename Trait::Element> deserialize(const xmlNode *cur,
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000241 typename Trait::PtrSerializingCtx serializingContext);
242
Mikhail Naganova289aea2018-09-17 15:26:23 -0700243private:
244 static constexpr const char *rootName = "audioPolicyConfiguration";
245 static constexpr const char *versionAttribute = "version";
Mikhail Naganova289aea2018-09-17 15:26:23 -0700246
247 typedef AudioPolicyConfig Element;
248
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800249 bool mIgnoreVendorExtensions = false;
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000250 std::string mChannelMasksSeparator = ",";
251 std::string mSamplingRatesSeparator = ",";
252 std::string mFlagsSeparator = "|";
Mikhail Naganova289aea2018-09-17 15:26:23 -0700253
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700254 // Children: ModulesTraits, VolumeTraits, SurroundSoundTraits (optional)
Mikhail Naganova289aea2018-09-17 15:26:23 -0700255};
256
Mikhail Naganov91d50bb2021-04-16 17:38:23 -0700257// Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
258struct FreeDelete {
259 // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
260 void operator()(const void* ptr) const {
261 free(const_cast<void*>(ptr));
262 }
263};
264
265// Alias for std::unique_ptr<> that uses the C function free() to delete objects.
266template <typename T>
267using UniqueCPtr = std::unique_ptr<T, FreeDelete>;
268
Mikhail Naganova289aea2018-09-17 15:26:23 -0700269template <class T>
270constexpr void (*xmlDeleter)(T* t);
271template <>
272constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
273template <>
Mikhail Naganov8916ae92020-10-21 13:04:58 -0700274constexpr auto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };
Mikhail Naganova289aea2018-09-17 15:26:23 -0700275
276/** @return a unique_ptr with the correct deleter for the libxml2 object. */
277template <class T>
278constexpr auto make_xmlUnique(T *t) {
279 // Wrap deleter in lambda to enable empty base optimization
280 auto deleter = [](T *t) { xmlDeleter<T>(t); };
281 return std::unique_ptr<T, decltype(deleter)>{t, deleter};
282}
283
284std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
285{
286 auto xmlValue = make_xmlUnique(xmlGetProp(cur, reinterpret_cast<const xmlChar*>(attribute)));
287 if (xmlValue == nullptr) {
288 return "";
289 }
290 std::string value(reinterpret_cast<const char*>(xmlValue.get()));
291 return value;
François Gaffiec9d7c4e2016-01-22 13:54:30 +0100292}
François Gaffief4ad6e52015-11-19 16:59:57 +0100293
294template <class Trait>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700295const xmlNode* getReference(const xmlNode *cur, const std::string &refName)
François Gaffief4ad6e52015-11-19 16:59:57 +0100296{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700297 for (; cur != NULL; cur = cur->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700298 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700299 for (const xmlNode *child = cur->children; child != NULL; child = child->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700300 if ((!xmlStrcmp(child->name,
301 reinterpret_cast<const xmlChar*>(Trait::referenceTag)))) {
302 std::string name = getXmlAttribute(child, Trait::Attributes::referenceName);
303 if (refName == name) {
304 return child;
305 }
306 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700307 }
308 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700309 }
310 return NULL;
311}
312
313template <class Trait>
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000314status_t PolicySerializer::deserializeCollection(const xmlNode *cur,
Mikhail Naganova289aea2018-09-17 15:26:23 -0700315 typename Trait::Collection *collection,
316 typename Trait::PtrSerializingCtx serializingContext)
317{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700318 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
319 const xmlNode *child = NULL;
320 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
321 child = cur->xmlChildrenNode;
322 } else if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
323 child = cur;
François Gaffief4ad6e52015-11-19 16:59:57 +0100324 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700325 for (; child != NULL; child = child->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700326 if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800327 auto maybeElement = deserialize<Trait>(child, serializingContext);
328 if (maybeElement.index() == 1) {
329 status_t status = Trait::addElementToCollection(
330 std::get<1>(maybeElement), collection);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700331 if (status != NO_ERROR) {
332 ALOGE("%s: could not add element to %s collection", __func__,
333 Trait::collectionTag);
334 return status;
335 }
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800336 } else if (mIgnoreVendorExtensions && std::get<status_t>(maybeElement) == NO_INIT) {
337 // Skip a vendor extension element.
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700338 } else {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700339 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100340 }
341 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100342 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700343 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
François Gaffied1ab2bd2015-12-02 18:20:06 +0100344 return NO_ERROR;
345 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100346 }
François Gaffied1ab2bd2015-12-02 18:20:06 +0100347 return NO_ERROR;
François Gaffief4ad6e52015-11-19 16:59:57 +0100348}
349
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000350template<>
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800351std::variant<status_t, AudioGainTraits::Element> PolicySerializer::deserialize<AudioGainTraits>(
352 const xmlNode *cur, AudioGainTraits::PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100353{
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000354 using Attributes = AudioGainTraits::Attributes;
355
François Gaffief4ad6e52015-11-19 16:59:57 +0100356 static uint32_t index = 0;
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000357 AudioGainTraits::Element gain = new AudioGain(index++, true);
François Gaffief4ad6e52015-11-19 16:59:57 +0100358
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700359 std::string mode = getXmlAttribute(cur, Attributes::mode);
François Gaffief4ad6e52015-11-19 16:59:57 +0100360 if (!mode.empty()) {
Mikhail Naganovdc6be0d2020-09-25 23:03:05 +0000361 gain->setMode(GainModeConverter::maskFromString(mode, " "));
François Gaffief4ad6e52015-11-19 16:59:57 +0100362 }
363
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700364 std::string channelsLiteral = getXmlAttribute(cur, Attributes::channelMask);
François Gaffief4ad6e52015-11-19 16:59:57 +0100365 if (!channelsLiteral.empty()) {
366 gain->setChannelMask(channelMaskFromString(channelsLiteral));
367 }
368
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700369 std::string minValueMBLiteral = getXmlAttribute(cur, Attributes::minValueMB);
Kevin Rocard575bb3a2017-10-27 16:49:20 -0700370 int32_t minValueMB;
François Gaffief4ad6e52015-11-19 16:59:57 +0100371 if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
372 gain->setMinValueInMb(minValueMB);
373 }
374
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700375 std::string maxValueMBLiteral = getXmlAttribute(cur, Attributes::maxValueMB);
Kevin Rocard575bb3a2017-10-27 16:49:20 -0700376 int32_t maxValueMB;
François Gaffief4ad6e52015-11-19 16:59:57 +0100377 if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
378 gain->setMaxValueInMb(maxValueMB);
379 }
380
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700381 std::string defaultValueMBLiteral = getXmlAttribute(cur, Attributes::defaultValueMB);
Kevin Rocard575bb3a2017-10-27 16:49:20 -0700382 int32_t defaultValueMB;
François Gaffief4ad6e52015-11-19 16:59:57 +0100383 if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
384 gain->setDefaultValueInMb(defaultValueMB);
385 }
386
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700387 std::string stepValueMBLiteral = getXmlAttribute(cur, Attributes::stepValueMB);
François Gaffief4ad6e52015-11-19 16:59:57 +0100388 uint32_t stepValueMB;
389 if (!stepValueMBLiteral.empty() && convertTo(stepValueMBLiteral, stepValueMB)) {
390 gain->setStepValueInMb(stepValueMB);
391 }
392
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700393 std::string minRampMsLiteral = getXmlAttribute(cur, Attributes::minRampMs);
François Gaffief4ad6e52015-11-19 16:59:57 +0100394 uint32_t minRampMs;
395 if (!minRampMsLiteral.empty() && convertTo(minRampMsLiteral, minRampMs)) {
396 gain->setMinRampInMs(minRampMs);
397 }
398
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700399 std::string maxRampMsLiteral = getXmlAttribute(cur, Attributes::maxRampMs);
François Gaffief4ad6e52015-11-19 16:59:57 +0100400 uint32_t maxRampMs;
401 if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
402 gain->setMaxRampInMs(maxRampMs);
403 }
François Gaffie43c73442018-11-08 08:21:55 +0100404 std::string useForVolumeLiteral = getXmlAttribute(cur, Attributes::useForVolume);
405 bool useForVolume = false;
406 if (!useForVolumeLiteral.empty() && convertTo(useForVolumeLiteral, useForVolume)) {
407 gain->setUseForVolume(useForVolume);
408 }
409 ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d UseForVolume: %d",
410 __func__, gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
411 gain->getMaxValueInMb(), useForVolume);
François Gaffief4ad6e52015-11-19 16:59:57 +0100412
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700413 if (gain->getMode() != 0) {
414 return gain;
415 } else {
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800416 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100417 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100418}
419
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000420template<>
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800421std::variant<status_t, AudioProfileTraits::Element>
422PolicySerializer::deserialize<AudioProfileTraits>(
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000423 const xmlNode *cur, AudioProfileTraits::PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100424{
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000425 using Attributes = AudioProfileTraits::Attributes;
426
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700427 std::string samplingRates = getXmlAttribute(cur, Attributes::samplingRates);
428 std::string format = getXmlAttribute(cur, Attributes::format);
429 std::string channels = getXmlAttribute(cur, Attributes::channelMasks);
François Gaffief4ad6e52015-11-19 16:59:57 +0100430
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800431 if (mIgnoreVendorExtensions && maybeVendorExtension(format)) {
432 ALOGI("%s: vendor extension format \"%s\" skipped", __func__, format.c_str());
433 return NO_INIT;
434 }
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000435 AudioProfileTraits::Element profile = new AudioProfile(formatFromString(format, gDynamicFormat),
436 channelMasksFromString(channels, mChannelMasksSeparator.c_str()),
437 samplingRatesFromString(samplingRates, mSamplingRatesSeparator.c_str()));
François Gaffief4ad6e52015-11-19 16:59:57 +0100438
439 profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
jiabin06e4bab2019-07-29 10:13:34 -0700440 profile->setDynamicChannels(profile->getChannels().empty());
441 profile->setDynamicRate(profile->getSampleRates().empty());
François Gaffief4ad6e52015-11-19 16:59:57 +0100442
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700443 return profile;
François Gaffief4ad6e52015-11-19 16:59:57 +0100444}
445
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000446template<>
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800447std::variant<status_t, MixPortTraits::Element> PolicySerializer::deserialize<MixPortTraits>(
448 const xmlNode *child, MixPortTraits::PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100449{
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000450 using Attributes = MixPortTraits::Attributes;
451
Mikhail Naganova289aea2018-09-17 15:26:23 -0700452 std::string name = getXmlAttribute(child, Attributes::name);
François Gaffief4ad6e52015-11-19 16:59:57 +0100453 if (name.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700454 ALOGE("%s: No %s found", __func__, Attributes::name);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800455 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100456 }
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000457 ALOGV("%s: %s %s=%s", __func__, MixPortTraits::tag, Attributes::name, name.c_str());
Mikhail Naganova289aea2018-09-17 15:26:23 -0700458 std::string role = getXmlAttribute(child, Attributes::role);
François Gaffief4ad6e52015-11-19 16:59:57 +0100459 if (role.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700460 ALOGE("%s: No %s found", __func__, Attributes::role);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800461 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100462 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700463 ALOGV("%s: Role=%s", __func__, role.c_str());
464 audio_port_role_t portRole = (role == Attributes::roleSource) ?
465 AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
François Gaffief4ad6e52015-11-19 16:59:57 +0100466
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000467 MixPortTraits::Element mixPort = new IOProfile(name, portRole);
François Gaffief4ad6e52015-11-19 16:59:57 +0100468
469 AudioProfileTraits::Collection profiles;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700470 status_t status = deserializeCollection<AudioProfileTraits>(child, &profiles, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700471 if (status != NO_ERROR) {
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800472 return status;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700473 }
jiabin06e4bab2019-07-29 10:13:34 -0700474 if (profiles.empty()) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700475 profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
François Gaffief4ad6e52015-11-19 16:59:57 +0100476 }
jiabin3e277cc2019-09-10 14:27:34 -0700477 // The audio profiles are in order of listed in audio policy configuration file.
478 // Sort audio profiles accroding to the format.
479 sortAudioProfiles(profiles);
François Gaffief4ad6e52015-11-19 16:59:57 +0100480 mixPort->setAudioProfiles(profiles);
481
Mikhail Naganova289aea2018-09-17 15:26:23 -0700482 std::string flags = getXmlAttribute(child, Attributes::flags);
François Gaffief4ad6e52015-11-19 16:59:57 +0100483 if (!flags.empty()) {
484 // Source role
485 if (portRole == AUDIO_PORT_ROLE_SOURCE) {
Eric Laurente28c66d2022-01-21 13:40:41 +0100486 //TODO: b/193496180 use spatializer flag at audio HAL when available until then,
487 // use DEEP_BUFFER+FAST flag combo to indicate the spatializer output profile
488 uint32_t intFlags =
489 OutputFlagConverter::maskFromString(flags, mFlagsSeparator.c_str());
490 if (intFlags == (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
491 intFlags = AUDIO_OUTPUT_FLAG_SPATIALIZER;
492 }
493 mixPort->setFlags(intFlags);
François Gaffief4ad6e52015-11-19 16:59:57 +0100494 } else {
495 // Sink role
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000496 mixPort->setFlags(InputFlagConverter::maskFromString(flags, mFlagsSeparator.c_str()));
François Gaffief4ad6e52015-11-19 16:59:57 +0100497 }
498 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700499 std::string maxOpenCount = getXmlAttribute(child, Attributes::maxOpenCount);
Eric Laurentae603172017-12-07 17:59:01 -0800500 if (!maxOpenCount.empty()) {
501 convertTo(maxOpenCount, mixPort->maxOpenCount);
502 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700503 std::string maxActiveCount = getXmlAttribute(child, Attributes::maxActiveCount);
Eric Laurentae603172017-12-07 17:59:01 -0800504 if (!maxActiveCount.empty()) {
505 convertTo(maxActiveCount, mixPort->maxActiveCount);
506 }
Jasmine Chaf6074fe2021-08-17 13:44:31 +0800507
508 std::string recommendedmuteDurationMsLiteral =
509 getXmlAttribute(child, Attributes::recommendedMuteDurationMs);
510 if (!recommendedmuteDurationMsLiteral.empty()) {
511 convertTo(recommendedmuteDurationMsLiteral, mixPort->recommendedMuteDurationMs);
512 }
513
François Gaffief4ad6e52015-11-19 16:59:57 +0100514 // Deserialize children
515 AudioGainTraits::Collection gains;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700516 status = deserializeCollection<AudioGainTraits>(child, &gains, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700517 if (status != NO_ERROR) {
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800518 return status;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700519 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100520 mixPort->setGains(gains);
521
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700522 return mixPort;
François Gaffief4ad6e52015-11-19 16:59:57 +0100523}
524
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000525template<>
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800526std::variant<status_t, DevicePortTraits::Element> PolicySerializer::deserialize<DevicePortTraits>(
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000527 const xmlNode *cur, DevicePortTraits::PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100528{
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000529 using Attributes = DevicePortTraits::Attributes;
530 auto& tag = DevicePortTraits::tag;
531
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700532 std::string name = getXmlAttribute(cur, Attributes::tagName);
François Gaffief4ad6e52015-11-19 16:59:57 +0100533 if (name.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700534 ALOGE("%s: No %s found", __func__, Attributes::tagName);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800535 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100536 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700537 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::tagName, name.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700538 std::string typeName = getXmlAttribute(cur, Attributes::type);
François Gaffief4ad6e52015-11-19 16:59:57 +0100539 if (typeName.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700540 ALOGE("%s: no type for %s", __func__, name.c_str());
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800541 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100542 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700543 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, typeName.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700544 std::string role = getXmlAttribute(cur, Attributes::role);
François Gaffief4ad6e52015-11-19 16:59:57 +0100545 if (role.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700546 ALOGE("%s: No %s found", __func__, Attributes::role);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800547 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100548 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700549 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::role, role.c_str());
François Gaffief4ad6e52015-11-19 16:59:57 +0100550 audio_port_role_t portRole = (role == Attributes::roleSource) ?
551 AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
552
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800553 if (mIgnoreVendorExtensions && maybeVendorExtension(typeName)) {
554 ALOGI("%s: vendor extension device type \"%s\" skipped", __func__, typeName.c_str());
555 return NO_INIT;
556 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100557 audio_devices_t type = AUDIO_DEVICE_NONE;
Mikhail Naganovdc6be0d2020-09-25 23:03:05 +0000558 if (!DeviceConverter::fromString(typeName, type) ||
François Gaffief4ad6e52015-11-19 16:59:57 +0100559 (!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
560 (!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700561 ALOGW("%s: bad type %08x", __func__, type);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800562 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100563 }
Aniket Kumar Lata4e464702019-01-10 23:38:46 -0800564 std::string encodedFormatsLiteral = getXmlAttribute(cur, Attributes::encodedFormats);
565 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::encodedFormats, encodedFormatsLiteral.c_str());
566 FormatVector encodedFormats;
567 if (!encodedFormatsLiteral.empty()) {
568 encodedFormats = formatsFromString(encodedFormatsLiteral, " ");
569 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700570 std::string address = getXmlAttribute(cur, Attributes::address);
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000571 DevicePortTraits::Element deviceDesc =
572 new DeviceDescriptor(type, name, address, encodedFormats);
François Gaffief4ad6e52015-11-19 16:59:57 +0100573
574 AudioProfileTraits::Collection profiles;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700575 status_t status = deserializeCollection<AudioProfileTraits>(cur, &profiles, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700576 if (status != NO_ERROR) {
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800577 return status;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700578 }
jiabin06e4bab2019-07-29 10:13:34 -0700579 if (profiles.empty()) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700580 profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
François Gaffief4ad6e52015-11-19 16:59:57 +0100581 }
jiabin3e277cc2019-09-10 14:27:34 -0700582 // The audio profiles are in order of listed in audio policy configuration file.
583 // Sort audio profiles accroding to the format.
584 sortAudioProfiles(profiles);
François Gaffief4ad6e52015-11-19 16:59:57 +0100585 deviceDesc->setAudioProfiles(profiles);
586
587 // Deserialize AudioGain children
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700588 status = deserializeCollection<AudioGainTraits>(cur, &deviceDesc->mGains, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700589 if (status != NO_ERROR) {
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800590 return status;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700591 }
592 ALOGV("%s: adding device tag %s type %08x address %s", __func__,
jiabince9f20e2019-09-12 16:29:15 -0700593 deviceDesc->getName().c_str(), type, deviceDesc->address().c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700594 return deviceDesc;
François Gaffief4ad6e52015-11-19 16:59:57 +0100595}
596
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000597template<>
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800598std::variant<status_t, RouteTraits::Element> PolicySerializer::deserialize<RouteTraits>(
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000599 const xmlNode *cur, RouteTraits::PtrSerializingCtx ctx)
François Gaffief4ad6e52015-11-19 16:59:57 +0100600{
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000601 using Attributes = RouteTraits::Attributes;
602
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700603 std::string type = getXmlAttribute(cur, Attributes::type);
François Gaffief4ad6e52015-11-19 16:59:57 +0100604 if (type.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700605 ALOGE("%s: No %s found", __func__, Attributes::type);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800606 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100607 }
608 audio_route_type_t routeType = (type == Attributes::typeMix) ?
609 AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
610
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000611 ALOGV("%s: %s %s=%s", __func__, RouteTraits::tag, Attributes::type, type.c_str());
612 RouteTraits::Element route = new AudioRoute(routeType);
François Gaffief4ad6e52015-11-19 16:59:57 +0100613
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700614 std::string sinkAttr = getXmlAttribute(cur, Attributes::sink);
François Gaffief4ad6e52015-11-19 16:59:57 +0100615 if (sinkAttr.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700616 ALOGE("%s: No %s found", __func__, Attributes::sink);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800617 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100618 }
619 // Convert Sink name to port pointer
jiabin4ef93452019-09-10 14:29:54 -0700620 sp<PolicyAudioPort> sink = ctx->findPortByTagName(sinkAttr);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800621 if (sink == NULL && !mIgnoreVendorExtensions) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700622 ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800623 return BAD_VALUE;
624 } else if (sink == NULL) {
625 ALOGW("Skipping route to sink \"%s\" as it likely has vendor extension type",
626 sinkAttr.c_str());
627 return NO_INIT;
François Gaffief4ad6e52015-11-19 16:59:57 +0100628 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700629 route->setSink(sink);
François Gaffief4ad6e52015-11-19 16:59:57 +0100630
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700631 std::string sourcesAttr = getXmlAttribute(cur, Attributes::sources);
François Gaffief4ad6e52015-11-19 16:59:57 +0100632 if (sourcesAttr.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700633 ALOGE("%s: No %s found", __func__, Attributes::sources);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800634 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100635 }
636 // Tokenize and Convert Sources name to port pointer
jiabin4ef93452019-09-10 14:29:54 -0700637 PolicyAudioPortVector sources;
Mikhail Naganov91d50bb2021-04-16 17:38:23 -0700638 UniqueCPtr<char> sourcesLiteral{strndup(
Mikhail Naganova289aea2018-09-17 15:26:23 -0700639 sourcesAttr.c_str(), strlen(sourcesAttr.c_str()))};
640 char *devTag = strtok(sourcesLiteral.get(), ",");
François Gaffief4ad6e52015-11-19 16:59:57 +0100641 while (devTag != NULL) {
642 if (strlen(devTag) != 0) {
jiabin4ef93452019-09-10 14:29:54 -0700643 sp<PolicyAudioPort> source = ctx->findPortByTagName(devTag);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800644 if (source == NULL && !mIgnoreVendorExtensions) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700645 ALOGE("%s: no source found with name=%s", __func__, devTag);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800646 return BAD_VALUE;
647 } else if (source == NULL) {
648 ALOGW("Skipping route source \"%s\" as it likely has vendor extension type",
649 devTag);
650 } else {
651 sources.add(source);
François Gaffief4ad6e52015-11-19 16:59:57 +0100652 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100653 }
654 devTag = strtok(NULL, ",");
655 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100656
Mikhail Naganova289aea2018-09-17 15:26:23 -0700657 sink->addRoute(route);
François Gaffief4ad6e52015-11-19 16:59:57 +0100658 for (size_t i = 0; i < sources.size(); i++) {
jiabin4ef93452019-09-10 14:29:54 -0700659 sp<PolicyAudioPort> source = sources.itemAt(i);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700660 source->addRoute(route);
François Gaffief4ad6e52015-11-19 16:59:57 +0100661 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700662 route->setSources(sources);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700663 return route;
François Gaffief4ad6e52015-11-19 16:59:57 +0100664}
665
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000666template<>
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800667std::variant<status_t, ModuleTraits::Element> PolicySerializer::deserialize<ModuleTraits>(
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000668 const xmlNode *cur, ModuleTraits::PtrSerializingCtx ctx)
François Gaffief4ad6e52015-11-19 16:59:57 +0100669{
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000670 using Attributes = ModuleTraits::Attributes;
671 auto& tag = ModuleTraits::tag;
672 auto& childAttachedDevicesTag = ModuleTraits::childAttachedDevicesTag;
673 auto& childAttachedDeviceTag = ModuleTraits::childAttachedDeviceTag;
674 auto& childDefaultOutputDeviceTag = ModuleTraits::childDefaultOutputDeviceTag;
675
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700676 std::string name = getXmlAttribute(cur, Attributes::name);
François Gaffief4ad6e52015-11-19 16:59:57 +0100677 if (name.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700678 ALOGE("%s: No %s found", __func__, Attributes::name);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800679 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100680 }
Mikhail Naganov9ee05402016-10-13 15:58:17 -0700681 uint32_t versionMajor = 0, versionMinor = 0;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700682 std::string versionLiteral = getXmlAttribute(cur, Attributes::version);
François Gaffief4ad6e52015-11-19 16:59:57 +0100683 if (!versionLiteral.empty()) {
Mikhail Naganov9ee05402016-10-13 15:58:17 -0700684 sscanf(versionLiteral.c_str(), "%u.%u", &versionMajor, &versionMinor);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700685 ALOGV("%s: mHalVersion = major %u minor %u", __func__,
Mikhail Naganov9ee05402016-10-13 15:58:17 -0700686 versionMajor, versionMajor);
François Gaffief4ad6e52015-11-19 16:59:57 +0100687 }
688
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000689 ALOGV("%s: %s %s=%s", __func__, ModuleTraits::tag, Attributes::name, name.c_str());
François Gaffief4ad6e52015-11-19 16:59:57 +0100690
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000691 ModuleTraits::Element module = new HwModule(name.c_str(), versionMajor, versionMinor);
François Gaffief4ad6e52015-11-19 16:59:57 +0100692
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000693 // Deserialize children: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
François Gaffief4ad6e52015-11-19 16:59:57 +0100694 MixPortTraits::Collection mixPorts;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700695 status_t status = deserializeCollection<MixPortTraits>(cur, &mixPorts, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700696 if (status != NO_ERROR) {
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800697 return status;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700698 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100699 module->setProfiles(mixPorts);
700
701 DevicePortTraits::Collection devicePorts;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700702 status = deserializeCollection<DevicePortTraits>(cur, &devicePorts, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700703 if (status != NO_ERROR) {
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800704 return status;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700705 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100706 module->setDeclaredDevices(devicePorts);
707
708 RouteTraits::Collection routes;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700709 status = deserializeCollection<RouteTraits>(cur, &routes, module.get());
Mikhail Naganova289aea2018-09-17 15:26:23 -0700710 if (status != NO_ERROR) {
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800711 return status;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700712 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100713 module->setRoutes(routes);
714
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700715 for (const xmlNode *children = cur->xmlChildrenNode; children != NULL;
716 children = children->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700717 if (!xmlStrcmp(children->name, reinterpret_cast<const xmlChar*>(childAttachedDevicesTag))) {
718 ALOGV("%s: %s %s found", __func__, tag, childAttachedDevicesTag);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700719 for (const xmlNode *child = children->xmlChildrenNode; child != NULL;
720 child = child->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700721 if (!xmlStrcmp(child->name,
722 reinterpret_cast<const xmlChar*>(childAttachedDeviceTag))) {
723 auto attachedDevice = make_xmlUnique(xmlNodeListGetString(
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700724 child->doc, child->xmlChildrenNode, 1));
Mikhail Naganova289aea2018-09-17 15:26:23 -0700725 if (attachedDevice != nullptr) {
726 ALOGV("%s: %s %s=%s", __func__, tag, childAttachedDeviceTag,
727 reinterpret_cast<const char*>(attachedDevice.get()));
728 sp<DeviceDescriptor> device = module->getDeclaredDevices().
jiabin5740f082019-08-19 15:08:30 -0700729 getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
Mikhail Naganova289aea2018-09-17 15:26:23 -0700730 attachedDevice.get())));
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800731 if (device == nullptr && mIgnoreVendorExtensions) {
732 ALOGW("Skipped attached device \"%s\" because it likely uses a vendor"
733 "extension type",
734 reinterpret_cast<const char*>(attachedDevice.get()));
735 continue;
736 }
Mikhail Naganovc0d04982020-03-02 21:02:28 +0000737 ctx->addDevice(device);
François Gaffief4ad6e52015-11-19 16:59:57 +0100738 }
739 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100740 }
741 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700742 if (!xmlStrcmp(children->name,
743 reinterpret_cast<const xmlChar*>(childDefaultOutputDeviceTag))) {
744 auto defaultOutputDevice = make_xmlUnique(xmlNodeListGetString(
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700745 children->doc, children->xmlChildrenNode, 1));
Mikhail Naganova289aea2018-09-17 15:26:23 -0700746 if (defaultOutputDevice != nullptr) {
747 ALOGV("%s: %s %s=%s", __func__, tag, childDefaultOutputDeviceTag,
748 reinterpret_cast<const char*>(defaultOutputDevice.get()));
749 sp<DeviceDescriptor> device = module->getDeclaredDevices().getDeviceFromTagName(
jiabin5740f082019-08-19 15:08:30 -0700750 std::string(reinterpret_cast<const char*>(defaultOutputDevice.get())));
François Gaffief4ad6e52015-11-19 16:59:57 +0100751 if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
752 ctx->setDefaultOutputDevice(device);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700753 ALOGV("%s: default is %08x",
754 __func__, ctx->getDefaultOutputDevice()->type());
François Gaffief4ad6e52015-11-19 16:59:57 +0100755 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100756 }
757 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100758 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700759 return module;
François Gaffief4ad6e52015-11-19 16:59:57 +0100760}
761
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000762template<>
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800763std::variant<status_t, GlobalConfigTraits::Element>
764PolicySerializer::deserialize<GlobalConfigTraits>(
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000765 const xmlNode *root, GlobalConfigTraits::PtrSerializingCtx config)
François Gaffief4ad6e52015-11-19 16:59:57 +0100766{
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000767 using Attributes = GlobalConfigTraits::Attributes;
768
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700769 for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000770 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(GlobalConfigTraits::tag))) {
Eric Laurent8340e672019-11-06 11:01:08 -0800771 bool value;
Mikhail Naganovffd97712023-05-03 17:45:36 -0700772 std::string attr = getXmlAttribute(cur, Attributes::callScreenModeSupported);
Eric Laurent8340e672019-11-06 11:01:08 -0800773 if (!attr.empty() &&
774 convertTo<std::string, bool>(attr, value)) {
775 config->setCallScreenModeSupported(value);
776 }
François Gaffie8475ae52019-11-19 09:50:48 +0100777 std::string engineLibrarySuffix = getXmlAttribute(cur, Attributes::engineLibrarySuffix);
778 if (!engineLibrarySuffix.empty()) {
779 config->setEngineLibraryNameSuffix(engineLibrarySuffix);
780 }
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800781 return NO_ERROR;
François Gaffief4ad6e52015-11-19 16:59:57 +0100782 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100783 }
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800784 return NO_ERROR;
François Gaffief4ad6e52015-11-19 16:59:57 +0100785}
786
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000787template<>
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800788std::variant<status_t, SurroundSoundTraits::Element>
789PolicySerializer::deserialize<SurroundSoundTraits>(
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000790 const xmlNode *root, SurroundSoundTraits::PtrSerializingCtx config)
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700791{
792 config->setDefaultSurroundFormats();
793
794 for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000795 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(SurroundSoundTraits::tag))) {
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700796 AudioPolicyConfig::SurroundFormats formats;
797 status_t status = deserializeCollection<SurroundSoundFormatTraits>(
798 cur, &formats, nullptr);
799 if (status == NO_ERROR) {
800 config->setSurroundFormats(formats);
801 }
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800802 return NO_ERROR;
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700803 }
804 }
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800805 return NO_ERROR;
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700806}
807
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000808template<>
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800809std::variant<status_t, SurroundSoundFormatTraits::Element>
810PolicySerializer::deserialize<SurroundSoundFormatTraits>(
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000811 const xmlNode *cur, SurroundSoundFormatTraits::PtrSerializingCtx /*serializingContext*/)
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700812{
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000813 using Attributes = SurroundSoundFormatTraits::Attributes;
814
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700815 std::string formatLiteral = getXmlAttribute(cur, Attributes::name);
816 if (formatLiteral.empty()) {
817 ALOGE("%s: No %s found for a surround format", __func__, Attributes::name);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800818 return BAD_VALUE;
819 }
820 if (mIgnoreVendorExtensions && maybeVendorExtension(formatLiteral)) {
821 ALOGI("%s: vendor extension format \"%s\" skipped", __func__, formatLiteral.c_str());
822 return NO_INIT;
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700823 }
824 audio_format_t format = formatFromString(formatLiteral);
825 if (format == AUDIO_FORMAT_DEFAULT) {
826 ALOGE("%s: Unrecognized format %s", __func__, formatLiteral.c_str());
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800827 return BAD_VALUE;
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700828 }
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000829 SurroundSoundFormatTraits::Element pair = std::make_pair(
830 format, SurroundSoundFormatTraits::Collection::mapped_type{});
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700831
832 std::string subformatsLiteral = getXmlAttribute(cur, Attributes::subformats);
833 if (subformatsLiteral.empty()) return pair;
834 FormatVector subformats = formatsFromString(subformatsLiteral, " ");
835 for (const auto& subformat : subformats) {
836 auto result = pair.second.insert(subformat);
837 if (!result.second) {
838 ALOGE("%s: could not add subformat %x to collection", __func__, subformat);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800839 return BAD_VALUE;
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700840 }
841 }
842 return pair;
843}
844
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800845status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config,
846 bool ignoreVendorExtensions)
François Gaffief4ad6e52015-11-19 16:59:57 +0100847{
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800848 mIgnoreVendorExtensions = ignoreVendorExtensions;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700849 auto doc = make_xmlUnique(xmlParseFile(configFile));
850 if (doc == nullptr) {
851 ALOGE("%s: Could not parse %s document.", __func__, configFile);
François Gaffief4ad6e52015-11-19 16:59:57 +0100852 return BAD_VALUE;
853 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700854 xmlNodePtr root = xmlDocGetRootElement(doc.get());
855 if (root == NULL) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700856 ALOGE("%s: Could not parse %s document: empty.", __func__, configFile);
François Gaffief4ad6e52015-11-19 16:59:57 +0100857 return BAD_VALUE;
858 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700859 if (xmlXIncludeProcess(doc.get()) < 0) {
860 ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __func__, configFile);
François Gaffief4ad6e52015-11-19 16:59:57 +0100861 }
862
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700863 if (xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>(rootName))) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700864 ALOGE("%s: No %s root element found in xml data %s.", __func__, rootName,
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700865 reinterpret_cast<const char*>(root->name));
François Gaffief4ad6e52015-11-19 16:59:57 +0100866 return BAD_VALUE;
867 }
868
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700869 std::string version = getXmlAttribute(root, versionAttribute);
François Gaffief4ad6e52015-11-19 16:59:57 +0100870 if (version.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700871 ALOGE("%s: No version found in root node %s", __func__, rootName);
François Gaffief4ad6e52015-11-19 16:59:57 +0100872 return BAD_VALUE;
873 }
Mikhail Naganov6718c392022-01-27 22:17:21 +0000874 if (version == "7.0" || version == "7.1") {
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000875 mChannelMasksSeparator = mSamplingRatesSeparator = mFlagsSeparator = " ";
876 } else if (version != "1.0") {
Mikhail Naganov6718c392022-01-27 22:17:21 +0000877 ALOGE("%s: Version does not match; expected \"1.0\", \"7.0\", or \"7.1\" got \"%s\"",
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000878 __func__, version.c_str());
François Gaffief4ad6e52015-11-19 16:59:57 +0100879 return BAD_VALUE;
880 }
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000881 // Let's deserialize children
François Gaffief4ad6e52015-11-19 16:59:57 +0100882 // Modules
883 ModuleTraits::Collection modules;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700884 status_t status = deserializeCollection<ModuleTraits>(root, &modules, config);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700885 if (status != NO_ERROR) {
886 return status;
887 }
888 config->setHwModules(modules);
François Gaffief4ad6e52015-11-19 16:59:57 +0100889
François Gaffief4ad6e52015-11-19 16:59:57 +0100890 // Global Configuration
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000891 deserialize<GlobalConfigTraits>(root, config);
François Gaffief4ad6e52015-11-19 16:59:57 +0100892
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700893 // Surround configuration
Mikhail Naganova7c4e032021-02-04 19:20:12 +0000894 deserialize<SurroundSoundTraits>(root, config);
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700895
François Gaffief4ad6e52015-11-19 16:59:57 +0100896 return android::OK;
897}
898
Mikhail Naganova289aea2018-09-17 15:26:23 -0700899} // namespace
900
901status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config)
902{
903 PolicySerializer serializer;
Mikhail Naganov8916ae92020-10-21 13:04:58 -0700904 status_t status = serializer.deserialize(fileName, config);
Mikhail Naganov8916ae92020-10-21 13:04:58 -0700905 return status;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700906}
907
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800908status_t deserializeAudioPolicyFileForVts(const char *fileName, AudioPolicyConfig *config)
909{
910 PolicySerializer serializer;
911 status_t status = serializer.deserialize(fileName, config, true /*ignoreVendorExtensions*/);
Mikhail Naganov6ef1b952021-02-25 18:22:02 -0800912 return status;
913}
914
Mikhail Naganov1b2a7942017-12-08 10:18:09 -0800915} // namespace android