From 60bd3ecc5d90d1d8ed4adc697fc8c48cef47e412 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 1 Nov 2019 16:28:37 -0700 Subject: [PATCH] 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; + } +};