1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "audio_log.h"
17
18 #include "xml_parser.h"
19
20 namespace OHOS {
21 namespace AudioStandard {
LoadConfiguration()22 bool XMLParser::LoadConfiguration()
23 {
24 AUDIO_INFO_LOG("start LoadConfiguration");
25 mDoc = xmlReadFile(CONFIG_FILE, nullptr, 0);
26 if (mDoc == nullptr) {
27 AUDIO_ERR_LOG("xmlReadFile Failed");
28 return false;
29 }
30
31 return true;
32 }
33
Parse()34 bool XMLParser::Parse()
35 {
36 xmlNode *root = xmlDocGetRootElement(mDoc);
37 if (root == nullptr) {
38 AUDIO_ERR_LOG("xmlDocGetRootElement Failed");
39 return false;
40 }
41
42 if (!ParseInternal(*root)) {
43 return false;
44 }
45
46 return true;
47 }
48
Destroy()49 void XMLParser::Destroy()
50 {
51 if (mDoc != nullptr) {
52 xmlFreeDoc(mDoc);
53 }
54 }
55
ParseInternal(xmlNode & node)56 bool XMLParser::ParseInternal(xmlNode &node)
57 {
58 xmlNode *currNode = &node;
59 for (; currNode; currNode = currNode->next) {
60 if (XML_ELEMENT_NODE == currNode->type) {
61 switch (GetNodeNameAsInt(*currNode)) {
62 case DEVICE_CLASS:
63 ParseDeviceClass(*currNode);
64 break;
65 case AUDIO_INTERRUPT_ENABLE:
66 ParseAudioInterrupt(*currNode);
67 break;
68 case UPDATE_ROUTE_SUPPORT:
69 ParseUpdateRouteSupport(*currNode);
70 break;
71 case AUDIO_LATENCY:
72 ParseAudioLatency(*currNode);
73 break;
74 case SINK_LATENCY:
75 ParseSinkLatency(*currNode);
76 break;
77 case VOLUME_GROUP_CONFIG:
78 ParseGroups(*currNode, VOLUME_GROUP_CONFIG);
79 break;
80 case INTERRUPT_GROUP_CONFIG:
81 ParseGroups(*currNode, INTERRUPT_GROUP_CONFIG);
82 break;
83 default:
84 ParseInternal(*(currNode->children));
85 break;
86 }
87 }
88 }
89
90 mPortObserver.OnXmlParsingCompleted(xmlParsedDataMap_);
91 mPortObserver.OnVolumeGroupParsed(volumeGroupMap_);
92 mPortObserver.OnInterruptGroupParsed(interruptGroupMap_);
93 return true;
94 }
95
ParseDeviceClass(xmlNode & node)96 void XMLParser::ParseDeviceClass(xmlNode &node)
97 {
98 xmlNode *modulesNode = nullptr;
99 modulesNode = node.xmlChildrenNode;
100
101 std::string className = ExtractPropertyValue("name", node);
102 if (className.empty()) {
103 AUDIO_ERR_LOG("No name provided for the device class %{public}s", node.name);
104 return;
105 }
106
107 deviceClassType_ = GetDeviceClassType(className);
108 xmlParsedDataMap_[deviceClassType_] = {};
109
110 while (modulesNode != nullptr) {
111 if (modulesNode->type == XML_ELEMENT_NODE) {
112 ParseModules(*modulesNode, className);
113 }
114 modulesNode = modulesNode->next;
115 }
116 }
117
ParseModules(xmlNode & node,std::string & className)118 void XMLParser::ParseModules(xmlNode &node, std::string &className)
119 {
120 xmlNode *moduleNode = nullptr;
121 std::list<AudioModuleInfo> moduleList = {};
122 moduleNode = node.xmlChildrenNode;
123
124 while (moduleNode != nullptr) {
125 if (moduleNode->type == XML_ELEMENT_NODE) {
126 AudioModuleInfo moduleInfo = {};
127 moduleInfo.className = className;
128 moduleInfo.name = ExtractPropertyValue("name", *moduleNode);
129 moduleInfo.lib = ExtractPropertyValue("lib", *moduleNode);
130 moduleInfo.role = ExtractPropertyValue("role", *moduleNode);
131 moduleInfo.rate = ExtractPropertyValue("rate", *moduleNode);
132 moduleInfo.format = ExtractPropertyValue("format", *moduleNode);
133 moduleInfo.channels = ExtractPropertyValue("channels", *moduleNode);
134 moduleInfo.bufferSize = ExtractPropertyValue("buffer_size", *moduleNode);
135 moduleInfo.fileName = ExtractPropertyValue("file", *moduleNode);
136 moduleInfo.ports = {};
137
138 ParsePorts(*moduleNode, moduleInfo);
139 moduleList.push_back(moduleInfo);
140 }
141 moduleNode = moduleNode->next;
142 }
143
144 xmlParsedDataMap_[deviceClassType_] = moduleList;
145 }
146
ParsePorts(xmlNode & node,AudioModuleInfo & moduleInfo)147 void XMLParser::ParsePorts(xmlNode &node, AudioModuleInfo &moduleInfo)
148 {
149 xmlNode *portsNode = nullptr;
150 portsNode = node.xmlChildrenNode;
151
152 while (portsNode != nullptr) {
153 if (portsNode->type == XML_ELEMENT_NODE) {
154 ParsePort(*portsNode, moduleInfo);
155 }
156 portsNode = portsNode->next;
157 }
158 }
159
ParsePort(xmlNode & node,AudioModuleInfo & moduleInfo)160 void XMLParser::ParsePort(xmlNode &node, AudioModuleInfo &moduleInfo)
161 {
162 xmlNode *portNode = nullptr;
163 std::list<AudioModuleInfo> portInfoList = {};
164 portNode = node.xmlChildrenNode;
165
166 while (portNode != nullptr) {
167 if (portNode->type == XML_ELEMENT_NODE) {
168 moduleInfo.adapterName = ExtractPropertyValue("adapter_name", *portNode);
169 moduleInfo.id = ExtractPropertyValue("id", *portNode);
170
171 // if some parameter is not configured inside <Port>, take data from moduleinfo
172 std::string value = ExtractPropertyValue("rate", *portNode);
173 if (!value.empty()) {
174 moduleInfo.rate = value;
175 }
176
177 value = ExtractPropertyValue("format", *portNode);
178 if (!value.empty()) {
179 moduleInfo.format = value;
180 }
181
182 value = ExtractPropertyValue("channels", *portNode);
183 if (!value.empty()) {
184 moduleInfo.channels = value;
185 }
186
187 value = ExtractPropertyValue("buffer_size", *portNode);
188 if (!value.empty()) {
189 moduleInfo.bufferSize = value;
190 }
191
192 value = ExtractPropertyValue("fixed_latency", *portNode);
193 if (!value.empty()) {
194 moduleInfo.fixedLatency = value;
195 }
196
197 value = ExtractPropertyValue("render_in_idle_state", *portNode);
198 if (!value.empty()) {
199 moduleInfo.renderInIdleState = value;
200 }
201
202 value = ExtractPropertyValue("open_mic_speaker", *portNode);
203 if (!value.empty()) {
204 moduleInfo.OpenMicSpeaker = value;
205 }
206
207 value = ExtractPropertyValue("source_type", *portNode);
208 if (!value.empty()) {
209 moduleInfo.sourceType = value;
210 }
211
212 value = ExtractPropertyValue("file", *portNode);
213 if (!value.empty()) {
214 moduleInfo.fileName = value;
215 }
216
217 portInfoList.push_back(moduleInfo);
218 }
219 portNode = portNode->next;
220 }
221
222 moduleInfo.ports.assign(portInfoList.begin(), portInfoList.end());
223 }
224
GetNodeNameAsInt(xmlNode & node)225 NodeName XMLParser::GetNodeNameAsInt(xmlNode &node)
226 {
227 if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("deviceclass"))) {
228 return DEVICE_CLASS;
229 } else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("AudioInterruptEnable"))) {
230 return AUDIO_INTERRUPT_ENABLE;
231 } else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("UpdateRouteSupport"))) {
232 return UPDATE_ROUTE_SUPPORT;
233 } else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("AudioLatency"))) {
234 return AUDIO_LATENCY;
235 } else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("SinkLatency"))) {
236 return SINK_LATENCY;
237 } else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("VolumeGroupConfig"))) {
238 return VOLUME_GROUP_CONFIG;
239 } else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("InterruptGroupConfig"))) {
240 return INTERRUPT_GROUP_CONFIG;
241 } else {
242 return UNKNOWN;
243 }
244 }
245
ParseUpdateRouteSupport(xmlNode & node)246 void XMLParser::ParseUpdateRouteSupport(xmlNode &node)
247 {
248 xmlNode *child = node.children;
249 xmlChar *supportFlag = xmlNodeGetContent(child);
250
251 if (!xmlStrcmp(supportFlag, reinterpret_cast<const xmlChar*>("true"))) {
252 mPortObserver.OnUpdateRouteSupport(true);
253 } else {
254 mPortObserver.OnUpdateRouteSupport(false);
255 }
256
257 xmlFree(supportFlag);
258 }
259
ParseAudioInterrupt(xmlNode & node)260 void XMLParser::ParseAudioInterrupt(xmlNode &node)
261 {
262 xmlNode *child = node.children;
263 xmlChar *enableFlag = xmlNodeGetContent(child);
264
265 if (!xmlStrcmp(enableFlag, reinterpret_cast<const xmlChar*>("true"))) {
266 mPortObserver.OnAudioInterruptEnable(true);
267 } else {
268 mPortObserver.OnAudioInterruptEnable(false);
269 }
270
271 xmlFree(enableFlag);
272 }
273
GetDeviceClassType(const std::string & deviceClass)274 ClassType XMLParser::GetDeviceClassType(const std::string &deviceClass)
275 {
276 if (deviceClass == PRIMARY_CLASS)
277 return ClassType::TYPE_PRIMARY;
278 else if (deviceClass == A2DP_CLASS)
279 return ClassType::TYPE_A2DP;
280 else if (deviceClass == USB_CLASS)
281 return ClassType::TYPE_USB;
282 else if (deviceClass == FILE_CLASS)
283 return ClassType::TYPE_FILE_IO;
284 else
285 return ClassType::TYPE_INVALID;
286 }
287
ExtractPropertyValue(const std::string & propName,xmlNode & node)288 std::string XMLParser::ExtractPropertyValue(const std::string &propName, xmlNode &node)
289 {
290 std::string propValue = "";
291 xmlChar *tempValue = nullptr;
292
293 if (xmlHasProp(&node, reinterpret_cast<const xmlChar*>(propName.c_str()))) {
294 tempValue = xmlGetProp(&node, reinterpret_cast<const xmlChar*>(propName.c_str()));
295 }
296
297 if (tempValue != nullptr) {
298 propValue = reinterpret_cast<const char*>(tempValue);
299 xmlFree(tempValue);
300 }
301
302 return propValue;
303 }
304
ParseAudioLatency(xmlNode & node)305 void XMLParser::ParseAudioLatency(xmlNode &node)
306 {
307 xmlNode *child = node.children;
308 xmlChar *audioLatency = xmlNodeGetContent(child);
309 std::string sAudioLatency(reinterpret_cast<char *>(audioLatency));
310 mPortObserver.OnAudioLatencyParsed((uint64_t)std::stoi(sAudioLatency));
311
312 xmlFree(audioLatency);
313 }
314
ParseSinkLatency(xmlNode & node)315 void XMLParser::ParseSinkLatency(xmlNode &node)
316 {
317 xmlNode *child = node.children;
318 xmlChar *latency = xmlNodeGetContent(child);
319 std::string sLatency(reinterpret_cast<char *>(latency));
320 mPortObserver.OnSinkLatencyParsed((uint64_t)std::stoi(sLatency));
321
322 xmlFree(latency);
323 }
324
ParseGroups(xmlNode & node,NodeName type)325 void XMLParser::ParseGroups(xmlNode& node, NodeName type)
326 {
327 xmlNode* groupsNode = nullptr;
328 groupsNode = node.xmlChildrenNode; // get <groups>
329 while (groupsNode != nullptr) {
330 if (groupsNode->type == XML_ELEMENT_NODE) {
331 ParseGroup(*groupsNode, type);
332 }
333 groupsNode = groupsNode->next;
334 }
335 }
336
ParseGroup(xmlNode & node,NodeName type)337 void XMLParser::ParseGroup(xmlNode& node, NodeName type)
338 {
339 xmlNode* groupNode = nullptr;
340 groupNode = node.xmlChildrenNode;
341
342 while (groupNode != nullptr) {
343 if (groupNode->type == XML_ELEMENT_NODE) {
344 std::string groupName = ExtractPropertyValue("name", *groupNode);
345 ParseGroupModule(*groupNode, type, groupName);
346 }
347 groupNode = groupNode->next;
348 }
349 }
350
ParseGroupModule(xmlNode & node,NodeName type,std::string groupName)351 void XMLParser::ParseGroupModule(xmlNode& node, NodeName type, std::string groupName)
352 {
353 xmlNode* moduleNode = nullptr;
354 moduleNode = node.xmlChildrenNode;
355 while (moduleNode != nullptr) {
356 if (moduleNode->type == XML_ELEMENT_NODE) {
357 std::string moduleName = ExtractPropertyValue("name", *moduleNode);
358 if (type == VOLUME_GROUP_CONFIG) {
359 volumeGroupMap_[moduleName] = groupName;
360 } else if (type == INTERRUPT_GROUP_CONFIG) {
361 interruptGroupMap_[moduleName] = groupName;
362 }
363 }
364 moduleNode = moduleNode->next;
365 }
366 }
367 } // namespace AudioStandard
368 } // namespace OHOS
369