Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e062de7b authored by Bao Do's avatar Bao Do
Browse files

Implement HFP codec provider and test

Bug: 322280104
Test: atest BluetoothHfpCodecsProviderTest
Change-Id: I4c5ca601de61d86a3caae88c47697a2586f4dc5c
parent 2fa1ab4b
Loading
Loading
Loading
Loading
+29 −2
Original line number Diff line number Diff line
@@ -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"],
+78 −3
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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 {
+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());
  }
}