LeAudio: Verify codec frame blocks pers SDU parameter

Bug: 308428644
Bug: 346568041
Test: atest VtsHalBluetoothAudioTargetTest
Change-Id: I6567950d24d1df8cabec2855c907c5611ca5bf6d
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index e83cb9e..110a628 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -195,6 +195,17 @@
   }
 }
 
+static std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
+    const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
+    CodecSpecificConfigurationLtv::Tag tag) {
+  for (const auto ltv : configurationLtvs) {
+    if (ltv.getTag() == tag) {
+      return ltv;
+    }
+  }
+  return std::nullopt;
+}
+
 class BluetoothAudioPort : public BnBluetoothAudioPort {
  public:
   BluetoothAudioPort() {}
@@ -2393,17 +2404,6 @@
     return capability;
   }
 
-  std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
-      const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
-      CodecSpecificConfigurationLtv::Tag tag) {
-    for (const auto ltv : configurationLtvs) {
-      if (ltv.getTag() == tag) {
-        return ltv;
-      }
-    }
-    return std::nullopt;
-  }
-
   bool IsAseRequirementSatisfiedWithUnknownChannelCount(
       const std::vector<std::optional<AseDirectionRequirement>>&
           ase_requirements,
@@ -2560,6 +2560,67 @@
     return (num_of_satisfied_ase_requirements == ase_requirements.size());
   }
 
+  static void VerifyCodecParameters(
+      ::aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider::
+          LeAudioAseConfigurationSetting::AseDirectionConfiguration config) {
+    ASSERT_NE(config.aseConfiguration.codecConfiguration.size(), 0lu);
+    ASSERT_TRUE(config.qosConfiguration.has_value());
+
+    int32_t frame_blocks = 1;  // by default 1 if not set
+    int8_t frame_duration = 0;
+    int32_t octets_per_frame = 0;
+    std::bitset<32> allocation_bitmask = 0;
+
+    for (auto const& param : config.aseConfiguration.codecConfiguration) {
+      if (param.getTag() ==
+          ::aidl::android::hardware::bluetooth::audio::
+              CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU) {
+        frame_blocks = param
+                           .get<::aidl::android::hardware::bluetooth::audio::
+                                    CodecSpecificConfigurationLtv::Tag::
+                                        codecFrameBlocksPerSDU>()
+                           .value;
+      } else if (param.getTag() ==
+                 ::aidl::android::hardware::bluetooth::audio::
+                     CodecSpecificConfigurationLtv::Tag::frameDuration) {
+        frame_duration = static_cast<int8_t>(
+            param.get<::aidl::android::hardware::bluetooth::audio::
+                          CodecSpecificConfigurationLtv::Tag::frameDuration>());
+      } else if (param.getTag() ==
+                 ::aidl::android::hardware::bluetooth::audio::
+                     CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame) {
+        octets_per_frame = static_cast<int32_t>(
+            param
+                .get<::aidl::android::hardware::bluetooth::audio::
+                         CodecSpecificConfigurationLtv::Tag::
+                             octetsPerCodecFrame>()
+                .value);
+      } else if (param.getTag() == ::aidl::android::hardware::bluetooth::audio::
+                                       CodecSpecificConfigurationLtv::Tag::
+                                           audioChannelAllocation) {
+        allocation_bitmask = static_cast<int32_t>(
+            param
+                .get<::aidl::android::hardware::bluetooth::audio::
+                         CodecSpecificConfigurationLtv::Tag::
+                             audioChannelAllocation>()
+                .bitmask);
+      }
+    }
+
+    ASSERT_NE(frame_blocks, 0);
+    ASSERT_NE(frame_duration, 0);
+    ASSERT_NE(octets_per_frame, 0);
+
+    auto const num_channels_per_cis = allocation_bitmask.count();
+    ASSERT_NE(num_channels_per_cis, 0);
+
+    // Verify if QoS takes the codec frame blocks per SDU into the account
+    ASSERT_TRUE(config.qosConfiguration->sduIntervalUs >=
+                frame_blocks * frame_duration);
+    ASSERT_TRUE(config.qosConfiguration->maxSdu >=
+                (frame_blocks * num_channels_per_cis * octets_per_frame));
+  }
+
   void VerifyIfRequirementsSatisfied(
       const std::vector<LeAudioConfigurationRequirement>& requirements,
       const std::vector<LeAudioAseConfigurationSetting>& configurations) {
@@ -2592,32 +2653,52 @@
           continue;
         }
 
+        bool sink_req_satisfied = false;
+        if (req.sinkAseRequirement) {
+          ASSERT_TRUE(conf.sinkAseConfiguration.has_value());
+          sink_req_satisfied = IsAseRequirementSatisfied(
+              *req.sinkAseRequirement, *conf.sinkAseConfiguration);
+
+          ASSERT_NE(conf.sinkAseConfiguration->size(), 0lu);
+          for (auto const& cfg : conf.sinkAseConfiguration.value()) {
+            ASSERT_TRUE(cfg.has_value());
+            VerifyCodecParameters(cfg.value());
+          }
+        }
+
+        bool source_req_satisfied = false;
+        if (req.sourceAseRequirement) {
+          ASSERT_TRUE(conf.sourceAseConfiguration.has_value());
+          source_req_satisfied = IsAseRequirementSatisfied(
+              *req.sourceAseRequirement, *conf.sourceAseConfiguration);
+
+          ASSERT_NE(conf.sourceAseConfiguration->size(), 0lu);
+          for (auto const& cfg : conf.sourceAseConfiguration.value()) {
+            ASSERT_TRUE(cfg.has_value());
+            VerifyCodecParameters(cfg.value());
+          }
+        }
+
         if (req.sinkAseRequirement && req.sourceAseRequirement) {
           if (!conf.sinkAseConfiguration || !conf.sourceAseConfiguration) {
             continue;
           }
 
-          if (!IsAseRequirementSatisfied(*req.sinkAseRequirement,
-                                         *conf.sinkAseConfiguration) ||
-              !IsAseRequirementSatisfied(*req.sourceAseRequirement,
-                                         *conf.sourceAseConfiguration)) {
+          if (!sink_req_satisfied || !source_req_satisfied) {
             continue;
           }
           num_of_satisfied_requirements +=
               std::bitset<32>(req.audioContext.bitmask).count();
-
           break;
         } else if (req.sinkAseRequirement) {
-          if (!IsAseRequirementSatisfied(*req.sinkAseRequirement,
-                                         *conf.sinkAseConfiguration)) {
+          if (!sink_req_satisfied) {
             continue;
           }
           num_of_satisfied_requirements +=
               std::bitset<32>(req.audioContext.bitmask).count();
           break;
         } else if (req.sourceAseRequirement) {
-          if (!IsAseRequirementSatisfied(*req.sourceAseRequirement,
-                                         *conf.sourceAseConfiguration)) {
+          if (!source_req_satisfied) {
             continue;
           }
           num_of_satisfied_requirements +=
@@ -4089,17 +4170,6 @@
     return media_audio_context;
   }
 
-  std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
-      const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
-      CodecSpecificConfigurationLtv::Tag tag) {
-    for (const auto ltv : configurationLtvs) {
-      if (ltv.getTag() == tag) {
-        return ltv;
-      }
-    }
-    return std::nullopt;
-  }
-
   std::optional<CodecSpecificConfigurationLtv::SamplingFrequency>
   GetBisSampleFreq(const LeAudioBisConfiguration& bis_conf) {
     auto sample_freq_ltv = GetConfigurationLtv(