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

Commit 4bde6695 authored by Bao Do's avatar Bao Do Committed by Gerrit Code Review
Browse files

Merge "Implement HFP codec provider and test" into main

parents 79dc7d43 e062de7b
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());
  }
}