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/FILE_VERSION/types.h)
24 #include PATH(android/hardware/audio/common/FILE_VERSION/types.h)
25 // clang-format on
26
27 #include <android_audio_policy_configuration_V7_0-enums.h>
28 #include <android_audio_policy_configuration_V7_0.h>
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::CPP_VERSION;
36 using namespace ::android::hardware::audio::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 static const std::vector<AudioInOutFlag> offloadFlags = {
61 toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
62 toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)};
63 std::vector<AudioInOutFlag> flags;
64 bool isOffload = false;
65 if (mixPort.hasFlags()) {
66 auto xsdFlags = mixPort.getFlags();
67 isOffload = std::find(xsdFlags.begin(), xsdFlags.end(),
68 xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) !=
69 xsdFlags.end();
70 if (!isOffload) {
71 for (auto flag : xsdFlags) {
72 if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
73 flags.push_back(toString(flag));
74 }
75 }
76 } else {
77 flags = offloadFlags;
78 }
79 }
80 return {flags, isOffload};
81 }
82
generateOffloadInfo(const AudioConfigBase & base)83 static AudioOffloadInfo generateOffloadInfo(const AudioConfigBase& base) {
84 return AudioOffloadInfo{
85 .base = base,
86 .streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC),
87 .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
88 .bitRatePerSecond = 320,
89 .durationMicroseconds = -1,
90 .bitWidth = 16,
91 .bufferSize = 256 // arbitrary value
92 };
93 }
94
generateOutputDeviceConfigParameters(bool oneProfilePerDevice)95 std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(bool oneProfilePerDevice) {
96 std::vector<DeviceConfigParameter> result;
97 for (const auto& device : getDeviceParameters()) {
98 const std::string moduleName = std::get<PARAM_DEVICE_NAME>(device);
99 auto module = getCachedPolicyConfig().getModuleFromName(moduleName);
100 if (!module || !module->getFirstMixPorts()) break;
101 for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
102 if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile
103 if (getCachedPolicyConfig()
104 .getAttachedSinkDeviceForMixPort(moduleName, mixPort.getName())
105 .empty()) {
106 continue; // no attached device
107 }
108 auto [flags, isOffload] = generateOutFlags(mixPort);
109 for (const auto& profile : mixPort.getProfile()) {
110 if (!profile.hasFormat() || !profile.hasSamplingRates() ||
111 !profile.hasChannelMasks())
112 continue;
113 auto configs = combineAudioConfig(profile.getChannelMasks(),
114 profile.getSamplingRates(), profile.getFormat());
115 for (auto& config : configs) {
116 // Some combinations of flags declared in the config file require special
117 // treatment.
118 if (isOffload) {
119 config.offloadInfo.info(generateOffloadInfo(config.base));
120 }
121 result.emplace_back(device, mixPort.getName(), config, flags);
122 if (oneProfilePerDevice) break;
123 }
124 if (oneProfilePerDevice) break;
125 }
126 if (oneProfilePerDevice) break;
127 }
128 }
129 return result;
130 }
131
getOutputDeviceConfigParameters()132 const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
133 static std::vector<DeviceConfigParameter> parameters =
134 generateOutputDeviceConfigParameters(false);
135 return parameters;
136 }
137
getOutputDeviceSingleConfigParameters()138 const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters() {
139 static std::vector<DeviceConfigParameter> parameters =
140 generateOutputDeviceConfigParameters(true);
141 return parameters;
142 }
143
getOutputDeviceInvalidConfigParameters(bool generateInvalidFlags)144 const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters(
145 bool generateInvalidFlags) {
146 static std::vector<DeviceConfigParameter> parameters = [&] {
147 std::vector<DeviceConfigParameter> result;
148 for (const auto& device : getDeviceParameters()) {
149 auto module =
150 getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
151 if (!module || !module->getFirstMixPorts()) break;
152 bool hasRegularConfig = false, hasOffloadConfig = false;
153 for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
154 if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile
155 auto [validFlags, isOffload] = generateOutFlags(mixPort);
156 if ((!isOffload && hasRegularConfig) || (isOffload && hasOffloadConfig)) continue;
157 for (const auto& profile : mixPort.getProfile()) {
158 if (!profile.hasFormat() || !profile.hasSamplingRates() ||
159 !profile.hasChannelMasks())
160 continue;
161 AudioConfigBase validBase = {
162 profile.getFormat(),
163 static_cast<uint32_t>(profile.getSamplingRates()[0]),
164 toString(profile.getChannelMasks()[0])};
165 {
166 AudioConfig config{.base = validBase};
167 config.base.channelMask = "random_string";
168 if (isOffload) {
169 config.offloadInfo.info(generateOffloadInfo(validBase));
170 }
171 result.emplace_back(device, mixPort.getName(), config, validFlags);
172 }
173 {
174 AudioConfig config{.base = validBase};
175 config.base.format = "random_string";
176 if (isOffload) {
177 config.offloadInfo.info(generateOffloadInfo(validBase));
178 }
179 result.emplace_back(device, mixPort.getName(), config, validFlags);
180 }
181 if (generateInvalidFlags) {
182 AudioConfig config{.base = validBase};
183 if (isOffload) {
184 config.offloadInfo.info(generateOffloadInfo(validBase));
185 }
186 std::vector<AudioInOutFlag> flags = {"random_string", ""};
187 result.emplace_back(device, mixPort.getName(), config, flags);
188 }
189 if (isOffload) {
190 {
191 AudioConfig config{.base = validBase};
192 config.offloadInfo.info(generateOffloadInfo(validBase));
193 config.offloadInfo.info().base.channelMask = "random_string";
194 result.emplace_back(device, mixPort.getName(), config, validFlags);
195 }
196 {
197 AudioConfig config{.base = validBase};
198 config.offloadInfo.info(generateOffloadInfo(validBase));
199 config.offloadInfo.info().base.format = "random_string";
200 result.emplace_back(device, mixPort.getName(), config, 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(), config, validFlags);
207 }
208 {
209 AudioConfig config{.base = validBase};
210 config.offloadInfo.info(generateOffloadInfo(validBase));
211 config.offloadInfo.info().usage = "random_string";
212 result.emplace_back(device, mixPort.getName(), config, validFlags);
213 }
214 hasOffloadConfig = true;
215 } else {
216 hasRegularConfig = true;
217 }
218 break;
219 }
220 if (hasOffloadConfig && hasRegularConfig) break;
221 }
222 }
223 return result;
224 }();
225 return parameters;
226 }
227
generateInputDeviceConfigParameters(bool oneProfilePerDevice)228 std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(bool oneProfilePerDevice) {
229 std::vector<DeviceConfigParameter> result;
230 for (const auto& device : getDeviceParameters()) {
231 const std::string moduleName = std::get<PARAM_DEVICE_NAME>(device);
232 auto module = getCachedPolicyConfig().getModuleFromName(moduleName);
233 if (!module || !module->getFirstMixPorts()) break;
234 for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
235 if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile
236 if (getCachedPolicyConfig()
237 .getAttachedSourceDeviceForMixPort(moduleName, mixPort.getName())
238 .empty()) {
239 continue; // no attached device
240 }
241 std::vector<AudioInOutFlag> flags;
242 if (mixPort.hasFlags()) {
243 std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
244 std::back_inserter(flags), [](auto flag) { return toString(flag); });
245 }
246 for (const auto& profile : mixPort.getProfile()) {
247 if (!profile.hasFormat() || !profile.hasSamplingRates() ||
248 !profile.hasChannelMasks())
249 continue;
250 auto configs = combineAudioConfig(profile.getChannelMasks(),
251 profile.getSamplingRates(), profile.getFormat());
252 for (const auto& config : configs) {
253 result.emplace_back(device, mixPort.getName(), config, flags);
254 if (oneProfilePerDevice) break;
255 }
256 if (oneProfilePerDevice) break;
257 }
258 if (oneProfilePerDevice) break;
259 }
260 }
261 return result;
262 }
263
getInputDeviceConfigParameters()264 const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
265 static std::vector<DeviceConfigParameter> parameters =
266 generateInputDeviceConfigParameters(false);
267 return parameters;
268 }
269
getInputDeviceSingleConfigParameters()270 const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters() {
271 static std::vector<DeviceConfigParameter> parameters =
272 generateInputDeviceConfigParameters(true);
273 return parameters;
274 }
275
getInputDeviceInvalidConfigParameters(bool generateInvalidFlags)276 const std::vector<DeviceConfigParameter>& getInputDeviceInvalidConfigParameters(
277 bool generateInvalidFlags) {
278 static std::vector<DeviceConfigParameter> parameters = [&] {
279 std::vector<DeviceConfigParameter> result;
280 for (const auto& device : getDeviceParameters()) {
281 auto module =
282 getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
283 if (!module || !module->getFirstMixPorts()) break;
284 bool hasConfig = false;
285 for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
286 if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile
287 std::vector<AudioInOutFlag> validFlags;
288 if (mixPort.hasFlags()) {
289 std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
290 std::back_inserter(validFlags),
291 [](auto flag) { return toString(flag); });
292 }
293 for (const auto& profile : mixPort.getProfile()) {
294 if (!profile.hasFormat() || !profile.hasSamplingRates() ||
295 !profile.hasChannelMasks())
296 continue;
297 AudioConfigBase validBase = {
298 profile.getFormat(),
299 static_cast<uint32_t>(profile.getSamplingRates()[0]),
300 toString(profile.getChannelMasks()[0])};
301 {
302 AudioConfig config{.base = validBase};
303 config.base.channelMask = "random_string";
304 result.emplace_back(device, mixPort.getName(), config, validFlags);
305 }
306 {
307 AudioConfig config{.base = validBase};
308 config.base.format = "random_string";
309 result.emplace_back(device, mixPort.getName(), config, validFlags);
310 }
311 if (generateInvalidFlags) {
312 AudioConfig config{.base = validBase};
313 std::vector<AudioInOutFlag> flags = {"random_string", ""};
314 result.emplace_back(device, mixPort.getName(), config, flags);
315 }
316 hasConfig = true;
317 break;
318 }
319 if (hasConfig) break;
320 }
321 }
322 return result;
323 }();
324 return parameters;
325 }
326