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
This commit is contained in:
jiabin 2021-03-05 06:42:05 +00:00
parent 442a08d3ee
commit 574a86fa36
7 changed files with 268 additions and 26 deletions

View file

@ -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<android.audio.policy.configuration.V7_0.AudioChannelMask> 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<java.math.BigInteger> getSamplingRates();
method public void setChannelMasks(@Nullable java.util.List<android.audio.policy.configuration.V7_0.AudioChannelMask>);
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<java.math.BigInteger>);

View file

@ -550,11 +550,18 @@
<xs:simpleType name="channelMasks">
<xs:list itemType="audioChannelMask" />
</xs:simpleType>
<xs:simpleType name="audioEncapsulationType">
<xs:restriction base="xs:string">
<xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_NONE"/>
<xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_IEC61937"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="profile">
<xs:attribute name="name" type="xs:token" use="optional"/>
<xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
<xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
<xs:attribute name="channelMasks" type="channelMasks" use="optional"/>
<xs:attribute name="encapsulationType" type="audioEncapsulationType" use="optional"/>
</xs:complexType>
<xs:simpleType name="audioGainMode">
<xs:restriction base="xs:string">

View file

@ -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

View file

@ -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<AudioChannelMask> 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<uint8_t> 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<AudioProfile> 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<AudioTransport> transports;
/** List of gain controls attached to the port. */
vec<AudioGain> gains;
/** Parameters that depend on the actual port role. */

View file

@ -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<AudioTransport>* 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<uint8_t>(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<AudioTransport>& 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;

View file

@ -126,6 +126,10 @@ struct HidlUtils {
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);
static status_t audioTransportsFromHal(const struct audio_port_v7& halPort, bool isInput,
hidl_vec<AudioTransport>* transports);
static status_t audioTransportsToHal(const hidl_vec<AudioTransport>& 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

View file

@ -47,6 +47,10 @@ static constexpr audio_source_t kInvalidHalSource = static_cast<audio_source_t>(
// AUDIO_STREAM_DEFAULT is framework-only
static constexpr audio_stream_type_t kInvalidHalStreamType = static_cast<audio_stream_type_t>(-2);
static constexpr audio_usage_t kInvalidHalUsage = static_cast<audio_usage_t>(0xFFFFFFFFU);
static constexpr audio_encapsulation_type_t kInvalidEncapsulationType =
static_cast<audio_encapsulation_type_t>(0xFFFFFFFFU);
static constexpr audio_standard_t kInvalidAudioStandard =
static_cast<audio_standard_t>(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<AudioTransport> 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<uint8_t>(EXTRA_AUDIO_DESCRIPTOR_SIZE + 1));
invalid[1].encapsulationType = "random string";
EXPECT_EQ(BAD_VALUE, HidlUtils::audioTransportsToHal(invalid, &halInvalid));
}
TEST(HidlUtils, ConvertAudioTransports) {
hidl_vec<AudioTransport> 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<uint8_t> 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<AudioTransport> 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<uint8_t> 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({});