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 #include "audio_focus_parser.h"
16
17 namespace OHOS {
18 namespace AudioStandard {
AudioFocusParser()19 AudioFocusParser::AudioFocusParser()
20 {
21 AUDIO_INFO_LOG("AudioFocusParser ctor");
22
23 // Initialize stream map with string vs AudioStreamType
24 audioFocusMap = {
25 // stream type for audio interrupt
26 {"STREAM_VOICE_CALL", {AudioStreamType::STREAM_VOICE_CALL, SourceType::SOURCE_TYPE_INVALID, true}},
27 {"STREAM_VOICE_MESSAGE", {AudioStreamType::STREAM_VOICE_MESSAGE, SourceType::SOURCE_TYPE_INVALID, true}},
28 {"STREAM_SYSTEM", {AudioStreamType::STREAM_SYSTEM, SourceType::SOURCE_TYPE_INVALID, true}},
29 {"STREAM_RING", {AudioStreamType::STREAM_RING, SourceType::SOURCE_TYPE_INVALID, true}},
30 {"STREAM_MUSIC", {AudioStreamType::STREAM_MUSIC, SourceType::SOURCE_TYPE_INVALID, true}},
31 {"STREAM_MOVIE", {AudioStreamType::STREAM_MOVIE, SourceType::SOURCE_TYPE_INVALID, true}},
32 {"STREAM_GAME", {AudioStreamType::STREAM_GAME, SourceType::SOURCE_TYPE_INVALID, true}},
33 {"STREAM_SPEECH", {AudioStreamType::STREAM_SPEECH, SourceType::SOURCE_TYPE_INVALID, true}},
34 {"STREAM_NAVIGATION", {AudioStreamType::STREAM_NAVIGATION, SourceType::SOURCE_TYPE_INVALID, true}},
35 {"STREAM_ALARM", {AudioStreamType::STREAM_ALARM, SourceType::SOURCE_TYPE_INVALID, true}},
36 {"STREAM_NOTIFICATION", {AudioStreamType::STREAM_NOTIFICATION, SourceType::SOURCE_TYPE_INVALID, true}},
37 {"STREAM_SYSTEM_ENFORCED", {AudioStreamType::STREAM_SYSTEM_ENFORCED, SourceType::SOURCE_TYPE_INVALID, true}},
38 {"STREAM_DTMF", {AudioStreamType::STREAM_DTMF, SourceType::SOURCE_TYPE_INVALID, true}},
39 {"STREAM_VOICE_ASSISTANT", {AudioStreamType::STREAM_VOICE_ASSISTANT, SourceType::SOURCE_TYPE_INVALID, true}},
40 {"STREAM_ACCESSIBILITY", {AudioStreamType::STREAM_ACCESSIBILITY, SourceType::SOURCE_TYPE_INVALID, true}},
41 {"STREAM_ULTRASONIC", {AudioStreamType::STREAM_ULTRASONIC, SourceType::SOURCE_TYPE_INVALID, true}},
42 // source type for audio interrupt
43 {"SOURCE_TYPE_MIC", {AudioStreamType::STREAM_DEFAULT, SourceType::SOURCE_TYPE_MIC, false}},
44 {"SOURCE_TYPE_VOICE_RECOGNITION", {AudioStreamType::STREAM_DEFAULT, SourceType::SOURCE_TYPE_VOICE_RECOGNITION,
45 false}},
46 {"SOURCE_TYPE_WAKEUP", {AudioStreamType::STREAM_DEFAULT, SourceType::SOURCE_TYPE_WAKEUP, false}},
47 {"SOURCE_TYPE_VOICE_COMMUNICATION", {AudioStreamType::STREAM_DEFAULT,
48 SourceType::SOURCE_TYPE_VOICE_COMMUNICATION, false}},
49 {"SOURCE_TYPE_ULTRASONIC", {AudioStreamType::STREAM_DEFAULT, SourceType::SOURCE_TYPE_ULTRASONIC, false}},
50 {"SOURCE_TYPE_PLAYBACK_CAPTURE", {AudioStreamType::STREAM_DEFAULT,
51 SourceType::SOURCE_TYPE_PLAYBACK_CAPTURE, false}}
52 };
53
54 // Initialize action map with string vs InterruptActionType
55 actionMap = {
56 {"DUCK", INTERRUPT_HINT_DUCK},
57 {"PAUSE", INTERRUPT_HINT_PAUSE},
58 {"REJECT", INTERRUPT_HINT_NONE},
59 {"STOP", INTERRUPT_HINT_STOP},
60 {"PLAY", INTERRUPT_HINT_NONE}
61 };
62
63 // Initialize target map with string vs InterruptActionTarget
64 targetMap = {
65 {"incoming", INCOMING},
66 {"existing", CURRENT},
67 {"both", BOTH},
68 };
69
70 forceMap = {
71 {"true", INTERRUPT_FORCE},
72 {"false", INTERRUPT_SHARE},
73 };
74 }
75
~AudioFocusParser()76 AudioFocusParser::~AudioFocusParser()
77 {
78 audioFocusMap.clear();
79 actionMap.clear();
80 targetMap.clear();
81 forceMap.clear();
82 }
83
LoadDefaultConfig(std::map<std::pair<AudioFocusType,AudioFocusType>,AudioFocusEntry> & focusMap)84 void AudioFocusParser::LoadDefaultConfig(std::map<std::pair<AudioFocusType, AudioFocusType>,
85 AudioFocusEntry> &focusMap)
86 {
87 }
88
LoadConfig(std::map<std::pair<AudioFocusType,AudioFocusType>,AudioFocusEntry> & focusMap)89 int32_t AudioFocusParser::LoadConfig(std::map<std::pair<AudioFocusType, AudioFocusType>,
90 AudioFocusEntry> &focusMap)
91 {
92 xmlDoc *doc = nullptr;
93 xmlNode *rootElement = nullptr;
94
95 if ((doc = xmlReadFile(AUDIO_FOCUS_CONFIG_FILE, nullptr, 0)) == nullptr) {
96 AUDIO_ERR_LOG("error: could not parse file %s", AUDIO_FOCUS_CONFIG_FILE);
97 LoadDefaultConfig(focusMap);
98 return ERROR;
99 }
100
101 rootElement = xmlDocGetRootElement(doc);
102 xmlNode *currNode = rootElement;
103 CHECK_AND_RETURN_RET_LOG(currNode != nullptr, ERROR, "root element is null");
104 if (xmlStrcmp(currNode->name, reinterpret_cast<const xmlChar*>("audio_focus_policy"))) {
105 AUDIO_ERR_LOG("Missing tag - focus_policy in : %s", AUDIO_FOCUS_CONFIG_FILE);
106 xmlFreeDoc(doc);
107 xmlCleanupParser();
108 return ERROR;
109 }
110
111 if (currNode->children) {
112 currNode = currNode->children;
113 } else {
114 AUDIO_ERR_LOG("Missing child: %s", AUDIO_FOCUS_CONFIG_FILE);
115 xmlFreeDoc(doc);
116 xmlCleanupParser();
117 return ERROR;
118 }
119
120 while (currNode != nullptr) {
121 if ((currNode->type == XML_ELEMENT_NODE) &&
122 (!xmlStrcmp(currNode->name, reinterpret_cast<const xmlChar*>("focus_type")))) {
123 ParseStreams(currNode, focusMap);
124 break;
125 } else {
126 currNode = currNode->next;
127 }
128 }
129
130 xmlFreeDoc(doc);
131 xmlCleanupParser();
132 return SUCCESS;
133 }
134
ParseFocusMap(xmlNode * node,const std::string & curStream,std::map<std::pair<AudioFocusType,AudioFocusType>,AudioFocusEntry> & focusMap)135 void AudioFocusParser::ParseFocusMap(xmlNode *node, const std::string &curStream,
136 std::map<std::pair<AudioFocusType, AudioFocusType>, AudioFocusEntry> &focusMap)
137 {
138 xmlNode *currNode = node;
139 while (currNode != nullptr) {
140 if (currNode->type == XML_ELEMENT_NODE) {
141 if (!xmlStrcmp(currNode->name, reinterpret_cast<const xmlChar*>("focus_table"))) {
142 AUDIO_DEBUG_LOG("node type: Element, name: %s", currNode->name);
143 xmlNode *sNode = currNode->children;
144 while (sNode) {
145 if (sNode->type == XML_ELEMENT_NODE) {
146 if (!xmlStrcmp(sNode->name, reinterpret_cast<const xmlChar*>("deny"))) {
147 ParseRejectedStreams(sNode->children, curStream, focusMap);
148 } else {
149 ParseAllowedStreams(sNode->children, curStream, focusMap);
150 }
151 }
152 sNode = sNode->next;
153 }
154 }
155 }
156 currNode = currNode->next;
157 }
158 }
159
ParseStreams(xmlNode * node,std::map<std::pair<AudioFocusType,AudioFocusType>,AudioFocusEntry> & focusMap)160 void AudioFocusParser::ParseStreams(xmlNode *node,
161 std::map<std::pair<AudioFocusType, AudioFocusType>, AudioFocusEntry> &focusMap)
162 {
163 xmlNode *currNode = node;
164 while (currNode) {
165 if (currNode->type == XML_ELEMENT_NODE) {
166 char *sType = reinterpret_cast<char*>(xmlGetProp(currNode,
167 reinterpret_cast<xmlChar*>(const_cast<char*>("value"))));
168 std::string typeStr(sType);
169 std::map<std::string, AudioFocusType>::iterator it = audioFocusMap.find(typeStr);
170 if (it != audioFocusMap.end()) {
171 AUDIO_DEBUG_LOG("stream type: %{public}s", sType);
172 ParseFocusMap(currNode->children, typeStr, focusMap);
173 }
174 xmlFree(sType);
175 }
176 currNode = currNode->next;
177 }
178 }
179
AddRejectedFocusEntry(xmlNode * currNode,const std::string & curStream,std::map<std::pair<AudioFocusType,AudioFocusType>,AudioFocusEntry> & focusMap)180 void AudioFocusParser::AddRejectedFocusEntry(xmlNode *currNode, const std::string &curStream,
181 std::map<std::pair<AudioFocusType, AudioFocusType>, AudioFocusEntry> &focusMap)
182 {
183 char *newStream = reinterpret_cast<char*>(xmlGetProp(currNode,
184 reinterpret_cast<xmlChar*>(const_cast<char*>("value"))));
185
186 std::string newStreamStr(newStream);
187 std::map<std::string, AudioFocusType>::iterator it1 = audioFocusMap.find(newStreamStr);
188 if (it1 != audioFocusMap.end()) {
189 std::pair<AudioFocusType, AudioFocusType> rejectedStreamsPair =
190 std::make_pair(audioFocusMap[curStream], audioFocusMap[newStreamStr]);
191 AudioFocusEntry rejectedFocusEntry;
192 rejectedFocusEntry.actionOn = INCOMING;
193 rejectedFocusEntry.hintType = INTERRUPT_HINT_NONE;
194 rejectedFocusEntry.forceType = INTERRUPT_FORCE;
195 rejectedFocusEntry.isReject = true;
196 focusMap.emplace(rejectedStreamsPair, rejectedFocusEntry);
197
198 AUDIO_DEBUG_LOG("current stream: %s, incoming stream: %s", curStream.c_str(), newStreamStr.c_str());
199 AUDIO_DEBUG_LOG("actionOn: %d, hintType: %d, forceType: %d isReject: %d",
200 rejectedFocusEntry.actionOn, rejectedFocusEntry.hintType,
201 rejectedFocusEntry.forceType, rejectedFocusEntry.isReject);
202 }
203 xmlFree(newStream);
204 }
205
ParseRejectedStreams(xmlNode * node,const std::string & curStream,std::map<std::pair<AudioFocusType,AudioFocusType>,AudioFocusEntry> & focusMap)206 void AudioFocusParser::ParseRejectedStreams(xmlNode *node, const std::string &curStream,
207 std::map<std::pair<AudioFocusType, AudioFocusType>, AudioFocusEntry> &focusMap)
208 {
209 xmlNode *currNode = node;
210
211 while (currNode) {
212 if (currNode->type == XML_ELEMENT_NODE) {
213 if (!xmlStrcmp(currNode->name, reinterpret_cast<const xmlChar*>("focus_type"))) {
214 AddRejectedFocusEntry(currNode, curStream, focusMap);
215 }
216 }
217 currNode = currNode->next;
218 }
219 }
220
AddAllowedFocusEntry(xmlNode * currNode,const std::string & curStream,std::map<std::pair<AudioFocusType,AudioFocusType>,AudioFocusEntry> & focusMap)221 void AudioFocusParser::AddAllowedFocusEntry(xmlNode *currNode, const std::string &curStream,
222 std::map<std::pair<AudioFocusType, AudioFocusType>, AudioFocusEntry> &focusMap)
223 {
224 char *newStream = reinterpret_cast<char*>(xmlGetProp(currNode,
225 reinterpret_cast<xmlChar*>(const_cast<char*>("value"))));
226 char *aType = reinterpret_cast<char*>(xmlGetProp(currNode,
227 reinterpret_cast<xmlChar*>(const_cast<char*>("action_type"))));
228 char *aTarget = reinterpret_cast<char*>(xmlGetProp(currNode,
229 reinterpret_cast<xmlChar*>(const_cast<char*>("action_on"))));
230 char *isForced = reinterpret_cast<char*>(xmlGetProp(currNode,
231 reinterpret_cast<xmlChar*>(const_cast<char*>("is_forced"))));
232
233 std::string newStreamStr(newStream);
234 std::map<std::string, AudioFocusType>::iterator it1 = audioFocusMap.find(newStreamStr);
235 std::string aTargetStr(aTarget);
236 std::map<std::string, ActionTarget>::iterator it2 = targetMap.find(aTargetStr);
237 std::string aTypeStr(aType);
238 std::map<std::string, InterruptHint>::iterator it3 = actionMap.find(aTypeStr);
239 std::string isForcedStr(isForced);
240 std::map<std::string, InterruptForceType>::iterator it4 = forceMap.find(isForcedStr);
241 if ((it1 != audioFocusMap.end()) && (it2 != targetMap.end()) && (it3 != actionMap.end()) &&
242 (it4 != forceMap.end())) {
243 std::pair<AudioFocusType, AudioFocusType> allowedStreamsPair =
244 std::make_pair(audioFocusMap[curStream], audioFocusMap[newStreamStr]);
245 AudioFocusEntry allowedFocusEntry;
246 allowedFocusEntry.actionOn = targetMap[aTargetStr];
247 allowedFocusEntry.hintType = actionMap[aTypeStr];
248 allowedFocusEntry.forceType = forceMap[isForcedStr];
249 allowedFocusEntry.isReject = false;
250 focusMap.emplace(allowedStreamsPair, allowedFocusEntry);
251
252 AUDIO_DEBUG_LOG("current stream: %s, incoming stream: %s", curStream.c_str(), newStreamStr.c_str());
253 AUDIO_DEBUG_LOG("actionOn: %d, hintType: %d, forceType: %d isReject: %d",
254 allowedFocusEntry.actionOn, allowedFocusEntry.hintType,
255 allowedFocusEntry.forceType, allowedFocusEntry.isReject);
256 }
257 xmlFree(newStream);
258 xmlFree(aType);
259 xmlFree(aTarget);
260 xmlFree(isForced);
261 }
262
ParseAllowedStreams(xmlNode * node,const std::string & curStream,std::map<std::pair<AudioFocusType,AudioFocusType>,AudioFocusEntry> & focusMap)263 void AudioFocusParser::ParseAllowedStreams(xmlNode *node, const std::string &curStream,
264 std::map<std::pair<AudioFocusType, AudioFocusType>, AudioFocusEntry> &focusMap)
265 {
266 xmlNode *currNode = node;
267
268 while (currNode) {
269 if (currNode->type == XML_ELEMENT_NODE) {
270 if (!xmlStrcmp(currNode->name, reinterpret_cast<const xmlChar*>("focus_type"))) {
271 AddAllowedFocusEntry(currNode, curStream, focusMap);
272 }
273 }
274 currNode = currNode->next;
275 }
276 }
277 } // namespace AudioStandard
278 } // namespace OHOS
279