blob: ef1ddf71fd51c3e54f378db926b4c8467f0d3fc2 [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
François Gaffie43c73442018-11-08 08:21:55 +010067struct AudioGainTraits : public AndroidCollectionTraits<AudioGain, AudioGains>
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";
François Gaffie43c73442018-11-08 08:21:55 +010087 /** needed to allow use setPortGain instead of setStreamVolume. */
88 static constexpr const char *useForVolume = "useForVolume";
89
Mikhail Naganova289aea2018-09-17 15:26:23 -070090 };
91
Mikhail Naganov43c386c2018-09-19 12:38:29 -070092 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
Mikhail Naganova289aea2018-09-17 15:26:23 -070093 // No children
94};
95
96// A profile section contains a name, one audio format and the list of supported sampling rates
97// and channel masks for this format
Mikhail Naganov778bc1f2018-09-14 16:28:52 -070098struct AudioProfileTraits : public AndroidCollectionTraits<AudioProfile, AudioProfileVector>
Mikhail Naganova289aea2018-09-17 15:26:23 -070099{
100 static constexpr const char *tag = "profile";
101 static constexpr const char *collectionTag = "profiles";
102
103 struct Attributes
104 {
105 static constexpr const char *samplingRates = "samplingRates";
106 static constexpr const char *format = "format";
107 static constexpr const char *channelMasks = "channelMasks";
108 };
109
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700110 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700111};
112
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700113struct MixPortTraits : public AndroidCollectionTraits<IOProfile, IOProfileCollection>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700114{
115 static constexpr const char *tag = "mixPort";
116 static constexpr const char *collectionTag = "mixPorts";
117
118 struct Attributes
119 {
120 static constexpr const char *name = "name";
121 static constexpr const char *role = "role";
122 static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
123 static constexpr const char *flags = "flags";
124 static constexpr const char *maxOpenCount = "maxOpenCount";
125 static constexpr const char *maxActiveCount = "maxActiveCount";
126 };
127
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700128 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700129 // Children: GainTraits
130};
131
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700132struct DevicePortTraits : public AndroidCollectionTraits<DeviceDescriptor, DeviceVector>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700133{
134 static constexpr const char *tag = "devicePort";
135 static constexpr const char *collectionTag = "devicePorts";
136
137 struct Attributes
138 {
139 /** <device tag name>: any string without space. */
140 static constexpr const char *tagName = "tagName";
141 static constexpr const char *type = "type"; /**< <device type>. */
142 static constexpr const char *role = "role"; /**< <device role: sink or source>. */
143 static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
144 /** optional: device address, char string less than 64. */
145 static constexpr const char *address = "address";
Aniket Kumar Lata4e464702019-01-10 23:38:46 -0800146 /** optional: the list of encoded audio formats that are known to be supported. */
147 static constexpr const char *encodedFormats = "encodedFormats";
Mikhail Naganova289aea2018-09-17 15:26:23 -0700148 };
149
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700150 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
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;
169
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700170 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700171};
172
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700173struct ModuleTraits : public AndroidCollectionTraits<HwModule, HwModuleCollection>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700174{
175 static constexpr const char *tag = "module";
176 static constexpr const char *collectionTag = "modules";
177
178 static constexpr const char *childAttachedDevicesTag = "attachedDevices";
179 static constexpr const char *childAttachedDeviceTag = "item";
180 static constexpr const char *childDefaultOutputDeviceTag = "defaultOutputDevice";
181
182 struct Attributes
183 {
184 static constexpr const char *name = "name";
185 static constexpr const char *version = "halVersion";
186 };
187
188 typedef AudioPolicyConfig *PtrSerializingCtx;
189
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700190 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700191 // Children: mixPortTraits, devicePortTraits, and routeTraits
192 // Need to call deserialize on each child
193};
194
195struct GlobalConfigTraits
196{
197 static constexpr const char *tag = "globalConfiguration";
198
199 struct Attributes
200 {
201 static constexpr const char *speakerDrcEnabled = "speaker_drc_enabled";
202 };
203
204 static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
205};
206
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700207struct SurroundSoundTraits
208{
209 static constexpr const char *tag = "surroundSound";
210
211 static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
212 // Children: SurroundSoundFormatTraits
213};
214
215struct SurroundSoundFormatTraits : public StdCollectionTraits<AudioPolicyConfig::SurroundFormats>
216{
217 static constexpr const char *tag = "format";
218 static constexpr const char *collectionTag = "formats";
219
220 struct Attributes
221 {
222 static constexpr const char *name = "name";
223 static constexpr const char *subformats = "subformats";
224 };
225
226 static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
227};
228
Mikhail Naganova289aea2018-09-17 15:26:23 -0700229class PolicySerializer
230{
231public:
232 PolicySerializer() : mVersion{std::to_string(gMajor) + "." + std::to_string(gMinor)}
233 {
234 ALOGV("%s: Version=%s Root=%s", __func__, mVersion.c_str(), rootName);
François Gaffiec9d7c4e2016-01-22 13:54:30 +0100235 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700236 status_t deserialize(const char *configFile, AudioPolicyConfig *config);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700237
238private:
239 static constexpr const char *rootName = "audioPolicyConfiguration";
240 static constexpr const char *versionAttribute = "version";
241 static constexpr uint32_t gMajor = 1; /**< the major number of the policy xml format version. */
242 static constexpr uint32_t gMinor = 0; /**< the minor number of the policy xml format version. */
243
244 typedef AudioPolicyConfig Element;
245
246 const std::string mVersion;
247
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700248 // Children: ModulesTraits, VolumeTraits, SurroundSoundTraits (optional)
Mikhail Naganova289aea2018-09-17 15:26:23 -0700249};
250
251template <class T>
252constexpr void (*xmlDeleter)(T* t);
253template <>
254constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
Stephen Hinese754a452018-09-20 17:08:23 -0700255// http://b/111067277 - Add back constexpr when we switch to C++17.
Mikhail Naganova289aea2018-09-17 15:26:23 -0700256template <>
Stephen Hinese754a452018-09-20 17:08:23 -0700257auto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };
Mikhail Naganova289aea2018-09-17 15:26:23 -0700258
259/** @return a unique_ptr with the correct deleter for the libxml2 object. */
260template <class T>
261constexpr auto make_xmlUnique(T *t) {
262 // Wrap deleter in lambda to enable empty base optimization
263 auto deleter = [](T *t) { xmlDeleter<T>(t); };
264 return std::unique_ptr<T, decltype(deleter)>{t, deleter};
265}
266
267std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
268{
269 auto xmlValue = make_xmlUnique(xmlGetProp(cur, reinterpret_cast<const xmlChar*>(attribute)));
270 if (xmlValue == nullptr) {
271 return "";
272 }
273 std::string value(reinterpret_cast<const char*>(xmlValue.get()));
274 return value;
François Gaffiec9d7c4e2016-01-22 13:54:30 +0100275}
François Gaffief4ad6e52015-11-19 16:59:57 +0100276
277template <class Trait>
Mikhail Naganova289aea2018-09-17 15:26:23 -0700278const xmlNode* getReference(const xmlNode *cur, const std::string &refName)
François Gaffief4ad6e52015-11-19 16:59:57 +0100279{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700280 for (; cur != NULL; cur = cur->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700281 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700282 for (const xmlNode *child = cur->children; child != NULL; child = child->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700283 if ((!xmlStrcmp(child->name,
284 reinterpret_cast<const xmlChar*>(Trait::referenceTag)))) {
285 std::string name = getXmlAttribute(child, Trait::Attributes::referenceName);
286 if (refName == name) {
287 return child;
288 }
289 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700290 }
291 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700292 }
293 return NULL;
294}
295
296template <class Trait>
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700297status_t deserializeCollection(const xmlNode *cur,
Mikhail Naganova289aea2018-09-17 15:26:23 -0700298 typename Trait::Collection *collection,
299 typename Trait::PtrSerializingCtx serializingContext)
300{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700301 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
302 const xmlNode *child = NULL;
303 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
304 child = cur->xmlChildrenNode;
305 } else if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
306 child = cur;
François Gaffief4ad6e52015-11-19 16:59:57 +0100307 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700308 for (; child != NULL; child = child->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700309 if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700310 auto element = Trait::deserialize(child, serializingContext);
311 if (element.isOk()) {
312 status_t status = Trait::addElementToCollection(element, collection);
313 if (status != NO_ERROR) {
314 ALOGE("%s: could not add element to %s collection", __func__,
315 Trait::collectionTag);
316 return status;
317 }
318 } else {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700319 return BAD_VALUE;
François Gaffief4ad6e52015-11-19 16:59:57 +0100320 }
321 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100322 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700323 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
François Gaffied1ab2bd2015-12-02 18:20:06 +0100324 return NO_ERROR;
325 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100326 }
François Gaffied1ab2bd2015-12-02 18:20:06 +0100327 return NO_ERROR;
François Gaffief4ad6e52015-11-19 16:59:57 +0100328}
329
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700330Return<AudioGainTraits::Element> AudioGainTraits::deserialize(const xmlNode *cur,
331 PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100332{
333 static uint32_t index = 0;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700334 Element gain = new AudioGain(index++, true);
François Gaffief4ad6e52015-11-19 16:59:57 +0100335
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700336 std::string mode = getXmlAttribute(cur, Attributes::mode);
François Gaffief4ad6e52015-11-19 16:59:57 +0100337 if (!mode.empty()) {
338 gain->setMode(GainModeConverter::maskFromString(mode));
339 }
340
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700341 std::string channelsLiteral = getXmlAttribute(cur, Attributes::channelMask);
François Gaffief4ad6e52015-11-19 16:59:57 +0100342 if (!channelsLiteral.empty()) {
343 gain->setChannelMask(channelMaskFromString(channelsLiteral));
344 }
345
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700346 std::string minValueMBLiteral = getXmlAttribute(cur, Attributes::minValueMB);
Kevin Rocard575bb3a2017-10-27 16:49:20 -0700347 int32_t minValueMB;
François Gaffief4ad6e52015-11-19 16:59:57 +0100348 if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
349 gain->setMinValueInMb(minValueMB);
350 }
351
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700352 std::string maxValueMBLiteral = getXmlAttribute(cur, Attributes::maxValueMB);
Kevin Rocard575bb3a2017-10-27 16:49:20 -0700353 int32_t maxValueMB;
François Gaffief4ad6e52015-11-19 16:59:57 +0100354 if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
355 gain->setMaxValueInMb(maxValueMB);
356 }
357
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700358 std::string defaultValueMBLiteral = getXmlAttribute(cur, Attributes::defaultValueMB);
Kevin Rocard575bb3a2017-10-27 16:49:20 -0700359 int32_t defaultValueMB;
François Gaffief4ad6e52015-11-19 16:59:57 +0100360 if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
361 gain->setDefaultValueInMb(defaultValueMB);
362 }
363
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700364 std::string stepValueMBLiteral = getXmlAttribute(cur, Attributes::stepValueMB);
François Gaffief4ad6e52015-11-19 16:59:57 +0100365 uint32_t stepValueMB;
366 if (!stepValueMBLiteral.empty() && convertTo(stepValueMBLiteral, stepValueMB)) {
367 gain->setStepValueInMb(stepValueMB);
368 }
369
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700370 std::string minRampMsLiteral = getXmlAttribute(cur, Attributes::minRampMs);
François Gaffief4ad6e52015-11-19 16:59:57 +0100371 uint32_t minRampMs;
372 if (!minRampMsLiteral.empty() && convertTo(minRampMsLiteral, minRampMs)) {
373 gain->setMinRampInMs(minRampMs);
374 }
375
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700376 std::string maxRampMsLiteral = getXmlAttribute(cur, Attributes::maxRampMs);
François Gaffief4ad6e52015-11-19 16:59:57 +0100377 uint32_t maxRampMs;
378 if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
379 gain->setMaxRampInMs(maxRampMs);
380 }
François Gaffie43c73442018-11-08 08:21:55 +0100381 std::string useForVolumeLiteral = getXmlAttribute(cur, Attributes::useForVolume);
382 bool useForVolume = false;
383 if (!useForVolumeLiteral.empty() && convertTo(useForVolumeLiteral, useForVolume)) {
384 gain->setUseForVolume(useForVolume);
385 }
386 ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d UseForVolume: %d",
387 __func__, gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
388 gain->getMaxValueInMb(), useForVolume);
François Gaffief4ad6e52015-11-19 16:59:57 +0100389
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700390 if (gain->getMode() != 0) {
391 return gain;
392 } else {
393 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100394 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100395}
396
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700397Return<AudioProfileTraits::Element> AudioProfileTraits::deserialize(const xmlNode *cur,
398 PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100399{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700400 std::string samplingRates = getXmlAttribute(cur, Attributes::samplingRates);
401 std::string format = getXmlAttribute(cur, Attributes::format);
402 std::string channels = getXmlAttribute(cur, Attributes::channelMasks);
François Gaffief4ad6e52015-11-19 16:59:57 +0100403
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700404 Element profile = new AudioProfile(formatFromString(format, gDynamicFormat),
Mikhail Naganova289aea2018-09-17 15:26:23 -0700405 channelMasksFromString(channels, ","),
406 samplingRatesFromString(samplingRates, ","));
François Gaffief4ad6e52015-11-19 16:59:57 +0100407
408 profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
jiabin06e4bab2019-07-29 10:13:34 -0700409 profile->setDynamicChannels(profile->getChannels().empty());
410 profile->setDynamicRate(profile->getSampleRates().empty());
François Gaffief4ad6e52015-11-19 16:59:57 +0100411
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700412 return profile;
François Gaffief4ad6e52015-11-19 16:59:57 +0100413}
414
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700415Return<MixPortTraits::Element> MixPortTraits::deserialize(const xmlNode *child,
416 PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100417{
Mikhail Naganova289aea2018-09-17 15:26:23 -0700418 std::string name = getXmlAttribute(child, Attributes::name);
François Gaffief4ad6e52015-11-19 16:59:57 +0100419 if (name.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700420 ALOGE("%s: No %s found", __func__, Attributes::name);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700421 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100422 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700423 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::name, name.c_str());
424 std::string role = getXmlAttribute(child, Attributes::role);
François Gaffief4ad6e52015-11-19 16:59:57 +0100425 if (role.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700426 ALOGE("%s: No %s found", __func__, Attributes::role);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700427 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100428 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700429 ALOGV("%s: Role=%s", __func__, role.c_str());
430 audio_port_role_t portRole = (role == Attributes::roleSource) ?
431 AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
François Gaffief4ad6e52015-11-19 16:59:57 +0100432
jiabin5740f082019-08-19 15:08:30 -0700433 Element mixPort = new IOProfile(name, portRole);
François Gaffief4ad6e52015-11-19 16:59:57 +0100434
435 AudioProfileTraits::Collection profiles;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700436 status_t status = deserializeCollection<AudioProfileTraits>(child, &profiles, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700437 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700438 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700439 }
jiabin06e4bab2019-07-29 10:13:34 -0700440 if (profiles.empty()) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700441 profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
François Gaffief4ad6e52015-11-19 16:59:57 +0100442 }
jiabin3e277cc2019-09-10 14:27:34 -0700443 // The audio profiles are in order of listed in audio policy configuration file.
444 // Sort audio profiles accroding to the format.
445 sortAudioProfiles(profiles);
François Gaffief4ad6e52015-11-19 16:59:57 +0100446 mixPort->setAudioProfiles(profiles);
447
Mikhail Naganova289aea2018-09-17 15:26:23 -0700448 std::string flags = getXmlAttribute(child, Attributes::flags);
François Gaffief4ad6e52015-11-19 16:59:57 +0100449 if (!flags.empty()) {
450 // Source role
451 if (portRole == AUDIO_PORT_ROLE_SOURCE) {
452 mixPort->setFlags(OutputFlagConverter::maskFromString(flags));
453 } else {
454 // Sink role
455 mixPort->setFlags(InputFlagConverter::maskFromString(flags));
456 }
457 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700458 std::string maxOpenCount = getXmlAttribute(child, Attributes::maxOpenCount);
Eric Laurentae603172017-12-07 17:59:01 -0800459 if (!maxOpenCount.empty()) {
460 convertTo(maxOpenCount, mixPort->maxOpenCount);
461 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700462 std::string maxActiveCount = getXmlAttribute(child, Attributes::maxActiveCount);
Eric Laurentae603172017-12-07 17:59:01 -0800463 if (!maxActiveCount.empty()) {
464 convertTo(maxActiveCount, mixPort->maxActiveCount);
465 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100466 // Deserialize children
467 AudioGainTraits::Collection gains;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700468 status = deserializeCollection<AudioGainTraits>(child, &gains, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700469 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700470 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700471 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100472 mixPort->setGains(gains);
473
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700474 return mixPort;
François Gaffief4ad6e52015-11-19 16:59:57 +0100475}
476
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700477Return<DevicePortTraits::Element> DevicePortTraits::deserialize(const xmlNode *cur,
478 PtrSerializingCtx /*serializingContext*/)
François Gaffief4ad6e52015-11-19 16:59:57 +0100479{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700480 std::string name = getXmlAttribute(cur, Attributes::tagName);
François Gaffief4ad6e52015-11-19 16:59:57 +0100481 if (name.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700482 ALOGE("%s: No %s found", __func__, Attributes::tagName);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700483 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100484 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700485 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::tagName, name.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700486 std::string typeName = getXmlAttribute(cur, Attributes::type);
François Gaffief4ad6e52015-11-19 16:59:57 +0100487 if (typeName.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700488 ALOGE("%s: no type for %s", __func__, name.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700489 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100490 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700491 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, typeName.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700492 std::string role = getXmlAttribute(cur, Attributes::role);
François Gaffief4ad6e52015-11-19 16:59:57 +0100493 if (role.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700494 ALOGE("%s: No %s found", __func__, Attributes::role);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700495 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100496 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700497 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::role, role.c_str());
François Gaffief4ad6e52015-11-19 16:59:57 +0100498 audio_port_role_t portRole = (role == Attributes::roleSource) ?
499 AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
500
501 audio_devices_t type = AUDIO_DEVICE_NONE;
Mikhail Naganov913d06c2016-11-01 12:49:22 -0700502 if (!deviceFromString(typeName, type) ||
François Gaffief4ad6e52015-11-19 16:59:57 +0100503 (!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
504 (!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700505 ALOGW("%s: bad type %08x", __func__, type);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700506 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100507 }
Aniket Kumar Lata4e464702019-01-10 23:38:46 -0800508 std::string encodedFormatsLiteral = getXmlAttribute(cur, Attributes::encodedFormats);
509 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::encodedFormats, encodedFormatsLiteral.c_str());
510 FormatVector encodedFormats;
511 if (!encodedFormatsLiteral.empty()) {
512 encodedFormats = formatsFromString(encodedFormatsLiteral, " ");
513 }
jiabin5740f082019-08-19 15:08:30 -0700514 Element deviceDesc = new DeviceDescriptor(type, encodedFormats, name);
François Gaffief4ad6e52015-11-19 16:59:57 +0100515
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700516 std::string address = getXmlAttribute(cur, Attributes::address);
François Gaffief4ad6e52015-11-19 16:59:57 +0100517 if (!address.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700518 ALOGV("%s: address=%s for %s", __func__, address.c_str(), name.c_str());
François Gaffieaca677c2018-05-03 10:47:50 +0200519 deviceDesc->setAddress(String8(address.c_str()));
François Gaffief4ad6e52015-11-19 16:59:57 +0100520 }
521
522 AudioProfileTraits::Collection profiles;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700523 status_t status = deserializeCollection<AudioProfileTraits>(cur, &profiles, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700524 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700525 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700526 }
jiabin06e4bab2019-07-29 10:13:34 -0700527 if (profiles.empty()) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700528 profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
François Gaffief4ad6e52015-11-19 16:59:57 +0100529 }
jiabin3e277cc2019-09-10 14:27:34 -0700530 // The audio profiles are in order of listed in audio policy configuration file.
531 // Sort audio profiles accroding to the format.
532 sortAudioProfiles(profiles);
François Gaffief4ad6e52015-11-19 16:59:57 +0100533 deviceDesc->setAudioProfiles(profiles);
534
535 // Deserialize AudioGain children
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700536 status = deserializeCollection<AudioGainTraits>(cur, &deviceDesc->mGains, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700537 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700538 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700539 }
540 ALOGV("%s: adding device tag %s type %08x address %s", __func__,
jiabin5740f082019-08-19 15:08:30 -0700541 deviceDesc->getName().c_str(), type, deviceDesc->address().string());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700542 return deviceDesc;
François Gaffief4ad6e52015-11-19 16:59:57 +0100543}
544
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700545Return<RouteTraits::Element> RouteTraits::deserialize(const xmlNode *cur, PtrSerializingCtx ctx)
François Gaffief4ad6e52015-11-19 16:59:57 +0100546{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700547 std::string type = getXmlAttribute(cur, Attributes::type);
François Gaffief4ad6e52015-11-19 16:59:57 +0100548 if (type.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700549 ALOGE("%s: No %s found", __func__, Attributes::type);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700550 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100551 }
552 audio_route_type_t routeType = (type == Attributes::typeMix) ?
553 AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
554
Mikhail Naganova289aea2018-09-17 15:26:23 -0700555 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, type.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700556 Element route = new AudioRoute(routeType);
François Gaffief4ad6e52015-11-19 16:59:57 +0100557
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700558 std::string sinkAttr = getXmlAttribute(cur, Attributes::sink);
François Gaffief4ad6e52015-11-19 16:59:57 +0100559 if (sinkAttr.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700560 ALOGE("%s: No %s found", __func__, Attributes::sink);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700561 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100562 }
563 // Convert Sink name to port pointer
jiabin4ef93452019-09-10 14:29:54 -0700564 sp<PolicyAudioPort> sink = ctx->findPortByTagName(sinkAttr);
François Gaffief4ad6e52015-11-19 16:59:57 +0100565 if (sink == NULL) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700566 ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700567 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100568 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700569 route->setSink(sink);
François Gaffief4ad6e52015-11-19 16:59:57 +0100570
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700571 std::string sourcesAttr = getXmlAttribute(cur, Attributes::sources);
François Gaffief4ad6e52015-11-19 16:59:57 +0100572 if (sourcesAttr.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700573 ALOGE("%s: No %s found", __func__, Attributes::sources);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700574 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100575 }
576 // Tokenize and Convert Sources name to port pointer
jiabin4ef93452019-09-10 14:29:54 -0700577 PolicyAudioPortVector sources;
Mikhail Naganova289aea2018-09-17 15:26:23 -0700578 std::unique_ptr<char[]> sourcesLiteral{strndup(
579 sourcesAttr.c_str(), strlen(sourcesAttr.c_str()))};
580 char *devTag = strtok(sourcesLiteral.get(), ",");
François Gaffief4ad6e52015-11-19 16:59:57 +0100581 while (devTag != NULL) {
582 if (strlen(devTag) != 0) {
jiabin4ef93452019-09-10 14:29:54 -0700583 sp<PolicyAudioPort> source = ctx->findPortByTagName(devTag);
François Gaffief4ad6e52015-11-19 16:59:57 +0100584 if (source == NULL) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700585 ALOGE("%s: no source found with name=%s", __func__, devTag);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700586 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100587 }
588 sources.add(source);
589 }
590 devTag = strtok(NULL, ",");
591 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100592
Mikhail Naganova289aea2018-09-17 15:26:23 -0700593 sink->addRoute(route);
François Gaffief4ad6e52015-11-19 16:59:57 +0100594 for (size_t i = 0; i < sources.size(); i++) {
jiabin4ef93452019-09-10 14:29:54 -0700595 sp<PolicyAudioPort> source = sources.itemAt(i);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700596 source->addRoute(route);
François Gaffief4ad6e52015-11-19 16:59:57 +0100597 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700598 route->setSources(sources);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700599 return route;
François Gaffief4ad6e52015-11-19 16:59:57 +0100600}
601
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700602Return<ModuleTraits::Element> ModuleTraits::deserialize(const xmlNode *cur, PtrSerializingCtx ctx)
François Gaffief4ad6e52015-11-19 16:59:57 +0100603{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700604 std::string name = getXmlAttribute(cur, Attributes::name);
François Gaffief4ad6e52015-11-19 16:59:57 +0100605 if (name.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700606 ALOGE("%s: No %s found", __func__, Attributes::name);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700607 return Status::fromStatusT(BAD_VALUE);
François Gaffief4ad6e52015-11-19 16:59:57 +0100608 }
Mikhail Naganov9ee05402016-10-13 15:58:17 -0700609 uint32_t versionMajor = 0, versionMinor = 0;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700610 std::string versionLiteral = getXmlAttribute(cur, Attributes::version);
François Gaffief4ad6e52015-11-19 16:59:57 +0100611 if (!versionLiteral.empty()) {
Mikhail Naganov9ee05402016-10-13 15:58:17 -0700612 sscanf(versionLiteral.c_str(), "%u.%u", &versionMajor, &versionMinor);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700613 ALOGV("%s: mHalVersion = major %u minor %u", __func__,
Mikhail Naganov9ee05402016-10-13 15:58:17 -0700614 versionMajor, versionMajor);
François Gaffief4ad6e52015-11-19 16:59:57 +0100615 }
616
Mikhail Naganova289aea2018-09-17 15:26:23 -0700617 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::name, name.c_str());
François Gaffief4ad6e52015-11-19 16:59:57 +0100618
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700619 Element module = new HwModule(name.c_str(), versionMajor, versionMinor);
François Gaffief4ad6e52015-11-19 16:59:57 +0100620
621 // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
622 MixPortTraits::Collection mixPorts;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700623 status_t status = deserializeCollection<MixPortTraits>(cur, &mixPorts, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700624 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700625 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700626 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100627 module->setProfiles(mixPorts);
628
629 DevicePortTraits::Collection devicePorts;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700630 status = deserializeCollection<DevicePortTraits>(cur, &devicePorts, NULL);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700631 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700632 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700633 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100634 module->setDeclaredDevices(devicePorts);
635
636 RouteTraits::Collection routes;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700637 status = deserializeCollection<RouteTraits>(cur, &routes, module.get());
Mikhail Naganova289aea2018-09-17 15:26:23 -0700638 if (status != NO_ERROR) {
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700639 return Status::fromStatusT(status);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700640 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100641 module->setRoutes(routes);
642
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700643 for (const xmlNode *children = cur->xmlChildrenNode; children != NULL;
644 children = children->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700645 if (!xmlStrcmp(children->name, reinterpret_cast<const xmlChar*>(childAttachedDevicesTag))) {
646 ALOGV("%s: %s %s found", __func__, tag, childAttachedDevicesTag);
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700647 for (const xmlNode *child = children->xmlChildrenNode; child != NULL;
648 child = child->next) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700649 if (!xmlStrcmp(child->name,
650 reinterpret_cast<const xmlChar*>(childAttachedDeviceTag))) {
651 auto attachedDevice = make_xmlUnique(xmlNodeListGetString(
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700652 child->doc, child->xmlChildrenNode, 1));
Mikhail Naganova289aea2018-09-17 15:26:23 -0700653 if (attachedDevice != nullptr) {
654 ALOGV("%s: %s %s=%s", __func__, tag, childAttachedDeviceTag,
655 reinterpret_cast<const char*>(attachedDevice.get()));
656 sp<DeviceDescriptor> device = module->getDeclaredDevices().
jiabin5740f082019-08-19 15:08:30 -0700657 getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
Mikhail Naganova289aea2018-09-17 15:26:23 -0700658 attachedDevice.get())));
François Gaffief4ad6e52015-11-19 16:59:57 +0100659 ctx->addAvailableDevice(device);
François Gaffief4ad6e52015-11-19 16:59:57 +0100660 }
661 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100662 }
663 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700664 if (!xmlStrcmp(children->name,
665 reinterpret_cast<const xmlChar*>(childDefaultOutputDeviceTag))) {
666 auto defaultOutputDevice = make_xmlUnique(xmlNodeListGetString(
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700667 children->doc, children->xmlChildrenNode, 1));
Mikhail Naganova289aea2018-09-17 15:26:23 -0700668 if (defaultOutputDevice != nullptr) {
669 ALOGV("%s: %s %s=%s", __func__, tag, childDefaultOutputDeviceTag,
670 reinterpret_cast<const char*>(defaultOutputDevice.get()));
671 sp<DeviceDescriptor> device = module->getDeclaredDevices().getDeviceFromTagName(
jiabin5740f082019-08-19 15:08:30 -0700672 std::string(reinterpret_cast<const char*>(defaultOutputDevice.get())));
François Gaffief4ad6e52015-11-19 16:59:57 +0100673 if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
674 ctx->setDefaultOutputDevice(device);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700675 ALOGV("%s: default is %08x",
676 __func__, ctx->getDefaultOutputDevice()->type());
François Gaffief4ad6e52015-11-19 16:59:57 +0100677 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100678 }
679 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100680 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700681 return module;
François Gaffief4ad6e52015-11-19 16:59:57 +0100682}
683
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700684status_t GlobalConfigTraits::deserialize(const xmlNode *root, AudioPolicyConfig *config)
François Gaffief4ad6e52015-11-19 16:59:57 +0100685{
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700686 for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
687 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(tag))) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700688 std::string speakerDrcEnabled =
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700689 getXmlAttribute(cur, Attributes::speakerDrcEnabled);
François Gaffief4ad6e52015-11-19 16:59:57 +0100690 bool isSpeakerDrcEnabled;
691 if (!speakerDrcEnabled.empty() &&
Mikhail Naganova289aea2018-09-17 15:26:23 -0700692 convertTo<std::string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
693 config->setSpeakerDrcEnabled(isSpeakerDrcEnabled);
François Gaffief4ad6e52015-11-19 16:59:57 +0100694 }
695 return NO_ERROR;
696 }
François Gaffief4ad6e52015-11-19 16:59:57 +0100697 }
698 return NO_ERROR;
699}
700
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700701status_t SurroundSoundTraits::deserialize(const xmlNode *root, AudioPolicyConfig *config)
702{
703 config->setDefaultSurroundFormats();
704
705 for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
706 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(tag))) {
707 AudioPolicyConfig::SurroundFormats formats;
708 status_t status = deserializeCollection<SurroundSoundFormatTraits>(
709 cur, &formats, nullptr);
710 if (status == NO_ERROR) {
711 config->setSurroundFormats(formats);
712 }
713 return NO_ERROR;
714 }
715 }
716 return NO_ERROR;
717}
718
719Return<SurroundSoundFormatTraits::Element> SurroundSoundFormatTraits::deserialize(
720 const xmlNode *cur, PtrSerializingCtx /*serializingContext*/)
721{
722 std::string formatLiteral = getXmlAttribute(cur, Attributes::name);
723 if (formatLiteral.empty()) {
724 ALOGE("%s: No %s found for a surround format", __func__, Attributes::name);
725 return Status::fromStatusT(BAD_VALUE);
726 }
727 audio_format_t format = formatFromString(formatLiteral);
728 if (format == AUDIO_FORMAT_DEFAULT) {
729 ALOGE("%s: Unrecognized format %s", __func__, formatLiteral.c_str());
730 return Status::fromStatusT(BAD_VALUE);
731 }
732 Element pair = std::make_pair(format, Collection::mapped_type{});
733
734 std::string subformatsLiteral = getXmlAttribute(cur, Attributes::subformats);
735 if (subformatsLiteral.empty()) return pair;
736 FormatVector subformats = formatsFromString(subformatsLiteral, " ");
737 for (const auto& subformat : subformats) {
738 auto result = pair.second.insert(subformat);
739 if (!result.second) {
740 ALOGE("%s: could not add subformat %x to collection", __func__, subformat);
741 return Status::fromStatusT(BAD_VALUE);
742 }
743 }
744 return pair;
745}
746
Mikhail Naganova289aea2018-09-17 15:26:23 -0700747status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config)
François Gaffief4ad6e52015-11-19 16:59:57 +0100748{
Mikhail Naganova289aea2018-09-17 15:26:23 -0700749 auto doc = make_xmlUnique(xmlParseFile(configFile));
750 if (doc == nullptr) {
751 ALOGE("%s: Could not parse %s document.", __func__, configFile);
François Gaffief4ad6e52015-11-19 16:59:57 +0100752 return BAD_VALUE;
753 }
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700754 xmlNodePtr root = xmlDocGetRootElement(doc.get());
755 if (root == NULL) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700756 ALOGE("%s: Could not parse %s document: empty.", __func__, configFile);
François Gaffief4ad6e52015-11-19 16:59:57 +0100757 return BAD_VALUE;
758 }
Mikhail Naganova289aea2018-09-17 15:26:23 -0700759 if (xmlXIncludeProcess(doc.get()) < 0) {
760 ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __func__, configFile);
François Gaffief4ad6e52015-11-19 16:59:57 +0100761 }
762
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700763 if (xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>(rootName))) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700764 ALOGE("%s: No %s root element found in xml data %s.", __func__, rootName,
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700765 reinterpret_cast<const char*>(root->name));
François Gaffief4ad6e52015-11-19 16:59:57 +0100766 return BAD_VALUE;
767 }
768
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700769 std::string version = getXmlAttribute(root, versionAttribute);
François Gaffief4ad6e52015-11-19 16:59:57 +0100770 if (version.empty()) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700771 ALOGE("%s: No version found in root node %s", __func__, rootName);
François Gaffief4ad6e52015-11-19 16:59:57 +0100772 return BAD_VALUE;
773 }
774 if (version != mVersion) {
Mikhail Naganova289aea2018-09-17 15:26:23 -0700775 ALOGE("%s: Version does not match; expect %s got %s", __func__, mVersion.c_str(),
François Gaffief4ad6e52015-11-19 16:59:57 +0100776 version.c_str());
777 return BAD_VALUE;
778 }
779 // Lets deserialize children
780 // Modules
781 ModuleTraits::Collection modules;
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700782 status_t status = deserializeCollection<ModuleTraits>(root, &modules, config);
Mikhail Naganova289aea2018-09-17 15:26:23 -0700783 if (status != NO_ERROR) {
784 return status;
785 }
786 config->setHwModules(modules);
François Gaffief4ad6e52015-11-19 16:59:57 +0100787
François Gaffief4ad6e52015-11-19 16:59:57 +0100788 // Global Configuration
Mikhail Naganov43c386c2018-09-19 12:38:29 -0700789 GlobalConfigTraits::deserialize(root, config);
François Gaffief4ad6e52015-11-19 16:59:57 +0100790
Mikhail Naganov778bc1f2018-09-14 16:28:52 -0700791 // Surround configuration
792 SurroundSoundTraits::deserialize(root, config);
793
François Gaffief4ad6e52015-11-19 16:59:57 +0100794 return android::OK;
795}
796
Mikhail Naganova289aea2018-09-17 15:26:23 -0700797} // namespace
798
799status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config)
800{
801 PolicySerializer serializer;
802 return serializer.deserialize(fileName, config);
803}
804
Mikhail Naganov1b2a7942017-12-08 10:18:09 -0800805} // namespace android