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 {