diff options
Diffstat (limited to 'bluetooth/audio')
5 files changed, 442 insertions, 7 deletions
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp index 674dd116cf..70797a7aaf 100644 --- a/bluetooth/audio/utils/Android.bp +++ b/bluetooth/audio/utils/Android.bp @@ -63,6 +63,31 @@ cc_library_shared { generated_headers: ["le_audio_codec_capabilities"], } +cc_test { + name: "BluetoothLeAudioCodecsProviderTest", + srcs: [ + "aidl_session/BluetoothLeAudioCodecsProvider.cpp", + "aidl_session/BluetoothLeAudioCodecsProviderTest.cpp", + ], + header_libs: [ + "libxsdc-utils", + ], + shared_libs: [ + "libbase", + "libbinder_ndk", + "android.hardware.bluetooth.audio-V2-ndk", + "libxml2", + ], + test_suites: [ + "general-tests", + ], + test_options: { + unit_test: false, + }, + generated_sources: ["le_audio_codec_capabilities"], + generated_headers: ["le_audio_codec_capabilities"], +} + xsd_config { name: "le_audio_codec_capabilities", srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"], diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp index 855dd28718..faebbbf32b 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp +++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp @@ -398,8 +398,11 @@ BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities( } if (kDefaultOffloadLeAudioCapabilities.empty()) { + auto le_audio_offload_setting = + BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile(); kDefaultOffloadLeAudioCapabilities = - BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(); + BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities( + le_audio_offload_setting); } return kDefaultOffloadLeAudioCapabilities; diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp index bf492706c8..1dec900aed 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp +++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp @@ -34,20 +34,40 @@ static const AudioLocation kMonoAudio = AudioLocation::UNKNOWN; static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities; +static bool isInvalidFileContent = false; + +std::optional<setting::LeAudioOffloadSetting> +BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile() { + if (!leAudioCodecCapabilities.empty() || isInvalidFileContent) { + return std::nullopt; + } + auto le_audio_offload_setting = + setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile); + if (!le_audio_offload_setting.has_value()) { + LOG(ERROR) << __func__ << ": Failed to read " + << kLeAudioCodecCapabilitiesFile; + } + return le_audio_offload_setting; +} + std::vector<LeAudioCodecCapabilitiesSetting> -BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() { +BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities( + const std::optional<setting::LeAudioOffloadSetting>& + le_audio_offload_setting) { if (!leAudioCodecCapabilities.empty()) { return leAudioCodecCapabilities; } - const auto le_audio_offload_setting = - setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile); if (!le_audio_offload_setting.has_value()) { - LOG(ERROR) << __func__ << ": Failed to read " - << kLeAudioCodecCapabilitiesFile; + LOG(ERROR) + << __func__ + << ": input le_audio_offload_setting content need to be non empty"; return {}; } + ClearLeAudioCodecCapabilities(); + isInvalidFileContent = true; + std::vector<setting::Scenario> supported_scenarios = GetScenarios(le_audio_offload_setting); if (supported_scenarios.empty()) { @@ -79,9 +99,18 @@ BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() { leAudioCodecCapabilities = ComposeLeAudioCodecCapabilities(supported_scenarios); + isInvalidFileContent = leAudioCodecCapabilities.empty(); + return leAudioCodecCapabilities; } +void BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities() { + leAudioCodecCapabilities.clear(); + configuration_map_.clear(); + codec_configuration_map_.clear(); + strategy_configuration_map_.clear(); +} + std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios( const std::optional<setting::LeAudioOffloadSetting>& le_audio_offload_setting) { diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h index 402235f0cd..e8799843ef 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h +++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h @@ -31,8 +31,13 @@ namespace audio { class BluetoothLeAudioCodecsProvider { public: + static std::optional<setting::LeAudioOffloadSetting> + ParseFromLeAudioOffloadSettingFile(); static std::vector<LeAudioCodecCapabilitiesSetting> - GetLeAudioCodecCapabilities(); + GetLeAudioCodecCapabilities( + const std::optional<setting::LeAudioOffloadSetting>& + le_audio_offload_setting); + static void ClearLeAudioCodecCapabilities(); private: static inline std::unordered_map<std::string, setting::Configuration> diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp new file mode 100644 index 0000000000..5393cd70e8 --- /dev/null +++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp @@ -0,0 +1,373 @@ +/* + * 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 <gtest/gtest.h> + +#include <optional> +#include <tuple> + +#include "BluetoothLeAudioCodecsProvider.h" + +using aidl::android::hardware::bluetooth::audio::BluetoothLeAudioCodecsProvider; +using aidl::android::hardware::bluetooth::audio:: + LeAudioCodecCapabilitiesSetting; +using aidl::android::hardware::bluetooth::audio::setting::AudioLocation; +using aidl::android::hardware::bluetooth::audio::setting::CodecConfiguration; +using aidl::android::hardware::bluetooth::audio::setting:: + CodecConfigurationList; +using aidl::android::hardware::bluetooth::audio::setting::CodecType; +using aidl::android::hardware::bluetooth::audio::setting::Configuration; +using aidl::android::hardware::bluetooth::audio::setting::ConfigurationList; +using aidl::android::hardware::bluetooth::audio::setting::LeAudioOffloadSetting; +using aidl::android::hardware::bluetooth::audio::setting::Scenario; +using aidl::android::hardware::bluetooth::audio::setting::ScenarioList; +using aidl::android::hardware::bluetooth::audio::setting::StrategyConfiguration; +using aidl::android::hardware::bluetooth::audio::setting:: + StrategyConfigurationList; + +typedef std::tuple<std::vector<ScenarioList>, std::vector<ConfigurationList>, + std::vector<CodecConfigurationList>, + std::vector<StrategyConfigurationList>> + OffloadSetting; + +// Define valid components for each list +// Scenario +static const Scenario kValidScenario(std::make_optional("OneChanStereo_16_1"), + std::make_optional("OneChanStereo_16_1")); +// Configuration +static const Configuration kValidConfigOneChanStereo_16_1( + std::make_optional("OneChanStereo_16_1"), std::make_optional("LC3_16k_1"), + std::make_optional("STEREO_ONE_CIS_PER_DEVICE")); +// CodecConfiguration +static const CodecConfiguration kValidCodecLC3_16k_1( + std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3), + std::nullopt, std::make_optional(16000), std::make_optional(7500), + std::make_optional(30), std::nullopt); +// StrategyConfiguration +static const StrategyConfiguration kValidStrategyStereoOneCis( + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), + std::make_optional(AudioLocation::STEREO), std::make_optional(2), + std::make_optional(1)); +static const StrategyConfiguration kValidStrategyStereoTwoCis( + std::make_optional("STEREO_TWO_CISES_PER_DEVICE"), + std::make_optional(AudioLocation::STEREO), std::make_optional(1), + std::make_optional(2)); +static const StrategyConfiguration kValidStrategyMonoOneCis( + std::make_optional("MONO_ONE_CIS_PER_DEVICE"), + std::make_optional(AudioLocation::MONO), std::make_optional(1), + std::make_optional(1)); + +// Define valid test list built from above valid components +// Scenario, Configuration, CodecConfiguration, StrategyConfiguration +static const std::vector<ScenarioList> kValidScenarioList = { + ScenarioList(std::vector<Scenario>{kValidScenario})}; +static const std::vector<ConfigurationList> kValidConfigurationList = { + ConfigurationList( + std::vector<Configuration>{kValidConfigOneChanStereo_16_1})}; +static const std::vector<CodecConfigurationList> kValidCodecConfigurationList = + {CodecConfigurationList( + std::vector<CodecConfiguration>{kValidCodecLC3_16k_1})}; +static const std::vector<StrategyConfigurationList> + kValidStrategyConfigurationList = { + StrategyConfigurationList(std::vector<StrategyConfiguration>{ + kValidStrategyStereoOneCis, kValidStrategyStereoTwoCis, + kValidStrategyMonoOneCis})}; + +class BluetoothLeAudioCodecsProviderTest + : public ::testing::TestWithParam<OffloadSetting> { + public: + static std::vector<OffloadSetting> CreateTestCases( + const std::vector<ScenarioList>& scenario_lists, + const std::vector<ConfigurationList>& configuration_lists, + const std::vector<CodecConfigurationList>& codec_configuration_lists, + const std::vector<StrategyConfigurationList>& + strategy_configuration_lists) { + // make each vector in output test_cases has only one element + // to match the input of test params + // normally only one vector in input has multiple elements + // we just split elements in this vector to several vector + std::vector<OffloadSetting> test_cases; + for (const auto& scenario_list : scenario_lists) { + for (const auto& configuration_list : configuration_lists) { + for (const auto& codec_configuration_list : codec_configuration_lists) { + for (const auto& strategy_configuration_list : + strategy_configuration_lists) { + test_cases.push_back(CreateTestCase( + scenario_list, configuration_list, codec_configuration_list, + strategy_configuration_list)); + } + } + } + } + return test_cases; + } + + protected: + void Initialize() { + BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities(); + } + + std::vector<LeAudioCodecCapabilitiesSetting> RunTestCase() { + auto& [scenario_lists, configuration_lists, codec_configuration_lists, + strategy_configuration_lists] = GetParam(); + LeAudioOffloadSetting le_audio_offload_setting( + scenario_lists, configuration_lists, codec_configuration_lists, + strategy_configuration_lists); + auto le_audio_codec_capabilities = + BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities( + std::make_optional(le_audio_offload_setting)); + return le_audio_codec_capabilities; + } + + private: + static inline OffloadSetting CreateTestCase( + const ScenarioList& scenario_list, + const ConfigurationList& configuration_list, + const CodecConfigurationList& codec_configuration_list, + const StrategyConfigurationList& strategy_configuration_list) { + return std::make_tuple( + std::vector<ScenarioList>{scenario_list}, + std::vector<ConfigurationList>{configuration_list}, + std::vector<CodecConfigurationList>{codec_configuration_list}, + std::vector<StrategyConfigurationList>{strategy_configuration_list}); + } +}; + +class GetScenariosTest : public BluetoothLeAudioCodecsProviderTest { + public: + static std::vector<ScenarioList> CreateInvalidScenarios() { + std::vector<ScenarioList> invalid_scenario_test_cases; + invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{ + Scenario(std::nullopt, std::make_optional("OneChanStereo_16_1"))})); + + invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{ + Scenario(std::make_optional("OneChanStereo_16_1"), std::nullopt)})); + + invalid_scenario_test_cases.push_back(ScenarioList( + std::vector<Scenario>{Scenario(std::nullopt, std::nullopt)})); + + invalid_scenario_test_cases.push_back( + ScenarioList(std::vector<Scenario>{})); + + return invalid_scenario_test_cases; + } +}; + +TEST_P(GetScenariosTest, InvalidScenarios) { + Initialize(); + auto le_audio_codec_capabilities = RunTestCase(); + ASSERT_TRUE(le_audio_codec_capabilities.empty()); +} + +class UpdateConfigurationsToMapTest + : public BluetoothLeAudioCodecsProviderTest { + public: + static std::vector<ConfigurationList> CreateInvalidConfigurations() { + std::vector<ConfigurationList> invalid_configuration_test_cases; + invalid_configuration_test_cases.push_back( + ConfigurationList(std::vector<Configuration>{ + Configuration(std::nullopt, std::make_optional("LC3_16k_1"), + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))})); + + invalid_configuration_test_cases.push_back( + ConfigurationList(std::vector<Configuration>{Configuration( + std::make_optional("OneChanStereo_16_1"), std::nullopt, + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))})); + + invalid_configuration_test_cases.push_back( + ConfigurationList(std::vector<Configuration>{ + Configuration(std::make_optional("OneChanStereo_16_1"), + std::make_optional("LC3_16k_1"), std::nullopt)})); + + invalid_configuration_test_cases.push_back( + ConfigurationList(std::vector<Configuration>{})); + + return invalid_configuration_test_cases; + } +}; + +TEST_P(UpdateConfigurationsToMapTest, InvalidConfigurations) { + Initialize(); + auto le_audio_codec_capabilities = RunTestCase(); + ASSERT_TRUE(le_audio_codec_capabilities.empty()); +} + +class UpdateCodecConfigurationsToMapTest + : public BluetoothLeAudioCodecsProviderTest { + public: + static std::vector<CodecConfigurationList> + CreateInvalidCodecConfigurations() { + std::vector<CodecConfigurationList> invalid_codec_configuration_test_cases; + invalid_codec_configuration_test_cases.push_back(CodecConfigurationList( + std::vector<CodecConfiguration>{CodecConfiguration( + std::nullopt, std::make_optional(CodecType::LC3), std::nullopt, + std::make_optional(16000), std::make_optional(7500), + std::make_optional(30), std::nullopt)})); + + invalid_codec_configuration_test_cases.push_back(CodecConfigurationList( + std::vector<CodecConfiguration>{CodecConfiguration( + std::make_optional("LC3_16k_1"), std::nullopt, std::nullopt, + std::make_optional(16000), std::make_optional(7500), + std::make_optional(30), std::nullopt)})); + + invalid_codec_configuration_test_cases.push_back(CodecConfigurationList( + std::vector<CodecConfiguration>{CodecConfiguration( + std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3), + std::nullopt, std::nullopt, std::make_optional(7500), + std::make_optional(30), std::nullopt)})); + + invalid_codec_configuration_test_cases.push_back(CodecConfigurationList( + std::vector<CodecConfiguration>{CodecConfiguration( + std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3), + std::nullopt, std::make_optional(16000), std::nullopt, + std::make_optional(30), std::nullopt)})); + + invalid_codec_configuration_test_cases.push_back(CodecConfigurationList( + std::vector<CodecConfiguration>{CodecConfiguration( + std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3), + std::nullopt, std::make_optional(16000), std::make_optional(7500), + std::nullopt, std::nullopt)})); + + invalid_codec_configuration_test_cases.push_back( + CodecConfigurationList(std::vector<CodecConfiguration>{})); + + return invalid_codec_configuration_test_cases; + } +}; + +TEST_P(UpdateCodecConfigurationsToMapTest, InvalidCodecConfigurations) { + Initialize(); + auto le_audio_codec_capabilities = RunTestCase(); + ASSERT_TRUE(le_audio_codec_capabilities.empty()); +} + +class UpdateStrategyConfigurationsToMapTest + : public BluetoothLeAudioCodecsProviderTest { + public: + static std::vector<StrategyConfigurationList> + CreateInvalidStrategyConfigurations() { + std::vector<StrategyConfigurationList> + invalid_strategy_configuration_test_cases; + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList( + std::vector<StrategyConfiguration>{StrategyConfiguration( + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), + std::make_optional(AudioLocation::STEREO), + std::make_optional(2), std::make_optional(2))})); + + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList( + std::vector<StrategyConfiguration>{StrategyConfiguration( + std::make_optional("MONO_ONE_CIS_PER_DEVICE"), + std::make_optional(AudioLocation::STEREO), + std::make_optional(2), std::make_optional(2))})); + + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList( + std::vector<StrategyConfiguration>{StrategyConfiguration( + std::nullopt, std::make_optional(AudioLocation::STEREO), + std::make_optional(2), std::make_optional(1))})); + + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList( + std::vector<StrategyConfiguration>{StrategyConfiguration( + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt, + std::make_optional(2), std::make_optional(1))})); + + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList( + std::vector<StrategyConfiguration>{StrategyConfiguration( + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), + std::make_optional(AudioLocation::STEREO), std::nullopt, + std::make_optional(1))})); + + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList( + std::vector<StrategyConfiguration>{StrategyConfiguration( + std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), + std::make_optional(AudioLocation::STEREO), + std::make_optional(2), std::nullopt)})); + + invalid_strategy_configuration_test_cases.push_back( + StrategyConfigurationList(std::vector<StrategyConfiguration>{})); + + return invalid_strategy_configuration_test_cases; + } +}; + +TEST_P(UpdateStrategyConfigurationsToMapTest, InvalidStrategyConfigurations) { + Initialize(); + auto le_audio_codec_capabilities = RunTestCase(); + ASSERT_TRUE(le_audio_codec_capabilities.empty()); +} + +class ComposeLeAudioCodecCapabilitiesTest + : public BluetoothLeAudioCodecsProviderTest { + public: +}; + +TEST_P(ComposeLeAudioCodecCapabilitiesTest, CodecCapabilitiesNotEmpty) { + Initialize(); + auto le_audio_codec_capabilities = RunTestCase(); + ASSERT_TRUE(!le_audio_codec_capabilities.empty()); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GetScenariosTest); +INSTANTIATE_TEST_SUITE_P( + BluetoothLeAudioCodecsProviderTest, GetScenariosTest, + ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases( + GetScenariosTest::CreateInvalidScenarios(), kValidConfigurationList, + kValidCodecConfigurationList, kValidStrategyConfigurationList))); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UpdateConfigurationsToMapTest); +INSTANTIATE_TEST_SUITE_P( + BluetoothLeAudioCodecsProviderTest, UpdateConfigurationsToMapTest, + ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases( + kValidScenarioList, + UpdateConfigurationsToMapTest::CreateInvalidConfigurations(), + kValidCodecConfigurationList, kValidStrategyConfigurationList))); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( + UpdateCodecConfigurationsToMapTest); +INSTANTIATE_TEST_SUITE_P( + BluetoothLeAudioCodecsProviderTest, UpdateCodecConfigurationsToMapTest, + ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases( + kValidScenarioList, kValidConfigurationList, + UpdateCodecConfigurationsToMapTest::CreateInvalidCodecConfigurations(), + kValidStrategyConfigurationList))); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( + UpdateStrategyConfigurationsToMapTest); +INSTANTIATE_TEST_SUITE_P( + BluetoothLeAudioCodecsProviderTest, UpdateStrategyConfigurationsToMapTest, + ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases( + kValidScenarioList, kValidConfigurationList, + kValidCodecConfigurationList, + UpdateStrategyConfigurationsToMapTest:: + CreateInvalidStrategyConfigurations()))); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( + ComposeLeAudioCodecCapabilitiesTest); +INSTANTIATE_TEST_SUITE_P( + BluetoothLeAudioCodecsProviderTest, ComposeLeAudioCodecCapabilitiesTest, + ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases( + kValidScenarioList, kValidConfigurationList, + kValidCodecConfigurationList, kValidStrategyConfigurationList))); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} |