/* * 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 #include #include #include #include #include #include #include #include #include #include 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; 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 std::vector ExtractValuesFromBitmask(T bitmasks, uint32_t bitfield, bool supported) { std::vector retval; if (!supported) { retval.push_back(static_cast(bitfield)); } uint32_t test_bit = 0x00000001; while (test_bit <= static_cast(bitmasks) && test_bit <= bitfield) { if ((bitfield & test_bit)) { if ((!(bitmasks & test_bit) && !supported) || ((bitmasks & test_bit) && supported)) { retval.push_back(static_cast(test_bit)); } } if (test_bit == 0x80000000) { break; } test_bit <<= 1; } return retval; } } // namespace // The base test class for Bluetooth Audio HAL. class BluetoothAudioProvidersFactoryHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { providers_factory_ = IBluetoothAudioProvidersFactory::getService(GetParam()); 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 startStream() override { parent_.audio_provider_->streamStarted(BluetoothAudioStatus::SUCCESS); return Void(); } Return suspendStream() override { parent_.audio_provider_->streamSuspended(BluetoothAudioStatus::SUCCESS); return Void(); } Return stopStream() override { return Void(); } Return getPresentationPosition(getPresentationPosition_cb _hidl_cb) { _hidl_cb(BluetoothAudioStatus::SUCCESS, 0, 0, {.tvSec = 0, .tvNSec = 0}); return Void(); } Return 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) { 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(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& 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 providers_factory_; // temp storage saves the specified provider capability by // GetProviderCapabilitiesHelper() std::vector temp_provider_capabilities_; // audio_provider_ is for the Bluetooth stack to report session started/ended // and handled audio stream started / suspended sp audio_provider_; // audio_port_ is for the Audio HAL to send stream start/suspend/stop commands // to Bluetooth stack sp 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_P(BluetoothAudioProvidersFactoryHidlTest, GetProvidersFactoryService) {} /** * Test whether we can open a provider for each provider returned by * getProviderCapabilities() with non-empty capabalities */ TEST_P(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_P(BluetoothAudioProviderA2dpSoftwareHidlTest, OpenA2dpSoftwareProvider) {} /** * Test whether each provider of type * SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with * different PCM config */ TEST_P(BluetoothAudioProviderA2dpSoftwareHidlTest, StartAndEndA2dpSoftwareSessionWithPossiblePcmConfig) { bool is_codec_config_valid; std::unique_ptr 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 GetSbcCodecSpecificSupportedList( bool supported) { std::vector 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 sample_rates = ExtractValuesFromBitmask( sbc_capability.sampleRate, 0xff, supported); std::vector channel_modes = ExtractValuesFromBitmask(sbc_capability.channelMode, 0x0f, supported); std::vector block_lengths = ExtractValuesFromBitmask(sbc_capability.blockLength, 0xf0, supported); std::vector num_subbandss = ExtractValuesFromBitmask(sbc_capability.numSubbands, 0x0c, supported); std::vector alloc_methods = ExtractValuesFromBitmask(sbc_capability.allocMethod, 0x03, supported); std::vector bits_per_samples = ExtractValuesFromBitmask(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 GetAacCodecSpecificSupportedList( bool supported) { std::vector 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 object_types = ExtractValuesFromBitmask(aac_capability.objectType, 0xf0, supported); std::vector sample_rates = ExtractValuesFromBitmask( aac_capability.sampleRate, 0xff, supported); std::vector channel_modes = ExtractValuesFromBitmask(aac_capability.channelMode, 0x03, supported); std::vector variable_bit_rate_enableds = { AacVariableBitRate::DISABLED}; if (aac_capability.variableBitRateEnabled == AacVariableBitRate::ENABLED) { variable_bit_rate_enableds.push_back(AacVariableBitRate::ENABLED); } std::vector bits_per_samples = ExtractValuesFromBitmask(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 GetLdacCodecSpecificSupportedList( bool supported) { std::vector 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 sample_rates = ExtractValuesFromBitmask( ldac_capability.sampleRate, 0xff, supported); std::vector channel_modes = ExtractValuesFromBitmask(ldac_capability.channelMode, 0x07, supported); std::vector quality_indexes = { LdacQualityIndex::QUALITY_HIGH, LdacQualityIndex::QUALITY_MID, LdacQualityIndex::QUALITY_LOW, LdacQualityIndex::QUALITY_ABR}; std::vector bits_per_samples = ExtractValuesFromBitmask(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 GetAptxCodecSpecificSupportedList( bool is_hd, bool supported) { std::vector 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 sample_rates = ExtractValuesFromBitmask( aptx_capability.sampleRate, 0xff, supported); std::vector channel_modes = ExtractValuesFromBitmask(aptx_capability.channelMode, 0x03, supported); std::vector bits_per_samples = ExtractValuesFromBitmask(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_P(BluetoothAudioProviderA2dpHardwareHidlTest, OpenA2dpHardwareProvider) {} /** * Test whether each provider of type * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with * SBC hardware encoding config */ TEST_P(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 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_P(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 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_P(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 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_P(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 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_P(BluetoothAudioProviderA2dpHardwareHidlTest, StartAndEndA2dpHardwareSessionInvalidCodecConfig) { if (!IsOffloadSupported()) { return; } ASSERT_NE(audio_provider_, nullptr); std::vector 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_P(BluetoothAudioProviderHearingAidSoftwareHidlTest, OpenHearingAidSoftwareProvider) {} /** * Test whether each provider of type * SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH can be started and * stopped with different PCM config */ TEST_P(BluetoothAudioProviderHearingAidSoftwareHidlTest, StartAndEndHearingAidSessionWithPossiblePcmConfig) { bool is_codec_config_valid; std::unique_ptr 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 } static const std::vector kAudioInstances = android::hardware::getAllHalInstanceNames( IBluetoothAudioProvidersFactory::descriptor); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( BluetoothAudioProvidersFactoryHidlTest); INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProvidersFactoryHidlTest, testing::ValuesIn(kAudioInstances), android::hardware::PrintInstanceNameToString); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( BluetoothAudioProviderA2dpSoftwareHidlTest); INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProviderA2dpSoftwareHidlTest, testing::ValuesIn(kAudioInstances), android::hardware::PrintInstanceNameToString); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( BluetoothAudioProviderA2dpHardwareHidlTest); INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProviderA2dpHardwareHidlTest, testing::ValuesIn(kAudioInstances), android::hardware::PrintInstanceNameToString); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( BluetoothAudioProviderHearingAidSoftwareHidlTest); INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProviderHearingAidSoftwareHidlTest, testing::ValuesIn(kAudioInstances), android::hardware::PrintInstanceNameToString);