blob: 858fa38825e4dbe58a963ba8a81f045b6b9c9ad5 [file] [log] [blame]
/*
* Copyright (C) 2022 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 <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/bluetooth/audio/BnBluetoothAudioPort.h>
#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioPort.h>
#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.h>
#include <android/binder_auto_utils.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <cutils/properties.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdint>
#include <future>
#include <unordered_set>
#include <vector>
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::hardware::bluetooth::audio::AacCapabilities;
using aidl::android::hardware::bluetooth::audio::AacConfiguration;
using aidl::android::hardware::bluetooth::audio::AptxAdaptiveLeCapabilities;
using aidl::android::hardware::bluetooth::audio::AptxAdaptiveLeConfiguration;
using aidl::android::hardware::bluetooth::audio::AptxCapabilities;
using aidl::android::hardware::bluetooth::audio::AptxConfiguration;
using aidl::android::hardware::bluetooth::audio::AudioCapabilities;
using aidl::android::hardware::bluetooth::audio::AudioConfiguration;
using aidl::android::hardware::bluetooth::audio::BnBluetoothAudioPort;
using aidl::android::hardware::bluetooth::audio::BroadcastCapability;
using aidl::android::hardware::bluetooth::audio::ChannelMode;
using aidl::android::hardware::bluetooth::audio::CodecCapabilities;
using aidl::android::hardware::bluetooth::audio::CodecConfiguration;
using aidl::android::hardware::bluetooth::audio::CodecType;
using aidl::android::hardware::bluetooth::audio::IBluetoothAudioPort;
using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider;
using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProviderFactory;
using aidl::android::hardware::bluetooth::audio::LatencyMode;
using aidl::android::hardware::bluetooth::audio::Lc3Capabilities;
using aidl::android::hardware::bluetooth::audio::Lc3Configuration;
using aidl::android::hardware::bluetooth::audio::LdacCapabilities;
using aidl::android::hardware::bluetooth::audio::LdacConfiguration;
using aidl::android::hardware::bluetooth::audio::LeAudioBroadcastConfiguration;
using aidl::android::hardware::bluetooth::audio::
LeAudioCodecCapabilitiesSetting;
using aidl::android::hardware::bluetooth::audio::LeAudioCodecConfiguration;
using aidl::android::hardware::bluetooth::audio::LeAudioConfiguration;
using aidl::android::hardware::bluetooth::audio::OpusCapabilities;
using aidl::android::hardware::bluetooth::audio::OpusConfiguration;
using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
using aidl::android::hardware::bluetooth::audio::PresentationPosition;
using aidl::android::hardware::bluetooth::audio::SbcAllocMethod;
using aidl::android::hardware::bluetooth::audio::SbcCapabilities;
using aidl::android::hardware::bluetooth::audio::SbcChannelMode;
using aidl::android::hardware::bluetooth::audio::SbcConfiguration;
using aidl::android::hardware::bluetooth::audio::SessionType;
using aidl::android::hardware::bluetooth::audio::UnicastCapability;
using aidl::android::hardware::common::fmq::MQDescriptor;
using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
using android::AidlMessageQueue;
using android::ProcessState;
using android::String16;
using ndk::ScopedAStatus;
using ndk::SpAIBinder;
using MqDataType = int8_t;
using MqDataMode = SynchronizedReadWrite;
using DataMQ = AidlMessageQueue<MqDataType, MqDataMode>;
using DataMQDesc = MQDescriptor<MqDataType, MqDataMode>;
// Constants
static constexpr int32_t a2dp_sample_rates[] = {0, 44100, 48000, 88200, 96000};
static constexpr int8_t a2dp_bits_per_samples[] = {0, 16, 24, 32};
static constexpr ChannelMode a2dp_channel_modes[] = {
ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
static std::vector<LatencyMode> latency_modes = {LatencyMode::FREE};
// Helpers
template <typename T>
struct identity {
typedef T type;
};
template <class T>
bool contained_in_vector(const std::vector<T>& vector,
const typename identity<T>::type& target) {
return std::find(vector.begin(), vector.end(), target) != vector.end();
}
void copy_codec_specific(CodecConfiguration::CodecSpecific& dst,
const CodecConfiguration::CodecSpecific& src) {
switch (src.getTag()) {
case CodecConfiguration::CodecSpecific::sbcConfig:
dst.set<CodecConfiguration::CodecSpecific::sbcConfig>(
src.get<CodecConfiguration::CodecSpecific::sbcConfig>());
break;
case CodecConfiguration::CodecSpecific::aacConfig:
dst.set<CodecConfiguration::CodecSpecific::aacConfig>(
src.get<CodecConfiguration::CodecSpecific::aacConfig>());
break;
case CodecConfiguration::CodecSpecific::ldacConfig:
dst.set<CodecConfiguration::CodecSpecific::ldacConfig>(
src.get<CodecConfiguration::CodecSpecific::ldacConfig>());
break;
case CodecConfiguration::CodecSpecific::aptxConfig:
dst.set<CodecConfiguration::CodecSpecific::aptxConfig>(
src.get<CodecConfiguration::CodecSpecific::aptxConfig>());
break;
case CodecConfiguration::CodecSpecific::opusConfig:
dst.set<CodecConfiguration::CodecSpecific::opusConfig>(
src.get<CodecConfiguration::CodecSpecific::opusConfig>());
break;
case CodecConfiguration::CodecSpecific::aptxAdaptiveConfig:
dst.set<CodecConfiguration::CodecSpecific::aptxAdaptiveConfig>(
src.get<CodecConfiguration::CodecSpecific::aptxAdaptiveConfig>());
break;
default:
break;
}
}
class BluetoothAudioPort : public BnBluetoothAudioPort {
public:
BluetoothAudioPort() {}
ndk::ScopedAStatus startStream(bool) { return ScopedAStatus::ok(); }
ndk::ScopedAStatus suspendStream() { return ScopedAStatus::ok(); }
ndk::ScopedAStatus stopStream() { return ScopedAStatus::ok(); }
ndk::ScopedAStatus getPresentationPosition(PresentationPosition*) {
return ScopedAStatus::ok();
}
ndk::ScopedAStatus updateSourceMetadata(const SourceMetadata&) {
return ScopedAStatus::ok();
}
ndk::ScopedAStatus updateSinkMetadata(const SinkMetadata&) {
return ScopedAStatus::ok();
}
ndk::ScopedAStatus setLatencyMode(const LatencyMode) {
return ScopedAStatus::ok();
}
ndk::ScopedAStatus setCodecType(const CodecType) {
return ScopedAStatus::ok();
}
protected:
virtual ~BluetoothAudioPort() = default;
};
class BluetoothAudioProviderFactoryAidl
: public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
provider_factory_ = IBluetoothAudioProviderFactory::fromBinder(
SpAIBinder(AServiceManager_getService(GetParam().c_str())));
audio_provider_ = nullptr;
ASSERT_NE(provider_factory_, nullptr);
}
virtual void TearDown() override { provider_factory_ = nullptr; }
void GetProviderCapabilitiesHelper(const SessionType& session_type) {
temp_provider_capabilities_.clear();
auto aidl_retval = provider_factory_->getProviderCapabilities(
session_type, &temp_provider_capabilities_);
// AIDL calls should not be failed and callback has to be executed
ASSERT_TRUE(aidl_retval.isOk());
switch (session_type) {
case SessionType::UNKNOWN: {
ASSERT_TRUE(temp_provider_capabilities_.empty());
} break;
case SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
case SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
case SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH:
case SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH: {
// All software paths are mandatory and must have exact 1
// "PcmParameters"
ASSERT_EQ(temp_provider_capabilities_.size(), 1);
ASSERT_EQ(temp_provider_capabilities_[0].getTag(),
AudioCapabilities::pcmCapabilities);
} break;
case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH: {
std::unordered_set<CodecType> codec_types;
// empty capability means offload is unsupported
for (auto& audio_capability : temp_provider_capabilities_) {
ASSERT_EQ(audio_capability.getTag(),
AudioCapabilities::a2dpCapabilities);
const auto& codec_capabilities =
audio_capability.get<AudioCapabilities::a2dpCapabilities>();
// Every codec can present once at most
ASSERT_EQ(codec_types.count(codec_capabilities.codecType), 0);
switch (codec_capabilities.codecType) {
case CodecType::SBC:
ASSERT_EQ(codec_capabilities.capabilities.getTag(),
CodecCapabilities::Capabilities::sbcCapabilities);
break;
case CodecType::AAC:
ASSERT_EQ(codec_capabilities.capabilities.getTag(),
CodecCapabilities::Capabilities::aacCapabilities);
break;
case CodecType::APTX:
case CodecType::APTX_HD:
ASSERT_EQ(codec_capabilities.capabilities.getTag(),
CodecCapabilities::Capabilities::aptxCapabilities);
break;
case CodecType::LDAC:
ASSERT_EQ(codec_capabilities.capabilities.getTag(),
CodecCapabilities::Capabilities::ldacCapabilities);
break;
case CodecType::OPUS:
ASSERT_EQ(codec_capabilities.capabilities.getTag(),
CodecCapabilities::Capabilities::opusCapabilities);
break;
case CodecType::APTX_ADAPTIVE:
case CodecType::APTX_ADAPTIVE_LE:
case CodecType::APTX_ADAPTIVE_LEX:
case CodecType::LC3:
case CodecType::VENDOR:
case CodecType::UNKNOWN:
break;
}
codec_types.insert(codec_capabilities.codecType);
}
} break;
case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
case SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH: {
// empty capability means offload is unsupported since capabilities are
// not hardcoded
for (auto audio_capability : temp_provider_capabilities_) {
ASSERT_EQ(audio_capability.getTag(),
AudioCapabilities::leAudioCapabilities);
}
} break;
case SessionType::A2DP_SOFTWARE_DECODING_DATAPATH: {
if (!temp_provider_capabilities_.empty()) {
ASSERT_EQ(temp_provider_capabilities_.size(), 1);
ASSERT_EQ(temp_provider_capabilities_[0].getTag(),
AudioCapabilities::pcmCapabilities);
}
} break;
default: {
ASSERT_TRUE(temp_provider_capabilities_.empty());
}
}
}
/***
* This helps to open the specified provider and check the openProvider()
* has corruct return values. BUT, to keep it simple, it does not consider
* the capability, and please do so at the SetUp of each session's test.
***/
void OpenProviderHelper(const SessionType& session_type) {
auto aidl_retval =
provider_factory_->openProvider(session_type, &audio_provider_);
if (aidl_retval.isOk()) {
ASSERT_NE(session_type, SessionType::UNKNOWN);
ASSERT_NE(audio_provider_, nullptr);
audio_port_ = ndk::SharedRefBase::make<BluetoothAudioPort>();
} else {
// optional session type
ASSERT_TRUE(
session_type == SessionType::UNKNOWN ||
session_type ==
SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
session_type ==
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
session_type ==
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
session_type ==
SessionType::
LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
session_type ==
SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
session_type == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH);
ASSERT_EQ(audio_provider_, nullptr);
}
}
void GetA2dpOffloadCapabilityHelper(const CodecType& codec_type) {
temp_codec_capabilities_ = nullptr;
for (auto& codec_capability : temp_provider_capabilities_) {
auto& a2dp_capabilities =
codec_capability.get<AudioCapabilities::a2dpCapabilities>();
if (a2dp_capabilities.codecType != codec_type) {
continue;
}
temp_codec_capabilities_ = &a2dp_capabilities;
}
}
std::vector<CodecConfiguration::CodecSpecific>
GetSbcCodecSpecificSupportedList(bool supported) {
std::vector<CodecConfiguration::CodecSpecific> sbc_codec_specifics;
if (!supported) {
SbcConfiguration sbc_config{.sampleRateHz = 0, .bitsPerSample = 0};
sbc_codec_specifics.push_back(
CodecConfiguration::CodecSpecific(sbc_config));
return sbc_codec_specifics;
}
GetA2dpOffloadCapabilityHelper(CodecType::SBC);
if (temp_codec_capabilities_ == nullptr ||
temp_codec_capabilities_->codecType != CodecType::SBC) {
return sbc_codec_specifics;
}
// parse the capability
auto& sbc_capability =
temp_codec_capabilities_->capabilities
.get<CodecCapabilities::Capabilities::sbcCapabilities>();
if (sbc_capability.minBitpool > sbc_capability.maxBitpool) {
return sbc_codec_specifics;
}
// combine those parameters into one list of
// CodecConfiguration::CodecSpecific
for (int32_t sample_rate : sbc_capability.sampleRateHz) {
for (int8_t block_length : sbc_capability.blockLength) {
for (int8_t num_subbands : sbc_capability.numSubbands) {
for (int8_t bits_per_sample : sbc_capability.bitsPerSample) {
for (auto channel_mode : sbc_capability.channelMode) {
for (auto alloc_method : sbc_capability.allocMethod) {
SbcConfiguration sbc_data = {
.sampleRateHz = sample_rate,
.channelMode = channel_mode,
.blockLength = block_length,
.numSubbands = num_subbands,
.allocMethod = alloc_method,
.bitsPerSample = bits_per_sample,
.minBitpool = sbc_capability.minBitpool,
.maxBitpool = sbc_capability.maxBitpool};
sbc_codec_specifics.push_back(
CodecConfiguration::CodecSpecific(sbc_data));
}
}
}
}
}
}
return sbc_codec_specifics;
}
std::vector<CodecConfiguration::CodecSpecific>
GetAacCodecSpecificSupportedList(bool supported) {
std::vector<CodecConfiguration::CodecSpecific> aac_codec_specifics;
if (!supported) {
AacConfiguration aac_config{.sampleRateHz = 0, .bitsPerSample = 0};
aac_codec_specifics.push_back(
CodecConfiguration::CodecSpecific(aac_config));
return aac_codec_specifics;
}
GetA2dpOffloadCapabilityHelper(CodecType::AAC);
if (temp_codec_capabilities_ == nullptr ||
temp_codec_capabilities_->codecType != CodecType::AAC) {
return aac_codec_specifics;
}
// parse the capability
auto& aac_capability =
temp_codec_capabilities_->capabilities
.get<CodecCapabilities::Capabilities::aacCapabilities>();
std::vector<bool> variable_bit_rate_enableds = {false};
if (aac_capability.variableBitRateSupported) {
variable_bit_rate_enableds.push_back(true);
}
std::vector<bool> adaptive_bit_rate_supporteds = {false};
if (aac_capability.adaptiveBitRateSupported) {
adaptive_bit_rate_supporteds.push_back(true);
}
// combine those parameters into one list of
// CodecConfiguration::CodecSpecific
for (auto object_type : aac_capability.objectType) {
for (int32_t sample_rate : aac_capability.sampleRateHz) {
for (auto channel_mode : aac_capability.channelMode) {
for (int8_t bits_per_sample : aac_capability.bitsPerSample) {
for (auto variable_bit_rate_enabled : variable_bit_rate_enableds) {
for (auto adaptive_bit_rate_supported :
adaptive_bit_rate_supporteds) {
AacConfiguration aac_data{
.objectType = object_type,
.sampleRateHz = sample_rate,
.channelMode = channel_mode,
.variableBitRateEnabled = variable_bit_rate_enabled,
.bitsPerSample = bits_per_sample,
.adaptiveBitRateSupported = adaptive_bit_rate_supported};
aac_codec_specifics.push_back(
CodecConfiguration::CodecSpecific(aac_data));
}
}
}
}
}
}
return aac_codec_specifics;
}
std::vector<CodecConfiguration::CodecSpecific>
GetLdacCodecSpecificSupportedList(bool supported) {
std::vector<CodecConfiguration::CodecSpecific> ldac_codec_specifics;
if (!supported) {
LdacConfiguration ldac_config{.sampleRateHz = 0, .bitsPerSample = 0};
ldac_codec_specifics.push_back(
CodecConfiguration::CodecSpecific(ldac_config));
return ldac_codec_specifics;
}
GetA2dpOffloadCapabilityHelper(CodecType::LDAC);
if (temp_codec_capabilities_ == nullptr ||
temp_codec_capabilities_->codecType != CodecType::LDAC) {
return ldac_codec_specifics;
}
// parse the capability
auto& ldac_capability =
temp_codec_capabilities_->capabilities
.get<CodecCapabilities::Capabilities::ldacCapabilities>();
// combine those parameters into one list of
// CodecConfiguration::CodecSpecific
for (int32_t sample_rate : ldac_capability.sampleRateHz) {
for (int8_t bits_per_sample : ldac_capability.bitsPerSample) {
for (auto channel_mode : ldac_capability.channelMode) {
for (auto quality_index : ldac_capability.qualityIndex) {
LdacConfiguration ldac_data{.sampleRateHz = sample_rate,
.channelMode = channel_mode,
.qualityIndex = quality_index,
.bitsPerSample = bits_per_sample};
ldac_codec_specifics.push_back(
CodecConfiguration::CodecSpecific(ldac_data));
}
}
}
}
return ldac_codec_specifics;
}
std::vector<CodecConfiguration::CodecSpecific>
GetAptxCodecSpecificSupportedList(bool is_hd, bool supported) {
std::vector<CodecConfiguration::CodecSpecific> aptx_codec_specifics;
if (!supported) {
AptxConfiguration aptx_config{.sampleRateHz = 0, .bitsPerSample = 0};
aptx_codec_specifics.push_back(
CodecConfiguration::CodecSpecific(aptx_config));
return aptx_codec_specifics;
}
GetA2dpOffloadCapabilityHelper(
(is_hd ? CodecType::APTX_HD : CodecType::APTX));
if (temp_codec_capabilities_ == nullptr) {
return aptx_codec_specifics;
}
if ((is_hd && temp_codec_capabilities_->codecType != CodecType::APTX_HD) ||
(!is_hd && temp_codec_capabilities_->codecType != CodecType::APTX)) {
return aptx_codec_specifics;
}
// parse the capability
auto& aptx_capability =
temp_codec_capabilities_->capabilities
.get<CodecCapabilities::Capabilities::aptxCapabilities>();
// combine those parameters into one list of
// CodecConfiguration::CodecSpecific
for (int8_t bits_per_sample : aptx_capability.bitsPerSample) {
for (int32_t sample_rate : aptx_capability.sampleRateHz) {
for (auto channel_mode : aptx_capability.channelMode) {
AptxConfiguration aptx_data{.sampleRateHz = sample_rate,
.channelMode = channel_mode,
.bitsPerSample = bits_per_sample};
aptx_codec_specifics.push_back(
CodecConfiguration::CodecSpecific(aptx_data));
}
}
}
return aptx_codec_specifics;
}
std::vector<CodecConfiguration::CodecSpecific>
GetOpusCodecSpecificSupportedList(bool supported) {
std::vector<CodecConfiguration::CodecSpecific> opus_codec_specifics;
if (!supported) {
OpusConfiguration opus_config{.samplingFrequencyHz = 0,
.frameDurationUs = 0};
opus_codec_specifics.push_back(
CodecConfiguration::CodecSpecific(opus_config));
return opus_codec_specifics;
}
GetA2dpOffloadCapabilityHelper(CodecType::OPUS);
if (temp_codec_capabilities_ == nullptr ||
temp_codec_capabilities_->codecType != CodecType::OPUS) {
return opus_codec_specifics;
}
// parse the capability
auto& opus_capability =
temp_codec_capabilities_->capabilities
.get<CodecCapabilities::Capabilities::opusCapabilities>();
// combine those parameters into one list of
// CodecConfiguration::CodecSpecific
for (int32_t samplingFrequencyHz : opus_capability->samplingFrequencyHz) {
for (int32_t frameDurationUs : opus_capability->frameDurationUs) {
for (auto channel_mode : opus_capability->channelMode) {
OpusConfiguration opus_data{
.samplingFrequencyHz = samplingFrequencyHz,
.frameDurationUs = frameDurationUs,
.channelMode = channel_mode,
};
opus_codec_specifics.push_back(
CodecConfiguration::CodecSpecific(opus_data));
}
}
}
return opus_codec_specifics;
}
bool IsPcmConfigSupported(const PcmConfiguration& pcm_config) {
if (temp_provider_capabilities_.size() != 1 ||
temp_provider_capabilities_[0].getTag() !=
AudioCapabilities::pcmCapabilities) {
return false;
}
auto pcm_capability = temp_provider_capabilities_[0]
.get<AudioCapabilities::pcmCapabilities>();
return (contained_in_vector(pcm_capability.channelMode,
pcm_config.channelMode) &&
contained_in_vector(pcm_capability.sampleRateHz,
pcm_config.sampleRateHz) &&
contained_in_vector(pcm_capability.bitsPerSample,
pcm_config.bitsPerSample));
}
std::shared_ptr<IBluetoothAudioProviderFactory> provider_factory_;
std::shared_ptr<IBluetoothAudioProvider> audio_provider_;
std::shared_ptr<IBluetoothAudioPort> audio_port_;
std::vector<AudioCapabilities> temp_provider_capabilities_;
// temp storage saves the specified codec capability by
// GetOffloadCodecCapabilityHelper()
CodecCapabilities* temp_codec_capabilities_;
static constexpr SessionType kSessionTypes[] = {
SessionType::UNKNOWN,
SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH,
SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH,
SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
SessionType::A2DP_SOFTWARE_DECODING_DATAPATH,
SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
};
};
/**
* Test whether we can get the FactoryService from HIDL
*/
TEST_P(BluetoothAudioProviderFactoryAidl, GetProviderFactoryService) {}
/**
* Test whether we can open a provider for each provider returned by
* getProviderCapabilities() with non-empty capabalities
*/
TEST_P(BluetoothAudioProviderFactoryAidl,
OpenProviderAndCheckCapabilitiesBySession) {
for (auto session_type : kSessionTypes) {
GetProviderCapabilitiesHelper(session_type);
OpenProviderHelper(session_type);
// We must be able to open a provider if its getProviderCapabilities()
// returns non-empty list.
EXPECT_TRUE(temp_provider_capabilities_.empty() ||
audio_provider_ != nullptr);
}
}
/**
* openProvider A2DP_SOFTWARE_ENCODING_DATAPATH
*/
class BluetoothAudioProviderA2dpEncodingSoftwareAidl
: public BluetoothAudioProviderFactoryAidl {
public:
virtual void SetUp() override {
BluetoothAudioProviderFactoryAidl::SetUp();
GetProviderCapabilitiesHelper(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH);
OpenProviderHelper(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH);
ASSERT_NE(audio_provider_, nullptr);
}
virtual void TearDown() override {
audio_port_ = nullptr;
audio_provider_ = nullptr;
BluetoothAudioProviderFactoryAidl::TearDown();
}
};
/**
* Test whether we can open a provider of type
*/
TEST_P(BluetoothAudioProviderA2dpEncodingSoftwareAidl,
OpenA2dpEncodingSoftwareProvider) {}
/**
* Test whether each provider of type
* SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with
* different PCM config
*/
TEST_P(BluetoothAudioProviderA2dpEncodingSoftwareAidl,
StartAndEndA2dpEncodingSoftwareSessionWithPossiblePcmConfig) {
for (auto sample_rate : a2dp_sample_rates) {
for (auto bits_per_sample : a2dp_bits_per_samples) {
for (auto channel_mode : a2dp_channel_modes) {
PcmConfiguration pcm_config{
.sampleRateHz = sample_rate,
.channelMode = channel_mode,
.bitsPerSample = bits_per_sample,
};
bool is_codec_config_valid = IsPcmConfigSupported(pcm_config);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(pcm_config), latency_modes,
&mq_desc);
DataMQ data_mq(mq_desc);
EXPECT_EQ(aidl_retval.isOk(), is_codec_config_valid);
if (is_codec_config_valid) {
EXPECT_TRUE(data_mq.isValid());
}
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
}
/**
* openProvider A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH
*/
class BluetoothAudioProviderA2dpEncodingHardwareAidl
: public BluetoothAudioProviderFactoryAidl {
public:
virtual void SetUp() override {
BluetoothAudioProviderFactoryAidl::SetUp();
GetProviderCapabilitiesHelper(
SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
OpenProviderHelper(SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
ASSERT_TRUE(temp_provider_capabilities_.empty() ||
audio_provider_ != nullptr);
}
virtual void TearDown() override {
audio_port_ = nullptr;
audio_provider_ = nullptr;
BluetoothAudioProviderFactoryAidl::TearDown();
}
bool IsOffloadSupported() { return (temp_provider_capabilities_.size() > 0); }
};
/**
* Test whether we can open a provider of type
*/
TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
OpenA2dpEncodingHardwareProvider) {}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
* SBC hardware encoding config
*/
TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
StartAndEndA2dpSbcEncodingHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
CodecConfiguration codec_config = {
.codecType = CodecType::SBC,
.encodedAudioBitrate = 328000,
.peerMtu = 1005,
.isScmstEnabled = false,
};
auto sbc_codec_specifics = GetSbcCodecSpecificSupportedList(true);
for (auto& codec_specific : sbc_codec_specifics) {
copy_codec_specific(codec_config.config, codec_specific);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(codec_config), latency_modes, &mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
* AAC hardware encoding config
*/
TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
StartAndEndA2dpAacEncodingHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
CodecConfiguration codec_config = {
.codecType = CodecType::AAC,
.encodedAudioBitrate = 320000,
.peerMtu = 1005,
.isScmstEnabled = false,
};
auto aac_codec_specifics = GetAacCodecSpecificSupportedList(true);
for (auto& codec_specific : aac_codec_specifics) {
copy_codec_specific(codec_config.config, codec_specific);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(codec_config), latency_modes, &mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
* LDAC hardware encoding config
*/
TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
StartAndEndA2dpLdacEncodingHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
CodecConfiguration codec_config = {
.codecType = CodecType::LDAC,
.encodedAudioBitrate = 990000,
.peerMtu = 1005,
.isScmstEnabled = false,
};
auto ldac_codec_specifics = GetLdacCodecSpecificSupportedList(true);
for (auto& codec_specific : ldac_codec_specifics) {
copy_codec_specific(codec_config.config, codec_specific);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(codec_config), latency_modes, &mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
* Opus hardware encoding config
*/
TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
StartAndEndA2dpOpusEncodingHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
CodecConfiguration codec_config = {
.codecType = CodecType::OPUS,
.encodedAudioBitrate = 990000,
.peerMtu = 1005,
.isScmstEnabled = false,
};
auto opus_codec_specifics = GetOpusCodecSpecificSupportedList(true);
for (auto& codec_specific : opus_codec_specifics) {
copy_codec_specific(codec_config.config, codec_specific);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(codec_config), latency_modes, &mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
* AptX hardware encoding config
*/
TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
StartAndEndA2dpAptxEncodingHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
for (auto codec_type : {CodecType::APTX, CodecType::APTX_HD}) {
CodecConfiguration codec_config = {
.codecType = codec_type,
.encodedAudioBitrate =
(codec_type == CodecType::APTX ? 352000 : 576000),
.peerMtu = 1005,
.isScmstEnabled = false,
};
auto aptx_codec_specifics = GetAptxCodecSpecificSupportedList(
(codec_type == CodecType::APTX_HD ? true : false), true);
for (auto& codec_specific : aptx_codec_specifics) {
copy_codec_specific(codec_config.config, codec_specific);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(codec_config), latency_modes,
&mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
* an invalid codec config
*/
TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
StartAndEndA2dpEncodingHardwareSessionInvalidCodecConfig) {
if (!IsOffloadSupported()) {
return;
}
ASSERT_NE(audio_provider_, nullptr);
std::vector<CodecConfiguration::CodecSpecific> codec_specifics;
for (auto codec_type : ndk::enum_range<CodecType>()) {
switch (codec_type) {
case CodecType::SBC:
codec_specifics = GetSbcCodecSpecificSupportedList(false);
break;
case CodecType::AAC:
codec_specifics = GetAacCodecSpecificSupportedList(false);
break;
case CodecType::LDAC:
codec_specifics = GetLdacCodecSpecificSupportedList(false);
break;
case CodecType::APTX:
codec_specifics = GetAptxCodecSpecificSupportedList(false, false);
break;
case CodecType::APTX_HD:
codec_specifics = GetAptxCodecSpecificSupportedList(true, false);
break;
case CodecType::OPUS:
codec_specifics = GetOpusCodecSpecificSupportedList(false);
continue;
case CodecType::APTX_ADAPTIVE:
case CodecType::APTX_ADAPTIVE_LE:
case CodecType::APTX_ADAPTIVE_LEX:
case CodecType::LC3:
case CodecType::VENDOR:
case CodecType::UNKNOWN:
codec_specifics.clear();
break;
}
if (codec_specifics.empty()) {
continue;
}
CodecConfiguration codec_config = {
.codecType = codec_type,
.encodedAudioBitrate = 328000,
.peerMtu = 1005,
.isScmstEnabled = false,
};
for (auto codec_specific : codec_specifics) {
copy_codec_specific(codec_config.config, codec_specific);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(codec_config), latency_modes,
&mq_desc);
// AIDL call should fail on invalid codec
ASSERT_FALSE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
/**
* openProvider HEARING_AID_SOFTWARE_ENCODING_DATAPATH
*/
class BluetoothAudioProviderHearingAidSoftwareAidl
: public BluetoothAudioProviderFactoryAidl {
public:
virtual void SetUp() override {
BluetoothAudioProviderFactoryAidl::SetUp();
GetProviderCapabilitiesHelper(
SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
OpenProviderHelper(SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
ASSERT_NE(audio_provider_, nullptr);
}
virtual void TearDown() override {
audio_port_ = nullptr;
audio_provider_ = nullptr;
BluetoothAudioProviderFactoryAidl::TearDown();
}
static constexpr int32_t hearing_aid_sample_rates_[] = {0, 16000, 24000};
static constexpr int8_t hearing_aid_bits_per_samples_[] = {0, 16, 24};
static constexpr ChannelMode hearing_aid_channel_modes_[] = {
ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
};
/**
* Test whether we can open a provider of type
*/
TEST_P(BluetoothAudioProviderHearingAidSoftwareAidl,
OpenHearingAidSoftwareProvider) {}
/**
* Test whether each provider of type
* SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH can be started and
* stopped with different PCM config
*/
TEST_P(BluetoothAudioProviderHearingAidSoftwareAidl,
StartAndEndHearingAidSessionWithPossiblePcmConfig) {
for (int32_t sample_rate : hearing_aid_sample_rates_) {
for (int8_t bits_per_sample : hearing_aid_bits_per_samples_) {
for (auto channel_mode : hearing_aid_channel_modes_) {
PcmConfiguration pcm_config{
.sampleRateHz = sample_rate,
.channelMode = channel_mode,
.bitsPerSample = bits_per_sample,
};
bool is_codec_config_valid = IsPcmConfigSupported(pcm_config);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(pcm_config), latency_modes,
&mq_desc);
DataMQ data_mq(mq_desc);
EXPECT_EQ(aidl_retval.isOk(), is_codec_config_valid);
if (is_codec_config_valid) {
EXPECT_TRUE(data_mq.isValid());
}
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
}
/**
* openProvider LE_AUDIO_SOFTWARE_ENCODING_DATAPATH
*/
class BluetoothAudioProviderLeAudioOutputSoftwareAidl
: public BluetoothAudioProviderFactoryAidl {
public:
virtual void SetUp() override {
BluetoothAudioProviderFactoryAidl::SetUp();
GetProviderCapabilitiesHelper(
SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH);
OpenProviderHelper(SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH);
ASSERT_NE(audio_provider_, nullptr);
}
virtual void TearDown() override {
audio_port_ = nullptr;
audio_provider_ = nullptr;
BluetoothAudioProviderFactoryAidl::TearDown();
}
static constexpr int32_t le_audio_output_sample_rates_[] = {
0, 8000, 16000, 24000, 32000, 44100, 48000,
};
static constexpr int8_t le_audio_output_bits_per_samples_[] = {0, 16, 24};
static constexpr ChannelMode le_audio_output_channel_modes_[] = {
ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
static constexpr int32_t le_audio_output_data_interval_us_[] = {
0 /* Invalid */, 10000 /* Valid 10ms */};
};
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH can be started and
* stopped
*/
TEST_P(BluetoothAudioProviderLeAudioOutputSoftwareAidl,
OpenLeAudioOutputSoftwareProvider) {}
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH can be started and
* stopped with different PCM config
*/
TEST_P(BluetoothAudioProviderLeAudioOutputSoftwareAidl,
StartAndEndLeAudioOutputSessionWithPossiblePcmConfig) {
for (auto sample_rate : le_audio_output_sample_rates_) {
for (auto bits_per_sample : le_audio_output_bits_per_samples_) {
for (auto channel_mode : le_audio_output_channel_modes_) {
for (auto data_interval_us : le_audio_output_data_interval_us_) {
PcmConfiguration pcm_config{
.sampleRateHz = sample_rate,
.channelMode = channel_mode,
.bitsPerSample = bits_per_sample,
.dataIntervalUs = data_interval_us,
};
bool is_codec_config_valid =
IsPcmConfigSupported(pcm_config) && pcm_config.dataIntervalUs > 0;
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(pcm_config), latency_modes,
&mq_desc);
DataMQ data_mq(mq_desc);
EXPECT_EQ(aidl_retval.isOk(), is_codec_config_valid);
if (is_codec_config_valid) {
EXPECT_TRUE(data_mq.isValid());
}
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
}
}
/**
* openProvider LE_AUDIO_SOFTWARE_DECODING_DATAPATH
*/
class BluetoothAudioProviderLeAudioInputSoftwareAidl
: public BluetoothAudioProviderFactoryAidl {
public:
virtual void SetUp() override {
BluetoothAudioProviderFactoryAidl::SetUp();
GetProviderCapabilitiesHelper(
SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH);
OpenProviderHelper(SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH);
ASSERT_NE(audio_provider_, nullptr);
}
virtual void TearDown() override {
audio_port_ = nullptr;
audio_provider_ = nullptr;
BluetoothAudioProviderFactoryAidl::TearDown();
}
static constexpr int32_t le_audio_input_sample_rates_[] = {
0, 8000, 16000, 24000, 32000, 44100, 48000};
static constexpr int8_t le_audio_input_bits_per_samples_[] = {0, 16, 24};
static constexpr ChannelMode le_audio_input_channel_modes_[] = {
ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
static constexpr int32_t le_audio_input_data_interval_us_[] = {
0 /* Invalid */, 10000 /* Valid 10ms */};
};
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH can be started and
* stopped
*/
TEST_P(BluetoothAudioProviderLeAudioInputSoftwareAidl,
OpenLeAudioInputSoftwareProvider) {}
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH can be started and
* stopped with different PCM config
*/
TEST_P(BluetoothAudioProviderLeAudioInputSoftwareAidl,
StartAndEndLeAudioInputSessionWithPossiblePcmConfig) {
for (auto sample_rate : le_audio_input_sample_rates_) {
for (auto bits_per_sample : le_audio_input_bits_per_samples_) {
for (auto channel_mode : le_audio_input_channel_modes_) {
for (auto data_interval_us : le_audio_input_data_interval_us_) {
PcmConfiguration pcm_config{
.sampleRateHz = sample_rate,
.channelMode = channel_mode,
.bitsPerSample = bits_per_sample,
.dataIntervalUs = data_interval_us,
};
bool is_codec_config_valid =
IsPcmConfigSupported(pcm_config) && pcm_config.dataIntervalUs > 0;
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(pcm_config), latency_modes,
&mq_desc);
DataMQ data_mq(mq_desc);
EXPECT_EQ(aidl_retval.isOk(), is_codec_config_valid);
if (is_codec_config_valid) {
EXPECT_TRUE(data_mq.isValid());
}
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
}
}
/**
* openProvider LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH
*/
class BluetoothAudioProviderLeAudioOutputHardwareAidl
: public BluetoothAudioProviderFactoryAidl {
public:
virtual void SetUp() override {
BluetoothAudioProviderFactoryAidl::SetUp();
GetProviderCapabilitiesHelper(
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
OpenProviderHelper(
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
ASSERT_TRUE(temp_provider_capabilities_.empty() ||
audio_provider_ != nullptr);
}
virtual void TearDown() override {
audio_port_ = nullptr;
audio_provider_ = nullptr;
BluetoothAudioProviderFactoryAidl::TearDown();
}
bool IsOffloadOutputSupported() {
for (auto& capability : temp_provider_capabilities_) {
if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
continue;
}
auto& le_audio_capability =
capability.get<AudioCapabilities::leAudioCapabilities>();
if (le_audio_capability.unicastEncodeCapability.codecType !=
CodecType::UNKNOWN)
return true;
}
return false;
}
std::vector<Lc3Configuration> GetUnicastLc3SupportedList(bool decoding,
bool supported) {
std::vector<Lc3Configuration> le_audio_codec_configs;
if (!supported) {
Lc3Configuration lc3_config{.pcmBitDepth = 0, .samplingFrequencyHz = 0};
le_audio_codec_configs.push_back(lc3_config);
return le_audio_codec_configs;
}
// There might be more than one LeAudioCodecCapabilitiesSetting
std::vector<Lc3Capabilities> lc3_capabilities;
for (auto& capability : temp_provider_capabilities_) {
if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
continue;
}
auto& le_audio_capability =
capability.get<AudioCapabilities::leAudioCapabilities>();
auto& unicast_capability =
decoding ? le_audio_capability.unicastDecodeCapability
: le_audio_capability.unicastEncodeCapability;
if (unicast_capability.codecType != CodecType::LC3) {
continue;
}
auto& lc3_capability = unicast_capability.leAudioCodecCapabilities.get<
UnicastCapability::LeAudioCodecCapabilities::lc3Capabilities>();
lc3_capabilities.push_back(lc3_capability);
}
// Combine those parameters into one list of LeAudioCodecConfiguration
// This seems horrible, but usually each Lc3Capability only contains a
// single Lc3Configuration, which means every array has a length of 1.
for (auto& lc3_capability : lc3_capabilities) {
for (int32_t samplingFrequencyHz : lc3_capability.samplingFrequencyHz) {
for (int32_t frameDurationUs : lc3_capability.frameDurationUs) {
for (int32_t octetsPerFrame : lc3_capability.octetsPerFrame) {
Lc3Configuration lc3_config = {
.samplingFrequencyHz = samplingFrequencyHz,
.frameDurationUs = frameDurationUs,
.octetsPerFrame = octetsPerFrame,
};
le_audio_codec_configs.push_back(lc3_config);
}
}
}
}
return le_audio_codec_configs;
}
static constexpr int32_t apx_adaptive_le_config_codec_modes[] = {0, 1, 2, 3};
std::vector<AptxAdaptiveLeConfiguration>
GetUnicastAptxAdaptiveLeSupportedList(bool decoding, bool supported,
bool is_le_extended) {
std::vector<AptxAdaptiveLeConfiguration> le_audio_codec_configs;
if (!supported) {
AptxAdaptiveLeConfiguration aptx_adaptive_le_config{
.pcmBitDepth = 0, .samplingFrequencyHz = 0};
le_audio_codec_configs.push_back(aptx_adaptive_le_config);
return le_audio_codec_configs;
}
// There might be more than one LeAudioCodecCapabilitiesSetting
std::vector<AptxAdaptiveLeCapabilities> aptx_adaptive_le_capabilities;
for (auto& capability : temp_provider_capabilities_) {
if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
continue;
}
auto& le_audio_capability =
capability.get<AudioCapabilities::leAudioCapabilities>();
auto& unicast_capability =
decoding ? le_audio_capability.unicastDecodeCapability
: le_audio_capability.unicastEncodeCapability;
if ((!is_le_extended &&
unicast_capability.codecType != CodecType::APTX_ADAPTIVE_LE) ||
(is_le_extended &&
unicast_capability.codecType != CodecType::APTX_ADAPTIVE_LEX)) {
continue;
}
auto& aptx_adaptive_le_capability =
unicast_capability.leAudioCodecCapabilities
.get<UnicastCapability::LeAudioCodecCapabilities::
aptxAdaptiveLeCapabilities>();
aptx_adaptive_le_capabilities.push_back(aptx_adaptive_le_capability);
}
for (auto& aptx_adaptive_le_capability : aptx_adaptive_le_capabilities) {
for (int32_t samplingFrequencyHz :
aptx_adaptive_le_capability.samplingFrequencyHz) {
for (int32_t frameDurationUs :
aptx_adaptive_le_capability.frameDurationUs) {
for (int32_t octetsPerFrame :
aptx_adaptive_le_capability.octetsPerFrame) {
for (int8_t blocksPerSdu :
aptx_adaptive_le_capability.blocksPerSdu) {
for (int32_t codecMode : apx_adaptive_le_config_codec_modes) {
AptxAdaptiveLeConfiguration aptx_adaptive_le_config = {
.samplingFrequencyHz = samplingFrequencyHz,
.frameDurationUs = frameDurationUs,
.octetsPerFrame = octetsPerFrame,
.blocksPerSdu = blocksPerSdu,
.codecMode = codecMode,
};
le_audio_codec_configs.push_back(aptx_adaptive_le_config);
}
}
}
}
}
}
return le_audio_codec_configs;
}
LeAudioCodecCapabilitiesSetting temp_le_audio_capabilities_;
};
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
* stopped
*/
TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
OpenLeAudioOutputHardwareProvider) {}
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
* stopped with Unicast hardware encoding config
*/
TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
StartAndEndLeAudioOutputSessionWithPossibleUnicastConfig) {
if (!IsOffloadOutputSupported()) {
return;
}
auto lc3_codec_configs =
GetUnicastLc3SupportedList(false /* decoding */, true /* supported */);
LeAudioConfiguration le_audio_config = {
.codecType = CodecType::LC3,
.peerDelayUs = 0,
};
for (auto& lc3_config : lc3_codec_configs) {
le_audio_config.leAudioCodecConfig
.set<LeAudioCodecConfiguration::lc3Config>(lc3_config);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(le_audio_config), latency_modes,
&mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
* stopped with Unicast hardware encoding config
*
* Disabled since offload codec checking is not ready
*/
TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
DISABLED_StartAndEndLeAudioOutputSessionWithInvalidAudioConfiguration) {
if (!IsOffloadOutputSupported()) {
return;
}
auto lc3_codec_configs =
GetUnicastLc3SupportedList(false /* decoding */, false /* supported */);
LeAudioConfiguration le_audio_config = {
.codecType = CodecType::LC3,
.peerDelayUs = 0,
};
for (auto& lc3_config : lc3_codec_configs) {
le_audio_config.leAudioCodecConfig
.set<LeAudioCodecConfiguration::lc3Config>(lc3_config);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(le_audio_config), latency_modes,
&mq_desc);
// AIDL call should fail on invalid codec
ASSERT_FALSE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
static std::vector<uint8_t> vendorMetadata = {0x0B, // Length
0xFF, // Type: Vendor-specific
0x0A, 0x00, // Company_ID
0x01, 0x02, 0x03, 0x04, // Data
0x05, 0x06, 0x07, 0x08};
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
* stopped with Unicast hardware encoding config
*/
TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
StartAndEndLeAudioOutputSessionWithAptxAdaptiveLeUnicastConfig) {
if (!IsOffloadOutputSupported()) {
return;
}
for (auto codec_type :
{CodecType::APTX_ADAPTIVE_LE, CodecType::APTX_ADAPTIVE_LEX}) {
bool is_le_extended = (codec_type == CodecType::APTX_ADAPTIVE_LEX);
auto aptx_adaptive_le_codec_configs =
GetUnicastAptxAdaptiveLeSupportedList(false, true, is_le_extended);
LeAudioConfiguration le_audio_config = {
.codecType = codec_type,
.peerDelayUs = 0,
.vendorSpecificMetadata = vendorMetadata,
};
for (auto& aptx_adaptive_le_config : aptx_adaptive_le_codec_configs) {
le_audio_config.leAudioCodecConfig
.set<LeAudioCodecConfiguration::aptxAdaptiveLeConfig>(
aptx_adaptive_le_config);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(le_audio_config), latency_modes,
&mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
* stopped with Unicast hardware encoding config
*/
TEST_P(
BluetoothAudioProviderLeAudioOutputHardwareAidl,
BluetoothAudioProviderLeAudioOutputHardwareAidl_StartAndEndLeAudioOutputSessionWithInvalidAptxAdaptiveLeAudioConfiguration) {
if (!IsOffloadOutputSupported()) {
return;
}
for (auto codec_type :
{CodecType::APTX_ADAPTIVE_LE, CodecType::APTX_ADAPTIVE_LEX}) {
bool is_le_extended = (codec_type == CodecType::APTX_ADAPTIVE_LEX);
auto aptx_adaptive_le_codec_configs =
GetUnicastAptxAdaptiveLeSupportedList(false, true, is_le_extended);
LeAudioConfiguration le_audio_config = {
.codecType = codec_type,
.peerDelayUs = 0,
.vendorSpecificMetadata = vendorMetadata,
};
for (auto& aptx_adaptive_le_config : aptx_adaptive_le_codec_configs) {
le_audio_config.leAudioCodecConfig
.set<LeAudioCodecConfiguration::aptxAdaptiveLeConfig>(
aptx_adaptive_le_config);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(le_audio_config), latency_modes,
&mq_desc);
// AIDL call should fail on invalid codec
ASSERT_FALSE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
/**
* openProvider LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH
*/
class BluetoothAudioProviderLeAudioInputHardwareAidl
: public BluetoothAudioProviderLeAudioOutputHardwareAidl {
public:
virtual void SetUp() override {
BluetoothAudioProviderFactoryAidl::SetUp();
GetProviderCapabilitiesHelper(
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
OpenProviderHelper(
SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
ASSERT_TRUE(temp_provider_capabilities_.empty() ||
audio_provider_ != nullptr);
}
bool IsOffloadInputSupported() {
for (auto& capability : temp_provider_capabilities_) {
if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
continue;
}
auto& le_audio_capability =
capability.get<AudioCapabilities::leAudioCapabilities>();
if (le_audio_capability.unicastDecodeCapability.codecType !=
CodecType::UNKNOWN)
return true;
}
return false;
}
virtual void TearDown() override {
audio_port_ = nullptr;
audio_provider_ = nullptr;
BluetoothAudioProviderFactoryAidl::TearDown();
}
};
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
* stopped
*/
TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
OpenLeAudioInputHardwareProvider) {}
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
* stopped with Unicast hardware encoding config
*/
TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
StartAndEndLeAudioInputSessionWithPossibleUnicastConfig) {
if (!IsOffloadInputSupported()) {
return;
}
auto lc3_codec_configs =
GetUnicastLc3SupportedList(true /* decoding */, true /* supported */);
LeAudioConfiguration le_audio_config = {
.codecType = CodecType::LC3,
.peerDelayUs = 0,
};
for (auto& lc3_config : lc3_codec_configs) {
le_audio_config.leAudioCodecConfig
.set<LeAudioCodecConfiguration::lc3Config>(lc3_config);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(le_audio_config), latency_modes,
&mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
* stopped with Unicast hardware encoding config
*
* Disabled since offload codec checking is not ready
*/
TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
DISABLED_StartAndEndLeAudioInputSessionWithInvalidAudioConfiguration) {
if (!IsOffloadInputSupported()) {
return;
}
auto lc3_codec_configs =
GetUnicastLc3SupportedList(true /* decoding */, false /* supported */);
LeAudioConfiguration le_audio_config = {
.codecType = CodecType::LC3,
.peerDelayUs = 0,
};
for (auto& lc3_config : lc3_codec_configs) {
le_audio_config.leAudioCodecConfig
.set<LeAudioCodecConfiguration::lc3Config>(lc3_config);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(le_audio_config), latency_modes,
&mq_desc);
// AIDL call should fail on invalid codec
ASSERT_FALSE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* openProvider LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH
*/
class BluetoothAudioProviderLeAudioBroadcastSoftwareAidl
: public BluetoothAudioProviderFactoryAidl {
public:
virtual void SetUp() override {
BluetoothAudioProviderFactoryAidl::SetUp();
GetProviderCapabilitiesHelper(
SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH);
OpenProviderHelper(
SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH);
ASSERT_NE(audio_provider_, nullptr);
}
virtual void TearDown() override {
audio_port_ = nullptr;
audio_provider_ = nullptr;
BluetoothAudioProviderFactoryAidl::TearDown();
}
static constexpr int32_t le_audio_output_sample_rates_[] = {
0, 8000, 16000, 24000, 32000, 44100, 48000,
};
static constexpr int8_t le_audio_output_bits_per_samples_[] = {0, 16, 24};
static constexpr ChannelMode le_audio_output_channel_modes_[] = {
ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
static constexpr int32_t le_audio_output_data_interval_us_[] = {
0 /* Invalid */, 10000 /* Valid 10ms */};
};
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH can be started and
* stopped
*/
TEST_P(BluetoothAudioProviderLeAudioBroadcastSoftwareAidl,
OpenLeAudioOutputSoftwareProvider) {}
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH can be started and
* stopped with different PCM config
*/
TEST_P(BluetoothAudioProviderLeAudioBroadcastSoftwareAidl,
StartAndEndLeAudioOutputSessionWithPossiblePcmConfig) {
for (auto sample_rate : le_audio_output_sample_rates_) {
for (auto bits_per_sample : le_audio_output_bits_per_samples_) {
for (auto channel_mode : le_audio_output_channel_modes_) {
for (auto data_interval_us : le_audio_output_data_interval_us_) {
PcmConfiguration pcm_config{
.sampleRateHz = sample_rate,
.channelMode = channel_mode,
.bitsPerSample = bits_per_sample,
.dataIntervalUs = data_interval_us,
};
bool is_codec_config_valid =
IsPcmConfigSupported(pcm_config) && pcm_config.dataIntervalUs > 0;
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(pcm_config), latency_modes,
&mq_desc);
DataMQ data_mq(mq_desc);
EXPECT_EQ(aidl_retval.isOk(), is_codec_config_valid);
if (is_codec_config_valid) {
EXPECT_TRUE(data_mq.isValid());
}
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
}
}
/**
* openProvider LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH
*/
class BluetoothAudioProviderLeAudioBroadcastHardwareAidl
: public BluetoothAudioProviderFactoryAidl {
public:
virtual void SetUp() override {
BluetoothAudioProviderFactoryAidl::SetUp();
GetProviderCapabilitiesHelper(
SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
OpenProviderHelper(
SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
ASSERT_TRUE(temp_provider_capabilities_.empty() ||
audio_provider_ != nullptr);
}
virtual void TearDown() override {
audio_port_ = nullptr;
audio_provider_ = nullptr;
BluetoothAudioProviderFactoryAidl::TearDown();
}
bool IsBroadcastOffloadSupported() {
for (auto& capability : temp_provider_capabilities_) {
if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
continue;
}
auto& le_audio_capability =
capability.get<AudioCapabilities::leAudioCapabilities>();
if (le_audio_capability.broadcastCapability.codecType !=
CodecType::UNKNOWN)
return true;
}
return false;
}
std::vector<Lc3Configuration> GetBroadcastLc3SupportedList(bool supported) {
std::vector<Lc3Configuration> le_audio_codec_configs;
if (!supported) {
Lc3Configuration lc3_config{.pcmBitDepth = 0, .samplingFrequencyHz = 0};
le_audio_codec_configs.push_back(lc3_config);
return le_audio_codec_configs;
}
// There might be more than one LeAudioCodecCapabilitiesSetting
std::vector<Lc3Capabilities> lc3_capabilities;
for (auto& capability : temp_provider_capabilities_) {
if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
continue;
}
auto& le_audio_capability =
capability.get<AudioCapabilities::leAudioCapabilities>();
auto& broadcast_capability = le_audio_capability.broadcastCapability;
if (broadcast_capability.codecType != CodecType::LC3) {
continue;
}
auto& lc3_capability = broadcast_capability.leAudioCodecCapabilities.get<
BroadcastCapability::LeAudioCodecCapabilities::lc3Capabilities>();
for (int idx = 0; idx < lc3_capability->size(); idx++)
lc3_capabilities.push_back(*lc3_capability->at(idx));
}
// Combine those parameters into one list of LeAudioCodecConfiguration
// This seems horrible, but usually each Lc3Capability only contains a
// single Lc3Configuration, which means every array has a length of 1.
for (auto& lc3_capability : lc3_capabilities) {
for (int32_t samplingFrequencyHz : lc3_capability.samplingFrequencyHz) {
for (int32_t frameDurationUs : lc3_capability.frameDurationUs) {
for (int32_t octetsPerFrame : lc3_capability.octetsPerFrame) {
Lc3Configuration lc3_config = {
.samplingFrequencyHz = samplingFrequencyHz,
.frameDurationUs = frameDurationUs,
.octetsPerFrame = octetsPerFrame,
};
le_audio_codec_configs.push_back(lc3_config);
}
}
}
}
return le_audio_codec_configs;
}
LeAudioCodecCapabilitiesSetting temp_le_audio_capabilities_;
};
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be
* started and stopped
*/
TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
OpenLeAudioOutputHardwareProvider) {}
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be
* started and stopped with broadcast hardware encoding config
*/
TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
StartAndEndLeAudioBroadcastSessionWithPossibleBroadcastConfig) {
if (!IsBroadcastOffloadSupported()) {
return;
}
auto lc3_codec_configs = GetBroadcastLc3SupportedList(true /* supported */);
LeAudioBroadcastConfiguration le_audio_broadcast_config = {
.codecType = CodecType::LC3,
.streamMap = {},
};
for (auto& lc3_config : lc3_codec_configs) {
le_audio_broadcast_config.streamMap.resize(1);
le_audio_broadcast_config.streamMap[0]
.leAudioCodecConfig.set<LeAudioCodecConfiguration::lc3Config>(
lc3_config);
le_audio_broadcast_config.streamMap[0].streamHandle = 0x0;
le_audio_broadcast_config.streamMap[0].pcmStreamId = 0x0;
le_audio_broadcast_config.streamMap[0].audioChannelAllocation = 0x1 << 0;
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(le_audio_broadcast_config),
latency_modes, &mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* Test whether each provider of type
* SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be
* started and stopped with Broadcast hardware encoding config
*
* Disabled since offload codec checking is not ready
*/
TEST_P(
BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
DISABLED_StartAndEndLeAudioBroadcastSessionWithInvalidAudioConfiguration) {
if (!IsBroadcastOffloadSupported()) {
return;
}
auto lc3_codec_configs = GetBroadcastLc3SupportedList(false /* supported */);
LeAudioBroadcastConfiguration le_audio_broadcast_config = {
.codecType = CodecType::LC3,
.streamMap = {},
};
for (auto& lc3_config : lc3_codec_configs) {
le_audio_broadcast_config.streamMap[0]
.leAudioCodecConfig.set<LeAudioCodecConfiguration::lc3Config>(
lc3_config);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(le_audio_broadcast_config),
latency_modes, &mq_desc);
// AIDL call should fail on invalid codec
ASSERT_FALSE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* openProvider A2DP_SOFTWARE_DECODING_DATAPATH
*/
class BluetoothAudioProviderA2dpDecodingSoftwareAidl
: public BluetoothAudioProviderFactoryAidl {
public:
virtual void SetUp() override {
BluetoothAudioProviderFactoryAidl::SetUp();
GetProviderCapabilitiesHelper(SessionType::A2DP_SOFTWARE_DECODING_DATAPATH);
OpenProviderHelper(SessionType::A2DP_SOFTWARE_DECODING_DATAPATH);
ASSERT_TRUE(temp_provider_capabilities_.empty() ||
audio_provider_ != nullptr);
}
virtual void TearDown() override {
audio_port_ = nullptr;
audio_provider_ = nullptr;
BluetoothAudioProviderFactoryAidl::TearDown();
}
};
/**
* Test whether we can open a provider of type
*/
TEST_P(BluetoothAudioProviderA2dpDecodingSoftwareAidl,
OpenA2dpDecodingSoftwareProvider) {}
/**
* Test whether each provider of type
* SessionType::A2DP_SOFTWARE_DECODING_DATAPATH can be started and stopped with
* different PCM config
*/
TEST_P(BluetoothAudioProviderA2dpDecodingSoftwareAidl,
StartAndEndA2dpDecodingSoftwareSessionWithPossiblePcmConfig) {
for (auto sample_rate : a2dp_sample_rates) {
for (auto bits_per_sample : a2dp_bits_per_samples) {
for (auto channel_mode : a2dp_channel_modes) {
PcmConfiguration pcm_config{
.sampleRateHz = sample_rate,
.channelMode = channel_mode,
.bitsPerSample = bits_per_sample,
};
bool is_codec_config_valid = IsPcmConfigSupported(pcm_config);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(pcm_config), latency_modes,
&mq_desc);
DataMQ data_mq(mq_desc);
EXPECT_EQ(aidl_retval.isOk(), is_codec_config_valid);
if (is_codec_config_valid) {
EXPECT_TRUE(data_mq.isValid());
}
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
}
/**
* openProvider A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH
*/
class BluetoothAudioProviderA2dpDecodingHardwareAidl
: public BluetoothAudioProviderFactoryAidl {
public:
virtual void SetUp() override {
BluetoothAudioProviderFactoryAidl::SetUp();
GetProviderCapabilitiesHelper(
SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH);
OpenProviderHelper(SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH);
ASSERT_TRUE(temp_provider_capabilities_.empty() ||
audio_provider_ != nullptr);
}
virtual void TearDown() override {
audio_port_ = nullptr;
audio_provider_ = nullptr;
BluetoothAudioProviderFactoryAidl::TearDown();
}
bool IsOffloadSupported() { return (temp_provider_capabilities_.size() > 0); }
};
/**
* Test whether we can open a provider of type
*/
TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
OpenA2dpDecodingHardwareProvider) {}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
* SBC hardware encoding config
*/
TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
StartAndEndA2dpSbcDecodingHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
CodecConfiguration codec_config = {
.codecType = CodecType::SBC,
.encodedAudioBitrate = 328000,
.peerMtu = 1005,
.isScmstEnabled = false,
};
auto sbc_codec_specifics = GetSbcCodecSpecificSupportedList(true);
for (auto& codec_specific : sbc_codec_specifics) {
copy_codec_specific(codec_config.config, codec_specific);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(codec_config), latency_modes, &mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
* AAC hardware encoding config
*/
TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
StartAndEndA2dpAacDecodingHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
CodecConfiguration codec_config = {
.codecType = CodecType::AAC,
.encodedAudioBitrate = 320000,
.peerMtu = 1005,
.isScmstEnabled = false,
};
auto aac_codec_specifics = GetAacCodecSpecificSupportedList(true);
for (auto& codec_specific : aac_codec_specifics) {
copy_codec_specific(codec_config.config, codec_specific);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(codec_config), latency_modes, &mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
* LDAC hardware encoding config
*/
TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
StartAndEndA2dpLdacDecodingHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
CodecConfiguration codec_config = {
.codecType = CodecType::LDAC,
.encodedAudioBitrate = 990000,
.peerMtu = 1005,
.isScmstEnabled = false,
};
auto ldac_codec_specifics = GetLdacCodecSpecificSupportedList(true);
for (auto& codec_specific : ldac_codec_specifics) {
copy_codec_specific(codec_config.config, codec_specific);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(codec_config), latency_modes, &mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
* Opus hardware encoding config
*/
TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
StartAndEndA2dpOpusDecodingHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
CodecConfiguration codec_config = {
.codecType = CodecType::OPUS,
.encodedAudioBitrate = 990000,
.peerMtu = 1005,
.isScmstEnabled = false,
};
auto opus_codec_specifics = GetOpusCodecSpecificSupportedList(true);
for (auto& codec_specific : opus_codec_specifics) {
copy_codec_specific(codec_config.config, codec_specific);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(codec_config), latency_modes, &mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
* AptX hardware encoding config
*/
TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
StartAndEndA2dpAptxDecodingHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
for (auto codec_type : {CodecType::APTX, CodecType::APTX_HD}) {
CodecConfiguration codec_config = {
.codecType = codec_type,
.encodedAudioBitrate =
(codec_type == CodecType::APTX ? 352000 : 576000),
.peerMtu = 1005,
.isScmstEnabled = false,
};
auto aptx_codec_specifics = GetAptxCodecSpecificSupportedList(
(codec_type == CodecType::APTX_HD ? true : false), true);
for (auto& codec_specific : aptx_codec_specifics) {
copy_codec_specific(codec_config.config, codec_specific);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(codec_config), latency_modes,
&mq_desc);
ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
* an invalid codec config
*/
TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
StartAndEndA2dpDecodingHardwareSessionInvalidCodecConfig) {
if (!IsOffloadSupported()) {
return;
}
ASSERT_NE(audio_provider_, nullptr);
std::vector<CodecConfiguration::CodecSpecific> codec_specifics;
for (auto codec_type : ndk::enum_range<CodecType>()) {
switch (codec_type) {
case CodecType::SBC:
codec_specifics = GetSbcCodecSpecificSupportedList(false);
break;
case CodecType::AAC:
codec_specifics = GetAacCodecSpecificSupportedList(false);
break;
case CodecType::LDAC:
codec_specifics = GetLdacCodecSpecificSupportedList(false);
break;
case CodecType::APTX:
codec_specifics = GetAptxCodecSpecificSupportedList(false, false);
break;
case CodecType::APTX_HD:
codec_specifics = GetAptxCodecSpecificSupportedList(true, false);
break;
case CodecType::OPUS:
codec_specifics = GetOpusCodecSpecificSupportedList(false);
continue;
case CodecType::APTX_ADAPTIVE:
case CodecType::APTX_ADAPTIVE_LE:
case CodecType::APTX_ADAPTIVE_LEX:
case CodecType::LC3:
case CodecType::VENDOR:
case CodecType::UNKNOWN:
codec_specifics.clear();
break;
}
if (codec_specifics.empty()) {
continue;
}
CodecConfiguration codec_config = {
.codecType = codec_type,
.encodedAudioBitrate = 328000,
.peerMtu = 1005,
.isScmstEnabled = false,
};
for (auto codec_specific : codec_specifics) {
copy_codec_specific(codec_config.config, codec_specific);
DataMQDesc mq_desc;
auto aidl_retval = audio_provider_->startSession(
audio_port_, AudioConfiguration(codec_config), latency_modes,
&mq_desc);
// AIDL call should fail on invalid codec
ASSERT_FALSE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
BluetoothAudioProviderFactoryAidl);
INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProviderFactoryAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(
IBluetoothAudioProviderFactory::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
BluetoothAudioProviderA2dpEncodingSoftwareAidl);
INSTANTIATE_TEST_SUITE_P(PerInstance,
BluetoothAudioProviderA2dpEncodingSoftwareAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(
IBluetoothAudioProviderFactory::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
BluetoothAudioProviderA2dpEncodingHardwareAidl);
INSTANTIATE_TEST_SUITE_P(PerInstance,
BluetoothAudioProviderA2dpEncodingHardwareAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(
IBluetoothAudioProviderFactory::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
BluetoothAudioProviderHearingAidSoftwareAidl);
INSTANTIATE_TEST_SUITE_P(PerInstance,
BluetoothAudioProviderHearingAidSoftwareAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(
IBluetoothAudioProviderFactory::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
BluetoothAudioProviderLeAudioOutputSoftwareAidl);
INSTANTIATE_TEST_SUITE_P(PerInstance,
BluetoothAudioProviderLeAudioOutputSoftwareAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(
IBluetoothAudioProviderFactory::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
BluetoothAudioProviderLeAudioInputSoftwareAidl);
INSTANTIATE_TEST_SUITE_P(PerInstance,
BluetoothAudioProviderLeAudioInputSoftwareAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(
IBluetoothAudioProviderFactory::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
BluetoothAudioProviderLeAudioOutputHardwareAidl);
INSTANTIATE_TEST_SUITE_P(PerInstance,
BluetoothAudioProviderLeAudioOutputHardwareAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(
IBluetoothAudioProviderFactory::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
BluetoothAudioProviderLeAudioInputHardwareAidl);
INSTANTIATE_TEST_SUITE_P(PerInstance,
BluetoothAudioProviderLeAudioInputHardwareAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(
IBluetoothAudioProviderFactory::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
BluetoothAudioProviderLeAudioBroadcastSoftwareAidl);
INSTANTIATE_TEST_SUITE_P(PerInstance,
BluetoothAudioProviderLeAudioBroadcastSoftwareAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(
IBluetoothAudioProviderFactory::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
BluetoothAudioProviderLeAudioBroadcastHardwareAidl);
INSTANTIATE_TEST_SUITE_P(PerInstance,
BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(
IBluetoothAudioProviderFactory::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
BluetoothAudioProviderA2dpDecodingSoftwareAidl);
INSTANTIATE_TEST_SUITE_P(PerInstance,
BluetoothAudioProviderA2dpDecodingSoftwareAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(
IBluetoothAudioProviderFactory::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
BluetoothAudioProviderA2dpDecodingHardwareAidl);
INSTANTIATE_TEST_SUITE_P(PerInstance,
BluetoothAudioProviderA2dpDecodingHardwareAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(
IBluetoothAudioProviderFactory::descriptor)),
android::PrintInstanceNameToString);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
ABinderProcess_setThreadPoolMaxThreadCount(1);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}