blob: 1f54e6ce2f9cdf7c6c3bb068ef9fdea6a088aa65 [file] [log] [blame]
Josh Wu6ab53e72021-12-29 23:53:33 -08001/*
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
Josh Wu98d7e082022-01-21 03:04:21 -080017#define LOG_TAG "BTAudioProviderLeAudioHW"
Josh Wu6ab53e72021-12-29 23:53:33 -080018
19#include "LeAudioOffloadAudioProvider.h"
20
21#include <BluetoothAudioCodecs.h>
22#include <BluetoothAudioSessionReport.h>
23#include <android-base/logging.h>
24
25namespace aidl {
26namespace android {
27namespace hardware {
28namespace bluetooth {
29namespace audio {
30
Bao Do867af602023-11-15 05:41:12 +000031constexpr uint8_t kLeAudioDirectionSink = 0x01;
32constexpr uint8_t kLeAudioDirectionSource = 0x02;
33
34const std::map<CodecSpecificConfigurationLtv::SamplingFrequency, uint32_t>
35 freq_to_support_bitmask_map = {
36 {CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000,
37 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000},
38 {CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025,
39 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ11025},
40 {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
41 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000},
42 {CodecSpecificConfigurationLtv::SamplingFrequency::HZ22050,
43 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ22050},
44 {CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
45 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ24000},
46 {CodecSpecificConfigurationLtv::SamplingFrequency::HZ32000,
47 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ32000},
48 {CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000,
49 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ48000},
50 {CodecSpecificConfigurationLtv::SamplingFrequency::HZ88200,
51 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ88200},
52 {CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000,
53 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ96000},
54 {CodecSpecificConfigurationLtv::SamplingFrequency::HZ176400,
55 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ176400},
56 {CodecSpecificConfigurationLtv::SamplingFrequency::HZ192000,
57 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ192000},
58 {CodecSpecificConfigurationLtv::SamplingFrequency::HZ384000,
59 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ384000},
60};
61
62// Helper map from capability's tag to configuration's tag
63std::map<CodecSpecificCapabilitiesLtv::Tag, CodecSpecificConfigurationLtv::Tag>
64 cap_to_cfg_tag_map = {
65 {CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies,
66 CodecSpecificConfigurationLtv::Tag::samplingFrequency},
67 {CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU,
68 CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU},
69 {CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations,
70 CodecSpecificConfigurationLtv::Tag::frameDuration},
71 {CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts,
72 CodecSpecificConfigurationLtv::Tag::audioChannelAllocation},
73 {CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame,
74 CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame},
75};
76
77const std::map<CodecSpecificConfigurationLtv::FrameDuration, uint32_t>
78 fduration_to_support_fduration_map = {
79 {CodecSpecificConfigurationLtv::FrameDuration::US7500,
80 CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500},
81 {CodecSpecificConfigurationLtv::FrameDuration::US10000,
82 CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000},
83};
84
Bao Do5b2fdab2023-11-20 08:02:55 +000085std::map<int32_t, CodecSpecificConfigurationLtv::SamplingFrequency>
86 sampling_freq_map = {
87 {16000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000},
88 {48000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000},
89 {96000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000},
90};
91
92std::map<int32_t, CodecSpecificConfigurationLtv::FrameDuration>
93 frame_duration_map = {
94 {7500, CodecSpecificConfigurationLtv::FrameDuration::US7500},
95 {10000, CodecSpecificConfigurationLtv::FrameDuration::US10000},
96};
97
Josh Wu6ab53e72021-12-29 23:53:33 -080098LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
99 : LeAudioOffloadAudioProvider() {
100 session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
101}
102
103LeAudioOffloadInputAudioProvider::LeAudioOffloadInputAudioProvider()
104 : LeAudioOffloadAudioProvider() {
105 session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
106}
107
Alice Kuoe80a5762022-02-09 14:44:29 +0800108LeAudioOffloadBroadcastAudioProvider::LeAudioOffloadBroadcastAudioProvider()
109 : LeAudioOffloadAudioProvider() {
110 session_type_ =
111 SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
112}
113
Josh Wu6ab53e72021-12-29 23:53:33 -0800114LeAudioOffloadAudioProvider::LeAudioOffloadAudioProvider()
115 : BluetoothAudioProvider() {}
116
117bool LeAudioOffloadAudioProvider::isValid(const SessionType& sessionType) {
118 return (sessionType == session_type_);
119}
120
121ndk::ScopedAStatus LeAudioOffloadAudioProvider::startSession(
122 const std::shared_ptr<IBluetoothAudioPort>& host_if,
Chen Chenc92270e2022-02-14 18:29:52 -0800123 const AudioConfiguration& audio_config,
Cheney Ni6ecbc762022-03-03 00:12:48 +0800124 const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
Alice Kuoee398a92022-07-10 23:59:18 +0800125 if (session_type_ ==
126 SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
127 if (audio_config.getTag() != AudioConfiguration::leAudioBroadcastConfig) {
128 LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
129 << audio_config.toString();
130 *_aidl_return = DataMQDesc();
131 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
132 }
133 } else if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
Josh Wu6ab53e72021-12-29 23:53:33 -0800134 LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
135 << audio_config.toString();
136 *_aidl_return = DataMQDesc();
137 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
138 }
Josh Wu6ab53e72021-12-29 23:53:33 -0800139
Bao Do6112bda2023-11-15 03:57:59 +0000140 return BluetoothAudioProvider::startSession(host_if, audio_config,
141 latency_modes, _aidl_return);
Josh Wu6ab53e72021-12-29 23:53:33 -0800142}
143
144ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady(
145 DataMQDesc* _aidl_return) {
Cheney Ni6ecbc762022-03-03 00:12:48 +0800146 BluetoothAudioSessionReport::OnSessionStarted(
147 session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
Josh Wu6ab53e72021-12-29 23:53:33 -0800148 *_aidl_return = DataMQDesc();
149 return ndk::ScopedAStatus::ok();
150}
Bao Do6112bda2023-11-15 03:57:59 +0000151ndk::ScopedAStatus LeAudioOffloadAudioProvider::setCodecPriority(
152 const CodecId& in_codecId, int32_t in_priority) {
153 codec_priority_map_[in_codecId] = in_priority;
154 return ndk::ScopedAStatus::ok();
155};
156
Bao Do867af602023-11-15 05:41:12 +0000157bool LeAudioOffloadAudioProvider::isMatchedValidCodec(CodecId cfg_codec,
158 CodecId req_codec) {
159 auto priority = codec_priority_map_.find(cfg_codec);
Jakub Tyszkowski1d214222024-01-16 09:44:48 +0000160 if (priority != codec_priority_map_.end() &&
161 priority->second ==
162 LeAudioOffloadAudioProvider::CODEC_PRIORITY_DISABLED) {
Bao Do867af602023-11-15 05:41:12 +0000163 return false;
Jakub Tyszkowski1d214222024-01-16 09:44:48 +0000164 }
Bao Do867af602023-11-15 05:41:12 +0000165 return cfg_codec == req_codec;
166}
167
Bao Do91d7ca22024-05-09 14:21:01 +0800168bool LeAudioOffloadAudioProvider::filterCapabilitiesMatchedContext(
169 AudioContext& setting_context,
Bao Do867af602023-11-15 05:41:12 +0000170 const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
171 // If has no metadata, assume match
172 if (!capabilities.metadata.has_value()) return true;
173
174 for (auto metadata : capabilities.metadata.value()) {
175 if (!metadata.has_value()) continue;
176 if (metadata.value().getTag() == MetadataLtv::Tag::preferredAudioContexts) {
177 // Check all pref audio context to see if anything matched
Bao Do57861bd2024-05-23 17:02:54 +0800178 auto& prefer_context =
179 metadata.value()
180 .get<MetadataLtv::Tag::preferredAudioContexts>()
181 .values;
182 if (setting_context.bitmask & prefer_context.bitmask) {
Bao Do91d7ca22024-05-09 14:21:01 +0800183 // New mask with matched capability
Bao Do57861bd2024-05-23 17:02:54 +0800184 setting_context.bitmask &= prefer_context.bitmask;
Bao Do91d7ca22024-05-09 14:21:01 +0800185 return true;
186 }
Bao Do867af602023-11-15 05:41:12 +0000187 }
188 }
189
190 return false;
191}
192
193bool LeAudioOffloadAudioProvider::isMatchedSamplingFreq(
194 CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
195 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
196 capability_freq) {
Bao Do91d7ca22024-05-09 14:21:01 +0800197 auto p = freq_to_support_bitmask_map.find(cfg_freq);
198 if (p != freq_to_support_bitmask_map.end()) {
199 if (capability_freq.bitmask & p->second) {
200 return true;
201 }
202 }
Bao Do867af602023-11-15 05:41:12 +0000203 return false;
204}
205
206bool LeAudioOffloadAudioProvider::isMatchedFrameDuration(
207 CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
208 CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
209 capability_fduration) {
Bao Do91d7ca22024-05-09 14:21:01 +0800210 auto p = fduration_to_support_fduration_map.find(cfg_fduration);
211 if (p != fduration_to_support_fduration_map.end())
212 if (capability_fduration.bitmask & p->second) {
213 return true;
214 }
Bao Do867af602023-11-15 05:41:12 +0000215 return false;
216}
217
218bool LeAudioOffloadAudioProvider::isMatchedAudioChannel(
219 CodecSpecificConfigurationLtv::AudioChannelAllocation&
220 /*cfg_channel*/,
221 CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
222 /*capability_channel*/) {
Bao Do57861bd2024-05-23 17:02:54 +0800223 // Simply ignore.
224 // Later can use additional capabilities to match requirement.
Bao Do867af602023-11-15 05:41:12 +0000225 bool isMatched = true;
Bao Do867af602023-11-15 05:41:12 +0000226 return isMatched;
227}
228
229bool LeAudioOffloadAudioProvider::isMatchedCodecFramesPerSDU(
230 CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU& cfg_frame_sdu,
231 CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU&
232 capability_frame_sdu) {
233 return cfg_frame_sdu.value <= capability_frame_sdu.value;
234}
235
236bool LeAudioOffloadAudioProvider::isMatchedOctetsPerCodecFrame(
237 CodecSpecificConfigurationLtv::OctetsPerCodecFrame& cfg_octets,
238 CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame&
239 capability_octets) {
Jakub Tyszkowski1d214222024-01-16 09:44:48 +0000240 return cfg_octets.value >= capability_octets.min &&
241 cfg_octets.value <= capability_octets.max;
Bao Do867af602023-11-15 05:41:12 +0000242}
243
244bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedCodecConfiguration(
245 std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
246 std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities) {
247 // Convert all codec_cfg into a map of tags -> correct data
248 std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
249 cfg_tag_map;
250 for (auto codec_cfg_data : codec_cfg)
251 cfg_tag_map[codec_cfg_data.getTag()] = codec_cfg_data;
252
253 for (auto& codec_capability : codec_capabilities) {
254 auto cfg = cfg_tag_map.find(cap_to_cfg_tag_map[codec_capability.getTag()]);
Bao Do91d7ca22024-05-09 14:21:01 +0800255 // If capability has this tag, but our configuration doesn't
256 // Then we will assume it is matched
257 if (cfg == cfg_tag_map.end()) {
258 continue;
259 }
Bao Do867af602023-11-15 05:41:12 +0000260
Bao Do91d7ca22024-05-09 14:21:01 +0800261 switch (codec_capability.getTag()) {
262 case CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies: {
263 if (!isMatchedSamplingFreq(
264 cfg->second.get<
265 CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
266 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
267 supportedSamplingFrequencies>())) {
268 return false;
269 }
270 break;
271 }
272
273 case CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations: {
274 if (!isMatchedFrameDuration(
275 cfg->second
276 .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
277 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
278 supportedFrameDurations>())) {
279 return false;
280 }
281 break;
282 }
283
284 case CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts: {
285 if (!isMatchedAudioChannel(
286 cfg->second.get<CodecSpecificConfigurationLtv::Tag::
287 audioChannelAllocation>(),
288 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
289 supportedAudioChannelCounts>())) {
290 return false;
291 }
292 break;
293 }
294
295 case CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU: {
296 if (!isMatchedCodecFramesPerSDU(
297 cfg->second.get<CodecSpecificConfigurationLtv::Tag::
298 codecFrameBlocksPerSDU>(),
299 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
300 supportedMaxCodecFramesPerSDU>())) {
301 return false;
302 }
303 break;
304 }
305
306 case CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame: {
307 if (!isMatchedOctetsPerCodecFrame(
308 cfg->second.get<
309 CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
310 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
311 supportedOctetsPerCodecFrame>())) {
312 return false;
313 }
314 break;
315 }
Bao Do867af602023-11-15 05:41:12 +0000316 }
317 }
318
319 return true;
320}
321
Bao Do57861bd2024-05-23 17:02:54 +0800322bool isMonoConfig(
323 CodecSpecificConfigurationLtv::AudioChannelAllocation allocation) {
324 auto channel_count = std::bitset<32>(allocation.bitmask);
325 return (channel_count.count() <= 1);
326}
327
328bool LeAudioOffloadAudioProvider::filterMatchedAseConfiguration(
329 LeAudioAseConfiguration& setting_cfg,
330 const LeAudioAseConfiguration& requirement_cfg) {
Bao Do867af602023-11-15 05:41:12 +0000331 // Check matching for codec configuration <=> requirement ASE codec
332 // Also match if no CodecId requirement
333 if (requirement_cfg.codecId.has_value()) {
334 if (!setting_cfg.codecId.has_value()) return false;
335 if (!isMatchedValidCodec(setting_cfg.codecId.value(),
Bao Do91d7ca22024-05-09 14:21:01 +0800336 requirement_cfg.codecId.value())) {
Bao Do57861bd2024-05-23 17:02:54 +0800337 LOG(WARNING) << __func__ << ": Doesn't match valid codec, cfg = "
338 << setting_cfg.codecId.value().toString()
339 << ", req = " << requirement_cfg.codecId.value().toString();
Bao Do867af602023-11-15 05:41:12 +0000340 return false;
Bao Do91d7ca22024-05-09 14:21:01 +0800341 }
Bao Do867af602023-11-15 05:41:12 +0000342 }
343
Bao Do57861bd2024-05-23 17:02:54 +0800344 if (requirement_cfg.targetLatency !=
345 LeAudioAseConfiguration::TargetLatency::UNDEFINED &&
Bao Do91d7ca22024-05-09 14:21:01 +0800346 setting_cfg.targetLatency != requirement_cfg.targetLatency) {
Bao Do57861bd2024-05-23 17:02:54 +0800347 LOG(WARNING) << __func__ << ": Doesn't match target latency, cfg = "
348 << int(setting_cfg.targetLatency)
349 << ", req = " << int(requirement_cfg.targetLatency);
Bao Do91d7ca22024-05-09 14:21:01 +0800350 return false;
351 }
Bao Do867af602023-11-15 05:41:12 +0000352 // Ignore PHY requirement
353
354 // Check all codec configuration
355 std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
356 cfg_tag_map;
357 for (auto cfg : setting_cfg.codecConfiguration)
358 cfg_tag_map[cfg.getTag()] = cfg;
359
360 for (auto requirement_cfg : requirement_cfg.codecConfiguration) {
361 // Directly compare CodecSpecificConfigurationLtv
362 auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
Bao Do57861bd2024-05-23 17:02:54 +0800363 // Config not found for this requirement, cannot match
Bao Do91d7ca22024-05-09 14:21:01 +0800364 if (cfg == cfg_tag_map.end()) {
Bao Do57861bd2024-05-23 17:02:54 +0800365 LOG(WARNING) << __func__ << ": Config not found for the requirement "
366 << requirement_cfg.toString();
Bao Do91d7ca22024-05-09 14:21:01 +0800367 return false;
368 }
Bao Do867af602023-11-15 05:41:12 +0000369
Bao Do57861bd2024-05-23 17:02:54 +0800370 // 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
Bao Do91d7ca22024-05-09 14:21:01 +0800376 if (cfg->second != requirement_cfg) {
Bao Do57861bd2024-05-23 17:02:54 +0800377 LOG(WARNING) << __func__
378 << ": Config doesn't match the requirement, cfg = "
379 << cfg->second.toString()
380 << ", req = " << requirement_cfg.toString();
Bao Do91d7ca22024-05-09 14:21:01 +0800381 return false;
382 }
Bao Do867af602023-11-15 05:41:12 +0000383 }
384 // Ignore vendor configuration and metadata requirement
385
386 return true;
387}
388
Bao Do5b2fdab2023-11-20 08:02:55 +0000389bool LeAudioOffloadAudioProvider::isMatchedBISConfiguration(
390 LeAudioBisConfiguration bis_cfg,
391 const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
Bao Do91d7ca22024-05-09 14:21:01 +0800392 if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) {
Bao Do5b2fdab2023-11-20 08:02:55 +0000393 return false;
Bao Do91d7ca22024-05-09 14:21:01 +0800394 }
395 if (!isCapabilitiesMatchedCodecConfiguration(
396 bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities)) {
397 return false;
398 }
Bao Do5b2fdab2023-11-20 08:02:55 +0000399 return true;
400}
401
Bao Do867af602023-11-15 05:41:12 +0000402void LeAudioOffloadAudioProvider::filterCapabilitiesAseDirectionConfiguration(
403 std::vector<std::optional<AseDirectionConfiguration>>&
404 direction_configurations,
405 const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
406 std::vector<std::optional<AseDirectionConfiguration>>&
407 valid_direction_configurations) {
408 for (auto direction_configuration : direction_configurations) {
409 if (!direction_configuration.has_value()) continue;
410 if (!direction_configuration.value().aseConfiguration.codecId.has_value())
411 continue;
412 if (!isMatchedValidCodec(
413 direction_configuration.value().aseConfiguration.codecId.value(),
414 capabilities.codecId))
415 continue;
416 // Check matching for codec configuration <=> codec capabilities
417 if (!isCapabilitiesMatchedCodecConfiguration(
418 direction_configuration.value().aseConfiguration.codecConfiguration,
419 capabilities.codecSpecificCapabilities))
420 continue;
421 valid_direction_configurations.push_back(direction_configuration);
422 }
423}
424
Bao Do57861bd2024-05-23 17:02:54 +0800425int getLeAudioAseConfigurationAllocationBitmask(LeAudioAseConfiguration cfg) {
426 for (auto cfg_ltv : cfg.codecConfiguration) {
427 if (cfg_ltv.getTag() ==
428 CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
429 return cfg_ltv
430 .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
431 .bitmask;
432 }
433 }
434 return 0;
435}
436
437int getCountFromBitmask(int bitmask) {
438 return std::bitset<32>(bitmask).count();
439}
440
441std::optional<AseDirectionConfiguration> findValidMonoConfig(
442 std::vector<AseDirectionConfiguration>& valid_direction_configurations,
443 int bitmask) {
444 for (auto& cfg : valid_direction_configurations) {
445 int cfg_bitmask =
446 getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
447 if (getCountFromBitmask(cfg_bitmask) <= 1) {
448 LOG(INFO) << __func__ << ": Found a mono config for the mono requirement";
449 // Modify the bitmask to be the same as the requirement
450 for (auto& codec_cfg : cfg.aseConfiguration.codecConfiguration) {
451 if (codec_cfg.getTag() ==
452 CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
453 codec_cfg
454 .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
455 .bitmask = bitmask;
456 return cfg;
457 }
458 }
459 }
460 }
461 return std::nullopt;
462}
463
464std::vector<AseDirectionConfiguration> getValidConfigurationsFromAllocation(
465 int req_allocation_bitmask,
466 std::vector<AseDirectionConfiguration>& valid_direction_configurations) {
467 // Prefer the same allocation_bitmask
468 int channel_count = getCountFromBitmask(req_allocation_bitmask);
469 for (auto& cfg : valid_direction_configurations) {
470 int cfg_bitmask =
471 getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
472 if (cfg_bitmask == req_allocation_bitmask) {
473 LOG(INFO) << __func__
474 << ": Found an exact match for the requirement allocation of "
475 << cfg_bitmask;
476 return {cfg};
477 }
478 }
479 // No exact match found
480 if (channel_count <= 1) {
481 // Mono requirement matched if cfg is a mono config
482 auto cfg = findValidMonoConfig(valid_direction_configurations,
483 req_allocation_bitmask);
484 if (cfg.has_value()) return {cfg.value()};
485 } else {
486 // Stereo requirement returns 2 mono configs
487 // that has a combined bitmask equal to the stereo config
488 std::vector<AseDirectionConfiguration> temp;
489 for (int bit = 0; bit < 32; ++bit)
490 if (req_allocation_bitmask & (1 << bit)) {
491 auto cfg =
492 findValidMonoConfig(valid_direction_configurations, (1 << bit));
493 if (cfg.has_value()) temp.push_back(cfg.value());
494 }
495 if (temp.size() == channel_count) return temp;
496 }
497 return {};
498}
499
Bao Do867af602023-11-15 05:41:12 +0000500void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
Bao Do91d7ca22024-05-09 14:21:01 +0800501 std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
Bao Do867af602023-11-15 05:41:12 +0000502 direction_configurations,
Bao Do91d7ca22024-05-09 14:21:01 +0800503 const std::vector<std::optional<AseDirectionRequirement>>& requirements,
504 std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
Bao Do867af602023-11-15 05:41:12 +0000505 valid_direction_configurations) {
Bao Do57861bd2024-05-23 17:02:54 +0800506 // For every requirement, find the matched ase configuration
507 if (!direction_configurations.has_value()) return;
508
Bao Do91d7ca22024-05-09 14:21:01 +0800509 if (!valid_direction_configurations.has_value()) {
510 valid_direction_configurations =
511 std::vector<std::optional<AseDirectionConfiguration>>();
512 }
Bao Do57861bd2024-05-23 17:02:54 +0800513
Bao Do91d7ca22024-05-09 14:21:01 +0800514 for (auto& requirement : requirements) {
515 if (!requirement.has_value()) continue;
Bao Do57861bd2024-05-23 17:02:54 +0800516 LOG(INFO) << __func__ << ": Testing for requirement = "
517 << requirement.value().toString();
518 auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
519 requirement.value().aseConfiguration);
520 auto req_channel_count = getCountFromBitmask(req_allocation_bitmask);
521
522 auto temp = std::vector<AseDirectionConfiguration>();
523
Bao Do91d7ca22024-05-09 14:21:01 +0800524 for (auto direction_configuration : direction_configurations.value()) {
525 if (!direction_configuration.has_value()) continue;
Bao Do57861bd2024-05-23 17:02:54 +0800526 if (!filterMatchedAseConfiguration(
Bao Do867af602023-11-15 05:41:12 +0000527 direction_configuration.value().aseConfiguration,
528 requirement.value().aseConfiguration))
529 continue;
530 // Valid if match any requirement.
Bao Do57861bd2024-05-23 17:02:54 +0800531 temp.push_back(direction_configuration.value());
Bao Do867af602023-11-15 05:41:12 +0000532 }
Bao Do57861bd2024-05-23 17:02:54 +0800533
534 // Get the best matching config based on channel allocation
535 auto total_cfg_channel_count = 0;
536 auto req_valid_configs =
537 getValidConfigurationsFromAllocation(req_allocation_bitmask, temp);
538 // Count and check required channel counts
539 for (auto& cfg : req_valid_configs) {
540 total_cfg_channel_count += getCountFromBitmask(
541 getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration));
542 valid_direction_configurations.value().push_back(cfg);
543 }
544 if (total_cfg_channel_count != req_channel_count) {
545 LOG(WARNING) << __func__
546 << ": Wrong channel count, req = " << req_channel_count
547 << ", total = " << total_cfg_channel_count;
548 valid_direction_configurations = std::nullopt;
549 return;
550 }
Bao Do91d7ca22024-05-09 14:21:01 +0800551 }
Bao Do867af602023-11-15 05:41:12 +0000552}
553
554/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
555 * capabilities. The new setting will have a filtered list of
556 * AseDirectionConfiguration that matched the capabilities */
557std::optional<LeAudioAseConfigurationSetting>
558LeAudioOffloadAudioProvider::getCapabilitiesMatchedAseConfigurationSettings(
559 IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
560 const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
561 uint8_t direction) {
Bao Do91d7ca22024-05-09 14:21:01 +0800562 // Create a new LeAudioAseConfigurationSetting and return
563 // For other direction will contain all settings
564 LeAudioAseConfigurationSetting filtered_setting{
565 .audioContext = setting.audioContext,
566 .sinkAseConfiguration = setting.sinkAseConfiguration,
567 .sourceAseConfiguration = setting.sourceAseConfiguration,
568 .flags = setting.flags,
569 .packing = setting.packing,
570 };
Bao Do867af602023-11-15 05:41:12 +0000571
572 // Get a list of all matched AseDirectionConfiguration
573 // for the input direction
574 std::vector<std::optional<AseDirectionConfiguration>>*
575 direction_configuration = nullptr;
576 if (direction == kLeAudioDirectionSink) {
Bao Do91d7ca22024-05-09 14:21:01 +0800577 if (!filtered_setting.sinkAseConfiguration.has_value()) return std::nullopt;
578 direction_configuration = &filtered_setting.sinkAseConfiguration.value();
Bao Do867af602023-11-15 05:41:12 +0000579 } else {
Bao Do91d7ca22024-05-09 14:21:01 +0800580 if (!filtered_setting.sourceAseConfiguration.has_value())
581 return std::nullopt;
582 direction_configuration = &filtered_setting.sourceAseConfiguration.value();
Bao Do867af602023-11-15 05:41:12 +0000583 }
584 std::vector<std::optional<AseDirectionConfiguration>>
585 valid_direction_configuration;
586 filterCapabilitiesAseDirectionConfiguration(
587 *direction_configuration, capabilities, valid_direction_configuration);
Bao Do91d7ca22024-05-09 14:21:01 +0800588
589 // No valid configuration for this direction
590 if (valid_direction_configuration.empty()) {
591 return std::nullopt;
592 }
Bao Do867af602023-11-15 05:41:12 +0000593
594 // Create a new LeAudioAseConfigurationSetting and return
Bao Do91d7ca22024-05-09 14:21:01 +0800595 // For other direction will contain all settings
Bao Do867af602023-11-15 05:41:12 +0000596 if (direction == kLeAudioDirectionSink) {
597 filtered_setting.sinkAseConfiguration = valid_direction_configuration;
598 } else {
599 filtered_setting.sourceAseConfiguration = valid_direction_configuration;
600 }
Bao Do867af602023-11-15 05:41:12 +0000601
602 return filtered_setting;
603}
604
605/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
606 * requirement. The new setting will have a filtered list of
607 * AseDirectionConfiguration that matched the requirement */
608std::optional<LeAudioAseConfigurationSetting>
609LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
610 IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
611 const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
612 requirement) {
613 // Try to match context in metadata.
Bao Do91d7ca22024-05-09 14:21:01 +0800614 if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
615 requirement.audioContext.bitmask)
616 return std::nullopt;
617
Bao Do57861bd2024-05-23 17:02:54 +0800618 LOG(INFO) << __func__
619 << ": Checking if the setting match: " << setting.toString();
Bao Do91d7ca22024-05-09 14:21:01 +0800620 // Further filter setting's context
621 setting.audioContext.bitmask &= requirement.audioContext.bitmask;
Bao Do867af602023-11-15 05:41:12 +0000622
Bao Do91d7ca22024-05-09 14:21:01 +0800623 // Create a new LeAudioAseConfigurationSetting to return
624 LeAudioAseConfigurationSetting filtered_setting{
625 .audioContext = setting.audioContext,
626 .packing = setting.packing,
627 .flags = setting.flags,
628 };
629
630 if (requirement.sinkAseRequirement.has_value()) {
631 filterRequirementAseDirectionConfiguration(
632 setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
633 filtered_setting.sinkAseConfiguration);
Bao Do57861bd2024-05-23 17:02:54 +0800634 if (!filtered_setting.sinkAseConfiguration.has_value()) {
635 LOG(WARNING) << __func__ << "Setting's sink doesn't match!";
636 return std::nullopt;
637 }
Bao Do867af602023-11-15 05:41:12 +0000638 }
639
Bao Do91d7ca22024-05-09 14:21:01 +0800640 if (requirement.sourceAseRequirement.has_value()) {
641 filterRequirementAseDirectionConfiguration(
642 setting.sourceAseConfiguration,
643 requirement.sourceAseRequirement.value(),
644 filtered_setting.sourceAseConfiguration);
Bao Do57861bd2024-05-23 17:02:54 +0800645 if (!filtered_setting.sourceAseConfiguration.has_value()) {
646 LOG(WARNING) << __func__ << "Setting's source doesn't match!";
Bao Do91d7ca22024-05-09 14:21:01 +0800647 return std::nullopt;
Bao Do57861bd2024-05-23 17:02:54 +0800648 }
Bao Do91d7ca22024-05-09 14:21:01 +0800649 }
Bao Do867af602023-11-15 05:41:12 +0000650
651 return filtered_setting;
652}
653
Bao Do57861bd2024-05-23 17:02:54 +0800654std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
655LeAudioOffloadAudioProvider::matchWithRequirement(
656 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
657 matched_ase_configuration_settings,
Bao Do6112bda2023-11-15 03:57:59 +0000658 const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
Bao Do57861bd2024-05-23 17:02:54 +0800659 in_requirements) {
Bao Do91d7ca22024-05-09 14:21:01 +0800660 // Each requirement will match with a valid setting
Bao Do867af602023-11-15 05:41:12 +0000661 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
Bao Do91d7ca22024-05-09 14:21:01 +0800662 for (auto& requirement : in_requirements) {
663 LOG(INFO) << __func__ << ": Trying to match for the requirement "
664 << requirement.toString();
665 bool is_matched = false;
666
667 for (auto& setting : matched_ase_configuration_settings) {
Bao Do867af602023-11-15 05:41:12 +0000668 auto filtered_ase_configuration_setting =
669 getRequirementMatchedAseConfigurationSettings(setting, requirement);
670 if (filtered_ase_configuration_setting.has_value()) {
671 result.push_back(filtered_ase_configuration_setting.value());
Bao Do91d7ca22024-05-09 14:21:01 +0800672 LOG(INFO) << __func__ << ": Result = "
673 << filtered_ase_configuration_setting.value().toString();
674 // Found a matched setting, ignore other settings
675 is_matched = true;
676 break;
Bao Do867af602023-11-15 05:41:12 +0000677 }
678 }
Bao Do91d7ca22024-05-09 14:21:01 +0800679 if (!is_matched) {
680 // If cannot satisfy this requirement, return an empty result
681 LOG(WARNING) << __func__ << ": Cannot match the requirement "
682 << requirement.toString();
683 result.clear();
684 break;
685 }
Bao Do867af602023-11-15 05:41:12 +0000686 }
Bao Do57861bd2024-05-23 17:02:54 +0800687 return result;
688}
Bao Do867af602023-11-15 05:41:12 +0000689
Bao Do57861bd2024-05-23 17:02:54 +0800690// For each requirement, a valid ASE configuration will satify:
691// - matched with any sink capability (if presented)
692// - OR matched with any source capability (if presented)
693// - and the setting need to pass the requirement
694ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
695 const std::optional<std::vector<
696 std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
697 in_remoteSinkAudioCapabilities,
698 const std::optional<std::vector<
699 std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
700 in_remoteSourceAudioCapabilities,
701 const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
702 in_requirements,
703 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
704 _aidl_return) {
705 // Get all configuration settings
706 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
707 ase_configuration_settings =
708 BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
709
710 if (!in_remoteSinkAudioCapabilities.has_value() &&
711 !in_remoteSourceAudioCapabilities.has_value()) {
712 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
713 }
714
715 // Split out preferred and non-preferred settings based on context
716 // An example: preferred = MEDIA, available: MEDIA | CONVERSATION
717 // -> preferred list will have settings with MEDIA context
718 // -> non-preferred list will have settings with any context
719 // We want to match requirement with preferred context settings first
720 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
721 matched_ase_configuration_settings;
722 // Matched ASE configuration with non-preferred audio context
723 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
724 non_prefer_matched_ase_configuration_settings;
725
726 if (in_remoteSinkAudioCapabilities.has_value())
727 // Matching each setting with any remote capabilities
728 for (auto& setting : ase_configuration_settings)
729 for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
730 if (!capability.has_value()) continue;
731 auto filtered_ase_configuration_setting =
732 getCapabilitiesMatchedAseConfigurationSettings(
733 setting, capability.value(), kLeAudioDirectionSink);
734 if (filtered_ase_configuration_setting.has_value()) {
735 // Push to non-prefer first for the broadest matching possible
736 non_prefer_matched_ase_configuration_settings.push_back(
737 filtered_ase_configuration_setting.value());
738 // Try to filter out prefer context to another vector.
739 if (filterCapabilitiesMatchedContext(
740 filtered_ase_configuration_setting.value().audioContext,
741 capability.value())) {
742 matched_ase_configuration_settings.push_back(
743 filtered_ase_configuration_setting.value());
744 }
745 }
746 }
747
748 // Combine filter every source capability
749 if (in_remoteSourceAudioCapabilities.has_value())
750 // Matching each setting with any remote capabilities
751 for (auto& setting : ase_configuration_settings)
752 for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
753 if (!capability.has_value()) continue;
754 auto filtered_ase_configuration_setting =
755 getCapabilitiesMatchedAseConfigurationSettings(
756 setting, capability.value(), kLeAudioDirectionSource);
757 if (filtered_ase_configuration_setting.has_value()) {
758 // Put into the same list
759 // possibly duplicated, filtered by requirement later
760 // Push to non-prefer first for the broadest matching possible
761 non_prefer_matched_ase_configuration_settings.push_back(
762 filtered_ase_configuration_setting.value());
763 // Try to filter out prefer context to another vector.
764 if (filterCapabilitiesMatchedContext(
765 filtered_ase_configuration_setting.value().audioContext,
766 capability.value())) {
767 matched_ase_configuration_settings.push_back(
768 filtered_ase_configuration_setting.value());
769 }
770 }
771 }
772
773 auto result =
774 matchWithRequirement(matched_ase_configuration_settings, in_requirements);
775 if (result.empty()) {
776 LOG(WARNING) << __func__
777 << ": Cannot match with preferred context settings";
778 result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
779 in_requirements);
780 if (result.empty())
781 LOG(WARNING) << __func__
782 << ": Cannot match with non preferred context settings";
783 }
Bao Do867af602023-11-15 05:41:12 +0000784 *_aidl_return = result;
785 return ndk::ScopedAStatus::ok();
Bao Do6112bda2023-11-15 03:57:59 +0000786};
787
Bao Doc4adf242023-11-15 08:03:20 +0000788bool LeAudioOffloadAudioProvider::isMatchedQosRequirement(
789 LeAudioAseQosConfiguration setting_qos,
790 AseQosDirectionRequirement requirement_qos) {
791 if (setting_qos.retransmissionNum !=
Bao Do91d7ca22024-05-09 14:21:01 +0800792 requirement_qos.preferredRetransmissionNum) {
Bao Doc4adf242023-11-15 08:03:20 +0000793 return false;
Bao Do91d7ca22024-05-09 14:21:01 +0800794 }
795 if (setting_qos.maxTransportLatencyMs >
796 requirement_qos.maxTransportLatencyMs) {
Bao Doc4adf242023-11-15 08:03:20 +0000797 return false;
Bao Do91d7ca22024-05-09 14:21:01 +0800798 }
Bao Doc4adf242023-11-15 08:03:20 +0000799 return true;
800}
801
Bao Do91d7ca22024-05-09 14:21:01 +0800802bool isValidQosRequirement(AseQosDirectionRequirement qosRequirement) {
803 return ((qosRequirement.maxTransportLatencyMs > 0) &&
804 (qosRequirement.presentationDelayMaxUs > 0) &&
805 (qosRequirement.presentationDelayMaxUs >=
806 qosRequirement.presentationDelayMinUs));
807}
Bao Doc4adf242023-11-15 08:03:20 +0000808
Bao Do91d7ca22024-05-09 14:21:01 +0800809std::optional<LeAudioAseQosConfiguration>
810LeAudioOffloadAudioProvider::getDirectionQosConfiguration(
811 uint8_t direction,
812 const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
813 qosRequirement,
814 std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings) {
Bao Doc4adf242023-11-15 08:03:20 +0000815 std::optional<AseQosDirectionRequirement> direction_qos_requirement =
816 std::nullopt;
Bao Do91d7ca22024-05-09 14:21:01 +0800817
818 // Get the correct direction
819 if (direction == kLeAudioDirectionSink) {
820 direction_qos_requirement = qosRequirement.sinkAseQosRequirement.value();
821 } else {
822 direction_qos_requirement = qosRequirement.sourceAseQosRequirement.value();
Bao Doc4adf242023-11-15 08:03:20 +0000823 }
824
825 for (auto& setting : ase_configuration_settings) {
826 // Context matching
Bao Do91d7ca22024-05-09 14:21:01 +0800827 if ((setting.audioContext.bitmask & qosRequirement.audioContext.bitmask) !=
828 qosRequirement.audioContext.bitmask)
829 continue;
Bao Doc4adf242023-11-15 08:03:20 +0000830
831 // Match configuration flags
832 // Currently configuration flags are not populated, ignore.
833
834 // Get a list of all matched AseDirectionConfiguration
835 // for the input direction
Bao Do57861bd2024-05-23 17:02:54 +0800836 std::optional<std::vector<std::optional<AseDirectionConfiguration>>>
837 direction_configuration = std::nullopt;
Bao Doc4adf242023-11-15 08:03:20 +0000838 if (direction == kLeAudioDirectionSink) {
839 if (!setting.sinkAseConfiguration.has_value()) continue;
Bao Do57861bd2024-05-23 17:02:54 +0800840 direction_configuration.emplace(setting.sinkAseConfiguration.value());
Bao Doc4adf242023-11-15 08:03:20 +0000841 } else {
842 if (!setting.sourceAseConfiguration.has_value()) continue;
Bao Do57861bd2024-05-23 17:02:54 +0800843 direction_configuration.emplace(setting.sourceAseConfiguration.value());
Bao Doc4adf242023-11-15 08:03:20 +0000844 }
845
Bao Do57861bd2024-05-23 17:02:54 +0800846 if (!direction_configuration.has_value()) {
847 return std::nullopt;
848 }
849
850 // Collect all valid cfg into a vector
851 // Then try to get the best match for audio allocation
852
853 auto temp = std::vector<AseDirectionConfiguration>();
854
855 for (auto& cfg : direction_configuration.value()) {
Bao Doc4adf242023-11-15 08:03:20 +0000856 if (!cfg.has_value()) continue;
857 // If no requirement, return the first QoS
858 if (!direction_qos_requirement.has_value()) {
Bao Do91d7ca22024-05-09 14:21:01 +0800859 return cfg.value().qosConfiguration;
Bao Doc4adf242023-11-15 08:03:20 +0000860 }
861
862 // If has requirement, return the first matched QoS
863 // Try to match the ASE configuration
864 // and QoS with requirement
865 if (!cfg.value().qosConfiguration.has_value()) continue;
Bao Do57861bd2024-05-23 17:02:54 +0800866 if (filterMatchedAseConfiguration(
Bao Doc4adf242023-11-15 08:03:20 +0000867 cfg.value().aseConfiguration,
868 direction_qos_requirement.value().aseConfiguration) &&
869 isMatchedQosRequirement(cfg.value().qosConfiguration.value(),
870 direction_qos_requirement.value())) {
Bao Do57861bd2024-05-23 17:02:54 +0800871 temp.push_back(cfg.value());
Bao Doc4adf242023-11-15 08:03:20 +0000872 }
873 }
Bao Do57861bd2024-05-23 17:02:54 +0800874 LOG(WARNING) << __func__ << ": Got " << temp.size()
875 << " configs, start matching allocation";
876
877 int qos_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
878 direction_qos_requirement.value().aseConfiguration);
879 // Get the best matching config based on channel allocation
880 auto req_valid_configs =
881 getValidConfigurationsFromAllocation(qos_allocation_bitmask, temp);
882 if (req_valid_configs.empty()) {
883 LOG(WARNING) << __func__
884 << ": Cannot find matching allocation for bitmask "
885 << qos_allocation_bitmask;
886
887 } else {
888 return req_valid_configs[0].qosConfiguration;
889 }
Bao Doc4adf242023-11-15 08:03:20 +0000890 }
891
Bao Do91d7ca22024-05-09 14:21:01 +0800892 return std::nullopt;
893}
894
895ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
896 const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
897 in_qosRequirement,
898 IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) {
899 IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
900
901 // Get all configuration settings
902 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
903 ase_configuration_settings =
904 BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
905
906 // Direction QoS matching
907 // Only handle one direction input case
908 if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
909 if (!isValidQosRequirement(in_qosRequirement.sinkAseQosRequirement.value()))
910 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
911 result.sinkQosConfiguration = getDirectionQosConfiguration(
912 kLeAudioDirectionSink, in_qosRequirement, ase_configuration_settings);
913 }
914 if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
915 if (!isValidQosRequirement(
916 in_qosRequirement.sourceAseQosRequirement.value()))
917 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
918 result.sourceQosConfiguration = getDirectionQosConfiguration(
919 kLeAudioDirectionSource, in_qosRequirement, ase_configuration_settings);
920 }
921
Bao Doc4adf242023-11-15 08:03:20 +0000922 *_aidl_return = result;
923 return ndk::ScopedAStatus::ok();
Bao Do6112bda2023-11-15 03:57:59 +0000924};
925
926ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSinkAseMetadataChanged(
Bao Do5b2fdab2023-11-20 08:02:55 +0000927 IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
928 int32_t /*in_cisId*/,
Bao Do6112bda2023-11-15 03:57:59 +0000929 const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
930 (void)in_state;
931 (void)in_metadata;
932 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
933};
934
935ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSourceAseMetadataChanged(
Bao Do5b2fdab2023-11-20 08:02:55 +0000936 IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
937 int32_t /*in_cisId*/,
Bao Do6112bda2023-11-15 03:57:59 +0000938 const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
939 (void)in_state;
940 (void)in_metadata;
941 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
942};
943
Bao Do5b2fdab2023-11-20 08:02:55 +0000944void LeAudioOffloadAudioProvider::getBroadcastSettings() {
945 if (!broadcast_settings.empty()) return;
946
947 LOG(INFO) << __func__ << ": Loading broadcast settings from provider info";
948
949 std::vector<CodecInfo> db_codec_info =
950 BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
951 SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
952 broadcast_settings.clear();
Bao Do91d7ca22024-05-09 14:21:01 +0800953
954 // Default value for unmapped fields
Bao Do5b2fdab2023-11-20 08:02:55 +0000955 CodecSpecificConfigurationLtv::AudioChannelAllocation default_allocation;
956 default_allocation.bitmask =
957 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
Bao Do91d7ca22024-05-09 14:21:01 +0800958 CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU default_frame;
959 default_frame.value = 2;
Bao Do5b2fdab2023-11-20 08:02:55 +0000960
961 for (auto& codec_info : db_codec_info) {
962 if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
963 continue;
964 auto& transport = codec_info.transport.get<CodecInfo::Transport::leAudio>();
965 LeAudioBroadcastConfigurationSetting setting;
966 // Default setting
967 setting.numBis = 1;
968 setting.phy = {Phy::TWO_M};
969 // Populate BIS configuration info using codec_info
970 LeAudioBisConfiguration bis_cfg;
971 bis_cfg.codecId = codec_info.id;
972
973 CodecSpecificConfigurationLtv::OctetsPerCodecFrame octets;
974 octets.value = transport.bitdepth[0];
975
976 bis_cfg.codecConfiguration = {
Bao Do91d7ca22024-05-09 14:21:01 +0800977 sampling_freq_map[transport.samplingFrequencyHz[0]],
978 octets,
979 frame_duration_map[transport.frameDurationUs[0]],
980 default_allocation,
981 default_frame,
982 };
Bao Do5b2fdab2023-11-20 08:02:55 +0000983
984 // Add information to structure
985 IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration sub_bis_cfg;
Bao Do91d7ca22024-05-09 14:21:01 +0800986 sub_bis_cfg.numBis = 2;
Bao Do5b2fdab2023-11-20 08:02:55 +0000987 sub_bis_cfg.bisConfiguration = bis_cfg;
988 IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration sub_cfg;
Bao Do91d7ca22024-05-09 14:21:01 +0800989 // Populate the same sub config
990 sub_cfg.bisConfigurations = {sub_bis_cfg, sub_bis_cfg};
Bao Do5b2fdab2023-11-20 08:02:55 +0000991 setting.subgroupsConfigurations = {sub_cfg};
992
993 broadcast_settings.push_back(setting);
994 }
995
996 LOG(INFO) << __func__
997 << ": Done loading broadcast settings from provider info";
998}
999
1000/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
1001 * capabilities. The new setting will have a filtered list of
1002 * AseDirectionConfiguration that matched the capabilities */
1003std::optional<LeAudioBroadcastConfigurationSetting>
1004LeAudioOffloadAudioProvider::
1005 getCapabilitiesMatchedBroadcastConfigurationSettings(
1006 LeAudioBroadcastConfigurationSetting& setting,
1007 const IBluetoothAudioProvider::LeAudioDeviceCapabilities&
1008 capabilities) {
1009 std::vector<IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration>
1010 filter_subgroup;
1011 for (auto& sub_cfg : setting.subgroupsConfigurations) {
1012 std::vector<IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration>
1013 filtered_bis_cfg;
1014 for (auto& bis_cfg : sub_cfg.bisConfigurations)
1015 if (isMatchedBISConfiguration(bis_cfg.bisConfiguration, capabilities)) {
1016 filtered_bis_cfg.push_back(bis_cfg);
1017 }
1018 if (!filtered_bis_cfg.empty()) {
1019 IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration
1020 subgroup_cfg;
1021 subgroup_cfg.bisConfigurations = filtered_bis_cfg;
1022 filter_subgroup.push_back(subgroup_cfg);
1023 }
1024 }
1025 if (filter_subgroup.empty()) return std::nullopt;
1026
1027 // Create a new LeAudioAseConfigurationSetting and return
1028 LeAudioBroadcastConfigurationSetting filtered_setting(setting);
1029 filtered_setting.subgroupsConfigurations = filter_subgroup;
1030
1031 return filtered_setting;
1032}
1033
Bao Do91d7ca22024-05-09 14:21:01 +08001034bool LeAudioOffloadAudioProvider::isSubgroupConfigurationMatchedContext(
1035 AudioContext setting_context,
1036 LeAudioBroadcastSubgroupConfiguration configuration) {
1037 // Find any valid context metadata in the bisConfigurations
1038 // assuming the bis configuration in the same bis subgroup
1039 // will have the same context metadata
1040 std::optional<AudioContext> config_context = std::nullopt;
1041
1042 for (auto& p : configuration.bisConfigurations)
1043 if (p.bisConfiguration.metadata.has_value()) {
1044 bool is_context_found = false;
1045 for (auto& metadata : p.bisConfiguration.metadata.value()) {
1046 if (!metadata.has_value()) continue;
1047 if (metadata.value().getTag() ==
1048 MetadataLtv::Tag::preferredAudioContexts) {
1049 config_context = metadata.value()
1050 .get<MetadataLtv::Tag::preferredAudioContexts>()
1051 .values;
1052 is_context_found = true;
1053 break;
1054 }
1055 }
1056 if (is_context_found) break;
1057 }
1058
1059 // Not found context metadata in any of the bis configuration, assume matched
1060 if (!config_context.has_value()) return true;
1061 return (setting_context.bitmask & config_context.value().bitmask);
1062}
1063
Bao Do6112bda2023-11-15 03:57:59 +00001064ndk::ScopedAStatus
1065LeAudioOffloadAudioProvider::getLeAudioBroadcastConfiguration(
1066 const std::optional<std::vector<
1067 std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
1068 in_remoteSinkAudioCapabilities,
1069 const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
1070 in_requirement,
Bao Do5b2fdab2023-11-20 08:02:55 +00001071 LeAudioBroadcastConfigurationSetting* _aidl_return) {
Bao Do91d7ca22024-05-09 14:21:01 +08001072 if (in_requirement.subgroupConfigurationRequirements.empty()) {
1073 LOG(WARNING) << __func__ << ": Empty requirement";
1074 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1075 }
Bao Do5b2fdab2023-11-20 08:02:55 +00001076
Bao Do91d7ca22024-05-09 14:21:01 +08001077 // Broadcast setting are from provider info
1078 // We will allow empty capability input, match all settings with requirements.
1079 getBroadcastSettings();
Bao Do5b2fdab2023-11-20 08:02:55 +00001080 std::vector<LeAudioBroadcastConfigurationSetting> filtered_settings;
1081 if (!in_remoteSinkAudioCapabilities.has_value()) {
Bao Do91d7ca22024-05-09 14:21:01 +08001082 LOG(INFO) << __func__ << ": Empty capability, get all broadcast settings";
1083 filtered_settings = broadcast_settings;
1084 } else {
1085 for (auto& setting : broadcast_settings) {
1086 for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
1087 if (!capability.has_value()) continue;
1088 auto filtered_setting =
1089 getCapabilitiesMatchedBroadcastConfigurationSettings(
1090 setting, capability.value());
1091 if (filtered_setting.has_value())
1092 filtered_settings.push_back(filtered_setting.value());
1093 }
Bao Do5b2fdab2023-11-20 08:02:55 +00001094 }
1095 }
1096
1097 if (filtered_settings.empty()) {
1098 LOG(WARNING) << __func__ << ": Cannot match any remote capability";
1099 return ndk::ScopedAStatus::ok();
1100 }
1101
Bao Do5b2fdab2023-11-20 08:02:55 +00001102 if (in_requirement.subgroupConfigurationRequirements.empty()) {
1103 LOG(INFO) << __func__ << ": Empty requirement";
1104 *_aidl_return = filtered_settings[0];
1105 return ndk::ScopedAStatus::ok();
1106 }
1107
Bao Do91d7ca22024-05-09 14:21:01 +08001108 // For each subgroup config requirement, find a suitable subgroup config.
1109 // Gather these suitable subgroup config in an array.
1110 // If the setting can satisfy all requirement, we can return the setting
1111 // with the filtered array.
Bao Do5b2fdab2023-11-20 08:02:55 +00001112 for (auto& setting : filtered_settings) {
Bao Do91d7ca22024-05-09 14:21:01 +08001113 LeAudioBroadcastConfigurationSetting matched_setting(setting);
1114 matched_setting.subgroupsConfigurations.clear();
1115 auto total_num_bis = 0;
1116
1117 bool matched_all_requirement = true;
1118
1119 for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
1120 bool is_matched = false;
1121 for (auto& sub_cfg : setting.subgroupsConfigurations) {
1122 // Match the context
1123 if (!isSubgroupConfigurationMatchedContext(sub_req.audioContext,
1124 sub_cfg))
1125 continue;
Bao Do5b2fdab2023-11-20 08:02:55 +00001126 // Matching number of BIS
1127 if (sub_req.bisNumPerSubgroup != sub_cfg.bisConfigurations.size())
1128 continue;
Bao Do91d7ca22024-05-09 14:21:01 +08001129 // Currently will ignore quality matching.
1130 matched_setting.subgroupsConfigurations.push_back(sub_cfg);
1131 total_num_bis += sub_cfg.bisConfigurations.size();
1132 is_matched = true;
Bao Do5b2fdab2023-11-20 08:02:55 +00001133 break;
1134 }
Bao Do91d7ca22024-05-09 14:21:01 +08001135 // There is an unmatched requirement, this setting cannot be used
1136 if (!is_matched) {
1137 matched_all_requirement = false;
1138 break;
1139 }
Bao Do5b2fdab2023-11-20 08:02:55 +00001140 }
Bao Do91d7ca22024-05-09 14:21:01 +08001141
1142 if (!matched_all_requirement) continue;
1143
1144 matched_setting.numBis = total_num_bis;
1145 // Return the filtered setting if all requirement satified
1146 *_aidl_return = matched_setting;
1147 return ndk::ScopedAStatus::ok();
Bao Do5b2fdab2023-11-20 08:02:55 +00001148 }
1149
1150 LOG(WARNING) << __func__ << ": Cannot match any requirement";
1151 return ndk::ScopedAStatus::ok();
Bao Do6112bda2023-11-15 03:57:59 +00001152};
Josh Wu6ab53e72021-12-29 23:53:33 -08001153
1154} // namespace audio
1155} // namespace bluetooth
1156} // namespace hardware
1157} // namespace android
Cheney Ni6ecbc762022-03-03 00:12:48 +08001158} // namespace aidl