From 574a86fa361314024c5e94cd6b0384e809740868 Mon Sep 17 00:00:00 2001 From: jiabin Date: Fri, 5 Mar 2021 06:42:05 +0000 Subject: [PATCH] Add AudioTransport to replace AudioProfile in AudioPort. An AudioTransport contains AudioProfile or hardware descriptor to describe the audio capabilities for an AudioPort and the encapsulation type to represent the encapsualtion format that must be used when sending the audio data with the format associated the AudioTransport to Android. The hardware descriptor will be used when the format is not recognized by the platform. Currently, the short audio descriptor is added as one of the hardware descriptors. Short audio descriptor is reported from EDID for HDMI. Bug: 131736540 Bug: 178619392 Test: atest android.hardware.audio.common@7.0-util_tests Test: atest VtsHalAudioV7_0TargetTest Change-Id: Ic5ed9ff9b694511fdd7e90cdcda2777bdfa74f65 --- audio/7.0/config/api/current.txt | 8 + .../7.0/config/audio_policy_configuration.xsd | 7 + ...id_audio_policy_configuration_V7_0-enums.h | 4 + audio/common/7.0/types.hal | 45 +++++- .../all-versions/default/7.0/HidlUtils.cpp | 141 ++++++++++++++++-- audio/common/all-versions/default/HidlUtils.h | 8 + .../default/tests/hidlutils_tests.cpp | 81 ++++++++-- 7 files changed, 268 insertions(+), 26 deletions(-) diff --git a/audio/7.0/config/api/current.txt b/audio/7.0/config/api/current.txt index 48093c599c..eb8c2dd35e 100644 --- a/audio/7.0/config/api/current.txt +++ b/audio/7.0/config/api/current.txt @@ -155,6 +155,12 @@ package android.audio.policy.configuration.V7_0 { enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET; } + public enum AudioEncapsulationType { + method @NonNull public String getRawName(); + enum_constant public static final android.audio.policy.configuration.V7_0.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_IEC61937; + enum_constant public static final android.audio.policy.configuration.V7_0.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_NONE; + } + public enum AudioFormat { method @NonNull public String getRawName(); enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC; @@ -487,10 +493,12 @@ package android.audio.policy.configuration.V7_0 { public class Profile { ctor public Profile(); method @Nullable public java.util.List getChannelMasks(); + method @Nullable public android.audio.policy.configuration.V7_0.AudioEncapsulationType getEncapsulationType(); method @Nullable public String getFormat(); method @Nullable public String getName(); method @Nullable public java.util.List getSamplingRates(); method public void setChannelMasks(@Nullable java.util.List); + method public void setEncapsulationType(@Nullable android.audio.policy.configuration.V7_0.AudioEncapsulationType); method public void setFormat(@Nullable String); method public void setName(@Nullable String); method public void setSamplingRates(@Nullable java.util.List); diff --git a/audio/7.0/config/audio_policy_configuration.xsd b/audio/7.0/config/audio_policy_configuration.xsd index ccaaf98288..007e2501cf 100644 --- a/audio/7.0/config/audio_policy_configuration.xsd +++ b/audio/7.0/config/audio_policy_configuration.xsd @@ -550,11 +550,18 @@ + + + + + + + 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 88dd12e94b..7d83556895 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 @@ -287,6 +287,10 @@ static inline bool isLinearPcm(const std::string& format) { return isLinearPcm(stringToAudioFormat(format)); } +static inline bool isUnknownAudioEncapsulationType(const std::string& encapsulationType) { + return stringToAudioEncapsulationType(encapsulationType) == AudioEncapsulationType::UNKNOWN; +} + } // namespace android::audio::policy::configuration::V7_0 #endif // ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0__ENUMS_H diff --git a/audio/common/7.0/types.hal b/audio/common/7.0/types.hal index 4f920e47cc..6fca93e85b 100644 --- a/audio/common/7.0/types.hal +++ b/audio/common/7.0/types.hal @@ -144,6 +144,14 @@ struct AudioConfigBaseOptional { } channelMask; }; +/** + * Audio encapsulation type indicates the encapsulation type that is required + * for playback/capture. + * See 'audioEncapsulationType' in audio_policy_configuration.xsd for the list + * of allowed values. + */ +typedef string AudioEncapsulationType; + /** * Configurations supported for a certain audio format. */ @@ -155,6 +163,35 @@ struct AudioProfile { vec channelMasks; }; +/** + * AudioTransport struct describes the capability of an audio port. The + * capability is described via AudioProfile or raw hardware descriptors for + * for formats that are not supported by the platform. + */ +struct AudioTransport { + safe_union AudioCapability { + /** + * A certain audio format that is known by the platform and its + * corresponding configuration. + */ + AudioProfile profile; + /** + * The audio descriptor that is reported from EDID. See HDMI + * specification 1.4b section 7 and CEA-861-G section 7.5.2 for more + * information. When this value is set, it indicates the standard is + * AUDIO_STANDARD_EDID. + */ + vec edid; + } audioCapability; + + /** + * The encapsulation type that is required when the framework is using this + * format when playing or capturing to/from a stream or device exposing this + * audio transport. + */ + AudioEncapsulationType encapsulationType; +}; + /** * Major modes for a mobile device. The current mode setting affects audio * routing. @@ -488,8 +525,12 @@ struct AudioPort { * E.g. "telephony_tx" or "fm_tuner". */ string name; - /** List of audio profiles supported by the port. */ - vec profiles; + /** + * List of audio transports supported by the audio port. This includes + * supported formats and raw hardware descriptors for formats not supported + * by the platform. + */ + vec transports; /** List of gain controls attached to the port. */ vec gains; /** Parameters that depend on the actual port role. */ diff --git a/audio/common/all-versions/default/7.0/HidlUtils.cpp b/audio/common/all-versions/default/7.0/HidlUtils.cpp index 2949fac293..5a5b5d276a 100644 --- a/audio/common/all-versions/default/7.0/HidlUtils.cpp +++ b/audio/common/all-versions/default/7.0/HidlUtils.cpp @@ -715,6 +715,27 @@ status_t HidlUtils::audioPortExtendedInfoToHal(const AudioPortExtendedInfo& ext, return result; } +status_t HidlUtils::encapsulationTypeFromHal(audio_encapsulation_type_t halEncapsulationType, + AudioEncapsulationType* encapsulationType) { + *encapsulationType = audio_encapsulation_type_to_string(halEncapsulationType); + if (!encapsulationType->empty() && !xsd::isUnknownAudioEncapsulationType(*encapsulationType)) { + return NO_ERROR; + } + ALOGE("Unknown audio encapsulation type value 0x%X", halEncapsulationType); + return BAD_VALUE; +} + +status_t HidlUtils::encapsulationTypeToHal(const AudioEncapsulationType& encapsulationType, + audio_encapsulation_type_t* halEncapsulationType) { + if (!xsd::isUnknownAudioEncapsulationType(encapsulationType) && + audio_encapsulation_type_from_string(encapsulationType.c_str(), halEncapsulationType)) { + return NO_ERROR; + } + ALOGE("Unknown audio encapsulation type \"%s\"", encapsulationType.c_str()); + *halEncapsulationType = AUDIO_ENCAPSULATION_TYPE_NONE; + return BAD_VALUE; +} + status_t HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) { struct audio_port_v7 halPortV7 = {}; audio_populate_audio_port_v7(&halPort, &halPortV7); @@ -758,11 +779,7 @@ status_t HidlUtils::audioPortFromHal(const struct audio_port_v7& halPort, AudioP CONVERT_CHECKED(audioPortExtendedInfoFromHal(halPort.role, halPort.type, halDevice, halMix, halSession, &port->ext, &isInput), result); - port->profiles.resize(halPort.num_audio_profiles); - for (size_t i = 0; i < halPort.num_audio_profiles; ++i) { - CONVERT_CHECKED(audioProfileFromHal(halPort.audio_profiles[i], isInput, &port->profiles[i]), - result); - } + CONVERT_CHECKED(audioTransportsFromHal(halPort, isInput, &port->transports), result); port->gains.resize(halPort.num_gains); for (size_t i = 0; i < halPort.num_gains; ++i) { CONVERT_CHECKED(audioGainFromHal(halPort.gains[i], isInput, &port->gains[i]), result); @@ -780,15 +797,7 @@ status_t HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port_v7* ALOGE("HIDL Audio Port name is too long: %zu", port.name.size()); result = BAD_VALUE; } - halPort->num_audio_profiles = port.profiles.size(); - if (halPort->num_audio_profiles > AUDIO_PORT_MAX_AUDIO_PROFILES) { - ALOGE("HIDL Audio Port has too many profiles: %u", halPort->num_audio_profiles); - halPort->num_audio_profiles = AUDIO_PORT_MAX_AUDIO_PROFILES; - result = BAD_VALUE; - } - for (size_t i = 0; i < halPort->num_audio_profiles; ++i) { - CONVERT_CHECKED(audioProfileToHal(port.profiles[i], &halPort->audio_profiles[i]), result); - } + CONVERT_CHECKED(audioTransportsToHal(port.transports, halPort), result); halPort->num_gains = port.gains.size(); if (halPort->num_gains > AUDIO_PORT_MAX_GAINS) { ALOGE("HIDL Audio Port has too many gains: %u", halPort->num_gains); @@ -824,6 +833,110 @@ status_t HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port_v7* return result; } +status_t HidlUtils::audioTransportsFromHal(const struct audio_port_v7& halPort, bool isInput, + hidl_vec* transports) { + if (halPort.num_audio_profiles > AUDIO_PORT_MAX_AUDIO_PROFILES || + halPort.num_extra_audio_descriptors > AUDIO_PORT_MAX_EXTRA_AUDIO_DESCRIPTORS) { + ALOGE("%s, too many audio profiles(%u) or extra audio descriptors(%u)", __func__, + halPort.num_audio_profiles, halPort.num_extra_audio_descriptors); + return BAD_VALUE; + } + status_t result = NO_ERROR; + transports->resize(halPort.num_audio_profiles + halPort.num_extra_audio_descriptors); + size_t idx = 0; + for (size_t i = 0; i < halPort.num_audio_profiles; ++i) { + auto& transport = (*transports)[idx++]; + transport.audioCapability.profile({}); + CONVERT_CHECKED(audioProfileFromHal(halPort.audio_profiles[i], isInput, + &transport.audioCapability.profile()), + result); + CONVERT_CHECKED(encapsulationTypeFromHal(halPort.audio_profiles[i].encapsulation_type, + &transport.encapsulationType), + result); + } + for (size_t i = 0; i < halPort.num_extra_audio_descriptors; ++i) { + switch (halPort.extra_audio_descriptors[i].standard) { + case AUDIO_STANDARD_EDID: { + const struct audio_extra_audio_descriptor* extraAudioDescriptor = + &halPort.extra_audio_descriptors[i]; + if (extraAudioDescriptor->descriptor_length <= EXTRA_AUDIO_DESCRIPTOR_SIZE) { + auto& transport = (*transports)[idx++]; + transport.audioCapability.edid( + hidl_vec(extraAudioDescriptor->descriptor, + extraAudioDescriptor->descriptor + + extraAudioDescriptor->descriptor_length)); + CONVERT_CHECKED( + encapsulationTypeFromHal(extraAudioDescriptor->encapsulation_type, + &transport.encapsulationType), + result); + } else { + ALOGE("%s, invalid descriptor length %u", __func__, + extraAudioDescriptor->descriptor_length); + result = BAD_VALUE; + } + } break; + case AUDIO_STANDARD_NONE: + default: + ALOGE("%s, invalid standard %u", __func__, + halPort.extra_audio_descriptors[i].standard); + result = BAD_VALUE; + break; + } + } + return result; +} + +status_t HidlUtils::audioTransportsToHal(const hidl_vec& transports, + struct audio_port_v7* halPort) { + status_t result = NO_ERROR; + halPort->num_audio_profiles = 0; + halPort->num_extra_audio_descriptors = 0; + for (const auto& transport : transports) { + switch (transport.audioCapability.getDiscriminator()) { + case AudioTransport::AudioCapability::hidl_discriminator::profile: + if (halPort->num_audio_profiles > AUDIO_PORT_MAX_AUDIO_PROFILES) { + ALOGE("%s, too many audio profiles", __func__); + result = BAD_VALUE; + break; + } + CONVERT_CHECKED( + audioProfileToHal(transport.audioCapability.profile(), + &halPort->audio_profiles[halPort->num_audio_profiles]), + result); + CONVERT_CHECKED(encapsulationTypeToHal( + transport.encapsulationType, + &halPort->audio_profiles[halPort->num_audio_profiles++] + .encapsulation_type), + result); + break; + case AudioTransport::AudioCapability::hidl_discriminator::edid: + if (halPort->num_extra_audio_descriptors > AUDIO_PORT_MAX_EXTRA_AUDIO_DESCRIPTORS) { + ALOGE("%s, too many extra audio descriptors", __func__); + result = BAD_VALUE; + break; + } + if (transport.audioCapability.edid().size() > EXTRA_AUDIO_DESCRIPTOR_SIZE) { + ALOGE("%s, wrong edid size %zu", __func__, + transport.audioCapability.edid().size()); + result = BAD_VALUE; + break; + } + struct audio_extra_audio_descriptor* extraAudioDescriptor = + &halPort->extra_audio_descriptors[halPort->num_extra_audio_descriptors++]; + extraAudioDescriptor->standard = AUDIO_STANDARD_EDID; + extraAudioDescriptor->descriptor_length = transport.audioCapability.edid().size(); + memcpy(extraAudioDescriptor->descriptor, transport.audioCapability.edid().data(), + transport.audioCapability.edid().size() * sizeof(uint8_t)); + + CONVERT_CHECKED(encapsulationTypeToHal(transport.encapsulationType, + &extraAudioDescriptor->encapsulation_type), + result); + break; + } + } + return result; +} + status_t HidlUtils::audioProfileFromHal(const struct audio_profile& halProfile, bool isInput, AudioProfile* profile) { status_t result = NO_ERROR; diff --git a/audio/common/all-versions/default/HidlUtils.h b/audio/common/all-versions/default/HidlUtils.h index dd4ca4d8ca..98ecc0754e 100644 --- a/audio/common/all-versions/default/HidlUtils.h +++ b/audio/common/all-versions/default/HidlUtils.h @@ -126,6 +126,10 @@ struct HidlUtils { static hidl_vec filterOutNonVendorTags(const hidl_vec& tags); static std::vector filterOutNonVendorTags(const std::vector& tags); static std::vector splitAudioTags(const char* halTags); + static status_t audioTransportsFromHal(const struct audio_port_v7& halPort, bool isInput, + hidl_vec* transports); + static status_t audioTransportsToHal(const hidl_vec& transports, + struct audio_port_v7* halTransport); private: static status_t audioIndexChannelMaskFromHal(audio_channel_mask_t halChannelMask, @@ -145,6 +149,10 @@ struct HidlUtils { struct audio_port_config_device_ext* device, struct audio_port_config_mix_ext* mix, struct audio_port_config_session_ext* session); + static status_t encapsulationTypeFromHal(audio_encapsulation_type_t halEncapsulationType, + AudioEncapsulationType* encapsulationType); + static status_t encapsulationTypeToHal(const AudioEncapsulationType& encapsulationType, + audio_encapsulation_type_t* halEncapsulationType); #endif // MAJOR_VERSION >= 7 diff --git a/audio/common/all-versions/default/tests/hidlutils_tests.cpp b/audio/common/all-versions/default/tests/hidlutils_tests.cpp index e154453e2b..c9e6fac7b2 100644 --- a/audio/common/all-versions/default/tests/hidlutils_tests.cpp +++ b/audio/common/all-versions/default/tests/hidlutils_tests.cpp @@ -47,6 +47,10 @@ static constexpr audio_source_t kInvalidHalSource = static_cast( // AUDIO_STREAM_DEFAULT is framework-only static constexpr audio_stream_type_t kInvalidHalStreamType = static_cast(-2); static constexpr audio_usage_t kInvalidHalUsage = static_cast(0xFFFFFFFFU); +static constexpr audio_encapsulation_type_t kInvalidEncapsulationType = + static_cast(0xFFFFFFFFU); +static constexpr audio_standard_t kInvalidAudioStandard = + static_cast(0xFFFFFFFFU); TEST(HidlUtils, ConvertInvalidChannelMask) { AudioChannelMask invalid; @@ -950,6 +954,53 @@ TEST(HidlUtils, ConvertAudioPortConfig) { EXPECT_TRUE(audio_port_configs_are_equal(&halConfig, &halConfigBack)); } +TEST(HidlUtils, ConvertInvalidAudioTransports) { + hidl_vec invalid; + struct audio_port_v7 halInvalid = {}; + halInvalid.num_audio_profiles = 1; + halInvalid.audio_profiles[0].format = kInvalidHalFormat; + halInvalid.audio_profiles[0].encapsulation_type = kInvalidEncapsulationType; + halInvalid.num_extra_audio_descriptors = 1; + halInvalid.extra_audio_descriptors[0].standard = kInvalidAudioStandard; + halInvalid.extra_audio_descriptors[0].descriptor_length = EXTRA_AUDIO_DESCRIPTOR_SIZE + 1; + EXPECT_EQ(BAD_VALUE, + HidlUtils::audioTransportsFromHal(halInvalid, false /*isInput*/, &invalid)); + invalid.resize(2); + AudioProfile invalidProfile; + invalidProfile.format = "random string"; + invalid[0].audioCapability.profile(invalidProfile); + invalid[0].encapsulationType = "random string"; + invalid[0].audioCapability.edid(hidl_vec(EXTRA_AUDIO_DESCRIPTOR_SIZE + 1)); + invalid[1].encapsulationType = "random string"; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioTransportsToHal(invalid, &halInvalid)); +} + +TEST(HidlUtils, ConvertAudioTransports) { + hidl_vec transports; + transports.resize(2); + AudioProfile profile; + profile.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT); + profile.sampleRates.resize(2); + profile.sampleRates[0] = 44100; + profile.sampleRates[1] = 48000; + profile.channelMasks.resize(2); + profile.channelMasks[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO); + profile.channelMasks[1] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO); + transports[0].audioCapability.profile(profile); + hidl_vec shortAudioDescriptor({0x11, 0x06, 0x01}); + transports[0].encapsulationType = + toString(xsd::AudioEncapsulationType::AUDIO_ENCAPSULATION_TYPE_NONE); + transports[1].audioCapability.edid(std::move(shortAudioDescriptor)); + transports[1].encapsulationType = + toString(xsd::AudioEncapsulationType::AUDIO_ENCAPSULATION_TYPE_IEC61937); + struct audio_port_v7 halPort; + EXPECT_EQ(NO_ERROR, HidlUtils::audioTransportsToHal(transports, &halPort)); + hidl_vec transportsBack; + EXPECT_EQ(NO_ERROR, + HidlUtils::audioTransportsFromHal(halPort, false /*isInput*/, &transportsBack)); + EXPECT_EQ(transports, transportsBack); +} + TEST(HidlUtils, ConvertInvalidAudioPort) { AudioPort invalid; struct audio_port_v7 halInvalid = {}; @@ -958,8 +1009,10 @@ TEST(HidlUtils, ConvertInvalidAudioPort) { halInvalid.num_audio_profiles = 1; halInvalid.audio_profiles[0].format = kInvalidHalFormat; EXPECT_EQ(BAD_VALUE, HidlUtils::audioPortFromHal(halInvalid, &invalid)); - invalid.profiles.resize(1); - invalid.profiles[0].format = "random string"; + invalid.transports.resize(1); + AudioProfile invalidProfile; + invalidProfile.format = "random string"; + invalid.transports[0].audioCapability.profile(invalidProfile); EXPECT_EQ(BAD_VALUE, HidlUtils::audioPortToHal(invalid, &halInvalid)); } @@ -967,14 +1020,22 @@ TEST(HidlUtils, ConvertAudioPort) { AudioPort port = {}; port.id = 42; port.name = "test"; - port.profiles.resize(1); - port.profiles[0].format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT); - port.profiles[0].sampleRates.resize(2); - port.profiles[0].sampleRates[0] = 44100; - port.profiles[0].sampleRates[1] = 48000; - port.profiles[0].channelMasks.resize(2); - port.profiles[0].channelMasks[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO); - port.profiles[0].channelMasks[1] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO); + port.transports.resize(2); + AudioProfile profile; + profile.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT); + profile.sampleRates.resize(2); + profile.sampleRates[0] = 44100; + profile.sampleRates[1] = 48000; + profile.channelMasks.resize(2); + profile.channelMasks[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO); + profile.channelMasks[1] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO); + port.transports[0].audioCapability.profile(profile); + port.transports[0].encapsulationType = + toString(xsd::AudioEncapsulationType::AUDIO_ENCAPSULATION_TYPE_NONE); + hidl_vec shortAudioDescriptor({0x11, 0x06, 0x01}); + port.transports[1].audioCapability.edid(std::move(shortAudioDescriptor)); + port.transports[1].encapsulationType = + toString(xsd::AudioEncapsulationType::AUDIO_ENCAPSULATION_TYPE_IEC61937); port.gains.resize(1); port.gains[0].channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO); port.ext.device({});