blob: 5002a1aeda4c984d4f02cf44049d9faaadca3dca [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
178 auto& context = metadata.value()
179 .get<MetadataLtv::Tag::preferredAudioContexts>()
180 .values;
Bao Do91d7ca22024-05-09 14:21:01 +0800181 if (setting_context.bitmask & context.bitmask) {
182 // New mask with matched capability
183 setting_context.bitmask &= context.bitmask;
184 return true;
185 }
Bao Do867af602023-11-15 05:41:12 +0000186 }
187 }
188
189 return false;
190}
191
192bool LeAudioOffloadAudioProvider::isMatchedSamplingFreq(
193 CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
194 CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
195 capability_freq) {
Bao Do91d7ca22024-05-09 14:21:01 +0800196 auto p = freq_to_support_bitmask_map.find(cfg_freq);
197 if (p != freq_to_support_bitmask_map.end()) {
198 if (capability_freq.bitmask & p->second) {
199 return true;
200 }
201 }
Bao Do867af602023-11-15 05:41:12 +0000202 return false;
203}
204
205bool LeAudioOffloadAudioProvider::isMatchedFrameDuration(
206 CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
207 CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
208 capability_fduration) {
Bao Do91d7ca22024-05-09 14:21:01 +0800209 auto p = fduration_to_support_fduration_map.find(cfg_fduration);
210 if (p != fduration_to_support_fduration_map.end())
211 if (capability_fduration.bitmask & p->second) {
212 return true;
213 }
Bao Do867af602023-11-15 05:41:12 +0000214 return false;
215}
216
217bool LeAudioOffloadAudioProvider::isMatchedAudioChannel(
218 CodecSpecificConfigurationLtv::AudioChannelAllocation&
219 /*cfg_channel*/,
220 CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
221 /*capability_channel*/) {
222 bool isMatched = true;
223 // TODO: how to match?
224 return isMatched;
225}
226
227bool LeAudioOffloadAudioProvider::isMatchedCodecFramesPerSDU(
228 CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU& cfg_frame_sdu,
229 CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU&
230 capability_frame_sdu) {
231 return cfg_frame_sdu.value <= capability_frame_sdu.value;
232}
233
234bool LeAudioOffloadAudioProvider::isMatchedOctetsPerCodecFrame(
235 CodecSpecificConfigurationLtv::OctetsPerCodecFrame& cfg_octets,
236 CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame&
237 capability_octets) {
Jakub Tyszkowski1d214222024-01-16 09:44:48 +0000238 return cfg_octets.value >= capability_octets.min &&
239 cfg_octets.value <= capability_octets.max;
Bao Do867af602023-11-15 05:41:12 +0000240}
241
242bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedCodecConfiguration(
243 std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
244 std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities) {
245 // Convert all codec_cfg into a map of tags -> correct data
246 std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
247 cfg_tag_map;
248 for (auto codec_cfg_data : codec_cfg)
249 cfg_tag_map[codec_cfg_data.getTag()] = codec_cfg_data;
250
251 for (auto& codec_capability : codec_capabilities) {
252 auto cfg = cfg_tag_map.find(cap_to_cfg_tag_map[codec_capability.getTag()]);
Bao Do91d7ca22024-05-09 14:21:01 +0800253 // If capability has this tag, but our configuration doesn't
254 // Then we will assume it is matched
255 if (cfg == cfg_tag_map.end()) {
256 continue;
257 }
Bao Do867af602023-11-15 05:41:12 +0000258
Bao Do91d7ca22024-05-09 14:21:01 +0800259 switch (codec_capability.getTag()) {
260 case CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies: {
261 if (!isMatchedSamplingFreq(
262 cfg->second.get<
263 CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
264 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
265 supportedSamplingFrequencies>())) {
266 return false;
267 }
268 break;
269 }
270
271 case CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations: {
272 if (!isMatchedFrameDuration(
273 cfg->second
274 .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
275 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
276 supportedFrameDurations>())) {
277 return false;
278 }
279 break;
280 }
281
282 case CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts: {
283 if (!isMatchedAudioChannel(
284 cfg->second.get<CodecSpecificConfigurationLtv::Tag::
285 audioChannelAllocation>(),
286 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
287 supportedAudioChannelCounts>())) {
288 return false;
289 }
290 break;
291 }
292
293 case CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU: {
294 if (!isMatchedCodecFramesPerSDU(
295 cfg->second.get<CodecSpecificConfigurationLtv::Tag::
296 codecFrameBlocksPerSDU>(),
297 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
298 supportedMaxCodecFramesPerSDU>())) {
299 return false;
300 }
301 break;
302 }
303
304 case CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame: {
305 if (!isMatchedOctetsPerCodecFrame(
306 cfg->second.get<
307 CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
308 codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
309 supportedOctetsPerCodecFrame>())) {
310 return false;
311 }
312 break;
313 }
Bao Do867af602023-11-15 05:41:12 +0000314 }
315 }
316
317 return true;
318}
319
320bool LeAudioOffloadAudioProvider::isMatchedAseConfiguration(
321 LeAudioAseConfiguration setting_cfg,
322 LeAudioAseConfiguration requirement_cfg) {
323 // Check matching for codec configuration <=> requirement ASE codec
324 // Also match if no CodecId requirement
325 if (requirement_cfg.codecId.has_value()) {
326 if (!setting_cfg.codecId.has_value()) return false;
327 if (!isMatchedValidCodec(setting_cfg.codecId.value(),
Bao Do91d7ca22024-05-09 14:21:01 +0800328 requirement_cfg.codecId.value())) {
Bao Do867af602023-11-15 05:41:12 +0000329 return false;
Bao Do91d7ca22024-05-09 14:21:01 +0800330 }
Bao Do867af602023-11-15 05:41:12 +0000331 }
332
Bao Do91d7ca22024-05-09 14:21:01 +0800333 if (requirement_cfg.targetLatency ==
334 LeAudioAseConfiguration::TargetLatency::UNDEFINED ||
335 setting_cfg.targetLatency != requirement_cfg.targetLatency) {
336 return false;
337 }
Bao Do867af602023-11-15 05:41:12 +0000338 // Ignore PHY requirement
339
340 // Check all codec configuration
341 std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
342 cfg_tag_map;
343 for (auto cfg : setting_cfg.codecConfiguration)
344 cfg_tag_map[cfg.getTag()] = cfg;
345
346 for (auto requirement_cfg : requirement_cfg.codecConfiguration) {
347 // Directly compare CodecSpecificConfigurationLtv
348 auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
Bao Do91d7ca22024-05-09 14:21:01 +0800349 if (cfg == cfg_tag_map.end()) {
350 return false;
351 }
Bao Do867af602023-11-15 05:41:12 +0000352
Bao Do91d7ca22024-05-09 14:21:01 +0800353 if (cfg->second != requirement_cfg) {
354 return false;
355 }
Bao Do867af602023-11-15 05:41:12 +0000356 }
357 // Ignore vendor configuration and metadata requirement
358
359 return true;
360}
361
Bao Do5b2fdab2023-11-20 08:02:55 +0000362bool LeAudioOffloadAudioProvider::isMatchedBISConfiguration(
363 LeAudioBisConfiguration bis_cfg,
364 const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
Bao Do91d7ca22024-05-09 14:21:01 +0800365 if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) {
Bao Do5b2fdab2023-11-20 08:02:55 +0000366 return false;
Bao Do91d7ca22024-05-09 14:21:01 +0800367 }
368 if (!isCapabilitiesMatchedCodecConfiguration(
369 bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities)) {
370 return false;
371 }
Bao Do5b2fdab2023-11-20 08:02:55 +0000372 return true;
373}
374
Bao Do867af602023-11-15 05:41:12 +0000375void LeAudioOffloadAudioProvider::filterCapabilitiesAseDirectionConfiguration(
376 std::vector<std::optional<AseDirectionConfiguration>>&
377 direction_configurations,
378 const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
379 std::vector<std::optional<AseDirectionConfiguration>>&
380 valid_direction_configurations) {
381 for (auto direction_configuration : direction_configurations) {
382 if (!direction_configuration.has_value()) continue;
383 if (!direction_configuration.value().aseConfiguration.codecId.has_value())
384 continue;
385 if (!isMatchedValidCodec(
386 direction_configuration.value().aseConfiguration.codecId.value(),
387 capabilities.codecId))
388 continue;
389 // Check matching for codec configuration <=> codec capabilities
390 if (!isCapabilitiesMatchedCodecConfiguration(
391 direction_configuration.value().aseConfiguration.codecConfiguration,
392 capabilities.codecSpecificCapabilities))
393 continue;
394 valid_direction_configurations.push_back(direction_configuration);
395 }
396}
397
398void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
Bao Do91d7ca22024-05-09 14:21:01 +0800399 std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
Bao Do867af602023-11-15 05:41:12 +0000400 direction_configurations,
Bao Do91d7ca22024-05-09 14:21:01 +0800401 const std::vector<std::optional<AseDirectionRequirement>>& requirements,
402 std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
Bao Do867af602023-11-15 05:41:12 +0000403 valid_direction_configurations) {
Bao Do91d7ca22024-05-09 14:21:01 +0800404 if (!valid_direction_configurations.has_value()) {
405 valid_direction_configurations =
406 std::vector<std::optional<AseDirectionConfiguration>>();
407 }
408 // For every requirement, find the matched ase configuration
409 if (!direction_configurations.has_value()) return;
410 for (auto& requirement : requirements) {
411 if (!requirement.has_value()) continue;
412 for (auto direction_configuration : direction_configurations.value()) {
413 if (!direction_configuration.has_value()) continue;
Bao Do867af602023-11-15 05:41:12 +0000414 if (!isMatchedAseConfiguration(
415 direction_configuration.value().aseConfiguration,
416 requirement.value().aseConfiguration))
417 continue;
418 // Valid if match any requirement.
Bao Do91d7ca22024-05-09 14:21:01 +0800419 valid_direction_configurations.value().push_back(direction_configuration);
Bao Do867af602023-11-15 05:41:12 +0000420 break;
421 }
422 }
Bao Do91d7ca22024-05-09 14:21:01 +0800423 // Ensure that each requirement will have one direction configurations
424 if (valid_direction_configurations.value().empty() ||
425 (valid_direction_configurations.value().size() != requirements.size())) {
426 valid_direction_configurations = std::nullopt;
427 }
Bao Do867af602023-11-15 05:41:12 +0000428}
429
430/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
431 * capabilities. The new setting will have a filtered list of
432 * AseDirectionConfiguration that matched the capabilities */
433std::optional<LeAudioAseConfigurationSetting>
434LeAudioOffloadAudioProvider::getCapabilitiesMatchedAseConfigurationSettings(
435 IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
436 const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
437 uint8_t direction) {
Bao Do91d7ca22024-05-09 14:21:01 +0800438 // Create a new LeAudioAseConfigurationSetting and return
439 // For other direction will contain all settings
440 LeAudioAseConfigurationSetting filtered_setting{
441 .audioContext = setting.audioContext,
442 .sinkAseConfiguration = setting.sinkAseConfiguration,
443 .sourceAseConfiguration = setting.sourceAseConfiguration,
444 .flags = setting.flags,
445 .packing = setting.packing,
446 };
Bao Do867af602023-11-15 05:41:12 +0000447 // Try to match context in metadata.
Bao Do91d7ca22024-05-09 14:21:01 +0800448 if (!filterCapabilitiesMatchedContext(filtered_setting.audioContext,
449 capabilities))
Bao Do867af602023-11-15 05:41:12 +0000450 return std::nullopt;
451
452 // Get a list of all matched AseDirectionConfiguration
453 // for the input direction
454 std::vector<std::optional<AseDirectionConfiguration>>*
455 direction_configuration = nullptr;
456 if (direction == kLeAudioDirectionSink) {
Bao Do91d7ca22024-05-09 14:21:01 +0800457 if (!filtered_setting.sinkAseConfiguration.has_value()) return std::nullopt;
458 direction_configuration = &filtered_setting.sinkAseConfiguration.value();
Bao Do867af602023-11-15 05:41:12 +0000459 } else {
Bao Do91d7ca22024-05-09 14:21:01 +0800460 if (!filtered_setting.sourceAseConfiguration.has_value())
461 return std::nullopt;
462 direction_configuration = &filtered_setting.sourceAseConfiguration.value();
Bao Do867af602023-11-15 05:41:12 +0000463 }
464 std::vector<std::optional<AseDirectionConfiguration>>
465 valid_direction_configuration;
466 filterCapabilitiesAseDirectionConfiguration(
467 *direction_configuration, capabilities, valid_direction_configuration);
Bao Do91d7ca22024-05-09 14:21:01 +0800468
469 // No valid configuration for this direction
470 if (valid_direction_configuration.empty()) {
471 return std::nullopt;
472 }
Bao Do867af602023-11-15 05:41:12 +0000473
474 // Create a new LeAudioAseConfigurationSetting and return
Bao Do91d7ca22024-05-09 14:21:01 +0800475 // For other direction will contain all settings
Bao Do867af602023-11-15 05:41:12 +0000476 if (direction == kLeAudioDirectionSink) {
477 filtered_setting.sinkAseConfiguration = valid_direction_configuration;
478 } else {
479 filtered_setting.sourceAseConfiguration = valid_direction_configuration;
480 }
Bao Do867af602023-11-15 05:41:12 +0000481
482 return filtered_setting;
483}
484
485/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
486 * requirement. The new setting will have a filtered list of
487 * AseDirectionConfiguration that matched the requirement */
488std::optional<LeAudioAseConfigurationSetting>
489LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
490 IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
491 const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
492 requirement) {
493 // Try to match context in metadata.
Bao Do91d7ca22024-05-09 14:21:01 +0800494 if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
495 requirement.audioContext.bitmask)
496 return std::nullopt;
497
498 // Further filter setting's context
499 setting.audioContext.bitmask &= requirement.audioContext.bitmask;
Bao Do867af602023-11-15 05:41:12 +0000500
501 // Check requirement for the correct direction
502 const std::optional<std::vector<std::optional<AseDirectionRequirement>>>*
503 direction_requirement;
504 std::vector<std::optional<AseDirectionConfiguration>>*
505 direction_configuration;
Bao Do91d7ca22024-05-09 14:21:01 +0800506
507 // Create a new LeAudioAseConfigurationSetting to return
508 LeAudioAseConfigurationSetting filtered_setting{
509 .audioContext = setting.audioContext,
510 .packing = setting.packing,
511 .flags = setting.flags,
512 };
513
514 if (requirement.sinkAseRequirement.has_value()) {
515 filterRequirementAseDirectionConfiguration(
516 setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
517 filtered_setting.sinkAseConfiguration);
518 if (!filtered_setting.sinkAseConfiguration.has_value()) return std::nullopt;
Bao Do867af602023-11-15 05:41:12 +0000519 }
520
Bao Do91d7ca22024-05-09 14:21:01 +0800521 if (requirement.sourceAseRequirement.has_value()) {
522 filterRequirementAseDirectionConfiguration(
523 setting.sourceAseConfiguration,
524 requirement.sourceAseRequirement.value(),
525 filtered_setting.sourceAseConfiguration);
526 if (!filtered_setting.sourceAseConfiguration.has_value())
527 return std::nullopt;
528 }
Bao Do867af602023-11-15 05:41:12 +0000529
530 return filtered_setting;
531}
532
Bao Do91d7ca22024-05-09 14:21:01 +0800533// For each requirement, a valid ASE configuration will satify:
534// - matched with any sink capability (if presented)
535// - OR matched with any source capability (if presented)
536// - and the setting need to pass the requirement
Bao Do6112bda2023-11-15 03:57:59 +0000537ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
538 const std::optional<std::vector<
539 std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
540 in_remoteSinkAudioCapabilities,
541 const std::optional<std::vector<
542 std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
543 in_remoteSourceAudioCapabilities,
544 const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
545 in_requirements,
546 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
547 _aidl_return) {
Bao Do867af602023-11-15 05:41:12 +0000548 // Get all configuration settings
549 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
550 ase_configuration_settings =
551 BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
552
Bao Do91d7ca22024-05-09 14:21:01 +0800553 if (!in_remoteSinkAudioCapabilities.has_value() &&
554 !in_remoteSourceAudioCapabilities.has_value()) {
555 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
Bao Do867af602023-11-15 05:41:12 +0000556 }
557
Bao Do91d7ca22024-05-09 14:21:01 +0800558 // Each setting consist of source and sink AseDirectionConfiguration vector
559 // Filter every sink capability
Bao Do867af602023-11-15 05:41:12 +0000560 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
Bao Do91d7ca22024-05-09 14:21:01 +0800561 matched_ase_configuration_settings;
562
563 if (in_remoteSinkAudioCapabilities.has_value()) {
564 // Matching each setting with any remote capabilities
565 for (auto& setting : ase_configuration_settings) {
566 for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
567 if (!capability.has_value()) continue;
568 auto filtered_ase_configuration_setting =
569 getCapabilitiesMatchedAseConfigurationSettings(
570 setting, capability.value(), kLeAudioDirectionSink);
571 if (filtered_ase_configuration_setting.has_value()) {
572 matched_ase_configuration_settings.push_back(
573 filtered_ase_configuration_setting.value());
574 }
Bao Do867af602023-11-15 05:41:12 +0000575 }
576 }
577 }
578
Bao Do91d7ca22024-05-09 14:21:01 +0800579 // Combine filter every source capability
580 if (in_remoteSourceAudioCapabilities.has_value()) {
581 // Matching each setting with any remote capabilities
582 for (auto& setting : ase_configuration_settings) {
583 for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
584 if (!capability.has_value()) continue;
585 auto filtered_ase_configuration_setting =
586 getCapabilitiesMatchedAseConfigurationSettings(
587 setting, capability.value(), kLeAudioDirectionSource);
588 if (filtered_ase_configuration_setting.has_value()) {
589 // Put into the same list
590 // possibly duplicated, filtered by requirement later
591 matched_ase_configuration_settings.push_back(
592 filtered_ase_configuration_setting.value());
593 }
594 }
595 }
596 }
597
598 if (matched_ase_configuration_settings.empty()) {
599 LOG(WARNING) << __func__ << ": No setting matched the capability";
600 return ndk::ScopedAStatus::ok();
601 }
602 // Each requirement will match with a valid setting
Bao Do867af602023-11-15 05:41:12 +0000603 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
Bao Do91d7ca22024-05-09 14:21:01 +0800604 for (auto& requirement : in_requirements) {
605 LOG(INFO) << __func__ << ": Trying to match for the requirement "
606 << requirement.toString();
607 bool is_matched = false;
608
609 for (auto& setting : matched_ase_configuration_settings) {
Bao Do867af602023-11-15 05:41:12 +0000610 auto filtered_ase_configuration_setting =
611 getRequirementMatchedAseConfigurationSettings(setting, requirement);
612 if (filtered_ase_configuration_setting.has_value()) {
613 result.push_back(filtered_ase_configuration_setting.value());
Bao Do91d7ca22024-05-09 14:21:01 +0800614 LOG(INFO) << __func__ << ": Result = "
615 << filtered_ase_configuration_setting.value().toString();
616 // Found a matched setting, ignore other settings
617 is_matched = true;
618 break;
Bao Do867af602023-11-15 05:41:12 +0000619 }
620 }
Bao Do91d7ca22024-05-09 14:21:01 +0800621 if (!is_matched) {
622 // If cannot satisfy this requirement, return an empty result
623 LOG(WARNING) << __func__ << ": Cannot match the requirement "
624 << requirement.toString();
625 result.clear();
626 break;
627 }
Bao Do867af602023-11-15 05:41:12 +0000628 }
629
630 *_aidl_return = result;
631 return ndk::ScopedAStatus::ok();
Bao Do6112bda2023-11-15 03:57:59 +0000632};
633
Bao Doc4adf242023-11-15 08:03:20 +0000634bool LeAudioOffloadAudioProvider::isMatchedQosRequirement(
635 LeAudioAseQosConfiguration setting_qos,
636 AseQosDirectionRequirement requirement_qos) {
637 if (setting_qos.retransmissionNum !=
Bao Do91d7ca22024-05-09 14:21:01 +0800638 requirement_qos.preferredRetransmissionNum) {
Bao Doc4adf242023-11-15 08:03:20 +0000639 return false;
Bao Do91d7ca22024-05-09 14:21:01 +0800640 }
641 if (setting_qos.maxTransportLatencyMs >
642 requirement_qos.maxTransportLatencyMs) {
Bao Doc4adf242023-11-15 08:03:20 +0000643 return false;
Bao Do91d7ca22024-05-09 14:21:01 +0800644 }
Bao Doc4adf242023-11-15 08:03:20 +0000645 // Ignore other parameters, as they are not populated in the setting_qos
646 return true;
647}
648
Bao Do91d7ca22024-05-09 14:21:01 +0800649bool isValidQosRequirement(AseQosDirectionRequirement qosRequirement) {
650 return ((qosRequirement.maxTransportLatencyMs > 0) &&
651 (qosRequirement.presentationDelayMaxUs > 0) &&
652 (qosRequirement.presentationDelayMaxUs >=
653 qosRequirement.presentationDelayMinUs));
654}
Bao Doc4adf242023-11-15 08:03:20 +0000655
Bao Do91d7ca22024-05-09 14:21:01 +0800656std::optional<LeAudioAseQosConfiguration>
657LeAudioOffloadAudioProvider::getDirectionQosConfiguration(
658 uint8_t direction,
659 const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
660 qosRequirement,
661 std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings) {
Bao Doc4adf242023-11-15 08:03:20 +0000662 std::optional<AseQosDirectionRequirement> direction_qos_requirement =
663 std::nullopt;
Bao Do91d7ca22024-05-09 14:21:01 +0800664
665 // Get the correct direction
666 if (direction == kLeAudioDirectionSink) {
667 direction_qos_requirement = qosRequirement.sinkAseQosRequirement.value();
668 } else {
669 direction_qos_requirement = qosRequirement.sourceAseQosRequirement.value();
Bao Doc4adf242023-11-15 08:03:20 +0000670 }
671
672 for (auto& setting : ase_configuration_settings) {
673 // Context matching
Bao Do91d7ca22024-05-09 14:21:01 +0800674 if ((setting.audioContext.bitmask & qosRequirement.audioContext.bitmask) !=
675 qosRequirement.audioContext.bitmask)
676 continue;
Bao Doc4adf242023-11-15 08:03:20 +0000677
678 // Match configuration flags
679 // Currently configuration flags are not populated, ignore.
680
681 // Get a list of all matched AseDirectionConfiguration
682 // for the input direction
683 std::vector<std::optional<AseDirectionConfiguration>>*
684 direction_configuration = nullptr;
685 if (direction == kLeAudioDirectionSink) {
686 if (!setting.sinkAseConfiguration.has_value()) continue;
687 direction_configuration = &setting.sinkAseConfiguration.value();
688 } else {
689 if (!setting.sourceAseConfiguration.has_value()) continue;
690 direction_configuration = &setting.sourceAseConfiguration.value();
691 }
692
693 for (auto cfg : *direction_configuration) {
694 if (!cfg.has_value()) continue;
695 // If no requirement, return the first QoS
696 if (!direction_qos_requirement.has_value()) {
Bao Do91d7ca22024-05-09 14:21:01 +0800697 return cfg.value().qosConfiguration;
Bao Doc4adf242023-11-15 08:03:20 +0000698 }
699
700 // If has requirement, return the first matched QoS
701 // Try to match the ASE configuration
702 // and QoS with requirement
703 if (!cfg.value().qosConfiguration.has_value()) continue;
704 if (isMatchedAseConfiguration(
705 cfg.value().aseConfiguration,
706 direction_qos_requirement.value().aseConfiguration) &&
707 isMatchedQosRequirement(cfg.value().qosConfiguration.value(),
708 direction_qos_requirement.value())) {
Bao Do91d7ca22024-05-09 14:21:01 +0800709 return cfg.value().qosConfiguration;
Bao Doc4adf242023-11-15 08:03:20 +0000710 }
711 }
712 }
713
Bao Do91d7ca22024-05-09 14:21:01 +0800714 return std::nullopt;
715}
716
717ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
718 const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
719 in_qosRequirement,
720 IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) {
721 IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
722
723 // Get all configuration settings
724 std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
725 ase_configuration_settings =
726 BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
727
728 // Direction QoS matching
729 // Only handle one direction input case
730 if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
731 if (!isValidQosRequirement(in_qosRequirement.sinkAseQosRequirement.value()))
732 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
733 result.sinkQosConfiguration = getDirectionQosConfiguration(
734 kLeAudioDirectionSink, in_qosRequirement, ase_configuration_settings);
735 }
736 if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
737 if (!isValidQosRequirement(
738 in_qosRequirement.sourceAseQosRequirement.value()))
739 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
740 result.sourceQosConfiguration = getDirectionQosConfiguration(
741 kLeAudioDirectionSource, in_qosRequirement, ase_configuration_settings);
742 }
743
Bao Doc4adf242023-11-15 08:03:20 +0000744 *_aidl_return = result;
745 return ndk::ScopedAStatus::ok();
Bao Do6112bda2023-11-15 03:57:59 +0000746};
747
748ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSinkAseMetadataChanged(
Bao Do5b2fdab2023-11-20 08:02:55 +0000749 IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
750 int32_t /*in_cisId*/,
Bao Do6112bda2023-11-15 03:57:59 +0000751 const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
752 (void)in_state;
753 (void)in_metadata;
754 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
755};
756
757ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSourceAseMetadataChanged(
Bao Do5b2fdab2023-11-20 08:02:55 +0000758 IBluetoothAudioProvider::AseState in_state, int32_t /*in_cigId*/,
759 int32_t /*in_cisId*/,
Bao Do6112bda2023-11-15 03:57:59 +0000760 const std::optional<std::vector<std::optional<MetadataLtv>>>& in_metadata) {
761 (void)in_state;
762 (void)in_metadata;
763 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
764};
765
Bao Do5b2fdab2023-11-20 08:02:55 +0000766void LeAudioOffloadAudioProvider::getBroadcastSettings() {
767 if (!broadcast_settings.empty()) return;
768
769 LOG(INFO) << __func__ << ": Loading broadcast settings from provider info";
770
771 std::vector<CodecInfo> db_codec_info =
772 BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
773 SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
774 broadcast_settings.clear();
Bao Do91d7ca22024-05-09 14:21:01 +0800775
776 // Default value for unmapped fields
Bao Do5b2fdab2023-11-20 08:02:55 +0000777 CodecSpecificConfigurationLtv::AudioChannelAllocation default_allocation;
778 default_allocation.bitmask =
779 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
Bao Do91d7ca22024-05-09 14:21:01 +0800780 CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU default_frame;
781 default_frame.value = 2;
Bao Do5b2fdab2023-11-20 08:02:55 +0000782
783 for (auto& codec_info : db_codec_info) {
784 if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
785 continue;
786 auto& transport = codec_info.transport.get<CodecInfo::Transport::leAudio>();
787 LeAudioBroadcastConfigurationSetting setting;
788 // Default setting
789 setting.numBis = 1;
790 setting.phy = {Phy::TWO_M};
791 // Populate BIS configuration info using codec_info
792 LeAudioBisConfiguration bis_cfg;
793 bis_cfg.codecId = codec_info.id;
794
795 CodecSpecificConfigurationLtv::OctetsPerCodecFrame octets;
796 octets.value = transport.bitdepth[0];
797
798 bis_cfg.codecConfiguration = {
Bao Do91d7ca22024-05-09 14:21:01 +0800799 sampling_freq_map[transport.samplingFrequencyHz[0]],
800 octets,
801 frame_duration_map[transport.frameDurationUs[0]],
802 default_allocation,
803 default_frame,
804 };
Bao Do5b2fdab2023-11-20 08:02:55 +0000805
806 // Add information to structure
807 IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration sub_bis_cfg;
Bao Do91d7ca22024-05-09 14:21:01 +0800808 sub_bis_cfg.numBis = 2;
Bao Do5b2fdab2023-11-20 08:02:55 +0000809 sub_bis_cfg.bisConfiguration = bis_cfg;
810 IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration sub_cfg;
Bao Do91d7ca22024-05-09 14:21:01 +0800811 // Populate the same sub config
812 sub_cfg.bisConfigurations = {sub_bis_cfg, sub_bis_cfg};
Bao Do5b2fdab2023-11-20 08:02:55 +0000813 setting.subgroupsConfigurations = {sub_cfg};
814
815 broadcast_settings.push_back(setting);
816 }
817
818 LOG(INFO) << __func__
819 << ": Done loading broadcast settings from provider info";
820}
821
822/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
823 * capabilities. The new setting will have a filtered list of
824 * AseDirectionConfiguration that matched the capabilities */
825std::optional<LeAudioBroadcastConfigurationSetting>
826LeAudioOffloadAudioProvider::
827 getCapabilitiesMatchedBroadcastConfigurationSettings(
828 LeAudioBroadcastConfigurationSetting& setting,
829 const IBluetoothAudioProvider::LeAudioDeviceCapabilities&
830 capabilities) {
831 std::vector<IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration>
832 filter_subgroup;
833 for (auto& sub_cfg : setting.subgroupsConfigurations) {
834 std::vector<IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration>
835 filtered_bis_cfg;
836 for (auto& bis_cfg : sub_cfg.bisConfigurations)
837 if (isMatchedBISConfiguration(bis_cfg.bisConfiguration, capabilities)) {
838 filtered_bis_cfg.push_back(bis_cfg);
839 }
840 if (!filtered_bis_cfg.empty()) {
841 IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration
842 subgroup_cfg;
843 subgroup_cfg.bisConfigurations = filtered_bis_cfg;
844 filter_subgroup.push_back(subgroup_cfg);
845 }
846 }
847 if (filter_subgroup.empty()) return std::nullopt;
848
849 // Create a new LeAudioAseConfigurationSetting and return
850 LeAudioBroadcastConfigurationSetting filtered_setting(setting);
851 filtered_setting.subgroupsConfigurations = filter_subgroup;
852
853 return filtered_setting;
854}
855
Bao Do91d7ca22024-05-09 14:21:01 +0800856bool LeAudioOffloadAudioProvider::isSubgroupConfigurationMatchedContext(
857 AudioContext setting_context,
858 LeAudioBroadcastSubgroupConfiguration configuration) {
859 // Find any valid context metadata in the bisConfigurations
860 // assuming the bis configuration in the same bis subgroup
861 // will have the same context metadata
862 std::optional<AudioContext> config_context = std::nullopt;
863
864 for (auto& p : configuration.bisConfigurations)
865 if (p.bisConfiguration.metadata.has_value()) {
866 bool is_context_found = false;
867 for (auto& metadata : p.bisConfiguration.metadata.value()) {
868 if (!metadata.has_value()) continue;
869 if (metadata.value().getTag() ==
870 MetadataLtv::Tag::preferredAudioContexts) {
871 config_context = metadata.value()
872 .get<MetadataLtv::Tag::preferredAudioContexts>()
873 .values;
874 is_context_found = true;
875 break;
876 }
877 }
878 if (is_context_found) break;
879 }
880
881 // Not found context metadata in any of the bis configuration, assume matched
882 if (!config_context.has_value()) return true;
883 return (setting_context.bitmask & config_context.value().bitmask);
884}
885
Bao Do6112bda2023-11-15 03:57:59 +0000886ndk::ScopedAStatus
887LeAudioOffloadAudioProvider::getLeAudioBroadcastConfiguration(
888 const std::optional<std::vector<
889 std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
890 in_remoteSinkAudioCapabilities,
891 const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
892 in_requirement,
Bao Do5b2fdab2023-11-20 08:02:55 +0000893 LeAudioBroadcastConfigurationSetting* _aidl_return) {
Bao Do91d7ca22024-05-09 14:21:01 +0800894 if (in_requirement.subgroupConfigurationRequirements.empty()) {
895 LOG(WARNING) << __func__ << ": Empty requirement";
896 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
897 }
Bao Do5b2fdab2023-11-20 08:02:55 +0000898
Bao Do91d7ca22024-05-09 14:21:01 +0800899 // Broadcast setting are from provider info
900 // We will allow empty capability input, match all settings with requirements.
901 getBroadcastSettings();
Bao Do5b2fdab2023-11-20 08:02:55 +0000902 std::vector<LeAudioBroadcastConfigurationSetting> filtered_settings;
903 if (!in_remoteSinkAudioCapabilities.has_value()) {
Bao Do91d7ca22024-05-09 14:21:01 +0800904 LOG(INFO) << __func__ << ": Empty capability, get all broadcast settings";
905 filtered_settings = broadcast_settings;
906 } else {
907 for (auto& setting : broadcast_settings) {
908 for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
909 if (!capability.has_value()) continue;
910 auto filtered_setting =
911 getCapabilitiesMatchedBroadcastConfigurationSettings(
912 setting, capability.value());
913 if (filtered_setting.has_value())
914 filtered_settings.push_back(filtered_setting.value());
915 }
Bao Do5b2fdab2023-11-20 08:02:55 +0000916 }
917 }
918
919 if (filtered_settings.empty()) {
920 LOG(WARNING) << __func__ << ": Cannot match any remote capability";
921 return ndk::ScopedAStatus::ok();
922 }
923
Bao Do5b2fdab2023-11-20 08:02:55 +0000924 if (in_requirement.subgroupConfigurationRequirements.empty()) {
925 LOG(INFO) << __func__ << ": Empty requirement";
926 *_aidl_return = filtered_settings[0];
927 return ndk::ScopedAStatus::ok();
928 }
929
Bao Do91d7ca22024-05-09 14:21:01 +0800930 // For each subgroup config requirement, find a suitable subgroup config.
931 // Gather these suitable subgroup config in an array.
932 // If the setting can satisfy all requirement, we can return the setting
933 // with the filtered array.
Bao Do5b2fdab2023-11-20 08:02:55 +0000934 for (auto& setting : filtered_settings) {
Bao Do91d7ca22024-05-09 14:21:01 +0800935 LeAudioBroadcastConfigurationSetting matched_setting(setting);
936 matched_setting.subgroupsConfigurations.clear();
937 auto total_num_bis = 0;
938
939 bool matched_all_requirement = true;
940
941 for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
942 bool is_matched = false;
943 for (auto& sub_cfg : setting.subgroupsConfigurations) {
944 // Match the context
945 if (!isSubgroupConfigurationMatchedContext(sub_req.audioContext,
946 sub_cfg))
947 continue;
Bao Do5b2fdab2023-11-20 08:02:55 +0000948 // Matching number of BIS
949 if (sub_req.bisNumPerSubgroup != sub_cfg.bisConfigurations.size())
950 continue;
Bao Do91d7ca22024-05-09 14:21:01 +0800951 // Currently will ignore quality matching.
952 matched_setting.subgroupsConfigurations.push_back(sub_cfg);
953 total_num_bis += sub_cfg.bisConfigurations.size();
954 is_matched = true;
Bao Do5b2fdab2023-11-20 08:02:55 +0000955 break;
956 }
Bao Do91d7ca22024-05-09 14:21:01 +0800957 // There is an unmatched requirement, this setting cannot be used
958 if (!is_matched) {
959 matched_all_requirement = false;
960 break;
961 }
Bao Do5b2fdab2023-11-20 08:02:55 +0000962 }
Bao Do91d7ca22024-05-09 14:21:01 +0800963
964 if (!matched_all_requirement) continue;
965
966 matched_setting.numBis = total_num_bis;
967 // Return the filtered setting if all requirement satified
968 *_aidl_return = matched_setting;
969 return ndk::ScopedAStatus::ok();
Bao Do5b2fdab2023-11-20 08:02:55 +0000970 }
971
972 LOG(WARNING) << __func__ << ": Cannot match any requirement";
973 return ndk::ScopedAStatus::ok();
Bao Do6112bda2023-11-15 03:57:59 +0000974};
Josh Wu6ab53e72021-12-29 23:53:33 -0800975
976} // namespace audio
977} // namespace bluetooth
978} // namespace hardware
979} // namespace android
Cheney Ni6ecbc762022-03-03 00:12:48 +0800980} // namespace aidl