blob: 99dea84a6ce22d723cdc8aabc04ddfa8916f77bc [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
Bao Do6aeb5d72023-12-11 10:53:18 +000017#include <set>
18
19#include "aidl/android/hardware/bluetooth/audio/ChannelMode.h"
20#include "aidl/android/hardware/bluetooth/audio/CodecId.h"
21#include "aidl_android_hardware_bluetooth_audio_setting_enums.h"
shihchienc8ed901a2022-09-06 08:44:44 +000022#define LOG_TAG "BTAudioCodecsProviderAidl"
23
24#include "BluetoothLeAudioCodecsProvider.h"
25
26namespace aidl {
27namespace android {
28namespace hardware {
29namespace bluetooth {
30namespace audio {
31
32static const char* kLeAudioCodecCapabilitiesFile =
33 "/vendor/etc/le_audio_codec_capabilities.xml";
34
35static const AudioLocation kStereoAudio = static_cast<AudioLocation>(
36 static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
37 static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
38static const AudioLocation kMonoAudio = AudioLocation::UNKNOWN;
39
40static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;
41
shihchiencd7f565a2022-10-14 13:45:37 +000042static bool isInvalidFileContent = false;
shihchienc8ed901a2022-09-06 08:44:44 +000043
shihchiencd7f565a2022-10-14 13:45:37 +000044std::optional<setting::LeAudioOffloadSetting>
45BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile() {
46 if (!leAudioCodecCapabilities.empty() || isInvalidFileContent) {
47 return std::nullopt;
48 }
49 auto le_audio_offload_setting =
shihchienc8ed901a2022-09-06 08:44:44 +000050 setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
51 if (!le_audio_offload_setting.has_value()) {
52 LOG(ERROR) << __func__ << ": Failed to read "
53 << kLeAudioCodecCapabilitiesFile;
shihchiencd7f565a2022-10-14 13:45:37 +000054 }
55 return le_audio_offload_setting;
56}
57
Bao Do6aeb5d72023-12-11 10:53:18 +000058std::unordered_map<SessionType, std::vector<CodecInfo>>
59BluetoothLeAudioCodecsProvider::GetLeAudioCodecInfo(
60 const std::optional<setting::LeAudioOffloadSetting>&
61 le_audio_offload_setting) {
62 // Load from previous storage if present
63 if (!session_codecs_map_.empty()) return session_codecs_map_;
64
65 isInvalidFileContent = true;
66 if (!le_audio_offload_setting.has_value()) return {};
67
68 // Load scenario, configuration, codec configuration and strategy
69 LoadConfigurationToMap(le_audio_offload_setting);
70 if (supported_scenarios_.empty() || configuration_map_.empty() ||
71 codec_configuration_map_.empty() || strategy_configuration_map_.empty())
72 return {};
73
74 // Map each configuration into a CodecInfo
75 std::unordered_map<std::string, CodecInfo> config_codec_info_map_;
76
77 for (auto& p : configuration_map_) {
78 // Initialize new CodecInfo for the config
79 auto config_name = p.first;
Bao Do6aeb5d72023-12-11 10:53:18 +000080
81 // Getting informations from codecConfig and strategyConfig
82 const auto codec_config_name = p.second.getCodecConfiguration();
83 const auto strategy_config_name = p.second.getStrategyConfiguration();
84 const auto codec_configuration_map_iter =
85 codec_configuration_map_.find(codec_config_name);
86 if (codec_configuration_map_iter == codec_configuration_map_.end())
87 continue;
88 const auto strategy_configuration_map_iter =
89 strategy_configuration_map_.find(strategy_config_name);
90 if (strategy_configuration_map_iter == strategy_configuration_map_.end())
91 continue;
92
Jakub Tyszkowski06781c02024-01-08 13:16:42 +000093 if (config_codec_info_map_.count(config_name) == 0)
94 config_codec_info_map_[config_name] = CodecInfo();
95
Bao Do6aeb5d72023-12-11 10:53:18 +000096 const auto& codec_config = codec_configuration_map_iter->second;
97 const auto codec = codec_config.getCodec();
98 const auto& strategy_config = strategy_configuration_map_iter->second;
99 const auto strategy_config_channel_count =
100 strategy_config.getChannelCount();
101
102 // Initiate information
103 auto& codec_info = config_codec_info_map_[config_name];
104 switch (codec) {
105 case setting::CodecType::LC3:
106 codec_info.name = "LC3";
107 codec_info.id = CodecId::Core::LC3;
108 break;
109 default:
110 codec_info.name = "UNDEFINE";
Bao Do5b2fdab2023-11-20 08:02:55 +0000111 codec_info.id = CodecId::Vendor();
Bao Do6aeb5d72023-12-11 10:53:18 +0000112 break;
113 }
114 codec_info.transport =
115 CodecInfo::Transport::make<CodecInfo::Transport::Tag::leAudio>();
116
117 // Mapping codec configuration information
118 auto& transport =
119 codec_info.transport.get<CodecInfo::Transport::Tag::leAudio>();
120 transport.samplingFrequencyHz.push_back(
121 codec_config.getSamplingFrequency());
122 // Mapping octetsPerCodecFrame to bitdepth for easier comparison.
123 transport.bitdepth.push_back(codec_config.getOctetsPerCodecFrame());
124 transport.frameDurationUs.push_back(codec_config.getFrameDurationUs());
125 switch (strategy_config.getAudioLocation()) {
126 case setting::AudioLocation::MONO:
127 if (strategy_config_channel_count == 1)
128 transport.channelMode.push_back(ChannelMode::MONO);
129 else
130 transport.channelMode.push_back(ChannelMode::DUALMONO);
131 break;
132 case setting::AudioLocation::STEREO:
133 transport.channelMode.push_back(ChannelMode::STEREO);
134 break;
135 default:
136 transport.channelMode.push_back(ChannelMode::UNKNOWN);
137 break;
138 }
139 }
140
Jakub Tyszkowski06781c02024-01-08 13:16:42 +0000141 // Goes through every scenario, deduplicate configuration, skip the invalid
142 // config references (e.g. the "invalid" entries in the xml file).
Bao Do6aeb5d72023-12-11 10:53:18 +0000143 std::set<std::string> encoding_config, decoding_config, broadcast_config;
144 for (auto& s : supported_scenarios_) {
Jakub Tyszkowski06781c02024-01-08 13:16:42 +0000145 if (s.hasEncode() && config_codec_info_map_.count(s.getEncode())) {
146 encoding_config.insert(s.getEncode());
147 }
148 if (s.hasDecode() && config_codec_info_map_.count(s.getDecode())) {
149 decoding_config.insert(s.getDecode());
150 }
151 if (s.hasBroadcast() && config_codec_info_map_.count(s.getBroadcast())) {
152 broadcast_config.insert(s.getBroadcast());
153 }
Bao Do6aeb5d72023-12-11 10:53:18 +0000154 }
155
156 // Split by session types and add results
157 const auto encoding_path =
158 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
159 const auto decoding_path =
160 SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
161 const auto broadcast_path =
162 SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
163 session_codecs_map_ =
164 std::unordered_map<SessionType, std::vector<CodecInfo>>();
165 session_codecs_map_[encoding_path] = std::vector<CodecInfo>();
166 session_codecs_map_[decoding_path] = std::vector<CodecInfo>();
167 session_codecs_map_[broadcast_path] = std::vector<CodecInfo>();
168 session_codecs_map_[encoding_path].reserve(encoding_config.size());
169 session_codecs_map_[decoding_path].reserve(decoding_config.size());
170 session_codecs_map_[broadcast_path].reserve(broadcast_config.size());
171 for (auto& c : encoding_config)
172 session_codecs_map_[encoding_path].push_back(config_codec_info_map_[c]);
173 for (auto& c : decoding_config)
174 session_codecs_map_[decoding_path].push_back(config_codec_info_map_[c]);
175 for (auto& c : broadcast_config)
176 session_codecs_map_[broadcast_path].push_back(config_codec_info_map_[c]);
177
178 isInvalidFileContent = session_codecs_map_.empty();
179
180 return session_codecs_map_;
181}
182
shihchiencd7f565a2022-10-14 13:45:37 +0000183std::vector<LeAudioCodecCapabilitiesSetting>
184BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
185 const std::optional<setting::LeAudioOffloadSetting>&
186 le_audio_offload_setting) {
187 if (!leAudioCodecCapabilities.empty()) {
188 return leAudioCodecCapabilities;
189 }
190
Bao Do6aeb5d72023-12-11 10:53:18 +0000191 isInvalidFileContent = true;
192
shihchiencd7f565a2022-10-14 13:45:37 +0000193 if (!le_audio_offload_setting.has_value()) {
194 LOG(ERROR)
195 << __func__
196 << ": input le_audio_offload_setting content need to be non empty";
shihchienc8ed901a2022-09-06 08:44:44 +0000197 return {};
198 }
199
Bao Do6aeb5d72023-12-11 10:53:18 +0000200 LoadConfigurationToMap(le_audio_offload_setting);
201 if (supported_scenarios_.empty() || configuration_map_.empty() ||
202 codec_configuration_map_.empty() || strategy_configuration_map_.empty())
shihchienc8ed901a2022-09-06 08:44:44 +0000203 return {};
shihchienc8ed901a2022-09-06 08:44:44 +0000204
205 leAudioCodecCapabilities =
Bao Do6aeb5d72023-12-11 10:53:18 +0000206 ComposeLeAudioCodecCapabilities(supported_scenarios_);
shihchiencd7f565a2022-10-14 13:45:37 +0000207 isInvalidFileContent = leAudioCodecCapabilities.empty();
208
shihchienc8ed901a2022-09-06 08:44:44 +0000209 return leAudioCodecCapabilities;
210}
211
shihchiencd7f565a2022-10-14 13:45:37 +0000212void BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities() {
213 leAudioCodecCapabilities.clear();
214 configuration_map_.clear();
215 codec_configuration_map_.clear();
216 strategy_configuration_map_.clear();
Bao Do6aeb5d72023-12-11 10:53:18 +0000217 session_codecs_map_.clear();
218 supported_scenarios_.clear();
shihchiencd7f565a2022-10-14 13:45:37 +0000219}
220
shihchienc8ed901a2022-09-06 08:44:44 +0000221std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
222 const std::optional<setting::LeAudioOffloadSetting>&
223 le_audio_offload_setting) {
224 std::vector<setting::Scenario> supported_scenarios;
225 if (le_audio_offload_setting->hasScenarioList()) {
226 for (const auto& scenario_list :
227 le_audio_offload_setting->getScenarioList()) {
228 if (!scenario_list.hasScenario()) {
229 continue;
230 }
231 for (const auto& scenario : scenario_list.getScenario()) {
232 if (scenario.hasEncode() && scenario.hasDecode()) {
233 supported_scenarios.push_back(scenario);
234 }
235 }
236 }
237 }
238 return supported_scenarios;
239}
240
241void BluetoothLeAudioCodecsProvider::UpdateConfigurationsToMap(
242 const std::optional<setting::LeAudioOffloadSetting>&
243 le_audio_offload_setting) {
244 if (le_audio_offload_setting->hasConfigurationList()) {
245 for (const auto& configuration_list :
246 le_audio_offload_setting->getConfigurationList()) {
247 if (!configuration_list.hasConfiguration()) {
248 continue;
249 }
250 for (const auto& configuration : configuration_list.getConfiguration()) {
251 if (configuration.hasName() && configuration.hasCodecConfiguration() &&
252 configuration.hasStrategyConfiguration()) {
253 configuration_map_.insert(
254 make_pair(configuration.getName(), configuration));
255 }
256 }
257 }
258 }
259}
260
261void BluetoothLeAudioCodecsProvider::UpdateCodecConfigurationsToMap(
262 const std::optional<setting::LeAudioOffloadSetting>&
263 le_audio_offload_setting) {
264 if (le_audio_offload_setting->hasCodecConfigurationList()) {
265 for (const auto& codec_configuration_list :
266 le_audio_offload_setting->getCodecConfigurationList()) {
267 if (!codec_configuration_list.hasCodecConfiguration()) {
268 continue;
269 }
270 for (const auto& codec_configuration :
271 codec_configuration_list.getCodecConfiguration()) {
272 if (IsValidCodecConfiguration(codec_configuration)) {
273 codec_configuration_map_.insert(
274 make_pair(codec_configuration.getName(), codec_configuration));
275 }
276 }
277 }
278 }
279}
280
281void BluetoothLeAudioCodecsProvider::UpdateStrategyConfigurationsToMap(
282 const std::optional<setting::LeAudioOffloadSetting>&
283 le_audio_offload_setting) {
284 if (le_audio_offload_setting->hasStrategyConfigurationList()) {
285 for (const auto& strategy_configuration_list :
286 le_audio_offload_setting->getStrategyConfigurationList()) {
287 if (!strategy_configuration_list.hasStrategyConfiguration()) {
288 continue;
289 }
290 for (const auto& strategy_configuration :
291 strategy_configuration_list.getStrategyConfiguration()) {
292 if (IsValidStrategyConfiguration(strategy_configuration)) {
293 strategy_configuration_map_.insert(make_pair(
294 strategy_configuration.getName(), strategy_configuration));
295 }
296 }
297 }
298 }
299}
300
Bao Do6aeb5d72023-12-11 10:53:18 +0000301void BluetoothLeAudioCodecsProvider::LoadConfigurationToMap(
302 const std::optional<setting::LeAudioOffloadSetting>&
303 le_audio_offload_setting) {
304 ClearLeAudioCodecCapabilities();
305
306 supported_scenarios_ = GetScenarios(le_audio_offload_setting);
307 if (supported_scenarios_.empty()) {
308 LOG(ERROR) << __func__ << ": No scenarios in "
309 << kLeAudioCodecCapabilitiesFile;
310 return;
311 }
312
313 UpdateConfigurationsToMap(le_audio_offload_setting);
314 if (configuration_map_.empty()) {
315 LOG(ERROR) << __func__ << ": No configurations in "
316 << kLeAudioCodecCapabilitiesFile;
317 return;
318 }
319
320 UpdateCodecConfigurationsToMap(le_audio_offload_setting);
321 if (codec_configuration_map_.empty()) {
322 LOG(ERROR) << __func__ << ": No codec configurations in "
323 << kLeAudioCodecCapabilitiesFile;
324 return;
325 }
326
327 UpdateStrategyConfigurationsToMap(le_audio_offload_setting);
328 if (strategy_configuration_map_.empty()) {
329 LOG(ERROR) << __func__ << ": No strategy configurations in "
330 << kLeAudioCodecCapabilitiesFile;
331 return;
332 }
333}
334
shihchienc8ed901a2022-09-06 08:44:44 +0000335std::vector<LeAudioCodecCapabilitiesSetting>
336BluetoothLeAudioCodecsProvider::ComposeLeAudioCodecCapabilities(
337 const std::vector<setting::Scenario>& supported_scenarios) {
338 std::vector<LeAudioCodecCapabilitiesSetting> le_audio_codec_capabilities;
339 for (const auto& scenario : supported_scenarios) {
340 UnicastCapability unicast_encode_capability =
341 GetUnicastCapability(scenario.getEncode());
342 UnicastCapability unicast_decode_capability =
343 GetUnicastCapability(scenario.getDecode());
shihchienc8ed901a2022-09-06 08:44:44 +0000344 BroadcastCapability broadcast_capability = {.codecType =
345 CodecType::UNKNOWN};
Patty Huangac077ef2022-11-23 14:45:15 +0800346
347 if (scenario.hasBroadcast()) {
348 broadcast_capability = GetBroadcastCapability(scenario.getBroadcast());
349 }
350
351 // At least one capability should be valid
352 if (unicast_encode_capability.codecType == CodecType::UNKNOWN &&
353 unicast_decode_capability.codecType == CodecType::UNKNOWN &&
354 broadcast_capability.codecType == CodecType::UNKNOWN) {
355 LOG(ERROR) << __func__ << ": None of the capability is valid.";
356 continue;
357 }
358
shihchienc8ed901a2022-09-06 08:44:44 +0000359 le_audio_codec_capabilities.push_back(
360 {.unicastEncodeCapability = unicast_encode_capability,
361 .unicastDecodeCapability = unicast_decode_capability,
362 .broadcastCapability = broadcast_capability});
363 }
364 return le_audio_codec_capabilities;
365}
366
367UnicastCapability BluetoothLeAudioCodecsProvider::GetUnicastCapability(
368 const std::string& coding_direction) {
369 if (coding_direction == "invalid") {
370 return {.codecType = CodecType::UNKNOWN};
371 }
372
373 auto configuration_iter = configuration_map_.find(coding_direction);
374 if (configuration_iter == configuration_map_.end()) {
375 return {.codecType = CodecType::UNKNOWN};
376 }
377
378 auto codec_configuration_iter = codec_configuration_map_.find(
379 configuration_iter->second.getCodecConfiguration());
380 if (codec_configuration_iter == codec_configuration_map_.end()) {
381 return {.codecType = CodecType::UNKNOWN};
382 }
383
384 auto strategy_configuration_iter = strategy_configuration_map_.find(
385 configuration_iter->second.getStrategyConfiguration());
386 if (strategy_configuration_iter == strategy_configuration_map_.end()) {
387 return {.codecType = CodecType::UNKNOWN};
388 }
389
390 CodecType codec_type =
391 GetCodecType(codec_configuration_iter->second.getCodec());
392 if (codec_type == CodecType::LC3) {
393 return ComposeUnicastCapability(
394 codec_type,
395 GetAudioLocation(
396 strategy_configuration_iter->second.getAudioLocation()),
397 strategy_configuration_iter->second.getConnectedDevice(),
398 strategy_configuration_iter->second.getChannelCount(),
399 ComposeLc3Capability(codec_configuration_iter->second));
Alice Kuof850de62023-10-04 04:02:24 +0800400 } else if (codec_type == CodecType::APTX_ADAPTIVE_LE ||
401 codec_type == CodecType::APTX_ADAPTIVE_LEX) {
402 return ComposeUnicastCapability(
403 codec_type,
404 GetAudioLocation(
405 strategy_configuration_iter->second.getAudioLocation()),
406 strategy_configuration_iter->second.getConnectedDevice(),
407 strategy_configuration_iter->second.getChannelCount(),
408 ComposeAptxAdaptiveLeCapability(codec_configuration_iter->second));
shihchienc8ed901a2022-09-06 08:44:44 +0000409 }
410 return {.codecType = CodecType::UNKNOWN};
411}
412
Patty Huangac077ef2022-11-23 14:45:15 +0800413BroadcastCapability BluetoothLeAudioCodecsProvider::GetBroadcastCapability(
414 const std::string& coding_direction) {
415 if (coding_direction == "invalid") {
416 return {.codecType = CodecType::UNKNOWN};
417 }
418
419 auto configuration_iter = configuration_map_.find(coding_direction);
420 if (configuration_iter == configuration_map_.end()) {
421 return {.codecType = CodecType::UNKNOWN};
422 }
423
424 auto codec_configuration_iter = codec_configuration_map_.find(
425 configuration_iter->second.getCodecConfiguration());
426 if (codec_configuration_iter == codec_configuration_map_.end()) {
427 return {.codecType = CodecType::UNKNOWN};
428 }
429
430 auto strategy_configuration_iter = strategy_configuration_map_.find(
431 configuration_iter->second.getStrategyConfiguration());
432 if (strategy_configuration_iter == strategy_configuration_map_.end()) {
433 return {.codecType = CodecType::UNKNOWN};
434 }
435
436 CodecType codec_type =
437 GetCodecType(codec_configuration_iter->second.getCodec());
438 std::vector<std::optional<Lc3Capabilities>> bcastLc3Cap(
439 1, std::optional(ComposeLc3Capability(codec_configuration_iter->second)));
440
441 if (codec_type == CodecType::LC3) {
442 return ComposeBroadcastCapability(
443 codec_type,
444 GetAudioLocation(
445 strategy_configuration_iter->second.getAudioLocation()),
446 strategy_configuration_iter->second.getChannelCount(), bcastLc3Cap);
447 }
448 return {.codecType = CodecType::UNKNOWN};
449}
450
451template <class T>
452BroadcastCapability BluetoothLeAudioCodecsProvider::ComposeBroadcastCapability(
453 const CodecType& codec_type, const AudioLocation& audio_location,
454 const uint8_t& channel_count, const std::vector<T>& capability) {
455 return {.codecType = codec_type,
456 .supportedChannel = audio_location,
457 .channelCountPerStream = channel_count,
458 .leAudioCodecCapabilities = std::optional(capability)};
459}
460
shihchienc8ed901a2022-09-06 08:44:44 +0000461template <class T>
462UnicastCapability BluetoothLeAudioCodecsProvider::ComposeUnicastCapability(
463 const CodecType& codec_type, const AudioLocation& audio_location,
464 const uint8_t& device_cnt, const uint8_t& channel_count,
465 const T& capability) {
466 return {
467 .codecType = codec_type,
468 .supportedChannel = audio_location,
469 .deviceCount = device_cnt,
470 .channelCountPerDevice = channel_count,
471 .leAudioCodecCapabilities =
472 UnicastCapability::LeAudioCodecCapabilities(capability),
473 };
474}
475
476Lc3Capabilities BluetoothLeAudioCodecsProvider::ComposeLc3Capability(
477 const setting::CodecConfiguration& codec_configuration) {
478 return {.samplingFrequencyHz = {codec_configuration.getSamplingFrequency()},
479 .frameDurationUs = {codec_configuration.getFrameDurationUs()},
480 .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}};
481}
482
Alice Kuof850de62023-10-04 04:02:24 +0800483AptxAdaptiveLeCapabilities
484BluetoothLeAudioCodecsProvider::ComposeAptxAdaptiveLeCapability(
485 const setting::CodecConfiguration& codec_configuration) {
486 return {.samplingFrequencyHz = {codec_configuration.getSamplingFrequency()},
487 .frameDurationUs = {codec_configuration.getFrameDurationUs()},
488 .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}};
489}
490
shihchienc8ed901a2022-09-06 08:44:44 +0000491AudioLocation BluetoothLeAudioCodecsProvider::GetAudioLocation(
492 const setting::AudioLocation& audio_location) {
493 switch (audio_location) {
494 case setting::AudioLocation::MONO:
495 return kMonoAudio;
496 case setting::AudioLocation::STEREO:
497 return kStereoAudio;
498 default:
499 return AudioLocation::UNKNOWN;
500 }
501}
502
503CodecType BluetoothLeAudioCodecsProvider::GetCodecType(
504 const setting::CodecType& codec_type) {
505 switch (codec_type) {
506 case setting::CodecType::LC3:
507 return CodecType::LC3;
Alice Kuof850de62023-10-04 04:02:24 +0800508 case setting::CodecType::APTX_ADAPTIVE_LE:
509 return CodecType::APTX_ADAPTIVE_LE;
510 case setting::CodecType::APTX_ADAPTIVE_LEX:
511 return CodecType::APTX_ADAPTIVE_LEX;
shihchienc8ed901a2022-09-06 08:44:44 +0000512 default:
513 return CodecType::UNKNOWN;
514 }
515}
516
517bool BluetoothLeAudioCodecsProvider::IsValidCodecConfiguration(
518 const setting::CodecConfiguration& codec_configuration) {
519 return codec_configuration.hasName() && codec_configuration.hasCodec() &&
520 codec_configuration.hasSamplingFrequency() &&
521 codec_configuration.hasFrameDurationUs() &&
522 codec_configuration.hasOctetsPerCodecFrame();
523}
524
525bool BluetoothLeAudioCodecsProvider::IsValidStrategyConfiguration(
526 const setting::StrategyConfiguration& strategy_configuration) {
527 if (!strategy_configuration.hasName() ||
528 !strategy_configuration.hasAudioLocation() ||
529 !strategy_configuration.hasConnectedDevice() ||
530 !strategy_configuration.hasChannelCount()) {
531 return false;
532 }
533 if (strategy_configuration.getAudioLocation() ==
534 setting::AudioLocation::STEREO) {
535 if ((strategy_configuration.getConnectedDevice() == 2 &&
536 strategy_configuration.getChannelCount() == 1) ||
537 (strategy_configuration.getConnectedDevice() == 1 &&
538 strategy_configuration.getChannelCount() == 2)) {
539 // Stereo
540 // 1. two connected device, one for L one for R
541 // 2. one connected device for both L and R
542 return true;
Patty Huangac077ef2022-11-23 14:45:15 +0800543 } else if (strategy_configuration.getConnectedDevice() == 0 &&
544 strategy_configuration.getChannelCount() == 2) {
545 // Broadcast
546 return true;
shihchienc8ed901a2022-09-06 08:44:44 +0000547 }
548 } else if (strategy_configuration.getAudioLocation() ==
549 setting::AudioLocation::MONO) {
550 if (strategy_configuration.getConnectedDevice() == 1 &&
551 strategy_configuration.getChannelCount() == 1) {
552 // Mono
553 return true;
554 }
555 }
556 return false;
557}
558
559} // namespace audio
560} // namespace bluetooth
561} // namespace hardware
562} // namespace android
563} // namespace aidl