Loading bluetooth/audio/utils/Android.bp +29 −2 Original line number Diff line number Diff line Loading @@ -87,8 +87,6 @@ cc_library_shared { ], } // TODO: Write test for BluetoothHfpCodecsProvider.cpp cc_test { name: "BluetoothLeAudioCodecsProviderTest", srcs: [ Loading @@ -114,6 +112,35 @@ cc_test { generated_headers: ["le_audio_codec_capabilities"], } cc_test { name: "BluetoothHfpCodecsProviderTest", defaults: [ "latest_android_hardware_audio_common_ndk_static", "latest_android_hardware_bluetooth_audio_ndk_static", "latest_android_media_audio_common_types_ndk_static", ], srcs: [ "aidl_session/BluetoothHfpCodecsProvider.cpp", "aidl_session/BluetoothHfpCodecsProviderTest.cpp", ], header_libs: [ "libxsdc-utils", ], shared_libs: [ "libbase", "libbinder_ndk", "libxml2", ], test_suites: [ "general-tests", ], test_options: { unit_test: false, }, generated_sources: ["hfp_codec_capabilities"], generated_headers: ["hfp_codec_capabilities"], } xsd_config { name: "le_audio_codec_capabilities", srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"], Loading bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.cpp +78 −3 Original line number Diff line number Diff line Loading @@ -16,21 +16,96 @@ #include "BluetoothHfpCodecsProvider.h" #include <unordered_map> namespace aidl { namespace android { namespace hardware { namespace bluetooth { namespace audio { using hfp::setting::CodecType; using hfp::setting::PathConfiguration; static const char* kHfpCodecCapabilitiesFile = "/vendor/etc/aidl/hfp/hfp_codec_capabilities.xml"; std::optional<HfpOffloadSetting> BluetoothHfpCodecsProvider::ParseFromHfpOffloadSettingFile() { return std::nullopt; auto hfp_offload_setting = hfp::setting::readHfpOffloadSetting(kHfpCodecCapabilitiesFile); if (!hfp_offload_setting.has_value()) { LOG(ERROR) << __func__ << ": Failed to read " << kHfpCodecCapabilitiesFile; } return hfp_offload_setting; } std::vector<CodecInfo> BluetoothHfpCodecsProvider::GetHfpAudioCodecInfo( const std::optional<HfpOffloadSetting>& hfp_offload_setting) { (void)hfp_offload_setting; return std::vector<CodecInfo>(); std::vector<CodecInfo> result; if (!hfp_offload_setting.has_value()) return result; // Convert path configuration into map // Currently transport configuration is unused if (!hfp_offload_setting.value().hasPathConfiguration() || hfp_offload_setting.value().getPathConfiguration().empty()) { LOG(WARNING) << __func__ << ": path configurations is empty"; return result; } auto path_configurations = hfp_offload_setting.value().getPathConfiguration(); std::unordered_map<std::string, PathConfiguration> path_config_map; for (const auto& path_cfg : path_configurations) if (path_cfg.hasName() && path_cfg.hasDataPath()) path_config_map.insert(make_pair(path_cfg.getName(), path_cfg)); for (const auto& cfg : hfp_offload_setting.value().getConfiguration()) { auto input_path_cfg = path_config_map.find(cfg.getInputPathConfiguration()); auto output_path_cfg = path_config_map.find(cfg.getOutputPathConfiguration()); if (input_path_cfg == path_config_map.end()) { LOG(WARNING) << __func__ << ": Input path configuration not found: " << cfg.getInputPathConfiguration(); continue; } if (output_path_cfg == path_config_map.end()) { LOG(WARNING) << __func__ << ": Output path configuration not found: " << cfg.getOutputPathConfiguration(); continue; } CodecInfo codec_info; switch (cfg.getCodec()) { case CodecType::LC3: codec_info.id = CodecId::Core::LC3; break; case CodecType::MSBC: codec_info.id = CodecId::Core::MSBC; break; case CodecType::CVSD: codec_info.id = CodecId::Core::CVSD; break; default: LOG(WARNING) << __func__ << ": Unknown codec from " << cfg.getName(); codec_info.id = CodecId::Vendor(); break; } codec_info.name = cfg.getName(); codec_info.transport = CodecInfo::Transport::make<CodecInfo::Transport::Tag::hfp>(); auto& transport = codec_info.transport.get<CodecInfo::Transport::Tag::hfp>(); transport.useControllerCodec = cfg.getUseControllerCodec(); transport.inputDataPath = input_path_cfg->second.getDataPath(); transport.outputDataPath = output_path_cfg->second.getDataPath(); result.push_back(codec_info); } LOG(INFO) << __func__ << ": Has " << result.size() << " codec info"; return result; } } // namespace audio Loading bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.h +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include "aidl/android/hardware/bluetooth/audio/CodecInfo.h" #include "aidl_android_hardware_bluetooth_audio_hfp_setting.h" #include "aidl_android_hardware_bluetooth_audio_hfp_setting_enums.h" namespace aidl { namespace android { Loading bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProviderTest.cpp 0 → 100644 +153 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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 "BluetoothHfpCodecsProvider.h" #include "gtest/gtest.h" using aidl::android::hardware::bluetooth::audio::BluetoothHfpCodecsProvider; using aidl::android::hardware::bluetooth::audio::CodecInfo; using aidl::android::hardware::bluetooth::audio::hfp::setting::CodecType; using aidl::android::hardware::bluetooth::audio::hfp::setting::Configuration; using aidl::android::hardware::bluetooth::audio::hfp::setting:: HfpOffloadSetting; using aidl::android::hardware::bluetooth::audio::hfp::setting:: PathConfiguration; using aidl::android::hardware::bluetooth::audio::hfp::setting:: TransportConfiguration; typedef std::tuple<std::vector<PathConfiguration>, std::vector<TransportConfiguration>, std::vector<Configuration>> HfpOffloadSettingTuple; // Define valid components for each list // PathConfiguration static const PathConfiguration kValidPathConfigurationCVSD("CVSD_IO", 16000, CodecType::CVSD, 16, 2, 0, 1, 0); static const PathConfiguration kInvalidPathConfigurationNULL(std::nullopt, 16000, CodecType::CVSD, 16, 2, 0, 1, 0); static const PathConfiguration kInvalidPathConfigurationNoPath( "CVSD_NULL", 16000, CodecType::CVSD, 16, 2, 0, std::nullopt, 0); // Configuration static const Configuration kValidConfigurationCVSD("CVSD", CodecType::CVSD, 65535, 7, 0, true, "CVSD_IO", "CVSD_IO", std::nullopt, std::nullopt); static const Configuration kInvalidConfigurationCVSDNoPath( "CVSD", CodecType::CVSD, 65535, 7, 0, true, "CVSD_NULL", "CVSD_NULL", std::nullopt, std::nullopt); static const Configuration kInvalidConfigurationCVSDNotFound( "CVSD", CodecType::CVSD, 65535, 7, 0, true, "CVSD_N", "CVSD_N", std::nullopt, std::nullopt); class BluetoothHfpCodecsProviderTest : public ::testing::Test { public: static std::vector<HfpOffloadSettingTuple> CreateTestCases( const std::vector<std::vector<PathConfiguration>> path_configs_list, const std::vector<std::vector<TransportConfiguration>> transport_configs_list, const std::vector<std::vector<Configuration>> configs_list) { std::vector<HfpOffloadSettingTuple> test_cases; for (const auto& path_configs : path_configs_list) { for (const auto& transport_configs : transport_configs_list) { for (const auto& configs : configs_list) test_cases.push_back( CreateTestCase(path_configs, transport_configs, configs)); } } return test_cases; } protected: std::vector<CodecInfo> RunTestCase(HfpOffloadSettingTuple test_case) { auto& [path_configuration_list, transport_configuration_list, configuration_list] = test_case; HfpOffloadSetting hfp_offload_setting(path_configuration_list, transport_configuration_list, configuration_list); auto capabilities = BluetoothHfpCodecsProvider::GetHfpAudioCodecInfo(hfp_offload_setting); return capabilities; } private: static inline HfpOffloadSettingTuple CreateTestCase( const std::vector<PathConfiguration> path_config_list, const std::vector<TransportConfiguration> transport_config_list, const std::vector<Configuration> config_list) { return std::make_tuple(path_config_list, transport_config_list, config_list); } }; class GetHfpCodecInfoTest : public BluetoothHfpCodecsProviderTest { public: static std::vector<std::vector<PathConfiguration>> GetInvalidPathConfigurationLists() { std::vector<std::vector<PathConfiguration>> result; result.push_back({kInvalidPathConfigurationNULL}); result.push_back({kInvalidPathConfigurationNoPath}); result.push_back({}); return result; } static std::vector<std::vector<Configuration>> GetInvalidConfigurationLists() { std::vector<std::vector<Configuration>> result; result.push_back({kInvalidConfigurationCVSDNotFound}); result.push_back({kInvalidConfigurationCVSDNoPath}); result.push_back({}); return result; } }; TEST_F(GetHfpCodecInfoTest, InvalidPathConfiguration) { auto test_cases = BluetoothHfpCodecsProviderTest::CreateTestCases( GetHfpCodecInfoTest::GetInvalidPathConfigurationLists(), {{}}, {{kValidConfigurationCVSD}}); for (auto& test_case : test_cases) { auto hfp_codec_capabilities = RunTestCase(test_case); ASSERT_TRUE(hfp_codec_capabilities.empty()); } } TEST_F(GetHfpCodecInfoTest, InvalidConfigurationName) { auto test_cases = BluetoothHfpCodecsProviderTest::CreateTestCases( GetHfpCodecInfoTest::GetInvalidPathConfigurationLists(), {{}}, {GetHfpCodecInfoTest::GetInvalidConfigurationLists()}); for (auto& test_case : test_cases) { auto hfp_codec_capabilities = RunTestCase(test_case); ASSERT_TRUE(hfp_codec_capabilities.empty()); } } TEST_F(GetHfpCodecInfoTest, ValidConfiguration) { auto test_cases = BluetoothHfpCodecsProviderTest::CreateTestCases( {{kValidPathConfigurationCVSD}}, {{}}, {{kValidConfigurationCVSD}}); for (auto& test_case : test_cases) { auto hfp_codec_capabilities = RunTestCase(test_case); ASSERT_FALSE(hfp_codec_capabilities.empty()); } } Loading
bluetooth/audio/utils/Android.bp +29 −2 Original line number Diff line number Diff line Loading @@ -87,8 +87,6 @@ cc_library_shared { ], } // TODO: Write test for BluetoothHfpCodecsProvider.cpp cc_test { name: "BluetoothLeAudioCodecsProviderTest", srcs: [ Loading @@ -114,6 +112,35 @@ cc_test { generated_headers: ["le_audio_codec_capabilities"], } cc_test { name: "BluetoothHfpCodecsProviderTest", defaults: [ "latest_android_hardware_audio_common_ndk_static", "latest_android_hardware_bluetooth_audio_ndk_static", "latest_android_media_audio_common_types_ndk_static", ], srcs: [ "aidl_session/BluetoothHfpCodecsProvider.cpp", "aidl_session/BluetoothHfpCodecsProviderTest.cpp", ], header_libs: [ "libxsdc-utils", ], shared_libs: [ "libbase", "libbinder_ndk", "libxml2", ], test_suites: [ "general-tests", ], test_options: { unit_test: false, }, generated_sources: ["hfp_codec_capabilities"], generated_headers: ["hfp_codec_capabilities"], } xsd_config { name: "le_audio_codec_capabilities", srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"], Loading
bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.cpp +78 −3 Original line number Diff line number Diff line Loading @@ -16,21 +16,96 @@ #include "BluetoothHfpCodecsProvider.h" #include <unordered_map> namespace aidl { namespace android { namespace hardware { namespace bluetooth { namespace audio { using hfp::setting::CodecType; using hfp::setting::PathConfiguration; static const char* kHfpCodecCapabilitiesFile = "/vendor/etc/aidl/hfp/hfp_codec_capabilities.xml"; std::optional<HfpOffloadSetting> BluetoothHfpCodecsProvider::ParseFromHfpOffloadSettingFile() { return std::nullopt; auto hfp_offload_setting = hfp::setting::readHfpOffloadSetting(kHfpCodecCapabilitiesFile); if (!hfp_offload_setting.has_value()) { LOG(ERROR) << __func__ << ": Failed to read " << kHfpCodecCapabilitiesFile; } return hfp_offload_setting; } std::vector<CodecInfo> BluetoothHfpCodecsProvider::GetHfpAudioCodecInfo( const std::optional<HfpOffloadSetting>& hfp_offload_setting) { (void)hfp_offload_setting; return std::vector<CodecInfo>(); std::vector<CodecInfo> result; if (!hfp_offload_setting.has_value()) return result; // Convert path configuration into map // Currently transport configuration is unused if (!hfp_offload_setting.value().hasPathConfiguration() || hfp_offload_setting.value().getPathConfiguration().empty()) { LOG(WARNING) << __func__ << ": path configurations is empty"; return result; } auto path_configurations = hfp_offload_setting.value().getPathConfiguration(); std::unordered_map<std::string, PathConfiguration> path_config_map; for (const auto& path_cfg : path_configurations) if (path_cfg.hasName() && path_cfg.hasDataPath()) path_config_map.insert(make_pair(path_cfg.getName(), path_cfg)); for (const auto& cfg : hfp_offload_setting.value().getConfiguration()) { auto input_path_cfg = path_config_map.find(cfg.getInputPathConfiguration()); auto output_path_cfg = path_config_map.find(cfg.getOutputPathConfiguration()); if (input_path_cfg == path_config_map.end()) { LOG(WARNING) << __func__ << ": Input path configuration not found: " << cfg.getInputPathConfiguration(); continue; } if (output_path_cfg == path_config_map.end()) { LOG(WARNING) << __func__ << ": Output path configuration not found: " << cfg.getOutputPathConfiguration(); continue; } CodecInfo codec_info; switch (cfg.getCodec()) { case CodecType::LC3: codec_info.id = CodecId::Core::LC3; break; case CodecType::MSBC: codec_info.id = CodecId::Core::MSBC; break; case CodecType::CVSD: codec_info.id = CodecId::Core::CVSD; break; default: LOG(WARNING) << __func__ << ": Unknown codec from " << cfg.getName(); codec_info.id = CodecId::Vendor(); break; } codec_info.name = cfg.getName(); codec_info.transport = CodecInfo::Transport::make<CodecInfo::Transport::Tag::hfp>(); auto& transport = codec_info.transport.get<CodecInfo::Transport::Tag::hfp>(); transport.useControllerCodec = cfg.getUseControllerCodec(); transport.inputDataPath = input_path_cfg->second.getDataPath(); transport.outputDataPath = output_path_cfg->second.getDataPath(); result.push_back(codec_info); } LOG(INFO) << __func__ << ": Has " << result.size() << " codec info"; return result; } } // namespace audio Loading
bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProvider.h +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include "aidl/android/hardware/bluetooth/audio/CodecInfo.h" #include "aidl_android_hardware_bluetooth_audio_hfp_setting.h" #include "aidl_android_hardware_bluetooth_audio_hfp_setting_enums.h" namespace aidl { namespace android { Loading
bluetooth/audio/utils/aidl_session/BluetoothHfpCodecsProviderTest.cpp 0 → 100644 +153 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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 "BluetoothHfpCodecsProvider.h" #include "gtest/gtest.h" using aidl::android::hardware::bluetooth::audio::BluetoothHfpCodecsProvider; using aidl::android::hardware::bluetooth::audio::CodecInfo; using aidl::android::hardware::bluetooth::audio::hfp::setting::CodecType; using aidl::android::hardware::bluetooth::audio::hfp::setting::Configuration; using aidl::android::hardware::bluetooth::audio::hfp::setting:: HfpOffloadSetting; using aidl::android::hardware::bluetooth::audio::hfp::setting:: PathConfiguration; using aidl::android::hardware::bluetooth::audio::hfp::setting:: TransportConfiguration; typedef std::tuple<std::vector<PathConfiguration>, std::vector<TransportConfiguration>, std::vector<Configuration>> HfpOffloadSettingTuple; // Define valid components for each list // PathConfiguration static const PathConfiguration kValidPathConfigurationCVSD("CVSD_IO", 16000, CodecType::CVSD, 16, 2, 0, 1, 0); static const PathConfiguration kInvalidPathConfigurationNULL(std::nullopt, 16000, CodecType::CVSD, 16, 2, 0, 1, 0); static const PathConfiguration kInvalidPathConfigurationNoPath( "CVSD_NULL", 16000, CodecType::CVSD, 16, 2, 0, std::nullopt, 0); // Configuration static const Configuration kValidConfigurationCVSD("CVSD", CodecType::CVSD, 65535, 7, 0, true, "CVSD_IO", "CVSD_IO", std::nullopt, std::nullopt); static const Configuration kInvalidConfigurationCVSDNoPath( "CVSD", CodecType::CVSD, 65535, 7, 0, true, "CVSD_NULL", "CVSD_NULL", std::nullopt, std::nullopt); static const Configuration kInvalidConfigurationCVSDNotFound( "CVSD", CodecType::CVSD, 65535, 7, 0, true, "CVSD_N", "CVSD_N", std::nullopt, std::nullopt); class BluetoothHfpCodecsProviderTest : public ::testing::Test { public: static std::vector<HfpOffloadSettingTuple> CreateTestCases( const std::vector<std::vector<PathConfiguration>> path_configs_list, const std::vector<std::vector<TransportConfiguration>> transport_configs_list, const std::vector<std::vector<Configuration>> configs_list) { std::vector<HfpOffloadSettingTuple> test_cases; for (const auto& path_configs : path_configs_list) { for (const auto& transport_configs : transport_configs_list) { for (const auto& configs : configs_list) test_cases.push_back( CreateTestCase(path_configs, transport_configs, configs)); } } return test_cases; } protected: std::vector<CodecInfo> RunTestCase(HfpOffloadSettingTuple test_case) { auto& [path_configuration_list, transport_configuration_list, configuration_list] = test_case; HfpOffloadSetting hfp_offload_setting(path_configuration_list, transport_configuration_list, configuration_list); auto capabilities = BluetoothHfpCodecsProvider::GetHfpAudioCodecInfo(hfp_offload_setting); return capabilities; } private: static inline HfpOffloadSettingTuple CreateTestCase( const std::vector<PathConfiguration> path_config_list, const std::vector<TransportConfiguration> transport_config_list, const std::vector<Configuration> config_list) { return std::make_tuple(path_config_list, transport_config_list, config_list); } }; class GetHfpCodecInfoTest : public BluetoothHfpCodecsProviderTest { public: static std::vector<std::vector<PathConfiguration>> GetInvalidPathConfigurationLists() { std::vector<std::vector<PathConfiguration>> result; result.push_back({kInvalidPathConfigurationNULL}); result.push_back({kInvalidPathConfigurationNoPath}); result.push_back({}); return result; } static std::vector<std::vector<Configuration>> GetInvalidConfigurationLists() { std::vector<std::vector<Configuration>> result; result.push_back({kInvalidConfigurationCVSDNotFound}); result.push_back({kInvalidConfigurationCVSDNoPath}); result.push_back({}); return result; } }; TEST_F(GetHfpCodecInfoTest, InvalidPathConfiguration) { auto test_cases = BluetoothHfpCodecsProviderTest::CreateTestCases( GetHfpCodecInfoTest::GetInvalidPathConfigurationLists(), {{}}, {{kValidConfigurationCVSD}}); for (auto& test_case : test_cases) { auto hfp_codec_capabilities = RunTestCase(test_case); ASSERT_TRUE(hfp_codec_capabilities.empty()); } } TEST_F(GetHfpCodecInfoTest, InvalidConfigurationName) { auto test_cases = BluetoothHfpCodecsProviderTest::CreateTestCases( GetHfpCodecInfoTest::GetInvalidPathConfigurationLists(), {{}}, {GetHfpCodecInfoTest::GetInvalidConfigurationLists()}); for (auto& test_case : test_cases) { auto hfp_codec_capabilities = RunTestCase(test_case); ASSERT_TRUE(hfp_codec_capabilities.empty()); } } TEST_F(GetHfpCodecInfoTest, ValidConfiguration) { auto test_cases = BluetoothHfpCodecsProviderTest::CreateTestCases( {{kValidPathConfigurationCVSD}}, {{}}, {{kValidConfigurationCVSD}}); for (auto& test_case : test_cases) { auto hfp_codec_capabilities = RunTestCase(test_case); ASSERT_FALSE(hfp_codec_capabilities.empty()); } }