• 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 #define LOG_TAG "BTAudioCodecsProviderAidl"
18 
19 #include "BluetoothLeAudioCodecsProvider.h"
20 
21 namespace aidl {
22 namespace android {
23 namespace hardware {
24 namespace bluetooth {
25 namespace audio {
26 
27 static const char* kLeAudioCodecCapabilitiesFile =
28     "/vendor/etc/le_audio_codec_capabilities.xml";
29 
30 static const AudioLocation kStereoAudio = static_cast<AudioLocation>(
31     static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
32     static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
33 static const AudioLocation kMonoAudio = AudioLocation::UNKNOWN;
34 
35 static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;
36 
37 static bool isInvalidFileContent = false;
38 
39 std::optional<setting::LeAudioOffloadSetting>
ParseFromLeAudioOffloadSettingFile()40 BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile() {
41   if (!leAudioCodecCapabilities.empty() || isInvalidFileContent) {
42     return std::nullopt;
43   }
44   auto le_audio_offload_setting =
45       setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
46   if (!le_audio_offload_setting.has_value()) {
47     LOG(ERROR) << __func__ << ": Failed to read "
48                << kLeAudioCodecCapabilitiesFile;
49   }
50   return le_audio_offload_setting;
51 }
52 
53 std::vector<LeAudioCodecCapabilitiesSetting>
GetLeAudioCodecCapabilities(const std::optional<setting::LeAudioOffloadSetting> & le_audio_offload_setting)54 BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
55     const std::optional<setting::LeAudioOffloadSetting>&
56         le_audio_offload_setting) {
57   if (!leAudioCodecCapabilities.empty()) {
58     return leAudioCodecCapabilities;
59   }
60 
61   if (!le_audio_offload_setting.has_value()) {
62     LOG(ERROR)
63         << __func__
64         << ": input le_audio_offload_setting content need to be non empty";
65     return {};
66   }
67 
68   ClearLeAudioCodecCapabilities();
69   isInvalidFileContent = true;
70 
71   std::vector<setting::Scenario> supported_scenarios =
72       GetScenarios(le_audio_offload_setting);
73   if (supported_scenarios.empty()) {
74     LOG(ERROR) << __func__ << ": No scenarios in "
75                << kLeAudioCodecCapabilitiesFile;
76     return {};
77   }
78 
79   UpdateConfigurationsToMap(le_audio_offload_setting);
80   if (configuration_map_.empty()) {
81     LOG(ERROR) << __func__ << ": No configurations in "
82                << kLeAudioCodecCapabilitiesFile;
83     return {};
84   }
85 
86   UpdateCodecConfigurationsToMap(le_audio_offload_setting);
87   if (codec_configuration_map_.empty()) {
88     LOG(ERROR) << __func__ << ": No codec configurations in "
89                << kLeAudioCodecCapabilitiesFile;
90     return {};
91   }
92 
93   UpdateStrategyConfigurationsToMap(le_audio_offload_setting);
94   if (strategy_configuration_map_.empty()) {
95     LOG(ERROR) << __func__ << ": No strategy configurations in "
96                << kLeAudioCodecCapabilitiesFile;
97     return {};
98   }
99 
100   leAudioCodecCapabilities =
101       ComposeLeAudioCodecCapabilities(supported_scenarios);
102   isInvalidFileContent = leAudioCodecCapabilities.empty();
103 
104   return leAudioCodecCapabilities;
105 }
106 
ClearLeAudioCodecCapabilities()107 void BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities() {
108   leAudioCodecCapabilities.clear();
109   configuration_map_.clear();
110   codec_configuration_map_.clear();
111   strategy_configuration_map_.clear();
112 }
113 
GetScenarios(const std::optional<setting::LeAudioOffloadSetting> & le_audio_offload_setting)114 std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
115     const std::optional<setting::LeAudioOffloadSetting>&
116         le_audio_offload_setting) {
117   std::vector<setting::Scenario> supported_scenarios;
118   if (le_audio_offload_setting->hasScenarioList()) {
119     for (const auto& scenario_list :
120          le_audio_offload_setting->getScenarioList()) {
121       if (!scenario_list.hasScenario()) {
122         continue;
123       }
124       for (const auto& scenario : scenario_list.getScenario()) {
125         if (scenario.hasEncode() && scenario.hasDecode()) {
126           supported_scenarios.push_back(scenario);
127         }
128       }
129     }
130   }
131   return supported_scenarios;
132 }
133 
UpdateConfigurationsToMap(const std::optional<setting::LeAudioOffloadSetting> & le_audio_offload_setting)134 void BluetoothLeAudioCodecsProvider::UpdateConfigurationsToMap(
135     const std::optional<setting::LeAudioOffloadSetting>&
136         le_audio_offload_setting) {
137   if (le_audio_offload_setting->hasConfigurationList()) {
138     for (const auto& configuration_list :
139          le_audio_offload_setting->getConfigurationList()) {
140       if (!configuration_list.hasConfiguration()) {
141         continue;
142       }
143       for (const auto& configuration : configuration_list.getConfiguration()) {
144         if (configuration.hasName() && configuration.hasCodecConfiguration() &&
145             configuration.hasStrategyConfiguration()) {
146           configuration_map_.insert(
147               make_pair(configuration.getName(), configuration));
148         }
149       }
150     }
151   }
152 }
153 
UpdateCodecConfigurationsToMap(const std::optional<setting::LeAudioOffloadSetting> & le_audio_offload_setting)154 void BluetoothLeAudioCodecsProvider::UpdateCodecConfigurationsToMap(
155     const std::optional<setting::LeAudioOffloadSetting>&
156         le_audio_offload_setting) {
157   if (le_audio_offload_setting->hasCodecConfigurationList()) {
158     for (const auto& codec_configuration_list :
159          le_audio_offload_setting->getCodecConfigurationList()) {
160       if (!codec_configuration_list.hasCodecConfiguration()) {
161         continue;
162       }
163       for (const auto& codec_configuration :
164            codec_configuration_list.getCodecConfiguration()) {
165         if (IsValidCodecConfiguration(codec_configuration)) {
166           codec_configuration_map_.insert(
167               make_pair(codec_configuration.getName(), codec_configuration));
168         }
169       }
170     }
171   }
172 }
173 
UpdateStrategyConfigurationsToMap(const std::optional<setting::LeAudioOffloadSetting> & le_audio_offload_setting)174 void BluetoothLeAudioCodecsProvider::UpdateStrategyConfigurationsToMap(
175     const std::optional<setting::LeAudioOffloadSetting>&
176         le_audio_offload_setting) {
177   if (le_audio_offload_setting->hasStrategyConfigurationList()) {
178     for (const auto& strategy_configuration_list :
179          le_audio_offload_setting->getStrategyConfigurationList()) {
180       if (!strategy_configuration_list.hasStrategyConfiguration()) {
181         continue;
182       }
183       for (const auto& strategy_configuration :
184            strategy_configuration_list.getStrategyConfiguration()) {
185         if (IsValidStrategyConfiguration(strategy_configuration)) {
186           strategy_configuration_map_.insert(make_pair(
187               strategy_configuration.getName(), strategy_configuration));
188         }
189       }
190     }
191   }
192 }
193 
194 std::vector<LeAudioCodecCapabilitiesSetting>
ComposeLeAudioCodecCapabilities(const std::vector<setting::Scenario> & supported_scenarios)195 BluetoothLeAudioCodecsProvider::ComposeLeAudioCodecCapabilities(
196     const std::vector<setting::Scenario>& supported_scenarios) {
197   std::vector<LeAudioCodecCapabilitiesSetting> le_audio_codec_capabilities;
198   for (const auto& scenario : supported_scenarios) {
199     UnicastCapability unicast_encode_capability =
200         GetUnicastCapability(scenario.getEncode());
201     UnicastCapability unicast_decode_capability =
202         GetUnicastCapability(scenario.getDecode());
203     BroadcastCapability broadcast_capability = {.codecType =
204                                                     CodecType::UNKNOWN};
205 
206     if (scenario.hasBroadcast()) {
207       broadcast_capability = GetBroadcastCapability(scenario.getBroadcast());
208     }
209 
210     // At least one capability should be valid
211     if (unicast_encode_capability.codecType == CodecType::UNKNOWN &&
212         unicast_decode_capability.codecType == CodecType::UNKNOWN &&
213         broadcast_capability.codecType == CodecType::UNKNOWN) {
214       LOG(ERROR) << __func__ << ": None of the capability is valid.";
215       continue;
216     }
217 
218     le_audio_codec_capabilities.push_back(
219         {.unicastEncodeCapability = unicast_encode_capability,
220          .unicastDecodeCapability = unicast_decode_capability,
221          .broadcastCapability = broadcast_capability});
222   }
223   return le_audio_codec_capabilities;
224 }
225 
GetUnicastCapability(const std::string & coding_direction)226 UnicastCapability BluetoothLeAudioCodecsProvider::GetUnicastCapability(
227     const std::string& coding_direction) {
228   if (coding_direction == "invalid") {
229     return {.codecType = CodecType::UNKNOWN};
230   }
231 
232   auto configuration_iter = configuration_map_.find(coding_direction);
233   if (configuration_iter == configuration_map_.end()) {
234     return {.codecType = CodecType::UNKNOWN};
235   }
236 
237   auto codec_configuration_iter = codec_configuration_map_.find(
238       configuration_iter->second.getCodecConfiguration());
239   if (codec_configuration_iter == codec_configuration_map_.end()) {
240     return {.codecType = CodecType::UNKNOWN};
241   }
242 
243   auto strategy_configuration_iter = strategy_configuration_map_.find(
244       configuration_iter->second.getStrategyConfiguration());
245   if (strategy_configuration_iter == strategy_configuration_map_.end()) {
246     return {.codecType = CodecType::UNKNOWN};
247   }
248 
249   CodecType codec_type =
250       GetCodecType(codec_configuration_iter->second.getCodec());
251   if (codec_type == CodecType::LC3) {
252     return ComposeUnicastCapability(
253         codec_type,
254         GetAudioLocation(
255             strategy_configuration_iter->second.getAudioLocation()),
256         strategy_configuration_iter->second.getConnectedDevice(),
257         strategy_configuration_iter->second.getChannelCount(),
258         ComposeLc3Capability(codec_configuration_iter->second));
259   }
260   return {.codecType = CodecType::UNKNOWN};
261 }
262 
GetBroadcastCapability(const std::string & coding_direction)263 BroadcastCapability BluetoothLeAudioCodecsProvider::GetBroadcastCapability(
264     const std::string& coding_direction) {
265   if (coding_direction == "invalid") {
266     return {.codecType = CodecType::UNKNOWN};
267   }
268 
269   auto configuration_iter = configuration_map_.find(coding_direction);
270   if (configuration_iter == configuration_map_.end()) {
271     return {.codecType = CodecType::UNKNOWN};
272   }
273 
274   auto codec_configuration_iter = codec_configuration_map_.find(
275       configuration_iter->second.getCodecConfiguration());
276   if (codec_configuration_iter == codec_configuration_map_.end()) {
277     return {.codecType = CodecType::UNKNOWN};
278   }
279 
280   auto strategy_configuration_iter = strategy_configuration_map_.find(
281       configuration_iter->second.getStrategyConfiguration());
282   if (strategy_configuration_iter == strategy_configuration_map_.end()) {
283     return {.codecType = CodecType::UNKNOWN};
284   }
285 
286   CodecType codec_type =
287       GetCodecType(codec_configuration_iter->second.getCodec());
288   std::vector<std::optional<Lc3Capabilities>> bcastLc3Cap(
289       1, std::optional(ComposeLc3Capability(codec_configuration_iter->second)));
290 
291   if (codec_type == CodecType::LC3) {
292     return ComposeBroadcastCapability(
293         codec_type,
294         GetAudioLocation(
295             strategy_configuration_iter->second.getAudioLocation()),
296         strategy_configuration_iter->second.getChannelCount(), bcastLc3Cap);
297   }
298   return {.codecType = CodecType::UNKNOWN};
299 }
300 
301 template <class T>
ComposeBroadcastCapability(const CodecType & codec_type,const AudioLocation & audio_location,const uint8_t & channel_count,const std::vector<T> & capability)302 BroadcastCapability BluetoothLeAudioCodecsProvider::ComposeBroadcastCapability(
303     const CodecType& codec_type, const AudioLocation& audio_location,
304     const uint8_t& channel_count, const std::vector<T>& capability) {
305   return {.codecType = codec_type,
306           .supportedChannel = audio_location,
307           .channelCountPerStream = channel_count,
308           .leAudioCodecCapabilities = std::optional(capability)};
309 }
310 
311 template <class T>
ComposeUnicastCapability(const CodecType & codec_type,const AudioLocation & audio_location,const uint8_t & device_cnt,const uint8_t & channel_count,const T & capability)312 UnicastCapability BluetoothLeAudioCodecsProvider::ComposeUnicastCapability(
313     const CodecType& codec_type, const AudioLocation& audio_location,
314     const uint8_t& device_cnt, const uint8_t& channel_count,
315     const T& capability) {
316   return {
317       .codecType = codec_type,
318       .supportedChannel = audio_location,
319       .deviceCount = device_cnt,
320       .channelCountPerDevice = channel_count,
321       .leAudioCodecCapabilities =
322           UnicastCapability::LeAudioCodecCapabilities(capability),
323   };
324 }
325 
ComposeLc3Capability(const setting::CodecConfiguration & codec_configuration)326 Lc3Capabilities BluetoothLeAudioCodecsProvider::ComposeLc3Capability(
327     const setting::CodecConfiguration& codec_configuration) {
328   return {.samplingFrequencyHz = {codec_configuration.getSamplingFrequency()},
329           .frameDurationUs = {codec_configuration.getFrameDurationUs()},
330           .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}};
331 }
332 
GetAudioLocation(const setting::AudioLocation & audio_location)333 AudioLocation BluetoothLeAudioCodecsProvider::GetAudioLocation(
334     const setting::AudioLocation& audio_location) {
335   switch (audio_location) {
336     case setting::AudioLocation::MONO:
337       return kMonoAudio;
338     case setting::AudioLocation::STEREO:
339       return kStereoAudio;
340     default:
341       return AudioLocation::UNKNOWN;
342   }
343 }
344 
GetCodecType(const setting::CodecType & codec_type)345 CodecType BluetoothLeAudioCodecsProvider::GetCodecType(
346     const setting::CodecType& codec_type) {
347   switch (codec_type) {
348     case setting::CodecType::LC3:
349       return CodecType::LC3;
350     default:
351       return CodecType::UNKNOWN;
352   }
353 }
354 
IsValidCodecConfiguration(const setting::CodecConfiguration & codec_configuration)355 bool BluetoothLeAudioCodecsProvider::IsValidCodecConfiguration(
356     const setting::CodecConfiguration& codec_configuration) {
357   return codec_configuration.hasName() && codec_configuration.hasCodec() &&
358          codec_configuration.hasSamplingFrequency() &&
359          codec_configuration.hasFrameDurationUs() &&
360          codec_configuration.hasOctetsPerCodecFrame();
361 }
362 
IsValidStrategyConfiguration(const setting::StrategyConfiguration & strategy_configuration)363 bool BluetoothLeAudioCodecsProvider::IsValidStrategyConfiguration(
364     const setting::StrategyConfiguration& strategy_configuration) {
365   if (!strategy_configuration.hasName() ||
366       !strategy_configuration.hasAudioLocation() ||
367       !strategy_configuration.hasConnectedDevice() ||
368       !strategy_configuration.hasChannelCount()) {
369     return false;
370   }
371   if (strategy_configuration.getAudioLocation() ==
372       setting::AudioLocation::STEREO) {
373     if ((strategy_configuration.getConnectedDevice() == 2 &&
374          strategy_configuration.getChannelCount() == 1) ||
375         (strategy_configuration.getConnectedDevice() == 1 &&
376          strategy_configuration.getChannelCount() == 2)) {
377       // Stereo
378       // 1. two connected device, one for L one for R
379       // 2. one connected device for both L and R
380       return true;
381     } else if (strategy_configuration.getConnectedDevice() == 0 &&
382                strategy_configuration.getChannelCount() == 2) {
383       // Broadcast
384       return true;
385     }
386   } else if (strategy_configuration.getAudioLocation() ==
387              setting::AudioLocation::MONO) {
388     if (strategy_configuration.getConnectedDevice() == 1 &&
389         strategy_configuration.getChannelCount() == 1) {
390       // Mono
391       return true;
392     }
393   }
394   return false;
395 }
396 
397 }  // namespace audio
398 }  // namespace bluetooth
399 }  // namespace hardware
400 }  // namespace android
401 }  // namespace aidl
402