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 "BTAudioProviderLeAudioHW"
18 
19 #include "LeAudioOffloadAudioProvider.h"
20 
21 #include <BluetoothAudioCodecs.h>
22 #include <BluetoothAudioSessionReport.h>
23 #include <android-base/logging.h>
24 
25 namespace aidl {
26 namespace android {
27 namespace hardware {
28 namespace bluetooth {
29 namespace audio {
30 
31 constexpr uint8_t kLeAudioDirectionSink = 0x01;
32 constexpr uint8_t kLeAudioDirectionSource = 0x02;
33 constexpr uint8_t kIsoDataPathHci = 0x00;
34 constexpr uint8_t kIsoDataPathPlatformDefault = 0x01;
35 
36 const std::map<CodecSpecificConfigurationLtv::SamplingFrequency, uint32_t>
37     freq_to_support_bitmask_map = {
38         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000,
39          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000},
40         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025,
41          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ11025},
42         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
43          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000},
44         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ22050,
45          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ22050},
46         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
47          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ24000},
48         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ32000,
49          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ32000},
50         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000,
51          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ48000},
52         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ88200,
53          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ88200},
54         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000,
55          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ96000},
56         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ176400,
57          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ176400},
58         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ192000,
59          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ192000},
60         {CodecSpecificConfigurationLtv::SamplingFrequency::HZ384000,
61          CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ384000},
62 };
63 
64 // Helper map from capability's tag to configuration's tag
65 std::map<CodecSpecificCapabilitiesLtv::Tag, CodecSpecificConfigurationLtv::Tag>
66     cap_to_cfg_tag_map = {
67         {CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies,
68          CodecSpecificConfigurationLtv::Tag::samplingFrequency},
69         {CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU,
70          CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU},
71         {CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations,
72          CodecSpecificConfigurationLtv::Tag::frameDuration},
73         {CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts,
74          CodecSpecificConfigurationLtv::Tag::audioChannelAllocation},
75         {CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame,
76          CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame},
77 };
78 
79 const std::map<CodecSpecificConfigurationLtv::FrameDuration, uint32_t>
80     fduration_to_support_fduration_map = {
81         {CodecSpecificConfigurationLtv::FrameDuration::US7500,
82          CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500},
83         {CodecSpecificConfigurationLtv::FrameDuration::US10000,
84          CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000},
85 };
86 
87 std::map<int32_t, CodecSpecificConfigurationLtv::SamplingFrequency>
88     sampling_freq_map = {
89         {16000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000},
90         {24000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000},
91         {48000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000},
92         {96000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000},
93 };
94 
95 std::map<int32_t, CodecSpecificConfigurationLtv::FrameDuration>
96     frame_duration_map = {
97         {7500, CodecSpecificConfigurationLtv::FrameDuration::US7500},
98         {10000, CodecSpecificConfigurationLtv::FrameDuration::US10000},
99 };
100 
LeAudioOffloadOutputAudioProvider()101 LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
102     : LeAudioOffloadAudioProvider() {
103   session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
104 }
105 
LeAudioOffloadInputAudioProvider()106 LeAudioOffloadInputAudioProvider::LeAudioOffloadInputAudioProvider()
107     : LeAudioOffloadAudioProvider() {
108   session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
109 }
110 
LeAudioOffloadBroadcastAudioProvider()111 LeAudioOffloadBroadcastAudioProvider::LeAudioOffloadBroadcastAudioProvider()
112     : LeAudioOffloadAudioProvider() {
113   session_type_ =
114       SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
115 }
116 
LeAudioOffloadAudioProvider()117 LeAudioOffloadAudioProvider::LeAudioOffloadAudioProvider()
118     : BluetoothAudioProvider() {}
119 
isValid(const SessionType & sessionType)120 bool LeAudioOffloadAudioProvider::isValid(const SessionType& sessionType) {
121   return (sessionType == session_type_);
122 }
123 
startSession(const std::shared_ptr<IBluetoothAudioPort> & host_if,const AudioConfiguration & audio_config,const std::vector<LatencyMode> & latency_modes,DataMQDesc * _aidl_return)124 ndk::ScopedAStatus LeAudioOffloadAudioProvider::startSession(
125     const std::shared_ptr<IBluetoothAudioPort>& host_if,
126     const AudioConfiguration& audio_config,
127     const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
128   if (session_type_ ==
129       SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
130     if (audio_config.getTag() != AudioConfiguration::leAudioBroadcastConfig) {
131       LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
132                    << audio_config.toString();
133       *_aidl_return = DataMQDesc();
134       return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
135     }
136   } else if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
137     LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
138                  << audio_config.toString();
139     *_aidl_return = DataMQDesc();
140     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
141   }
142 
143   return BluetoothAudioProvider::startSession(host_if, audio_config,
144                                               latency_modes, _aidl_return);
145 }
146 
onSessionReady(DataMQDesc * _aidl_return)147 ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady(
148     DataMQDesc* _aidl_return) {
149   BluetoothAudioSessionReport::OnSessionStarted(
150       session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
151   *_aidl_return = DataMQDesc();
152   return ndk::ScopedAStatus::ok();
153 }
setCodecPriority(const CodecId & in_codecId,int32_t in_priority)154 ndk::ScopedAStatus LeAudioOffloadAudioProvider::setCodecPriority(
155     const CodecId& in_codecId, int32_t in_priority) {
156   codec_priority_map_[in_codecId] = in_priority;
157   return ndk::ScopedAStatus::ok();
158 };
159 
isMatchedValidCodec(CodecId cfg_codec,CodecId req_codec)160 bool LeAudioOffloadAudioProvider::isMatchedValidCodec(CodecId cfg_codec,
161                                                       CodecId req_codec) {
162   auto priority = codec_priority_map_.find(cfg_codec);
163   if (priority != codec_priority_map_.end() &&
164       priority->second ==
165           LeAudioOffloadAudioProvider::CODEC_PRIORITY_DISABLED) {
166     return false;
167   }
168   return cfg_codec == req_codec;
169 }
170 
filterCapabilitiesMatchedContext(AudioContext & setting_context,const IBluetoothAudioProvider::LeAudioDeviceCapabilities & capabilities)171 bool LeAudioOffloadAudioProvider::filterCapabilitiesMatchedContext(
172     AudioContext& setting_context,
173     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
174   // If has no metadata, assume match
175   if (!capabilities.metadata.has_value()) return true;
176 
177   for (auto metadata : capabilities.metadata.value()) {
178     if (!metadata.has_value()) continue;
179     if (metadata.value().getTag() == MetadataLtv::Tag::preferredAudioContexts) {
180       // Check all pref audio context to see if anything matched
181       auto& prefer_context =
182           metadata.value()
183               .get<MetadataLtv::Tag::preferredAudioContexts>()
184               .values;
185       if (setting_context.bitmask & prefer_context.bitmask) {
186         // New mask with matched capability
187         setting_context.bitmask &= prefer_context.bitmask;
188         return true;
189       }
190     }
191   }
192 
193   return false;
194 }
195 
isMatchedSamplingFreq(CodecSpecificConfigurationLtv::SamplingFrequency & cfg_freq,CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies & capability_freq)196 bool LeAudioOffloadAudioProvider::isMatchedSamplingFreq(
197     CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
198     CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
199         capability_freq) {
200   auto p = freq_to_support_bitmask_map.find(cfg_freq);
201   if (p != freq_to_support_bitmask_map.end()) {
202     if (capability_freq.bitmask & p->second) {
203       return true;
204     }
205   }
206   return false;
207 }
208 
isMatchedFrameDuration(CodecSpecificConfigurationLtv::FrameDuration & cfg_fduration,CodecSpecificCapabilitiesLtv::SupportedFrameDurations & capability_fduration)209 bool LeAudioOffloadAudioProvider::isMatchedFrameDuration(
210     CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
211     CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
212         capability_fduration) {
213   auto p = fduration_to_support_fduration_map.find(cfg_fduration);
214   if (p != fduration_to_support_fduration_map.end())
215     if (capability_fduration.bitmask & p->second) {
216       return true;
217     }
218   return false;
219 }
220 
isMatchedAudioChannel(CodecSpecificConfigurationLtv::AudioChannelAllocation &,CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts &)221 bool LeAudioOffloadAudioProvider::isMatchedAudioChannel(
222     CodecSpecificConfigurationLtv::AudioChannelAllocation&
223     /*cfg_channel*/,
224     CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
225     /*capability_channel*/) {
226   // Simply ignore.
227   // Later can use additional capabilities to match requirement.
228   bool isMatched = true;
229   return isMatched;
230 }
231 
isMatchedCodecFramesPerSDU(CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU & cfg_frame_sdu,CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU & capability_frame_sdu)232 bool LeAudioOffloadAudioProvider::isMatchedCodecFramesPerSDU(
233     CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU& cfg_frame_sdu,
234     CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU&
235         capability_frame_sdu) {
236   return cfg_frame_sdu.value <= capability_frame_sdu.value;
237 }
238 
isMatchedOctetsPerCodecFrame(CodecSpecificConfigurationLtv::OctetsPerCodecFrame & cfg_octets,CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame & capability_octets)239 bool LeAudioOffloadAudioProvider::isMatchedOctetsPerCodecFrame(
240     CodecSpecificConfigurationLtv::OctetsPerCodecFrame& cfg_octets,
241     CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame&
242         capability_octets) {
243   return cfg_octets.value >= capability_octets.min &&
244          cfg_octets.value <= capability_octets.max;
245 }
246 
isCapabilitiesMatchedCodecConfiguration(std::vector<CodecSpecificConfigurationLtv> & codec_cfg,std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities)247 bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedCodecConfiguration(
248     std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
249     std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities) {
250   // Convert all codec_cfg into a map of tags -> correct data
251   std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
252       cfg_tag_map;
253   for (auto codec_cfg_data : codec_cfg)
254     cfg_tag_map[codec_cfg_data.getTag()] = codec_cfg_data;
255 
256   for (auto& codec_capability : codec_capabilities) {
257     auto cfg = cfg_tag_map.find(cap_to_cfg_tag_map[codec_capability.getTag()]);
258     // If capability has this tag, but our configuration doesn't
259     // Then we will assume it is matched
260     if (cfg == cfg_tag_map.end()) {
261       continue;
262     }
263 
264     switch (codec_capability.getTag()) {
265       case CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies: {
266         if (!isMatchedSamplingFreq(
267                 cfg->second.get<
268                     CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
269                 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
270                                          supportedSamplingFrequencies>())) {
271           return false;
272         }
273         break;
274       }
275 
276       case CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations: {
277         if (!isMatchedFrameDuration(
278                 cfg->second
279                     .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
280                 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
281                                          supportedFrameDurations>())) {
282           return false;
283         }
284         break;
285       }
286 
287       case CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts: {
288         if (!isMatchedAudioChannel(
289                 cfg->second.get<CodecSpecificConfigurationLtv::Tag::
290                                     audioChannelAllocation>(),
291                 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
292                                          supportedAudioChannelCounts>())) {
293           return false;
294         }
295         break;
296       }
297 
298       case CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU: {
299         if (!isMatchedCodecFramesPerSDU(
300                 cfg->second.get<CodecSpecificConfigurationLtv::Tag::
301                                     codecFrameBlocksPerSDU>(),
302                 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
303                                          supportedMaxCodecFramesPerSDU>())) {
304           return false;
305         }
306         break;
307       }
308 
309       case CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame: {
310         if (!isMatchedOctetsPerCodecFrame(
311                 cfg->second.get<
312                     CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
313                 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
314                                          supportedOctetsPerCodecFrame>())) {
315           return false;
316         }
317         break;
318       }
319     }
320   }
321 
322   return true;
323 }
324 
isMonoConfig(CodecSpecificConfigurationLtv::AudioChannelAllocation allocation)325 bool isMonoConfig(
326     CodecSpecificConfigurationLtv::AudioChannelAllocation allocation) {
327   auto channel_count = std::bitset<32>(allocation.bitmask);
328   return (channel_count.count() <= 1);
329 }
330 
filterMatchedAseConfiguration(LeAudioAseConfiguration & setting_cfg,const LeAudioAseConfiguration & requirement_cfg)331 bool LeAudioOffloadAudioProvider::filterMatchedAseConfiguration(
332     LeAudioAseConfiguration& setting_cfg,
333     const LeAudioAseConfiguration& requirement_cfg) {
334   // Check matching for codec configuration <=> requirement ASE codec
335   // Also match if no CodecId requirement
336   if (requirement_cfg.codecId.has_value()) {
337     if (!setting_cfg.codecId.has_value()) return false;
338     if (!isMatchedValidCodec(setting_cfg.codecId.value(),
339                              requirement_cfg.codecId.value())) {
340       LOG(WARNING) << __func__ << ": Doesn't match valid codec, cfg = "
341                    << setting_cfg.codecId.value().toString()
342                    << ", req = " << requirement_cfg.codecId.value().toString();
343       return false;
344     }
345   }
346 
347   if (requirement_cfg.targetLatency !=
348           LeAudioAseConfiguration::TargetLatency::UNDEFINED &&
349       setting_cfg.targetLatency != requirement_cfg.targetLatency) {
350     LOG(WARNING) << __func__ << ": Doesn't match target latency, cfg = "
351                  << int(setting_cfg.targetLatency)
352                  << ", req = " << int(requirement_cfg.targetLatency);
353     return false;
354   }
355   // Ignore PHY requirement
356 
357   // Check all codec configuration
358   std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
359       cfg_tag_map;
360   for (auto cfg : setting_cfg.codecConfiguration)
361     cfg_tag_map[cfg.getTag()] = cfg;
362 
363   for (auto requirement_cfg : requirement_cfg.codecConfiguration) {
364     // Directly compare CodecSpecificConfigurationLtv
365     auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
366     // Config not found for this requirement, cannot match
367     if (cfg == cfg_tag_map.end()) {
368       LOG(WARNING) << __func__ << ": Config not found for the requirement "
369                    << requirement_cfg.toString();
370       return false;
371     }
372 
373     // Ignore matching for audio channel allocation
374     // since the rule is complicated. Match outside instead
375     if (requirement_cfg.getTag() ==
376         CodecSpecificConfigurationLtv::Tag::audioChannelAllocation)
377       continue;
378 
379     if (cfg->second != requirement_cfg) {
380       LOG(WARNING) << __func__
381                    << ": Config doesn't match the requirement, cfg = "
382                    << cfg->second.toString()
383                    << ", req = " << requirement_cfg.toString();
384       return false;
385     }
386   }
387   // Ignore vendor configuration and metadata requirement
388 
389   return true;
390 }
391 
isMatchedBISConfiguration(LeAudioBisConfiguration bis_cfg,const IBluetoothAudioProvider::LeAudioDeviceCapabilities & capabilities)392 bool LeAudioOffloadAudioProvider::isMatchedBISConfiguration(
393     LeAudioBisConfiguration bis_cfg,
394     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
395   if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) {
396     return false;
397   }
398   if (!isCapabilitiesMatchedCodecConfiguration(
399           bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities)) {
400     return false;
401   }
402   return true;
403 }
404 
filterCapabilitiesAseDirectionConfiguration(std::vector<std::optional<AseDirectionConfiguration>> & direction_configurations,const IBluetoothAudioProvider::LeAudioDeviceCapabilities & capabilities,std::vector<std::optional<AseDirectionConfiguration>> & valid_direction_configurations)405 void LeAudioOffloadAudioProvider::filterCapabilitiesAseDirectionConfiguration(
406     std::vector<std::optional<AseDirectionConfiguration>>&
407         direction_configurations,
408     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
409     std::vector<std::optional<AseDirectionConfiguration>>&
410         valid_direction_configurations) {
411   for (auto direction_configuration : direction_configurations) {
412     if (!direction_configuration.has_value()) continue;
413     if (!direction_configuration.value().aseConfiguration.codecId.has_value())
414       continue;
415     if (!isMatchedValidCodec(
416             direction_configuration.value().aseConfiguration.codecId.value(),
417             capabilities.codecId))
418       continue;
419     // Check matching for codec configuration <=> codec capabilities
420     if (!isCapabilitiesMatchedCodecConfiguration(
421             direction_configuration.value().aseConfiguration.codecConfiguration,
422             capabilities.codecSpecificCapabilities))
423       continue;
424     valid_direction_configurations.push_back(direction_configuration);
425   }
426 }
427 
getLeAudioAseConfigurationAllocationBitmask(LeAudioAseConfiguration cfg)428 int getLeAudioAseConfigurationAllocationBitmask(LeAudioAseConfiguration cfg) {
429   for (auto cfg_ltv : cfg.codecConfiguration) {
430     if (cfg_ltv.getTag() ==
431         CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
432       return cfg_ltv
433           .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
434           .bitmask;
435     }
436   }
437   return 0;
438 }
439 
getCountFromBitmask(int bitmask)440 int getCountFromBitmask(int bitmask) {
441   return std::bitset<32>(bitmask).count();
442 }
443 
findValidMonoConfig(std::vector<AseDirectionConfiguration> & valid_direction_configurations,int bitmask)444 std::optional<AseDirectionConfiguration> findValidMonoConfig(
445     std::vector<AseDirectionConfiguration>& valid_direction_configurations,
446     int bitmask) {
447   for (auto& cfg : valid_direction_configurations) {
448     int cfg_bitmask =
449         getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
450     if (getCountFromBitmask(cfg_bitmask) <= 1) {
451       // Modify the bitmask to be the same as the requirement
452       for (auto& codec_cfg : cfg.aseConfiguration.codecConfiguration) {
453         if (codec_cfg.getTag() ==
454             CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
455           codec_cfg
456               .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
457               .bitmask = bitmask;
458           return cfg;
459         }
460       }
461     }
462   }
463   return std::nullopt;
464 }
465 
getValidConfigurationsFromAllocation(int req_allocation_bitmask,std::vector<AseDirectionConfiguration> & valid_direction_configurations,bool is_exact)466 std::vector<AseDirectionConfiguration> getValidConfigurationsFromAllocation(
467     int req_allocation_bitmask,
468     std::vector<AseDirectionConfiguration>& valid_direction_configurations,
469     bool is_exact) {
470   // Prefer the same allocation_bitmask
471   int channel_count = getCountFromBitmask(req_allocation_bitmask);
472 
473   if (is_exact) {
474     for (auto& cfg : valid_direction_configurations) {
475       int cfg_bitmask =
476           getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
477       if (cfg_bitmask == req_allocation_bitmask) {
478         LOG(DEBUG)
479             << __func__
480             << ": Found an exact match for the requirement allocation of "
481             << cfg_bitmask;
482         return {cfg};
483       }
484     }
485     return {};
486   }
487   // Not using exact match strategy
488   if (channel_count <= 1) {
489     // Mono requirement matched if cfg is a mono config
490     auto cfg = findValidMonoConfig(valid_direction_configurations,
491                                    req_allocation_bitmask);
492     if (cfg.has_value()) return {cfg.value()};
493   } else {
494     // Stereo requirement returns 2 mono configs
495     // that has a combined bitmask equal to the stereo config
496     std::vector<AseDirectionConfiguration> temp;
497     for (int bit = 0; bit < 32; ++bit)
498       if (req_allocation_bitmask & (1 << bit)) {
499         auto cfg =
500             findValidMonoConfig(valid_direction_configurations, (1 << bit));
501         if (cfg.has_value()) temp.push_back(cfg.value());
502       }
503     if (temp.size() == channel_count) return temp;
504   }
505   return {};
506 }
507 
filterRequirementAseDirectionConfiguration(std::optional<std::vector<std::optional<AseDirectionConfiguration>>> & direction_configurations,const std::vector<std::optional<AseDirectionRequirement>> & requirements,std::optional<std::vector<std::optional<AseDirectionConfiguration>>> & valid_direction_configurations,bool is_exact)508 void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
509     std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
510         direction_configurations,
511     const std::vector<std::optional<AseDirectionRequirement>>& requirements,
512     std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
513         valid_direction_configurations,
514     bool is_exact) {
515   // For every requirement, find the matched ase configuration
516   if (!direction_configurations.has_value()) return;
517 
518   if (!valid_direction_configurations.has_value()) {
519     valid_direction_configurations =
520         std::vector<std::optional<AseDirectionConfiguration>>();
521   }
522 
523   for (auto& requirement : requirements) {
524     if (!requirement.has_value()) continue;
525     auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
526         requirement.value().aseConfiguration);
527     auto req_channel_count = getCountFromBitmask(req_allocation_bitmask);
528 
529     auto temp = std::vector<AseDirectionConfiguration>();
530 
531     for (auto direction_configuration : direction_configurations.value()) {
532       if (!direction_configuration.has_value()) continue;
533       if (!filterMatchedAseConfiguration(
534               direction_configuration.value().aseConfiguration,
535               requirement.value().aseConfiguration))
536         continue;
537       // Valid if match any requirement.
538       temp.push_back(direction_configuration.value());
539     }
540 
541     // Get the best matching config based on channel allocation
542     auto total_cfg_channel_count = 0;
543     auto req_valid_configs = getValidConfigurationsFromAllocation(
544         req_allocation_bitmask, temp, is_exact);
545     // Count and check required channel counts
546     for (auto& cfg : req_valid_configs) {
547       total_cfg_channel_count += getCountFromBitmask(
548           getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration));
549       valid_direction_configurations.value().push_back(cfg);
550     }
551     if (total_cfg_channel_count != req_channel_count) {
552       valid_direction_configurations = std::nullopt;
553       return;
554     }
555   }
556 }
557 
558 /* Get a new LeAudioAseConfigurationSetting by matching a setting with a
559  * capabilities. The new setting will have a filtered list of
560  * AseDirectionConfiguration that matched the capabilities */
561 std::optional<LeAudioAseConfigurationSetting>
getCapabilitiesMatchedAseConfigurationSettings(IBluetoothAudioProvider::LeAudioAseConfigurationSetting & setting,const IBluetoothAudioProvider::LeAudioDeviceCapabilities & capabilities,uint8_t direction)562 LeAudioOffloadAudioProvider::getCapabilitiesMatchedAseConfigurationSettings(
563     IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
564     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
565     uint8_t direction) {
566   // Create a new LeAudioAseConfigurationSetting and return
567   // For other direction will contain all settings
568   LeAudioAseConfigurationSetting filtered_setting{
569       .audioContext = setting.audioContext,
570       .sinkAseConfiguration = setting.sinkAseConfiguration,
571       .sourceAseConfiguration = setting.sourceAseConfiguration,
572       .flags = setting.flags,
573       .packing = setting.packing,
574   };
575 
576   // Get a list of all matched AseDirectionConfiguration
577   // for the input direction
578   std::vector<std::optional<AseDirectionConfiguration>>*
579       direction_configuration = nullptr;
580   if (direction == kLeAudioDirectionSink) {
581     if (!filtered_setting.sinkAseConfiguration.has_value()) return std::nullopt;
582     direction_configuration = &filtered_setting.sinkAseConfiguration.value();
583   } else {
584     if (!filtered_setting.sourceAseConfiguration.has_value())
585       return std::nullopt;
586     direction_configuration = &filtered_setting.sourceAseConfiguration.value();
587   }
588   std::vector<std::optional<AseDirectionConfiguration>>
589       valid_direction_configuration;
590   filterCapabilitiesAseDirectionConfiguration(
591       *direction_configuration, capabilities, valid_direction_configuration);
592 
593   // No valid configuration for this direction
594   if (valid_direction_configuration.empty()) {
595     return std::nullopt;
596   }
597 
598   // Create a new LeAudioAseConfigurationSetting and return
599   // For other direction will contain all settings
600   if (direction == kLeAudioDirectionSink) {
601     filtered_setting.sinkAseConfiguration = valid_direction_configuration;
602   } else {
603     filtered_setting.sourceAseConfiguration = valid_direction_configuration;
604   }
605 
606   return filtered_setting;
607 }
608 
609 /* Get a new LeAudioAseConfigurationSetting by matching a setting with a
610  * requirement. The new setting will have a filtered list of
611  * AseDirectionConfiguration that matched the requirement */
612 std::optional<LeAudioAseConfigurationSetting>
getRequirementMatchedAseConfigurationSettings(IBluetoothAudioProvider::LeAudioAseConfigurationSetting & setting,const IBluetoothAudioProvider::LeAudioConfigurationRequirement & requirement,bool is_exact)613 LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
614     IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
615     const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
616     bool is_exact) {
617   // Try to match context in metadata.
618   if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
619       requirement.audioContext.bitmask)
620     return std::nullopt;
621 
622   // Further filter setting's context
623   setting.audioContext.bitmask &= requirement.audioContext.bitmask;
624 
625   // Create a new LeAudioAseConfigurationSetting to return
626   LeAudioAseConfigurationSetting filtered_setting{
627       .audioContext = setting.audioContext,
628       .packing = setting.packing,
629       .flags = setting.flags,
630   };
631 
632   if (requirement.sinkAseRequirement.has_value()) {
633     filterRequirementAseDirectionConfiguration(
634         setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
635         filtered_setting.sinkAseConfiguration, is_exact);
636     if (!filtered_setting.sinkAseConfiguration.has_value()) {
637       return std::nullopt;
638     }
639   }
640 
641   if (requirement.sourceAseRequirement.has_value()) {
642     filterRequirementAseDirectionConfiguration(
643         setting.sourceAseConfiguration,
644         requirement.sourceAseRequirement.value(),
645         filtered_setting.sourceAseConfiguration, is_exact);
646     if (!filtered_setting.sourceAseConfiguration.has_value()) {
647       return std::nullopt;
648     }
649   }
650 
651   return filtered_setting;
652 }
653 
654 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
matchWithRequirement(std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> & matched_ase_configuration_settings,const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement> & in_requirements,bool is_exact)655 LeAudioOffloadAudioProvider::matchWithRequirement(
656     std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
657         matched_ase_configuration_settings,
658     const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
659         in_requirements,
660     bool is_exact) {
661   // Each requirement will match with a valid setting
662   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
663   for (auto& requirement : in_requirements) {
664     LOG(INFO) << __func__ << ": Trying to match for the requirement "
665               << requirement.toString();
666     bool is_matched = false;
667 
668     for (auto& setting : matched_ase_configuration_settings) {
669       auto filtered_ase_configuration_setting =
670           getRequirementMatchedAseConfigurationSettings(setting, requirement,
671                                                         is_exact);
672       if (filtered_ase_configuration_setting.has_value()) {
673         result.push_back(filtered_ase_configuration_setting.value());
674         LOG(INFO) << __func__ << ": Result = "
675                   << filtered_ase_configuration_setting.value().toString();
676         // Found a matched setting, ignore other settings
677         is_matched = true;
678         break;
679       }
680     }
681     if (!is_matched) {
682       // If cannot satisfy this requirement, return an empty result
683       LOG(WARNING) << __func__ << ": Cannot match the requirement "
684                    << requirement.toString();
685       result.clear();
686       break;
687     }
688   }
689   return result;
690 }
691 
692 // For each requirement, a valid ASE configuration will satify:
693 // - matched with any sink capability (if presented)
694 // - OR matched with any source capability (if presented)
695 // - and the setting need to pass the requirement
getLeAudioAseConfiguration(const std::optional<std::vector<std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>> & in_remoteSinkAudioCapabilities,const std::optional<std::vector<std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>> & in_remoteSourceAudioCapabilities,const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement> & in_requirements,std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> * _aidl_return)696 ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
697     const std::optional<std::vector<
698         std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
699         in_remoteSinkAudioCapabilities,
700     const std::optional<std::vector<
701         std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
702         in_remoteSourceAudioCapabilities,
703     const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
704         in_requirements,
705     std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
706         _aidl_return) {
707   // Get all configuration settings
708   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
709       ase_configuration_settings =
710           BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
711 
712   if (!in_remoteSinkAudioCapabilities.has_value() &&
713       !in_remoteSourceAudioCapabilities.has_value()) {
714     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
715   }
716 
717   // Split out preferred and non-preferred settings based on context
718   // An example: preferred = MEDIA, available: MEDIA | CONVERSATION
719   // -> preferred list will have settings with MEDIA context
720   // -> non-preferred list will have settings with any context
721   // We want to match requirement with preferred context settings first
722   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
723       matched_ase_configuration_settings;
724   // Matched ASE configuration with non-preferred audio context
725   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
726       non_prefer_matched_ase_configuration_settings;
727 
728   if (in_remoteSinkAudioCapabilities.has_value())
729     // Matching each setting with any remote capabilities
730     for (auto& setting : ase_configuration_settings)
731       for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
732         if (!capability.has_value()) continue;
733         auto filtered_ase_configuration_setting =
734             getCapabilitiesMatchedAseConfigurationSettings(
735                 setting, capability.value(), kLeAudioDirectionSink);
736         if (filtered_ase_configuration_setting.has_value()) {
737           // Push to non-prefer first for the broadest matching possible
738           non_prefer_matched_ase_configuration_settings.push_back(
739               filtered_ase_configuration_setting.value());
740           // Try to filter out prefer context to another vector.
741           if (filterCapabilitiesMatchedContext(
742                   filtered_ase_configuration_setting.value().audioContext,
743                   capability.value())) {
744             matched_ase_configuration_settings.push_back(
745                 filtered_ase_configuration_setting.value());
746           }
747         }
748       }
749 
750   // Combine filter every source capability
751   if (in_remoteSourceAudioCapabilities.has_value())
752     // Matching each setting with any remote capabilities
753     for (auto& setting : ase_configuration_settings)
754       for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
755         if (!capability.has_value()) continue;
756         auto filtered_ase_configuration_setting =
757             getCapabilitiesMatchedAseConfigurationSettings(
758                 setting, capability.value(), kLeAudioDirectionSource);
759         if (filtered_ase_configuration_setting.has_value()) {
760           // Put into the same list
761           // possibly duplicated, filtered by requirement later
762           // Push to non-prefer first for the broadest matching possible
763           non_prefer_matched_ase_configuration_settings.push_back(
764               filtered_ase_configuration_setting.value());
765           // Try to filter out prefer context to another vector.
766           if (filterCapabilitiesMatchedContext(
767                   filtered_ase_configuration_setting.value().audioContext,
768                   capability.value())) {
769             matched_ase_configuration_settings.push_back(
770                 filtered_ase_configuration_setting.value());
771           }
772         }
773       }
774 
775   // Matching priority list:
776   // Preferred context - exact match with allocation
777   // Any context - exact match with allocation
778   // Preferred context - loose match with allocation
779   // Any context - loose match with allocation
780 
781   // A loose match will attempt to return 2 settings with the
782   // combined allocation bitmask equal the required allocation.
783   // For example, we can return 2 link (left link and right link) when
784   // the requirement required 1 (left + right) link.
785   auto result = matchWithRequirement(matched_ase_configuration_settings,
786                                      in_requirements, true);
787   if (result.empty()) {
788     LOG(WARNING)
789         << __func__
790         << ": Cannot match with preferred context settings - exact match";
791     result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
792                                   in_requirements, true);
793   }
794   if (result.empty()) {
795     LOG(WARNING)
796         << __func__
797         << ": Cannot match with non-preferred context settings - exact match";
798     result = matchWithRequirement(matched_ase_configuration_settings,
799                                   in_requirements, false);
800   }
801   if (result.empty()) {
802     LOG(WARNING) << __func__
803                  << ": Cannot match with preferred context settings - "
804                     "non-exact match";
805     result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
806                                   in_requirements, false);
807   }
808   if (result.empty())
809     LOG(ERROR) << __func__
810                << ": Cannot match with non preferred context settings - "
811                   "non-exact match";
812   *_aidl_return = result;
813   return ndk::ScopedAStatus::ok();
814 };
815 
isMatchedQosRequirement(LeAudioAseQosConfiguration setting_qos,AseQosDirectionRequirement requirement_qos)816 bool LeAudioOffloadAudioProvider::isMatchedQosRequirement(
817     LeAudioAseQosConfiguration setting_qos,
818     AseQosDirectionRequirement requirement_qos) {
819   if (setting_qos.retransmissionNum !=
820       requirement_qos.preferredRetransmissionNum) {
821     return false;
822   }
823   if (setting_qos.maxTransportLatencyMs >
824       requirement_qos.maxTransportLatencyMs) {
825     return false;
826   }
827   return true;
828 }
829 
isValidQosRequirement(AseQosDirectionRequirement qosRequirement)830 bool isValidQosRequirement(AseQosDirectionRequirement qosRequirement) {
831   return ((qosRequirement.maxTransportLatencyMs > 0) &&
832           (qosRequirement.presentationDelayMaxUs > 0) &&
833           (qosRequirement.presentationDelayMaxUs >=
834            qosRequirement.presentationDelayMinUs));
835 }
836 
837 std::optional<LeAudioAseQosConfiguration>
getDirectionQosConfiguration(uint8_t direction,const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement & qosRequirement,std::vector<LeAudioAseConfigurationSetting> & ase_configuration_settings,bool is_exact)838 LeAudioOffloadAudioProvider::getDirectionQosConfiguration(
839     uint8_t direction,
840     const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
841         qosRequirement,
842     std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings,
843     bool is_exact) {
844   std::optional<AseQosDirectionRequirement> direction_qos_requirement =
845       std::nullopt;
846 
847   // Get the correct direction
848   if (direction == kLeAudioDirectionSink) {
849     direction_qos_requirement = qosRequirement.sinkAseQosRequirement.value();
850   } else {
851     direction_qos_requirement = qosRequirement.sourceAseQosRequirement.value();
852   }
853 
854   for (auto& setting : ase_configuration_settings) {
855     // Context matching
856     if ((setting.audioContext.bitmask & qosRequirement.audioContext.bitmask) !=
857         qosRequirement.audioContext.bitmask)
858       continue;
859 
860     // Match configuration flags
861     // Currently configuration flags are not populated, ignore.
862 
863     // Get a list of all matched AseDirectionConfiguration
864     // for the input direction
865     std::optional<std::vector<std::optional<AseDirectionConfiguration>>>
866         direction_configuration = std::nullopt;
867     if (direction == kLeAudioDirectionSink) {
868       if (!setting.sinkAseConfiguration.has_value()) continue;
869       direction_configuration.emplace(setting.sinkAseConfiguration.value());
870     } else {
871       if (!setting.sourceAseConfiguration.has_value()) continue;
872       direction_configuration.emplace(setting.sourceAseConfiguration.value());
873     }
874 
875     if (!direction_configuration.has_value()) {
876       return std::nullopt;
877     }
878 
879     // Collect all valid cfg into a vector
880     // Then try to get the best match for audio allocation
881 
882     auto temp = std::vector<AseDirectionConfiguration>();
883 
884     for (auto& cfg : direction_configuration.value()) {
885       if (!cfg.has_value()) continue;
886       // If no requirement, return the first QoS
887       if (!direction_qos_requirement.has_value()) {
888         return cfg.value().qosConfiguration;
889       }
890 
891       // If has requirement, return the first matched QoS
892       // Try to match the ASE configuration
893       // and QoS with requirement
894       if (!cfg.value().qosConfiguration.has_value()) continue;
895       if (filterMatchedAseConfiguration(
896               cfg.value().aseConfiguration,
897               direction_qos_requirement.value().aseConfiguration) &&
898           isMatchedQosRequirement(cfg.value().qosConfiguration.value(),
899                                   direction_qos_requirement.value())) {
900         temp.push_back(cfg.value());
901       }
902     }
903     LOG(WARNING) << __func__ << ": Got " << temp.size()
904                  << " configs, start matching allocation";
905 
906     int qos_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
907         direction_qos_requirement.value().aseConfiguration);
908     // Get the best matching config based on channel allocation
909     auto req_valid_configs = getValidConfigurationsFromAllocation(
910         qos_allocation_bitmask, temp, is_exact);
911     if (req_valid_configs.empty()) {
912       LOG(WARNING) << __func__
913                    << ": Cannot find matching allocation for bitmask "
914                    << qos_allocation_bitmask;
915 
916     } else {
917       return req_valid_configs[0].qosConfiguration;
918     }
919   }
920 
921   return std::nullopt;
922 }
923 
getLeAudioAseQosConfiguration(const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement & in_qosRequirement,IBluetoothAudioProvider::LeAudioAseQosConfigurationPair * _aidl_return)924 ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
925     const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
926         in_qosRequirement,
927     IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) {
928   IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
929 
930   // Get all configuration settings
931   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
932       ase_configuration_settings =
933           BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
934 
935   // Direction QoS matching
936   // Only handle one direction input case
937   if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
938     if (!isValidQosRequirement(in_qosRequirement.sinkAseQosRequirement.value()))
939       return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
940     {
941       // Try exact match first
942       result.sinkQosConfiguration =
943           getDirectionQosConfiguration(kLeAudioDirectionSink, in_qosRequirement,
944                                        ase_configuration_settings, true);
945       if (!result.sinkQosConfiguration.has_value()) {
946         result.sinkQosConfiguration = getDirectionQosConfiguration(
947             kLeAudioDirectionSink, in_qosRequirement,
948             ase_configuration_settings, false);
949       }
950     }
951   }
952   if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
953     if (!isValidQosRequirement(
954             in_qosRequirement.sourceAseQosRequirement.value()))
955       return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
956     result.sourceQosConfiguration =
957         getDirectionQosConfiguration(kLeAudioDirectionSource, in_qosRequirement,
958                                      ase_configuration_settings, true);
959     if (!result.sourceQosConfiguration.has_value()) {
960       result.sourceQosConfiguration = getDirectionQosConfiguration(
961           kLeAudioDirectionSource, in_qosRequirement,
962           ase_configuration_settings, false);
963     }
964   }
965 
966   *_aidl_return = result;
967   return ndk::ScopedAStatus::ok();
968 };
969 
onSinkAseMetadataChanged(IBluetoothAudioProvider::AseState in_state,int32_t,int32_t,const std::optional<std::vector<std::optional<MetadataLtv>>> & in_metadata)970 ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSinkAseMetadataChanged(
971     IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
972     int32_t /*in_cisId*/,
973     const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
974   (void)in_state;
975   (void)in_metadata;
976   return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
977 };
978 
onSourceAseMetadataChanged(IBluetoothAudioProvider::AseState in_state,int32_t,int32_t,const std::optional<std::vector<std::optional<MetadataLtv>>> & in_metadata)979 ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSourceAseMetadataChanged(
980     IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
981     int32_t /*in_cisId*/,
982     const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
983   (void)in_state;
984   (void)in_metadata;
985   return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
986 };
987 
getDefaultBroadcastSetting(int context_bitmask,IBluetoothAudioProvider::BroadcastQuality quality)988 LeAudioBroadcastConfigurationSetting getDefaultBroadcastSetting(
989     int context_bitmask, IBluetoothAudioProvider::BroadcastQuality quality) {
990   LeAudioBroadcastConfigurationSetting setting;
991   setting.retransmitionNum = 4;
992   setting.maxTransportLatencyMs = 60;
993   setting.sduIntervalUs = 10000;
994   setting.maxSduOctets = 40;
995 
996   if (quality == IBluetoothAudioProvider::BroadcastQuality::HIGH) {
997     LOG(INFO) << __func__ << ": High quality, returning high quality settings";
998     setting.retransmitionNum = 4;
999     setting.maxTransportLatencyMs = 65;
1000     setting.maxSduOctets = 200;
1001     return setting;
1002   }
1003 
1004   // Populate other settings base on context
1005   // TODO: Populate with better design
1006   if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME)) {
1007     setting.retransmitionNum = 2;
1008     setting.maxTransportLatencyMs = 10;
1009     setting.maxSduOctets = 120;
1010   } else if (context_bitmask & (AudioContext::INSTRUCTIONAL)) {
1011     setting.retransmitionNum = 2;
1012     setting.maxTransportLatencyMs = 10;
1013     setting.maxSduOctets = 40;
1014   } else if (context_bitmask &
1015              (AudioContext::SOUND_EFFECTS | AudioContext::UNSPECIFIED)) {
1016     setting.retransmitionNum = 4;
1017     setting.maxTransportLatencyMs = 60;
1018     setting.maxSduOctets = 80;
1019   } else if (context_bitmask &
1020              (AudioContext::ALERTS | AudioContext::NOTIFICATIONS |
1021               AudioContext::EMERGENCY_ALARM)) {
1022     setting.retransmitionNum = 4;
1023     setting.maxTransportLatencyMs = 60;
1024     setting.maxSduOctets = 40;
1025   } else if (context_bitmask & AudioContext::MEDIA) {
1026     setting.retransmitionNum = 4;
1027     setting.maxTransportLatencyMs = 60;
1028     setting.maxSduOctets = 120;
1029   }
1030 
1031   return setting;
1032 }
modifySubBISConfigAllocation(IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration & sub_bis_cfg,int allocation_bitmask)1033 void modifySubBISConfigAllocation(
1034     IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration& sub_bis_cfg,
1035     int allocation_bitmask) {
1036   for (auto& codec_cfg : sub_bis_cfg.bisConfiguration.codecConfiguration) {
1037     if (codec_cfg.getTag() ==
1038         CodecSpecificConfigurationLtv::audioChannelAllocation) {
1039       codec_cfg.get<CodecSpecificConfigurationLtv::audioChannelAllocation>()
1040           .bitmask = allocation_bitmask;
1041       break;
1042     }
1043   }
1044 }
modifySubgroupConfiguration(IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration & subgroup_cfg,int context_bitmask)1045 void modifySubgroupConfiguration(
1046     IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration&
1047         subgroup_cfg,
1048     int context_bitmask) {
1049   // STEREO configs
1050   // Split into 2 sub BIS config, each has numBis = 1
1051   if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME |
1052                          AudioContext::SOUND_EFFECTS |
1053                          AudioContext::UNSPECIFIED | AudioContext::MEDIA)) {
1054     if (subgroup_cfg.bisConfigurations.size() == 1)
1055       subgroup_cfg.bisConfigurations.push_back(
1056           subgroup_cfg.bisConfigurations[0]);
1057 
1058     subgroup_cfg.bisConfigurations[0].numBis = 1;
1059     modifySubBISConfigAllocation(
1060         subgroup_cfg.bisConfigurations[0],
1061         CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT);
1062 
1063     subgroup_cfg.bisConfigurations[1].numBis = 1;
1064     modifySubBISConfigAllocation(
1065         subgroup_cfg.bisConfigurations[1],
1066         CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT);
1067     return;
1068   }
1069 
1070   // MONO configs
1071   for (auto& sub_bis_cfg : subgroup_cfg.bisConfigurations) {
1072     sub_bis_cfg.numBis = 1;
1073     modifySubBISConfigAllocation(
1074         sub_bis_cfg,
1075         CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER);
1076   }
1077 }
1078 
getBroadcastSettings()1079 void LeAudioOffloadAudioProvider::getBroadcastSettings() {
1080   if (!broadcast_settings.empty()) return;
1081 
1082   LOG(INFO) << __func__
1083             << ": Loading basic broadcast settings from provider info";
1084 
1085   std::vector<CodecInfo> db_codec_info =
1086       BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
1087           SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
1088   for (auto x : db_codec_info) {
1089     LOG(INFO) << __func__ << ": codec info = " << x.toString();
1090   }
1091   broadcast_settings.clear();
1092 
1093   // Default value population
1094   CodecSpecificConfigurationLtv::AudioChannelAllocation default_allocation;
1095   default_allocation.bitmask =
1096       CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
1097   CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU default_frame;
1098   default_frame.value = 1;
1099 
1100   for (auto& codec_info : db_codec_info) {
1101     if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
1102       continue;
1103     auto& transport = codec_info.transport.get<CodecInfo::Transport::leAudio>();
1104     LeAudioBroadcastConfigurationSetting setting;
1105     setting.retransmitionNum = 4;
1106     setting.maxTransportLatencyMs = 60;
1107     setting.sduIntervalUs = 10000;
1108     setting.maxSduOctets = 40;
1109     // Default setting
1110     setting.numBis = 1;
1111     setting.phy = {Phy::TWO_M};
1112     // Populate BIS configuration info using codec_info
1113     LeAudioBisConfiguration bis_cfg;
1114     bis_cfg.codecId = codec_info.id;
1115 
1116     CodecSpecificConfigurationLtv::OctetsPerCodecFrame octets;
1117     octets.value = transport.bitdepth[0];
1118 
1119     bis_cfg.codecConfiguration = {
1120         sampling_freq_map[transport.samplingFrequencyHz[0]],
1121         octets,
1122         frame_duration_map[transport.frameDurationUs[0]],
1123         default_allocation,
1124         default_frame,
1125     };
1126 
1127     // Ignore bis_cfg.metadata
1128 
1129     // Add information to structure
1130     IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration sub_bis_cfg;
1131     sub_bis_cfg.numBis = 1;
1132     sub_bis_cfg.bisConfiguration = bis_cfg;
1133     IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration sub_cfg;
1134     // Populate the same sub config
1135     sub_cfg.bisConfigurations = {sub_bis_cfg};
1136     setting.subgroupsConfigurations = {sub_cfg};
1137 
1138     broadcast_settings.push_back(setting);
1139   }
1140 
1141   LOG(INFO) << __func__
1142             << ": Done loading broadcast settings from provider info";
1143 }
1144 
1145 /* Get a new LeAudioAseConfigurationSetting by matching a setting with a
1146  * capabilities. The new setting will have a filtered list of
1147  * AseDirectionConfiguration that matched the capabilities */
1148 std::optional<LeAudioBroadcastConfigurationSetting>
1149 LeAudioOffloadAudioProvider::
getCapabilitiesMatchedBroadcastConfigurationSettings(LeAudioBroadcastConfigurationSetting & setting,const IBluetoothAudioProvider::LeAudioDeviceCapabilities & capabilities)1150     getCapabilitiesMatchedBroadcastConfigurationSettings(
1151         LeAudioBroadcastConfigurationSetting& setting,
1152         const IBluetoothAudioProvider::LeAudioDeviceCapabilities&
1153             capabilities) {
1154   std::vector<IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration>
1155       filter_subgroup;
1156   for (auto& sub_cfg : setting.subgroupsConfigurations) {
1157     std::vector<IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration>
1158         filtered_bis_cfg;
1159     for (auto& bis_cfg : sub_cfg.bisConfigurations)
1160       if (isMatchedBISConfiguration(bis_cfg.bisConfiguration, capabilities)) {
1161         filtered_bis_cfg.push_back(bis_cfg);
1162       }
1163     if (!filtered_bis_cfg.empty()) {
1164       IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration
1165           subgroup_cfg;
1166       subgroup_cfg.bisConfigurations = filtered_bis_cfg;
1167       filter_subgroup.push_back(subgroup_cfg);
1168     }
1169   }
1170   if (filter_subgroup.empty()) return std::nullopt;
1171 
1172   // Create a new LeAudioAseConfigurationSetting and return
1173   LeAudioBroadcastConfigurationSetting filtered_setting(setting);
1174   filtered_setting.subgroupsConfigurations = filter_subgroup;
1175 
1176   return filtered_setting;
1177 }
1178 
getCodecRequirementBasedOnContext(int context_bitmask,IBluetoothAudioProvider::BroadcastQuality quality)1179 std::vector<CodecSpecificConfigurationLtv> getCodecRequirementBasedOnContext(
1180     int context_bitmask, IBluetoothAudioProvider::BroadcastQuality quality) {
1181   // Default requirement: lc3_stereo_16_2
1182   std::vector<CodecSpecificConfigurationLtv> requirement = {
1183       CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
1184       CodecSpecificConfigurationLtv::FrameDuration::US10000,
1185   };
1186 
1187   if (quality == IBluetoothAudioProvider::BroadcastQuality::HIGH) {
1188     LOG(INFO) << __func__
1189               << ": High quality, returning high quality requirement";
1190     requirement = {
1191         CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000,
1192         CodecSpecificConfigurationLtv::FrameDuration::US10000,
1193     };
1194     return requirement;
1195   }
1196 
1197   if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME)) {
1198     // lc3_stereo_24_2_1
1199     requirement = {
1200         CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
1201         CodecSpecificConfigurationLtv::FrameDuration::US10000,
1202     };
1203   } else if (context_bitmask & (AudioContext::INSTRUCTIONAL)) {
1204     // lc3_mono_16_2
1205     requirement = {
1206         CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
1207         CodecSpecificConfigurationLtv::FrameDuration::US10000,
1208     };
1209   } else if (context_bitmask &
1210              (AudioContext::SOUND_EFFECTS | AudioContext::UNSPECIFIED)) {
1211     // lc3_stereo_16_2
1212     requirement = {
1213         CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
1214         CodecSpecificConfigurationLtv::FrameDuration::US10000,
1215     };
1216   } else if (context_bitmask &
1217              (AudioContext::ALERTS | AudioContext::NOTIFICATIONS |
1218               AudioContext::EMERGENCY_ALARM)) {
1219     // Default requirement: lc3_stereo_16_2
1220     requirement = {
1221         CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
1222         CodecSpecificConfigurationLtv::FrameDuration::US10000,
1223     };
1224   } else if (context_bitmask & AudioContext::MEDIA) {
1225     // Default requirement: lc3_stereo_16_2
1226     // Return the 48k requirement
1227     requirement = {
1228         CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
1229         CodecSpecificConfigurationLtv::FrameDuration::US10000,
1230     };
1231   }
1232   return requirement;
1233 }
1234 
isSubgroupConfigurationMatchedContext(AudioContext requirement_context,IBluetoothAudioProvider::BroadcastQuality quality,LeAudioBroadcastSubgroupConfiguration configuration)1235 bool LeAudioOffloadAudioProvider::isSubgroupConfigurationMatchedContext(
1236     AudioContext requirement_context,
1237     IBluetoothAudioProvider::BroadcastQuality quality,
1238     LeAudioBroadcastSubgroupConfiguration configuration) {
1239   // Find any valid context metadata in the bisConfigurations
1240   // assuming the bis configuration in the same bis subgroup
1241   // will have the same context metadata
1242   std::optional<AudioContext> config_context = std::nullopt;
1243 
1244   auto codec_requirement =
1245       getCodecRequirementBasedOnContext(requirement_context.bitmask, quality);
1246   std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
1247       req_tag_map;
1248   for (auto x : codec_requirement) req_tag_map[x.getTag()] = x;
1249 
1250   for (auto& bis_cfg : configuration.bisConfigurations) {
1251     // Check every sub_bis_cfg to see which match
1252     for (auto& x : bis_cfg.bisConfiguration.codecConfiguration) {
1253       auto p = req_tag_map.find(x.getTag());
1254       if (p == req_tag_map.end()) continue;
1255       if (p->second != x) {
1256         LOG(WARNING) << __func__ << ": does not match for context "
1257                      << requirement_context.toString()
1258                      << ", cfg = " << x.toString();
1259         return false;
1260       }
1261     }
1262   }
1263   return true;
1264 }
1265 
1266 ndk::ScopedAStatus
getLeAudioBroadcastConfiguration(const std::optional<std::vector<std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>> & in_remoteSinkAudioCapabilities,const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement & in_requirement,LeAudioBroadcastConfigurationSetting * _aidl_return)1267 LeAudioOffloadAudioProvider::getLeAudioBroadcastConfiguration(
1268     const std::optional<std::vector<
1269         std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
1270         in_remoteSinkAudioCapabilities,
1271     const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
1272         in_requirement,
1273     LeAudioBroadcastConfigurationSetting* _aidl_return) {
1274   if (in_requirement.subgroupConfigurationRequirements.empty()) {
1275     LOG(WARNING) << __func__ << ": Empty requirement";
1276     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1277   }
1278 
1279   // Broadcast setting are from provider info
1280   // We will allow empty capability input, match all settings with requirements.
1281   getBroadcastSettings();
1282   std::vector<LeAudioBroadcastConfigurationSetting> filtered_settings;
1283   if (!in_remoteSinkAudioCapabilities.has_value() ||
1284       in_remoteSinkAudioCapabilities.value().empty()) {
1285     LOG(INFO) << __func__ << ": Empty capability, get all broadcast settings";
1286     filtered_settings = broadcast_settings;
1287   } else {
1288     for (auto& setting : broadcast_settings) {
1289       for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
1290         if (!capability.has_value()) continue;
1291         auto filtered_setting =
1292             getCapabilitiesMatchedBroadcastConfigurationSettings(
1293                 setting, capability.value());
1294         if (filtered_setting.has_value())
1295           filtered_settings.push_back(filtered_setting.value());
1296       }
1297     }
1298   }
1299 
1300   if (filtered_settings.empty()) {
1301     LOG(WARNING) << __func__ << ": Cannot match any remote capability";
1302     return ndk::ScopedAStatus::ok();
1303   }
1304 
1305   if (in_requirement.subgroupConfigurationRequirements.empty()) {
1306     LOG(INFO) << __func__ << ": Empty requirement";
1307     *_aidl_return = filtered_settings[0];
1308     return ndk::ScopedAStatus::ok();
1309   }
1310 
1311   // For each subgroup config requirement, find a suitable subgroup config.
1312   // Gather these suitable subgroup config in an array.
1313   // If the setting can satisfy all requirement, we can return the setting
1314   // with the filtered array.
1315 
1316   auto context_bitmask =
1317       in_requirement.subgroupConfigurationRequirements[0].audioContext.bitmask;
1318   auto quality = in_requirement.subgroupConfigurationRequirements[0].quality;
1319   LeAudioBroadcastConfigurationSetting return_setting =
1320       getDefaultBroadcastSetting(context_bitmask, quality);
1321   // Default setting
1322   return_setting.numBis = 0;
1323   return_setting.subgroupsConfigurations = {};
1324 
1325   LeAudioDataPathConfiguration path;
1326   path.isoDataPathConfiguration.isTransparent = true;
1327   path.dataPathId = kIsoDataPathPlatformDefault;
1328 
1329   // Each subreq, find a setting that match
1330   for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
1331     bool is_setting_matched = false;
1332     for (auto setting : filtered_settings) {
1333       bool is_matched = true;
1334       // Check if every sub BIS config satisfy
1335       for (auto& sub_group_config : setting.subgroupsConfigurations) {
1336         if (!isSubgroupConfigurationMatchedContext(
1337                 sub_req.audioContext, sub_req.quality, sub_group_config)) {
1338           is_matched = false;
1339           break;
1340         }
1341         path.isoDataPathConfiguration.codecId =
1342             sub_group_config.bisConfigurations[0].bisConfiguration.codecId;
1343         // Also modify the subgroup config to match the context
1344         modifySubgroupConfiguration(sub_group_config, context_bitmask);
1345       }
1346 
1347       if (is_matched) {
1348         is_setting_matched = true;
1349         for (auto& sub_group_config : setting.subgroupsConfigurations)
1350           return_setting.subgroupsConfigurations.push_back(sub_group_config);
1351         break;
1352       }
1353     }
1354 
1355     if (!is_setting_matched) {
1356       LOG(WARNING) << __func__
1357                    << ": Cannot find a setting that match requirement "
1358                    << sub_req.toString();
1359       return ndk::ScopedAStatus::ok();
1360     }
1361   }
1362 
1363   // Populate all numBis
1364   for (auto& sub_group_config : return_setting.subgroupsConfigurations) {
1365     for (auto& sub_bis_config : sub_group_config.bisConfigurations) {
1366       return_setting.numBis += sub_bis_config.numBis;
1367     }
1368   }
1369   return_setting.phy = std::vector<Phy>(return_setting.numBis, Phy::TWO_M);
1370   // Populate data path config
1371   return_setting.dataPathConfiguration = path;
1372   // TODO: Workaround for STEREO configs maxSduOctets being doubled
1373   if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME |
1374                          AudioContext::SOUND_EFFECTS |
1375                          AudioContext::UNSPECIFIED | AudioContext::MEDIA)) {
1376     return_setting.maxSduOctets /= 2;
1377   }
1378   LOG(INFO) << __func__
1379             << ": Combined setting that match: " << return_setting.toString();
1380   *_aidl_return = return_setting;
1381   return ndk::ScopedAStatus::ok();
1382 };
1383 
1384 }  // namespace audio
1385 }  // namespace bluetooth
1386 }  // namespace hardware
1387 }  // namespace android
1388 }  // namespace aidl
1389