Additional context matching logic for LEA multi-codec

When we match with the remote capabilities, we don't filter by
preferred audio context, since they are suggestion.

Instead, we populate settings into 2 separated vector:
- Matched settings with matched preferred context,
- Matched settings,

We then filter by the first vector, then by the second vector.

Bug: 306225778
Test: atest VtsHalBluetoothAudioTargetTest
Change-Id: I03f322e8de509127d218a9de6b41dd39b2ebdcba
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index 5002a1a..1f54e6c 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -175,12 +175,13 @@
     if (!metadata.has_value()) continue;
     if (metadata.value().getTag() == MetadataLtv::Tag::preferredAudioContexts) {
       // Check all pref audio context to see if anything matched
-      auto& context = metadata.value()
-                          .get<MetadataLtv::Tag::preferredAudioContexts>()
-                          .values;
-      if (setting_context.bitmask & context.bitmask) {
+      auto& prefer_context =
+          metadata.value()
+              .get<MetadataLtv::Tag::preferredAudioContexts>()
+              .values;
+      if (setting_context.bitmask & prefer_context.bitmask) {
         // New mask with matched capability
-        setting_context.bitmask &= context.bitmask;
+        setting_context.bitmask &= prefer_context.bitmask;
         return true;
       }
     }
@@ -219,8 +220,9 @@
     /*cfg_channel*/,
     CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
     /*capability_channel*/) {
+  // Simply ignore.
+  // Later can use additional capabilities to match requirement.
   bool isMatched = true;
-  // TODO: how to match?
   return isMatched;
 }
 
@@ -317,22 +319,34 @@
   return true;
 }
 
-bool LeAudioOffloadAudioProvider::isMatchedAseConfiguration(
-    LeAudioAseConfiguration setting_cfg,
-    LeAudioAseConfiguration requirement_cfg) {
+bool isMonoConfig(
+    CodecSpecificConfigurationLtv::AudioChannelAllocation allocation) {
+  auto channel_count = std::bitset<32>(allocation.bitmask);
+  return (channel_count.count() <= 1);
+}
+
+bool LeAudioOffloadAudioProvider::filterMatchedAseConfiguration(
+    LeAudioAseConfiguration& setting_cfg,
+    const LeAudioAseConfiguration& requirement_cfg) {
   // Check matching for codec configuration <=> requirement ASE codec
   // Also match if no CodecId requirement
   if (requirement_cfg.codecId.has_value()) {
     if (!setting_cfg.codecId.has_value()) return false;
     if (!isMatchedValidCodec(setting_cfg.codecId.value(),
                              requirement_cfg.codecId.value())) {
+      LOG(WARNING) << __func__ << ": Doesn't match valid codec, cfg = "
+                   << setting_cfg.codecId.value().toString()
+                   << ", req = " << requirement_cfg.codecId.value().toString();
       return false;
     }
   }
 
-  if (requirement_cfg.targetLatency ==
-          LeAudioAseConfiguration::TargetLatency::UNDEFINED ||
+  if (requirement_cfg.targetLatency !=
+          LeAudioAseConfiguration::TargetLatency::UNDEFINED &&
       setting_cfg.targetLatency != requirement_cfg.targetLatency) {
+    LOG(WARNING) << __func__ << ": Doesn't match target latency, cfg = "
+                 << int(setting_cfg.targetLatency)
+                 << ", req = " << int(requirement_cfg.targetLatency);
     return false;
   }
   // Ignore PHY requirement
@@ -346,11 +360,24 @@
   for (auto requirement_cfg : requirement_cfg.codecConfiguration) {
     // Directly compare CodecSpecificConfigurationLtv
     auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
+    // Config not found for this requirement, cannot match
     if (cfg == cfg_tag_map.end()) {
+      LOG(WARNING) << __func__ << ": Config not found for the requirement "
+                   << requirement_cfg.toString();
       return false;
     }
 
+    // Ignore matching for audio channel allocation
+    // since the rule is complicated. Match outside instead
+    if (requirement_cfg.getTag() ==
+        CodecSpecificConfigurationLtv::Tag::audioChannelAllocation)
+      continue;
+
     if (cfg->second != requirement_cfg) {
+      LOG(WARNING) << __func__
+                   << ": Config doesn't match the requirement, cfg = "
+                   << cfg->second.toString()
+                   << ", req = " << requirement_cfg.toString();
       return false;
     }
   }
@@ -395,35 +422,132 @@
   }
 }
 
+int getLeAudioAseConfigurationAllocationBitmask(LeAudioAseConfiguration cfg) {
+  for (auto cfg_ltv : cfg.codecConfiguration) {
+    if (cfg_ltv.getTag() ==
+        CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
+      return cfg_ltv
+          .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+          .bitmask;
+    }
+  }
+  return 0;
+}
+
+int getCountFromBitmask(int bitmask) {
+  return std::bitset<32>(bitmask).count();
+}
+
+std::optional<AseDirectionConfiguration> findValidMonoConfig(
+    std::vector<AseDirectionConfiguration>& valid_direction_configurations,
+    int bitmask) {
+  for (auto& cfg : valid_direction_configurations) {
+    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() ==
+            CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
+          codec_cfg
+              .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+              .bitmask = bitmask;
+          return cfg;
+        }
+      }
+    }
+  }
+  return std::nullopt;
+}
+
+std::vector<AseDirectionConfiguration> getValidConfigurationsFromAllocation(
+    int req_allocation_bitmask,
+    std::vector<AseDirectionConfiguration>& valid_direction_configurations) {
+  // 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};
+    }
+  }
+  // No exact match found
+  if (channel_count <= 1) {
+    // Mono requirement matched if cfg is a mono config
+    auto cfg = findValidMonoConfig(valid_direction_configurations,
+                                   req_allocation_bitmask);
+    if (cfg.has_value()) return {cfg.value()};
+  } else {
+    // Stereo requirement returns 2 mono configs
+    // that has a combined bitmask equal to the stereo config
+    std::vector<AseDirectionConfiguration> temp;
+    for (int bit = 0; bit < 32; ++bit)
+      if (req_allocation_bitmask & (1 << bit)) {
+        auto cfg =
+            findValidMonoConfig(valid_direction_configurations, (1 << bit));
+        if (cfg.has_value()) temp.push_back(cfg.value());
+      }
+    if (temp.size() == channel_count) return temp;
+  }
+  return {};
+}
+
 void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
     std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
         direction_configurations,
     const std::vector<std::optional<AseDirectionRequirement>>& requirements,
     std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
         valid_direction_configurations) {
+  // For every requirement, find the matched ase configuration
+  if (!direction_configurations.has_value()) return;
+
   if (!valid_direction_configurations.has_value()) {
     valid_direction_configurations =
         std::vector<std::optional<AseDirectionConfiguration>>();
   }
-  // For every requirement, find the matched ase configuration
-  if (!direction_configurations.has_value()) return;
+
   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);
+
+    auto temp = std::vector<AseDirectionConfiguration>();
+
     for (auto direction_configuration : direction_configurations.value()) {
       if (!direction_configuration.has_value()) continue;
-      if (!isMatchedAseConfiguration(
+      if (!filterMatchedAseConfiguration(
               direction_configuration.value().aseConfiguration,
               requirement.value().aseConfiguration))
         continue;
       // Valid if match any requirement.
-      valid_direction_configurations.value().push_back(direction_configuration);
-      break;
+      temp.push_back(direction_configuration.value());
     }
-  }
-  // Ensure that each requirement will have one direction configurations
-  if (valid_direction_configurations.value().empty() ||
-      (valid_direction_configurations.value().size() != requirements.size())) {
-    valid_direction_configurations = std::nullopt;
+
+    // Get the best matching config based on channel allocation
+    auto total_cfg_channel_count = 0;
+    auto req_valid_configs =
+        getValidConfigurationsFromAllocation(req_allocation_bitmask, temp);
+    // Count and check required channel counts
+    for (auto& cfg : req_valid_configs) {
+      total_cfg_channel_count += getCountFromBitmask(
+          getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration));
+      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;
+    }
   }
 }
 
@@ -444,10 +568,6 @@
       .flags = setting.flags,
       .packing = setting.packing,
   };
-  // Try to match context in metadata.
-  if (!filterCapabilitiesMatchedContext(filtered_setting.audioContext,
-                                        capabilities))
-    return std::nullopt;
 
   // Get a list of all matched AseDirectionConfiguration
   // for the input direction
@@ -495,15 +615,11 @@
       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;
 
-  // Check requirement for the correct direction
-  const std::optional<std::vector<std::optional<AseDirectionRequirement>>>*
-      direction_requirement;
-  std::vector<std::optional<AseDirectionConfiguration>>*
-      direction_configuration;
-
   // Create a new LeAudioAseConfigurationSetting to return
   LeAudioAseConfigurationSetting filtered_setting{
       .audioContext = setting.audioContext,
@@ -515,7 +631,10 @@
     filterRequirementAseDirectionConfiguration(
         setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
         filtered_setting.sinkAseConfiguration);
-    if (!filtered_setting.sinkAseConfiguration.has_value()) return std::nullopt;
+    if (!filtered_setting.sinkAseConfiguration.has_value()) {
+      LOG(WARNING) << __func__ << "Setting's sink doesn't match!";
+      return std::nullopt;
+    }
   }
 
   if (requirement.sourceAseRequirement.has_value()) {
@@ -523,82 +642,21 @@
         setting.sourceAseConfiguration,
         requirement.sourceAseRequirement.value(),
         filtered_setting.sourceAseConfiguration);
-    if (!filtered_setting.sourceAseConfiguration.has_value())
+    if (!filtered_setting.sourceAseConfiguration.has_value()) {
+      LOG(WARNING) << __func__ << "Setting's source doesn't match!";
       return std::nullopt;
+    }
   }
 
   return filtered_setting;
 }
 
-// For each requirement, a valid ASE configuration will satify:
-// - matched with any sink capability (if presented)
-// - OR matched with any source capability (if presented)
-// - and the setting need to pass the requirement
-ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
-    const std::optional<std::vector<
-        std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
-        in_remoteSinkAudioCapabilities,
-    const std::optional<std::vector<
-        std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
-        in_remoteSourceAudioCapabilities,
+std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+LeAudioOffloadAudioProvider::matchWithRequirement(
+    std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
+        matched_ase_configuration_settings,
     const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
-        in_requirements,
-    std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
-        _aidl_return) {
-  // Get all configuration settings
-  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
-      ase_configuration_settings =
-          BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
-
-  if (!in_remoteSinkAudioCapabilities.has_value() &&
-      !in_remoteSourceAudioCapabilities.has_value()) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
-  }
-
-  // Each setting consist of source and sink AseDirectionConfiguration vector
-  // Filter every sink capability
-  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
-      matched_ase_configuration_settings;
-
-  if (in_remoteSinkAudioCapabilities.has_value()) {
-    // Matching each setting with any remote capabilities
-    for (auto& setting : ase_configuration_settings) {
-      for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
-        if (!capability.has_value()) continue;
-        auto filtered_ase_configuration_setting =
-            getCapabilitiesMatchedAseConfigurationSettings(
-                setting, capability.value(), kLeAudioDirectionSink);
-        if (filtered_ase_configuration_setting.has_value()) {
-          matched_ase_configuration_settings.push_back(
-              filtered_ase_configuration_setting.value());
-        }
-      }
-    }
-  }
-
-  // Combine filter every source capability
-  if (in_remoteSourceAudioCapabilities.has_value()) {
-    // Matching each setting with any remote capabilities
-    for (auto& setting : ase_configuration_settings) {
-      for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
-        if (!capability.has_value()) continue;
-        auto filtered_ase_configuration_setting =
-            getCapabilitiesMatchedAseConfigurationSettings(
-                setting, capability.value(), kLeAudioDirectionSource);
-        if (filtered_ase_configuration_setting.has_value()) {
-          // Put into the same list
-          // possibly duplicated, filtered by requirement later
-          matched_ase_configuration_settings.push_back(
-              filtered_ase_configuration_setting.value());
-        }
-      }
-    }
-  }
-
-  if (matched_ase_configuration_settings.empty()) {
-    LOG(WARNING) << __func__ << ": No setting matched the capability";
-    return ndk::ScopedAStatus::ok();
-  }
+        in_requirements) {
   // Each requirement will match with a valid setting
   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
   for (auto& requirement : in_requirements) {
@@ -626,7 +684,103 @@
       break;
     }
   }
+  return result;
+}
 
+// For each requirement, a valid ASE configuration will satify:
+// - matched with any sink capability (if presented)
+// - OR matched with any source capability (if presented)
+// - and the setting need to pass the requirement
+ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
+    const std::optional<std::vector<
+        std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+        in_remoteSinkAudioCapabilities,
+    const std::optional<std::vector<
+        std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
+        in_remoteSourceAudioCapabilities,
+    const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
+        in_requirements,
+    std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
+        _aidl_return) {
+  // Get all configuration settings
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+      ase_configuration_settings =
+          BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
+
+  if (!in_remoteSinkAudioCapabilities.has_value() &&
+      !in_remoteSourceAudioCapabilities.has_value()) {
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+  }
+
+  // Split out preferred and non-preferred settings based on context
+  // An example: preferred = MEDIA, available: MEDIA | CONVERSATION
+  // -> preferred list will have settings with MEDIA context
+  // -> non-preferred list will have settings with any context
+  // We want to match requirement with preferred context settings first
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+      matched_ase_configuration_settings;
+  // Matched ASE configuration with non-preferred audio context
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+      non_prefer_matched_ase_configuration_settings;
+
+  if (in_remoteSinkAudioCapabilities.has_value())
+    // Matching each setting with any remote capabilities
+    for (auto& setting : ase_configuration_settings)
+      for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
+        if (!capability.has_value()) continue;
+        auto filtered_ase_configuration_setting =
+            getCapabilitiesMatchedAseConfigurationSettings(
+                setting, capability.value(), kLeAudioDirectionSink);
+        if (filtered_ase_configuration_setting.has_value()) {
+          // Push to non-prefer first for the broadest matching possible
+          non_prefer_matched_ase_configuration_settings.push_back(
+              filtered_ase_configuration_setting.value());
+          // Try to filter out prefer context to another vector.
+          if (filterCapabilitiesMatchedContext(
+                  filtered_ase_configuration_setting.value().audioContext,
+                  capability.value())) {
+            matched_ase_configuration_settings.push_back(
+                filtered_ase_configuration_setting.value());
+          }
+        }
+      }
+
+  // Combine filter every source capability
+  if (in_remoteSourceAudioCapabilities.has_value())
+    // Matching each setting with any remote capabilities
+    for (auto& setting : ase_configuration_settings)
+      for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
+        if (!capability.has_value()) continue;
+        auto filtered_ase_configuration_setting =
+            getCapabilitiesMatchedAseConfigurationSettings(
+                setting, capability.value(), kLeAudioDirectionSource);
+        if (filtered_ase_configuration_setting.has_value()) {
+          // Put into the same list
+          // possibly duplicated, filtered by requirement later
+          // Push to non-prefer first for the broadest matching possible
+          non_prefer_matched_ase_configuration_settings.push_back(
+              filtered_ase_configuration_setting.value());
+          // Try to filter out prefer context to another vector.
+          if (filterCapabilitiesMatchedContext(
+                  filtered_ase_configuration_setting.value().audioContext,
+                  capability.value())) {
+            matched_ase_configuration_settings.push_back(
+                filtered_ase_configuration_setting.value());
+          }
+        }
+      }
+
+  auto result =
+      matchWithRequirement(matched_ase_configuration_settings, in_requirements);
+  if (result.empty()) {
+    LOG(WARNING) << __func__
+                 << ": Cannot match with preferred context settings";
+    result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
+                                  in_requirements);
+    if (result.empty())
+      LOG(WARNING) << __func__
+                   << ": Cannot match with non preferred context settings";
+  }
   *_aidl_return = result;
   return ndk::ScopedAStatus::ok();
 };
@@ -642,7 +796,6 @@
       requirement_qos.maxTransportLatencyMs) {
     return false;
   }
-  // Ignore other parameters, as they are not populated in the setting_qos
   return true;
 }
 
@@ -680,17 +833,26 @@
 
     // Get a list of all matched AseDirectionConfiguration
     // for the input direction
-    std::vector<std::optional<AseDirectionConfiguration>>*
-        direction_configuration = nullptr;
+    std::optional<std::vector<std::optional<AseDirectionConfiguration>>>
+        direction_configuration = std::nullopt;
     if (direction == kLeAudioDirectionSink) {
       if (!setting.sinkAseConfiguration.has_value()) continue;
-      direction_configuration = &setting.sinkAseConfiguration.value();
+      direction_configuration.emplace(setting.sinkAseConfiguration.value());
     } else {
       if (!setting.sourceAseConfiguration.has_value()) continue;
-      direction_configuration = &setting.sourceAseConfiguration.value();
+      direction_configuration.emplace(setting.sourceAseConfiguration.value());
     }
 
-    for (auto cfg : *direction_configuration) {
+    if (!direction_configuration.has_value()) {
+      return std::nullopt;
+    }
+
+    // Collect all valid cfg into a vector
+    // Then try to get the best match for audio allocation
+
+    auto temp = std::vector<AseDirectionConfiguration>();
+
+    for (auto& cfg : direction_configuration.value()) {
       if (!cfg.has_value()) continue;
       // If no requirement, return the first QoS
       if (!direction_qos_requirement.has_value()) {
@@ -701,14 +863,30 @@
       // Try to match the ASE configuration
       // and QoS with requirement
       if (!cfg.value().qosConfiguration.has_value()) continue;
-      if (isMatchedAseConfiguration(
+      if (filterMatchedAseConfiguration(
               cfg.value().aseConfiguration,
               direction_qos_requirement.value().aseConfiguration) &&
           isMatchedQosRequirement(cfg.value().qosConfiguration.value(),
                                   direction_qos_requirement.value())) {
-        return cfg.value().qosConfiguration;
+        temp.push_back(cfg.value());
       }
     }
+    LOG(WARNING) << __func__ << ": Got " << temp.size()
+                 << " configs, start matching allocation";
+
+    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);
+    if (req_valid_configs.empty()) {
+      LOG(WARNING) << __func__
+                   << ": Cannot find matching allocation for bitmask "
+                   << qos_allocation_bitmask;
+
+    } else {
+      return req_valid_configs[0].qosConfiguration;
+    }
   }
 
   return std::nullopt;
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index 06cd405..afa2efd 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -122,8 +122,9 @@
   bool isCapabilitiesMatchedCodecConfiguration(
       std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
       std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities);
-  bool isMatchedAseConfiguration(LeAudioAseConfiguration setting_cfg,
-                                 LeAudioAseConfiguration requirement_cfg);
+  bool filterMatchedAseConfiguration(
+      LeAudioAseConfiguration& setting_cfg,
+      const LeAudioAseConfiguration& requirement_cfg);
   bool isMatchedBISConfiguration(
       LeAudioBisConfiguration bis_cfg,
       const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
@@ -164,6 +165,13 @@
   bool isSubgroupConfigurationMatchedContext(
       AudioContext requirement_context,
       LeAudioBroadcastSubgroupConfiguration configuration);
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+  matchWithRequirement(
+      std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
+          matched_ase_configuration_settings,
+      const std::vector<
+          IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
+          in_requirements);
 };
 
 class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index ec63831..66cca0b 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -4177,6 +4177,7 @@
         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
     sampling_rate.bitmask =
         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ48000 |
+        CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ24000 |
         CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000;
     auto frame_duration =
         CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
index 5429a8f..780154a 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
@@ -267,7 +267,7 @@
     ase_configuration_settings_.clear();
     configurations_.clear();
     auto loaded = LoadContent(kLeAudioSetConfigs, kLeAudioSetScenarios,
-                              CodecLocation::HOST);
+                              CodecLocation::ADSP);
     if (!loaded)
       LOG(ERROR) << ": Unable to load le audio set configuration files.";
   } else
@@ -371,7 +371,6 @@
       CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU();
   frame_sdu_structure.value = codec_frames_blocks_per_sdu;
   ase.codecConfiguration.push_back(frame_sdu_structure);
-  // TODO: Channel count
 }
 
 void AudioSetConfigurationProviderJson::populateAseConfiguration(
@@ -415,8 +414,53 @@
 }
 
 void AudioSetConfigurationProviderJson::populateAseQosConfiguration(
-    LeAudioAseQosConfiguration& qos,
-    const le_audio::QosConfiguration* qos_cfg) {
+    LeAudioAseQosConfiguration& qos, const le_audio::QosConfiguration* qos_cfg,
+    LeAudioAseConfiguration& ase) {
+  std::optional<CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU>
+      frameBlock = std::nullopt;
+  std::optional<CodecSpecificConfigurationLtv::FrameDuration> frameDuration =
+      std::nullopt;
+  std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>
+      allocation = std::nullopt;
+  std::optional<CodecSpecificConfigurationLtv::OctetsPerCodecFrame> octet =
+      std::nullopt;
+
+  for (auto& cfg_ltv : ase.codecConfiguration) {
+    auto tag = cfg_ltv.getTag();
+    if (tag == CodecSpecificConfigurationLtv::codecFrameBlocksPerSDU) {
+      frameBlock =
+          cfg_ltv.get<CodecSpecificConfigurationLtv::codecFrameBlocksPerSDU>();
+    } else if (tag == CodecSpecificConfigurationLtv::frameDuration) {
+      frameDuration =
+          cfg_ltv.get<CodecSpecificConfigurationLtv::frameDuration>();
+    } else if (tag == CodecSpecificConfigurationLtv::audioChannelAllocation) {
+      allocation =
+          cfg_ltv.get<CodecSpecificConfigurationLtv::audioChannelAllocation>();
+    } else if (tag == CodecSpecificConfigurationLtv::octetsPerCodecFrame) {
+      octet = cfg_ltv.get<CodecSpecificConfigurationLtv::octetsPerCodecFrame>();
+    }
+  }
+
+  int frameBlockValue = 1;
+  if (frameBlock.has_value()) frameBlockValue = frameBlock.value().value;
+
+  // Populate maxSdu
+  if (allocation.has_value() && octet.has_value()) {
+    auto channel_count = std::bitset<32>(allocation.value().bitmask).count();
+    qos.maxSdu = channel_count * octet.value().value * frameBlockValue;
+  }
+  // Populate sduIntervalUs
+  if (frameDuration.has_value()) {
+    switch (frameDuration.value()) {
+      case CodecSpecificConfigurationLtv::FrameDuration::US7500:
+        qos.sduIntervalUs = 7500;
+        break;
+      case CodecSpecificConfigurationLtv::FrameDuration::US10000:
+        qos.sduIntervalUs = 10000;
+        break;
+    }
+    qos.sduIntervalUs *= frameBlockValue;
+  }
   qos.maxTransportLatencyMs = qos_cfg->max_transport_latency();
   qos.retransmissionNum = qos_cfg->retransmission_number();
 }
@@ -436,7 +480,7 @@
   populateAseConfiguration(ase, flat_subconfig, qos_cfg);
 
   // Translate into LeAudioAseQosConfiguration
-  populateAseQosConfiguration(qos, qos_cfg);
+  populateAseQosConfiguration(qos, qos_cfg, ase);
 
   // Translate location to data path id
   switch (location) {
@@ -453,6 +497,8 @@
       path.dataPathId = kIsoDataPathPlatformDefault;
       break;
   }
+  // Move codecId to iso data path
+  path.isoDataPathConfiguration.codecId = ase.codecId.value();
 
   direction_conf.aseConfiguration = ase;
   direction_conf.qosConfiguration = qos;
@@ -678,7 +724,8 @@
   media_context.bitmask =
       (AudioContext::ALERTS | AudioContext::INSTRUCTIONAL |
        AudioContext::NOTIFICATIONS | AudioContext::EMERGENCY_ALARM |
-       AudioContext::UNSPECIFIED | AudioContext::MEDIA);
+       AudioContext::UNSPECIFIED | AudioContext::MEDIA |
+       AudioContext::SOUND_EFFECTS);
 
   AudioContext conversational_context = AudioContext();
   conversational_context.bitmask =
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
index ce91fca..6639009 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
@@ -79,7 +79,7 @@
 
   static void populateAseQosConfiguration(
       LeAudioAseQosConfiguration& qos,
-      const le_audio::QosConfiguration* qos_cfg);
+      const le_audio::QosConfiguration* qos_cfg, LeAudioAseConfiguration& ase);
 
   static AseDirectionConfiguration SetConfigurationFromFlatSubconfig(
       const le_audio::AudioSetSubConfiguration* flat_subconfig,