• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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