blob: 0d12f9d9e139bd237c7161c503d9e7f5c84825f7 [file] [log] [blame]
/*
* Copyright (C) 2021 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 <iostream>
#include <string>
#include <gtest/gtest.h>
#include <media/AidlConversion.h>
#include <media/AudioCommonTypes.h>
using namespace android;
using namespace android::aidl_utils;
using media::AudioDirectMode;
using media::AudioPortConfigFw;
using media::AudioPortDeviceExtSys;
using media::AudioPortFw;
using media::AudioPortRole;
using media::AudioPortType;
using media::audio::common::AudioChannelLayout;
using media::audio::common::AudioDevice;
using media::audio::common::AudioDeviceAddress;
using media::audio::common::AudioDeviceDescription;
using media::audio::common::AudioDeviceType;
using media::audio::common::AudioEncapsulationMetadataType;
using media::audio::common::AudioEncapsulationType;
using media::audio::common::AudioFormatDescription;
using media::audio::common::AudioFormatType;
using media::audio::common::AudioGain;
using media::audio::common::AudioGainConfig;
using media::audio::common::AudioGainMode;
using media::audio::common::AudioIoFlags;
using media::audio::common::AudioPortDeviceExt;
using media::audio::common::AudioProfile;
using media::audio::common::AudioStandard;
using media::audio::common::ExtraAudioDescriptor;
using media::audio::common::Int;
using media::audio::common::MicrophoneDynamicInfo;
using media::audio::common::MicrophoneInfo;
using media::audio::common::PcmType;
// Provide value printers for types generated from AIDL
// They need to be in the same namespace as the types we intend to print
namespace android::media {
#define DEFINE_PRINTING_TEMPLATES() \
template <typename P> \
std::enable_if_t<std::is_base_of_v<::android::Parcelable, P>, std::ostream&> operator<<( \
std::ostream& os, const P& p) { \
return os << p.toString(); \
} \
template <typename E> \
std::enable_if_t<std::is_enum_v<E>, std::ostream&> operator<<(std::ostream& os, const E& e) { \
return os << toString(e); \
}
DEFINE_PRINTING_TEMPLATES();
namespace audio::common {
DEFINE_PRINTING_TEMPLATES();
} // namespace audio::common
#undef DEFINE_PRINTING_TEMPLATES
} // namespace android::media
namespace {
template <typename T>
size_t hash(const T& t) {
return std::hash<T>{}(t);
}
AudioChannelLayout make_ACL_None() {
return AudioChannelLayout{};
}
AudioChannelLayout make_ACL_Invalid() {
return AudioChannelLayout::make<AudioChannelLayout::Tag::invalid>(0);
}
AudioChannelLayout make_ACL_Stereo() {
return AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::LAYOUT_STEREO);
}
AudioChannelLayout make_ACL_LayoutArbitrary() {
return AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
// Use channels that exist both for input and output,
// but doesn't form a known layout mask.
AudioChannelLayout::CHANNEL_FRONT_LEFT | AudioChannelLayout::CHANNEL_FRONT_RIGHT |
AudioChannelLayout::CHANNEL_TOP_SIDE_LEFT | AudioChannelLayout::CHANNEL_TOP_SIDE_RIGHT);
}
AudioChannelLayout make_ACL_ChannelIndex2() {
return AudioChannelLayout::make<AudioChannelLayout::Tag::indexMask>(
AudioChannelLayout::INDEX_MASK_2);
}
AudioChannelLayout make_ACL_ChannelIndexArbitrary() {
// Use channels 1 and 3.
return AudioChannelLayout::make<AudioChannelLayout::Tag::indexMask>(5);
}
AudioChannelLayout make_ACL_VoiceCall() {
return AudioChannelLayout::make<AudioChannelLayout::Tag::voiceMask>(
AudioChannelLayout::VOICE_CALL_MONO);
}
AudioDeviceDescription make_AudioDeviceDescription(AudioDeviceType type,
const std::string& connection = "") {
AudioDeviceDescription result;
result.type = type;
result.connection = connection;
return result;
}
AudioDeviceDescription make_ADD_None() {
return AudioDeviceDescription{};
}
AudioDeviceDescription make_ADD_DefaultIn() {
return make_AudioDeviceDescription(AudioDeviceType::IN_DEFAULT);
}
AudioDeviceDescription make_ADD_MicIn() {
return make_AudioDeviceDescription(AudioDeviceType::IN_MICROPHONE);
}
AudioDeviceDescription make_ADD_RSubmixIn() {
return make_AudioDeviceDescription(AudioDeviceType::IN_SUBMIX);
}
AudioDeviceDescription make_ADD_DefaultOut() {
return make_AudioDeviceDescription(AudioDeviceType::OUT_DEFAULT);
}
AudioDeviceDescription make_ADD_WiredHeadset() {
return make_AudioDeviceDescription(AudioDeviceType::OUT_HEADSET,
AudioDeviceDescription::CONNECTION_ANALOG());
}
AudioDeviceDescription make_ADD_BtScoHeadset() {
return make_AudioDeviceDescription(AudioDeviceType::OUT_HEADSET,
AudioDeviceDescription::CONNECTION_BT_SCO());
}
AudioDeviceDescription make_ADD_BtA2dpHeadphone() {
return make_AudioDeviceDescription(AudioDeviceType::OUT_HEADPHONE,
AudioDeviceDescription::CONNECTION_BT_A2DP());
}
AudioDeviceDescription make_ADD_BtLeHeadset() {
return make_AudioDeviceDescription(AudioDeviceType::OUT_HEADSET,
AudioDeviceDescription::CONNECTION_BT_LE());
}
AudioDeviceDescription make_ADD_BtLeBroadcast() {
return make_AudioDeviceDescription(AudioDeviceType::OUT_BROADCAST,
AudioDeviceDescription::CONNECTION_BT_LE());
}
AudioDeviceDescription make_ADD_IpV4Device() {
return make_AudioDeviceDescription(AudioDeviceType::OUT_DEVICE,
AudioDeviceDescription::CONNECTION_IP_V4());
}
AudioDeviceDescription make_ADD_UsbHeadset() {
return make_AudioDeviceDescription(AudioDeviceType::OUT_HEADSET,
AudioDeviceDescription::CONNECTION_USB());
}
AudioDevice make_AudioDevice(const AudioDeviceDescription& type,
const AudioDeviceAddress& address) {
AudioDevice result;
result.type = type;
result.address = address;
return result;
}
AudioFormatDescription make_AudioFormatDescription(AudioFormatType type) {
AudioFormatDescription result;
result.type = type;
return result;
}
AudioFormatDescription make_AudioFormatDescription(PcmType pcm) {
auto result = make_AudioFormatDescription(AudioFormatType::PCM);
result.pcm = pcm;
return result;
}
AudioFormatDescription make_AudioFormatDescription(const std::string& encoding) {
AudioFormatDescription result;
result.encoding = encoding;
return result;
}
AudioFormatDescription make_AudioFormatDescription(PcmType transport, const std::string& encoding) {
auto result = make_AudioFormatDescription(encoding);
result.pcm = transport;
return result;
}
AudioFormatDescription make_AFD_Default() {
return AudioFormatDescription{};
}
AudioFormatDescription make_AFD_Invalid() {
return make_AudioFormatDescription(AudioFormatType::SYS_RESERVED_INVALID);
}
AudioFormatDescription make_AFD_Pcm16Bit() {
return make_AudioFormatDescription(PcmType::INT_16_BIT);
}
AudioFormatDescription make_AFD_Bitstream() {
return make_AudioFormatDescription("example");
}
AudioFormatDescription make_AFD_Encap() {
return make_AudioFormatDescription(PcmType::INT_16_BIT, "example.encap");
}
AudioFormatDescription make_AFD_Encap_with_Enc() {
auto afd = make_AFD_Encap();
afd.encoding += "+example";
return afd;
}
android::media::TrackSecondaryOutputInfo make_TrackSecondaryOutputInfo() {
android::media::TrackSecondaryOutputInfo result;
result.portId = 1;
result.secondaryOutputIds = {0, 5, 7};
return result;
}
ExtraAudioDescriptor make_ExtraAudioDescriptor(AudioStandard audioStandard,
AudioEncapsulationType audioEncapsulationType) {
ExtraAudioDescriptor result;
result.standard = audioStandard;
result.audioDescriptor = {0xb4, 0xaf, 0x98, 0x1a};
result.encapsulationType = audioEncapsulationType;
return result;
}
} // namespace
// Verify that two independently constructed ADDs/AFDs have the same hash.
// This ensures that regardless of whether the ADD/AFD instance originates
// from, it can be correctly compared to other ADD/AFD instance. Thus,
// for example, a 16-bit integer format description provided by HAL
// is identical to the same format description constructed by the framework.
class HashIdentityTest : public ::testing::Test {
public:
template <typename T>
void verifyHashIdentity(const std::vector<std::function<T()>>& valueGens) {
for (size_t i = 0; i < valueGens.size(); ++i) {
for (size_t j = 0; j < valueGens.size(); ++j) {
if (i == j) {
EXPECT_EQ(hash(valueGens[i]()), hash(valueGens[i]())) << i;
} else {
EXPECT_NE(hash(valueGens[i]()), hash(valueGens[j]())) << i << ", " << j;
}
}
}
}
};
TEST_F(HashIdentityTest, AudioChannelLayoutHashIdentity) {
verifyHashIdentity<AudioChannelLayout>({make_ACL_None, make_ACL_Invalid, make_ACL_Stereo,
make_ACL_LayoutArbitrary, make_ACL_ChannelIndex2,
make_ACL_ChannelIndexArbitrary, make_ACL_VoiceCall});
}
TEST_F(HashIdentityTest, AudioDeviceDescriptionHashIdentity) {
verifyHashIdentity<AudioDeviceDescription>({make_ADD_None, make_ADD_DefaultIn,
make_ADD_DefaultOut, make_ADD_WiredHeadset,
make_ADD_BtScoHeadset});
}
TEST_F(HashIdentityTest, AudioFormatDescriptionHashIdentity) {
verifyHashIdentity<AudioFormatDescription>({make_AFD_Default, make_AFD_Invalid,
make_AFD_Pcm16Bit, make_AFD_Bitstream,
make_AFD_Encap, make_AFD_Encap_with_Enc});
}
using ChannelLayoutParam = std::tuple<AudioChannelLayout, bool /*isInput*/>;
class AudioChannelLayoutRoundTripTest : public testing::TestWithParam<ChannelLayoutParam> {};
TEST_P(AudioChannelLayoutRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = std::get<0>(GetParam());
const bool isInput = std::get<1>(GetParam());
auto conv = aidl2legacy_AudioChannelLayout_audio_channel_mask_t(initial, isInput);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_audio_channel_mask_t_AudioChannelLayout(conv.value(), isInput);
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
INSTANTIATE_TEST_SUITE_P(
AudioChannelLayoutRoundTrip, AudioChannelLayoutRoundTripTest,
testing::Combine(
testing::Values(AudioChannelLayout{}, make_ACL_Invalid(), make_ACL_Stereo(),
make_ACL_LayoutArbitrary(), make_ACL_ChannelIndex2(),
make_ACL_ChannelIndexArbitrary(),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_FRONT_LEFT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_FRONT_RIGHT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_BACK_CENTER),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_BACK_LEFT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_BACK_RIGHT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_FRONT_CENTER),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_LOW_FREQUENCY),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_TOP_SIDE_LEFT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_TOP_SIDE_RIGHT)),
testing::Values(false, true)));
INSTANTIATE_TEST_SUITE_P(AudioChannelVoiceRoundTrip, AudioChannelLayoutRoundTripTest,
// In legacy constants the voice call is only defined for input.
testing::Combine(testing::Values(make_ACL_VoiceCall()),
testing::Values(true)));
INSTANTIATE_TEST_SUITE_P(
OutAudioChannelLayoutLayoutRoundTrip, AudioChannelLayoutRoundTripTest,
testing::Combine(
testing::Values(AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_FRONT_LEFT_OF_CENTER),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_FRONT_RIGHT_OF_CENTER),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_SIDE_LEFT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_SIDE_RIGHT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_TOP_CENTER),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_TOP_FRONT_LEFT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_TOP_FRONT_CENTER),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_TOP_FRONT_RIGHT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_TOP_BACK_LEFT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_TOP_BACK_CENTER),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_TOP_BACK_RIGHT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_BOTTOM_FRONT_LEFT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_BOTTOM_FRONT_CENTER),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_BOTTOM_FRONT_RIGHT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_LOW_FREQUENCY_2),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_FRONT_WIDE_LEFT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_FRONT_WIDE_RIGHT),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_HAPTIC_A),
AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
AudioChannelLayout::CHANNEL_HAPTIC_B)),
testing::Values(false)));
using ChannelLayoutEdgeCaseParam = std::tuple<int /*legacy*/, bool /*isInput*/, bool /*isValid*/>;
class AudioChannelLayoutEdgeCaseTest : public testing::TestWithParam<ChannelLayoutEdgeCaseParam> {};
TEST_P(AudioChannelLayoutEdgeCaseTest, Legacy2Aidl) {
const audio_channel_mask_t legacy = static_cast<audio_channel_mask_t>(std::get<0>(GetParam()));
const bool isInput = std::get<1>(GetParam());
const bool isValid = std::get<2>(GetParam());
auto conv = legacy2aidl_audio_channel_mask_t_AudioChannelLayout(legacy, isInput);
EXPECT_EQ(isValid, conv.ok());
}
INSTANTIATE_TEST_SUITE_P(
AudioChannelLayoutEdgeCase, AudioChannelLayoutEdgeCaseTest,
testing::Values(
// Valid legacy input masks.
std::make_tuple(AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO, true, true),
std::make_tuple(AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO, true, true),
std::make_tuple(AUDIO_CHANNEL_IN_VOICE_CALL_MONO, true, true),
// Valid legacy output masks.
std::make_tuple(
// This has the same numerical representation as Mask 'A' below
AUDIO_CHANNEL_OUT_FRONT_CENTER | AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT,
false, true),
std::make_tuple(
// This has the same numerical representation as Mask 'B' below
AUDIO_CHANNEL_OUT_FRONT_CENTER | AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
AUDIO_CHANNEL_OUT_TOP_BACK_LEFT,
false, true),
// Invalid legacy input masks.
std::make_tuple(AUDIO_CHANNEL_IN_6, true, false),
std::make_tuple(AUDIO_CHANNEL_IN_6 | AUDIO_CHANNEL_IN_FRONT_PROCESSED, true, false),
std::make_tuple(AUDIO_CHANNEL_IN_PRESSURE | AUDIO_CHANNEL_IN_X_AXIS |
AUDIO_CHANNEL_IN_Y_AXIS | AUDIO_CHANNEL_IN_Z_AXIS,
true, false),
std::make_tuple( // Mask 'A'
AUDIO_CHANNEL_IN_STEREO | AUDIO_CHANNEL_IN_VOICE_UPLINK, true, false),
std::make_tuple( // Mask 'B'
AUDIO_CHANNEL_IN_STEREO | AUDIO_CHANNEL_IN_VOICE_DNLINK, true, false)));
class AudioDeviceDescriptionRoundTripTest : public testing::TestWithParam<AudioDeviceDescription> {
};
TEST_P(AudioDeviceDescriptionRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = GetParam();
auto conv = aidl2legacy_AudioDeviceDescription_audio_devices_t(initial);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_audio_devices_t_AudioDeviceDescription(conv.value());
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
INSTANTIATE_TEST_SUITE_P(AudioDeviceDescriptionRoundTrip, AudioDeviceDescriptionRoundTripTest,
testing::Values(AudioDeviceDescription{}, make_ADD_DefaultIn(),
make_ADD_DefaultOut(), make_ADD_WiredHeadset(),
make_ADD_BtScoHeadset()));
class AudioDeviceRoundTripTest : public testing::TestWithParam<AudioDevice> {};
TEST_P(AudioDeviceRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = GetParam();
audio_devices_t legacyType;
String8 legacyAddress;
status_t status = aidl2legacy_AudioDevice_audio_device(initial, &legacyType, &legacyAddress);
ASSERT_EQ(OK, status);
auto convBack = legacy2aidl_audio_device_AudioDevice(legacyType, legacyAddress);
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
INSTANTIATE_TEST_SUITE_P(
AudioDeviceRoundTrip, AudioDeviceRoundTripTest,
testing::Values(
make_AudioDevice(make_ADD_MicIn(),
AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("bottom")),
make_AudioDevice(make_ADD_RSubmixIn(),
AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("1:2-in-3")),
// The case of a "blueprint" device port for an external device.
make_AudioDevice(make_ADD_BtScoHeadset(),
AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("")),
make_AudioDevice(make_ADD_BtScoHeadset(),
AudioDeviceAddress::make<AudioDeviceAddress::Tag::mac>(
std::vector<uint8_t>{1, 2, 3, 4, 5, 6})),
// Another "blueprint"
make_AudioDevice(make_ADD_BtA2dpHeadphone(),
AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("")),
make_AudioDevice(make_ADD_BtA2dpHeadphone(),
AudioDeviceAddress::make<AudioDeviceAddress::Tag::mac>(
std::vector<uint8_t>{1, 2, 3, 4, 5, 6})),
make_AudioDevice(make_ADD_BtLeHeadset(),
AudioDeviceAddress::make<AudioDeviceAddress::Tag::mac>(
std::vector<uint8_t>{1, 2, 3, 4, 5, 6})),
make_AudioDevice(make_ADD_BtLeBroadcast(),
AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("42")),
make_AudioDevice(make_ADD_IpV4Device(),
AudioDeviceAddress::make<AudioDeviceAddress::Tag::ipv4>(
std::vector<uint8_t>{192, 168, 0, 1})),
make_AudioDevice(make_ADD_UsbHeadset(),
AudioDeviceAddress::make<AudioDeviceAddress::Tag::alsa>(
std::vector<int32_t>{1, 2}))));
class AudioFormatDescriptionRoundTripTest : public testing::TestWithParam<AudioFormatDescription> {
};
TEST_P(AudioFormatDescriptionRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = GetParam();
auto conv = aidl2legacy_AudioFormatDescription_audio_format_t(initial);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_audio_format_t_AudioFormatDescription(conv.value());
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
INSTANTIATE_TEST_SUITE_P(AudioFormatDescriptionRoundTrip, AudioFormatDescriptionRoundTripTest,
testing::Values(make_AFD_Invalid(), AudioFormatDescription{},
make_AFD_Pcm16Bit()));
AudioPortConfigFw createAudioPortConfigFw(const AudioChannelLayout& layout,
const AudioFormatDescription& format,
const AudioDeviceDescription& device) {
const bool isInput = device.type < AudioDeviceType::OUT_DEFAULT;
AudioPortConfigFw result;
result.hal.id = 43;
result.hal.portId = 42;
Int sr44100;
sr44100.value = 44100;
result.hal.sampleRate = sr44100;
result.hal.channelMask = layout;
result.hal.format = format;
AudioGainConfig gain;
gain.mode = 1 << static_cast<int>(AudioGainMode::JOINT);
gain.values = std::vector<int32_t>({100});
result.hal.gain = gain;
AudioPortDeviceExt ext;
AudioDevice audioDevice;
audioDevice.type = device;
ext.device = audioDevice;
result.hal.ext = ext;
result.sys.role = isInput ? AudioPortRole::SOURCE : AudioPortRole::SINK;
result.sys.type = AudioPortType::DEVICE;
AudioPortDeviceExtSys sysDevice;
sysDevice.hwModule = 1;
result.sys.ext = sysDevice;
return result;
}
using AudioPortConfigParam =
std::tuple<AudioChannelLayout, AudioFormatDescription, AudioDeviceDescription>;
class AudioPortConfigRoundTripTest : public testing::TestWithParam<AudioPortConfigParam> {};
TEST_P(AudioPortConfigRoundTripTest, Aidl2Legacy2Aidl) {
const AudioChannelLayout layout = std::get<0>(GetParam());
const AudioFormatDescription format = std::get<1>(GetParam());
const AudioDeviceDescription device = std::get<2>(GetParam());
const bool isInput = device.type < AudioDeviceType::OUT_DEFAULT;
AudioPortConfigFw initial = createAudioPortConfigFw(layout, format, device);
{
audio_port_config conv{};
int32_t portId = -1;
status_t status =
aidl2legacy_AudioPortConfig_audio_port_config(initial.hal, isInput, &conv, &portId);
ASSERT_EQ(OK, status);
EXPECT_NE(-1, portId);
auto convBack = legacy2aidl_audio_port_config_AudioPortConfig(conv, isInput, portId);
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial.hal, convBack.value());
}
{
int32_t portId = -1;
auto conv = aidl2legacy_AudioPortConfigFw_audio_port_config(initial, &portId);
ASSERT_TRUE(conv.ok());
EXPECT_NE(-1, portId);
auto convBack = legacy2aidl_audio_port_config_AudioPortConfigFw(conv.value(), portId);
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
}
INSTANTIATE_TEST_SUITE_P(
AudioPortConfig, AudioPortConfigRoundTripTest,
testing::Combine(testing::Values(make_ACL_Stereo(), make_ACL_ChannelIndex2()),
testing::Values(make_AFD_Pcm16Bit()),
testing::Values(make_ADD_DefaultIn(), make_ADD_DefaultOut(),
make_ADD_WiredHeadset())));
class AudioPortFwRoundTripTest : public testing::TestWithParam<AudioDeviceDescription> {
public:
AudioProfile createProfile(const AudioFormatDescription& format,
const std::vector<AudioChannelLayout>& channelMasks,
const std::vector<int32_t>& sampleRates) {
AudioProfile profile;
profile.format = format;
profile.channelMasks = channelMasks;
profile.sampleRates = sampleRates;
return profile;
}
};
TEST_P(AudioPortFwRoundTripTest, Aidl2Legacy2Aidl) {
const AudioDeviceDescription device = GetParam();
const bool isInput = device.type < AudioDeviceType::OUT_DEFAULT;
AudioPortFw initial;
initial.hal.id = 42;
initial.hal.profiles.push_back(createProfile(
make_AFD_Pcm16Bit(), {make_ACL_Stereo(), make_ACL_ChannelIndex2()}, {44100, 48000}));
if (isInput) {
initial.hal.flags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
} else {
initial.hal.flags = AudioIoFlags::make<AudioIoFlags::Tag::output>(0);
}
AudioGain initialGain;
initialGain.mode = 1 << static_cast<int>(AudioGainMode::JOINT);
initialGain.channelMask = make_ACL_Stereo();
initial.hal.gains.push_back(initialGain);
AudioPortDeviceExt initialExt;
AudioDevice initialDevice;
initialDevice.type = device;
initialExt.device = initialDevice;
initial.hal.ext = initialExt;
{
auto conv = aidl2legacy_AudioPort_audio_port_v7(initial.hal, isInput);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_audio_port_v7_AudioPort(conv.value(), isInput);
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial.hal, convBack.value());
}
initial.sys.role = isInput ? AudioPortRole::SOURCE : AudioPortRole::SINK;
initial.sys.type = AudioPortType::DEVICE;
initial.sys.profiles.resize(initial.hal.profiles.size());
initial.sys.gains.resize(initial.hal.gains.size());
initial.sys.activeConfig =
createAudioPortConfigFw(make_ACL_Stereo(), make_AFD_Pcm16Bit(), device);
initial.sys.activeConfig.hal.flags = initial.hal.flags;
AudioPortDeviceExtSys initialSysDevice;
initialSysDevice.hwModule = 1;
initial.sys.ext = initialSysDevice;
{
auto conv = aidl2legacy_AudioPortFw_audio_port_v7(initial);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_audio_port_v7_AudioPortFw(conv.value());
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
}
INSTANTIATE_TEST_SUITE_P(AudioPortFw, AudioPortFwRoundTripTest,
testing::Values(make_ADD_DefaultIn(), make_ADD_DefaultOut(),
make_ADD_WiredHeadset()));
class AudioDirectModeRoundTripTest : public testing::TestWithParam<AudioDirectMode> {};
TEST_P(AudioDirectModeRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = GetParam();
auto conv = aidl2legacy_AudioDirectMode_audio_direct_mode_t(initial);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_audio_direct_mode_t_AudioDirectMode(conv.value());
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
INSTANTIATE_TEST_SUITE_P(AudioDirectMode, AudioDirectModeRoundTripTest,
testing::Values(AudioDirectMode::NONE, AudioDirectMode::OFFLOAD,
AudioDirectMode::OFFLOAD_GAPLESS,
AudioDirectMode::BITSTREAM));
class AudioStandardRoundTripTest : public testing::TestWithParam<AudioStandard> {};
TEST_P(AudioStandardRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = GetParam();
auto conv = aidl2legacy_AudioStandard_audio_standard_t(initial);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_audio_standard_t_AudioStandard(conv.value());
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
INSTANTIATE_TEST_SUITE_P(AudioStandard, AudioStandardRoundTripTest,
testing::Values(AudioStandard::NONE, AudioStandard::EDID,
AudioStandard::SADB, AudioStandard::VSADB));
class AudioEncapsulationMetadataTypeRoundTripTest
: public testing::TestWithParam<AudioEncapsulationMetadataType> {};
TEST_P(AudioEncapsulationMetadataTypeRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = GetParam();
auto conv =
aidl2legacy_AudioEncapsulationMetadataType_audio_encapsulation_metadata_type_t(initial);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_audio_encapsulation_metadata_type_t_AudioEncapsulationMetadataType(
conv.value());
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
INSTANTIATE_TEST_SUITE_P(AudioEncapsulationMetadataType,
AudioEncapsulationMetadataTypeRoundTripTest,
testing::Values(AudioEncapsulationMetadataType::NONE,
AudioEncapsulationMetadataType::FRAMEWORK_TUNER,
AudioEncapsulationMetadataType::DVB_AD_DESCRIPTOR));
class AudioGainModeRoundTripTest : public testing::TestWithParam<AudioGainMode> {};
TEST_P(AudioGainModeRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = GetParam();
auto conv = aidl2legacy_AudioGainMode_audio_gain_mode_t(initial);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_audio_gain_mode_t_AudioGainMode(conv.value());
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
INSTANTIATE_TEST_SUITE_P(AudioGainMode, AudioGainModeRoundTripTest,
testing::Values(AudioGainMode::JOINT, AudioGainMode::CHANNELS,
AudioGainMode::RAMP));
TEST(AudioTrackSecondaryOutputInfoRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = make_TrackSecondaryOutputInfo();
auto conv = aidl2legacy_TrackSecondaryOutputInfo_TrackSecondaryOutputInfoPair(initial);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_TrackSecondaryOutputInfoPair_TrackSecondaryOutputInfo(conv.value());
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
using ExtraAudioDescriptorParam = std::tuple<AudioStandard, AudioEncapsulationType>;
class ExtraAudioDescriptorRoundTripTest : public testing::TestWithParam<ExtraAudioDescriptorParam> {
};
TEST_P(ExtraAudioDescriptorRoundTripTest, Aidl2Legacy2Aidl) {
ExtraAudioDescriptor initial =
make_ExtraAudioDescriptor(std::get<0>(GetParam()), std::get<1>(GetParam()));
auto conv = aidl2legacy_ExtraAudioDescriptor_audio_extra_audio_descriptor(initial);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_audio_extra_audio_descriptor_ExtraAudioDescriptor(conv.value());
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
INSTANTIATE_TEST_SUITE_P(
ExtraAudioDescriptor, ExtraAudioDescriptorRoundTripTest,
testing::Values(std::make_tuple(AudioStandard::NONE, AudioEncapsulationType::NONE),
std::make_tuple(AudioStandard::EDID, AudioEncapsulationType::NONE),
std::make_tuple(AudioStandard::EDID, AudioEncapsulationType::IEC61937),
std::make_tuple(AudioStandard::SADB, AudioEncapsulationType::NONE),
std::make_tuple(AudioStandard::SADB, AudioEncapsulationType::IEC61937),
std::make_tuple(AudioStandard::VSADB, AudioEncapsulationType::NONE),
std::make_tuple(AudioStandard::VSADB, AudioEncapsulationType::IEC61937)));
TEST(AudioPortSessionExtRoundTripTest, Aidl2Legacy2Aidl) {
const int32_t initial = 7;
auto conv = aidl2legacy_int32_t_audio_port_session_ext(initial);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_audio_port_session_ext_int32_t(conv.value());
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
class AudioGainTest : public testing::TestWithParam<bool> {};
TEST_P(AudioGainTest, Legacy2Aidl2Legacy) {
audio_port_v7 port;
port.num_gains = 2;
port.gains[0] = {.mode = AUDIO_GAIN_MODE_JOINT,
.channel_mask = AUDIO_CHANNEL_IN_STEREO,
.min_value = -3200,
.max_value = 600,
.default_value = 0,
.step_value = 100,
.min_ramp_ms = 10,
.max_ramp_ms = 20};
port.gains[1] = {.mode = AUDIO_GAIN_MODE_JOINT,
.channel_mask = AUDIO_CHANNEL_IN_MONO,
.min_value = -8800,
.max_value = 4000,
.default_value = 0,
.step_value = 100,
.min_ramp_ms = 192,
.max_ramp_ms = 224};
const auto isInput = GetParam();
for (int i = 0; i < port.num_gains; i++) {
auto initial = port.gains[i];
auto conv = legacy2aidl_audio_gain_AudioGain(initial, isInput);
ASSERT_TRUE(conv.ok());
auto convBack = aidl2legacy_AudioGain_audio_gain(conv.value(), isInput);
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial.mode, convBack.value().mode);
EXPECT_EQ(initial.channel_mask, convBack.value().channel_mask);
EXPECT_EQ(initial.min_value, convBack.value().min_value);
EXPECT_EQ(initial.max_value, convBack.value().max_value);
EXPECT_EQ(initial.default_value, convBack.value().default_value);
EXPECT_EQ(initial.step_value, convBack.value().step_value);
EXPECT_EQ(initial.min_ramp_ms, convBack.value().min_ramp_ms);
EXPECT_EQ(initial.max_ramp_ms, convBack.value().max_ramp_ms);
}
}
INSTANTIATE_TEST_SUITE_P(AudioGain, AudioGainTest, testing::Values(true, false));
TEST(AudioMicrophoneInfoFw, Aidl2Legacy2Aidl) {
media::MicrophoneInfoFw initial{};
// HALs must return at least 1 element in channelMapping. The zero value is 'UNUSED'.
initial.dynamic.channelMapping.resize(1);
auto conv = aidl2legacy_MicrophoneInfoFw_audio_microphone_characteristic_t(initial);
ASSERT_TRUE(conv.ok());
auto convBack = legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(conv.value());
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
TEST(AudioMicrophoneInfoFw, UnknownValues) {
{
media::MicrophoneInfoFw initial;
initial.dynamic.channelMapping.resize(1);
initial.info.indexInTheGroup = MicrophoneInfo::INDEX_IN_THE_GROUP_UNKNOWN;
auto conv = aidl2legacy_MicrophoneInfoFw_audio_microphone_characteristic_t(initial);
ASSERT_TRUE(conv.ok());
auto convBack =
legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(conv.value());
ASSERT_TRUE(convBack.ok());
EXPECT_EQ(initial, convBack.value());
}
for (const auto f : {&audio_microphone_characteristic_t::sensitivity,
&audio_microphone_characteristic_t::max_spl,
&audio_microphone_characteristic_t::min_spl}) {
audio_microphone_characteristic_t mic{};
if (f == &audio_microphone_characteristic_t::sensitivity) {
mic.*f = AUDIO_MICROPHONE_SENSITIVITY_UNKNOWN;
} else {
mic.*f = AUDIO_MICROPHONE_SPL_UNKNOWN;
}
auto aidl = legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(mic);
ASSERT_TRUE(aidl.ok());
EXPECT_FALSE(aidl.value().info.sensitivity.has_value());
}
for (const auto f : {&audio_microphone_characteristic_t::geometric_location,
&audio_microphone_characteristic_t::orientation}) {
for (const auto c : {&audio_microphone_coordinate::x, &audio_microphone_coordinate::y,
&audio_microphone_coordinate::z}) {
audio_microphone_characteristic_t mic{};
mic.*f.*c = AUDIO_MICROPHONE_COORDINATE_UNKNOWN;
auto conv = legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(mic);
ASSERT_TRUE(conv.ok());
const auto& aidl = conv.value();
if (f == &audio_microphone_characteristic_t::geometric_location) {
EXPECT_FALSE(aidl.info.position.has_value());
EXPECT_TRUE(aidl.info.orientation.has_value());
} else {
EXPECT_TRUE(aidl.info.position.has_value());
EXPECT_FALSE(aidl.info.orientation.has_value());
}
}
}
}
TEST(AudioMicrophoneInfoFw, ChannelMapping) {
audio_microphone_characteristic_t mic{};
mic.channel_mapping[1] = AUDIO_MICROPHONE_CHANNEL_MAPPING_DIRECT;
mic.channel_mapping[3] = AUDIO_MICROPHONE_CHANNEL_MAPPING_PROCESSED;
auto conv = legacy2aidl_audio_microphone_characteristic_t_MicrophoneInfoFw(mic);
ASSERT_TRUE(conv.ok());
const auto& aidl = conv.value();
EXPECT_EQ(4, aidl.dynamic.channelMapping.size());
EXPECT_EQ(MicrophoneDynamicInfo::ChannelMapping::UNUSED, aidl.dynamic.channelMapping[0]);
EXPECT_EQ(MicrophoneDynamicInfo::ChannelMapping::DIRECT, aidl.dynamic.channelMapping[1]);
EXPECT_EQ(MicrophoneDynamicInfo::ChannelMapping::UNUSED, aidl.dynamic.channelMapping[2]);
EXPECT_EQ(MicrophoneDynamicInfo::ChannelMapping::PROCESSED, aidl.dynamic.channelMapping[3]);
}