Audio: Add VTS tests for invalid enum-strings, Part 1
Add tests that try passing invalid enum-string values to HAL methods taking enum-strings. Fix issues found in the default wrapper. Interface updates: - Update AudioConfig structure to indicate whether AudioOffloadInfo is specified. - Add return value to IStreamIn.updateSinkMetadata and IStreamOut.updateSourceMetadata to provide indication of invalid arguments. - Specify the behavior of IDevice.open{Input|Output}Stream in the case of invalid arguments vs. rejected config. Bug: 142480271 Test: atest VtsHalAudioV6_0TargetTest Test: atest VtsHalAudioV7_0TargetTest with side-loaded V7 default wrapper Change-Id: I6bd7be3869cc7a8d5d00506565bbf0b3a050b630
This commit is contained in:
parent
daedb0dc2e
commit
3f1457b953
22 changed files with 1006 additions and 340 deletions
|
@ -103,6 +103,11 @@ interface IDevice {
|
|||
* If the stream can not be opened with the proposed audio config,
|
||||
* HAL must provide suggested values for the audio config.
|
||||
*
|
||||
* Note: INVALID_ARGUMENTS is returned both in the case when the
|
||||
* HAL can not use the provided config and in the case when
|
||||
* the value of any argument is invalid. In the latter case the
|
||||
* HAL must provide a default initialized suggested config.
|
||||
*
|
||||
* @param ioHandle handle assigned by AudioFlinger.
|
||||
* @param device device type and (if needed) address.
|
||||
* @param config stream configuration.
|
||||
|
@ -111,7 +116,8 @@ interface IDevice {
|
|||
May be used by implementations to configure hardware effects.
|
||||
* @return retval operation completion status.
|
||||
* @return outStream created output stream.
|
||||
* @return suggestedConfig in case of invalid parameters, suggested config.
|
||||
* @return suggestedConfig in the case of rejection of the proposed config,
|
||||
* a config suggested by the HAL.
|
||||
*/
|
||||
openOutputStream(
|
||||
AudioIoHandle ioHandle,
|
||||
|
@ -128,6 +134,11 @@ interface IDevice {
|
|||
* If the stream can not be opened with the proposed audio config,
|
||||
* HAL must provide suggested values for the audio config.
|
||||
*
|
||||
* Note: INVALID_ARGUMENTS is returned both in the case when the
|
||||
* HAL can not use the provided config and in the case when
|
||||
* the value of any argument is invalid. In the latter case the
|
||||
* HAL must provide a default initialized suggested config.
|
||||
*
|
||||
* @param ioHandle handle assigned by AudioFlinger.
|
||||
* @param device device type and (if needed) address.
|
||||
* @param config stream configuration.
|
||||
|
@ -136,7 +147,8 @@ interface IDevice {
|
|||
* May be used by implementations to configure processing effects.
|
||||
* @return retval operation completion status.
|
||||
* @return inStream in case of success, created input stream.
|
||||
* @return suggestedConfig in case of invalid parameters, suggested config.
|
||||
* @return suggestedConfig in the case of rejection of the proposed config,
|
||||
* a config suggested by the HAL.
|
||||
*/
|
||||
openInputStream(
|
||||
AudioIoHandle ioHandle,
|
||||
|
|
|
@ -40,6 +40,18 @@ interface IStreamIn extends IStream {
|
|||
*/
|
||||
setGain(float gain) generates (Result retval);
|
||||
|
||||
/**
|
||||
* Called when the metadata of the stream's sink has been changed.
|
||||
* Optional method
|
||||
*
|
||||
* @param sinkMetadata Description of the audio that is suggested by the clients.
|
||||
* @return retval operation completion status.
|
||||
* If any of the metadata fields contains an invalid value,
|
||||
* returns INVALID_ARGUMENTS.
|
||||
* If method isn't supported by the HAL returns NOT_SUPPORTED.
|
||||
*/
|
||||
updateSinkMetadata(SinkMetadata sinkMetadata) generates (Result retval);
|
||||
|
||||
/**
|
||||
* Commands that can be executed on the driver reader thread.
|
||||
*/
|
||||
|
@ -81,12 +93,6 @@ interface IStreamIn extends IStream {
|
|||
} reply;
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the metadata of the stream's sink has been changed.
|
||||
* @param sinkMetadata Description of the audio that is suggested by the clients.
|
||||
*/
|
||||
updateSinkMetadata(SinkMetadata sinkMetadata);
|
||||
|
||||
/**
|
||||
* Set up required transports for receiving audio buffers from the driver.
|
||||
*
|
||||
|
|
|
@ -44,6 +44,18 @@ interface IStreamOut extends IStream {
|
|||
*/
|
||||
setVolume(float left, float right) generates (Result retval);
|
||||
|
||||
/**
|
||||
* Called when the metadata of the stream's source has been changed.
|
||||
* Optional method
|
||||
*
|
||||
* @param sourceMetadata Description of the audio that is played by the clients.
|
||||
* @return retval operation completion status.
|
||||
* If any of the metadata fields contains an invalid value,
|
||||
* returns INVALID_ARGUMENTS.
|
||||
* If method isn't supported by the HAL returns NOT_SUPPORTED.
|
||||
*/
|
||||
updateSourceMetadata(SourceMetadata sourceMetadata) generates (Result retval);
|
||||
|
||||
/**
|
||||
* Commands that can be executed on the driver writer thread.
|
||||
*/
|
||||
|
@ -76,12 +88,6 @@ interface IStreamOut extends IStream {
|
|||
} reply;
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the metadata of the stream's source has been changed.
|
||||
* @param sourceMetadata Description of the audio that is played by the clients.
|
||||
*/
|
||||
updateSourceMetadata(SourceMetadata sourceMetadata);
|
||||
|
||||
/**
|
||||
* Set up required transports for passing audio buffers to the driver.
|
||||
*
|
||||
|
|
|
@ -212,12 +212,11 @@ static inline bool isOutputDevice(const std::string& device) {
|
|||
return isOutputDevice(stringToAudioDevice(device));
|
||||
}
|
||||
|
||||
static inline bool isVendorExtension(const std::string& device) {
|
||||
static inline bool isVendorExtension(const std::string& s) {
|
||||
// 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(),
|
||||
return s.size() > vendorPrefix.size() && s.substr(0, vendorPrefix.size()) == vendorPrefix &&
|
||||
std::all_of(s.begin() + vendorPrefix.size(), s.end(),
|
||||
[](unsigned char c) { return c == '_' || std::isalnum(c); });
|
||||
}
|
||||
|
||||
|
|
|
@ -270,7 +270,10 @@ struct AudioOffloadInfo {
|
|||
*/
|
||||
struct AudioConfig {
|
||||
AudioConfigBase base;
|
||||
AudioOffloadInfo offloadInfo;
|
||||
safe_union OffloadInfo {
|
||||
Monostate unspecified;
|
||||
AudioOffloadInfo info;
|
||||
} offloadInfo;
|
||||
uint64_t frameCount;
|
||||
};
|
||||
|
||||
|
@ -278,7 +281,8 @@ struct AudioConfig {
|
|||
* AudioTag is an additional use case qualifier complementing
|
||||
* AudioUsage and AudioContentType. Tags are set by vendor specific applications
|
||||
* and must be prefixed by "VX_". Vendor must namespace their tag
|
||||
* names to avoid conflicts.
|
||||
* names to avoid conflicts. See 'vendorExtension' in audio_policy_configuration.xsd
|
||||
* for a formal definition.
|
||||
*/
|
||||
typedef string AudioTag;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <log/log.h>
|
||||
|
||||
#include <android_audio_policy_configuration_V7_0-enums.h>
|
||||
#include <common/all-versions/HidlSupport.h>
|
||||
#include <common/all-versions/VersionUtils.h>
|
||||
|
||||
#include "HidlUtils.h"
|
||||
|
@ -306,7 +307,12 @@ status_t HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, bool isI
|
|||
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);
|
||||
if (halConfig.offload_info.sample_rate != 0) {
|
||||
config->offloadInfo.info({});
|
||||
CONVERT_CHECKED(
|
||||
audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo.info()),
|
||||
result);
|
||||
}
|
||||
config->frameCount = halConfig.frame_count;
|
||||
return result;
|
||||
}
|
||||
|
@ -319,7 +325,11 @@ status_t HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t*
|
|||
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);
|
||||
if (config.offloadInfo.getDiscriminator() ==
|
||||
AudioConfig::OffloadInfo::hidl_discriminator::info) {
|
||||
CONVERT_CHECKED(audioOffloadInfoToHal(config.offloadInfo.info(), &halConfig->offload_info),
|
||||
result);
|
||||
}
|
||||
halConfig->frame_count = config.frameCount;
|
||||
return result;
|
||||
}
|
||||
|
@ -800,6 +810,47 @@ status_t HidlUtils::audioProfileToHal(const AudioProfile& profile,
|
|||
return result;
|
||||
}
|
||||
|
||||
status_t HidlUtils::audioTagsFromHal(const char* halTags, hidl_vec<AudioTag>* tags) {
|
||||
std::vector<std::string> strTags = utils::splitString(halTags, sAudioTagSeparator);
|
||||
status_t result = NO_ERROR;
|
||||
tags->resize(strTags.size());
|
||||
size_t to = 0;
|
||||
for (size_t from = 0; from < strTags.size(); ++from) {
|
||||
if (xsd::isVendorExtension(strTags[from])) {
|
||||
(*tags)[to++] = strTags[from];
|
||||
} else {
|
||||
result = BAD_VALUE;
|
||||
}
|
||||
}
|
||||
if (to != strTags.size()) {
|
||||
tags->resize(to);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t HidlUtils::audioTagsToHal(const hidl_vec<AudioTag>& tags, char* halTags) {
|
||||
memset(halTags, 0, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
|
||||
status_t result = NO_ERROR;
|
||||
std::ostringstream halTagsBuffer;
|
||||
bool hasValue = false;
|
||||
for (const auto& tag : tags) {
|
||||
if (hasValue) {
|
||||
halTagsBuffer << sAudioTagSeparator;
|
||||
}
|
||||
if (xsd::isVendorExtension(tag) && strchr(tag.c_str(), sAudioTagSeparator) == nullptr) {
|
||||
halTagsBuffer << tag;
|
||||
hasValue = true;
|
||||
} else {
|
||||
result = BAD_VALUE;
|
||||
}
|
||||
}
|
||||
std::string fullHalTags{std::move(halTagsBuffer.str())};
|
||||
strncpy(halTags, fullHalTags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
|
||||
CONVERT_CHECKED(fullHalTags.length() <= AUDIO_ATTRIBUTES_TAGS_MAX_SIZE ? NO_ERROR : BAD_VALUE,
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t HidlUtils::deviceAddressFromHal(audio_devices_t halDeviceType,
|
||||
const char* halDeviceAddress, DeviceAddress* device) {
|
||||
status_t result = NO_ERROR;
|
||||
|
|
|
@ -109,6 +109,8 @@ struct HidlUtils {
|
|||
AudioStreamType* streamType);
|
||||
static status_t audioStreamTypeToHal(const AudioStreamType& streamType,
|
||||
audio_stream_type_t* halStreamType);
|
||||
static status_t audioTagsFromHal(const char* halTags, hidl_vec<AudioTag>* tags);
|
||||
static status_t audioTagsToHal(const hidl_vec<AudioTag>& tags, char* halTags);
|
||||
|
||||
private:
|
||||
static status_t audioIndexChannelMaskFromHal(audio_channel_mask_t halChannelMask,
|
||||
|
|
|
@ -589,16 +589,29 @@ TEST(HidlUtils, ConvertConfig) {
|
|||
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, ConvertConfigWithOffloadInfo) {
|
||||
AudioConfig config = {};
|
||||
config.base.sampleRateHz = 44100;
|
||||
config.base.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
|
||||
config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
|
||||
config.offloadInfo.info(
|
||||
AudioOffloadInfo{.base = config.base,
|
||||
.streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC),
|
||||
.bitRatePerSecond = 320,
|
||||
.durationMicroseconds = -1,
|
||||
.bitWidth = 16,
|
||||
.bufferSize = 1024,
|
||||
.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
|
||||
.encapsulationMode = AudioEncapsulationMode::ELEMENTARY_STREAM,
|
||||
.contentId = 42,
|
||||
.syncId = 13});
|
||||
audio_config_t halConfig;
|
||||
EXPECT_EQ(NO_ERROR, HidlUtils::audioConfigToHal(config, &halConfig));
|
||||
AudioConfig configBack;
|
||||
|
@ -707,3 +720,43 @@ TEST(HidlUtils, ConvertAudioPort) {
|
|||
EXPECT_EQ(NO_ERROR, HidlUtils::audioPortToHal(portBack, &halPortBack));
|
||||
EXPECT_TRUE(audio_ports_v7_are_equal(&halPort, &halPortBack));
|
||||
}
|
||||
|
||||
TEST(HidlUtils, ConvertInvalidAudioTags) {
|
||||
char halTag[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {};
|
||||
|
||||
hidl_vec<AudioTag> emptyTag = {{""}};
|
||||
EXPECT_EQ(BAD_VALUE, HidlUtils::audioTagsToHal(emptyTag, halTag));
|
||||
|
||||
hidl_vec<AudioTag> longTag = {{std::string(AUDIO_ATTRIBUTES_TAGS_MAX_SIZE + 1, 'A')}};
|
||||
EXPECT_EQ(BAD_VALUE, HidlUtils::audioTagsToHal(longTag, halTag));
|
||||
|
||||
hidl_vec<AudioTag> tagSeparator = {
|
||||
{std::string(AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1, HidlUtils::sAudioTagSeparator)}};
|
||||
EXPECT_EQ(BAD_VALUE, HidlUtils::audioTagsToHal(tagSeparator, halTag));
|
||||
|
||||
hidl_vec<AudioTag> notExtensions = {{"random string", "VX_", "VX_GOOGLE_$$"}};
|
||||
EXPECT_EQ(BAD_VALUE, HidlUtils::audioTagsToHal(notExtensions, halTag));
|
||||
}
|
||||
|
||||
TEST(HidlUtils, ConvertAudioTags) {
|
||||
hidl_vec<AudioTag> emptyTags;
|
||||
char halEmptyTags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {};
|
||||
EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsToHal(emptyTags, halEmptyTags));
|
||||
hidl_vec<AudioTag> emptyTagsBack;
|
||||
EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsFromHal(halEmptyTags, &emptyTagsBack));
|
||||
EXPECT_EQ(emptyTags, emptyTagsBack);
|
||||
|
||||
hidl_vec<AudioTag> oneTag = {{"VX_GOOGLE_VR"}};
|
||||
char halOneTag[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {};
|
||||
EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsToHal(oneTag, halOneTag));
|
||||
hidl_vec<AudioTag> oneTagBack;
|
||||
EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsFromHal(halOneTag, &oneTagBack));
|
||||
EXPECT_EQ(oneTag, oneTagBack);
|
||||
|
||||
hidl_vec<AudioTag> twoTags = {{"VX_GOOGLE_VR_42", "VX_GOOGLE_1E100"}};
|
||||
char halTwoTags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {};
|
||||
EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsToHal(twoTags, halTwoTags));
|
||||
hidl_vec<AudioTag> twoTagsBack;
|
||||
EXPECT_EQ(NO_ERROR, HidlUtils::audioTagsFromHal(halTwoTags, &twoTagsBack));
|
||||
EXPECT_EQ(twoTags, twoTagsBack);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
|
||||
#include <hidl/HidlSupport.h>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace android::hardware::audio::common::utils {
|
||||
|
||||
|
@ -29,6 +32,16 @@ bool isValidHidlEnum(Enum e) {
|
|||
return std::find(values.begin(), values.end(), e) != values.end();
|
||||
}
|
||||
|
||||
static inline std::vector<std::string> splitString(const std::string& s, char separator) {
|
||||
std::istringstream iss(s);
|
||||
std::string t;
|
||||
std::vector<std::string> result;
|
||||
while (std::getline(iss, t, separator)) {
|
||||
result.push_back(std::move(t));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace android::hardware::audio::common::utils
|
||||
|
||||
#endif // android_hardware_audio_common_HidlSupport_H_
|
||||
|
|
|
@ -32,14 +32,10 @@ namespace implementation {
|
|||
|
||||
using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
|
||||
|
||||
#if MAJOR_VERSION <= 6
|
||||
std::string deviceAddressToHal(const DeviceAddress& address) {
|
||||
audio_devices_t halDevice;
|
||||
char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
|
||||
(void)deviceAddressToHal(address, &halDevice, halAddress);
|
||||
return halAddress;
|
||||
}
|
||||
#endif
|
||||
#define CONVERT_CHECKED(expr, result) \
|
||||
if (status_t status = (expr); status != NO_ERROR) { \
|
||||
result = status; \
|
||||
}
|
||||
|
||||
status_t deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType,
|
||||
char* halDeviceAddress) {
|
||||
|
@ -97,6 +93,52 @@ bool halToMicrophoneCharacteristics(MicrophoneInfo* pDst,
|
|||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
status_t sinkMetadataToHal(const SinkMetadata& sinkMetadata,
|
||||
std::vector<record_track_metadata>* halTracks) {
|
||||
status_t result = NO_ERROR;
|
||||
if (halTracks != nullptr) {
|
||||
halTracks->reserve(sinkMetadata.tracks.size());
|
||||
}
|
||||
for (auto& metadata : sinkMetadata.tracks) {
|
||||
record_track_metadata halTrackMetadata{.gain = metadata.gain};
|
||||
CONVERT_CHECKED(HidlUtils::audioSourceToHal(metadata.source, &halTrackMetadata.source),
|
||||
result);
|
||||
#if MAJOR_VERSION >= 5
|
||||
if (metadata.destination.getDiscriminator() ==
|
||||
RecordTrackMetadata::Destination::hidl_discriminator::device) {
|
||||
CONVERT_CHECKED(
|
||||
deviceAddressToHal(metadata.destination.device(), &halTrackMetadata.dest_device,
|
||||
halTrackMetadata.dest_device_address),
|
||||
result);
|
||||
}
|
||||
#endif
|
||||
if (halTracks != nullptr) {
|
||||
halTracks->push_back(std::move(halTrackMetadata));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t sourceMetadataToHal(const SourceMetadata& sourceMetadata,
|
||||
std::vector<playback_track_metadata_t>* halTracks) {
|
||||
status_t result = NO_ERROR;
|
||||
if (halTracks != nullptr) {
|
||||
halTracks->reserve(sourceMetadata.tracks.size());
|
||||
}
|
||||
for (auto& metadata : sourceMetadata.tracks) {
|
||||
playback_track_metadata_t halTrackMetadata{.gain = metadata.gain};
|
||||
CONVERT_CHECKED(HidlUtils::audioUsageToHal(metadata.usage, &halTrackMetadata.usage),
|
||||
result);
|
||||
CONVERT_CHECKED(HidlUtils::audioContentTypeToHal(metadata.contentType,
|
||||
&halTrackMetadata.content_type),
|
||||
result);
|
||||
if (halTracks != nullptr) {
|
||||
halTracks->push_back(std::move(halTrackMetadata));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif // MAJOR_VERSION >= 4
|
||||
|
||||
#if MAJOR_VERSION >= 7
|
||||
|
@ -135,6 +177,50 @@ bool audioOutputFlagsToHal(const hidl_vec<AudioInOutFlag>& flags, audio_output_f
|
|||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
status_t sinkMetadataToHalV7(const SinkMetadata& sinkMetadata,
|
||||
std::vector<record_track_metadata_v7_t>* halTracks) {
|
||||
std::vector<record_track_metadata> bases;
|
||||
status_t result = sinkMetadataToHal(sinkMetadata, halTracks != nullptr ? &bases : nullptr);
|
||||
if (halTracks != nullptr) {
|
||||
halTracks->reserve(bases.size());
|
||||
}
|
||||
auto baseIter = std::make_move_iterator(bases.begin());
|
||||
for (auto& metadata : sinkMetadata.tracks) {
|
||||
record_track_metadata_v7_t halTrackMetadata;
|
||||
CONVERT_CHECKED(HidlUtils::audioChannelMaskToHal(metadata.channelMask,
|
||||
&halTrackMetadata.channel_mask),
|
||||
result);
|
||||
CONVERT_CHECKED(HidlUtils::audioTagsToHal(metadata.tags, halTrackMetadata.tags), result);
|
||||
if (halTracks != nullptr) {
|
||||
halTrackMetadata.base = std::move(*baseIter++);
|
||||
halTracks->push_back(std::move(halTrackMetadata));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t sourceMetadataToHalV7(const SourceMetadata& sourceMetadata,
|
||||
std::vector<playback_track_metadata_v7_t>* halTracks) {
|
||||
std::vector<playback_track_metadata_t> bases;
|
||||
status_t result = sourceMetadataToHal(sourceMetadata, halTracks != nullptr ? &bases : nullptr);
|
||||
if (halTracks != nullptr) {
|
||||
halTracks->reserve(bases.size());
|
||||
}
|
||||
auto baseIter = std::make_move_iterator(bases.begin());
|
||||
for (auto& metadata : sourceMetadata.tracks) {
|
||||
playback_track_metadata_v7_t halTrackMetadata;
|
||||
CONVERT_CHECKED(HidlUtils::audioChannelMaskToHal(metadata.channelMask,
|
||||
&halTrackMetadata.channel_mask),
|
||||
result);
|
||||
CONVERT_CHECKED(HidlUtils::audioTagsToHal(metadata.tags, halTrackMetadata.tags), result);
|
||||
if (halTracks != nullptr) {
|
||||
halTrackMetadata.base = std::move(*baseIter++);
|
||||
halTracks->push_back(std::move(halTrackMetadata));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace implementation
|
||||
|
|
|
@ -135,13 +135,14 @@ Return<void> Device::getMasterMute(getMasterMute_cb _hidl_cb) {
|
|||
|
||||
Return<void> Device::getInputBufferSize(const AudioConfig& config, getInputBufferSize_cb _hidl_cb) {
|
||||
audio_config_t halConfig;
|
||||
HidlUtils::audioConfigToHal(config, &halConfig);
|
||||
size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig);
|
||||
Result retval(Result::INVALID_ARGUMENTS);
|
||||
uint64_t bufferSize = 0;
|
||||
if (halBufferSize != 0) {
|
||||
retval = Result::OK;
|
||||
bufferSize = halBufferSize;
|
||||
if (HidlUtils::audioConfigToHal(config, &halConfig) == NO_ERROR) {
|
||||
size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig);
|
||||
if (halBufferSize != 0) {
|
||||
retval = Result::OK;
|
||||
bufferSize = halBufferSize;
|
||||
}
|
||||
}
|
||||
_hidl_cb(retval, bufferSize);
|
||||
return Void();
|
||||
|
@ -153,7 +154,9 @@ std::tuple<Result, sp<IStreamOut>> Device::openOutputStreamImpl(int32_t ioHandle
|
|||
const AudioOutputFlags& flags,
|
||||
AudioConfig* suggestedConfig) {
|
||||
audio_config_t halConfig;
|
||||
HidlUtils::audioConfigToHal(config, &halConfig);
|
||||
if (HidlUtils::audioConfigToHal(config, &halConfig) != NO_ERROR) {
|
||||
return {Result::INVALID_ARGUMENTS, nullptr};
|
||||
}
|
||||
audio_stream_out_t* halStream;
|
||||
audio_devices_t halDevice;
|
||||
char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
|
||||
|
@ -186,7 +189,9 @@ std::tuple<Result, sp<IStreamIn>> Device::openInputStreamImpl(
|
|||
int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config,
|
||||
const AudioInputFlags& flags, AudioSource source, AudioConfig* suggestedConfig) {
|
||||
audio_config_t halConfig;
|
||||
HidlUtils::audioConfigToHal(config, &halConfig);
|
||||
if (HidlUtils::audioConfigToHal(config, &halConfig) != NO_ERROR) {
|
||||
return {Result::INVALID_ARGUMENTS, nullptr};
|
||||
}
|
||||
audio_stream_in_t* halStream;
|
||||
audio_devices_t halDevice;
|
||||
char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
|
||||
|
@ -248,6 +253,14 @@ Return<void> Device::openOutputStream(int32_t ioHandle, const DeviceAddress& dev
|
|||
#endif
|
||||
const SourceMetadata& sourceMetadata,
|
||||
openOutputStream_cb _hidl_cb) {
|
||||
#if MAJOR_VERSION <= 6
|
||||
if (status_t status = sourceMetadataToHal(sourceMetadata, nullptr); status != NO_ERROR) {
|
||||
#else
|
||||
if (status_t status = sourceMetadataToHalV7(sourceMetadata, nullptr); status != NO_ERROR) {
|
||||
#endif
|
||||
_hidl_cb(analyzeStatus("sourceMetadataToHal", status), nullptr, AudioConfig{});
|
||||
return Void();
|
||||
}
|
||||
AudioConfig suggestedConfig;
|
||||
auto [result, streamOut] =
|
||||
openOutputStreamImpl(ioHandle, device, config, flags, &suggestedConfig);
|
||||
|
@ -271,7 +284,15 @@ Return<void> Device::openInputStream(int32_t ioHandle, const DeviceAddress& devi
|
|||
// This should never happen, the framework must not create as stream
|
||||
// if there is no client
|
||||
ALOGE("openInputStream called without tracks connected");
|
||||
_hidl_cb(Result::INVALID_ARGUMENTS, nullptr, AudioConfig());
|
||||
_hidl_cb(Result::INVALID_ARGUMENTS, nullptr, AudioConfig{});
|
||||
return Void();
|
||||
}
|
||||
#if MAJOR_VERSION <= 6
|
||||
if (status_t status = sinkMetadataToHal(sinkMetadata, nullptr); status != NO_ERROR) {
|
||||
#else
|
||||
if (status_t status = sinkMetadataToHalV7(sinkMetadata, nullptr); status != NO_ERROR) {
|
||||
#endif
|
||||
_hidl_cb(analyzeStatus("sinkMetadataToHal", status), nullptr, AudioConfig{});
|
||||
return Void();
|
||||
}
|
||||
// Pick the first one as the main.
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#define LOG_TAG "StreamHAL"
|
||||
|
||||
#include "core/default/Stream.h"
|
||||
#include "common/all-versions/HidlSupport.h"
|
||||
#include "common/all-versions/default/EffectMap.h"
|
||||
#include "core/default/Conversions.h"
|
||||
#include "core/default/Util.h"
|
||||
|
@ -37,6 +38,7 @@ namespace CPP_VERSION {
|
|||
namespace implementation {
|
||||
|
||||
using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
|
||||
using ::android::hardware::audio::common::utils::splitString;
|
||||
|
||||
Stream::Stream(bool isInput, audio_stream_t* stream) : mIsInput(isInput), mStream(stream) {
|
||||
(void)mIsInput; // prevent 'unused field' warnings in pre-V7 versions.
|
||||
|
@ -220,7 +222,7 @@ Return<void> Stream::getSupportedProfiles(getSupportedProfiles_cb _hidl_cb) {
|
|||
// Ensure that the separator is one character, despite that it's defined as a C string.
|
||||
static_assert(sizeof(AUDIO_PARAMETER_VALUE_LIST_SEPARATOR) == 2);
|
||||
std::vector<std::string> halFormats =
|
||||
util::splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
|
||||
splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
|
||||
hidl_vec<AudioFormat> formats;
|
||||
(void)HidlUtils::audioFormatsFromHal(halFormats, &formats);
|
||||
std::vector<AudioProfile> tempProfiles;
|
||||
|
@ -235,7 +237,7 @@ Return<void> Stream::getSupportedProfiles(getSupportedProfiles_cb _hidl_cb) {
|
|||
result = getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue, context);
|
||||
if (result != Result::OK) break;
|
||||
std::vector<std::string> halSampleRates =
|
||||
util::splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
|
||||
splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
|
||||
hidl_vec<uint32_t> sampleRates;
|
||||
sampleRates.resize(halSampleRates.size());
|
||||
for (size_t i = 0; i < sampleRates.size(); ++i) {
|
||||
|
@ -245,7 +247,7 @@ Return<void> Stream::getSupportedProfiles(getSupportedProfiles_cb _hidl_cb) {
|
|||
result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue, context);
|
||||
if (result != Result::OK) break;
|
||||
std::vector<std::string> halChannelMasks =
|
||||
util::splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
|
||||
splitString(halListValue.string(), AUDIO_PARAMETER_VALUE_LIST_SEPARATOR[0]);
|
||||
hidl_vec<AudioChannelMask> channelMasks;
|
||||
(void)HidlUtils::audioChannelMasksFromHal(halChannelMasks, &channelMasks);
|
||||
// Create a profile.
|
||||
|
|
|
@ -478,87 +478,59 @@ Return<void> StreamIn::debug(const hidl_handle& fd, const hidl_vec<hidl_string>&
|
|||
}
|
||||
|
||||
#if MAJOR_VERSION >= 4
|
||||
|
||||
record_track_metadata StreamIn::convertRecordTrackMetadata(
|
||||
const RecordTrackMetadata& trackMetadata) {
|
||||
record_track_metadata halTrackMetadata = {.gain = trackMetadata.gain};
|
||||
(void)HidlUtils::audioSourceToHal(trackMetadata.source, &halTrackMetadata.source);
|
||||
#if MAJOR_VERSION >= 5
|
||||
if (trackMetadata.destination.getDiscriminator() ==
|
||||
RecordTrackMetadata::Destination::hidl_discriminator::device) {
|
||||
(void)deviceAddressToHal(trackMetadata.destination.device(), &halTrackMetadata.dest_device,
|
||||
halTrackMetadata.dest_device_address);
|
||||
}
|
||||
#endif
|
||||
return halTrackMetadata;
|
||||
}
|
||||
|
||||
void StreamIn::doUpdateSinkMetadata(const SinkMetadata& sinkMetadata) {
|
||||
Result StreamIn::doUpdateSinkMetadata(const SinkMetadata& sinkMetadata,
|
||||
bool abortOnConversionFailure) {
|
||||
std::vector<record_track_metadata> halTracks;
|
||||
halTracks.reserve(sinkMetadata.tracks.size());
|
||||
for (auto& metadata : sinkMetadata.tracks) {
|
||||
halTracks.push_back(convertRecordTrackMetadata(metadata));
|
||||
if (status_t status = sinkMetadataToHal(sinkMetadata, &halTracks);
|
||||
status != NO_ERROR && abortOnConversionFailure) {
|
||||
return Stream::analyzeStatus("sinkMetadataToHal", status);
|
||||
}
|
||||
const sink_metadata_t halMetadata = {
|
||||
.track_count = halTracks.size(),
|
||||
.tracks = halTracks.data(),
|
||||
};
|
||||
mStream->update_sink_metadata(mStream, &halMetadata);
|
||||
return Result::OK;
|
||||
}
|
||||
|
||||
#if MAJOR_VERSION >= 7
|
||||
record_track_metadata_v7 StreamIn::convertRecordTrackMetadataV7(
|
||||
const RecordTrackMetadata& trackMetadata) {
|
||||
record_track_metadata_v7 halTrackMetadata;
|
||||
halTrackMetadata.base = convertRecordTrackMetadata(trackMetadata);
|
||||
(void)HidlUtils::audioChannelMaskToHal(trackMetadata.channelMask,
|
||||
&halTrackMetadata.channel_mask);
|
||||
std::string halTags;
|
||||
for (const auto& tag : trackMetadata.tags) {
|
||||
if (&tag != &trackMetadata.tags[0]) {
|
||||
halTags += HidlUtils::sAudioTagSeparator;
|
||||
}
|
||||
halTags += tag.c_str();
|
||||
}
|
||||
strncpy(halTrackMetadata.tags, halTags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
|
||||
return halTrackMetadata;
|
||||
}
|
||||
|
||||
void StreamIn::doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata) {
|
||||
Result StreamIn::doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata) {
|
||||
std::vector<record_track_metadata_v7> halTracks;
|
||||
halTracks.reserve(sinkMetadata.tracks.size());
|
||||
for (auto& metadata : sinkMetadata.tracks) {
|
||||
halTracks.push_back(convertRecordTrackMetadataV7(metadata));
|
||||
if (status_t status = sinkMetadataToHalV7(sinkMetadata, &halTracks); status != NO_ERROR) {
|
||||
return Stream::analyzeStatus("sinkMetadataToHal", status);
|
||||
}
|
||||
const sink_metadata_v7_t halMetadata = {
|
||||
.track_count = halTracks.size(),
|
||||
.tracks = halTracks.data(),
|
||||
};
|
||||
mStream->update_sink_metadata_v7(mStream, &halMetadata);
|
||||
return Result::OK;
|
||||
}
|
||||
#endif // MAJOR_VERSION >= 7
|
||||
|
||||
#if MAJOR_VERSION <= 6
|
||||
Return<void> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
|
||||
#if MAJOR_VERSION < 7
|
||||
if (mStream->update_sink_metadata == nullptr) {
|
||||
return Void(); // not supported by the HAL
|
||||
}
|
||||
doUpdateSinkMetadata(sinkMetadata);
|
||||
#else
|
||||
if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
|
||||
if (mStream->update_sink_metadata == nullptr) {
|
||||
return Void(); // not supported by the HAL
|
||||
}
|
||||
doUpdateSinkMetadata(sinkMetadata);
|
||||
} else {
|
||||
if (mStream->update_sink_metadata_v7 == nullptr) {
|
||||
return Void(); // not supported by the HAL
|
||||
}
|
||||
doUpdateSinkMetadataV7(sinkMetadata);
|
||||
}
|
||||
#endif // MAJOR_VERSION < 7
|
||||
(void)doUpdateSinkMetadata(sinkMetadata, false /*abortOnConversionFailure*/);
|
||||
return Void();
|
||||
}
|
||||
#elif MAJOR_VERSION >= 7
|
||||
Return<Result> StreamIn::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
|
||||
if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
|
||||
if (mStream->update_sink_metadata == nullptr) {
|
||||
return Result::NOT_SUPPORTED;
|
||||
}
|
||||
return doUpdateSinkMetadata(sinkMetadata, true /*abortOnConversionFailure*/);
|
||||
} else {
|
||||
if (mStream->update_sink_metadata_v7 == nullptr) {
|
||||
return Result::NOT_SUPPORTED;
|
||||
}
|
||||
return doUpdateSinkMetadataV7(sinkMetadata);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Return<void> StreamIn::getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) {
|
||||
Result retval = Result::NOT_SUPPORTED;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#define LOG_TAG "StreamOutHAL"
|
||||
|
||||
#include "core/default/StreamOut.h"
|
||||
#include "core/default/Conversions.h"
|
||||
#include "core/default/Util.h"
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
|
@ -585,81 +586,59 @@ Return<void> StreamOut::debug(const hidl_handle& fd, const hidl_vec<hidl_string>
|
|||
}
|
||||
|
||||
#if MAJOR_VERSION >= 4
|
||||
playback_track_metadata StreamOut::convertPlaybackTrackMetadata(
|
||||
const PlaybackTrackMetadata& trackMetadata) {
|
||||
playback_track_metadata_t halTrackMetadata = {.gain = trackMetadata.gain};
|
||||
(void)HidlUtils::audioUsageToHal(trackMetadata.usage, &halTrackMetadata.usage);
|
||||
(void)HidlUtils::audioContentTypeToHal(trackMetadata.contentType,
|
||||
&halTrackMetadata.content_type);
|
||||
return halTrackMetadata;
|
||||
}
|
||||
|
||||
void StreamOut::doUpdateSourceMetadata(const SourceMetadata& sourceMetadata) {
|
||||
Result StreamOut::doUpdateSourceMetadata(const SourceMetadata& sourceMetadata,
|
||||
bool abortOnConversionFailure) {
|
||||
std::vector<playback_track_metadata_t> halTracks;
|
||||
halTracks.reserve(sourceMetadata.tracks.size());
|
||||
for (auto& metadata : sourceMetadata.tracks) {
|
||||
halTracks.push_back(convertPlaybackTrackMetadata(metadata));
|
||||
if (status_t status = sourceMetadataToHal(sourceMetadata, &halTracks);
|
||||
status != NO_ERROR && abortOnConversionFailure) {
|
||||
return Stream::analyzeStatus("sourceMetadataToHal", status);
|
||||
}
|
||||
const source_metadata_t halMetadata = {
|
||||
.track_count = halTracks.size(),
|
||||
.tracks = halTracks.data(),
|
||||
};
|
||||
mStream->update_source_metadata(mStream, &halMetadata);
|
||||
return Result::OK;
|
||||
}
|
||||
|
||||
#if MAJOR_VERSION >= 7
|
||||
playback_track_metadata_v7 StreamOut::convertPlaybackTrackMetadataV7(
|
||||
const PlaybackTrackMetadata& trackMetadata) {
|
||||
playback_track_metadata_v7 halTrackMetadata;
|
||||
halTrackMetadata.base = convertPlaybackTrackMetadata(trackMetadata);
|
||||
(void)HidlUtils::audioChannelMaskToHal(trackMetadata.channelMask,
|
||||
&halTrackMetadata.channel_mask);
|
||||
std::string halTags;
|
||||
for (const auto& tag : trackMetadata.tags) {
|
||||
if (&tag != &trackMetadata.tags[0]) {
|
||||
halTags += HidlUtils::sAudioTagSeparator;
|
||||
}
|
||||
halTags += tag.c_str();
|
||||
}
|
||||
strncpy(halTrackMetadata.tags, halTags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
|
||||
return halTrackMetadata;
|
||||
}
|
||||
|
||||
void StreamOut::doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata) {
|
||||
Result StreamOut::doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata) {
|
||||
std::vector<playback_track_metadata_v7> halTracks;
|
||||
halTracks.reserve(sourceMetadata.tracks.size());
|
||||
for (auto& metadata : sourceMetadata.tracks) {
|
||||
halTracks.push_back(convertPlaybackTrackMetadataV7(metadata));
|
||||
if (status_t status = sourceMetadataToHalV7(sourceMetadata, &halTracks); status != NO_ERROR) {
|
||||
return Stream::analyzeStatus("sourceMetadataToHal", status);
|
||||
}
|
||||
const source_metadata_v7_t halMetadata = {
|
||||
.track_count = halTracks.size(),
|
||||
.tracks = halTracks.data(),
|
||||
};
|
||||
mStream->update_source_metadata_v7(mStream, &halMetadata);
|
||||
return Result::OK;
|
||||
}
|
||||
#endif // MAJOR_VERSION >= 7
|
||||
|
||||
#if MAJOR_VERSION <= 6
|
||||
Return<void> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
|
||||
#if MAJOR_VERSION < 7
|
||||
if (mStream->update_source_metadata == nullptr) {
|
||||
return Void(); // not supported by the HAL
|
||||
}
|
||||
doUpdateSourceMetadata(sourceMetadata);
|
||||
#else
|
||||
if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
|
||||
if (mStream->update_source_metadata == nullptr) {
|
||||
return Void(); // not supported by the HAL
|
||||
}
|
||||
doUpdateSourceMetadata(sourceMetadata);
|
||||
} else {
|
||||
if (mStream->update_source_metadata_v7 == nullptr) {
|
||||
return Void(); // not supported by the HAL
|
||||
}
|
||||
doUpdateSourceMetadataV7(sourceMetadata);
|
||||
}
|
||||
#endif // MAJOR_VERSION < 7
|
||||
(void)doUpdateSourceMetadata(sourceMetadata, false /*abortOnConversionFailure*/);
|
||||
return Void();
|
||||
}
|
||||
#elif MAJOR_VERSION >= 7
|
||||
Return<Result> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
|
||||
if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
|
||||
if (mStream->update_source_metadata == nullptr) {
|
||||
return Result::NOT_SUPPORTED;
|
||||
}
|
||||
return doUpdateSourceMetadata(sourceMetadata, true /*abortOnConversionFailure*/);
|
||||
} else {
|
||||
if (mStream->update_source_metadata_v7 == nullptr) {
|
||||
return Result::NOT_SUPPORTED;
|
||||
}
|
||||
return doUpdateSourceMetadataV7(sourceMetadata);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Return<Result> StreamOut::selectPresentation(int32_t /*presentationId*/, int32_t /*programId*/) {
|
||||
return Result::NOT_SUPPORTED; // TODO: propagate to legacy
|
||||
|
|
|
@ -35,12 +35,6 @@ using ::android::hardware::hidl_vec;
|
|||
using namespace ::android::hardware::audio::common::CPP_VERSION;
|
||||
using namespace ::android::hardware::audio::CPP_VERSION;
|
||||
|
||||
#if MAJOR_VERSION <= 6
|
||||
// Temporary version for compatibility with forks of the default implementation.
|
||||
// Will be removed, do not use!
|
||||
std::string deviceAddressToHal(const DeviceAddress& address);
|
||||
#endif
|
||||
|
||||
status_t deviceAddressToHal(const DeviceAddress& device, audio_devices_t* halDeviceType,
|
||||
char* halDeviceAddress);
|
||||
status_t deviceAddressFromHal(audio_devices_t halDeviceType, const char* halDeviceAddress,
|
||||
|
@ -49,6 +43,10 @@ status_t deviceAddressFromHal(audio_devices_t halDeviceType, const char* halDevi
|
|||
#if MAJOR_VERSION >= 4
|
||||
bool halToMicrophoneCharacteristics(MicrophoneInfo* pDst,
|
||||
const struct audio_microphone_characteristic_t& src);
|
||||
status_t sinkMetadataToHal(const SinkMetadata& sinkMetadata,
|
||||
std::vector<record_track_metadata>* halTracks);
|
||||
status_t sourceMetadataToHal(const SourceMetadata& sourceMetadata,
|
||||
std::vector<playback_track_metadata_t>* halTracks);
|
||||
#endif
|
||||
|
||||
#if MAJOR_VERSION <= 6
|
||||
|
@ -69,6 +67,11 @@ inline bool audioOutputFlagsToHal(AudioOutputFlags flags, audio_output_flags_t*
|
|||
#else
|
||||
bool audioInputFlagsToHal(const hidl_vec<AudioInOutFlag>& flags, audio_input_flags_t* halFlags);
|
||||
bool audioOutputFlagsToHal(const hidl_vec<AudioInOutFlag>& flags, audio_output_flags_t* halFlags);
|
||||
// Overloading isn't convenient when passing a nullptr.
|
||||
status_t sinkMetadataToHalV7(const SinkMetadata& sinkMetadata,
|
||||
std::vector<record_track_metadata_v7_t>* halTracks);
|
||||
status_t sourceMetadataToHalV7(const SourceMetadata& sourceMetadata,
|
||||
std::vector<playback_track_metadata_v7_t>* halTracks);
|
||||
#endif
|
||||
|
||||
} // namespace implementation
|
||||
|
|
|
@ -114,9 +114,13 @@ struct StreamIn : public IStreamIn {
|
|||
Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
|
||||
Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
|
||||
#if MAJOR_VERSION >= 4
|
||||
#if MAJOR_VERSION <= 6
|
||||
Return<void> updateSinkMetadata(const SinkMetadata& sinkMetadata) override;
|
||||
Return<void> getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) override;
|
||||
#else
|
||||
Return<Result> updateSinkMetadata(const SinkMetadata& sinkMetadata) override;
|
||||
#endif
|
||||
Return<void> getActiveMicrophones(getActiveMicrophones_cb _hidl_cb) override;
|
||||
#endif // MAJOR_VERSION >= 4
|
||||
#if MAJOR_VERSION >= 5
|
||||
Return<Result> setMicrophoneDirection(MicrophoneDirection direction) override;
|
||||
Return<Result> setMicrophoneFieldDimension(float zoom) override;
|
||||
|
@ -126,13 +130,11 @@ struct StreamIn : public IStreamIn {
|
|||
|
||||
private:
|
||||
#if MAJOR_VERSION >= 4
|
||||
record_track_metadata convertRecordTrackMetadata(const RecordTrackMetadata& trackMetadata);
|
||||
void doUpdateSinkMetadata(const SinkMetadata& sinkMetadata);
|
||||
Result doUpdateSinkMetadata(const SinkMetadata& sinkMetadata, bool abortOnConversionFailure);
|
||||
#if MAJOR_VERSION >= 7
|
||||
record_track_metadata_v7 convertRecordTrackMetadataV7(const RecordTrackMetadata& trackMetadata);
|
||||
void doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata);
|
||||
#endif
|
||||
Result doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata);
|
||||
#endif
|
||||
#endif // MAJOR_VERSION >= 4
|
||||
|
||||
const sp<Device> mDevice;
|
||||
audio_stream_in_t* mStream;
|
||||
|
|
|
@ -123,9 +123,13 @@ struct StreamOut : public IStreamOut {
|
|||
Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
|
||||
Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
|
||||
#if MAJOR_VERSION >= 4
|
||||
Return<void> updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
|
||||
Return<Result> selectPresentation(int32_t presentationId, int32_t programId) override;
|
||||
#if MAJOR_VERSION <= 6
|
||||
Return<void> updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
|
||||
#else
|
||||
Return<Result> updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
|
||||
#endif
|
||||
#endif // MAJOR_VERSION >= 4
|
||||
#if MAJOR_VERSION >= 6
|
||||
Return<void> getDualMonoMode(getDualMonoMode_cb _hidl_cb) override;
|
||||
Return<Result> setDualMonoMode(DualMonoMode mode) override;
|
||||
|
@ -144,15 +148,12 @@ struct StreamOut : public IStreamOut {
|
|||
|
||||
private:
|
||||
#if MAJOR_VERSION >= 4
|
||||
playback_track_metadata convertPlaybackTrackMetadata(
|
||||
const PlaybackTrackMetadata& trackMetadata);
|
||||
void doUpdateSourceMetadata(const SourceMetadata& sourceMetadata);
|
||||
Result doUpdateSourceMetadata(const SourceMetadata& sourceMetadata,
|
||||
bool abortOnConversionFailure);
|
||||
#if MAJOR_VERSION >= 7
|
||||
playback_track_metadata_v7 convertPlaybackTrackMetadataV7(
|
||||
const PlaybackTrackMetadata& trackMetadata);
|
||||
void doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata);
|
||||
#endif
|
||||
Result doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata);
|
||||
#endif
|
||||
#endif // MAJOR_VERSION >= 4
|
||||
|
||||
const sp<Device> mDevice;
|
||||
audio_stream_out_t* mStream;
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include PATH(android/hardware/audio/FILE_VERSION/types.h)
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <system/audio.h>
|
||||
|
@ -72,16 +70,6 @@ static inline Result analyzeStatus(const char* className, const char* funcName,
|
|||
return analyzeStatus(status);
|
||||
}
|
||||
|
||||
static inline std::vector<std::string> splitString(const std::string& s, char separator) {
|
||||
std::istringstream iss(s);
|
||||
std::string t;
|
||||
std::vector<std::string> result;
|
||||
while (std::getline(iss, t, separator)) {
|
||||
result.push_back(std::move(t));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace implementation
|
||||
} // namespace CPP_VERSION
|
||||
|
|
|
@ -237,26 +237,14 @@ TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(g
|
|||
|
||||
TEST_P(InputStreamTest, updateSinkMetadata) {
|
||||
doc::test("The HAL should not crash on metadata change");
|
||||
|
||||
#if MAJOR_VERSION <= 6
|
||||
hidl_enum_range<AudioSource> range;
|
||||
#elif MAJOR_VERSION >= 7
|
||||
xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioSource> range;
|
||||
#endif
|
||||
// Test all possible track configuration
|
||||
for (auto source : range) {
|
||||
for (float volume : {0.0, 0.5, 1.0}) {
|
||||
#if MAJOR_VERSION <= 6
|
||||
const SinkMetadata metadata = {{{.source = source, .gain = volume}}};
|
||||
#elif MAJOR_VERSION >= 7
|
||||
const SinkMetadata metadata = {
|
||||
{{.source = toString(source),
|
||||
.gain = volume,
|
||||
.tags = {},
|
||||
.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO)}}};
|
||||
#endif
|
||||
ASSERT_OK(stream->updateSinkMetadata(metadata))
|
||||
<< "source=" << toString(source) << ", volume=" << volume;
|
||||
<< "source=" << toString(source) << ", volume=" << volume;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,9 +252,30 @@ TEST_P(InputStreamTest, updateSinkMetadata) {
|
|||
|
||||
// Set no metadata as if all stream track had stopped
|
||||
ASSERT_OK(stream->updateSinkMetadata({}));
|
||||
|
||||
// Restore initial
|
||||
ASSERT_OK(stream->updateSinkMetadata(initMetadata));
|
||||
|
||||
#elif MAJOR_VERSION >= 7
|
||||
xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioSource> range;
|
||||
// Test all possible track configuration
|
||||
for (auto source : range) {
|
||||
for (float volume : {0.0, 0.5, 1.0}) {
|
||||
const SinkMetadata metadata = {
|
||||
{{.source = toString(source),
|
||||
.gain = volume,
|
||||
.tags = {},
|
||||
.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO)}}};
|
||||
ASSERT_RESULT(okOrNotSupported, stream->updateSinkMetadata(metadata))
|
||||
<< "source=" << toString(source) << ", volume=" << volume;
|
||||
}
|
||||
}
|
||||
// Do not test concurrent capture as this is not officially supported
|
||||
|
||||
// Set no metadata as if all stream track had stopped
|
||||
ASSERT_RESULT(okOrNotSupported, stream->updateSinkMetadata({}));
|
||||
// Restore initial
|
||||
ASSERT_RESULT(okOrNotSupported, stream->updateSinkMetadata(initMetadata));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_P(OutputStreamTest, SelectPresentation) {
|
||||
|
@ -276,44 +285,55 @@ TEST_P(OutputStreamTest, SelectPresentation) {
|
|||
|
||||
TEST_P(OutputStreamTest, updateSourceMetadata) {
|
||||
doc::test("The HAL should not crash on metadata change");
|
||||
|
||||
#if MAJOR_VERSION <= 6
|
||||
hidl_enum_range<AudioUsage> usageRange;
|
||||
hidl_enum_range<AudioContentType> contentRange;
|
||||
#elif MAJOR_VERSION >= 7
|
||||
xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioUsage> usageRange;
|
||||
xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioContentType> contentRange;
|
||||
#endif
|
||||
// Test all possible track configuration
|
||||
for (auto usage : usageRange) {
|
||||
for (auto content : contentRange) {
|
||||
for (float volume : {0.0, 0.5, 1.0}) {
|
||||
#if MAJOR_VERSION <= 6
|
||||
const SourceMetadata metadata = {{{usage, content, volume}}};
|
||||
#elif MAJOR_VERSION >= 7
|
||||
const SourceMetadata metadata = {
|
||||
{{toString(usage),
|
||||
toString(content),
|
||||
{} /* tags */,
|
||||
toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO),
|
||||
volume}}};
|
||||
#endif
|
||||
ASSERT_OK(stream->updateSourceMetadata(metadata))
|
||||
<< "usage=" << toString(usage) << ", content=" << toString(content)
|
||||
<< ", volume=" << volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
// Set many track of different configuration
|
||||
// clang-format off
|
||||
ASSERT_OK(stream->updateSourceMetadata(
|
||||
#if MAJOR_VERSION <= 6
|
||||
{{{AudioUsage::MEDIA, AudioContentType::MUSIC, 0.1},
|
||||
{AudioUsage::VOICE_COMMUNICATION, AudioContentType::SPEECH, 1.0},
|
||||
{AudioUsage::ALARM, AudioContentType::SONIFICATION, 0.0},
|
||||
{AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, 0.3}}}
|
||||
));
|
||||
// clang-format on
|
||||
// Set no metadata as if all stream track had stopped
|
||||
ASSERT_OK(stream->updateSourceMetadata({}));
|
||||
// Restore initial
|
||||
ASSERT_OK(stream->updateSourceMetadata(initMetadata));
|
||||
#elif MAJOR_VERSION >= 7
|
||||
xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioUsage> usageRange;
|
||||
xsdc_enum_range<android::audio::policy::configuration::V7_0::AudioContentType> contentRange;
|
||||
// Test all possible track configuration
|
||||
for (auto usage : usageRange) {
|
||||
for (auto content : contentRange) {
|
||||
for (float volume : {0.0, 0.5, 1.0}) {
|
||||
const SourceMetadata metadata = {
|
||||
{{toString(usage),
|
||||
toString(content),
|
||||
{} /* tags */,
|
||||
toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO),
|
||||
volume}}};
|
||||
ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata(metadata))
|
||||
<< "usage=" << toString(usage) << ", content=" << toString(content)
|
||||
<< ", volume=" << volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set many track of different configuration
|
||||
// clang-format off
|
||||
ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata(
|
||||
{{{toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
|
||||
toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC),
|
||||
{},
|
||||
|
@ -334,15 +354,13 @@ TEST_P(OutputStreamTest, updateSourceMetadata) {
|
|||
{},
|
||||
toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO),
|
||||
0.3}}}
|
||||
#endif
|
||||
));
|
||||
// clang-format on
|
||||
|
||||
// Set no metadata as if all stream track had stopped
|
||||
ASSERT_OK(stream->updateSourceMetadata({}));
|
||||
|
||||
ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata({}));
|
||||
// Restore initial
|
||||
ASSERT_OK(stream->updateSourceMetadata(initMetadata));
|
||||
ASSERT_RESULT(okOrNotSupported, stream->updateSourceMetadata(initMetadata));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_P(AudioPrimaryHidlTest, setMode) {
|
||||
|
|
|
@ -18,84 +18,110 @@
|
|||
#include "5.0/AudioPrimaryHidlHalTest.cpp"
|
||||
|
||||
#if MAJOR_VERSION <= 6
|
||||
const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
|
||||
static std::vector<DeviceConfigParameter> parameters = [] {
|
||||
std::vector<DeviceConfigParameter> result;
|
||||
for (const auto& device : getDeviceParameters()) {
|
||||
auto module =
|
||||
getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
|
||||
for (const auto& ioProfile : module->getOutputProfiles()) {
|
||||
for (const auto& profile : ioProfile->getAudioProfiles()) {
|
||||
const auto& channels = profile->getChannels();
|
||||
const auto& sampleRates = profile->getSampleRates();
|
||||
auto configs = ConfigHelper::combineAudioConfig(
|
||||
std::vector<audio_channel_mask_t>(channels.begin(), channels.end()),
|
||||
std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
|
||||
profile->getFormat());
|
||||
auto flags = ioProfile->getFlags();
|
||||
for (auto& config : configs) {
|
||||
// Some combinations of flags declared in the config file require special
|
||||
// treatment.
|
||||
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
|
||||
config.offloadInfo.sampleRateHz = config.sampleRateHz;
|
||||
config.offloadInfo.channelMask = config.channelMask;
|
||||
config.offloadInfo.format = config.format;
|
||||
config.offloadInfo.streamType = AudioStreamType::MUSIC;
|
||||
config.offloadInfo.bitRatePerSecond = 320;
|
||||
config.offloadInfo.durationMicroseconds = -1;
|
||||
config.offloadInfo.bitWidth = 16;
|
||||
config.offloadInfo.bufferSize = 256; // arbitrary value
|
||||
config.offloadInfo.usage = AudioUsage::MEDIA;
|
||||
result.emplace_back(device, config,
|
||||
AudioOutputFlag(AudioOutputFlag::COMPRESS_OFFLOAD |
|
||||
AudioOutputFlag::DIRECT));
|
||||
} else {
|
||||
if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { // ignore the flag
|
||||
flags &= ~AUDIO_OUTPUT_FLAG_PRIMARY;
|
||||
}
|
||||
result.emplace_back(device, config, AudioOutputFlag(flags));
|
||||
static std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(
|
||||
bool oneProfilePerDevice) {
|
||||
std::vector<DeviceConfigParameter> result;
|
||||
for (const auto& device : getDeviceParameters()) {
|
||||
auto module =
|
||||
getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
|
||||
for (const auto& ioProfile : module->getOutputProfiles()) {
|
||||
for (const auto& profile : ioProfile->getAudioProfiles()) {
|
||||
const auto& channels = profile->getChannels();
|
||||
const auto& sampleRates = profile->getSampleRates();
|
||||
auto configs = ConfigHelper::combineAudioConfig(
|
||||
std::vector<audio_channel_mask_t>(channels.begin(), channels.end()),
|
||||
std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
|
||||
profile->getFormat());
|
||||
auto flags = ioProfile->getFlags();
|
||||
for (auto& config : configs) {
|
||||
// Some combinations of flags declared in the config file require special
|
||||
// treatment.
|
||||
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
|
||||
config.offloadInfo.sampleRateHz = config.sampleRateHz;
|
||||
config.offloadInfo.channelMask = config.channelMask;
|
||||
config.offloadInfo.format = config.format;
|
||||
config.offloadInfo.streamType = AudioStreamType::MUSIC;
|
||||
config.offloadInfo.bitRatePerSecond = 320;
|
||||
config.offloadInfo.durationMicroseconds = -1;
|
||||
config.offloadInfo.bitWidth = 16;
|
||||
config.offloadInfo.bufferSize = 256; // arbitrary value
|
||||
config.offloadInfo.usage = AudioUsage::MEDIA;
|
||||
result.emplace_back(device, config,
|
||||
AudioOutputFlag(AudioOutputFlag::COMPRESS_OFFLOAD |
|
||||
AudioOutputFlag::DIRECT));
|
||||
} else {
|
||||
if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) { // ignore the flag
|
||||
flags &= ~AUDIO_OUTPUT_FLAG_PRIMARY;
|
||||
}
|
||||
result.emplace_back(device, config, AudioOutputFlag(flags));
|
||||
}
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
|
||||
static std::vector<DeviceConfigParameter> parameters =
|
||||
generateOutputDeviceConfigParameters(false);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
|
||||
static std::vector<DeviceConfigParameter> parameters = [] {
|
||||
std::vector<DeviceConfigParameter> result;
|
||||
for (const auto& device : getDeviceParameters()) {
|
||||
auto module =
|
||||
getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
|
||||
for (const auto& ioProfile : module->getInputProfiles()) {
|
||||
for (const auto& profile : ioProfile->getAudioProfiles()) {
|
||||
const auto& channels = profile->getChannels();
|
||||
const auto& sampleRates = profile->getSampleRates();
|
||||
auto configs = ConfigHelper::combineAudioConfig(
|
||||
std::vector<audio_channel_mask_t>(channels.begin(), channels.end()),
|
||||
std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
|
||||
profile->getFormat());
|
||||
for (const auto& config : configs) {
|
||||
result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags()));
|
||||
}
|
||||
const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters() {
|
||||
static std::vector<DeviceConfigParameter> parameters =
|
||||
generateOutputDeviceConfigParameters(true);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
static std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(
|
||||
bool oneProfilePerDevice) {
|
||||
std::vector<DeviceConfigParameter> result;
|
||||
for (const auto& device : getDeviceParameters()) {
|
||||
auto module =
|
||||
getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
|
||||
for (const auto& ioProfile : module->getInputProfiles()) {
|
||||
for (const auto& profile : ioProfile->getAudioProfiles()) {
|
||||
const auto& channels = profile->getChannels();
|
||||
const auto& sampleRates = profile->getSampleRates();
|
||||
auto configs = ConfigHelper::combineAudioConfig(
|
||||
std::vector<audio_channel_mask_t>(channels.begin(), channels.end()),
|
||||
std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
|
||||
profile->getFormat());
|
||||
for (const auto& config : configs) {
|
||||
result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags()));
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
|
||||
static std::vector<DeviceConfigParameter> parameters =
|
||||
generateInputDeviceConfigParameters(false);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters() {
|
||||
static std::vector<DeviceConfigParameter> parameters =
|
||||
generateInputDeviceConfigParameters(true);
|
||||
return parameters;
|
||||
}
|
||||
#endif // MAJOR_VERSION <= 6
|
||||
|
||||
TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedOutputStreams) {
|
||||
doc::test("Verify that a device can't be closed if there are streams opened");
|
||||
class SingleOutputConfigTest : public AudioHidlTestWithDeviceConfigParameter {};
|
||||
TEST_P(SingleOutputConfigTest, CloseDeviceWithOpenedOutputStreams) {
|
||||
doc::test("Verify that a device can't be closed if there are output streams opened");
|
||||
#if MAJOR_VERSION <= 6
|
||||
DeviceAddress address{.device = AudioDevice::OUT_DEFAULT};
|
||||
SourceMetadata initMetadata = {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 1 /* gain */}}};
|
||||
auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE);
|
||||
#elif MAJOR_VERSION >= 7
|
||||
DeviceAddress address{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)};
|
||||
SourceMetadata initMetadata = {{{toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
|
||||
|
@ -103,9 +129,9 @@ TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedOutputStreams) {
|
|||
{} /* tags */,
|
||||
toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO),
|
||||
1 /* gain */}}};
|
||||
hidl_vec<AudioInOutFlag> flags;
|
||||
#endif
|
||||
AudioConfig config{};
|
||||
const AudioConfig& config = getConfig();
|
||||
auto flags = getOutputFlags();
|
||||
sp<IStreamOut> stream;
|
||||
StreamHelper<IStreamOut> helper(stream);
|
||||
AudioConfig suggestedConfig{};
|
||||
|
@ -120,16 +146,17 @@ TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedOutputStreams) {
|
|||
ASSERT_OK(getDevice()->close());
|
||||
ASSERT_TRUE(resetDevice());
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(SingleOutputConfig, SingleOutputConfigTest,
|
||||
::testing::ValuesIn(getOutputDeviceSingleConfigParameters()),
|
||||
&DeviceConfigParameterToString);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SingleOutputConfig);
|
||||
|
||||
TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) {
|
||||
doc::test("Verify that a device can't be closed if there are streams opened");
|
||||
if (!getCachedPolicyConfig().haveInputProfilesInModule(getDeviceName())) {
|
||||
GTEST_SKIP() << "Device doesn't have input profiles";
|
||||
}
|
||||
class SingleInputConfigTest : public AudioHidlTestWithDeviceConfigParameter {};
|
||||
TEST_P(SingleInputConfigTest, CloseDeviceWithOpenedInputStreams) {
|
||||
doc::test("Verify that a device can't be closed if there are input streams opened");
|
||||
#if MAJOR_VERSION <= 6
|
||||
DeviceAddress address{.device = AudioDevice::IN_DEFAULT};
|
||||
SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}};
|
||||
auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
|
||||
#elif MAJOR_VERSION >= 7
|
||||
DeviceAddress address{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)};
|
||||
SinkMetadata initMetadata = {
|
||||
|
@ -137,9 +164,9 @@ TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) {
|
|||
.gain = 1,
|
||||
.tags = {},
|
||||
.channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO)}}};
|
||||
hidl_vec<AudioInOutFlag> flags;
|
||||
#endif
|
||||
AudioConfig config{};
|
||||
const AudioConfig& config = getConfig();
|
||||
auto flags = getInputFlags();
|
||||
sp<IStreamIn> stream;
|
||||
StreamHelper<IStreamIn> helper(stream);
|
||||
AudioConfig suggestedConfig{};
|
||||
|
@ -154,6 +181,10 @@ TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) {
|
|||
ASSERT_OK(getDevice()->close());
|
||||
ASSERT_TRUE(resetDevice());
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(SingleInputConfig, SingleInputConfigTest,
|
||||
::testing::ValuesIn(getInputDeviceSingleConfigParameters()),
|
||||
&DeviceConfigParameterToString);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SingleInputConfig);
|
||||
|
||||
TEST_P(AudioPatchHidlTest, UpdatePatchInvalidHandle) {
|
||||
doc::test("Verify that passing an invalid handle to updateAudioPatch is checked");
|
||||
|
|
|
@ -25,7 +25,6 @@ static std::vector<AudioConfig> combineAudioConfig(std::vector<xsd::AudioChannel
|
|||
for (auto channelMask : channelMasks) {
|
||||
for (auto sampleRate : sampleRates) {
|
||||
AudioConfig config{};
|
||||
// leave offloadInfo to 0
|
||||
config.base.channelMask = toString(channelMask);
|
||||
config.base.sampleRateHz = sampleRate;
|
||||
config.base.format = format;
|
||||
|
@ -35,56 +34,158 @@ static std::vector<AudioConfig> combineAudioConfig(std::vector<xsd::AudioChannel
|
|||
return configs;
|
||||
}
|
||||
|
||||
static std::tuple<std::vector<AudioInOutFlag>, bool> generateOutFlags(
|
||||
const xsd::MixPorts::MixPort& mixPort) {
|
||||
static const std::vector<AudioInOutFlag> offloadFlags = {
|
||||
toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
|
||||
toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)};
|
||||
std::vector<AudioInOutFlag> flags;
|
||||
bool isOffload = false;
|
||||
if (mixPort.hasFlags()) {
|
||||
auto xsdFlags = mixPort.getFlags();
|
||||
isOffload = std::find(xsdFlags.begin(), xsdFlags.end(),
|
||||
xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) !=
|
||||
xsdFlags.end();
|
||||
if (!isOffload) {
|
||||
for (auto flag : xsdFlags) {
|
||||
if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
|
||||
flags.push_back(toString(flag));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
flags = offloadFlags;
|
||||
}
|
||||
}
|
||||
return {flags, isOffload};
|
||||
}
|
||||
|
||||
static AudioOffloadInfo generateOffloadInfo(const AudioConfigBase& base) {
|
||||
return AudioOffloadInfo{
|
||||
.base = base,
|
||||
.streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC),
|
||||
.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
|
||||
.bitRatePerSecond = 320,
|
||||
.durationMicroseconds = -1,
|
||||
.bitWidth = 16,
|
||||
.bufferSize = 256 // arbitrary value
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(
|
||||
bool oneProfilePerDevice) {
|
||||
std::vector<DeviceConfigParameter> result;
|
||||
for (const auto& device : getDeviceParameters()) {
|
||||
auto module =
|
||||
getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
|
||||
if (!module || !module->getFirstMixPorts()) break;
|
||||
for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
|
||||
if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile
|
||||
auto [flags, isOffload] = generateOutFlags(mixPort);
|
||||
for (const auto& profile : mixPort.getProfile()) {
|
||||
auto configs = combineAudioConfig(profile.getChannelMasks(),
|
||||
profile.getSamplingRates(), profile.getFormat());
|
||||
for (auto& config : configs) {
|
||||
// Some combinations of flags declared in the config file require special
|
||||
// treatment.
|
||||
if (isOffload) {
|
||||
config.offloadInfo.info(generateOffloadInfo(config.base));
|
||||
}
|
||||
result.emplace_back(device, config, flags);
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
|
||||
static std::vector<DeviceConfigParameter> parameters = [] {
|
||||
static std::vector<DeviceConfigParameter> parameters =
|
||||
generateOutputDeviceConfigParameters(false);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters() {
|
||||
static std::vector<DeviceConfigParameter> parameters =
|
||||
generateOutputDeviceConfigParameters(true);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters(
|
||||
bool generateInvalidFlags = true) {
|
||||
static std::vector<DeviceConfigParameter> parameters = [&] {
|
||||
std::vector<DeviceConfigParameter> result;
|
||||
const std::vector<AudioInOutFlag> offloadFlags = {
|
||||
toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
|
||||
toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)};
|
||||
for (const auto& device : getDeviceParameters()) {
|
||||
auto module =
|
||||
getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
|
||||
if (!module || !module->getFirstMixPorts()) break;
|
||||
bool hasRegularConfig = false, hasOffloadConfig = false;
|
||||
for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
|
||||
if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile
|
||||
std::vector<AudioInOutFlag> flags;
|
||||
bool isOffload = false;
|
||||
if (mixPort.hasFlags()) {
|
||||
auto xsdFlags = mixPort.getFlags();
|
||||
isOffload =
|
||||
std::find(xsdFlags.begin(), xsdFlags.end(),
|
||||
xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) !=
|
||||
xsdFlags.end();
|
||||
if (!isOffload) {
|
||||
for (auto flag : xsdFlags) {
|
||||
if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
|
||||
flags.push_back(toString(flag));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
flags = offloadFlags;
|
||||
}
|
||||
}
|
||||
auto [validFlags, isOffload] = generateOutFlags(mixPort);
|
||||
if ((!isOffload && hasRegularConfig) || (isOffload && hasOffloadConfig)) continue;
|
||||
for (const auto& profile : mixPort.getProfile()) {
|
||||
auto configs =
|
||||
combineAudioConfig(profile.getChannelMasks(),
|
||||
profile.getSamplingRates(), profile.getFormat());
|
||||
for (auto& config : configs) {
|
||||
// Some combinations of flags declared in the config file require special
|
||||
// treatment.
|
||||
if (!profile.hasFormat() || !profile.hasSamplingRates() ||
|
||||
!profile.hasChannelMasks())
|
||||
continue;
|
||||
AudioConfigBase validBase = {
|
||||
profile.getFormat(),
|
||||
static_cast<uint32_t>(profile.getSamplingRates()[0]),
|
||||
toString(profile.getChannelMasks()[0])};
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.base.channelMask = "random_string";
|
||||
if (isOffload) {
|
||||
config.offloadInfo.base = config.base;
|
||||
config.offloadInfo.streamType =
|
||||
toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC);
|
||||
config.offloadInfo.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA);
|
||||
config.offloadInfo.bitRatePerSecond = 320;
|
||||
config.offloadInfo.durationMicroseconds = -1;
|
||||
config.offloadInfo.bitWidth = 16;
|
||||
config.offloadInfo.bufferSize = 256; // arbitrary value
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
}
|
||||
result.emplace_back(device, config, validFlags);
|
||||
}
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.base.format = "random_string";
|
||||
if (isOffload) {
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
}
|
||||
result.emplace_back(device, config, validFlags);
|
||||
}
|
||||
if (generateInvalidFlags) {
|
||||
AudioConfig config{.base = validBase};
|
||||
if (isOffload) {
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
}
|
||||
std::vector<AudioInOutFlag> flags = {"random_string", ""};
|
||||
result.emplace_back(device, config, flags);
|
||||
}
|
||||
if (isOffload) {
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
config.offloadInfo.info().base.channelMask = "random_string";
|
||||
}
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
config.offloadInfo.info().base.format = "random_string";
|
||||
}
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
config.offloadInfo.info().streamType = "random_string";
|
||||
}
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
config.offloadInfo.info().usage = "random_string";
|
||||
}
|
||||
hasOffloadConfig = true;
|
||||
} else {
|
||||
hasRegularConfig = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (hasOffloadConfig && hasRegularConfig) break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -92,32 +193,346 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
|
|||
return parameters;
|
||||
}
|
||||
|
||||
static std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(
|
||||
bool oneProfilePerDevice) {
|
||||
std::vector<DeviceConfigParameter> result;
|
||||
for (const auto& device : getDeviceParameters()) {
|
||||
auto module =
|
||||
getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
|
||||
if (!module || !module->getFirstMixPorts()) break;
|
||||
for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
|
||||
if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile
|
||||
std::vector<AudioInOutFlag> flags;
|
||||
if (mixPort.hasFlags()) {
|
||||
std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
|
||||
std::back_inserter(flags), [](auto flag) { return toString(flag); });
|
||||
}
|
||||
for (const auto& profile : mixPort.getProfile()) {
|
||||
auto configs = combineAudioConfig(profile.getChannelMasks(),
|
||||
profile.getSamplingRates(), profile.getFormat());
|
||||
for (const auto& config : configs) {
|
||||
result.emplace_back(device, config, flags);
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
|
||||
static std::vector<DeviceConfigParameter> parameters = [] {
|
||||
static std::vector<DeviceConfigParameter> parameters =
|
||||
generateInputDeviceConfigParameters(false);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters() {
|
||||
static std::vector<DeviceConfigParameter> parameters =
|
||||
generateInputDeviceConfigParameters(true);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
const std::vector<DeviceConfigParameter>& getInputDeviceInvalidConfigParameters(
|
||||
bool generateInvalidFlags = true) {
|
||||
static std::vector<DeviceConfigParameter> parameters = [&] {
|
||||
std::vector<DeviceConfigParameter> result;
|
||||
for (const auto& device : getDeviceParameters()) {
|
||||
auto module =
|
||||
getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
|
||||
if (!module || !module->getFirstMixPorts()) break;
|
||||
bool hasConfig = false;
|
||||
for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
|
||||
if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile
|
||||
std::vector<AudioInOutFlag> flags;
|
||||
std::vector<AudioInOutFlag> validFlags;
|
||||
if (mixPort.hasFlags()) {
|
||||
std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
|
||||
std::back_inserter(flags),
|
||||
std::back_inserter(validFlags),
|
||||
[](auto flag) { return toString(flag); });
|
||||
}
|
||||
for (const auto& profile : mixPort.getProfile()) {
|
||||
auto configs =
|
||||
combineAudioConfig(profile.getChannelMasks(),
|
||||
profile.getSamplingRates(), profile.getFormat());
|
||||
for (const auto& config : configs) {
|
||||
if (!profile.hasFormat() || !profile.hasSamplingRates() ||
|
||||
!profile.hasChannelMasks())
|
||||
continue;
|
||||
AudioConfigBase validBase = {
|
||||
profile.getFormat(),
|
||||
static_cast<uint32_t>(profile.getSamplingRates()[0]),
|
||||
toString(profile.getChannelMasks()[0])};
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.base.channelMask = "random_string";
|
||||
result.emplace_back(device, config, validFlags);
|
||||
}
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.base.format = "random_string";
|
||||
result.emplace_back(device, config, validFlags);
|
||||
}
|
||||
if (generateInvalidFlags) {
|
||||
AudioConfig config{.base = validBase};
|
||||
std::vector<AudioInOutFlag> flags = {"random_string", ""};
|
||||
result.emplace_back(device, config, flags);
|
||||
}
|
||||
hasConfig = true;
|
||||
break;
|
||||
}
|
||||
if (hasConfig) break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
return parameters;
|
||||
}
|
||||
|
||||
class InvalidInputConfigNoFlagsTest : public AudioHidlTestWithDeviceConfigParameter {};
|
||||
TEST_P(InvalidInputConfigNoFlagsTest, InputBufferSizeTest) {
|
||||
doc::test("Verify that invalid config is rejected by IDevice::getInputBufferSize method.");
|
||||
uint64_t bufferSize;
|
||||
ASSERT_OK(getDevice()->getInputBufferSize(getConfig(), returnIn(res, bufferSize)));
|
||||
EXPECT_EQ(Result::INVALID_ARGUMENTS, res);
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
InputBufferSizeInvalidConfig, InvalidInputConfigNoFlagsTest,
|
||||
::testing::ValuesIn(getInputDeviceInvalidConfigParameters(false /*generateInvalidFlags*/)),
|
||||
&DeviceConfigParameterToString);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputBufferSizeInvalidConfig);
|
||||
|
||||
enum { PARAM_DEVICE_CONFIG, PARAM_ADDRESS, PARAM_METADATA };
|
||||
enum { INDEX_SINK, INDEX_SOURCE };
|
||||
using SinkOrSourceMetadata = std::variant<SinkMetadata, SourceMetadata>;
|
||||
using StreamOpenParameter = std::tuple<DeviceConfigParameter, DeviceAddress, SinkOrSourceMetadata>;
|
||||
|
||||
static std::string StreamOpenParameterToString(
|
||||
const ::testing::TestParamInfo<StreamOpenParameter>& info) {
|
||||
return DeviceConfigParameterToString(::testing::TestParamInfo<DeviceConfigParameter>{
|
||||
std::get<PARAM_DEVICE_CONFIG>(info.param), info.index}) +
|
||||
"__" +
|
||||
SanitizeStringForGTestName(
|
||||
::testing::PrintToString(std::get<PARAM_ADDRESS>(info.param))) +
|
||||
"__" +
|
||||
SanitizeStringForGTestName(std::visit(
|
||||
[](auto&& arg) -> std::string { return ::testing::PrintToString(arg); },
|
||||
std::get<PARAM_METADATA>(info.param)));
|
||||
}
|
||||
|
||||
class StreamOpenTest : public HidlTest, public ::testing::WithParamInterface<StreamOpenParameter> {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base
|
||||
ASSERT_TRUE(getDevicesFactory() != nullptr);
|
||||
ASSERT_TRUE(getDevice() != nullptr);
|
||||
}
|
||||
const std::string& getFactoryName() const override {
|
||||
return std::get<PARAM_FACTORY_NAME>(
|
||||
std::get<PARAM_DEVICE>(std::get<PARAM_DEVICE_CONFIG>(GetParam())));
|
||||
}
|
||||
const std::string& getDeviceName() const override {
|
||||
return std::get<PARAM_DEVICE_NAME>(
|
||||
std::get<PARAM_DEVICE>(std::get<PARAM_DEVICE_CONFIG>(GetParam())));
|
||||
}
|
||||
const AudioConfig& getConfig() const {
|
||||
return std::get<PARAM_CONFIG>(std::get<PARAM_DEVICE_CONFIG>(GetParam()));
|
||||
}
|
||||
const hidl_vec<AudioInOutFlag> getFlags() const {
|
||||
return std::get<PARAM_FLAGS>(std::get<PARAM_DEVICE_CONFIG>(GetParam()));
|
||||
}
|
||||
const DeviceAddress& getDeviceAddress() const { return std::get<PARAM_ADDRESS>(GetParam()); }
|
||||
bool isParamForInputStream() const {
|
||||
return std::get<PARAM_METADATA>(GetParam()).index() == INDEX_SINK;
|
||||
}
|
||||
const SinkMetadata& getSinkMetadata() const {
|
||||
return std::get<INDEX_SINK>(std::get<PARAM_METADATA>(GetParam()));
|
||||
}
|
||||
const SourceMetadata& getSourceMetadata() const {
|
||||
return std::get<INDEX_SOURCE>(std::get<PARAM_METADATA>(GetParam()));
|
||||
}
|
||||
};
|
||||
|
||||
static const DeviceAddress& getValidInputDeviceAddress() {
|
||||
static const DeviceAddress valid = {
|
||||
.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)};
|
||||
return valid;
|
||||
}
|
||||
|
||||
static const DeviceAddress& getValidOutputDeviceAddress() {
|
||||
static const DeviceAddress valid = {
|
||||
.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)};
|
||||
return valid;
|
||||
}
|
||||
|
||||
static const DeviceAddress& getInvalidDeviceAddress() {
|
||||
static const DeviceAddress valid = {.deviceType = "random_string"};
|
||||
return valid;
|
||||
}
|
||||
|
||||
static const RecordTrackMetadata& getValidRecordTrackMetadata() {
|
||||
static const RecordTrackMetadata valid = {
|
||||
.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT), .gain = 1};
|
||||
return valid;
|
||||
}
|
||||
|
||||
static const RecordTrackMetadata& getValidRecordTrackMetadataWithDest() {
|
||||
static const RecordTrackMetadata valid = {
|
||||
.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT),
|
||||
.gain = 1,
|
||||
.destination = [] {
|
||||
RecordTrackMetadata::Destination dest;
|
||||
dest.device(getValidOutputDeviceAddress());
|
||||
return dest;
|
||||
}()};
|
||||
return valid;
|
||||
}
|
||||
|
||||
static const RecordTrackMetadata& getInvalidSourceRecordTrackMetadata() {
|
||||
static const RecordTrackMetadata invalid = {.source = "random_string", .gain = 1};
|
||||
return invalid;
|
||||
}
|
||||
|
||||
static const RecordTrackMetadata& getRecordTrackMetadataWithInvalidDest() {
|
||||
static const RecordTrackMetadata invalid = {
|
||||
.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT),
|
||||
.gain = 1,
|
||||
.destination = [] {
|
||||
RecordTrackMetadata::Destination dest;
|
||||
dest.device(getInvalidDeviceAddress());
|
||||
return dest;
|
||||
}()};
|
||||
return invalid;
|
||||
}
|
||||
|
||||
static const PlaybackTrackMetadata& getValidPlaybackTrackMetadata() {
|
||||
static const PlaybackTrackMetadata valid = {
|
||||
.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
|
||||
.contentType = toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC),
|
||||
.gain = 1};
|
||||
return valid;
|
||||
}
|
||||
|
||||
static const PlaybackTrackMetadata& getInvalidUsagePlaybackTrackMetadata() {
|
||||
static const PlaybackTrackMetadata invalid = {
|
||||
.usage = "random_string",
|
||||
.contentType = toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC),
|
||||
.gain = 1};
|
||||
return invalid;
|
||||
}
|
||||
|
||||
static const PlaybackTrackMetadata& getInvalidContentTypePlaybackTrackMetadata() {
|
||||
static const PlaybackTrackMetadata invalid = {
|
||||
.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
|
||||
.contentType = "random_string",
|
||||
.gain = 1};
|
||||
return invalid;
|
||||
}
|
||||
|
||||
static const std::vector<SourceMetadata>& getInvalidSourceMetadatas() {
|
||||
static const std::vector<SourceMetadata> invalids = {
|
||||
SourceMetadata{.tracks = {{getInvalidUsagePlaybackTrackMetadata()}}},
|
||||
SourceMetadata{.tracks = {{getInvalidContentTypePlaybackTrackMetadata()}}},
|
||||
SourceMetadata{.tracks = {{getValidPlaybackTrackMetadata(),
|
||||
getInvalidUsagePlaybackTrackMetadata()}}},
|
||||
SourceMetadata{.tracks = {{getValidPlaybackTrackMetadata(),
|
||||
getInvalidContentTypePlaybackTrackMetadata()}}}};
|
||||
return invalids;
|
||||
}
|
||||
static const std::vector<SinkMetadata>& getInvalidSinkMetadatas() {
|
||||
static const std::vector<SinkMetadata> invalids = {
|
||||
SinkMetadata{.tracks = {{getInvalidSourceRecordTrackMetadata()}}},
|
||||
SinkMetadata{.tracks = {{getRecordTrackMetadataWithInvalidDest()}}},
|
||||
SinkMetadata{.tracks = {{getValidRecordTrackMetadata(),
|
||||
getInvalidSourceRecordTrackMetadata()}}},
|
||||
SinkMetadata{.tracks = {{getValidRecordTrackMetadata(),
|
||||
getRecordTrackMetadataWithInvalidDest()}}}};
|
||||
return invalids;
|
||||
}
|
||||
template <typename T>
|
||||
static inline std::vector<SinkOrSourceMetadata> wrapMetadata(const std::vector<T>& metadata) {
|
||||
return std::vector<SinkOrSourceMetadata>{metadata.begin(), metadata.end()};
|
||||
}
|
||||
|
||||
TEST_P(StreamOpenTest, OpenInputOrOutputStreamTest) {
|
||||
doc::test(
|
||||
"Verify that invalid arguments are rejected by "
|
||||
"IDevice::open{Input|Output}Stream method.");
|
||||
AudioConfig suggestedConfig{};
|
||||
if (isParamForInputStream()) {
|
||||
sp<IStreamIn> stream;
|
||||
ASSERT_OK(getDevice()->openInputStream(AudioIoHandle{}, getDeviceAddress(), getConfig(),
|
||||
getFlags(), getSinkMetadata(),
|
||||
returnIn(res, stream, suggestedConfig)));
|
||||
ASSERT_TRUE(stream == nullptr);
|
||||
} else {
|
||||
sp<IStreamOut> stream;
|
||||
ASSERT_OK(getDevice()->openOutputStream(AudioIoHandle{}, getDeviceAddress(), getConfig(),
|
||||
getFlags(), getSourceMetadata(),
|
||||
returnIn(res, stream, suggestedConfig)));
|
||||
ASSERT_TRUE(stream == nullptr);
|
||||
}
|
||||
EXPECT_EQ(Result::INVALID_ARGUMENTS, res);
|
||||
EXPECT_EQ(AudioConfig{}, suggestedConfig);
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
InputStreamInvalidConfig, StreamOpenTest,
|
||||
::testing::Combine(::testing::ValuesIn(getInputDeviceInvalidConfigParameters()),
|
||||
::testing::Values(getValidInputDeviceAddress()),
|
||||
::testing::Values(SinkMetadata{
|
||||
.tracks = {{getValidRecordTrackMetadata(),
|
||||
getValidRecordTrackMetadataWithDest()}}})),
|
||||
&StreamOpenParameterToString);
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
InputStreamInvalidAddress, StreamOpenTest,
|
||||
::testing::Combine(::testing::ValuesIn(getInputDeviceSingleConfigParameters()),
|
||||
::testing::Values(getInvalidDeviceAddress()),
|
||||
::testing::Values(SinkMetadata{
|
||||
.tracks = {{getValidRecordTrackMetadata(),
|
||||
getValidRecordTrackMetadataWithDest()}}})),
|
||||
&StreamOpenParameterToString);
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
InputStreamInvalidMetadata, StreamOpenTest,
|
||||
::testing::Combine(::testing::ValuesIn(getInputDeviceSingleConfigParameters()),
|
||||
::testing::Values(getValidInputDeviceAddress()),
|
||||
::testing::ValuesIn(wrapMetadata(getInvalidSinkMetadatas()))),
|
||||
&StreamOpenParameterToString);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamInvalidConfig);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamInvalidAddress);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamInvalidMetadata);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
OutputStreamInvalidConfig, StreamOpenTest,
|
||||
::testing::Combine(::testing::ValuesIn(getOutputDeviceInvalidConfigParameters()),
|
||||
::testing::Values(getValidOutputDeviceAddress()),
|
||||
::testing::Values(SourceMetadata{
|
||||
.tracks = {{getValidPlaybackTrackMetadata()}}})),
|
||||
&StreamOpenParameterToString);
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
OutputStreamInvalidAddress, StreamOpenTest,
|
||||
::testing::Combine(::testing::ValuesIn(getOutputDeviceSingleConfigParameters()),
|
||||
::testing::Values(getInvalidDeviceAddress()),
|
||||
::testing::Values(SourceMetadata{
|
||||
.tracks = {{getValidPlaybackTrackMetadata()}}})),
|
||||
&StreamOpenParameterToString);
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
OutputStreamInvalidMetadata, StreamOpenTest,
|
||||
::testing::Combine(::testing::ValuesIn(getOutputDeviceSingleConfigParameters()),
|
||||
::testing::Values(getValidOutputDeviceAddress()),
|
||||
::testing::ValuesIn(wrapMetadata(getInvalidSourceMetadatas()))),
|
||||
&StreamOpenParameterToString);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamInvalidConfig);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamInvalidAddress);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamInvalidMetadata);
|
||||
|
||||
TEST_P(OutputStreamTest, UpdateInvalidSourceMetadata) {
|
||||
doc::test("Verify that invalid metadata is rejected by IStreamOut::updateSourceMetadata");
|
||||
for (const auto& metadata : getInvalidSourceMetadatas()) {
|
||||
ASSERT_RESULT(invalidArgsOrNotSupported, stream->updateSourceMetadata(metadata))
|
||||
<< ::testing::PrintToString(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(InputStreamTest, UpdateInvalidSinkMetadata) {
|
||||
doc::test("Verify that invalid metadata is rejected by IStreamIn::updateSinkMetadata");
|
||||
for (const auto& metadata : getInvalidSinkMetadatas()) {
|
||||
ASSERT_RESULT(invalidArgsOrNotSupported, stream->updateSinkMetadata(metadata))
|
||||
<< ::testing::PrintToString(metadata);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -522,7 +522,9 @@ using DeviceConfigParameter = std::tuple<DeviceParameter, AudioConfig, std::vect
|
|||
|
||||
#if MAJOR_VERSION >= 6
|
||||
const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters();
|
||||
const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters();
|
||||
const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters();
|
||||
const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters();
|
||||
#endif
|
||||
|
||||
#if MAJOR_VERSION >= 4
|
||||
|
@ -883,7 +885,7 @@ class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter {
|
|||
AudioHidlTestWithDeviceConfigParameter::TearDown();
|
||||
}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
AudioConfig audioConfig;
|
||||
DeviceAddress address = {};
|
||||
sp<Stream> stream;
|
||||
|
@ -973,7 +975,7 @@ class InputStreamTest : public OpenStreamTest<IStreamIn> {
|
|||
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
|
||||
#if MAJOR_VERSION <= 6
|
||||
address.device = AudioDevice::IN_DEFAULT;
|
||||
#elif MAJOR_VERSION <= 7
|
||||
#elif MAJOR_VERSION >= 7
|
||||
address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
|
||||
#endif
|
||||
const AudioConfig& config = getConfig();
|
||||
|
@ -988,7 +990,7 @@ class InputStreamTest : public OpenStreamTest<IStreamIn> {
|
|||
|
||||
protected:
|
||||
#if MAJOR_VERSION == 2
|
||||
const AudioSource initMetadata = AudioSource::DEFAULT;
|
||||
const AudioSource initMetadata = AudioSource::DEFAULT;
|
||||
#elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
|
||||
const SinkMetadata initMetadata = {{ {.source = AudioSource::DEFAULT, .gain = 1 } }};
|
||||
#elif MAJOR_VERSION >= 7
|
||||
|
|
Loading…
Reference in a new issue