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 auto module =
99 getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
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 auto [flags, isOffload] = generateOutFlags(mixPort);
104 for (const auto& profile : mixPort.getProfile()) {
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(), config, flags);
114 if (oneProfilePerDevice) break;
115 }
116 if (oneProfilePerDevice) break;
117 }
118 if (oneProfilePerDevice) break;
119 }
120 }
121 return result;
122 }
123
getOutputDeviceConfigParameters()124 const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
125 static std::vector<DeviceConfigParameter> parameters =
126 generateOutputDeviceConfigParameters(false);
127 return parameters;
128 }
129
getOutputDeviceSingleConfigParameters()130 const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters() {
131 static std::vector<DeviceConfigParameter> parameters =
132 generateOutputDeviceConfigParameters(true);
133 return parameters;
134 }
135
getOutputDeviceInvalidConfigParameters(bool generateInvalidFlags)136 const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters(
137 bool generateInvalidFlags) {
138 static std::vector<DeviceConfigParameter> parameters = [&] {
139 std::vector<DeviceConfigParameter> result;
140 for (const auto& device : getDeviceParameters()) {
141 auto module =
142 getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
143 if (!module || !module->getFirstMixPorts()) break;
144 bool hasRegularConfig = false, hasOffloadConfig = false;
145 for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
146 if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile
147 auto [validFlags, isOffload] = generateOutFlags(mixPort);
148 if ((!isOffload && hasRegularConfig) || (isOffload && hasOffloadConfig)) continue;
149 for (const auto& profile : mixPort.getProfile()) {
150 if (!profile.hasFormat() || !profile.hasSamplingRates() ||
151 !profile.hasChannelMasks())
152 continue;
153 AudioConfigBase validBase = {
154 profile.getFormat(),
155 static_cast<uint32_t>(profile.getSamplingRates()[0]),
156 toString(profile.getChannelMasks()[0])};
157 {
158 AudioConfig config{.base = validBase};
159 config.base.channelMask = "random_string";
160 if (isOffload) {
161 config.offloadInfo.info(generateOffloadInfo(validBase));
162 }
163 result.emplace_back(device, mixPort.getName(), config, validFlags);
164 }
165 {
166 AudioConfig config{.base = validBase};
167 config.base.format = "random_string";
168 if (isOffload) {
169 config.offloadInfo.info(generateOffloadInfo(validBase));
170 }
171 result.emplace_back(device, mixPort.getName(), config, validFlags);
172 }
173 if (generateInvalidFlags) {
174 AudioConfig config{.base = validBase};
175 if (isOffload) {
176 config.offloadInfo.info(generateOffloadInfo(validBase));
177 }
178 std::vector<AudioInOutFlag> flags = {"random_string", ""};
179 result.emplace_back(device, mixPort.getName(), config, flags);
180 }
181 if (isOffload) {
182 {
183 AudioConfig config{.base = validBase};
184 config.offloadInfo.info(generateOffloadInfo(validBase));
185 config.offloadInfo.info().base.channelMask = "random_string";
186 result.emplace_back(device, mixPort.getName(), config, validFlags);
187 }
188 {
189 AudioConfig config{.base = validBase};
190 config.offloadInfo.info(generateOffloadInfo(validBase));
191 config.offloadInfo.info().base.format = "random_string";
192 result.emplace_back(device, mixPort.getName(), config, validFlags);
193 }
194 {
195 AudioConfig config{.base = validBase};
196 config.offloadInfo.info(generateOffloadInfo(validBase));
197 config.offloadInfo.info().streamType = "random_string";
198 result.emplace_back(device, mixPort.getName(), config, validFlags);
199 }
200 {
201 AudioConfig config{.base = validBase};
202 config.offloadInfo.info(generateOffloadInfo(validBase));
203 config.offloadInfo.info().usage = "random_string";
204 result.emplace_back(device, mixPort.getName(), config, validFlags);
205 }
206 hasOffloadConfig = true;
207 } else {
208 hasRegularConfig = true;
209 }
210 break;
211 }
212 if (hasOffloadConfig && hasRegularConfig) break;
213 }
214 }
215 return result;
216 }();
217 return parameters;
218 }
219
generateInputDeviceConfigParameters(bool oneProfilePerDevice)220 std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(bool oneProfilePerDevice) {
221 std::vector<DeviceConfigParameter> result;
222 for (const auto& device : getDeviceParameters()) {
223 auto module =
224 getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
225 if (!module || !module->getFirstMixPorts()) break;
226 for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
227 if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile
228 std::vector<AudioInOutFlag> flags;
229 if (mixPort.hasFlags()) {
230 std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
231 std::back_inserter(flags), [](auto flag) { return toString(flag); });
232 }
233 for (const auto& profile : mixPort.getProfile()) {
234 auto configs = combineAudioConfig(profile.getChannelMasks(),
235 profile.getSamplingRates(), profile.getFormat());
236 for (const auto& config : configs) {
237 result.emplace_back(device, mixPort.getName(), config, flags);
238 if (oneProfilePerDevice) break;
239 }
240 if (oneProfilePerDevice) break;
241 }
242 if (oneProfilePerDevice) break;
243 }
244 }
245 return result;
246 }
247
getInputDeviceConfigParameters()248 const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
249 static std::vector<DeviceConfigParameter> parameters =
250 generateInputDeviceConfigParameters(false);
251 return parameters;
252 }
253
getInputDeviceSingleConfigParameters()254 const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters() {
255 static std::vector<DeviceConfigParameter> parameters =
256 generateInputDeviceConfigParameters(true);
257 return parameters;
258 }
259
getInputDeviceInvalidConfigParameters(bool generateInvalidFlags)260 const std::vector<DeviceConfigParameter>& getInputDeviceInvalidConfigParameters(
261 bool generateInvalidFlags) {
262 static std::vector<DeviceConfigParameter> parameters = [&] {
263 std::vector<DeviceConfigParameter> result;
264 for (const auto& device : getDeviceParameters()) {
265 auto module =
266 getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
267 if (!module || !module->getFirstMixPorts()) break;
268 bool hasConfig = false;
269 for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
270 if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile
271 std::vector<AudioInOutFlag> validFlags;
272 if (mixPort.hasFlags()) {
273 std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
274 std::back_inserter(validFlags),
275 [](auto flag) { return toString(flag); });
276 }
277 for (const auto& profile : mixPort.getProfile()) {
278 if (!profile.hasFormat() || !profile.hasSamplingRates() ||
279 !profile.hasChannelMasks())
280 continue;
281 AudioConfigBase validBase = {
282 profile.getFormat(),
283 static_cast<uint32_t>(profile.getSamplingRates()[0]),
284 toString(profile.getChannelMasks()[0])};
285 {
286 AudioConfig config{.base = validBase};
287 config.base.channelMask = "random_string";
288 result.emplace_back(device, mixPort.getName(), config, validFlags);
289 }
290 {
291 AudioConfig config{.base = validBase};
292 config.base.format = "random_string";
293 result.emplace_back(device, mixPort.getName(), config, validFlags);
294 }
295 if (generateInvalidFlags) {
296 AudioConfig config{.base = validBase};
297 std::vector<AudioInOutFlag> flags = {"random_string", ""};
298 result.emplace_back(device, mixPort.getName(), config, flags);
299 }
300 hasConfig = true;
301 break;
302 }
303 if (hasConfig) break;
304 }
305 }
306 return result;
307 }();
308 return parameters;
309 }
310