From 8ebfba6589e5230153b2d5bcbb749c82672ee5ff Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Mon, 22 Feb 2021 11:04:42 -0800 Subject: [PATCH] audio: Verify that VTS tests can work with vendor extensions Vendors can have vendor-extended device types and audio formats supported by their HALs and frameworks. VTS tests are built using AOSP sources, thus they don't have these vendor modifications. Ensure that VTS tests behave correctly when dealing with audio policy manager configurations that contain vendor extensions. Since verifying this behavior requires using specially crafted APM configs, verification is done using unit tests. Test: atest HalAudioV6_0GeneratorTest Test: atest HalAudioV7_0GeneratorTest Change-Id: I9dc1a18863418a8fbd7d1dc14abc844fd9060ca5 --- audio/core/all-versions/default/TEST_MAPPING | 6 + .../6.0/AudioPrimaryHidlHalTest.cpp | 99 ------ .../vts/functional/6.0/Generators.cpp | 129 ++++++++ .../vts/functional/6.0/Generators.h | 30 ++ .../7.0/AudioPrimaryHidlHalTest.cpp | 270 +-------------- .../vts/functional/7.0/Generators.cpp | 309 ++++++++++++++++++ .../vts/functional/7.0/Generators.h | 34 ++ .../vts/functional/7.0/PolicyConfig.h | 67 +++- .../all-versions/vts/functional/Android.bp | 56 ++++ .../vts/functional/AudioPrimaryHidlHalTest.h | 26 +- .../vts/functional/AudioTestDefinitions.h | 45 +++ .../vts/functional/ConfigHelper.h | 21 +- .../vts/functional/DeviceManager.h | 26 +- .../vts/functional/PolicyConfig.h | 71 ++-- .../tests/HalAudioV6_0GeneratorTest.xml | 34 ++ .../tests/HalAudioV7_0GeneratorTest.xml | 34 ++ .../vts/functional/tests/apm_config_no_vx.xml | 68 ++++ .../functional/tests/apm_config_no_vx_7_0.xml | 68 ++++ .../functional/tests/apm_config_with_vx.xml | 81 +++++ .../tests/apm_config_with_vx_7_0.xml | 81 +++++ .../vts/functional/tests/generators_tests.cpp | 132 ++++++++ 21 files changed, 1247 insertions(+), 440 deletions(-) create mode 100644 audio/core/all-versions/vts/functional/6.0/Generators.cpp create mode 100644 audio/core/all-versions/vts/functional/6.0/Generators.h create mode 100644 audio/core/all-versions/vts/functional/7.0/Generators.cpp create mode 100644 audio/core/all-versions/vts/functional/7.0/Generators.h create mode 100644 audio/core/all-versions/vts/functional/AudioTestDefinitions.h create mode 100644 audio/core/all-versions/vts/functional/tests/HalAudioV6_0GeneratorTest.xml create mode 100644 audio/core/all-versions/vts/functional/tests/HalAudioV7_0GeneratorTest.xml create mode 100644 audio/core/all-versions/vts/functional/tests/apm_config_no_vx.xml create mode 100644 audio/core/all-versions/vts/functional/tests/apm_config_no_vx_7_0.xml create mode 100644 audio/core/all-versions/vts/functional/tests/apm_config_with_vx.xml create mode 100644 audio/core/all-versions/vts/functional/tests/apm_config_with_vx_7_0.xml create mode 100644 audio/core/all-versions/vts/functional/tests/generators_tests.cpp diff --git a/audio/core/all-versions/default/TEST_MAPPING b/audio/core/all-versions/default/TEST_MAPPING index d53c97afaa..1e2944060b 100644 --- a/audio/core/all-versions/default/TEST_MAPPING +++ b/audio/core/all-versions/default/TEST_MAPPING @@ -2,6 +2,12 @@ "presubmit": [ { "name": "android.hardware.audio@7.0-util_tests" + }, + { + "name": "HalAudioV6_0GeneratorTest" + }, + { + "name": "HalAudioV7_0GeneratorTest" } ] } 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 0ebe4c24ff..8af4c7855a 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -17,105 +17,6 @@ // pull in all the <= 5.0 tests #include "5.0/AudioPrimaryHidlHalTest.cpp" -#if MAJOR_VERSION <= 6 -static std::vector generateOutputDeviceConfigParameters( - bool oneProfilePerDevice) { - 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( - std::vector(channels.begin(), channels.end()), - std::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. - 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(AudioOutputFlag::COMPRESS_OFFLOAD | - AudioOutputFlag::DIRECT)); - } else { - if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { // ignore the flag - flags &= ~AUDIO_OUTPUT_FLAG_PRIMARY; - } - result.emplace_back(device, config, AudioOutputFlag(flags)); - } - if (oneProfilePerDevice) break; - } - if (oneProfilePerDevice) break; - } - if (oneProfilePerDevice) break; - } - } - return result; -} - -const std::vector& getOutputDeviceConfigParameters() { - static std::vector parameters = - generateOutputDeviceConfigParameters(false); - return parameters; -} - -const std::vector& getOutputDeviceSingleConfigParameters() { - static std::vector parameters = - generateOutputDeviceConfigParameters(true); - return parameters; -} - -static std::vector generateInputDeviceConfigParameters( - bool oneProfilePerDevice) { - 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( - std::vector(channels.begin(), channels.end()), - std::vector(sampleRates.begin(), sampleRates.end()), - profile->getFormat()); - for (const auto& config : configs) { - result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags())); - if (oneProfilePerDevice) break; - } - if (oneProfilePerDevice) break; - } - if (oneProfilePerDevice) break; - } - } - return result; -} - -const std::vector& getInputDeviceConfigParameters() { - static std::vector parameters = - generateInputDeviceConfigParameters(false); - return parameters; -} - -const std::vector& getInputDeviceSingleConfigParameters() { - static std::vector parameters = - generateInputDeviceConfigParameters(true); - return parameters; -} -#endif // MAJOR_VERSION <= 6 - class SingleConfigOutputStreamTest : public OutputStreamTest {}; TEST_P(SingleConfigOutputStreamTest, CloseDeviceWithOpenedOutputStreams) { doc::test("Verify that a device can't be closed if there are output streams opened"); diff --git a/audio/core/all-versions/vts/functional/6.0/Generators.cpp b/audio/core/all-versions/vts/functional/6.0/Generators.cpp new file mode 100644 index 0000000000..6b4dbc17af --- /dev/null +++ b/audio/core/all-versions/vts/functional/6.0/Generators.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2021 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. + */ + +#include + +#include "6.0/Generators.h" +#include "ConfigHelper.h" +#include "PolicyConfig.h" + +// clang-format off +#include PATH(android/hardware/audio/FILE_VERSION/types.h) +#include PATH(android/hardware/audio/common/FILE_VERSION/types.h) +// clang-format on + +// Forward declaration for functions that are substituted +// in generator unit tests. +const PolicyConfig& getCachedPolicyConfig(); +const std::vector& getDeviceParameters(); + +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; + +std::vector generateOutputDeviceConfigParameters(bool oneProfilePerDevice) { + 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( + std::vector(channels.begin(), channels.end()), + std::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. + 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(AudioOutputFlag::COMPRESS_OFFLOAD | + AudioOutputFlag::DIRECT)); + } else { + if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { // ignore the flag + flags &= ~AUDIO_OUTPUT_FLAG_PRIMARY; + } + result.emplace_back(device, config, AudioOutputFlag(flags)); + } + if (oneProfilePerDevice) break; + } + if (oneProfilePerDevice) break; + } + if (oneProfilePerDevice) break; + } + } + return result; +} + +const std::vector& getOutputDeviceConfigParameters() { + static std::vector parameters = + generateOutputDeviceConfigParameters(false); + return parameters; +} + +const std::vector& getOutputDeviceSingleConfigParameters() { + static std::vector parameters = + generateOutputDeviceConfigParameters(true); + return parameters; +} + +std::vector generateInputDeviceConfigParameters(bool oneProfilePerDevice) { + 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( + std::vector(channels.begin(), channels.end()), + std::vector(sampleRates.begin(), sampleRates.end()), + profile->getFormat()); + for (const auto& config : configs) { + result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags())); + if (oneProfilePerDevice) break; + } + if (oneProfilePerDevice) break; + } + if (oneProfilePerDevice) break; + } + } + return result; +} + +const std::vector& getInputDeviceConfigParameters() { + static std::vector parameters = + generateInputDeviceConfigParameters(false); + return parameters; +} + +const std::vector& getInputDeviceSingleConfigParameters() { + static std::vector parameters = + generateInputDeviceConfigParameters(true); + return parameters; +} diff --git a/audio/core/all-versions/vts/functional/6.0/Generators.h b/audio/core/all-versions/vts/functional/6.0/Generators.h new file mode 100644 index 0000000000..1e87163477 --- /dev/null +++ b/audio/core/all-versions/vts/functional/6.0/Generators.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 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. + */ + +#pragma once + +#include + +#include "AudioTestDefinitions.h" + +const std::vector& getOutputDeviceConfigParameters(); +const std::vector& getOutputDeviceSingleConfigParameters(); +const std::vector& getInputDeviceConfigParameters(); +const std::vector& getInputDeviceSingleConfigParameters(); + +// For unit tests +std::vector generateOutputDeviceConfigParameters(bool oneProfilePerDevice); +std::vector generateInputDeviceConfigParameters(bool oneProfilePerDevice); diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp index be1ffbbcfe..c1923f1230 100644 --- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp @@ -14,277 +14,11 @@ * limitations under the License. */ +#include "Generators.h" + // pull in all the <= 6.0 tests #include "6.0/AudioPrimaryHidlHalTest.cpp" -static std::vector combineAudioConfig(std::vector channelMasks, - std::vector sampleRates, - const std::string& format) { - std::vector configs; - configs.reserve(channelMasks.size() * sampleRates.size()); - for (auto channelMask : channelMasks) { - for (auto sampleRate : sampleRates) { - AudioConfig config{}; - config.base.channelMask = toString(channelMask); - config.base.sampleRateHz = sampleRate; - config.base.format = format; - configs.push_back(config); - } - } - return configs; -} - -static std::tuple, bool> generateOutFlags( - const xsd::MixPorts::MixPort& mixPort) { - static const std::vector offloadFlags = { - toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD), - toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)}; - std::vector flags; - bool isOffload = false; - if (mixPort.hasFlags()) { - auto xsdFlags = mixPort.getFlags(); - isOffload = std::find(xsdFlags.begin(), xsdFlags.end(), - xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != - xsdFlags.end(); - if (!isOffload) { - for (auto flag : xsdFlags) { - if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) { - flags.push_back(toString(flag)); - } - } - } else { - flags = offloadFlags; - } - } - return {flags, isOffload}; -} - -static AudioOffloadInfo generateOffloadInfo(const AudioConfigBase& base) { - return AudioOffloadInfo{ - .base = base, - .streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC), - .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA), - .bitRatePerSecond = 320, - .durationMicroseconds = -1, - .bitWidth = 16, - .bufferSize = 256 // arbitrary value - }; -} - -static std::vector generateOutputDeviceConfigParameters( - bool oneProfilePerDevice) { - std::vector result; - for (const auto& device : getDeviceParameters()) { - auto module = - getCachedPolicyConfig().getModuleFromName(std::get(device)); - if (!module || !module->getFirstMixPorts()) break; - for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) { - if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile - auto [flags, isOffload] = generateOutFlags(mixPort); - for (const auto& profile : mixPort.getProfile()) { - auto configs = combineAudioConfig(profile.getChannelMasks(), - profile.getSamplingRates(), profile.getFormat()); - for (auto& config : configs) { - // Some combinations of flags declared in the config file require special - // treatment. - if (isOffload) { - config.offloadInfo.info(generateOffloadInfo(config.base)); - } - result.emplace_back(device, config, flags); - if (oneProfilePerDevice) break; - } - if (oneProfilePerDevice) break; - } - if (oneProfilePerDevice) break; - } - } - return result; -} - -const std::vector& getOutputDeviceConfigParameters() { - static std::vector parameters = - generateOutputDeviceConfigParameters(false); - return parameters; -} - -const std::vector& getOutputDeviceSingleConfigParameters() { - static std::vector parameters = - generateOutputDeviceConfigParameters(true); - return parameters; -} - -const std::vector& getOutputDeviceInvalidConfigParameters( - bool generateInvalidFlags = true) { - static std::vector parameters = [&] { - std::vector result; - for (const auto& device : getDeviceParameters()) { - auto module = - getCachedPolicyConfig().getModuleFromName(std::get(device)); - if (!module || !module->getFirstMixPorts()) break; - bool hasRegularConfig = false, hasOffloadConfig = false; - for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) { - if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile - auto [validFlags, isOffload] = generateOutFlags(mixPort); - if ((!isOffload && hasRegularConfig) || (isOffload && hasOffloadConfig)) continue; - for (const auto& profile : mixPort.getProfile()) { - if (!profile.hasFormat() || !profile.hasSamplingRates() || - !profile.hasChannelMasks()) - continue; - AudioConfigBase validBase = { - profile.getFormat(), - static_cast(profile.getSamplingRates()[0]), - toString(profile.getChannelMasks()[0])}; - { - AudioConfig config{.base = validBase}; - config.base.channelMask = "random_string"; - if (isOffload) { - config.offloadInfo.info(generateOffloadInfo(validBase)); - } - result.emplace_back(device, config, validFlags); - } - { - AudioConfig config{.base = validBase}; - config.base.format = "random_string"; - if (isOffload) { - config.offloadInfo.info(generateOffloadInfo(validBase)); - } - result.emplace_back(device, config, validFlags); - } - if (generateInvalidFlags) { - AudioConfig config{.base = validBase}; - if (isOffload) { - config.offloadInfo.info(generateOffloadInfo(validBase)); - } - std::vector flags = {"random_string", ""}; - result.emplace_back(device, config, flags); - } - if (isOffload) { - { - AudioConfig config{.base = validBase}; - config.offloadInfo.info(generateOffloadInfo(validBase)); - config.offloadInfo.info().base.channelMask = "random_string"; - } - { - AudioConfig config{.base = validBase}; - config.offloadInfo.info(generateOffloadInfo(validBase)); - config.offloadInfo.info().base.format = "random_string"; - } - { - AudioConfig config{.base = validBase}; - config.offloadInfo.info(generateOffloadInfo(validBase)); - config.offloadInfo.info().streamType = "random_string"; - } - { - AudioConfig config{.base = validBase}; - config.offloadInfo.info(generateOffloadInfo(validBase)); - config.offloadInfo.info().usage = "random_string"; - } - hasOffloadConfig = true; - } else { - hasRegularConfig = true; - } - break; - } - if (hasOffloadConfig && hasRegularConfig) break; - } - } - return result; - }(); - return parameters; -} - -static std::vector generateInputDeviceConfigParameters( - bool oneProfilePerDevice) { - std::vector result; - for (const auto& device : getDeviceParameters()) { - auto module = - getCachedPolicyConfig().getModuleFromName(std::get(device)); - if (!module || !module->getFirstMixPorts()) break; - for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) { - if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile - std::vector flags; - if (mixPort.hasFlags()) { - std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(), - std::back_inserter(flags), [](auto flag) { return toString(flag); }); - } - for (const auto& profile : mixPort.getProfile()) { - auto configs = combineAudioConfig(profile.getChannelMasks(), - profile.getSamplingRates(), profile.getFormat()); - for (const auto& config : configs) { - result.emplace_back(device, config, flags); - if (oneProfilePerDevice) break; - } - if (oneProfilePerDevice) break; - } - if (oneProfilePerDevice) break; - } - } - return result; -} - -const std::vector& getInputDeviceConfigParameters() { - static std::vector parameters = - generateInputDeviceConfigParameters(false); - return parameters; -} - -const std::vector& getInputDeviceSingleConfigParameters() { - static std::vector parameters = - generateInputDeviceConfigParameters(true); - return parameters; -} - -const std::vector& getInputDeviceInvalidConfigParameters( - bool generateInvalidFlags = true) { - static std::vector parameters = [&] { - std::vector result; - for (const auto& device : getDeviceParameters()) { - auto module = - getCachedPolicyConfig().getModuleFromName(std::get(device)); - if (!module || !module->getFirstMixPorts()) break; - bool hasConfig = false; - for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) { - if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile - std::vector validFlags; - if (mixPort.hasFlags()) { - std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(), - std::back_inserter(validFlags), - [](auto flag) { return toString(flag); }); - } - for (const auto& profile : mixPort.getProfile()) { - if (!profile.hasFormat() || !profile.hasSamplingRates() || - !profile.hasChannelMasks()) - continue; - AudioConfigBase validBase = { - profile.getFormat(), - static_cast(profile.getSamplingRates()[0]), - toString(profile.getChannelMasks()[0])}; - { - AudioConfig config{.base = validBase}; - config.base.channelMask = "random_string"; - result.emplace_back(device, config, validFlags); - } - { - AudioConfig config{.base = validBase}; - config.base.format = "random_string"; - result.emplace_back(device, config, validFlags); - } - if (generateInvalidFlags) { - AudioConfig config{.base = validBase}; - std::vector flags = {"random_string", ""}; - result.emplace_back(device, config, flags); - } - hasConfig = true; - break; - } - if (hasConfig) break; - } - } - return result; - }(); - return parameters; -} - class InvalidInputConfigNoFlagsTest : public AudioHidlTestWithDeviceConfigParameter {}; TEST_P(InvalidInputConfigNoFlagsTest, InputBufferSizeTest) { doc::test("Verify that invalid config is rejected by IDevice::getInputBufferSize method."); diff --git a/audio/core/all-versions/vts/functional/7.0/Generators.cpp b/audio/core/all-versions/vts/functional/7.0/Generators.cpp new file mode 100644 index 0000000000..eafc813cf9 --- /dev/null +++ b/audio/core/all-versions/vts/functional/7.0/Generators.cpp @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2021 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. + */ + +#include + +#include "7.0/Generators.h" +#include "7.0/PolicyConfig.h" + +// clang-format off +#include PATH(android/hardware/audio/FILE_VERSION/types.h) +#include PATH(android/hardware/audio/common/FILE_VERSION/types.h) +// clang-format on + +#include +#include + +// Forward declaration for functions that are substituted +// in generator unit tests. +const PolicyConfig& getCachedPolicyConfig(); +const std::vector& getDeviceParameters(); + +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; +namespace xsd { +using namespace ::android::audio::policy::configuration::CPP_VERSION; +} + +static std::vector combineAudioConfig(std::vector channelMasks, + std::vector sampleRates, + const std::string& format) { + std::vector configs; + configs.reserve(channelMasks.size() * sampleRates.size()); + for (auto channelMask : channelMasks) { + for (auto sampleRate : sampleRates) { + AudioConfig config{}; + config.base.channelMask = toString(channelMask); + config.base.sampleRateHz = sampleRate; + config.base.format = format; + configs.push_back(config); + } + } + return configs; +} + +static std::tuple, bool> generateOutFlags( + const xsd::MixPorts::MixPort& mixPort) { + static const std::vector offloadFlags = { + toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD), + toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)}; + std::vector flags; + bool isOffload = false; + if (mixPort.hasFlags()) { + auto xsdFlags = mixPort.getFlags(); + isOffload = std::find(xsdFlags.begin(), xsdFlags.end(), + xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != + xsdFlags.end(); + if (!isOffload) { + for (auto flag : xsdFlags) { + if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) { + flags.push_back(toString(flag)); + } + } + } else { + flags = offloadFlags; + } + } + return {flags, isOffload}; +} + +static AudioOffloadInfo generateOffloadInfo(const AudioConfigBase& base) { + return AudioOffloadInfo{ + .base = base, + .streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC), + .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA), + .bitRatePerSecond = 320, + .durationMicroseconds = -1, + .bitWidth = 16, + .bufferSize = 256 // arbitrary value + }; +} + +std::vector generateOutputDeviceConfigParameters(bool oneProfilePerDevice) { + std::vector result; + for (const auto& device : getDeviceParameters()) { + auto module = + getCachedPolicyConfig().getModuleFromName(std::get(device)); + if (!module || !module->getFirstMixPorts()) break; + for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) { + if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile + auto [flags, isOffload] = generateOutFlags(mixPort); + for (const auto& profile : mixPort.getProfile()) { + auto configs = combineAudioConfig(profile.getChannelMasks(), + profile.getSamplingRates(), profile.getFormat()); + for (auto& config : configs) { + // Some combinations of flags declared in the config file require special + // treatment. + if (isOffload) { + config.offloadInfo.info(generateOffloadInfo(config.base)); + } + result.emplace_back(device, config, flags); + if (oneProfilePerDevice) break; + } + if (oneProfilePerDevice) break; + } + if (oneProfilePerDevice) break; + } + } + return result; +} + +const std::vector& getOutputDeviceConfigParameters() { + static std::vector parameters = + generateOutputDeviceConfigParameters(false); + return parameters; +} + +const std::vector& getOutputDeviceSingleConfigParameters() { + static std::vector parameters = + generateOutputDeviceConfigParameters(true); + return parameters; +} + +const std::vector& getOutputDeviceInvalidConfigParameters( + bool generateInvalidFlags) { + static std::vector parameters = [&] { + std::vector result; + for (const auto& device : getDeviceParameters()) { + auto module = + getCachedPolicyConfig().getModuleFromName(std::get(device)); + if (!module || !module->getFirstMixPorts()) break; + bool hasRegularConfig = false, hasOffloadConfig = false; + for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) { + if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile + auto [validFlags, isOffload] = generateOutFlags(mixPort); + if ((!isOffload && hasRegularConfig) || (isOffload && hasOffloadConfig)) continue; + for (const auto& profile : mixPort.getProfile()) { + if (!profile.hasFormat() || !profile.hasSamplingRates() || + !profile.hasChannelMasks()) + continue; + AudioConfigBase validBase = { + profile.getFormat(), + static_cast(profile.getSamplingRates()[0]), + toString(profile.getChannelMasks()[0])}; + { + AudioConfig config{.base = validBase}; + config.base.channelMask = "random_string"; + if (isOffload) { + config.offloadInfo.info(generateOffloadInfo(validBase)); + } + result.emplace_back(device, config, validFlags); + } + { + AudioConfig config{.base = validBase}; + config.base.format = "random_string"; + if (isOffload) { + config.offloadInfo.info(generateOffloadInfo(validBase)); + } + result.emplace_back(device, config, validFlags); + } + if (generateInvalidFlags) { + AudioConfig config{.base = validBase}; + if (isOffload) { + config.offloadInfo.info(generateOffloadInfo(validBase)); + } + std::vector flags = {"random_string", ""}; + result.emplace_back(device, config, flags); + } + if (isOffload) { + { + AudioConfig config{.base = validBase}; + config.offloadInfo.info(generateOffloadInfo(validBase)); + config.offloadInfo.info().base.channelMask = "random_string"; + result.emplace_back(device, config, validFlags); + } + { + AudioConfig config{.base = validBase}; + config.offloadInfo.info(generateOffloadInfo(validBase)); + config.offloadInfo.info().base.format = "random_string"; + result.emplace_back(device, config, validFlags); + } + { + AudioConfig config{.base = validBase}; + config.offloadInfo.info(generateOffloadInfo(validBase)); + config.offloadInfo.info().streamType = "random_string"; + result.emplace_back(device, config, validFlags); + } + { + AudioConfig config{.base = validBase}; + config.offloadInfo.info(generateOffloadInfo(validBase)); + config.offloadInfo.info().usage = "random_string"; + result.emplace_back(device, config, validFlags); + } + hasOffloadConfig = true; + } else { + hasRegularConfig = true; + } + break; + } + if (hasOffloadConfig && hasRegularConfig) break; + } + } + return result; + }(); + return parameters; +} + +std::vector generateInputDeviceConfigParameters(bool oneProfilePerDevice) { + std::vector result; + for (const auto& device : getDeviceParameters()) { + auto module = + getCachedPolicyConfig().getModuleFromName(std::get(device)); + if (!module || !module->getFirstMixPorts()) break; + for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) { + if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile + std::vector flags; + if (mixPort.hasFlags()) { + std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(), + std::back_inserter(flags), [](auto flag) { return toString(flag); }); + } + for (const auto& profile : mixPort.getProfile()) { + auto configs = combineAudioConfig(profile.getChannelMasks(), + profile.getSamplingRates(), profile.getFormat()); + for (const auto& config : configs) { + result.emplace_back(device, config, flags); + if (oneProfilePerDevice) break; + } + if (oneProfilePerDevice) break; + } + if (oneProfilePerDevice) break; + } + } + return result; +} + +const std::vector& getInputDeviceConfigParameters() { + static std::vector parameters = + generateInputDeviceConfigParameters(false); + return parameters; +} + +const std::vector& getInputDeviceSingleConfigParameters() { + static std::vector parameters = + generateInputDeviceConfigParameters(true); + return parameters; +} + +const std::vector& getInputDeviceInvalidConfigParameters( + bool generateInvalidFlags) { + static std::vector parameters = [&] { + std::vector result; + for (const auto& device : getDeviceParameters()) { + auto module = + getCachedPolicyConfig().getModuleFromName(std::get(device)); + if (!module || !module->getFirstMixPorts()) break; + bool hasConfig = false; + for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) { + if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile + std::vector validFlags; + if (mixPort.hasFlags()) { + std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(), + std::back_inserter(validFlags), + [](auto flag) { return toString(flag); }); + } + for (const auto& profile : mixPort.getProfile()) { + if (!profile.hasFormat() || !profile.hasSamplingRates() || + !profile.hasChannelMasks()) + continue; + AudioConfigBase validBase = { + profile.getFormat(), + static_cast(profile.getSamplingRates()[0]), + toString(profile.getChannelMasks()[0])}; + { + AudioConfig config{.base = validBase}; + config.base.channelMask = "random_string"; + result.emplace_back(device, config, validFlags); + } + { + AudioConfig config{.base = validBase}; + config.base.format = "random_string"; + result.emplace_back(device, config, validFlags); + } + if (generateInvalidFlags) { + AudioConfig config{.base = validBase}; + std::vector flags = {"random_string", ""}; + result.emplace_back(device, config, flags); + } + hasConfig = true; + break; + } + if (hasConfig) break; + } + } + return result; + }(); + return parameters; +} diff --git a/audio/core/all-versions/vts/functional/7.0/Generators.h b/audio/core/all-versions/vts/functional/7.0/Generators.h new file mode 100644 index 0000000000..e36cfad31b --- /dev/null +++ b/audio/core/all-versions/vts/functional/7.0/Generators.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 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. + */ + +#pragma once + +#include + +#include "AudioTestDefinitions.h" + +const std::vector& getOutputDeviceConfigParameters(); +const std::vector& getOutputDeviceSingleConfigParameters(); +const std::vector& getOutputDeviceInvalidConfigParameters( + bool generateInvalidFlags = true); +const std::vector& getInputDeviceConfigParameters(); +const std::vector& getInputDeviceSingleConfigParameters(); +const std::vector& getInputDeviceInvalidConfigParameters( + bool generateInvalidFlags = true); + +// For unit tests +std::vector generateOutputDeviceConfigParameters(bool oneProfilePerDevice); +std::vector generateInputDeviceConfigParameters(bool oneProfilePerDevice); diff --git a/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h b/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h index 7d8864284c..feb4d4b3aa 100644 --- a/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h +++ b/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h @@ -16,11 +16,35 @@ #pragma once -// Note: it is assumed that this file is included from AudioPrimaryHidlTest.h -// and thus it doesn't have all '#include' and 'using' directives required -// for a standalone compilation. +#include +#include +#include +#include +#include + +#include +#include +#include + +// clang-format off +#include PATH(android/hardware/audio/FILE_VERSION/types.h) +#include PATH(android/hardware/audio/common/FILE_VERSION/types.h) +// clang-format on + +#include +#include + +#include "DeviceManager.h" + +using ::android::NO_INIT; +using ::android::OK; +using ::android::status_t; + +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; namespace xsd { +using namespace ::android::audio::policy::configuration::CPP_VERSION; using Module = Modules::Module; } @@ -30,20 +54,13 @@ class PolicyConfig { : mConfigFileName{configFileName}, mFilePath{findExistingConfigurationFile(mConfigFileName)}, mConfig{xsd::read(mFilePath.c_str())} { - if (mConfig) { - mStatus = OK; - mPrimaryModule = getModuleFromName(DeviceManager::kPrimaryDevice); - if (mConfig->getFirstModules()) { - for (const auto& module : mConfig->getFirstModules()->get_module()) { - if (module.getFirstAttachedDevices()) { - auto attachedDevices = module.getFirstAttachedDevices()->getItem(); - if (!attachedDevices.empty()) { - mModulesWithDevicesNames.insert(module.getName()); - } - } - } - } - } + init(); + } + PolicyConfig(const std::string& configPath, const std::string& configFileName) + : mConfigFileName{configFileName}, + mFilePath{configPath + "/" + mConfigFileName}, + mConfig{xsd::read(mFilePath.c_str())} { + init(); } status_t getStatus() const { return mStatus; } std::string getError() const { @@ -87,6 +104,22 @@ class PolicyConfig { } return std::string{}; } + void init() { + if (mConfig) { + mStatus = OK; + mPrimaryModule = getModuleFromName(DeviceManager::kPrimaryDevice); + if (mConfig->getFirstModules()) { + for (const auto& module : mConfig->getFirstModules()->get_module()) { + if (module.getFirstAttachedDevices()) { + auto attachedDevices = module.getFirstAttachedDevices()->getItem(); + if (!attachedDevices.empty()) { + mModulesWithDevicesNames.insert(module.getName()); + } + } + } + } + } + } const std::string mConfigFileName; const std::string mFilePath; diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp index 4520dc3f8d..91c54dce35 100644 --- a/audio/core/all-versions/vts/functional/Android.bp +++ b/audio/core/all-versions/vts/functional/Android.bp @@ -126,6 +126,7 @@ cc_test { defaults: ["VtsHalAudioTargetTest_defaults"], srcs: [ "6.0/AudioPrimaryHidlHalTest.cpp", + "6.0/Generators.cpp", ], static_libs: [ "libaudiofoundation", @@ -152,6 +153,7 @@ cc_test { defaults: ["VtsHalAudioTargetTest_defaults"], srcs: [ "7.0/AudioPrimaryHidlHalTest.cpp", + "7.0/Generators.cpp", ], generated_headers: ["audio_policy_configuration_V7_0_parser"], generated_sources: ["audio_policy_configuration_V7_0_parser"], @@ -172,3 +174,57 @@ cc_test { // TODO(b/146104851): Add auto-gen rules and remove it. test_config: "VtsHalAudioV7_0TargetTest.xml", } + +// Note: the following aren't VTS tests, but rather unit tests +// to verify correctness of test parameter generator utilities. +cc_test { + name: "HalAudioV6_0GeneratorTest", + defaults: ["VtsHalAudioTargetTest_defaults"], + srcs: [ + "6.0/Generators.cpp", + "tests/generators_tests.cpp", + ], + static_libs: [ + "android.hardware.audio@6.0", + "android.hardware.audio.common@6.0", + "libaudiofoundation", + "libaudiopolicycomponents", + "libmedia_helper", + ], + cflags: [ + "-DMAJOR_VERSION=6", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], + data: [ + "tests/apm_config_no_vx.xml", + "tests/apm_config_with_vx.xml", + ], + test_config: "tests/HalAudioV6_0GeneratorTest.xml", +} + +cc_test { + name: "HalAudioV7_0GeneratorTest", + defaults: ["VtsHalAudioTargetTest_defaults"], + srcs: [ + "7.0/Generators.cpp", + "tests/generators_tests.cpp", + ], + generated_headers: ["audio_policy_configuration_V7_0_parser"], + generated_sources: ["audio_policy_configuration_V7_0_parser"], + static_libs: [ + "android.hardware.audio@7.0", + "android.hardware.audio.common@7.0", + "android.hardware.audio.common@7.0-enums", + ], + cflags: [ + "-DMAJOR_VERSION=7", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], + data: [ + "tests/apm_config_no_vx_7_0.xml", + "tests/apm_config_with_vx_7_0.xml", + ], + test_config: "tests/HalAudioV7_0GeneratorTest.xml", +} diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index 61e99e8699..56939fe6e6 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -59,6 +59,7 @@ #include "utility/ReturnIn.h" #include "utility/ValidateXml.h" +#include "AudioTestDefinitions.h" /** Provide version specific functions that are used in the generic tests */ #if MAJOR_VERSION == 2 #include "2.0/AudioPrimaryHidlHalUtils.h" @@ -107,7 +108,11 @@ static auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUP #include "DeviceManager.h" #if MAJOR_VERSION <= 6 #include "PolicyConfig.h" +#if MAJOR_VERSION == 6 +#include "6.0/Generators.h" +#endif #elif MAJOR_VERSION >= 7 +#include "7.0/Generators.h" #include "7.0/PolicyConfig.h" #endif @@ -175,9 +180,6 @@ TEST(CheckConfig, audioPolicyConfigurationValidation) { //////////////////// 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) { const auto& deviceName = std::get(info.param); @@ -509,24 +511,6 @@ INSTANTIATE_TEST_CASE_P(AudioPatchHidl, AudioPatchHidlTest, // list is empty, this isn't a problem. GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioPatchHidlTest); -// 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, PARAM_FLAGS }; -#if MAJOR_VERSION <= 6 -enum { INDEX_INPUT, INDEX_OUTPUT }; -using DeviceConfigParameter = - std::tuple>; -#elif MAJOR_VERSION >= 7 -using DeviceConfigParameter = std::tuple>; -#endif - -#if MAJOR_VERSION >= 6 -const std::vector& getInputDeviceConfigParameters(); -const std::vector& getInputDeviceSingleConfigParameters(); -const std::vector& getOutputDeviceConfigParameters(); -const std::vector& getOutputDeviceSingleConfigParameters(); -#endif - #if MAJOR_VERSION >= 4 static std::string SanitizeStringForGTestName(const std::string& s) { std::string result = s; diff --git a/audio/core/all-versions/vts/functional/AudioTestDefinitions.h b/audio/core/all-versions/vts/functional/AudioTestDefinitions.h new file mode 100644 index 0000000000..5b14a216c9 --- /dev/null +++ b/audio/core/all-versions/vts/functional/AudioTestDefinitions.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 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. + */ + +#pragma once + +#include +#include +#include +#include + +// clang-format off +#include PATH(android/hardware/audio/FILE_VERSION/types.h) +#include PATH(android/hardware/audio/common/FILE_VERSION/types.h) +// clang-format on + +enum { PARAM_FACTORY_NAME, PARAM_DEVICE_NAME }; +using DeviceParameter = std::tuple; + +// 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, PARAM_FLAGS }; +#if MAJOR_VERSION <= 6 +enum { INDEX_INPUT, INDEX_OUTPUT }; +using DeviceConfigParameter = + std::tuple>; +#elif MAJOR_VERSION >= 7 +using DeviceConfigParameter = + std::tuple>; +#endif diff --git a/audio/core/all-versions/vts/functional/ConfigHelper.h b/audio/core/all-versions/vts/functional/ConfigHelper.h index 1a1dbea939..a2bb1eecf0 100644 --- a/audio/core/all-versions/vts/functional/ConfigHelper.h +++ b/audio/core/all-versions/vts/functional/ConfigHelper.h @@ -16,10 +16,21 @@ #pragma once -// Code in this file uses 'getCachedPolicyConfig' -#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST -#error Must be included from AudioPrimaryHidlTest.h -#endif +#include + +#include "PolicyConfig.h" + +// clang-format off +#include PATH(android/hardware/audio/FILE_VERSION/types.h) +#include PATH(android/hardware/audio/common/FILE_VERSION/types.h) +// clang-format on + +using ::android::hardware::audio::common::utils::EnumBitfield; +using ::android::hardware::audio::common::utils::mkEnumBitfield; + +// Forward declaration for functions that are substituted +// in generator unit tests. +const PolicyConfig& getCachedPolicyConfig(); ////////////////////////////////////////////////////////////////////////////// //////////////// Required and recommended audio format support /////////////// @@ -35,7 +46,7 @@ struct ConfigHelper { // FIXME: in the next audio HAL version, test all available devices static bool primaryHasMic() { auto& policyConfig = getCachedPolicyConfig(); - if (policyConfig.getStatus() != OK || policyConfig.getPrimaryModule() == nullptr) { + if (policyConfig.getStatus() != android::OK || policyConfig.getPrimaryModule() == nullptr) { return true; // Could not get the information, run all tests } auto getMic = [](auto& devs) { diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h index 6efed7991e..6db78a77d6 100644 --- a/audio/core/all-versions/vts/functional/DeviceManager.h +++ b/audio/core/all-versions/vts/functional/DeviceManager.h @@ -16,9 +16,27 @@ #pragma once -// Note: it is assumed that this file is included from AudioPrimaryHidlTest.h -// and thus it doesn't have all '#include' and 'using' directives required -// for a standalone compilation. +#include + +#include + +#include +#include + +// clang-format off +#include PATH(android/hardware/audio/FILE_VERSION/IDevice.h) +#include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h) +#include PATH(android/hardware/audio/FILE_VERSION/IPrimaryDevice.h) +#include PATH(android/hardware/audio/FILE_VERSION/types.h) +#include PATH(android/hardware/audio/common/FILE_VERSION/types.h) +// clang-format on + +#include "utility/ReturnIn.h" + +using ::android::sp; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::common::test::utility; +using namespace ::android::hardware::audio::CPP_VERSION; template class InterfaceManager { @@ -56,7 +74,7 @@ class InterfaceManager { // 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(); + ::android::hardware::IPCThreadState::self()->flushCommands(); usleep(100 * 1000); } diff --git a/audio/core/all-versions/vts/functional/PolicyConfig.h b/audio/core/all-versions/vts/functional/PolicyConfig.h index c9e0c0dd5a..a94041c427 100644 --- a/audio/core/all-versions/vts/functional/PolicyConfig.h +++ b/audio/core/all-versions/vts/functional/PolicyConfig.h @@ -16,11 +16,19 @@ #pragma once -// Note: it is assumed that this file is included from AudioPrimaryHidlTest.h -// and thus it doesn't have all '#include' and 'using' directives required -// for a standalone compilation. +#include +#include +#include +#include #include +#include +#include + +#include "DeviceManager.h" + +using ::android::sp; +using ::android::status_t; struct PolicyConfigData { android::HwModuleCollection hwModules; @@ -42,28 +50,14 @@ class PolicyConfig : private PolicyConfigData, public android::AudioPolicyConfig break; } } - mStatus = android::deserializeAudioPolicyFile(mFilePath.c_str(), this); - if (mStatus == OK) { - mPrimaryModule = 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; - } - } - } - } + init(); + } + PolicyConfig(const std::string& configPath, const std::string& configFileName) + : android::AudioPolicyConfig(hwModules, availableOutputDevices, availableInputDevices, + defaultOutputDevice), + mConfigFileName{configFileName}, + mFilePath{configPath + "/" + mConfigFileName} { + init(); } status_t getStatus() const { return mStatus; } std::string getError() const { @@ -88,8 +82,33 @@ class PolicyConfig : private PolicyConfigData, public android::AudioPolicyConfig } private: + void init() { + mStatus = android::deserializeAudioPolicyFileForVts(mFilePath.c_str(), this); + if (mStatus == android::OK) { + mPrimaryModule = 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; + } + } + } + } + } + const std::string mConfigFileName; - status_t mStatus = NO_INIT; + status_t mStatus = android::NO_INIT; std::string mFilePath; sp mPrimaryModule = nullptr; std::set mModulesWithDevicesNames; diff --git a/audio/core/all-versions/vts/functional/tests/HalAudioV6_0GeneratorTest.xml b/audio/core/all-versions/vts/functional/tests/HalAudioV6_0GeneratorTest.xml new file mode 100644 index 0000000000..0c85a05838 --- /dev/null +++ b/audio/core/all-versions/vts/functional/tests/HalAudioV6_0GeneratorTest.xml @@ -0,0 +1,34 @@ + + + + diff --git a/audio/core/all-versions/vts/functional/tests/HalAudioV7_0GeneratorTest.xml b/audio/core/all-versions/vts/functional/tests/HalAudioV7_0GeneratorTest.xml new file mode 100644 index 0000000000..2e794554c8 --- /dev/null +++ b/audio/core/all-versions/vts/functional/tests/HalAudioV7_0GeneratorTest.xml @@ -0,0 +1,34 @@ + + + + diff --git a/audio/core/all-versions/vts/functional/tests/apm_config_no_vx.xml b/audio/core/all-versions/vts/functional/tests/apm_config_no_vx.xml new file mode 100644 index 0000000000..61972b26d5 --- /dev/null +++ b/audio/core/all-versions/vts/functional/tests/apm_config_no_vx.xml @@ -0,0 +1,68 @@ + + + + + + + + + Speaker + Built-In Mic + + Speaker + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/audio/core/all-versions/vts/functional/tests/apm_config_no_vx_7_0.xml b/audio/core/all-versions/vts/functional/tests/apm_config_no_vx_7_0.xml new file mode 100644 index 0000000000..abcdb1274c --- /dev/null +++ b/audio/core/all-versions/vts/functional/tests/apm_config_no_vx_7_0.xml @@ -0,0 +1,68 @@ + + + + + + + + + Speaker + Built-In Mic + + Speaker + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/audio/core/all-versions/vts/functional/tests/apm_config_with_vx.xml b/audio/core/all-versions/vts/functional/tests/apm_config_with_vx.xml new file mode 100644 index 0000000000..aabb52e68c --- /dev/null +++ b/audio/core/all-versions/vts/functional/tests/apm_config_with_vx.xml @@ -0,0 +1,81 @@ + + + + + + + + + Speaker + Built-In Mic + + Speaker + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/audio/core/all-versions/vts/functional/tests/apm_config_with_vx_7_0.xml b/audio/core/all-versions/vts/functional/tests/apm_config_with_vx_7_0.xml new file mode 100644 index 0000000000..8dd5f45db6 --- /dev/null +++ b/audio/core/all-versions/vts/functional/tests/apm_config_with_vx_7_0.xml @@ -0,0 +1,81 @@ + + + + + + + + + Speaker + Built-In Mic + + Speaker + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/audio/core/all-versions/vts/functional/tests/generators_tests.cpp b/audio/core/all-versions/vts/functional/tests/generators_tests.cpp new file mode 100644 index 0000000000..583ff01fc2 --- /dev/null +++ b/audio/core/all-versions/vts/functional/tests/generators_tests.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2021 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. + */ + +#include +#include +#include + +#include +#include +#define LOG_TAG "Generators_Test" +#include + +#if MAJOR_VERSION == 6 +#include +#include "6.0/Generators.h" +#include "PolicyConfig.h" +#elif MAJOR_VERSION == 7 +#include "7.0/Generators.h" +#include "7.0/PolicyConfig.h" +#endif + +using namespace android; +using namespace ::android::hardware::audio::common::CPP_VERSION; +#if MAJOR_VERSION == 7 +namespace xsd { +using namespace ::android::audio::policy::configuration::CPP_VERSION; +} +#endif + +// Stringify the argument. +#define QUOTE(x) #x +#define STRINGIFY(x) QUOTE(x) + +struct PolicyConfigManager { + static PolicyConfigManager& getInstance() { + static PolicyConfigManager instance; + return instance; + } + bool init(const std::string& filePath, const std::string& fileName) { + mConfig = std::make_unique(filePath, fileName); + mDeviceParameters.clear(); + if (mConfig->getStatus() == OK) { + const auto devices = mConfig->getModulesWithDevicesNames(); + mDeviceParameters.reserve(devices.size()); + for (const auto& deviceName : devices) { + mDeviceParameters.emplace_back( + "android.hardware.audio.IDevicesFactory@" STRINGIFY(FILE_VERSION), + deviceName); + } + return true; + } else { + ALOGE("%s", mConfig->getError().c_str()); + return false; + } + } + const PolicyConfig& getConfig() { return *mConfig; } + const std::vector& getDeviceParameters() { return mDeviceParameters; } + + private: + std::unique_ptr mConfig; + std::vector mDeviceParameters; +}; + +// Test implementations +const PolicyConfig& getCachedPolicyConfig() { + return PolicyConfigManager::getInstance().getConfig(); +} + +const std::vector& getDeviceParameters() { + return PolicyConfigManager::getInstance().getDeviceParameters(); +} + +static const std::string kDataDir = "/data/local/tmp"; + +class GeneratorsTest : public ::testing::TestWithParam { + public: + static void validateConfig(const AudioConfig& config) { +#if MAJOR_VERSION == 6 + ASSERT_TRUE(audio_is_valid_format(static_cast(config.format))) + << "Audio format is invalid " << ::testing::PrintToString(config.format); + ASSERT_TRUE( + audio_channel_mask_is_valid(static_cast(config.channelMask))) + << "Audio channel mask is invalid " << ::testing::PrintToString(config.channelMask); +#elif MAJOR_VERSION == 7 + ASSERT_FALSE(xsd::isUnknownAudioFormat(config.base.format)) + << "Audio format is invalid " << ::testing::PrintToString(config.base.format); + ASSERT_FALSE(xsd::isUnknownAudioChannelMask(config.base.channelMask)) + << "Audio channel mask is invalid " + << ::testing::PrintToString(config.base.channelMask); +#endif + } + static void validateDeviceConfigs(const std::vector& params) { + for (const auto& param : params) { + ASSERT_NO_FATAL_FAILURE(validateConfig(std::get(param))); + } + } +}; + +TEST_P(GeneratorsTest, ValidateConfigs) { + ASSERT_TRUE(PolicyConfigManager::getInstance().init(kDataDir, GetParam())); + EXPECT_NE(nullptr, getCachedPolicyConfig().getPrimaryModule()); + EXPECT_FALSE(getCachedPolicyConfig().getModulesWithDevicesNames().empty()); + const auto allOutConfigs = generateOutputDeviceConfigParameters(false /*oneProfilePerDevice*/); + EXPECT_FALSE(allOutConfigs.empty()); + EXPECT_NO_FATAL_FAILURE(validateDeviceConfigs(allOutConfigs)); + const auto singleOutConfig = generateOutputDeviceConfigParameters(true /*oneProfilePerDevice*/); + EXPECT_FALSE(singleOutConfig.empty()); + EXPECT_NO_FATAL_FAILURE(validateDeviceConfigs(singleOutConfig)); + const auto allInConfigs = generateInputDeviceConfigParameters(false /*oneProfilePerDevice*/); + EXPECT_FALSE(allInConfigs.empty()); + EXPECT_NO_FATAL_FAILURE(validateDeviceConfigs(allInConfigs)); + const auto singleInConfig = generateInputDeviceConfigParameters(true /*oneProfilePerDevice*/); + EXPECT_FALSE(singleInConfig.empty()); + EXPECT_NO_FATAL_FAILURE(validateDeviceConfigs(singleInConfig)); +} + +// Target file names are the same for all versions, see 'HalAudioVx_0GeneratorTest.xml' test configs +INSTANTIATE_TEST_SUITE_P(Generators, GeneratorsTest, + ::testing::Values("apm_config_no_vx.xml", "apm_config_with_vx.xml"));