• 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 
18 #include <string>
19 #include <string_view>
20 
21 #include "audio_set_configurations_generated.h"
22 #include "audio_set_scenarios_generated.h"
23 #include "codec_manager.h"
24 #include "flatbuffers/idl.h"
25 #include "flatbuffers/util.h"
26 #include "le_audio_set_configuration_provider.h"
27 #include "osi/include/log.h"
28 #include "osi/include/osi.h"
29 
30 using le_audio::set_configurations::AudioSetConfiguration;
31 using le_audio::set_configurations::AudioSetConfigurations;
32 using le_audio::set_configurations::CodecCapabilitySetting;
33 using le_audio::set_configurations::LeAudioCodecIdLc3;
34 using le_audio::set_configurations::QosConfigSetting;
35 using le_audio::set_configurations::SetConfiguration;
36 using le_audio::types::LeAudioContextType;
37 
38 namespace le_audio {
39 using ::le_audio::CodecManager;
40 
41 #ifdef OS_ANDROID
42 static const std::vector<
43     std::pair<const char* /*schema*/, const char* /*content*/>>
44     kLeAudioSetConfigs = {
45         {"/apex/com.android.btservices/etc/bluetooth/le_audio/"
46          "audio_set_configurations.bfbs",
47          "/apex/com.android.btservices/etc/bluetooth/le_audio/"
48          "audio_set_configurations.json"}};
49 static const std::vector<
50     std::pair<const char* /*schema*/, const char* /*content*/>>
51     kLeAudioSetScenarios = {{"/apex/com.android.btservices/etc/bluetooth/"
52                              "le_audio/audio_set_scenarios.bfbs",
53                              "/apex/com.android.btservices/etc/bluetooth/"
54                              "le_audio/audio_set_scenarios.json"}};
55 #else
56 static const std::vector<
57     std::pair<const char* /*schema*/, const char* /*content*/>>
58     kLeAudioSetConfigs = {
59         {"audio_set_configurations.bfbs", "audio_set_configurations.json"}};
60 static const std::vector<
61     std::pair<const char* /*schema*/, const char* /*content*/>>
62     kLeAudioSetScenarios = {
63         {"audio_set_scenarios.bfbs", "audio_set_scenarios.json"}};
64 #endif
65 
66 /** Provides a set configurations for the given context type */
67 struct AudioSetConfigurationProviderJson {
68   static constexpr auto kDefaultScenario = "Media";
69 
AudioSetConfigurationProviderJsonle_audio::AudioSetConfigurationProviderJson70   AudioSetConfigurationProviderJson() {
71     ASSERT_LOG(LoadContent(kLeAudioSetConfigs, kLeAudioSetScenarios),
72                ": Unable to load le audio set configuration files.");
73   }
74 
75   /* Use the same scenario configurations for different contexts to avoid
76    * internal reconfiguration and handover that produces time gap. When using
77    * the same scenario for different contexts, quality and configuration remains
78    * the same while changing to same scenario based context type.
79    */
ScenarioToContextTypesle_audio::AudioSetConfigurationProviderJson80   static auto ScenarioToContextTypes(const std::string& scenario) {
81     static const std::multimap<std::string,
82                                ::le_audio::types::LeAudioContextType>
83         scenarios = {
84             {"Media", types::LeAudioContextType::ALERTS},
85             {"Media", types::LeAudioContextType::INSTRUCTIONAL},
86             {"Media", types::LeAudioContextType::NOTIFICATIONS},
87             {"Media", types::LeAudioContextType::EMERGENCYALARM},
88             {"Media", types::LeAudioContextType::UNSPECIFIED},
89             {"Media", types::LeAudioContextType::MEDIA},
90             {"Conversational", types::LeAudioContextType::RINGTONE},
91             {"Conversational", types::LeAudioContextType::CONVERSATIONAL},
92             {"Live", types::LeAudioContextType::LIVE},
93             {"Game", types::LeAudioContextType::GAME},
94             {"VoiceAssistants", types::LeAudioContextType::VOICEASSISTANTS},
95         };
96     return scenarios.equal_range(scenario);
97   }
98 
ContextTypeToScenariole_audio::AudioSetConfigurationProviderJson99   static std::string ContextTypeToScenario(
100       ::le_audio::types::LeAudioContextType context_type) {
101     switch (context_type) {
102       case types::LeAudioContextType::ALERTS:
103         FALLTHROUGH_INTENDED;
104       case types::LeAudioContextType::INSTRUCTIONAL:
105         FALLTHROUGH_INTENDED;
106       case types::LeAudioContextType::NOTIFICATIONS:
107         FALLTHROUGH_INTENDED;
108       case types::LeAudioContextType::EMERGENCYALARM:
109         FALLTHROUGH_INTENDED;
110       case types::LeAudioContextType::UNSPECIFIED:
111         FALLTHROUGH_INTENDED;
112       case types::LeAudioContextType::SOUNDEFFECTS:
113         FALLTHROUGH_INTENDED;
114       case types::LeAudioContextType::MEDIA:
115         return "Media";
116       case types::LeAudioContextType::RINGTONE:
117         FALLTHROUGH_INTENDED;
118       case types::LeAudioContextType::CONVERSATIONAL:
119         return "Conversational";
120       case types::LeAudioContextType::LIVE:
121         return "Live";
122       case types::LeAudioContextType::GAME:
123         return "Game";
124       case types::LeAudioContextType::VOICEASSISTANTS:
125         return "VoiceAssistants";
126       default:
127         return kDefaultScenario;
128     }
129   }
130 
GetConfigurationsByContextTypele_audio::AudioSetConfigurationProviderJson131   const AudioSetConfigurations* GetConfigurationsByContextType(
132       LeAudioContextType context_type) const {
133     if (context_configurations_.count(context_type))
134       return &context_configurations_.at(context_type);
135 
136     LOG_WARN(": No predefined scenario for the context %d was found.",
137              (int)context_type);
138 
139     auto [it_begin, it_end] = ScenarioToContextTypes(kDefaultScenario);
140     if (it_begin != it_end) {
141       LOG_WARN(": Using '%s' scenario by default.", kDefaultScenario);
142       return &context_configurations_.at(it_begin->second);
143     }
144 
145     LOG_ERROR(
146         ": No valid configuration for the default '%s' scenario, or no audio "
147         "set configurations loaded at all.",
148         kDefaultScenario);
149     return nullptr;
150   };
151 
152  private:
153   /* Codec configurations */
154   std::map<std::string, const AudioSetConfiguration> configurations_;
155 
156   /* Maps of context types to a set of configuration structs */
157   std::map<::le_audio::types::LeAudioContextType, AudioSetConfigurations>
158       context_configurations_;
159 
160   static const bluetooth::le_audio::CodecSpecificConfiguration*
LookupCodecSpecificParamle_audio::AudioSetConfigurationProviderJson161   LookupCodecSpecificParam(
162       const flatbuffers::Vector<
163           flatbuffers::Offset<bluetooth::le_audio::CodecSpecificConfiguration>>*
164           flat_codec_specific_params,
165       bluetooth::le_audio::CodecSpecificLtvGenericTypes type) {
166     auto it = std::find_if(
167         flat_codec_specific_params->cbegin(),
168         flat_codec_specific_params->cend(),
169         [&type](const auto& csc) { return (csc->type() == type); });
170     return (it != flat_codec_specific_params->cend()) ? *it : nullptr;
171   }
172 
CodecCapabilitySettingFromFlatle_audio::AudioSetConfigurationProviderJson173   static CodecCapabilitySetting CodecCapabilitySettingFromFlat(
174       const bluetooth::le_audio::CodecId* flat_codec_id,
175       const flatbuffers::Vector<
176           flatbuffers::Offset<bluetooth::le_audio::CodecSpecificConfiguration>>*
177           flat_codec_specific_params) {
178     CodecCapabilitySetting codec;
179 
180     /* Cache the le_audio::types::CodecId type value */
181     codec.id = types::LeAudioCodecId({
182         .coding_format = flat_codec_id->coding_format(),
183         .vendor_company_id = flat_codec_id->vendor_company_id(),
184         .vendor_codec_id = flat_codec_id->vendor_codec_id(),
185     });
186 
187     /* Cache the types::LeAudioLc3Config type value */
188     uint8_t sampling_frequency = 0;
189     uint8_t frame_duration = 0;
190     uint32_t audio_channel_allocation = 0;
191     uint16_t octets_per_codec_frame = 0;
192     uint8_t codec_frames_blocks_per_sdu = 0;
193 
194     auto param = LookupCodecSpecificParam(
195         flat_codec_specific_params,
196         bluetooth::le_audio::
197             CodecSpecificLtvGenericTypes_SUPPORTED_SAMPLING_FREQUENCY);
198     if (param) {
199       ASSERT_LOG((param->compound_value()->value()->size() == 1),
200                  " Invalid compound value length: %d",
201                  param->compound_value()->value()->size());
202       auto ptr = param->compound_value()->value()->data();
203       STREAM_TO_UINT8(sampling_frequency, ptr);
204     }
205 
206     param = LookupCodecSpecificParam(
207         flat_codec_specific_params,
208         bluetooth::le_audio::
209             CodecSpecificLtvGenericTypes_SUPPORTED_FRAME_DURATION);
210     if (param) {
211       LOG_ASSERT(param->compound_value()->value()->size() == 1)
212           << " Invalid compound value length: "
213           << param->compound_value()->value()->size();
214       auto ptr = param->compound_value()->value()->data();
215       STREAM_TO_UINT8(frame_duration, ptr);
216     }
217 
218     param = LookupCodecSpecificParam(
219         flat_codec_specific_params,
220         bluetooth::le_audio::
221             CodecSpecificLtvGenericTypes_SUPPORTED_AUDIO_CHANNEL_ALLOCATION);
222     if (param) {
223       ASSERT_LOG((param->compound_value()->value()->size() == 4),
224                  " Invalid compound value length %d",
225                  param->compound_value()->value()->size());
226       auto ptr = param->compound_value()->value()->data();
227       STREAM_TO_UINT32(audio_channel_allocation, ptr);
228     }
229 
230     param = LookupCodecSpecificParam(
231         flat_codec_specific_params,
232         bluetooth::le_audio::
233             CodecSpecificLtvGenericTypes_SUPPORTED_OCTETS_PER_CODEC_FRAME);
234     if (param) {
235       ASSERT_LOG((param->compound_value()->value()->size() == 2),
236                  " Invalid compound value length %d",
237                  param->compound_value()->value()->size());
238       auto ptr = param->compound_value()->value()->data();
239       STREAM_TO_UINT16(octets_per_codec_frame, ptr);
240     }
241 
242     param = LookupCodecSpecificParam(
243         flat_codec_specific_params,
244         bluetooth::le_audio::
245             CodecSpecificLtvGenericTypes_SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU);
246     if (param) {
247       ASSERT_LOG((param->compound_value()->value()->size() == 1),
248                  " Invalid compound value length %d",
249                  param->compound_value()->value()->size());
250       auto ptr = param->compound_value()->value()->data();
251       STREAM_TO_UINT8(codec_frames_blocks_per_sdu, ptr);
252     }
253 
254     codec.config = types::LeAudioLc3Config({
255         .sampling_frequency = sampling_frequency,
256         .frame_duration = frame_duration,
257         .octets_per_codec_frame = octets_per_codec_frame,
258         .codec_frames_blocks_per_sdu = codec_frames_blocks_per_sdu,
259         .channel_count =
260             (uint8_t)std::bitset<32>(audio_channel_allocation).count(),
261         .audio_channel_allocation = audio_channel_allocation,
262     });
263     return codec;
264   }
265 
SetConfigurationFromFlatSubconfigle_audio::AudioSetConfigurationProviderJson266   SetConfiguration SetConfigurationFromFlatSubconfig(
267       const bluetooth::le_audio::AudioSetSubConfiguration* flat_subconfig,
268       QosConfigSetting qos) {
269     auto strategy_int =
270         static_cast<int>(flat_subconfig->configuration_strategy());
271 
272     bool valid_strategy =
273         (strategy_int >=
274          (int)types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE) &&
275         strategy_int < (int)types::LeAudioConfigurationStrategy::RFU;
276 
277     types::LeAudioConfigurationStrategy strategy =
278         valid_strategy
279             ? static_cast<types::LeAudioConfigurationStrategy>(strategy_int)
280             : types::LeAudioConfigurationStrategy::RFU;
281 
282     auto target_latency_int =
283         static_cast<int>(flat_subconfig->target_latency());
284 
285     bool valid_target_latency =
286         (target_latency_int >= (int)types::kTargetLatencyLower &&
287          target_latency_int <= (int)types::kTargetLatencyHigherReliability);
288 
289     uint8_t target_latency =
290         valid_target_latency ? static_cast<uint8_t>(target_latency_int)
291                              : types::kTargetLatencyBalancedLatencyReliability;
292     return SetConfiguration(
293         flat_subconfig->direction(), flat_subconfig->device_cnt(),
294         flat_subconfig->ase_cnt(), target_latency,
295         CodecCapabilitySettingFromFlat(flat_subconfig->codec_id(),
296                                        flat_subconfig->codec_configuration()),
297         qos, strategy);
298   }
299 
AudioSetConfigurationFromFlatle_audio::AudioSetConfigurationProviderJson300   AudioSetConfiguration AudioSetConfigurationFromFlat(
301       const bluetooth::le_audio::AudioSetConfiguration* flat_cfg,
302       std::vector<const bluetooth::le_audio::CodecConfiguration*>* codec_cfgs,
303       std::vector<const bluetooth::le_audio::QosConfiguration*>* qos_cfgs) {
304     ASSERT_LOG(flat_cfg != nullptr, "flat_cfg cannot be null");
305     std::string codec_config_key = flat_cfg->codec_config_name()->str();
306     auto* qos_config_key_array = flat_cfg->qos_config_name();
307 
308     constexpr std::string_view default_qos = "QoS_Config_Server_Preferred";
309 
310     std::string qos_sink_key(default_qos);
311     std::string qos_source_key(default_qos);
312 
313     /* We expect maximum two QoS settings. First for Sink and second for Source
314      */
315     if (qos_config_key_array->size() > 0) {
316       qos_sink_key = qos_config_key_array->Get(0)->str();
317       if (qos_config_key_array->size() > 1) {
318         qos_source_key = qos_config_key_array->Get(1)->str();
319       } else {
320         qos_source_key = qos_sink_key;
321       }
322     }
323 
324     LOG_INFO("Config name %s, qos_sink %s, qos_source %s",
325              codec_config_key.c_str(), qos_sink_key.c_str(),
326              qos_source_key.c_str());
327 
328     const bluetooth::le_audio::QosConfiguration* qos_sink_cfg = nullptr;
329     for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) {
330       if ((*i)->name()->str() == qos_sink_key) {
331         qos_sink_cfg = *i;
332         break;
333       }
334     }
335 
336     const bluetooth::le_audio::QosConfiguration* qos_source_cfg = nullptr;
337     for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) {
338       if ((*i)->name()->str() == qos_source_key) {
339         qos_source_cfg = *i;
340         break;
341       }
342     }
343 
344     QosConfigSetting qos_sink;
345     if (qos_sink_cfg != nullptr) {
346       qos_sink.retransmission_number = qos_sink_cfg->retransmission_number();
347       qos_sink.max_transport_latency = qos_sink_cfg->max_transport_latency();
348     } else {
349       LOG_ERROR("No qos config matching key %s found", qos_sink_key.c_str());
350     }
351 
352     QosConfigSetting qos_source;
353     if (qos_source_cfg != nullptr) {
354       qos_source.retransmission_number =
355           qos_source_cfg->retransmission_number();
356       qos_source.max_transport_latency =
357           qos_source_cfg->max_transport_latency();
358     } else {
359       LOG_ERROR("No qos config matching key %s found", qos_source_key.c_str());
360     }
361 
362     const bluetooth::le_audio::CodecConfiguration* codec_cfg = nullptr;
363     for (auto i = codec_cfgs->begin(); i != codec_cfgs->end(); ++i) {
364       if ((*i)->name()->str() == codec_config_key) {
365         codec_cfg = *i;
366         break;
367       }
368     }
369 
370     std::vector<SetConfiguration> subconfigs;
371     if (codec_cfg != nullptr && codec_cfg->subconfigurations()) {
372       /* Load subconfigurations */
373       for (auto subconfig : *codec_cfg->subconfigurations()) {
374         if (subconfig->direction() == le_audio::types::kLeAudioDirectionSink) {
375           subconfigs.push_back(
376               SetConfigurationFromFlatSubconfig(subconfig, qos_sink));
377         } else {
378           subconfigs.push_back(
379               SetConfigurationFromFlatSubconfig(subconfig, qos_source));
380         }
381       }
382     } else {
383       if (codec_cfg == nullptr) {
384         LOG_ERROR("No codec config matching key %s found",
385                   codec_config_key.c_str());
386       } else {
387         LOG_ERROR("Configuration '%s' has no valid subconfigurations.",
388                   flat_cfg->name()->c_str());
389       }
390     }
391 
392     return AudioSetConfiguration({flat_cfg->name()->c_str(), subconfigs});
393   }
394 
LoadConfigurationsFromFilesle_audio::AudioSetConfigurationProviderJson395   bool LoadConfigurationsFromFiles(const char* schema_file,
396                                    const char* content_file) {
397     flatbuffers::Parser configurations_parser_;
398     std::string configurations_schema_binary_content;
399     bool ok = flatbuffers::LoadFile(schema_file, true,
400                                     &configurations_schema_binary_content);
401     if (!ok) return ok;
402 
403     /* Load the binary schema */
404     ok = configurations_parser_.Deserialize(
405         (uint8_t*)configurations_schema_binary_content.c_str(),
406         configurations_schema_binary_content.length());
407     if (!ok) return ok;
408 
409     /* Load the content from JSON */
410     std::string configurations_json_content;
411     ok = flatbuffers::LoadFile(content_file, false,
412                                &configurations_json_content);
413     if (!ok) return ok;
414 
415     /* Parse */
416     ok = configurations_parser_.Parse(configurations_json_content.c_str());
417     if (!ok) return ok;
418 
419     /* Import from flatbuffers */
420     auto configurations_root = bluetooth::le_audio::GetAudioSetConfigurations(
421         configurations_parser_.builder_.GetBufferPointer());
422     if (!configurations_root) return false;
423 
424     auto flat_qos_configs = configurations_root->qos_configurations();
425     if ((flat_qos_configs == nullptr) || (flat_qos_configs->size() == 0))
426       return false;
427 
428     LOG_DEBUG(": Updating %d qos config entries.", flat_qos_configs->size());
429     std::vector<const bluetooth::le_audio::QosConfiguration*> qos_cfgs;
430     for (auto const& flat_qos_cfg : *flat_qos_configs) {
431       qos_cfgs.push_back(flat_qos_cfg);
432     }
433 
434     auto flat_codec_configs = configurations_root->codec_configurations();
435     if ((flat_codec_configs == nullptr) || (flat_codec_configs->size() == 0))
436       return false;
437 
438     LOG_DEBUG(": Updating %d codec config entries.",
439               flat_codec_configs->size());
440     std::vector<const bluetooth::le_audio::CodecConfiguration*> codec_cfgs;
441     for (auto const& flat_codec_cfg : *flat_codec_configs) {
442       codec_cfgs.push_back(flat_codec_cfg);
443     }
444 
445     auto flat_configs = configurations_root->configurations();
446     if ((flat_configs == nullptr) || (flat_configs->size() == 0)) return false;
447 
448     LOG_DEBUG(": Updating %d config entries.", flat_configs->size());
449     for (auto const& flat_cfg : *flat_configs) {
450       configurations_.insert(
451           {flat_cfg->name()->str(),
452            AudioSetConfigurationFromFlat(flat_cfg, &codec_cfgs, &qos_cfgs)});
453     }
454 
455     return true;
456   }
457 
AudioSetConfigurationsFromFlatScenariole_audio::AudioSetConfigurationProviderJson458   AudioSetConfigurations AudioSetConfigurationsFromFlatScenario(
459       const bluetooth::le_audio::AudioSetScenario* const flat_scenario) {
460     AudioSetConfigurations items;
461     if (!flat_scenario->configurations()) return items;
462 
463     for (auto config_name : *flat_scenario->configurations()) {
464       if (configurations_.count(config_name->str()) == 0) continue;
465 
466       auto& cfg = configurations_.at(config_name->str());
467       items.push_back(&cfg);
468     }
469 
470     return items;
471   }
472 
LoadScenariosFromFilesle_audio::AudioSetConfigurationProviderJson473   bool LoadScenariosFromFiles(const char* schema_file,
474                               const char* content_file) {
475     flatbuffers::Parser scenarios_parser_;
476     std::string scenarios_schema_binary_content;
477     bool ok = flatbuffers::LoadFile(schema_file, true,
478                                     &scenarios_schema_binary_content);
479     if (!ok) return ok;
480 
481     /* Load the binary schema */
482     ok = scenarios_parser_.Deserialize(
483         (uint8_t*)scenarios_schema_binary_content.c_str(),
484         scenarios_schema_binary_content.length());
485     if (!ok) return ok;
486 
487     /* Load the content from JSON */
488     std::string scenarios_json_content;
489     ok = flatbuffers::LoadFile(content_file, false, &scenarios_json_content);
490     if (!ok) return ok;
491 
492     /* Parse */
493     ok = scenarios_parser_.Parse(scenarios_json_content.c_str());
494     if (!ok) return ok;
495 
496     /* Import from flatbuffers */
497     auto scenarios_root = bluetooth::le_audio::GetAudioSetScenarios(
498         scenarios_parser_.builder_.GetBufferPointer());
499     if (!scenarios_root) return false;
500 
501     auto flat_scenarios = scenarios_root->scenarios();
502     if ((flat_scenarios == nullptr) || (flat_scenarios->size() == 0))
503       return false;
504 
505     LOG_DEBUG(": Updating %d scenarios.", flat_scenarios->size());
506     for (auto const& scenario : *flat_scenarios) {
507       auto [it_begin, it_end] =
508           ScenarioToContextTypes(scenario->name()->c_str());
509       for (auto it = it_begin; it != it_end; ++it) {
510         context_configurations_.insert_or_assign(
511             it->second, AudioSetConfigurationsFromFlatScenario(scenario));
512       }
513     }
514 
515     return true;
516   }
517 
LoadContentle_audio::AudioSetConfigurationProviderJson518   bool LoadContent(
519       std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
520           config_files,
521       std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
522           scenario_files) {
523     for (auto [schema, content] : config_files) {
524       if (!LoadConfigurationsFromFiles(schema, content)) return false;
525     }
526 
527     for (auto [schema, content] : scenario_files) {
528       if (!LoadScenariosFromFiles(schema, content)) return false;
529     }
530     return true;
531   }
532 };
533 
534 struct AudioSetConfigurationProvider::impl {
implle_audio::AudioSetConfigurationProvider::impl535   impl(const AudioSetConfigurationProvider& config_provider)
536       : config_provider_(config_provider) {}
537 
Initializele_audio::AudioSetConfigurationProvider::impl538   void Initialize() {
539     ASSERT_LOG(!config_provider_impl_, " Config provider not available.");
540     config_provider_impl_ =
541         std::make_unique<AudioSetConfigurationProviderJson>();
542   }
543 
Cleanuple_audio::AudioSetConfigurationProvider::impl544   void Cleanup() {
545     ASSERT_LOG(config_provider_impl_, " Config provider not available.");
546     config_provider_impl_.reset();
547   }
548 
IsRunningle_audio::AudioSetConfigurationProvider::impl549   bool IsRunning() { return config_provider_impl_ ? true : false; }
550 
Dumple_audio::AudioSetConfigurationProvider::impl551   void Dump(int fd) {
552     std::stringstream stream;
553 
554     for (LeAudioContextType context : types::kLeAudioContextAllTypesArray) {
555       auto confs = Get()->GetConfigurations(context);
556       stream << "\n  === Configurations for context type: " << (int)context
557              << ", num: " << (confs == nullptr ? 0 : confs->size()) << " \n";
558       if (confs && confs->size() > 0) {
559         for (const auto& conf : *confs) {
560           stream << "  name: " << conf->name << " \n";
561           for (const auto& ent : conf->confs) {
562             stream << "    direction: "
563                    << (ent.direction == types::kLeAudioDirectionSink
564                            ? "Sink (speaker)\n"
565                            : "Source (mic)\n")
566                    << "     number of devices: " << +ent.device_cnt << " \n"
567                    << "     number of ASEs: " << +ent.ase_cnt << " \n"
568                    << "     target latency: " << +ent.target_latency << " \n"
569                    << "     strategy: " << (int)(ent.strategy) << " \n"
570                    << "     qos->retransmission_number: "
571                    << +ent.qos.retransmission_number << " \n"
572                    << "     qos->max_transport_latency: "
573                    << +ent.qos.max_transport_latency << " \n"
574                    << "     channel count: "
575                    << +ent.codec.GetConfigChannelCount() << "\n";
576           }
577         }
578       }
579     }
580     dprintf(fd, "%s", stream.str().c_str());
581   }
582 
583   const AudioSetConfigurationProvider& config_provider_;
584   std::unique_ptr<AudioSetConfigurationProviderJson> config_provider_impl_;
585 };
586 
587 static std::unique_ptr<AudioSetConfigurationProvider> config_provider;
588 
AudioSetConfigurationProvider()589 AudioSetConfigurationProvider::AudioSetConfigurationProvider()
590     : pimpl_(std::make_unique<AudioSetConfigurationProvider::impl>(*this)) {}
591 
Initialize()592 void AudioSetConfigurationProvider::Initialize() {
593   if (!config_provider)
594     config_provider = std::make_unique<AudioSetConfigurationProvider>();
595 
596   if (!config_provider->pimpl_->IsRunning())
597     config_provider->pimpl_->Initialize();
598 }
599 
DebugDump(int fd)600 void AudioSetConfigurationProvider::DebugDump(int fd) {
601   if (!config_provider || !config_provider->pimpl_->IsRunning()) {
602     dprintf(
603         fd,
604         "\n AudioSetConfigurationProvider not initialized: config provider: "
605         "%d, pimpl: %d \n",
606         config_provider != nullptr,
607         (config_provider == nullptr ? 0
608                                     : config_provider->pimpl_->IsRunning()));
609     return;
610   }
611   dprintf(fd, "\n AudioSetConfigurationProvider: \n");
612   config_provider->pimpl_->Dump(fd);
613 }
614 
Cleanup()615 void AudioSetConfigurationProvider::Cleanup() {
616   if (!config_provider) return;
617   if (config_provider->pimpl_->IsRunning()) config_provider->pimpl_->Cleanup();
618   config_provider.reset();
619 }
620 
Get()621 AudioSetConfigurationProvider* AudioSetConfigurationProvider::Get() {
622   return config_provider.get();
623 }
624 
625 const set_configurations::AudioSetConfigurations*
GetConfigurations(::le_audio::types::LeAudioContextType content_type) const626 AudioSetConfigurationProvider::GetConfigurations(
627     ::le_audio::types::LeAudioContextType content_type) const {
628   if (CodecManager::GetInstance()->GetCodecLocation() ==
629       types::CodecLocation::ADSP) {
630     LOG_DEBUG("Get offload config for the context type: %d", (int)content_type);
631     const AudioSetConfigurations* offload_confs =
632         CodecManager::GetInstance()->GetOffloadCodecConfig(content_type);
633 
634     if (offload_confs != nullptr && !(*offload_confs).empty()) {
635       return offload_confs;
636     }
637 
638     // TODO: Need to have a mechanism to switch to software session if offload
639     // doesn't support.
640   }
641 
642   LOG_DEBUG("Get software config for the context type: %d", (int)content_type);
643 
644   if (pimpl_->IsRunning())
645     return pimpl_->config_provider_impl_->GetConfigurationsByContextType(
646         content_type);
647 
648   return nullptr;
649 }
650 
651 }  // namespace le_audio
652