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("file", *portNode);
208 if (!value.empty()) {
209 moduleInfo.fileName = value;
210 }
211
212 portInfoList.push_back(moduleInfo);
213 }
214 portNode = portNode->next;
215 }
216
217 moduleInfo.ports.assign(portInfoList.begin(), portInfoList.end());
218 }
219
GetNodeNameAsInt(xmlNode & node)220 NodeName XMLParser::GetNodeNameAsInt(xmlNode &node)
221 {
222 if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("deviceclass"))) {
223 return DEVICE_CLASS;
224 } else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("AudioInterruptEnable"))) {
225 return AUDIO_INTERRUPT_ENABLE;
226 } else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("UpdateRouteSupport"))) {
227 return UPDATE_ROUTE_SUPPORT;
228 } else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("AudioLatency"))) {
229 return AUDIO_LATENCY;
230 } else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("SinkLatency"))) {
231 return SINK_LATENCY;
232 } else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("VolumeGroupConfig"))) {
233 return VOLUME_GROUP_CONFIG;
234 } else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("InterruptGroupConfig"))) {
235 return INTERRUPT_GROUP_CONFIG;
236 } else {
237 return UNKNOWN;
238 }
239 }
240
ParseUpdateRouteSupport(xmlNode & node)241 void XMLParser::ParseUpdateRouteSupport(xmlNode &node)
242 {
243 xmlNode *child = node.children;
244 xmlChar *supportFlag = xmlNodeGetContent(child);
245
246 if (!xmlStrcmp(supportFlag, reinterpret_cast<const xmlChar*>("true"))) {
247 mPortObserver.OnUpdateRouteSupport(true);
248 } else {
249 mPortObserver.OnUpdateRouteSupport(false);
250 }
251
252 xmlFree(supportFlag);
253 }
254
ParseAudioInterrupt(xmlNode & node)255 void XMLParser::ParseAudioInterrupt(xmlNode &node)
256 {
257 xmlNode *child = node.children;
258 xmlChar *enableFlag = xmlNodeGetContent(child);
259
260 if (!xmlStrcmp(enableFlag, reinterpret_cast<const xmlChar*>("true"))) {
261 mPortObserver.OnAudioInterruptEnable(true);
262 } else {
263 mPortObserver.OnAudioInterruptEnable(false);
264 }
265
266 xmlFree(enableFlag);
267 }
268
GetDeviceClassType(const std::string & deviceClass)269 ClassType XMLParser::GetDeviceClassType(const std::string &deviceClass)
270 {
271 if (deviceClass == PRIMARY_CLASS)
272 return ClassType::TYPE_PRIMARY;
273 else if (deviceClass == A2DP_CLASS)
274 return ClassType::TYPE_A2DP;
275 else if (deviceClass == USB_CLASS)
276 return ClassType::TYPE_USB;
277 else if (deviceClass == FILE_CLASS)
278 return ClassType::TYPE_FILE_IO;
279 else
280 return ClassType::TYPE_INVALID;
281 }
282
ExtractPropertyValue(const std::string & propName,xmlNode & node)283 std::string XMLParser::ExtractPropertyValue(const std::string &propName, xmlNode &node)
284 {
285 std::string propValue = "";
286 xmlChar *tempValue = nullptr;
287
288 if (xmlHasProp(&node, reinterpret_cast<const xmlChar*>(propName.c_str()))) {
289 tempValue = xmlGetProp(&node, reinterpret_cast<const xmlChar*>(propName.c_str()));
290 }
291
292 if (tempValue != nullptr) {
293 propValue = reinterpret_cast<const char*>(tempValue);
294 xmlFree(tempValue);
295 }
296
297 return propValue;
298 }
299
ParseAudioLatency(xmlNode & node)300 void XMLParser::ParseAudioLatency(xmlNode &node)
301 {
302 xmlNode *child = node.children;
303 xmlChar *audioLatency = xmlNodeGetContent(child);
304 std::string sAudioLatency(reinterpret_cast<char *>(audioLatency));
305 mPortObserver.OnAudioLatencyParsed((uint64_t)std::stoi(sAudioLatency));
306
307 xmlFree(audioLatency);
308 }
309
ParseSinkLatency(xmlNode & node)310 void XMLParser::ParseSinkLatency(xmlNode &node)
311 {
312 xmlNode *child = node.children;
313 xmlChar *latency = xmlNodeGetContent(child);
314 std::string sLatency(reinterpret_cast<char *>(latency));
315 mPortObserver.OnSinkLatencyParsed((uint64_t)std::stoi(sLatency));
316
317 xmlFree(latency);
318 }
319
ParseGroups(xmlNode & node,NodeName type)320 void XMLParser::ParseGroups(xmlNode& node, NodeName type)
321 {
322 xmlNode* groupsNode = nullptr;
323 groupsNode = node.xmlChildrenNode; // get <groups>
324 while (groupsNode != nullptr) {
325 if (groupsNode->type == XML_ELEMENT_NODE) {
326 ParseGroup(*groupsNode, type);
327 }
328 groupsNode = groupsNode->next;
329 }
330 }
331
ParseGroup(xmlNode & node,NodeName type)332 void XMLParser::ParseGroup(xmlNode& node, NodeName type)
333 {
334 xmlNode* groupNode = nullptr;
335 groupNode = node.xmlChildrenNode;
336
337 while (groupNode != nullptr) {
338 if (groupNode->type == XML_ELEMENT_NODE) {
339 std::string groupName = ExtractPropertyValue("name", *groupNode);
340 ParseGroupModule(*groupNode, type, groupName);
341 }
342 groupNode = groupNode->next;
343 }
344 }
345
ParseGroupModule(xmlNode & node,NodeName type,std::string groupName)346 void XMLParser::ParseGroupModule(xmlNode& node, NodeName type, std::string groupName)
347 {
348 xmlNode* moduleNode = nullptr;
349 moduleNode = node.xmlChildrenNode;
350 while (moduleNode != nullptr) {
351 if (moduleNode->type == XML_ELEMENT_NODE) {
352 std::string moduleName = ExtractPropertyValue("name", *moduleNode);
353 if (type == VOLUME_GROUP_CONFIG) {
354 volumeGroupMap_[moduleName] = groupName;
355 } else if (type == INTERRUPT_GROUP_CONFIG) {
356 interruptGroupMap_[moduleName] = groupName;
357 }
358 }
359 moduleNode = moduleNode->next;
360 }
361 }
362 } // namespace AudioStandard
363 } // namespace OHOS
364