blob: 6783c0f0b710f8dff207209f210a388b9f6dea1a [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;
Bao Do81092bb2024-05-30 21:27:10 +080033constexpr uint8_t kIsoDataPathHci = 0x00;
34constexpr uint8_t kIsoDataPathPlatformDefault = 0x01;
Bao Do867af602023-11-15 05:41:12 +000035
36const 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
65std::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
79const std::map<CodecSpecificConfigurationLtv::FrameDuration, uint32_t>
80 fduration_to_support_fduration_map = {
81 {CodecSpecificConfigurationLtv::FrameDuration::US7500,
82 CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500},
83 {CodecSpecificConfigurationLtv::FrameDuration::US10000,
84 CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000},
85};
86
Bao Do5b2fdab2023-11-20 08:02:55 +000087std::map<int32_t, CodecSpecificConfigurationLtv::SamplingFrequency>
88 sampling_freq_map = {
89 {16000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000},
Bao Do81092bb2024-05-30 21:27:10 +080090 {24000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000},
Bao Do5b2fdab2023-11-20 08:02:55 +000091 {48000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000},
92 {96000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000},
93};
94
95std::map<int32_t, CodecSpecificConfigurationLtv::FrameDuration>
96 frame_duration_map = {
97 {7500, CodecSpecificConfigurationLtv::FrameDuration::US7500},
98 {10000, CodecSpecificConfigurationLtv::FrameDuration::US10000},
99};
100
Josh Wu6ab53e72021-12-29 23:53:33 -0800101LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
102 : LeAudioOffloadAudioProvider() {
103 session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
104}
105
106LeAudioOffloadInputAudioProvider::LeAudioOffloadInputAudioProvider()
107 : LeAudioOffloadAudioProvider() {
108 session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
109}
110
Alice Kuoe80a5762022-02-09 14:44:29 +0800111LeAudioOffloadBroadcastAudioProvider::LeAudioOffloadBroadcastAudioProvider()
112 : LeAudioOffloadAudioProvider() {
113 session_type_ =
114 SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
115}
116
Josh Wu6ab53e72021-12-29 23:53:33 -0800117LeAudioOffloadAudioProvider::LeAudioOffloadAudioProvider()
118 : BluetoothAudioProvider() {}
119
120bool LeAudioOffloadAudioProvider::isValid(const SessionType& sessionType) {
121 return (sessionType == session_type_);
122}
123
124ndk::ScopedAStatus LeAudioOffloadAudioProvider::startSession(
125 const std::shared_ptr<IBluetoothAudioPort>& host_if,
Chen Chenc92270e2022-02-14 18:29:52 -0800126 const AudioConfiguration& audio_config,
Cheney Ni6ecbc762022-03-03 00:12:48 +0800127 const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
Alice Kuoee398a92022-07-10 23:59:18 +0800128 if (session_type_ ==
129 SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
130 if (audio_config.getTag() != AudioConfiguration::leAudioBroadcastConfig) {
131 LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
132 << audio_config.toString();
133 *_aidl_return = DataMQDesc();
134 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
135 }
136 } else if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
Josh Wu6ab53e72021-12-29 23:53:33 -0800137 LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
138 << audio_config.toString();
139 *_aidl_return = DataMQDesc();
140 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
141 }
Josh Wu6ab53e72021-12-29 23:53:33 -0800142
Bao Do6112bda2023-11-15 03:57:59 +0000143 return BluetoothAudioProvider::startSession(host_if, audio_config,
144 latency_modes, _aidl_return);
Josh Wu6ab53e72021-12-29 23:53:33 -0800145}
146
147ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady(
148 DataMQDesc* _aidl_return) {
Cheney Ni6ecbc762022-03-03 00:12:48 +0800149 BluetoothAudioSessionReport::OnSessionStarted(
150 session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
Josh Wu6ab53e72021-12-29 23:53:33 -0800151 *_aidl_return = DataMQDesc();
152 return ndk::ScopedAStatus::ok();
153}
Bao Do6112bda2023-11-15 03:57:59 +0000154ndk::ScopedAStatus LeAudioOffloadAudioProvider::setCodecPriority(
155 const CodecId& in_codecId, int32_t in_priority) {
156 codec_priority_map_[in_codecId] = in_priority;
157 return ndk::ScopedAStatus::ok();
158};
159
Bao Do867af602023-11-15 05:41:12 +0000160bool LeAudioOffloadAudioProvider::isMatchedValidCodec(CodecId cfg_codec,
161 CodecId req_codec) {
162 auto priority = codec_priority_map_.find(cfg_codec);
Jakub Tyszkowski1d214222024-01-16 09:44:48 +0000163 if (priority != codec_priority_map_.end() &&
164 priority->second ==
165 LeAudioOffloadAudioProvider::CODEC_PRIORITY_DISABLED) {
Bao Do867af602023-11-15 05:41:12 +0000166 return false;
Jakub Tyszkowski1d214222024-01-16 09:44:48 +0000167 }
Bao Do867af602023-11-15 05:41:12 +0000168 return cfg_codec == req_codec;
169}
170
Bao Do91d7ca22024-05-09 14:21:01 +0800171bool LeAudioOffloadAudioProvider::filterCapabilitiesMatchedContext(
172 AudioContext& setting_context,
Bao Do867af602023-11-15 05:41:12 +0000173 const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
174 // If has no metadata, assume match
175 if (!capabilities.metadata.has_value()) return true;
176
177 for (auto metadata : capabilities.metadata.value()) {
178 if (!metadata.has_value()) continue;
179 if (metadata.value().getTag() == MetadataLtv::Tag::preferredAudioContexts) {
180 // Check all pref audio context to see if anything matched
Bao Do57861bd2024-05-23 17:02:54 +0800181 auto& prefer_context =
182 metadata.value()
183 .get<MetadataLtv::Tag::preferredAudioContexts>()
184 .values;
185 if (setting_context.bitmask & prefer_context.bitmask) {
Bao Do91d7ca22024-05-09 14:21:01 +0800186 // New mask with matched capability
Bao Do57861bd2024-05-23 17:02:54 +0800187 setting_context.bitmask &= prefer_context.bitmask;
Bao Do91d7ca22024-05-09 14:21:01 +0800188 return true;
189 }
Bao Do867af602023-11-15 05:41:12 +0000190 }
191 }
192
193 return false;
194}
195
196bool LeAudioOffloadAudioProvider::isMatchedSamplingFreq(
197 CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
198 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
199 capability_freq) {
Bao Do91d7ca22024-05-09 14:21:01 +0800200 auto p = freq_to_support_bitmask_map.find(cfg_freq);
201 if (p != freq_to_support_bitmask_map.end()) {
202 if (capability_freq.bitmask & p->second) {
203 return true;
204 }
205 }
Bao Do867af602023-11-15 05:41:12 +0000206 return false;
207}
208
209bool LeAudioOffloadAudioProvider::isMatchedFrameDuration(
210 CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
211 CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
212 capability_fduration) {
Bao Do91d7ca22024-05-09 14:21:01 +0800213 auto p = fduration_to_support_fduration_map.find(cfg_fduration);
214 if (p != fduration_to_support_fduration_map.end())
215 if (capability_fduration.bitmask & p->second) {
216 return true;
217 }
Bao Do867af602023-11-15 05:41:12 +0000218 return false;
219}
220
221bool LeAudioOffloadAudioProvider::isMatchedAudioChannel(
222 CodecSpecificConfigurationLtv::AudioChannelAllocation&
223 /*cfg_channel*/,
224 CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
225 /*capability_channel*/) {
Bao Do57861bd2024-05-23 17:02:54 +0800226 // Simply ignore.
227 // Later can use additional capabilities to match requirement.
Bao Do867af602023-11-15 05:41:12 +0000228 bool isMatched = true;
Bao Do867af602023-11-15 05:41:12 +0000229 return isMatched;
230}
231
232bool LeAudioOffloadAudioProvider::isMatchedCodecFramesPerSDU(
233 CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU& cfg_frame_sdu,
234 CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU&
235 capability_frame_sdu) {
236 return cfg_frame_sdu.value <= capability_frame_sdu.value;
237}
238
239bool LeAudioOffloadAudioProvider::isMatchedOctetsPerCodecFrame(
240 CodecSpecificConfigurationLtv::OctetsPerCodecFrame& cfg_octets,
241 CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame&
242 capability_octets) {
Jakub Tyszkowski1d214222024-01-16 09:44:48 +0000243 return cfg_octets.value >= capability_octets.min &&
244 cfg_octets.value <= capability_octets.max;
Bao Do867af602023-11-15 05:41:12 +0000245}
246
247bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedCodecConfiguration(
248 std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
249 std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities) {
250 // Convert all codec_cfg into a map of tags -> correct data
251 std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
252 cfg_tag_map;
253 for (auto codec_cfg_data : codec_cfg)
254 cfg_tag_map[codec_cfg_data.getTag()] = codec_cfg_data;
255
256 for (auto& codec_capability : codec_capabilities) {
257 auto cfg = cfg_tag_map.find(cap_to_cfg_tag_map[codec_capability.getTag()]);
Bao Do91d7ca22024-05-09 14:21:01 +0800258 // If capability has this tag, but our configuration doesn't
259 // Then we will assume it is matched
260 if (cfg == cfg_tag_map.end()) {
261 continue;
262 }
Bao Do867af602023-11-15 05:41:12 +0000263
Bao Do91d7ca22024-05-09 14:21:01 +0800264 switch (codec_capability.getTag()) {
265 case CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies: {
266 if (!isMatchedSamplingFreq(
267 cfg->second.get<
268 CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
269 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
270 supportedSamplingFrequencies>())) {
271 return false;
272 }
273 break;
274 }
275
276 case CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations: {
277 if (!isMatchedFrameDuration(
278 cfg->second
279 .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
280 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
281 supportedFrameDurations>())) {
282 return false;
283 }
284 break;
285 }
286
287 case CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts: {
288 if (!isMatchedAudioChannel(
289 cfg->second.get<CodecSpecificConfigurationLtv::Tag::
290 audioChannelAllocation>(),
291 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
292 supportedAudioChannelCounts>())) {
293 return false;
294 }
295 break;
296 }
297
298 case CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU: {
299 if (!isMatchedCodecFramesPerSDU(
300 cfg->second.get<CodecSpecificConfigurationLtv::Tag::
301 codecFrameBlocksPerSDU>(),
302 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
303 supportedMaxCodecFramesPerSDU>())) {
304 return false;
305 }
306 break;
307 }
308
309 case CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame: {
310 if (!isMatchedOctetsPerCodecFrame(
311 cfg->second.get<
312 CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
313 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
314 supportedOctetsPerCodecFrame>())) {
315 return false;
316 }
317 break;
318 }
Bao Do867af602023-11-15 05:41:12 +0000319 }
320 }
321
322 return true;
323}
324
Bao Do57861bd2024-05-23 17:02:54 +0800325bool isMonoConfig(
326 CodecSpecificConfigurationLtv::AudioChannelAllocation allocation) {
327 auto channel_count = std::bitset<32>(allocation.bitmask);
328 return (channel_count.count() <= 1);
329}
330
331bool LeAudioOffloadAudioProvider::filterMatchedAseConfiguration(
332 LeAudioAseConfiguration& setting_cfg,
333 const LeAudioAseConfiguration& requirement_cfg) {
Bao Do867af602023-11-15 05:41:12 +0000334 // Check matching for codec configuration <=> requirement ASE codec
335 // Also match if no CodecId requirement
336 if (requirement_cfg.codecId.has_value()) {
337 if (!setting_cfg.codecId.has_value()) return false;
338 if (!isMatchedValidCodec(setting_cfg.codecId.value(),
Bao Do91d7ca22024-05-09 14:21:01 +0800339 requirement_cfg.codecId.value())) {
Bao Do57861bd2024-05-23 17:02:54 +0800340 LOG(WARNING) << __func__ << ": Doesn't match valid codec, cfg = "
341 << setting_cfg.codecId.value().toString()
342 << ", req = " << requirement_cfg.codecId.value().toString();
Bao Do867af602023-11-15 05:41:12 +0000343 return false;
Bao Do91d7ca22024-05-09 14:21:01 +0800344 }
Bao Do867af602023-11-15 05:41:12 +0000345 }
346
Bao Do57861bd2024-05-23 17:02:54 +0800347 if (requirement_cfg.targetLatency !=
348 LeAudioAseConfiguration::TargetLatency::UNDEFINED &&
Bao Do91d7ca22024-05-09 14:21:01 +0800349 setting_cfg.targetLatency != requirement_cfg.targetLatency) {
Bao Do57861bd2024-05-23 17:02:54 +0800350 LOG(WARNING) << __func__ << ": Doesn't match target latency, cfg = "
351 << int(setting_cfg.targetLatency)
352 << ", req = " << int(requirement_cfg.targetLatency);
Bao Do91d7ca22024-05-09 14:21:01 +0800353 return false;
354 }
Bao Do867af602023-11-15 05:41:12 +0000355 // Ignore PHY requirement
356
357 // Check all codec configuration
358 std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
359 cfg_tag_map;
360 for (auto cfg : setting_cfg.codecConfiguration)
361 cfg_tag_map[cfg.getTag()] = cfg;
362
363 for (auto requirement_cfg : requirement_cfg.codecConfiguration) {
364 // Directly compare CodecSpecificConfigurationLtv
365 auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
Bao Do57861bd2024-05-23 17:02:54 +0800366 // Config not found for this requirement, cannot match
Bao Do91d7ca22024-05-09 14:21:01 +0800367 if (cfg == cfg_tag_map.end()) {
Bao Do57861bd2024-05-23 17:02:54 +0800368 LOG(WARNING) << __func__ << ": Config not found for the requirement "
369 << requirement_cfg.toString();
Bao Do91d7ca22024-05-09 14:21:01 +0800370 return false;
371 }
Bao Do867af602023-11-15 05:41:12 +0000372
Bao Do57861bd2024-05-23 17:02:54 +0800373 // Ignore matching for audio channel allocation
374 // since the rule is complicated. Match outside instead
375 if (requirement_cfg.getTag() ==
376 CodecSpecificConfigurationLtv::Tag::audioChannelAllocation)
377 continue;
378
Bao Do91d7ca22024-05-09 14:21:01 +0800379 if (cfg->second != requirement_cfg) {
Bao Do57861bd2024-05-23 17:02:54 +0800380 LOG(WARNING) << __func__
381 << ": Config doesn't match the requirement, cfg = "
382 << cfg->second.toString()
383 << ", req = " << requirement_cfg.toString();
Bao Do91d7ca22024-05-09 14:21:01 +0800384 return false;
385 }
Bao Do867af602023-11-15 05:41:12 +0000386 }
387 // Ignore vendor configuration and metadata requirement
388
389 return true;
390}
391
Bao Do5b2fdab2023-11-20 08:02:55 +0000392bool LeAudioOffloadAudioProvider::isMatchedBISConfiguration(
393 LeAudioBisConfiguration bis_cfg,
394 const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
Bao Do91d7ca22024-05-09 14:21:01 +0800395 if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) {
Bao Do5b2fdab2023-11-20 08:02:55 +0000396 return false;
Bao Do91d7ca22024-05-09 14:21:01 +0800397 }
398 if (!isCapabilitiesMatchedCodecConfiguration(
399 bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities)) {
400 return false;
401 }
Bao Do5b2fdab2023-11-20 08:02:55 +0000402 return true;
403}
404
Bao Do867af602023-11-15 05:41:12 +0000405void LeAudioOffloadAudioProvider::filterCapabilitiesAseDirectionConfiguration(
406 std::vector<std::optional<AseDirectionConfiguration>>&
407 direction_configurations,
408 const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
409 std::vector<std::optional<AseDirectionConfiguration>>&
410 valid_direction_configurations) {
411 for (auto direction_configuration : direction_configurations) {
412 if (!direction_configuration.has_value()) continue;
413 if (!direction_configuration.value().aseConfiguration.codecId.has_value())
414 continue;
415 if (!isMatchedValidCodec(
416 direction_configuration.value().aseConfiguration.codecId.value(),
417 capabilities.codecId))
418 continue;
419 // Check matching for codec configuration <=> codec capabilities
420 if (!isCapabilitiesMatchedCodecConfiguration(
421 direction_configuration.value().aseConfiguration.codecConfiguration,
422 capabilities.codecSpecificCapabilities))
423 continue;
424 valid_direction_configurations.push_back(direction_configuration);
425 }
426}
427
Bao Do57861bd2024-05-23 17:02:54 +0800428int getLeAudioAseConfigurationAllocationBitmask(LeAudioAseConfiguration cfg) {
429 for (auto cfg_ltv : cfg.codecConfiguration) {
430 if (cfg_ltv.getTag() ==
431 CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
432 return cfg_ltv
433 .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
434 .bitmask;
435 }
436 }
437 return 0;
438}
439
440int getCountFromBitmask(int bitmask) {
441 return std::bitset<32>(bitmask).count();
442}
443
444std::optional<AseDirectionConfiguration> findValidMonoConfig(
445 std::vector<AseDirectionConfiguration>& valid_direction_configurations,
446 int bitmask) {
447 for (auto& cfg : valid_direction_configurations) {
448 int cfg_bitmask =
449 getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
450 if (getCountFromBitmask(cfg_bitmask) <= 1) {
Bao Do57861bd2024-05-23 17:02:54 +0800451 // Modify the bitmask to be the same as the requirement
452 for (auto& codec_cfg : cfg.aseConfiguration.codecConfiguration) {
453 if (codec_cfg.getTag() ==
454 CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
455 codec_cfg
456 .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
457 .bitmask = bitmask;
458 return cfg;
459 }
460 }
461 }
462 }
463 return std::nullopt;
464}
465
466std::vector<AseDirectionConfiguration> getValidConfigurationsFromAllocation(
467 int req_allocation_bitmask,
Bao Do81092bb2024-05-30 21:27:10 +0800468 std::vector<AseDirectionConfiguration>& valid_direction_configurations,
469 bool is_exact) {
Bao Do57861bd2024-05-23 17:02:54 +0800470 // Prefer the same allocation_bitmask
471 int channel_count = getCountFromBitmask(req_allocation_bitmask);
Bao Do81092bb2024-05-30 21:27:10 +0800472
473 if (is_exact) {
474 for (auto& cfg : valid_direction_configurations) {
475 int cfg_bitmask =
476 getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
477 if (cfg_bitmask == req_allocation_bitmask) {
478 LOG(DEBUG)
479 << __func__
480 << ": Found an exact match for the requirement allocation of "
481 << cfg_bitmask;
482 return {cfg};
483 }
Bao Do57861bd2024-05-23 17:02:54 +0800484 }
Bao Do81092bb2024-05-30 21:27:10 +0800485 return {};
Bao Do57861bd2024-05-23 17:02:54 +0800486 }
Bao Do81092bb2024-05-30 21:27:10 +0800487 // Not using exact match strategy
Bao Do57861bd2024-05-23 17:02:54 +0800488 if (channel_count <= 1) {
489 // Mono requirement matched if cfg is a mono config
490 auto cfg = findValidMonoConfig(valid_direction_configurations,
491 req_allocation_bitmask);
492 if (cfg.has_value()) return {cfg.value()};
493 } else {
494 // Stereo requirement returns 2 mono configs
495 // that has a combined bitmask equal to the stereo config
496 std::vector<AseDirectionConfiguration> temp;
497 for (int bit = 0; bit < 32; ++bit)
498 if (req_allocation_bitmask & (1 << bit)) {
499 auto cfg =
500 findValidMonoConfig(valid_direction_configurations, (1 << bit));
501 if (cfg.has_value()) temp.push_back(cfg.value());
502 }
503 if (temp.size() == channel_count) return temp;
504 }
505 return {};
506}
507
Bao Do867af602023-11-15 05:41:12 +0000508void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
Bao Do91d7ca22024-05-09 14:21:01 +0800509 std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
Bao Do867af602023-11-15 05:41:12 +0000510 direction_configurations,
Bao Do91d7ca22024-05-09 14:21:01 +0800511 const std::vector<std::optional<AseDirectionRequirement>>& requirements,
512 std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
Bao Do81092bb2024-05-30 21:27:10 +0800513 valid_direction_configurations,
514 bool is_exact) {
Bao Do57861bd2024-05-23 17:02:54 +0800515 // For every requirement, find the matched ase configuration
516 if (!direction_configurations.has_value()) return;
517
Bao Do91d7ca22024-05-09 14:21:01 +0800518 if (!valid_direction_configurations.has_value()) {
519 valid_direction_configurations =
520 std::vector<std::optional<AseDirectionConfiguration>>();
521 }
Bao Do57861bd2024-05-23 17:02:54 +0800522
Bao Do91d7ca22024-05-09 14:21:01 +0800523 for (auto& requirement : requirements) {
524 if (!requirement.has_value()) continue;
Bao Do57861bd2024-05-23 17:02:54 +0800525 auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
526 requirement.value().aseConfiguration);
527 auto req_channel_count = getCountFromBitmask(req_allocation_bitmask);
528
529 auto temp = std::vector<AseDirectionConfiguration>();
530
Bao Do91d7ca22024-05-09 14:21:01 +0800531 for (auto direction_configuration : direction_configurations.value()) {
532 if (!direction_configuration.has_value()) continue;
Bao Do57861bd2024-05-23 17:02:54 +0800533 if (!filterMatchedAseConfiguration(
Bao Do867af602023-11-15 05:41:12 +0000534 direction_configuration.value().aseConfiguration,
535 requirement.value().aseConfiguration))
536 continue;
537 // Valid if match any requirement.
Bao Do57861bd2024-05-23 17:02:54 +0800538 temp.push_back(direction_configuration.value());
Bao Do867af602023-11-15 05:41:12 +0000539 }
Bao Do57861bd2024-05-23 17:02:54 +0800540
541 // Get the best matching config based on channel allocation
542 auto total_cfg_channel_count = 0;
Bao Do81092bb2024-05-30 21:27:10 +0800543 auto req_valid_configs = getValidConfigurationsFromAllocation(
544 req_allocation_bitmask, temp, is_exact);
Bao Do57861bd2024-05-23 17:02:54 +0800545 // Count and check required channel counts
546 for (auto& cfg : req_valid_configs) {
547 total_cfg_channel_count += getCountFromBitmask(
548 getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration));
549 valid_direction_configurations.value().push_back(cfg);
550 }
551 if (total_cfg_channel_count != req_channel_count) {
Bao Do57861bd2024-05-23 17:02:54 +0800552 valid_direction_configurations = std::nullopt;
553 return;
554 }
Bao Do91d7ca22024-05-09 14:21:01 +0800555 }
Bao Do867af602023-11-15 05:41:12 +0000556}
557
558/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
559 * capabilities. The new setting will have a filtered list of
560 * AseDirectionConfiguration that matched the capabilities */
561std::optional<LeAudioAseConfigurationSetting>
562LeAudioOffloadAudioProvider::getCapabilitiesMatchedAseConfigurationSettings(
563 IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
564 const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
565 uint8_t direction) {
Bao Do91d7ca22024-05-09 14:21:01 +0800566 // Create a new LeAudioAseConfigurationSetting and return
567 // For other direction will contain all settings
568 LeAudioAseConfigurationSetting filtered_setting{
569 .audioContext = setting.audioContext,
570 .sinkAseConfiguration = setting.sinkAseConfiguration,
571 .sourceAseConfiguration = setting.sourceAseConfiguration,
572 .flags = setting.flags,
573 .packing = setting.packing,
574 };
Bao Do867af602023-11-15 05:41:12 +0000575
576 // Get a list of all matched AseDirectionConfiguration
577 // for the input direction
578 std::vector<std::optional<AseDirectionConfiguration>>*
579 direction_configuration = nullptr;
580 if (direction == kLeAudioDirectionSink) {
Bao Do91d7ca22024-05-09 14:21:01 +0800581 if (!filtered_setting.sinkAseConfiguration.has_value()) return std::nullopt;
582 direction_configuration = &filtered_setting.sinkAseConfiguration.value();
Bao Do867af602023-11-15 05:41:12 +0000583 } else {
Bao Do91d7ca22024-05-09 14:21:01 +0800584 if (!filtered_setting.sourceAseConfiguration.has_value())
585 return std::nullopt;
586 direction_configuration = &filtered_setting.sourceAseConfiguration.value();
Bao Do867af602023-11-15 05:41:12 +0000587 }
588 std::vector<std::optional<AseDirectionConfiguration>>
589 valid_direction_configuration;
590 filterCapabilitiesAseDirectionConfiguration(
591 *direction_configuration, capabilities, valid_direction_configuration);
Bao Do91d7ca22024-05-09 14:21:01 +0800592
593 // No valid configuration for this direction
594 if (valid_direction_configuration.empty()) {
595 return std::nullopt;
596 }
Bao Do867af602023-11-15 05:41:12 +0000597
598 // Create a new LeAudioAseConfigurationSetting and return
Bao Do91d7ca22024-05-09 14:21:01 +0800599 // For other direction will contain all settings
Bao Do867af602023-11-15 05:41:12 +0000600 if (direction == kLeAudioDirectionSink) {
601 filtered_setting.sinkAseConfiguration = valid_direction_configuration;
602 } else {
603 filtered_setting.sourceAseConfiguration = valid_direction_configuration;
604 }
Bao Do867af602023-11-15 05:41:12 +0000605
606 return filtered_setting;
607}
608
609/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
610 * requirement. The new setting will have a filtered list of
611 * AseDirectionConfiguration that matched the requirement */
612std::optional<LeAudioAseConfigurationSetting>
613LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
614 IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
Bao Do81092bb2024-05-30 21:27:10 +0800615 const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
616 bool is_exact) {
Bao Do867af602023-11-15 05:41:12 +0000617 // Try to match context in metadata.
Bao Do91d7ca22024-05-09 14:21:01 +0800618 if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
619 requirement.audioContext.bitmask)
620 return std::nullopt;
621
622 // Further filter setting's context
623 setting.audioContext.bitmask &= requirement.audioContext.bitmask;
Bao Do867af602023-11-15 05:41:12 +0000624
Bao Do91d7ca22024-05-09 14:21:01 +0800625 // Create a new LeAudioAseConfigurationSetting to return
626 LeAudioAseConfigurationSetting filtered_setting{
627 .audioContext = setting.audioContext,
628 .packing = setting.packing,
629 .flags = setting.flags,
630 };
631
632 if (requirement.sinkAseRequirement.has_value()) {
633 filterRequirementAseDirectionConfiguration(
634 setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
Bao Do81092bb2024-05-30 21:27:10 +0800635 filtered_setting.sinkAseConfiguration, is_exact);
Bao Do57861bd2024-05-23 17:02:54 +0800636 if (!filtered_setting.sinkAseConfiguration.has_value()) {
Bao Do57861bd2024-05-23 17:02:54 +0800637 return std::nullopt;
638 }
Bao Do867af602023-11-15 05:41:12 +0000639 }
640
Bao Do91d7ca22024-05-09 14:21:01 +0800641 if (requirement.sourceAseRequirement.has_value()) {
642 filterRequirementAseDirectionConfiguration(
643 setting.sourceAseConfiguration,
644 requirement.sourceAseRequirement.value(),
Bao Do81092bb2024-05-30 21:27:10 +0800645 filtered_setting.sourceAseConfiguration, is_exact);
Bao Do57861bd2024-05-23 17:02:54 +0800646 if (!filtered_setting.sourceAseConfiguration.has_value()) {
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 Do81092bb2024-05-30 21:27:10 +0800659 in_requirements,
660 bool is_exact) {
Bao Do91d7ca22024-05-09 14:21:01 +0800661 // Each requirement will match with a valid setting
Bao Do867af602023-11-15 05:41:12 +0000662 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
Bao Do91d7ca22024-05-09 14:21:01 +0800663 for (auto& requirement : in_requirements) {
664 LOG(INFO) << __func__ << ": Trying to match for the requirement "
665 << requirement.toString();
666 bool is_matched = false;
667
668 for (auto& setting : matched_ase_configuration_settings) {
Bao Do867af602023-11-15 05:41:12 +0000669 auto filtered_ase_configuration_setting =
Bao Do81092bb2024-05-30 21:27:10 +0800670 getRequirementMatchedAseConfigurationSettings(setting, requirement,
671 is_exact);
Bao Do867af602023-11-15 05:41:12 +0000672 if (filtered_ase_configuration_setting.has_value()) {
673 result.push_back(filtered_ase_configuration_setting.value());
Bao Do91d7ca22024-05-09 14:21:01 +0800674 LOG(INFO) << __func__ << ": Result = "
675 << filtered_ase_configuration_setting.value().toString();
676 // Found a matched setting, ignore other settings
677 is_matched = true;
678 break;
Bao Do867af602023-11-15 05:41:12 +0000679 }
680 }
Bao Do91d7ca22024-05-09 14:21:01 +0800681 if (!is_matched) {
682 // If cannot satisfy this requirement, return an empty result
683 LOG(WARNING) << __func__ << ": Cannot match the requirement "
684 << requirement.toString();
685 result.clear();
686 break;
687 }
Bao Do867af602023-11-15 05:41:12 +0000688 }
Bao Do57861bd2024-05-23 17:02:54 +0800689 return result;
690}
Bao Do867af602023-11-15 05:41:12 +0000691
Bao Do57861bd2024-05-23 17:02:54 +0800692// For each requirement, a valid ASE configuration will satify:
693// - matched with any sink capability (if presented)
694// - OR matched with any source capability (if presented)
695// - and the setting need to pass the requirement
696ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
697 const std::optional<std::vector<
698 std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
699 in_remoteSinkAudioCapabilities,
700 const std::optional<std::vector<
701 std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
702 in_remoteSourceAudioCapabilities,
703 const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
704 in_requirements,
705 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
706 _aidl_return) {
707 // Get all configuration settings
708 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
709 ase_configuration_settings =
710 BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
711
712 if (!in_remoteSinkAudioCapabilities.has_value() &&
713 !in_remoteSourceAudioCapabilities.has_value()) {
714 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
715 }
716
717 // Split out preferred and non-preferred settings based on context
718 // An example: preferred = MEDIA, available: MEDIA | CONVERSATION
719 // -> preferred list will have settings with MEDIA context
720 // -> non-preferred list will have settings with any context
721 // We want to match requirement with preferred context settings first
722 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
723 matched_ase_configuration_settings;
724 // Matched ASE configuration with non-preferred audio context
725 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
726 non_prefer_matched_ase_configuration_settings;
727
728 if (in_remoteSinkAudioCapabilities.has_value())
729 // Matching each setting with any remote capabilities
730 for (auto& setting : ase_configuration_settings)
731 for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
732 if (!capability.has_value()) continue;
733 auto filtered_ase_configuration_setting =
734 getCapabilitiesMatchedAseConfigurationSettings(
735 setting, capability.value(), kLeAudioDirectionSink);
736 if (filtered_ase_configuration_setting.has_value()) {
737 // Push to non-prefer first for the broadest matching possible
738 non_prefer_matched_ase_configuration_settings.push_back(
739 filtered_ase_configuration_setting.value());
740 // Try to filter out prefer context to another vector.
741 if (filterCapabilitiesMatchedContext(
742 filtered_ase_configuration_setting.value().audioContext,
743 capability.value())) {
744 matched_ase_configuration_settings.push_back(
745 filtered_ase_configuration_setting.value());
746 }
747 }
748 }
749
750 // Combine filter every source capability
751 if (in_remoteSourceAudioCapabilities.has_value())
752 // Matching each setting with any remote capabilities
753 for (auto& setting : ase_configuration_settings)
754 for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
755 if (!capability.has_value()) continue;
756 auto filtered_ase_configuration_setting =
757 getCapabilitiesMatchedAseConfigurationSettings(
758 setting, capability.value(), kLeAudioDirectionSource);
759 if (filtered_ase_configuration_setting.has_value()) {
760 // Put into the same list
761 // possibly duplicated, filtered by requirement later
762 // Push to non-prefer first for the broadest matching possible
763 non_prefer_matched_ase_configuration_settings.push_back(
764 filtered_ase_configuration_setting.value());
765 // Try to filter out prefer context to another vector.
766 if (filterCapabilitiesMatchedContext(
767 filtered_ase_configuration_setting.value().audioContext,
768 capability.value())) {
769 matched_ase_configuration_settings.push_back(
770 filtered_ase_configuration_setting.value());
771 }
772 }
773 }
774
Bao Do81092bb2024-05-30 21:27:10 +0800775 // Matching priority list:
776 // Preferred context - exact match with allocation
777 // Any context - exact match with allocation
778 // Preferred context - loose match with allocation
779 // Any context - loose match with allocation
780
781 // A loose match will attempt to return 2 settings with the
782 // combined allocation bitmask equal the required allocation.
783 // For example, we can return 2 link (left link and right link) when
784 // the requirement required 1 (left + right) link.
785 auto result = matchWithRequirement(matched_ase_configuration_settings,
786 in_requirements, true);
787 if (result.empty()) {
788 LOG(WARNING)
789 << __func__
790 << ": Cannot match with preferred context settings - exact match";
791 result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
792 in_requirements, true);
793 }
794 if (result.empty()) {
795 LOG(WARNING)
796 << __func__
797 << ": Cannot match with non-preferred context settings - exact match";
798 result = matchWithRequirement(matched_ase_configuration_settings,
799 in_requirements, false);
800 }
Bao Do57861bd2024-05-23 17:02:54 +0800801 if (result.empty()) {
802 LOG(WARNING) << __func__
Bao Do81092bb2024-05-30 21:27:10 +0800803 << ": Cannot match with preferred context settings - "
804 "non-exact match";
Bao Do57861bd2024-05-23 17:02:54 +0800805 result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
Bao Do81092bb2024-05-30 21:27:10 +0800806 in_requirements, false);
Bao Do57861bd2024-05-23 17:02:54 +0800807 }
Bao Do81092bb2024-05-30 21:27:10 +0800808 if (result.empty())
809 LOG(ERROR) << __func__
810 << ": Cannot match with non preferred context settings - "
811 "non-exact match";
Bao Do867af602023-11-15 05:41:12 +0000812 *_aidl_return = result;
813 return ndk::ScopedAStatus::ok();
Bao Do6112bda2023-11-15 03:57:59 +0000814};
815
Bao Doc4adf242023-11-15 08:03:20 +0000816bool LeAudioOffloadAudioProvider::isMatchedQosRequirement(
817 LeAudioAseQosConfiguration setting_qos,
818 AseQosDirectionRequirement requirement_qos) {
819 if (setting_qos.retransmissionNum !=
Bao Do91d7ca22024-05-09 14:21:01 +0800820 requirement_qos.preferredRetransmissionNum) {
Bao Doc4adf242023-11-15 08:03:20 +0000821 return false;
Bao Do91d7ca22024-05-09 14:21:01 +0800822 }
823 if (setting_qos.maxTransportLatencyMs >
824 requirement_qos.maxTransportLatencyMs) {
Bao Doc4adf242023-11-15 08:03:20 +0000825 return false;
Bao Do91d7ca22024-05-09 14:21:01 +0800826 }
Bao Doc4adf242023-11-15 08:03:20 +0000827 return true;
828}
829
Bao Do91d7ca22024-05-09 14:21:01 +0800830bool isValidQosRequirement(AseQosDirectionRequirement qosRequirement) {
831 return ((qosRequirement.maxTransportLatencyMs > 0) &&
832 (qosRequirement.presentationDelayMaxUs > 0) &&
833 (qosRequirement.presentationDelayMaxUs >=
834 qosRequirement.presentationDelayMinUs));
835}
Bao Doc4adf242023-11-15 08:03:20 +0000836
Bao Do91d7ca22024-05-09 14:21:01 +0800837std::optional<LeAudioAseQosConfiguration>
838LeAudioOffloadAudioProvider::getDirectionQosConfiguration(
839 uint8_t direction,
840 const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
841 qosRequirement,
Bao Do81092bb2024-05-30 21:27:10 +0800842 std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings,
843 bool is_exact) {
Bao Doc4adf242023-11-15 08:03:20 +0000844 std::optional<AseQosDirectionRequirement> direction_qos_requirement =
845 std::nullopt;
Bao Do91d7ca22024-05-09 14:21:01 +0800846
847 // Get the correct direction
848 if (direction == kLeAudioDirectionSink) {
849 direction_qos_requirement = qosRequirement.sinkAseQosRequirement.value();
850 } else {
851 direction_qos_requirement = qosRequirement.sourceAseQosRequirement.value();
Bao Doc4adf242023-11-15 08:03:20 +0000852 }
853
854 for (auto& setting : ase_configuration_settings) {
855 // Context matching
Bao Do91d7ca22024-05-09 14:21:01 +0800856 if ((setting.audioContext.bitmask & qosRequirement.audioContext.bitmask) !=
857 qosRequirement.audioContext.bitmask)
858 continue;
Bao Doc4adf242023-11-15 08:03:20 +0000859
860 // Match configuration flags
861 // Currently configuration flags are not populated, ignore.
862
863 // Get a list of all matched AseDirectionConfiguration
864 // for the input direction
Bao Do57861bd2024-05-23 17:02:54 +0800865 std::optional<std::vector<std::optional<AseDirectionConfiguration>>>
866 direction_configuration = std::nullopt;
Bao Doc4adf242023-11-15 08:03:20 +0000867 if (direction == kLeAudioDirectionSink) {
868 if (!setting.sinkAseConfiguration.has_value()) continue;
Bao Do57861bd2024-05-23 17:02:54 +0800869 direction_configuration.emplace(setting.sinkAseConfiguration.value());
Bao Doc4adf242023-11-15 08:03:20 +0000870 } else {
871 if (!setting.sourceAseConfiguration.has_value()) continue;
Bao Do57861bd2024-05-23 17:02:54 +0800872 direction_configuration.emplace(setting.sourceAseConfiguration.value());
Bao Doc4adf242023-11-15 08:03:20 +0000873 }
874
Bao Do57861bd2024-05-23 17:02:54 +0800875 if (!direction_configuration.has_value()) {
876 return std::nullopt;
877 }
878
879 // Collect all valid cfg into a vector
880 // Then try to get the best match for audio allocation
881
882 auto temp = std::vector<AseDirectionConfiguration>();
883
884 for (auto& cfg : direction_configuration.value()) {
Bao Doc4adf242023-11-15 08:03:20 +0000885 if (!cfg.has_value()) continue;
886 // If no requirement, return the first QoS
887 if (!direction_qos_requirement.has_value()) {
Bao Do91d7ca22024-05-09 14:21:01 +0800888 return cfg.value().qosConfiguration;
Bao Doc4adf242023-11-15 08:03:20 +0000889 }
890
891 // If has requirement, return the first matched QoS
892 // Try to match the ASE configuration
893 // and QoS with requirement
894 if (!cfg.value().qosConfiguration.has_value()) continue;
Bao Do57861bd2024-05-23 17:02:54 +0800895 if (filterMatchedAseConfiguration(
Bao Doc4adf242023-11-15 08:03:20 +0000896 cfg.value().aseConfiguration,
897 direction_qos_requirement.value().aseConfiguration) &&
898 isMatchedQosRequirement(cfg.value().qosConfiguration.value(),
899 direction_qos_requirement.value())) {
Bao Do57861bd2024-05-23 17:02:54 +0800900 temp.push_back(cfg.value());
Bao Doc4adf242023-11-15 08:03:20 +0000901 }
902 }
Bao Do57861bd2024-05-23 17:02:54 +0800903 LOG(WARNING) << __func__ << ": Got " << temp.size()
904 << " configs, start matching allocation";
905
906 int qos_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
907 direction_qos_requirement.value().aseConfiguration);
908 // Get the best matching config based on channel allocation
Bao Do81092bb2024-05-30 21:27:10 +0800909 auto req_valid_configs = getValidConfigurationsFromAllocation(
910 qos_allocation_bitmask, temp, is_exact);
Bao Do57861bd2024-05-23 17:02:54 +0800911 if (req_valid_configs.empty()) {
912 LOG(WARNING) << __func__
913 << ": Cannot find matching allocation for bitmask "
914 << qos_allocation_bitmask;
915
916 } else {
917 return req_valid_configs[0].qosConfiguration;
918 }
Bao Doc4adf242023-11-15 08:03:20 +0000919 }
920
Bao Do91d7ca22024-05-09 14:21:01 +0800921 return std::nullopt;
922}
923
924ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
925 const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
926 in_qosRequirement,
927 IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) {
928 IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
929
930 // Get all configuration settings
931 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
932 ase_configuration_settings =
933 BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
934
935 // Direction QoS matching
936 // Only handle one direction input case
937 if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
938 if (!isValidQosRequirement(in_qosRequirement.sinkAseQosRequirement.value()))
939 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
Bao Do81092bb2024-05-30 21:27:10 +0800940 {
941 // Try exact match first
942 result.sinkQosConfiguration =
943 getDirectionQosConfiguration(kLeAudioDirectionSink, in_qosRequirement,
944 ase_configuration_settings, true);
945 if (!result.sinkQosConfiguration.has_value()) {
946 result.sinkQosConfiguration = getDirectionQosConfiguration(
947 kLeAudioDirectionSink, in_qosRequirement,
948 ase_configuration_settings, false);
949 }
950 }
Bao Do91d7ca22024-05-09 14:21:01 +0800951 }
952 if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
953 if (!isValidQosRequirement(
954 in_qosRequirement.sourceAseQosRequirement.value()))
955 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
Bao Do81092bb2024-05-30 21:27:10 +0800956 result.sourceQosConfiguration =
957 getDirectionQosConfiguration(kLeAudioDirectionSource, in_qosRequirement,
958 ase_configuration_settings, true);
959 if (!result.sourceQosConfiguration.has_value()) {
960 result.sourceQosConfiguration = getDirectionQosConfiguration(
961 kLeAudioDirectionSource, in_qosRequirement,
962 ase_configuration_settings, false);
963 }
Bao Do91d7ca22024-05-09 14:21:01 +0800964 }
965
Bao Doc4adf242023-11-15 08:03:20 +0000966 *_aidl_return = result;
967 return ndk::ScopedAStatus::ok();
Bao Do6112bda2023-11-15 03:57:59 +0000968};
969
970ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSinkAseMetadataChanged(
Bao Do5b2fdab2023-11-20 08:02:55 +0000971 IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
972 int32_t /*in_cisId*/,
Bao Do6112bda2023-11-15 03:57:59 +0000973 const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
974 (void)in_state;
975 (void)in_metadata;
976 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
977};
978
979ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSourceAseMetadataChanged(
Bao Do5b2fdab2023-11-20 08:02:55 +0000980 IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
981 int32_t /*in_cisId*/,
Bao Do6112bda2023-11-15 03:57:59 +0000982 const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
983 (void)in_state;
984 (void)in_metadata;
985 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
986};
987
Bao Do81092bb2024-05-30 21:27:10 +0800988LeAudioBroadcastConfigurationSetting getDefaultBroadcastSetting(
989 int context_bitmask, IBluetoothAudioProvider::BroadcastQuality quality) {
990 LeAudioBroadcastConfigurationSetting setting;
991 setting.retransmitionNum = 4;
992 setting.maxTransportLatencyMs = 60;
993 setting.sduIntervalUs = 10000;
994 setting.maxSduOctets = 40;
995
996 if (quality == IBluetoothAudioProvider::BroadcastQuality::HIGH) {
997 LOG(INFO) << __func__ << ": High quality, returning high quality settings";
998 setting.retransmitionNum = 4;
999 setting.maxTransportLatencyMs = 65;
1000 setting.maxSduOctets = 200;
1001 return setting;
1002 }
1003
1004 // Populate other settings base on context
1005 // TODO: Populate with better design
1006 if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME)) {
1007 setting.retransmitionNum = 2;
1008 setting.maxTransportLatencyMs = 10;
1009 setting.maxSduOctets = 120;
1010 } else if (context_bitmask & (AudioContext::INSTRUCTIONAL)) {
1011 setting.retransmitionNum = 2;
1012 setting.maxTransportLatencyMs = 10;
1013 setting.maxSduOctets = 40;
1014 } else if (context_bitmask &
1015 (AudioContext::SOUND_EFFECTS | AudioContext::UNSPECIFIED)) {
1016 setting.retransmitionNum = 4;
1017 setting.maxTransportLatencyMs = 60;
1018 setting.maxSduOctets = 80;
1019 } else if (context_bitmask &
1020 (AudioContext::ALERTS | AudioContext::NOTIFICATIONS |
1021 AudioContext::EMERGENCY_ALARM)) {
1022 setting.retransmitionNum = 4;
1023 setting.maxTransportLatencyMs = 60;
1024 setting.maxSduOctets = 40;
1025 } else if (context_bitmask & AudioContext::MEDIA) {
1026 setting.retransmitionNum = 4;
1027 setting.maxTransportLatencyMs = 60;
1028 setting.maxSduOctets = 120;
1029 }
1030
1031 return setting;
1032}
1033void modifySubBISConfigAllocation(
1034 IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration& sub_bis_cfg,
1035 int allocation_bitmask) {
1036 for (auto& codec_cfg : sub_bis_cfg.bisConfiguration.codecConfiguration) {
1037 if (codec_cfg.getTag() ==
1038 CodecSpecificConfigurationLtv::audioChannelAllocation) {
1039 codec_cfg.get<CodecSpecificConfigurationLtv::audioChannelAllocation>()
1040 .bitmask = allocation_bitmask;
1041 break;
1042 }
1043 }
1044}
1045void modifySubgroupConfiguration(
1046 IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration&
1047 subgroup_cfg,
1048 int context_bitmask) {
1049 // STEREO configs
1050 // Split into 2 sub BIS config, each has numBis = 1
1051 if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME |
1052 AudioContext::SOUND_EFFECTS |
1053 AudioContext::UNSPECIFIED | AudioContext::MEDIA)) {
1054 if (subgroup_cfg.bisConfigurations.size() == 1)
1055 subgroup_cfg.bisConfigurations.push_back(
1056 subgroup_cfg.bisConfigurations[0]);
1057
1058 subgroup_cfg.bisConfigurations[0].numBis = 1;
1059 modifySubBISConfigAllocation(
1060 subgroup_cfg.bisConfigurations[0],
1061 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT);
1062
1063 subgroup_cfg.bisConfigurations[1].numBis = 1;
1064 modifySubBISConfigAllocation(
1065 subgroup_cfg.bisConfigurations[1],
1066 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT);
1067 return;
1068 }
1069
1070 // MONO configs
1071 for (auto& sub_bis_cfg : subgroup_cfg.bisConfigurations) {
1072 sub_bis_cfg.numBis = 1;
1073 modifySubBISConfigAllocation(
1074 sub_bis_cfg,
1075 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER);
1076 }
1077}
1078
Bao Do5b2fdab2023-11-20 08:02:55 +00001079void LeAudioOffloadAudioProvider::getBroadcastSettings() {
1080 if (!broadcast_settings.empty()) return;
1081
Bao Do81092bb2024-05-30 21:27:10 +08001082 LOG(INFO) << __func__
1083 << ": Loading basic broadcast settings from provider info";
Bao Do5b2fdab2023-11-20 08:02:55 +00001084
1085 std::vector<CodecInfo> db_codec_info =
1086 BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
1087 SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
Bao Do81092bb2024-05-30 21:27:10 +08001088 for (auto x : db_codec_info) {
1089 LOG(INFO) << __func__ << ": codec info = " << x.toString();
1090 }
Bao Do5b2fdab2023-11-20 08:02:55 +00001091 broadcast_settings.clear();
Bao Do91d7ca22024-05-09 14:21:01 +08001092
Bao Do81092bb2024-05-30 21:27:10 +08001093 // Default value population
Bao Do5b2fdab2023-11-20 08:02:55 +00001094 CodecSpecificConfigurationLtv::AudioChannelAllocation default_allocation;
1095 default_allocation.bitmask =
1096 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
Bao Do91d7ca22024-05-09 14:21:01 +08001097 CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU default_frame;
Bao Do81092bb2024-05-30 21:27:10 +08001098 default_frame.value = 1;
Bao Do5b2fdab2023-11-20 08:02:55 +00001099
1100 for (auto& codec_info : db_codec_info) {
1101 if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
1102 continue;
1103 auto& transport = codec_info.transport.get<CodecInfo::Transport::leAudio>();
1104 LeAudioBroadcastConfigurationSetting setting;
Bao Do81092bb2024-05-30 21:27:10 +08001105 setting.retransmitionNum = 4;
1106 setting.maxTransportLatencyMs = 60;
1107 setting.sduIntervalUs = 10000;
1108 setting.maxSduOctets = 40;
Bao Do5b2fdab2023-11-20 08:02:55 +00001109 // Default setting
1110 setting.numBis = 1;
1111 setting.phy = {Phy::TWO_M};
1112 // Populate BIS configuration info using codec_info
1113 LeAudioBisConfiguration bis_cfg;
1114 bis_cfg.codecId = codec_info.id;
1115
1116 CodecSpecificConfigurationLtv::OctetsPerCodecFrame octets;
1117 octets.value = transport.bitdepth[0];
1118
1119 bis_cfg.codecConfiguration = {
Bao Do91d7ca22024-05-09 14:21:01 +08001120 sampling_freq_map[transport.samplingFrequencyHz[0]],
1121 octets,
1122 frame_duration_map[transport.frameDurationUs[0]],
1123 default_allocation,
1124 default_frame,
1125 };
Bao Do5b2fdab2023-11-20 08:02:55 +00001126
Bao Do81092bb2024-05-30 21:27:10 +08001127 // Ignore bis_cfg.metadata
1128
Bao Do5b2fdab2023-11-20 08:02:55 +00001129 // Add information to structure
1130 IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration sub_bis_cfg;
Bao Do81092bb2024-05-30 21:27:10 +08001131 sub_bis_cfg.numBis = 1;
Bao Do5b2fdab2023-11-20 08:02:55 +00001132 sub_bis_cfg.bisConfiguration = bis_cfg;
1133 IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration sub_cfg;
Bao Do91d7ca22024-05-09 14:21:01 +08001134 // Populate the same sub config
Bao Do81092bb2024-05-30 21:27:10 +08001135 sub_cfg.bisConfigurations = {sub_bis_cfg};
Bao Do5b2fdab2023-11-20 08:02:55 +00001136 setting.subgroupsConfigurations = {sub_cfg};
1137
1138 broadcast_settings.push_back(setting);
1139 }
1140
1141 LOG(INFO) << __func__
1142 << ": Done loading broadcast settings from provider info";
1143}
1144
1145/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
1146 * capabilities. The new setting will have a filtered list of
1147 * AseDirectionConfiguration that matched the capabilities */
1148std::optional<LeAudioBroadcastConfigurationSetting>
1149LeAudioOffloadAudioProvider::
1150 getCapabilitiesMatchedBroadcastConfigurationSettings(
1151 LeAudioBroadcastConfigurationSetting& setting,
1152 const IBluetoothAudioProvider::LeAudioDeviceCapabilities&
1153 capabilities) {
1154 std::vector<IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration>
1155 filter_subgroup;
1156 for (auto& sub_cfg : setting.subgroupsConfigurations) {
1157 std::vector<IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration>
1158 filtered_bis_cfg;
1159 for (auto& bis_cfg : sub_cfg.bisConfigurations)
1160 if (isMatchedBISConfiguration(bis_cfg.bisConfiguration, capabilities)) {
1161 filtered_bis_cfg.push_back(bis_cfg);
1162 }
1163 if (!filtered_bis_cfg.empty()) {
1164 IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration
1165 subgroup_cfg;
1166 subgroup_cfg.bisConfigurations = filtered_bis_cfg;
1167 filter_subgroup.push_back(subgroup_cfg);
1168 }
1169 }
1170 if (filter_subgroup.empty()) return std::nullopt;
1171
1172 // Create a new LeAudioAseConfigurationSetting and return
1173 LeAudioBroadcastConfigurationSetting filtered_setting(setting);
1174 filtered_setting.subgroupsConfigurations = filter_subgroup;
1175
1176 return filtered_setting;
1177}
1178
Bao Do81092bb2024-05-30 21:27:10 +08001179std::vector<CodecSpecificConfigurationLtv> getCodecRequirementBasedOnContext(
1180 int context_bitmask, IBluetoothAudioProvider::BroadcastQuality quality) {
1181 // Default requirement: lc3_stereo_16_2
1182 std::vector<CodecSpecificConfigurationLtv> requirement = {
1183 CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
1184 CodecSpecificConfigurationLtv::FrameDuration::US10000,
1185 };
1186
1187 if (quality == IBluetoothAudioProvider::BroadcastQuality::HIGH) {
1188 LOG(INFO) << __func__
1189 << ": High quality, returning high quality requirement";
1190 requirement = {
1191 CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000,
1192 CodecSpecificConfigurationLtv::FrameDuration::US10000,
1193 };
1194 return requirement;
1195 }
1196
1197 if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME)) {
1198 // lc3_stereo_24_2_1
1199 requirement = {
1200 CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
1201 CodecSpecificConfigurationLtv::FrameDuration::US10000,
1202 };
1203 } else if (context_bitmask & (AudioContext::INSTRUCTIONAL)) {
1204 // lc3_mono_16_2
1205 requirement = {
1206 CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
1207 CodecSpecificConfigurationLtv::FrameDuration::US10000,
1208 };
1209 } else if (context_bitmask &
1210 (AudioContext::SOUND_EFFECTS | AudioContext::UNSPECIFIED)) {
1211 // lc3_stereo_16_2
1212 requirement = {
1213 CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
1214 CodecSpecificConfigurationLtv::FrameDuration::US10000,
1215 };
1216 } else if (context_bitmask &
1217 (AudioContext::ALERTS | AudioContext::NOTIFICATIONS |
1218 AudioContext::EMERGENCY_ALARM)) {
1219 // Default requirement: lc3_stereo_16_2
1220 requirement = {
1221 CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
1222 CodecSpecificConfigurationLtv::FrameDuration::US10000,
1223 };
1224 } else if (context_bitmask & AudioContext::MEDIA) {
1225 // Default requirement: lc3_stereo_16_2
1226 // Return the 48k requirement
1227 requirement = {
1228 CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
1229 CodecSpecificConfigurationLtv::FrameDuration::US10000,
1230 };
1231 }
1232 return requirement;
1233}
1234
Bao Do91d7ca22024-05-09 14:21:01 +08001235bool LeAudioOffloadAudioProvider::isSubgroupConfigurationMatchedContext(
Bao Do81092bb2024-05-30 21:27:10 +08001236 AudioContext requirement_context,
1237 IBluetoothAudioProvider::BroadcastQuality quality,
Bao Do91d7ca22024-05-09 14:21:01 +08001238 LeAudioBroadcastSubgroupConfiguration configuration) {
1239 // Find any valid context metadata in the bisConfigurations
1240 // assuming the bis configuration in the same bis subgroup
1241 // will have the same context metadata
1242 std::optional<AudioContext> config_context = std::nullopt;
1243
Bao Do81092bb2024-05-30 21:27:10 +08001244 auto codec_requirement =
1245 getCodecRequirementBasedOnContext(requirement_context.bitmask, quality);
1246 std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
1247 req_tag_map;
1248 for (auto x : codec_requirement) req_tag_map[x.getTag()] = x;
Bao Do91d7ca22024-05-09 14:21:01 +08001249
Bao Do81092bb2024-05-30 21:27:10 +08001250 for (auto& bis_cfg : configuration.bisConfigurations) {
1251 // Check every sub_bis_cfg to see which match
1252 for (auto& x : bis_cfg.bisConfiguration.codecConfiguration) {
1253 auto p = req_tag_map.find(x.getTag());
1254 if (p == req_tag_map.end()) continue;
1255 if (p->second != x) {
1256 LOG(WARNING) << __func__ << ": does not match for context "
1257 << requirement_context.toString()
1258 << ", cfg = " << x.toString();
1259 return false;
1260 }
1261 }
1262 }
1263 return true;
Bao Do91d7ca22024-05-09 14:21:01 +08001264}
1265
Bao Do6112bda2023-11-15 03:57:59 +00001266ndk::ScopedAStatus
1267LeAudioOffloadAudioProvider::getLeAudioBroadcastConfiguration(
1268 const std::optional<std::vector<
1269 std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
1270 in_remoteSinkAudioCapabilities,
1271 const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
1272 in_requirement,
Bao Do5b2fdab2023-11-20 08:02:55 +00001273 LeAudioBroadcastConfigurationSetting* _aidl_return) {
Bao Do91d7ca22024-05-09 14:21:01 +08001274 if (in_requirement.subgroupConfigurationRequirements.empty()) {
1275 LOG(WARNING) << __func__ << ": Empty requirement";
1276 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
1277 }
Bao Do5b2fdab2023-11-20 08:02:55 +00001278
Bao Do91d7ca22024-05-09 14:21:01 +08001279 // Broadcast setting are from provider info
1280 // We will allow empty capability input, match all settings with requirements.
1281 getBroadcastSettings();
Bao Do5b2fdab2023-11-20 08:02:55 +00001282 std::vector<LeAudioBroadcastConfigurationSetting> filtered_settings;
Bao Do81092bb2024-05-30 21:27:10 +08001283 if (!in_remoteSinkAudioCapabilities.has_value() ||
1284 in_remoteSinkAudioCapabilities.value().empty()) {
Bao Do91d7ca22024-05-09 14:21:01 +08001285 LOG(INFO) << __func__ << ": Empty capability, get all broadcast settings";
1286 filtered_settings = broadcast_settings;
1287 } else {
1288 for (auto& setting : broadcast_settings) {
1289 for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
1290 if (!capability.has_value()) continue;
1291 auto filtered_setting =
1292 getCapabilitiesMatchedBroadcastConfigurationSettings(
1293 setting, capability.value());
1294 if (filtered_setting.has_value())
1295 filtered_settings.push_back(filtered_setting.value());
1296 }
Bao Do5b2fdab2023-11-20 08:02:55 +00001297 }
1298 }
1299
1300 if (filtered_settings.empty()) {
1301 LOG(WARNING) << __func__ << ": Cannot match any remote capability";
1302 return ndk::ScopedAStatus::ok();
1303 }
1304
Bao Do5b2fdab2023-11-20 08:02:55 +00001305 if (in_requirement.subgroupConfigurationRequirements.empty()) {
1306 LOG(INFO) << __func__ << ": Empty requirement";
1307 *_aidl_return = filtered_settings[0];
1308 return ndk::ScopedAStatus::ok();
1309 }
1310
Bao Do91d7ca22024-05-09 14:21:01 +08001311 // For each subgroup config requirement, find a suitable subgroup config.
1312 // Gather these suitable subgroup config in an array.
1313 // If the setting can satisfy all requirement, we can return the setting
1314 // with the filtered array.
Bao Do91d7ca22024-05-09 14:21:01 +08001315
Bao Do81092bb2024-05-30 21:27:10 +08001316 auto context_bitmask =
1317 in_requirement.subgroupConfigurationRequirements[0].audioContext.bitmask;
1318 auto quality = in_requirement.subgroupConfigurationRequirements[0].quality;
1319 LeAudioBroadcastConfigurationSetting return_setting =
1320 getDefaultBroadcastSetting(context_bitmask, quality);
1321 // Default setting
1322 return_setting.numBis = 0;
1323 return_setting.subgroupsConfigurations = {};
Bao Do91d7ca22024-05-09 14:21:01 +08001324
Bao Do81092bb2024-05-30 21:27:10 +08001325 LeAudioDataPathConfiguration path;
1326 path.isoDataPathConfiguration.isTransparent = true;
1327 path.dataPathId = kIsoDataPathPlatformDefault;
1328
1329 // Each subreq, find a setting that match
1330 for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
1331 bool is_setting_matched = false;
1332 for (auto setting : filtered_settings) {
1333 bool is_matched = true;
1334 // Check if every sub BIS config satisfy
1335 for (auto& sub_group_config : setting.subgroupsConfigurations) {
1336 if (!isSubgroupConfigurationMatchedContext(
1337 sub_req.audioContext, sub_req.quality, sub_group_config)) {
1338 is_matched = false;
1339 break;
1340 }
1341 path.isoDataPathConfiguration.codecId =
1342 sub_group_config.bisConfigurations[0].bisConfiguration.codecId;
1343 // Also modify the subgroup config to match the context
1344 modifySubgroupConfiguration(sub_group_config, context_bitmask);
Bao Do5b2fdab2023-11-20 08:02:55 +00001345 }
Bao Do81092bb2024-05-30 21:27:10 +08001346
1347 if (is_matched) {
1348 is_setting_matched = true;
1349 for (auto& sub_group_config : setting.subgroupsConfigurations)
1350 return_setting.subgroupsConfigurations.push_back(sub_group_config);
Bao Do91d7ca22024-05-09 14:21:01 +08001351 break;
1352 }
Bao Do5b2fdab2023-11-20 08:02:55 +00001353 }
Bao Do91d7ca22024-05-09 14:21:01 +08001354
Bao Do81092bb2024-05-30 21:27:10 +08001355 if (!is_setting_matched) {
1356 LOG(WARNING) << __func__
1357 << ": Cannot find a setting that match requirement "
1358 << sub_req.toString();
1359 return ndk::ScopedAStatus::ok();
1360 }
Bao Do5b2fdab2023-11-20 08:02:55 +00001361 }
1362
Bao Do81092bb2024-05-30 21:27:10 +08001363 // Populate all numBis
1364 for (auto& sub_group_config : return_setting.subgroupsConfigurations) {
1365 for (auto& sub_bis_config : sub_group_config.bisConfigurations) {
1366 return_setting.numBis += sub_bis_config.numBis;
1367 }
1368 }
1369 return_setting.phy = std::vector<Phy>(return_setting.numBis, Phy::TWO_M);
1370 // Populate data path config
1371 return_setting.dataPathConfiguration = path;
1372 // TODO: Workaround for STEREO configs maxSduOctets being doubled
1373 if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME |
1374 AudioContext::SOUND_EFFECTS |
1375 AudioContext::UNSPECIFIED | AudioContext::MEDIA)) {
1376 return_setting.maxSduOctets /= 2;
1377 }
1378 LOG(INFO) << __func__
1379 << ": Combined setting that match: " << return_setting.toString();
1380 *_aidl_return = return_setting;
Bao Do5b2fdab2023-11-20 08:02:55 +00001381 return ndk::ScopedAStatus::ok();
Bao Do6112bda2023-11-15 03:57:59 +00001382};
Josh Wu6ab53e72021-12-29 23:53:33 -08001383
1384} // namespace audio
1385} // namespace bluetooth
1386} // namespace hardware
1387} // namespace android
Cheney Ni6ecbc762022-03-03 00:12:48 +08001388} // namespace aidl