Exercise AV1 simulcast paths in tests (re-upload).

- Patch Set 1: Re-land of 297982.
- Patch Set 2: Skip test (return early) if AV1 is not available.

Original CL description (297982):

This is something we get "for free" with the
"WebRTC-AllowDisablingLegacyScalability" field trial that has been
wired up to support VP9 simulcast.

This test works and passes, however the ramp-up time is pretty bad.
- VP9 simulcast takes approximately 4 seconds to ramp up.
- VP9 SVC takes approximately 16 seconds to ramp up.
- AV1 simulcast takes approximately 22 seconds to ramp up.

A TODO is added (webrtc:15006) and the test is given extra timeout,
a full minute to get bytes flowing on all layers.

Despite ramp-up being bad, it's important to test that AV1 simulcast
is in fact working to avoid regressions due to obsolete assumptions
about which codec do or do not support simulcast. AV1 simulcast is an
opt-in feature so there is no harm in the API not being perfect yet.

Bug: webrtc:15005, webrtc:15006
Change-Id: Ie8ec9f17c709ef93525e4ea5feb7c95496062add
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/298050
Reviewed-by: Jeremy Leconte <jleconte@google.com>
Auto-Submit: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Jeremy Leconte <jleconte@google.com>
Cr-Commit-Position: refs/heads/main@{#39597}
diff --git a/pc/peer_connection_simulcast_unittest.cc b/pc/peer_connection_simulcast_unittest.cc
index 1e8955b..1f5f17a 100644
--- a/pc/peer_connection_simulcast_unittest.cc
+++ b/pc/peer_connection_simulcast_unittest.cc
@@ -886,6 +886,19 @@
     return transceiver_or_error.value();
   }
 
+  bool HasSenderVideoCodecCapability(
+      rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper,
+      absl::string_view codec_name) {
+    std::vector<RtpCodecCapability> codecs =
+        pc_wrapper->pc_factory()
+            ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
+            .codecs;
+    return std::find_if(codecs.begin(), codecs.end(),
+                        [&codec_name](const RtpCodecCapability& codec) {
+                          return absl::EqualsIgnoreCase(codec.name, codec_name);
+                        }) != codecs.end();
+  }
+
   std::vector<RtpCodecCapability> GetCapabilitiesAndRestrictToCodec(
       rtc::scoped_refptr<PeerConnectionTestWrapper> pc_wrapper,
       absl::string_view codec_name) {
@@ -1490,4 +1503,87 @@
   EXPECT_THAT(*outbound_rtps[2]->scalability_mode, StrEq("L1T3"));
 }
 
+// TODO(https://crbug.com/webrtc/15005): A field trial shouldn't be needed to
+// get spec-compliant behavior! The same field trial is also used for VP9
+// simulcast (https://crbug.com/webrtc/14884).
+TEST_F(PeerConnectionSimulcastWithMediaFlowTests,
+       SendingThreeEncodings_AV1_Simulcast) {
+  test::ScopedFieldTrials field_trials(
+      "WebRTC-AllowDisablingLegacyScalability/Enabled/");
+
+  rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
+  // TODO(https://crbug.com/webrtc/15011): Expand testing support for AV1 or
+  // allow compile time checks so that gates like this isn't needed at runtime.
+  if (!HasSenderVideoCodecCapability(local_pc_wrapper, "AV1")) {
+    RTC_LOG(LS_WARNING) << "\n***\nAV1 is not available, skipping test.\n***";
+    return;
+  }
+  rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
+  ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
+
+  std::vector<SimulcastLayer> layers =
+      CreateLayers({"f", "h", "q"}, /*active=*/true);
+  rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
+      AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
+                                        layers);
+  std::vector<RtpCodecCapability> codecs =
+      GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "AV1");
+  transceiver->SetCodecPreferences(codecs);
+
+  // Opt-in to spec-compliant simulcast by explicitly setting the
+  // `scalability_mode`.
+  rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
+  RtpParameters parameters = sender->GetParameters();
+  ASSERT_EQ(parameters.encodings.size(), 3u);
+  parameters.encodings[0].scalability_mode = "L1T3";
+  parameters.encodings[1].scalability_mode = "L1T3";
+  parameters.encodings[2].scalability_mode = "L1T3";
+  sender->SetParameters(parameters);
+
+  NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
+  local_pc_wrapper->WaitForConnection();
+  remote_pc_wrapper->WaitForConnection();
+
+  // GetParameters() does not report any fallback.
+  parameters = sender->GetParameters();
+  ASSERT_EQ(parameters.encodings.size(), 3u);
+  EXPECT_THAT(parameters.encodings[0].scalability_mode,
+              Optional(std::string("L1T3")));
+  EXPECT_THAT(parameters.encodings[1].scalability_mode,
+              Optional(std::string("L1T3")));
+  EXPECT_THAT(parameters.encodings[2].scalability_mode,
+              Optional(std::string("L1T3")));
+
+  // Wait until media is flowing on all three layers.
+  // Ramp up time is needed before all three layers are sending.
+  //
+  // This test is given 2X timeout because AV1 simulcast ramp-up time is
+  // terrible compared to other codecs.
+  // TODO(https://crbug.com/webrtc/15006): Improve the ramp-up time and stop
+  // giving this test extra long timeout.
+  EXPECT_TRUE_WAIT(HasOutboundRtpBytesSent(local_pc_wrapper, 3u),
+                   (2 * kLongTimeoutForRampingUp).ms());
+  // Sometimes additional ramp up is needed to get the expected resolutions. If
+  // that has not happened yet we log (`log_during_ramp_up=true`).
+  EXPECT_TRUE_WAIT(HasOutboundRtpExpectedResolutions(
+                       local_pc_wrapper,
+                       {{"f", 320, 180}, {"h", 640, 360}, {"q", 1280, 720}},
+                       /*log_during_ramp_up=*/true),
+                   kLongTimeoutForRampingUp.ms());
+  // Verify codec and scalability mode.
+  rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
+  std::vector<const RTCOutboundRtpStreamStats*> outbound_rtps =
+      report->GetStatsOfType<RTCOutboundRtpStreamStats>();
+  ASSERT_THAT(outbound_rtps, SizeIs(3u));
+  EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]),
+              StrCaseEq("video/AV1"));
+  EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[1]),
+              StrCaseEq("video/AV1"));
+  EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[2]),
+              StrCaseEq("video/AV1"));
+  EXPECT_THAT(*outbound_rtps[0]->scalability_mode, StrEq("L1T3"));
+  EXPECT_THAT(*outbound_rtps[1]->scalability_mode, StrEq("L1T3"));
+  EXPECT_THAT(*outbound_rtps[2]->scalability_mode, StrEq("L1T3"));
+}
+
 }  // namespace webrtc