Additional broadcast config logic for LEA multi-codec
Broadcast settings matching now base on context to
populate configurations
Bug: 306225778
Test: atest VtsHalBluetoothAudioTargetTest
Change-Id: I150754558ceb74f19888ef63210e2a42b3f00cd8
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index 1f54e6c..6783c0f 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -30,6 +30,8 @@
constexpr uint8_t kLeAudioDirectionSink = 0x01;
constexpr uint8_t kLeAudioDirectionSource = 0x02;
+constexpr uint8_t kIsoDataPathHci = 0x00;
+constexpr uint8_t kIsoDataPathPlatformDefault = 0x01;
const std::map<CodecSpecificConfigurationLtv::SamplingFrequency, uint32_t>
freq_to_support_bitmask_map = {
@@ -85,6 +87,7 @@
std::map<int32_t, CodecSpecificConfigurationLtv::SamplingFrequency>
sampling_freq_map = {
{16000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000},
+ {24000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000},
{48000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000},
{96000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000},
};
@@ -445,7 +448,6 @@
int cfg_bitmask =
getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
if (getCountFromBitmask(cfg_bitmask) <= 1) {
- LOG(INFO) << __func__ << ": Found a mono config for the mono requirement";
// Modify the bitmask to be the same as the requirement
for (auto& codec_cfg : cfg.aseConfiguration.codecConfiguration) {
if (codec_cfg.getTag() ==
@@ -463,20 +465,26 @@
std::vector<AseDirectionConfiguration> getValidConfigurationsFromAllocation(
int req_allocation_bitmask,
- std::vector<AseDirectionConfiguration>& valid_direction_configurations) {
+ std::vector<AseDirectionConfiguration>& valid_direction_configurations,
+ bool is_exact) {
// Prefer the same allocation_bitmask
int channel_count = getCountFromBitmask(req_allocation_bitmask);
- for (auto& cfg : valid_direction_configurations) {
- int cfg_bitmask =
- getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
- if (cfg_bitmask == req_allocation_bitmask) {
- LOG(INFO) << __func__
- << ": Found an exact match for the requirement allocation of "
- << cfg_bitmask;
- return {cfg};
+
+ if (is_exact) {
+ for (auto& cfg : valid_direction_configurations) {
+ int cfg_bitmask =
+ getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
+ if (cfg_bitmask == req_allocation_bitmask) {
+ LOG(DEBUG)
+ << __func__
+ << ": Found an exact match for the requirement allocation of "
+ << cfg_bitmask;
+ return {cfg};
+ }
}
+ return {};
}
- // No exact match found
+ // Not using exact match strategy
if (channel_count <= 1) {
// Mono requirement matched if cfg is a mono config
auto cfg = findValidMonoConfig(valid_direction_configurations,
@@ -502,7 +510,8 @@
direction_configurations,
const std::vector<std::optional<AseDirectionRequirement>>& requirements,
std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
- valid_direction_configurations) {
+ valid_direction_configurations,
+ bool is_exact) {
// For every requirement, find the matched ase configuration
if (!direction_configurations.has_value()) return;
@@ -513,8 +522,6 @@
for (auto& requirement : requirements) {
if (!requirement.has_value()) continue;
- LOG(INFO) << __func__ << ": Testing for requirement = "
- << requirement.value().toString();
auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
requirement.value().aseConfiguration);
auto req_channel_count = getCountFromBitmask(req_allocation_bitmask);
@@ -533,8 +540,8 @@
// Get the best matching config based on channel allocation
auto total_cfg_channel_count = 0;
- auto req_valid_configs =
- getValidConfigurationsFromAllocation(req_allocation_bitmask, temp);
+ auto req_valid_configs = getValidConfigurationsFromAllocation(
+ req_allocation_bitmask, temp, is_exact);
// Count and check required channel counts
for (auto& cfg : req_valid_configs) {
total_cfg_channel_count += getCountFromBitmask(
@@ -542,9 +549,6 @@
valid_direction_configurations.value().push_back(cfg);
}
if (total_cfg_channel_count != req_channel_count) {
- LOG(WARNING) << __func__
- << ": Wrong channel count, req = " << req_channel_count
- << ", total = " << total_cfg_channel_count;
valid_direction_configurations = std::nullopt;
return;
}
@@ -608,15 +612,13 @@
std::optional<LeAudioAseConfigurationSetting>
LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
- const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
- requirement) {
+ const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
+ bool is_exact) {
// Try to match context in metadata.
if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
requirement.audioContext.bitmask)
return std::nullopt;
- LOG(INFO) << __func__
- << ": Checking if the setting match: " << setting.toString();
// Further filter setting's context
setting.audioContext.bitmask &= requirement.audioContext.bitmask;
@@ -630,9 +632,8 @@
if (requirement.sinkAseRequirement.has_value()) {
filterRequirementAseDirectionConfiguration(
setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
- filtered_setting.sinkAseConfiguration);
+ filtered_setting.sinkAseConfiguration, is_exact);
if (!filtered_setting.sinkAseConfiguration.has_value()) {
- LOG(WARNING) << __func__ << "Setting's sink doesn't match!";
return std::nullopt;
}
}
@@ -641,9 +642,8 @@
filterRequirementAseDirectionConfiguration(
setting.sourceAseConfiguration,
requirement.sourceAseRequirement.value(),
- filtered_setting.sourceAseConfiguration);
+ filtered_setting.sourceAseConfiguration, is_exact);
if (!filtered_setting.sourceAseConfiguration.has_value()) {
- LOG(WARNING) << __func__ << "Setting's source doesn't match!";
return std::nullopt;
}
}
@@ -656,7 +656,8 @@
std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
matched_ase_configuration_settings,
const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
- in_requirements) {
+ in_requirements,
+ bool is_exact) {
// Each requirement will match with a valid setting
std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
for (auto& requirement : in_requirements) {
@@ -666,7 +667,8 @@
for (auto& setting : matched_ase_configuration_settings) {
auto filtered_ase_configuration_setting =
- getRequirementMatchedAseConfigurationSettings(setting, requirement);
+ getRequirementMatchedAseConfigurationSettings(setting, requirement,
+ is_exact);
if (filtered_ase_configuration_setting.has_value()) {
result.push_back(filtered_ase_configuration_setting.value());
LOG(INFO) << __func__ << ": Result = "
@@ -770,17 +772,43 @@
}
}
- auto result =
- matchWithRequirement(matched_ase_configuration_settings, in_requirements);
+ // Matching priority list:
+ // Preferred context - exact match with allocation
+ // Any context - exact match with allocation
+ // Preferred context - loose match with allocation
+ // Any context - loose match with allocation
+
+ // A loose match will attempt to return 2 settings with the
+ // combined allocation bitmask equal the required allocation.
+ // For example, we can return 2 link (left link and right link) when
+ // the requirement required 1 (left + right) link.
+ auto result = matchWithRequirement(matched_ase_configuration_settings,
+ in_requirements, true);
+ if (result.empty()) {
+ LOG(WARNING)
+ << __func__
+ << ": Cannot match with preferred context settings - exact match";
+ result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
+ in_requirements, true);
+ }
+ if (result.empty()) {
+ LOG(WARNING)
+ << __func__
+ << ": Cannot match with non-preferred context settings - exact match";
+ result = matchWithRequirement(matched_ase_configuration_settings,
+ in_requirements, false);
+ }
if (result.empty()) {
LOG(WARNING) << __func__
- << ": Cannot match with preferred context settings";
+ << ": Cannot match with preferred context settings - "
+ "non-exact match";
result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
- in_requirements);
- if (result.empty())
- LOG(WARNING) << __func__
- << ": Cannot match with non preferred context settings";
+ in_requirements, false);
}
+ if (result.empty())
+ LOG(ERROR) << __func__
+ << ": Cannot match with non preferred context settings - "
+ "non-exact match";
*_aidl_return = result;
return ndk::ScopedAStatus::ok();
};
@@ -811,7 +839,8 @@
uint8_t direction,
const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
qosRequirement,
- std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings) {
+ std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings,
+ bool is_exact) {
std::optional<AseQosDirectionRequirement> direction_qos_requirement =
std::nullopt;
@@ -877,8 +906,8 @@
int qos_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
direction_qos_requirement.value().aseConfiguration);
// Get the best matching config based on channel allocation
- auto req_valid_configs =
- getValidConfigurationsFromAllocation(qos_allocation_bitmask, temp);
+ auto req_valid_configs = getValidConfigurationsFromAllocation(
+ qos_allocation_bitmask, temp, is_exact);
if (req_valid_configs.empty()) {
LOG(WARNING) << __func__
<< ": Cannot find matching allocation for bitmask "
@@ -908,15 +937,30 @@
if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
if (!isValidQosRequirement(in_qosRequirement.sinkAseQosRequirement.value()))
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
- result.sinkQosConfiguration = getDirectionQosConfiguration(
- kLeAudioDirectionSink, in_qosRequirement, ase_configuration_settings);
+ {
+ // Try exact match first
+ result.sinkQosConfiguration =
+ getDirectionQosConfiguration(kLeAudioDirectionSink, in_qosRequirement,
+ ase_configuration_settings, true);
+ if (!result.sinkQosConfiguration.has_value()) {
+ result.sinkQosConfiguration = getDirectionQosConfiguration(
+ kLeAudioDirectionSink, in_qosRequirement,
+ ase_configuration_settings, false);
+ }
+ }
}
if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
if (!isValidQosRequirement(
in_qosRequirement.sourceAseQosRequirement.value()))
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
- result.sourceQosConfiguration = getDirectionQosConfiguration(
- kLeAudioDirectionSource, in_qosRequirement, ase_configuration_settings);
+ result.sourceQosConfiguration =
+ getDirectionQosConfiguration(kLeAudioDirectionSource, in_qosRequirement,
+ ase_configuration_settings, true);
+ if (!result.sourceQosConfiguration.has_value()) {
+ result.sourceQosConfiguration = getDirectionQosConfiguration(
+ kLeAudioDirectionSource, in_qosRequirement,
+ ase_configuration_settings, false);
+ }
}
*_aidl_return = result;
@@ -941,28 +985,127 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
};
+LeAudioBroadcastConfigurationSetting getDefaultBroadcastSetting(
+ int context_bitmask, IBluetoothAudioProvider::BroadcastQuality quality) {
+ LeAudioBroadcastConfigurationSetting setting;
+ setting.retransmitionNum = 4;
+ setting.maxTransportLatencyMs = 60;
+ setting.sduIntervalUs = 10000;
+ setting.maxSduOctets = 40;
+
+ if (quality == IBluetoothAudioProvider::BroadcastQuality::HIGH) {
+ LOG(INFO) << __func__ << ": High quality, returning high quality settings";
+ setting.retransmitionNum = 4;
+ setting.maxTransportLatencyMs = 65;
+ setting.maxSduOctets = 200;
+ return setting;
+ }
+
+ // Populate other settings base on context
+ // TODO: Populate with better design
+ if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME)) {
+ setting.retransmitionNum = 2;
+ setting.maxTransportLatencyMs = 10;
+ setting.maxSduOctets = 120;
+ } else if (context_bitmask & (AudioContext::INSTRUCTIONAL)) {
+ setting.retransmitionNum = 2;
+ setting.maxTransportLatencyMs = 10;
+ setting.maxSduOctets = 40;
+ } else if (context_bitmask &
+ (AudioContext::SOUND_EFFECTS | AudioContext::UNSPECIFIED)) {
+ setting.retransmitionNum = 4;
+ setting.maxTransportLatencyMs = 60;
+ setting.maxSduOctets = 80;
+ } else if (context_bitmask &
+ (AudioContext::ALERTS | AudioContext::NOTIFICATIONS |
+ AudioContext::EMERGENCY_ALARM)) {
+ setting.retransmitionNum = 4;
+ setting.maxTransportLatencyMs = 60;
+ setting.maxSduOctets = 40;
+ } else if (context_bitmask & AudioContext::MEDIA) {
+ setting.retransmitionNum = 4;
+ setting.maxTransportLatencyMs = 60;
+ setting.maxSduOctets = 120;
+ }
+
+ return setting;
+}
+void modifySubBISConfigAllocation(
+ IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration& sub_bis_cfg,
+ int allocation_bitmask) {
+ for (auto& codec_cfg : sub_bis_cfg.bisConfiguration.codecConfiguration) {
+ if (codec_cfg.getTag() ==
+ CodecSpecificConfigurationLtv::audioChannelAllocation) {
+ codec_cfg.get<CodecSpecificConfigurationLtv::audioChannelAllocation>()
+ .bitmask = allocation_bitmask;
+ break;
+ }
+ }
+}
+void modifySubgroupConfiguration(
+ IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration&
+ subgroup_cfg,
+ int context_bitmask) {
+ // STEREO configs
+ // Split into 2 sub BIS config, each has numBis = 1
+ if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME |
+ AudioContext::SOUND_EFFECTS |
+ AudioContext::UNSPECIFIED | AudioContext::MEDIA)) {
+ if (subgroup_cfg.bisConfigurations.size() == 1)
+ subgroup_cfg.bisConfigurations.push_back(
+ subgroup_cfg.bisConfigurations[0]);
+
+ subgroup_cfg.bisConfigurations[0].numBis = 1;
+ modifySubBISConfigAllocation(
+ subgroup_cfg.bisConfigurations[0],
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT);
+
+ subgroup_cfg.bisConfigurations[1].numBis = 1;
+ modifySubBISConfigAllocation(
+ subgroup_cfg.bisConfigurations[1],
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT);
+ return;
+ }
+
+ // MONO configs
+ for (auto& sub_bis_cfg : subgroup_cfg.bisConfigurations) {
+ sub_bis_cfg.numBis = 1;
+ modifySubBISConfigAllocation(
+ sub_bis_cfg,
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER);
+ }
+}
+
void LeAudioOffloadAudioProvider::getBroadcastSettings() {
if (!broadcast_settings.empty()) return;
- LOG(INFO) << __func__ << ": Loading broadcast settings from provider info";
+ LOG(INFO) << __func__
+ << ": Loading basic broadcast settings from provider info";
std::vector<CodecInfo> db_codec_info =
BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+ for (auto x : db_codec_info) {
+ LOG(INFO) << __func__ << ": codec info = " << x.toString();
+ }
broadcast_settings.clear();
- // Default value for unmapped fields
+ // Default value population
CodecSpecificConfigurationLtv::AudioChannelAllocation default_allocation;
default_allocation.bitmask =
CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU default_frame;
- default_frame.value = 2;
+ default_frame.value = 1;
for (auto& codec_info : db_codec_info) {
if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
continue;
auto& transport = codec_info.transport.get<CodecInfo::Transport::leAudio>();
LeAudioBroadcastConfigurationSetting setting;
+ setting.retransmitionNum = 4;
+ setting.maxTransportLatencyMs = 60;
+ setting.sduIntervalUs = 10000;
+ setting.maxSduOctets = 40;
// Default setting
setting.numBis = 1;
setting.phy = {Phy::TWO_M};
@@ -981,13 +1124,15 @@
default_frame,
};
+ // Ignore bis_cfg.metadata
+
// Add information to structure
IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration sub_bis_cfg;
- sub_bis_cfg.numBis = 2;
+ sub_bis_cfg.numBis = 1;
sub_bis_cfg.bisConfiguration = bis_cfg;
IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration sub_cfg;
// Populate the same sub config
- sub_cfg.bisConfigurations = {sub_bis_cfg, sub_bis_cfg};
+ sub_cfg.bisConfigurations = {sub_bis_cfg};
setting.subgroupsConfigurations = {sub_cfg};
broadcast_settings.push_back(setting);
@@ -1031,34 +1176,91 @@
return filtered_setting;
}
+std::vector<CodecSpecificConfigurationLtv> getCodecRequirementBasedOnContext(
+ int context_bitmask, IBluetoothAudioProvider::BroadcastQuality quality) {
+ // Default requirement: lc3_stereo_16_2
+ std::vector<CodecSpecificConfigurationLtv> requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+
+ if (quality == IBluetoothAudioProvider::BroadcastQuality::HIGH) {
+ LOG(INFO) << __func__
+ << ": High quality, returning high quality requirement";
+ requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+ return requirement;
+ }
+
+ if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME)) {
+ // lc3_stereo_24_2_1
+ requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+ } else if (context_bitmask & (AudioContext::INSTRUCTIONAL)) {
+ // lc3_mono_16_2
+ requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+ } else if (context_bitmask &
+ (AudioContext::SOUND_EFFECTS | AudioContext::UNSPECIFIED)) {
+ // lc3_stereo_16_2
+ requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+ } else if (context_bitmask &
+ (AudioContext::ALERTS | AudioContext::NOTIFICATIONS |
+ AudioContext::EMERGENCY_ALARM)) {
+ // Default requirement: lc3_stereo_16_2
+ requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+ } else if (context_bitmask & AudioContext::MEDIA) {
+ // Default requirement: lc3_stereo_16_2
+ // Return the 48k requirement
+ requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+ }
+ return requirement;
+}
+
bool LeAudioOffloadAudioProvider::isSubgroupConfigurationMatchedContext(
- AudioContext setting_context,
+ AudioContext requirement_context,
+ IBluetoothAudioProvider::BroadcastQuality quality,
LeAudioBroadcastSubgroupConfiguration configuration) {
// Find any valid context metadata in the bisConfigurations
// assuming the bis configuration in the same bis subgroup
// will have the same context metadata
std::optional<AudioContext> config_context = std::nullopt;
- for (auto& p : configuration.bisConfigurations)
- if (p.bisConfiguration.metadata.has_value()) {
- bool is_context_found = false;
- for (auto& metadata : p.bisConfiguration.metadata.value()) {
- if (!metadata.has_value()) continue;
- if (metadata.value().getTag() ==
- MetadataLtv::Tag::preferredAudioContexts) {
- config_context = metadata.value()
- .get<MetadataLtv::Tag::preferredAudioContexts>()
- .values;
- is_context_found = true;
- break;
- }
- }
- if (is_context_found) break;
- }
+ auto codec_requirement =
+ getCodecRequirementBasedOnContext(requirement_context.bitmask, quality);
+ std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
+ req_tag_map;
+ for (auto x : codec_requirement) req_tag_map[x.getTag()] = x;
- // Not found context metadata in any of the bis configuration, assume matched
- if (!config_context.has_value()) return true;
- return (setting_context.bitmask & config_context.value().bitmask);
+ for (auto& bis_cfg : configuration.bisConfigurations) {
+ // Check every sub_bis_cfg to see which match
+ for (auto& x : bis_cfg.bisConfiguration.codecConfiguration) {
+ auto p = req_tag_map.find(x.getTag());
+ if (p == req_tag_map.end()) continue;
+ if (p->second != x) {
+ LOG(WARNING) << __func__ << ": does not match for context "
+ << requirement_context.toString()
+ << ", cfg = " << x.toString();
+ return false;
+ }
+ }
+ }
+ return true;
}
ndk::ScopedAStatus
@@ -1078,7 +1280,8 @@
// We will allow empty capability input, match all settings with requirements.
getBroadcastSettings();
std::vector<LeAudioBroadcastConfigurationSetting> filtered_settings;
- if (!in_remoteSinkAudioCapabilities.has_value()) {
+ if (!in_remoteSinkAudioCapabilities.has_value() ||
+ in_remoteSinkAudioCapabilities.value().empty()) {
LOG(INFO) << __func__ << ": Empty capability, get all broadcast settings";
filtered_settings = broadcast_settings;
} else {
@@ -1109,45 +1312,72 @@
// Gather these suitable subgroup config in an array.
// If the setting can satisfy all requirement, we can return the setting
// with the filtered array.
- for (auto& setting : filtered_settings) {
- LeAudioBroadcastConfigurationSetting matched_setting(setting);
- matched_setting.subgroupsConfigurations.clear();
- auto total_num_bis = 0;
- bool matched_all_requirement = true;
+ auto context_bitmask =
+ in_requirement.subgroupConfigurationRequirements[0].audioContext.bitmask;
+ auto quality = in_requirement.subgroupConfigurationRequirements[0].quality;
+ LeAudioBroadcastConfigurationSetting return_setting =
+ getDefaultBroadcastSetting(context_bitmask, quality);
+ // Default setting
+ return_setting.numBis = 0;
+ return_setting.subgroupsConfigurations = {};
- for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
- bool is_matched = false;
- for (auto& sub_cfg : setting.subgroupsConfigurations) {
- // Match the context
- if (!isSubgroupConfigurationMatchedContext(sub_req.audioContext,
- sub_cfg))
- continue;
- // Matching number of BIS
- if (sub_req.bisNumPerSubgroup != sub_cfg.bisConfigurations.size())
- continue;
- // Currently will ignore quality matching.
- matched_setting.subgroupsConfigurations.push_back(sub_cfg);
- total_num_bis += sub_cfg.bisConfigurations.size();
- is_matched = true;
- break;
+ LeAudioDataPathConfiguration path;
+ path.isoDataPathConfiguration.isTransparent = true;
+ path.dataPathId = kIsoDataPathPlatformDefault;
+
+ // Each subreq, find a setting that match
+ for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
+ bool is_setting_matched = false;
+ for (auto setting : filtered_settings) {
+ bool is_matched = true;
+ // Check if every sub BIS config satisfy
+ for (auto& sub_group_config : setting.subgroupsConfigurations) {
+ if (!isSubgroupConfigurationMatchedContext(
+ sub_req.audioContext, sub_req.quality, sub_group_config)) {
+ is_matched = false;
+ break;
+ }
+ path.isoDataPathConfiguration.codecId =
+ sub_group_config.bisConfigurations[0].bisConfiguration.codecId;
+ // Also modify the subgroup config to match the context
+ modifySubgroupConfiguration(sub_group_config, context_bitmask);
}
- // There is an unmatched requirement, this setting cannot be used
- if (!is_matched) {
- matched_all_requirement = false;
+
+ if (is_matched) {
+ is_setting_matched = true;
+ for (auto& sub_group_config : setting.subgroupsConfigurations)
+ return_setting.subgroupsConfigurations.push_back(sub_group_config);
break;
}
}
- if (!matched_all_requirement) continue;
-
- matched_setting.numBis = total_num_bis;
- // Return the filtered setting if all requirement satified
- *_aidl_return = matched_setting;
- return ndk::ScopedAStatus::ok();
+ if (!is_setting_matched) {
+ LOG(WARNING) << __func__
+ << ": Cannot find a setting that match requirement "
+ << sub_req.toString();
+ return ndk::ScopedAStatus::ok();
+ }
}
- LOG(WARNING) << __func__ << ": Cannot match any requirement";
+ // Populate all numBis
+ for (auto& sub_group_config : return_setting.subgroupsConfigurations) {
+ for (auto& sub_bis_config : sub_group_config.bisConfigurations) {
+ return_setting.numBis += sub_bis_config.numBis;
+ }
+ }
+ return_setting.phy = std::vector<Phy>(return_setting.numBis, Phy::TWO_M);
+ // Populate data path config
+ return_setting.dataPathConfiguration = path;
+ // TODO: Workaround for STEREO configs maxSduOctets being doubled
+ if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME |
+ AudioContext::SOUND_EFFECTS |
+ AudioContext::UNSPECIFIED | AudioContext::MEDIA)) {
+ return_setting.maxSduOctets /= 2;
+ }
+ LOG(INFO) << __func__
+ << ": Combined setting that match: " << return_setting.toString();
+ *_aidl_return = return_setting;
return ndk::ScopedAStatus::ok();
};
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index afa2efd..043d923 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -139,7 +139,8 @@
direction_configurations,
const std::vector<std::optional<AseDirectionRequirement>>& requirements,
std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
- valid_direction_configurations);
+ valid_direction_configurations,
+ bool is_exact);
std::optional<LeAudioAseConfigurationSetting>
getCapabilitiesMatchedAseConfigurationSettings(
IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
@@ -149,7 +150,8 @@
getRequirementMatchedAseConfigurationSettings(
IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
- requirement);
+ requirement,
+ bool is_exact);
bool isMatchedQosRequirement(LeAudioAseQosConfiguration setting_qos,
AseQosDirectionRequirement requirement_qos);
std::optional<LeAudioBroadcastConfigurationSetting>
@@ -161,9 +163,11 @@
uint8_t direction,
const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
qosRequirement,
- std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings);
+ std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings,
+ bool is_exact);
bool isSubgroupConfigurationMatchedContext(
AudioContext requirement_context,
+ IBluetoothAudioProvider::BroadcastQuality quality,
LeAudioBroadcastSubgroupConfiguration configuration);
std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
matchWithRequirement(
@@ -171,7 +175,8 @@
matched_ase_configuration_settings,
const std::vector<
IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
- in_requirements);
+ in_requirements,
+ bool is_exact);
};
class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {