1 /*
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 #include <optional>
18 #include <set>
19
20 #include "aidl/android/hardware/bluetooth/audio/ChannelMode.h"
21 #include "aidl/android/hardware/bluetooth/audio/CodecId.h"
22 #include "aidl/android/hardware/bluetooth/audio/CodecInfo.h"
23 #include "aidl/android/hardware/bluetooth/audio/ConfigurationFlags.h"
24 #include "aidl_android_hardware_bluetooth_audio_setting_enums.h"
25 #define LOG_TAG "BTAudioCodecsProviderAidl"
26
27 #include "BluetoothLeAudioCodecsProvider.h"
28
29 namespace aidl {
30 namespace android {
31 namespace hardware {
32 namespace bluetooth {
33 namespace audio {
34
35 static const char* kLeAudioCodecCapabilitiesFile =
36 "/vendor/etc/le_audio_codec_capabilities.xml";
37
38 static const AudioLocation kStereoAudio = static_cast<AudioLocation>(
39 static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
40 static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
41 static const AudioLocation kMonoAudio = AudioLocation::UNKNOWN;
42
43 static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;
44
45 static bool isInvalidFileContent = false;
46
47 std::optional<setting::LeAudioOffloadSetting>
ParseFromLeAudioOffloadSettingFile()48 BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile() {
49 auto le_audio_offload_setting =
50 setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
51 if (!le_audio_offload_setting.has_value()) {
52 LOG(ERROR) << __func__ << ": Failed to read "
53 << kLeAudioCodecCapabilitiesFile;
54 }
55 return le_audio_offload_setting;
56 }
57
add_flag(CodecInfo & codec_info,int32_t bitmask)58 void add_flag(CodecInfo& codec_info, int32_t bitmask) {
59 auto& transport =
60 codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
61 if (!transport.flags.has_value()) transport.flags = ConfigurationFlags();
62 transport.flags->bitmask |= bitmask;
63 }
64
65 // Compare 2 codec info to see if they are equal.
66 // Currently only compare bitdepth, frameDurationUs and samplingFrequencyHz
is_equal(CodecInfo & codec_info_a,CodecInfo & codec_info_b)67 bool is_equal(CodecInfo& codec_info_a, CodecInfo& codec_info_b) {
68 auto& transport_a =
69 codec_info_a.transport.get<CodecInfo::Transport::Tag::leAudio>();
70 auto& transport_b =
71 codec_info_b.transport.get<CodecInfo::Transport::Tag::leAudio>();
72 return codec_info_a.name == codec_info_b.name &&
73 transport_a.bitdepth == transport_b.bitdepth &&
74 transport_a.frameDurationUs == transport_b.frameDurationUs &&
75 transport_a.samplingFrequencyHz == transport_b.samplingFrequencyHz;
76 }
77
78 std::unordered_map<SessionType, std::vector<CodecInfo>>
GetLeAudioCodecInfo(const std::optional<setting::LeAudioOffloadSetting> & le_audio_offload_setting)79 BluetoothLeAudioCodecsProvider::GetLeAudioCodecInfo(
80 const std::optional<setting::LeAudioOffloadSetting>&
81 le_audio_offload_setting) {
82 // Load from previous storage if present
83 if (!session_codecs_map_.empty()) return session_codecs_map_;
84
85 isInvalidFileContent = true;
86 if (!le_audio_offload_setting.has_value()) return {};
87
88 // Load scenario, configuration, codec configuration and strategy
89 LoadConfigurationToMap(le_audio_offload_setting);
90 if (supported_scenarios_.empty() || configuration_map_.empty() ||
91 codec_configuration_map_.empty() || strategy_configuration_map_.empty())
92 return {};
93
94 // Map each configuration into a CodecInfo
95 std::unordered_map<std::string, CodecInfo> config_codec_info_map_;
96
97 for (auto& p : configuration_map_) {
98 // Initialize new CodecInfo for the config
99 auto config_name = p.first;
100
101 // Getting informations from codecConfig and strategyConfig
102 const auto codec_config_name = p.second.getCodecConfiguration();
103 const auto strategy_config_name = p.second.getStrategyConfiguration();
104 const auto codec_configuration_map_iter =
105 codec_configuration_map_.find(codec_config_name);
106 if (codec_configuration_map_iter == codec_configuration_map_.end())
107 continue;
108 const auto strategy_configuration_map_iter =
109 strategy_configuration_map_.find(strategy_config_name);
110 if (strategy_configuration_map_iter == strategy_configuration_map_.end())
111 continue;
112
113 if (config_codec_info_map_.count(config_name) == 0)
114 config_codec_info_map_[config_name] = CodecInfo();
115
116 const auto& codec_config = codec_configuration_map_iter->second;
117 const auto codec = codec_config.getCodec();
118 const auto& strategy_config = strategy_configuration_map_iter->second;
119 const auto strategy_config_channel_count =
120 strategy_config.getChannelCount();
121
122 // Initiate information
123 auto& codec_info = config_codec_info_map_[config_name];
124 switch (codec) {
125 case setting::CodecType::LC3:
126 codec_info.name = "LC3";
127 codec_info.id = CodecId::Core::LC3;
128 break;
129 default:
130 codec_info.name = "UNDEFINE";
131 codec_info.id = CodecId::Vendor();
132 break;
133 }
134 codec_info.transport =
135 CodecInfo::Transport::make<CodecInfo::Transport::Tag::leAudio>();
136
137 // Add low latency support by default
138 add_flag(codec_info, ConfigurationFlags::LOW_LATENCY);
139
140 // Mapping codec configuration information
141 auto& transport =
142 codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
143 transport.samplingFrequencyHz.push_back(
144 codec_config.getSamplingFrequency());
145 // Mapping octetsPerCodecFrame to bitdepth for easier comparison.
146 transport.bitdepth.push_back(codec_config.getOctetsPerCodecFrame());
147 transport.frameDurationUs.push_back(codec_config.getFrameDurationUs());
148 if (strategy_config.hasAudioLocation()) {
149 switch (strategy_config.getAudioLocation()) {
150 case setting::AudioLocation::MONO:
151 if (strategy_config_channel_count == 1)
152 transport.channelMode.push_back(ChannelMode::MONO);
153 else
154 transport.channelMode.push_back(ChannelMode::DUALMONO);
155 break;
156 case setting::AudioLocation::STEREO:
157 transport.channelMode.push_back(ChannelMode::STEREO);
158 break;
159 default:
160 transport.channelMode.push_back(ChannelMode::UNKNOWN);
161 break;
162 }
163 } else if (strategy_config.hasAudioChannelAllocation()) {
164 auto count =
165 std::bitset<32>(strategy_config.getAudioChannelAllocation()).count();
166 if (count <= 1) {
167 if (strategy_config_channel_count == 1)
168 transport.channelMode.push_back(ChannelMode::MONO);
169 else
170 transport.channelMode.push_back(ChannelMode::DUALMONO);
171 } else if (count == 2) {
172 transport.channelMode.push_back(ChannelMode::STEREO);
173 } else {
174 transport.channelMode.push_back(ChannelMode::UNKNOWN);
175 }
176 } else {
177 transport.channelMode.push_back(ChannelMode::UNKNOWN);
178 }
179 }
180
181 // Goes through a list of scenarios and detect asymmetrical config using
182 // codecConfiguration name.
183 for (auto& s : supported_scenarios_) {
184 if (s.hasEncode() && s.hasDecode() &&
185 config_codec_info_map_.count(s.getEncode()) &&
186 config_codec_info_map_.count(s.getDecode())) {
187 // Check if it's actually using the different codec
188 auto& encode_codec_info = config_codec_info_map_[s.getEncode()];
189 auto& decode_codec_info = config_codec_info_map_[s.getDecode()];
190 if (!is_equal(encode_codec_info, decode_codec_info)) {
191 // Change both x and y to become asymmetrical
192 add_flag(encode_codec_info,
193 ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS);
194 add_flag(decode_codec_info,
195 ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS);
196 }
197 }
198 }
199
200 // Goes through every scenario, deduplicate configuration, skip the invalid
201 // config references (e.g. the "invalid" entries in the xml file).
202 std::set<std::string> encoding_config, decoding_config, broadcast_config;
203 for (auto& s : supported_scenarios_) {
204 if (s.hasEncode() && config_codec_info_map_.count(s.getEncode())) {
205 encoding_config.insert(s.getEncode());
206 }
207 if (s.hasDecode() && config_codec_info_map_.count(s.getDecode())) {
208 decoding_config.insert(s.getDecode());
209 }
210 if (s.hasBroadcast() && config_codec_info_map_.count(s.getBroadcast())) {
211 broadcast_config.insert(s.getBroadcast());
212 }
213 }
214
215 // Split by session types and add results
216 const auto encoding_path =
217 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
218 const auto decoding_path =
219 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
220 const auto broadcast_path =
221 SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
222 session_codecs_map_ =
223 std::unordered_map<SessionType, std::vector<CodecInfo>>();
224 session_codecs_map_[encoding_path] = std::vector<CodecInfo>();
225 session_codecs_map_[decoding_path] = std::vector<CodecInfo>();
226 session_codecs_map_[broadcast_path] = std::vector<CodecInfo>();
227 session_codecs_map_[encoding_path].reserve(encoding_config.size());
228 session_codecs_map_[decoding_path].reserve(decoding_config.size());
229 session_codecs_map_[broadcast_path].reserve(broadcast_config.size());
230 for (auto& c : encoding_config)
231 session_codecs_map_[encoding_path].push_back(config_codec_info_map_[c]);
232 for (auto& c : decoding_config)
233 session_codecs_map_[decoding_path].push_back(config_codec_info_map_[c]);
234 for (auto& c : broadcast_config)
235 session_codecs_map_[broadcast_path].push_back(config_codec_info_map_[c]);
236
237 isInvalidFileContent = session_codecs_map_.empty();
238
239 return session_codecs_map_;
240 }
241
242 std::vector<LeAudioCodecCapabilitiesSetting>
GetLeAudioCodecCapabilities(const std::optional<setting::LeAudioOffloadSetting> & le_audio_offload_setting)243 BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
244 const std::optional<setting::LeAudioOffloadSetting>&
245 le_audio_offload_setting) {
246 if (!leAudioCodecCapabilities.empty()) {
247 return leAudioCodecCapabilities;
248 }
249
250 isInvalidFileContent = true;
251
252 if (!le_audio_offload_setting.has_value()) {
253 LOG(ERROR)
254 << __func__
255 << ": input le_audio_offload_setting content need to be non empty";
256 return {};
257 }
258
259 LoadConfigurationToMap(le_audio_offload_setting);
260 if (supported_scenarios_.empty() || configuration_map_.empty() ||
261 codec_configuration_map_.empty() || strategy_configuration_map_.empty())
262 return {};
263
264 leAudioCodecCapabilities =
265 ComposeLeAudioCodecCapabilities(supported_scenarios_);
266 isInvalidFileContent = leAudioCodecCapabilities.empty();
267
268 return leAudioCodecCapabilities;
269 }
270
ClearLeAudioCodecCapabilities()271 void BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities() {
272 leAudioCodecCapabilities.clear();
273 configuration_map_.clear();
274 codec_configuration_map_.clear();
275 strategy_configuration_map_.clear();
276 session_codecs_map_.clear();
277 supported_scenarios_.clear();
278 }
279
GetScenarios(const std::optional<setting::LeAudioOffloadSetting> & le_audio_offload_setting)280 std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
281 const std::optional<setting::LeAudioOffloadSetting>&
282 le_audio_offload_setting) {
283 std::vector<setting::Scenario> supported_scenarios;
284 if (le_audio_offload_setting->hasScenarioList()) {
285 for (const auto& scenario_list :
286 le_audio_offload_setting->getScenarioList()) {
287 if (!scenario_list.hasScenario()) {
288 continue;
289 }
290 for (const auto& scenario : scenario_list.getScenario()) {
291 if (scenario.hasEncode() && scenario.hasDecode()) {
292 supported_scenarios.push_back(scenario);
293 }
294 }
295 }
296 }
297 return supported_scenarios;
298 }
299
UpdateConfigurationsToMap(const std::optional<setting::LeAudioOffloadSetting> & le_audio_offload_setting)300 void BluetoothLeAudioCodecsProvider::UpdateConfigurationsToMap(
301 const std::optional<setting::LeAudioOffloadSetting>&
302 le_audio_offload_setting) {
303 if (le_audio_offload_setting->hasConfigurationList()) {
304 for (const auto& configuration_list :
305 le_audio_offload_setting->getConfigurationList()) {
306 if (!configuration_list.hasConfiguration()) {
307 continue;
308 }
309 for (const auto& configuration : configuration_list.getConfiguration()) {
310 if (configuration.hasName() && configuration.hasCodecConfiguration() &&
311 configuration.hasStrategyConfiguration()) {
312 configuration_map_.insert(
313 make_pair(configuration.getName(), configuration));
314 }
315 }
316 }
317 }
318 }
319
UpdateCodecConfigurationsToMap(const std::optional<setting::LeAudioOffloadSetting> & le_audio_offload_setting)320 void BluetoothLeAudioCodecsProvider::UpdateCodecConfigurationsToMap(
321 const std::optional<setting::LeAudioOffloadSetting>&
322 le_audio_offload_setting) {
323 if (le_audio_offload_setting->hasCodecConfigurationList()) {
324 for (const auto& codec_configuration_list :
325 le_audio_offload_setting->getCodecConfigurationList()) {
326 if (!codec_configuration_list.hasCodecConfiguration()) {
327 continue;
328 }
329 for (const auto& codec_configuration :
330 codec_configuration_list.getCodecConfiguration()) {
331 if (IsValidCodecConfiguration(codec_configuration)) {
332 codec_configuration_map_.insert(
333 make_pair(codec_configuration.getName(), codec_configuration));
334 }
335 }
336 }
337 }
338 }
339
UpdateStrategyConfigurationsToMap(const std::optional<setting::LeAudioOffloadSetting> & le_audio_offload_setting)340 void BluetoothLeAudioCodecsProvider::UpdateStrategyConfigurationsToMap(
341 const std::optional<setting::LeAudioOffloadSetting>&
342 le_audio_offload_setting) {
343 if (le_audio_offload_setting->hasStrategyConfigurationList()) {
344 for (const auto& strategy_configuration_list :
345 le_audio_offload_setting->getStrategyConfigurationList()) {
346 if (!strategy_configuration_list.hasStrategyConfiguration()) {
347 continue;
348 }
349 for (const auto& strategy_configuration :
350 strategy_configuration_list.getStrategyConfiguration()) {
351 if (IsValidStrategyConfiguration(strategy_configuration)) {
352 strategy_configuration_map_.insert(make_pair(
353 strategy_configuration.getName(), strategy_configuration));
354 }
355 }
356 }
357 }
358 }
359
LoadConfigurationToMap(const std::optional<setting::LeAudioOffloadSetting> & le_audio_offload_setting)360 void BluetoothLeAudioCodecsProvider::LoadConfigurationToMap(
361 const std::optional<setting::LeAudioOffloadSetting>&
362 le_audio_offload_setting) {
363 ClearLeAudioCodecCapabilities();
364
365 supported_scenarios_ = GetScenarios(le_audio_offload_setting);
366 if (supported_scenarios_.empty()) {
367 LOG(ERROR) << __func__ << ": No scenarios in "
368 << kLeAudioCodecCapabilitiesFile;
369 return;
370 }
371
372 UpdateConfigurationsToMap(le_audio_offload_setting);
373 if (configuration_map_.empty()) {
374 LOG(ERROR) << __func__ << ": No configurations in "
375 << kLeAudioCodecCapabilitiesFile;
376 return;
377 }
378
379 UpdateCodecConfigurationsToMap(le_audio_offload_setting);
380 if (codec_configuration_map_.empty()) {
381 LOG(ERROR) << __func__ << ": No codec configurations in "
382 << kLeAudioCodecCapabilitiesFile;
383 return;
384 }
385
386 UpdateStrategyConfigurationsToMap(le_audio_offload_setting);
387 if (strategy_configuration_map_.empty()) {
388 LOG(ERROR) << __func__ << ": No strategy configurations in "
389 << kLeAudioCodecCapabilitiesFile;
390 return;
391 }
392 }
393
394 std::vector<LeAudioCodecCapabilitiesSetting>
ComposeLeAudioCodecCapabilities(const std::vector<setting::Scenario> & supported_scenarios)395 BluetoothLeAudioCodecsProvider::ComposeLeAudioCodecCapabilities(
396 const std::vector<setting::Scenario>& supported_scenarios) {
397 std::vector<LeAudioCodecCapabilitiesSetting> le_audio_codec_capabilities;
398 for (const auto& scenario : supported_scenarios) {
399 UnicastCapability unicast_encode_capability =
400 GetUnicastCapability(scenario.getEncode());
401 LOG(INFO) << __func__ << ": Unicast capability encode = "
402 << unicast_encode_capability.toString();
403 UnicastCapability unicast_decode_capability =
404 GetUnicastCapability(scenario.getDecode());
405 LOG(INFO) << __func__ << ": Unicast capability decode = "
406 << unicast_decode_capability.toString();
407 BroadcastCapability broadcast_capability = {.codecType =
408 CodecType::UNKNOWN};
409
410 if (scenario.hasBroadcast()) {
411 broadcast_capability = GetBroadcastCapability(scenario.getBroadcast());
412 }
413
414 // At least one capability should be valid
415 if (unicast_encode_capability.codecType == CodecType::UNKNOWN &&
416 unicast_decode_capability.codecType == CodecType::UNKNOWN &&
417 broadcast_capability.codecType == CodecType::UNKNOWN) {
418 LOG(ERROR) << __func__ << ": None of the capability is valid.";
419 continue;
420 }
421
422 le_audio_codec_capabilities.push_back(
423 {.unicastEncodeCapability = unicast_encode_capability,
424 .unicastDecodeCapability = unicast_decode_capability,
425 .broadcastCapability = broadcast_capability});
426 }
427 return le_audio_codec_capabilities;
428 }
429
GetUnicastCapability(const std::string & coding_direction)430 UnicastCapability BluetoothLeAudioCodecsProvider::GetUnicastCapability(
431 const std::string& coding_direction) {
432 if (coding_direction == "invalid") {
433 return {.codecType = CodecType::UNKNOWN};
434 }
435
436 auto configuration_iter = configuration_map_.find(coding_direction);
437 if (configuration_iter == configuration_map_.end()) {
438 return {.codecType = CodecType::UNKNOWN};
439 }
440
441 auto codec_configuration_iter = codec_configuration_map_.find(
442 configuration_iter->second.getCodecConfiguration());
443 if (codec_configuration_iter == codec_configuration_map_.end()) {
444 return {.codecType = CodecType::UNKNOWN};
445 }
446
447 auto strategy_configuration_iter = strategy_configuration_map_.find(
448 configuration_iter->second.getStrategyConfiguration());
449 if (strategy_configuration_iter == strategy_configuration_map_.end()) {
450 return {.codecType = CodecType::UNKNOWN};
451 }
452
453 // Populate audio location
454 AudioLocation audio_location = AudioLocation::UNKNOWN;
455 if (strategy_configuration_iter->second.hasAudioLocation()) {
456 audio_location = GetAudioLocation(
457 strategy_configuration_iter->second.getAudioLocation());
458 }
459
460 // Populate audio channel allocation
461 std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>
462 audio_channel_allocation = std::nullopt;
463 if (strategy_configuration_iter->second.hasAudioChannelAllocation()) {
464 LOG(INFO) << __func__ << ": has allocation";
465 CodecSpecificConfigurationLtv::AudioChannelAllocation tmp;
466 tmp.bitmask =
467 strategy_configuration_iter->second.getAudioChannelAllocation();
468 audio_channel_allocation = tmp;
469 }
470
471 CodecType codec_type =
472 GetCodecType(codec_configuration_iter->second.getCodec());
473 if (codec_type == CodecType::LC3) {
474 return ComposeUnicastCapability(
475 codec_type, audio_location, audio_channel_allocation,
476 strategy_configuration_iter->second.getConnectedDevice(),
477 strategy_configuration_iter->second.getChannelCount(),
478 ComposeLc3Capability(codec_configuration_iter->second));
479 } else if (codec_type == CodecType::APTX_ADAPTIVE_LE ||
480 codec_type == CodecType::APTX_ADAPTIVE_LEX) {
481 return ComposeUnicastCapability(
482 codec_type, audio_location, audio_channel_allocation,
483 strategy_configuration_iter->second.getConnectedDevice(),
484 strategy_configuration_iter->second.getChannelCount(),
485 ComposeAptxAdaptiveLeCapability(codec_configuration_iter->second));
486 }
487 return {.codecType = CodecType::UNKNOWN};
488 }
489
GetBroadcastCapability(const std::string & coding_direction)490 BroadcastCapability BluetoothLeAudioCodecsProvider::GetBroadcastCapability(
491 const std::string& coding_direction) {
492 if (coding_direction == "invalid") {
493 return {.codecType = CodecType::UNKNOWN};
494 }
495
496 auto configuration_iter = configuration_map_.find(coding_direction);
497 if (configuration_iter == configuration_map_.end()) {
498 return {.codecType = CodecType::UNKNOWN};
499 }
500
501 auto codec_configuration_iter = codec_configuration_map_.find(
502 configuration_iter->second.getCodecConfiguration());
503 if (codec_configuration_iter == codec_configuration_map_.end()) {
504 return {.codecType = CodecType::UNKNOWN};
505 }
506
507 auto strategy_configuration_iter = strategy_configuration_map_.find(
508 configuration_iter->second.getStrategyConfiguration());
509 if (strategy_configuration_iter == strategy_configuration_map_.end()) {
510 return {.codecType = CodecType::UNKNOWN};
511 }
512
513 CodecType codec_type =
514 GetCodecType(codec_configuration_iter->second.getCodec());
515 std::vector<std::optional<Lc3Capabilities>> bcastLc3Cap(
516 1, std::optional(ComposeLc3Capability(codec_configuration_iter->second)));
517
518 // Populate audio location
519 AudioLocation audio_location = AudioLocation::UNKNOWN;
520 if (strategy_configuration_iter->second.hasAudioLocation()) {
521 audio_location = GetAudioLocation(
522 strategy_configuration_iter->second.getAudioLocation());
523 }
524
525 // Populate audio channel allocation
526 std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>
527 audio_channel_allocation = std::nullopt;
528 if (strategy_configuration_iter->second.hasAudioChannelAllocation()) {
529 LOG(INFO) << __func__ << ": has allocation";
530 CodecSpecificConfigurationLtv::AudioChannelAllocation tmp;
531 tmp.bitmask =
532 strategy_configuration_iter->second.getAudioChannelAllocation();
533 audio_channel_allocation = tmp;
534 }
535
536 if (codec_type == CodecType::LC3) {
537 return ComposeBroadcastCapability(
538 codec_type, audio_location, audio_channel_allocation,
539 strategy_configuration_iter->second.getChannelCount(), bcastLc3Cap);
540 }
541 return {.codecType = CodecType::UNKNOWN};
542 }
543
544 template <class T>
ComposeBroadcastCapability(const CodecType & codec_type,const AudioLocation & audio_location,const std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation> & audio_channel_allocation,const uint8_t & channel_count,const std::vector<T> & capability)545 BroadcastCapability BluetoothLeAudioCodecsProvider::ComposeBroadcastCapability(
546 const CodecType& codec_type, const AudioLocation& audio_location,
547 const std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>&
548 audio_channel_allocation,
549 const uint8_t& channel_count, const std::vector<T>& capability) {
550 return {.codecType = codec_type,
551 .supportedChannel = audio_location,
552 .channelCountPerStream = channel_count,
553 .leAudioCodecCapabilities = std::optional(capability),
554 .audioLocation = audio_channel_allocation};
555 }
556
557 template <class T>
ComposeUnicastCapability(const CodecType & codec_type,const AudioLocation & audio_location,const std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation> & audio_channel_allocation,const uint8_t & device_cnt,const uint8_t & channel_count,const T & capability)558 UnicastCapability BluetoothLeAudioCodecsProvider::ComposeUnicastCapability(
559 const CodecType& codec_type, const AudioLocation& audio_location,
560 const std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>&
561 audio_channel_allocation,
562 const uint8_t& device_cnt, const uint8_t& channel_count,
563 const T& capability) {
564 return {
565 .codecType = codec_type,
566 .supportedChannel = audio_location,
567 .deviceCount = device_cnt,
568 .channelCountPerDevice = channel_count,
569 .leAudioCodecCapabilities =
570 UnicastCapability::LeAudioCodecCapabilities(capability),
571 .audioLocation = audio_channel_allocation,
572 };
573 }
574
ComposeLc3Capability(const setting::CodecConfiguration & codec_configuration)575 Lc3Capabilities BluetoothLeAudioCodecsProvider::ComposeLc3Capability(
576 const setting::CodecConfiguration& codec_configuration) {
577 return {.samplingFrequencyHz = {codec_configuration.getSamplingFrequency()},
578 .frameDurationUs = {codec_configuration.getFrameDurationUs()},
579 .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}};
580 }
581
582 AptxAdaptiveLeCapabilities
ComposeAptxAdaptiveLeCapability(const setting::CodecConfiguration & codec_configuration)583 BluetoothLeAudioCodecsProvider::ComposeAptxAdaptiveLeCapability(
584 const setting::CodecConfiguration& codec_configuration) {
585 return {.samplingFrequencyHz = {codec_configuration.getSamplingFrequency()},
586 .frameDurationUs = {codec_configuration.getFrameDurationUs()},
587 .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}};
588 }
589
GetAudioLocation(const setting::AudioLocation & audio_location)590 AudioLocation BluetoothLeAudioCodecsProvider::GetAudioLocation(
591 const setting::AudioLocation& audio_location) {
592 switch (audio_location) {
593 case setting::AudioLocation::MONO:
594 return kMonoAudio;
595 case setting::AudioLocation::STEREO:
596 return kStereoAudio;
597 default:
598 return AudioLocation::UNKNOWN;
599 }
600 }
601
GetCodecType(const setting::CodecType & codec_type)602 CodecType BluetoothLeAudioCodecsProvider::GetCodecType(
603 const setting::CodecType& codec_type) {
604 switch (codec_type) {
605 case setting::CodecType::LC3:
606 return CodecType::LC3;
607 case setting::CodecType::APTX_ADAPTIVE_LE:
608 return CodecType::APTX_ADAPTIVE_LE;
609 case setting::CodecType::APTX_ADAPTIVE_LEX:
610 return CodecType::APTX_ADAPTIVE_LEX;
611 default:
612 return CodecType::UNKNOWN;
613 }
614 }
615
IsValidCodecConfiguration(const setting::CodecConfiguration & codec_configuration)616 bool BluetoothLeAudioCodecsProvider::IsValidCodecConfiguration(
617 const setting::CodecConfiguration& codec_configuration) {
618 return codec_configuration.hasName() && codec_configuration.hasCodec() &&
619 codec_configuration.hasSamplingFrequency() &&
620 codec_configuration.hasFrameDurationUs() &&
621 codec_configuration.hasOctetsPerCodecFrame();
622 }
623
IsValidStereoAudioLocation(const setting::StrategyConfiguration & strategy_configuration)624 bool IsValidStereoAudioLocation(
625 const setting::StrategyConfiguration& strategy_configuration) {
626 if ((strategy_configuration.getConnectedDevice() == 2 &&
627 strategy_configuration.getChannelCount() == 1) ||
628 (strategy_configuration.getConnectedDevice() == 1 &&
629 strategy_configuration.getChannelCount() == 2)) {
630 // Stereo
631 // 1. two connected device, one for L one for R
632 // 2. one connected device for both L and R
633 return true;
634 } else if (strategy_configuration.getConnectedDevice() == 0 &&
635 strategy_configuration.getChannelCount() == 2) {
636 // Broadcast
637 return true;
638 }
639 return false;
640 }
641
IsValidMonoAudioLocation(const setting::StrategyConfiguration & strategy_configuration)642 bool IsValidMonoAudioLocation(
643 const setting::StrategyConfiguration& strategy_configuration) {
644 if (strategy_configuration.getConnectedDevice() == 1 &&
645 strategy_configuration.getChannelCount() == 1) {
646 return true;
647 }
648 return false;
649 }
650
IsValidAudioLocation(const setting::StrategyConfiguration & strategy_configuration)651 bool IsValidAudioLocation(
652 const setting::StrategyConfiguration& strategy_configuration) {
653 if (strategy_configuration.getAudioLocation() ==
654 setting::AudioLocation::STEREO)
655 return IsValidStereoAudioLocation(strategy_configuration);
656 else if (strategy_configuration.getAudioLocation() ==
657 setting::AudioLocation::MONO)
658 return IsValidMonoAudioLocation(strategy_configuration);
659 return false;
660 }
661
IsValidAudioChannelAllocation(const setting::StrategyConfiguration & strategy_configuration)662 bool IsValidAudioChannelAllocation(
663 const setting::StrategyConfiguration& strategy_configuration) {
664 // First, ensure that there's only 2 bitmask enabled
665 int audio_channel_allocation =
666 strategy_configuration.getAudioChannelAllocation();
667 int count = 0;
668 for (int bit = 0; bit < 32; ++bit)
669 if (audio_channel_allocation & (1 << bit)) ++count;
670 if (count > 2) {
671 LOG(WARNING) << "Cannot parse more than 2 audio location, input is "
672 << audio_channel_allocation;
673 return false;
674 }
675
676 if (count == 2)
677 return IsValidStereoAudioLocation(strategy_configuration);
678 else
679 return IsValidMonoAudioLocation(strategy_configuration);
680 }
681
IsValidStrategyConfiguration(const setting::StrategyConfiguration & strategy_configuration)682 bool BluetoothLeAudioCodecsProvider::IsValidStrategyConfiguration(
683 const setting::StrategyConfiguration& strategy_configuration) {
684 if (!strategy_configuration.hasName() ||
685 !strategy_configuration.hasConnectedDevice() ||
686 !strategy_configuration.hasChannelCount()) {
687 return false;
688 }
689
690 // Both audio location field cannot be empty
691 if (!strategy_configuration.hasAudioLocation() &&
692 !strategy_configuration.hasAudioChannelAllocation())
693 return false;
694
695 // Any audio location field that presents must be valid
696 if (strategy_configuration.hasAudioLocation() &&
697 !IsValidAudioLocation(strategy_configuration))
698 return false;
699
700 if (strategy_configuration.hasAudioChannelAllocation() &&
701 !IsValidAudioChannelAllocation(strategy_configuration))
702 return false;
703
704 return true;
705 }
706
707 } // namespace audio
708 } // namespace bluetooth
709 } // namespace hardware
710 } // namespace android
711 } // namespace aidl
712