/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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; using DataMQDesc = MQDescriptor; // 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 latency_modes = {LatencyMode::FREE}; // Helpers template struct identity { typedef T type; }; template bool contained_in_vector(const std::vector& vector, const typename identity::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( src.get()); break; case CodecConfiguration::CodecSpecific::aacConfig: dst.set( src.get()); break; case CodecConfiguration::CodecSpecific::ldacConfig: dst.set( src.get()); break; case CodecConfiguration::CodecSpecific::aptxConfig: dst.set( src.get()); break; case CodecConfiguration::CodecSpecific::opusConfig: dst.set( src.get()); break; case CodecConfiguration::CodecSpecific::aptxAdaptiveConfig: dst.set( src.get()); 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 { 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 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(); // 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(); } 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(); if (a2dp_capabilities.codecType != codec_type) { continue; } temp_codec_capabilities_ = &a2dp_capabilities; } } std::vector GetSbcCodecSpecificSupportedList(bool supported) { std::vector 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(); 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 GetAacCodecSpecificSupportedList(bool supported) { std::vector 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(); std::vector variable_bit_rate_enableds = {false}; if (aac_capability.variableBitRateSupported) { variable_bit_rate_enableds.push_back(true); } std::vector 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 GetLdacCodecSpecificSupportedList(bool supported) { std::vector 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(); // 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 GetAptxCodecSpecificSupportedList(bool is_hd, bool supported) { std::vector 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(); // 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 GetOpusCodecSpecificSupportedList(bool supported) { std::vector 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(); // 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(); 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 provider_factory_; std::shared_ptr audio_provider_; std::shared_ptr audio_port_; std::vector 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 codec_specifics; for (auto codec_type : ndk::enum_range()) { 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(); if (le_audio_capability.unicastEncodeCapability.codecType != CodecType::UNKNOWN) return true; } return false; } std::vector GetUnicastLc3SupportedList(bool decoding, bool supported) { std::vector 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 lc3_capabilities; for (auto& capability : temp_provider_capabilities_) { if (capability.getTag() != AudioCapabilities::leAudioCapabilities) { continue; } auto& le_audio_capability = capability.get(); 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 GetUnicastAptxAdaptiveLeSupportedList(bool decoding, bool supported, bool is_le_extended) { std::vector 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 aptx_adaptive_le_capabilities; for (auto& capability : temp_provider_capabilities_) { if (capability.getTag() != AudioCapabilities::leAudioCapabilities) { continue; } auto& le_audio_capability = capability.get(); 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(); 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(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(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 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( 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( 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(); 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(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(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(); if (le_audio_capability.broadcastCapability.codecType != CodecType::UNKNOWN) return true; } return false; } std::vector GetBroadcastLc3SupportedList(bool supported) { std::vector 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 lc3_capabilities; for (auto& capability : temp_provider_capabilities_) { if (capability.getTag() != AudioCapabilities::leAudioCapabilities) { continue; } auto& le_audio_capability = capability.get(); 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( 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( 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 codec_specifics; for (auto codec_type : ndk::enum_range()) { 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(); }