diff options
author | Mikhail Naganov <mnaganov@google.com> | 2020-12-17 15:01:54 -0800 |
---|---|---|
committer | Mikhail Naganov <mnaganov@google.com> | 2021-01-07 10:32:06 -0800 |
commit | 3f1457b9537b1ff23704e17be7588dadf1e2884e (patch) | |
tree | 82878ed14f6c3b93734a211ffbaa75c5fd0aad32 /audio | |
parent | daedb0dc2e582d6db90793045759a7acef6f1096 (diff) | |
download | platform_hardware_interfaces-3f1457b9537b1ff23704e17be7588dadf1e2884e.tar.gz platform_hardware_interfaces-3f1457b9537b1ff23704e17be7588dadf1e2884e.tar.bz2 platform_hardware_interfaces-3f1457b9537b1ff23704e17be7588dadf1e2884e.zip |
Audio: Add VTS tests for invalid enum-strings, Part 1
Add tests that try passing invalid enum-string values to HAL
methods taking enum-strings. Fix issues found in the default
wrapper.
Interface updates:
- Update AudioConfig structure to indicate whether
AudioOffloadInfo is specified.
- Add return value to IStreamIn.updateSinkMetadata
and IStreamOut.updateSourceMetadata to provide indication
of invalid arguments.
- Specify the behavior of IDevice.open{Input|Output}Stream
in the case of invalid arguments vs. rejected config.
Bug: 142480271
Test: atest VtsHalAudioV6_0TargetTest
Test: atest VtsHalAudioV7_0TargetTest
with side-loaded V7 default wrapper
Change-Id: I6bd7be3869cc7a8d5d00506565bbf0b3a050b630
Diffstat (limited to 'audio')
22 files changed, 991 insertions, 325 deletions
diff --git a/audio/7.0/IDevice.hal b/audio/7.0/IDevice.hal index e30e5456bc..d9e0ad205f 100644 --- a/audio/7.0/IDevice.hal +++ b/audio/7.0/IDevice.hal @@ -103,6 +103,11 @@ interface IDevice { * If the stream can not be opened with the proposed audio config, * HAL must provide suggested values for the audio config. * + * Note: INVALID_ARGUMENTS is returned both in the case when the + * HAL can not use the provided config and in the case when + * the value of any argument is invalid. In the latter case the + * HAL must provide a default initialized suggested config. + * * @param ioHandle handle assigned by AudioFlinger. * @param device device type and (if needed) address. * @param config stream configuration. @@ -111,7 +116,8 @@ interface IDevice { May be used by implementations to configure hardware effects. * @return retval operation completion status. * @return outStream created output stream. - * @return suggestedConfig in case of invalid parameters, suggested config. + * @return suggestedConfig in the case of rejection of the proposed config, + * a config suggested by the HAL. */ openOutputStream( AudioIoHandle ioHandle, @@ -128,6 +134,11 @@ interface IDevice { * If the stream can not be opened with the proposed audio config, * HAL must provide suggested values for the audio config. * + * Note: INVALID_ARGUMENTS is returned both in the case when the + * HAL can not use the provided config and in the case when + * the value of any argument is invalid. In the latter case the + * HAL must provide a default initialized suggested config. + * * @param ioHandle handle assigned by AudioFlinger. * @param device device type and (if needed) address. * @param config stream configuration. @@ -136,7 +147,8 @@ interface IDevice { * May be used by implementations to configure processing effects. * @return retval operation completion status. * @return inStream in case of success, created input stream. - * @return suggestedConfig in case of invalid parameters, suggested config. + * @return suggestedConfig in the case of rejection of the proposed config, + * a config suggested by the HAL. */ openInputStream( AudioIoHandle ioHandle, diff --git a/audio/7.0/IStreamIn.hal b/audio/7.0/IStreamIn.hal index 0a3f24b840..bf9ae52923 100644 --- a/audio/7.0/IStreamIn.hal +++ b/audio/7.0/IStreamIn.hal @@ -41,6 +41,18 @@ interface IStreamIn extends IStream { setGain(float gain) generates (Result retval); /** + * Called when the metadata of the stream's sink has been changed. + * Optional method + * + * @param sinkMetadata Description of the audio that is suggested by the clients. + * @return retval operation completion status. + * If any of the metadata fields contains an invalid value, + * returns INVALID_ARGUMENTS. + * If method isn't supported by the HAL returns NOT_SUPPORTED. + */ + updateSinkMetadata(SinkMetadata sinkMetadata) generates (Result retval); + + /** * Commands that can be executed on the driver reader thread. */ enum ReadCommand : int32_t { @@ -82,12 +94,6 @@ interface IStreamIn extends IStream { }; /** - * Called when the metadata of the stream's sink has been changed. - * @param sinkMetadata Description of the audio that is suggested by the clients. - */ - updateSinkMetadata(SinkMetadata sinkMetadata); - - /** * Set up required transports for receiving audio buffers from the driver. * * The transport consists of three message queues: diff --git a/audio/7.0/IStreamOut.hal b/audio/7.0/IStreamOut.hal index 38d750f76b..4daab26571 100644 --- a/audio/7.0/IStreamOut.hal +++ b/audio/7.0/IStreamOut.hal @@ -45,6 +45,18 @@ interface IStreamOut extends IStream { setVolume(float left, float right) generates (Result retval); /** + * Called when the metadata of the stream's source has been changed. + * Optional method + * + * @param sourceMetadata Description of the audio that is played by the clients. + * @return retval operation completion status. + * If any of the metadata fields contains an invalid value, + * returns INVALID_ARGUMENTS. + * If method isn't supported by the HAL returns NOT_SUPPORTED. + */ + updateSourceMetadata(SourceMetadata sourceMetadata) generates (Result retval); + + /** * Commands that can be executed on the driver writer thread. */ enum WriteCommand : int32_t { @@ -77,12 +89,6 @@ interface IStreamOut extends IStream { }; /** - * Called when the metadata of the stream's source has been changed. - * @param sourceMetadata Description of the audio that is played by the clients. - */ - updateSourceMetadata(SourceMetadata sourceMetadata); - - /** * Set up required transports for passing audio buffers to the driver. * * The transport consists of three message queues: diff --git a/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h b/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h index b7c1cc97bc..c0042db0ba 100644 --- a/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h +++ b/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h @@ -212,12 +212,11 @@ static inline bool isOutputDevice(const std::string& device) { return isOutputDevice(stringToAudioDevice(device)); } -static inline bool isVendorExtension(const std::string& device) { +static inline bool isVendorExtension(const std::string& s) { // Must match the "vendorExtension" rule from the XSD file. static const std::string vendorPrefix = "VX_"; - return device.size() > vendorPrefix.size() && - device.substr(0, vendorPrefix.size()) == vendorPrefix && - std::all_of(device.begin() + vendorPrefix.size(), device.end(), + return s.size() > vendorPrefix.size() && s.substr(0, vendorPrefix.size()) == vendorPrefix && + std::all_of(s.begin() + vendorPrefix.size(), s.end(), [](unsigned char c) { return c == '_' || std::isalnum(c); }); } diff --git a/audio/common/7.0/types.hal b/audio/common/7.0/types.hal index b14ebd48d9..ed6d94f988 100644 --- a/audio/common/7.0/types.hal +++ b/audio/common/7.0/types.hal @@ -270,7 +270,10 @@ struct AudioOffloadInfo { */ struct AudioConfig { AudioConfigBase base; - AudioOffloadInfo offloadInfo; + safe_union OffloadInfo { + Monostate unspecified; + AudioOffloadInfo info; + } offloadInfo; uint64_t frameCount; }; @@ -278,7 +281,8 @@ struct AudioConfig { * AudioTag is an additional use case qualifier complementing * AudioUsage and AudioContentType. Tags are set by vendor specific applications * and must be prefixed by "VX_". Vendor must namespace their tag - * names to avoid conflicts. + * names to avoid conflicts. See 'vendorExtension' in audio_policy_configuration.xsd + * for a formal definition. */ typedef string AudioTag; diff --git a/audio/common/all-versions/default/7.0/HidlUtils.cpp b/audio/common/all-versions/default/7.0/HidlUtils.cpp index c985a7027a..de19faf153 100644 --- a/audio/common/all-versions/default/7.0/HidlUtils.cpp +++ b/audio/common/all-versions/default/7.0/HidlUtils.cpp @@ -21,6 +21,7 @@ #include <log/log.h> #include <android_audio_policy_configuration_V7_0-enums.h> +#include <common/all-versions/HidlSupport.h> #include <common/all-versions/VersionUtils.h> #include "HidlUtils.h" @@ -306,7 +307,12 @@ status_t HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, bool isI audio_config_base_t halConfigBase = {halConfig.sample_rate, halConfig.channel_mask, halConfig.format}; CONVERT_CHECKED(audioConfigBaseFromHal(halConfigBase, isInput, &config->base), result); - CONVERT_CHECKED(audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo), result); + if (halConfig.offload_info.sample_rate != 0) { + config->offloadInfo.info({}); + CONVERT_CHECKED( + audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo.info()), + result); + } config->frameCount = halConfig.frame_count; return result; } @@ -319,7 +325,11 @@ status_t HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig->sample_rate = halConfigBase.sample_rate; halConfig->channel_mask = halConfigBase.channel_mask; halConfig->format = halConfigBase.format; - CONVERT_CHECKED(audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info), result); + if (config.offloadInfo.getDiscriminator() == + AudioConfig::OffloadInfo::hidl_discriminator::info) { + CONVERT_CHECKED(audioOffloadInfoToHal(config.offloadInfo.info(), &halConfig->offload_info), + result); + } halConfig->frame_count = config.frameCount; return result; } @@ -800,6 +810,47 @@ status_t HidlUtils::audioProfileToHal(const AudioProfile& profile, return result; } +status_t HidlUtils::audioTagsFromHal(const char* halTags, hidl_vec<AudioTag>* tags) { + std::vector<std::string> strTags = utils::splitString(halTags, sAudioTagSeparator); + status_t result = NO_ERROR; + tags->resize(strTags.size()); + size_t to = 0; + for (size_t from = 0; from < strTags.size(); ++from) { + if (xsd::isVendorExtension(strTags[from])) { + (*tags)[to++] = strTags[from]; + } else { + result = BAD_VALUE; + } + } + if (to != strTags.size()) { + tags->resize(to); + } + return result; +} + +status_t HidlUtils::audioTagsToHal(const hidl_vec<AudioTag>& tags, char* halTags) { + memset(halTags, 0, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE); + status_t result = NO_ERROR; + std::ostringstream halTagsBuffer; + bool hasValue = false; + for (const auto& tag : tags) { + if (hasValue) { + halTagsBuffer << sAudioTagSeparator; + } + if (xsd::isVendorExtension(tag) && strchr(tag.c_str(), sAudioTagSeparator) == nullptr) { + halTagsBuffer << tag; + hasValue = true; + } else { + result = BAD_VALUE; + } + } + std::string fullHalTags{std::move(halTagsBuffer.str())}; + strncpy(halTags, fullHalTags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE); + CONVERT_CHECKED(fullHalTags.length() <= AUDIO_ATTRIBUTES_TAGS_MAX_SIZE ? NO_ERROR : BAD_VALUE, + result); + return result; +} + status_t HidlUtils::deviceAddressFromHal(audio_devices_t halDeviceType, const char* halDeviceAddress, DeviceAddress* device) { status_t result = NO_ERROR; diff --git a/audio/common/all-versions/default/HidlUtils.h b/audio/common/all-versions/default/HidlUtils.h index d8b7ba419e..8e9275c441 100644 --- a/audio/common/all-versions/default/HidlUtils.h +++ b/audio/common/all-versions/default/HidlUtils.h @@ -109,6 +109,8 @@ struct HidlUtils { AudioStreamType* streamType); static status_t audioStreamTypeToHal(const AudioStreamType& streamType, audio_stream_type_t* halStreamType); + static status_t audioTagsFromHal(const char* halTags, hidl_vec<AudioTag>* tags); + static status_t audioTagsToHal(const hidl_vec<AudioTag>& tags, char* halTags); private: static status_t audioIndexChannelMaskFromHal(audio_channel_mask_t halChannelMask, diff --git a/audio/common/all-versions/default/tests/hidlutils_tests.cpp b/audio/common/all-versions/default/tests/hidlutils_tests.cpp index 22571c0411..fef88b450b 100644 --- a/audio/common/all-versions/default/tests/hidlutils_tests.cpp +++ b/audio/common/all-versions/default/tests/hidlutils_tests.cpp @@ -589,16 +589,29 @@ TEST(HidlUtils, ConvertConfig) { config.base.sampleRateHz = 44100; config.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO); config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT); - config.offloadInfo.base = config.base; - config.offloadInfo.streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC); - config.offloadInfo.bitRatePerSecond = 320; - config.offloadInfo.durationMicroseconds = -1; - config.offloadInfo.bitWidth = 16; - config.offloadInfo.bufferSize = 1024; - config.offloadInfo.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA); - config.offloadInfo.encapsulationMode = AudioEncapsulationMode::ELEMENTARY_STREAM; - config.offloadInfo.contentId = 42; - config.offloadInfo.syncId = 13; + audio_config_t halConfig; + EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigToHal(config, &halConfig)); + AudioConfig configBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigFromHal(halConfig, false /*isInput*/, &configBack)); + EXPECT_EQ(config, configBack); +} + +TEST(HidlUtils, ConvertConfigWithOffloadInfo) { + AudioConfig config = {}; + config.base.sampleRateHz = 44100; + config.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO); + config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT); + config.offloadInfo.info( + AudioOffloadInfo{.base = config.base, + .streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC), + .bitRatePerSecond = 320, + .durationMicroseconds = -1, + .bitWidth = 16, + .bufferSize = 1024, + .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA), + .encapsulationMode = AudioEncapsulationMode::ELEMENTARY_STREAM, + .contentId = 42, + .syncId = 13}); audio_config_t halConfig; EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigToHal(config, &halConfig)); AudioConfig configBack; @@ -707,3 +720,43 @@ TEST(HidlUtils, ConvertAudioPort) { EXPECT_EQ(NO_ERROR, HidlUtils::audioPortToHal(portBack, &halPortBack)); EXPECT_TRUE(audio_ports_v7_are_equal(&halPort, &halPortBack)); } + +TEST(HidlUtils, ConvertInvalidAudioTags) { + char halTag[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {}; + + hidl_vec<AudioTag> emptyTag = {{""}}; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioTagsToHal(emptyTag, halTag)); + + hidl_vec<AudioTag> longTag = {{std::string(AUDIO_ATTRIBUTES_TAGS_MAX_SIZE + 1, 'A')}}; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioTagsToHal(longTag, halTag)); + + hidl_vec<AudioTag> tagSeparator = { + {std::string(AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1, HidlUtils::sAudioTagSeparator)}}; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioTagsToHal(tagSeparator, halTag)); + + hidl_vec<AudioTag> notExtensions = {{"random string", "VX_", "VX_GOOGLE_$$"}}; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioTagsToHal(notExtensions, halTag)); +} + +TEST(HidlUtils, ConvertAudioTags) { + hidl_vec<AudioTag> emptyTags; + char halEmptyTags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {}; + EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsToHal(emptyTags, halEmptyTags)); + hidl_vec<AudioTag> emptyTagsBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsFromHal(halEmptyTags, &emptyTagsBack)); + EXPECT_EQ(emptyTags, emptyTagsBack); + + hidl_vec<AudioTag> oneTag = {{"VX_GOOGLE_VR"}}; + char halOneTag[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {}; + EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsToHal(oneTag, halOneTag)); + hidl_vec<AudioTag> oneTagBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsFromHal(halOneTag, &oneTagBack)); + EXPECT_EQ(oneTag, oneTagBack); + + hidl_vec<AudioTag> twoTags = {{"VX_GOOGLE_VR_42", "VX_GOOGLE_1E100"}}; + char halTwoTags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {}; + EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsToHal(twoTags, halTwoTags)); + hidl_vec<AudioTag> twoTagsBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsFromHal(halTwoTags, &twoTagsBack)); + EXPECT_EQ(twoTags, twoTagsBack); +} diff --git a/audio/common/all-versions/util/include/common/all-versions/HidlSupport.h b/audio/common/all-versions/util/include/common/all-versions/HidlSupport.h index b514a43a85..d7802cf683 100644 --- a/audio/common/all-versions/util/include/common/all-versions/HidlSupport.h +++ b/audio/common/all-versions/util/include/common/all-versions/HidlSupport.h @@ -20,6 +20,9 @@ #include <hidl/HidlSupport.h> #include <algorithm> +#include <sstream> +#include <string> +#include <vector> namespace android::hardware::audio::common::utils { @@ -29,6 +32,16 @@ bool isValidHidlEnum(Enum e) { return std::find(values.begin(), values.end(), e) != values.end(); } +static inline std::vector<std::string> splitString(const std::string& s, char separator) { + std::istringstream iss(s); + std::string t; + std::vector<std::string> result; + while (std::getline(iss, t, separator)) { + result.push_back(std::move(t)); + } + return result; +} + } // namespace android::hardware::audio::common::utils #endif // android_hardware_audio_common_HidlSupport_H_ diff --git a/audio/core/all-versions/default/Conversions.cpp b/audio/core/all-versions/default/Conversions.cpp index 8e0a140f0b..f1752ccba3 100644 --- a/audio/core/all-versions/default/Conversions.cpp +++ b/audio/core/all-versions/default/Conversions.cpp @@ -32,14 +32,10 @@ namespace implementation { using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils; -#if MAJOR_VERSION <= 6 -std::string deviceAddressToHal(const DeviceAddress& address) { - audio_devices_t halDevice; - char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; - (void)deviceAddressToHal(address, &halDevice, halAddress); - return halAddress; -} -#endif +#define CONVERT_CHECKED(expr, result) \ + if (status_t status = (expr); status != NO_ERROR) { \ + result = status; \ + } status_t deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType, char* halDeviceAddress) { @@ -97,6 +93,52 @@ bool halToMicrophoneCharacteristics(MicrophoneInfo* pDst, } return status; } + +status_t sinkMetadataToHal(const SinkMetadata& sinkMetadata, + std::vector<record_track_metadata>* halTracks) { + status_t result = NO_ERROR; + if (halTracks != nullptr) { + halTracks->reserve(sinkMetadata.tracks.size()); + } + for (auto& metadata : sinkMetadata.tracks) { + record_track_metadata halTrackMetadata{.gain = metadata.gain}; + CONVERT_CHECKED(HidlUtils::audioSourceToHal(metadata.source, &halTrackMetadata.source), + result); +#if MAJOR_VERSION >= 5 + if (metadata.destination.getDiscriminator() == + RecordTrackMetadata::Destination::hidl_discriminator::device) { + CONVERT_CHECKED( + deviceAddressToHal(metadata.destination.device(), &halTrackMetadata.dest_device, + halTrackMetadata.dest_device_address), + result); + } +#endif + if (halTracks != nullptr) { + halTracks->push_back(std::move(halTrackMetadata)); + } + } + return result; +} + +status_t sourceMetadataToHal(const SourceMetadata& sourceMetadata, + std::vector<playback_track_metadata_t>* halTracks) { + status_t result = NO_ERROR; + if (halTracks != nullptr) { + halTracks->reserve(sourceMetadata.tracks.size()); + } + for (auto& metadata : sourceMetadata.tracks) { + playback_track_metadata_t halTrackMetadata{.gain = metadata.gain}; + CONVERT_CHECKED(HidlUtils::audioUsageToHal(metadata.usage, &halTrackMetadata.usage), + result); + CONVERT_CHECKED(HidlUtils::audioContentTypeToHal(metadata.contentType, + &halTrackMetadata.content_type), + result); + if (halTracks != nullptr) { + halTracks->push_back(std::move(halTrackMetadata)); + } + } + return result; +} #endif // MAJOR_VERSION >= 4 #if MAJOR_VERSION >= 7 @@ -135,6 +177,50 @@ bool audioOutputFlagsToHal(const hidl_vec<AudioInOutFlag>& flags, audio_output_f } return success; } + +status_t sinkMetadataToHalV7(const SinkMetadata& sinkMetadata, + std::vector<record_track_metadata_v7_t>* halTracks) { + std::vector<record_track_metadata> bases; + status_t result = sinkMetadataToHal(sinkMetadata, halTracks != nullptr ? &bases : nullptr); + if (halTracks != nullptr) { + halTracks->reserve(bases.size()); + } + auto baseIter = std::make_move_iterator(bases.begin()); + for (auto& metadata : sinkMetadata.tracks) { + record_track_metadata_v7_t halTrackMetadata; + CONVERT_CHECKED(HidlUtils::audioChannelMaskToHal(metadata.channelMask, + &halTrackMetadata.channel_mask), + result); + CONVERT_CHECKED(HidlUtils::audioTagsToHal(metadata.tags, halTrackMetadata.tags), result); + if (halTracks != nullptr) { + halTrackMetadata.base = std::move(*baseIter++); + halTracks->push_back(std::move(halTrackMetadata)); + } + } + return result; +} + +status_t sourceMetadataToHalV7(const SourceMetadata& sourceMetadata, + std::vector<playback_track_metadata_v7_t>* halTracks) { + std::vector<playback_track_metadata_t> bases; + status_t result = sourceMetadataToHal(sourceMetadata, halTracks != nullptr ? &bases : nullptr); + if (halTracks != nullptr) { + halTracks->reserve(bases.size()); + } + auto baseIter = std::make_move_iterator(bases.begin()); + for (auto& metadata : sourceMetadata.tracks) { + playback_track_metadata_v7_t halTrackMetadata; + CONVERT_CHECKED(HidlUtils::audioChannelMaskToHal(metadata.channelMask, + &halTrackMetadata.channel_mask), + result); + CONVERT_CHECKED(HidlUtils::audioTagsToHal(metadata.tags, halTrackMetadata.tags), result); + if (halTracks != nullptr) { + halTrackMetadata.base = std::move(*baseIter++); + halTracks->push_back(std::move(halTrackMetadata)); + } + } + return result; +} #endif } // namespace implementation diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp index bb69f0b88d..05c1066ba9 100644 --- a/audio/core/all-versions/default/Device.cpp +++ b/audio/core/all-versions/default/Device.cpp @@ -135,13 +135,14 @@ Return<void> Device::getMasterMute(getMasterMute_cb _hidl_cb) { Return<void> Device::getInputBufferSize(const AudioConfig& config, getInputBufferSize_cb _hidl_cb) { audio_config_t halConfig; - HidlUtils::audioConfigToHal(config, &halConfig); - size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig); Result retval(Result::INVALID_ARGUMENTS); uint64_t bufferSize = 0; - if (halBufferSize != 0) { - retval = Result::OK; - bufferSize = halBufferSize; + if (HidlUtils::audioConfigToHal(config, &halConfig) == NO_ERROR) { + size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig); + if (halBufferSize != 0) { + retval = Result::OK; + bufferSize = halBufferSize; + } } _hidl_cb(retval, bufferSize); return Void(); @@ -153,7 +154,9 @@ std::tuple<Result, sp<IStreamOut>> Device::openOutputStreamImpl(int32_t ioHandle const AudioOutputFlags& flags, AudioConfig* suggestedConfig) { audio_config_t halConfig; - HidlUtils::audioConfigToHal(config, &halConfig); + if (HidlUtils::audioConfigToHal(config, &halConfig) != NO_ERROR) { + return {Result::INVALID_ARGUMENTS, nullptr}; + } audio_stream_out_t* halStream; audio_devices_t halDevice; char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; @@ -186,7 +189,9 @@ std::tuple<Result, sp<IStreamIn>> Device::openInputStreamImpl( int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config, const AudioInputFlags& flags, AudioSource source, AudioConfig* suggestedConfig) { audio_config_t halConfig; - HidlUtils::audioConfigToHal(config, &halConfig); + if (HidlUtils::audioConfigToHal(config, &halConfig) != NO_ERROR) { + return {Result::INVALID_ARGUMENTS, nullptr}; + } audio_stream_in_t* halStream; audio_devices_t halDevice; char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; @@ -248,6 +253,14 @@ Return<void> Device::openOutputStream(int32_t ioHandle, const DeviceAddress& dev #endif const SourceMetadata& sourceMetadata, openOutputStream_cb _hidl_cb) { +#if MAJOR_VERSION <= 6 + if (status_t status = sourceMetadataToHal(sourceMetadata, nullptr); status != NO_ERROR) { +#else + if (status_t status = sourceMetadataToHalV7(sourceMetadata, nullptr); status != NO_ERROR) { +#endif + _hidl_cb(analyzeStatus("sourceMetadataToHal", status), nullptr, AudioConfig{}); + return Void(); + } AudioConfig suggestedConfig; auto [result, streamOut] = openOutputStreamImpl(ioHandle, device, config, flags, &suggestedConfig); @@ -271,7 +284,15 @@ Return<void> Device::openInputStream(int32_t ioHandle, const DeviceAddress& devi // This should never happen, the framework must not create as stream // if there is no client ALOGE("openInputStream called without tracks connected"); - _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, AudioConfig()); + _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, AudioConfig{}); + return Void(); + } +#if MAJOR_VERSION <= 6 + if (status_t status = sinkMetadataToHal(sinkMetadata, nullptr); status != NO_ERROR) { +#else + if (status_t status = sinkMetadataToHalV7(sinkMetadata, nullptr); status != NO_ERROR) { +#endif + _hidl_cb(analyzeStatus("sinkMetadataToHal", status), nullptr, AudioConfig{}); return Void(); } // Pick the first one as the main. diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp index c74079d9ce..f964cbb804 100644 --- a/audio/core/all-versions/default/Stream.cpp +++ b/audio/core/all-versions/default/Stream.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "StreamHAL" #include "core/default/Stream.h" +#include "common/all-versions/HidlSupport.h" #include "common/all-versions/default/EffectMap.h" #include "core/default/Conversions.h" #include "core/default/Util.h" @@ -37,6 +38,7 @@ namespace CPP_VERSION { namespace implementation { using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils; +using ::android::hardware::audio::common::utils::splitString; Stream::Stream(bool isInput, audio_stream_t* stream) : mIsInput(isInput), mStream(stream) { (void)mIsInput; // prevent 'unused field' warnings in pre-V7 versions. @@ -220,7 +222,7 @@ Return<void> Stream::getSupportedProfiles(getSupportedProfiles_cb _hidl_cb) { // Ensure that the separator is one character, despite that it's defined as a C string. static_assert(sizeof(AUDIO_PARAMETER_VALUE_LIST_SEPARATOR) == 2); std::vector<std::string> halFormats = - util::splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]); + splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]); hidl_vec<AudioFormat> formats; (void)HidlUtils::audioFormatsFromHal(halFormats, &formats); std::vector<AudioProfile> tempProfiles; @@ -235,7 +237,7 @@ Return<void> Stream::getSupportedProfiles(getSupportedProfiles_cb _hidl_cb) { result = getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue, context); if (result != Result::OK) break; std::vector<std::string> halSampleRates = - util::splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]); + splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]); hidl_vec<uint32_t> sampleRates; sampleRates.resize(halSampleRates.size()); for (size_t i = 0; i < sampleRates.size(); ++i) { @@ -245,7 +247,7 @@ Return<void> Stream::getSupportedProfiles(getSupportedProfiles_cb _hidl_cb) { result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue, context); if (result != Result::OK) break; std::vector<std::string> halChannelMasks = - util::splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]); + splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]); hidl_vec<AudioChannelMask> channelMasks; (void)HidlUtils::audioChannelMasksFromHal(halChannelMasks, &channelMasks); // Create a profile. diff --git a/audio/core/all-versions/default/StreamIn.cpp b/audio/core/all-versions/default/StreamIn.cpp index a6735546f3..39a4c27210 100644 --- a/audio/core/all-versions/default/StreamIn.cpp +++ b/audio/core/all-versions/default/StreamIn.cpp @@ -478,87 +478,59 @@ Return<void> StreamIn::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& } #if MAJOR_VERSION >= 4 - -record_track_metadata StreamIn::convertRecordTrackMetadata( - const RecordTrackMetadata& trackMetadata) { - record_track_metadata halTrackMetadata = {.gain = trackMetadata.gain}; - (void)HidlUtils::audioSourceToHal(trackMetadata.source, &halTrackMetadata.source); -#if MAJOR_VERSION >= 5 - if (trackMetadata.destination.getDiscriminator() == - RecordTrackMetadata::Destination::hidl_discriminator::device) { - (void)deviceAddressToHal(trackMetadata.destination.device(), &halTrackMetadata.dest_device, - halTrackMetadata.dest_device_address); - } -#endif - return halTrackMetadata; -} - -void StreamIn::doUpdateSinkMetadata(const SinkMetadata& sinkMetadata) { +Result StreamIn::doUpdateSinkMetadata(const SinkMetadata& sinkMetadata, + bool abortOnConversionFailure) { std::vector<record_track_metadata> halTracks; - halTracks.reserve(sinkMetadata.tracks.size()); - for (auto& metadata : sinkMetadata.tracks) { - halTracks.push_back(convertRecordTrackMetadata(metadata)); + if (status_t status = sinkMetadataToHal(sinkMetadata, &halTracks); + status != NO_ERROR && abortOnConversionFailure) { + return Stream::analyzeStatus("sinkMetadataToHal", status); } const sink_metadata_t halMetadata = { .track_count = halTracks.size(), .tracks = halTracks.data(), }; mStream->update_sink_metadata(mStream, &halMetadata); + return Result::OK; } #if MAJOR_VERSION >= 7 -record_track_metadata_v7 StreamIn::convertRecordTrackMetadataV7( - const RecordTrackMetadata& trackMetadata) { - record_track_metadata_v7 halTrackMetadata; - halTrackMetadata.base = convertRecordTrackMetadata(trackMetadata); - (void)HidlUtils::audioChannelMaskToHal(trackMetadata.channelMask, - &halTrackMetadata.channel_mask); - std::string halTags; - for (const auto& tag : trackMetadata.tags) { - if (&tag != &trackMetadata.tags[0]) { - halTags += HidlUtils::sAudioTagSeparator; - } - halTags += tag.c_str(); - } - strncpy(halTrackMetadata.tags, halTags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE); - return halTrackMetadata; -} - -void StreamIn::doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata) { +Result StreamIn::doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata) { std::vector<record_track_metadata_v7> halTracks; - halTracks.reserve(sinkMetadata.tracks.size()); - for (auto& metadata : sinkMetadata.tracks) { - halTracks.push_back(convertRecordTrackMetadataV7(metadata)); + if (status_t status = sinkMetadataToHalV7(sinkMetadata, &halTracks); status != NO_ERROR) { + return Stream::analyzeStatus("sinkMetadataToHal", status); } const sink_metadata_v7_t halMetadata = { .track_count = halTracks.size(), .tracks = halTracks.data(), }; mStream->update_sink_metadata_v7(mStream, &halMetadata); + return Result::OK; } #endif // MAJOR_VERSION >= 7 +#if MAJOR_VERSION <= 6 Return<void> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) { -#if MAJOR_VERSION < 7 if (mStream->update_sink_metadata == nullptr) { return Void(); // not supported by the HAL } - doUpdateSinkMetadata(sinkMetadata); -#else + (void)doUpdateSinkMetadata(sinkMetadata, false /*abortOnConversionFailure*/); + return Void(); +} +#elif MAJOR_VERSION >= 7 +Return<Result> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) { if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) { if (mStream->update_sink_metadata == nullptr) { - return Void(); // not supported by the HAL + return Result::NOT_SUPPORTED; } - doUpdateSinkMetadata(sinkMetadata); + return doUpdateSinkMetadata(sinkMetadata, true /*abortOnConversionFailure*/); } else { if (mStream->update_sink_metadata_v7 == nullptr) { - return Void(); // not supported by the HAL + return Result::NOT_SUPPORTED; } - doUpdateSinkMetadataV7(sinkMetadata); + return doUpdateSinkMetadataV7(sinkMetadata); } -#endif // MAJOR_VERSION < 7 - return Void(); } +#endif Return<void> StreamIn::getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) { Result retval = Result::NOT_SUPPORTED; diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp index 2451b9eb3a..0ff918213d 100644 --- a/audio/core/all-versions/default/StreamOut.cpp +++ b/audio/core/all-versions/default/StreamOut.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "StreamOutHAL" #include "core/default/StreamOut.h" +#include "core/default/Conversions.h" #include "core/default/Util.h" //#define LOG_NDEBUG 0 @@ -585,81 +586,59 @@ Return<void> StreamOut::debug(const hidl_handle& fd, const hidl_vec<hidl_string> } #if MAJOR_VERSION >= 4 -playback_track_metadata StreamOut::convertPlaybackTrackMetadata( - const PlaybackTrackMetadata& trackMetadata) { - playback_track_metadata_t halTrackMetadata = {.gain = trackMetadata.gain}; - (void)HidlUtils::audioUsageToHal(trackMetadata.usage, &halTrackMetadata.usage); - (void)HidlUtils::audioContentTypeToHal(trackMetadata.contentType, - &halTrackMetadata.content_type); - return halTrackMetadata; -} - -void StreamOut::doUpdateSourceMetadata(const SourceMetadata& sourceMetadata) { +Result StreamOut::doUpdateSourceMetadata(const SourceMetadata& sourceMetadata, + bool abortOnConversionFailure) { std::vector<playback_track_metadata_t> halTracks; - halTracks.reserve(sourceMetadata.tracks.size()); - for (auto& metadata : sourceMetadata.tracks) { - halTracks.push_back(convertPlaybackTrackMetadata(metadata)); + if (status_t status = sourceMetadataToHal(sourceMetadata, &halTracks); + status != NO_ERROR && abortOnConversionFailure) { + return Stream::analyzeStatus("sourceMetadataToHal", status); } const source_metadata_t halMetadata = { .track_count = halTracks.size(), .tracks = halTracks.data(), }; mStream->update_source_metadata(mStream, &halMetadata); + return Result::OK; } #if MAJOR_VERSION >= 7 -playback_track_metadata_v7 StreamOut::convertPlaybackTrackMetadataV7( - const PlaybackTrackMetadata& trackMetadata) { - playback_track_metadata_v7 halTrackMetadata; - halTrackMetadata.base = convertPlaybackTrackMetadata(trackMetadata); - (void)HidlUtils::audioChannelMaskToHal(trackMetadata.channelMask, - &halTrackMetadata.channel_mask); - std::string halTags; - for (const auto& tag : trackMetadata.tags) { - if (&tag != &trackMetadata.tags[0]) { - halTags += HidlUtils::sAudioTagSeparator; - } - halTags += tag.c_str(); - } - strncpy(halTrackMetadata.tags, halTags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE); - return halTrackMetadata; -} - -void StreamOut::doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata) { +Result StreamOut::doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata) { std::vector<playback_track_metadata_v7> halTracks; - halTracks.reserve(sourceMetadata.tracks.size()); - for (auto& metadata : sourceMetadata.tracks) { - halTracks.push_back(convertPlaybackTrackMetadataV7(metadata)); + if (status_t status = sourceMetadataToHalV7(sourceMetadata, &halTracks); status != NO_ERROR) { + return Stream::analyzeStatus("sourceMetadataToHal", status); } const source_metadata_v7_t halMetadata = { .track_count = halTracks.size(), .tracks = halTracks.data(), }; mStream->update_source_metadata_v7(mStream, &halMetadata); + return Result::OK; } #endif // MAJOR_VERSION >= 7 +#if MAJOR_VERSION <= 6 Return<void> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) { -#if MAJOR_VERSION < 7 if (mStream->update_source_metadata == nullptr) { return Void(); // not supported by the HAL } - doUpdateSourceMetadata(sourceMetadata); -#else + (void)doUpdateSourceMetadata(sourceMetadata, false /*abortOnConversionFailure*/); + return Void(); +} +#elif MAJOR_VERSION >= 7 +Return<Result> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) { if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) { if (mStream->update_source_metadata == nullptr) { - return Void(); // not supported by the HAL + return Result::NOT_SUPPORTED; } - doUpdateSourceMetadata(sourceMetadata); + return doUpdateSourceMetadata(sourceMetadata, true /*abortOnConversionFailure*/); } else { if (mStream->update_source_metadata_v7 == nullptr) { - return Void(); // not supported by the HAL + return Result::NOT_SUPPORTED; } - doUpdateSourceMetadataV7(sourceMetadata); + return doUpdateSourceMetadataV7(sourceMetadata); } -#endif // MAJOR_VERSION < 7 - return Void(); } +#endif Return<Result> StreamOut::selectPresentation(int32_t /*presentationId*/, int32_t /*programId*/) { return Result::NOT_SUPPORTED; // TODO: propagate to legacy diff --git a/audio/core/all-versions/default/include/core/default/Conversions.h b/audio/core/all-versions/default/include/core/default/Conversions.h index 2372771b85..61720d5303 100644 --- a/audio/core/all-versions/default/include/core/default/Conversions.h +++ b/audio/core/all-versions/default/include/core/default/Conversions.h @@ -35,12 +35,6 @@ using ::android::hardware::hidl_vec; using namespace ::android::hardware::audio::common::CPP_VERSION; using namespace ::android::hardware::audio::CPP_VERSION; -#if MAJOR_VERSION <= 6 -// Temporary version for compatibility with forks of the default implementation. -// Will be removed, do not use! -std::string deviceAddressToHal(const DeviceAddress& address); -#endif - status_t deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType, char* halDeviceAddress); status_t deviceAddressFromHal(audio_devices_t halDeviceType, const char* halDeviceAddress, @@ -49,6 +43,10 @@ status_t deviceAddressFromHal(audio_devices_t halDeviceType, const char* halDevi #if MAJOR_VERSION >= 4 bool halToMicrophoneCharacteristics(MicrophoneInfo* pDst, const struct audio_microphone_characteristic_t& src); +status_t sinkMetadataToHal(const SinkMetadata& sinkMetadata, + std::vector<record_track_metadata>* halTracks); +status_t sourceMetadataToHal(const SourceMetadata& sourceMetadata, + std::vector<playback_track_metadata_t>* halTracks); #endif #if MAJOR_VERSION <= 6 @@ -69,6 +67,11 @@ inline bool audioOutputFlagsToHal(AudioOutputFlags flags, audio_output_flags_t* #else bool audioInputFlagsToHal(const hidl_vec<AudioInOutFlag>& flags, audio_input_flags_t* halFlags); bool audioOutputFlagsToHal(const hidl_vec<AudioInOutFlag>& flags, audio_output_flags_t* halFlags); +// Overloading isn't convenient when passing a nullptr. +status_t sinkMetadataToHalV7(const SinkMetadata& sinkMetadata, + std::vector<record_track_metadata_v7_t>* halTracks); +status_t sourceMetadataToHalV7(const SourceMetadata& sourceMetadata, + std::vector<playback_track_metadata_v7_t>* halTracks); #endif } // namespace implementation diff --git a/audio/core/all-versions/default/include/core/default/StreamIn.h b/audio/core/all-versions/default/include/core/default/StreamIn.h index 512da559bf..ccb5eedc91 100644 --- a/audio/core/all-versions/default/include/core/default/StreamIn.h +++ b/audio/core/all-versions/default/include/core/default/StreamIn.h @@ -114,9 +114,13 @@ struct StreamIn : public IStreamIn { Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override; Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override; #if MAJOR_VERSION >= 4 +#if MAJOR_VERSION <= 6 Return<void> updateSinkMetadata(const SinkMetadata& sinkMetadata) override; - Return<void> getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) override; +#else + Return<Result> updateSinkMetadata(const SinkMetadata& sinkMetadata) override; #endif + Return<void> getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) override; +#endif // MAJOR_VERSION >= 4 #if MAJOR_VERSION >= 5 Return<Result> setMicrophoneDirection(MicrophoneDirection direction) override; Return<Result> setMicrophoneFieldDimension(float zoom) override; @@ -126,13 +130,11 @@ struct StreamIn : public IStreamIn { private: #if MAJOR_VERSION >= 4 - record_track_metadata convertRecordTrackMetadata(const RecordTrackMetadata& trackMetadata); - void doUpdateSinkMetadata(const SinkMetadata& sinkMetadata); + Result doUpdateSinkMetadata(const SinkMetadata& sinkMetadata, bool abortOnConversionFailure); #if MAJOR_VERSION >= 7 - record_track_metadata_v7 convertRecordTrackMetadataV7(const RecordTrackMetadata& trackMetadata); - void doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata); -#endif + Result doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata); #endif +#endif // MAJOR_VERSION >= 4 const sp<Device> mDevice; audio_stream_in_t* mStream; diff --git a/audio/core/all-versions/default/include/core/default/StreamOut.h b/audio/core/all-versions/default/include/core/default/StreamOut.h index 8da940d846..b7f211efaa 100644 --- a/audio/core/all-versions/default/include/core/default/StreamOut.h +++ b/audio/core/all-versions/default/include/core/default/StreamOut.h @@ -123,9 +123,13 @@ struct StreamOut : public IStreamOut { Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override; Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override; #if MAJOR_VERSION >= 4 - Return<void> updateSourceMetadata(const SourceMetadata& sourceMetadata) override; Return<Result> selectPresentation(int32_t presentationId, int32_t programId) override; +#if MAJOR_VERSION <= 6 + Return<void> updateSourceMetadata(const SourceMetadata& sourceMetadata) override; +#else + Return<Result> updateSourceMetadata(const SourceMetadata& sourceMetadata) override; #endif +#endif // MAJOR_VERSION >= 4 #if MAJOR_VERSION >= 6 Return<void> getDualMonoMode(getDualMonoMode_cb _hidl_cb) override; Return<Result> setDualMonoMode(DualMonoMode mode) override; @@ -144,15 +148,12 @@ struct StreamOut : public IStreamOut { private: #if MAJOR_VERSION >= 4 - playback_track_metadata convertPlaybackTrackMetadata( - const PlaybackTrackMetadata& trackMetadata); - void doUpdateSourceMetadata(const SourceMetadata& sourceMetadata); + Result doUpdateSourceMetadata(const SourceMetadata& sourceMetadata, + bool abortOnConversionFailure); #if MAJOR_VERSION >= 7 - playback_track_metadata_v7 convertPlaybackTrackMetadataV7( - const PlaybackTrackMetadata& trackMetadata); - void doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata); -#endif + Result doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata); #endif +#endif // MAJOR_VERSION >= 4 const sp<Device> mDevice; audio_stream_out_t* mStream; diff --git a/audio/core/all-versions/default/include/core/default/Util.h b/audio/core/all-versions/default/include/core/default/Util.h index 3d629cdefd..78ae03eab2 100644 --- a/audio/core/all-versions/default/include/core/default/Util.h +++ b/audio/core/all-versions/default/include/core/default/Util.h @@ -20,8 +20,6 @@ #include PATH(android/hardware/audio/FILE_VERSION/types.h) #include <algorithm> -#include <sstream> -#include <string> #include <vector> #include <system/audio.h> @@ -72,16 +70,6 @@ static inline Result analyzeStatus(const char* className, const char* funcName, return analyzeStatus(status); } -static inline std::vector<std::string> splitString(const std::string& s, char separator) { - std::istringstream iss(s); - std::string t; - std::vector<std::string> result; - while (std::getline(iss, t, separator)) { - result.push_back(std::move(t)); - } - return result; -} - } // namespace util } // namespace implementation } // namespace CPP_VERSION 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 c53ae8dfb4..5076dcfdb0 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp @@ -237,36 +237,45 @@ TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(g TEST_P(InputStreamTest, updateSinkMetadata) { doc::test("The HAL should not crash on metadata change"); - #if MAJOR_VERSION <= 6 hidl_enum_range<AudioSource> range; -#elif MAJOR_VERSION >= 7 - xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioSource> range; -#endif // Test all possible track configuration for (auto source : range) { for (float volume : {0.0, 0.5, 1.0}) { -#if MAJOR_VERSION <= 6 const SinkMetadata metadata = {{{.source = source, .gain = volume}}}; + ASSERT_OK(stream->updateSinkMetadata(metadata)) + << "source=" << toString(source) << ", volume=" << volume; + } + } + + // Do not test concurrent capture as this is not officially supported + + // Set no metadata as if all stream track had stopped + ASSERT_OK(stream->updateSinkMetadata({})); + // Restore initial + ASSERT_OK(stream->updateSinkMetadata(initMetadata)); + #elif MAJOR_VERSION >= 7 + xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioSource> range; + // Test all possible track configuration + for (auto source : range) { + for (float volume : {0.0, 0.5, 1.0}) { const SinkMetadata metadata = { {{.source = toString(source), .gain = volume, .tags = {}, .channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO)}}}; -#endif - ASSERT_OK(stream->updateSinkMetadata(metadata)) - << "source=" << toString(source) << ", volume=" << volume; + ASSERT_RESULT(okOrNotSupported, stream->updateSinkMetadata(metadata)) + << "source=" << toString(source) << ", volume=" << volume; } } - // Do not test concurrent capture as this is not officially supported // Set no metadata as if all stream track had stopped - ASSERT_OK(stream->updateSinkMetadata({})); - + ASSERT_RESULT(okOrNotSupported, stream->updateSinkMetadata({})); // Restore initial - ASSERT_OK(stream->updateSinkMetadata(initMetadata)); + ASSERT_RESULT(okOrNotSupported, stream->updateSinkMetadata(initMetadata)); +#endif } TEST_P(OutputStreamTest, SelectPresentation) { @@ -276,44 +285,55 @@ TEST_P(OutputStreamTest, SelectPresentation) { TEST_P(OutputStreamTest, updateSourceMetadata) { doc::test("The HAL should not crash on metadata change"); - #if MAJOR_VERSION <= 6 hidl_enum_range<AudioUsage> usageRange; hidl_enum_range<AudioContentType> contentRange; -#elif MAJOR_VERSION >= 7 - xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioUsage> usageRange; - xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioContentType> contentRange; -#endif // Test all possible track configuration for (auto usage : usageRange) { for (auto content : contentRange) { for (float volume : {0.0, 0.5, 1.0}) { -#if MAJOR_VERSION <= 6 const SourceMetadata metadata = {{{usage, content, volume}}}; -#elif MAJOR_VERSION >= 7 - const SourceMetadata metadata = { - {{toString(usage), - toString(content), - {} /* tags */, - toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO), - volume}}}; -#endif ASSERT_OK(stream->updateSourceMetadata(metadata)) << "usage=" << toString(usage) << ", content=" << toString(content) << ", volume=" << volume; } } } - - // clang-format off // Set many track of different configuration + // clang-format off ASSERT_OK(stream->updateSourceMetadata( -#if MAJOR_VERSION <= 6 {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 0.1}, {AudioUsage::VOICE_COMMUNICATION, AudioContentType::SPEECH, 1.0}, {AudioUsage::ALARM, AudioContentType::SONIFICATION, 0.0}, {AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, 0.3}}} + )); + // clang-format on + // Set no metadata as if all stream track had stopped + ASSERT_OK(stream->updateSourceMetadata({})); + // Restore initial + ASSERT_OK(stream->updateSourceMetadata(initMetadata)); #elif MAJOR_VERSION >= 7 + xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioUsage> usageRange; + xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioContentType> contentRange; + // Test all possible track configuration + for (auto usage : usageRange) { + for (auto content : contentRange) { + for (float volume : {0.0, 0.5, 1.0}) { + const SourceMetadata metadata = { + {{toString(usage), + toString(content), + {} /* tags */, + toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO), + volume}}}; + ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata(metadata)) + << "usage=" << toString(usage) << ", content=" << toString(content) + << ", volume=" << volume; + } + } + } + // Set many track of different configuration + // clang-format off + ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata( {{{toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA), toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC), {}, @@ -334,15 +354,13 @@ TEST_P(OutputStreamTest, updateSourceMetadata) { {}, toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO), 0.3}}} -#endif )); // clang-format on - // Set no metadata as if all stream track had stopped - ASSERT_OK(stream->updateSourceMetadata({})); - + ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata({})); // Restore initial - ASSERT_OK(stream->updateSourceMetadata(initMetadata)); + ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata(initMetadata)); +#endif } TEST_P(AudioPrimaryHidlTest, setMode) { 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 5ad38de412..94fa92a622 100644 --- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp @@ -18,84 +18,110 @@ #include "5.0/AudioPrimaryHidlHalTest.cpp" #if MAJOR_VERSION <= 6 -const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() { - static std::vector<DeviceConfigParameter> parameters = [] { - std::vector<DeviceConfigParameter> result; - for (const auto& device : getDeviceParameters()) { - auto module = - getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(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<audio_channel_mask_t>(channels.begin(), channels.end()), - std::vector<uint32_t>(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)); +static std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters( + bool oneProfilePerDevice) { + std::vector<DeviceConfigParameter> result; + for (const auto& device : getDeviceParameters()) { + auto module = + getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(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<audio_channel_mask_t>(channels.begin(), channels.end()), + std::vector<uint32_t>(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; - }(); + } + return result; +} + +const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() { + static std::vector<DeviceConfigParameter> parameters = + generateOutputDeviceConfigParameters(false); return parameters; } -const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() { - static std::vector<DeviceConfigParameter> parameters = [] { - std::vector<DeviceConfigParameter> result; - for (const auto& device : getDeviceParameters()) { - auto module = - getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(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<audio_channel_mask_t>(channels.begin(), channels.end()), - std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()), - profile->getFormat()); - for (const auto& config : configs) { - result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags())); - } +const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters() { + static std::vector<DeviceConfigParameter> parameters = + generateOutputDeviceConfigParameters(true); + return parameters; +} + +static std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters( + bool oneProfilePerDevice) { + std::vector<DeviceConfigParameter> result; + for (const auto& device : getDeviceParameters()) { + auto module = + getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(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<audio_channel_mask_t>(channels.begin(), channels.end()), + std::vector<uint32_t>(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; - }(); + } + return result; +} + +const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() { + static std::vector<DeviceConfigParameter> parameters = + generateInputDeviceConfigParameters(false); + return parameters; +} + +const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters() { + static std::vector<DeviceConfigParameter> parameters = + generateInputDeviceConfigParameters(true); return parameters; } #endif // MAJOR_VERSION <= 6 -TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedOutputStreams) { - doc::test("Verify that a device can't be closed if there are streams opened"); +class SingleOutputConfigTest : public AudioHidlTestWithDeviceConfigParameter {}; +TEST_P(SingleOutputConfigTest, CloseDeviceWithOpenedOutputStreams) { + doc::test("Verify that a device can't be closed if there are output streams opened"); #if MAJOR_VERSION <= 6 DeviceAddress address{.device = AudioDevice::OUT_DEFAULT}; SourceMetadata initMetadata = {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 1 /* gain */}}}; - auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE); #elif MAJOR_VERSION >= 7 DeviceAddress address{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)}; SourceMetadata initMetadata = {{{toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA), @@ -103,9 +129,9 @@ TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedOutputStreams) { {} /* tags */, toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO), 1 /* gain */}}}; - hidl_vec<AudioInOutFlag> flags; #endif - AudioConfig config{}; + const AudioConfig& config = getConfig(); + auto flags = getOutputFlags(); sp<IStreamOut> stream; StreamHelper<IStreamOut> helper(stream); AudioConfig suggestedConfig{}; @@ -120,16 +146,17 @@ TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedOutputStreams) { ASSERT_OK(getDevice()->close()); ASSERT_TRUE(resetDevice()); } +INSTANTIATE_TEST_CASE_P(SingleOutputConfig, SingleOutputConfigTest, + ::testing::ValuesIn(getOutputDeviceSingleConfigParameters()), + &DeviceConfigParameterToString); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SingleOutputConfig); -TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) { - doc::test("Verify that a device can't be closed if there are streams opened"); - if (!getCachedPolicyConfig().haveInputProfilesInModule(getDeviceName())) { - GTEST_SKIP() << "Device doesn't have input profiles"; - } +class SingleInputConfigTest : public AudioHidlTestWithDeviceConfigParameter {}; +TEST_P(SingleInputConfigTest, CloseDeviceWithOpenedInputStreams) { + doc::test("Verify that a device can't be closed if there are input streams opened"); #if MAJOR_VERSION <= 6 DeviceAddress address{.device = AudioDevice::IN_DEFAULT}; SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}}; - auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE); #elif MAJOR_VERSION >= 7 DeviceAddress address{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)}; SinkMetadata initMetadata = { @@ -137,9 +164,9 @@ TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) { .gain = 1, .tags = {}, .channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO)}}}; - hidl_vec<AudioInOutFlag> flags; #endif - AudioConfig config{}; + const AudioConfig& config = getConfig(); + auto flags = getInputFlags(); sp<IStreamIn> stream; StreamHelper<IStreamIn> helper(stream); AudioConfig suggestedConfig{}; @@ -154,6 +181,10 @@ TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) { ASSERT_OK(getDevice()->close()); ASSERT_TRUE(resetDevice()); } +INSTANTIATE_TEST_CASE_P(SingleInputConfig, SingleInputConfigTest, + ::testing::ValuesIn(getInputDeviceSingleConfigParameters()), + &DeviceConfigParameterToString); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SingleInputConfig); TEST_P(AudioPatchHidlTest, UpdatePatchInvalidHandle) { doc::test("Verify that passing an invalid handle to updateAudioPatch is checked"); 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 6bb7995353..2ed578de2c 100644 --- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp @@ -25,7 +25,6 @@ static std::vector<AudioConfig> combineAudioConfig(std::vector<xsd::AudioChannel for (auto channelMask : channelMasks) { for (auto sampleRate : sampleRates) { AudioConfig config{}; - // leave offloadInfo to 0 config.base.channelMask = toString(channelMask); config.base.sampleRateHz = sampleRate; config.base.format = format; @@ -35,56 +34,158 @@ static std::vector<AudioConfig> combineAudioConfig(std::vector<xsd::AudioChannel return configs; } +static std::tuple<std::vector<AudioInOutFlag>, bool> generateOutFlags( + const xsd::MixPorts::MixPort& mixPort) { + static const std::vector<AudioInOutFlag> offloadFlags = { + toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD), + toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)}; + std::vector<AudioInOutFlag> 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<DeviceConfigParameter> generateOutputDeviceConfigParameters( + bool oneProfilePerDevice) { + std::vector<DeviceConfigParameter> result; + for (const auto& device : getDeviceParameters()) { + auto module = + getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(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<DeviceConfigParameter>& getOutputDeviceConfigParameters() { - static std::vector<DeviceConfigParameter> parameters = [] { + static std::vector<DeviceConfigParameter> parameters = + generateOutputDeviceConfigParameters(false); + return parameters; +} + +const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters() { + static std::vector<DeviceConfigParameter> parameters = + generateOutputDeviceConfigParameters(true); + return parameters; +} + +const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters( + bool generateInvalidFlags = true) { + static std::vector<DeviceConfigParameter> parameters = [&] { std::vector<DeviceConfigParameter> result; - const std::vector<AudioInOutFlag> offloadFlags = { - toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD), - toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)}; for (const auto& device : getDeviceParameters()) { auto module = getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(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 - std::vector<AudioInOutFlag> 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)); - } + 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<uint32_t>(profile.getSamplingRates()[0]), + toString(profile.getChannelMasks()[0])}; + { + AudioConfig config{.base = validBase}; + config.base.channelMask = "random_string"; + if (isOffload) { + config.offloadInfo.info(generateOffloadInfo(validBase)); } - } else { - flags = offloadFlags; + result.emplace_back(device, config, validFlags); } - } - 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. + { + AudioConfig config{.base = validBase}; + config.base.format = "random_string"; if (isOffload) { - config.offloadInfo.base = config.base; - config.offloadInfo.streamType = - toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC); - config.offloadInfo.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA); - config.offloadInfo.bitRatePerSecond = 320; - config.offloadInfo.durationMicroseconds = -1; - config.offloadInfo.bitWidth = 16; - config.offloadInfo.bufferSize = 256; // arbitrary value + 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<AudioInOutFlag> 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; @@ -92,32 +193,346 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() { return parameters; } +static std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters( + bool oneProfilePerDevice) { + std::vector<DeviceConfigParameter> result; + for (const auto& device : getDeviceParameters()) { + auto module = + getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(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<AudioInOutFlag> 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<DeviceConfigParameter>& getInputDeviceConfigParameters() { - static std::vector<DeviceConfigParameter> parameters = [] { + static std::vector<DeviceConfigParameter> parameters = + generateInputDeviceConfigParameters(false); + return parameters; +} + +const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters() { + static std::vector<DeviceConfigParameter> parameters = + generateInputDeviceConfigParameters(true); + return parameters; +} + +const std::vector<DeviceConfigParameter>& getInputDeviceInvalidConfigParameters( + bool generateInvalidFlags = true) { + static std::vector<DeviceConfigParameter> parameters = [&] { std::vector<DeviceConfigParameter> result; for (const auto& device : getDeviceParameters()) { auto module = getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(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<AudioInOutFlag> flags; + std::vector<AudioInOutFlag> validFlags; if (mixPort.hasFlags()) { std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(), - std::back_inserter(flags), + std::back_inserter(validFlags), [](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) { + if (!profile.hasFormat() || !profile.hasSamplingRates() || + !profile.hasChannelMasks()) + continue; + AudioConfigBase validBase = { + profile.getFormat(), + static_cast<uint32_t>(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<AudioInOutFlag> 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."); + uint64_t bufferSize; + ASSERT_OK(getDevice()->getInputBufferSize(getConfig(), returnIn(res, bufferSize))); + EXPECT_EQ(Result::INVALID_ARGUMENTS, res); +} +INSTANTIATE_TEST_CASE_P( + InputBufferSizeInvalidConfig, InvalidInputConfigNoFlagsTest, + ::testing::ValuesIn(getInputDeviceInvalidConfigParameters(false /*generateInvalidFlags*/)), + &DeviceConfigParameterToString); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputBufferSizeInvalidConfig); + +enum { PARAM_DEVICE_CONFIG, PARAM_ADDRESS, PARAM_METADATA }; +enum { INDEX_SINK, INDEX_SOURCE }; +using SinkOrSourceMetadata = std::variant<SinkMetadata, SourceMetadata>; +using StreamOpenParameter = std::tuple<DeviceConfigParameter, DeviceAddress, SinkOrSourceMetadata>; + +static std::string StreamOpenParameterToString( + const ::testing::TestParamInfo<StreamOpenParameter>& info) { + return DeviceConfigParameterToString(::testing::TestParamInfo<DeviceConfigParameter>{ + std::get<PARAM_DEVICE_CONFIG>(info.param), info.index}) + + "__" + + SanitizeStringForGTestName( + ::testing::PrintToString(std::get<PARAM_ADDRESS>(info.param))) + + "__" + + SanitizeStringForGTestName(std::visit( + [](auto&& arg) -> std::string { return ::testing::PrintToString(arg); }, + std::get<PARAM_METADATA>(info.param))); +} + +class StreamOpenTest : public HidlTest, public ::testing::WithParamInterface<StreamOpenParameter> { + protected: + 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<PARAM_FACTORY_NAME>( + std::get<PARAM_DEVICE>(std::get<PARAM_DEVICE_CONFIG>(GetParam()))); + } + const std::string& getDeviceName() const override { + return std::get<PARAM_DEVICE_NAME>( + std::get<PARAM_DEVICE>(std::get<PARAM_DEVICE_CONFIG>(GetParam()))); + } + const AudioConfig& getConfig() const { + return std::get<PARAM_CONFIG>(std::get<PARAM_DEVICE_CONFIG>(GetParam())); + } + const hidl_vec<AudioInOutFlag> getFlags() const { + return std::get<PARAM_FLAGS>(std::get<PARAM_DEVICE_CONFIG>(GetParam())); + } + const DeviceAddress& getDeviceAddress() const { return std::get<PARAM_ADDRESS>(GetParam()); } + bool isParamForInputStream() const { + return std::get<PARAM_METADATA>(GetParam()).index() == INDEX_SINK; + } + const SinkMetadata& getSinkMetadata() const { + return std::get<INDEX_SINK>(std::get<PARAM_METADATA>(GetParam())); + } + const SourceMetadata& getSourceMetadata() const { + return std::get<INDEX_SOURCE>(std::get<PARAM_METADATA>(GetParam())); + } +}; + +static const DeviceAddress& getValidInputDeviceAddress() { + static const DeviceAddress valid = { + .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)}; + return valid; +} + +static const DeviceAddress& getValidOutputDeviceAddress() { + static const DeviceAddress valid = { + .deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)}; + return valid; +} + +static const DeviceAddress& getInvalidDeviceAddress() { + static const DeviceAddress valid = {.deviceType = "random_string"}; + return valid; +} + +static const RecordTrackMetadata& getValidRecordTrackMetadata() { + static const RecordTrackMetadata valid = { + .source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT), .gain = 1}; + return valid; +} + +static const RecordTrackMetadata& getValidRecordTrackMetadataWithDest() { + static const RecordTrackMetadata valid = { + .source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT), + .gain = 1, + .destination = [] { + RecordTrackMetadata::Destination dest; + dest.device(getValidOutputDeviceAddress()); + return dest; + }()}; + return valid; +} + +static const RecordTrackMetadata& getInvalidSourceRecordTrackMetadata() { + static const RecordTrackMetadata invalid = {.source = "random_string", .gain = 1}; + return invalid; +} + +static const RecordTrackMetadata& getRecordTrackMetadataWithInvalidDest() { + static const RecordTrackMetadata invalid = { + .source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT), + .gain = 1, + .destination = [] { + RecordTrackMetadata::Destination dest; + dest.device(getInvalidDeviceAddress()); + return dest; + }()}; + return invalid; +} + +static const PlaybackTrackMetadata& getValidPlaybackTrackMetadata() { + static const PlaybackTrackMetadata valid = { + .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA), + .contentType = toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC), + .gain = 1}; + return valid; +} + +static const PlaybackTrackMetadata& getInvalidUsagePlaybackTrackMetadata() { + static const PlaybackTrackMetadata invalid = { + .usage = "random_string", + .contentType = toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC), + .gain = 1}; + return invalid; +} + +static const PlaybackTrackMetadata& getInvalidContentTypePlaybackTrackMetadata() { + static const PlaybackTrackMetadata invalid = { + .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA), + .contentType = "random_string", + .gain = 1}; + return invalid; +} + +static const std::vector<SourceMetadata>& getInvalidSourceMetadatas() { + static const std::vector<SourceMetadata> invalids = { + SourceMetadata{.tracks = {{getInvalidUsagePlaybackTrackMetadata()}}}, + SourceMetadata{.tracks = {{getInvalidContentTypePlaybackTrackMetadata()}}}, + SourceMetadata{.tracks = {{getValidPlaybackTrackMetadata(), + getInvalidUsagePlaybackTrackMetadata()}}}, + SourceMetadata{.tracks = {{getValidPlaybackTrackMetadata(), + getInvalidContentTypePlaybackTrackMetadata()}}}}; + return invalids; +} +static const std::vector<SinkMetadata>& getInvalidSinkMetadatas() { + static const std::vector<SinkMetadata> invalids = { + SinkMetadata{.tracks = {{getInvalidSourceRecordTrackMetadata()}}}, + SinkMetadata{.tracks = {{getRecordTrackMetadataWithInvalidDest()}}}, + SinkMetadata{.tracks = {{getValidRecordTrackMetadata(), + getInvalidSourceRecordTrackMetadata()}}}, + SinkMetadata{.tracks = {{getValidRecordTrackMetadata(), + getRecordTrackMetadataWithInvalidDest()}}}}; + return invalids; +} +template <typename T> +static inline std::vector<SinkOrSourceMetadata> wrapMetadata(const std::vector<T>& metadata) { + return std::vector<SinkOrSourceMetadata>{metadata.begin(), metadata.end()}; +} + +TEST_P(StreamOpenTest, OpenInputOrOutputStreamTest) { + doc::test( + "Verify that invalid arguments are rejected by " + "IDevice::open{Input|Output}Stream method."); + AudioConfig suggestedConfig{}; + if (isParamForInputStream()) { + sp<IStreamIn> stream; + ASSERT_OK(getDevice()->openInputStream(AudioIoHandle{}, getDeviceAddress(), getConfig(), + getFlags(), getSinkMetadata(), + returnIn(res, stream, suggestedConfig))); + ASSERT_TRUE(stream == nullptr); + } else { + sp<IStreamOut> stream; + ASSERT_OK(getDevice()->openOutputStream(AudioIoHandle{}, getDeviceAddress(), getConfig(), + getFlags(), getSourceMetadata(), + returnIn(res, stream, suggestedConfig))); + ASSERT_TRUE(stream == nullptr); + } + EXPECT_EQ(Result::INVALID_ARGUMENTS, res); + EXPECT_EQ(AudioConfig{}, suggestedConfig); +} +INSTANTIATE_TEST_CASE_P( + InputStreamInvalidConfig, StreamOpenTest, + ::testing::Combine(::testing::ValuesIn(getInputDeviceInvalidConfigParameters()), + ::testing::Values(getValidInputDeviceAddress()), + ::testing::Values(SinkMetadata{ + .tracks = {{getValidRecordTrackMetadata(), + getValidRecordTrackMetadataWithDest()}}})), + &StreamOpenParameterToString); +INSTANTIATE_TEST_CASE_P( + InputStreamInvalidAddress, StreamOpenTest, + ::testing::Combine(::testing::ValuesIn(getInputDeviceSingleConfigParameters()), + ::testing::Values(getInvalidDeviceAddress()), + ::testing::Values(SinkMetadata{ + .tracks = {{getValidRecordTrackMetadata(), + getValidRecordTrackMetadataWithDest()}}})), + &StreamOpenParameterToString); +INSTANTIATE_TEST_CASE_P( + InputStreamInvalidMetadata, StreamOpenTest, + ::testing::Combine(::testing::ValuesIn(getInputDeviceSingleConfigParameters()), + ::testing::Values(getValidInputDeviceAddress()), + ::testing::ValuesIn(wrapMetadata(getInvalidSinkMetadatas()))), + &StreamOpenParameterToString); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamInvalidConfig); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamInvalidAddress); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamInvalidMetadata); + +INSTANTIATE_TEST_CASE_P( + OutputStreamInvalidConfig, StreamOpenTest, + ::testing::Combine(::testing::ValuesIn(getOutputDeviceInvalidConfigParameters()), + ::testing::Values(getValidOutputDeviceAddress()), + ::testing::Values(SourceMetadata{ + .tracks = {{getValidPlaybackTrackMetadata()}}})), + &StreamOpenParameterToString); +INSTANTIATE_TEST_CASE_P( + OutputStreamInvalidAddress, StreamOpenTest, + ::testing::Combine(::testing::ValuesIn(getOutputDeviceSingleConfigParameters()), + ::testing::Values(getInvalidDeviceAddress()), + ::testing::Values(SourceMetadata{ + .tracks = {{getValidPlaybackTrackMetadata()}}})), + &StreamOpenParameterToString); +INSTANTIATE_TEST_CASE_P( + OutputStreamInvalidMetadata, StreamOpenTest, + ::testing::Combine(::testing::ValuesIn(getOutputDeviceSingleConfigParameters()), + ::testing::Values(getValidOutputDeviceAddress()), + ::testing::ValuesIn(wrapMetadata(getInvalidSourceMetadatas()))), + &StreamOpenParameterToString); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamInvalidConfig); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamInvalidAddress); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamInvalidMetadata); + +TEST_P(OutputStreamTest, UpdateInvalidSourceMetadata) { + doc::test("Verify that invalid metadata is rejected by IStreamOut::updateSourceMetadata"); + for (const auto& metadata : getInvalidSourceMetadatas()) { + ASSERT_RESULT(invalidArgsOrNotSupported, stream->updateSourceMetadata(metadata)) + << ::testing::PrintToString(metadata); + } +} + +TEST_P(InputStreamTest, UpdateInvalidSinkMetadata) { + doc::test("Verify that invalid metadata is rejected by IStreamIn::updateSinkMetadata"); + for (const auto& metadata : getInvalidSinkMetadatas()) { + ASSERT_RESULT(invalidArgsOrNotSupported, stream->updateSinkMetadata(metadata)) + << ::testing::PrintToString(metadata); + } +} diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h index a16a0fb4d3..f145b606de 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -522,7 +522,9 @@ using DeviceConfigParameter = std::tuple<DeviceParameter, AudioConfig, std::vect #if MAJOR_VERSION >= 6 const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters(); +const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters(); const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters(); +const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters(); #endif #if MAJOR_VERSION >= 4 @@ -883,7 +885,7 @@ class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter { AudioHidlTestWithDeviceConfigParameter::TearDown(); } - protected: + protected: AudioConfig audioConfig; DeviceAddress address = {}; sp<Stream> stream; @@ -973,7 +975,7 @@ class InputStreamTest : public OpenStreamTest<IStreamIn> { ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base #if MAJOR_VERSION <= 6 address.device = AudioDevice::IN_DEFAULT; -#elif MAJOR_VERSION <= 7 +#elif MAJOR_VERSION >= 7 address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT); #endif const AudioConfig& config = getConfig(); @@ -988,7 +990,7 @@ class InputStreamTest : public OpenStreamTest<IStreamIn> { protected: #if MAJOR_VERSION == 2 - const AudioSource initMetadata = AudioSource::DEFAULT; + const AudioSource initMetadata = AudioSource::DEFAULT; #elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6 const SinkMetadata initMetadata = {{ {.source = AudioSource::DEFAULT, .gain = 1 } }}; #elif MAJOR_VERSION >= 7 |