summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBao Do <quocbaodo@google.com>2023-12-14 03:01:09 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-12-14 03:01:09 +0000
commite44972d2f256dc812adb7e2a30d51ebfafe0ef35 (patch)
treeb762596de2058b6127f88177f9849850c8fa062d
parent55718123bab331ac7da3a79572c7bf3f80c616b8 (diff)
parentb448b9c84ced01b96f4a6d443d9b990509ae3a27 (diff)
downloadinterfaces-e44972d2f256dc812adb7e2a30d51ebfafe0ef35.tar.gz
Default implementation of getLeAudioAseConfiguration am: 867af60a77 am: bf3e0f9b53 am: b448b9c84c
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2836201 Change-Id: Ia744b52dda52d7b64336ed42a9dfa381e4bafb25 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp413
-rw-r--r--bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h7
2 files changed, 410 insertions, 10 deletions
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index 91ede92667..406856896c 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -28,6 +28,60 @@ namespace hardware {
namespace bluetooth {
namespace audio {
+constexpr uint8_t kLeAudioDirectionSink = 0x01;
+constexpr uint8_t kLeAudioDirectionSource = 0x02;
+
+const std::map<CodecSpecificConfigurationLtv::SamplingFrequency, uint32_t>
+ freq_to_support_bitmask_map = {
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000},
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ11025},
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000},
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ22050,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ22050},
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ24000},
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ32000,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ32000},
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ48000},
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ88200,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ88200},
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ96000},
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ176400,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ176400},
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ192000,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ192000},
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ384000,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ384000},
+};
+
+// Helper map from capability's tag to configuration's tag
+std::map<CodecSpecificCapabilitiesLtv::Tag, CodecSpecificConfigurationLtv::Tag>
+ cap_to_cfg_tag_map = {
+ {CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies,
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency},
+ {CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU,
+ CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU},
+ {CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations,
+ CodecSpecificConfigurationLtv::Tag::frameDuration},
+ {CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation},
+ {CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame,
+ CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame},
+};
+
+const std::map<CodecSpecificConfigurationLtv::FrameDuration, uint32_t>
+ fduration_to_support_fduration_map = {
+ {CodecSpecificConfigurationLtv::FrameDuration::US7500,
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500},
+ {CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000},
+};
+
LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
: LeAudioOffloadAudioProvider() {
session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
@@ -87,6 +141,310 @@ ndk::ScopedAStatus LeAudioOffloadAudioProvider::setCodecPriority(
return ndk::ScopedAStatus::ok();
};
+bool LeAudioOffloadAudioProvider::isMatchedValidCodec(CodecId cfg_codec,
+ CodecId req_codec) {
+ auto priority = codec_priority_map_.find(cfg_codec);
+ if (priority != codec_priority_map_.end() && priority->second == -1)
+ return false;
+ return cfg_codec == req_codec;
+}
+
+bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedContext(
+ AudioContext setting_context,
+ const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
+ // If has no metadata, assume match
+ if (!capabilities.metadata.has_value()) return true;
+
+ for (auto metadata : capabilities.metadata.value()) {
+ 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) return true;
+ }
+ }
+
+ return false;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedSamplingFreq(
+ CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
+ capability_freq) {
+ for (auto [freq, bitmask] : freq_to_support_bitmask_map)
+ if (cfg_freq == freq) return (capability_freq.bitmask & bitmask);
+ return false;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedFrameDuration(
+ CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
+ capability_fduration) {
+ for (auto [fduration, bitmask] : fduration_to_support_fduration_map)
+ if (cfg_fduration == fduration)
+ return (capability_fduration.bitmask & bitmask);
+ return false;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedAudioChannel(
+ CodecSpecificConfigurationLtv::AudioChannelAllocation&
+ /*cfg_channel*/,
+ CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
+ /*capability_channel*/) {
+ bool isMatched = true;
+ // TODO: how to match?
+ return isMatched;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedCodecFramesPerSDU(
+ CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU& cfg_frame_sdu,
+ CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU&
+ capability_frame_sdu) {
+ return cfg_frame_sdu.value <= capability_frame_sdu.value;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedOctetsPerCodecFrame(
+ CodecSpecificConfigurationLtv::OctetsPerCodecFrame& cfg_octets,
+ CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame&
+ capability_octets) {
+ return cfg_octets.value >= capability_octets.minimum &&
+ cfg_octets.value <= capability_octets.maximum;
+}
+
+bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedCodecConfiguration(
+ std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
+ std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities) {
+ // Convert all codec_cfg into a map of tags -> correct data
+ std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
+ cfg_tag_map;
+ for (auto codec_cfg_data : codec_cfg)
+ cfg_tag_map[codec_cfg_data.getTag()] = codec_cfg_data;
+
+ for (auto& codec_capability : codec_capabilities) {
+ auto cfg = cfg_tag_map.find(cap_to_cfg_tag_map[codec_capability.getTag()]);
+ // Cannot find tag for the capability:
+ if (cfg == cfg_tag_map.end()) return false;
+
+ // Matching logic for sampling frequency
+ if (codec_capability.getTag() ==
+ CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies) {
+ if (!isMatchedSamplingFreq(
+ cfg->second
+ .get<CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedSamplingFrequencies>()))
+ return false;
+ } else if (codec_capability.getTag() ==
+ CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations) {
+ if (!isMatchedFrameDuration(
+ cfg->second
+ .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedFrameDurations>()))
+ return false;
+ } else if (codec_capability.getTag() ==
+ CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts) {
+ if (!isMatchedAudioChannel(
+ cfg->second.get<
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedAudioChannelCounts>()))
+ return false;
+ } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag::
+ supportedMaxCodecFramesPerSDU) {
+ if (!isMatchedCodecFramesPerSDU(
+ cfg->second.get<
+ CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedMaxCodecFramesPerSDU>()))
+ return false;
+ } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag::
+ supportedOctetsPerCodecFrame) {
+ if (!isMatchedOctetsPerCodecFrame(
+ cfg->second.get<
+ CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedOctetsPerCodecFrame>()))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool LeAudioOffloadAudioProvider::isMatchedAseConfiguration(
+ LeAudioAseConfiguration setting_cfg,
+ 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()))
+ return false;
+ }
+
+ if (setting_cfg.targetLatency != requirement_cfg.targetLatency) return false;
+ // Ignore PHY requirement
+
+ // Check all codec configuration
+ std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
+ cfg_tag_map;
+ for (auto cfg : setting_cfg.codecConfiguration)
+ cfg_tag_map[cfg.getTag()] = cfg;
+
+ for (auto requirement_cfg : requirement_cfg.codecConfiguration) {
+ // Directly compare CodecSpecificConfigurationLtv
+ auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
+ if (cfg == cfg_tag_map.end()) return false;
+
+ if (cfg->second != requirement_cfg) return false;
+ }
+ // Ignore vendor configuration and metadata requirement
+
+ return true;
+}
+
+void LeAudioOffloadAudioProvider::filterCapabilitiesAseDirectionConfiguration(
+ std::vector<std::optional<AseDirectionConfiguration>>&
+ direction_configurations,
+ const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
+ std::vector<std::optional<AseDirectionConfiguration>>&
+ valid_direction_configurations) {
+ for (auto direction_configuration : direction_configurations) {
+ if (!direction_configuration.has_value()) continue;
+ if (!direction_configuration.value().aseConfiguration.codecId.has_value())
+ continue;
+ if (!isMatchedValidCodec(
+ direction_configuration.value().aseConfiguration.codecId.value(),
+ capabilities.codecId))
+ continue;
+ // Check matching for codec configuration <=> codec capabilities
+ if (!isCapabilitiesMatchedCodecConfiguration(
+ direction_configuration.value().aseConfiguration.codecConfiguration,
+ capabilities.codecSpecificCapabilities))
+ continue;
+ valid_direction_configurations.push_back(direction_configuration);
+ }
+}
+
+void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
+ std::vector<std::optional<AseDirectionConfiguration>>&
+ direction_configurations,
+ const std::optional<std::vector<std::optional<AseDirectionRequirement>>>&
+ requirements,
+ std::vector<std::optional<AseDirectionConfiguration>>&
+ valid_direction_configurations) {
+ for (auto direction_configuration : direction_configurations) {
+ if (!requirements.has_value()) {
+ // If there's no requirement, all are valid
+ valid_direction_configurations.push_back(direction_configuration);
+ continue;
+ }
+ if (!direction_configuration.has_value()) continue;
+
+ for (auto& requirement : requirements.value()) {
+ if (!requirement.has_value()) continue;
+ if (!isMatchedAseConfiguration(
+ direction_configuration.value().aseConfiguration,
+ requirement.value().aseConfiguration))
+ continue;
+ // Valid if match any requirement.
+ valid_direction_configurations.push_back(direction_configuration);
+ break;
+ }
+ }
+}
+
+/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
+ * capabilities. The new setting will have a filtered list of
+ * AseDirectionConfiguration that matched the capabilities */
+std::optional<LeAudioAseConfigurationSetting>
+LeAudioOffloadAudioProvider::getCapabilitiesMatchedAseConfigurationSettings(
+ IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
+ const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
+ uint8_t direction) {
+ // Try to match context in metadata.
+ if (!isCapabilitiesMatchedContext(setting.audioContext, capabilities))
+ return std::nullopt;
+
+ // Get a list of all matched AseDirectionConfiguration
+ // for the input direction
+ std::vector<std::optional<AseDirectionConfiguration>>*
+ direction_configuration = nullptr;
+ if (direction == kLeAudioDirectionSink) {
+ if (!setting.sinkAseConfiguration.has_value()) return std::nullopt;
+ direction_configuration = &setting.sinkAseConfiguration.value();
+ } else {
+ if (!setting.sourceAseConfiguration.has_value()) return std::nullopt;
+ direction_configuration = &setting.sourceAseConfiguration.value();
+ }
+ std::vector<std::optional<AseDirectionConfiguration>>
+ valid_direction_configuration;
+ filterCapabilitiesAseDirectionConfiguration(
+ *direction_configuration, capabilities, valid_direction_configuration);
+ if (valid_direction_configuration.empty()) return std::nullopt;
+
+ // Create a new LeAudioAseConfigurationSetting and return
+ LeAudioAseConfigurationSetting filtered_setting;
+ filtered_setting.audioContext = setting.audioContext;
+ filtered_setting.packing = setting.packing;
+ if (direction == kLeAudioDirectionSink) {
+ filtered_setting.sinkAseConfiguration = valid_direction_configuration;
+ } else {
+ filtered_setting.sourceAseConfiguration = valid_direction_configuration;
+ }
+ filtered_setting.flags = setting.flags;
+
+ return filtered_setting;
+}
+
+/* Get a new LeAudioAseConfigurationSetting by matching a setting with a
+ * requirement. The new setting will have a filtered list of
+ * AseDirectionConfiguration that matched the requirement */
+std::optional<LeAudioAseConfigurationSetting>
+LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
+ IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
+ const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
+ requirement) {
+ // Try to match context in metadata.
+ if (setting.audioContext != requirement.audioContext) return std::nullopt;
+
+ // Check requirement for the correct direction
+ const std::optional<std::vector<std::optional<AseDirectionRequirement>>>*
+ direction_requirement;
+ std::vector<std::optional<AseDirectionConfiguration>>*
+ direction_configuration;
+ if (setting.sinkAseConfiguration.has_value()) {
+ direction_configuration = &setting.sinkAseConfiguration.value();
+ direction_requirement = &requirement.sinkAseRequirement;
+ } else {
+ direction_configuration = &setting.sourceAseConfiguration.value();
+ direction_requirement = &requirement.sourceAseRequirement;
+ }
+
+ std::vector<std::optional<AseDirectionConfiguration>>
+ valid_direction_configuration;
+ filterRequirementAseDirectionConfiguration(*direction_configuration,
+ *direction_requirement,
+ valid_direction_configuration);
+ if (valid_direction_configuration.empty()) return std::nullopt;
+
+ // Create a new LeAudioAseConfigurationSetting and return
+ LeAudioAseConfigurationSetting filtered_setting;
+ filtered_setting.audioContext = setting.audioContext;
+ filtered_setting.packing = setting.packing;
+ if (setting.sinkAseConfiguration.has_value())
+ filtered_setting.sinkAseConfiguration = valid_direction_configuration;
+ else
+ filtered_setting.sourceAseConfiguration = valid_direction_configuration;
+ filtered_setting.flags = setting.flags;
+
+ return filtered_setting;
+}
+
ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
const std::optional<std::vector<
std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
@@ -98,12 +456,55 @@ ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
in_requirements,
std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>*
_aidl_return) {
- /* TODO: Implement */
- (void)in_remoteSinkAudioCapabilities;
- (void)in_remoteSourceAudioCapabilities;
- (void)in_requirements;
- (void)_aidl_return;
- return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ // Get all configuration settings
+ std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+ ase_configuration_settings =
+ BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
+
+ // Currently won't handle case where both sink and source capabilities
+ // are passed in. Only handle one of them.
+ const std::optional<std::vector<
+ std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>*
+ in_remoteAudioCapabilities;
+ uint8_t direction = 0;
+ if (in_remoteSinkAudioCapabilities.has_value()) {
+ direction = kLeAudioDirectionSink;
+ in_remoteAudioCapabilities = &in_remoteSinkAudioCapabilities;
+ } else {
+ direction = kLeAudioDirectionSource;
+ in_remoteAudioCapabilities = &in_remoteSourceAudioCapabilities;
+ }
+
+ std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+ capability_matched_ase_configuration_settings;
+ // Matching with remote capabilities
+ for (auto& setting : ase_configuration_settings) {
+ for (auto& capability : in_remoteAudioCapabilities->value()) {
+ if (!capability.has_value()) continue;
+ auto filtered_ase_configuration_setting =
+ getCapabilitiesMatchedAseConfigurationSettings(
+ setting, capability.value(), direction);
+ if (filtered_ase_configuration_setting.has_value()) {
+ capability_matched_ase_configuration_settings.push_back(
+ filtered_ase_configuration_setting.value());
+ }
+ }
+ }
+
+ // Matching with requirements
+ std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
+ for (auto& setting : capability_matched_ase_configuration_settings) {
+ for (auto& requirement : in_requirements) {
+ auto filtered_ase_configuration_setting =
+ getRequirementMatchedAseConfigurationSettings(setting, requirement);
+ if (filtered_ase_configuration_setting.has_value()) {
+ result.push_back(filtered_ase_configuration_setting.value());
+ }
+ }
+ }
+
+ *_aidl_return = result;
+ return ndk::ScopedAStatus::ok();
};
ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index bfca061ddd..2488f9b78b 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -87,7 +87,7 @@ class LeAudioOffloadAudioProvider : public BluetoothAudioProvider {
// Private matching function definitions
bool isMatchedValidCodec(CodecId cfg_codec, CodecId req_codec);
- bool isMatchedContext(
+ bool isCapabilitiesMatchedContext(
AudioContext setting_context,
const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
bool isMatchedSamplingFreq(
@@ -113,9 +113,8 @@ class LeAudioOffloadAudioProvider : public BluetoothAudioProvider {
bool isCapabilitiesMatchedCodecConfiguration(
std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities);
- bool isRequirementAseConfigurationMatched(
- LeAudioAseConfiguration setting_cfg,
- LeAudioAseConfiguration requirement_cfg);
+ bool isMatchedAseConfiguration(LeAudioAseConfiguration setting_cfg,
+ LeAudioAseConfiguration requirement_cfg);
void filterCapabilitiesAseDirectionConfiguration(
std::vector<std::optional<AseDirectionConfiguration>>&
direction_configurations,