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 "AudioConverterParser"
17 #endif
18
19 #include "audio_converter_parser.h"
20 #ifdef USE_CONFIG_POLICY
21 #endif
22
23 #include "media_monitor_manager.h"
24 #include "audio_xml_parser.h"
25 #include "audio_errors.h"
26
27 namespace OHOS {
28 namespace AudioStandard {
29
30 #ifdef USE_CONFIG_POLICY
31 static constexpr char AUDIO_CONVERTER_CONFIG_FILE[] = "/etc/audio/audio_converter_config.xml";
32 #else
33 static constexpr char AUDIO_CONVERTER_CONFIG_FILE[] = "/system/etc/audio/audio_converter_config.xml";
34 #endif
35
36 static constexpr int32_t FILE_CONTENT_ERROR = -2;
37 static constexpr int32_t FILE_PARSE_ERROR = -3;
38
39 enum XML_ERROR {
40 XML_PARSE_RECOVER = 1 << 0, // recover on errors
41 XML_PARSE_NOERROR = 1 << 5, // suppress error reports
42 XML_PARSE_NOWARNING = 1 << 6, // suppress warning reports
43 XML_PARSE_PEDANTIC = 1 << 7 // pedantic error reporting
44 };
45
46 static std::map<std::string, AudioChannelLayout> str2layout = {
47 {"CH_LAYOUT_UNKNOWN", CH_LAYOUT_UNKNOWN},
48 {"CH_LAYOUT_MONO", CH_LAYOUT_MONO},
49 {"CH_LAYOUT_STEREO", CH_LAYOUT_STEREO},
50 {"CH_LAYOUT_STEREO_DOWNMIX", CH_LAYOUT_STEREO_DOWNMIX},
51 {"CH_LAYOUT_2POINT1", CH_LAYOUT_2POINT1},
52 {"CH_LAYOUT_3POINT0", CH_LAYOUT_3POINT0},
53 {"CH_LAYOUT_SURROUND", CH_LAYOUT_SURROUND},
54 {"CH_LAYOUT_3POINT1", CH_LAYOUT_3POINT1},
55 {"CH_LAYOUT_4POINT0", CH_LAYOUT_4POINT0},
56 {"CH_LAYOUT_QUAD_SIDE", CH_LAYOUT_QUAD_SIDE},
57 {"CH_LAYOUT_QUAD", CH_LAYOUT_QUAD},
58 {"CH_LAYOUT_2POINT0POINT2", CH_LAYOUT_2POINT0POINT2},
59 {"CH_LAYOUT_4POINT1", CH_LAYOUT_4POINT1},
60 {"CH_LAYOUT_5POINT0", CH_LAYOUT_5POINT0},
61 {"CH_LAYOUT_5POINT0_BACK", CH_LAYOUT_5POINT0_BACK},
62 {"CH_LAYOUT_2POINT1POINT2", CH_LAYOUT_2POINT1POINT2},
63 {"CH_LAYOUT_3POINT0POINT2", CH_LAYOUT_3POINT0POINT2},
64 {"CH_LAYOUT_5POINT1", CH_LAYOUT_5POINT1},
65 {"CH_LAYOUT_5POINT1_BACK", CH_LAYOUT_5POINT1_BACK},
66 {"CH_LAYOUT_6POINT0", CH_LAYOUT_6POINT0},
67 {"CH_LAYOUT_HEXAGONAL", CH_LAYOUT_HEXAGONAL},
68 {"CH_LAYOUT_3POINT1POINT2", CH_LAYOUT_3POINT1POINT2},
69 {"CH_LAYOUT_6POINT0_FRONT", CH_LAYOUT_6POINT0_FRONT},
70 {"CH_LAYOUT_6POINT1", CH_LAYOUT_6POINT1},
71 {"CH_LAYOUT_6POINT1_BACK", CH_LAYOUT_6POINT1_BACK},
72 {"CH_LAYOUT_6POINT1_FRONT", CH_LAYOUT_6POINT1_FRONT},
73 {"CH_LAYOUT_7POINT0", CH_LAYOUT_7POINT0},
74 {"CH_LAYOUT_7POINT0_FRONT", CH_LAYOUT_7POINT0_FRONT},
75 {"CH_LAYOUT_7POINT1", CH_LAYOUT_7POINT1},
76 {"CH_LAYOUT_OCTAGONAL", CH_LAYOUT_OCTAGONAL},
77 {"CH_LAYOUT_5POINT1POINT2", CH_LAYOUT_5POINT1POINT2},
78 {"CH_LAYOUT_7POINT1_WIDE", CH_LAYOUT_7POINT1_WIDE},
79 {"CH_LAYOUT_7POINT1_WIDE_BACK", CH_LAYOUT_7POINT1_WIDE_BACK},
80 {"CH_LAYOUT_5POINT1POINT4", CH_LAYOUT_5POINT1POINT4},
81 {"CH_LAYOUT_7POINT1POINT2", CH_LAYOUT_7POINT1POINT2},
82 {"CH_LAYOUT_7POINT1POINT4", CH_LAYOUT_7POINT1POINT4},
83 {"CH_LAYOUT_10POINT2", CH_LAYOUT_10POINT2},
84 {"CH_LAYOUT_9POINT1POINT4", CH_LAYOUT_9POINT1POINT4},
85 {"CH_LAYOUT_9POINT1POINT6", CH_LAYOUT_9POINT1POINT6},
86 {"CH_LAYOUT_HEXADECAGONAL", CH_LAYOUT_HEXADECAGONAL},
87 {"CH_LAYOUT_AMB_ORDER1_ACN_N3D", CH_LAYOUT_HOA_ORDER1_ACN_N3D},
88 {"CH_LAYOUT_AMB_ORDER1_ACN_SN3D", CH_LAYOUT_HOA_ORDER1_ACN_SN3D},
89 {"CH_LAYOUT_AMB_ORDER1_FUMA", CH_LAYOUT_HOA_ORDER1_FUMA},
90 {"CH_LAYOUT_AMB_ORDER2_ACN_N3D", CH_LAYOUT_HOA_ORDER2_ACN_N3D},
91 {"CH_LAYOUT_AMB_ORDER2_ACN_SN3D", CH_LAYOUT_HOA_ORDER2_ACN_SN3D},
92 {"CH_LAYOUT_AMB_ORDER2_FUMA", CH_LAYOUT_HOA_ORDER2_FUMA},
93 {"CH_LAYOUT_AMB_ORDER3_ACN_N3D", CH_LAYOUT_HOA_ORDER3_ACN_N3D},
94 {"CH_LAYOUT_AMB_ORDER3_ACN_SN3D", CH_LAYOUT_HOA_ORDER3_ACN_SN3D},
95 {"CH_LAYOUT_AMB_ORDER3_FUMA", CH_LAYOUT_HOA_ORDER3_FUMA},
96 };
97
WriteConverterConfigError()98 static void WriteConverterConfigError()
99 {
100 std::shared_ptr<Media::MediaMonitor::EventBean> bean = std::make_shared<Media::MediaMonitor::EventBean>(
101 Media::MediaMonitor::AUDIO, Media::MediaMonitor::LOAD_CONFIG_ERROR,
102 Media::MediaMonitor::FAULT_EVENT);
103 bean->Add("CATEGORY", Media::MediaMonitor::AUDIO_CONVERTER_CONFIG);
104 Media::MediaMonitor::MediaMonitorManager::GetInstance().WriteLogMsg(bean);
105 }
106
AudioConverterParser()107 AudioConverterParser::AudioConverterParser()
108 {
109 AUDIO_INFO_LOG("AudioConverterParser created");
110 }
111
LoadConfigLibrary(ConverterConfig & result,std::shared_ptr<AudioXmlNode> curNode)112 static void LoadConfigLibrary(ConverterConfig &result, std::shared_ptr<AudioXmlNode> curNode)
113 {
114 std::string libName;
115 std::string libPath;
116 curNode->GetProp("name", libName);
117 curNode->GetProp("path", libPath);
118 result.library = {libName, libPath};
119 }
120
LoadConfigChannelLayout(ConverterConfig & result,std::shared_ptr<AudioXmlNode> curNode)121 static void LoadConfigChannelLayout(ConverterConfig &result, std::shared_ptr<AudioXmlNode> curNode)
122 {
123 if (!curNode->HasProp("out_channel_layout")) {
124 AUDIO_ERR_LOG("missing information: config has no out_channel_layout attribute, set to default STEREO");
125 result.outChannelLayout = CH_LAYOUT_STEREO;
126 } else {
127 std::string strChannelLayout;
128 curNode->GetProp("out_channel_layout", strChannelLayout);
129 if (str2layout.count(strChannelLayout) == 0) {
130 AUDIO_ERR_LOG("unsupported format: invalid channel layout, set to STEREO");
131 result.outChannelLayout = CH_LAYOUT_STEREO;
132 } else {
133 result.outChannelLayout = str2layout[strChannelLayout];
134 AUDIO_INFO_LOG("AudioVivid MCR output format is %{public}s", strChannelLayout.c_str());
135 }
136 }
137 }
138
GetInstance()139 AudioConverterParser &AudioConverterParser::GetInstance()
140 {
141 static AudioConverterParser instance;
142 return instance;
143 }
144
LoadConfig()145 ConverterConfig AudioConverterParser::LoadConfig()
146 {
147 std::lock_guard<std::mutex> lock(loadConfigMutex_);
148 AUDIO_INFO_LOG("AudioConverterParser::LoadConfig");
149 CHECK_AND_RETURN_RET(cfg_ == nullptr, *cfg_);
150 std::shared_ptr<AudioXmlNode> curNode = AudioXmlNode::Create();
151 cfg_ = std::make_unique<ConverterConfig>();
152 ConverterConfig &result = *cfg_;
153
154 AUDIO_INFO_LOG("use default audio effect config file path: %{public}s", AUDIO_CONVERTER_CONFIG_FILE);
155 curNode->Config(AUDIO_CONVERTER_CONFIG_FILE, nullptr, XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
156 if (!curNode->IsNodeValid()) {
157 WriteConverterConfigError();
158 AUDIO_ERR_LOG("error: could not parse file %{public}s", AUDIO_CONVERTER_CONFIG_FILE);
159 return result;
160 }
161
162 CHECK_AND_RETURN_RET_LOG(curNode->CompareName("audio_converter_conf"), result,
163 "Missing tag - audio_converter_conf: %{public}s", AUDIO_CONVERTER_CONFIG_FILE);
164 curNode->GetProp("version", result.version);
165
166 curNode->MoveToChildren();
167 while (curNode->IsNodeValid()) {
168 if (!curNode->IsElementNode()) {
169 curNode->MoveToNext();
170 continue;
171 }
172 if (curNode->CompareName("library")) {
173 LoadConfigLibrary(result, curNode->GetCopyNode());
174 } else if (curNode->CompareName("converter_conf")) {
175 LoadConfigChannelLayout(result, curNode->GetCopyNode());
176 }
177 curNode->MoveToNext();
178 }
179 curNode = nullptr;
180 return result;
181 }
182 } // namespace AudioStandard
183 } // namespace OHOS