From 5b8a144d8ca5c99c1d3149ef74399b9a38b05cdc Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 29 Oct 2020 13:08:05 -0700 Subject: [PATCH] Implement a.h.audio.common@7.0-util module This includes a rewrite of HidlUtils for V7. A unit test is added for its conversion functions. Made necessary minor adjustments to the HAL V7 types. Also, fixed definition of 'audioFormatsList' to allow for vendor extensions. Bug: 142480271 Bug: 173647783 Test: m && atest android.hardware.audio.common@7.0-util_tests Change-Id: Ib883f1c246fce78c004846516699aa724d4b5d44 --- audio/7.0/config/api/current.txt | 12 +- .../7.0/config/audio_policy_configuration.xsd | 4 +- audio/7.0/types.hal | 35 +- ...id_audio_policy_configuration_V7_0-enums.h | 39 + audio/common/7.0/types.hal | 30 +- .../all-versions/default/7.0/HidlUtils.cpp | 847 ++++++++++++++++++ audio/common/all-versions/default/Android.bp | 58 +- .../common/all-versions/default/HidlUtils.cpp | 69 +- audio/common/all-versions/default/HidlUtils.h | 135 ++- .../common/all-versions/default/TEST_MAPPING | 7 + .../default/tests/hidlutils_tests.cpp | 631 +++++++++++++ .../core/all-versions/default/Conversions.cpp | 1 + audio/core/all-versions/default/Device.cpp | 6 +- .../4.0/AudioPrimaryHidlHalTest.cpp | 3 +- .../7.0/AudioPrimaryHidlHalTest.cpp | 3 +- 15 files changed, 1771 insertions(+), 109 deletions(-) create mode 100644 audio/common/all-versions/default/7.0/HidlUtils.cpp create mode 100644 audio/common/all-versions/default/TEST_MAPPING create mode 100644 audio/common/all-versions/default/tests/hidlutils_tests.cpp diff --git a/audio/7.0/config/api/current.txt b/audio/7.0/config/api/current.txt index fea697993e..1da8b095bc 100644 --- a/audio/7.0/config/api/current.txt +++ b/audio/7.0/config/api/current.txt @@ -360,7 +360,7 @@ package android.audio.policy.configuration.V7_0 { public static class DevicePorts.DevicePort { ctor public DevicePorts.DevicePort(); method @Nullable public String getAddress(); - method @Nullable public java.util.List getEncodedFormats(); + method @Nullable public java.util.List getEncodedFormats(); method @Nullable public android.audio.policy.configuration.V7_0.Gains getGains(); method @Nullable public java.util.List getProfile(); method @Nullable public android.audio.policy.configuration.V7_0.Role getRole(); @@ -368,7 +368,7 @@ package android.audio.policy.configuration.V7_0 { method @Nullable public String getType(); method @Nullable public boolean get_default(); method public void setAddress(@Nullable String); - method public void setEncodedFormats(@Nullable java.util.List); + method public void setEncodedFormats(@Nullable java.util.List); method public void setGains(@Nullable android.audio.policy.configuration.V7_0.Gains); method public void setRole(@Nullable android.audio.policy.configuration.V7_0.Role); method public void setTagName(@Nullable String); @@ -527,10 +527,10 @@ package android.audio.policy.configuration.V7_0 { public static class SurroundFormats.Format { ctor public SurroundFormats.Format(); - method @Nullable public android.audio.policy.configuration.V7_0.AudioFormat getName(); - method @Nullable public java.util.List getSubformats(); - method public void setName(@Nullable android.audio.policy.configuration.V7_0.AudioFormat); - method public void setSubformats(@Nullable java.util.List); + method @Nullable public String getName(); + method @Nullable public java.util.List getSubformats(); + method public void setName(@Nullable String); + method public void setSubformats(@Nullable java.util.List); } public class SurroundSound { diff --git a/audio/7.0/config/audio_policy_configuration.xsd b/audio/7.0/config/audio_policy_configuration.xsd index 67848287ef..56b3a27161 100644 --- a/audio/7.0/config/audio_policy_configuration.xsd +++ b/audio/7.0/config/audio_policy_configuration.xsd @@ -774,13 +774,13 @@ - + - + diff --git a/audio/7.0/types.hal b/audio/7.0/types.hal index 6cac9c95fe..1ae7bad310 100644 --- a/audio/7.0/types.hal +++ b/audio/7.0/types.hal @@ -179,7 +179,8 @@ struct AudioFrequencyResponsePoint { * Used by StreamIn and Device */ struct MicrophoneInfo { - /** Unique alphanumeric id for microphone. Guaranteed to be the same + /** + * Unique alphanumeric id for microphone. Guaranteed to be the same * even after rebooting. */ string deviceId; @@ -187,18 +188,21 @@ struct MicrophoneInfo { * Device specific information */ DeviceAddress deviceAddress; - /** Each element of the vector must describe the channel with the same - * index. + /** + * Each element of the vector must describe the channel with the same + * index. */ vec channelMapping; /** Location of the microphone in regard to the body of the device */ AudioMicrophoneLocation location; - /** Identifier to help group related microphones together - * e.g. microphone arrays should belong to the same group + /** + * Identifier to help group related microphones together + * e.g. microphone arrays should belong to the same group */ AudioMicrophoneGroup group; - /** Index of this microphone within the group. - * (group, index) must be unique within the same device. + /** + * Index of this microphone within the group. + * (group, index) must be unique within the same device. */ uint32_t indexInTheGroup; /** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL */ @@ -209,17 +213,20 @@ struct MicrophoneInfo { float minSpl; /** Standard polar pattern of the microphone */ AudioMicrophoneDirectionality directionality; - /** Vector with ordered frequency responses (from low to high frequencies) - * with the frequency response of the microphone. - * Levels are in dB, relative to level at 1000 Hz + /** + * Vector with ordered frequency responses (from low to high frequencies) + * with the frequency response of the microphone. + * Levels are in dB, relative to level at 1000 Hz */ vec frequencyResponse; - /** Position of the microphone's capsule in meters, from the - * bottom-left-back corner of the bounding box of device. + /** + * Position of the microphone's capsule in meters, from the + * bottom-left-back corner of the bounding box of device. */ AudioMicrophoneCoordinate position; - /** Normalized point to signal the main orientation of the microphone's - * capsule. sqrt(x^2 + y^2 + z^2) = 1 + /** + * Normalized point to signal the main orientation of the microphone's + * capsule. sqrt(x^2 + y^2 + z^2) = 1 */ AudioMicrophoneCoordinate orientation; }; 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 7148d76820..414eede6d1 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 @@ -18,6 +18,8 @@ #define ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H #include +#include +#include #include @@ -210,6 +212,43 @@ static inline bool isOutputDevice(const std::string& device) { return isOutputDevice(stringToAudioDevice(device)); } +static inline bool isVendorExtension(const std::string& device) { + // Must match the "vendorExtension" rule from the XSD file. + static const std::string vendorPrefix = "VX_"; + return device.size() > vendorPrefix.size() && + device.substr(0, vendorPrefix.size()) == vendorPrefix && + std::all_of(device.begin() + vendorPrefix.size(), device.end(), + [](unsigned char c) { return c == '_' || std::isalnum(c); }); +} + +static inline bool isUnknownAudioChannelMask(const std::string& mask) { + return stringToAudioChannelMask(mask) == AudioChannelMask::UNKNOWN; +} + +static inline bool isUnknownAudioDevice(const std::string& device) { + return stringToAudioDevice(device) == AudioDevice::UNKNOWN && !isVendorExtension(device); +} + +static inline bool isUnknownAudioFormat(const std::string& format) { + return stringToAudioFormat(format) == AudioFormat::UNKNOWN && !isVendorExtension(format); +} + +static inline bool isUnknownAudioGainMode(const std::string& mode) { + return stringToAudioGainMode(mode) == AudioGainMode::UNKNOWN; +} + +static inline bool isUnknownAudioSource(const std::string& source) { + return stringToAudioSource(source) == AudioSource::UNKNOWN; +} + +static inline bool isUnknownAudioStreamType(const std::string& streamType) { + return stringToAudioStreamType(streamType) == AudioStreamType::UNKNOWN; +} + +static inline bool isUnknownAudioUsage(const std::string& usage) { + return stringToAudioUsage(usage) == AudioUsage::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 631d5240a2..2da9815cbd 100644 --- a/audio/common/7.0/types.hal +++ b/audio/common/7.0/types.hal @@ -118,9 +118,9 @@ typedef string AudioChannelMask; * Base configuration attributes applicable to any stream of audio. */ struct AudioConfigBase { - AudioFormat format; // 'DEFAULT' means 'unspecified' + AudioFormat format; // empty means 'unspecified' uint32_t sampleRateHz; // 0 means 'unspecified' - vec channelMask; // empty means 'unspecified' + AudioChannelMask channelMask; // empty means 'unspecified' }; /** @@ -167,10 +167,18 @@ struct DeviceAddress { AudioDevice deviceType; safe_union Address { /** - * The address may be left unspecified if 'device' specifies - * a physical device unambiguously. + * String uniquely identifying the device among other devices + * of the same type. Can be empty in case there is only one device + * of this type. + * + * Depending on the device type, its id may be assigned by the framework + * (this is done for REMOTE_SUBMIX), or specified in the audio policy + * configuration file (typically done for BUS devices), or assigned + * by the HAL service. In any case, both framework and HAL must + * never attempt to parse the value of the id. If the address must + * be parsed, one of the members below must be used instead of 'id'. */ - Monostate unspecified; + string id; /** IEEE 802 MAC address. Set for Bluetooth devices. */ uint8_t[6] mac; /** IPv4 Address. Set for IPv4 devices. */ @@ -182,10 +190,6 @@ struct DeviceAddress { int32_t card; int32_t device; } alsa; - /** Arbitrary BUS device unique address. Not interpreted by the framework. */ - string bus; - /** Arbitrary REMOTE_SUBMIX device unique address. Not interpreted by the HAL. */ - string rSubmix; } address; }; @@ -349,9 +353,9 @@ struct AudioGainConfig { /** * Gain values in millibels for each channel ordered from LSb to MSb in * channel mask. The number of values is 1 in joint mode or - * popcount(channel_mask). + * the number of channels in the channel mask. */ - int32_t[4 * 8] values; + vec values; uint32_t rampDurationMs; // ramp duration in ms }; @@ -409,7 +413,7 @@ struct AudioPortConfig { * parameters (or none) may be set. See the documentation of the * AudioConfigBase struct. */ - AudioConfigBase config; + AudioConfigBase base; /** Associated gain control. */ safe_union OptionalGain { Monostate unspecified; @@ -439,6 +443,8 @@ struct AudioPort { vec profiles; /** List of gain controls attached to the port. */ vec gains; + /** Parameters that depend on the actual port role. */ + AudioPortExtendedInfo ext; /** * Current configuration of the audio port, may have all the fields left * unspecified. diff --git a/audio/common/all-versions/default/7.0/HidlUtils.cpp b/audio/common/all-versions/default/7.0/HidlUtils.cpp new file mode 100644 index 0000000000..1a662825bd --- /dev/null +++ b/audio/common/all-versions/default/7.0/HidlUtils.cpp @@ -0,0 +1,847 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#define LOG_TAG "HidlUtils" +#include + +#include +#include + +#include "HidlUtils.h" + +namespace android { +namespace hardware { +namespace audio { +namespace common { +namespace CPP_VERSION { +namespace implementation { + +namespace xsd { +using namespace ::android::audio::policy::configuration::V7_0; +} + +#define CONVERT_CHECKED(expr, result) \ + if (status_t status = (expr); status != NO_ERROR) { \ + result = status; \ + } + +status_t HidlUtils::audioIndexChannelMaskFromHal(audio_channel_mask_t halChannelMask, + AudioChannelMask* channelMask) { + *channelMask = audio_channel_index_mask_to_string(halChannelMask); + if (!channelMask->empty() && !xsd::isUnknownAudioChannelMask(*channelMask)) { + return NO_ERROR; + } + ALOGE("Unknown index channel mask value 0x%X", halChannelMask); + *channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE); + return BAD_VALUE; +} + +status_t HidlUtils::audioInputChannelMaskFromHal(audio_channel_mask_t halChannelMask, + AudioChannelMask* channelMask) { + *channelMask = audio_channel_in_mask_to_string(halChannelMask); + if (!channelMask->empty() && !xsd::isUnknownAudioChannelMask(*channelMask)) { + return NO_ERROR; + } + ALOGE("Unknown input channel mask value 0x%X", halChannelMask); + *channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE); + return BAD_VALUE; +} + +status_t HidlUtils::audioOutputChannelMaskFromHal(audio_channel_mask_t halChannelMask, + AudioChannelMask* channelMask) { + *channelMask = audio_channel_out_mask_to_string(halChannelMask); + if (!channelMask->empty() && !xsd::isUnknownAudioChannelMask(*channelMask)) { + return NO_ERROR; + } + ALOGE("Unknown output channel mask value 0x%X", halChannelMask); + *channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE); + return BAD_VALUE; +} + +status_t HidlUtils::audioChannelMaskFromHal(audio_channel_mask_t halChannelMask, bool isInput, + AudioChannelMask* channelMask) { + if (halChannelMask != AUDIO_CHANNEL_NONE) { + if (audio_channel_mask_is_valid(halChannelMask)) { + switch (audio_channel_mask_get_representation(halChannelMask)) { + case AUDIO_CHANNEL_REPRESENTATION_POSITION: + return isInput ? audioInputChannelMaskFromHal(halChannelMask, channelMask) + : audioOutputChannelMaskFromHal(halChannelMask, channelMask); + case AUDIO_CHANNEL_REPRESENTATION_INDEX: + // Index masks do not have direction. + return audioIndexChannelMaskFromHal(halChannelMask, channelMask); + // no default + } + } + *channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE); + return BAD_VALUE; + } + *channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_NONE); + return NO_ERROR; +} + +status_t HidlUtils::audioChannelMaskToHal(const AudioChannelMask& channelMask, + audio_channel_mask_t* halChannelMask) { + if (!xsd::isUnknownAudioChannelMask(channelMask) && + audio_channel_mask_from_string(channelMask.c_str(), halChannelMask)) { + return NO_ERROR; + } + ALOGE("Unknown channel mask \"%s\"", channelMask.c_str()); + *halChannelMask = AUDIO_CHANNEL_NONE; + return BAD_VALUE; +} + +status_t HidlUtils::audioConfigBaseFromHal(const audio_config_base_t& halConfigBase, bool isInput, + AudioConfigBase* configBase) { + status_t result = NO_ERROR; + configBase->sampleRateHz = halConfigBase.sample_rate; + CONVERT_CHECKED( + audioChannelMaskFromHal(halConfigBase.channel_mask, isInput, &configBase->channelMask), + result); + CONVERT_CHECKED(audioFormatFromHal(halConfigBase.format, &configBase->format), result); + return result; +} + +status_t HidlUtils::audioConfigBaseToHal(const AudioConfigBase& configBase, + audio_config_base_t* halConfigBase) { + status_t result = NO_ERROR; + halConfigBase->sample_rate = configBase.sampleRateHz; + CONVERT_CHECKED(audioChannelMaskToHal(configBase.channelMask, &halConfigBase->channel_mask), + result); + CONVERT_CHECKED(audioFormatToHal(configBase.format, &halConfigBase->format), result); + return result; +} + +status_t HidlUtils::audioDeviceTypeFromHal(audio_devices_t halDevice, AudioDevice* device) { + *device = audio_device_to_string(halDevice); + if (!device->empty() && !xsd::isUnknownAudioDevice(*device)) { + return NO_ERROR; + } + ALOGE("Unknown audio device value 0x%X", halDevice); + *device = toString(xsd::AudioDevice::AUDIO_DEVICE_NONE); + return BAD_VALUE; +} + +status_t HidlUtils::audioDeviceTypeToHal(const AudioDevice& device, audio_devices_t* halDevice) { + if (!xsd::isUnknownAudioDevice(device) && audio_device_from_string(device.c_str(), halDevice)) { + return NO_ERROR; + } + ALOGE("Unknown audio device \"%s\"", device.c_str()); + *halDevice = AUDIO_DEVICE_NONE; + return BAD_VALUE; +} + +status_t HidlUtils::audioFormatFromHal(audio_format_t halFormat, AudioFormat* format) { + *format = audio_format_to_string(halFormat); + if (!format->empty() && !xsd::isUnknownAudioFormat(*format)) { + return NO_ERROR; + } + ALOGE("Unknown audio format value 0x%X", halFormat); + return BAD_VALUE; +} + +status_t HidlUtils::audioFormatToHal(const AudioFormat& format, audio_format_t* halFormat) { + if (!xsd::isUnknownAudioFormat(format) && audio_format_from_string(format.c_str(), halFormat)) { + return NO_ERROR; + } + ALOGE("Unknown audio format \"%s\"", format.c_str()); + *halFormat = AUDIO_FORMAT_DEFAULT; + return BAD_VALUE; +} + +status_t HidlUtils::audioGainModeMaskFromHal(audio_gain_mode_t halGainModeMask, + hidl_vec* gainModeMask) { + status_t status = NO_ERROR; + std::vector result; + for (uint32_t bit = 0; bit < sizeof(audio_gain_mode_t) * 8; ++bit) { + audio_gain_mode_t flag = static_cast(1u << bit); + if ((flag & halGainModeMask) == flag) { + AudioGainMode flagStr = audio_gain_mode_to_string(flag); + if (!flagStr.empty() && !xsd::isUnknownAudioGainMode(flagStr)) { + result.push_back(flagStr); + } else { + ALOGE("Unknown audio gain mode value 0x%X", flag); + status = BAD_VALUE; + } + } + } + *gainModeMask = result; + return status; +} + +status_t HidlUtils::audioGainModeMaskToHal(const hidl_vec& gainModeMask, + audio_gain_mode_t* halGainModeMask) { + status_t status = NO_ERROR; + *halGainModeMask = {}; + for (const auto& gainMode : gainModeMask) { + audio_gain_mode_t halGainMode; + if (!xsd::isUnknownAudioGainMode(gainMode) && + audio_gain_mode_from_string(gainMode.c_str(), &halGainMode)) { + *halGainModeMask = static_cast(*halGainModeMask | halGainMode); + } else { + ALOGE("Unknown audio gain mode \"%s\"", gainMode.c_str()); + status = BAD_VALUE; + } + } + return status; +} + +status_t HidlUtils::audioSourceFromHal(audio_source_t halSource, AudioSource* source) { + *source = audio_source_to_string(halSource); + if (!source->empty() && !xsd::isUnknownAudioSource(*source)) { + return NO_ERROR; + } + ALOGE("Unknown audio source value 0x%X", halSource); + *source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT); + return BAD_VALUE; +} + +status_t HidlUtils::audioSourceToHal(const AudioSource& source, audio_source_t* halSource) { + if (!xsd::isUnknownAudioSource(source) && audio_source_from_string(source.c_str(), halSource)) { + return NO_ERROR; + } + ALOGE("Unknown audio source \"%s\"", source.c_str()); + *halSource = AUDIO_SOURCE_DEFAULT; + return BAD_VALUE; +} + +status_t HidlUtils::audioStreamTypeFromHal(audio_stream_type_t halStreamType, + AudioStreamType* streamType) { + *streamType = audio_stream_type_to_string(halStreamType); + if (!streamType->empty() && !xsd::isUnknownAudioStreamType(*streamType)) { + return NO_ERROR; + } + ALOGE("Unknown audio stream type value 0x%X", halStreamType); + return BAD_VALUE; +} + +status_t HidlUtils::audioStreamTypeToHal(const AudioStreamType& streamType, + audio_stream_type_t* halStreamType) { + if (!xsd::isUnknownAudioStreamType(streamType) && + audio_stream_type_from_string(streamType.c_str(), halStreamType)) { + return NO_ERROR; + } + ALOGE("Unknown audio stream type \"%s\"", streamType.c_str()); + *halStreamType = AUDIO_STREAM_DEFAULT; + return BAD_VALUE; +} + +status_t HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, bool isInput, + AudioConfig* config) { + status_t result = NO_ERROR; + audio_config_base_t halConfigBase = {halConfig.sample_rate, halConfig.channel_mask, + halConfig.format}; + CONVERT_CHECKED(audioConfigBaseFromHal(halConfigBase, isInput, &config->base), result); + CONVERT_CHECKED(audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo), result); + config->frameCount = halConfig.frame_count; + return result; +} + +status_t HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) { + status_t result = NO_ERROR; + *halConfig = AUDIO_CONFIG_INITIALIZER; + audio_config_base_t halConfigBase = AUDIO_CONFIG_BASE_INITIALIZER; + CONVERT_CHECKED(audioConfigBaseToHal(config.base, &halConfigBase), result); + halConfig->sample_rate = halConfigBase.sample_rate; + halConfig->channel_mask = halConfigBase.channel_mask; + halConfig->format = halConfigBase.format; + CONVERT_CHECKED(audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info), result); + halConfig->frame_count = config.frameCount; + return result; +} + +status_t HidlUtils::audioGainConfigFromHal(const struct audio_gain_config& halConfig, bool isInput, + AudioGainConfig* config) { + status_t result = NO_ERROR; + config->index = halConfig.index; + CONVERT_CHECKED(audioGainModeMaskFromHal(halConfig.mode, &config->mode), result); + CONVERT_CHECKED(audioChannelMaskFromHal(halConfig.channel_mask, isInput, &config->channelMask), + result); + if (halConfig.mode & AUDIO_GAIN_MODE_JOINT) { + config->values.resize(1); + config->values[0] = halConfig.values[0]; + } + if (halConfig.mode & (AUDIO_GAIN_MODE_CHANNELS | AUDIO_GAIN_MODE_RAMP)) { + config->values.resize(__builtin_popcount(halConfig.channel_mask)); + for (size_t i = 0; i < config->values.size(); ++i) { + config->values[i] = halConfig.values[i]; + } + } + config->rampDurationMs = halConfig.ramp_duration_ms; + return result; +} + +status_t HidlUtils::audioGainConfigToHal(const AudioGainConfig& config, + struct audio_gain_config* halConfig) { + status_t result = NO_ERROR; + halConfig->index = config.index; + CONVERT_CHECKED(audioGainModeMaskToHal(config.mode, &halConfig->mode), result); + CONVERT_CHECKED(audioChannelMaskToHal(config.channelMask, &halConfig->channel_mask), result); + memset(halConfig->values, 0, sizeof(halConfig->values)); + if (halConfig->mode & AUDIO_GAIN_MODE_JOINT) { + if (config.values.size() > 0) { + halConfig->values[0] = config.values[0]; + } else { + ALOGE("Empty values vector in AudioGainConfig"); + result = BAD_VALUE; + } + } + if (halConfig->mode & (AUDIO_GAIN_MODE_CHANNELS | AUDIO_GAIN_MODE_RAMP)) { + size_t channelCount = __builtin_popcount(halConfig->channel_mask); + size_t valuesCount = config.values.size(); + if (channelCount != valuesCount) { + ALOGE("Wrong number of values in AudioGainConfig, expected: %zu, found: %zu", + channelCount, valuesCount); + result = BAD_VALUE; + if (channelCount < valuesCount) { + valuesCount = channelCount; + } + } + for (size_t i = 0; i < valuesCount; ++i) { + halConfig->values[i] = config.values[i]; + } + } + halConfig->ramp_duration_ms = config.rampDurationMs; + return result; +} + +status_t HidlUtils::audioGainFromHal(const struct audio_gain& halGain, bool isInput, + AudioGain* gain) { + status_t result = NO_ERROR; + CONVERT_CHECKED(audioGainModeMaskFromHal(halGain.mode, &gain->mode), result); + CONVERT_CHECKED(audioChannelMaskFromHal(halGain.channel_mask, isInput, &gain->channelMask), + result); + gain->minValue = halGain.min_value; + gain->maxValue = halGain.max_value; + gain->defaultValue = halGain.default_value; + gain->stepValue = halGain.step_value; + gain->minRampMs = halGain.min_ramp_ms; + gain->maxRampMs = halGain.max_ramp_ms; + return result; +} + +status_t HidlUtils::audioGainToHal(const AudioGain& gain, struct audio_gain* halGain) { + status_t result = NO_ERROR; + CONVERT_CHECKED(audioGainModeMaskToHal(gain.mode, &halGain->mode), result); + CONVERT_CHECKED(audioChannelMaskToHal(gain.channelMask, &halGain->channel_mask), result); + halGain->min_value = gain.minValue; + halGain->max_value = gain.maxValue; + halGain->default_value = gain.defaultValue; + halGain->step_value = gain.stepValue; + halGain->min_ramp_ms = gain.minRampMs; + halGain->max_ramp_ms = gain.maxRampMs; + return result; +} + +status_t HidlUtils::audioUsageFromHal(audio_usage_t halUsage, AudioUsage* usage) { + if (halUsage == AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST || + halUsage == AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT || + halUsage == AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED || + halUsage == AUDIO_USAGE_NOTIFICATION_EVENT) { + halUsage = AUDIO_USAGE_NOTIFICATION; + } + *usage = audio_usage_to_string(halUsage); + if (!usage->empty() && !xsd::isUnknownAudioUsage(*usage)) { + return NO_ERROR; + } + ALOGE("Unknown audio usage %d", halUsage); + *usage = toString(xsd::AudioUsage::AUDIO_USAGE_UNKNOWN); + return BAD_VALUE; +} + +status_t HidlUtils::audioUsageToHal(const AudioUsage& usage, audio_usage_t* halUsage) { + if (!xsd::isUnknownAudioUsage(usage) && audio_usage_from_string(usage.c_str(), halUsage)) { + return NO_ERROR; + } + ALOGE("Unknown audio usage \"%s\"", usage.c_str()); + *halUsage = AUDIO_USAGE_UNKNOWN; + return BAD_VALUE; +} + +status_t HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload, + AudioOffloadInfo* offload) { + status_t result = NO_ERROR; + audio_config_base_t halConfigBase = {halOffload.sample_rate, halOffload.channel_mask, + halOffload.format}; + CONVERT_CHECKED(audioConfigBaseFromHal(halConfigBase, false /*isInput*/, &offload->base), + result); + CONVERT_CHECKED(audioStreamTypeFromHal(halOffload.stream_type, &offload->streamType), result); + offload->bitRatePerSecond = halOffload.bit_rate; + offload->durationMicroseconds = halOffload.duration_us; + offload->hasVideo = halOffload.has_video; + offload->isStreaming = halOffload.is_streaming; + offload->bitWidth = halOffload.bit_width; + offload->bufferSize = halOffload.offload_buffer_size; + CONVERT_CHECKED(audioUsageFromHal(halOffload.usage, &offload->usage), result); + if (halOffload.version >= AUDIO_OFFLOAD_INFO_VERSION_0_2) { + offload->encapsulationMode = + static_cast(halOffload.encapsulation_mode); + offload->contentId = halOffload.content_id; + offload->syncId = halOffload.sync_id; + } else { + offload->encapsulationMode = AudioEncapsulationMode::NONE; + offload->contentId = 0; + offload->syncId = 0; + } + return result; +} + +status_t HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload, + audio_offload_info_t* halOffload) { + status_t result = NO_ERROR; + *halOffload = AUDIO_INFO_INITIALIZER; + audio_config_base_t halConfigBase = AUDIO_CONFIG_BASE_INITIALIZER; + CONVERT_CHECKED(audioConfigBaseToHal(offload.base, &halConfigBase), result); + halOffload->sample_rate = halConfigBase.sample_rate; + halOffload->channel_mask = halConfigBase.channel_mask; + halOffload->format = halConfigBase.format; + CONVERT_CHECKED(audioStreamTypeToHal(offload.streamType, &halOffload->stream_type), result); + halOffload->bit_rate = offload.bitRatePerSecond; + halOffload->duration_us = offload.durationMicroseconds; + halOffload->has_video = offload.hasVideo; + halOffload->is_streaming = offload.isStreaming; + halOffload->bit_width = offload.bitWidth; + halOffload->offload_buffer_size = offload.bufferSize; + CONVERT_CHECKED(audioUsageToHal(offload.usage, &halOffload->usage), result); + halOffload->encapsulation_mode = + static_cast(offload.encapsulationMode); + halOffload->content_id = offload.contentId; + halOffload->sync_id = offload.syncId; + return result; +} + +status_t HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig, + AudioPortConfig* config) { + status_t result = NO_ERROR; + bool isInput = false; + config->id = halConfig.id; + CONVERT_CHECKED(audioPortExtendedInfoFromHal(halConfig.role, halConfig.type, + halConfig.ext.device, halConfig.ext.mix, + halConfig.ext.session, &config->ext, &isInput), + result); + if (audio_port_config_has_input_direction(&halConfig) != isInput) { + ALOGE("Inconsistent port config direction data, is input: %d (hal) != %d (converter)", + audio_port_config_has_input_direction(&halConfig), isInput); + result = BAD_VALUE; + } + if (halConfig.config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) { + config->base.sampleRateHz = halConfig.sample_rate; + } else { + config->base.sampleRateHz = {}; + } + if (halConfig.config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) { + CONVERT_CHECKED( + audioChannelMaskFromHal(halConfig.channel_mask, isInput, &config->base.channelMask), + result); + } else { + config->base.channelMask = {}; + } + if (halConfig.config_mask & AUDIO_PORT_CONFIG_FORMAT) { + CONVERT_CHECKED(audioFormatFromHal(halConfig.format, &config->base.format), result); + } else { + config->base.format = {}; + } + if (halConfig.config_mask & AUDIO_PORT_CONFIG_GAIN) { + config->gain.config({}); + CONVERT_CHECKED(audioGainConfigFromHal(halConfig.gain, isInput, &config->gain.config()), + result); + } else { + config->gain.unspecified({}); + } + return result; +} + +status_t HidlUtils::audioPortConfigToHal(const AudioPortConfig& config, + struct audio_port_config* halConfig) { + status_t result = NO_ERROR; + memset(halConfig, 0, sizeof(audio_port_config)); + halConfig->id = config.id; + halConfig->config_mask = {}; + if (config.base.sampleRateHz != 0) { + halConfig->config_mask |= AUDIO_PORT_CONFIG_SAMPLE_RATE; + halConfig->sample_rate = config.base.sampleRateHz; + } + if (!config.base.channelMask.empty()) { + halConfig->config_mask |= AUDIO_PORT_CONFIG_CHANNEL_MASK; + CONVERT_CHECKED(audioChannelMaskToHal(config.base.channelMask, &halConfig->channel_mask), + result); + } + if (!config.base.format.empty()) { + halConfig->config_mask |= AUDIO_PORT_CONFIG_FORMAT; + CONVERT_CHECKED(audioFormatToHal(config.base.format, &halConfig->format), result); + } + if (config.gain.getDiscriminator() == + AudioPortConfig::OptionalGain::hidl_discriminator::config) { + halConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN; + CONVERT_CHECKED(audioGainConfigToHal(config.gain.config(), &halConfig->gain), result); + } + CONVERT_CHECKED(audioPortExtendedInfoToHal(config.ext, &halConfig->role, &halConfig->type, + &halConfig->ext.device, &halConfig->ext.mix, + &halConfig->ext.session), + result); + return result; +} + +status_t HidlUtils::audioPortExtendedInfoFromHal( + audio_port_role_t role, audio_port_type_t type, + const struct audio_port_config_device_ext& device, + const struct audio_port_config_mix_ext& mix, + const struct audio_port_config_session_ext& session, AudioPortExtendedInfo* ext, + bool* isInput) { + status_t result = NO_ERROR; + *isInput = false; + switch (type) { + case AUDIO_PORT_TYPE_NONE: + ext->unspecified({}); + break; + case AUDIO_PORT_TYPE_DEVICE: { + *isInput = role == AUDIO_PORT_ROLE_SOURCE; + ext->device({}); + CONVERT_CHECKED(deviceAddressFromHal(device.type, device.address, &ext->device()), + result); + break; + } + case AUDIO_PORT_TYPE_MIX: { + *isInput = role == AUDIO_PORT_ROLE_SINK; + ext->mix({}); + ext->mix().ioHandle = mix.handle; + if (role == AUDIO_PORT_ROLE_SOURCE) { + ext->mix().useCase.stream({}); + CONVERT_CHECKED( + audioStreamTypeFromHal(mix.usecase.stream, &ext->mix().useCase.stream()), + result); + } else if (role == AUDIO_PORT_ROLE_SINK) { + ext->mix().useCase.source({}); + CONVERT_CHECKED( + audioSourceFromHal(mix.usecase.source, &ext->mix().useCase.source()), + result); + } + break; + } + case AUDIO_PORT_TYPE_SESSION: { + ext->session(session.session); + break; + } + } + return result; +} + +status_t HidlUtils::audioPortExtendedInfoToHal(const AudioPortExtendedInfo& ext, + audio_port_role_t* role, audio_port_type_t* type, + struct audio_port_config_device_ext* device, + struct audio_port_config_mix_ext* mix, + struct audio_port_config_session_ext* session) { + status_t result = NO_ERROR; + switch (ext.getDiscriminator()) { + case AudioPortExtendedInfo::hidl_discriminator::unspecified: + *role = AUDIO_PORT_ROLE_NONE; + *type = AUDIO_PORT_TYPE_NONE; + break; + case AudioPortExtendedInfo::hidl_discriminator::device: + *role = xsd::isOutputDevice(ext.device().deviceType) ? AUDIO_PORT_ROLE_SINK + : AUDIO_PORT_ROLE_SOURCE; + *type = AUDIO_PORT_TYPE_DEVICE; + CONVERT_CHECKED(deviceAddressToHal(ext.device(), &device->type, device->address), + result); + break; + case AudioPortExtendedInfo::hidl_discriminator::mix: + *type = AUDIO_PORT_TYPE_MIX; + switch (ext.mix().useCase.getDiscriminator()) { + case AudioPortExtendedInfo::AudioPortMixExt::UseCase::hidl_discriminator::stream: + *role = AUDIO_PORT_ROLE_SOURCE; + CONVERT_CHECKED( + audioStreamTypeToHal(ext.mix().useCase.stream(), &mix->usecase.stream), + result); + break; + case AudioPortExtendedInfo::AudioPortMixExt::UseCase::hidl_discriminator::source: + *role = AUDIO_PORT_ROLE_SINK; + CONVERT_CHECKED( + audioSourceToHal(ext.mix().useCase.source(), &mix->usecase.source), + result); + break; + } + mix->handle = ext.mix().ioHandle; + break; + case AudioPortExtendedInfo::hidl_discriminator::session: + *role = AUDIO_PORT_ROLE_NONE; + *type = AUDIO_PORT_TYPE_SESSION; + session->session = static_cast(ext.session()); + break; + } + return result; +} + +status_t HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) { + struct audio_port_v7 halPortV7 = {}; + audio_populate_audio_port_v7(&halPort, &halPortV7); + return audioPortFromHal(halPortV7, port); +} + +status_t HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port* halPort) { + status_t result = NO_ERROR; + struct audio_port_v7 halPortV7 = {}; + CONVERT_CHECKED(audioPortToHal(port, &halPortV7), result); + if (!audio_populate_audio_port(&halPortV7, halPort)) { + result = BAD_VALUE; + } + return result; +} + +status_t HidlUtils::audioPortFromHal(const struct audio_port_v7& halPort, AudioPort* port) { + status_t result = NO_ERROR; + bool isInput = false; + port->id = halPort.id; + port->name.setToExternal(halPort.name, strlen(halPort.name)); + // HAL uses slightly different but convertible structures for the extended info in port + // and port config structures. + struct audio_port_config_device_ext halDevice = {}; + struct audio_port_config_mix_ext halMix = {}; + struct audio_port_config_session_ext halSession = {}; + switch (halPort.type) { + case AUDIO_PORT_TYPE_NONE: + break; + case AUDIO_PORT_TYPE_DEVICE: + halDevice.type = halPort.ext.device.type; + memcpy(halDevice.address, halPort.ext.device.address, AUDIO_DEVICE_MAX_ADDRESS_LEN); + break; + case AUDIO_PORT_TYPE_MIX: + halMix.handle = halPort.ext.mix.handle; + break; + case AUDIO_PORT_TYPE_SESSION: + halSession.session = halPort.ext.session.session; + break; + } + 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); + } + 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); + } + CONVERT_CHECKED(audioPortConfigFromHal(halPort.active_config, &port->activeConfig), result); + return result; +} + +status_t HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port_v7* halPort) { + status_t result = NO_ERROR; + halPort->id = port.id; + strncpy(halPort->name, port.name.c_str(), AUDIO_PORT_MAX_NAME_LEN); + halPort->name[AUDIO_PORT_MAX_NAME_LEN - 1] = '\0'; + if (port.name.size() >= AUDIO_PORT_MAX_NAME_LEN) { + 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); + } + 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); + halPort->num_gains = AUDIO_PORT_MAX_GAINS; + result = BAD_VALUE; + } + for (size_t i = 0; i < halPort->num_gains; ++i) { + CONVERT_CHECKED(audioGainToHal(port.gains[i], &halPort->gains[i]), result); + } + // HAL uses slightly different but convertible structures for the extended info in port + // and port config structures. + struct audio_port_config_device_ext halDevice = {}; + struct audio_port_config_mix_ext halMix = {}; + struct audio_port_config_session_ext halSession = {}; + CONVERT_CHECKED(audioPortExtendedInfoToHal(port.ext, &halPort->role, &halPort->type, &halDevice, + &halMix, &halSession), + result); + switch (halPort->type) { + case AUDIO_PORT_TYPE_NONE: + break; + case AUDIO_PORT_TYPE_DEVICE: + halPort->ext.device.type = halDevice.type; + memcpy(halPort->ext.device.address, halDevice.address, AUDIO_DEVICE_MAX_ADDRESS_LEN); + break; + case AUDIO_PORT_TYPE_MIX: + halPort->ext.mix.handle = halMix.handle; + break; + case AUDIO_PORT_TYPE_SESSION: + halPort->ext.session.session = halSession.session; + break; + } + CONVERT_CHECKED(audioPortConfigToHal(port.activeConfig, &halPort->active_config), result); + return result; +} + +status_t HidlUtils::audioProfileFromHal(const struct audio_profile& halProfile, bool isInput, + AudioProfile* profile) { + status_t result = NO_ERROR; + CONVERT_CHECKED(audioFormatFromHal(halProfile.format, &profile->format), result); + profile->sampleRates.resize(halProfile.num_sample_rates); + for (size_t i = 0; i < halProfile.num_sample_rates; ++i) { + profile->sampleRates[i] = halProfile.sample_rates[i]; + } + profile->channelMasks.resize(halProfile.num_channel_masks); + for (size_t i = 0; i < halProfile.num_channel_masks; ++i) { + CONVERT_CHECKED(audioChannelMaskFromHal(halProfile.channel_masks[i], isInput, + &profile->channelMasks[i]), + result); + } + return result; +} + +status_t HidlUtils::audioProfileToHal(const AudioProfile& profile, + struct audio_profile* halProfile) { + status_t result = NO_ERROR; + CONVERT_CHECKED(audioFormatToHal(profile.format, &halProfile->format), result); + memset(halProfile->sample_rates, 0, sizeof(halProfile->sample_rates)); + halProfile->num_sample_rates = profile.sampleRates.size(); + if (halProfile->num_sample_rates > AUDIO_PORT_MAX_SAMPLING_RATES) { + ALOGE("HIDL Audio profile has too many sample rates: %u", halProfile->num_sample_rates); + halProfile->num_sample_rates = AUDIO_PORT_MAX_SAMPLING_RATES; + result = BAD_VALUE; + } + for (size_t i = 0; i < halProfile->num_sample_rates; ++i) { + halProfile->sample_rates[i] = profile.sampleRates[i]; + } + memset(halProfile->channel_masks, 0, sizeof(halProfile->channel_masks)); + halProfile->num_channel_masks = profile.channelMasks.size(); + if (halProfile->num_channel_masks > AUDIO_PORT_MAX_CHANNEL_MASKS) { + ALOGE("HIDL Audio profile has too many channel masks: %u", halProfile->num_channel_masks); + halProfile->num_channel_masks = AUDIO_PORT_MAX_CHANNEL_MASKS; + result = BAD_VALUE; + } + for (size_t i = 0; i < halProfile->num_channel_masks; ++i) { + CONVERT_CHECKED( + audioChannelMaskToHal(profile.channelMasks[i], &halProfile->channel_masks[i]), + status); + } + return result; +} + +status_t HidlUtils::deviceAddressFromHal(audio_devices_t halDeviceType, + const char* halDeviceAddress, DeviceAddress* device) { + status_t result = NO_ERROR; + CONVERT_CHECKED(audioDeviceTypeFromHal(halDeviceType, &device->deviceType), result); + if (audio_is_a2dp_out_device(halDeviceType) || audio_is_a2dp_in_device(halDeviceType)) { + device->address.mac({}); + if (halDeviceAddress != nullptr) { + auto& mac = device->address.mac(); + int status = sscanf(halDeviceAddress, "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX", &mac[0], &mac[1], + &mac[2], &mac[3], &mac[4], &mac[5]); + if (status != 6) { + ALOGE("BT A2DP device \"%s\" MAC address \"%s\" is invalid", + device->deviceType.c_str(), halDeviceAddress); + result = BAD_VALUE; + } + } else { + ALOGE("BT A2DP device \"%s\" does not have a MAC address", halDeviceAddress); + result = BAD_VALUE; + } + } else if (halDeviceType == AUDIO_DEVICE_OUT_IP || halDeviceType == AUDIO_DEVICE_IN_IP) { + device->address.ipv4({}); + if (halDeviceAddress != nullptr) { + auto& ipv4 = device->address.ipv4(); + int status = sscanf(halDeviceAddress, "%hhu.%hhu.%hhu.%hhu", &ipv4[0], &ipv4[1], + &ipv4[2], &ipv4[3]); + if (status != 4) { + ALOGE("IP device \"%s\" IPv4 address \"%s\" is invalid", device->deviceType.c_str(), + halDeviceAddress); + result = BAD_VALUE; + } + } else { + ALOGE("IP device \"%s\" does not have an IPv4 address", device->deviceType.c_str()); + result = BAD_VALUE; + } + } else if (audio_is_usb_out_device(halDeviceType) || audio_is_usb_in_device(halDeviceType)) { + device->address.alsa({}); + if (halDeviceAddress != nullptr) { + auto& alsa = device->address.alsa(); + int status = sscanf(halDeviceAddress, "card=%d;device=%d", &alsa.card, &alsa.device); + if (status != 2) { + ALOGE("USB device \"%s\" ALSA address \"%s\" is invalid", + device->deviceType.c_str(), halDeviceAddress); + result = BAD_VALUE; + } + } else { + ALOGE("USB device \"%s\" does not have ALSA address", device->deviceType.c_str()); + result = BAD_VALUE; + } + } else { + // Any other device type uses the 'id' field. + device->address.id(halDeviceAddress != nullptr ? halDeviceAddress : ""); + } + return result; +} + +status_t HidlUtils::deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType, + char* halDeviceAddress) { + status_t result = NO_ERROR; + CONVERT_CHECKED(audioDeviceTypeToHal(device.deviceType, halDeviceType), result); + memset(halDeviceAddress, 0, AUDIO_DEVICE_MAX_ADDRESS_LEN); + if (audio_is_a2dp_out_device(*halDeviceType) || audio_is_a2dp_in_device(*halDeviceType)) { + if (device.address.getDiscriminator() == DeviceAddress::Address::hidl_discriminator::mac) { + const auto& mac = device.address.mac(); + snprintf(halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN, + "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], + mac[5]); + } else { + ALOGE("BT A2DP device \"%s\" does not have MAC address set", device.deviceType.c_str()); + result = BAD_VALUE; + } + } else if (*halDeviceType == AUDIO_DEVICE_OUT_IP || *halDeviceType == AUDIO_DEVICE_IN_IP) { + if (device.address.getDiscriminator() == DeviceAddress::Address::hidl_discriminator::ipv4) { + const auto& ipv4 = device.address.ipv4(); + snprintf(halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%d.%d.%d.%d", ipv4[0], + ipv4[1], ipv4[2], ipv4[3]); + } else { + ALOGE("IP device \"%s\" does not have IPv4 address set", device.deviceType.c_str()); + result = BAD_VALUE; + } + } else if (audio_is_usb_out_device(*halDeviceType) || audio_is_usb_in_device(*halDeviceType)) { + if (device.address.getDiscriminator() == DeviceAddress::Address::hidl_discriminator::alsa) { + const auto& alsa = device.address.alsa(); + snprintf(halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN, "card=%d;device=%d", alsa.card, + alsa.device); + } else { + ALOGE("USB device \"%s\" does not have ALSA address set", device.deviceType.c_str()); + result = BAD_VALUE; + } + } else { + // Any other device type uses the 'id' field. + if (device.address.getDiscriminator() == DeviceAddress::Address::hidl_discriminator::id) { + snprintf(halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%s", + device.address.id().c_str()); + } + } + return result; +} + +} // namespace implementation +} // namespace CPP_VERSION +} // namespace common +} // namespace audio +} // namespace hardware +} // namespace android diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp index afaa7bb41a..b83a58a3ec 100644 --- a/audio/common/all-versions/default/Android.bp +++ b/audio/common/all-versions/default/Android.bp @@ -39,15 +39,19 @@ cc_library_shared { ], } +filegroup { + name: "android.hardware.audio.common-util@2-6", + srcs: [ + "HidlUtils.cpp", + "UuidUtils.cpp", + ], +} + cc_defaults { name: "android.hardware.audio.common-util_default", defaults: ["hidl_defaults"], vendor_available: true, - srcs: [ - "HidlUtils.cpp", - "UuidUtils.cpp", - ], export_include_dirs: ["."], @@ -70,6 +74,7 @@ cc_defaults { cc_library_shared { name: "android.hardware.audio.common@2.0-util", defaults: ["android.hardware.audio.common-util_default"], + srcs: [":android.hardware.audio.common-util@2-6"], shared_libs: [ "android.hardware.audio.common@2.0", ], @@ -83,6 +88,7 @@ cc_library_shared { cc_library_shared { name: "android.hardware.audio.common@4.0-util", defaults: ["android.hardware.audio.common-util_default"], + srcs: [":android.hardware.audio.common-util@2-6"], shared_libs: [ "android.hardware.audio.common@4.0", ], @@ -96,6 +102,7 @@ cc_library_shared { cc_library_shared { name: "android.hardware.audio.common@5.0-util", defaults: ["android.hardware.audio.common-util_default"], + srcs: [":android.hardware.audio.common-util@2-6"], shared_libs: [ "android.hardware.audio.common@5.0", ], @@ -109,6 +116,7 @@ cc_library_shared { cc_library_shared { name: "android.hardware.audio.common@6.0-util", defaults: ["android.hardware.audio.common-util_default"], + srcs: [":android.hardware.audio.common-util@2-6"], shared_libs: [ "android.hardware.audio.common@6.0", ], @@ -119,12 +127,18 @@ cc_library_shared { ], } -cc_library_shared { - enabled: false, +cc_library { name: "android.hardware.audio.common@7.0-util", defaults: ["android.hardware.audio.common-util_default"], + srcs: [ + "7.0/HidlUtils.cpp", + "UuidUtils.cpp", + ], shared_libs: [ "android.hardware.audio.common@7.0", + "android.hardware.audio.common@7.0-enums", + "libbase", + "libxml2", ], cflags: [ "-DMAJOR_VERSION=7", @@ -132,3 +146,35 @@ cc_library_shared { "-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.common@7.0-util_tests", + defaults: ["android.hardware.audio.common-util_default"], + + srcs: ["tests/hidlutils_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-enums", + "android.hardware.audio.common@7.0-util", + "android.hardware.audio.common@7.0", + ], + + 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/common/all-versions/default/HidlUtils.cpp b/audio/common/all-versions/default/HidlUtils.cpp index 7530d050ff..ab3c1c7b33 100644 --- a/audio/common/all-versions/default/HidlUtils.cpp +++ b/audio/common/all-versions/default/HidlUtils.cpp @@ -37,13 +37,14 @@ status_t HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, AudioCon return status; } -void HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) { +status_t HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) { memset(halConfig, 0, sizeof(audio_config_t)); halConfig->sample_rate = config.sampleRateHz; halConfig->channel_mask = static_cast(config.channelMask); halConfig->format = static_cast(config.format); audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info); halConfig->frame_count = config.frameCount; + return NO_ERROR; } void HidlUtils::audioGainConfigFromHal(const struct audio_gain_config& halConfig, @@ -57,8 +58,8 @@ void HidlUtils::audioGainConfigFromHal(const struct audio_gain_config& halConfig config->rampDurationMs = halConfig.ramp_duration_ms; } -void HidlUtils::audioGainConfigToHal(const AudioGainConfig& config, - struct audio_gain_config* halConfig) { +status_t HidlUtils::audioGainConfigToHal(const AudioGainConfig& config, + struct audio_gain_config* halConfig) { halConfig->index = config.index; halConfig->mode = static_cast(config.mode); halConfig->channel_mask = static_cast(config.channelMask); @@ -67,6 +68,7 @@ void HidlUtils::audioGainConfigToHal(const AudioGainConfig& config, halConfig->values[i] = config.values[i]; } halConfig->ramp_duration_ms = config.rampDurationMs; + return NO_ERROR; } void HidlUtils::audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain) { @@ -80,7 +82,7 @@ void HidlUtils::audioGainFromHal(const struct audio_gain& halGain, AudioGain* ga gain->maxRampMs = halGain.max_ramp_ms; } -void HidlUtils::audioGainToHal(const AudioGain& gain, struct audio_gain* halGain) { +status_t HidlUtils::audioGainToHal(const AudioGain& gain, struct audio_gain* halGain) { halGain->mode = static_cast(gain.mode); halGain->channel_mask = static_cast(gain.channelMask); halGain->min_value = gain.minValue; @@ -89,22 +91,26 @@ void HidlUtils::audioGainToHal(const AudioGain& gain, struct audio_gain* halGain halGain->step_value = gain.stepValue; halGain->min_ramp_ms = gain.minRampMs; halGain->max_ramp_ms = gain.maxRampMs; + return NO_ERROR; } -AudioUsage HidlUtils::audioUsageFromHal(const audio_usage_t halUsage) { +status_t HidlUtils::audioUsageFromHal(audio_usage_t halUsage, AudioUsage* usage) { switch (halUsage) { case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST: case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT: case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED: case AUDIO_USAGE_NOTIFICATION_EVENT: - return AudioUsage::NOTIFICATION; + *usage = AudioUsage::NOTIFICATION; + break; default: - return static_cast(halUsage); + *usage = static_cast(halUsage); } + return NO_ERROR; } -audio_usage_t HidlUtils::audioUsageToHal(const AudioUsage usage) { - return static_cast(usage); +status_t HidlUtils::audioUsageToHal(const AudioUsage& usage, audio_usage_t* halUsage) { + *halUsage = static_cast(usage); + return NO_ERROR; } status_t HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload, @@ -119,7 +125,7 @@ status_t HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOfflo offload->isStreaming = halOffload.is_streaming; offload->bitWidth = halOffload.bit_width; offload->bufferSize = halOffload.offload_buffer_size; - offload->usage = audioUsageFromHal(halOffload.usage); + audioUsageFromHal(halOffload.usage, &offload->usage); #if MAJOR_VERSION >= 6 if (halOffload.version >= AUDIO_OFFLOAD_INFO_VERSION_0_2) { offload->encapsulationMode = @@ -139,11 +145,11 @@ status_t HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOfflo return BAD_VALUE; } #endif - return OK; + return NO_ERROR; } -void HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload, - audio_offload_info_t* halOffload) { +status_t HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload, + audio_offload_info_t* halOffload) { *halOffload = AUDIO_INFO_INITIALIZER; halOffload->sample_rate = offload.sampleRateHz; halOffload->channel_mask = static_cast(offload.channelMask); @@ -155,7 +161,7 @@ void HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload, halOffload->is_streaming = offload.isStreaming; halOffload->bit_width = offload.bitWidth; halOffload->offload_buffer_size = offload.bufferSize; - halOffload->usage = audioUsageToHal(offload.usage); + audioUsageToHal(offload.usage, &halOffload->usage); #if MAJOR_VERSION >= 6 halOffload->encapsulation_mode = static_cast(offload.encapsulationMode); @@ -164,10 +170,11 @@ void HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload, #else // offload doesn't contain encapsulationMode, contentId, syncId, so this is OK. #endif + return NO_ERROR; } -void HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig, - AudioPortConfig* config) { +status_t HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig, + AudioPortConfig* config) { config->id = halConfig.id; config->role = AudioPortRole(halConfig.role); config->type = AudioPortType(halConfig.type); @@ -201,10 +208,11 @@ void HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig break; } } + return NO_ERROR; } -void HidlUtils::audioPortConfigToHal(const AudioPortConfig& config, - struct audio_port_config* halConfig) { +status_t HidlUtils::audioPortConfigToHal(const AudioPortConfig& config, + struct audio_port_config* halConfig) { memset(halConfig, 0, sizeof(audio_port_config)); halConfig->id = config.id; halConfig->role = static_cast(config.role); @@ -242,27 +250,10 @@ void HidlUtils::audioPortConfigToHal(const AudioPortConfig& config, break; } } + return NO_ERROR; } -void HidlUtils::audioPortConfigsFromHal(unsigned int numHalConfigs, - const struct audio_port_config* halConfigs, - hidl_vec* configs) { - configs->resize(numHalConfigs); - for (unsigned int i = 0; i < numHalConfigs; ++i) { - audioPortConfigFromHal(halConfigs[i], &(*configs)[i]); - } -} - -std::unique_ptr HidlUtils::audioPortConfigsToHal( - const hidl_vec& configs) { - std::unique_ptr halConfigs(new audio_port_config[configs.size()]); - for (size_t i = 0; i < configs.size(); ++i) { - audioPortConfigToHal(configs[i], &halConfigs[i]); - } - return halConfigs; -} - -void HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) { +status_t HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) { port->id = halPort.id; port->role = AudioPortRole(halPort.role); port->type = AudioPortType(halPort.type); @@ -305,9 +296,10 @@ void HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* po break; } } + return NO_ERROR; } -void HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port* halPort) { +status_t HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port* halPort) { memset(halPort, 0, sizeof(audio_port)); halPort->id = port.id; halPort->role = static_cast(port.role); @@ -356,6 +348,7 @@ void HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port* halPort break; } } + return NO_ERROR; } } // namespace implementation diff --git a/audio/common/all-versions/default/HidlUtils.h b/audio/common/all-versions/default/HidlUtils.h index 20fddef1ab..4e609ca4fd 100644 --- a/audio/common/all-versions/default/HidlUtils.h +++ b/audio/common/all-versions/default/HidlUtils.h @@ -34,38 +34,123 @@ namespace implementation { using namespace ::android::hardware::audio::common::CPP_VERSION; -class HidlUtils { - public: - // A failure here indicates a platform config that is incompatible with - // the compiled HIDL interface version. +struct HidlUtils { +#if MAJOR_VERSION < 7 static status_t audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config); - - static void audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig); static void audioGainConfigFromHal(const struct audio_gain_config& halConfig, AudioGainConfig* config); - static void audioGainConfigToHal(const AudioGainConfig& config, - struct audio_gain_config* halConfig); static void audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain); - static void audioGainToHal(const AudioGain& gain, struct audio_gain* halGain); - static AudioUsage audioUsageFromHal(const audio_usage_t halUsage); - static audio_usage_t audioUsageToHal(const AudioUsage usage); - // A failure here indicates a platform offload info that is incompatible with - // the compiled HIDL interface version. +#else + static status_t audioConfigFromHal(const audio_config_t& halConfig, bool isInput, + AudioConfig* config); + static status_t audioGainConfigFromHal(const struct audio_gain_config& halConfig, bool isInput, + AudioGainConfig* config); + static status_t audioGainFromHal(const struct audio_gain& halGain, bool isInput, + AudioGain* gain); +#endif + static status_t audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig); + static status_t audioGainConfigToHal(const AudioGainConfig& config, + struct audio_gain_config* halConfig); + static status_t audioGainToHal(const AudioGain& gain, struct audio_gain* halGain); + static status_t audioUsageFromHal(audio_usage_t halUsage, AudioUsage* usage); + static status_t audioUsageToHal(const AudioUsage& usage, audio_usage_t* halUsage); static status_t audioOffloadInfoFromHal(const audio_offload_info_t& halOffload, AudioOffloadInfo* offload); - static void audioOffloadInfoToHal(const AudioOffloadInfo& offload, - audio_offload_info_t* halOffload); - static void audioPortConfigFromHal(const struct audio_port_config& halConfig, - AudioPortConfig* config); - static void audioPortConfigToHal(const AudioPortConfig& config, - struct audio_port_config* halConfig); - static void audioPortConfigsFromHal(unsigned int numHalConfigs, - const struct audio_port_config* halConfigs, - hidl_vec* configs); + static status_t audioOffloadInfoToHal(const AudioOffloadInfo& offload, + audio_offload_info_t* halOffload); + static status_t audioPortConfigFromHal(const struct audio_port_config& halConfig, + AudioPortConfig* config); + static status_t audioPortConfigToHal(const AudioPortConfig& config, + struct audio_port_config* halConfig); + static status_t audioPortConfigsFromHal(unsigned int numHalConfigs, + const struct audio_port_config* halConfigs, + hidl_vec* configs) { + status_t result = NO_ERROR; + configs->resize(numHalConfigs); + for (unsigned int i = 0; i < numHalConfigs; ++i) { + if (status_t status = audioPortConfigFromHal(halConfigs[i], &(*configs)[i]); + status != NO_ERROR) { + result = status; + } + } + return result; + } + static status_t audioPortConfigsToHal(const hidl_vec& configs, + std::unique_ptr* halConfigs) { + status_t result = NO_ERROR; + halConfigs->reset(new audio_port_config[configs.size()]); + for (size_t i = 0; i < configs.size(); ++i) { + if (status_t status = audioPortConfigToHal(configs[i], &(*halConfigs)[i]); + status != NO_ERROR) { + result = status; + } + } + return result; + } + + // PLEASE DO NOT USE, will be removed in a couple of days static std::unique_ptr audioPortConfigsToHal( - const hidl_vec& configs); - static void audioPortFromHal(const struct audio_port& halPort, AudioPort* port); - static void audioPortToHal(const AudioPort& port, struct audio_port* halPort); + const hidl_vec& configs) { + std::unique_ptr halConfigs; + (void)audioPortConfigsToHal(configs, &halConfigs); + return halConfigs; + } + + static status_t audioPortFromHal(const struct audio_port& halPort, AudioPort* port); + static status_t audioPortToHal(const AudioPort& port, struct audio_port* halPort); +#if MAJOR_VERSION >= 7 + static status_t audioChannelMaskFromHal(audio_channel_mask_t halChannelMask, bool isInput, + AudioChannelMask* channelMask); + static status_t audioChannelMaskToHal(const AudioChannelMask& channelMask, + audio_channel_mask_t* halChannelMask); + static status_t audioConfigBaseFromHal(const audio_config_base_t& halConfigBase, bool isInput, + AudioConfigBase* configBase); + static status_t audioConfigBaseToHal(const AudioConfigBase& configBase, + audio_config_base_t* halConfigBase); + static status_t audioDeviceTypeFromHal(audio_devices_t halDevice, AudioDevice* device); + static status_t audioDeviceTypeToHal(const AudioDevice& device, audio_devices_t* halDevice); + static status_t audioFormatFromHal(audio_format_t halFormat, AudioFormat* format); + static status_t audioFormatToHal(const AudioFormat& format, audio_format_t* halFormat); + static status_t audioGainModeMaskFromHal(audio_gain_mode_t halGainModeMask, + hidl_vec* gainModeMask); + static status_t audioGainModeMaskToHal(const hidl_vec& gainModeMask, + audio_gain_mode_t* halGainModeMask); + static status_t audioPortFromHal(const struct audio_port_v7& halPort, AudioPort* port); + static status_t audioPortToHal(const AudioPort& port, struct audio_port_v7* halPort); + static status_t audioProfileFromHal(const struct audio_profile& halProfile, bool isInput, + AudioProfile* profile); + static status_t audioProfileToHal(const AudioProfile& profile, + struct audio_profile* halProfile); + static status_t audioSourceFromHal(audio_source_t halSource, AudioSource* source); + static status_t audioSourceToHal(const AudioSource& source, audio_source_t* halSource); + static status_t audioStreamTypeFromHal(audio_stream_type_t halStreamType, + AudioStreamType* streamType); + static status_t audioStreamTypeToHal(const AudioStreamType& streamType, + audio_stream_type_t* halStreamType); + 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); + + private: + static status_t audioIndexChannelMaskFromHal(audio_channel_mask_t halChannelMask, + AudioChannelMask* channelMask); + static status_t audioInputChannelMaskFromHal(audio_channel_mask_t halChannelMask, + AudioChannelMask* channelMask); + static status_t audioOutputChannelMaskFromHal(audio_channel_mask_t halChannelMask, + AudioChannelMask* channelMask); + static status_t audioPortExtendedInfoFromHal( + audio_port_role_t role, audio_port_type_t type, + const struct audio_port_config_device_ext& device, + const struct audio_port_config_mix_ext& mix, + const struct audio_port_config_session_ext& session, AudioPortExtendedInfo* ext, + bool* isInput); + static status_t audioPortExtendedInfoToHal(const AudioPortExtendedInfo& ext, + audio_port_role_t* role, audio_port_type_t* type, + struct audio_port_config_device_ext* device, + struct audio_port_config_mix_ext* mix, + struct audio_port_config_session_ext* session); +#endif }; } // namespace implementation diff --git a/audio/common/all-versions/default/TEST_MAPPING b/audio/common/all-versions/default/TEST_MAPPING new file mode 100644 index 0000000000..4316ccf4f5 --- /dev/null +++ b/audio/common/all-versions/default/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "android.hardware.audio.common@7.0-util_tests" + } + ] +} diff --git a/audio/common/all-versions/default/tests/hidlutils_tests.cpp b/audio/common/all-versions/default/tests/hidlutils_tests.cpp new file mode 100644 index 0000000000..bfc99e6b48 --- /dev/null +++ b/audio/common/all-versions/default/tests/hidlutils_tests.cpp @@ -0,0 +1,631 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#define LOG_TAG "HidlUtils_Test" +#include + +#include +#include +#include +#include + +using namespace android; +using namespace ::android::hardware::audio::common::CPP_VERSION; +using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils; +namespace xsd { +using namespace ::android::audio::policy::configuration::V7_0; +} + +static constexpr audio_channel_mask_t kInvalidHalChannelMask = + static_cast(0xFFFFFFFFU); +static constexpr audio_devices_t kInvalidHalDevice = static_cast(0xFFFFFFFFU); +static constexpr audio_format_t kInvalidHalFormat = static_cast(0xFFFFFFFFU); +static constexpr audio_gain_mode_t kInvalidHalGainMode = + static_cast(0xFFFFFFFFU); +static constexpr audio_source_t kInvalidHalSource = static_cast(0xFFFFFFFFU); +static constexpr audio_stream_type_t kInvalidHalStreamType = + static_cast(0xFFFFFFFFU); +static constexpr audio_usage_t kInvalidHalUsage = static_cast(0xFFFFFFFFU); + +TEST(HidlUtils, ConvertInvalidChannelMask) { + AudioChannelMask invalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioChannelMaskFromHal(AUDIO_CHANNEL_INVALID, + false /*isInput*/, &invalid)); + EXPECT_EQ(BAD_VALUE, HidlUtils::audioChannelMaskFromHal(AUDIO_CHANNEL_INVALID, true /*isInput*/, + &invalid)); + EXPECT_EQ(BAD_VALUE, HidlUtils::audioChannelMaskFromHal(kInvalidHalChannelMask, + false /*isInput*/, &invalid)); + EXPECT_EQ(BAD_VALUE, HidlUtils::audioChannelMaskFromHal(kInvalidHalChannelMask, + true /*isInput*/, &invalid)); + audio_channel_mask_t halInvalid; + // INVALID channel mask is not in XSD thus it's not allowed for transfer over HIDL. + EXPECT_EQ(BAD_VALUE, HidlUtils::audioChannelMaskToHal("AUDIO_CHANNEL_INVALID", &halInvalid)); + EXPECT_EQ(BAD_VALUE, HidlUtils::audioChannelMaskToHal("random string", &halInvalid)); +} + +// Might move these to the audio_policy_configuration_V7_0-enums library +// if there would be usages in the default wrapper code. In that case, +// it would be better to reimplement these methods using a proper switch statement +// over all known enum values. +static bool isInputChannelMask(xsd::AudioChannelMask channelMask) { + return toString(channelMask).find("_CHANNEL_IN_") != std::string::npos; +} + +static bool isOutputChannelMask(xsd::AudioChannelMask channelMask) { + return toString(channelMask).find("_CHANNEL_OUT_") != std::string::npos; +} + +static bool isIndexChannelMask(xsd::AudioChannelMask channelMask) { + return toString(channelMask).find("_CHANNEL_INDEX_") != std::string::npos; +} + +TEST(HidlUtils, ConvertChannelMask) { + for (const auto enumVal : xsdc_enum_range{}) { + const AudioChannelMask channelMask = toString(enumVal); + audio_channel_mask_t halChannelMask, halChannelMaskBack; + AudioChannelMask channelMaskBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioChannelMaskToHal(channelMask, &halChannelMask)) + << "Conversion of \"" << channelMask << "\" failed"; + EXPECT_EQ(enumVal != xsd::AudioChannelMask::AUDIO_CHANNEL_NONE, + audio_channel_mask_is_valid(halChannelMask)) + << "Validity of \"" << channelMask << "\" is not as expected"; + if (bool isInput = isInputChannelMask(enumVal); isInput || isOutputChannelMask(enumVal)) { + EXPECT_EQ(NO_ERROR, + HidlUtils::audioChannelMaskFromHal(halChannelMask, isInput, &channelMaskBack)) + << "Conversion of " << (isInput ? "input" : "output") << " channel mask " + << halChannelMask << " failed"; + // Due to aliased values, the result of 'fromHal' might not be the same + // as 'channelMask', thus we need to compare the results of 'toHal' conversion instead. + EXPECT_EQ(NO_ERROR, + HidlUtils::audioChannelMaskToHal(channelMaskBack, &halChannelMaskBack)) + << "Conversion of \"" << channelMaskBack << "\" failed"; + EXPECT_EQ(halChannelMask, halChannelMaskBack); + } else if (isIndexChannelMask(enumVal) || + enumVal == xsd::AudioChannelMask::AUDIO_CHANNEL_NONE) { + // Conversions for indexed masks and "none" must not depend on the provided direction. + EXPECT_EQ(NO_ERROR, HidlUtils::audioChannelMaskFromHal(halChannelMask, true /*isInput*/, + &channelMaskBack)) + << "Conversion of indexed / none channel mask " << halChannelMask + << " failed (as input channel mask)"; + EXPECT_EQ(channelMask, channelMaskBack); + EXPECT_EQ(NO_ERROR, HidlUtils::audioChannelMaskFromHal( + halChannelMask, false /*isInput*/, &channelMaskBack)) + << "Conversion of indexed / none channel mask " << halChannelMask + << " failed (as output channel mask)"; + EXPECT_EQ(channelMask, channelMaskBack); + } else { + FAIL() << "Unrecognized channel mask \"" << channelMask << "\""; + } + } +} + +TEST(HidlUtils, ConvertInvalidConfigBase) { + AudioConfigBase invalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigBaseFromHal({.sample_rate = 0, + .channel_mask = kInvalidHalChannelMask, + .format = kInvalidHalFormat}, + false /*isInput*/, &invalid)); + EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigBaseFromHal({.sample_rate = 0, + .channel_mask = kInvalidHalChannelMask, + .format = kInvalidHalFormat}, + true /*isInput*/, &invalid)); + audio_config_base_t halInvalid; + invalid.sampleRateHz = 0; + invalid.channelMask = "random string"; + invalid.format = "random string"; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioConfigBaseToHal(invalid, &halInvalid)); +} + +TEST(HidlUtils, ConvertConfigBase) { + AudioConfigBase configBase; + configBase.sampleRateHz = 44100; + configBase.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO); + configBase.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT); + audio_config_base_t halConfigBase; + EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigBaseToHal(configBase, &halConfigBase)); + AudioConfigBase configBaseBack; + EXPECT_EQ(NO_ERROR, + HidlUtils::audioConfigBaseFromHal(halConfigBase, false /*isInput*/, &configBaseBack)); + EXPECT_EQ(configBase, configBaseBack); +} + +TEST(HidlUtils, ConvertInvalidDeviceType) { + AudioDevice invalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioDeviceTypeFromHal(kInvalidHalDevice, &invalid)); + audio_devices_t halInvalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioDeviceTypeToHal("random string", &halInvalid)); +} + +TEST(HidlUtils, ConvertDeviceType) { + for (const auto enumVal : xsdc_enum_range{}) { + const AudioDevice deviceType = toString(enumVal); + audio_devices_t halDeviceType, halDeviceTypeBack; + AudioDevice deviceTypeBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioDeviceTypeToHal(deviceType, &halDeviceType)) + << "Conversion of \"" << deviceType << "\" failed"; + if (enumVal != xsd::AudioDevice::AUDIO_DEVICE_NONE) { + EXPECT_TRUE(audio_is_input_device(halDeviceType) || + audio_is_output_device(halDeviceType)) + << "Device \"" << deviceType << "\" is neither input, nor output device"; + } else { + EXPECT_FALSE(audio_is_input_device(halDeviceType)); + EXPECT_FALSE(audio_is_output_device(halDeviceType)); + } + EXPECT_EQ(NO_ERROR, HidlUtils::audioDeviceTypeFromHal(halDeviceType, &deviceTypeBack)) + << "Conversion of device type " << halDeviceType << " failed"; + // Due to aliased values, the result of 'fromHal' might not be the same + // as 'deviceType', thus we need to compare the results of 'toHal' conversion instead. + EXPECT_EQ(NO_ERROR, HidlUtils::audioDeviceTypeToHal(deviceTypeBack, &halDeviceTypeBack)) + << "Conversion of \"" << deviceTypeBack << "\" failed"; + EXPECT_EQ(halDeviceType, halDeviceTypeBack); + } +} + +// The enums module is too small to have unit tests on its own. +TEST(HidlUtils, VendorExtension) { + EXPECT_TRUE(xsd::isVendorExtension("VX_GOOGLE_VR_42")); + EXPECT_FALSE(xsd::isVendorExtension("random string")); + EXPECT_FALSE(xsd::isVendorExtension("VX_")); + EXPECT_FALSE(xsd::isVendorExtension("VX_GOOGLE_$$")); +} + +TEST(HidlUtils, ConvertInvalidDeviceAddress) { + DeviceAddress invalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressFromHal(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, + nullptr, &invalid)); + EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressFromHal(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, + "", &invalid)); + EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressFromHal(AUDIO_DEVICE_OUT_IP, nullptr, &invalid)); + EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressFromHal(AUDIO_DEVICE_OUT_IP, "", &invalid)); + EXPECT_EQ(BAD_VALUE, + HidlUtils::deviceAddressFromHal(AUDIO_DEVICE_OUT_USB_HEADSET, nullptr, &invalid)); + EXPECT_EQ(BAD_VALUE, + HidlUtils::deviceAddressFromHal(AUDIO_DEVICE_OUT_USB_HEADSET, "", &invalid)); + + audio_devices_t halInvalid; + char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN] = {}; + invalid = {}; + invalid.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER); + EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressToHal(invalid, &halInvalid, halAddress)); + invalid.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_IP); + EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressToHal(invalid, &halInvalid, halAddress)); + invalid.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_USB_HEADSET); + EXPECT_EQ(BAD_VALUE, HidlUtils::deviceAddressToHal(invalid, &halInvalid, halAddress)); +} + +static void ConvertDeviceAddress(const DeviceAddress& device) { + audio_devices_t halDeviceType; + char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN] = {}; + EXPECT_EQ(NO_ERROR, HidlUtils::deviceAddressToHal(device, &halDeviceType, halDeviceAddress)); + DeviceAddress deviceBack; + EXPECT_EQ(NO_ERROR, + HidlUtils::deviceAddressFromHal(halDeviceType, halDeviceAddress, &deviceBack)); + EXPECT_EQ(device, deviceBack); +} + +TEST(HidlUtils, ConvertUniqueDeviceAddress) { + DeviceAddress speaker; + speaker.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER); + ConvertDeviceAddress(speaker); +} + +TEST(HidlUtils, ConvertA2dpDeviceAddress) { + DeviceAddress a2dpSpeaker; + a2dpSpeaker.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER); + a2dpSpeaker.address.mac(std::array{1, 2, 3, 4, 5, 6}); + ConvertDeviceAddress(a2dpSpeaker); +} + +TEST(HidlUtils, ConvertIpv4DeviceAddress) { + DeviceAddress ipv4; + ipv4.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_IP); + ipv4.address.ipv4(std::array{1, 2, 3, 4}); + ConvertDeviceAddress(ipv4); +} + +TEST(HidlUtils, ConvertUsbDeviceAddress) { + DeviceAddress usbHeadset; + usbHeadset.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_USB_HEADSET); + usbHeadset.address.alsa({1, 2}); + ConvertDeviceAddress(usbHeadset); +} + +TEST(HidlUtils, ConvertBusDeviceAddress) { + DeviceAddress bus; + bus.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_BUS); + bus.address.id("bus_device"); + ConvertDeviceAddress(bus); +} + +TEST(HidlUtils, ConvertRSubmixDeviceAddress) { + DeviceAddress rSubmix; + rSubmix.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_REMOTE_SUBMIX); + rSubmix.address.id(AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS); + ConvertDeviceAddress(rSubmix); +} + +TEST(HidlUtils, ConvertVendorDeviceAddress) { + // The address part is not mandatory, both cases must work. + { + DeviceAddress vendor; + vendor.deviceType = "VX_GOOGLE_VR"; + audio_devices_t halDeviceType; + char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN] = {}; + // Ignore the result. Vendors will also add the extended device into + // the list of devices in audio-hal-enums.h. Without that, the conversion + // officially fails, but it still maps the device type to NONE. + (void)HidlUtils::deviceAddressToHal(vendor, &halDeviceType, halDeviceAddress); + EXPECT_EQ(AUDIO_DEVICE_NONE, halDeviceType); + EXPECT_EQ(0, strnlen(halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN)); + } + { + DeviceAddress vendor; + vendor.deviceType = "VX_GOOGLE_VR"; + vendor.address.id("vr1"); + audio_devices_t halDeviceType; + char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN] = {}; + // Ignore the result. Vendors will also add the extended device into + // the list of devices in audio-hal-enums.h. Without that, the conversion + // officially fails, but it still maps the device type to NONE and converts + // the address. + (void)HidlUtils::deviceAddressToHal(vendor, &halDeviceType, halDeviceAddress); + EXPECT_EQ(AUDIO_DEVICE_NONE, halDeviceType); + EXPECT_EQ(0, strncmp("vr1", halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN)); + } +} + +TEST(HidlUtils, ConvertInvalidFormat) { + AudioFormat invalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioFormatFromHal(kInvalidHalFormat, &invalid)); + audio_format_t halInvalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioFormatToHal("random string", &halInvalid)); +} + +TEST(HidlUtils, ConvertFormat) { + for (const auto enumVal : xsdc_enum_range{}) { + const AudioFormat format = toString(enumVal); + audio_format_t halFormat; + AudioFormat formatBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioFormatToHal(format, &halFormat)) + << "Conversion of \"" << format << "\" failed"; + EXPECT_TRUE(audio_is_valid_format(halFormat)) + << "Converted format \"" << format << "\" is invalid"; + EXPECT_EQ(NO_ERROR, HidlUtils::audioFormatFromHal(halFormat, &formatBack)) + << "Conversion of format " << halFormat << " failed"; + EXPECT_EQ(format, formatBack); + } +} + +TEST(HidlUtils, ConvertInvalidGainModeMask) { + hidl_vec invalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainModeMaskFromHal(kInvalidHalGainMode, &invalid)); + audio_gain_mode_t halInvalid; + invalid.resize(1); + invalid[0] = "random string"; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainModeMaskToHal(invalid, &halInvalid)); +} + +TEST(HidlUtils, ConvertGainModeMask) { + hidl_vec emptyGainModes; + audio_gain_mode_t halEmptyGainModes; + EXPECT_EQ(NO_ERROR, HidlUtils::audioGainModeMaskToHal(emptyGainModes, &halEmptyGainModes)); + hidl_vec emptyGainModesBack; + EXPECT_EQ(NO_ERROR, + HidlUtils::audioGainModeMaskFromHal(halEmptyGainModes, &emptyGainModesBack)); + EXPECT_EQ(emptyGainModes, emptyGainModesBack); + + std::vector allEnumValues; + for (const auto enumVal : xsdc_enum_range{}) { + allEnumValues.push_back(toString(enumVal)); + } + hidl_vec allGainModes; + allGainModes.resize(allEnumValues.size()); + for (size_t i = 0; i < allEnumValues.size(); ++i) { + allGainModes[i] = allEnumValues[i]; + } + audio_gain_mode_t halAllGainModes; + EXPECT_EQ(NO_ERROR, HidlUtils::audioGainModeMaskToHal(allGainModes, &halAllGainModes)); + hidl_vec allGainModesBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioGainModeMaskFromHal(halAllGainModes, &allGainModesBack)); + EXPECT_EQ(allGainModes, allGainModesBack); +} + +TEST(HidlUtils, ConvertInvalidSource) { + AudioSource invalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioSourceFromHal(kInvalidHalSource, &invalid)); + audio_source_t halInvalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioSourceToHal("random string", &halInvalid)); +} + +TEST(HidlUtils, ConvertSource) { + for (const auto enumVal : xsdc_enum_range{}) { + const AudioSource source = toString(enumVal); + audio_source_t halSource; + AudioSource sourceBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioSourceToHal(source, &halSource)) + << "Conversion of \"" << source << "\" failed"; + EXPECT_EQ(enumVal != xsd::AudioSource::AUDIO_SOURCE_DEFAULT, + audio_is_valid_audio_source(halSource)) + << "Validity of \"" << source << "\" is not as expected"; + EXPECT_EQ(NO_ERROR, HidlUtils::audioSourceFromHal(halSource, &sourceBack)) + << "Conversion of source " << halSource << " failed"; + EXPECT_EQ(source, sourceBack); + } +} + +TEST(HidlUtils, ConvertInvalidStreamType) { + AudioStreamType invalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioStreamTypeFromHal(kInvalidHalStreamType, &invalid)); + audio_stream_type_t halInvalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioStreamTypeToHal("random string", &halInvalid)); +} + +TEST(HidlUtils, ConvertStreamType) { + for (const auto enumVal : xsdc_enum_range{}) { + const AudioStreamType streamType = toString(enumVal); + audio_stream_type_t halStreamType; + AudioStreamType streamTypeBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioStreamTypeToHal(streamType, &halStreamType)) + << "Conversion of \"" << streamType << "\" failed"; + EXPECT_EQ(NO_ERROR, HidlUtils::audioStreamTypeFromHal(halStreamType, &streamTypeBack)) + << "Conversion of stream type " << halStreamType << " failed"; + EXPECT_EQ(streamType, streamTypeBack); + } +} + +TEST(HidlUtils, ConvertInvalidGain) { + AudioGain invalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainFromHal({.mode = kInvalidHalGainMode}, + false /*isInput*/, &invalid)); + EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainFromHal({.mode = kInvalidHalGainMode}, + true /*isInput*/, &invalid)); + struct audio_gain halInvalid; + invalid.mode.resize(1); + invalid.mode[0] = "random string"; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainToHal(invalid, &halInvalid)); +} + +TEST(HidlUtils, ConvertGain) { + AudioGain gain = {}; + gain.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO); + struct audio_gain halGain; + EXPECT_EQ(NO_ERROR, HidlUtils::audioGainToHal(gain, &halGain)); + AudioGain gainBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioGainFromHal(halGain, false /*isInput*/, &gainBack)); + EXPECT_EQ(gain, gainBack); + struct audio_gain halGainBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioGainToHal(gainBack, &halGainBack)); + EXPECT_TRUE(audio_gains_are_equal(&halGain, &halGainBack)); +} + +TEST(HidlUtils, ConvertInvalidGainConfig) { + AudioGainConfig invalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainConfigFromHal({.mode = kInvalidHalGainMode}, + false /*isInput*/, &invalid)); + EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainConfigFromHal({.mode = kInvalidHalGainMode}, + true /*isInput*/, &invalid)); + struct audio_gain_config halInvalid; + invalid.mode.resize(1); + invalid.mode[0] = "random string"; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioGainConfigToHal(invalid, &halInvalid)); +} + +TEST(HidlUtils, ConvertGainConfig) { + AudioGainConfig gainConfig = {}; + gainConfig.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO); + struct audio_gain_config halGainConfig; + EXPECT_EQ(NO_ERROR, HidlUtils::audioGainConfigToHal(gainConfig, &halGainConfig)); + AudioGainConfig gainConfigBack; + EXPECT_EQ(NO_ERROR, + HidlUtils::audioGainConfigFromHal(halGainConfig, false /*isInput*/, &gainConfigBack)); + EXPECT_EQ(gainConfig, gainConfigBack); + struct audio_gain_config halGainConfigBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioGainConfigToHal(gainConfigBack, &halGainConfigBack)); + EXPECT_TRUE(audio_gain_config_are_equal(&halGainConfig, &halGainConfigBack)); +} + +TEST(HidlUtils, ConvertInvalidUsage) { + AudioUsage invalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioUsageFromHal(kInvalidHalUsage, &invalid)); + audio_usage_t halInvalid; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioUsageToHal("random string", &halInvalid)); +} + +TEST(HidlUtils, ConvertUsage) { + for (const auto enumVal : xsdc_enum_range{}) { + const AudioUsage usage = toString(enumVal); + audio_usage_t halUsage; + AudioUsage usageBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioUsageToHal(usage, &halUsage)) + << "Conversion of \"" << usage << "\" failed"; + EXPECT_EQ(NO_ERROR, HidlUtils::audioUsageFromHal(halUsage, &usageBack)) + << "Conversion of usage " << halUsage << " failed"; + EXPECT_EQ(usage, usageBack); + } +} + +TEST(HidlUtils, ConvertInvalidOffloadInfo) { + AudioOffloadInfo invalid; + audio_offload_info_t halInvalid = AUDIO_INFO_INITIALIZER; + halInvalid.channel_mask = AUDIO_CHANNEL_INVALID; + halInvalid.format = kInvalidHalFormat; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioOffloadInfoFromHal(halInvalid, &invalid)); + invalid.base.channelMask = "random string"; + invalid.base.format = "random string"; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioOffloadInfoToHal(invalid, &halInvalid)); +} + +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.streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC); + offloadInfo.bitRatePerSecond = 320; + offloadInfo.durationMicroseconds = -1; + offloadInfo.bitWidth = 16; + offloadInfo.bufferSize = 1024; + offloadInfo.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA); + offloadInfo.encapsulationMode = AudioEncapsulationMode::ELEMENTARY_STREAM; + offloadInfo.contentId = 42; + offloadInfo.syncId = 13; + audio_offload_info_t halOffloadInfo; + EXPECT_EQ(NO_ERROR, HidlUtils::audioOffloadInfoToHal(offloadInfo, &halOffloadInfo)); + AudioOffloadInfo offloadInfoBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioOffloadInfoFromHal(halOffloadInfo, &offloadInfoBack)); + EXPECT_EQ(offloadInfo, offloadInfoBack); +} + +TEST(HidlUtils, ConvertInvalidConfig) { + AudioConfig invalid; + audio_config_t halInvalid = AUDIO_CONFIG_INITIALIZER; + halInvalid.channel_mask = AUDIO_CHANNEL_INVALID; + 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)); +} + +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); + config.offloadInfo.base = config.base; + config.offloadInfo.streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC); + config.offloadInfo.bitRatePerSecond = 320; + config.offloadInfo.durationMicroseconds = -1; + config.offloadInfo.bitWidth = 16; + config.offloadInfo.bufferSize = 1024; + config.offloadInfo.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA); + config.offloadInfo.encapsulationMode = AudioEncapsulationMode::ELEMENTARY_STREAM; + config.offloadInfo.contentId = 42; + config.offloadInfo.syncId = 13; + audio_config_t halConfig; + EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigToHal(config, &halConfig)); + AudioConfig configBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigFromHal(halConfig, false /*isInput*/, &configBack)); + EXPECT_EQ(config, configBack); +} + +TEST(HidlUtils, ConvertInvalidAudioProfile) { + AudioProfile invalid; + struct audio_profile halInvalid = {}; + halInvalid.format = kInvalidHalFormat; + halInvalid.num_sample_rates = 0; + halInvalid.num_channel_masks = 1; + halInvalid.channel_masks[0] = kInvalidHalChannelMask; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioProfileFromHal(halInvalid, false /*isInput*/, &invalid)); + EXPECT_EQ(BAD_VALUE, HidlUtils::audioProfileFromHal(halInvalid, true /*isInput*/, &invalid)); + invalid.format = "random string"; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioProfileToHal(invalid, &halInvalid)); +} + +TEST(HidlUtils, ConvertAudioProfile) { + 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); + struct audio_profile halProfile; + EXPECT_EQ(NO_ERROR, HidlUtils::audioProfileToHal(profile, &halProfile)); + AudioProfile profileBack; + EXPECT_EQ(NO_ERROR, + HidlUtils::audioProfileFromHal(halProfile, false /*isInput*/, &profileBack)); + EXPECT_EQ(profile, profileBack); +} + +TEST(HidlUtils, ConvertInvalidAudioPortConfig) { + AudioPortConfig invalid; + struct audio_port_config halInvalid = {}; + halInvalid.type = AUDIO_PORT_TYPE_MIX; + halInvalid.role = AUDIO_PORT_ROLE_NONE; // note: this is valid. + halInvalid.config_mask = AUDIO_PORT_CONFIG_CHANNEL_MASK; + halInvalid.channel_mask = AUDIO_CHANNEL_INVALID; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioPortConfigFromHal(halInvalid, &invalid)); + invalid.base.channelMask = "random string"; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioPortConfigToHal(invalid, &halInvalid)); +} + +TEST(HidlUtils, ConvertAudioPortConfig) { + AudioPortConfig config = {}; + config.id = 42; + 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.gain.config({}); + config.gain.config().channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO); + config.ext.device({}); + config.ext.device().deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER); + struct audio_port_config halConfig; + EXPECT_EQ(NO_ERROR, HidlUtils::audioPortConfigToHal(config, &halConfig)); + AudioPortConfig configBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioPortConfigFromHal(halConfig, &configBack)); + EXPECT_EQ(config, configBack); + struct audio_port_config halConfigBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioPortConfigToHal(configBack, &halConfigBack)); + EXPECT_TRUE(audio_port_configs_are_equal(&halConfig, &halConfigBack)); +} + +TEST(HidlUtils, ConvertInvalidAudioPort) { + AudioPort invalid; + struct audio_port_v7 halInvalid = {}; + halInvalid.type = AUDIO_PORT_TYPE_MIX; + halInvalid.role = AUDIO_PORT_ROLE_NONE; // note: this is valid. + 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"; + EXPECT_EQ(BAD_VALUE, HidlUtils::audioPortToHal(invalid, &halInvalid)); +} + +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.gains.resize(1); + port.gains[0].channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO); + port.ext.device({}); + port.ext.device().deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER); + // active config left unspecified. + struct audio_port_v7 halPort; + EXPECT_EQ(NO_ERROR, HidlUtils::audioPortToHal(port, &halPort)); + AudioPort portBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioPortFromHal(halPort, &portBack)); + EXPECT_EQ(port, portBack); + struct audio_port_v7 halPortBack; + EXPECT_EQ(NO_ERROR, HidlUtils::audioPortToHal(portBack, &halPortBack)); + EXPECT_TRUE(audio_ports_v7_are_equal(&halPort, &halPortBack)); +} diff --git a/audio/core/all-versions/default/Conversions.cpp b/audio/core/all-versions/default/Conversions.cpp index 0db210a58a..28d8f78bbc 100644 --- a/audio/core/all-versions/default/Conversions.cpp +++ b/audio/core/all-versions/default/Conversions.cpp @@ -27,6 +27,7 @@ namespace audio { namespace CPP_VERSION { namespace implementation { +// TODO(mnaganov): Use method from HidlUtils for V7 std::string deviceAddressToHal(const DeviceAddress& address) { // HAL assumes that the address is NUL-terminated. char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp index 6260ba1979..3c28159816 100644 --- a/audio/core/all-versions/default/Device.cpp +++ b/audio/core/all-versions/default/Device.cpp @@ -283,8 +283,10 @@ std::tuple Device::createOrUpdateAudioPatch( const hidl_vec& sinks) { Result retval(Result::NOT_SUPPORTED); if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { - std::unique_ptr halSources(HidlUtils::audioPortConfigsToHal(sources)); - std::unique_ptr halSinks(HidlUtils::audioPortConfigsToHal(sinks)); + std::unique_ptr halSources; + HidlUtils::audioPortConfigsToHal(sources, &halSources); + std::unique_ptr halSinks; + HidlUtils::audioPortConfigsToHal(sinks, &halSinks); audio_patch_handle_t halPatch = static_cast(patch); retval = analyzeStatus("create_audio_patch", mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0], 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 eb8cb3f4f7..1612d3c30c 100644 --- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp @@ -67,8 +67,7 @@ TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) { auto flags = hidl_bitfield(AudioInputFlag::NONE); const SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}}; #elif MAJOR_VERSION >= 7 - config.base.channelMask.resize(1); - config.base.channelMask[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO); + config.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO); config.base.sampleRateHz = 8000; config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT); hidl_vec flags; diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp index 63eaea8acc..941c4bdbc9 100644 --- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp @@ -26,8 +26,7 @@ static std::vector combineAudioConfig(std::vector