Merge "VTS for Bluetooth Audio HAL v2"

This commit is contained in:
Treehugger Robot 2019-01-31 18:16:35 +00:00 committed by Gerrit Code Review
commit 5203e215e2
3 changed files with 930 additions and 0 deletions

View file

@ -0,0 +1,3 @@
include platform/system/bt:/OWNERS
cheneyni@google.com

View file

@ -0,0 +1,12 @@
cc_test {
name: "VtsHalBluetoothAudioV2_0TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalBluetoothAudioV2_0TargetTest.cpp"],
static_libs: [
"android.hardware.audio.common@5.0",
"android.hardware.bluetooth.audio@2.0",
],
shared_libs: [
"libfmq",
],
}

View file

@ -0,0 +1,915 @@
/*
* Copyright 2018 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.
*/
#define LOG_TAG "bluetooth_audio_hidl_hal_test"
#include <android-base/logging.h>
#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioPort.h>
#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvider.h>
#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
#include <fmq/MessageQueue.h>
#include <hidl/MQDescriptor.h>
#include <utils/Log.h>
#include <VtsHalHidlTargetCallbackBase.h>
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
using ::android::sp;
using ::android::hardware::hidl_vec;
using ::android::hardware::kSynchronizedReadWrite;
using ::android::hardware::MessageQueue;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::audio::common::V5_0::SourceMetadata;
using ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
using ::android::hardware::bluetooth::audio::V2_0::AacParameters;
using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
using ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
using ::android::hardware::bluetooth::audio::V2_0::AudioCapabilities;
using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities;
using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
using ::android::hardware::bluetooth::audio::V2_0::CodecType;
using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioPort;
using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioProvider;
using ::android::hardware::bluetooth::audio::V2_0::
IBluetoothAudioProvidersFactory;
using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
using ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
using ::android::hardware::bluetooth::audio::V2_0::SbcParameters;
using ::android::hardware::bluetooth::audio::V2_0::SessionType;
using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
using BluetoothAudioStatus =
::android::hardware::bluetooth::audio::V2_0::Status;
using CodecSpecificConfig = ::android::hardware::bluetooth::audio::V2_0::
CodecConfiguration::CodecSpecific;
namespace {
constexpr SampleRate a2dp_sample_rates[5] = {
SampleRate::RATE_UNKNOWN, SampleRate::RATE_44100, SampleRate::RATE_48000,
SampleRate::RATE_88200, SampleRate::RATE_96000};
constexpr BitsPerSample a2dp_bits_per_samples[4] = {
BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16, BitsPerSample::BITS_24,
BitsPerSample::BITS_32};
constexpr ChannelMode a2dp_channel_modes[3] = {
ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
constexpr CodecType a2dp_codec_types[6] = {CodecType::UNKNOWN, CodecType::SBC,
CodecType::AAC, CodecType::APTX,
CodecType::APTX_HD, CodecType::LDAC};
template <typename T>
std::vector<T> ExtractValuesFromBitmask(T bitmasks, uint32_t bitfield,
bool supported) {
std::vector<T> retval;
if (!supported) {
retval.push_back(static_cast<T>(bitfield));
}
uint32_t test_bit = 0x00000001;
while (test_bit <= static_cast<uint32_t>(bitmasks) && test_bit <= bitfield) {
if ((bitfield & test_bit)) {
if ((!(bitmasks & test_bit) && !supported) ||
((bitmasks & test_bit) && supported)) {
retval.push_back(static_cast<T>(test_bit));
}
}
if (test_bit == 0x80000000) {
break;
}
test_bit <<= 1;
}
return retval;
}
} // namespace
// Test environment for Bluetooth Audio HAL.
class BluetoothAudioHidlEnvironment
: public ::testing::VtsHalHidlTargetTestEnvBase {
public:
// get the test environment singleton
static BluetoothAudioHidlEnvironment* Instance() {
static BluetoothAudioHidlEnvironment* instance =
new BluetoothAudioHidlEnvironment;
return instance;
}
virtual void registerTestServices() override {
registerTestService<IBluetoothAudioProvidersFactory>();
}
private:
BluetoothAudioHidlEnvironment() {}
};
// The base test class for Bluetooth Audio HAL.
class BluetoothAudioProvidersFactoryHidlTest
: public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {
providers_factory_ = ::testing::VtsHalHidlTargetTestBase::getService<
IBluetoothAudioProvidersFactory>(
BluetoothAudioHidlEnvironment::Instance()
->getServiceName<IBluetoothAudioProvidersFactory>());
ASSERT_NE(providers_factory_, nullptr);
}
virtual void TearDown() override { providers_factory_ = nullptr; }
// A simple test implementation of IBluetoothAudioPort.
class BluetoothAudioPort : public ::testing::VtsHalHidlTargetCallbackBase<
BluetoothAudioProvidersFactoryHidlTest>,
public IBluetoothAudioPort {
BluetoothAudioProvidersFactoryHidlTest& parent_;
public:
BluetoothAudioPort(BluetoothAudioProvidersFactoryHidlTest& parent)
: parent_(parent) {}
virtual ~BluetoothAudioPort() = default;
Return<void> startStream() override {
parent_.audio_provider_->streamStarted(BluetoothAudioStatus::SUCCESS);
return Void();
}
Return<void> suspendStream() override {
parent_.audio_provider_->streamSuspended(BluetoothAudioStatus::SUCCESS);
return Void();
}
Return<void> stopStream() override { return Void(); }
Return<void> getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
_hidl_cb(BluetoothAudioStatus::SUCCESS, 0, 0, {.tvSec = 0, .tvNSec = 0});
return Void();
}
Return<void> updateMetadata(const SourceMetadata& sourceMetadata __unused) {
return Void();
}
};
void GetProviderCapabilitiesHelper(const SessionType& session_type) {
temp_provider_capabilities_.clear();
auto hidl_cb = [& temp_capabilities = this->temp_provider_capabilities_](
const hidl_vec<AudioCapabilities>& audioCapabilities) {
for (auto audioCapability : audioCapabilities)
temp_capabilities.push_back(audioCapability);
};
auto hidl_retval =
providers_factory_->getProviderCapabilities(session_type, hidl_cb);
// HIDL calls should not be failed and callback has to be executed
ASSERT_TRUE(hidl_retval.isOk());
if (session_type == SessionType::UNKNOWN) {
ASSERT_TRUE(temp_provider_capabilities_.empty());
} else if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_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].getDiscriminator(),
AudioCapabilities::hidl_discriminator::pcmCapabilities);
} else {
uint32_t codec_type_bitmask = 0x00000000;
// empty capability means offload is unsupported
for (auto audio_capability : temp_provider_capabilities_) {
ASSERT_EQ(audio_capability.getDiscriminator(),
AudioCapabilities::hidl_discriminator::codecCapabilities);
const CodecCapabilities& codec_capabilities =
audio_capability.codecCapabilities();
// Every codec can present once at most
ASSERT_EQ(codec_type_bitmask &
static_cast<uint32_t>(codec_capabilities.codecType),
0);
switch (codec_capabilities.codecType) {
case CodecType::SBC:
ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(),
CodecCapabilities::Capabilities::hidl_discriminator::
sbcCapabilities);
break;
case CodecType::AAC:
ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(),
CodecCapabilities::Capabilities::hidl_discriminator::
aacCapabilities);
break;
case CodecType::APTX:
FALLTHROUGH_INTENDED;
case CodecType::APTX_HD:
ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(),
CodecCapabilities::Capabilities::hidl_discriminator::
aptxCapabilities);
break;
case CodecType::LDAC:
ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(),
CodecCapabilities::Capabilities::hidl_discriminator::
ldacCapabilities);
break;
case CodecType::UNKNOWN:
break;
}
codec_type_bitmask |= codec_capabilities.codecType;
}
}
}
// 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) {
BluetoothAudioStatus cb_status;
auto hidl_cb = [&cb_status, &local_provider = this->audio_provider_](
BluetoothAudioStatus status,
const sp<IBluetoothAudioProvider>& provider) {
cb_status = status;
local_provider = provider;
};
auto hidl_retval = providers_factory_->openProvider(session_type, hidl_cb);
// HIDL calls should not be failed and callback has to be executed
ASSERT_TRUE(hidl_retval.isOk());
if (cb_status == BluetoothAudioStatus::SUCCESS) {
ASSERT_NE(session_type, SessionType::UNKNOWN);
ASSERT_NE(audio_provider_, nullptr);
audio_port_ = new BluetoothAudioPort(*this);
} else {
// A2DP_HARDWARE_OFFLOAD_DATAPATH is optional
ASSERT_TRUE(session_type == SessionType::UNKNOWN ||
session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
ASSERT_EQ(cb_status, BluetoothAudioStatus::FAILURE);
ASSERT_EQ(audio_provider_, nullptr);
}
}
bool IsPcmParametersSupported(const PcmParameters& pcm_parameters) {
if (temp_provider_capabilities_.size() != 1 ||
temp_provider_capabilities_[0].getDiscriminator() !=
AudioCapabilities::hidl_discriminator::pcmCapabilities) {
return false;
}
auto pcm_capability = temp_provider_capabilities_[0].pcmCapabilities();
bool is_parameter_valid =
(pcm_parameters.sampleRate != SampleRate::RATE_UNKNOWN &&
pcm_parameters.channelMode != ChannelMode::UNKNOWN &&
pcm_parameters.bitsPerSample != BitsPerSample::BITS_UNKNOWN);
bool is_parameter_in_capability =
(pcm_capability.sampleRate & pcm_parameters.sampleRate &&
pcm_capability.channelMode & pcm_parameters.channelMode &&
pcm_capability.bitsPerSample & pcm_parameters.bitsPerSample);
return is_parameter_valid && is_parameter_in_capability;
}
sp<IBluetoothAudioProvidersFactory> providers_factory_;
// temp storage saves the specified provider capability by
// GetProviderCapabilitiesHelper()
std::vector<AudioCapabilities> temp_provider_capabilities_;
// audio_provider_ is for the Bluetooth stack to report session started/ended
// and handled audio stream started / suspended
sp<IBluetoothAudioProvider> audio_provider_;
// audio_port_ is for the Audio HAL to send stream start/suspend/stop commands
// to Bluetooth stack
sp<IBluetoothAudioPort> audio_port_;
static constexpr SessionType session_types_[4] = {
SessionType::UNKNOWN, SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH,
SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH,
SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH};
};
/**
* Test whether we can get the FactoryService from HIDL
*/
TEST_F(BluetoothAudioProvidersFactoryHidlTest, GetProvidersFactoryService) {}
/**
* Test whether we can open a provider for each provider returned by
* getProviderCapabilities() with non-empty capabalities
*/
TEST_F(BluetoothAudioProvidersFactoryHidlTest,
OpenProviderAndCheckCapabilitiesBySession) {
for (auto session_type : session_types_) {
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 BluetoothAudioProviderA2dpSoftwareHidlTest
: public BluetoothAudioProvidersFactoryHidlTest {
public:
virtual void SetUp() override {
BluetoothAudioProvidersFactoryHidlTest::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;
BluetoothAudioProvidersFactoryHidlTest::TearDown();
}
};
/**
* Test whether we can open a provider of type
*/
TEST_F(BluetoothAudioProviderA2dpSoftwareHidlTest, OpenA2dpSoftwareProvider) {}
/**
* Test whether each provider of type
* SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with
* different PCM config
*/
TEST_F(BluetoothAudioProviderA2dpSoftwareHidlTest,
StartAndEndA2dpSoftwareSessionWithPossiblePcmConfig) {
bool is_codec_config_valid;
std::unique_ptr<DataMQ> tempDataMQ;
auto hidl_cb = [&is_codec_config_valid, &tempDataMQ](
BluetoothAudioStatus status,
const DataMQ::Descriptor& dataMQ) {
if (is_codec_config_valid) {
ASSERT_EQ(status, BluetoothAudioStatus::SUCCESS);
ASSERT_TRUE(dataMQ.isHandleValid());
tempDataMQ.reset(new DataMQ(dataMQ));
} else {
EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
EXPECT_FALSE(dataMQ.isHandleValid());
}
};
AudioConfiguration audio_config = {};
PcmParameters pcm_parameters = {};
for (auto sample_rate : a2dp_sample_rates) {
pcm_parameters.sampleRate = sample_rate;
for (auto bits_per_sample : a2dp_bits_per_samples) {
pcm_parameters.bitsPerSample = bits_per_sample;
for (auto channel_mode : a2dp_channel_modes) {
pcm_parameters.channelMode = channel_mode;
is_codec_config_valid = IsPcmParametersSupported(pcm_parameters);
audio_config.pcmConfig(pcm_parameters);
auto hidl_retval =
audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
// HIDL calls should not be failed and callback has to be executed
ASSERT_TRUE(hidl_retval.isOk());
if (is_codec_config_valid) {
EXPECT_TRUE(tempDataMQ != nullptr && tempDataMQ->isValid());
}
EXPECT_TRUE(audio_provider_->endSession().isOk());
} // ChannelMode
} // BitsPerSampple
} // SampleRate
}
/**
* openProvider A2DP_HARDWARE_OFFLOAD_DATAPATH
*/
class BluetoothAudioProviderA2dpHardwareHidlTest
: public BluetoothAudioProvidersFactoryHidlTest {
public:
virtual void SetUp() override {
BluetoothAudioProvidersFactoryHidlTest::SetUp();
GetProviderCapabilitiesHelper(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
OpenProviderHelper(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
ASSERT_TRUE(temp_provider_capabilities_.empty() ||
audio_provider_ != nullptr);
}
virtual void TearDown() override {
audio_port_ = nullptr;
audio_provider_ = nullptr;
BluetoothAudioProvidersFactoryHidlTest::TearDown();
}
bool IsOffloadSupported() { return (temp_provider_capabilities_.size() > 0); }
void GetOffloadCodecCapabilityHelper(const CodecType& codec_type) {
temp_codec_capabilities_ = {};
for (auto codec_capability : temp_provider_capabilities_) {
if (codec_capability.codecCapabilities().codecType != codec_type) {
continue;
}
temp_codec_capabilities_ = codec_capability.codecCapabilities();
}
}
std::vector<CodecSpecificConfig> GetSbcCodecSpecificSupportedList(
bool supported) {
std::vector<CodecSpecificConfig> sbc_codec_specifics;
GetOffloadCodecCapabilityHelper(CodecType::SBC);
if (temp_codec_capabilities_.codecType != CodecType::SBC) {
return sbc_codec_specifics;
}
// parse the capability
SbcParameters sbc_capability =
temp_codec_capabilities_.capabilities.sbcCapabilities();
if (sbc_capability.minBitpool > sbc_capability.maxBitpool) {
return sbc_codec_specifics;
}
std::vector<SampleRate> sample_rates = ExtractValuesFromBitmask<SampleRate>(
sbc_capability.sampleRate, 0xff, supported);
std::vector<SbcChannelMode> channel_modes =
ExtractValuesFromBitmask<SbcChannelMode>(sbc_capability.channelMode,
0x0f, supported);
std::vector<SbcBlockLength> block_lengths =
ExtractValuesFromBitmask<SbcBlockLength>(sbc_capability.blockLength,
0xf0, supported);
std::vector<SbcNumSubbands> num_subbandss =
ExtractValuesFromBitmask<SbcNumSubbands>(sbc_capability.numSubbands,
0x0c, supported);
std::vector<SbcAllocMethod> alloc_methods =
ExtractValuesFromBitmask<SbcAllocMethod>(sbc_capability.allocMethod,
0x03, supported);
std::vector<BitsPerSample> bits_per_samples =
ExtractValuesFromBitmask<BitsPerSample>(sbc_capability.bitsPerSample,
0x07, supported);
// combine those parameters into one list of
// CodecConfiguration::CodecSpecific
CodecSpecificConfig codec_specific = {};
SbcParameters sbc_data;
for (auto sample_rate : sample_rates) {
for (auto channel_mode : channel_modes) {
for (auto block_length : block_lengths) {
for (auto num_subbands : num_subbandss) {
for (auto alloc_method : alloc_methods) {
for (auto bits_per_sample : bits_per_samples) {
sbc_data = {.sampleRate = 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};
codec_specific.sbcConfig(sbc_data);
sbc_codec_specifics.push_back(codec_specific);
}
}
}
}
}
}
return sbc_codec_specifics;
}
std::vector<CodecSpecificConfig> GetAacCodecSpecificSupportedList(
bool supported) {
std::vector<CodecSpecificConfig> aac_codec_specifics;
GetOffloadCodecCapabilityHelper(CodecType::AAC);
if (temp_codec_capabilities_.codecType != CodecType::AAC) {
return aac_codec_specifics;
}
// parse the capability
AacParameters aac_capability =
temp_codec_capabilities_.capabilities.aacCapabilities();
std::vector<AacObjectType> object_types =
ExtractValuesFromBitmask<AacObjectType>(aac_capability.objectType, 0xf0,
supported);
std::vector<SampleRate> sample_rates = ExtractValuesFromBitmask<SampleRate>(
aac_capability.sampleRate, 0xff, supported);
std::vector<ChannelMode> channel_modes =
ExtractValuesFromBitmask<ChannelMode>(aac_capability.channelMode, 0x03,
supported);
std::vector<AacVariableBitRate> variable_bit_rate_enableds = {
AacVariableBitRate::DISABLED};
if (aac_capability.variableBitRateEnabled == AacVariableBitRate::ENABLED) {
variable_bit_rate_enableds.push_back(AacVariableBitRate::ENABLED);
}
std::vector<BitsPerSample> bits_per_samples =
ExtractValuesFromBitmask<BitsPerSample>(aac_capability.bitsPerSample,
0x07, supported);
// combine those parameters into one list of
// CodecConfiguration::CodecSpecific
CodecSpecificConfig codec_specific = {};
AacParameters aac_data;
for (auto object_type : object_types) {
for (auto sample_rate : sample_rates) {
for (auto channel_mode : channel_modes) {
for (auto variable_bit_rate_enabled : variable_bit_rate_enableds) {
for (auto bits_per_sample : bits_per_samples) {
aac_data = {.objectType = object_type,
.sampleRate = sample_rate,
.channelMode = channel_mode,
.variableBitRateEnabled = variable_bit_rate_enabled,
.bitsPerSample = bits_per_sample};
codec_specific.aacConfig(aac_data);
aac_codec_specifics.push_back(codec_specific);
}
}
}
}
}
return aac_codec_specifics;
}
std::vector<CodecSpecificConfig> GetLdacCodecSpecificSupportedList(
bool supported) {
std::vector<CodecSpecificConfig> ldac_codec_specifics;
GetOffloadCodecCapabilityHelper(CodecType::LDAC);
if (temp_codec_capabilities_.codecType != CodecType::LDAC) {
return ldac_codec_specifics;
}
// parse the capability
LdacParameters ldac_capability =
temp_codec_capabilities_.capabilities.ldacCapabilities();
std::vector<SampleRate> sample_rates = ExtractValuesFromBitmask<SampleRate>(
ldac_capability.sampleRate, 0xff, supported);
std::vector<LdacChannelMode> channel_modes =
ExtractValuesFromBitmask<LdacChannelMode>(ldac_capability.channelMode,
0x07, supported);
std::vector<LdacQualityIndex> quality_indexes = {
LdacQualityIndex::QUALITY_HIGH, LdacQualityIndex::QUALITY_MID,
LdacQualityIndex::QUALITY_LOW, LdacQualityIndex::QUALITY_ABR};
std::vector<BitsPerSample> bits_per_samples =
ExtractValuesFromBitmask<BitsPerSample>(ldac_capability.bitsPerSample,
0x07, supported);
// combine those parameters into one list of
// CodecConfiguration::CodecSpecific
CodecSpecificConfig codec_specific = {};
LdacParameters ldac_data;
for (auto sample_rate : sample_rates) {
for (auto channel_mode : channel_modes) {
for (auto quality_index : quality_indexes) {
for (auto bits_per_sample : bits_per_samples) {
ldac_data = {.sampleRate = sample_rate,
.channelMode = channel_mode,
.qualityIndex = quality_index,
.bitsPerSample = bits_per_sample};
codec_specific.ldacConfig(ldac_data);
ldac_codec_specifics.push_back(codec_specific);
}
}
}
}
return ldac_codec_specifics;
}
std::vector<CodecSpecificConfig> GetAptxCodecSpecificSupportedList(
bool is_hd, bool supported) {
std::vector<CodecSpecificConfig> aptx_codec_specifics;
GetOffloadCodecCapabilityHelper(
(is_hd ? CodecType::APTX_HD : CodecType::APTX));
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
AptxParameters aptx_capability =
temp_codec_capabilities_.capabilities.aptxCapabilities();
std::vector<SampleRate> sample_rates = ExtractValuesFromBitmask<SampleRate>(
aptx_capability.sampleRate, 0xff, supported);
std::vector<ChannelMode> channel_modes =
ExtractValuesFromBitmask<ChannelMode>(aptx_capability.channelMode, 0x03,
supported);
std::vector<BitsPerSample> bits_per_samples =
ExtractValuesFromBitmask<BitsPerSample>(aptx_capability.bitsPerSample,
0x07, supported);
// combine those parameters into one list of
// CodecConfiguration::CodecSpecific
CodecSpecificConfig codec_specific = {};
AptxParameters aptx_data;
for (auto sample_rate : sample_rates) {
for (auto channel_mode : channel_modes) {
for (auto bits_per_sample : bits_per_samples) {
aptx_data = {.sampleRate = sample_rate,
.channelMode = channel_mode,
.bitsPerSample = bits_per_sample};
codec_specific.aptxConfig(aptx_data);
aptx_codec_specifics.push_back(codec_specific);
}
}
}
return aptx_codec_specifics;
}
// temp storage saves the specified codec capability by
// GetOffloadCodecCapabilityHelper()
CodecCapabilities temp_codec_capabilities_;
};
/**
* Test whether we can open a provider of type
*/
TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest, OpenA2dpHardwareProvider) {}
/**
* Test whether each provider of type
* SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
* SBC hardware encoding config
*/
TEST_F(BluetoothAudioProviderA2dpHardwareHidlTest,
StartAndEndA2dpSbcHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
CodecConfiguration codec_config = {};
codec_config.codecType = CodecType::SBC;
codec_config.encodedAudioBitrate = 328000;
codec_config.peerMtu = 1005;
codec_config.isScmstEnabled = false;
AudioConfiguration audio_config = {};
std::vector<CodecSpecificConfig> sbc_codec_specifics =
GetSbcCodecSpecificSupportedList(true);
auto hidl_cb = [](BluetoothAudioStatus status,
const DataMQ::Descriptor& dataMQ) {
EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS);
EXPECT_FALSE(dataMQ.isHandleValid());
};
for (auto codec_specific : sbc_codec_specifics) {
codec_config.config = codec_specific;
audio_config.codecConfig(codec_config);
auto hidl_retval =
audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
// HIDL calls should not be failed and callback has to be executed
ASSERT_TRUE(hidl_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_F(BluetoothAudioProviderA2dpHardwareHidlTest,
StartAndEndA2dpAacHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
CodecConfiguration codec_config = {};
codec_config.codecType = CodecType::AAC;
codec_config.encodedAudioBitrate = 320000;
codec_config.peerMtu = 1005;
codec_config.isScmstEnabled = false;
AudioConfiguration audio_config = {};
std::vector<CodecSpecificConfig> aac_codec_specifics =
GetAacCodecSpecificSupportedList(true);
auto hidl_cb = [](BluetoothAudioStatus status,
const DataMQ::Descriptor& dataMQ) {
EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS);
EXPECT_FALSE(dataMQ.isHandleValid());
};
for (auto codec_specific : aac_codec_specifics) {
codec_config.config = codec_specific;
audio_config.codecConfig(codec_config);
auto hidl_retval =
audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
// HIDL calls should not be failed and callback has to be executed
ASSERT_TRUE(hidl_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_F(BluetoothAudioProviderA2dpHardwareHidlTest,
StartAndEndA2dpLdacHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
CodecConfiguration codec_config = {};
codec_config.codecType = CodecType::LDAC;
codec_config.encodedAudioBitrate = 990000;
codec_config.peerMtu = 1005;
codec_config.isScmstEnabled = false;
AudioConfiguration audio_config = {};
std::vector<CodecSpecificConfig> ldac_codec_specifics =
GetLdacCodecSpecificSupportedList(true);
auto hidl_cb = [](BluetoothAudioStatus status,
const DataMQ::Descriptor& dataMQ) {
EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS);
EXPECT_FALSE(dataMQ.isHandleValid());
};
for (auto codec_specific : ldac_codec_specifics) {
codec_config.config = codec_specific;
audio_config.codecConfig(codec_config);
auto hidl_retval =
audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
// HIDL calls should not be failed and callback has to be executed
ASSERT_TRUE(hidl_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_F(BluetoothAudioProviderA2dpHardwareHidlTest,
StartAndEndA2dpAptxHardwareSession) {
if (!IsOffloadSupported()) {
return;
}
for (auto codec_type : {CodecType::APTX, CodecType::APTX_HD}) {
CodecConfiguration codec_config = {};
codec_config.codecType = codec_type;
codec_config.encodedAudioBitrate =
(codec_type == CodecType::APTX ? 352000 : 576000);
codec_config.peerMtu = 1005;
codec_config.isScmstEnabled = false;
AudioConfiguration audio_config = {};
std::vector<CodecSpecificConfig> aptx_codec_specifics =
GetAptxCodecSpecificSupportedList(
(codec_type == CodecType::APTX_HD ? true : false), true);
auto hidl_cb = [](BluetoothAudioStatus status,
const DataMQ::Descriptor& dataMQ) {
EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS);
EXPECT_FALSE(dataMQ.isHandleValid());
};
for (auto codec_specific : aptx_codec_specifics) {
codec_config.config = codec_specific;
audio_config.codecConfig(codec_config);
auto hidl_retval =
audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
// HIDL calls should not be failed and callback has to be executed
ASSERT_TRUE(hidl_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_F(BluetoothAudioProviderA2dpHardwareHidlTest,
StartAndEndA2dpHardwareSessionInvalidCodecConfig) {
if (!IsOffloadSupported()) {
return;
}
ASSERT_NE(audio_provider_, nullptr);
std::vector<CodecSpecificConfig> codec_specifics;
for (auto codec_type : a2dp_codec_types) {
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::UNKNOWN:
codec_specifics.clear();
break;
}
if (codec_specifics.empty()) {
continue;
}
CodecConfiguration codec_config = {};
codec_config.codecType = codec_type;
codec_config.encodedAudioBitrate = 328000;
codec_config.peerMtu = 1005;
codec_config.isScmstEnabled = false;
AudioConfiguration audio_config = {};
auto hidl_cb = [](BluetoothAudioStatus status,
const DataMQ::Descriptor& dataMQ) {
EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
EXPECT_FALSE(dataMQ.isHandleValid());
};
for (auto codec_specific : codec_specifics) {
codec_config.config = codec_specific;
audio_config.codecConfig(codec_config);
auto hidl_retval =
audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
// HIDL calls should not be failed and callback has to be executed
ASSERT_TRUE(hidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
}
/**
* openProvider HEARING_AID_SOFTWARE_ENCODING_DATAPATH
*/
class BluetoothAudioProviderHearingAidSoftwareHidlTest
: public BluetoothAudioProvidersFactoryHidlTest {
public:
virtual void SetUp() override {
BluetoothAudioProvidersFactoryHidlTest::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;
BluetoothAudioProvidersFactoryHidlTest::TearDown();
}
static constexpr SampleRate hearing_aid_sample_rates_[3] = {
SampleRate::RATE_UNKNOWN, SampleRate::RATE_16000, SampleRate::RATE_24000};
static constexpr BitsPerSample hearing_aid_bits_per_samples_[3] = {
BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16,
BitsPerSample::BITS_24};
static constexpr ChannelMode hearing_aid_channel_modes_[3] = {
ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
};
/**
* Test whether each provider of type
* SessionType::HEARING_AID_HARDWARE_ENCODING_DATAPATH can be started and
* stopped with SBC hardware encoding config
*/
TEST_F(BluetoothAudioProviderHearingAidSoftwareHidlTest,
OpenHearingAidSoftwareProvider) {}
/**
* Test whether each provider of type
* SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH can be started and
* stopped with different PCM config
*/
TEST_F(BluetoothAudioProviderHearingAidSoftwareHidlTest,
StartAndEndHearingAidSessionWithPossiblePcmConfig) {
bool is_codec_config_valid;
std::unique_ptr<DataMQ> tempDataMQ;
auto hidl_cb = [&is_codec_config_valid, &tempDataMQ](
BluetoothAudioStatus status,
const DataMQ::Descriptor& dataMQ) {
if (is_codec_config_valid) {
ASSERT_EQ(status, BluetoothAudioStatus::SUCCESS);
ASSERT_TRUE(dataMQ.isHandleValid());
tempDataMQ.reset(new DataMQ(dataMQ));
} else {
EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
EXPECT_FALSE(dataMQ.isHandleValid());
}
};
AudioConfiguration audio_config = {};
PcmParameters pcm_parameters = {};
for (auto sample_rate : hearing_aid_sample_rates_) {
pcm_parameters.sampleRate = sample_rate;
for (auto bits_per_sample : hearing_aid_bits_per_samples_) {
pcm_parameters.bitsPerSample = bits_per_sample;
for (auto channel_mode : hearing_aid_channel_modes_) {
pcm_parameters.channelMode = channel_mode;
is_codec_config_valid = IsPcmParametersSupported(pcm_parameters);
audio_config.pcmConfig(pcm_parameters);
auto hidl_retval =
audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
// HIDL calls should not be failed and callback has to be executed
ASSERT_TRUE(hidl_retval.isOk());
if (is_codec_config_valid) {
EXPECT_TRUE(tempDataMQ != nullptr && tempDataMQ->isValid());
}
EXPECT_TRUE(audio_provider_->endSession().isOk());
} // ChannelMode
} // BitsPerSampple
} // SampleRate
}
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(
BluetoothAudioHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
BluetoothAudioHidlEnvironment::Instance()->init(&argc, argv);
int status = RUN_ALL_TESTS();
LOG(INFO) << "Test result = " << status;
return status;
}