blob: bf492706c81226092cc14cdbfd92f1cc0b7078fa [file] [log] [blame]
shihchienc8ed901a2022-09-06 08:44:44 +00001/*
2 * Copyright (C) 2022 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#define LOG_TAG "BTAudioCodecsProviderAidl"
18
19#include "BluetoothLeAudioCodecsProvider.h"
20
21namespace aidl {
22namespace android {
23namespace hardware {
24namespace bluetooth {
25namespace audio {
26
27static const char* kLeAudioCodecCapabilitiesFile =
28 "/vendor/etc/le_audio_codec_capabilities.xml";
29
30static const AudioLocation kStereoAudio = static_cast<AudioLocation>(
31 static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
32 static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
33static const AudioLocation kMonoAudio = AudioLocation::UNKNOWN;
34
35static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;
36
37std::vector<LeAudioCodecCapabilitiesSetting>
38BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() {
39 if (!leAudioCodecCapabilities.empty()) {
40 return leAudioCodecCapabilities;
41 }
42
43 const auto le_audio_offload_setting =
44 setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
45 if (!le_audio_offload_setting.has_value()) {
46 LOG(ERROR) << __func__ << ": Failed to read "
47 << kLeAudioCodecCapabilitiesFile;
48 return {};
49 }
50
51 std::vector<setting::Scenario> supported_scenarios =
52 GetScenarios(le_audio_offload_setting);
53 if (supported_scenarios.empty()) {
54 LOG(ERROR) << __func__ << ": No scenarios in "
55 << kLeAudioCodecCapabilitiesFile;
56 return {};
57 }
58
59 UpdateConfigurationsToMap(le_audio_offload_setting);
60 if (configuration_map_.empty()) {
61 LOG(ERROR) << __func__ << ": No configurations in "
62 << kLeAudioCodecCapabilitiesFile;
63 return {};
64 }
65
66 UpdateCodecConfigurationsToMap(le_audio_offload_setting);
67 if (codec_configuration_map_.empty()) {
68 LOG(ERROR) << __func__ << ": No codec configurations in "
69 << kLeAudioCodecCapabilitiesFile;
70 return {};
71 }
72
73 UpdateStrategyConfigurationsToMap(le_audio_offload_setting);
74 if (strategy_configuration_map_.empty()) {
75 LOG(ERROR) << __func__ << ": No strategy configurations in "
76 << kLeAudioCodecCapabilitiesFile;
77 return {};
78 }
79
80 leAudioCodecCapabilities =
81 ComposeLeAudioCodecCapabilities(supported_scenarios);
82 return leAudioCodecCapabilities;
83}
84
85std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
86 const std::optional<setting::LeAudioOffloadSetting>&
87 le_audio_offload_setting) {
88 std::vector<setting::Scenario> supported_scenarios;
89 if (le_audio_offload_setting->hasScenarioList()) {
90 for (const auto& scenario_list :
91 le_audio_offload_setting->getScenarioList()) {
92 if (!scenario_list.hasScenario()) {
93 continue;
94 }
95 for (const auto& scenario : scenario_list.getScenario()) {
96 if (scenario.hasEncode() && scenario.hasDecode()) {
97 supported_scenarios.push_back(scenario);
98 }
99 }
100 }
101 }
102 return supported_scenarios;
103}
104
105void BluetoothLeAudioCodecsProvider::UpdateConfigurationsToMap(
106 const std::optional<setting::LeAudioOffloadSetting>&
107 le_audio_offload_setting) {
108 if (le_audio_offload_setting->hasConfigurationList()) {
109 for (const auto& configuration_list :
110 le_audio_offload_setting->getConfigurationList()) {
111 if (!configuration_list.hasConfiguration()) {
112 continue;
113 }
114 for (const auto& configuration : configuration_list.getConfiguration()) {
115 if (configuration.hasName() && configuration.hasCodecConfiguration() &&
116 configuration.hasStrategyConfiguration()) {
117 configuration_map_.insert(
118 make_pair(configuration.getName(), configuration));
119 }
120 }
121 }
122 }
123}
124
125void BluetoothLeAudioCodecsProvider::UpdateCodecConfigurationsToMap(
126 const std::optional<setting::LeAudioOffloadSetting>&
127 le_audio_offload_setting) {
128 if (le_audio_offload_setting->hasCodecConfigurationList()) {
129 for (const auto& codec_configuration_list :
130 le_audio_offload_setting->getCodecConfigurationList()) {
131 if (!codec_configuration_list.hasCodecConfiguration()) {
132 continue;
133 }
134 for (const auto& codec_configuration :
135 codec_configuration_list.getCodecConfiguration()) {
136 if (IsValidCodecConfiguration(codec_configuration)) {
137 codec_configuration_map_.insert(
138 make_pair(codec_configuration.getName(), codec_configuration));
139 }
140 }
141 }
142 }
143}
144
145void BluetoothLeAudioCodecsProvider::UpdateStrategyConfigurationsToMap(
146 const std::optional<setting::LeAudioOffloadSetting>&
147 le_audio_offload_setting) {
148 if (le_audio_offload_setting->hasStrategyConfigurationList()) {
149 for (const auto& strategy_configuration_list :
150 le_audio_offload_setting->getStrategyConfigurationList()) {
151 if (!strategy_configuration_list.hasStrategyConfiguration()) {
152 continue;
153 }
154 for (const auto& strategy_configuration :
155 strategy_configuration_list.getStrategyConfiguration()) {
156 if (IsValidStrategyConfiguration(strategy_configuration)) {
157 strategy_configuration_map_.insert(make_pair(
158 strategy_configuration.getName(), strategy_configuration));
159 }
160 }
161 }
162 }
163}
164
165std::vector<LeAudioCodecCapabilitiesSetting>
166BluetoothLeAudioCodecsProvider::ComposeLeAudioCodecCapabilities(
167 const std::vector<setting::Scenario>& supported_scenarios) {
168 std::vector<LeAudioCodecCapabilitiesSetting> le_audio_codec_capabilities;
169 for (const auto& scenario : supported_scenarios) {
170 UnicastCapability unicast_encode_capability =
171 GetUnicastCapability(scenario.getEncode());
172 UnicastCapability unicast_decode_capability =
173 GetUnicastCapability(scenario.getDecode());
174 // encode and decode cannot be unknown at the same time
175 if (unicast_encode_capability.codecType == CodecType::UNKNOWN &&
176 unicast_decode_capability.codecType == CodecType::UNKNOWN) {
177 continue;
178 }
179 BroadcastCapability broadcast_capability = {.codecType =
180 CodecType::UNKNOWN};
181 le_audio_codec_capabilities.push_back(
182 {.unicastEncodeCapability = unicast_encode_capability,
183 .unicastDecodeCapability = unicast_decode_capability,
184 .broadcastCapability = broadcast_capability});
185 }
186 return le_audio_codec_capabilities;
187}
188
189UnicastCapability BluetoothLeAudioCodecsProvider::GetUnicastCapability(
190 const std::string& coding_direction) {
191 if (coding_direction == "invalid") {
192 return {.codecType = CodecType::UNKNOWN};
193 }
194
195 auto configuration_iter = configuration_map_.find(coding_direction);
196 if (configuration_iter == configuration_map_.end()) {
197 return {.codecType = CodecType::UNKNOWN};
198 }
199
200 auto codec_configuration_iter = codec_configuration_map_.find(
201 configuration_iter->second.getCodecConfiguration());
202 if (codec_configuration_iter == codec_configuration_map_.end()) {
203 return {.codecType = CodecType::UNKNOWN};
204 }
205
206 auto strategy_configuration_iter = strategy_configuration_map_.find(
207 configuration_iter->second.getStrategyConfiguration());
208 if (strategy_configuration_iter == strategy_configuration_map_.end()) {
209 return {.codecType = CodecType::UNKNOWN};
210 }
211
212 CodecType codec_type =
213 GetCodecType(codec_configuration_iter->second.getCodec());
214 if (codec_type == CodecType::LC3) {
215 return ComposeUnicastCapability(
216 codec_type,
217 GetAudioLocation(
218 strategy_configuration_iter->second.getAudioLocation()),
219 strategy_configuration_iter->second.getConnectedDevice(),
220 strategy_configuration_iter->second.getChannelCount(),
221 ComposeLc3Capability(codec_configuration_iter->second));
222 }
223 return {.codecType = CodecType::UNKNOWN};
224}
225
226template <class T>
227UnicastCapability BluetoothLeAudioCodecsProvider::ComposeUnicastCapability(
228 const CodecType& codec_type, const AudioLocation& audio_location,
229 const uint8_t& device_cnt, const uint8_t& channel_count,
230 const T& capability) {
231 return {
232 .codecType = codec_type,
233 .supportedChannel = audio_location,
234 .deviceCount = device_cnt,
235 .channelCountPerDevice = channel_count,
236 .leAudioCodecCapabilities =
237 UnicastCapability::LeAudioCodecCapabilities(capability),
238 };
239}
240
241Lc3Capabilities BluetoothLeAudioCodecsProvider::ComposeLc3Capability(
242 const setting::CodecConfiguration& codec_configuration) {
243 return {.samplingFrequencyHz = {codec_configuration.getSamplingFrequency()},
244 .frameDurationUs = {codec_configuration.getFrameDurationUs()},
245 .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}};
246}
247
248AudioLocation BluetoothLeAudioCodecsProvider::GetAudioLocation(
249 const setting::AudioLocation& audio_location) {
250 switch (audio_location) {
251 case setting::AudioLocation::MONO:
252 return kMonoAudio;
253 case setting::AudioLocation::STEREO:
254 return kStereoAudio;
255 default:
256 return AudioLocation::UNKNOWN;
257 }
258}
259
260CodecType BluetoothLeAudioCodecsProvider::GetCodecType(
261 const setting::CodecType& codec_type) {
262 switch (codec_type) {
263 case setting::CodecType::LC3:
264 return CodecType::LC3;
265 default:
266 return CodecType::UNKNOWN;
267 }
268}
269
270bool BluetoothLeAudioCodecsProvider::IsValidCodecConfiguration(
271 const setting::CodecConfiguration& codec_configuration) {
272 return codec_configuration.hasName() && codec_configuration.hasCodec() &&
273 codec_configuration.hasSamplingFrequency() &&
274 codec_configuration.hasFrameDurationUs() &&
275 codec_configuration.hasOctetsPerCodecFrame();
276}
277
278bool BluetoothLeAudioCodecsProvider::IsValidStrategyConfiguration(
279 const setting::StrategyConfiguration& strategy_configuration) {
280 if (!strategy_configuration.hasName() ||
281 !strategy_configuration.hasAudioLocation() ||
282 !strategy_configuration.hasConnectedDevice() ||
283 !strategy_configuration.hasChannelCount()) {
284 return false;
285 }
286 if (strategy_configuration.getAudioLocation() ==
287 setting::AudioLocation::STEREO) {
288 if ((strategy_configuration.getConnectedDevice() == 2 &&
289 strategy_configuration.getChannelCount() == 1) ||
290 (strategy_configuration.getConnectedDevice() == 1 &&
291 strategy_configuration.getChannelCount() == 2)) {
292 // Stereo
293 // 1. two connected device, one for L one for R
294 // 2. one connected device for both L and R
295 return true;
296 }
297 } else if (strategy_configuration.getAudioLocation() ==
298 setting::AudioLocation::MONO) {
299 if (strategy_configuration.getConnectedDevice() == 1 &&
300 strategy_configuration.getChannelCount() == 1) {
301 // Mono
302 return true;
303 }
304 }
305 return false;
306}
307
308} // namespace audio
309} // namespace bluetooth
310} // namespace hardware
311} // namespace android
312} // namespace aidl