1 /*
2 * Copyright (c) 2023 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 #ifndef LOG_TAG
16 #define LOG_TAG "AudioVolumeParser"
17 #endif
18
19 #include "audio_volume_parser.h"
20 #ifdef USE_CONFIG_POLICY
21 #include "config_policy_utils.h"
22 #endif
23 #include "audio_utils.h"
24 #include "media_monitor_manager.h"
25
26 namespace OHOS {
27 namespace AudioStandard {
AudioVolumeParser()28 AudioVolumeParser::AudioVolumeParser()
29 {
30 AUDIO_INFO_LOG("AudioVolumeParser ctor");
31 audioStreamMap_ = {
32 {"VOICE_CALL", STREAM_VOICE_CALL},
33 {"MUSIC", STREAM_MUSIC},
34 {"RING", STREAM_RING},
35 {"VOICE_ASSISTANT", STREAM_VOICE_ASSISTANT},
36 {"ALARM", STREAM_ALARM},
37 {"ACCESSIBILITY", STREAM_ACCESSIBILITY},
38 {"ULTRASONIC", STREAM_ULTRASONIC},
39 {"SYSTEM", STREAM_SYSTEM},
40 {"APP", STREAM_APP}
41 };
42
43 audioDeviceMap_ = {
44 {"earpiece", EARPIECE_VOLUME_TYPE},
45 {"speaker", SPEAKER_VOLUME_TYPE},
46 {"headset", HEADSET_VOLUME_TYPE},
47 };
48 }
49
~AudioVolumeParser()50 AudioVolumeParser::~AudioVolumeParser()
51 {
52 AUDIO_INFO_LOG("AudioVolumeParser dtor");
53 }
54
ParseVolumeConfig(const char * path,StreamVolumeInfoMap & streamVolumeInfoMap)55 int32_t AudioVolumeParser::ParseVolumeConfig(const char *path, StreamVolumeInfoMap &streamVolumeInfoMap)
56 {
57 std::shared_ptr<AudioXmlNode> curNode = AudioXmlNode::Create();
58 int32_t ret = curNode->Config(path, nullptr, 0);
59 if (ret != SUCCESS) {
60 WriteVolumeConfigErrorEvent();
61 return ERROR;
62 }
63
64 if (!curNode->CompareName("audio_volume_config")) {
65 AUDIO_ERR_LOG("Missing tag - audio_volume_config in : %s", path);
66 WriteVolumeConfigErrorEvent();
67 curNode = nullptr;
68 return ERROR;
69 }
70 curNode->MoveToChildren();
71 if (!curNode->IsNodeValid()) {
72 AUDIO_ERR_LOG("empty volume config in : %s", path);
73 WriteVolumeConfigErrorEvent();
74 curNode = nullptr;
75 return ERROR;
76 }
77
78 while (curNode->IsNodeValid()) {
79 if (curNode->CompareName("volume_type")) {
80 ParseStreamInfos(curNode->GetCopyNode(), streamVolumeInfoMap);
81 break;
82 } else {
83 curNode->MoveToNext();
84 }
85 }
86 curNode = nullptr;
87 int32_t result = UseVoiceAssistantFixedVolumeConfig(streamVolumeInfoMap);
88 AUDIO_INFO_LOG("The voice assistant uses a fixed volume configuration. Result: %{public}d", result);
89 return SUCCESS;
90 }
91
UseVoiceAssistantFixedVolumeConfig(StreamVolumeInfoMap & streamVolumeInfoMap)92 int32_t AudioVolumeParser::UseVoiceAssistantFixedVolumeConfig(StreamVolumeInfoMap &streamVolumeInfoMap)
93 {
94 if (streamVolumeInfoMap.find(STREAM_VOICE_ASSISTANT) == streamVolumeInfoMap.end() ||
95 streamVolumeInfoMap[STREAM_VOICE_ASSISTANT] == nullptr) {
96 AUDIO_ERR_LOG("Failed to find the volume config of STREAM_VOICE_ASSISTANT!");
97 return ERROR;
98 }
99
100 // Allow to set voice assistant volume to 0.
101 streamVolumeInfoMap[STREAM_VOICE_ASSISTANT]->minLevel = 0;
102
103 // Modify the volume point index for volume level 0.
104 const std::vector<DeviceVolumeType> DEVICE_VOLUME_TYPE_LIST = {
105 EARPIECE_VOLUME_TYPE,
106 SPEAKER_VOLUME_TYPE,
107 HEADSET_VOLUME_TYPE,
108 };
109 DeviceVolumeInfoMap &deviceVolumeInfos = streamVolumeInfoMap[STREAM_VOICE_ASSISTANT]->deviceVolumeInfos;
110 for (auto device : DEVICE_VOLUME_TYPE_LIST) {
111 if (deviceVolumeInfos.find(device) == deviceVolumeInfos.end() ||
112 deviceVolumeInfos[device] == nullptr) {
113 AUDIO_ERR_LOG("Failed to find the device %{public}d in deviceVolumeInfos!", device);
114 continue;
115 }
116 deviceVolumeInfos[device]->minLevel = -1; // Ensure that the minLevel of this device is an invalid value.
117 std::vector<VolumePoint> &volumePoints = deviceVolumeInfos[device]->volumePoints;
118 if (volumePoints.empty()) {
119 AUDIO_ERR_LOG("The vector fo volumePoints is empty!");
120 continue;
121 }
122 if (volumePoints[0].index == 0) {
123 volumePoints[0].index = 1;
124 }
125 }
126 return SUCCESS;
127 }
128
WriteVolumeConfigErrorEvent()129 void AudioVolumeParser::WriteVolumeConfigErrorEvent()
130 {
131 Trace trace("SYSEVENT FAULT EVENT LOAD_CONFIG_ERROR, CATEGORY: "
132 + std::to_string(Media::MediaMonitor::AUDIO_VOLUME_CONFIG));
133 std::shared_ptr<Media::MediaMonitor::EventBean> bean = std::make_shared<Media::MediaMonitor::EventBean>(
134 Media::MediaMonitor::AUDIO, Media::MediaMonitor::LOAD_CONFIG_ERROR,
135 Media::MediaMonitor::FAULT_EVENT);
136 bean->Add("CATEGORY", Media::MediaMonitor::AUDIO_VOLUME_CONFIG);
137 Media::MediaMonitor::MediaMonitorManager::GetInstance().WriteLogMsg(bean);
138 }
139
LoadConfig(StreamVolumeInfoMap & streamVolumeInfoMap)140 int32_t AudioVolumeParser::LoadConfig(StreamVolumeInfoMap &streamVolumeInfoMap)
141 {
142 AUDIO_INFO_LOG("Load Volume Config xml");
143 int ret = ERROR;
144 #ifdef USE_CONFIG_POLICY
145 CfgFiles *cfgFiles = GetCfgFiles(AUDIO_VOLUME_CONFIG_FILE);
146 if (cfgFiles == nullptr) {
147 Trace trace("SYSEVENT FAULT EVENT LOAD_CONFIG_ERROR, CATEGORY: "
148 + std::to_string(Media::MediaMonitor::AUDIO_VOLUME_CONFIG));
149 AUDIO_ERR_LOG("Not found audio_volume_config.xml!");
150 std::shared_ptr<Media::MediaMonitor::EventBean> bean = std::make_shared<Media::MediaMonitor::EventBean>(
151 Media::MediaMonitor::AUDIO, Media::MediaMonitor::LOAD_CONFIG_ERROR,
152 Media::MediaMonitor::FAULT_EVENT);
153 bean->Add("CATEGORY", Media::MediaMonitor::AUDIO_VOLUME_CONFIG);
154 Media::MediaMonitor::MediaMonitorManager::GetInstance().WriteLogMsg(bean);
155 return ERROR;
156 }
157
158 for (int32_t i = MAX_CFG_POLICY_DIRS_CNT - 1; i >= 0; i--) {
159 if (cfgFiles->paths[i] && *(cfgFiles->paths[i]) != '\0') {
160 AUDIO_INFO_LOG("volume config file path:%{public}s", cfgFiles->paths[i]);
161 ret = ParseVolumeConfig(cfgFiles->paths[i], streamVolumeInfoMap);
162 break;
163 }
164 }
165 FreeCfgFiles(cfgFiles);
166 #else
167 ret = ParseVolumeConfig(AUDIO_VOLUME_CONFIG_FILE, streamVolumeInfoMap);
168 AUDIO_INFO_LOG("use default volume config file path:%{public}s", AUDIO_VOLUME_CONFIG_FILE);
169 #endif
170 return ret;
171 }
172
ParseStreamInfos(std::shared_ptr<AudioXmlNode> curNode,StreamVolumeInfoMap & streamVolumeInfoMap)173 void AudioVolumeParser::ParseStreamInfos(std::shared_ptr<AudioXmlNode> curNode,
174 StreamVolumeInfoMap &streamVolumeInfoMap)
175 {
176 AUDIO_DEBUG_LOG("AudioVolumeParser::ParseStreamInfos");
177 while (curNode->IsNodeValid()) {
178 if (curNode->CompareName("volume_type")) {
179 std::shared_ptr<StreamVolumeInfo> streamVolInfo = std::make_shared<StreamVolumeInfo>();
180 if (ParseStreamVolumeInfoAttr(curNode->GetCopyNode(), streamVolInfo) == AUDIO_OK) {
181 ParseDeviceVolumeInfos(curNode->GetChildrenNode(), streamVolInfo);
182 AUDIO_DEBUG_LOG("Parse streamType:%{public}d ", streamVolInfo->streamType);
183 streamVolumeInfoMap[streamVolInfo->streamType] = streamVolInfo;
184 }
185 }
186 curNode->MoveToNext();
187 }
188 }
189
ParseStreamVolumeInfoAttr(std::shared_ptr<AudioXmlNode> curNode,std::shared_ptr<StreamVolumeInfo> & streamVolInfo)190 int32_t AudioVolumeParser::ParseStreamVolumeInfoAttr(std::shared_ptr<AudioXmlNode> curNode,
191 std::shared_ptr<StreamVolumeInfo> &streamVolInfo)
192 {
193 AUDIO_DEBUG_LOG("AudioVolumeParser::ParseStreamVolumeInfoAttr");
194 std::string pValueStr;
195 CHECK_AND_RETURN_RET_LOG(curNode->GetProp("type", pValueStr) == SUCCESS,
196 ERR_INVALID_PARAM, "invalid type parameter");
197
198 if (pValueStr == "VOICE_PC") {
199 VolumeUtils::SetPCVolumeEnable(true);
200 AUDIO_INFO_LOG("PC Volume is Enable");
201 // only read PC volume flag
202 return ERR_NOT_SUPPORTED;
203 }
204 streamVolInfo->streamType = audioStreamMap_[pValueStr];
205
206 CHECK_AND_RETURN_RET_LOG(curNode->GetProp("minidx", pValueStr) == SUCCESS,
207 ERR_INVALID_PARAM, "invalid minidx parameter");
208 CHECK_AND_RETURN_RET_LOG(StringConverter<int32_t>(pValueStr, streamVolInfo->minLevel), ERROR,
209 "convert streamVolInfo->minLevel fail!");
210 AUDIO_DEBUG_LOG("minidx: %{public}d", streamVolInfo->minLevel);
211
212 CHECK_AND_RETURN_RET_LOG(curNode->GetProp("maxidx", pValueStr) == SUCCESS,
213 ERR_INVALID_PARAM, "invalid maxidx parameter");
214 CHECK_AND_RETURN_RET_LOG(StringConverter<int32_t>(pValueStr, streamVolInfo->maxLevel), ERROR,
215 "convert streamVolInfo->maxLevel fail!");
216 AUDIO_DEBUG_LOG("maxidx: %{public}d", streamVolInfo->maxLevel);
217
218 CHECK_AND_RETURN_RET_LOG(curNode->GetProp("defaultidx", pValueStr) == SUCCESS,
219 ERR_INVALID_PARAM, "invalid defaultidx parameter");
220 CHECK_AND_RETURN_RET_LOG(StringConverter<int32_t>(pValueStr, streamVolInfo->defaultLevel), ERROR,
221 "convert streamVolInfo->defaultLevel fail!");
222 AUDIO_DEBUG_LOG("defaultidx: %{public}d", streamVolInfo->defaultLevel);
223
224 return AUDIO_OK;
225 }
226
ParseDeviceVolumeInfos(std::shared_ptr<AudioXmlNode> curNode,std::shared_ptr<StreamVolumeInfo> & streamVolInfo)227 void AudioVolumeParser::ParseDeviceVolumeInfos(std::shared_ptr<AudioXmlNode> curNode,
228 std::shared_ptr<StreamVolumeInfo> &streamVolInfo)
229 {
230 AUDIO_DEBUG_LOG("AudioVolumeParser::ParseDeviceVolumeInfos");
231 while (curNode->IsNodeValid()) {
232 if (curNode->CompareName("volumecurve")) {
233 std::string pValueStr;
234 curNode->GetProp("deviceClass", pValueStr);
235 std::shared_ptr<DeviceVolumeInfo> deviceVolInfo = std::make_shared<DeviceVolumeInfo>();
236 deviceVolInfo->deviceType = audioDeviceMap_[pValueStr];
237 AUDIO_DEBUG_LOG("deviceVolInfo->deviceType %{public}d;", deviceVolInfo->deviceType);
238 int32_t result = curNode->GetProp("minidx", pValueStr);
239 if (result == SUCCESS) {
240 StringConverter<int32_t>(pValueStr, deviceVolInfo->minLevel);
241 AUDIO_DEBUG_LOG("minidx: %{public}d", deviceVolInfo->minLevel);
242 } else {
243 AUDIO_DEBUG_LOG("The minidx attribute is not configured or minidx parameter is invalid");
244 }
245 result = curNode->GetProp("maxidx", pValueStr);
246 if (result == SUCCESS) {
247 StringConverter<int32_t>(pValueStr, deviceVolInfo->maxLevel);
248 AUDIO_DEBUG_LOG("maxidx: %{public}d", deviceVolInfo->maxLevel);
249 } else {
250 AUDIO_DEBUG_LOG("The maxidx attribute is not configured or maxidx parameter is invalid");
251 }
252 result = curNode->GetProp("defaultidx", pValueStr);
253 if (result == SUCCESS) {
254 StringConverter<int32_t>(pValueStr, deviceVolInfo->defaultLevel);
255 AUDIO_DEBUG_LOG("defaultidx: %{public}d", deviceVolInfo->defaultLevel);
256 } else {
257 AUDIO_DEBUG_LOG("The defaultidx attribute is not configured or defaultidx parameter is invalid");
258 }
259 ParseVolumePoints(curNode->GetChildrenNode(), deviceVolInfo);
260 streamVolInfo->deviceVolumeInfos[deviceVolInfo->deviceType] = deviceVolInfo;
261 }
262 curNode->MoveToNext();
263 }
264 }
265
ParseVolumePoints(std::shared_ptr<AudioXmlNode> curNode,std::shared_ptr<DeviceVolumeInfo> & deviceVolInfo)266 void AudioVolumeParser::ParseVolumePoints(std::shared_ptr<AudioXmlNode> curNode,
267 std::shared_ptr<DeviceVolumeInfo> &deviceVolInfo)
268 {
269 AUDIO_DEBUG_LOG("AudioVolumeParser::ParseVolumePoints");
270 while (curNode->IsNodeValid()) {
271 if (curNode->CompareName("point")) {
272 struct VolumePoint volumePoint;
273 std::string pValueStr;
274 curNode->GetProp("idx", pValueStr);
275 CHECK_AND_RETURN_LOG(StringConverter(pValueStr, volumePoint.index),
276 "convert volumePoint.index fail!");
277 AUDIO_DEBUG_LOG("idx: %{public}d", volumePoint.index);
278
279 curNode->GetProp("decibel", pValueStr);
280 CHECK_AND_RETURN_LOG(StringConverter(pValueStr, volumePoint.dbValue),
281 "convert volumePoint.dbValue fail!");
282 AUDIO_DEBUG_LOG("decibel: %{public}d", volumePoint.dbValue);
283
284 deviceVolInfo->volumePoints.push_back(volumePoint);
285 }
286 curNode->MoveToNext();
287 }
288 }
289 } // namespace AudioStandard
290 } // namespace OHOS
291