1 /*
2 * Copyright (C) 2023 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 <set>
18 #include <string>
19 #include <unordered_map>
20 #include <unordered_set>
21 #include <vector>
22
23 #define LOG_TAG "VtsHalAudioCore.Config"
24
25 #include <Utils.h>
26 #include <aidl/Gtest.h>
27 #include <aidl/Vintf.h>
28 #include <aidl/android/hardware/audio/core/IConfig.h>
29 #include <aidl/android/media/audio/common/AudioFlag.h>
30 #include <aidl/android/media/audio/common/AudioProductStrategyType.h>
31 #include <android-base/logging.h>
32
33 #include "AudioHalBinderServiceUtil.h"
34 #include "TestUtils.h"
35
36 using namespace android;
37 using aidl::android::hardware::audio::common::isDefaultAudioFormat;
38 using aidl::android::hardware::audio::core::IConfig;
39 using aidl::android::hardware::audio::core::SurroundSoundConfig;
40 using aidl::android::media::audio::common::AudioAttributes;
41 using aidl::android::media::audio::common::AudioDeviceAddress;
42 using aidl::android::media::audio::common::AudioDeviceDescription;
43 using aidl::android::media::audio::common::AudioFlag;
44 using aidl::android::media::audio::common::AudioFormatDescription;
45 using aidl::android::media::audio::common::AudioFormatType;
46 using aidl::android::media::audio::common::AudioHalAttributesGroup;
47 using aidl::android::media::audio::common::AudioHalCapConfiguration;
48 using aidl::android::media::audio::common::AudioHalCapCriterionV2;
49 using aidl::android::media::audio::common::AudioHalCapDomain;
50 using aidl::android::media::audio::common::AudioHalCapParameter;
51 using aidl::android::media::audio::common::AudioHalCapRule;
52 using aidl::android::media::audio::common::AudioHalEngineConfig;
53 using aidl::android::media::audio::common::AudioHalProductStrategy;
54 using aidl::android::media::audio::common::AudioHalVolumeCurve;
55 using aidl::android::media::audio::common::AudioHalVolumeGroup;
56 using aidl::android::media::audio::common::AudioMode;
57 using aidl::android::media::audio::common::AudioPolicyForceUse;
58 using aidl::android::media::audio::common::AudioProductStrategyType;
59 using aidl::android::media::audio::common::AudioSource;
60 using aidl::android::media::audio::common::AudioStreamType;
61 using aidl::android::media::audio::common::AudioUsage;
62 using aidl::android::media::audio::common::PcmType;
63
64 class AudioCoreConfig : public testing::TestWithParam<std::string> {
65 public:
SetUp()66 void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService()); }
ConnectToService()67 void ConnectToService() {
68 mConfig = IConfig::fromBinder(mBinderUtil.connectToService(GetParam()));
69 ASSERT_NE(mConfig, nullptr);
70 }
71
RestartService()72 void RestartService() {
73 ASSERT_NE(mConfig, nullptr);
74 mEngineConfig.reset();
75 mSurroundSoundConfig.reset();
76 mConfig = IConfig::fromBinder(mBinderUtil.restartService());
77 ASSERT_NE(mConfig, nullptr);
78 }
79
SetUpEngineConfig()80 void SetUpEngineConfig() {
81 if (mEngineConfig == nullptr) {
82 auto tempConfig = std::make_unique<AudioHalEngineConfig>();
83 ASSERT_IS_OK(mConfig->getEngineConfig(tempConfig.get()));
84 mEngineConfig = std::move(tempConfig);
85 }
86 }
87
SetUpSurroundSoundConfig()88 void SetUpSurroundSoundConfig() {
89 if (mSurroundSoundConfig == nullptr) {
90 auto tempConfig = std::make_unique<SurroundSoundConfig>();
91 ASSERT_IS_OK(mConfig->getSurroundSoundConfig(tempConfig.get()));
92 mSurroundSoundConfig = std::move(tempConfig);
93 }
94 }
95
IsProductStrategyTypeReservedForSystemUse(const AudioProductStrategyType & pst)96 static bool IsProductStrategyTypeReservedForSystemUse(const AudioProductStrategyType& pst) {
97 switch (pst) {
98 case AudioProductStrategyType::SYS_RESERVED_NONE:
99 case AudioProductStrategyType::SYS_RESERVED_REROUTING:
100 case AudioProductStrategyType::SYS_RESERVED_CALL_ASSISTANT:
101 return true;
102 default:
103 return false;
104 }
105 }
106
IsStreamTypeReservedForSystemUse(const AudioStreamType & streamType)107 static bool IsStreamTypeReservedForSystemUse(const AudioStreamType& streamType) {
108 switch (streamType) {
109 case AudioStreamType::SYS_RESERVED_DEFAULT:
110 case AudioStreamType::SYS_RESERVED_REROUTING:
111 case AudioStreamType::SYS_RESERVED_PATCH:
112 case AudioStreamType::CALL_ASSISTANT:
113 return true;
114 default:
115 return false;
116 }
117 }
118
IsAudioUsageValid(const AudioUsage & usage)119 static bool IsAudioUsageValid(const AudioUsage& usage) {
120 switch (usage) {
121 case AudioUsage::INVALID:
122 case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_REQUEST:
123 case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_INSTANT:
124 case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_DELAYED:
125 return false;
126 default:
127 return true;
128 }
129 }
130
IsAudioSourceValid(const AudioSource & source)131 static bool IsAudioSourceValid(const AudioSource& source) {
132 return (source != AudioSource::SYS_RESERVED_INVALID);
133 }
134
GetSupportedAudioProductStrategyTypes()135 static const std::unordered_set<int>& GetSupportedAudioProductStrategyTypes() {
136 static const std::unordered_set<int> supportedAudioProductStrategyTypes = []() {
137 std::unordered_set<int> supportedStrategyTypes;
138 for (const auto& audioProductStrategyType :
139 ndk::enum_range<AudioProductStrategyType>()) {
140 if (!IsProductStrategyTypeReservedForSystemUse(audioProductStrategyType)) {
141 supportedStrategyTypes.insert(static_cast<int>(audioProductStrategyType));
142 }
143 }
144 return supportedStrategyTypes;
145 }();
146 return supportedAudioProductStrategyTypes;
147 }
148
GetSupportedAudioFlagsMask()149 static int GetSupportedAudioFlagsMask() {
150 static const int supportedAudioFlagsMask = []() {
151 int mask = 0;
152 for (const auto& audioFlag : ndk::enum_range<AudioFlag>()) {
153 mask |= static_cast<int>(audioFlag);
154 }
155 return mask;
156 }();
157 return supportedAudioFlagsMask;
158 }
159
160 /**
161 * Verify streamType is not INVALID if using default engine.
162 * Verify that streamType is a valid AudioStreamType if the associated
163 * volumeGroup minIndex/maxIndex is INDEX_DEFERRED_TO_AUDIO_SERVICE.
164 */
ValidateAudioStreamType(const AudioStreamType & streamType,const AudioHalVolumeGroup & associatedVolumeGroup)165 void ValidateAudioStreamType(const AudioStreamType& streamType,
166 const AudioHalVolumeGroup& associatedVolumeGroup) {
167 EXPECT_FALSE(IsStreamTypeReservedForSystemUse(streamType));
168 if (!mEngineConfig->capSpecificConfig ||
169 associatedVolumeGroup.minIndex ==
170 AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE) {
171 EXPECT_NE(streamType, AudioStreamType::INVALID);
172 }
173 }
174
175 /**
176 * Verify contained enum types are valid.
177 */
ValidateAudioAttributes(const AudioAttributes & attributes)178 void ValidateAudioAttributes(const AudioAttributes& attributes) {
179 // No need to check contentType; there are no INVALID or SYS_RESERVED values
180 EXPECT_TRUE(IsAudioUsageValid(attributes.usage));
181 EXPECT_TRUE(IsAudioSourceValid(attributes.source));
182 EXPECT_EQ(attributes.flags & ~GetSupportedAudioFlagsMask(), 0);
183 }
184
185 /**
186 * Verify volumeGroupName corresponds to an AudioHalVolumeGroup.
187 * Validate contained types.
188 */
ValidateAudioHalAttributesGroup(const AudioHalAttributesGroup & attributesGroup,std::unordered_map<std::string,const AudioHalVolumeGroup &> & volumeGroupMap,std::unordered_set<std::string> & volumeGroupsUsedInStrategies)189 void ValidateAudioHalAttributesGroup(
190 const AudioHalAttributesGroup& attributesGroup,
191 std::unordered_map<std::string, const AudioHalVolumeGroup&>& volumeGroupMap,
192 std::unordered_set<std::string>& volumeGroupsUsedInStrategies) {
193 bool isVolumeGroupNameValid = volumeGroupMap.count(attributesGroup.volumeGroupName);
194 EXPECT_TRUE(isVolumeGroupNameValid);
195 EXPECT_NO_FATAL_FAILURE(ValidateAudioStreamType(
196 attributesGroup.streamType, volumeGroupMap.at(attributesGroup.volumeGroupName)));
197 if (isVolumeGroupNameValid) {
198 volumeGroupsUsedInStrategies.insert(attributesGroup.volumeGroupName);
199 }
200 for (const AudioAttributes& attr : attributesGroup.attributes) {
201 EXPECT_NO_FATAL_FAILURE(ValidateAudioAttributes(attr));
202 }
203 }
204
205 /**
206 * Default engine: verify productStrategy.id is valid AudioProductStrategyType.
207 * CAP engine: verify productStrategy.id is either valid AudioProductStrategyType
208 * or is >= VENDOR_STRATEGY_ID_START.
209 * Validate contained types.
210 */
ValidateAudioHalProductStrategy(const AudioHalProductStrategy & strategy,std::unordered_map<std::string,const AudioHalVolumeGroup &> & volumeGroupMap,std::unordered_set<std::string> & volumeGroupsUsedInStrategies)211 void ValidateAudioHalProductStrategy(
212 const AudioHalProductStrategy& strategy,
213 std::unordered_map<std::string, const AudioHalVolumeGroup&>& volumeGroupMap,
214 std::unordered_set<std::string>& volumeGroupsUsedInStrategies) {
215 if (!mEngineConfig->capSpecificConfig ||
216 (strategy.id < AudioHalProductStrategy::VENDOR_STRATEGY_ID_START)) {
217 EXPECT_NE(GetSupportedAudioProductStrategyTypes().find(strategy.id),
218 GetSupportedAudioProductStrategyTypes().end());
219 }
220 for (const AudioHalAttributesGroup& attributesGroup : strategy.attributesGroups) {
221 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalAttributesGroup(attributesGroup, volumeGroupMap,
222 volumeGroupsUsedInStrategies));
223 }
224 }
225
226 /**
227 * Verify curve point index is in [CurvePoint::MIN_INDEX, CurvePoint::MAX_INDEX].
228 */
ValidateAudioHalVolumeCurve(const AudioHalVolumeCurve & volumeCurve)229 void ValidateAudioHalVolumeCurve(const AudioHalVolumeCurve& volumeCurve) {
230 for (const AudioHalVolumeCurve::CurvePoint& curvePoint : volumeCurve.curvePoints) {
231 EXPECT_TRUE(curvePoint.index >= AudioHalVolumeCurve::CurvePoint::MIN_INDEX);
232 EXPECT_TRUE(curvePoint.index <= AudioHalVolumeCurve::CurvePoint::MAX_INDEX);
233 }
234 }
235
236 /**
237 * Verify minIndex, maxIndex are non-negative.
238 * Verify minIndex <= maxIndex.
239 * Verify no two volume curves use the same device category.
240 * Validate contained types.
241 */
ValidateAudioHalVolumeGroup(const AudioHalVolumeGroup & volumeGroup)242 void ValidateAudioHalVolumeGroup(const AudioHalVolumeGroup& volumeGroup) {
243 /**
244 * Legacy volume curves in audio_policy_configuration.xsd don't use
245 * minIndex or maxIndex. Use of audio_policy_configuration.xml still
246 * allows, and in some cases, relies on, AudioService to provide the min
247 * and max indices for a volumeGroup. From the VTS perspective, there is
248 * no way to differentiate between use of audio_policy_configuration.xml
249 * or audio_policy_engine_configuration.xml, as either one can be used
250 * for the default audio policy engine.
251 */
252 if (volumeGroup.minIndex != AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE ||
253 volumeGroup.maxIndex != AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE) {
254 EXPECT_TRUE(volumeGroup.minIndex >= 0);
255 EXPECT_TRUE(volumeGroup.maxIndex >= 0);
256 }
257 EXPECT_TRUE(volumeGroup.minIndex <= volumeGroup.maxIndex);
258 std::unordered_set<AudioHalVolumeCurve::DeviceCategory> deviceCategorySet;
259 for (const AudioHalVolumeCurve& volumeCurve : volumeGroup.volumeCurves) {
260 EXPECT_TRUE(deviceCategorySet.insert(volumeCurve.deviceCategory).second);
261 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalVolumeCurve(volumeCurve));
262 }
263 }
264
265 /**
266 * Verify criterion provides a non empty value list.
267 * Verify logic rule provided is the expected one.
268 */
ValidateAudioHalCapCriterion(const AudioHalCapCriterionV2 & criterionV2)269 void ValidateAudioHalCapCriterion(const AudioHalCapCriterionV2& criterionV2) {
270 switch (criterionV2.getTag()) {
271 case AudioHalCapCriterionV2::availableInputDevices: {
272 auto criterion = criterionV2.get<AudioHalCapCriterionV2::availableInputDevices>();
273 EXPECT_FALSE(criterion.values.empty());
274 EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
275 break;
276 }
277 case AudioHalCapCriterionV2::availableOutputDevices: {
278 auto criterion = criterionV2.get<AudioHalCapCriterionV2::availableOutputDevices>();
279 EXPECT_FALSE(criterion.values.empty());
280 EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
281 break;
282 }
283 case AudioHalCapCriterionV2::availableInputDevicesAddresses: {
284 auto criterion =
285 criterionV2.get<AudioHalCapCriterionV2::availableInputDevicesAddresses>();
286 EXPECT_FALSE(criterion.values.empty());
287 EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
288 break;
289 }
290 case AudioHalCapCriterionV2::availableOutputDevicesAddresses: {
291 auto criterion =
292 criterionV2.get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>();
293 EXPECT_FALSE(criterion.values.empty());
294 EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
295 break;
296 }
297 case AudioHalCapCriterionV2::telephonyMode: {
298 auto criterion = criterionV2.get<AudioHalCapCriterionV2::telephonyMode>();
299 EXPECT_FALSE(criterion.values.empty());
300 EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::EXCLUSIVE);
301 break;
302 }
303 case AudioHalCapCriterionV2::forceConfigForUse: {
304 auto criterion = criterionV2.get<AudioHalCapCriterionV2::forceConfigForUse>();
305 EXPECT_FALSE(criterion.values.empty());
306 EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::EXCLUSIVE);
307 break;
308 }
309 default:
310 ADD_FAILURE() << "Invalid criterion tag " << toString(criterionV2.getTag());
311 }
312 }
313
314 /**
315 * Verify the rule involve the right matching logic according to the criterion logic.
316 * @param matchingRule logic followed by the rule
317 * @param logicalDisjunction logic exposed by the criterion
318 */
ValidateAudioHalCapRuleMatchingRule(const AudioHalCapRule::MatchingRule matchingRule,const AudioHalCapCriterionV2::LogicalDisjunction logicalDisjunction)319 void ValidateAudioHalCapRuleMatchingRule(
320 const AudioHalCapRule::MatchingRule matchingRule,
321 const AudioHalCapCriterionV2::LogicalDisjunction logicalDisjunction) {
322 if (logicalDisjunction == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE) {
323 EXPECT_TRUE(matchingRule == AudioHalCapRule::MatchingRule::EXCLUDES ||
324 matchingRule == AudioHalCapRule::MatchingRule::INCLUDES);
325 } else if (logicalDisjunction == AudioHalCapCriterionV2::LogicalDisjunction::EXCLUSIVE) {
326 EXPECT_TRUE(matchingRule == AudioHalCapRule::MatchingRule::IS ||
327 matchingRule == AudioHalCapRule::MatchingRule::IS_NOT);
328 } else {
329 ADD_FAILURE() << "Invalid criterion Logical rule";
330 }
331 }
332
333 /**
334 * Verify that the value and the matching rule are supported by the given criterion
335 */
336 template <typename CriterionV2, typename Value>
validateAudioHalCapRule(CriterionV2 criterionV2,Value value,const AudioHalCapRule::MatchingRule matchingRule)337 void validateAudioHalCapRule(CriterionV2 criterionV2, Value value,
338 const AudioHalCapRule::MatchingRule matchingRule) {
339 ValidateAudioHalCapRuleMatchingRule(matchingRule, criterionV2.logic);
340 EXPECT_FALSE(criterionV2.values.empty());
341 auto values = criterionV2.values;
342 auto valueIt = find_if(values.begin(), values.end(),
343 [&](const auto& typedValue) { return typedValue == value; });
344 EXPECT_NE(valueIt, values.end());
345 }
346
347 /**
348 * Verify rule involves a supported criterion.
349 * Verify rule involves supported logic keyword according to logic rule exposed by the
350 * criterion.
351 * Verify rule involves a value supported by the associated criterion.
352 */
ValidateAudioHalConfigurationRule(const AudioHalCapRule & rule,const std::vector<std::optional<AudioHalCapCriterionV2>> & criteria)353 void ValidateAudioHalConfigurationRule(
354 const AudioHalCapRule& rule,
355 const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) {
356 const auto& compoundRule = rule.compoundRule;
357 if (rule.nestedRules.empty() && rule.criterionRules.empty()) {
358 EXPECT_EQ(compoundRule, AudioHalCapRule::CompoundRule::ALL);
359 }
360 EXPECT_TRUE(compoundRule == AudioHalCapRule::CompoundRule::ANY ||
361 compoundRule == AudioHalCapRule::CompoundRule::ALL);
362 for (const auto& nestedRule : rule.nestedRules) {
363 ValidateAudioHalConfigurationRule(nestedRule, criteria);
364 }
365 for (const auto& criterionRule : rule.criterionRules) {
366 auto selectionCriterion = criterionRule.criterionAndValue;
367 auto criterionValue = criterionRule.criterionAndValue;
368 auto matchesWhen = criterionRule.matchingRule;
369 auto criteriaIt = find_if(criteria.begin(), criteria.end(), [&](const auto& criterion) {
370 return criterion.has_value() &&
371 criterion.value().getTag() == selectionCriterion.getTag();
372 });
373 EXPECT_NE(criteriaIt, criteria.end())
374 << " Invalid rule criterion " << toString(selectionCriterion.getTag());
375 AudioHalCapCriterionV2 matchingCriterion = (*criteriaIt).value();
376 switch (selectionCriterion.getTag()) {
377 case AudioHalCapCriterionV2::availableInputDevices: {
378 const auto& values =
379 criterionValue.get<AudioHalCapCriterionV2::availableInputDevices>()
380 .values;
381 ASSERT_FALSE(values.empty());
382 validateAudioHalCapRule(
383 matchingCriterion.get<AudioHalCapCriterionV2::availableInputDevices>(),
384 values[0], matchesWhen);
385 break;
386 }
387 case AudioHalCapCriterionV2::availableOutputDevices: {
388 const auto& values =
389 criterionValue.get<AudioHalCapCriterionV2::availableOutputDevices>()
390 .values;
391 ASSERT_FALSE(values.empty());
392 validateAudioHalCapRule(
393 matchingCriterion.get<AudioHalCapCriterionV2::availableOutputDevices>(),
394 values[0], matchesWhen);
395 break;
396 }
397 case AudioHalCapCriterionV2::availableInputDevicesAddresses: {
398 const auto& values =
399 criterionValue
400 .get<AudioHalCapCriterionV2::availableInputDevicesAddresses>()
401 .values;
402 ASSERT_FALSE(values.empty());
403 validateAudioHalCapRule(
404 matchingCriterion
405 .get<AudioHalCapCriterionV2::availableInputDevicesAddresses>(),
406 values[0], matchesWhen);
407 break;
408 }
409 case AudioHalCapCriterionV2::availableOutputDevicesAddresses: {
410 const auto& values =
411 criterionValue
412 .get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>()
413 .values;
414 ASSERT_FALSE(values.empty());
415 validateAudioHalCapRule(
416 matchingCriterion
417 .get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>(),
418 values[0], matchesWhen);
419 break;
420 }
421 case AudioHalCapCriterionV2::telephonyMode: {
422 const auto& values =
423 criterionValue.get<AudioHalCapCriterionV2::telephonyMode>().values;
424 ASSERT_FALSE(values.empty());
425 validateAudioHalCapRule(
426 matchingCriterion.get<AudioHalCapCriterionV2::telephonyMode>(),
427 values[0], matchesWhen);
428 break;
429 }
430 case AudioHalCapCriterionV2::forceConfigForUse: {
431 const auto& values =
432 criterionValue.get<AudioHalCapCriterionV2::forceConfigForUse>().values;
433 ASSERT_FALSE(values.empty());
434 validateAudioHalCapRule(
435 matchingCriterion.get<AudioHalCapCriterionV2::forceConfigForUse>(),
436 values[0], matchesWhen);
437 break;
438 }
439 default:
440 break;
441 }
442 }
443 }
444
445 /**
446 * Get the number of occurrence of a given parameter within a given vector of parameter.
447 * It just take into account the parameter, not its associated value.
448 * @param parameter to consider
449 * @param domainParameters to check against
450 * @return matching occurrence of the parameter within the provided vector.
451 */
countsParameter(const AudioHalCapParameter & parameter,const std::vector<AudioHalCapParameter> & domainParameters)452 size_t countsParameter(const AudioHalCapParameter& parameter,
453 const std::vector<AudioHalCapParameter>& domainParameters) {
454 size_t count = 0;
455 for (const auto& domainParameter : domainParameters) {
456 if (domainParameter.getTag() != parameter.getTag()) {
457 continue;
458 }
459 switch (domainParameter.getTag()) {
460 case AudioHalCapParameter::selectedStrategyDevice: {
461 auto typedDomainParam =
462 domainParameter.get<AudioHalCapParameter::selectedStrategyDevice>();
463 auto typedParam = parameter.get<AudioHalCapParameter::selectedStrategyDevice>();
464 if (typedDomainParam.id == typedParam.id &&
465 typedDomainParam.device == typedParam.device) {
466 count += 1;
467 }
468 break;
469 }
470 case AudioHalCapParameter::strategyDeviceAddress: {
471 auto typedDomainParam =
472 domainParameter.get<AudioHalCapParameter::strategyDeviceAddress>();
473 auto typedParam = parameter.get<AudioHalCapParameter::strategyDeviceAddress>();
474 if (typedDomainParam.id == typedParam.id) {
475 count += 1;
476 }
477 break;
478 }
479 case AudioHalCapParameter::selectedInputSourceDevice: {
480 auto typedDomainParam =
481 domainParameter.get<AudioHalCapParameter::selectedInputSourceDevice>();
482 auto typedParam =
483 parameter.get<AudioHalCapParameter::selectedInputSourceDevice>();
484 if (typedDomainParam.inputSource == typedParam.inputSource &&
485 typedDomainParam.device == typedParam.device) {
486 count += 1;
487 }
488 break;
489 }
490 case AudioHalCapParameter::streamVolumeProfile: {
491 auto typedDomainParam =
492 domainParameter.get<AudioHalCapParameter::streamVolumeProfile>();
493 auto typedParam = parameter.get<AudioHalCapParameter::streamVolumeProfile>();
494 if (typedDomainParam.stream == typedParam.stream) {
495 count += 1;
496 }
497 break;
498 }
499 default:
500 break;
501 }
502 }
503 return count;
504 }
505
506 /**
507 * Verify each configuration has unique name within a domain
508 * Verify no duplicate parameter within a domain.
509 * Verify that each configuration has no duplicated parameter.
510 * Verify that each configuration has an associated value for all parameter within a domain.
511 */
ValidateAudioHalCapDomain(const AudioHalCapDomain & domain,const std::vector<std::optional<AudioHalCapCriterionV2>> & criteria)512 void ValidateAudioHalCapDomain(
513 const AudioHalCapDomain& domain,
514 const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) {
515 std::unordered_set<std::string> configurationNames;
516 for (const AudioHalCapConfiguration& configuration : domain.configurations) {
517 EXPECT_TRUE(configurationNames.insert(configuration.name).second);
518 ValidateAudioHalConfigurationRule(configuration.rule, criteria);
519 }
520 auto domainParameters = domain.configurations[0].parameterSettings;
521 for (const auto& settingParameter : domainParameters) {
522 EXPECT_EQ(1ul, countsParameter(settingParameter, domainParameters))
523 << "Duplicated parameter within domain " << domain.name << " configuration "
524 << domain.configurations[0].name << " for parameter "
525 << settingParameter.toString();
526 }
527 for (const auto& configuration : domain.configurations) {
528 auto configurationParameters = configuration.parameterSettings;
529 for (const auto& configurationParameter : configurationParameters) {
530 EXPECT_EQ(1ul, countsParameter(configurationParameter, configurationParameters))
531 << "Duplicated parameter within domain " << domain.name << " configuration "
532 << configuration.name << " for parameter "
533 << configurationParameter.toString();
534 }
535 EXPECT_EQ(domainParameters.size(), configurationParameters.size());
536 for (const auto& settingParameter : configuration.parameterSettings) {
537 EXPECT_EQ(1ul, countsParameter(settingParameter, domainParameters))
538 << "Confiugration " << configuration.name << " within domain "
539 << domain.name << " exposes invalid parameter "
540 << settingParameter.toString();
541 ;
542 }
543 }
544 }
545
546 /**
547 * Verify each domain has a unique name.
548 * Verify that a given parameter does not appear in more than one domain.
549 */
ValidateAudioHalCapDomains(const std::vector<std::optional<AudioHalCapDomain>> & domains,const std::vector<std::optional<AudioHalCapCriterionV2>> & criteria)550 void ValidateAudioHalCapDomains(
551 const std::vector<std::optional<AudioHalCapDomain>>& domains,
552 const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) {
553 std::unordered_map<std::string, AudioHalCapDomain> domainMap;
554 std::vector<AudioHalCapParameter> allDomainParameters;
555 for (const auto& domain : domains) {
556 EXPECT_TRUE(domain.has_value());
557 EXPECT_FALSE(domain.value().configurations.empty());
558 auto domainParameters = domain.value().configurations[0].parameterSettings;
559 for (const auto& domainParameter : domainParameters) {
560 EXPECT_EQ(0ul, countsParameter(domainParameter, allDomainParameters))
561 << "Duplicated parameter in domain " << domain.value().name
562 << " for parameter " << domainParameter.toString();
563 allDomainParameters.push_back(domainParameter);
564 }
565 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapDomain(domain.value(), criteria));
566 EXPECT_TRUE(domainMap.insert({domain.value().name, domain.value()}).second);
567 }
568 }
569
570 /**
571 * Verify unique criterion is provided for a given Tag, except for ForceUse
572 * Verify unique forceUse criterion are provided for usage
573 * Verify each criterion is validating.
574 * Verify domains.
575 */
ValidateCapSpecificConfig(const AudioHalEngineConfig::CapSpecificConfig & capCfg)576 void ValidateCapSpecificConfig(const AudioHalEngineConfig::CapSpecificConfig& capCfg) {
577 EXPECT_TRUE(capCfg.criteriaV2.has_value());
578 std::unordered_set<AudioHalCapCriterionV2::Tag> criterionTagSet;
579 std::unordered_set<AudioPolicyForceUse::Tag> forceUseCriterionUseSet;
580 for (const auto& criterion : capCfg.criteriaV2.value()) {
581 EXPECT_TRUE(criterion.has_value());
582 if (criterion.value().getTag() != AudioHalCapCriterionV2::forceConfigForUse) {
583 EXPECT_TRUE(criterionTagSet.insert(criterion.value().getTag()).second);
584 } else {
585 auto forceUseCriterion =
586 criterion.value().get<AudioHalCapCriterionV2::forceConfigForUse>();
587 ASSERT_FALSE(forceUseCriterion.values.empty());
588 EXPECT_TRUE(forceUseCriterionUseSet.insert(forceUseCriterion.values[0].getTag())
589 .second);
590 }
591 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapCriterion(criterion.value()));
592 }
593 ValidateAudioHalCapDomains(capCfg.domains.value(), capCfg.criteriaV2.value());
594 }
595
596 /**
597 * Verify VolumeGroups are non-empty.
598 * Verify defaultProductStrategyId matches one of the provided productStrategies.
599 * Otherwise, must be left uninitialized.
600 * Verify each volumeGroup has a unique name.
601 * Verify each productStrategy has a unique id.
602 * Verify each volumeGroup is used in a product strategy.
603 * CAP engine: verify productStrategies are non-empty.
604 * Validate contained types.
605 */
ValidateAudioHalEngineConfig()606 void ValidateAudioHalEngineConfig() {
607 EXPECT_NE(mEngineConfig->volumeGroups.size(), 0UL);
608 std::unordered_map<std::string, const AudioHalVolumeGroup&> volumeGroupMap;
609 for (const AudioHalVolumeGroup& volumeGroup : mEngineConfig->volumeGroups) {
610 EXPECT_TRUE(volumeGroupMap.insert({volumeGroup.name, volumeGroup}).second);
611 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalVolumeGroup(volumeGroup));
612 }
613 if (!mEngineConfig->productStrategies.empty()) {
614 std::unordered_set<int> productStrategyIdSet;
615 std::unordered_set<std::string> volumeGroupsUsedInStrategies;
616 for (const AudioHalProductStrategy& strategy : mEngineConfig->productStrategies) {
617 EXPECT_TRUE(productStrategyIdSet.insert(strategy.id).second);
618 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalProductStrategy(
619 strategy, volumeGroupMap, volumeGroupsUsedInStrategies));
620 }
621 EXPECT_TRUE(productStrategyIdSet.count(mEngineConfig->defaultProductStrategyId))
622 << "defaultProductStrategyId doesn't match any of the provided "
623 "productStrategies";
624 EXPECT_EQ(volumeGroupMap.size(), volumeGroupsUsedInStrategies.size());
625 } else {
626 EXPECT_EQ(mEngineConfig->defaultProductStrategyId,
627 static_cast<int>(AudioProductStrategyType::SYS_RESERVED_NONE))
628 << "defaultProductStrategyId defined, but no productStrategies were provided";
629 }
630 if (mEngineConfig->capSpecificConfig) {
631 EXPECT_NO_FATAL_FAILURE(
632 ValidateCapSpecificConfig(mEngineConfig->capSpecificConfig.value()));
633 EXPECT_FALSE(mEngineConfig->productStrategies.empty());
634 }
635 }
636
ValidateAudioFormatDescription(const AudioFormatDescription & format)637 void ValidateAudioFormatDescription(const AudioFormatDescription& format) {
638 EXPECT_NE(AudioFormatType::SYS_RESERVED_INVALID, format.type);
639 if (format.type == AudioFormatType::PCM) {
640 EXPECT_NE(PcmType::DEFAULT, format.pcm);
641 EXPECT_TRUE(format.encoding.empty()) << format.encoding;
642 } else {
643 EXPECT_FALSE(format.encoding.empty());
644 }
645 }
646
647 /**
648 * Verify that the surround sound configuration is not empty.
649 * Verify each of the formatFamilies has a non-empty primaryFormat.
650 * Verify that each format only appears once.
651 */
ValidateSurroundSoundConfig()652 void ValidateSurroundSoundConfig() {
653 EXPECT_FALSE(mSurroundSoundConfig->formatFamilies.empty());
654 std::set<AudioFormatDescription> formatSet;
655 for (const SurroundSoundConfig::SurroundFormatFamily& family :
656 mSurroundSoundConfig->formatFamilies) {
657 EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(family.primaryFormat));
658 EXPECT_FALSE(isDefaultAudioFormat(family.primaryFormat));
659 EXPECT_TRUE(formatSet.insert(family.primaryFormat).second);
660 for (const AudioFormatDescription& subformat : family.subFormats) {
661 EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(subformat));
662 EXPECT_FALSE(isDefaultAudioFormat(subformat));
663 EXPECT_TRUE(formatSet.insert(subformat).second);
664 }
665 }
666 }
667
668 private:
669 std::shared_ptr<IConfig> mConfig;
670 std::unique_ptr<AudioHalEngineConfig> mEngineConfig;
671 std::unique_ptr<SurroundSoundConfig> mSurroundSoundConfig;
672 AudioHalBinderServiceUtil mBinderUtil;
673 };
674
TEST_P(AudioCoreConfig,Published)675 TEST_P(AudioCoreConfig, Published) {
676 // SetUp must complete with no failures.
677 }
678
TEST_P(AudioCoreConfig,CanBeRestarted)679 TEST_P(AudioCoreConfig, CanBeRestarted) {
680 ASSERT_NO_FATAL_FAILURE(RestartService());
681 }
682
TEST_P(AudioCoreConfig,GetEngineConfigIsValid)683 TEST_P(AudioCoreConfig, GetEngineConfigIsValid) {
684 ASSERT_NO_FATAL_FAILURE(SetUpEngineConfig());
685 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalEngineConfig());
686 }
687
TEST_P(AudioCoreConfig,GetSurroundSoundConfigIsValid)688 TEST_P(AudioCoreConfig, GetSurroundSoundConfigIsValid) {
689 ASSERT_NO_FATAL_FAILURE(SetUpSurroundSoundConfig());
690 EXPECT_NO_FATAL_FAILURE(ValidateSurroundSoundConfig());
691 }
692
693 INSTANTIATE_TEST_SUITE_P(AudioCoreConfigTest, AudioCoreConfig,
694 testing::ValuesIn(android::getAidlHalInstanceNames(IConfig::descriptor)),
695 android::PrintInstanceNameToString);
696 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreConfig);
697