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