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()) << "Not found: \"" << value << "\"";
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 auto getForceConfigTag = [](const AudioHalCapCriterionV2& forceConfig) {
371 return forceConfig.get<AudioHalCapCriterionV2::forceConfigForUse>()
372 .values[0].getTag();
373 };
374 return criterion.has_value() &&
375 criterion.value().getTag() == selectionCriterion.getTag() &&
376 (criterion.value().getTag() != AudioHalCapCriterionV2::forceConfigForUse ||
377 getForceConfigTag(criterion.value()) ==
378 getForceConfigTag(selectionCriterion));
379 });
380 EXPECT_NE(criteriaIt, criteria.end())
381 << " Invalid rule criterion " << toString(selectionCriterion.getTag());
382 AudioHalCapCriterionV2 matchingCriterion = (*criteriaIt).value();
383 switch (selectionCriterion.getTag()) {
384 case AudioHalCapCriterionV2::availableInputDevices: {
385 const auto& values =
386 criterionValue.get<AudioHalCapCriterionV2::availableInputDevices>()
387 .values;
388 ASSERT_FALSE(values.empty());
389 validateAudioHalCapRule(
390 matchingCriterion.get<AudioHalCapCriterionV2::availableInputDevices>(),
391 values[0], matchesWhen);
392 break;
393 }
394 case AudioHalCapCriterionV2::availableOutputDevices: {
395 const auto& values =
396 criterionValue.get<AudioHalCapCriterionV2::availableOutputDevices>()
397 .values;
398 ASSERT_FALSE(values.empty());
399 validateAudioHalCapRule(
400 matchingCriterion.get<AudioHalCapCriterionV2::availableOutputDevices>(),
401 values[0], matchesWhen);
402 break;
403 }
404 case AudioHalCapCriterionV2::availableInputDevicesAddresses: {
405 const auto& values =
406 criterionValue
407 .get<AudioHalCapCriterionV2::availableInputDevicesAddresses>()
408 .values;
409 ASSERT_FALSE(values.empty());
410 validateAudioHalCapRule(
411 matchingCriterion
412 .get<AudioHalCapCriterionV2::availableInputDevicesAddresses>(),
413 values[0], matchesWhen);
414 break;
415 }
416 case AudioHalCapCriterionV2::availableOutputDevicesAddresses: {
417 const auto& values =
418 criterionValue
419 .get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>()
420 .values;
421 ASSERT_FALSE(values.empty());
422 validateAudioHalCapRule(
423 matchingCriterion
424 .get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>(),
425 values[0], matchesWhen);
426 break;
427 }
428 case AudioHalCapCriterionV2::telephonyMode: {
429 const auto& values =
430 criterionValue.get<AudioHalCapCriterionV2::telephonyMode>().values;
431 ASSERT_FALSE(values.empty());
432 validateAudioHalCapRule(
433 matchingCriterion.get<AudioHalCapCriterionV2::telephonyMode>(),
434 values[0], matchesWhen);
435 break;
436 }
437 case AudioHalCapCriterionV2::forceConfigForUse: {
438 const auto& values =
439 criterionValue.get<AudioHalCapCriterionV2::forceConfigForUse>().values;
440 ASSERT_FALSE(values.empty());
441 validateAudioHalCapRule(
442 matchingCriterion.get<AudioHalCapCriterionV2::forceConfigForUse>(),
443 values[0], matchesWhen);
444 break;
445 }
446 default:
447 break;
448 }
449 }
450 }
451
452 /**
453 * Get the number of occurrence of a given parameter within a given vector of parameter.
454 * It just take into account the parameter, not its associated value.
455 * @param parameter to consider
456 * @param domainParameters to check against
457 * @return matching occurrence of the parameter within the provided vector.
458 */
countsParameter(const AudioHalCapParameter & parameter,const std::vector<AudioHalCapParameter> & domainParameters)459 size_t countsParameter(const AudioHalCapParameter& parameter,
460 const std::vector<AudioHalCapParameter>& domainParameters) {
461 size_t count = 0;
462 for (const auto& domainParameter : domainParameters) {
463 if (domainParameter.getTag() != parameter.getTag()) {
464 continue;
465 }
466 switch (domainParameter.getTag()) {
467 case AudioHalCapParameter::selectedStrategyDevice: {
468 auto typedDomainParam =
469 domainParameter.get<AudioHalCapParameter::selectedStrategyDevice>();
470 auto typedParam = parameter.get<AudioHalCapParameter::selectedStrategyDevice>();
471 if (typedDomainParam.id == typedParam.id &&
472 typedDomainParam.device == typedParam.device) {
473 count += 1;
474 }
475 break;
476 }
477 case AudioHalCapParameter::strategyDeviceAddress: {
478 auto typedDomainParam =
479 domainParameter.get<AudioHalCapParameter::strategyDeviceAddress>();
480 auto typedParam = parameter.get<AudioHalCapParameter::strategyDeviceAddress>();
481 if (typedDomainParam.id == typedParam.id) {
482 count += 1;
483 }
484 break;
485 }
486 case AudioHalCapParameter::selectedInputSourceDevice: {
487 auto typedDomainParam =
488 domainParameter.get<AudioHalCapParameter::selectedInputSourceDevice>();
489 auto typedParam =
490 parameter.get<AudioHalCapParameter::selectedInputSourceDevice>();
491 if (typedDomainParam.inputSource == typedParam.inputSource &&
492 typedDomainParam.device == typedParam.device) {
493 count += 1;
494 }
495 break;
496 }
497 case AudioHalCapParameter::streamVolumeProfile: {
498 auto typedDomainParam =
499 domainParameter.get<AudioHalCapParameter::streamVolumeProfile>();
500 auto typedParam = parameter.get<AudioHalCapParameter::streamVolumeProfile>();
501 if (typedDomainParam.stream == typedParam.stream) {
502 count += 1;
503 }
504 break;
505 }
506 default:
507 break;
508 }
509 }
510 return count;
511 }
512
513 /**
514 * Verify each configuration has unique name within a domain
515 * Verify no duplicate parameter within a domain.
516 * Verify that each configuration has no duplicated parameter.
517 * Verify that each configuration has an associated value for all parameter within a domain.
518 */
ValidateAudioHalCapDomain(const AudioHalCapDomain & domain,const std::vector<std::optional<AudioHalCapCriterionV2>> & criteria)519 void ValidateAudioHalCapDomain(
520 const AudioHalCapDomain& domain,
521 const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) {
522 std::unordered_set<std::string> configurationNames;
523 for (const AudioHalCapConfiguration& configuration : domain.configurations) {
524 EXPECT_TRUE(configurationNames.insert(configuration.name).second);
525 ASSERT_NO_FATAL_FAILURE(
526 ValidateAudioHalConfigurationRule(configuration.rule, criteria));
527 }
528 auto domainParameters = domain.configurations[0].parameterSettings;
529 for (const auto& settingParameter : domainParameters) {
530 EXPECT_EQ(1ul, countsParameter(settingParameter, domainParameters))
531 << "Duplicated parameter within domain " << domain.name << " configuration "
532 << domain.configurations[0].name << " for parameter "
533 << settingParameter.toString();
534 }
535 for (const auto& configuration : domain.configurations) {
536 auto configurationParameters = configuration.parameterSettings;
537 for (const auto& configurationParameter : configurationParameters) {
538 EXPECT_EQ(1ul, countsParameter(configurationParameter, configurationParameters))
539 << "Duplicated parameter within domain " << domain.name << " configuration "
540 << configuration.name << " for parameter "
541 << configurationParameter.toString();
542 }
543 EXPECT_EQ(domainParameters.size(), configurationParameters.size());
544 for (const auto& settingParameter : configuration.parameterSettings) {
545 EXPECT_EQ(1ul, countsParameter(settingParameter, domainParameters))
546 << "Confiugration " << configuration.name << " within domain "
547 << domain.name << " exposes invalid parameter "
548 << settingParameter.toString();
549 ;
550 }
551 }
552 }
553
554 /**
555 * Verify each domain has a unique name.
556 * Verify that a given parameter does not appear in more than one domain.
557 */
ValidateAudioHalCapDomains(const std::vector<std::optional<AudioHalCapDomain>> & domains,const std::vector<std::optional<AudioHalCapCriterionV2>> & criteria)558 void ValidateAudioHalCapDomains(
559 const std::vector<std::optional<AudioHalCapDomain>>& domains,
560 const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) {
561 std::unordered_map<std::string, AudioHalCapDomain> domainMap;
562 std::vector<AudioHalCapParameter> allDomainParameters;
563 for (const auto& domain : domains) {
564 EXPECT_TRUE(domain.has_value());
565 EXPECT_FALSE(domain.value().configurations.empty());
566 auto domainParameters = domain.value().configurations[0].parameterSettings;
567 for (const auto& domainParameter : domainParameters) {
568 EXPECT_EQ(0ul, countsParameter(domainParameter, allDomainParameters))
569 << "Duplicated parameter in domain " << domain.value().name
570 << " for parameter " << domainParameter.toString();
571 allDomainParameters.push_back(domainParameter);
572 }
573 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapDomain(domain.value(), criteria));
574 EXPECT_TRUE(domainMap.insert({domain.value().name, domain.value()}).second);
575 }
576 }
577
578 /**
579 * Verify unique criterion is provided for a given Tag, except for ForceUse
580 * Verify unique forceUse criterion are provided for usage
581 * Verify each criterion is validating.
582 * Verify domains.
583 */
ValidateCapSpecificConfig(const AudioHalEngineConfig::CapSpecificConfig & capCfg)584 void ValidateCapSpecificConfig(const AudioHalEngineConfig::CapSpecificConfig& capCfg) {
585 EXPECT_TRUE(capCfg.criteriaV2.has_value());
586 std::unordered_set<AudioHalCapCriterionV2::Tag> criterionTagSet;
587 std::unordered_set<AudioPolicyForceUse::Tag> forceUseCriterionUseSet;
588 for (const auto& criterion : capCfg.criteriaV2.value()) {
589 EXPECT_TRUE(criterion.has_value());
590 if (criterion.value().getTag() != AudioHalCapCriterionV2::forceConfigForUse) {
591 EXPECT_TRUE(criterionTagSet.insert(criterion.value().getTag()).second);
592 } else {
593 auto forceUseCriterion =
594 criterion.value().get<AudioHalCapCriterionV2::forceConfigForUse>();
595 ASSERT_FALSE(forceUseCriterion.values.empty());
596 EXPECT_TRUE(forceUseCriterionUseSet.insert(forceUseCriterion.values[0].getTag())
597 .second);
598 }
599 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapCriterion(criterion.value()));
600 }
601 ASSERT_NO_FATAL_FAILURE(
602 ValidateAudioHalCapDomains(capCfg.domains.value(), capCfg.criteriaV2.value()));
603 }
604
605 /**
606 * Verify VolumeGroups are non-empty.
607 * Verify defaultProductStrategyId matches one of the provided productStrategies.
608 * Otherwise, must be left uninitialized.
609 * Verify each volumeGroup has a unique name.
610 * Verify each productStrategy has a unique id.
611 * Verify each volumeGroup is used in a product strategy.
612 * CAP engine: verify productStrategies are non-empty.
613 * Validate contained types.
614 */
ValidateAudioHalEngineConfig()615 void ValidateAudioHalEngineConfig() {
616 EXPECT_NE(mEngineConfig->volumeGroups.size(), 0UL);
617 std::unordered_map<std::string, const AudioHalVolumeGroup&> volumeGroupMap;
618 for (const AudioHalVolumeGroup& volumeGroup : mEngineConfig->volumeGroups) {
619 EXPECT_TRUE(volumeGroupMap.insert({volumeGroup.name, volumeGroup}).second);
620 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalVolumeGroup(volumeGroup));
621 }
622 if (!mEngineConfig->productStrategies.empty()) {
623 std::unordered_set<int> productStrategyIdSet;
624 std::unordered_set<std::string> volumeGroupsUsedInStrategies;
625 for (const AudioHalProductStrategy& strategy : mEngineConfig->productStrategies) {
626 EXPECT_TRUE(productStrategyIdSet.insert(strategy.id).second);
627 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalProductStrategy(
628 strategy, volumeGroupMap, volumeGroupsUsedInStrategies));
629 }
630 EXPECT_TRUE(productStrategyIdSet.count(mEngineConfig->defaultProductStrategyId))
631 << "defaultProductStrategyId doesn't match any of the provided "
632 "productStrategies";
633 EXPECT_EQ(volumeGroupMap.size(), volumeGroupsUsedInStrategies.size());
634 } else {
635 EXPECT_EQ(mEngineConfig->defaultProductStrategyId,
636 static_cast<int>(AudioProductStrategyType::SYS_RESERVED_NONE))
637 << "defaultProductStrategyId defined, but no productStrategies were provided";
638 }
639 if (mEngineConfig->capSpecificConfig) {
640 EXPECT_NO_FATAL_FAILURE(
641 ValidateCapSpecificConfig(mEngineConfig->capSpecificConfig.value()));
642 EXPECT_FALSE(mEngineConfig->productStrategies.empty());
643 }
644 }
645
ValidateAudioFormatDescription(const AudioFormatDescription & format)646 void ValidateAudioFormatDescription(const AudioFormatDescription& format) {
647 EXPECT_NE(AudioFormatType::SYS_RESERVED_INVALID, format.type);
648 if (format.type == AudioFormatType::PCM) {
649 EXPECT_NE(PcmType::DEFAULT, format.pcm);
650 EXPECT_TRUE(format.encoding.empty()) << format.encoding;
651 } else {
652 EXPECT_FALSE(format.encoding.empty());
653 }
654 }
655
656 /**
657 * Verify that the surround sound configuration is not empty.
658 * Verify each of the formatFamilies has a non-empty primaryFormat.
659 * Verify that each format only appears once.
660 */
ValidateSurroundSoundConfig()661 void ValidateSurroundSoundConfig() {
662 EXPECT_FALSE(mSurroundSoundConfig->formatFamilies.empty());
663 std::set<AudioFormatDescription> formatSet;
664 for (const SurroundSoundConfig::SurroundFormatFamily& family :
665 mSurroundSoundConfig->formatFamilies) {
666 EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(family.primaryFormat));
667 EXPECT_FALSE(isDefaultAudioFormat(family.primaryFormat));
668 EXPECT_TRUE(formatSet.insert(family.primaryFormat).second);
669 for (const AudioFormatDescription& subformat : family.subFormats) {
670 EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(subformat));
671 EXPECT_FALSE(isDefaultAudioFormat(subformat));
672 EXPECT_TRUE(formatSet.insert(subformat).second);
673 }
674 }
675 }
676
677 private:
678 std::shared_ptr<IConfig> mConfig;
679 std::unique_ptr<AudioHalEngineConfig> mEngineConfig;
680 std::unique_ptr<SurroundSoundConfig> mSurroundSoundConfig;
681 AudioHalBinderServiceUtil mBinderUtil;
682 };
683
TEST_P(AudioCoreConfig,Published)684 TEST_P(AudioCoreConfig, Published) {
685 // SetUp must complete with no failures.
686 }
687
TEST_P(AudioCoreConfig,CanBeRestarted)688 TEST_P(AudioCoreConfig, CanBeRestarted) {
689 ASSERT_NO_FATAL_FAILURE(RestartService());
690 }
691
TEST_P(AudioCoreConfig,GetEngineConfigIsValid)692 TEST_P(AudioCoreConfig, GetEngineConfigIsValid) {
693 ASSERT_NO_FATAL_FAILURE(SetUpEngineConfig());
694 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalEngineConfig());
695 }
696
TEST_P(AudioCoreConfig,GetSurroundSoundConfigIsValid)697 TEST_P(AudioCoreConfig, GetSurroundSoundConfigIsValid) {
698 ASSERT_NO_FATAL_FAILURE(SetUpSurroundSoundConfig());
699 EXPECT_NO_FATAL_FAILURE(ValidateSurroundSoundConfig());
700 }
701
702 INSTANTIATE_TEST_SUITE_P(AudioCoreConfigTest, AudioCoreConfig,
703 testing::ValuesIn(android::getAidlHalInstanceNames(IConfig::descriptor)),
704 android::PrintInstanceNameToString);
705 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreConfig);
706