blob: 98d375c115a6ce03ebf32ec2d5bb1e211b60c217 [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 Naganova289aea2018-09-17 15:26:23 -070023
Mikhail Naganov43c386c2018-09-19 12:38:29 -070024#include <hidl/Status.h>
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>
32#include "Serializer.h"
33#include "TypeConverter.h"
François Gaffief4ad6e52015-11-19 16:59:57 +010034
35namespace android {
36
Mikhail Naganova289aea2018-09-17 15:26:23 -070037namespace {
François Gaffief4ad6e52015-11-19 16:59:57 +010038
Mikhail Naganov43c386c2018-09-19 12:38:29 -070039// TODO(mnaganov): Consider finding an alternative for using HIDL code.
40using hardware::Return;
41using hardware::Status;
François Gaffief4ad6e52015-11-19 16:59:57 +010042using utilities::convertTo;
43
Mikhail Naganova289aea2018-09-17 15:26:23 -070044template<typename E, typename C>
Mikhail Naganov778bc1f2018-09-14 16:28:52 -070045struct AndroidCollectionTraits {
Mikhail Naganov43c386c2018-09-19 12:38:29 -070046 typedef sp<E> Element;
Mikhail Naganova289aea2018-09-17 15:26:23 -070047 typedef C Collection;
48 typedef void* PtrSerializingCtx;
Mikhail Naganov43c386c2018-09-19 12:38:29 -070049
50 static status_t addElementToCollection(const Element &element, Collection *collection) {
51 return collection->add(element) >= 0 ? NO_ERROR : BAD_VALUE;
52 }
Mikhail Naganova289aea2018-09-17 15:26:23 -070053};
François Gaffiec9d7c4e2016-01-22 13:54:30 +010054
Mikhail Naganov778bc1f2018-09-14 16:28:52 -070055template<typename C>
56struct StdCollectionTraits {
57 typedef C Collection;
58 typedef typename C::value_type Element;
59 typedef void* PtrSerializingCtx;
60
61 static status_t addElementToCollection(const Element &element, Collection *collection) {
62 auto pair = collection->insert(element);
63 return pair.second ? NO_ERROR : BAD_VALUE;
64 }
65};
66
67struct AudioGainTraits : public AndroidCollectionTraits<AudioGain, AudioGainCollection>
François Gaffiec9d7c4e2016-01-22 13:54:30 +010068{
Mikhail Naganova289aea2018-09-17 15:26:23 -070069 static constexpr const char *tag = "gain";
70 static constexpr const char *collectionTag = "gains";
71
72 struct Attributes
73 {
74 /** gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
75 static constexpr const char *mode = "mode";
76 /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
77 static constexpr const char *channelMask = "channel_mask";
78 static constexpr const char *minValueMB = "minValueMB"; /**< min value in millibel. */
79 static constexpr const char *maxValueMB = "maxValueMB"; /**< max value in millibel. */
80 /** default value in millibel. */
81 static constexpr const char *defaultValueMB = "defaultValueMB";
82 static constexpr const char *stepValueMB = "stepValueMB"; /**< step value in millibel. */
83 /** needed if mode AUDIO_GAIN_MODE_RAMP. */
84 static constexpr const char *minRampMs = "minRampMs";
85 /** needed if mode AUDIO_GAIN_MODE_RAMP. */
86 static constexpr const char *maxRampMs = "maxRampMs";
87 };
88
Mikhail Naganov43c386c2018-09-19 12:38:29 -070089 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
Mikhail Naganova289aea2018-09-17 15:26:23 -070090 // No children
91};
92
93// A profile section contains a name, one audio format and the list of supported sampling rates
94// and channel masks for this format
Mikhail Naganov778bc1f2018-09-14 16:28:52 -070095struct AudioProfileTraits : public AndroidCollectionTraits<AudioProfile, AudioProfileVector>
Mikhail Naganova289aea2018-09-17 15:26:23 -070096{
97 static constexpr const char *tag = "profile";
98 static constexpr const char *collectionTag = "profiles";
99
100 struct Attributes
101 {
102 static constexpr const char *samplingRates = "samplingRates";
103 static constexpr const char *format = "format";
104 static constexpr const char *channelMasks = "channelMasks";
105 };
106
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700107 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700108};
109
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700110struct MixPortTraits : public AndroidCollectionTraits<IOProfile, IOProfileCollection>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700111{
112 static constexpr const char *tag = "mixPort";
113 static constexpr const char *collectionTag = "mixPorts";
114
115 struct Attributes
116 {
117 static constexpr const char *name = "name";
118 static constexpr const char *role = "role";
119 static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
120 static constexpr const char *flags = "flags";
121 static constexpr const char *maxOpenCount = "maxOpenCount";
122 static constexpr const char *maxActiveCount = "maxActiveCount";
123 };
124
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700125 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700126 // Children: GainTraits
127};
128
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700129struct DevicePortTraits : public AndroidCollectionTraits<DeviceDescriptor, DeviceVector>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700130{
131 static constexpr const char *tag = "devicePort";
132 static constexpr const char *collectionTag = "devicePorts";
133
134 struct Attributes
135 {
136 /** <device tag name>: any string without space. */
137 static constexpr const char *tagName = "tagName";
138 static constexpr const char *type = "type"; /**< <device type>. */
139 static constexpr const char *role = "role"; /**< <device role: sink or source>. */
140 static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
141 /** optional: device address, char string less than 64. */
142 static constexpr const char *address = "address";
Aniket Kumar Lata4e464702019-01-10 23:38:46 -0800143 /** optional: the list of encoded audio formats that are known to be supported. */
144 static constexpr const char *encodedFormats = "encodedFormats";
Mikhail Naganova289aea2018-09-17 15:26:23 -0700145 };
146
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700147 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700148 // Children: GainTraits (optional)
149};
150
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700151struct RouteTraits : public AndroidCollectionTraits<AudioRoute, AudioRouteVector>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700152{
153 static constexpr const char *tag = "route";
154 static constexpr const char *collectionTag = "routes";
155
156 struct Attributes
157 {
158 static constexpr const char *type = "type"; /**< <route type>: mix or mux. */
159 static constexpr const char *typeMix = "mix"; /**< type attribute mix value. */
160 static constexpr const char *sink = "sink"; /**< <sink: involved in this route>. */
161 /** sources: all source that can be involved in this route. */
162 static constexpr const char *sources = "sources";
163 };
164
165 typedef HwModule *PtrSerializingCtx;
166
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700167 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700168};
169
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700170struct ModuleTraits : public AndroidCollectionTraits<HwModule, HwModuleCollection>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700171{
172 static constexpr const char *tag = "module";
173 static constexpr const char *collectionTag = "modules";
174
175 static constexpr const char *childAttachedDevicesTag = "attachedDevices";
176 static constexpr const char *childAttachedDeviceTag = "item";
177 static constexpr const char *childDefaultOutputDeviceTag = "defaultOutputDevice";
178
179 struct Attributes
180 {
181 static constexpr const char *name = "name";
182 static constexpr const char *version = "halVersion";
183 };
184
185 typedef AudioPolicyConfig *PtrSerializingCtx;
186
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700187 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
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{
194 static constexpr const char *tag = "globalConfiguration";
195
196 struct Attributes
197 {
198 static constexpr const char *speakerDrcEnabled = "speaker_drc_enabled";
199 };
200
201 static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
202};
203
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700204struct VolumeTraits : public AndroidCollectionTraits<VolumeCurve, VolumeCurvesCollection>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700205{
206 static constexpr const char *tag = "volume";
207 static constexpr const char *collectionTag = "volumes";
208 static constexpr const char *volumePointTag = "point";
209 static constexpr const char *referenceTag = "reference";
210
211 struct Attributes
212 {
213 static constexpr const char *stream = "stream";
214 static constexpr const char *deviceCategory = "deviceCategory";
215 static constexpr const char *reference = "ref";
216 static constexpr const char *referenceName = "name";
217 };
218
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700219 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700220 // No Children
221};
222
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700223struct SurroundSoundTraits
224{
225 static constexpr const char *tag = "surroundSound";
226
227 static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
228 // Children: SurroundSoundFormatTraits
229};
230
231struct SurroundSoundFormatTraits : public StdCollectionTraits<AudioPolicyConfig::SurroundFormats>
232{
233 static constexpr const char *tag = "format";
234 static constexpr const char *collectionTag = "formats";
235
236 struct Attributes
237 {
238 static constexpr const char *name = "name";
239 static constexpr const char *subformats = "subformats";
240 };
241
242 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
243};
244
Mikhail Naganova289aea2018-09-17 15:26:23 -0700245class PolicySerializer
246{
247public:
248 PolicySerializer() : mVersion{std::to_string(gMajor) + "." + std::to_string(gMinor)}
249 {
250 ALOGV("%s: Version=%s Root=%s", __func__, mVersion.c_str(), rootName);
François Gaffiec9d7c4e2016-01-22 13:54:30 +0100251 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700252 status_t deserialize(const char *configFile, AudioPolicyConfig *config);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700253
254private:
255 static constexpr const char *rootName = "audioPolicyConfiguration";
256 static constexpr const char *versionAttribute = "version";
257 static constexpr uint32_t gMajor = 1; /**< the major number of the policy xml format version. */
258 static constexpr uint32_t gMinor = 0; /**< the minor number of the policy xml format version. */
259
260 typedef AudioPolicyConfig Element;
261
262 const std::string mVersion;
263
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700264 // Children: ModulesTraits, VolumeTraits, SurroundSoundTraits (optional)
Mikhail Naganova289aea2018-09-17 15:26:23 -0700265};
266
267template <class T>
268constexpr void (*xmlDeleter)(T* t);
269template <>
270constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
Stephen Hinese754a452018-09-20 17:08:23 -0700271// http://b/111067277 - Add back constexpr when we switch to C++17.
Mikhail Naganova289aea2018-09-17 15:26:23 -0700272template <>
Stephen Hinese754a452018-09-20 17:08:23 -0700273auto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };
Mikhail Naganova289aea2018-09-17 15:26:23 -0700274
275/** @return a unique_ptr with the correct deleter for the libxml2 object. */
276template <class T>
277constexpr auto make_xmlUnique(T *t) {
278 // Wrap deleter in lambda to enable empty base optimization
279 auto deleter = [](T *t) { xmlDeleter<T>(t); };
280 return std::unique_ptr<T, decltype(deleter)>{t, deleter};
281}
282
283std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
284{
285 auto xmlValue = make_xmlUnique(xmlGetProp(cur, reinterpret_cast<const xmlChar*>(attribute)));
286 if (xmlValue == nullptr) {
287 return "";
288 }
289 std::string value(reinterpret_cast<const char*>(xmlValue.get()));
290 return value;
François Gaffiec9d7c4e2016-01-22 13:54:30 +0100291}
François Gaffief4ad6e52015-11-19 16:59:57 +0100292
293template <class Trait>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700294const xmlNode* getReference(const xmlNode *cur, const std::string &refName)
François Gaffief4ad6e52015-11-19 16:59:57 +0100295{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700296 for (; cur != NULL; cur = cur->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700297 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700298 for (const xmlNode *child = cur->children; child != NULL; child = child->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700299 if ((!xmlStrcmp(child->name,
300 reinterpret_cast<const xmlChar*>(Trait::referenceTag)))) {
301 std::string name = getXmlAttribute(child, Trait::Attributes::referenceName);
302 if (refName == name) {
303 return child;
304 }
305 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700306 }
307 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700308 }
309 return NULL;
310}
311
312template <class Trait>
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700313status_t deserializeCollection(const xmlNode *cur,
Mikhail Naganova289aea2018-09-17 15:26:23 -0700314 typename Trait::Collection *collection,
315 typename Trait::PtrSerializingCtx serializingContext)
316{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700317 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
318 const xmlNode *child = NULL;
319 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
320 child = cur->xmlChildrenNode;
321 } else if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
322 child = cur;
François Gaffief4ad6e52015-11-19 16:59:57 +0100323 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700324 for (; child != NULL; child = child->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700325 if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700326 auto element = Trait::deserialize(child, serializingContext);
327 if (element.isOk()) {
328 status_t status = Trait::addElementToCollection(element, collection);
329 if (status != NO_ERROR) {
330 ALOGE("%s: could not add element to %s collection", __func__,
331 Trait::collectionTag);
332 return status;
333 }
334 } else {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700335 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100336 }
337 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100338 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700339 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
François Gaffied1ab2bd2015-12-02 18:20:06 +0100340 return NO_ERROR;
341 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100342 }
François Gaffied1ab2bd2015-12-02 18:20:06 +0100343 return NO_ERROR;
François Gaffief4ad6e52015-11-19 16:59:57 +0100344}
345
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700346Return<AudioGainTraits::Element> AudioGainTraits::deserialize(const xmlNode *cur,
347 PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100348{
349 static uint32_t index = 0;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700350 Element gain = new AudioGain(index++, true);
François Gaffief4ad6e52015-11-19 16:59:57 +0100351
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700352 std::string mode = getXmlAttribute(cur, Attributes::mode);
François Gaffief4ad6e52015-11-19 16:59:57 +0100353 if (!mode.empty()) {
354 gain->setMode(GainModeConverter::maskFromString(mode));
355 }
356
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700357 std::string channelsLiteral = getXmlAttribute(cur, Attributes::channelMask);
François Gaffief4ad6e52015-11-19 16:59:57 +0100358 if (!channelsLiteral.empty()) {
359 gain->setChannelMask(channelMaskFromString(channelsLiteral));
360 }
361
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700362 std::string minValueMBLiteral = getXmlAttribute(cur, Attributes::minValueMB);
Kevin Rocard575bb3a2017-10-27 16:49:20 -0700363 int32_t minValueMB;
François Gaffief4ad6e52015-11-19 16:59:57 +0100364 if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
365 gain->setMinValueInMb(minValueMB);
366 }
367
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700368 std::string maxValueMBLiteral = getXmlAttribute(cur, Attributes::maxValueMB);
Kevin Rocard575bb3a2017-10-27 16:49:20 -0700369 int32_t maxValueMB;
François Gaffief4ad6e52015-11-19 16:59:57 +0100370 if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
371 gain->setMaxValueInMb(maxValueMB);
372 }
373
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700374 std::string defaultValueMBLiteral = getXmlAttribute(cur, Attributes::defaultValueMB);
Kevin Rocard575bb3a2017-10-27 16:49:20 -0700375 int32_t defaultValueMB;
François Gaffief4ad6e52015-11-19 16:59:57 +0100376 if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
377 gain->setDefaultValueInMb(defaultValueMB);
378 }
379
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700380 std::string stepValueMBLiteral = getXmlAttribute(cur, Attributes::stepValueMB);
François Gaffief4ad6e52015-11-19 16:59:57 +0100381 uint32_t stepValueMB;
382 if (!stepValueMBLiteral.empty() && convertTo(stepValueMBLiteral, stepValueMB)) {
383 gain->setStepValueInMb(stepValueMB);
384 }
385
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700386 std::string minRampMsLiteral = getXmlAttribute(cur, Attributes::minRampMs);
François Gaffief4ad6e52015-11-19 16:59:57 +0100387 uint32_t minRampMs;
388 if (!minRampMsLiteral.empty() && convertTo(minRampMsLiteral, minRampMs)) {
389 gain->setMinRampInMs(minRampMs);
390 }
391
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700392 std::string maxRampMsLiteral = getXmlAttribute(cur, Attributes::maxRampMs);
François Gaffief4ad6e52015-11-19 16:59:57 +0100393 uint32_t maxRampMs;
394 if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
395 gain->setMaxRampInMs(maxRampMs);
396 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700397 ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __func__,
François Gaffief4ad6e52015-11-19 16:59:57 +0100398 gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
399 gain->getMaxValueInMb());
400
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700401 if (gain->getMode() != 0) {
402 return gain;
403 } else {
404 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100405 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100406}
407
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700408Return<AudioProfileTraits::Element> AudioProfileTraits::deserialize(const xmlNode *cur,
409 PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100410{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700411 std::string samplingRates = getXmlAttribute(cur, Attributes::samplingRates);
412 std::string format = getXmlAttribute(cur, Attributes::format);
413 std::string channels = getXmlAttribute(cur, Attributes::channelMasks);
François Gaffief4ad6e52015-11-19 16:59:57 +0100414
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700415 Element profile = new AudioProfile(formatFromString(format, gDynamicFormat),
Mikhail Naganova289aea2018-09-17 15:26:23 -0700416 channelMasksFromString(channels, ","),
417 samplingRatesFromString(samplingRates, ","));
François Gaffief4ad6e52015-11-19 16:59:57 +0100418
419 profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
420 profile->setDynamicChannels(profile->getChannels().isEmpty());
421 profile->setDynamicRate(profile->getSampleRates().isEmpty());
422
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700423 return profile;
François Gaffief4ad6e52015-11-19 16:59:57 +0100424}
425
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700426Return<MixPortTraits::Element> MixPortTraits::deserialize(const xmlNode *child,
427 PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100428{
Mikhail Naganova289aea2018-09-17 15:26:23 -0700429 std::string name = getXmlAttribute(child, Attributes::name);
François Gaffief4ad6e52015-11-19 16:59:57 +0100430 if (name.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700431 ALOGE("%s: No %s found", __func__, Attributes::name);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700432 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100433 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700434 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::name, name.c_str());
435 std::string role = getXmlAttribute(child, Attributes::role);
François Gaffief4ad6e52015-11-19 16:59:57 +0100436 if (role.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700437 ALOGE("%s: No %s found", __func__, Attributes::role);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700438 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100439 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700440 ALOGV("%s: Role=%s", __func__, role.c_str());
441 audio_port_role_t portRole = (role == Attributes::roleSource) ?
442 AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
François Gaffief4ad6e52015-11-19 16:59:57 +0100443
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700444 Element mixPort = new IOProfile(String8(name.c_str()), portRole);
François Gaffief4ad6e52015-11-19 16:59:57 +0100445
446 AudioProfileTraits::Collection profiles;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700447 status_t status = deserializeCollection<AudioProfileTraits>(child, &profiles, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700448 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700449 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700450 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100451 if (profiles.isEmpty()) {
Mikhail Naganov21b43362018-06-04 10:37:09 -0700452 profiles.add(AudioProfile::createFullDynamic());
François Gaffief4ad6e52015-11-19 16:59:57 +0100453 }
454 mixPort->setAudioProfiles(profiles);
455
Mikhail Naganova289aea2018-09-17 15:26:23 -0700456 std::string flags = getXmlAttribute(child, Attributes::flags);
François Gaffief4ad6e52015-11-19 16:59:57 +0100457 if (!flags.empty()) {
458 // Source role
459 if (portRole == AUDIO_PORT_ROLE_SOURCE) {
460 mixPort->setFlags(OutputFlagConverter::maskFromString(flags));
461 } else {
462 // Sink role
463 mixPort->setFlags(InputFlagConverter::maskFromString(flags));
464 }
465 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700466 std::string maxOpenCount = getXmlAttribute(child, Attributes::maxOpenCount);
Eric Laurentae603172017-12-07 17:59:01 -0800467 if (!maxOpenCount.empty()) {
468 convertTo(maxOpenCount, mixPort->maxOpenCount);
469 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700470 std::string maxActiveCount = getXmlAttribute(child, Attributes::maxActiveCount);
Eric Laurentae603172017-12-07 17:59:01 -0800471 if (!maxActiveCount.empty()) {
472 convertTo(maxActiveCount, mixPort->maxActiveCount);
473 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100474 // Deserialize children
475 AudioGainTraits::Collection gains;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700476 status = deserializeCollection<AudioGainTraits>(child, &gains, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700477 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700478 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700479 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100480 mixPort->setGains(gains);
481
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700482 return mixPort;
François Gaffief4ad6e52015-11-19 16:59:57 +0100483}
484
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700485Return<DevicePortTraits::Element> DevicePortTraits::deserialize(const xmlNode *cur,
486 PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100487{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700488 std::string name = getXmlAttribute(cur, Attributes::tagName);
François Gaffief4ad6e52015-11-19 16:59:57 +0100489 if (name.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700490 ALOGE("%s: No %s found", __func__, Attributes::tagName);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700491 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100492 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700493 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::tagName, name.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700494 std::string typeName = getXmlAttribute(cur, Attributes::type);
François Gaffief4ad6e52015-11-19 16:59:57 +0100495 if (typeName.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700496 ALOGE("%s: no type for %s", __func__, name.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700497 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100498 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700499 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, typeName.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700500 std::string role = getXmlAttribute(cur, Attributes::role);
François Gaffief4ad6e52015-11-19 16:59:57 +0100501 if (role.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700502 ALOGE("%s: No %s found", __func__, Attributes::role);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700503 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100504 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700505 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::role, role.c_str());
François Gaffief4ad6e52015-11-19 16:59:57 +0100506 audio_port_role_t portRole = (role == Attributes::roleSource) ?
507 AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
508
509 audio_devices_t type = AUDIO_DEVICE_NONE;
Mikhail Naganov913d06c2016-11-01 12:49:22 -0700510 if (!deviceFromString(typeName, type) ||
François Gaffief4ad6e52015-11-19 16:59:57 +0100511 (!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
512 (!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700513 ALOGW("%s: bad type %08x", __func__, type);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700514 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100515 }
Aniket Kumar Lata4e464702019-01-10 23:38:46 -0800516 std::string encodedFormatsLiteral = getXmlAttribute(cur, Attributes::encodedFormats);
517 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::encodedFormats, encodedFormatsLiteral.c_str());
518 FormatVector encodedFormats;
519 if (!encodedFormatsLiteral.empty()) {
520 encodedFormats = formatsFromString(encodedFormatsLiteral, " ");
521 }
522 Element deviceDesc = new DeviceDescriptor(type, encodedFormats, String8(name.c_str()));
François Gaffief4ad6e52015-11-19 16:59:57 +0100523
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700524 std::string address = getXmlAttribute(cur, Attributes::address);
François Gaffief4ad6e52015-11-19 16:59:57 +0100525 if (!address.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700526 ALOGV("%s: address=%s for %s", __func__, address.c_str(), name.c_str());
François Gaffieaca677c2018-05-03 10:47:50 +0200527 deviceDesc->setAddress(String8(address.c_str()));
François Gaffief4ad6e52015-11-19 16:59:57 +0100528 }
529
530 AudioProfileTraits::Collection profiles;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700531 status_t status = deserializeCollection<AudioProfileTraits>(cur, &profiles, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700532 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700533 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700534 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100535 if (profiles.isEmpty()) {
Mikhail Naganov21b43362018-06-04 10:37:09 -0700536 profiles.add(AudioProfile::createFullDynamic());
François Gaffief4ad6e52015-11-19 16:59:57 +0100537 }
538 deviceDesc->setAudioProfiles(profiles);
539
540 // Deserialize AudioGain children
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700541 status = deserializeCollection<AudioGainTraits>(cur, &deviceDesc->mGains, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700542 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700543 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700544 }
545 ALOGV("%s: adding device tag %s type %08x address %s", __func__,
François Gaffieaca677c2018-05-03 10:47:50 +0200546 deviceDesc->getName().string(), type, deviceDesc->address().string());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700547 return deviceDesc;
François Gaffief4ad6e52015-11-19 16:59:57 +0100548}
549
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700550Return<RouteTraits::Element> RouteTraits::deserialize(const xmlNode *cur, PtrSerializingCtx ctx)
François Gaffief4ad6e52015-11-19 16:59:57 +0100551{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700552 std::string type = getXmlAttribute(cur, Attributes::type);
François Gaffief4ad6e52015-11-19 16:59:57 +0100553 if (type.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700554 ALOGE("%s: No %s found", __func__, Attributes::type);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700555 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100556 }
557 audio_route_type_t routeType = (type == Attributes::typeMix) ?
558 AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
559
Mikhail Naganova289aea2018-09-17 15:26:23 -0700560 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, type.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700561 Element route = new AudioRoute(routeType);
François Gaffief4ad6e52015-11-19 16:59:57 +0100562
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700563 std::string sinkAttr = getXmlAttribute(cur, Attributes::sink);
François Gaffief4ad6e52015-11-19 16:59:57 +0100564 if (sinkAttr.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700565 ALOGE("%s: No %s found", __func__, Attributes::sink);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700566 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100567 }
568 // Convert Sink name to port pointer
569 sp<AudioPort> sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
570 if (sink == NULL) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700571 ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700572 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100573 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700574 route->setSink(sink);
François Gaffief4ad6e52015-11-19 16:59:57 +0100575
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700576 std::string sourcesAttr = getXmlAttribute(cur, Attributes::sources);
François Gaffief4ad6e52015-11-19 16:59:57 +0100577 if (sourcesAttr.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700578 ALOGE("%s: No %s found", __func__, Attributes::sources);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700579 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100580 }
581 // Tokenize and Convert Sources name to port pointer
582 AudioPortVector sources;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700583 std::unique_ptr<char[]> sourcesLiteral{strndup(
584 sourcesAttr.c_str(), strlen(sourcesAttr.c_str()))};
585 char *devTag = strtok(sourcesLiteral.get(), ",");
François Gaffief4ad6e52015-11-19 16:59:57 +0100586 while (devTag != NULL) {
587 if (strlen(devTag) != 0) {
588 sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
589 if (source == NULL) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700590 ALOGE("%s: no source found with name=%s", __func__, devTag);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700591 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100592 }
593 sources.add(source);
594 }
595 devTag = strtok(NULL, ",");
596 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100597
Mikhail Naganova289aea2018-09-17 15:26:23 -0700598 sink->addRoute(route);
François Gaffief4ad6e52015-11-19 16:59:57 +0100599 for (size_t i = 0; i < sources.size(); i++) {
600 sp<AudioPort> source = sources.itemAt(i);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700601 source->addRoute(route);
François Gaffief4ad6e52015-11-19 16:59:57 +0100602 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700603 route->setSources(sources);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700604 return route;
François Gaffief4ad6e52015-11-19 16:59:57 +0100605}
606
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700607Return<ModuleTraits::Element> ModuleTraits::deserialize(const xmlNode *cur, PtrSerializingCtx ctx)
François Gaffief4ad6e52015-11-19 16:59:57 +0100608{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700609 std::string name = getXmlAttribute(cur, Attributes::name);
François Gaffief4ad6e52015-11-19 16:59:57 +0100610 if (name.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700611 ALOGE("%s: No %s found", __func__, Attributes::name);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700612 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100613 }
Mikhail Naganov9ee05402016-10-13 15:58:17 -0700614 uint32_t versionMajor = 0, versionMinor = 0;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700615 std::string versionLiteral = getXmlAttribute(cur, Attributes::version);
François Gaffief4ad6e52015-11-19 16:59:57 +0100616 if (!versionLiteral.empty()) {
Mikhail Naganov9ee05402016-10-13 15:58:17 -0700617 sscanf(versionLiteral.c_str(), "%u.%u", &versionMajor, &versionMinor);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700618 ALOGV("%s: mHalVersion = major %u minor %u", __func__,
Mikhail Naganov9ee05402016-10-13 15:58:17 -0700619 versionMajor, versionMajor);
François Gaffief4ad6e52015-11-19 16:59:57 +0100620 }
621
Mikhail Naganova289aea2018-09-17 15:26:23 -0700622 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::name, name.c_str());
François Gaffief4ad6e52015-11-19 16:59:57 +0100623
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700624 Element module = new HwModule(name.c_str(), versionMajor, versionMinor);
François Gaffief4ad6e52015-11-19 16:59:57 +0100625
626 // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
627 MixPortTraits::Collection mixPorts;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700628 status_t status = deserializeCollection<MixPortTraits>(cur, &mixPorts, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700629 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700630 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700631 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100632 module->setProfiles(mixPorts);
633
634 DevicePortTraits::Collection devicePorts;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700635 status = deserializeCollection<DevicePortTraits>(cur, &devicePorts, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700636 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700637 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700638 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100639 module->setDeclaredDevices(devicePorts);
640
641 RouteTraits::Collection routes;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700642 status = deserializeCollection<RouteTraits>(cur, &routes, module.get());
Mikhail Naganova289aea2018-09-17 15:26:23 -0700643 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700644 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700645 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100646 module->setRoutes(routes);
647
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700648 for (const xmlNode *children = cur->xmlChildrenNode; children != NULL;
649 children = children->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700650 if (!xmlStrcmp(children->name, reinterpret_cast<const xmlChar*>(childAttachedDevicesTag))) {
651 ALOGV("%s: %s %s found", __func__, tag, childAttachedDevicesTag);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700652 for (const xmlNode *child = children->xmlChildrenNode; child != NULL;
653 child = child->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700654 if (!xmlStrcmp(child->name,
655 reinterpret_cast<const xmlChar*>(childAttachedDeviceTag))) {
656 auto attachedDevice = make_xmlUnique(xmlNodeListGetString(
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700657 child->doc, child->xmlChildrenNode, 1));
Mikhail Naganova289aea2018-09-17 15:26:23 -0700658 if (attachedDevice != nullptr) {
659 ALOGV("%s: %s %s=%s", __func__, tag, childAttachedDeviceTag,
660 reinterpret_cast<const char*>(attachedDevice.get()));
661 sp<DeviceDescriptor> device = module->getDeclaredDevices().
662 getDeviceFromTagName(String8(reinterpret_cast<const char*>(
663 attachedDevice.get())));
François Gaffief4ad6e52015-11-19 16:59:57 +0100664 ctx->addAvailableDevice(device);
François Gaffief4ad6e52015-11-19 16:59:57 +0100665 }
666 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100667 }
668 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700669 if (!xmlStrcmp(children->name,
670 reinterpret_cast<const xmlChar*>(childDefaultOutputDeviceTag))) {
671 auto defaultOutputDevice = make_xmlUnique(xmlNodeListGetString(
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700672 children->doc, children->xmlChildrenNode, 1));
Mikhail Naganova289aea2018-09-17 15:26:23 -0700673 if (defaultOutputDevice != nullptr) {
674 ALOGV("%s: %s %s=%s", __func__, tag, childDefaultOutputDeviceTag,
675 reinterpret_cast<const char*>(defaultOutputDevice.get()));
676 sp<DeviceDescriptor> device = module->getDeclaredDevices().getDeviceFromTagName(
677 String8(reinterpret_cast<const char*>(defaultOutputDevice.get())));
François Gaffief4ad6e52015-11-19 16:59:57 +0100678 if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
679 ctx->setDefaultOutputDevice(device);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700680 ALOGV("%s: default is %08x",
681 __func__, ctx->getDefaultOutputDevice()->type());
François Gaffief4ad6e52015-11-19 16:59:57 +0100682 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100683 }
684 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100685 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700686 return module;
François Gaffief4ad6e52015-11-19 16:59:57 +0100687}
688
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700689status_t GlobalConfigTraits::deserialize(const xmlNode *root, AudioPolicyConfig *config)
François Gaffief4ad6e52015-11-19 16:59:57 +0100690{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700691 for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
692 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(tag))) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700693 std::string speakerDrcEnabled =
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700694 getXmlAttribute(cur, Attributes::speakerDrcEnabled);
François Gaffief4ad6e52015-11-19 16:59:57 +0100695 bool isSpeakerDrcEnabled;
696 if (!speakerDrcEnabled.empty() &&
Mikhail Naganova289aea2018-09-17 15:26:23 -0700697 convertTo<std::string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
698 config->setSpeakerDrcEnabled(isSpeakerDrcEnabled);
François Gaffief4ad6e52015-11-19 16:59:57 +0100699 }
700 return NO_ERROR;
701 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100702 }
703 return NO_ERROR;
704}
705
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700706Return<VolumeTraits::Element> VolumeTraits::deserialize(const xmlNode *cur,
707 PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100708{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700709 std::string streamTypeLiteral = getXmlAttribute(cur, Attributes::stream);
François Gaffief4ad6e52015-11-19 16:59:57 +0100710 if (streamTypeLiteral.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700711 ALOGE("%s: No %s found", __func__, Attributes::stream);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700712 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100713 }
714 audio_stream_type_t streamType;
715 if (!StreamTypeConverter::fromString(streamTypeLiteral, streamType)) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700716 ALOGE("%s: Invalid %s", __func__, Attributes::stream);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700717 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100718 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700719 std::string deviceCategoryLiteral = getXmlAttribute(cur, Attributes::deviceCategory);
François Gaffief4ad6e52015-11-19 16:59:57 +0100720 if (deviceCategoryLiteral.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700721 ALOGE("%s: No %s found", __func__, Attributes::deviceCategory);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700722 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100723 }
724 device_category deviceCategory;
725 if (!DeviceCategoryConverter::fromString(deviceCategoryLiteral, deviceCategory)) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700726 ALOGE("%s: Invalid %s=%s", __func__, Attributes::deviceCategory,
François Gaffief4ad6e52015-11-19 16:59:57 +0100727 deviceCategoryLiteral.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700728 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100729 }
François Gaffiec9d7c4e2016-01-22 13:54:30 +0100730
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700731 std::string referenceName = getXmlAttribute(cur, Attributes::reference);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700732 const xmlNode *ref = NULL;
François Gaffiec9d7c4e2016-01-22 13:54:30 +0100733 if (!referenceName.empty()) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700734 ref = getReference<VolumeTraits>(cur->parent, referenceName);
François Gaffiec9d7c4e2016-01-22 13:54:30 +0100735 if (ref == NULL) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700736 ALOGE("%s: No reference Ptr found for %s", __func__, referenceName.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700737 return Status::fromStatusT(BAD_VALUE);
François Gaffiec9d7c4e2016-01-22 13:54:30 +0100738 }
739 }
740
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700741 Element volCurve = new VolumeCurve(deviceCategory, streamType);
François Gaffied1ab2bd2015-12-02 18:20:06 +0100742
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700743 for (const xmlNode *child = referenceName.empty() ? cur->xmlChildrenNode : ref->xmlChildrenNode;
744 child != NULL; child = child->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700745 if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(volumePointTag))) {
746 auto pointDefinition = make_xmlUnique(xmlNodeListGetString(
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700747 child->doc, child->xmlChildrenNode, 1));
Mikhail Naganova289aea2018-09-17 15:26:23 -0700748 if (pointDefinition == nullptr) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700749 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100750 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700751 ALOGV("%s: %s=%s",
752 __func__, tag, reinterpret_cast<const char*>(pointDefinition.get()));
François Gaffie2b167172018-06-04 16:05:14 +0200753 std::vector<int32_t> point;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700754 collectionFromString<DefaultTraits<int32_t>>(
755 reinterpret_cast<const char*>(pointDefinition.get()), point, ",");
François Gaffief4ad6e52015-11-19 16:59:57 +0100756 if (point.size() != 2) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700757 ALOGE("%s: Invalid %s: %s", __func__, volumePointTag,
758 reinterpret_cast<const char*>(pointDefinition.get()));
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700759 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100760 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700761 volCurve->add(CurvePoint(point[0], point[1]));
François Gaffief4ad6e52015-11-19 16:59:57 +0100762 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100763 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700764 return volCurve;
François Gaffief4ad6e52015-11-19 16:59:57 +0100765}
766
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700767status_t SurroundSoundTraits::deserialize(const xmlNode *root, AudioPolicyConfig *config)
768{
769 config->setDefaultSurroundFormats();
770
771 for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
772 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(tag))) {
773 AudioPolicyConfig::SurroundFormats formats;
774 status_t status = deserializeCollection<SurroundSoundFormatTraits>(
775 cur, &formats, nullptr);
776 if (status == NO_ERROR) {
777 config->setSurroundFormats(formats);
778 }
779 return NO_ERROR;
780 }
781 }
782 return NO_ERROR;
783}
784
785Return<SurroundSoundFormatTraits::Element> SurroundSoundFormatTraits::deserialize(
786 const xmlNode *cur, PtrSerializingCtx /*serializingContext*/)
787{
788 std::string formatLiteral = getXmlAttribute(cur, Attributes::name);
789 if (formatLiteral.empty()) {
790 ALOGE("%s: No %s found for a surround format", __func__, Attributes::name);
791 return Status::fromStatusT(BAD_VALUE);
792 }
793 audio_format_t format = formatFromString(formatLiteral);
794 if (format == AUDIO_FORMAT_DEFAULT) {
795 ALOGE("%s: Unrecognized format %s", __func__, formatLiteral.c_str());
796 return Status::fromStatusT(BAD_VALUE);
797 }
798 Element pair = std::make_pair(format, Collection::mapped_type{});
799
800 std::string subformatsLiteral = getXmlAttribute(cur, Attributes::subformats);
801 if (subformatsLiteral.empty()) return pair;
802 FormatVector subformats = formatsFromString(subformatsLiteral, " ");
803 for (const auto& subformat : subformats) {
804 auto result = pair.second.insert(subformat);
805 if (!result.second) {
806 ALOGE("%s: could not add subformat %x to collection", __func__, subformat);
807 return Status::fromStatusT(BAD_VALUE);
808 }
809 }
810 return pair;
811}
812
Mikhail Naganova289aea2018-09-17 15:26:23 -0700813status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config)
François Gaffief4ad6e52015-11-19 16:59:57 +0100814{
Mikhail Naganova289aea2018-09-17 15:26:23 -0700815 auto doc = make_xmlUnique(xmlParseFile(configFile));
816 if (doc == nullptr) {
817 ALOGE("%s: Could not parse %s document.", __func__, configFile);
François Gaffief4ad6e52015-11-19 16:59:57 +0100818 return BAD_VALUE;
819 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700820 xmlNodePtr root = xmlDocGetRootElement(doc.get());
821 if (root == NULL) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700822 ALOGE("%s: Could not parse %s document: empty.", __func__, configFile);
François Gaffief4ad6e52015-11-19 16:59:57 +0100823 return BAD_VALUE;
824 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700825 if (xmlXIncludeProcess(doc.get()) < 0) {
826 ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __func__, configFile);
François Gaffief4ad6e52015-11-19 16:59:57 +0100827 }
828
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700829 if (xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>(rootName))) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700830 ALOGE("%s: No %s root element found in xml data %s.", __func__, rootName,
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700831 reinterpret_cast<const char*>(root->name));
François Gaffief4ad6e52015-11-19 16:59:57 +0100832 return BAD_VALUE;
833 }
834
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700835 std::string version = getXmlAttribute(root, versionAttribute);
François Gaffief4ad6e52015-11-19 16:59:57 +0100836 if (version.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700837 ALOGE("%s: No version found in root node %s", __func__, rootName);
François Gaffief4ad6e52015-11-19 16:59:57 +0100838 return BAD_VALUE;
839 }
840 if (version != mVersion) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700841 ALOGE("%s: Version does not match; expect %s got %s", __func__, mVersion.c_str(),
François Gaffief4ad6e52015-11-19 16:59:57 +0100842 version.c_str());
843 return BAD_VALUE;
844 }
845 // Lets deserialize children
846 // Modules
847 ModuleTraits::Collection modules;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700848 status_t status = deserializeCollection<ModuleTraits>(root, &modules, config);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700849 if (status != NO_ERROR) {
850 return status;
851 }
852 config->setHwModules(modules);
François Gaffief4ad6e52015-11-19 16:59:57 +0100853
854 // deserialize volume section
855 VolumeTraits::Collection volumes;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700856 status = deserializeCollection<VolumeTraits>(root, &volumes, config);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700857 if (status != NO_ERROR) {
858 return status;
859 }
860 config->setVolumes(volumes);
François Gaffief4ad6e52015-11-19 16:59:57 +0100861
862 // Global Configuration
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700863 GlobalConfigTraits::deserialize(root, config);
François Gaffief4ad6e52015-11-19 16:59:57 +0100864
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700865 // Surround configuration
866 SurroundSoundTraits::deserialize(root, config);
867
François Gaffief4ad6e52015-11-19 16:59:57 +0100868 return android::OK;
869}
870
Mikhail Naganova289aea2018-09-17 15:26:23 -0700871} // namespace
872
873status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config)
874{
875 PolicySerializer serializer;
876 return serializer.deserialize(fileName, config);
877}
878
Mikhail Naganov1b2a7942017-12-08 10:18:09 -0800879} // namespace android