• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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