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