1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <android-base/macros.h>
18
19 #include "7.0/Generators.h"
20 #include "7.0/PolicyConfig.h"
21
22 // clang-format off
23 #include PATH(android/hardware/audio/CORE_TYPES_FILE_VERSION/types.h)
24 #include PATH(android/hardware/audio/common/COMMON_TYPES_FILE_VERSION/types.h)
25 // clang-format on
26
27 #include PATH(APM_XSD_ENUMS_H_FILENAME)
28 #include PATH(APM_XSD_H_FILENAME)
29
30 // Forward declaration for functions that are substituted
31 // in generator unit tests.
32 const PolicyConfig& getCachedPolicyConfig();
33 const std::vector<DeviceParameter>& getDeviceParameters();
34
35 using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
36 using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
37 namespace xsd {
38 using namespace ::android::audio::policy::configuration::CPP_VERSION;
39 }
40
combineAudioConfig(std::vector<xsd::AudioChannelMask> channelMasks,std::vector<int64_t> sampleRates,const std::string & format)41 static std::vector<AudioConfig> combineAudioConfig(std::vector<xsd::AudioChannelMask> channelMasks,
42 std::vector<int64_t> sampleRates,
43 const std::string& format) {
44 std::vector<AudioConfig> configs;
45 configs.reserve(channelMasks.size() * sampleRates.size());
46 for (auto channelMask : channelMasks) {
47 for (auto sampleRate : sampleRates) {
48 AudioConfig config{};
49 config.base.channelMask = toString(channelMask);
50 config.base.sampleRateHz = sampleRate;
51 config.base.format = format;
52 configs.push_back(config);
53 }
54 }
55 return configs;
56 }
57
generateOutFlags(const xsd::MixPorts::MixPort & mixPort)58 static std::tuple<std::vector<AudioInOutFlag>, bool> generateOutFlags(
59 const xsd::MixPorts::MixPort& mixPort) {
60 std::vector<AudioInOutFlag> flags;
61 bool isOffload = false;
62 if (mixPort.hasFlags()) {
63 auto xsdFlags = mixPort.getFlags();
64 isOffload = std::find(xsdFlags.begin(), xsdFlags.end(),
65 xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) !=
66 xsdFlags.end();
67 for (auto flag : xsdFlags) {
68 if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
69 flags.push_back(toString(flag));
70 }
71 }
72 }
73 return {flags, isOffload};
74 }
75
generateOffloadInfo(const AudioConfigBase & base)76 static AudioOffloadInfo generateOffloadInfo(const AudioConfigBase& base) {
77 return AudioOffloadInfo{
78 .base = base,
79 .streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC),
80 .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
81 .bitRatePerSecond = 192, // as in sine882hz3s.mp3
82 .durationMicroseconds = -1,
83 .bitWidth = 16,
84 .bufferSize = 72000 // 3 seconds at 192 kbps, as in sine882hz3s.mp3
85 };
86 }
87
generateOutputDeviceConfigParameters(bool oneProfilePerDevice)88 std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(bool oneProfilePerDevice) {
89 std::vector<DeviceConfigParameter> result;
90 for (const auto& device : getDeviceParameters()) {
91 const std::string moduleName = std::get<PARAM_DEVICE_NAME>(device);
92 auto module = getCachedPolicyConfig().getModuleFromName(moduleName);
93 if (!module || !module->getFirstMixPorts()) break;
94 for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
95 if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile
96 const auto attachedDeviceAddress =
97 getCachedPolicyConfig().getDeviceAddressOfSinkDeviceAttachedToMixPort(
98 moduleName, mixPort.getName());
99 if (!attachedDeviceAddress.has_value()) continue;
100 auto [flags, isOffload] = generateOutFlags(mixPort);
101 for (const auto& profile : mixPort.getProfile()) {
102 if (!profile.hasFormat() || !profile.hasSamplingRates() ||
103 !profile.hasChannelMasks())
104 continue;
105 auto configs = combineAudioConfig(profile.getChannelMasks(),
106 profile.getSamplingRates(), profile.getFormat());
107 for (auto& config : configs) {
108 // Some combinations of flags declared in the config file require special
109 // treatment.
110 if (isOffload) {
111 config.offloadInfo.info(generateOffloadInfo(config.base));
112 }
113 result.emplace_back(device, mixPort.getName(), attachedDeviceAddress.value(),
114 config, flags);
115 if (oneProfilePerDevice) break;
116 }
117 if (oneProfilePerDevice) break;
118 }
119 if (oneProfilePerDevice) break;
120 }
121 }
122 return result;
123 }
124
getOutputDeviceConfigParameters()125 const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
126 static std::vector<DeviceConfigParameter> parameters =
127 generateOutputDeviceConfigParameters(false);
128 return parameters;
129 }
130
getOutputDeviceSingleConfigParameters()131 const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters() {
132 static std::vector<DeviceConfigParameter> parameters =
133 generateOutputDeviceConfigParameters(true);
134 return parameters;
135 }
136
getOutputDeviceInvalidConfigParameters(bool generateInvalidFlags)137 const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters(
138 bool generateInvalidFlags) {
139 static std::vector<DeviceConfigParameter> parameters = [&] {
140 std::vector<DeviceConfigParameter> result;
141 for (const auto& device : getDeviceParameters()) {
142 auto module =
143 getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
144 if (!module || !module->getFirstMixPorts()) break;
145 bool hasRegularConfig = false, hasOffloadConfig = false;
146 for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
147 if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile
148 auto [validFlags, isOffload] = generateOutFlags(mixPort);
149 if ((!isOffload && hasRegularConfig) || (isOffload && hasOffloadConfig)) continue;
150 for (const auto& profile : mixPort.getProfile()) {
151 if (!profile.hasFormat() || !profile.hasSamplingRates() ||
152 !profile.hasChannelMasks())
153 continue;
154 AudioConfigBase validBase = {
155 profile.getFormat(),
156 static_cast<uint32_t>(profile.getSamplingRates()[0]),
157 toString(profile.getChannelMasks()[0])};
158 DeviceAddress defaultDevice = {
159 toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT), {}};
160 {
161 AudioConfig config{.base = validBase};
162 config.base.channelMask = "random_string";
163 if (isOffload) {
164 config.offloadInfo.info(generateOffloadInfo(validBase));
165 }
166 result.emplace_back(device, mixPort.getName(), defaultDevice, config,
167 validFlags);
168 }
169 {
170 AudioConfig config{.base = validBase};
171 config.base.format = "random_string";
172 if (isOffload) {
173 config.offloadInfo.info(generateOffloadInfo(validBase));
174 }
175 result.emplace_back(device, mixPort.getName(), defaultDevice, config,
176 validFlags);
177 }
178 if (generateInvalidFlags) {
179 AudioConfig config{.base = validBase};
180 if (isOffload) {
181 config.offloadInfo.info(generateOffloadInfo(validBase));
182 }
183 std::vector<AudioInOutFlag> flags = {"random_string", ""};
184 result.emplace_back(device, mixPort.getName(), defaultDevice, config,
185 flags);
186 }
187 if (isOffload) {
188 {
189 AudioConfig config{.base = validBase};
190 config.offloadInfo.info(generateOffloadInfo(validBase));
191 config.offloadInfo.info().base.channelMask = "random_string";
192 result.emplace_back(device, mixPort.getName(), defaultDevice, config,
193 validFlags);
194 }
195 {
196 AudioConfig config{.base = validBase};
197 config.offloadInfo.info(generateOffloadInfo(validBase));
198 config.offloadInfo.info().base.format = "random_string";
199 result.emplace_back(device, mixPort.getName(), defaultDevice, config,
200 validFlags);
201 }
202 {
203 AudioConfig config{.base = validBase};
204 config.offloadInfo.info(generateOffloadInfo(validBase));
205 config.offloadInfo.info().streamType = "random_string";
206 result.emplace_back(device, mixPort.getName(), defaultDevice, config,
207 validFlags);
208 }
209 {
210 AudioConfig config{.base = validBase};
211 config.offloadInfo.info(generateOffloadInfo(validBase));
212 config.offloadInfo.info().usage = "random_string";
213 result.emplace_back(device, mixPort.getName(), defaultDevice, config,
214 validFlags);
215 }
216 hasOffloadConfig = true;
217 } else {
218 hasRegularConfig = true;
219 }
220 break;
221 }
222 if (hasOffloadConfig && hasRegularConfig) break;
223 }
224 }
225 return result;
226 }();
227 return parameters;
228 }
229
generateInputDeviceConfigParameters(bool oneProfilePerDevice)230 std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(bool oneProfilePerDevice) {
231 std::vector<DeviceConfigParameter> result;
232 for (const auto& device : getDeviceParameters()) {
233 const std::string moduleName = std::get<PARAM_DEVICE_NAME>(device);
234 auto module = getCachedPolicyConfig().getModuleFromName(moduleName);
235 if (!module || !module->getFirstMixPorts()) break;
236 for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
237 if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile
238 const auto attachedDeviceAddress =
239 getCachedPolicyConfig().getDeviceAddressOfSourceDeviceAttachedToMixPort(
240 moduleName, mixPort.getName());
241 if (!attachedDeviceAddress.has_value()) continue;
242 std::vector<AudioInOutFlag> flags;
243 if (mixPort.hasFlags()) {
244 std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
245 std::back_inserter(flags), [](auto flag) { return toString(flag); });
246 }
247 for (const auto& profile : mixPort.getProfile()) {
248 if (!profile.hasFormat() || !profile.hasSamplingRates() ||
249 !profile.hasChannelMasks())
250 continue;
251 auto configs = combineAudioConfig(profile.getChannelMasks(),
252 profile.getSamplingRates(), profile.getFormat());
253 for (const auto& config : configs) {
254 result.emplace_back(device, mixPort.getName(), attachedDeviceAddress.value(),
255 config, flags);
256 if (oneProfilePerDevice) break;
257 }
258 if (oneProfilePerDevice) break;
259 }
260 if (oneProfilePerDevice) break;
261 }
262 }
263 return result;
264 }
265
getInputDeviceConfigParameters()266 const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
267 static std::vector<DeviceConfigParameter> parameters =
268 generateInputDeviceConfigParameters(false);
269 return parameters;
270 }
271
getInputDeviceSingleConfigParameters()272 const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters() {
273 static std::vector<DeviceConfigParameter> parameters =
274 generateInputDeviceConfigParameters(true);
275 return parameters;
276 }
277
getInputDeviceInvalidConfigParameters(bool generateInvalidFlags)278 const std::vector<DeviceConfigParameter>& getInputDeviceInvalidConfigParameters(
279 bool generateInvalidFlags) {
280 static std::vector<DeviceConfigParameter> parameters = [&] {
281 std::vector<DeviceConfigParameter> result;
282 for (const auto& device : getDeviceParameters()) {
283 auto module =
284 getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
285 if (!module || !module->getFirstMixPorts()) break;
286 bool hasConfig = false;
287 for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
288 if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile
289 std::vector<AudioInOutFlag> validFlags;
290 if (mixPort.hasFlags()) {
291 std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
292 std::back_inserter(validFlags),
293 [](auto flag) { return toString(flag); });
294 }
295 for (const auto& profile : mixPort.getProfile()) {
296 if (!profile.hasFormat() || !profile.hasSamplingRates() ||
297 !profile.hasChannelMasks())
298 continue;
299 AudioConfigBase validBase = {
300 profile.getFormat(),
301 static_cast<uint32_t>(profile.getSamplingRates()[0]),
302 toString(profile.getChannelMasks()[0])};
303 DeviceAddress defaultDevice = {
304 toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT), {}};
305 {
306 AudioConfig config{.base = validBase};
307 config.base.channelMask = "random_string";
308 result.emplace_back(device, mixPort.getName(), defaultDevice, config,
309 validFlags);
310 }
311 {
312 AudioConfig config{.base = validBase};
313 config.base.format = "random_string";
314 result.emplace_back(device, mixPort.getName(), defaultDevice, config,
315 validFlags);
316 }
317 if (generateInvalidFlags) {
318 AudioConfig config{.base = validBase};
319 std::vector<AudioInOutFlag> flags = {"random_string", ""};
320 result.emplace_back(device, mixPort.getName(), defaultDevice, config,
321 flags);
322 }
323 hasConfig = true;
324 break;
325 }
326 if (hasConfig) break;
327 }
328 }
329 return result;
330 }();
331 return parameters;
332 }
333