1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "BluetoothHfpCodecsProvider.h"
18 
19 #include <unordered_map>
20 
21 namespace aidl {
22 namespace android {
23 namespace hardware {
24 namespace bluetooth {
25 namespace audio {
26 
27 using hfp::setting::CodecType;
28 using hfp::setting::PathConfiguration;
29 
30 static const char* kHfpCodecCapabilitiesFile =
31     "/vendor/etc/aidl/hfp/hfp_codec_capabilities.xml";
32 
33 std::optional<HfpOffloadSetting>
ParseFromHfpOffloadSettingFile()34 BluetoothHfpCodecsProvider::ParseFromHfpOffloadSettingFile() {
35   auto hfp_offload_setting =
36       hfp::setting::readHfpOffloadSetting(kHfpCodecCapabilitiesFile);
37   if (!hfp_offload_setting.has_value()) {
38     LOG(ERROR) << __func__ << ": Failed to read " << kHfpCodecCapabilitiesFile;
39   }
40   return hfp_offload_setting;
41 }
42 
GetHfpAudioCodecInfo(const std::optional<HfpOffloadSetting> & hfp_offload_setting)43 std::vector<CodecInfo> BluetoothHfpCodecsProvider::GetHfpAudioCodecInfo(
44     const std::optional<HfpOffloadSetting>& hfp_offload_setting) {
45   std::vector<CodecInfo> result;
46   if (!hfp_offload_setting.has_value()) return result;
47 
48   // Convert path configuration into map
49   // Currently transport configuration is unused
50   if (!hfp_offload_setting.value().hasPathConfiguration() ||
51       hfp_offload_setting.value().getPathConfiguration().empty()) {
52     LOG(WARNING) << __func__ << ": path configurations is empty";
53     return result;
54   }
55   auto path_configurations = hfp_offload_setting.value().getPathConfiguration();
56   std::unordered_map<std::string, PathConfiguration> path_config_map;
57   for (const auto& path_cfg : path_configurations)
58     if (path_cfg.hasName() && path_cfg.hasDataPath())
59       path_config_map.insert(make_pair(path_cfg.getName(), path_cfg));
60 
61   for (const auto& cfg : hfp_offload_setting.value().getConfiguration()) {
62     auto input_path_cfg = path_config_map.find(cfg.getInputPathConfiguration());
63     auto output_path_cfg =
64         path_config_map.find(cfg.getOutputPathConfiguration());
65     if (input_path_cfg == path_config_map.end()) {
66       LOG(WARNING) << __func__ << ": Input path configuration not found: "
67                    << cfg.getInputPathConfiguration();
68       continue;
69     }
70 
71     if (output_path_cfg == path_config_map.end()) {
72       LOG(WARNING) << __func__ << ": Output path configuration not found: "
73                    << cfg.getOutputPathConfiguration();
74       continue;
75     }
76 
77     CodecInfo codec_info;
78 
79     switch (cfg.getCodec()) {
80       case CodecType::LC3:
81         codec_info.id = CodecId::Core::LC3;
82         break;
83       case CodecType::MSBC:
84         codec_info.id = CodecId::Core::MSBC;
85         break;
86       case CodecType::CVSD:
87         codec_info.id = CodecId::Core::CVSD;
88         break;
89       default:
90         LOG(WARNING) << __func__ << ": Unknown codec from " << cfg.getName();
91         codec_info.id = CodecId::Vendor();
92         break;
93     }
94     codec_info.name = cfg.getName();
95 
96     codec_info.transport =
97         CodecInfo::Transport::make<CodecInfo::Transport::Tag::hfp>();
98 
99     auto& transport =
100         codec_info.transport.get<CodecInfo::Transport::Tag::hfp>();
101     transport.useControllerCodec = cfg.getUseControllerCodec();
102     transport.inputDataPath = input_path_cfg->second.getDataPath();
103     transport.outputDataPath = output_path_cfg->second.getDataPath();
104 
105     result.push_back(codec_info);
106   }
107   LOG(INFO) << __func__ << ": Has " << result.size() << " codec info";
108   return result;
109 }
110 
111 }  // namespace audio
112 }  // namespace bluetooth
113 }  // namespace hardware
114 }  // namespace android
115 }  // namespace aidl
116