xref: /aosp_15_r20/hardware/interfaces/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
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