1 /*
2 * Copyright (C) 2020 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 #define LOG_TAG "VtsAidlHalAudioControlTest"
17
18 #include <aidl/Gtest.h>
19 #include <aidl/Vintf.h>
20 #include <gmock/gmock.h>
21 #include <utils/String16.h>
22 #include <set>
23
24 #include <android/hardware/automotive/audiocontrol/BnAudioGainCallback.h>
25 #include <android/hardware/automotive/audiocontrol/BnFocusListener.h>
26 #include <android/hardware/automotive/audiocontrol/BnModuleChangeCallback.h>
27 #include <android/hardware/automotive/audiocontrol/IAudioControl.h>
28 #include <android/log.h>
29 #include <android/media/audio/common/AudioHalProductStrategy.h>
30 #include <binder/IServiceManager.h>
31 #include <binder/ProcessState.h>
32 #include <include/AudioControlTestUtils.h>
33
34 using android::ProcessState;
35 using android::sp;
36 using android::String16;
37 using android::binder::Status;
38 using android::hardware::automotive::audiocontrol::AudioDeviceConfiguration;
39 using android::hardware::automotive::audiocontrol::AudioFadeConfiguration;
40 using android::hardware::automotive::audiocontrol::AudioFocusChange;
41 using android::hardware::automotive::audiocontrol::AudioGainConfigInfo;
42 using android::hardware::automotive::audiocontrol::AudioZone;
43 using android::hardware::automotive::audiocontrol::AudioZoneConfig;
44 using android::hardware::automotive::audiocontrol::AudioZoneContextInfo;
45 using android::hardware::automotive::audiocontrol::AudioZoneFadeConfiguration;
46 using android::hardware::automotive::audiocontrol::BnAudioGainCallback;
47 using android::hardware::automotive::audiocontrol::BnFocusListener;
48 using android::hardware::automotive::audiocontrol::BnModuleChangeCallback;
49 using android::hardware::automotive::audiocontrol::DeviceToContextEntry;
50 using android::hardware::automotive::audiocontrol::DuckingInfo;
51 using android::hardware::automotive::audiocontrol::FadeConfiguration;
52 using android::hardware::automotive::audiocontrol::IAudioControl;
53 using android::hardware::automotive::audiocontrol::IModuleChangeCallback;
54 using android::hardware::automotive::audiocontrol::MutingInfo;
55 using android::hardware::automotive::audiocontrol::Reasons;
56 using android::hardware::automotive::audiocontrol::VolumeActivationConfiguration;
57 using android::hardware::automotive::audiocontrol::VolumeActivationConfigurationEntry;
58 using android::hardware::automotive::audiocontrol::VolumeGroupConfig;
59 using android::hardware::automotive::audiocontrol::RoutingDeviceConfiguration::
60 CONFIGURABLE_AUDIO_ENGINE_ROUTING;
61 using android::hardware::automotive::audiocontrol::RoutingDeviceConfiguration::
62 DEFAULT_AUDIO_ROUTING;
63 using android::hardware::automotive::audiocontrol::VolumeActivationConfigurationEntry::
64 DEFAULT_MAX_ACTIVATION_VALUE;
65 using android::hardware::automotive::audiocontrol::VolumeActivationConfigurationEntry::
66 DEFAULT_MIN_ACTIVATION_VALUE;
67 using android::media::audio::common::AudioHalProductStrategy;
68
69 using ::testing::AnyOf;
70 using ::testing::Eq;
71
72 using ::testing::Not;
73 using ::testing::UnorderedElementsAreArray;
74
75 using android::internal::ToString;
76
77 #include "android_audio_policy_configuration_V7_0.h"
78
79 namespace xsd {
80 using namespace android::audio::policy::configuration::V7_0;
81 }
82
83 namespace audiohalcommon = android::hardware::audio::common;
84 namespace audiomediacommon = android::media::audio::common;
85 namespace testutils = android::hardware::audiocontrol::testutils;
86
87 namespace {
88 constexpr int32_t kAidlVersionThree = 3;
89 constexpr int32_t kAidlVersionFive = 5;
90
hasValidVolumeGroupActivation(const VolumeActivationConfiguration & activation,std::string & message)91 bool hasValidVolumeGroupActivation(const VolumeActivationConfiguration& activation,
92 std::string& message) {
93 if (activation.volumeActivationEntries.empty()) {
94 message = "Volume group activation must have at least one volume activation entry";
95 return false;
96 }
97 for (const auto& entry : activation.volumeActivationEntries) {
98 int32_t max = entry.maxActivationVolumePercentage;
99 int32_t min = entry.minActivationVolumePercentage;
100 if (min > DEFAULT_MAX_ACTIVATION_VALUE || min < DEFAULT_MIN_ACTIVATION_VALUE) {
101 message = "Invalid minActivationVolumePercentage, must be between " +
102 std::to_string(DEFAULT_MIN_ACTIVATION_VALUE) + " and " +
103 std::to_string(DEFAULT_MAX_ACTIVATION_VALUE);
104 return false;
105 }
106 if (max > DEFAULT_MAX_ACTIVATION_VALUE || max < DEFAULT_MIN_ACTIVATION_VALUE) {
107 message = "Invalid maxActivationVolumePercentage, must be between " +
108 std::to_string(DEFAULT_MIN_ACTIVATION_VALUE) + " and " +
109 std::to_string(DEFAULT_MAX_ACTIVATION_VALUE);
110 return false;
111 }
112 if (min >= max) {
113 message =
114 "Invalid maxActivationVolumePercentage and minActivationVolumePercentage "
115 "combination, minActivationVolumePercentage must be less than "
116 "maxActivationVolumePercentage";
117 return false;
118 }
119 }
120 return true;
121 }
122
hasValidAudioRoute(const DeviceToContextEntry & entry,std::string & message,std::set<std::string> & groupDevices)123 bool hasValidAudioRoute(const DeviceToContextEntry& entry, std::string& message,
124 std::set<std::string>& groupDevices) {
125 if (entry.contextNames.empty()) {
126 message = " Contexts can not be empty for DeviceToContextEntry";
127 return false;
128 }
129 std::set<std::string> contextInRoute;
130 for (const auto& context : entry.contextNames) {
131 std::string contextString = ToString(context);
132 if (contextInRoute.contains(contextString)) {
133 message = " Context " + contextString + " repeats for DeviceToContextEntry";
134 return false;
135 }
136 groupDevices.insert(contextString);
137 }
138 audiomediacommon::AudioDeviceDescription description;
139 if (!testutils::getAudioPortDeviceDescriptor(entry.device, description)) {
140 message = " DeviceToContextEntry must have a valid device port";
141 return false;
142 }
143 // BUS type also has empty connection
144 // Note: OUT_BUS is also mapped to OUT_DEVICE
145 if (description.type != audiomediacommon::AudioDeviceType::OUT_BUS &&
146 !description.connection.empty()) {
147 return true;
148 }
149 std::string address;
150 if (!testutils::getAddressForAudioPort(entry.device, address) || address.empty()) {
151 message = " Address can not be empty for BUS devices";
152 return false;
153 }
154 if (groupDevices.contains(address)) {
155 message =
156 " Audio device address can not repeat in the same volume group or within audio"
157 " zone configuration if not using configurable audio policy engine";
158 return false;
159 }
160 groupDevices.insert(address);
161 return true;
162 }
163
hasValidTimeout(int64_t timeout)164 inline bool hasValidTimeout(int64_t timeout) {
165 return timeout > 0;
166 }
hasValidFadeConfiguration(const FadeConfiguration & fadeConfiguration,const std::string & prefix,std::string & message)167 bool hasValidFadeConfiguration(const FadeConfiguration& fadeConfiguration,
168 const std::string& prefix, std::string& message) {
169 if (!hasValidTimeout(fadeConfiguration.fadeDurationMillis)) {
170 message = prefix + " duration must be greater than 0";
171 return false;
172 }
173 return true;
174 }
hadValidAudioFadeConfiguration(const AudioFadeConfiguration & fadeConfiguration,std::string & message)175 bool hadValidAudioFadeConfiguration(const AudioFadeConfiguration& fadeConfiguration,
176 std::string& message) {
177 if (!hasValidTimeout(fadeConfiguration.fadeInDurationMs)) {
178 message = "Fade-in duration must be greater than 0";
179 return false;
180 }
181 if (!hasValidTimeout(fadeConfiguration.fadeOutDurationMs)) {
182 message = "Fade-out duration must be greater than 0";
183 return false;
184 }
185 if (!hasValidTimeout(fadeConfiguration.fadeInDelayedForOffendersMs)) {
186 message = "Fade-in delayed for offenders duration must be greater than 0";
187 return false;
188 }
189 for (const auto& fadeOutConfig : fadeConfiguration.fadeOutConfigurations) {
190 if (!hasValidFadeConfiguration(fadeOutConfig, "Fade-out", message)) {
191 return false;
192 }
193 }
194 for (const auto& fadeOutConfig : fadeConfiguration.fadeInConfigurations) {
195 if (!hasValidFadeConfiguration(fadeOutConfig, "Fade-in", message)) {
196 return false;
197 }
198 }
199 return true;
200 }
201
validateVolumeGroupInfo(const AudioZoneConfig & audioZoneConfig,const VolumeGroupConfig & volumeGroupConfig,const AudioDeviceConfiguration & deviceConfig,std::set<std::string> & groupDevices,std::set<int> & groupIds)202 void validateVolumeGroupInfo(const AudioZoneConfig& audioZoneConfig,
203 const VolumeGroupConfig& volumeGroupConfig,
204 const AudioDeviceConfiguration& deviceConfig,
205 std::set<std::string>& groupDevices, std::set<int>& groupIds) {
206 std::string zoneConfigName = testutils::toAlphaNumeric(ToString(audioZoneConfig.name));
207 std::string volumeGroupName = testutils::toAlphaNumeric(ToString(volumeGroupConfig.name));
208 std::string volumeGroupInfo =
209 "Audio zone config " + zoneConfigName + " volume group " + volumeGroupName;
210 ALOGI("%s test", volumeGroupInfo.c_str());
211
212 EXPECT_FALSE(volumeGroupConfig.carAudioRoutes.empty())
213 << volumeGroupInfo << " must have at least one audio route";
214 if (deviceConfig.routingConfig == CONFIGURABLE_AUDIO_ENGINE_ROUTING) {
215 EXPECT_FALSE(volumeGroupConfig.name.empty())
216 << volumeGroupInfo << " must have a non-empty volume name";
217 }
218 if (volumeGroupConfig.id != VolumeGroupConfig::UNASSIGNED_ID) {
219 EXPECT_TRUE(groupIds.insert(volumeGroupConfig.id).second)
220 << volumeGroupInfo << " repeats volume group id " << volumeGroupConfig.id;
221 }
222 for (const auto& audioRoute : volumeGroupConfig.carAudioRoutes) {
223 std::string routeMessage;
224 EXPECT_TRUE(hasValidAudioRoute(audioRoute, routeMessage, groupDevices))
225 << volumeGroupInfo << " Volume route message: " << routeMessage;
226 }
227 if (volumeGroupConfig.activationConfiguration.has_value()) {
228 std::string activationMessage;
229 EXPECT_TRUE(hasValidVolumeGroupActivation(volumeGroupConfig.activationConfiguration.value(),
230 activationMessage))
231 << volumeGroupInfo << " Activation message: " << activationMessage;
232 }
233 }
234
validateAudioZoneFadeConfiguration(const AudioZoneFadeConfiguration & fadeConfiguration)235 void validateAudioZoneFadeConfiguration(const AudioZoneFadeConfiguration& fadeConfiguration) {
236 ALOGI("Fade configuration test");
237 std::set<audiomediacommon::AudioUsage> usages;
238 std::string defaultValidationMessage;
239 EXPECT_TRUE(hadValidAudioFadeConfiguration(fadeConfiguration.defaultConfiguration,
240 defaultValidationMessage))
241 << "Default configuration validation failed: " << defaultValidationMessage;
242 for (const auto& entry : fadeConfiguration.transientConfiguration) {
243 ALOGI("Transient fade configuration test");
244 std::string transientFadeConfigurationMessage;
245 EXPECT_TRUE(hadValidAudioFadeConfiguration(entry.transientFadeConfiguration,
246 transientFadeConfigurationMessage))
247 << "Transient fade configuration validation failed: "
248 << transientFadeConfigurationMessage;
249 EXPECT_FALSE(entry.transientUsages.empty())
250 << "Transient fade configuration must have at least one audio usage";
251 for (const auto& usage : entry.transientUsages) {
252 EXPECT_FALSE(usages.contains(usage)) << "Audio usages " << ToString(usage)
253 << " repeat in transient fade configuration";
254 }
255 }
256 }
257
validateAudioZoneConfiguration(const AudioZone & carAudioZone,const AudioZoneConfig & audioZoneConfig,const AudioDeviceConfiguration & deviceConfig)258 void validateAudioZoneConfiguration(const AudioZone& carAudioZone,
259 const AudioZoneConfig& audioZoneConfig,
260 const AudioDeviceConfiguration& deviceConfig) {
261 std::string zoneConfigName = testutils::toAlphaNumeric(ToString(audioZoneConfig.name));
262 ALOGI("Zone config name %s test", zoneConfigName.c_str());
263 std::set<std::string> contextInfoNames;
264 EXPECT_FALSE(audioZoneConfig.volumeGroups.empty())
265 << "Volume groups for zone config " << zoneConfigName.c_str();
266 std::set<std::string> groupDevices;
267 std::set<int> groupIds;
268 for (const auto& volumeGroup : audioZoneConfig.volumeGroups) {
269 ALOGI("Zone config name %s volume group test %s", zoneConfigName.c_str(),
270 ToString(volumeGroup.name).c_str());
271 std::vector<std::string> groupContexts =
272 testutils::getContextInfoNamesForVolumeGroup(volumeGroup);
273 for (const auto& context : groupContexts) {
274 EXPECT_FALSE(contextInfoNames.contains(context))
275 << "Context " << context << " repeats in zone config " << zoneConfigName;
276 contextInfoNames.insert(context);
277 }
278 // Configurable audio policy engine can share devices among volume groups
279 if (deviceConfig.routingConfig == CONFIGURABLE_AUDIO_ENGINE_ROUTING) {
280 groupDevices.clear();
281 }
282 validateVolumeGroupInfo(audioZoneConfig, volumeGroup, deviceConfig, groupDevices, groupIds);
283 }
284 const auto& audioZoneContexts = carAudioZone.audioZoneContext.audioContextInfos;
285 std::map<std::string, AudioZoneContextInfo> infoNameToInfo;
286 std::transform(audioZoneContexts.begin(), audioZoneContexts.end(),
287 std::inserter(infoNameToInfo, infoNameToInfo.end()),
288 [&](const AudioZoneContextInfo& context) {
289 return std::make_pair(ToString(context.name), context);
290 });
291 std::vector<AudioZoneContextInfo> configContextInfos;
292 for (const auto& contextName : contextInfoNames) {
293 const auto& pair = infoNameToInfo.find(contextName);
294 if (pair == infoNameToInfo.end()) {
295 continue;
296 }
297 configContextInfos.push_back(pair->second);
298 }
299 std::string message;
300 EXPECT_TRUE(testutils::contextInfosContainAllAudioAttributeUsages(configContextInfos, message))
301 << "Config " << zoneConfigName << " message: " << message;
302
303 if (audioZoneConfig.fadeConfiguration.has_value()) {
304 validateAudioZoneFadeConfiguration(audioZoneConfig.fadeConfiguration.value());
305 }
306 }
307
308 } // namespace
309
310 class AudioControlAidl : public testing::TestWithParam<std::string> {
311 public:
SetUp()312 virtual void SetUp() override {
313 audioControl = android::waitForDeclaredService<IAudioControl>(String16(GetParam().c_str()));
314 ASSERT_NE(audioControl, nullptr);
315 aidlVersion = audioControl->getInterfaceVersion();
316 }
317
TearDown()318 void TearDown() override { audioControl = nullptr; }
319
isAidlVersionAtleast(int version) const320 bool isAidlVersionAtleast(int version) const { return aidlVersion >= version; }
321
322 sp<IAudioControl> audioControl;
323 int32_t capabilities;
324 int32_t aidlVersion;
325 };
326
TEST_P(AudioControlAidl,OnSetFadeTowardsFront)327 TEST_P(AudioControlAidl, OnSetFadeTowardsFront) {
328 ALOGI("Fader exercise test (silent)");
329
330 // Set the fader all the way to the back
331 ASSERT_TRUE(audioControl->setFadeTowardFront(-1.0f).isOk());
332
333 // Set the fader all the way to the front
334 ASSERT_TRUE(audioControl->setFadeTowardFront(1.0f).isOk());
335
336 // Set the fader part way toward the back
337 ASSERT_TRUE(audioControl->setFadeTowardFront(-0.333f).isOk());
338
339 // Set the fader to a out of bounds value (driver should clamp)
340 ASSERT_TRUE(audioControl->setFadeTowardFront(99999.9f).isOk());
341
342 // Set the fader to a negative out of bounds value (driver should clamp)
343 ASSERT_TRUE(audioControl->setFadeTowardFront(-99999.9f).isOk());
344
345 // Set the fader back to the middle
346 ASSERT_TRUE(audioControl->setFadeTowardFront(0.0f).isOk());
347 }
348
TEST_P(AudioControlAidl,OnSetBalanceTowardsRight)349 TEST_P(AudioControlAidl, OnSetBalanceTowardsRight) {
350 ALOGI("Balance exercise test (silent)");
351
352 // Set the balance all the way to the left
353 ASSERT_TRUE(audioControl->setBalanceTowardRight(-1.0f).isOk());
354
355 // Set the balance all the way to the right
356 ASSERT_TRUE(audioControl->setBalanceTowardRight(1.0f).isOk());
357
358 // Set the balance part way toward the left
359 ASSERT_TRUE(audioControl->setBalanceTowardRight(-0.333f).isOk());
360
361 // Set the balance to a out of bounds value (driver should clamp)
362 ASSERT_TRUE(audioControl->setBalanceTowardRight(99999.9f).isOk());
363
364 // Set the balance to a negative out of bounds value (driver should clamp)
365 ASSERT_TRUE(audioControl->setBalanceTowardRight(-99999.9f).isOk());
366
367 // Set the balance back to the middle
368 ASSERT_TRUE(audioControl->setBalanceTowardRight(0.0f).isOk());
369
370 // Set the balance back to the middle
371 audioControl->setBalanceTowardRight(0.0f).isOk();
372 }
373
374 struct FocusListenerMock : BnFocusListener {
375 MOCK_METHOD(Status, requestAudioFocus,
376 (const String16& usage, int32_t zoneId, AudioFocusChange focusGain));
377 MOCK_METHOD(Status, abandonAudioFocus, (const String16& usage, int32_t zoneId));
378 MOCK_METHOD(Status, requestAudioFocusWithMetaData,
379 (const audiohalcommon::PlaybackTrackMetadata& metaData, int32_t zoneId,
380 AudioFocusChange focusGain));
381 MOCK_METHOD(Status, abandonAudioFocusWithMetaData,
382 (const audiohalcommon::PlaybackTrackMetadata& metaData, int32_t zoneId));
383 };
384
385 /*
386 * Test focus listener registration.
387 *
388 * Verifies that:
389 * - registerFocusListener succeeds;
390 * - registering a second listener succeeds in replacing the first;
391 * - closing handle does not crash;
392 */
TEST_P(AudioControlAidl,FocusListenerRegistration)393 TEST_P(AudioControlAidl, FocusListenerRegistration) {
394 ALOGI("Focus listener test");
395
396 sp<FocusListenerMock> listener = new FocusListenerMock();
397 ASSERT_TRUE(audioControl->registerFocusListener(listener).isOk());
398
399 sp<FocusListenerMock> listener2 = new FocusListenerMock();
400 ASSERT_TRUE(audioControl->registerFocusListener(listener2).isOk());
401 };
402
TEST_P(AudioControlAidl,FocusChangeExercise)403 TEST_P(AudioControlAidl, FocusChangeExercise) {
404 ALOGI("Focus Change test");
405
406 String16 usage = String16(xsd::toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA).c_str());
407 ASSERT_TRUE(
408 audioControl->onAudioFocusChange(usage, 0, AudioFocusChange::GAIN_TRANSIENT).isOk());
409 };
410
TEST_P(AudioControlAidl,MuteChangeExercise)411 TEST_P(AudioControlAidl, MuteChangeExercise) {
412 ALOGI("Mute change test");
413
414 MutingInfo mutingInfo;
415 mutingInfo.zoneId = 0;
416 mutingInfo.deviceAddressesToMute = {String16("address 1"), String16("address 2")};
417 mutingInfo.deviceAddressesToUnmute = {String16("address 3"), String16("address 4")};
418 std::vector<MutingInfo> mutingInfos = {mutingInfo};
419 ALOGI("Mute change test start");
420 ASSERT_TRUE(audioControl->onDevicesToMuteChange(mutingInfos).isOk());
421 }
422
TEST_P(AudioControlAidl,DuckChangeExercise)423 TEST_P(AudioControlAidl, DuckChangeExercise) {
424 ALOGI("Duck change test");
425
426 DuckingInfo duckingInfo;
427 duckingInfo.zoneId = 0;
428 duckingInfo.deviceAddressesToDuck = {String16("address 1"), String16("address 2")};
429 duckingInfo.deviceAddressesToUnduck = {String16("address 3"), String16("address 4")};
430 duckingInfo.usagesHoldingFocus = {
431 String16(xsd::toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA).c_str()),
432 String16(xsd::toString(xsd::AudioUsage::AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
433 .c_str())};
434 std::vector<DuckingInfo> duckingInfos = {duckingInfo};
435 ALOGI("Duck change test start");
436 ASSERT_TRUE(audioControl->onDevicesToDuckChange(duckingInfos).isOk());
437 }
438
TEST_P(AudioControlAidl,FocusChangeWithMetaDataExercise)439 TEST_P(AudioControlAidl, FocusChangeWithMetaDataExercise) {
440 ALOGI("Focus Change test");
441
442 audiohalcommon::PlaybackTrackMetadata metadata;
443 metadata.usage = audiomediacommon::AudioUsage::MEDIA;
444 metadata.contentType = audiomediacommon::AudioContentType::MUSIC;
445 metadata.tags = {"com.google.android=VR"};
446 ASSERT_TRUE(
447 audioControl
448 ->onAudioFocusChangeWithMetaData(metadata, 0, AudioFocusChange::GAIN_TRANSIENT)
449 .isOk());
450 };
451
TEST_P(AudioControlAidl,SetAudioDeviceGainsChangedExercise)452 TEST_P(AudioControlAidl, SetAudioDeviceGainsChangedExercise) {
453 ALOGI("Set Audio Gains Changed test");
454
455 const std::vector<Reasons> reasons{Reasons::FORCED_MASTER_MUTE, Reasons::NAV_DUCKING};
456 AudioGainConfigInfo agci1;
457 agci1.zoneId = 0;
458 agci1.devicePortAddress = String16("address 1");
459 agci1.volumeIndex = 8;
460
461 AudioGainConfigInfo agci2;
462 agci1.zoneId = 0;
463 agci1.devicePortAddress = String16("address 2");
464 agci1.volumeIndex = 1;
465
466 std::vector<AudioGainConfigInfo> gains{agci1, agci2};
467 ASSERT_TRUE(audioControl->setAudioDeviceGainsChanged(reasons, gains).isOk());
468 }
469
470 /*
471 * Test Audio Gain Callback registration.
472 *
473 * Verifies that:
474 * - registerGainCallback succeeds;
475 * - registering a second callback succeeds in replacing the first;
476 * - closing handle does not crash;
477 */
478 struct AudioGainCallbackMock : BnAudioGainCallback {
479 MOCK_METHOD(Status, onAudioDeviceGainsChanged,
480 (const std::vector<Reasons>& reasons,
481 const std::vector<AudioGainConfigInfo>& gains));
482 };
483
TEST_P(AudioControlAidl,AudioGainCallbackRegistration)484 TEST_P(AudioControlAidl, AudioGainCallbackRegistration) {
485 ALOGI("Focus listener test");
486
487 sp<AudioGainCallbackMock> gainCallback = new AudioGainCallbackMock();
488 ASSERT_TRUE(audioControl->registerGainCallback(gainCallback).isOk());
489
490 sp<AudioGainCallbackMock> gainCallback2 = new AudioGainCallbackMock();
491 ASSERT_TRUE(audioControl->registerGainCallback(gainCallback2).isOk());
492 }
493
494 /*
495 * Test Module change Callback registration.
496 *
497 * Verifies that:
498 * - setModuleChangeCallback succeeds
499 * - setting a double callback fails with exception
500 * - clearModuleChangeCallback succeeds
501 * - setting with nullptr callback fails with exception
502 * - closing handle does not crash
503 */
504 struct ModuleChangeCallbackMock : BnModuleChangeCallback {
505 MOCK_METHOD(Status, onAudioPortsChanged,
506 (const std::vector<android::media::audio::common::AudioPort>& audioPorts));
507 };
508
TEST_P(AudioControlAidl,RegisterModuleChangeCallbackTwiceThrowsException)509 TEST_P(AudioControlAidl, RegisterModuleChangeCallbackTwiceThrowsException) {
510 ALOGI("Register Module change callback test");
511 if (!isAidlVersionAtleast(kAidlVersionThree)) {
512 GTEST_SKIP() << "Device does not support the new APIs for module change callback";
513 return;
514 }
515
516 // make sure no stale callbacks.
517 audioControl->clearModuleChangeCallback();
518
519 sp<ModuleChangeCallbackMock> moduleChangeCallback = new ModuleChangeCallbackMock();
520 auto status = audioControl->setModuleChangeCallback(moduleChangeCallback);
521 EXPECT_THAT(status.exceptionCode(),
522 AnyOf(Eq(Status::EX_NONE), Eq(Status::EX_UNSUPPORTED_OPERATION)));
523 if (!status.isOk()) return;
524
525 sp<ModuleChangeCallbackMock> moduleChangeCallback2 = new ModuleChangeCallbackMock();
526 // no need to check for unsupported feature
527 EXPECT_EQ(Status::EX_ILLEGAL_STATE,
528 audioControl->setModuleChangeCallback(moduleChangeCallback2).exceptionCode());
529 ASSERT_TRUE(audioControl->clearModuleChangeCallback().isOk());
530 ASSERT_TRUE(audioControl->setModuleChangeCallback(moduleChangeCallback2).isOk());
531 }
532
TEST_P(AudioControlAidl,RegisterModuleChangeNullCallbackThrowsException)533 TEST_P(AudioControlAidl, RegisterModuleChangeNullCallbackThrowsException) {
534 ALOGI("Register Module change callback with nullptr test");
535 if (!isAidlVersionAtleast(kAidlVersionThree)) {
536 GTEST_SKIP() << "Device does not support the new APIs for module change callback";
537 return;
538 }
539
540 auto status = audioControl->setModuleChangeCallback(nullptr);
541 EXPECT_THAT(status.exceptionCode(),
542 AnyOf(Eq(Status::EX_ILLEGAL_ARGUMENT), Eq(Status::EX_UNSUPPORTED_OPERATION)));
543 }
544
545 class AudioControlVersionFiveAndAbove : public AudioControlAidl {
546 public:
SetUp()547 virtual void SetUp() override {
548 AudioControlAidl::SetUp();
549 if (isAidlVersionAtleast(kAidlVersionFive)) {
550 return;
551 }
552 GTEST_SKIP() << " Version is lower than " << std::to_string(kAidlVersionFive);
553 }
554 };
555
556 class AudioControlWithAudioConfiguration : public AudioControlVersionFiveAndAbove {
557 public:
SetUp()558 virtual void SetUp() override {
559 AudioControlVersionFiveAndAbove::SetUp();
560
561 if (IsSkipped()) {
562 return;
563 }
564
565 const auto& configStatus =
566 audioControl->getAudioDeviceConfiguration(&audioDeviceConfiguration);
567
568 EXPECT_THAT(configStatus.exceptionCode(),
569 AnyOf(Eq(Status::EX_NONE), Eq(Status::EX_UNSUPPORTED_OPERATION)));
570 if (!configStatus.isOk()) {
571 GTEST_SKIP() << "Device does not support audio configurations APIs";
572 }
573 ALOGD("Audio device info: %s", audioDeviceConfiguration.toString().c_str());
574 }
575
576 AudioDeviceConfiguration audioDeviceConfiguration;
577 };
578
TEST_P(AudioControlWithAudioConfiguration,DefaultAudioRoutingConfiguration)579 TEST_P(AudioControlWithAudioConfiguration, DefaultAudioRoutingConfiguration) {
580 if (audioDeviceConfiguration.routingConfig != DEFAULT_AUDIO_ROUTING) {
581 GTEST_SKIP() << "Default audio routing not supported";
582 }
583 std::vector<AudioZone> zones;
584
585 const auto& zoneStatus = audioControl->getCarAudioZones(&zones);
586
587 EXPECT_THAT(zoneStatus.exceptionCode(),
588 AnyOf(Eq(Status::EX_NONE), Eq(Status::EX_UNSUPPORTED_OPERATION)))
589 << "Default routing can be implemented or unsupported";
590 if (!zoneStatus.isOk()) return;
591 EXPECT_TRUE(zones.empty()) << "Zones must be empty for default routing";
592 }
593
594 class AudioControlWithDynamicConfiguration : public AudioControlWithAudioConfiguration {
595 public:
SetUp()596 virtual void SetUp() override {
597 AudioControlWithAudioConfiguration::SetUp();
598 if (IsSkipped()) {
599 return;
600 }
601 if (audioDeviceConfiguration.routingConfig == DEFAULT_AUDIO_ROUTING) {
602 GTEST_SKIP() << "Dynamic/core audio routing not supported";
603 }
604 const auto& zoneStatus = audioControl->getCarAudioZones(&audioZones);
605 EXPECT_EQ(zoneStatus.exceptionCode(), Status::EX_NONE)
606 << "Zones API must be supported for core/dynamic routing";
607 }
608
609 std::vector<AudioZone> audioZones;
610 };
611
TEST_P(AudioControlWithDynamicConfiguration,DynamicAudioRoutingConfiguration)612 TEST_P(AudioControlWithDynamicConfiguration, DynamicAudioRoutingConfiguration) {
613 EXPECT_FALSE(audioZones.empty()) << "Zones must not be empty for core/dynamic routing";
614 }
615
616 class AudioControlWithAudioZoneInfo : public AudioControlWithDynamicConfiguration {
617 public:
SetUp()618 virtual void SetUp() override {
619 AudioControlWithDynamicConfiguration::SetUp();
620 if (IsSkipped()) {
621 return;
622 }
623 EXPECT_TRUE(!audioZones.empty()) << "Zones must exist for core/dynamic routing";
624 }
625 };
626
TEST_P(AudioControlWithAudioZoneInfo,AudioZonesRequirements)627 TEST_P(AudioControlWithAudioZoneInfo, AudioZonesRequirements) {
628 bool primaryZoneFound = false;
629 std::set<int> zoneIds;
630 std::set<int> occupantIds;
631 std::set<android::String16> zoneNames;
632 std::set<std::string> deviceAddresses;
633 for (const auto& zone : audioZones) {
634 if (zone.id == static_cast<int>(AudioHalProductStrategy::ZoneId::DEFAULT)) {
635 EXPECT_FALSE(primaryZoneFound) << "There can only be one primary zone";
636 primaryZoneFound = true;
637 }
638 EXPECT_FALSE(zoneIds.contains(zone.id)) << "Zone " << std::to_string(zone.id) << " repeats";
639 zoneIds.insert(zone.id);
640 if (!zone.name.empty()) {
641 EXPECT_FALSE(zoneNames.contains(zone.name)) << "Zone " << zone.name << " repeats";
642 zoneNames.insert(zone.name);
643 }
644 if (zone.occupantZoneId != AudioZone::UNASSIGNED_OCCUPANT) {
645 EXPECT_FALSE(occupantIds.contains(zone.occupantZoneId))
646 << "Occupant zone id " << zone.occupantZoneId << " repeats";
647 occupantIds.insert(zone.occupantZoneId);
648 }
649 const auto& zoneAddresses = testutils::getDeviceAddressesForZone(zone);
650 for (const auto& address : zoneAddresses) {
651 EXPECT_FALSE(deviceAddresses.contains(address))
652 << "Device address " << address << " in zone " << zone.name << " repeats";
653 }
654 // Add after zone comparison is done since devices may repeat within a zone for different
655 // configurations
656 deviceAddresses.insert(zoneAddresses.begin(), zoneAddresses.end());
657 }
658 EXPECT_TRUE(primaryZoneFound) << "Primary zone must exist";
659 }
660
TEST_P(AudioControlWithAudioZoneInfo,AudioZoneInfoRequirements)661 TEST_P(AudioControlWithAudioZoneInfo, AudioZoneInfoRequirements) {
662 for (const auto& carAudioZone : audioZones) {
663 ALOGI("Zone id %d test", carAudioZone.id);
664 std::string missingContextMessage;
665 EXPECT_TRUE(testutils::contextContainsAllAudioAttributeUsages(carAudioZone.audioZoneContext,
666 missingContextMessage))
667 << "Audio zone context for zone id " << std::to_string(carAudioZone.id)
668 << missingContextMessage;
669 EXPECT_FALSE(carAudioZone.audioZoneConfigs.empty())
670 << "Audio zone zone id " << std::to_string(carAudioZone.id)
671 << " missing zone configs";
672 std::set<android::String16> configNames;
673 bool defaultConfigFound = false;
674 for (const auto& config : carAudioZone.audioZoneConfigs) {
675 ALOGI("Zone id %d config name %s test", carAudioZone.id, ToString(config.name).c_str());
676 if (config.isDefault) {
677 EXPECT_FALSE(defaultConfigFound)
678 << "Config name " << config.name
679 << " repeats default config value in zone id " << carAudioZone.id;
680 defaultConfigFound = true;
681 }
682 EXPECT_FALSE(configNames.contains(config.name))
683 << "Config name " << config.name << " repeats in " << carAudioZone.id;
684 }
685 EXPECT_TRUE(defaultConfigFound)
686 << "Audio zone " << carAudioZone.id << " must contain default config";
687 std::set<audiomediacommon::AudioPort> inputPorts;
688 ALOGI("Zone id %d input devices test", carAudioZone.id);
689 for (const auto& audioPort : carAudioZone.inputAudioDevices) {
690 std::string address;
691 const auto hasAddress = testutils::getAddressForAudioPort(audioPort, address);
692 EXPECT_FALSE(inputPorts.contains(audioPort))
693 << "Repeating input device for " << carAudioZone.id << ", device address "
694 << (hasAddress ? address : "empty address");
695 inputPorts.insert(audioPort);
696 }
697 }
698 }
699
TEST_P(AudioControlWithAudioZoneInfo,AudioZoneConfigInfoRequirements)700 TEST_P(AudioControlWithAudioZoneInfo, AudioZoneConfigInfoRequirements) {
701 for (const auto& carAudioZone : audioZones) {
702 for (const auto& audioZoneConfig : carAudioZone.audioZoneConfigs) {
703 validateAudioZoneConfiguration(carAudioZone, audioZoneConfig, audioDeviceConfiguration);
704 }
705 }
706 }
707
708 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlAidl);
709 INSTANTIATE_TEST_SUITE_P(
710 Audiocontrol, AudioControlAidl,
711 testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)),
712 android::PrintInstanceNameToString);
713
714 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlWithAudioConfiguration);
715 INSTANTIATE_TEST_SUITE_P(
716 Audiocontrol, AudioControlWithAudioConfiguration,
717 testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)),
718 android::PrintInstanceNameToString);
719
720 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlWithDynamicConfiguration);
721 INSTANTIATE_TEST_SUITE_P(
722 Audiocontrol, AudioControlWithDynamicConfiguration,
723 testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)),
724 android::PrintInstanceNameToString);
725
726 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlWithAudioZoneInfo);
727 INSTANTIATE_TEST_SUITE_P(
728 Audiocontrol, AudioControlWithAudioZoneInfo,
729 testing::ValuesIn(android::getAidlHalInstanceNames(IAudioControl::descriptor)),
730 android::PrintInstanceNameToString);
731
main(int argc,char ** argv)732 int main(int argc, char** argv) {
733 ::testing::InitGoogleTest(&argc, argv);
734 ProcessState::self()->setThreadPoolMaxThreadCount(1);
735 ProcessState::self()->startThreadPool();
736 return RUN_ALL_TESTS();
737 }
738