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