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
Merged-In: Ib883f1c246fce78c004846516699aa724d4b5d44
This commit is contained in:
Mikhail Naganov 2020-10-29 13:08:05 -07:00
parent 4122f6328a
commit 1b444a5332
15 changed files with 1771 additions and 109 deletions

View file

@ -360,7 +360,7 @@ package android.audio.policy.configuration.V7_0 {
public static class DevicePorts.DevicePort { public static class DevicePorts.DevicePort {
ctor public DevicePorts.DevicePort(); ctor public DevicePorts.DevicePort();
method @Nullable public String getAddress(); method @Nullable public String getAddress();
method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.AudioFormat> getEncodedFormats(); method @Nullable public java.util.List<java.lang.String> getEncodedFormats();
method @Nullable public android.audio.policy.configuration.V7_0.Gains getGains(); method @Nullable public android.audio.policy.configuration.V7_0.Gains getGains();
method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.Profile> getProfile(); method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.Profile> getProfile();
method @Nullable public android.audio.policy.configuration.V7_0.Role getRole(); 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 String getType();
method @Nullable public boolean get_default(); method @Nullable public boolean get_default();
method public void setAddress(@Nullable String); method public void setAddress(@Nullable String);
method public void setEncodedFormats(@Nullable java.util.List<android.audio.policy.configuration.V7_0.AudioFormat>); method public void setEncodedFormats(@Nullable java.util.List<java.lang.String>);
method public void setGains(@Nullable android.audio.policy.configuration.V7_0.Gains); 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 setRole(@Nullable android.audio.policy.configuration.V7_0.Role);
method public void setTagName(@Nullable String); method public void setTagName(@Nullable String);
@ -527,10 +527,10 @@ package android.audio.policy.configuration.V7_0 {
public static class SurroundFormats.Format { public static class SurroundFormats.Format {
ctor public SurroundFormats.Format(); ctor public SurroundFormats.Format();
method @Nullable public android.audio.policy.configuration.V7_0.AudioFormat getName(); method @Nullable public String getName();
method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.AudioFormat> getSubformats(); method @Nullable public java.util.List<java.lang.String> getSubformats();
method public void setName(@Nullable android.audio.policy.configuration.V7_0.AudioFormat); method public void setName(@Nullable String);
method public void setSubformats(@Nullable java.util.List<android.audio.policy.configuration.V7_0.AudioFormat>); method public void setSubformats(@Nullable java.util.List<java.lang.String>);
} }
public class SurroundSound { public class SurroundSound {

View file

@ -774,13 +774,13 @@
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
<xs:simpleType name="audioFormatsList"> <xs:simpleType name="audioFormatsList">
<xs:list itemType="audioFormat" /> <xs:list itemType="extendableAudioFormat" />
</xs:simpleType> </xs:simpleType>
<xs:complexType name="surroundFormats"> <xs:complexType name="surroundFormats">
<xs:sequence> <xs:sequence>
<xs:element name="format" minOccurs="0" maxOccurs="unbounded"> <xs:element name="format" minOccurs="0" maxOccurs="unbounded">
<xs:complexType> <xs:complexType>
<xs:attribute name="name" type="audioFormat" use="required"/> <xs:attribute name="name" type="extendableAudioFormat" use="required"/>
<xs:attribute name="subformats" type="audioFormatsList" /> <xs:attribute name="subformats" type="audioFormatsList" />
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>

View file

@ -179,7 +179,8 @@ struct AudioFrequencyResponsePoint {
* Used by StreamIn and Device * Used by StreamIn and Device
*/ */
struct MicrophoneInfo { 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. * even after rebooting.
*/ */
string deviceId; string deviceId;
@ -187,18 +188,21 @@ struct MicrophoneInfo {
* Device specific information * Device specific information
*/ */
DeviceAddress deviceAddress; 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<AudioMicrophoneChannelMapping> channelMapping; vec<AudioMicrophoneChannelMapping> channelMapping;
/** Location of the microphone in regard to the body of the device */ /** Location of the microphone in regard to the body of the device */
AudioMicrophoneLocation location; 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; 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; uint32_t indexInTheGroup;
/** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL */ /** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL */
@ -209,17 +213,20 @@ struct MicrophoneInfo {
float minSpl; float minSpl;
/** Standard polar pattern of the microphone */ /** Standard polar pattern of the microphone */
AudioMicrophoneDirectionality directionality; AudioMicrophoneDirectionality directionality;
/** Vector with ordered frequency responses (from low to high frequencies) /**
* with the frequency response of the microphone. * Vector with ordered frequency responses (from low to high frequencies)
* Levels are in dB, relative to level at 1000 Hz * with the frequency response of the microphone.
* Levels are in dB, relative to level at 1000 Hz
*/ */
vec<AudioFrequencyResponsePoint> frequencyResponse; vec<AudioFrequencyResponsePoint> 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; 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; AudioMicrophoneCoordinate orientation;
}; };

View file

@ -18,6 +18,8 @@
#define ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H #define ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
#include <sys/types.h> #include <sys/types.h>
#include <algorithm>
#include <cctype>
#include <android_audio_policy_configuration_V7_0.h> #include <android_audio_policy_configuration_V7_0.h>
@ -210,6 +212,43 @@ static inline bool isOutputDevice(const std::string& device) {
return isOutputDevice(stringToAudioDevice(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 } // namespace android::audio::policy::configuration::V7_0
#endif // ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H #endif // ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H

View file

@ -118,9 +118,9 @@ typedef string AudioChannelMask;
* Base configuration attributes applicable to any stream of audio. * Base configuration attributes applicable to any stream of audio.
*/ */
struct AudioConfigBase { struct AudioConfigBase {
AudioFormat format; // 'DEFAULT' means 'unspecified' AudioFormat format; // empty means 'unspecified'
uint32_t sampleRateHz; // 0 means 'unspecified' uint32_t sampleRateHz; // 0 means 'unspecified'
vec<AudioChannelMask> channelMask; // empty means 'unspecified' AudioChannelMask channelMask; // empty means 'unspecified'
}; };
/** /**
@ -167,10 +167,18 @@ struct DeviceAddress {
AudioDevice deviceType; AudioDevice deviceType;
safe_union Address { safe_union Address {
/** /**
* The address may be left unspecified if 'device' specifies * String uniquely identifying the device among other devices
* a physical device unambiguously. * 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. */ /** IEEE 802 MAC address. Set for Bluetooth devices. */
uint8_t[6] mac; uint8_t[6] mac;
/** IPv4 Address. Set for IPv4 devices. */ /** IPv4 Address. Set for IPv4 devices. */
@ -182,10 +190,6 @@ struct DeviceAddress {
int32_t card; int32_t card;
int32_t device; int32_t device;
} alsa; } 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; } address;
}; };
@ -349,9 +353,9 @@ struct AudioGainConfig {
/** /**
* Gain values in millibels for each channel ordered from LSb to MSb in * 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 * 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<int32_t> values;
uint32_t rampDurationMs; // ramp duration in ms uint32_t rampDurationMs; // ramp duration in ms
}; };
@ -409,7 +413,7 @@ struct AudioPortConfig {
* parameters (or none) may be set. See the documentation of the * parameters (or none) may be set. See the documentation of the
* AudioConfigBase struct. * AudioConfigBase struct.
*/ */
AudioConfigBase config; AudioConfigBase base;
/** Associated gain control. */ /** Associated gain control. */
safe_union OptionalGain { safe_union OptionalGain {
Monostate unspecified; Monostate unspecified;
@ -439,6 +443,8 @@ struct AudioPort {
vec<AudioProfile> profiles; vec<AudioProfile> profiles;
/** List of gain controls attached to the port. */ /** List of gain controls attached to the port. */
vec<AudioGain> gains; vec<AudioGain> gains;
/** Parameters that depend on the actual port role. */
AudioPortExtendedInfo ext;
/** /**
* Current configuration of the audio port, may have all the fields left * Current configuration of the audio port, may have all the fields left
* unspecified. * unspecified.

View file

@ -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 <stdio.h>
#include <string.h>
#define LOG_TAG "HidlUtils"
#include <log/log.h>
#include <android_audio_policy_configuration_V7_0-enums.h>
#include <common/all-versions/VersionUtils.h>
#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<AudioGainMode>* gainModeMask) {
status_t status = NO_ERROR;
std::vector<AudioGainMode> result;
for (uint32_t bit = 0; bit < sizeof(audio_gain_mode_t) * 8; ++bit) {
audio_gain_mode_t flag = static_cast<audio_gain_mode_t>(1u << bit);
if ((flag & halGainModeMask) == flag) {
AudioGainMode flagStr = audio_gain_mode_to_string(flag);
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<AudioGainMode>& 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<audio_gain_mode_t>(*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<AudioEncapsulationMode>(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<audio_encapsulation_mode_t>(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<audio_session_t>(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

View file

@ -39,15 +39,19 @@ cc_library_shared {
], ],
} }
filegroup {
name: "android.hardware.audio.common-util@2-6",
srcs: [
"HidlUtils.cpp",
"UuidUtils.cpp",
],
}
cc_defaults { cc_defaults {
name: "android.hardware.audio.common-util_default", name: "android.hardware.audio.common-util_default",
defaults: ["hidl_defaults"], defaults: ["hidl_defaults"],
vendor_available: true, vendor_available: true,
srcs: [
"HidlUtils.cpp",
"UuidUtils.cpp",
],
export_include_dirs: ["."], export_include_dirs: ["."],
@ -70,6 +74,7 @@ cc_defaults {
cc_library_shared { cc_library_shared {
name: "android.hardware.audio.common@2.0-util", name: "android.hardware.audio.common@2.0-util",
defaults: ["android.hardware.audio.common-util_default"], defaults: ["android.hardware.audio.common-util_default"],
srcs: [":android.hardware.audio.common-util@2-6"],
shared_libs: [ shared_libs: [
"android.hardware.audio.common@2.0", "android.hardware.audio.common@2.0",
], ],
@ -83,6 +88,7 @@ cc_library_shared {
cc_library_shared { cc_library_shared {
name: "android.hardware.audio.common@4.0-util", name: "android.hardware.audio.common@4.0-util",
defaults: ["android.hardware.audio.common-util_default"], defaults: ["android.hardware.audio.common-util_default"],
srcs: [":android.hardware.audio.common-util@2-6"],
shared_libs: [ shared_libs: [
"android.hardware.audio.common@4.0", "android.hardware.audio.common@4.0",
], ],
@ -96,6 +102,7 @@ cc_library_shared {
cc_library_shared { cc_library_shared {
name: "android.hardware.audio.common@5.0-util", name: "android.hardware.audio.common@5.0-util",
defaults: ["android.hardware.audio.common-util_default"], defaults: ["android.hardware.audio.common-util_default"],
srcs: [":android.hardware.audio.common-util@2-6"],
shared_libs: [ shared_libs: [
"android.hardware.audio.common@5.0", "android.hardware.audio.common@5.0",
], ],
@ -109,6 +116,7 @@ cc_library_shared {
cc_library_shared { cc_library_shared {
name: "android.hardware.audio.common@6.0-util", name: "android.hardware.audio.common@6.0-util",
defaults: ["android.hardware.audio.common-util_default"], defaults: ["android.hardware.audio.common-util_default"],
srcs: [":android.hardware.audio.common-util@2-6"],
shared_libs: [ shared_libs: [
"android.hardware.audio.common@6.0", "android.hardware.audio.common@6.0",
], ],
@ -119,12 +127,18 @@ cc_library_shared {
], ],
} }
cc_library_shared { cc_library {
enabled: false,
name: "android.hardware.audio.common@7.0-util", name: "android.hardware.audio.common@7.0-util",
defaults: ["android.hardware.audio.common-util_default"], defaults: ["android.hardware.audio.common-util_default"],
srcs: [
"7.0/HidlUtils.cpp",
"UuidUtils.cpp",
],
shared_libs: [ shared_libs: [
"android.hardware.audio.common@7.0", "android.hardware.audio.common@7.0",
"android.hardware.audio.common@7.0-enums",
"libbase",
"libxml2",
], ],
cflags: [ cflags: [
"-DMAJOR_VERSION=7", "-DMAJOR_VERSION=7",
@ -132,3 +146,35 @@ cc_library_shared {
"-include common/all-versions/VersionMacro.h", "-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"],
}

View file

@ -37,13 +37,14 @@ status_t HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, AudioCon
return status; 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)); memset(halConfig, 0, sizeof(audio_config_t));
halConfig->sample_rate = config.sampleRateHz; halConfig->sample_rate = config.sampleRateHz;
halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask); halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
halConfig->format = static_cast<audio_format_t>(config.format); halConfig->format = static_cast<audio_format_t>(config.format);
audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info); audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info);
halConfig->frame_count = config.frameCount; halConfig->frame_count = config.frameCount;
return NO_ERROR;
} }
void HidlUtils::audioGainConfigFromHal(const struct audio_gain_config& halConfig, 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; config->rampDurationMs = halConfig.ramp_duration_ms;
} }
void HidlUtils::audioGainConfigToHal(const AudioGainConfig& config, status_t HidlUtils::audioGainConfigToHal(const AudioGainConfig& config,
struct audio_gain_config* halConfig) { struct audio_gain_config* halConfig) {
halConfig->index = config.index; halConfig->index = config.index;
halConfig->mode = static_cast<audio_gain_mode_t>(config.mode); halConfig->mode = static_cast<audio_gain_mode_t>(config.mode);
halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask); halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
@ -67,6 +68,7 @@ void HidlUtils::audioGainConfigToHal(const AudioGainConfig& config,
halConfig->values[i] = config.values[i]; halConfig->values[i] = config.values[i];
} }
halConfig->ramp_duration_ms = config.rampDurationMs; halConfig->ramp_duration_ms = config.rampDurationMs;
return NO_ERROR;
} }
void HidlUtils::audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain) { 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; 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<audio_gain_mode_t>(gain.mode); halGain->mode = static_cast<audio_gain_mode_t>(gain.mode);
halGain->channel_mask = static_cast<audio_channel_mask_t>(gain.channelMask); halGain->channel_mask = static_cast<audio_channel_mask_t>(gain.channelMask);
halGain->min_value = gain.minValue; 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->step_value = gain.stepValue;
halGain->min_ramp_ms = gain.minRampMs; halGain->min_ramp_ms = gain.minRampMs;
halGain->max_ramp_ms = gain.maxRampMs; 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) { switch (halUsage) {
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST: case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT: case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED: case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
case AUDIO_USAGE_NOTIFICATION_EVENT: case AUDIO_USAGE_NOTIFICATION_EVENT:
return AudioUsage::NOTIFICATION; *usage = AudioUsage::NOTIFICATION;
break;
default: default:
return static_cast<AudioUsage>(halUsage); *usage = static_cast<AudioUsage>(halUsage);
} }
return NO_ERROR;
} }
audio_usage_t HidlUtils::audioUsageToHal(const AudioUsage usage) { status_t HidlUtils::audioUsageToHal(const AudioUsage& usage, audio_usage_t* halUsage) {
return static_cast<audio_usage_t>(usage); *halUsage = static_cast<audio_usage_t>(usage);
return NO_ERROR;
} }
status_t HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload, 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->isStreaming = halOffload.is_streaming;
offload->bitWidth = halOffload.bit_width; offload->bitWidth = halOffload.bit_width;
offload->bufferSize = halOffload.offload_buffer_size; offload->bufferSize = halOffload.offload_buffer_size;
offload->usage = audioUsageFromHal(halOffload.usage); audioUsageFromHal(halOffload.usage, &offload->usage);
#if MAJOR_VERSION >= 6 #if MAJOR_VERSION >= 6
if (halOffload.version >= AUDIO_OFFLOAD_INFO_VERSION_0_2) { if (halOffload.version >= AUDIO_OFFLOAD_INFO_VERSION_0_2) {
offload->encapsulationMode = offload->encapsulationMode =
@ -139,11 +145,11 @@ status_t HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOfflo
return BAD_VALUE; return BAD_VALUE;
} }
#endif #endif
return OK; return NO_ERROR;
} }
void HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload, status_t HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload,
audio_offload_info_t* halOffload) { audio_offload_info_t* halOffload) {
*halOffload = AUDIO_INFO_INITIALIZER; *halOffload = AUDIO_INFO_INITIALIZER;
halOffload->sample_rate = offload.sampleRateHz; halOffload->sample_rate = offload.sampleRateHz;
halOffload->channel_mask = static_cast<audio_channel_mask_t>(offload.channelMask); halOffload->channel_mask = static_cast<audio_channel_mask_t>(offload.channelMask);
@ -155,7 +161,7 @@ void HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload,
halOffload->is_streaming = offload.isStreaming; halOffload->is_streaming = offload.isStreaming;
halOffload->bit_width = offload.bitWidth; halOffload->bit_width = offload.bitWidth;
halOffload->offload_buffer_size = offload.bufferSize; halOffload->offload_buffer_size = offload.bufferSize;
halOffload->usage = audioUsageToHal(offload.usage); audioUsageToHal(offload.usage, &halOffload->usage);
#if MAJOR_VERSION >= 6 #if MAJOR_VERSION >= 6
halOffload->encapsulation_mode = halOffload->encapsulation_mode =
static_cast<audio_encapsulation_mode_t>(offload.encapsulationMode); static_cast<audio_encapsulation_mode_t>(offload.encapsulationMode);
@ -164,10 +170,11 @@ void HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload,
#else #else
// offload doesn't contain encapsulationMode, contentId, syncId, so this is OK. // offload doesn't contain encapsulationMode, contentId, syncId, so this is OK.
#endif #endif
return NO_ERROR;
} }
void HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig, status_t HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig,
AudioPortConfig* config) { AudioPortConfig* config) {
config->id = halConfig.id; config->id = halConfig.id;
config->role = AudioPortRole(halConfig.role); config->role = AudioPortRole(halConfig.role);
config->type = AudioPortType(halConfig.type); config->type = AudioPortType(halConfig.type);
@ -201,10 +208,11 @@ void HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig
break; break;
} }
} }
return NO_ERROR;
} }
void HidlUtils::audioPortConfigToHal(const AudioPortConfig& config, status_t HidlUtils::audioPortConfigToHal(const AudioPortConfig& config,
struct audio_port_config* halConfig) { struct audio_port_config* halConfig) {
memset(halConfig, 0, sizeof(audio_port_config)); memset(halConfig, 0, sizeof(audio_port_config));
halConfig->id = config.id; halConfig->id = config.id;
halConfig->role = static_cast<audio_port_role_t>(config.role); halConfig->role = static_cast<audio_port_role_t>(config.role);
@ -242,27 +250,10 @@ void HidlUtils::audioPortConfigToHal(const AudioPortConfig& config,
break; break;
} }
} }
return NO_ERROR;
} }
void HidlUtils::audioPortConfigsFromHal(unsigned int numHalConfigs, status_t HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) {
const struct audio_port_config* halConfigs,
hidl_vec<AudioPortConfig>* configs) {
configs->resize(numHalConfigs);
for (unsigned int i = 0; i < numHalConfigs; ++i) {
audioPortConfigFromHal(halConfigs[i], &(*configs)[i]);
}
}
std::unique_ptr<audio_port_config[]> HidlUtils::audioPortConfigsToHal(
const hidl_vec<AudioPortConfig>& configs) {
std::unique_ptr<audio_port_config[]> 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) {
port->id = halPort.id; port->id = halPort.id;
port->role = AudioPortRole(halPort.role); port->role = AudioPortRole(halPort.role);
port->type = AudioPortType(halPort.type); port->type = AudioPortType(halPort.type);
@ -305,9 +296,10 @@ void HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* po
break; 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)); memset(halPort, 0, sizeof(audio_port));
halPort->id = port.id; halPort->id = port.id;
halPort->role = static_cast<audio_port_role_t>(port.role); halPort->role = static_cast<audio_port_role_t>(port.role);
@ -356,6 +348,7 @@ void HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port* halPort
break; break;
} }
} }
return NO_ERROR;
} }
} // namespace implementation } // namespace implementation

View file

@ -34,38 +34,123 @@ namespace implementation {
using namespace ::android::hardware::audio::common::CPP_VERSION; using namespace ::android::hardware::audio::common::CPP_VERSION;
class HidlUtils { struct HidlUtils {
public: #if MAJOR_VERSION < 7
// A failure here indicates a platform config that is incompatible with
// the compiled HIDL interface version.
static status_t audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config); 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, static void audioGainConfigFromHal(const struct audio_gain_config& halConfig,
AudioGainConfig* config); 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 audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain);
static void audioGainToHal(const AudioGain& gain, struct audio_gain* halGain); #else
static AudioUsage audioUsageFromHal(const audio_usage_t halUsage); static status_t audioConfigFromHal(const audio_config_t& halConfig, bool isInput,
static audio_usage_t audioUsageToHal(const AudioUsage usage); AudioConfig* config);
// A failure here indicates a platform offload info that is incompatible with static status_t audioGainConfigFromHal(const struct audio_gain_config& halConfig, bool isInput,
// the compiled HIDL interface version. 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, static status_t audioOffloadInfoFromHal(const audio_offload_info_t& halOffload,
AudioOffloadInfo* offload); AudioOffloadInfo* offload);
static void audioOffloadInfoToHal(const AudioOffloadInfo& offload, static status_t audioOffloadInfoToHal(const AudioOffloadInfo& offload,
audio_offload_info_t* halOffload); audio_offload_info_t* halOffload);
static void audioPortConfigFromHal(const struct audio_port_config& halConfig, static status_t audioPortConfigFromHal(const struct audio_port_config& halConfig,
AudioPortConfig* config); AudioPortConfig* config);
static void audioPortConfigToHal(const AudioPortConfig& config, static status_t audioPortConfigToHal(const AudioPortConfig& config,
struct audio_port_config* halConfig); struct audio_port_config* halConfig);
static void audioPortConfigsFromHal(unsigned int numHalConfigs, static status_t audioPortConfigsFromHal(unsigned int numHalConfigs,
const struct audio_port_config* halConfigs, const struct audio_port_config* halConfigs,
hidl_vec<AudioPortConfig>* configs); hidl_vec<AudioPortConfig>* 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<AudioPortConfig>& configs,
std::unique_ptr<audio_port_config[]>* 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<audio_port_config[]> audioPortConfigsToHal( static std::unique_ptr<audio_port_config[]> audioPortConfigsToHal(
const hidl_vec<AudioPortConfig>& configs); const hidl_vec<AudioPortConfig>& configs) {
static void audioPortFromHal(const struct audio_port& halPort, AudioPort* port); std::unique_ptr<audio_port_config[]> halConfigs;
static void audioPortToHal(const AudioPort& port, struct audio_port* halPort); (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<AudioGainMode>* gainModeMask);
static status_t audioGainModeMaskToHal(const hidl_vec<AudioGainMode>& 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 } // namespace implementation

View file

@ -0,0 +1,7 @@
{
"presubmit": [
{
"name": "android.hardware.audio.common@7.0-util_tests"
}
]
}

View file

@ -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 <array>
#include <string>
#include <gtest/gtest.h>
#define LOG_TAG "HidlUtils_Test"
#include <log/log.h>
#include <HidlUtils.h>
#include <android_audio_policy_configuration_V7_0-enums.h>
#include <system/audio.h>
#include <xsdc/XsdcSupport.h>
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<audio_channel_mask_t>(0xFFFFFFFFU);
static constexpr audio_devices_t kInvalidHalDevice = static_cast<audio_devices_t>(0xFFFFFFFFU);
static constexpr audio_format_t kInvalidHalFormat = static_cast<audio_format_t>(0xFFFFFFFFU);
static constexpr audio_gain_mode_t kInvalidHalGainMode =
static_cast<audio_gain_mode_t>(0xFFFFFFFFU);
static constexpr audio_source_t kInvalidHalSource = static_cast<audio_source_t>(0xFFFFFFFFU);
static constexpr audio_stream_type_t kInvalidHalStreamType =
static_cast<audio_stream_type_t>(0xFFFFFFFFU);
static constexpr audio_usage_t kInvalidHalUsage = static_cast<audio_usage_t>(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<xsd::AudioChannelMask>{}) {
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<xsd::AudioDevice>{}) {
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<uint8_t, 6>{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<uint8_t, 4>{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<xsd::AudioFormat>{}) {
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<AudioGainMode> 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<AudioGainMode> emptyGainModes;
audio_gain_mode_t halEmptyGainModes;
EXPECT_EQ(NO_ERROR, HidlUtils::audioGainModeMaskToHal(emptyGainModes, &halEmptyGainModes));
hidl_vec<AudioGainMode> emptyGainModesBack;
EXPECT_EQ(NO_ERROR,
HidlUtils::audioGainModeMaskFromHal(halEmptyGainModes, &emptyGainModesBack));
EXPECT_EQ(emptyGainModes, emptyGainModesBack);
std::vector<std::string> allEnumValues;
for (const auto enumVal : xsdc_enum_range<xsd::AudioGainMode>{}) {
allEnumValues.push_back(toString(enumVal));
}
hidl_vec<AudioGainMode> 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<AudioGainMode> 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<xsd::AudioSource>{}) {
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<xsd::AudioStreamType>{}) {
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<xsd::AudioUsage>{}) {
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));
}

View file

@ -27,6 +27,7 @@ namespace audio {
namespace CPP_VERSION { namespace CPP_VERSION {
namespace implementation { namespace implementation {
// TODO(mnaganov): Use method from HidlUtils for V7
std::string deviceAddressToHal(const DeviceAddress& address) { std::string deviceAddressToHal(const DeviceAddress& address) {
// HAL assumes that the address is NUL-terminated. // HAL assumes that the address is NUL-terminated.
char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];

View file

@ -283,8 +283,10 @@ std::tuple<Result, AudioPatchHandle> Device::createOrUpdateAudioPatch(
const hidl_vec<AudioPortConfig>& sinks) { const hidl_vec<AudioPortConfig>& sinks) {
Result retval(Result::NOT_SUPPORTED); Result retval(Result::NOT_SUPPORTED);
if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
std::unique_ptr<audio_port_config[]> halSources(HidlUtils::audioPortConfigsToHal(sources)); std::unique_ptr<audio_port_config[]> halSources;
std::unique_ptr<audio_port_config[]> halSinks(HidlUtils::audioPortConfigsToHal(sinks)); HidlUtils::audioPortConfigsToHal(sources, &halSources);
std::unique_ptr<audio_port_config[]> halSinks;
HidlUtils::audioPortConfigsToHal(sinks, &halSinks);
audio_patch_handle_t halPatch = static_cast<audio_patch_handle_t>(patch); audio_patch_handle_t halPatch = static_cast<audio_patch_handle_t>(patch);
retval = analyzeStatus("create_audio_patch", retval = analyzeStatus("create_audio_patch",
mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0], mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0],

View file

@ -67,8 +67,7 @@ TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) {
auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE); auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
const SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}}; const SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}};
#elif MAJOR_VERSION >= 7 #elif MAJOR_VERSION >= 7
config.base.channelMask.resize(1); config.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO);
config.base.channelMask[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO);
config.base.sampleRateHz = 8000; config.base.sampleRateHz = 8000;
config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT); config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
hidl_vec<hidl_string> flags; hidl_vec<hidl_string> flags;

View file

@ -26,8 +26,7 @@ static std::vector<AudioConfig> combineAudioConfig(std::vector<xsd::AudioChannel
for (auto sampleRate : sampleRates) { for (auto sampleRate : sampleRates) {
AudioConfig config{}; AudioConfig config{};
// leave offloadInfo to 0 // leave offloadInfo to 0
config.base.channelMask.resize(1); config.base.channelMask = toString(channelMask);
config.base.channelMask[0] = toString(channelMask);
config.base.sampleRateHz = sampleRate; config.base.sampleRateHz = sampleRate;
config.base.format = format; config.base.format = format;
configs.push_back(config); configs.push_back(config);