mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Implement HFP codec provider and test
Bug: 322280104 Test: atest BluetoothHfpCodecsProviderTest Change-Id: I4c5ca601de61d86a3caae88c47697a2586f4dc5c
This commit is contained in:
@@ -87,8 +87,6 @@ cc_library_shared {
|
||||
],
|
||||
}
|
||||
|
||||
// TODO: Write test for BluetoothHfpCodecsProvider.cpp
|
||||
|
||||
cc_test {
|
||||
name: "BluetoothLeAudioCodecsProviderTest",
|
||||
srcs: [
|
||||
@@ -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"],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user