Merge "Implement HFP codec provider and test" into main am: 4bde669522

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2967267

Change-Id: I6514030d591d0531680dad2494a54268aa3b7ff9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Bao Do
2024-03-08 19:03:57 +00:00
committed by Automerger Merge Worker
4 changed files with 261 additions and 5 deletions

View File

@@ -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"],

View File

@@ -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

View File

@@ -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 {

View File

@@ -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());
}
}