diff options
36 files changed, 2048 insertions, 645 deletions
diff --git a/audio/7.0/config/api/current.txt b/audio/7.0/config/api/current.txt index f585d8e405..78f2f29c17 100644 --- a/audio/7.0/config/api/current.txt +++ b/audio/7.0/config/api/current.txt @@ -251,7 +251,6 @@ package android.audio.policy.configuration.V7_0 { enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_HW_AV_SYNC; enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_HW_HOTWORD; enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_MMAP_NOIRQ; - enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_NONE; enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_RAW; enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_SYNC; enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_VOIP_TX; @@ -265,7 +264,6 @@ package android.audio.policy.configuration.V7_0 { enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO; enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_INCALL_MUSIC; enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_MMAP_NOIRQ; - enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_NONE; enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_NON_BLOCKING; enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_PRIMARY; enum_constant public static final android.audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_RAW; diff --git a/audio/7.0/config/audio_policy_configuration.xsd b/audio/7.0/config/audio_policy_configuration.xsd index 87e5774337..50c179352f 100644 --- a/audio/7.0/config/audio_policy_configuration.xsd +++ b/audio/7.0/config/audio_policy_configuration.xsd @@ -159,13 +159,9 @@ <xs:annotation> <xs:documentation xml:lang="en"> The flags indicate suggested stream attributes supported by the profile. - Use of AUDIO_{INPUT|OUTPUT}_FLAG_NONE in the XML file isn't required - as empty flag lists are allowed. However these constants are useful for - representing an empty enum value. </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"> - <xs:enumeration value="AUDIO_OUTPUT_FLAG_NONE" /> <xs:enumeration value="AUDIO_OUTPUT_FLAG_DIRECT" /> <xs:enumeration value="AUDIO_OUTPUT_FLAG_PRIMARY" /> <xs:enumeration value="AUDIO_OUTPUT_FLAG_FAST" /> @@ -182,7 +178,6 @@ <xs:enumeration value="AUDIO_OUTPUT_FLAG_VOIP_RX" /> <xs:enumeration value="AUDIO_OUTPUT_FLAG_INCALL_MUSIC" /> <xs:enumeration value="AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD" /> - <xs:enumeration value="AUDIO_INPUT_FLAG_NONE" /> <xs:enumeration value="AUDIO_INPUT_FLAG_FAST" /> <xs:enumeration value="AUDIO_INPUT_FLAG_HW_HOTWORD" /> <xs:enumeration value="AUDIO_INPUT_FLAG_RAW" /> diff --git a/audio/README.md b/audio/README.md index b77b9ba42d..1938ad4d11 100644 --- a/audio/README.md +++ b/audio/README.md @@ -7,47 +7,49 @@ based on an existing one. ## Directory Structure -* `2.0` -- version 2.0 of the core HIDL API. Note that `.hal` files +* `2.0` — version 2.0 of the core HIDL API. Note that `.hal` files can not be moved into the `core` directory because that would change its namespace and include path. - - `config` -- the XSD schema for the Audio Policy Manager + - `config` — the XSD schema for the Audio Policy Manager configuration file. -* `4.0` -- version 4.0 of the core HIDL API. +* `4.0` — version 4.0 of the core HIDL API. * ... -* `common` -- common types for audio core and effect HIDL API. - - `2.0` -- version 2.0 of the common types HIDL API. - - `4.0` -- version 4.0. +* `common` — common types for audio core and effect HIDL API. + - `2.0` — version 2.0 of the common types HIDL API. + - `4.0` — version 4.0. - ... - - `7.0` -- version 7.0. - - `example` -- example implementation of the core and effect + - `7.0` — version 7.0. + - `example` — example implementation of the core and effect V7.0 API. It represents a "fake" audio HAL that doesn't actually communicate with hardware. - - `all-versions` -- code common to all version of both core and effect API. - - `default` -- shared code of the default implementation. - - `service` -- vendor HAL service for hosting the default + - `all-versions` — code common to all version of both core and effect API. + - `default` — shared code of the default implementation. + - `service` — vendor HAL service for hosting the default implementation. - - `test` -- utilities used by tests. - - `util` -- utilities used by both implementation and tests. -* `core` -- VTS tests and the default implementation of the core API + - `test` — utilities used by tests. + - `util` — utilities used by both implementation and tests. +* `core` — VTS tests and the default implementation of the core API (not HIDL API, it's in `audio/N.M`). - - `7.0` -- code specific to version V7.0 of the core HIDL API - - `all-versions` -- the code is common between all versions, + - `7.0` — code specific to version V7.0 of the core HIDL API + - `all-versions` — the code is common between all versions, version-specific parts are enclosed into conditional directives of preprocessor or reside in dedicated files. - - `default` -- code that wraps the legacy API (from + - `default` — code that wraps the legacy API (from `hardware/libhardware`). + - `util` — utilities for the default implementation. - `vts` VTS tests for the core HIDL API. -* `effect` -- same for the effect HIDL API. +* `effect` — same for the effect HIDL API. - `2.0` - - `config` -- the XSD schema for the Audio Effects configuration - file. + - `config` — the XSD schema for the Audio Effects configuration file. - `4.0` - ... - `all-versions` - - `default` - - `vts` -* `policy` -- Configurable Audio Policy schemes. - - `1.0` -- note that versions of CAP are not linked to the versions + - `default` — code that wraps the legacy API (from + `hardware/libhardware`). + - `util` — utilities for the default implementation. + - `vts` VTS tests for the effect HIDL API. +* `policy` — Configurable Audio Policy schemes. + - `1.0` — note that versions of CAP are not linked to the versions of audio HAL. - - `vts` -- VTS tests for validating actual configuration files. - - `xml` -- XSD schemas for CAP configuration files. + - `vts` — VTS tests for validating actual configuration files. + - `xml` — XSD schemas for CAP configuration files. 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 c0042db0ba..b427f3a0d4 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,10 +212,16 @@ static inline bool isOutputDevice(const std::string& device) { return isOutputDevice(stringToAudioDevice(device)); } +static inline bool maybeVendorExtension(const std::string& s) { + // Only checks whether the string starts with the "vendor prefix". + static const std::string vendorPrefix = "VX_"; + return s.size() > vendorPrefix.size() && s.substr(0, vendorPrefix.size()) == vendorPrefix; +} + static inline bool isVendorExtension(const std::string& s) { // Must match the "vendorExtension" rule from the XSD file. static const std::string vendorPrefix = "VX_"; - return s.size() > vendorPrefix.size() && s.substr(0, vendorPrefix.size()) == vendorPrefix && + return maybeVendorExtension(s) && 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 3903a0b2ce..99c2e5a0eb 100644 --- a/audio/common/7.0/types.hal +++ b/audio/common/7.0/types.hal @@ -309,15 +309,15 @@ typedef string AudioTag; struct PlaybackTrackMetadata { AudioUsage usage; AudioContentType contentType; - /** Tags from AudioTrack audio atttributes */ - vec<AudioTag> tags; - AudioChannelMask channelMask; /** * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation, * 2 means double amplification... * Must not be negative. */ float gain; + AudioChannelMask channelMask; + /** Tags from AudioTrack audio atttributes */ + vec<AudioTag> tags; }; /** Metadatas of the source of a StreamOut. */ @@ -328,9 +328,6 @@ struct SourceMetadata { /** Metadata of a record track for a StreamIn. */ struct RecordTrackMetadata { AudioSource source; - /** Tags from AudioTrack audio atttributes */ - vec<AudioTag> tags; - AudioChannelMask channelMask; /** * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation, * 2 means double amplification... @@ -344,6 +341,9 @@ struct RecordTrackMetadata { Monostate unspecified; DeviceAddress device; } destination; + AudioChannelMask channelMask; + /** Tags from AudioTrack audio atttributes */ + vec<AudioTag> tags; }; /** Metadatas of the sink of a StreamIn. */ diff --git a/audio/common/all-versions/default/7.0/HidlUtils.cpp b/audio/common/all-versions/default/7.0/HidlUtils.cpp index f09db5ed98..bb3a5968b5 100644 --- a/audio/common/all-versions/default/7.0/HidlUtils.cpp +++ b/audio/common/all-versions/default/7.0/HidlUtils.cpp @@ -16,6 +16,7 @@ #include <stdio.h> #include <string.h> +#include <algorithm> #define LOG_TAG "HidlUtils" #include <log/log.h> @@ -281,7 +282,7 @@ status_t HidlUtils::audioGainModeMaskFromHal(audio_gain_mode_t halGainModeMask, hidl_vec<AudioGainMode>* gainModeMask) { status_t status = NO_ERROR; std::vector<AudioGainMode> result; - for (uint32_t bit = 0; bit < sizeof(audio_gain_mode_t) * 8; ++bit) { + for (uint32_t bit = 0; halGainModeMask != 0 && bit < sizeof(audio_gain_mode_t) * 8; ++bit) { audio_gain_mode_t flag = static_cast<audio_gain_mode_t>(1u << bit); if ((flag & halGainModeMask) == flag) { AudioGainMode flagStr = audio_gain_mode_to_string(flag); @@ -291,6 +292,7 @@ status_t HidlUtils::audioGainModeMaskFromHal(audio_gain_mode_t halGainModeMask, ALOGE("Unknown audio gain mode value 0x%X", flag); status = BAD_VALUE; } + halGainModeMask = static_cast<audio_gain_mode_t>(halGainModeMask & ~flag); } } *gainModeMask = result; @@ -858,15 +860,17 @@ 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 HidlUtils::audioTagsFromHal(const std::vector<std::string>& strTags, + hidl_vec<AudioTag>* tags) { 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]; + const auto& tag = strTags[from]; + if (xsd::isVendorExtension(tag)) { + (*tags)[to++] = tag; } else { + ALOGE("Vendor extension tag is ill-formed: \"%s\"", tag.c_str()); result = BAD_VALUE; } } @@ -889,6 +893,7 @@ status_t HidlUtils::audioTagsToHal(const hidl_vec<AudioTag>& tags, char* halTags halTagsBuffer << tag; hasValue = true; } else { + ALOGE("Vendor extension tag is ill-formed: \"%s\"", tag.c_str()); result = BAD_VALUE; } } @@ -899,6 +904,31 @@ status_t HidlUtils::audioTagsToHal(const hidl_vec<AudioTag>& tags, char* halTags return result; } +hidl_vec<AudioTag> HidlUtils::filterOutNonVendorTags(const hidl_vec<AudioTag>& tags) { + hidl_vec<AudioTag> result; + result.resize(tags.size()); + size_t resultIdx = 0; + for (const auto& tag : tags) { + if (xsd::maybeVendorExtension(tag)) { + result[resultIdx++] = tag; + } + } + if (resultIdx != result.size()) { + result.resize(resultIdx); + } + return result; +} + +std::vector<std::string> HidlUtils::filterOutNonVendorTags(const std::vector<std::string>& tags) { + std::vector<std::string> result; + std::copy_if(tags.begin(), tags.end(), std::back_inserter(result), xsd::maybeVendorExtension); + return result; +} + +std::vector<std::string> HidlUtils::splitAudioTags(const char* halTags) { + return utils::splitString(halTags, sAudioTagSeparator); +} + 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 cc4fbf2f15..22b7152f99 100644 --- a/audio/common/all-versions/default/HidlUtils.h +++ b/audio/common/all-versions/default/HidlUtils.h @@ -20,6 +20,8 @@ #include PATH(android/hardware/audio/common/FILE_VERSION/types.h) #include <memory> +#include <string> +#include <vector> #include <system/audio.h> @@ -118,8 +120,12 @@ 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 audioTagsFromHal(const std::vector<std::string>& strTags, + hidl_vec<AudioTag>* tags); static status_t audioTagsToHal(const hidl_vec<AudioTag>& tags, char* halTags); + static hidl_vec<AudioTag> filterOutNonVendorTags(const hidl_vec<AudioTag>& tags); + static std::vector<std::string> filterOutNonVendorTags(const std::vector<std::string>& tags); + static std::vector<std::string> splitAudioTags(const char* halTags); private: static status_t audioIndexChannelMaskFromHal(audio_channel_mask_t halChannelMask, diff --git a/audio/common/all-versions/default/UuidUtils.cpp b/audio/common/all-versions/default/UuidUtils.cpp index 85edc7b2f4..6c4c94d415 100644 --- a/audio/common/all-versions/default/UuidUtils.cpp +++ b/audio/common/all-versions/default/UuidUtils.cpp @@ -42,6 +42,14 @@ void UuidUtils::uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid) { memcpy(halUuid->node, uuid.node.data(), uuid.node.size()); } +std::string UuidUtils::uuidToString(const audio_uuid_t& halUuid) { + char str[64]; + snprintf(str, sizeof(str), "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", halUuid.timeLow, + halUuid.timeMid, halUuid.timeHiAndVersion, halUuid.clockSeq, halUuid.node[0], + halUuid.node[1], halUuid.node[2], halUuid.node[3], halUuid.node[4], halUuid.node[5]); + return str; +} + } // namespace implementation } // namespace CPP_VERSION } // namespace common diff --git a/audio/common/all-versions/default/UuidUtils.h b/audio/common/all-versions/default/UuidUtils.h index 38db48a730..cd04fb039a 100644 --- a/audio/common/all-versions/default/UuidUtils.h +++ b/audio/common/all-versions/default/UuidUtils.h @@ -17,14 +17,14 @@ #ifndef android_hardware_audio_Uuid_Utils_H_ #define android_hardware_audio_Uuid_Utils_H_ +#include <string> + // clang-format off #include PATH(android/hardware/audio/common/FILE_VERSION/types.h) // clang-format on #include <system/audio.h> -using ::android::hardware::hidl_vec; - namespace android { namespace hardware { namespace audio { @@ -38,6 +38,7 @@ class UuidUtils { public: static void uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid); static void uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid); + static std::string uuidToString(const audio_uuid_t& halUuid); }; } // namespace implementation diff --git a/audio/common/all-versions/default/tests/hidlutils_tests.cpp b/audio/common/all-versions/default/tests/hidlutils_tests.cpp index 642ece3255..40fc5c81c6 100644 --- a/audio/common/all-versions/default/tests/hidlutils_tests.cpp +++ b/audio/common/all-versions/default/tests/hidlutils_tests.cpp @@ -762,9 +762,7 @@ TEST(HidlUtils, ConvertInvalidOffloadInfo) { TEST(HidlUtils, ConvertOffloadInfo) { AudioOffloadInfo offloadInfo = {}; - offloadInfo.base.sampleRateHz = 44100; - offloadInfo.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO); - offloadInfo.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT); + offloadInfo.base = generateValidConfigBase(false /*isInput*/); offloadInfo.streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC); offloadInfo.bitRatePerSecond = 320; offloadInfo.durationMicroseconds = -1; @@ -783,33 +781,76 @@ TEST(HidlUtils, ConvertOffloadInfo) { TEST(HidlUtils, ConvertInvalidConfig) { AudioConfig invalid; - audio_config_t halInvalid = AUDIO_CONFIG_INITIALIZER; - halInvalid.channel_mask = kInvalidHalChannelMask; - halInvalid.format = kInvalidHalFormat; - EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigFromHal(halInvalid, false /*isInput*/, &invalid)); - EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigFromHal(halInvalid, true /*isInput*/, &invalid)); - invalid.base.channelMask = "random string"; - invalid.base.format = "random string"; - EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigToHal(invalid, &halInvalid)); + audio_config_t halInvalidChannelMask = AUDIO_CONFIG_INITIALIZER; + halInvalidChannelMask.channel_mask = kInvalidHalChannelMask; + EXPECT_EQ(BAD_VALUE, + HidlUtils::audioConfigFromHal(halInvalidChannelMask, false /*isInput*/, &invalid)); + EXPECT_EQ(BAD_VALUE, + HidlUtils::audioConfigFromHal(halInvalidChannelMask, true /*isInput*/, &invalid)); + audio_config_t halInvalidFormat = AUDIO_CONFIG_INITIALIZER; + halInvalidFormat.format = kInvalidHalFormat; + EXPECT_EQ(BAD_VALUE, + HidlUtils::audioConfigFromHal(halInvalidFormat, false /*isInput*/, &invalid)); + EXPECT_EQ(BAD_VALUE, + HidlUtils::audioConfigFromHal(halInvalidFormat, true /*isInput*/, &invalid)); + + AudioConfig invalidChannelMask; + audio_config_t halInvalid; + invalidChannelMask.base.channelMask = "random string"; + invalidChannelMask.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_DEFAULT); + EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigToHal(invalidChannelMask, &halInvalid)); + AudioConfig invalidFormat; + invalidFormat.base.format = "random string"; + invalidFormat.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE); + EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigToHal(invalidFormat, &halInvalid)); +} + +TEST(HidlUtils, ConvertConfigDefault) { + audio_config_t halDefault = AUDIO_CONFIG_INITIALIZER; + AudioConfig defaultOut, defaultIn; + EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigFromHal(halDefault, false /*isInput*/, &defaultOut)); + EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigFromHal(halDefault, true /*isInput*/, &defaultIn)); + EXPECT_EQ(defaultOut, defaultIn); + EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigToHal(defaultOut, &halDefault)); + + // Note: empty channel mask and config are not valid values. + AudioConfig defaultCfg{}; + defaultCfg.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE); + defaultCfg.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_DEFAULT); + audio_config_t halDefaultCfg; + EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigToHal(defaultCfg, &halDefaultCfg)); + AudioConfig defaultCfgBackOut, defaultCfgBackIn; + EXPECT_EQ(NO_ERROR, + HidlUtils::audioConfigFromHal(halDefaultCfg, false /*isInput*/, &defaultCfgBackOut)); + EXPECT_EQ(NO_ERROR, + HidlUtils::audioConfigFromHal(halDefaultCfg, true /*isInput*/, &defaultCfgBackIn)); + EXPECT_EQ(defaultCfgBackOut, defaultCfgBackIn); + EXPECT_EQ(defaultCfg, defaultCfgBackOut); } TEST(HidlUtils, ConvertConfig) { - 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); - 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); + AudioConfig configOut{}; + configOut.base = generateValidConfigBase(false /*isInput*/); + audio_config_t halConfigOut; + EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigToHal(configOut, &halConfigOut)); + AudioConfig configOutBack; + EXPECT_EQ(NO_ERROR, + HidlUtils::audioConfigFromHal(halConfigOut, false /*isInput*/, &configOutBack)); + EXPECT_EQ(configOut, configOutBack); + + AudioConfig configIn{}; + configIn.base = generateValidConfigBase(true /*isInput*/); + audio_config_t halConfigIn; + EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigToHal(configIn, &halConfigIn)); + AudioConfig configInBack; + EXPECT_EQ(NO_ERROR, + HidlUtils::audioConfigFromHal(halConfigIn, true /*isInput*/, &configInBack)); + EXPECT_EQ(configIn, configInBack); } 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.base = generateValidConfigBase(false /*isInput*/); config.offloadInfo.info( AudioOffloadInfo{.base = config.base, .streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC), @@ -952,20 +993,51 @@ TEST(HidlUtils, ConvertAudioTags) { 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(NO_ERROR, + HidlUtils::audioTagsFromHal(HidlUtils::splitAudioTags(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(NO_ERROR, + HidlUtils::audioTagsFromHal(HidlUtils::splitAudioTags(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(NO_ERROR, + HidlUtils::audioTagsFromHal(HidlUtils::splitAudioTags(halTwoTags), &twoTagsBack)); EXPECT_EQ(twoTags, twoTagsBack); } + +template <typename T> +class FilterTest : public ::testing::Test {}; +using FilterTestTypeParams = ::testing::Types<hidl_vec<AudioTag>, std::vector<std::string>>; +TYPED_TEST_SUITE(FilterTest, FilterTestTypeParams); + +TYPED_TEST(FilterTest, FilterOutNonVendorTags) { + TypeParam emptyTags; + EXPECT_EQ(emptyTags, HidlUtils::filterOutNonVendorTags(emptyTags)); + + TypeParam allVendorTags = {{"VX_GOOGLE_VR_42", "VX_GOOGLE_1E100"}}; + EXPECT_EQ(allVendorTags, HidlUtils::filterOutNonVendorTags(allVendorTags)); + + TypeParam oneVendorTag = {{"", "VX_GOOGLE_VR", "random_string"}}; + TypeParam oneVendorTagOnly = HidlUtils::filterOutNonVendorTags(oneVendorTag); + EXPECT_EQ(1, oneVendorTagOnly.size()); + EXPECT_EQ(oneVendorTag[1], oneVendorTagOnly[0]); + + // The vendor extension isn't valid, however it must not be filtered out + // so the converter can detect the issue. + TypeParam oneMaybeVendorTag = {{"", "random string", "VX_GOOGLE_$$"}}; + TypeParam oneMaybeVendorTagOnly = HidlUtils::filterOutNonVendorTags(oneMaybeVendorTag); + EXPECT_EQ(1, oneMaybeVendorTagOnly.size()); + EXPECT_EQ(oneMaybeVendorTag[2], oneMaybeVendorTagOnly[0]); + + TypeParam noVendorTags = {{"", "random string", "V_"}}; + EXPECT_EQ(emptyTags, HidlUtils::filterOutNonVendorTags(noVendorTags)); +} diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp index c75c779a91..e0f089425f 100644 --- a/audio/core/all-versions/default/Android.bp +++ b/audio/core/all-versions/default/Android.bp @@ -1,7 +1,6 @@ filegroup { name: "android.hardware.audio-impl_srcs", srcs: [ - "Conversions.cpp", "Device.cpp", "DevicesFactory.cpp", "ParametersUtil.cpp", @@ -64,6 +63,7 @@ cc_library_shared { defaults: ["android.hardware.audio-impl_default"], shared_libs: [ "android.hardware.audio@2.0", + "android.hardware.audio@2.0-util", "android.hardware.audio.common@2.0", "android.hardware.audio.common@2.0-util", ], @@ -80,6 +80,7 @@ cc_library_shared { shared_libs: [ "android.hardware.audio@4.0", + "android.hardware.audio@4.0-util", "android.hardware.audio.common@4.0", "android.hardware.audio.common@4.0-util", ], @@ -95,6 +96,7 @@ cc_library_shared { defaults: ["android.hardware.audio-impl_default"], shared_libs: [ "android.hardware.audio@5.0", + "android.hardware.audio@5.0-util", "android.hardware.audio.common@5.0", "android.hardware.audio.common@5.0-util", ], @@ -110,6 +112,7 @@ cc_defaults { defaults: ["android.hardware.audio-impl_default"], shared_libs: [ "android.hardware.audio@6.0", + "android.hardware.audio@6.0-util", "android.hardware.audio.common@6.0", "android.hardware.audio.common@6.0-util", ], @@ -130,6 +133,7 @@ cc_library_shared { defaults: ["android.hardware.audio-impl_default"], shared_libs: [ "android.hardware.audio@7.0", + "android.hardware.audio@7.0-util", "android.hardware.audio.common@7.0", "android.hardware.audio.common@7.0-enums", "android.hardware.audio.common@7.0-util", diff --git a/audio/core/all-versions/default/Conversions.cpp b/audio/core/all-versions/default/Conversions.cpp deleted file mode 100644 index f1752ccba3..0000000000 --- a/audio/core/all-versions/default/Conversions.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2018 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 "core/default/Conversions.h" - -#include <stdio.h> - -#if MAJOR_VERSION >= 7 -#include <android_audio_policy_configuration_V7_0-enums.h> -#endif -#include <HidlUtils.h> -#include <log/log.h> - -namespace android { -namespace hardware { -namespace audio { -namespace CPP_VERSION { -namespace implementation { - -using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils; - -#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) { -#if MAJOR_VERSION >= 5 - return HidlUtils::deviceAddressToHal(device, halDeviceType, halDeviceAddress); -#else - return HidlUtils::deviceAddressToHalImpl(device, halDeviceType, halDeviceAddress); -#endif -} - -status_t deviceAddressFromHal(audio_devices_t halDeviceType, const char* halDeviceAddress, - DeviceAddress* device) { -#if MAJOR_VERSION >= 5 - return HidlUtils::deviceAddressFromHal(halDeviceType, halDeviceAddress, device); -#else - return HidlUtils::deviceAddressFromHalImpl(halDeviceType, halDeviceAddress, device); -#endif -} - -#if MAJOR_VERSION >= 4 -bool halToMicrophoneCharacteristics(MicrophoneInfo* pDst, - const struct audio_microphone_characteristic_t& src) { - bool status = false; - if (pDst != NULL) { - pDst->deviceId = src.device_id; - - if (deviceAddressFromHal(src.device, src.address, &pDst->deviceAddress) != OK) { - return false; - } - pDst->channelMapping.resize(AUDIO_CHANNEL_COUNT_MAX); - for (size_t ch = 0; ch < pDst->channelMapping.size(); ch++) { - pDst->channelMapping[ch] = AudioMicrophoneChannelMapping(src.channel_mapping[ch]); - } - pDst->location = AudioMicrophoneLocation(src.location); - pDst->group = (AudioMicrophoneGroup)src.group; - pDst->indexInTheGroup = (uint32_t)src.index_in_the_group; - pDst->sensitivity = src.sensitivity; - pDst->maxSpl = src.max_spl; - pDst->minSpl = src.min_spl; - pDst->directionality = AudioMicrophoneDirectionality(src.directionality); - pDst->frequencyResponse.resize(src.num_frequency_responses); - for (size_t k = 0; k < src.num_frequency_responses; k++) { - pDst->frequencyResponse[k].frequency = src.frequency_responses[0][k]; - pDst->frequencyResponse[k].level = src.frequency_responses[1][k]; - } - pDst->position.x = src.geometric_location.x; - pDst->position.y = src.geometric_location.y; - pDst->position.z = src.geometric_location.z; - - pDst->orientation.x = src.orientation.x; - pDst->orientation.y = src.orientation.y; - pDst->orientation.z = src.orientation.z; - - status = true; - } - 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 -namespace xsd { -using namespace ::android::audio::policy::configuration::V7_0; -} - -bool audioInputFlagsToHal(const hidl_vec<AudioInOutFlag>& flags, audio_input_flags_t* halFlags) { - bool success = true; - *halFlags = {}; - for (const auto& flag : flags) { - audio_input_flags_t halFlag; - if (!xsd::isUnknownAudioInOutFlag(flag) && - audio_input_flag_from_string(flag.c_str(), &halFlag)) { - *halFlags = static_cast<audio_input_flags_t>(*halFlags | halFlag); - } else { - ALOGE("Unknown audio input flag \"%s\"", flag.c_str()); - success = false; - } - } - return success; -} - -bool audioOutputFlagsToHal(const hidl_vec<AudioInOutFlag>& flags, audio_output_flags_t* halFlags) { - bool success = true; - *halFlags = {}; - for (const auto& flag : flags) { - audio_output_flags_t halFlag; - if (!xsd::isUnknownAudioInOutFlag(flag) && - audio_output_flag_from_string(flag.c_str(), &halFlag)) { - *halFlags = static_cast<audio_output_flags_t>(*halFlags | halFlag); - } else { - ALOGE("Unknown audio output flag \"%s\"", flag.c_str()); - success = false; - } - } - 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 -} // namespace CPP_VERSION -} // namespace audio -} // namespace hardware -} // namespace android diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp index 7caed44bc9..70a1a4d1c1 100644 --- a/audio/core/all-versions/default/Device.cpp +++ b/audio/core/all-versions/default/Device.cpp @@ -17,9 +17,7 @@ #define LOG_TAG "DeviceHAL" #include "core/default/Device.h" -#include <HidlUtils.h> #include "common/all-versions/default/EffectMap.h" -#include "core/default/Conversions.h" #include "core/default/StreamIn.h" #include "core/default/StreamOut.h" #include "core/default/Util.h" @@ -33,6 +31,8 @@ #include <android/log.h> +#include <HidlUtils.h> + namespace android { namespace hardware { namespace audio { @@ -160,11 +160,11 @@ std::tuple<Result, sp<IStreamOut>> Device::openOutputStreamImpl(int32_t ioHandle audio_stream_out_t* halStream; audio_devices_t halDevice; char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; - if (deviceAddressToHal(device, &halDevice, halDeviceAddress) != NO_ERROR) { + if (CoreUtils::deviceAddressToHal(device, &halDevice, halDeviceAddress) != NO_ERROR) { return {Result::INVALID_ARGUMENTS, nullptr}; } audio_output_flags_t halFlags; - if (!audioOutputFlagsToHal(flags, &halFlags)) { + if (CoreUtils::audioOutputFlagsToHal(flags, &halFlags) != NO_ERROR) { return {Result::INVALID_ARGUMENTS, nullptr}; } ALOGV("open_output_stream handle: %d devices: %x flags: %#x " @@ -195,12 +195,12 @@ std::tuple<Result, sp<IStreamIn>> Device::openInputStreamImpl( audio_stream_in_t* halStream; audio_devices_t halDevice; char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; - if (deviceAddressToHal(device, &halDevice, halDeviceAddress) != NO_ERROR) { + if (CoreUtils::deviceAddressToHal(device, &halDevice, halDeviceAddress) != NO_ERROR) { return {Result::INVALID_ARGUMENTS, nullptr}; } audio_input_flags_t halFlags; audio_source_t halSource; - if (!audioInputFlagsToHal(flags, &halFlags) || + if (CoreUtils::audioInputFlagsToHal(flags, &halFlags) != NO_ERROR || HidlUtils::audioSourceToHal(source, &halSource) != NO_ERROR) { return {Result::INVALID_ARGUMENTS, nullptr}; } @@ -254,9 +254,12 @@ Return<void> Device::openOutputStream(int32_t ioHandle, const DeviceAddress& dev const SourceMetadata& sourceMetadata, openOutputStream_cb _hidl_cb) { #if MAJOR_VERSION <= 6 - if (status_t status = sourceMetadataToHal(sourceMetadata, nullptr); status != NO_ERROR) { + if (status_t status = CoreUtils::sourceMetadataToHal(sourceMetadata, nullptr); + status != NO_ERROR) { #else - if (status_t status = sourceMetadataToHalV7(sourceMetadata, nullptr); status != NO_ERROR) { + if (status_t status = CoreUtils::sourceMetadataToHalV7(sourceMetadata, + false /*ignoreNonVendorTags*/, nullptr); + status != NO_ERROR) { #endif _hidl_cb(analyzeStatus("sourceMetadataToHal", status), nullptr, AudioConfig{}); return Void(); @@ -288,9 +291,11 @@ Return<void> Device::openInputStream(int32_t ioHandle, const DeviceAddress& devi return Void(); } #if MAJOR_VERSION <= 6 - if (status_t status = sinkMetadataToHal(sinkMetadata, nullptr); status != NO_ERROR) { + if (status_t status = CoreUtils::sinkMetadataToHal(sinkMetadata, nullptr); status != NO_ERROR) { #else - if (status_t status = sinkMetadataToHalV7(sinkMetadata, nullptr); status != NO_ERROR) { + if (status_t status = CoreUtils::sinkMetadataToHalV7(sinkMetadata, + false /*ignoreNonVendorTags*/, nullptr); + status != NO_ERROR) { #endif _hidl_cb(analyzeStatus("sinkMetadataToHal", status), nullptr, AudioConfig{}); return Void(); @@ -444,7 +449,7 @@ Return<void> Device::getMicrophones(getMicrophones_cb _hidl_cb) { mDevice->get_microphones(mDevice, &mic_array[0], &actual_mics) == 0) { microphones.resize(actual_mics); for (size_t i = 0; i < actual_mics; ++i) { - halToMicrophoneCharacteristics(µphones[i], mic_array[i]); + (void)CoreUtils::microphoneInfoFromHal(mic_array[i], µphones[i]); } retval = Result::OK; } diff --git a/audio/core/all-versions/default/ParametersUtil.cpp b/audio/core/all-versions/default/ParametersUtil.cpp index 694eb73aee..4d536455d4 100644 --- a/audio/core/all-versions/default/ParametersUtil.cpp +++ b/audio/core/all-versions/default/ParametersUtil.cpp @@ -15,11 +15,12 @@ */ #include "core/default/ParametersUtil.h" -#include "core/default/Conversions.h" #include "core/default/Util.h" #include <system/audio.h> +#include <util/CoreUtils.h> + namespace android { namespace hardware { namespace audio { @@ -153,7 +154,7 @@ Result ParametersUtil::setParametersImpl(const hidl_vec<ParameterValue>& context Result ParametersUtil::setParam(const char* name, const DeviceAddress& address) { audio_devices_t halDeviceType; char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; - if (deviceAddressToHal(address, &halDeviceType, halDeviceAddress) != NO_ERROR) { + if (CoreUtils::deviceAddressToHal(address, &halDeviceType, halDeviceAddress) != NO_ERROR) { return Result::INVALID_ARGUMENTS; } AudioParameter params{String8(halDeviceAddress)}; diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp index 3f8efd231f..7e3257399c 100644 --- a/audio/core/all-versions/default/Stream.cpp +++ b/audio/core/all-versions/default/Stream.cpp @@ -19,7 +19,6 @@ #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" #include <inttypes.h> @@ -30,6 +29,7 @@ #include <hardware/audio_effect.h> #include <media/AudioContainers.h> #include <media/TypeConverter.h> +#include <util/CoreUtils.h> namespace android { namespace hardware { @@ -373,9 +373,10 @@ Return<void> Stream::getDevices(getDevices_cb _hidl_cb) { hidl_vec<DeviceAddress> devices; if (retval == Result::OK) { devices.resize(1); - retval = Stream::analyzeStatus("get_devices", - deviceAddressFromHal(static_cast<audio_devices_t>(halDevice), - nullptr, &devices[0])); + retval = Stream::analyzeStatus( + "get_devices", + CoreUtils::deviceAddressFromHal(static_cast<audio_devices_t>(halDevice), nullptr, + &devices[0])); } _hidl_cb(retval, devices); return Void(); diff --git a/audio/core/all-versions/default/StreamIn.cpp b/audio/core/all-versions/default/StreamIn.cpp index c670a4da73..599f3c396e 100644 --- a/audio/core/all-versions/default/StreamIn.cpp +++ b/audio/core/all-versions/default/StreamIn.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "StreamInHAL" #include "core/default/StreamIn.h" -#include "core/default/Conversions.h" #include "core/default/Util.h" #include "common/all-versions/HidlSupport.h" @@ -27,6 +26,7 @@ #include <HidlUtils.h> #include <android/log.h> #include <hardware/audio.h> +#include <util/CoreUtils.h> #include <utils/Trace.h> #include <cmath> #include <memory> @@ -481,13 +481,15 @@ Return<void> StreamIn::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& Result StreamIn::doUpdateSinkMetadata(const SinkMetadata& sinkMetadata) { std::vector<record_track_metadata> halTracks; #if MAJOR_VERSION <= 6 - (void)sinkMetadataToHal(sinkMetadata, &halTracks); + (void)CoreUtils::sinkMetadataToHal(sinkMetadata, &halTracks); #else // Validate whether a conversion to V7 is possible. This is needed // to have a consistent behavior of the HAL regardless of the API // version of the legacy HAL (and also to be consistent with openInputStream). std::vector<record_track_metadata_v7> halTracksV7; - if (status_t status = sinkMetadataToHalV7(sinkMetadata, &halTracksV7); status == NO_ERROR) { + if (status_t status = CoreUtils::sinkMetadataToHalV7( + sinkMetadata, false /*ignoreNonVendorTags*/, &halTracksV7); + status == NO_ERROR) { halTracks.reserve(halTracksV7.size()); for (auto metadata_v7 : halTracksV7) { halTracks.push_back(std::move(metadata_v7.base)); @@ -507,7 +509,9 @@ Result StreamIn::doUpdateSinkMetadata(const SinkMetadata& sinkMetadata) { #if MAJOR_VERSION >= 7 Result StreamIn::doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata) { std::vector<record_track_metadata_v7> halTracks; - if (status_t status = sinkMetadataToHalV7(sinkMetadata, &halTracks); status != NO_ERROR) { + if (status_t status = CoreUtils::sinkMetadataToHalV7(sinkMetadata, + false /*ignoreNonVendorTags*/, &halTracks); + status != NO_ERROR) { return Stream::analyzeStatus("sinkMetadataToHal", status); } const sink_metadata_v7_t halMetadata = { @@ -553,7 +557,7 @@ Return<void> StreamIn::getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) { mStream->get_active_microphones(mStream, &mic_array[0], &actual_mics) == 0) { microphones.resize(actual_mics); for (size_t i = 0; i < actual_mics; ++i) { - halToMicrophoneCharacteristics(µphones[i], mic_array[i]); + (void)CoreUtils::microphoneInfoFromHal(mic_array[i], µphones[i]); } retval = Result::OK; } diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp index c2ad7206ab..5e4dd2ad40 100644 --- a/audio/core/all-versions/default/StreamOut.cpp +++ b/audio/core/all-versions/default/StreamOut.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "StreamOutHAL" #include "core/default/StreamOut.h" -#include "core/default/Conversions.h" #include "core/default/Util.h" //#define LOG_NDEBUG 0 @@ -30,6 +29,7 @@ #include <HidlUtils.h> #include <android/log.h> #include <hardware/audio.h> +#include <util/CoreUtils.h> #include <utils/Trace.h> namespace android { @@ -589,13 +589,15 @@ Return<void> StreamOut::debug(const hidl_handle& fd, const hidl_vec<hidl_string> Result StreamOut::doUpdateSourceMetadata(const SourceMetadata& sourceMetadata) { std::vector<playback_track_metadata_t> halTracks; #if MAJOR_VERSION <= 6 - (void)sourceMetadataToHal(sourceMetadata, &halTracks); + (void)CoreUtils::sourceMetadataToHal(sourceMetadata, &halTracks); #else // Validate whether a conversion to V7 is possible. This is needed // to have a consistent behavior of the HAL regardless of the API // version of the legacy HAL (and also to be consistent with openOutputStream). std::vector<playback_track_metadata_v7> halTracksV7; - if (status_t status = sourceMetadataToHalV7(sourceMetadata, &halTracksV7); status == NO_ERROR) { + if (status_t status = CoreUtils::sourceMetadataToHalV7( + sourceMetadata, false /*ignoreNonVendorTags*/, &halTracksV7); + status == NO_ERROR) { halTracks.reserve(halTracksV7.size()); for (auto metadata_v7 : halTracksV7) { halTracks.push_back(std::move(metadata_v7.base)); @@ -615,7 +617,9 @@ Result StreamOut::doUpdateSourceMetadata(const SourceMetadata& sourceMetadata) { #if MAJOR_VERSION >= 7 Result StreamOut::doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata) { std::vector<playback_track_metadata_v7> halTracks; - if (status_t status = sourceMetadataToHalV7(sourceMetadata, &halTracks); status != NO_ERROR) { + if (status_t status = CoreUtils::sourceMetadataToHalV7( + sourceMetadata, false /*ignoreNonVendorTags*/, &halTracks); + status != NO_ERROR) { return Stream::analyzeStatus("sourceMetadataToHal", status); } const source_metadata_v7_t halMetadata = { diff --git a/audio/core/all-versions/default/TEST_MAPPING b/audio/core/all-versions/default/TEST_MAPPING new file mode 100644 index 0000000000..d53c97afaa --- /dev/null +++ b/audio/core/all-versions/default/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "android.hardware.audio@7.0-util_tests" + } + ] +} diff --git a/audio/core/all-versions/default/include/core/default/Conversions.h b/audio/core/all-versions/default/include/core/default/Conversions.h deleted file mode 100644 index 61720d5303..0000000000 --- a/audio/core/all-versions/default/include/core/default/Conversions.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HARDWARE_AUDIO_CONVERSIONS_H_ -#define ANDROID_HARDWARE_AUDIO_CONVERSIONS_H_ - -#include PATH(android/hardware/audio/FILE_VERSION/types.h) - -#include <string> - -#include <system/audio.h> - -#include <VersionUtils.h> - -namespace android { -namespace hardware { -namespace audio { -namespace CPP_VERSION { -namespace implementation { - -using ::android::hardware::hidl_vec; -using namespace ::android::hardware::audio::common::CPP_VERSION; -using namespace ::android::hardware::audio::CPP_VERSION; - -status_t deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType, - char* halDeviceAddress); -status_t deviceAddressFromHal(audio_devices_t halDeviceType, const char* halDeviceAddress, - DeviceAddress* device); - -#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 -using AudioInputFlags = - ::android::hardware::audio::common::CPP_VERSION::implementation::AudioInputFlagBitfield; -using AudioOutputFlags = - ::android::hardware::audio::common::CPP_VERSION::implementation::AudioOutputFlagBitfield; - -inline bool audioInputFlagsToHal(AudioInputFlags flags, audio_input_flags_t* halFlags) { - *halFlags = static_cast<audio_input_flags_t>(flags); - return true; -} - -inline bool audioOutputFlagsToHal(AudioOutputFlags flags, audio_output_flags_t* halFlags) { - *halFlags = static_cast<audio_output_flags_t>(flags); - return true; -} -#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 -} // namespace CPP_VERSION -} // namespace audio -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_AUDIO_CONVERSIONS_H_ diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h index 2a4d22651a..5851fc949c 100644 --- a/audio/core/all-versions/default/include/core/default/Device.h +++ b/audio/core/all-versions/default/include/core/default/Device.h @@ -31,6 +31,7 @@ #include <hidl/MQDescriptor.h> #include <VersionUtils.h> +#include <util/CoreUtils.h> namespace android { namespace hardware { @@ -43,17 +44,10 @@ using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -#if MAJOR_VERSION <= 6 -using AudioInputFlags = - ::android::hardware::audio::common::CPP_VERSION::implementation::AudioInputFlagBitfield; -using AudioOutputFlags = - ::android::hardware::audio::common::CPP_VERSION::implementation::AudioOutputFlagBitfield; -#else -using AudioInputFlags = hidl_vec<::android::hardware::audio::CPP_VERSION::AudioInOutFlag>; -using AudioOutputFlags = hidl_vec<::android::hardware::audio::CPP_VERSION::AudioInOutFlag>; -#endif using namespace ::android::hardware::audio::common::CPP_VERSION; using namespace ::android::hardware::audio::CPP_VERSION; +using AudioInputFlags = CoreUtils::AudioInputFlags; +using AudioOutputFlags = CoreUtils::AudioOutputFlags; struct Device : public IDevice, public ParametersUtil { explicit Device(audio_hw_device_t* device); diff --git a/audio/core/all-versions/default/util/Android.bp b/audio/core/all-versions/default/util/Android.bp new file mode 100644 index 0000000000..447184bbe7 --- /dev/null +++ b/audio/core/all-versions/default/util/Android.bp @@ -0,0 +1,139 @@ +cc_defaults { + name: "android.hardware.audio-util_default", + defaults: ["hidl_defaults"], + + vendor_available: true, + + export_include_dirs: ["include"], + + srcs: [ + "CoreUtils.cpp", + ], + + shared_libs: [ + "liblog", + "libutils", + "libhidlbase", + "android.hardware.audio.common-util", + ], + export_shared_lib_headers: [ + "android.hardware.audio.common-util", + ], + + header_libs: [ + "libaudio_system_headers", + "libhardware_headers", + ], +} + +cc_library_shared { + name: "android.hardware.audio@2.0-util", + defaults: ["android.hardware.audio-util_default"], + shared_libs: [ + "android.hardware.audio.common@2.0", + "android.hardware.audio.common@2.0-util", + "android.hardware.audio@2.0", + ], + cflags: [ + "-DMAJOR_VERSION=2", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], +} + +cc_library_shared { + name: "android.hardware.audio@4.0-util", + defaults: ["android.hardware.audio-util_default"], + shared_libs: [ + "android.hardware.audio.common@4.0", + "android.hardware.audio.common@4.0-util", + "android.hardware.audio@4.0", + ], + cflags: [ + "-DMAJOR_VERSION=4", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], +} + +cc_library_shared { + name: "android.hardware.audio@5.0-util", + defaults: ["android.hardware.audio-util_default"], + shared_libs: [ + "android.hardware.audio.common@5.0", + "android.hardware.audio.common@5.0-util", + "android.hardware.audio@5.0", + ], + cflags: [ + "-DMAJOR_VERSION=5", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], +} + +cc_library_shared { + name: "android.hardware.audio@6.0-util", + defaults: ["android.hardware.audio-util_default"], + shared_libs: [ + "android.hardware.audio.common@6.0", + "android.hardware.audio.common@6.0-util", + "android.hardware.audio@6.0", + ], + cflags: [ + "-DMAJOR_VERSION=6", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], +} + +cc_library { + name: "android.hardware.audio@7.0-util", + defaults: ["android.hardware.audio-util_default"], + shared_libs: [ + "android.hardware.audio.common@7.0", + "android.hardware.audio.common@7.0-enums", + "android.hardware.audio.common@7.0-util", + "android.hardware.audio@7.0", + "libbase", + "libxml2", + ], + cflags: [ + "-DMAJOR_VERSION=7", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], +} + +// Note: this isn't a VTS test, but rather a unit test +// to verify correctness of conversion utilities. +cc_test { + name: "android.hardware.audio@7.0-util_tests", + defaults: ["android.hardware.audio-util_default"], + + srcs: ["tests/coreutils_tests.cpp"], + + // Use static linking to allow running in presubmit on + // targets that don't have HAL V7. + static_libs: [ + "android.hardware.audio.common@7.0", + "android.hardware.audio.common@7.0-enums", + "android.hardware.audio.common@7.0-util", + "android.hardware.audio@7.0", + "android.hardware.audio@7.0-util", + ], + + shared_libs: [ + "libbase", + "libxml2", + ], + + cflags: [ + "-Werror", + "-Wall", + "-DMAJOR_VERSION=7", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], + + test_suites: ["device-tests"], +} diff --git a/audio/core/all-versions/default/util/CoreUtils.cpp b/audio/core/all-versions/default/util/CoreUtils.cpp new file mode 100644 index 0000000000..14f76f3c65 --- /dev/null +++ b/audio/core/all-versions/default/util/CoreUtils.cpp @@ -0,0 +1,476 @@ +/* + * 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. + */ + +#if MAJOR_VERSION >= 7 +#include <android_audio_policy_configuration_V7_0-enums.h> +#endif +#include <HidlUtils.h> +#include <log/log.h> + +#include "util/CoreUtils.h" + +using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils; +#if MAJOR_VERSION >= 7 +namespace xsd { +using namespace ::android::audio::policy::configuration::V7_0; +} +#endif + +namespace android { +namespace hardware { +namespace audio { +namespace CPP_VERSION { +namespace implementation { + +#define CONVERT_CHECKED(expr, result) \ + if (status_t status = (expr); status != NO_ERROR) { \ + result = status; \ + } + +status_t CoreUtils::deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType, + char* halDeviceAddress) { +#if MAJOR_VERSION >= 5 + return HidlUtils::deviceAddressToHal(device, halDeviceType, halDeviceAddress); +#else + return HidlUtils::deviceAddressToHalImpl(device, halDeviceType, halDeviceAddress); +#endif +} + +status_t CoreUtils::deviceAddressFromHal(audio_devices_t halDeviceType, + const char* halDeviceAddress, DeviceAddress* device) { +#if MAJOR_VERSION >= 5 + return HidlUtils::deviceAddressFromHal(halDeviceType, halDeviceAddress, device); +#else + return HidlUtils::deviceAddressFromHalImpl(halDeviceType, halDeviceAddress, device); +#endif +} + +#if MAJOR_VERSION >= 4 +status_t CoreUtils::microphoneInfoFromHal( + const struct audio_microphone_characteristic_t& halMicInfo, MicrophoneInfo* micInfo) { + status_t result = NO_ERROR; + micInfo->deviceId = halMicInfo.device_id; + CONVERT_CHECKED( + deviceAddressFromHal(halMicInfo.device, halMicInfo.address, &micInfo->deviceAddress), + result); + size_t chCount; + for (chCount = 0; chCount < AUDIO_CHANNEL_COUNT_MAX; ++chCount) { + if (halMicInfo.channel_mapping[chCount] == AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED) { + break; + } + } + micInfo->channelMapping.resize(chCount); + for (size_t ch = 0; ch < micInfo->channelMapping.size(); ch++) { + micInfo->channelMapping[ch] = AudioMicrophoneChannelMapping(halMicInfo.channel_mapping[ch]); + } + micInfo->location = AudioMicrophoneLocation(halMicInfo.location); + micInfo->group = AudioMicrophoneGroup(halMicInfo.group); + micInfo->indexInTheGroup = static_cast<uint32_t>(halMicInfo.index_in_the_group); + micInfo->sensitivity = halMicInfo.sensitivity; + micInfo->maxSpl = halMicInfo.max_spl; + micInfo->minSpl = halMicInfo.min_spl; + micInfo->directionality = AudioMicrophoneDirectionality(halMicInfo.directionality); + micInfo->frequencyResponse.resize(halMicInfo.num_frequency_responses); + for (size_t k = 0; k < halMicInfo.num_frequency_responses; k++) { + micInfo->frequencyResponse[k].frequency = halMicInfo.frequency_responses[0][k]; + micInfo->frequencyResponse[k].level = halMicInfo.frequency_responses[1][k]; + } + micInfo->position.x = halMicInfo.geometric_location.x; + micInfo->position.y = halMicInfo.geometric_location.y; + micInfo->position.z = halMicInfo.geometric_location.z; + micInfo->orientation.x = halMicInfo.orientation.x; + micInfo->orientation.y = halMicInfo.orientation.y; + micInfo->orientation.z = halMicInfo.orientation.z; + return result; +} + +status_t CoreUtils::microphoneInfoToHal(const MicrophoneInfo& micInfo, + audio_microphone_characteristic_t* halMicInfo) { + status_t result = NO_ERROR; + strncpy(halMicInfo->device_id, micInfo.deviceId.c_str(), AUDIO_MICROPHONE_ID_MAX_LEN); + halMicInfo->device_id[AUDIO_MICROPHONE_ID_MAX_LEN - 1] = '\0'; + if (micInfo.deviceId.size() >= AUDIO_MICROPHONE_ID_MAX_LEN) { + ALOGE("HIDL MicrophoneInfo device ID is too long: %zu", micInfo.deviceId.size()); + result = BAD_VALUE; + } + CONVERT_CHECKED( + deviceAddressToHal(micInfo.deviceAddress, &halMicInfo->device, halMicInfo->address), + result); + if (micInfo.channelMapping.size() > AUDIO_CHANNEL_COUNT_MAX) { + ALOGE("HIDL MicrophoneInfo has too many channelMapping elements: %zu", + micInfo.channelMapping.size()); + result = BAD_VALUE; + } + size_t ch; + for (ch = 0; ch < micInfo.channelMapping.size() && ch < AUDIO_CHANNEL_COUNT_MAX; ch++) { + halMicInfo->channel_mapping[ch] = + static_cast<audio_microphone_channel_mapping_t>(micInfo.channelMapping[ch]); + } + for (; ch < AUDIO_CHANNEL_COUNT_MAX; ch++) { + halMicInfo->channel_mapping[ch] = AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED; + } + halMicInfo->location = static_cast<audio_microphone_location_t>(micInfo.location); + halMicInfo->group = static_cast<audio_microphone_group_t>(micInfo.group); + halMicInfo->index_in_the_group = static_cast<unsigned int>(micInfo.indexInTheGroup); + halMicInfo->sensitivity = micInfo.sensitivity; + halMicInfo->max_spl = micInfo.maxSpl; + halMicInfo->min_spl = micInfo.minSpl; + halMicInfo->directionality = + static_cast<audio_microphone_directionality_t>(micInfo.directionality); + halMicInfo->num_frequency_responses = + static_cast<unsigned int>(micInfo.frequencyResponse.size()); + if (halMicInfo->num_frequency_responses > AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES) { + ALOGE("HIDL MicrophoneInfo has too many frequency responses: %u", + halMicInfo->num_frequency_responses); + halMicInfo->num_frequency_responses = AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES; + result = BAD_VALUE; + } + for (size_t k = 0; k < halMicInfo->num_frequency_responses; k++) { + halMicInfo->frequency_responses[0][k] = micInfo.frequencyResponse[k].frequency; + halMicInfo->frequency_responses[1][k] = micInfo.frequencyResponse[k].level; + } + halMicInfo->geometric_location.x = micInfo.position.x; + halMicInfo->geometric_location.y = micInfo.position.y; + halMicInfo->geometric_location.z = micInfo.position.z; + halMicInfo->orientation.x = micInfo.orientation.x; + halMicInfo->orientation.y = micInfo.orientation.y; + halMicInfo->orientation.z = micInfo.orientation.z; + return result; +} + +status_t CoreUtils::sinkMetadataFromHal(const std::vector<record_track_metadata_t>& halTracks, + SinkMetadata* sinkMetadata) { + status_t result = NO_ERROR; + sinkMetadata->tracks.resize(halTracks.size()); + for (size_t i = 0; i < sinkMetadata->tracks.size(); ++i) { + const auto& halTrackMetadata = halTracks[i]; + RecordTrackMetadata trackMetadata{}; + CONVERT_CHECKED( + HidlUtils::audioSourceFromHal(halTrackMetadata.source, &trackMetadata.source), + result); + trackMetadata.gain = halTrackMetadata.gain; +#if MAJOR_VERSION >= 5 + if (halTrackMetadata.dest_device != AUDIO_DEVICE_NONE) { + DeviceAddress address; + if (status_t status = + deviceAddressFromHal(halTrackMetadata.dest_device, + halTrackMetadata.dest_device_address, &address); + status == NO_ERROR) { + trackMetadata.destination.device(std::move(address)); + } else { + result = status; + } + } +#if MAJOR_VERSION >= 7 + trackMetadata.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE); +#endif +#endif // MAJOR_VERSION >= 5 + sinkMetadata->tracks[i] = std::move(trackMetadata); + } + return result; +} + +status_t CoreUtils::sinkMetadataFromHalV7(const std::vector<record_track_metadata_v7_t>& halTracks, + bool ignoreNonVendorTags, SinkMetadata* sinkMetadata) { + std::vector<record_track_metadata_t> bases; + bases.reserve(halTracks.size()); + std::transform(halTracks.begin(), halTracks.end(), std::back_inserter(bases), + [](const record_track_metadata_v7_t& src) -> record_track_metadata_t { + record_track_metadata_t result; + record_track_metadata_from_v7(&result, &src); + return result; + }); + status_t result = sinkMetadataFromHal(bases, sinkMetadata); +#if MAJOR_VERSION >= 7 + for (size_t i = 0; i < halTracks.size(); ++i) { + auto& trackMetadata = sinkMetadata->tracks[i]; + const auto& halTrackMetadata = halTracks[i]; + CONVERT_CHECKED( + HidlUtils::audioChannelMaskFromHal(halTrackMetadata.channel_mask, true /*isInput*/, + &trackMetadata.channelMask), + result); + std::vector<std::string> strTags = HidlUtils::splitAudioTags(halTrackMetadata.tags); + if (ignoreNonVendorTags) { + strTags = HidlUtils::filterOutNonVendorTags(strTags); + } + CONVERT_CHECKED(HidlUtils::audioTagsFromHal(strTags, &trackMetadata.tags), result); + } +#else + (void)ignoreNonVendorTags; +#endif + return result; +} + +status_t CoreUtils::sinkMetadataToHal(const SinkMetadata& sinkMetadata, + std::vector<record_track_metadata_t>* halTracks) { + status_t result = NO_ERROR; + if (halTracks != nullptr) { + halTracks->reserve(sinkMetadata.tracks.size()); + } + for (auto& trackMetadata : sinkMetadata.tracks) { + record_track_metadata halTrackMetadata{.gain = trackMetadata.gain}; + CONVERT_CHECKED(HidlUtils::audioSourceToHal(trackMetadata.source, &halTrackMetadata.source), + result); +#if MAJOR_VERSION >= 5 + if (trackMetadata.destination.getDiscriminator() == + RecordTrackMetadata::Destination::hidl_discriminator::device) { + CONVERT_CHECKED(deviceAddressToHal(trackMetadata.destination.device(), + &halTrackMetadata.dest_device, + halTrackMetadata.dest_device_address), + result); + } +#endif + if (halTracks != nullptr) { + halTracks->push_back(std::move(halTrackMetadata)); + } + } + return result; +} + +status_t CoreUtils::sinkMetadataToHalV7(const SinkMetadata& sinkMetadata, bool ignoreNonVendorTags, + 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(sinkMetadata.tracks.size()); + } + for (size_t i = 0; i < sinkMetadata.tracks.size(); ++i) { + record_track_metadata_v7_t halTrackMetadata; + if (halTracks != nullptr) { + record_track_metadata_to_v7(&halTrackMetadata, &bases[i]); + } +#if MAJOR_VERSION >= 7 + const auto& trackMetadata = sinkMetadata.tracks[i]; + CONVERT_CHECKED(HidlUtils::audioChannelMaskToHal(trackMetadata.channelMask, + &halTrackMetadata.channel_mask), + result); + if (ignoreNonVendorTags) { + CONVERT_CHECKED( + HidlUtils::audioTagsToHal(HidlUtils::filterOutNonVendorTags(trackMetadata.tags), + halTrackMetadata.tags), + result); + } else { + CONVERT_CHECKED(HidlUtils::audioTagsToHal(trackMetadata.tags, halTrackMetadata.tags), + result); + } +#else + (void)ignoreNonVendorTags; +#endif + if (halTracks != nullptr) { + halTracks->push_back(std::move(halTrackMetadata)); + } + } + return result; +} + +status_t CoreUtils::sourceMetadataFromHal(const std::vector<playback_track_metadata_t>& halTracks, + SourceMetadata* sourceMetadata) { + status_t result = NO_ERROR; + sourceMetadata->tracks.resize(halTracks.size()); + for (size_t i = 0; i < sourceMetadata->tracks.size(); ++i) { + const auto& halTrackMetadata = halTracks[i]; + PlaybackTrackMetadata trackMetadata{}; + CONVERT_CHECKED(HidlUtils::audioUsageFromHal(halTrackMetadata.usage, &trackMetadata.usage), + result); + CONVERT_CHECKED(HidlUtils::audioContentTypeFromHal(halTrackMetadata.content_type, + &trackMetadata.contentType), + result); + trackMetadata.gain = halTrackMetadata.gain; +#if MAJOR_VERSION >= 7 + trackMetadata.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE); +#endif + sourceMetadata->tracks[i] = std::move(trackMetadata); + } + return result; +} + +status_t CoreUtils::sourceMetadataFromHalV7( + const std::vector<playback_track_metadata_v7_t>& halTracks, bool ignoreNonVendorTags, + SourceMetadata* sourceMetadata) { + std::vector<playback_track_metadata_t> bases; + bases.reserve(halTracks.size()); + std::transform(halTracks.begin(), halTracks.end(), std::back_inserter(bases), + [](const playback_track_metadata_v7_t& src) -> playback_track_metadata_t { + playback_track_metadata_t result; + playback_track_metadata_from_v7(&result, &src); + return result; + }); + status_t result = sourceMetadataFromHal(bases, sourceMetadata); +#if MAJOR_VERSION >= 7 + for (size_t i = 0; i < halTracks.size(); ++i) { + auto& trackMetadata = sourceMetadata->tracks[i]; + const auto& halTrackMetadata = halTracks[i]; + CONVERT_CHECKED( + HidlUtils::audioChannelMaskFromHal(halTrackMetadata.channel_mask, false /*isInput*/, + &trackMetadata.channelMask), + result); + std::vector<std::string> strTags = HidlUtils::splitAudioTags(halTrackMetadata.tags); + if (ignoreNonVendorTags) { + strTags = HidlUtils::filterOutNonVendorTags(strTags); + } + CONVERT_CHECKED(HidlUtils::audioTagsFromHal(strTags, &trackMetadata.tags), result); + } +#else + (void)ignoreNonVendorTags; +#endif + return result; +} + +status_t CoreUtils::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& trackMetadata : sourceMetadata.tracks) { + playback_track_metadata_t halTrackMetadata{.gain = trackMetadata.gain}; + CONVERT_CHECKED(HidlUtils::audioUsageToHal(trackMetadata.usage, &halTrackMetadata.usage), + result); + CONVERT_CHECKED(HidlUtils::audioContentTypeToHal(trackMetadata.contentType, + &halTrackMetadata.content_type), + result); + if (halTracks != nullptr) { + halTracks->push_back(std::move(halTrackMetadata)); + } + } + return result; +} + +status_t CoreUtils::sourceMetadataToHalV7(const SourceMetadata& sourceMetadata, + bool ignoreNonVendorTags, + 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(sourceMetadata.tracks.size()); + } + for (size_t i = 0; i < sourceMetadata.tracks.size(); ++i) { + playback_track_metadata_v7_t halTrackMetadata; + if (halTracks != nullptr) { + playback_track_metadata_to_v7(&halTrackMetadata, &bases[i]); + } +#if MAJOR_VERSION >= 7 + const auto& trackMetadata = sourceMetadata.tracks[i]; + CONVERT_CHECKED(HidlUtils::audioChannelMaskToHal(trackMetadata.channelMask, + &halTrackMetadata.channel_mask), + result); + if (ignoreNonVendorTags) { + CONVERT_CHECKED( + HidlUtils::audioTagsToHal(HidlUtils::filterOutNonVendorTags(trackMetadata.tags), + halTrackMetadata.tags), + result); + } else { + CONVERT_CHECKED(HidlUtils::audioTagsToHal(trackMetadata.tags, halTrackMetadata.tags), + result); + } +#else + (void)ignoreNonVendorTags; +#endif + if (halTracks != nullptr) { + halTracks->push_back(std::move(halTrackMetadata)); + } + } + return result; +} +#endif // MAJOR_VERSION >= 4 + +#if MAJOR_VERSION >= 7 +namespace xsd { +using namespace ::android::audio::policy::configuration::V7_0; +} + +status_t CoreUtils::audioInputFlagsFromHal(audio_input_flags_t halFlagMask, + AudioInputFlags* flags) { + status_t status = NO_ERROR; + std::vector<AudioInOutFlag> result; + for (uint32_t bit = 0; halFlagMask != 0 && bit < sizeof(audio_input_flags_t) * 8; ++bit) { + audio_input_flags_t flag = static_cast<audio_input_flags_t>(1u << bit); + if ((flag & halFlagMask) == flag) { + AudioInOutFlag flagStr = audio_input_flag_to_string(flag); + if (!flagStr.empty() && !xsd::isUnknownAudioInOutFlag(flagStr)) { + result.push_back(flagStr); + } else { + ALOGE("Unknown audio input flag value 0x%X", flag); + status = BAD_VALUE; + } + halFlagMask = static_cast<audio_input_flags_t>(halFlagMask & ~flag); + } + } + *flags = result; + return status; +} + +status_t CoreUtils::audioInputFlagsToHal(const AudioInputFlags& flags, + audio_input_flags_t* halFlagMask) { + status_t status = NO_ERROR; + *halFlagMask = {}; + for (const auto& flag : flags) { + audio_input_flags_t halFlag; + if (!xsd::isUnknownAudioInOutFlag(flag) && + audio_input_flag_from_string(flag.c_str(), &halFlag)) { + *halFlagMask = static_cast<audio_input_flags_t>(*halFlagMask | halFlag); + } else { + ALOGE("Unknown audio input flag \"%s\"", flag.c_str()); + status = BAD_VALUE; + } + } + return status; +} + +status_t CoreUtils::audioOutputFlagsFromHal(audio_output_flags_t halFlagMask, + AudioOutputFlags* flags) { + status_t status = NO_ERROR; + std::vector<AudioInOutFlag> result; + for (uint32_t bit = 0; halFlagMask != 0 && bit < sizeof(audio_output_flags_t) * 8; ++bit) { + audio_output_flags_t flag = static_cast<audio_output_flags_t>(1u << bit); + if ((flag & halFlagMask) == flag) { + AudioInOutFlag flagStr = audio_output_flag_to_string(flag); + if (!flagStr.empty() && !xsd::isUnknownAudioInOutFlag(flagStr)) { + result.push_back(flagStr); + } else { + ALOGE("Unknown audio output flag value 0x%X", flag); + status = BAD_VALUE; + } + halFlagMask = static_cast<audio_output_flags_t>(halFlagMask & ~flag); + } + } + *flags = result; + return status; +} + +status_t CoreUtils::audioOutputFlagsToHal(const AudioOutputFlags& flags, + audio_output_flags_t* halFlagMask) { + status_t status = NO_ERROR; + *halFlagMask = {}; + for (const auto& flag : flags) { + audio_output_flags_t halFlag; + if (!xsd::isUnknownAudioInOutFlag(flag) && + audio_output_flag_from_string(flag.c_str(), &halFlag)) { + *halFlagMask = static_cast<audio_output_flags_t>(*halFlagMask | halFlag); + } else { + ALOGE("Unknown audio output flag \"%s\"", flag.c_str()); + status = BAD_VALUE; + } + } + return status; +} +#endif + +} // namespace implementation +} // namespace CPP_VERSION +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/core/all-versions/default/util/include/util/CoreUtils.h b/audio/core/all-versions/default/util/include/util/CoreUtils.h new file mode 100644 index 0000000000..1e5272a479 --- /dev/null +++ b/audio/core/all-versions/default/util/include/util/CoreUtils.h @@ -0,0 +1,110 @@ +/* + * 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 + +// clang-format off +#include PATH(android/hardware/audio/FILE_VERSION/types.h) +// clang-format off + +#include <vector> + +#include <system/audio.h> + +#include <common/all-versions/VersionUtils.h> +#include <VersionUtils.h> + +namespace android { +namespace hardware { +namespace audio { +namespace CPP_VERSION { +namespace implementation { + +using ::android::hardware::audio::common::utils::EnumBitfield; +using ::android::hardware::hidl_vec; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; + +struct CoreUtils { + // Note: the converters for DeviceAddress have to be in CoreUtils for HAL V4 + // because DeviceAddress used to be defined in the core HAL. For V5 and above + // these functions simply delegate to HidlUtils. + static status_t deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType, + char* halDeviceAddress); + static status_t deviceAddressFromHal(audio_devices_t halDeviceType, const char* halDeviceAddress, + DeviceAddress* device); +#if MAJOR_VERSION >= 4 + static status_t microphoneInfoFromHal(const struct audio_microphone_characteristic_t& halMicInfo, + MicrophoneInfo* micInfo); + static status_t microphoneInfoToHal(const MicrophoneInfo& micInfo, audio_microphone_characteristic_t* halMicInfo); + // Note: {Sink|Source}Metadata types are defined in 'common' (since V5), so they can be used + // by the BT HAL. However, the converters are defined here, not in HidlUtils to avoid adding + // conditionals to handle V4. The converters are only used by 'core' HAL anyways. + static status_t sinkMetadataFromHal(const std::vector<record_track_metadata_t>& halTracks, + SinkMetadata* sinkMetadata); + static status_t sinkMetadataFromHalV7(const std::vector<record_track_metadata_v7_t>& halTracks, + bool ignoreNonVendorTags, SinkMetadata* sinkMetadata); + static status_t sinkMetadataToHal(const SinkMetadata& sinkMetadata, + std::vector<record_track_metadata_t>* halTracks); + static status_t sinkMetadataToHalV7(const SinkMetadata& sinkMetadata, bool ignoreNonVendorTags, + std::vector<record_track_metadata_v7_t>* halTracks); + static status_t sourceMetadataFromHal(const std::vector<playback_track_metadata_t>& halTracks, + SourceMetadata* sourceMetadata); + static status_t sourceMetadataFromHalV7(const std::vector<playback_track_metadata_v7_t>& halTracks, + bool ignoreNonVendorTags, SourceMetadata* sourceMetadata); + static status_t sourceMetadataToHal(const SourceMetadata& sourceMetadata, + std::vector<playback_track_metadata_t>* halTracks); + static status_t sourceMetadataToHalV7(const SourceMetadata& sourceMetadata, bool ignoreNonVendorTags, + std::vector<playback_track_metadata_v7_t>* halTracks); +#endif + +#if MAJOR_VERSION <= 6 + using AudioInputFlags = + ::android::hardware::audio::common::CPP_VERSION::implementation::AudioInputFlagBitfield; + using AudioOutputFlags = + ::android::hardware::audio::common::CPP_VERSION::implementation::AudioOutputFlagBitfield; + static inline status_t audioInputFlagsFromHal(audio_input_flags_t halFlagMask, AudioInputFlags* flags) { + *flags = EnumBitfield<AudioInputFlag>(halFlagMask); + return NO_ERROR; + } + static inline status_t audioInputFlagsToHal(AudioInputFlags flags, audio_input_flags_t* halFlagMask) { + *halFlagMask = static_cast<audio_input_flags_t>(flags); + return NO_ERROR; + } + static inline status_t audioOutputFlagsFromHal(audio_output_flags_t halFlagMask, AudioOutputFlags* flags) { + *flags = EnumBitfield<AudioOutputFlag>(halFlagMask); + return NO_ERROR; + } + static inline status_t audioOutputFlagsToHal(AudioOutputFlags flags, audio_output_flags_t* halFlagMask) { + *halFlagMask = static_cast<audio_output_flags_t>(flags); + return NO_ERROR; + } +#else + using AudioInputFlags = hidl_vec<::android::hardware::audio::CPP_VERSION::AudioInOutFlag>; + using AudioOutputFlags = hidl_vec<::android::hardware::audio::CPP_VERSION::AudioInOutFlag>; + static status_t audioInputFlagsFromHal(audio_input_flags_t halFlagMask, AudioInputFlags* flags); + static status_t audioInputFlagsToHal(const AudioInputFlags& flags, audio_input_flags_t* halFlagMask); + static status_t audioOutputFlagsFromHal(audio_output_flags_t halFlagMask, AudioOutputFlags* flags); + static status_t audioOutputFlagsToHal(const AudioOutputFlags& flags, audio_output_flags_t* halFlagMask); +#endif + +}; + +} // namespace implementation +} // namespace CPP_VERSION +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/core/all-versions/default/util/tests/coreutils_tests.cpp b/audio/core/all-versions/default/util/tests/coreutils_tests.cpp new file mode 100644 index 0000000000..0c18482632 --- /dev/null +++ b/audio/core/all-versions/default/util/tests/coreutils_tests.cpp @@ -0,0 +1,525 @@ +/* + * 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 <string> +#include <vector> + +#include <gtest/gtest.h> + +#define LOG_TAG "CoreUtils_Test" +#include <log/log.h> + +#include <android_audio_policy_configuration_V7_0-enums.h> +#include <system/audio.h> +#include <util/CoreUtils.h> +#include <xsdc/XsdcSupport.h> + +using namespace android; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::CPP_VERSION; +using ::android::hardware::hidl_vec; +using ::android::hardware::audio::CPP_VERSION::implementation::CoreUtils; +namespace xsd { +using namespace ::android::audio::policy::configuration::V7_0; +} + +static constexpr audio_channel_mask_t kInvalidHalChannelMask = AUDIO_CHANNEL_INVALID; +static constexpr audio_content_type_t kInvalidHalContentType = + static_cast<audio_content_type_t>(0xFFFFFFFFU); +static constexpr audio_devices_t kInvalidHalDevice = static_cast<audio_devices_t>(0xFFFFFFFFU); +static constexpr audio_input_flags_t kInvalidInputFlags = + static_cast<audio_input_flags_t>(0xFFFFFFFFU); +static constexpr audio_output_flags_t kInvalidOutputFlags = + static_cast<audio_output_flags_t>(0xFFFFFFFFU); +// AUDIO_SOURCE_INVALID is framework-only. +static constexpr audio_source_t kInvalidHalSource = static_cast<audio_source_t>(-1); +static constexpr audio_usage_t kInvalidHalUsage = static_cast<audio_usage_t>(0xFFFFFFFFU); + +static bool isInputFlag(xsd::AudioInOutFlag flag) { + return toString(flag).find("_INPUT_FLAG_") != std::string::npos; +} + +static bool isOutputFlag(xsd::AudioInOutFlag flag) { + return toString(flag).find("_OUTPUT_FLAG_") != std::string::npos; +} + +TEST(CoreUtils, ConvertInvalidInputFlagMask) { + CoreUtils::AudioInputFlags invalid; + EXPECT_EQ(BAD_VALUE, CoreUtils::audioInputFlagsFromHal(kInvalidInputFlags, &invalid)); + audio_input_flags_t halInvalid; + invalid.resize(1); + invalid[0] = "random string"; + EXPECT_EQ(BAD_VALUE, CoreUtils::audioInputFlagsToHal(invalid, &halInvalid)); +} + +TEST(CoreUtils, ConvertInputFlagMask) { + CoreUtils::AudioInputFlags emptyInputFlags; + audio_input_flags_t halEmptyInputFlags; + EXPECT_EQ(NO_ERROR, CoreUtils::audioInputFlagsToHal(emptyInputFlags, &halEmptyInputFlags)); + EXPECT_EQ(AUDIO_INPUT_FLAG_NONE, halEmptyInputFlags); + CoreUtils::AudioInputFlags emptyInputFlagsBack; + EXPECT_EQ(NO_ERROR, + CoreUtils::audioInputFlagsFromHal(halEmptyInputFlags, &emptyInputFlagsBack)); + EXPECT_EQ(emptyInputFlags, emptyInputFlagsBack); + CoreUtils::AudioInputFlags emptyInputFlagsFromNone; + EXPECT_EQ(NO_ERROR, + CoreUtils::audioInputFlagsFromHal(AUDIO_INPUT_FLAG_NONE, &emptyInputFlagsFromNone)); + EXPECT_EQ(emptyInputFlags, emptyInputFlagsFromNone); + + std::vector<std::string> allEnumValues; + for (const auto enumVal : xsdc_enum_range<xsd::AudioInOutFlag>{}) { + if (isInputFlag(enumVal)) { + allEnumValues.push_back(toString(enumVal)); + } + } + CoreUtils::AudioInputFlags allInputFlags; + allInputFlags.resize(allEnumValues.size()); + for (size_t i = 0; i < allEnumValues.size(); ++i) { + allInputFlags[i] = allEnumValues[i]; + } + audio_input_flags_t halAllInputFlags; + EXPECT_EQ(NO_ERROR, CoreUtils::audioInputFlagsToHal(allInputFlags, &halAllInputFlags)); + CoreUtils::AudioInputFlags allInputFlagsBack; + EXPECT_EQ(NO_ERROR, CoreUtils::audioInputFlagsFromHal(halAllInputFlags, &allInputFlagsBack)); + EXPECT_EQ(allInputFlags, allInputFlagsBack); +} + +TEST(CoreUtils, ConvertInvalidOutputFlagMask) { + CoreUtils::AudioOutputFlags invalid; + EXPECT_EQ(BAD_VALUE, CoreUtils::audioOutputFlagsFromHal(kInvalidOutputFlags, &invalid)); + audio_output_flags_t halInvalid; + invalid.resize(1); + invalid[0] = "random string"; + EXPECT_EQ(BAD_VALUE, CoreUtils::audioOutputFlagsToHal(invalid, &halInvalid)); +} + +TEST(CoreUtils, ConvertOutputFlagMask) { + CoreUtils::AudioOutputFlags emptyOutputFlags; + audio_output_flags_t halEmptyOutputFlags; + EXPECT_EQ(NO_ERROR, CoreUtils::audioOutputFlagsToHal(emptyOutputFlags, &halEmptyOutputFlags)); + EXPECT_EQ(AUDIO_OUTPUT_FLAG_NONE, halEmptyOutputFlags); + CoreUtils::AudioOutputFlags emptyOutputFlagsBack; + EXPECT_EQ(NO_ERROR, + CoreUtils::audioOutputFlagsFromHal(halEmptyOutputFlags, &emptyOutputFlagsBack)); + EXPECT_EQ(emptyOutputFlags, emptyOutputFlagsBack); + CoreUtils::AudioOutputFlags emptyOutputFlagsFromNone; + EXPECT_EQ(NO_ERROR, CoreUtils::audioOutputFlagsFromHal(AUDIO_OUTPUT_FLAG_NONE, + &emptyOutputFlagsFromNone)); + EXPECT_EQ(emptyOutputFlags, emptyOutputFlagsFromNone); + + std::vector<std::string> allEnumValues; + for (const auto enumVal : xsdc_enum_range<xsd::AudioInOutFlag>{}) { + if (isOutputFlag(enumVal)) { + allEnumValues.push_back(toString(enumVal)); + } + } + CoreUtils::AudioOutputFlags allOutputFlags; + allOutputFlags.resize(allEnumValues.size()); + for (size_t i = 0; i < allEnumValues.size(); ++i) { + allOutputFlags[i] = allEnumValues[i]; + } + audio_output_flags_t halAllOutputFlags; + EXPECT_EQ(NO_ERROR, CoreUtils::audioOutputFlagsToHal(allOutputFlags, &halAllOutputFlags)); + CoreUtils::AudioOutputFlags allOutputFlagsBack; + EXPECT_EQ(NO_ERROR, CoreUtils::audioOutputFlagsFromHal(halAllOutputFlags, &allOutputFlagsBack)); + EXPECT_EQ(allOutputFlags, allOutputFlagsBack); +} + +static MicrophoneInfo generateValidMicrophoneInfo() { + MicrophoneInfo micInfo{}; + micInfo.deviceAddress.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_BUILTIN_MIC); + micInfo.channelMapping.resize(1); + micInfo.channelMapping[0] = AudioMicrophoneChannelMapping::DIRECT; + micInfo.location = AudioMicrophoneLocation::MAINBODY_MOVABLE; + micInfo.group = 42; + micInfo.indexInTheGroup = 13; + micInfo.sensitivity = 65.5; + micInfo.maxSpl = 100.5; + micInfo.minSpl = 36.6; + micInfo.directionality = AudioMicrophoneDirectionality::HYPER_CARDIOID; + micInfo.frequencyResponse.resize(1); + micInfo.frequencyResponse[0].frequency = 1000; + micInfo.frequencyResponse[0].level = 85; + micInfo.position.x = 0; + micInfo.position.y = 1; + micInfo.position.z = 0; + micInfo.orientation.x = 0; + micInfo.orientation.y = 0; + micInfo.orientation.z = 1; + return micInfo; +} + +TEST(CoreUtils, ConvertInvalidMicrophoneInfo) { + MicrophoneInfo invalid; + audio_microphone_characteristic_t halInvalid{}; + halInvalid.device = kInvalidHalDevice; + EXPECT_EQ(BAD_VALUE, CoreUtils::microphoneInfoFromHal(halInvalid, &invalid)); + + MicrophoneInfo oversizeDeviceId = generateValidMicrophoneInfo(); + oversizeDeviceId.deviceId = std::string(AUDIO_MICROPHONE_ID_MAX_LEN + 1, 'A'); + EXPECT_EQ(BAD_VALUE, CoreUtils::microphoneInfoToHal(oversizeDeviceId, &halInvalid)); + MicrophoneInfo invalidDeviceType = generateValidMicrophoneInfo(); + invalidDeviceType.deviceAddress.deviceType = "random string"; + EXPECT_EQ(BAD_VALUE, CoreUtils::microphoneInfoToHal(invalidDeviceType, &halInvalid)); + MicrophoneInfo oversizeChannelMapping = generateValidMicrophoneInfo(); + oversizeChannelMapping.channelMapping.resize(AUDIO_CHANNEL_COUNT_MAX + 1); + EXPECT_EQ(BAD_VALUE, CoreUtils::microphoneInfoToHal(oversizeChannelMapping, &halInvalid)); + MicrophoneInfo oversizeFrequencyResponses = generateValidMicrophoneInfo(); + oversizeFrequencyResponses.frequencyResponse.resize(AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES + + 1); + EXPECT_EQ(BAD_VALUE, CoreUtils::microphoneInfoToHal(oversizeFrequencyResponses, &halInvalid)); +} + +TEST(CoreUtils, ConvertMicrophoneInfo) { + MicrophoneInfo micInfo = generateValidMicrophoneInfo(); + audio_microphone_characteristic_t halMicInfo; + EXPECT_EQ(NO_ERROR, CoreUtils::microphoneInfoToHal(micInfo, &halMicInfo)); + MicrophoneInfo micInfoBack; + EXPECT_EQ(NO_ERROR, CoreUtils::microphoneInfoFromHal(halMicInfo, &micInfoBack)); + EXPECT_EQ(micInfo, micInfoBack); +} + +static RecordTrackMetadata generateMinimalRecordTrackMetadata() { + RecordTrackMetadata metadata{}; + metadata.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT); + metadata.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE); + return metadata; +} + +static RecordTrackMetadata generateValidRecordTrackMetadata() { + RecordTrackMetadata metadata = generateMinimalRecordTrackMetadata(); + metadata.tags.resize(1); + metadata.tags[0] = "VX_GOOGLE_42"; + metadata.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO); + metadata.gain = 1.0; + return metadata; +} + +static RecordTrackMetadata generateValidRecordTrackMetadataWithDevice() { + RecordTrackMetadata metadata = generateValidRecordTrackMetadata(); + metadata.destination.device({}); + metadata.destination.device().deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER); + return metadata; +} + +using SinkTracks = hidl_vec<RecordTrackMetadata>; + +TEST(CoreUtils, ConvertInvalidSinkMetadata) { + SinkMetadata invalidSource; + invalidSource.tracks = SinkTracks{generateMinimalRecordTrackMetadata()}; + invalidSource.tracks[0].source = "random string"; + EXPECT_EQ(BAD_VALUE, CoreUtils::sinkMetadataToHal(invalidSource, nullptr)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sinkMetadataToHalV7(invalidSource, + false /*ignoreNonVendorTags*/, nullptr)); + EXPECT_EQ(BAD_VALUE, + CoreUtils::sinkMetadataToHalV7(invalidSource, true /*ignoreNonVendorTags*/, nullptr)); + SinkMetadata invalidDeviceType; + invalidDeviceType.tracks = SinkTracks{generateValidRecordTrackMetadataWithDevice()}; + invalidDeviceType.tracks[0].destination.device().deviceType = "random string"; + EXPECT_EQ(BAD_VALUE, CoreUtils::sinkMetadataToHal(invalidDeviceType, nullptr)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sinkMetadataToHalV7(invalidDeviceType, + false /*ignoreNonVendorTags*/, nullptr)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sinkMetadataToHalV7(invalidDeviceType, + true /*ignoreNonVendorTags*/, nullptr)); + SinkMetadata invalidChannelMask; + invalidChannelMask.tracks = SinkTracks{generateValidRecordTrackMetadata()}; + invalidChannelMask.tracks[0].channelMask = "random string"; + // Channel mask is sliced away by 'sinkMetadataToHal' + EXPECT_EQ(NO_ERROR, CoreUtils::sinkMetadataToHal(invalidChannelMask, nullptr)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sinkMetadataToHalV7(invalidChannelMask, + false /*ignoreNonVendorTags*/, nullptr)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sinkMetadataToHalV7(invalidChannelMask, + true /*ignoreNonVendorTags*/, nullptr)); + SinkMetadata invalidTags; + invalidTags.tracks = SinkTracks{generateValidRecordTrackMetadata()}; + invalidTags.tracks[0].tags[0] = "random string"; + // Tags are sliced away by 'sinkMetadataToHal' + EXPECT_EQ(NO_ERROR, CoreUtils::sinkMetadataToHal(invalidTags, nullptr)); + EXPECT_EQ(BAD_VALUE, + CoreUtils::sinkMetadataToHalV7(invalidTags, false /*ignoreNonVendorTags*/, nullptr)); + // Non-vendor tags should be filtered out. + EXPECT_EQ(NO_ERROR, + CoreUtils::sinkMetadataToHalV7(invalidTags, true /*ignoreNonVendorTags*/, nullptr)); + + // Verify that a default-initialized metadata is valid. + std::vector<record_track_metadata_t> halValid(1, record_track_metadata_t{}); + std::vector<record_track_metadata_v7_t> halValidV7(1, record_track_metadata_v7_t{}); + SinkMetadata valid; + EXPECT_EQ(NO_ERROR, CoreUtils::sinkMetadataFromHal(halValid, &valid)); + EXPECT_EQ(NO_ERROR, + CoreUtils::sinkMetadataFromHalV7(halValidV7, false /*ignoreNonVendorTags*/, &valid)); + EXPECT_EQ(NO_ERROR, + CoreUtils::sinkMetadataFromHalV7(halValidV7, true /*ignoreNonVendorTags*/, &valid)); + + std::vector<record_track_metadata_t> halInvalidSource = {{.source = kInvalidHalSource}}; + std::vector<record_track_metadata_v7_t> halInvalidSourceV7 = { + {.base = {.source = kInvalidHalSource}}}; + EXPECT_EQ(BAD_VALUE, CoreUtils::sinkMetadataFromHal(halInvalidSource, &invalidSource)); + EXPECT_EQ(BAD_VALUE, + CoreUtils::sinkMetadataFromHalV7(halInvalidSourceV7, false /*ignoreNonVendorTags*/, + &invalidSource)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sinkMetadataFromHalV7( + halInvalidSourceV7, true /*ignoreNonVendorTags*/, &invalidSource)); + std::vector<record_track_metadata_t> halInvalidDeviceType = { + {.dest_device = kInvalidHalDevice}}; + std::vector<record_track_metadata_v7_t> halInvalidDeviceTypeV7 = { + {.base = {.dest_device = kInvalidHalDevice}}}; + EXPECT_EQ(BAD_VALUE, CoreUtils::sinkMetadataFromHal(halInvalidDeviceType, &invalidDeviceType)); + EXPECT_EQ(BAD_VALUE, + CoreUtils::sinkMetadataFromHalV7(halInvalidDeviceTypeV7, + false /*ignoreNonVendorTags*/, &invalidDeviceType)); + EXPECT_EQ(BAD_VALUE, + CoreUtils::sinkMetadataFromHalV7(halInvalidDeviceTypeV7, true /*ignoreNonVendorTags*/, + &invalidDeviceType)); + std::vector<record_track_metadata_v7_t> halInvalidChannelMaskV7 = { + {.channel_mask = kInvalidHalChannelMask}}; + EXPECT_EQ(BAD_VALUE, + CoreUtils::sinkMetadataFromHalV7(halInvalidChannelMaskV7, + false /*ignoreNonVendorTags*/, &invalidChannelMask)); + EXPECT_EQ(BAD_VALUE, + CoreUtils::sinkMetadataFromHalV7(halInvalidChannelMaskV7, + true /*ignoreNonVendorTags*/, &invalidChannelMask)); + std::vector<record_track_metadata_v7_t> halInvalidTagsV7 = {{.tags = "random string"}}; + EXPECT_EQ(BAD_VALUE, CoreUtils::sinkMetadataFromHalV7( + halInvalidTagsV7, false /*ignoreNonVendorTags*/, &invalidTags)); + // Non-vendor tags should be filtered out. + EXPECT_EQ(NO_ERROR, CoreUtils::sinkMetadataFromHalV7( + halInvalidTagsV7, true /*ignoreNonVendorTags*/, &invalidTags)); +} + +TEST(CoreUtils, ConvertEmptySinkMetadata) { + SinkMetadata emptySinkMetadata; + std::vector<record_track_metadata_t> halEmptySinkMetadata; + EXPECT_EQ(NO_ERROR, CoreUtils::sinkMetadataToHal(emptySinkMetadata, &halEmptySinkMetadata)); + EXPECT_TRUE(halEmptySinkMetadata.empty()); + SinkMetadata emptySinkMetadataBack; + EXPECT_EQ(NO_ERROR, + CoreUtils::sinkMetadataFromHal(halEmptySinkMetadata, &emptySinkMetadataBack)); + EXPECT_EQ(emptySinkMetadata, emptySinkMetadataBack); + std::vector<record_track_metadata_v7_t> halEmptySinkMetadataV7; + EXPECT_EQ(NO_ERROR, + CoreUtils::sinkMetadataToHalV7(emptySinkMetadata, false /*ignoreNonVendorTags*/, + &halEmptySinkMetadataV7)); + EXPECT_TRUE(halEmptySinkMetadataV7.empty()); + SinkMetadata emptySinkMetadataBackFromV7; + EXPECT_EQ(NO_ERROR, CoreUtils::sinkMetadataFromHalV7(halEmptySinkMetadataV7, + false /*ignoreNonVendorTags*/, + &emptySinkMetadataBackFromV7)); + EXPECT_EQ(emptySinkMetadata, emptySinkMetadataBackFromV7); +} + +class SinkMetadataConvertTest : public ::testing::TestWithParam<SinkTracks> {}; + +TEST_P(SinkMetadataConvertTest, ToFromHal) { + SinkMetadata sinkMetadata; + sinkMetadata.tracks = GetParam(); + std::vector<record_track_metadata_t> halSinkMetadata; + EXPECT_EQ(NO_ERROR, CoreUtils::sinkMetadataToHal(sinkMetadata, &halSinkMetadata)); + EXPECT_EQ(sinkMetadata.tracks.size(), halSinkMetadata.size()); + SinkMetadata sinkMetadataBackTrimmed; + EXPECT_EQ(NO_ERROR, CoreUtils::sinkMetadataFromHal(halSinkMetadata, &sinkMetadataBackTrimmed)); + // Can't compare 'sinkMetadata' to 'sinkMetadataBackTrimmed' + std::vector<record_track_metadata_v7_t> halSinkMetadataV7; + EXPECT_EQ(NO_ERROR, CoreUtils::sinkMetadataToHalV7(sinkMetadata, false /*ignoreNonVendorTags*/, + &halSinkMetadataV7)); + EXPECT_EQ(sinkMetadata.tracks.size(), halSinkMetadataV7.size()); + SinkMetadata sinkMetadataBackFromV7; + EXPECT_EQ(NO_ERROR, + CoreUtils::sinkMetadataFromHalV7(halSinkMetadataV7, false /*ignoreNonVendorTags*/, + &sinkMetadataBackFromV7)); + EXPECT_EQ(sinkMetadata, sinkMetadataBackFromV7); + std::vector<record_track_metadata_v7_t> halSinkMetadataV7FromTrimmed; + EXPECT_EQ(NO_ERROR, + CoreUtils::sinkMetadataToHalV7(sinkMetadataBackTrimmed, false /*ignoreNonVendorTags*/, + &halSinkMetadataV7FromTrimmed)); + EXPECT_EQ(sinkMetadata.tracks.size(), halSinkMetadataV7FromTrimmed.size()); + SinkMetadata sinkMetadataBackFromV7Trimmed; + EXPECT_EQ(NO_ERROR, CoreUtils::sinkMetadataFromHalV7(halSinkMetadataV7FromTrimmed, + false /*ignoreNonVendorTags*/, + &sinkMetadataBackFromV7Trimmed)); + EXPECT_EQ(sinkMetadataBackTrimmed, sinkMetadataBackFromV7Trimmed); +} + +INSTANTIATE_TEST_SUITE_P(ValidRecordTrackMetadatas, SinkMetadataConvertTest, + ::testing::Values(SinkTracks{generateMinimalRecordTrackMetadata()}, + SinkTracks{generateValidRecordTrackMetadata()}, + SinkTracks{generateValidRecordTrackMetadataWithDevice()}, + SinkTracks{ + generateMinimalRecordTrackMetadata(), + generateValidRecordTrackMetadata(), + generateValidRecordTrackMetadataWithDevice()})); + +static PlaybackTrackMetadata generateMinimalPlaybackTrackMetadata() { + PlaybackTrackMetadata metadata{}; + metadata.usage = toString(xsd::AudioUsage::AUDIO_USAGE_UNKNOWN); + metadata.contentType = toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_UNKNOWN); + metadata.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE); + return metadata; +} + +static PlaybackTrackMetadata generateValidPlaybackTrackMetadata() { + PlaybackTrackMetadata metadata = generateMinimalPlaybackTrackMetadata(); + metadata.tags.resize(1); + metadata.tags[0] = "VX_GOOGLE_42"; + metadata.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO); + metadata.gain = 1.0; + return metadata; +} + +using SourceTracks = hidl_vec<PlaybackTrackMetadata>; + +TEST(CoreUtils, ConvertInvalidSourceMetadata) { + SourceMetadata invalidUsage; + invalidUsage.tracks = SourceTracks{generateMinimalPlaybackTrackMetadata()}; + invalidUsage.tracks[0].usage = "random string"; + EXPECT_EQ(BAD_VALUE, CoreUtils::sourceMetadataToHal(invalidUsage, nullptr)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sourceMetadataToHalV7(invalidUsage, + false /*ignoreNonVendorTags*/, nullptr)); + SourceMetadata invalidContentType; + invalidContentType.tracks = SourceTracks{generateMinimalPlaybackTrackMetadata()}; + invalidContentType.tracks[0].contentType = "random string"; + EXPECT_EQ(BAD_VALUE, CoreUtils::sourceMetadataToHal(invalidContentType, nullptr)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sourceMetadataToHalV7(invalidContentType, + false /*ignoreNonVendorTags*/, nullptr)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sourceMetadataToHalV7(invalidContentType, + true /*ignoreNonVendorTags*/, nullptr)); + SourceMetadata invalidChannelMask; + invalidChannelMask.tracks = SourceTracks{generateValidPlaybackTrackMetadata()}; + invalidChannelMask.tracks[0].channelMask = "random string"; + // Channel mask is sliced away by 'sourceMetadataToHal' + EXPECT_EQ(NO_ERROR, CoreUtils::sourceMetadataToHal(invalidChannelMask, nullptr)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sourceMetadataToHalV7(invalidChannelMask, + false /*ignoreNonVendorTags*/, nullptr)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sourceMetadataToHalV7(invalidChannelMask, + true /*ignoreNonVendorTags*/, nullptr)); + SourceMetadata invalidTags; + invalidTags.tracks = SourceTracks{generateValidPlaybackTrackMetadata()}; + invalidTags.tracks[0].tags[0] = "random string"; + // Tags are sliced away by 'sourceMetadataToHal' + EXPECT_EQ(NO_ERROR, CoreUtils::sourceMetadataToHal(invalidTags, nullptr)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sourceMetadataToHalV7(invalidTags, + false /*ignoreNonVendorTags*/, nullptr)); + // Non-vendor tags should be filtered out. + EXPECT_EQ(NO_ERROR, + CoreUtils::sourceMetadataToHalV7(invalidTags, true /*ignoreNonVendorTags*/, nullptr)); + + // Verify that a default-initialized metadata is valid. + std::vector<playback_track_metadata_t> halValid(1, playback_track_metadata_t{}); + std::vector<playback_track_metadata_v7_t> halValidV7(1, playback_track_metadata_v7_t{}); + SourceMetadata valid; + EXPECT_EQ(NO_ERROR, CoreUtils::sourceMetadataFromHal(halValid, &valid)); + EXPECT_EQ(NO_ERROR, CoreUtils::sourceMetadataFromHalV7(halValidV7, + false /*ignoreNonVendorTags*/, &valid)); + EXPECT_EQ(NO_ERROR, + CoreUtils::sourceMetadataFromHalV7(halValidV7, true /*ignoreNonVendorTags*/, &valid)); + + std::vector<playback_track_metadata_t> halInvalidUsage = {{.usage = kInvalidHalUsage}}; + std::vector<playback_track_metadata_v7_t> halInvalidUsageV7 = { + {.base = {.usage = kInvalidHalUsage}}}; + EXPECT_EQ(BAD_VALUE, CoreUtils::sourceMetadataFromHal(halInvalidUsage, &invalidUsage)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sourceMetadataFromHalV7( + halInvalidUsageV7, false /*ignoreNonVendorTags*/, &invalidUsage)); + EXPECT_EQ(BAD_VALUE, CoreUtils::sourceMetadataFromHalV7( + halInvalidUsageV7, true /*ignoreNonVendorTags*/, &invalidUsage)); + std::vector<playback_track_metadata_t> halInvalidContentType = { + {.content_type = kInvalidHalContentType}}; + std::vector<playback_track_metadata_v7_t> halInvalidContentTypeV7 = { + {.base = {.content_type = kInvalidHalContentType}}}; + EXPECT_EQ(BAD_VALUE, + CoreUtils::sourceMetadataFromHal(halInvalidContentType, &invalidContentType)); + EXPECT_EQ(BAD_VALUE, + CoreUtils::sourceMetadataFromHalV7( + halInvalidContentTypeV7, false /*ignoreNonVendorTags*/, &invalidContentType)); + EXPECT_EQ(BAD_VALUE, + CoreUtils::sourceMetadataFromHalV7( + halInvalidContentTypeV7, true /*ignoreNonVendorTags*/, &invalidContentType)); + std::vector<playback_track_metadata_v7_t> halInvalidChannelMaskV7 = { + {.channel_mask = kInvalidHalChannelMask}}; + EXPECT_EQ(BAD_VALUE, + CoreUtils::sourceMetadataFromHalV7( + halInvalidChannelMaskV7, false /*ignoreNonVendorTags*/, &invalidChannelMask)); + EXPECT_EQ(BAD_VALUE, + CoreUtils::sourceMetadataFromHalV7( + halInvalidChannelMaskV7, true /*ignoreNonVendorTags*/, &invalidChannelMask)); + std::vector<playback_track_metadata_v7_t> halInvalidTagsV7 = {{.tags = "random string"}}; + EXPECT_EQ(BAD_VALUE, CoreUtils::sourceMetadataFromHalV7( + halInvalidTagsV7, false /*ignoreNonVendorTags*/, &invalidTags)); + // Non-vendor tags should be filtered out. + EXPECT_EQ(NO_ERROR, CoreUtils::sourceMetadataFromHalV7( + halInvalidTagsV7, true /*ignoreNonVendorTags*/, &invalidTags)); +} + +TEST(CoreUtils, ConvertEmptySourceMetadata) { + SourceMetadata emptySourceMetadata; + std::vector<playback_track_metadata_t> halEmptySourceMetadata; + EXPECT_EQ(NO_ERROR, + CoreUtils::sourceMetadataToHal(emptySourceMetadata, &halEmptySourceMetadata)); + EXPECT_TRUE(halEmptySourceMetadata.empty()); + SourceMetadata emptySourceMetadataBack; + EXPECT_EQ(NO_ERROR, + CoreUtils::sourceMetadataFromHal(halEmptySourceMetadata, &emptySourceMetadataBack)); + EXPECT_EQ(emptySourceMetadata, emptySourceMetadataBack); + std::vector<playback_track_metadata_v7_t> halEmptySourceMetadataV7; + EXPECT_EQ(NO_ERROR, + CoreUtils::sourceMetadataToHalV7(emptySourceMetadata, false /*ignoreNonVendorTags*/, + &halEmptySourceMetadataV7)); + EXPECT_TRUE(halEmptySourceMetadataV7.empty()); + SourceMetadata emptySourceMetadataBackFromV7; + EXPECT_EQ(NO_ERROR, CoreUtils::sourceMetadataFromHalV7(halEmptySourceMetadataV7, + false /*ignoreNonVendorTags*/, + &emptySourceMetadataBackFromV7)); + EXPECT_EQ(emptySourceMetadata, emptySourceMetadataBackFromV7); +} + +class SourceMetadataConvertTest : public ::testing::TestWithParam<SourceTracks> {}; + +TEST_P(SourceMetadataConvertTest, ToFromHal) { + SourceMetadata sourceMetadata; + sourceMetadata.tracks = GetParam(); + std::vector<playback_track_metadata_t> halSourceMetadata; + EXPECT_EQ(NO_ERROR, CoreUtils::sourceMetadataToHal(sourceMetadata, &halSourceMetadata)); + EXPECT_EQ(sourceMetadata.tracks.size(), halSourceMetadata.size()); + SourceMetadata sourceMetadataBackTrimmed; + EXPECT_EQ(NO_ERROR, + CoreUtils::sourceMetadataFromHal(halSourceMetadata, &sourceMetadataBackTrimmed)); + // Can't compare 'sourceMetadata' to 'sourceMetadataBackTrimmed' + std::vector<playback_track_metadata_v7_t> halSourceMetadataV7; + EXPECT_EQ(NO_ERROR, + CoreUtils::sourceMetadataToHalV7(sourceMetadata, false /*ignoreNonVendorTags*/, + &halSourceMetadataV7)); + EXPECT_EQ(sourceMetadata.tracks.size(), halSourceMetadataV7.size()); + SourceMetadata sourceMetadataBackFromV7; + EXPECT_EQ(NO_ERROR, + CoreUtils::sourceMetadataFromHalV7(halSourceMetadataV7, false /*ignoreNonVendorTags*/, + &sourceMetadataBackFromV7)); + EXPECT_EQ(sourceMetadata, sourceMetadataBackFromV7); + std::vector<playback_track_metadata_v7_t> halSourceMetadataV7FromTrimmed; + EXPECT_EQ(NO_ERROR, CoreUtils::sourceMetadataToHalV7(sourceMetadataBackTrimmed, + false /*ignoreNonVendorTags*/, + &halSourceMetadataV7FromTrimmed)); + EXPECT_EQ(sourceMetadata.tracks.size(), halSourceMetadataV7FromTrimmed.size()); + SourceMetadata sourceMetadataBackFromV7Trimmed; + EXPECT_EQ(NO_ERROR, CoreUtils::sourceMetadataFromHalV7(halSourceMetadataV7FromTrimmed, + false /*ignoreNonVendorTags*/, + &sourceMetadataBackFromV7Trimmed)); + EXPECT_EQ(sourceMetadataBackTrimmed, sourceMetadataBackFromV7Trimmed); +} + +INSTANTIATE_TEST_SUITE_P(ValidPlaybackTrackMetadatas, SourceMetadataConvertTest, + ::testing::Values(SourceTracks{generateMinimalPlaybackTrackMetadata()}, + SourceTracks{generateValidPlaybackTrackMetadata()}, + SourceTracks{generateMinimalPlaybackTrackMetadata(), + generateValidPlaybackTrackMetadata()})); 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 5076dcfdb0..bb7c6d3d3e 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp @@ -336,24 +336,24 @@ TEST_P(OutputStreamTest, updateSourceMetadata) { ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata( {{{toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA), toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC), - {}, + 0.1, // gain toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO), - 0.1}, + {}}, // tags {toString(xsd::AudioUsage::AUDIO_USAGE_VOICE_COMMUNICATION), toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_SPEECH), - {}, // tags + 1.0, toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO), - 1.0}, + {}}, {toString(xsd::AudioUsage::AUDIO_USAGE_ALARM), toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_SONIFICATION), - {}, // tags + 0.0, toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO), - 0.0}, + {}}, {toString(xsd::AudioUsage::AUDIO_USAGE_ASSISTANT), toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_UNKNOWN), - {}, + 0.3, toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO), - 0.3}}} + {}}}} )); // clang-format on // Set no metadata as if all stream track had stopped diff --git a/audio/effect/all-versions/default/Android.bp b/audio/effect/all-versions/default/Android.bp index a0cd6120e2..99b1120218 100644 --- a/audio/effect/all-versions/default/Android.bp +++ b/audio/effect/all-versions/default/Android.bp @@ -8,7 +8,6 @@ cc_defaults { "AudioBufferManager.cpp", "AutomaticGainControlEffect.cpp", "BassBoostEffect.cpp", - "Conversions.cpp", "DownmixEffect.cpp", "Effect.cpp", "EffectsFactory.cpp", @@ -51,6 +50,7 @@ cc_library_shared { "android.hardware.audio.common@2.0", "android.hardware.audio.common@2.0-util", "android.hardware.audio.effect@2.0", + "android.hardware.audio.effect@2.0-util", ], cflags: [ "-DMAJOR_VERSION=2", @@ -66,6 +66,7 @@ cc_library_shared { "android.hardware.audio.common@4.0", "android.hardware.audio.common@4.0-util", "android.hardware.audio.effect@4.0", + "android.hardware.audio.effect@4.0-util", ], cflags: [ "-DMAJOR_VERSION=4", @@ -81,6 +82,7 @@ cc_library_shared { "android.hardware.audio.common@5.0", "android.hardware.audio.common@5.0-util", "android.hardware.audio.effect@5.0", + "android.hardware.audio.effect@5.0-util", ], cflags: [ "-DMAJOR_VERSION=5", @@ -96,6 +98,7 @@ cc_library_shared { "android.hardware.audio.common@6.0", "android.hardware.audio.common@6.0-util", "android.hardware.audio.effect@6.0", + "android.hardware.audio.effect@6.0-util", ], cflags: [ "-DMAJOR_VERSION=6", @@ -111,6 +114,7 @@ cc_library_shared { "android.hardware.audio.common@7.0", "android.hardware.audio.common@7.0-util", "android.hardware.audio.effect@7.0", + "android.hardware.audio.effect@7.0-util", ], cflags: [ "-DMAJOR_VERSION=7", diff --git a/audio/effect/all-versions/default/Conversions.cpp b/audio/effect/all-versions/default/Conversions.cpp deleted file mode 100644 index 0cc8767e8d..0000000000 --- a/audio/effect/all-versions/default/Conversions.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2018 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 "Conversions.h" -#include "UuidUtils.h" - -#include <memory.h> -#include <stdio.h> - -#include <common/all-versions/VersionUtils.h> - -using ::android::hardware::audio::common::utils::EnumBitfield; - -namespace android { -namespace hardware { -namespace audio { -namespace effect { -namespace CPP_VERSION { -namespace implementation { - -using ::android::hardware::audio::common::CPP_VERSION::implementation::UuidUtils; - -void effectDescriptorFromHal(const effect_descriptor_t& halDescriptor, - EffectDescriptor* descriptor) { - UuidUtils::uuidFromHal(halDescriptor.type, &descriptor->type); - UuidUtils::uuidFromHal(halDescriptor.uuid, &descriptor->uuid); - descriptor->flags = EnumBitfield<EffectFlags>(halDescriptor.flags); - descriptor->cpuLoad = halDescriptor.cpuLoad; - descriptor->memoryUsage = halDescriptor.memoryUsage; - memcpy(descriptor->name.data(), halDescriptor.name, descriptor->name.size()); - memcpy(descriptor->implementor.data(), halDescriptor.implementor, - descriptor->implementor.size()); -} - -std::string uuidToString(const effect_uuid_t& halUuid) { - char str[64]; - snprintf(str, sizeof(str), "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", halUuid.timeLow, - halUuid.timeMid, halUuid.timeHiAndVersion, halUuid.clockSeq, halUuid.node[0], - halUuid.node[1], halUuid.node[2], halUuid.node[3], halUuid.node[4], halUuid.node[5]); - return str; -} - -} // namespace implementation -} // namespace CPP_VERSION -} // namespace effect -} // namespace audio -} // namespace hardware -} // namespace android diff --git a/audio/effect/all-versions/default/Conversions.h b/audio/effect/all-versions/default/Conversions.h deleted file mode 100644 index 75aab24efe..0000000000 --- a/audio/effect/all-versions/default/Conversions.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_CONVERSIONS_H_ -#define ANDROID_HARDWARE_AUDIO_EFFECT_CONVERSIONS_H_ - -#include PATH(android/hardware/audio/effect/FILE_VERSION/types.h) - -#include <string> - -#include <system/audio_effect.h> - -namespace android { -namespace hardware { -namespace audio { -namespace effect { -namespace CPP_VERSION { -namespace implementation { - -using ::android::hardware::audio::effect::CPP_VERSION::EffectDescriptor; - -void effectDescriptorFromHal(const effect_descriptor_t& halDescriptor, - EffectDescriptor* descriptor); -std::string uuidToString(const effect_uuid_t& halUuid); - -} // namespace implementation -} // namespace CPP_VERSION -} // namespace effect -} // namespace audio -} // namespace hardware -} // namespace android - -#endif // ANDROID_HARDWARE_AUDIO_EFFECT_CONVERSIONS_H_ diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp index 58f1779ffd..ccfc6b22c9 100644 --- a/audio/effect/all-versions/default/Effect.cpp +++ b/audio/effect/all-versions/default/Effect.cpp @@ -19,7 +19,6 @@ #define LOG_TAG "EffectHAL" #define ATRACE_TAG ATRACE_TAG_AUDIO -#include "Conversions.h" #include "Effect.h" #include "common/all-versions/default/EffectMap.h" @@ -30,6 +29,7 @@ #include <HidlUtils.h> #include <android/log.h> #include <media/EffectsFactoryApi.h> +#include <util/EffectUtils.h> #include <utils/Trace.h> #include "VersionUtils.h" @@ -202,34 +202,6 @@ void Effect::effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig& config, halConfig->aux_channels = static_cast<audio_channel_mask_t>(config.auxChannels); } -void Effect::effectBufferConfigFromHal(const buffer_config_t& halConfig, - EffectBufferConfig* config) { - config->buffer.id = 0; - config->buffer.frameCount = 0; - config->samplingRateHz = halConfig.samplingRate; - config->channels = AudioChannelBitfield(halConfig.channels); - config->format = AudioFormat(halConfig.format); - config->accessMode = EffectBufferAccess(halConfig.accessMode); - config->mask = static_cast<decltype(config->mask)>(halConfig.mask); -} - -// static -void Effect::effectBufferConfigToHal(const EffectBufferConfig& config, buffer_config_t* halConfig) { - // Note: setting the buffers directly is considered obsolete. They need to be set - // using 'setProcessBuffers'. - halConfig->buffer.frameCount = 0; - halConfig->buffer.raw = NULL; - halConfig->samplingRate = config.samplingRateHz; - halConfig->channels = static_cast<uint32_t>(config.channels); - // Note: The framework code does not use BP. - halConfig->bufferProvider.cookie = NULL; - halConfig->bufferProvider.getBuffer = NULL; - halConfig->bufferProvider.releaseBuffer = NULL; - halConfig->format = static_cast<uint8_t>(config.format); - halConfig->accessMode = static_cast<uint8_t>(config.accessMode); - halConfig->mask = static_cast<uint8_t>(config.mask); -} - #else // MAJOR_VERSION <= 6 void Effect::effectAuxChannelsConfigFromHal(const channel_config_t& halConfig, @@ -247,68 +219,8 @@ void Effect::effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig& config, (void)HidlUtils::audioChannelMaskToHal(config.auxChannels, &halConfig->aux_channels); } -void Effect::effectBufferConfigFromHal(const buffer_config_t& halConfig, - EffectBufferConfig* config) { - config->buffer.unspecified(); - audio_config_base_t halConfigBase = {halConfig.samplingRate, - static_cast<audio_channel_mask_t>(halConfig.channels), - static_cast<audio_format_t>(halConfig.format)}; - (void)HidlUtils::audioConfigBaseOptionalFromHal( - halConfigBase, mIsInput, halConfig.mask & EFFECT_CONFIG_FORMAT, - halConfig.mask & EFFECT_CONFIG_SMP_RATE, halConfig.mask & EFFECT_CONFIG_CHANNELS, - &config->base); - if (halConfig.mask & EFFECT_CONFIG_ACC_MODE) { - config->accessMode.value(EffectBufferAccess(halConfig.accessMode)); - } -} - -// static -void Effect::effectBufferConfigToHal(const EffectBufferConfig& config, buffer_config_t* halConfig) { - // Note: setting the buffers directly is considered obsolete. They need to be set - // using 'setProcessBuffers'. - halConfig->buffer.frameCount = 0; - halConfig->buffer.raw = nullptr; - audio_config_base_t halConfigBase = AUDIO_CONFIG_BASE_INITIALIZER; - bool formatSpecified = false, sRateSpecified = false, channelMaskSpecified = false; - (void)HidlUtils::audioConfigBaseOptionalToHal(config.base, &halConfigBase, &formatSpecified, - &sRateSpecified, &channelMaskSpecified); - halConfig->mask = 0; - if (sRateSpecified) { - halConfig->mask |= EFFECT_CONFIG_SMP_RATE; - halConfig->samplingRate = halConfigBase.sample_rate; - } - if (channelMaskSpecified) { - halConfig->mask |= EFFECT_CONFIG_CHANNELS; - halConfig->channels = halConfigBase.channel_mask; - } - if (formatSpecified) { - halConfig->mask |= EFFECT_CONFIG_FORMAT; - halConfig->format = halConfigBase.format; - } - // Note: The framework code does not use BP. - halConfig->bufferProvider.cookie = nullptr; - halConfig->bufferProvider.getBuffer = nullptr; - halConfig->bufferProvider.releaseBuffer = nullptr; - if (config.accessMode.getDiscriminator() == - EffectBufferConfig::OptionalAccessMode::hidl_discriminator::value) { - halConfig->mask |= EFFECT_CONFIG_ACC_MODE; - halConfig->accessMode = static_cast<uint8_t>(config.accessMode.value()); - } -} - #endif // MAJOR_VERSION <= 6 -void Effect::effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config) { - effectBufferConfigFromHal(halConfig.inputCfg, &config->inputCfg); - effectBufferConfigFromHal(halConfig.outputCfg, &config->outputCfg); -} - -// static -void Effect::effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig) { - effectBufferConfigToHal(config.inputCfg, &halConfig->inputCfg); - effectBufferConfigToHal(config.outputCfg, &halConfig->outputCfg); -} - // static void Effect::effectOffloadParamToHal(const EffectOffloadParameter& offload, effect_offload_param_t* halOffload) { @@ -373,7 +285,7 @@ void Effect::getConfigImpl(int commandCode, const char* commandName, GetConfigCa (*mHandle)->command(mHandle, commandCode, 0, NULL, &halResultSize, &halConfig); EffectConfig config; if (status == OK) { - effectConfigFromHal(halConfig, &config); + status = EffectUtils::effectConfigFromHal(halConfig, mIsInput, &config); } cb(analyzeCommandStatus(commandName, sContextCallToCommand, status), config); } @@ -538,7 +450,7 @@ Result Effect::setConfigImpl(int commandCode, const char* commandName, const Eff const sp<IEffectBufferProviderCallback>& inputBufferProvider, const sp<IEffectBufferProviderCallback>& outputBufferProvider) { effect_config_t halConfig; - effectConfigToHal(config, &halConfig); + EffectUtils::effectConfigToHal(config, &halConfig); if (inputBufferProvider != 0) { LOG_FATAL("Using input buffer provider is not supported"); } @@ -733,7 +645,7 @@ Return<void> Effect::getDescriptor(getDescriptor_cb _hidl_cb) { status_t status = (*mHandle)->get_descriptor(mHandle, &halDescriptor); EffectDescriptor descriptor; if (status == OK) { - effectDescriptorFromHal(halDescriptor, &descriptor); + status = EffectUtils::effectDescriptorFromHal(halDescriptor, &descriptor); } _hidl_cb(analyzeStatus("get_descriptor", "", sContextCallFunction, status), descriptor); return Void(); diff --git a/audio/effect/all-versions/default/Effect.h b/audio/effect/all-versions/default/Effect.h index 9aa47ea7d9..d5218f7240 100644 --- a/audio/effect/all-versions/default/Effect.h +++ b/audio/effect/all-versions/default/Effect.h @@ -203,11 +203,6 @@ struct Effect : public IEffect { EffectAuxChannelsConfig* config); static void effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig& config, channel_config_t* halConfig); - void effectBufferConfigFromHal(const buffer_config_t& halConfig, EffectBufferConfig* config); - static void effectBufferConfigToHal(const EffectBufferConfig& config, - buffer_config_t* halConfig); - void effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config); - static void effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig); static void effectOffloadParamToHal(const EffectOffloadParameter& offload, effect_offload_param_t* halOffload); static std::vector<uint8_t> parameterToHal(uint32_t paramSize, const void* paramData, diff --git a/audio/effect/all-versions/default/EffectsFactory.cpp b/audio/effect/all-versions/default/EffectsFactory.cpp index 1ea990b3b6..eb1cb4971c 100644 --- a/audio/effect/all-versions/default/EffectsFactory.cpp +++ b/audio/effect/all-versions/default/EffectsFactory.cpp @@ -19,7 +19,6 @@ #include "AcousticEchoCancelerEffect.h" #include "AutomaticGainControlEffect.h" #include "BassBoostEffect.h" -#include "Conversions.h" #include "DownmixEffect.h" #include "Effect.h" #include "EnvironmentalReverbEffect.h" @@ -27,11 +26,11 @@ #include "LoudnessEnhancerEffect.h" #include "NoiseSuppressionEffect.h" #include "PresetReverbEffect.h" -#include "UuidUtils.h" #include "VirtualizerEffect.h" #include "VisualizerEffect.h" #include "common/all-versions/default/EffectMap.h" +#include <UuidUtils.h> #include <android/log.h> #include <media/EffectsFactoryApi.h> #include <system/audio_effects/effect_aec.h> @@ -45,6 +44,7 @@ #include <system/audio_effects/effect_presetreverb.h> #include <system/audio_effects/effect_virtualizer.h> #include <system/audio_effects/effect_visualizer.h> +#include <util/EffectUtils.h> namespace android { namespace hardware { @@ -107,7 +107,7 @@ restart: effect_descriptor_t halDescriptor; status = EffectQueryEffect(i, &halDescriptor); if (status == OK) { - effectDescriptorFromHal(halDescriptor, &result[i]); + EffectUtils::effectDescriptorFromHal(halDescriptor, &result[i]); } else { ALOGE("Error querying effect at position %d / %d: %s", i, numEffects, strerror(-status)); @@ -141,11 +141,11 @@ Return<void> EffectsFactory::getDescriptor(const Uuid& uuid, getDescriptor_cb _h effect_descriptor_t halDescriptor; status_t status = EffectGetDescriptor(&halUuid, &halDescriptor); EffectDescriptor descriptor; - effectDescriptorFromHal(halDescriptor, &descriptor); + EffectUtils::effectDescriptorFromHal(halDescriptor, &descriptor); Result retval(Result::OK); if (status != OK) { - ALOGE("Error querying effect descriptor for %s: %s", uuidToString(halUuid).c_str(), - strerror(-status)); + ALOGE("Error querying effect descriptor for %s: %s", + UuidUtils::uuidToString(halUuid).c_str(), strerror(-status)); if (status == -ENOENT) { retval = Result::INVALID_ARGUMENTS; } else { @@ -191,13 +191,14 @@ Return<void> EffectsFactory::createEffectImpl(const Uuid& uuid, int32_t session, effect = dispatchEffectInstanceCreation(halDescriptor, handle); effectId = EffectMap::getInstance().add(handle); } else { - ALOGE("Error querying effect descriptor for %s: %s", uuidToString(halUuid).c_str(), - strerror(-status)); + ALOGE("Error querying effect descriptor for %s: %s", + UuidUtils::uuidToString(halUuid).c_str(), strerror(-status)); EffectRelease(handle); } } if (status != OK) { - ALOGE("Error creating effect %s: %s", uuidToString(halUuid).c_str(), strerror(-status)); + ALOGE("Error creating effect %s: %s", UuidUtils::uuidToString(halUuid).c_str(), + strerror(-status)); if (status == -ENOENT) { retval = Result::INVALID_ARGUMENTS; } else { diff --git a/audio/effect/all-versions/default/TEST_MAPPING b/audio/effect/all-versions/default/TEST_MAPPING new file mode 100644 index 0000000000..b66e4e4758 --- /dev/null +++ b/audio/effect/all-versions/default/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "android.hardware.audio.effect@7.0-util_tests" + } + ] +} diff --git a/audio/effect/all-versions/default/util/Android.bp b/audio/effect/all-versions/default/util/Android.bp new file mode 100644 index 0000000000..5ba19d3a2d --- /dev/null +++ b/audio/effect/all-versions/default/util/Android.bp @@ -0,0 +1,136 @@ +cc_defaults { + name: "android.hardware.audio.effect-util_default", + defaults: ["hidl_defaults"], + + vendor_available: true, + + export_include_dirs: ["include"], + + srcs: [ + "EffectUtils.cpp", + ], + + shared_libs: [ + "liblog", + "libutils", + "libhidlbase", + "android.hardware.audio.common-util", + ], + export_shared_lib_headers: [ + "android.hardware.audio.common-util", + ], + + header_libs: [ + "libaudio_system_headers", + "libhardware_headers", + ], +} + +cc_library_shared { + name: "android.hardware.audio.effect@2.0-util", + defaults: ["android.hardware.audio.effect-util_default"], + shared_libs: [ + "android.hardware.audio.common@2.0", + "android.hardware.audio.common@2.0-util", + "android.hardware.audio.effect@2.0", + ], + cflags: [ + "-DMAJOR_VERSION=2", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], +} + +cc_library_shared { + name: "android.hardware.audio.effect@4.0-util", + defaults: ["android.hardware.audio.effect-util_default"], + shared_libs: [ + "android.hardware.audio.common@4.0", + "android.hardware.audio.common@4.0-util", + "android.hardware.audio.effect@4.0", + ], + cflags: [ + "-DMAJOR_VERSION=4", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], +} + +cc_library_shared { + name: "android.hardware.audio.effect@5.0-util", + defaults: ["android.hardware.audio.effect-util_default"], + shared_libs: [ + "android.hardware.audio.common@5.0", + "android.hardware.audio.common@5.0-util", + "android.hardware.audio.effect@5.0", + ], + cflags: [ + "-DMAJOR_VERSION=5", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], +} + +cc_library_shared { + name: "android.hardware.audio.effect@6.0-util", + defaults: ["android.hardware.audio.effect-util_default"], + shared_libs: [ + "android.hardware.audio.common@6.0", + "android.hardware.audio.common@6.0-util", + "android.hardware.audio.effect@6.0", + ], + cflags: [ + "-DMAJOR_VERSION=6", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], +} + +cc_library { + name: "android.hardware.audio.effect@7.0-util", + defaults: ["android.hardware.audio.effect-util_default"], + shared_libs: [ + "android.hardware.audio.common@7.0", + "android.hardware.audio.common@7.0-util", + "android.hardware.audio.effect@7.0", + ], + cflags: [ + "-DMAJOR_VERSION=7", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], +} + +// Note: this isn't a VTS test, but rather a unit test +// to verify correctness of conversion utilities. +cc_test { + name: "android.hardware.audio.effect@7.0-util_tests", + defaults: ["android.hardware.audio.effect-util_default"], + + srcs: ["tests/effectutils_tests.cpp"], + + // Use static linking to allow running in presubmit on + // targets that don't have HAL V7. + static_libs: [ + "android.hardware.audio.common@7.0", + "android.hardware.audio.common@7.0-enums", + "android.hardware.audio.common@7.0-util", + "android.hardware.audio.effect@7.0", + "android.hardware.audio.effect@7.0-util", + ], + + shared_libs: [ + "libbase", + "libxml2", + ], + + cflags: [ + "-Werror", + "-Wall", + "-DMAJOR_VERSION=7", + "-DMINOR_VERSION=0", + "-include common/all-versions/VersionMacro.h", + ], + + test_suites: ["device-tests"], +} diff --git a/audio/effect/all-versions/default/util/EffectUtils.cpp b/audio/effect/all-versions/default/util/EffectUtils.cpp new file mode 100644 index 0000000000..1c0419aba3 --- /dev/null +++ b/audio/effect/all-versions/default/util/EffectUtils.cpp @@ -0,0 +1,183 @@ +/* + * 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 <memory.h> + +#include <HidlUtils.h> +#include <UuidUtils.h> +#include <common/all-versions/VersionUtils.h> + +#include "util/EffectUtils.h" + +using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils; +using ::android::hardware::audio::common::CPP_VERSION::implementation::UuidUtils; +using ::android::hardware::audio::common::utils::EnumBitfield; + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace CPP_VERSION { +namespace implementation { + +using namespace ::android::hardware::audio::common::CPP_VERSION; + +#define CONVERT_CHECKED(expr, result) \ + if (status_t status = (expr); status != NO_ERROR) { \ + result = status; \ + } + +#if MAJOR_VERSION <= 6 + +status_t EffectUtils::effectBufferConfigFromHal(const buffer_config_t& halConfig, bool /*isInput*/, + EffectBufferConfig* config) { + config->buffer.id = 0; + config->buffer.frameCount = 0; + config->samplingRateHz = halConfig.samplingRate; + config->channels = EnumBitfield<AudioChannelMask>(halConfig.channels); + config->format = AudioFormat(halConfig.format); + config->accessMode = EffectBufferAccess(halConfig.accessMode); + config->mask = EnumBitfield<EffectConfigParameters>(halConfig.mask); + return NO_ERROR; +} + +status_t EffectUtils::effectBufferConfigToHal(const EffectBufferConfig& config, + buffer_config_t* halConfig) { + // Note: setting the buffers directly is considered obsolete. They need to be set + // using 'setProcessBuffers'. + halConfig->buffer.frameCount = 0; + halConfig->buffer.raw = nullptr; + halConfig->samplingRate = config.samplingRateHz; + halConfig->channels = static_cast<uint32_t>(config.channels); + // Note: The framework code does not use BP. + halConfig->bufferProvider.cookie = nullptr; + halConfig->bufferProvider.getBuffer = nullptr; + halConfig->bufferProvider.releaseBuffer = nullptr; + halConfig->format = static_cast<uint8_t>(config.format); + halConfig->accessMode = static_cast<uint8_t>(config.accessMode); + halConfig->mask = static_cast<uint8_t>(config.mask); + return NO_ERROR; +} + +#else + +status_t EffectUtils::effectBufferConfigFromHal(const buffer_config_t& halConfig, bool isInput, + EffectBufferConfig* config) { + status_t result = NO_ERROR; + config->buffer.unspecified(); + audio_config_base_t halConfigBase = {halConfig.samplingRate, + static_cast<audio_channel_mask_t>(halConfig.channels), + static_cast<audio_format_t>(halConfig.format)}; + CONVERT_CHECKED(HidlUtils::audioConfigBaseOptionalFromHal( + halConfigBase, isInput, halConfig.mask & EFFECT_CONFIG_FORMAT, + halConfig.mask & EFFECT_CONFIG_SMP_RATE, + halConfig.mask & EFFECT_CONFIG_CHANNELS, &config->base), + result); + if (halConfig.mask & EFFECT_CONFIG_ACC_MODE) { + config->accessMode.value(EffectBufferAccess(halConfig.accessMode)); + } + return result; +} + +status_t EffectUtils::effectBufferConfigToHal(const EffectBufferConfig& config, + buffer_config_t* halConfig) { + status_t result = NO_ERROR; + // Note: setting the buffers directly is considered obsolete. They need to be set + // using 'setProcessBuffers'. + halConfig->buffer.frameCount = 0; + halConfig->buffer.raw = nullptr; + audio_config_base_t halConfigBase = AUDIO_CONFIG_BASE_INITIALIZER; + bool formatSpecified = false, sRateSpecified = false, channelMaskSpecified = false; + CONVERT_CHECKED( + HidlUtils::audioConfigBaseOptionalToHal(config.base, &halConfigBase, &formatSpecified, + &sRateSpecified, &channelMaskSpecified), + result); + halConfig->mask = 0; + if (sRateSpecified) { + halConfig->mask |= EFFECT_CONFIG_SMP_RATE; + halConfig->samplingRate = halConfigBase.sample_rate; + } + if (channelMaskSpecified) { + halConfig->mask |= EFFECT_CONFIG_CHANNELS; + halConfig->channels = halConfigBase.channel_mask; + } + if (formatSpecified) { + halConfig->mask |= EFFECT_CONFIG_FORMAT; + halConfig->format = halConfigBase.format; + } + // Note: The framework code does not use BP. + halConfig->bufferProvider.cookie = nullptr; + halConfig->bufferProvider.getBuffer = nullptr; + halConfig->bufferProvider.releaseBuffer = nullptr; + if (config.accessMode.getDiscriminator() == + EffectBufferConfig::OptionalAccessMode::hidl_discriminator::value) { + halConfig->mask |= EFFECT_CONFIG_ACC_MODE; + halConfig->accessMode = static_cast<uint8_t>(config.accessMode.value()); + } + return result; +} + +#endif // MAJOR_VERSION >= 6 + +status_t EffectUtils::effectConfigFromHal(const effect_config_t& halConfig, bool isInput, + EffectConfig* config) { + status_t result = NO_ERROR; + CONVERT_CHECKED(effectBufferConfigFromHal(halConfig.inputCfg, isInput, &config->inputCfg), + result); + CONVERT_CHECKED(effectBufferConfigFromHal(halConfig.outputCfg, isInput, &config->outputCfg), + result); + return result; +} + +status_t EffectUtils::effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig) { + status_t result = NO_ERROR; + CONVERT_CHECKED(effectBufferConfigToHal(config.inputCfg, &halConfig->inputCfg), result); + CONVERT_CHECKED(effectBufferConfigToHal(config.outputCfg, &halConfig->outputCfg), result); + return result; +} + +status_t EffectUtils::effectDescriptorFromHal(const effect_descriptor_t& halDescriptor, + EffectDescriptor* descriptor) { + UuidUtils::uuidFromHal(halDescriptor.type, &descriptor->type); + UuidUtils::uuidFromHal(halDescriptor.uuid, &descriptor->uuid); + descriptor->flags = EnumBitfield<EffectFlags>(halDescriptor.flags); + descriptor->cpuLoad = halDescriptor.cpuLoad; + descriptor->memoryUsage = halDescriptor.memoryUsage; + memcpy(descriptor->name.data(), halDescriptor.name, descriptor->name.size()); + memcpy(descriptor->implementor.data(), halDescriptor.implementor, + descriptor->implementor.size()); + return NO_ERROR; +} + +status_t EffectUtils::effectDescriptorToHal(const EffectDescriptor& descriptor, + effect_descriptor_t* halDescriptor) { + UuidUtils::uuidToHal(descriptor.type, &halDescriptor->type); + UuidUtils::uuidToHal(descriptor.uuid, &halDescriptor->uuid); + halDescriptor->flags = static_cast<uint32_t>(descriptor.flags); + halDescriptor->cpuLoad = descriptor.cpuLoad; + halDescriptor->memoryUsage = descriptor.memoryUsage; + memcpy(halDescriptor->name, descriptor.name.data(), descriptor.name.size()); + memcpy(halDescriptor->implementor, descriptor.implementor.data(), + descriptor.implementor.size()); + return NO_ERROR; +} + +} // namespace implementation +} // namespace CPP_VERSION +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/effect/all-versions/default/util/include/util/EffectUtils.h b/audio/effect/all-versions/default/util/include/util/EffectUtils.h new file mode 100644 index 0000000000..23963b4d41 --- /dev/null +++ b/audio/effect/all-versions/default/util/include/util/EffectUtils.h @@ -0,0 +1,53 @@ +/* + * 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 + +// clang-format off +#include PATH(android/hardware/audio/effect/FILE_VERSION/types.h) +// clang-format on + +#include <system/audio_effect.h> + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace CPP_VERSION { +namespace implementation { + +using namespace ::android::hardware::audio::effect::CPP_VERSION; + +struct EffectUtils { + static status_t effectBufferConfigFromHal(const buffer_config_t& halConfig, bool isInput, + EffectBufferConfig* config); + static status_t effectBufferConfigToHal(const EffectBufferConfig& config, + buffer_config_t* halConfig); + static status_t effectConfigFromHal(const effect_config_t& halConfig, bool isInput, + EffectConfig* config); + static status_t effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig); + static status_t effectDescriptorFromHal(const effect_descriptor_t& halDescriptor, + EffectDescriptor* descriptor); + static status_t effectDescriptorToHal(const EffectDescriptor& descriptor, + effect_descriptor_t* halDescriptor); +}; + +} // namespace implementation +} // namespace CPP_VERSION +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/effect/all-versions/default/util/tests/effectutils_tests.cpp b/audio/effect/all-versions/default/util/tests/effectutils_tests.cpp new file mode 100644 index 0000000000..7eb8cd2958 --- /dev/null +++ b/audio/effect/all-versions/default/util/tests/effectutils_tests.cpp @@ -0,0 +1,144 @@ +/* + * 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 <string> + +#include <gtest/gtest.h> + +#define LOG_TAG "EffectUtils_Test" +#include <log/log.h> + +#include <android_audio_policy_configuration_V7_0-enums.h> +#include <system/audio_effect.h> +#include <util/EffectUtils.h> +#include <xsdc/XsdcSupport.h> + +using namespace android; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using namespace ::android::hardware::audio::effect::CPP_VERSION; +using ::android::hardware::audio::effect::CPP_VERSION::implementation::EffectUtils; +namespace xsd { +using namespace ::android::audio::policy::configuration::V7_0; +} + +static constexpr audio_channel_mask_t kInvalidHalChannelMask = AUDIO_CHANNEL_INVALID; +static constexpr audio_format_t kInvalidHalFormat = AUDIO_FORMAT_INVALID; + +// Not generated automatically because AudioBuffer contains +// instances of hidl_memory which can't be compared properly +// in general case due to presence of handles. +// +// However, in this particular case, handles must not present +// thus comparison is possible. +// +// operator== must be defined in the same namespace as the structures. +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace CPP_VERSION { +inline bool operator==(const AudioBuffer& lhs, const AudioBuffer& rhs) { + return lhs.id == rhs.id && lhs.frameCount == rhs.frameCount && lhs.data.handle() == nullptr && + rhs.data.handle() == nullptr; +} + +inline bool operator==(const EffectBufferConfig& lhs, const EffectBufferConfig& rhs) { + return lhs.buffer.getDiscriminator() == rhs.buffer.getDiscriminator() && + (lhs.buffer.getDiscriminator() == + EffectBufferConfig::OptionalBuffer::hidl_discriminator::unspecified || + lhs.buffer.buf() == rhs.buffer.buf()) && + lhs.base == rhs.base && lhs.accessMode == rhs.accessMode; +} + +inline bool operator==(const EffectConfig& lhs, const EffectConfig& rhs) { + return lhs.inputCfg == rhs.inputCfg && lhs.outputCfg == rhs.outputCfg; +} +} // namespace CPP_VERSION +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +TEST(EffectUtils, ConvertInvalidBufferConfig) { + buffer_config_t halInvalid; + EffectBufferConfig invalidChannelMask; + invalidChannelMask.base.channelMask.value("random string"); + EXPECT_EQ(BAD_VALUE, EffectUtils::effectBufferConfigToHal(invalidChannelMask, &halInvalid)); + EffectBufferConfig invalidFormat; + invalidFormat.base.format.value("random string"); + EXPECT_EQ(BAD_VALUE, EffectUtils::effectBufferConfigToHal(invalidFormat, &halInvalid)); + + buffer_config_t halInvalidChannelMask; + EffectBufferConfig invalid; + halInvalidChannelMask.channels = kInvalidHalChannelMask; + halInvalidChannelMask.mask = EFFECT_CONFIG_CHANNELS; + EXPECT_EQ(BAD_VALUE, EffectUtils::effectBufferConfigFromHal(halInvalidChannelMask, + false /*isInput*/, &invalid)); + EXPECT_EQ(BAD_VALUE, EffectUtils::effectBufferConfigFromHal(halInvalidChannelMask, + true /*isInput*/, &invalid)); + buffer_config_t halInvalidFormat; + halInvalidFormat.format = (uint8_t)kInvalidHalFormat; + halInvalidFormat.mask = EFFECT_CONFIG_FORMAT; + EXPECT_EQ(BAD_VALUE, EffectUtils::effectBufferConfigFromHal(halInvalidFormat, false /*isInput*/, + &invalid)); + EXPECT_EQ(BAD_VALUE, + EffectUtils::effectBufferConfigFromHal(halInvalidFormat, true /*isInput*/, &invalid)); +} + +TEST(EffectUtils, ConvertBufferConfig) { + EffectBufferConfig empty; + buffer_config_t halEmpty; + EXPECT_EQ(NO_ERROR, EffectUtils::effectBufferConfigToHal(empty, &halEmpty)); + EffectBufferConfig emptyBackOut; + EXPECT_EQ(NO_ERROR, + EffectUtils::effectBufferConfigFromHal(halEmpty, false /*isInput*/, &emptyBackOut)); + EXPECT_EQ(empty, emptyBackOut); + EffectBufferConfig emptyBackIn; + EXPECT_EQ(NO_ERROR, + EffectUtils::effectBufferConfigFromHal(halEmpty, true /*isInput*/, &emptyBackIn)); + EXPECT_EQ(empty, emptyBackIn); + + EffectBufferConfig chanMask; + chanMask.base.channelMask.value(toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO)); + buffer_config_t halChanMask; + EXPECT_EQ(NO_ERROR, EffectUtils::effectBufferConfigToHal(chanMask, &halChanMask)); + EffectBufferConfig chanMaskBack; + EXPECT_EQ(NO_ERROR, EffectUtils::effectBufferConfigFromHal(halChanMask, false /*isInput*/, + &chanMaskBack)); + EXPECT_EQ(chanMask, chanMaskBack); + + EffectBufferConfig format; + format.base.format.value(toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT)); + buffer_config_t halFormat; + EXPECT_EQ(NO_ERROR, EffectUtils::effectBufferConfigToHal(format, &halFormat)); + EffectBufferConfig formatBackOut; + EXPECT_EQ(NO_ERROR, + EffectUtils::effectBufferConfigFromHal(halFormat, false /*isInput*/, &formatBackOut)); + EXPECT_EQ(format, formatBackOut); + EffectBufferConfig formatBackIn; + EXPECT_EQ(NO_ERROR, + EffectUtils::effectBufferConfigFromHal(halFormat, true /*isInput*/, &formatBackIn)); + EXPECT_EQ(format, formatBackIn); +} + +TEST(EffectUtils, ConvertDescriptor) { + EffectDescriptor desc{}; + effect_descriptor_t halDesc; + EXPECT_EQ(NO_ERROR, EffectUtils::effectDescriptorToHal(desc, &halDesc)); + EffectDescriptor descBack; + EXPECT_EQ(NO_ERROR, EffectUtils::effectDescriptorFromHal(halDesc, &descBack)); + EXPECT_EQ(desc, descBack); +} |