From 315ce41a5de1e0c11a8a54437fdd159d9047a382 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 23 Oct 2019 16:46:54 -0700 Subject: [PATCH 1/4] audio: Parametrize effect VTS tests for V6.0 Parametrize tests to accept IEffectsFactory instance name. Discover the instances in the test. Bug: 141847510 Bug: 141989952 Test: atest VtsHalAudioEffectV5_0TargetTest atest VtsHalAudioEffectV6_0TargetTest Change-Id: Iaf19109fc77a93b211cc3da85c21c0584d4f2b88 Merged-In: Iaf19109fc77a93b211cc3da85c21c0584d4f2b88 --- .../VtsHalAudioEffectTargetTest.cpp | 121 ++++++++++++------ 1 file changed, 83 insertions(+), 38 deletions(-) diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp index c4c7f7ccc4..3c712b5ca3 100644 --- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp +++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp @@ -28,8 +28,14 @@ #include +#if MAJOR_VERSION <= 5 #include #include +#elif MAJOR_VERSION >= 6 +#include +#include +#include +#endif using ::android::sp; using ::android::hardware::hidl_handle; @@ -49,6 +55,11 @@ using namespace ::android::hardware::audio::effect::CPP_VERSION; #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) #endif +#if MAJOR_VERSION <= 5 +// For HAL versions 2..5 Vts Environment and Test base classes are used. +// The tests are non-parametrized. +#define EFFECT_TEST TEST_F + // Test environment for Audio Effects Factory HIDL HAL. class AudioEffectsFactoryHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -71,6 +82,18 @@ class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase { ASSERT_NE(effectsFactory, nullptr); } +#elif MAJOR_VERSION >= 6 +// For HAL version 6 and above, standard GTest Environment and Test base classes are used. +// The tests are parametrized by the IEffectsFactory instance name. +#define EFFECT_TEST TEST_P + +class AudioEffectsFactoryHidlTest : public ::testing::TestWithParam { + public: + void SetUp() override { + effectsFactory = IEffectsFactory::getService(GetParam()); + ASSERT_NE(effectsFactory, nullptr); + } +#endif // The rest of the AudioEffectsFactoryHidlTest class definition is the same. void TearDown() override { effectsFactory.clear(); } protected: @@ -81,7 +104,7 @@ class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp effectsFactory; }; -TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) { +EFFECT_TEST(AudioEffectsFactoryHidlTest, EnumerateEffects) { description("Verify that EnumerateEffects returns at least one effect"); Result retval = Result::NOT_INITIALIZED; size_t effectCount = 0; @@ -95,7 +118,7 @@ TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) { EXPECT_GT(effectCount, 0u); } -TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) { +EFFECT_TEST(AudioEffectsFactoryHidlTest, CreateEffect) { description("Verify that an effect can be created via CreateEffect"); bool gotEffect = false; Uuid effectUuid; @@ -123,7 +146,7 @@ TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) { EXPECT_NE(nullptr, effect.get()); } -TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) { +EFFECT_TEST(AudioEffectsFactoryHidlTest, GetDescriptor) { description( "Verify that effects factory can provide an effect descriptor via " "GetDescriptor"); @@ -146,7 +169,7 @@ TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) { EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) { +EFFECT_TEST(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) { description("Verify that debugDump doesn't crash on invalid arguments"); #if MAJOR_VERSION == 2 Return ret = effectsFactory->debugDump(hidl_handle()); @@ -168,10 +191,17 @@ static const Uuid LOUDNESS_ENHANCER_EFFECT_TYPE = { std::array{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}}; // The main test class for Audio Effect HIDL HAL. +#if MAJOR_VERSION <= 5 class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: void SetUp() override { effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService(); +#elif MAJOR_VERSION >= 6 +class AudioEffectHidlTest : public ::testing::TestWithParam { + public: + void SetUp() override { + effectsFactory = IEffectsFactory::getService(GetParam()); +#endif ASSERT_NE(nullptr, effectsFactory.get()); findAndCreateEffect(getEffectType()); @@ -250,14 +280,14 @@ void AudioEffectHidlTest::getChannelCount(uint32_t* channelCount) { static_cast(currentConfig.outputCfg.channels)); } -TEST_F(AudioEffectHidlTest, Close) { +EFFECT_TEST(AudioEffectHidlTest, Close) { description("Verify that an effect can be closed"); Return ret = effect->close(); EXPECT_TRUE(ret.isOk()); EXPECT_EQ(Result::OK, ret); } -TEST_F(AudioEffectHidlTest, GetDescriptor) { +EFFECT_TEST(AudioEffectHidlTest, GetDescriptor) { description("Verify that an effect can return its own descriptor via GetDescriptor"); Result retval = Result::NOT_INITIALIZED; Uuid actualType; @@ -272,7 +302,7 @@ TEST_F(AudioEffectHidlTest, GetDescriptor) { EXPECT_EQ(getEffectType(), actualType); } -TEST_F(AudioEffectHidlTest, GetSetConfig) { +EFFECT_TEST(AudioEffectHidlTest, GetSetConfig) { description( "Verify that it is possible to manipulate effect config via Get / " "SetConfig"); @@ -291,26 +321,26 @@ TEST_F(AudioEffectHidlTest, GetSetConfig) { EXPECT_EQ(Result::OK, ret2); } -TEST_F(AudioEffectHidlTest, GetConfigReverse) { +EFFECT_TEST(AudioEffectHidlTest, GetConfigReverse) { description("Verify that GetConfigReverse does not crash"); Return ret = effect->getConfigReverse([&](Result, const EffectConfig&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) { +EFFECT_TEST(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) { description("Verify that GetSupportedAuxChannelsConfigs does not crash"); Return ret = effect->getSupportedAuxChannelsConfigs( 0, [&](Result, const hidl_vec&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, GetAuxChannelsConfig) { +EFFECT_TEST(AudioEffectHidlTest, GetAuxChannelsConfig) { description("Verify that GetAuxChannelsConfig does not crash"); Return ret = effect->getAuxChannelsConfig([&](Result, const EffectAuxChannelsConfig&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, SetAuxChannelsConfig) { +EFFECT_TEST(AudioEffectHidlTest, SetAuxChannelsConfig) { description("Verify that SetAuxChannelsConfig does not crash"); Return ret = effect->setAuxChannelsConfig(EffectAuxChannelsConfig()); EXPECT_TRUE(ret.isOk()); @@ -349,7 +379,7 @@ inline bool operator==(const EffectConfig& lhs, const EffectConfig& rhs) { } // namespace hardware } // namespace android -TEST_F(AudioEffectHidlTest, Reset) { +EFFECT_TEST(AudioEffectHidlTest, Reset) { description("Verify that Reset preserves effect configuration"); Result retval = Result::NOT_INITIALIZED; EffectConfig originalConfig; @@ -374,7 +404,7 @@ TEST_F(AudioEffectHidlTest, Reset) { EXPECT_EQ(originalConfig, configAfterReset); } -TEST_F(AudioEffectHidlTest, DisableEnableDisable) { +EFFECT_TEST(AudioEffectHidlTest, DisableEnableDisable) { description("Verify Disable -> Enable -> Disable sequence for an effect"); Return ret = effect->disable(); EXPECT_TRUE(ret.isOk()); @@ -387,14 +417,14 @@ TEST_F(AudioEffectHidlTest, DisableEnableDisable) { EXPECT_EQ(Result::OK, ret); } -TEST_F(AudioEffectHidlTest, SetDevice) { +EFFECT_TEST(AudioEffectHidlTest, SetDevice) { description("Verify that SetDevice works for an output chain effect"); Return ret = effect->setDevice(mkEnumBitfield(AudioDevice::OUT_SPEAKER)); EXPECT_TRUE(ret.isOk()); EXPECT_EQ(Result::OK, ret); } -TEST_F(AudioEffectHidlTest, SetAndGetVolume) { +EFFECT_TEST(AudioEffectHidlTest, SetAndGetVolume) { description("Verify that SetAndGetVolume method works for an effect"); uint32_t channelCount; getChannelCount(&channelCount); @@ -410,7 +440,7 @@ TEST_F(AudioEffectHidlTest, SetAndGetVolume) { EXPECT_EQ(Result::OK, retval); } -TEST_F(AudioEffectHidlTest, VolumeChangeNotification) { +EFFECT_TEST(AudioEffectHidlTest, VolumeChangeNotification) { description("Verify that effect accepts VolumeChangeNotification"); uint32_t channelCount; getChannelCount(&channelCount); @@ -424,32 +454,32 @@ TEST_F(AudioEffectHidlTest, VolumeChangeNotification) { EXPECT_EQ(Result::OK, ret); } -TEST_F(AudioEffectHidlTest, SetAudioMode) { +EFFECT_TEST(AudioEffectHidlTest, SetAudioMode) { description("Verify that SetAudioMode works for an effect"); Return ret = effect->setAudioMode(AudioMode::NORMAL); EXPECT_TRUE(ret.isOk()); EXPECT_EQ(Result::OK, ret); } -TEST_F(AudioEffectHidlTest, SetConfigReverse) { +EFFECT_TEST(AudioEffectHidlTest, SetConfigReverse) { description("Verify that SetConfigReverse does not crash"); Return ret = effect->setConfigReverse(EffectConfig(), nullptr, nullptr); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, SetInputDevice) { +EFFECT_TEST(AudioEffectHidlTest, SetInputDevice) { description("Verify that SetInputDevice does not crash"); Return ret = effect->setInputDevice(mkEnumBitfield(AudioDevice::IN_BUILTIN_MIC)); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, SetAudioSource) { +EFFECT_TEST(AudioEffectHidlTest, SetAudioSource) { description("Verify that SetAudioSource does not crash"); Return ret = effect->setAudioSource(AudioSource::MIC); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, Offload) { +EFFECT_TEST(AudioEffectHidlTest, Offload) { description("Verify that calling Offload method does not crash"); EffectOffloadParameter offloadParam; offloadParam.isOffload = false; @@ -458,7 +488,7 @@ TEST_F(AudioEffectHidlTest, Offload) { EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, PrepareForProcessing) { +EFFECT_TEST(AudioEffectHidlTest, PrepareForProcessing) { description("Verify that PrepareForProcessing method works for an effect"); Result retval = Result::NOT_INITIALIZED; Return ret = effect->prepareForProcessing( @@ -467,7 +497,7 @@ TEST_F(AudioEffectHidlTest, PrepareForProcessing) { EXPECT_EQ(Result::OK, retval); } -TEST_F(AudioEffectHidlTest, SetProcessBuffers) { +EFFECT_TEST(AudioEffectHidlTest, SetProcessBuffers) { description("Verify that SetProcessBuffers works for an effect"); sp ashmem = IAllocator::getService("ashmem"); ASSERT_NE(nullptr, ashmem.get()); @@ -486,41 +516,41 @@ TEST_F(AudioEffectHidlTest, SetProcessBuffers) { EXPECT_EQ(Result::OK, ret2); } -TEST_F(AudioEffectHidlTest, Command) { +EFFECT_TEST(AudioEffectHidlTest, Command) { description("Verify that Command does not crash"); Return ret = effect->command(0, hidl_vec(), 0, [&](int32_t, const hidl_vec&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, SetParameter) { +EFFECT_TEST(AudioEffectHidlTest, SetParameter) { description("Verify that SetParameter does not crash"); Return ret = effect->setParameter(hidl_vec(), hidl_vec()); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, GetParameter) { +EFFECT_TEST(AudioEffectHidlTest, GetParameter) { description("Verify that GetParameter does not crash"); Return ret = effect->getParameter(hidl_vec(), 0, [&](Result, const hidl_vec&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, GetSupportedConfigsForFeature) { +EFFECT_TEST(AudioEffectHidlTest, GetSupportedConfigsForFeature) { description("Verify that GetSupportedConfigsForFeature does not crash"); Return ret = effect->getSupportedConfigsForFeature( 0, 0, 0, [&](Result, uint32_t, const hidl_vec&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, GetCurrentConfigForFeature) { +EFFECT_TEST(AudioEffectHidlTest, GetCurrentConfigForFeature) { description("Verify that GetCurrentConfigForFeature does not crash"); Return ret = effect->getCurrentConfigForFeature(0, 0, [&](Result, const hidl_vec&) {}); EXPECT_TRUE(ret.isOk()); } -TEST_F(AudioEffectHidlTest, SetCurrentConfigForFeature) { +EFFECT_TEST(AudioEffectHidlTest, SetCurrentConfigForFeature) { description("Verify that SetCurrentConfigForFeature does not crash"); Return ret = effect->setCurrentConfigForFeature(0, hidl_vec()); EXPECT_TRUE(ret.isOk()); @@ -606,21 +636,21 @@ void EqualizerAudioEffectHidlTest::getPresetCount(size_t* count) { ASSERT_EQ(Result::OK, retval); } -TEST_F(EqualizerAudioEffectHidlTest, GetNumBands) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetNumBands) { description("Verify that Equalizer effect reports at least one band"); uint16_t numBands = 0; getNumBands(&numBands); EXPECT_GT(numBands, 0); } -TEST_F(EqualizerAudioEffectHidlTest, GetLevelRange) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetLevelRange) { description("Verify that Equalizer effect reports adequate band level range"); int16_t minLevel = 0x7fff, maxLevel = 0; getLevelRange(&minLevel, &maxLevel); EXPECT_GT(maxLevel, minLevel); } -TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetBandLevel) { description("Verify that manipulating band levels works for Equalizer effect"); uint16_t numBands = 0; getNumBands(&numBands); @@ -649,7 +679,7 @@ TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) { } } -TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) { description("Verify that Equalizer effect reports adequate band frequency range"); uint16_t numBands = 0; getNumBands(&numBands); @@ -664,7 +694,7 @@ TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) { } } -TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetBandForFrequency) { description("Verify that Equalizer effect supports GetBandForFrequency correctly"); uint16_t numBands = 0; getNumBands(&numBands); @@ -693,14 +723,14 @@ TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) { } } -TEST_F(EqualizerAudioEffectHidlTest, GetPresetNames) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetPresetNames) { description("Verify that Equalizer effect reports at least one preset"); size_t presetCount; getPresetCount(&presetCount); EXPECT_GT(presetCount, 0u); } -TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) { description("Verify that manipulating the current preset for Equalizer effect"); size_t presetCount; getPresetCount(&presetCount); @@ -723,7 +753,7 @@ TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) { } } -TEST_F(EqualizerAudioEffectHidlTest, GetSetAllProperties) { +EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetAllProperties) { description( "Verify that setting band levels and presets works via Get / " "SetAllProperties for Equalizer effect"); @@ -787,7 +817,7 @@ class LoudnessEnhancerAudioEffectHidlTest : public AudioEffectHidlTest { sp enhancer; }; -TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { +EFFECT_TEST(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { description( "Verify that manipulating the target gain works for Loudness Enhancer " "effect"); @@ -808,6 +838,7 @@ TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { EXPECT_EQ(gain, actualGain); } +#if MAJOR_VERSION <= 5 int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(AudioEffectsFactoryHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); @@ -816,3 +847,17 @@ int main(int argc, char** argv) { LOG(INFO) << "Test result = " << status; return status; } +#elif MAJOR_VERSION >= 6 +INSTANTIATE_TEST_SUITE_P( + EffectsFactory, AudioEffectsFactoryHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)), + android::hardware::PrintInstanceNameToString); +INSTANTIATE_TEST_SUITE_P( + Equalizer, EqualizerAudioEffectHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)), + android::hardware::PrintInstanceNameToString); +INSTANTIATE_TEST_SUITE_P( + LoudnessEnhancer, LoudnessEnhancerAudioEffectHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)), + android::hardware::PrintInstanceNameToString); +#endif From ccd484bb80b2bdf4c1240e4853e776e2f069e855 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 18 Oct 2019 13:09:35 -0700 Subject: [PATCH 2/4] audio: Parametrize core VTS tests Parametrize tests to accept IDevicesFactory instance name and IDevice instance name. For audio HAL versions 2..5 the factory instance name is taken from the VTS environment, and the device is always "primary". For the next versions the factories are discovered by the test, and the devices are taken from the audio policy configuration (to be implemented, see added FIXME comments). Split the Environment class into two versions: for HAL 2..5 and for next versions. They use different base class. Move device factories and device caching into dedicated classes DevicesFactoryManager and DeviceManager. They deal with instance caching and proper release of server resources. Bug: 141847510 Bug: 141989952 Test: atest VtsHalAudioV5_0TargetTest atest VtsHalAudioV6_0TargetTest Change-Id: I92c44e0c3f900164dded7e9c4bfc642ca2c335db Merged-In: I92c44e0c3f900164dded7e9c4bfc642ca2c335db --- .../include/utility/EnvironmentTearDown.h | 13 +- .../2.0/AudioPrimaryHidlHalTest.cpp | 9 +- .../vts/functional/2.0/EnvironmentTearDown.h | 34 ++ .../4.0/AudioPrimaryHidlHalTest.cpp | 71 ++- .../vts/functional/6.0/EnvironmentTearDown.h | 35 ++ .../vts/functional/AudioPrimaryHidlHalTest.h | 434 ++++++++++++------ .../vts/functional/DeviceManager.h | 143 ++++++ 7 files changed, 537 insertions(+), 202 deletions(-) create mode 100644 audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h create mode 100644 audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h create mode 100644 audio/core/all-versions/vts/functional/DeviceManager.h diff --git a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h index 0e416f3c64..2b240ce309 100644 --- a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h +++ b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h @@ -20,9 +20,6 @@ #include #include -#include -#include - namespace android { namespace hardware { namespace audio { @@ -34,18 +31,20 @@ namespace utility { * Avoid destroying static objects after main return. * Post main return destruction leads to incorrect gtest timing measurements as * well as harder debuging if anything goes wrong during destruction. */ -class Environment : public ::testing::VtsHalHidlTargetTestEnvBase { - public: +class EnvironmentTearDown { + public: using TearDownFunc = std::function; void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_front(std::move(tearDown)); } - private: - void HidlTearDown() override { + protected: + void executeAllTearDowns() { // Call the tear downs in reverse order of insertion for (auto& tearDown : tearDowns) { tearDown(); } } + + private: std::list tearDowns; }; diff --git a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp index 7906bf1b62..c1894645fd 100644 --- a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp @@ -60,19 +60,20 @@ TEST_IO_STREAM(SetConnectedState, "deconnection", testConnectedState(stream.get())) -TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", ASSERT_IS_OK(device->getHwAvSync())); +TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", + ASSERT_IS_OK(getDevice()->getHwAvSync())); -TEST_F(AudioPrimaryHidlTest, setMode) { +TEST_P(AudioPrimaryHidlTest, setMode) { doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise"); // Test Invalid values for (AudioMode mode : {AudioMode::INVALID, AudioMode::CURRENT, AudioMode::CNT}) { SCOPED_TRACE("mode=" + toString(mode)); - ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(mode)); + ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(mode)); } // Test valid values for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE, AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) { SCOPED_TRACE("mode=" + toString(mode)); - ASSERT_OK(device->setMode(mode)); + ASSERT_OK(getDevice()->setMode(mode)); } } diff --git a/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h new file mode 100644 index 0000000000..6373e39111 --- /dev/null +++ b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H +#define ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H + +#include +#include + +#include "utility/EnvironmentTearDown.h" + +class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown, + public ::testing::VtsHalHidlTargetTestEnvBase { + private: + void HidlTearDown() override { + executeAllTearDowns(); + VtsHalHidlTargetTestEnvBase::HidlTearDown(); + } +}; + +#endif // ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp index 15be3bf470..b8defb620a 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp @@ -16,25 +16,14 @@ #include "AudioPrimaryHidlHalTest.h" -static void waitForDeviceDestruction() { - // FIXME: there is no way to know when the remote IDevice is being destroyed - // Binder does not support testing if an object is alive, thus - // wait for 100ms to let the binder destruction propagates and - // the remote device has the time to be destroyed. - // flushCommand makes sure all local command are sent, thus should reduce - // the latency between local and remote destruction. - IPCThreadState::self()->flushCommands(); - usleep(100 * 1000); -} - -TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { +TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { doc::test("Calling openDevice(\"primary\") should return the primary device."); struct WaitExecutor { - ~WaitExecutor() { waitForDeviceDestruction(); } + ~WaitExecutor() { DeviceManager::waitForInstanceDestruction(); } } waitExecutor; // Make sure we wait for the device destruction on exiting from the test. Result result; sp baseDevice; - ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice))); + ASSERT_OK(getDevicesFactory()->openDevice("primary", returnIn(result, baseDevice))); if (result != Result::OK && isPrimaryDeviceOptional()) { GTEST_SKIP() << "No primary device on this factory"; // returns } @@ -50,10 +39,10 @@ TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { /////////////////////////// get(Active)Microphones /////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) { +TEST_P(AudioPrimaryHidlTest, GetMicrophonesTest) { doc::test("Make sure getMicrophones always succeeds"); hidl_vec microphones; - ASSERT_OK(device->getMicrophones(returnIn(res, microphones))); + ASSERT_OK(getDevice()->getMicrophones(returnIn(res, microphones))); ASSERT_OK(res); if (microphones.size() > 0) { // When there is microphone on the phone, try to open an input stream @@ -75,15 +64,15 @@ TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) { } sp stream; AudioConfig suggestedConfig{}; - ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, config, flags, - initMetadata, - returnIn(res, stream, suggestedConfig))); + ASSERT_OK(getDevice()->openInputStream(ioHandle, microphone.deviceAddress, config, + flags, initMetadata, + returnIn(res, stream, suggestedConfig))); if (res != Result::OK) { ASSERT_TRUE(stream == nullptr); AudioConfig suggestedConfigRetry{}; - ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, - suggestedConfig, flags, initMetadata, - returnIn(res, stream, suggestedConfigRetry))); + ASSERT_OK(getDevice()->openInputStream( + ioHandle, microphone.deviceAddress, suggestedConfig, flags, initMetadata, + returnIn(res, stream, suggestedConfigRetry))); } ASSERT_OK(res); hidl_vec activeMicrophones; @@ -131,7 +120,7 @@ TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) { } } -TEST_F(AudioPrimaryHidlTest, SetConnectedState) { +TEST_P(AudioPrimaryHidlTest, SetConnectedState) { doc::test("Check that the HAL can be notified of device connection and deconnection"); using AD = AudioDevice; for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) { @@ -140,7 +129,7 @@ TEST_F(AudioPrimaryHidlTest, SetConnectedState) { SCOPED_TRACE("state=" + ::testing::PrintToString(state)); DeviceAddress address = {}; address.device = deviceType; - auto ret = device->setConnectedState(address, state); + auto ret = getDevice()->setConnectedState(address, state); ASSERT_TRUE(ret.isOk()); if (ret == Result::NOT_SUPPORTED) { doc::partialTest("setConnectedState is not supported"); @@ -153,9 +142,7 @@ TEST_F(AudioPrimaryHidlTest, SetConnectedState) { // Because there is no way of knowing if the devices were connected before // calling setConnectedState, there is no way to restore the HAL to its // initial state. To workaround this, destroy the HAL at the end of this test. - device.clear(); - waitForDeviceDestruction(); - ASSERT_NO_FATAL_FAILURE(initPrimaryDevice()); + ASSERT_TRUE(DeviceManager::getInstance().resetPrimary(getFactoryName())); } static void testGetDevices(IStream* stream, AudioDevice expectedDevice) { @@ -199,7 +186,7 @@ static void checkGetHwAVSync(IDevice* device) { } ASSERT_OK(res); } -TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(device.get())); +TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(getDevice().get())); TEST_P(InputStreamTest, updateSinkMetadata) { doc::test("The HAL should not crash on metadata change"); @@ -259,58 +246,58 @@ TEST_P(OutputStreamTest, updateSourceMetadata) { ASSERT_OK(stream->updateSourceMetadata(initMetadata)); } -TEST_F(AudioPrimaryHidlTest, setMode) { +TEST_P(AudioPrimaryHidlTest, setMode) { doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise"); // Test Invalid values for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) { - ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode(mode))) - << "mode=" << mode; + ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode))) + << "mode=" << mode; } // Test valid values for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE, AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) { - ASSERT_OK(device->setMode(mode)) << "mode=" << toString(mode); + ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode); } } -TEST_F(AudioPrimaryHidlTest, setBtHfpSampleRate) { +TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) { doc::test( "Make sure setBtHfpSampleRate either succeeds or " "indicates that it is not supported at all, or that the provided value is invalid"); for (auto samplingRate : {8000, 16000, 22050, 24000}) { - ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, device->setBtHfpSampleRate(samplingRate)); + ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setBtHfpSampleRate(samplingRate)); } } -TEST_F(AudioPrimaryHidlTest, setBtHfpVolume) { +TEST_P(AudioPrimaryHidlTest, setBtHfpVolume) { doc::test( "Make sure setBtHfpVolume is either not supported or " "only succeed if volume is in [0,1]"); - auto ret = device->setBtHfpVolume(0.0); + auto ret = getDevice()->setBtHfpVolume(0.0); ASSERT_TRUE(ret.isOk()); if (ret == Result::NOT_SUPPORTED) { doc::partialTest("setBtHfpVolume is not supported"); return; } - testUnitaryGain([](float volume) { return device->setBtHfpVolume(volume); }); + testUnitaryGain([this](float volume) { return getDevice()->setBtHfpVolume(volume); }); } -TEST_F(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) { +TEST_P(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) { doc::test( "Make sure setBtScoHeadsetDebugName either succeeds or " "indicates that it is not supported"); - ASSERT_RESULT(okOrNotSupported, device->setBtScoHeadsetDebugName("test")); + ASSERT_RESULT(okOrNotSupported, getDevice()->setBtScoHeadsetDebugName("test")); } -TEST_F(AudioPrimaryHidlTest, updateRotation) { +TEST_P(AudioPrimaryHidlTest, updateRotation) { doc::test("Check that the hal can receive the current rotation"); for (Rotation rotation : {Rotation::DEG_0, Rotation::DEG_90, Rotation::DEG_180, Rotation::DEG_270, Rotation::DEG_0}) { - ASSERT_RESULT(okOrNotSupported, device->updateRotation(rotation)); + ASSERT_RESULT(okOrNotSupported, getDevice()->updateRotation(rotation)); } } -TEST_F(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) { +TEST_P(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) { doc::test("Query and set the BT HFP state"); testAccessors("BtHfpEnabled", Initial{false, OPTIONAL}, {true}, &IPrimaryDevice::setBtHfpEnabled, &IPrimaryDevice::getBtHfpEnabled); diff --git a/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h new file mode 100644 index 0000000000..593759f17c --- /dev/null +++ b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H +#define ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H + +#include + +#include "utility/EnvironmentTearDown.h" + +class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown, + public ::testing::Environment { + public: + void init(int* /*argc*/, char** /*argv*/) {} // emulate VtsHalHidlTargetTestEnvBase + private: + void TearDown() override { executeAllTearDowns(); } +}; + +// FIXME: Will be removed while making getDeviceParameters to use the config +static constexpr const char* kDefaultServiceName = "default"; + +#endif // ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index 6c51c1ba7f..e59ab9855e 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -31,7 +32,9 @@ #include +#if MAJOR_VERSION <= 5 #include +#endif #include @@ -44,16 +47,25 @@ #include #include #include +#if MAJOR_VERSION >= 6 +#include +#include +#endif #include #include "utility/AssertOk.h" #include "utility/Documentation.h" -#include "utility/EnvironmentTearDown.h" #include "utility/PrettyPrintAudioTypes.h" #include "utility/ReturnIn.h" #include "utility/ValidateXml.h" +#if MAJOR_VERSION <= 5 +#include "2.0/EnvironmentTearDown.h" +#elif MAJOR_VERSION >= 6 +#include "6.0/EnvironmentTearDown.h" +#endif + /** Provide version specific functions that are used in the generic tests */ #if MAJOR_VERSION == 2 #include "2.0/AudioPrimaryHidlHalUtils.h" @@ -105,14 +117,23 @@ static auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUP class AudioHidlTestEnvironment : public ::Environment { public: - virtual void registerTestServices() override { registerTestService(); } +#if MAJOR_VERSION <= 5 + void registerTestServices() override { registerTestService(); } +#endif }; // Instance to register global tearDown static AudioHidlTestEnvironment* environment; +#define AUDIO_PRIMARY_HIDL_HAL_TEST +#include "DeviceManager.h" + +#if MAJOR_VERSION <= 5 class HidlTest : public ::testing::VtsHalHidlTargetTestBase { - protected: +#elif MAJOR_VERSION >= 6 +class HidlTest : public ::testing::Test { +#endif + protected: // Convenient member to store results Result res; }; @@ -201,6 +222,21 @@ class AudioPolicyConfigTest : public HidlTest { ASSERT_TRUE(mPrimaryConfig) << "Could not find primary module in configuration file: " << policyConfig.getFilePath(); } + + protected: + sp getDevicesFactory(const std::string& factoryName) const { + return DevicesFactoryManager::getInstance().get(factoryName); + } + + sp getPrimaryDevice(const std::string& factoryName) const { + return DeviceManager::getInstance().getPrimary(factoryName); + } + + bool isPrimaryDeviceOptional(const std::string& factoryName) const { + // It's OK not to have "primary" device on non-default audio HAL service. + return factoryName != kDefaultServiceName; + } + sp mPrimaryConfig = nullptr; }; @@ -208,42 +244,86 @@ TEST_F(AudioPolicyConfigTest, LoadAudioPolicyXMLConfiguration) { doc::test("Test parsing audio_policy_configuration.xml (called in SetUp)"); } +////////////////////////////////////////////////////////////////////////////// +//////////////////// Test parameter types and definitions //////////////////// +////////////////////////////////////////////////////////////////////////////// + +enum { PARAM_FACTORY_NAME, PARAM_DEVICE_NAME }; +using DeviceParameter = std::tuple; + +static inline std::string DeviceParameterToString( + const ::testing::TestParamInfo& info) { +#if MAJOR_VERSION <= 5 + return std::get(info.param); +#elif MAJOR_VERSION >= 6 + const auto factoryName = + ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo{ + std::get(info.param), info.index}); + const auto& deviceName = std::get(info.param); + return !deviceName.empty() ? factoryName + "_" + deviceName : factoryName; +#endif +} + +#if MAJOR_VERSION <= 5 +// For V2..5 the factory is looked up using the instance name passed +// in the environment, only one factory is returned. This is because the VTS +// framework will call the test for each instance. Only the primary device of +// the factory specified in the environment is tested. +const std::vector& getDeviceParameters() { + static std::vector parameters = { + {environment->getServiceName(), DeviceManager::kPrimaryDevice}}; + return parameters; +} +#elif MAJOR_VERSION >= 6 +// FIXME: Will be replaced with code that analyzes the audio policy config file. +const std::vector& getDeviceParameters() { + static std::vector parameters = [] { + const auto instances = + ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor); + std::vector result; + result.reserve(instances.size()); + for (const auto& instance : instances) { + result.emplace_back(instance, DeviceManager::kPrimaryDevice); + } + return result; + }(); + return parameters; +} +#endif + +class AudioHidlTestWithDeviceParameter : public AudioPolicyConfigTest, + public ::testing::WithParamInterface { + protected: + const std::string& getFactoryName() const { return std::get(GetParam()); } + bool isPrimaryDeviceOptional() const { + return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName()); + } + sp getDevicesFactory() const { + return AudioPolicyConfigTest::getDevicesFactory(getFactoryName()); + } + sp getPrimaryDevice() const { + return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName()); + } +}; + ////////////////////////////////////////////////////////////////////////////// ////////////////////// getService audio_devices_factory ////////////////////// ////////////////////////////////////////////////////////////////////////////// // Test all audio devices -class AudioHidlTest : public AudioPolicyConfigTest { - public: - static void SetUpTestSuite() { - devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService( - environment->getServiceName()); - } - - static void TearDownTestSuite() { devicesFactory.clear(); } - - void SetUp() override { - ASSERT_NO_FATAL_FAILURE(AudioPolicyConfigTest::SetUp()); // setup base - // Failures during SetUpTestSuite do not cause test termination. - ASSERT_TRUE(devicesFactory != nullptr); - } - - protected: - // Cache the devicesFactory retrieval to speed up each test by ~0.5s - static sp devicesFactory; - - static bool isPrimaryDeviceOptional() { - // It's OK not to have "primary" device on non-default audio HAL service. - return environment->getServiceName() != kDefaultServiceName; +class AudioHidlTest : public AudioHidlTestWithDeviceParameter { + public: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceParameter::SetUp()); // setup base + ASSERT_TRUE(getDevicesFactory() != nullptr); } }; -sp AudioHidlTest::devicesFactory; -TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) { +TEST_P(AudioHidlTest, GetAudioDevicesFactoryService) { doc::test("Test the getService"); } -TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) { +TEST_P(AudioHidlTest, OpenDeviceInvalidParameter) { doc::test("Test passing an invalid parameter to openDevice"); Result result; sp device; @@ -252,11 +332,14 @@ TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) { #elif MAJOR_VERSION >= 4 auto invalidDevice = "Non existing device"; #endif - ASSERT_OK(devicesFactory->openDevice(invalidDevice, returnIn(result, device))); + ASSERT_OK(getDevicesFactory()->openDevice(invalidDevice, returnIn(result, device))); ASSERT_EQ(Result::INVALID_ARGUMENTS, result); ASSERT_TRUE(device == nullptr); } +INSTANTIATE_TEST_CASE_P(AudioHidl, AudioHidlTest, ::testing::ValuesIn(getDeviceParameters()), + &DeviceParameterToString); + ////////////////////////////////////////////////////////////////////////////// /////////////////////////////// openDevice primary /////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -264,57 +347,30 @@ TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) { // Test the primary device class AudioPrimaryHidlTest : public AudioHidlTest { public: - static void SetUpTestSuite() { - ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUpTestSuite()); - ASSERT_NO_FATAL_FAILURE(initPrimaryDevice()); - } - - static void TearDownTestSuite() { - device.clear(); - AudioHidlTest::TearDownTestSuite(); - } - void SetUp() override { ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base - if (device == nullptr && isPrimaryDeviceOptional()) { + if (getDevice() == nullptr && isPrimaryDeviceOptional()) { GTEST_SKIP() << "No primary device on this factory"; } - ASSERT_TRUE(device != nullptr); + ASSERT_TRUE(getDevice() != nullptr); } protected: - // Cache the device opening to speed up each test by ~0.5s - static sp device; - - static void initPrimaryDevice() { - // Failures during test suite set up do not cause test termination. - ASSERT_TRUE(devicesFactory != nullptr); - Result result; -#if MAJOR_VERSION == 2 - sp baseDevice; - ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY, - returnIn(result, baseDevice))); - ASSERT_OK(result); - ASSERT_TRUE(baseDevice != nullptr); - - device = IPrimaryDevice::castFrom(baseDevice); -#elif MAJOR_VERSION >= 4 - ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device))); - ASSERT_OK(result); -#endif - } + sp getDevice() const { return getPrimaryDevice(); } }; -sp AudioPrimaryHidlTest::device; -TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) { +TEST_P(AudioPrimaryHidlTest, OpenPrimaryDevice) { doc::test("Test the openDevice (called during setup)"); } -TEST_F(AudioPrimaryHidlTest, Init) { +TEST_P(AudioPrimaryHidlTest, Init) { doc::test("Test that the audio primary hal initialized correctly"); - ASSERT_OK(device->initCheck()); + ASSERT_OK(getDevice()->initCheck()); } +INSTANTIATE_TEST_CASE_P(AudioPrimaryHidl, AudioPrimaryHidlTest, + ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + ////////////////////////////////////////////////////////////////////////////// ///////////////////// {set,get}{Master,Mic}{Mute,Volume} ///////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -339,7 +395,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK}; Property initialValue = expectedInitial.value; - ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue))); + ASSERT_OK((getDevice().get()->*getter)(returnIn(res, initialValue))); ASSERT_RESULT(expectedResults, res); if (res == Result::OK && expectedInitial.check == REQUIRED) { EXPECT_EQ(expectedInitial.value, initialValue); @@ -350,7 +406,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { for (Property setValue : valuesToTest) { SCOPED_TRACE("Test " + propertyName + " getter and setter for " + testing::PrintToString(setValue)); - auto ret = (device.get()->*setter)(setValue); + auto ret = (getDevice().get()->*setter)(setValue); ASSERT_RESULT(expectedResults, ret); if (ret == Result::NOT_SUPPORTED) { doc::partialTest(propertyName + " setter is not supported"); @@ -358,7 +414,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { } Property getValue; // Make sure the getter returns the same value just set - ASSERT_OK((device.get()->*getter)(returnIn(res, getValue))); + ASSERT_OK((getDevice().get()->*getter)(returnIn(res, getValue))); ASSERT_RESULT(expectedResults, res); if (res == Result::NOT_SUPPORTED) { doc::partialTest(propertyName + " getter is not supported"); @@ -370,31 +426,34 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { for (Property invalidValue : invalidValues) { SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " + testing::PrintToString(invalidValue)); - EXPECT_RESULT(invalidArgsOrNotSupported, (device.get()->*setter)(invalidValue)); + EXPECT_RESULT(invalidArgsOrNotSupported, (getDevice().get()->*setter)(invalidValue)); } // Restore initial value - EXPECT_RESULT(expectedResults, (device.get()->*setter)(initialValue)); + EXPECT_RESULT(expectedResults, (getDevice().get()->*setter)(initialValue)); } }; using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; -TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) { +TEST_P(BoolAccessorPrimaryHidlTest, MicMuteTest) { doc::test("Check that the mic can be muted and unmuted"); testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, &IDevice::getMicMute); // TODO: check that the mic is really muted (all sample are 0) } -TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) { +TEST_P(BoolAccessorPrimaryHidlTest, MasterMuteTest) { doc::test("If master mute is supported, try to mute and unmute the master output"); testAccessors("master mute", Initial{false}, {true}, &IDevice::setMasterMute, &IDevice::getMasterMute); // TODO: check that the master volume is really muted } +INSTANTIATE_TEST_CASE_P(BoolAccessorPrimaryHidl, BoolAccessorPrimaryHidlTest, + ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; -TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { +TEST_P(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { doc::test("Test the master volume if supported"); testAccessors( "master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume, @@ -402,16 +461,19 @@ TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { // TODO: check that the master volume is really changed } +INSTANTIATE_TEST_CASE_P(FloatAccessorPrimaryHidl, FloatAccessorPrimaryHidlTest, + ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + ////////////////////////////////////////////////////////////////////////////// //////////////////////////////// AudioPatches //////////////////////////////// ////////////////////////////////////////////////////////////////////////////// class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest { protected: - bool areAudioPatchesSupported() { return extract(device->supportsAudioPatches()); } + bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); } }; -TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) { +TEST_P(AudioPatchPrimaryHidlTest, AudioPatches) { doc::test("Test if audio patches are supported"); if (!areAudioPatchesSupported()) { doc::partialTest("Audio patches are not supported"); @@ -420,6 +482,9 @@ TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) { // TODO: test audio patches } +INSTANTIATE_TEST_CASE_P(AudioPatchPrimaryHidl, AudioPatchPrimaryHidlTest, + ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + ////////////////////////////////////////////////////////////////////////////// //////////////// Required and recommended audio format support /////////////// // From: @@ -429,8 +494,7 @@ TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) { /////////// TODO: move to the beginning of the file for easier update //////// ////////////////////////////////////////////////////////////////////////////// -class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest { - public: +struct ConfigHelper { // for retro compatibility only test the primary device IN_BUILTIN_MIC // FIXME: in the next audio HAL version, test all available devices static bool primaryHasMic() { @@ -502,21 +566,51 @@ class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest { } }; +// Nesting a tuple in another tuple allows to use GTest Combine function to generate +// all combinations of devices and configs. +enum { PARAM_DEVICE, PARAM_CONFIG }; +using DeviceConfigParameter = std::tuple; + /** Generate a test name based on an audio config. * * As the only parameter changing are channel mask and sample rate, * only print those ones in the test name. */ -static string generateTestName(const testing::TestParamInfo& info) { - const AudioConfig& config = info.param; - return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" + +static string DeviceConfigParameterToString( + const testing::TestParamInfo& info) { + const AudioConfig& config = std::get(info.param); + const auto deviceName = DeviceParameterToString(::testing::TestParamInfo{ + std::get(info.param), info.index}); + return (deviceName.empty() ? "" : deviceName + "_") + to_string(info.index) + "__" + + to_string(config.sampleRateHz) + "_" + // "MONO" is more clear than "FRONT_LEFT" ((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) || config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO)) - ? "MONO" - : ::testing::PrintToString(config.channelMask)); + ? "MONO" + : ::testing::PrintToString(config.channelMask)); } +class AudioHidlTestWithDeviceConfigParameter + : public AudioPolicyConfigTest, + public ::testing::WithParamInterface { + protected: + const std::string& getFactoryName() const { + return std::get(std::get(GetParam())); + } + bool isPrimaryDeviceOptional() const { + return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName()); + } + sp getDevicesFactory() const { + return AudioPolicyConfigTest::getDevicesFactory(getFactoryName()); + } + sp getPrimaryDevice() const { + return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName()); + } + const AudioConfig& getConfig() const { return std::get(GetParam()); } + // FIXME: Split out tests that don't require primary device + sp getDevice() const { return getPrimaryDevice(); } +}; + ////////////////////////////////////////////////////////////////////////////// ///////////////////////////// getInputBufferSize ///////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -525,12 +619,21 @@ static string generateTestName(const testing::TestParamInfo& info) // android.hardware.microphone // how to get this value ? is it a property ??? -class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest, - public ::testing::WithParamInterface { - protected: +class AudioCaptureConfigPrimaryTest : public AudioHidlTestWithDeviceConfigParameter { + public: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp()); // setup base + ASSERT_TRUE(getDevicesFactory() != nullptr); + if (getDevice() == nullptr && isPrimaryDeviceOptional()) { + GTEST_SKIP() << "No primary device on this factory"; + } + ASSERT_TRUE(getDevice() != nullptr); + } + + protected: void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) { uint64_t bufferSize; - ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize))); + ASSERT_OK(getDevice()->getInputBufferSize(audioConfig, returnIn(res, bufferSize))); switch (res) { case Result::INVALID_ARGUMENTS: @@ -554,16 +657,19 @@ TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) { doc::test( "Input buffer size must be retrievable for a format with required " "support."); - inputBufferSizeTest(GetParam(), true); + inputBufferSizeTest(getConfig(), true); } INSTANTIATE_TEST_CASE_P( - RequiredInputBufferSize, RequiredInputBufferSizeTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()), - &generateTestName); + RequiredInputBufferSize, RequiredInputBufferSizeTest, + ::testing::Combine( + ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())), + &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( - SupportedInputBufferSize, RequiredInputBufferSizeTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()), - &generateTestName); + SupportedInputBufferSize, RequiredInputBufferSizeTest, + ::testing::Combine(::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())), + &DeviceConfigParameterToString); // Test that the recommended capture config are supported or lead to a // INVALID_ARGUMENTS return @@ -572,21 +678,23 @@ TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) { doc::test( "Input buffer size should be retrievable for a format with recommended " "support."); - inputBufferSizeTest(GetParam(), false); + inputBufferSizeTest(getConfig(), false); } INSTANTIATE_TEST_CASE_P( - RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()), - &generateTestName); + RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest, + ::testing::Combine( + ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())), + &DeviceConfigParameterToString); ////////////////////////////////////////////////////////////////////////////// /////////////////////////////// setScreenState /////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_F(AudioPrimaryHidlTest, setScreenState) { +TEST_P(AudioPrimaryHidlTest, setScreenState) { doc::test("Check that the hal can receive the screen state"); for (bool turnedOn : {false, true, true, false, false}) { - ASSERT_RESULT(okOrNotSupported, device->setScreenState(turnedOn)); + ASSERT_RESULT(okOrNotSupported, getDevice()->setScreenState(turnedOn)); } } @@ -594,15 +702,15 @@ TEST_F(AudioPrimaryHidlTest, setScreenState) { //////////////////////////// {get,set}Parameters ///////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_F(AudioPrimaryHidlTest, getParameters) { +TEST_P(AudioPrimaryHidlTest, getParameters) { doc::test("Check that the hal can set and get parameters"); hidl_vec context; hidl_vec keys; hidl_vec values; - ASSERT_OK(Parameters::get(device, keys, returnIn(res, values))); - ASSERT_OK(Parameters::set(device, values)); + ASSERT_OK(Parameters::get(getDevice(), keys, returnIn(res, values))); + ASSERT_OK(Parameters::set(getDevice(), values)); values.resize(0); - ASSERT_OK(Parameters::set(device, values)); + ASSERT_OK(Parameters::set(getDevice(), values)); } ////////////////////////////////////////////////////////////////////////////// @@ -643,14 +751,14 @@ static void testDebugDump(DebugDump debugDump) { EXPECT_EQ(0, close(fds[1])) << errno; } -TEST_F(AudioPrimaryHidlTest, DebugDump) { +TEST_P(AudioPrimaryHidlTest, DebugDump) { doc::test("Check that the hal can dump its state without error"); - testDebugDump([](const auto& handle) { return dump(device, handle); }); + testDebugDump([this](const auto& handle) { return dump(getDevice(), handle); }); } -TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) { +TEST_P(AudioPrimaryHidlTest, DebugDumpInvalidArguments) { doc::test("Check that the hal dump doesn't crash on invalid arguments"); - ASSERT_OK(dump(device, hidl_handle())); + ASSERT_OK(dump(getDevice(), hidl_handle())); } ////////////////////////////////////////////////////////////////////////////// @@ -658,9 +766,17 @@ TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) { ////////////////////////////////////////////////////////////////////////////// template -class OpenStreamTest : public AudioConfigPrimaryTest, - public ::testing::WithParamInterface { - protected: +class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp()); // setup base + ASSERT_TRUE(getDevicesFactory() != nullptr); + if (getDevice() == nullptr && isPrimaryDeviceOptional()) { + GTEST_SKIP() << "No primary device on this factory"; + } + ASSERT_TRUE(getDevice() != nullptr); + } + template void testOpen(Open openStream, const AudioConfig& config) { // FIXME: Open a stream without an IOHandle @@ -701,7 +817,7 @@ class OpenStreamTest : public AudioConfigPrimaryTest, return res; } - void waitForStreamDestruction() { + static void waitForStreamDestruction() { // FIXME: there is no way to know when the remote IStream is being destroyed // Binder does not support testing if an object is alive, thus // wait for 100ms to let the binder destruction propagates and @@ -712,12 +828,14 @@ class OpenStreamTest : public AudioConfigPrimaryTest, usleep(100 * 1000); } - private: + bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); } + + private: void TearDown() override { if (open) { ASSERT_OK(closeStream()); } - AudioConfigPrimaryTest::TearDown(); + AudioPolicyConfigTest::TearDown(); } protected: @@ -734,18 +852,19 @@ class OutputStreamTest : public OpenStreamTest { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base if (IsSkipped()) return; // do not attempt to use 'device' address.device = AudioDevice::OUT_DEFAULT; - const AudioConfig& config = GetParam(); + const AudioConfig& config = getConfig(); // TODO: test all flag combination auto flags = mkEnumBitfield(AudioOutputFlag::NONE); testOpen( - [&](AudioIoHandle handle, AudioConfig config, auto cb) { + [&](AudioIoHandle handle, AudioConfig config, auto cb) { #if MAJOR_VERSION == 2 - return device->openOutputStream(handle, address, config, flags, cb); + return getDevice()->openOutputStream(handle, address, config, flags, cb); #elif MAJOR_VERSION >= 4 - return device->openOutputStream(handle, address, config, flags, initMetadata, cb); + return getDevice()->openOutputStream(handle, address, config, flags, + initMetadata, cb); #endif - }, - config); + }, + config); } #if MAJOR_VERSION >= 4 @@ -763,18 +882,23 @@ TEST_P(OutputStreamTest, OpenOutputStreamTest) { // Open done in SetUp } INSTANTIATE_TEST_CASE_P( - RequiredOutputStreamConfigSupport, OutputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()), - &generateTestName); + RequiredOutputStreamConfigSupport, OutputStreamTest, + ::testing::Combine( + ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig())), + &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( - SupportedOutputStreamConfig, OutputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()), - &generateTestName); + SupportedOutputStreamConfig, OutputStreamTest, + ::testing::Combine(::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getSupportedPlaybackAudioConfig())), + &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( - RecommendedOutputStreamConfigSupport, OutputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()), - &generateTestName); + RecommendedOutputStreamConfigSupport, OutputStreamTest, + ::testing::Combine( + ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig())), + &DeviceConfigParameterToString); ////////////////////////////// openInputStream ////////////////////////////// @@ -783,14 +907,15 @@ class InputStreamTest : public OpenStreamTest { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base if (IsSkipped()) return; // do not attempt to use 'device' address.device = AudioDevice::IN_DEFAULT; - const AudioConfig& config = GetParam(); + const AudioConfig& config = getConfig(); // TODO: test all supported flags and source auto flags = mkEnumBitfield(AudioInputFlag::NONE); testOpen( - [&](AudioIoHandle handle, AudioConfig config, auto cb) { - return device->openInputStream(handle, address, config, flags, initMetadata, cb); - }, - config); + [&](AudioIoHandle handle, AudioConfig config, auto cb) { + return getDevice()->openInputStream(handle, address, config, flags, + initMetadata, cb); + }, + config); } protected: @@ -808,18 +933,23 @@ TEST_P(InputStreamTest, OpenInputStreamTest) { // Open done in setup } INSTANTIATE_TEST_CASE_P( - RequiredInputStreamConfigSupport, InputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()), - &generateTestName); + RequiredInputStreamConfigSupport, InputStreamTest, + ::testing::Combine( + ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())), + &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( - SupportedInputStreamConfig, InputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()), - &generateTestName); + SupportedInputStreamConfig, InputStreamTest, + ::testing::Combine(::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())), + &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( - RecommendedInputStreamConfigSupport, InputStreamTest, - ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()), - &generateTestName); + RecommendedInputStreamConfigSupport, InputStreamTest, + ::testing::Combine( + ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())), + &DeviceConfigParameterToString); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////// IStream getters /////////////////////////////// @@ -1332,19 +1462,19 @@ TEST_P(OutputStreamTest, GetPresentationPositionStop) { /////////////////////////////// PrimaryDevice //////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_F(AudioPrimaryHidlTest, setVoiceVolume) { +TEST_P(AudioPrimaryHidlTest, setVoiceVolume) { doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]"); - testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); }); + testUnitaryGain([this](float volume) { return getDevice()->setVoiceVolume(volume); }); } -TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) { +TEST_P(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) { doc::test("Query and set the BT SCO NR&EC state"); testAccessors("BtScoNrecEnabled", Initial{false, OPTIONAL}, {true}, &IPrimaryDevice::setBtScoNrecEnabled, &IPrimaryDevice::getBtScoNrecEnabled); } -TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) { +TEST_P(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) { doc::test("Query and set the SCO whideband state"); testAccessors("BtScoWideband", Initial{false, OPTIONAL}, {true}, &IPrimaryDevice::setBtScoWidebandEnabled, @@ -1352,15 +1482,17 @@ TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) { } using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; -TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) { +TEST_P(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) { doc::test("Query and set the TTY mode state"); testAccessors( "TTY mode", Initial{IPrimaryDevice::TtyMode::OFF}, {IPrimaryDevice::TtyMode::HCO, IPrimaryDevice::TtyMode::VCO, IPrimaryDevice::TtyMode::FULL}, &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode); } +INSTANTIATE_TEST_CASE_P(TtyModeAccessorPrimaryHidl, TtyModeAccessorPrimaryHidlTest, + ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); -TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) { +TEST_P(BoolAccessorPrimaryHidlTest, setGetHac) { doc::test("Query and set the HAC state"); testAccessors("HAC", Initial{false}, {true}, &IPrimaryDevice::setHacEnabled, &IPrimaryDevice::getHacEnabled); @@ -1372,9 +1504,13 @@ TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) { int main(int argc, char** argv) { environment = new AudioHidlTestEnvironment; + // For V2..5 it's critical to initialize environment before GTest. + // The environment parses the service name from the command line, + // then it can be used in GTest parameter generators which are + // initialized during the call to InitGoogleTest. + environment->init(&argc, argv); ::testing::AddGlobalTestEnvironment(environment); ::testing::InitGoogleTest(&argc, argv); - environment->init(&argc, argv); int status = RUN_ALL_TESTS(); return status; } diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h new file mode 100644 index 0000000000..b6e2db0685 --- /dev/null +++ b/audio/core/all-versions/vts/functional/DeviceManager.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Code in this file uses 'environment' +#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST +#error Must be included from AudioPrimaryHidlTest.h +#endif + +template +class InterfaceManager { + public: + sp get(const Key& name) { + auto existing = instances.find(name); + if (existing != instances.end()) return existing->second; + auto [inserted, _] = instances.emplace(name, Derived::createInterfaceInstance(name)); + if (inserted->second) { + environment->registerTearDown([name]() { (void)Derived::getInstance().reset(name); }); + } + return inserted->second; + } + + // The test must check that reset was successful. Reset failure means that the test code + // is holding a strong reference to the device. + bool reset(const Key& name) __attribute__((warn_unused_result)) { + auto iter = instances.find(name); + if (iter == instances.end()) return true; + ::android::wp weak = iter->second; + instances.erase(iter); + if (weak.promote() != nullptr) return false; + waitForInstanceDestruction(); + return true; + } + + static void waitForInstanceDestruction() { + // FIXME: there is no way to know when the remote IDevice is being destroyed + // Binder does not support testing if an object is alive, thus + // wait for 100ms to let the binder destruction propagates and + // the remote device has the time to be destroyed. + // flushCommand makes sure all local command are sent, thus should reduce + // the latency between local and remote destruction. + IPCThreadState::self()->flushCommands(); + usleep(100 * 1000); + } + + protected: + std::map> instances; +}; + +class DevicesFactoryManager + : public InterfaceManager { + public: + static DevicesFactoryManager& getInstance() { + static DevicesFactoryManager instance; + return instance; + } + static sp createInterfaceInstance(const std::string& name) { +#if MAJOR_VERSION <= 5 + return ::testing::VtsHalHidlTargetTestBase::getService(name); +#elif MAJOR_VERSION >= 6 + return IDevicesFactory::getService(name); +#endif + } +}; + +using FactoryAndDevice = std::tuple; +class DeviceManager : public InterfaceManager { + public: + static DeviceManager& getInstance() { + static DeviceManager instance; + return instance; + } + static sp createInterfaceInstance(const FactoryAndDevice& factoryAndDevice) { + auto [factoryName, name] = factoryAndDevice; + sp factory = DevicesFactoryManager::getInstance().get(factoryName); + return name == kPrimaryDevice ? openPrimaryDevice(factory) : openDevice(factory, name); + } + using InterfaceManager::reset; + + static constexpr const char* kPrimaryDevice = "primary"; + + sp get(const std::string& factoryName, const std::string& name) { + return InterfaceManager::get(std::make_tuple(factoryName, name)); + } + sp getPrimary(const std::string& factoryName) { + sp device = get(factoryName, kPrimaryDevice); + return device != nullptr ? IPrimaryDevice::castFrom(device) : nullptr; + } + bool reset(const std::string& factoryName, const std::string& name) + __attribute__((warn_unused_result)) { + return InterfaceManager::reset(std::make_tuple(factoryName, name)); + } + bool resetPrimary(const std::string& factoryName) __attribute__((warn_unused_result)) { + return reset(factoryName, kPrimaryDevice); + } + + private: + static sp openDevice(const sp& factory, const std::string& name) { + if (factory == nullptr) return nullptr; + sp device; +#if MAJOR_VERSION >= 4 + Result result; + auto ret = factory->openDevice(name, returnIn(result, device)); + if (!ret.isOk() || result != Result::OK || device == nullptr) { + ALOGW("Device %s can not be opened, transaction: %s, result %d, device %p", + name.c_str(), ret.description().c_str(), result, device.get()); + return nullptr; + } +#else + (void)name; +#endif + return device; + } + + static sp openPrimaryDevice(const sp& factory) { + if (factory == nullptr) return nullptr; + Result result; + sp device; +#if MAJOR_VERSION == 2 + auto ret = factory->openDevice(IDevicesFactory::Device::PRIMARY, returnIn(result, device)); +#elif MAJOR_VERSION >= 4 + auto ret = factory->openPrimaryDevice(returnIn(result, device)); +#endif + if (!ret.isOk() || result != Result::OK || device == nullptr) { + ALOGW("Primary device can not be opened, transaction: %s, result %d, device %p", + ret.description().c_str(), result, device.get()); + return nullptr; + } + return device; + } +}; From 686af1cc4351de44ed77c1cd32986ec04f8885ca Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 25 Oct 2019 13:04:19 -0700 Subject: [PATCH 3/4] audio: Run VTS tests for non-primary modules for HAL V6 Implement parsing of AudioPolicyManager config for finding out declared modules (IDevice instances) with permanently attached devices and run tests for them. This only applies when running tests for HAL V6. Change class hierarchy to use IDevice interface as much as possible, only use IPrimaryDevice for its specific methods. Fix the following issues found while running the tests for "r_submix" and "msd" modules: - IDevice::getMicrophones can return NOT_SUPPORTED status; - IDevice::get/setParameters can return NOT_SUPPORTED. Other changes: - Factor out common code for getting devices via DeviceManager; - Factor out AudioPolicyConfigTest.HasPrimaryModule test from SetUp code; - Add device parameter generator for primary device only. Bug: 141989952 Bug: 141847510 Test: atest VtsHalAudioV5_0TargetTest atest VtsHalAudioV6_0TargetTest also, run modified V5_0 test using generators for V6_0 Change-Id: I51cec21670120d8dce75609954a18b886cc0c18d Merged-In: I51cec21670120d8dce75609954a18b886cc0c18d --- audio/6.0/IDevice.hal | 3 +- .../4.0/AudioPrimaryHidlHalTest.cpp | 16 +- .../6.0/AudioPrimaryHidlHalTest.cpp | 48 +++ .../vts/functional/AudioPrimaryHidlHalTest.h | 341 ++++++++++-------- 4 files changed, 254 insertions(+), 154 deletions(-) diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal index 42a545b0be..e885fe2267 100644 --- a/audio/6.0/IDevice.hal +++ b/audio/6.0/IDevice.hal @@ -260,7 +260,8 @@ interface IDevice { /** * Returns an array with available microphones in device. * - * @return retval INVALID_STATE if the call is not successful, + * @return retval NOT_SUPPORTED if there are no microphones on this device + * INVALID_STATE if the call is not successful, * OK otherwise. * * @return microphones array with microphones info diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp index b8defb620a..cd93643b95 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp @@ -18,15 +18,16 @@ TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { doc::test("Calling openDevice(\"primary\") should return the primary device."); + if (getDeviceName() != DeviceManager::kPrimaryDevice) { + GTEST_SKIP() << "No primary device on this factory"; // returns + } + struct WaitExecutor { ~WaitExecutor() { DeviceManager::waitForInstanceDestruction(); } } waitExecutor; // Make sure we wait for the device destruction on exiting from the test. Result result; sp baseDevice; ASSERT_OK(getDevicesFactory()->openDevice("primary", returnIn(result, baseDevice))); - if (result != Result::OK && isPrimaryDeviceOptional()) { - GTEST_SKIP() << "No primary device on this factory"; // returns - } ASSERT_OK(result); ASSERT_TRUE(baseDevice != nullptr); @@ -39,10 +40,13 @@ TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) { /////////////////////////// get(Active)Microphones /////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_P(AudioPrimaryHidlTest, GetMicrophonesTest) { +TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) { doc::test("Make sure getMicrophones always succeeds"); hidl_vec microphones; ASSERT_OK(getDevice()->getMicrophones(returnIn(res, microphones))); + if (res == Result::NOT_SUPPORTED) { + GTEST_SKIP() << "getMicrophones is not supported"; // returns + } ASSERT_OK(res); if (microphones.size() > 0) { // When there is microphone on the phone, try to open an input stream @@ -120,7 +124,7 @@ TEST_P(AudioPrimaryHidlTest, GetMicrophonesTest) { } } -TEST_P(AudioPrimaryHidlTest, SetConnectedState) { +TEST_P(AudioHidlDeviceTest, SetConnectedState) { doc::test("Check that the HAL can be notified of device connection and deconnection"); using AD = AudioDevice; for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) { @@ -142,7 +146,7 @@ TEST_P(AudioPrimaryHidlTest, SetConnectedState) { // Because there is no way of knowing if the devices were connected before // calling setConnectedState, there is no way to restore the HAL to its // initial state. To workaround this, destroy the HAL at the end of this test. - ASSERT_TRUE(DeviceManager::getInstance().resetPrimary(getFactoryName())); + ASSERT_TRUE(resetDevice()); } static void testGetDevices(IStream* stream, AudioDevice expectedDevice) { diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp index 6314ea72ec..937de0a18d 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -16,3 +16,51 @@ // pull in all the <= 5.0 tests #include "5.0/AudioPrimaryHidlHalTest.cpp" + +const std::vector& getDeviceParametersForFactoryTests() { + static std::vector parameters = [] { + std::vector result; + const auto factories = + ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor); + for (const auto& factoryName : factories) { + result.emplace_back(factoryName, + DeviceManager::getInstance().getPrimary(factoryName) != nullptr + ? DeviceManager::kPrimaryDevice + : ""); + } + return result; + }(); + return parameters; +} + +const std::vector& getDeviceParametersForPrimaryDeviceTests() { + static std::vector parameters = [] { + std::vector result; + const auto primary = std::find_if( + getDeviceParameters().begin(), getDeviceParameters().end(), [](const auto& elem) { + return std::get(elem) == DeviceManager::kPrimaryDevice; + }); + if (primary != getDeviceParameters().end()) result.push_back(*primary); + return result; + }(); + return parameters; +} + +const std::vector& getDeviceParameters() { + static std::vector parameters = [] { + std::vector result; + const auto factories = + ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor); + const auto devices = getCachedPolicyConfig().getModulesWithDevicesNames(); + result.reserve(devices.size()); + for (const auto& factoryName : factories) { + for (const auto& deviceName : devices) { + if (DeviceManager::getInstance().get(factoryName, deviceName) != nullptr) { + result.emplace_back(factoryName, deviceName); + } + } + } + return result; + }(); + return parameters; +} diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index e59ab9855e..7bdc5e1eb1 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -129,11 +130,31 @@ static AudioHidlTestEnvironment* environment; #include "DeviceManager.h" #if MAJOR_VERSION <= 5 -class HidlTest : public ::testing::VtsHalHidlTargetTestBase { +using HidlTestBase = ::testing::VtsHalHidlTargetTestBase; #elif MAJOR_VERSION >= 6 -class HidlTest : public ::testing::Test { +using HidlTestBase = ::testing::Test; #endif + +class HidlTest : public HidlTestBase { + public: + virtual ~HidlTest() = default; + protected: + // Factory and device name getters to be overridden in subclasses. + virtual const std::string& getFactoryName() const = 0; + virtual const std::string& getDeviceName() const = 0; + + sp getDevicesFactory() const { + return DevicesFactoryManager::getInstance().get(getFactoryName()); + } + sp getDevice() const { + return DeviceManager::getInstance().get(getFactoryName(), getDeviceName()); + } + bool resetDevice() const { + return DeviceManager::getInstance().reset(getFactoryName(), getDeviceName()); + } + bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); } + // Convenient member to store results Result res; }; @@ -179,7 +200,25 @@ class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig { } mStatus = android::deserializeAudioPolicyFile(mFilePath.c_str(), this); if (mStatus == OK) { - mPrimaryModule = getHwModules().getModuleFromName("primary"); + mPrimaryModule = getHwModules().getModuleFromName(DeviceManager::kPrimaryDevice); + // Available devices are not 'attached' to modules at this moment. + // Need to go over available devices and find their module. + for (const auto& device : availableOutputDevices) { + for (const auto& module : hwModules) { + if (module->getDeclaredDevices().indexOf(device) >= 0) { + mModulesWithDevicesNames.insert(module->getName()); + break; + } + } + } + for (const auto& device : availableInputDevices) { + for (const auto& module : hwModules) { + if (module->getDeclaredDevices().indexOf(device) >= 0) { + mModulesWithDevicesNames.insert(module->getName()); + break; + } + } + } } } status_t getStatus() const { return mStatus; } @@ -193,11 +232,15 @@ class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig { } const std::string& getFilePath() const { return mFilePath; } sp getPrimaryModule() const { return mPrimaryModule; } + const std::set& getModulesWithDevicesNames() const { + return mModulesWithDevicesNames; + } private: status_t mStatus = NO_INIT; std::string mFilePath; sp mPrimaryModule = nullptr; + std::set mModulesWithDevicesNames; }; // Cached policy config after parsing for faster test startup @@ -210,40 +253,26 @@ const PolicyConfig& getCachedPolicyConfig() { return *policyConfig; } -class AudioPolicyConfigTest : public HidlTest { - public: +class AudioPolicyConfigTest : public HidlTestBase { + public: void SetUp() override { - ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base - + ASSERT_NO_FATAL_FAILURE(HidlTestBase::SetUp()); // setup base auto& policyConfig = getCachedPolicyConfig(); ASSERT_EQ(0, policyConfig.getStatus()) << policyConfig.getError(); - - mPrimaryConfig = policyConfig.getPrimaryModule(); - ASSERT_TRUE(mPrimaryConfig) << "Could not find primary module in configuration file: " - << policyConfig.getFilePath(); } - - protected: - sp getDevicesFactory(const std::string& factoryName) const { - return DevicesFactoryManager::getInstance().get(factoryName); - } - - sp getPrimaryDevice(const std::string& factoryName) const { - return DeviceManager::getInstance().getPrimary(factoryName); - } - - bool isPrimaryDeviceOptional(const std::string& factoryName) const { - // It's OK not to have "primary" device on non-default audio HAL service. - return factoryName != kDefaultServiceName; - } - - sp mPrimaryConfig = nullptr; }; TEST_F(AudioPolicyConfigTest, LoadAudioPolicyXMLConfiguration) { doc::test("Test parsing audio_policy_configuration.xml (called in SetUp)"); } +TEST_F(AudioPolicyConfigTest, HasPrimaryModule) { + auto& policyConfig = getCachedPolicyConfig(); + ASSERT_TRUE(policyConfig.getPrimaryModule() != nullptr) + << "Could not find primary module in configuration file: " + << policyConfig.getFilePath(); +} + ////////////////////////////////////////////////////////////////////////////// //////////////////// Test parameter types and definitions //////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -253,13 +282,13 @@ using DeviceParameter = std::tuple; static inline std::string DeviceParameterToString( const ::testing::TestParamInfo& info) { + const auto& deviceName = std::get(info.param); #if MAJOR_VERSION <= 5 - return std::get(info.param); + return !deviceName.empty() ? deviceName : std::to_string(info.index); #elif MAJOR_VERSION >= 6 const auto factoryName = ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo{ std::get(info.param), info.index}); - const auto& deviceName = std::get(info.param); return !deviceName.empty() ? factoryName + "_" + deviceName : factoryName; #endif } @@ -268,41 +297,48 @@ static inline std::string DeviceParameterToString( // For V2..5 the factory is looked up using the instance name passed // in the environment, only one factory is returned. This is because the VTS // framework will call the test for each instance. Only the primary device of -// the factory specified in the environment is tested. -const std::vector& getDeviceParameters() { +// the default service factory can be tested. + +// Return a pair of <"default", "primary"> or <[non-default name], ""> +// This is used to parametrize device factory tests. +// The device name is used to indicate whether IPrimaryDevice is required. +const std::vector& getDeviceParametersForFactoryTests() { static std::vector parameters = { - {environment->getServiceName(), DeviceManager::kPrimaryDevice}}; + {environment->getServiceName(), + environment->getServiceName() == kDefaultServiceName + ? DeviceManager::kPrimaryDevice + : ""}}; return parameters; } +// Return a pair of <"default", "primary"> or nothing. +// This is used to parametrize primary device tests. +const std::vector& getDeviceParametersForPrimaryDeviceTests() { + static std::vector parameters = + !std::get(*getDeviceParametersForFactoryTests().begin()).empty() + ? getDeviceParametersForFactoryTests() + : std::vector{}; + return parameters; +} +// In V2..5 device tests must only test the primary device. +// No device tests are executed for non-primary devices. +const std::vector& getDeviceParameters() { + return getDeviceParametersForPrimaryDeviceTests(); +} #elif MAJOR_VERSION >= 6 -// FIXME: Will be replaced with code that analyzes the audio policy config file. -const std::vector& getDeviceParameters() { - static std::vector parameters = [] { - const auto instances = - ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor); - std::vector result; - result.reserve(instances.size()); - for (const auto& instance : instances) { - result.emplace_back(instance, DeviceManager::kPrimaryDevice); - } - return result; - }(); - return parameters; -} +// For V6 and above these functions are implemented in 6.0/AudioPrimaryHidlHalTest.cpp +const std::vector& getDeviceParametersForFactoryTests(); +const std::vector& getDeviceParametersForPrimaryDeviceTests(); +const std::vector& getDeviceParameters(); #endif -class AudioHidlTestWithDeviceParameter : public AudioPolicyConfigTest, +class AudioHidlTestWithDeviceParameter : public HidlTest, public ::testing::WithParamInterface { protected: - const std::string& getFactoryName() const { return std::get(GetParam()); } - bool isPrimaryDeviceOptional() const { - return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName()); + const std::string& getFactoryName() const override { + return std::get(GetParam()); } - sp getDevicesFactory() const { - return AudioPolicyConfigTest::getDevicesFactory(getFactoryName()); - } - sp getPrimaryDevice() const { - return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName()); + const std::string& getDeviceName() const override { + return std::get(GetParam()); } }; @@ -310,7 +346,7 @@ class AudioHidlTestWithDeviceParameter : public AudioPolicyConfigTest, ////////////////////// getService audio_devices_factory ////////////////////// ////////////////////////////////////////////////////////////////////////////// -// Test all audio devices +// Test audio devices factory class AudioHidlTest : public AudioHidlTestWithDeviceParameter { public: void SetUp() override { @@ -337,53 +373,75 @@ TEST_P(AudioHidlTest, OpenDeviceInvalidParameter) { ASSERT_TRUE(device == nullptr); } -INSTANTIATE_TEST_CASE_P(AudioHidl, AudioHidlTest, ::testing::ValuesIn(getDeviceParameters()), +INSTANTIATE_TEST_CASE_P(AudioHidl, AudioHidlTest, + ::testing::ValuesIn(getDeviceParametersForFactoryTests()), &DeviceParameterToString); +////////////////////////////////////////////////////////////////////////////// +/////////////////////////////// openDevice /////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// Test all audio devices +class AudioHidlDeviceTest : public AudioHidlTest { + public: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base + ASSERT_TRUE(getDevice() != nullptr); + } +}; + +TEST_P(AudioHidlDeviceTest, OpenDevice) { + doc::test("Test openDevice (called during setup)"); +} + +TEST_P(AudioHidlDeviceTest, Init) { + doc::test("Test that the audio hal initialized correctly"); + ASSERT_OK(getDevice()->initCheck()); +} + +INSTANTIATE_TEST_CASE_P(AudioHidlDevice, AudioHidlDeviceTest, + ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + ////////////////////////////////////////////////////////////////////////////// /////////////////////////////// openDevice primary /////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Test the primary device -class AudioPrimaryHidlTest : public AudioHidlTest { - public: +class AudioPrimaryHidlTest : public AudioHidlDeviceTest { + public: void SetUp() override { - ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base - if (getDevice() == nullptr && isPrimaryDeviceOptional()) { - GTEST_SKIP() << "No primary device on this factory"; - } + ASSERT_NO_FATAL_FAILURE(AudioHidlDeviceTest::SetUp()); // setup base ASSERT_TRUE(getDevice() != nullptr); } - protected: - sp getDevice() const { return getPrimaryDevice(); } + protected: + sp getDevice() const { + return DeviceManager::getInstance().getPrimary(getFactoryName()); + } }; TEST_P(AudioPrimaryHidlTest, OpenPrimaryDevice) { - doc::test("Test the openDevice (called during setup)"); -} - -TEST_P(AudioPrimaryHidlTest, Init) { - doc::test("Test that the audio primary hal initialized correctly"); - ASSERT_OK(getDevice()->initCheck()); + doc::test("Test openPrimaryDevice (called during setup)"); } INSTANTIATE_TEST_CASE_P(AudioPrimaryHidl, AudioPrimaryHidlTest, - ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), + &DeviceParameterToString); ////////////////////////////////////////////////////////////////////////////// ///////////////////// {set,get}{Master,Mic}{Mute,Volume} ///////////////////// ////////////////////////////////////////////////////////////////////////////// -template -class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { - protected: +template +class AccessorHidlTest : public BaseTestClass { + protected: enum Optionality { REQUIRED, OPTIONAL }; struct Initial { // Initial property value Initial(Property value, Optionality check = REQUIRED) : value(value), check(check) {} Property value; Optionality check; // If this initial value should be checked }; + using BaseTestClass::res; /** Test a property getter and setter. * The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL. */ @@ -395,7 +453,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK}; Property initialValue = expectedInitial.value; - ASSERT_OK((getDevice().get()->*getter)(returnIn(res, initialValue))); + ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, initialValue))); ASSERT_RESULT(expectedResults, res); if (res == Result::OK && expectedInitial.check == REQUIRED) { EXPECT_EQ(expectedInitial.value, initialValue); @@ -406,7 +464,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { for (Property setValue : valuesToTest) { SCOPED_TRACE("Test " + propertyName + " getter and setter for " + testing::PrintToString(setValue)); - auto ret = (getDevice().get()->*setter)(setValue); + auto ret = (BaseTestClass::getDevice().get()->*setter)(setValue); ASSERT_RESULT(expectedResults, ret); if (ret == Result::NOT_SUPPORTED) { doc::partialTest(propertyName + " setter is not supported"); @@ -414,7 +472,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { } Property getValue; // Make sure the getter returns the same value just set - ASSERT_OK((getDevice().get()->*getter)(returnIn(res, getValue))); + ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, getValue))); ASSERT_RESULT(expectedResults, res); if (res == Result::NOT_SUPPORTED) { doc::partialTest(propertyName + " getter is not supported"); @@ -426,34 +484,40 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { for (Property invalidValue : invalidValues) { SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " + testing::PrintToString(invalidValue)); - EXPECT_RESULT(invalidArgsOrNotSupported, (getDevice().get()->*setter)(invalidValue)); + EXPECT_RESULT(invalidArgsOrNotSupported, + (BaseTestClass::getDevice().get()->*setter)(invalidValue)); } // Restore initial value - EXPECT_RESULT(expectedResults, (getDevice().get()->*setter)(initialValue)); + EXPECT_RESULT(expectedResults, (BaseTestClass::getDevice().get()->*setter)(initialValue)); } }; -using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; +using BoolAccessorHidlTest = AccessorHidlTest; +using BoolAccessorPrimaryHidlTest = AccessorHidlTest; -TEST_P(BoolAccessorPrimaryHidlTest, MicMuteTest) { +TEST_P(BoolAccessorHidlTest, MicMuteTest) { doc::test("Check that the mic can be muted and unmuted"); - testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, &IDevice::getMicMute); + testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, + &IDevice::getMicMute); // TODO: check that the mic is really muted (all sample are 0) } -TEST_P(BoolAccessorPrimaryHidlTest, MasterMuteTest) { +TEST_P(BoolAccessorHidlTest, MasterMuteTest) { doc::test("If master mute is supported, try to mute and unmute the master output"); testAccessors("master mute", Initial{false}, {true}, &IDevice::setMasterMute, &IDevice::getMasterMute); // TODO: check that the master volume is really muted } -INSTANTIATE_TEST_CASE_P(BoolAccessorPrimaryHidl, BoolAccessorPrimaryHidlTest, +INSTANTIATE_TEST_CASE_P(BoolAccessorHidl, BoolAccessorHidlTest, ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); +INSTANTIATE_TEST_CASE_P(BoolAccessorPrimaryHidl, BoolAccessorPrimaryHidlTest, + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), + &DeviceParameterToString); -using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; -TEST_P(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { +using FloatAccessorHidlTest = AccessorHidlTest; +TEST_P(FloatAccessorHidlTest, MasterVolumeTest) { doc::test("Test the master volume if supported"); testAccessors( "master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume, @@ -461,28 +525,29 @@ TEST_P(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { // TODO: check that the master volume is really changed } -INSTANTIATE_TEST_CASE_P(FloatAccessorPrimaryHidl, FloatAccessorPrimaryHidlTest, +INSTANTIATE_TEST_CASE_P(FloatAccessorHidl, FloatAccessorHidlTest, ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); ////////////////////////////////////////////////////////////////////////////// //////////////////////////////// AudioPatches //////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest { - protected: - bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); } +class AudioPatchHidlTest : public AudioHidlDeviceTest { + public: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioHidlDeviceTest::SetUp()); // setup base + if (!areAudioPatchesSupported()) { + GTEST_SKIP() << "Audio patches are not supported"; + } + } }; -TEST_P(AudioPatchPrimaryHidlTest, AudioPatches) { +TEST_P(AudioPatchHidlTest, AudioPatches) { doc::test("Test if audio patches are supported"); - if (!areAudioPatchesSupported()) { - doc::partialTest("Audio patches are not supported"); - return; - } // TODO: test audio patches } -INSTANTIATE_TEST_CASE_P(AudioPatchPrimaryHidl, AudioPatchPrimaryHidlTest, +INSTANTIATE_TEST_CASE_P(AudioPatchHidl, AudioPatchHidlTest, ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); ////////////////////////////////////////////////////////////////////////////// @@ -591,24 +656,21 @@ static string DeviceConfigParameterToString( } class AudioHidlTestWithDeviceConfigParameter - : public AudioPolicyConfigTest, + : public HidlTest, public ::testing::WithParamInterface { protected: - const std::string& getFactoryName() const { + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base + ASSERT_TRUE(getDevicesFactory() != nullptr); + ASSERT_TRUE(getDevice() != nullptr); + } + const std::string& getFactoryName() const override { return std::get(std::get(GetParam())); } - bool isPrimaryDeviceOptional() const { - return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName()); - } - sp getDevicesFactory() const { - return AudioPolicyConfigTest::getDevicesFactory(getFactoryName()); - } - sp getPrimaryDevice() const { - return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName()); + const std::string& getDeviceName() const override { + return std::get(std::get(GetParam())); } const AudioConfig& getConfig() const { return std::get(GetParam()); } - // FIXME: Split out tests that don't require primary device - sp getDevice() const { return getPrimaryDevice(); } }; ////////////////////////////////////////////////////////////////////////////// @@ -620,16 +682,6 @@ class AudioHidlTestWithDeviceConfigParameter // how to get this value ? is it a property ??? class AudioCaptureConfigPrimaryTest : public AudioHidlTestWithDeviceConfigParameter { - public: - void SetUp() override { - ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp()); // setup base - ASSERT_TRUE(getDevicesFactory() != nullptr); - if (getDevice() == nullptr && isPrimaryDeviceOptional()) { - GTEST_SKIP() << "No primary device on this factory"; - } - ASSERT_TRUE(getDevice() != nullptr); - } - protected: void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) { uint64_t bufferSize; @@ -661,8 +713,9 @@ TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) { } INSTANTIATE_TEST_CASE_P( RequiredInputBufferSize, RequiredInputBufferSizeTest, + // FIXME: uses primaryHasMic ::testing::Combine( - ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())), &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( @@ -682,8 +735,9 @@ TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) { } INSTANTIATE_TEST_CASE_P( RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest, + // FIXME: uses primaryHasMic ::testing::Combine( - ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())), &DeviceConfigParameterToString); @@ -691,7 +745,7 @@ INSTANTIATE_TEST_CASE_P( /////////////////////////////// setScreenState /////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_P(AudioPrimaryHidlTest, setScreenState) { +TEST_P(AudioHidlDeviceTest, setScreenState) { doc::test("Check that the hal can receive the screen state"); for (bool turnedOn : {false, true, true, false, false}) { ASSERT_RESULT(okOrNotSupported, getDevice()->setScreenState(turnedOn)); @@ -702,15 +756,16 @@ TEST_P(AudioPrimaryHidlTest, setScreenState) { //////////////////////////// {get,set}Parameters ///////////////////////////// ////////////////////////////////////////////////////////////////////////////// -TEST_P(AudioPrimaryHidlTest, getParameters) { +TEST_P(AudioHidlDeviceTest, getParameters) { doc::test("Check that the hal can set and get parameters"); hidl_vec context; hidl_vec keys; hidl_vec values; ASSERT_OK(Parameters::get(getDevice(), keys, returnIn(res, values))); - ASSERT_OK(Parameters::set(getDevice(), values)); + ASSERT_RESULT(okOrNotSupported, res); + ASSERT_RESULT(okOrNotSupported, Parameters::set(getDevice(), values)); values.resize(0); - ASSERT_OK(Parameters::set(getDevice(), values)); + ASSERT_RESULT(okOrNotSupported, Parameters::set(getDevice(), values)); } ////////////////////////////////////////////////////////////////////////////// @@ -751,12 +806,12 @@ static void testDebugDump(DebugDump debugDump) { EXPECT_EQ(0, close(fds[1])) << errno; } -TEST_P(AudioPrimaryHidlTest, DebugDump) { +TEST_P(AudioHidlDeviceTest, DebugDump) { doc::test("Check that the hal can dump its state without error"); testDebugDump([this](const auto& handle) { return dump(getDevice(), handle); }); } -TEST_P(AudioPrimaryHidlTest, DebugDumpInvalidArguments) { +TEST_P(AudioHidlDeviceTest, DebugDumpInvalidArguments) { doc::test("Check that the hal dump doesn't crash on invalid arguments"); ASSERT_OK(dump(getDevice(), hidl_handle())); } @@ -768,15 +823,6 @@ TEST_P(AudioPrimaryHidlTest, DebugDumpInvalidArguments) { template class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter { protected: - void SetUp() override { - ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp()); // setup base - ASSERT_TRUE(getDevicesFactory() != nullptr); - if (getDevice() == nullptr && isPrimaryDeviceOptional()) { - GTEST_SKIP() << "No primary device on this factory"; - } - ASSERT_TRUE(getDevice() != nullptr); - } - template void testOpen(Open openStream, const AudioConfig& config) { // FIXME: Open a stream without an IOHandle @@ -828,14 +874,12 @@ class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter { usleep(100 * 1000); } - bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); } - private: void TearDown() override { if (open) { ASSERT_OK(closeStream()); } - AudioPolicyConfigTest::TearDown(); + AudioHidlTestWithDeviceConfigParameter::TearDown(); } protected: @@ -850,7 +894,6 @@ class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter { class OutputStreamTest : public OpenStreamTest { void SetUp() override { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base - if (IsSkipped()) return; // do not attempt to use 'device' address.device = AudioDevice::OUT_DEFAULT; const AudioConfig& config = getConfig(); // TODO: test all flag combination @@ -881,10 +924,11 @@ TEST_P(OutputStreamTest, OpenOutputStreamTest) { "recommended config"); // Open done in SetUp } +// FIXME: Add instantiations for non-primary devices with configs harvested from the APM config file INSTANTIATE_TEST_CASE_P( RequiredOutputStreamConfigSupport, OutputStreamTest, ::testing::Combine( - ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), ::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig())), &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( @@ -896,7 +940,7 @@ INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P( RecommendedOutputStreamConfigSupport, OutputStreamTest, ::testing::Combine( - ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), ::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig())), &DeviceConfigParameterToString); @@ -905,7 +949,6 @@ INSTANTIATE_TEST_CASE_P( class InputStreamTest : public OpenStreamTest { void SetUp() override { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base - if (IsSkipped()) return; // do not attempt to use 'device' address.device = AudioDevice::IN_DEFAULT; const AudioConfig& config = getConfig(); // TODO: test all supported flags and source @@ -934,8 +977,9 @@ TEST_P(InputStreamTest, OpenInputStreamTest) { } INSTANTIATE_TEST_CASE_P( RequiredInputStreamConfigSupport, InputStreamTest, + // FIXME: uses primaryHasMic ::testing::Combine( - ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())), &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( @@ -946,8 +990,9 @@ INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P( RecommendedInputStreamConfigSupport, InputStreamTest, + // FIXME: uses primaryHasMic ::testing::Combine( - ::testing::ValuesIn(getDeviceParameters()), + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())), &DeviceConfigParameterToString); @@ -1481,7 +1526,8 @@ TEST_P(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) { &IPrimaryDevice::getBtScoWidebandEnabled); } -using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest; +using TtyModeAccessorPrimaryHidlTest = + AccessorHidlTest; TEST_P(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) { doc::test("Query and set the TTY mode state"); testAccessors( @@ -1490,7 +1536,8 @@ TEST_P(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) { &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode); } INSTANTIATE_TEST_CASE_P(TtyModeAccessorPrimaryHidl, TtyModeAccessorPrimaryHidlTest, - ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); + ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), + &DeviceParameterToString); TEST_P(BoolAccessorPrimaryHidlTest, setGetHac) { doc::test("Query and set the HAC state"); From 60bd3ecc5d90d1d8ed4adc697fc8c48cef47e412 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 1 Nov 2019 16:28:37 -0700 Subject: [PATCH 4/4] audio: Run VTS tests for streams of non-primary modules for HAL V6 Implement parsing of AudioPolicyManager config for finding out supported format configurations of streams. This only applies when running tests for HAL V6. Previously format configurations mandated by CDD were used for testing, this does not work well for non-primary modules. Fix the following issues found while running the tests for "r_submix" and "msd" modules: - IStream::getSupportedFormats must return a status to indicate that this capability is not supported by HAL; - it is allowed for IStream::setDevices to return NOT_SUPPORTED status. Other changes: - Factor out helper functions for generating format configurations; - Fix generation of the channel mask component in the names of tests that use AudioConfig, add sampling rate to test names. Squashed with the following commit to avoid breaking compilation: audio vts: Remove explicit dependency on the new types Avoid using the new ChannelMaskSet and SampleRateSet types directly to simplify upstreaming. Bug: 141989952 Bug: 141847510 Test: atest VtsHalAudioV5_0TargetTest atest VtsHalAudioV6_0TargetTest also, run modified V5_0 test using generators for V6_0 Change-Id: If0d330881901908e546baab89f63d3333003e355 Merged-In: If0d330881901908e546baab89f63d3333003e355 --- audio/6.0/IStream.hal | 4 +- audio/core/all-versions/default/Stream.cpp | 9 + .../4.0/AudioPrimaryHidlHalTest.cpp | 5 +- .../functional/4.0/AudioPrimaryHidlHalUtils.h | 9 +- .../6.0/AudioPrimaryHidlHalTest.cpp | 80 ++++++ .../vts/functional/AudioPrimaryHidlHalTest.h | 248 ++++++++++-------- .../vts/functional/ConfigHelper.h | 120 +++++++++ 7 files changed, 355 insertions(+), 120 deletions(-) create mode 100644 audio/core/all-versions/vts/functional/ConfigHelper.h diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal index f4c91f826d..451e1162bf 100644 --- a/audio/6.0/IStream.hal +++ b/audio/6.0/IStream.hal @@ -123,9 +123,11 @@ interface IStream { * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_FORMATS on the legacy * HAL. * + * @return retval operation completion status. * @return formats supported audio formats. + * Must be non empty if retval is OK. */ - getSupportedFormats() generates (vec formats); + getSupportedFormats() generates (Result retval, vec formats); /** * Sets the audio format of the stream. Calling this method is equivalent to diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp index e62f6d3b0a..5f24a5d781 100644 --- a/audio/core/all-versions/default/Stream.cpp +++ b/audio/core/all-versions/default/Stream.cpp @@ -175,8 +175,17 @@ Return Stream::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { for (size_t i = 0; i < halFormats.size(); ++i) { formats[i] = AudioFormat(halFormats[i]); } + // Legacy get_parameter does not return a status_t, thus can not advertise of failure. + // Note that the method must not return an empty list if this capability is supported. + if (formats.size() == 0) { + result = Result::NOT_SUPPORTED; + } } +#if MAJOR_VERSION <= 5 _hidl_cb(formats); +#elif MAJOR_VERSION >= 6 + _hidl_cb(result, formats); +#endif return Void(); } diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp index cd93643b95..e267a5ea72 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp @@ -172,9 +172,10 @@ static void testSetDevices(IStream* stream, const DeviceAddress& address) { DeviceAddress otherAddress = address; otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? AudioDevice::OUT_SPEAKER : AudioDevice::IN_BUILTIN_MIC; - EXPECT_OK(stream->setDevices({otherAddress})); + EXPECT_RESULT(okOrNotSupported, stream->setDevices({otherAddress})); - ASSERT_OK(stream->setDevices({address})); // Go back to the original value + ASSERT_RESULT(okOrNotSupported, + stream->setDevices({address})); // Go back to the original value } TEST_IO_STREAM(SetDevices, "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC", diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h index 8415053ffc..7a52d0e364 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h @@ -75,11 +75,18 @@ struct GetSupported { return res; } +#if MAJOR_VERSION <= 5 static Result formats(IStream* stream, hidl_vec& capabilities) { EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities))); - // TODO: this should be an optional function return Result::OK; } +#elif MAJOR_VERSION >= 6 + static Result formats(IStream* stream, hidl_vec& capabilities) { + Result res; + EXPECT_OK(stream->getSupportedFormats(returnIn(res, capabilities))); + return res; + } +#endif }; template diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp index 937de0a18d..30f8a7ade7 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -64,3 +64,83 @@ const std::vector& getDeviceParameters() { }(); return parameters; } + +const std::vector& getOutputDeviceConfigParameters() { + static std::vector parameters = [] { + std::vector result; + for (const auto& device : getDeviceParameters()) { + auto module = + getCachedPolicyConfig().getModuleFromName(std::get(device)); + for (const auto& ioProfile : module->getOutputProfiles()) { + for (const auto& profile : ioProfile->getAudioProfiles()) { + const auto& channels = profile->getChannels(); + const auto& sampleRates = profile->getSampleRates(); + auto configs = ConfigHelper::combineAudioConfig( + vector(channels.begin(), channels.end()), + vector(sampleRates.begin(), sampleRates.end()), + profile->getFormat()); + auto flags = ioProfile->getFlags(); + for (auto& config : configs) { + // Some combinations of flags declared in the config file require special + // treatment. + bool special = false; + if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { + config.offloadInfo.sampleRateHz = config.sampleRateHz; + config.offloadInfo.channelMask = config.channelMask; + config.offloadInfo.format = config.format; + config.offloadInfo.streamType = AudioStreamType::MUSIC; + config.offloadInfo.bitRatePerSecond = 320; + config.offloadInfo.durationMicroseconds = -1; + config.offloadInfo.bitWidth = 16; + config.offloadInfo.bufferSize = 256; // arbitrary value + config.offloadInfo.usage = AudioUsage::MEDIA; + result.emplace_back( + device, config, + AudioOutputFlag(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)); + special = true; + } + if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) && + !(flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC)) { + result.emplace_back(device, config, + AudioOutputFlag(AUDIO_OUTPUT_FLAG_DIRECT)); + special = true; + } + if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { // ignore the flag + flags &= ~AUDIO_OUTPUT_FLAG_PRIMARY; + } + if (!special) { + result.emplace_back(device, config, AudioOutputFlag(flags)); + } + } + } + } + } + return result; + }(); + return parameters; +} + +const std::vector& getInputDeviceConfigParameters() { + static std::vector parameters = [] { + std::vector result; + for (const auto& device : getDeviceParameters()) { + auto module = + getCachedPolicyConfig().getModuleFromName(std::get(device)); + for (const auto& ioProfile : module->getInputProfiles()) { + for (const auto& profile : ioProfile->getAudioProfiles()) { + const auto& channels = profile->getChannels(); + const auto& sampleRates = profile->getSampleRates(); + auto configs = ConfigHelper::combineAudioConfig( + vector(channels.begin(), channels.end()), + vector(sampleRates.begin(), sampleRates.end()), + profile->getFormat()); + for (const auto& config : configs) { + result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags())); + } + } + } + } + return result; + }(); + return parameters; +} diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index 7bdc5e1eb1..468f9b2da6 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -97,7 +98,9 @@ using ::android::hardware::kSynchronizedReadWrite; using ::android::hardware::MessageQueue; using ::android::hardware::MQDescriptorSync; using ::android::hardware::Return; +using ::android::hardware::audio::common::utils::EnumBitfield; using ::android::hardware::audio::common::utils::mkEnumBitfield; +using ::android::hardware::details::toHexString; using namespace ::android::hardware::audio::common::CPP_VERSION; using namespace ::android::hardware::audio::common::test::utility; @@ -231,6 +234,9 @@ class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig { } } const std::string& getFilePath() const { return mFilePath; } + sp getModuleFromName(const std::string& name) const { + return getHwModules().getModuleFromName(name.c_str()); + } sp getPrimaryModule() const { return mPrimaryModule; } const std::set& getModulesWithDevicesNames() const { return mModulesWithDevicesNames; @@ -550,91 +556,28 @@ TEST_P(AudioPatchHidlTest, AudioPatches) { INSTANTIATE_TEST_CASE_P(AudioPatchHidl, AudioPatchHidlTest, ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString); -////////////////////////////////////////////////////////////////////////////// -//////////////// Required and recommended audio format support /////////////// -// From: -// https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording -// From: -// https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback -/////////// TODO: move to the beginning of the file for easier update //////// -////////////////////////////////////////////////////////////////////////////// - -struct ConfigHelper { - // for retro compatibility only test the primary device IN_BUILTIN_MIC - // FIXME: in the next audio HAL version, test all available devices - static bool primaryHasMic() { - auto& policyConfig = getCachedPolicyConfig(); - if (policyConfig.getStatus() != OK || policyConfig.getPrimaryModule() == nullptr) { - return true; // Could not get the information, run all tests - } - auto getMic = [](auto& devs) { return devs.getDevice( - AUDIO_DEVICE_IN_BUILTIN_MIC, {}, AUDIO_FORMAT_DEFAULT); }; - auto primaryMic = getMic(policyConfig.getPrimaryModule()->getDeclaredDevices()); - auto availableMic = getMic(policyConfig.getAvailableInputDevices()); - - return primaryMic != nullptr && primaryMic->equals(availableMic); - } - - // Cache result ? - static const vector getRequiredSupportPlaybackAudioConfig() { - return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, - {8000, 11025, 16000, 22050, 32000, 44100}, - {AudioFormat::PCM_16_BIT}); - } - - static const vector getRecommendedSupportPlaybackAudioConfig() { - return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, - {24000, 48000}, {AudioFormat::PCM_16_BIT}); - } - - static const vector getSupportedPlaybackAudioConfig() { - // TODO: retrieve audio config supported by the platform - // as declared in the policy configuration - return {}; - } - - static const vector getRequiredSupportCaptureAudioConfig() { - if (!primaryHasMic()) return {}; - return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100}, - {AudioFormat::PCM_16_BIT}); - } - static const vector getRecommendedSupportCaptureAudioConfig() { - if (!primaryHasMic()) return {}; - return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000}, - {AudioFormat::PCM_16_BIT}); - } - static const vector getSupportedCaptureAudioConfig() { - // TODO: retrieve audio config supported by the platform - // as declared in the policy configuration - return {}; - } - - private: - static const vector combineAudioConfig(vector channelMasks, - vector sampleRates, - vector formats) { - vector configs; - for (auto channelMask : channelMasks) { - for (auto sampleRate : sampleRates) { - for (auto format : formats) { - AudioConfig config{}; - // leave offloadInfo to 0 - config.channelMask = mkEnumBitfield(channelMask); - config.sampleRateHz = sampleRate; - config.format = format; - // FIXME: leave frameCount to 0 ? - configs.push_back(config); - } - } - } - return configs; - } -}; - // Nesting a tuple in another tuple allows to use GTest Combine function to generate // all combinations of devices and configs. -enum { PARAM_DEVICE, PARAM_CONFIG }; -using DeviceConfigParameter = std::tuple; +enum { PARAM_DEVICE, PARAM_CONFIG, PARAM_FLAGS }; +enum { INDEX_INPUT, INDEX_OUTPUT }; +using DeviceConfigParameter = + std::tuple>; + +#if MAJOR_VERSION >= 6 +const std::vector& getInputDeviceConfigParameters(); +const std::vector& getOutputDeviceConfigParameters(); +#endif + +#if MAJOR_VERSION >= 4 +static string SanitizeStringForGTestName(const string& s) { + string result = s; + for (size_t i = 0; i < result.size(); i++) { + // gtest test names must only contain alphanumeric characters + if (!std::isalnum(result[i])) result[i] = '_'; + } + return result; +} +#endif /** Generate a test name based on an audio config. * @@ -652,7 +595,32 @@ static string DeviceConfigParameterToString( ((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) || config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO)) ? "MONO" - : ::testing::PrintToString(config.channelMask)); +#if MAJOR_VERSION == 2 + : ::testing::PrintToString(config.channelMask) +#elif MAJOR_VERSION >= 4 + // In V4 and above the channel mask is a bitfield. + // Printing its value using HIDL's toString for a bitfield emits a lot of extra + // text due to overlapping constant values. Instead, we print the bitfield value + // as if it was a single value + its hex representation + : SanitizeStringForGTestName( + ::testing::PrintToString(AudioChannelMask(config.channelMask)) + "_" + + toHexString(config.channelMask)) +#endif + ) + + "_" + +#if MAJOR_VERSION == 2 + std::visit([](auto&& arg) -> std::string { return ::testing::PrintToString(arg); }, + std::get(info.param)); +#elif MAJOR_VERSION >= 4 + SanitizeStringForGTestName(std::visit( + [](auto&& arg) -> std::string { + using T = std::decay_t; + // Need to use FQN of toString to avoid confusing the compiler + return ::android::hardware::audio::common::CPP_VERSION::toString( + hidl_bitfield(arg)); + }, + std::get(info.param))); +#endif } class AudioHidlTestWithDeviceConfigParameter @@ -671,8 +639,27 @@ class AudioHidlTestWithDeviceConfigParameter return std::get(std::get(GetParam())); } const AudioConfig& getConfig() const { return std::get(GetParam()); } +#if MAJOR_VERSION == 2 + AudioInputFlag getInputFlags() const { + return std::get(std::get(GetParam())); + } + AudioOutputFlag getOutputFlags() const { + return std::get(std::get(GetParam())); + } +#elif MAJOR_VERSION >= 4 + hidl_bitfield getInputFlags() const { + return hidl_bitfield( + std::get(std::get(GetParam()))); + } + hidl_bitfield getOutputFlags() const { + return hidl_bitfield( + std::get(std::get(GetParam()))); + } +#endif }; +#include "ConfigHelper.h" + ////////////////////////////////////////////////////////////////////////////// ///////////////////////////// getInputBufferSize ///////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -681,7 +668,7 @@ class AudioHidlTestWithDeviceConfigParameter // android.hardware.microphone // how to get this value ? is it a property ??? -class AudioCaptureConfigPrimaryTest : public AudioHidlTestWithDeviceConfigParameter { +class AudioCaptureConfigTest : public AudioHidlTestWithDeviceConfigParameter { protected: void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) { uint64_t bufferSize; @@ -704,42 +691,51 @@ class AudioCaptureConfigPrimaryTest : public AudioHidlTestWithDeviceConfigParame // Test that the required capture config and those declared in the policy are // indeed supported -class RequiredInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {}; +class RequiredInputBufferSizeTest : public AudioCaptureConfigTest {}; TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) { doc::test( "Input buffer size must be retrievable for a format with required " "support."); inputBufferSizeTest(getConfig(), true); } + +// Test that the recommended capture config are supported or lead to a +// INVALID_ARGUMENTS return +class OptionalInputBufferSizeTest : public AudioCaptureConfigTest {}; +TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) { + doc::test( + "Input buffer size should be retrievable for a format with recommended " + "support."); + inputBufferSizeTest(getConfig(), false); +} + +#if MAJOR_VERSION <= 5 +// For V2..5 test the primary device according to CDD requirements. INSTANTIATE_TEST_CASE_P( RequiredInputBufferSize, RequiredInputBufferSizeTest, - // FIXME: uses primaryHasMic ::testing::Combine( ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), - ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig()), + ::testing::Values(AudioInputFlag::NONE)), &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( SupportedInputBufferSize, RequiredInputBufferSizeTest, ::testing::Combine(::testing::ValuesIn(getDeviceParameters()), - ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig()), + ::testing::Values(AudioInputFlag::NONE)), &DeviceConfigParameterToString); - -// Test that the recommended capture config are supported or lead to a -// INVALID_ARGUMENTS return -class OptionalInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {}; -TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) { - doc::test( - "Input buffer size should be retrievable for a format with recommended " - "support."); - inputBufferSizeTest(getConfig(), false); -} INSTANTIATE_TEST_CASE_P( RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest, - // FIXME: uses primaryHasMic ::testing::Combine( ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), - ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig()), + ::testing::Values(AudioInputFlag::NONE)), &DeviceConfigParameterToString); +#elif MAJOR_VERSION >= 6 +INSTANTIATE_TEST_CASE_P(SupportedInputBufferSize, RequiredInputBufferSizeTest, + ::testing::ValuesIn(getInputDeviceConfigParameters()), + &DeviceConfigParameterToString); +#endif ////////////////////////////////////////////////////////////////////////////// /////////////////////////////// setScreenState /////////////////////////////// @@ -896,8 +892,7 @@ class OutputStreamTest : public OpenStreamTest { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base address.device = AudioDevice::OUT_DEFAULT; const AudioConfig& config = getConfig(); - // TODO: test all flag combination - auto flags = mkEnumBitfield(AudioOutputFlag::NONE); + auto flags = getOutputFlags(); testOpen( [&](AudioIoHandle handle, AudioConfig config, auto cb) { #if MAJOR_VERSION == 2 @@ -924,25 +919,37 @@ TEST_P(OutputStreamTest, OpenOutputStreamTest) { "recommended config"); // Open done in SetUp } -// FIXME: Add instantiations for non-primary devices with configs harvested from the APM config file + +#if MAJOR_VERSION <= 5 +// For V2..5 test the primary device according to CDD requirements. INSTANTIATE_TEST_CASE_P( RequiredOutputStreamConfigSupport, OutputStreamTest, ::testing::Combine( ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), - ::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig()), + ::testing::Values(AudioOutputFlag::NONE)), &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( SupportedOutputStreamConfig, OutputStreamTest, ::testing::Combine(::testing::ValuesIn(getDeviceParameters()), - ::testing::ValuesIn(ConfigHelper::getSupportedPlaybackAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getSupportedPlaybackAudioConfig()), + ::testing::Values(AudioOutputFlag::NONE)), &DeviceConfigParameterToString); - INSTANTIATE_TEST_CASE_P( RecommendedOutputStreamConfigSupport, OutputStreamTest, ::testing::Combine( ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), - ::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig()), + ::testing::Values(AudioOutputFlag::NONE)), &DeviceConfigParameterToString); +#elif MAJOR_VERSION >= 6 +// For V6 and above test according to the audio policy manager configuration. +// This is more correct as CDD is written from the apps perspective. +// Audio system provides necessary format conversions for the missing configurations. +INSTANTIATE_TEST_CASE_P(DeclaredOutputStreamConfigSupport, OutputStreamTest, + ::testing::ValuesIn(getOutputDeviceConfigParameters()), + &DeviceConfigParameterToString); +#endif ////////////////////////////// openInputStream ////////////////////////////// @@ -951,8 +958,7 @@ class InputStreamTest : public OpenStreamTest { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base address.device = AudioDevice::IN_DEFAULT; const AudioConfig& config = getConfig(); - // TODO: test all supported flags and source - auto flags = mkEnumBitfield(AudioInputFlag::NONE); + auto flags = getInputFlags(); testOpen( [&](AudioIoHandle handle, AudioConfig config, auto cb) { return getDevice()->openInputStream(handle, address, config, flags, @@ -975,26 +981,36 @@ TEST_P(InputStreamTest, OpenInputStreamTest) { "recommended config"); // Open done in setup } +#if MAJOR_VERSION <= 5 +// For V2..5 test the primary device according to CDD requirements. INSTANTIATE_TEST_CASE_P( RequiredInputStreamConfigSupport, InputStreamTest, - // FIXME: uses primaryHasMic ::testing::Combine( ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), - ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig()), + ::testing::Values(AudioInputFlag::NONE)), &DeviceConfigParameterToString); INSTANTIATE_TEST_CASE_P( SupportedInputStreamConfig, InputStreamTest, ::testing::Combine(::testing::ValuesIn(getDeviceParameters()), - ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig()), + ::testing::Values(AudioInputFlag::NONE)), &DeviceConfigParameterToString); - INSTANTIATE_TEST_CASE_P( RecommendedInputStreamConfigSupport, InputStreamTest, - // FIXME: uses primaryHasMic ::testing::Combine( ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()), - ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())), + ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig()), + ::testing::Values(AudioInputFlag::NONE)), &DeviceConfigParameterToString); +#elif MAJOR_VERSION >= 6 +// For V6 and above test according to the audio policy manager configuration. +// This is more correct as CDD is written from the apps perspective. +// Audio system provides necessary format conversions for the missing configurations. +INSTANTIATE_TEST_CASE_P(DeclaredInputStreamConfigSupport, InputStreamTest, + ::testing::ValuesIn(getInputDeviceConfigParameters()), + &DeviceConfigParameterToString); +#endif ////////////////////////////////////////////////////////////////////////////// ////////////////////////////// IStream getters /////////////////////////////// diff --git a/audio/core/all-versions/vts/functional/ConfigHelper.h b/audio/core/all-versions/vts/functional/ConfigHelper.h new file mode 100644 index 0000000000..48aae8c5b3 --- /dev/null +++ b/audio/core/all-versions/vts/functional/ConfigHelper.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Code in this file uses 'getCachedPolicyConfig' +#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST +#error Must be included from AudioPrimaryHidlTest.h +#endif + +////////////////////////////////////////////////////////////////////////////// +//////////////// Required and recommended audio format support /////////////// +// From: +// https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording +// From: +// https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback +/////////// TODO: move to the beginning of the file for easier update //////// +////////////////////////////////////////////////////////////////////////////// + +struct ConfigHelper { + // for retro compatibility only test the primary device IN_BUILTIN_MIC + // FIXME: in the next audio HAL version, test all available devices + static bool primaryHasMic() { + auto& policyConfig = getCachedPolicyConfig(); + if (policyConfig.getStatus() != OK || policyConfig.getPrimaryModule() == nullptr) { + return true; // Could not get the information, run all tests + } + auto getMic = [](auto& devs) { + return devs.getDevice(AUDIO_DEVICE_IN_BUILTIN_MIC, {}, AUDIO_FORMAT_DEFAULT); + }; + auto primaryMic = getMic(policyConfig.getPrimaryModule()->getDeclaredDevices()); + auto availableMic = getMic(policyConfig.getAvailableInputDevices()); + + return primaryMic != nullptr && primaryMic->equals(availableMic); + } + + // Cache result ? + static const vector getRequiredSupportPlaybackAudioConfig() { + return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, + {8000, 11025, 16000, 22050, 32000, 44100}, + {AudioFormat::PCM_16_BIT}); + } + + static const vector getRecommendedSupportPlaybackAudioConfig() { + return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, + {24000, 48000}, {AudioFormat::PCM_16_BIT}); + } + + static const vector getSupportedPlaybackAudioConfig() { + // TODO: retrieve audio config supported by the platform + // as declared in the policy configuration + return {}; + } + + static const vector getRequiredSupportCaptureAudioConfig() { + if (!primaryHasMic()) return {}; + return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100}, + {AudioFormat::PCM_16_BIT}); + } + static const vector getRecommendedSupportCaptureAudioConfig() { + if (!primaryHasMic()) return {}; + return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000}, + {AudioFormat::PCM_16_BIT}); + } + static const vector getSupportedCaptureAudioConfig() { + // TODO: retrieve audio config supported by the platform + // as declared in the policy configuration + return {}; + } + + static vector combineAudioConfig(vector channelMasks, + vector sampleRates, + audio_format_t format) { + vector configs; + configs.reserve(channelMasks.size() * sampleRates.size()); + for (auto channelMask : channelMasks) { + for (auto sampleRate : sampleRates) { + AudioConfig config{}; + // leave offloadInfo to 0 + config.channelMask = EnumBitfield(channelMask); + config.sampleRateHz = sampleRate; + config.format = AudioFormat(format); + configs.push_back(config); + } + } + return configs; + } + + static vector combineAudioConfig(vector channelMasks, + vector sampleRates, + vector formats) { + vector configs; + configs.reserve(channelMasks.size() * sampleRates.size() * formats.size()); + for (auto channelMask : channelMasks) { + for (auto sampleRate : sampleRates) { + for (auto format : formats) { + AudioConfig config{}; + // leave offloadInfo to 0 + config.channelMask = mkEnumBitfield(channelMask); + config.sampleRateHz = sampleRate; + config.format = format; + // FIXME: leave frameCount to 0 ? + configs.push_back(config); + } + } + } + return configs; + } +};