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