From 6b233bb40e2c965134aaed1dccc485d33c86664b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Bostr=C3=B6m?= Date: Sat, 18 Mar 2023 11:19:53 +0100 Subject: [PATCH] Exercise AV1 simulcast paths in tests (re-upload). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 Auto-Submit: Henrik Boström Reviewed-by: Mirko Bonadei Commit-Queue: Jeremy Leconte Cr-Commit-Position: refs/heads/main@{#39597} --- pc/peer_connection_simulcast_unittest.cc | 96 ++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/pc/peer_connection_simulcast_unittest.cc b/pc/peer_connection_simulcast_unittest.cc index 1e8955be03..1f5f17a517 100644 --- a/pc/peer_connection_simulcast_unittest.cc +++ b/pc/peer_connection_simulcast_unittest.cc @@ -886,6 +886,19 @@ class PeerConnectionSimulcastWithMediaFlowTests return transceiver_or_error.value(); } + bool HasSenderVideoCodecCapability( + rtc::scoped_refptr pc_wrapper, + absl::string_view codec_name) { + std::vector 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 GetCapabilitiesAndRestrictToCodec( rtc::scoped_refptr pc_wrapper, absl::string_view codec_name) { @@ -1490,4 +1503,87 @@ TEST_F(PeerConnectionSimulcastWithMediaFlowTests, 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 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 remote_pc_wrapper = CreatePc(); + ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); + + std::vector layers = + CreateLayers({"f", "h", "q"}, /*active=*/true); + rtc::scoped_refptr transceiver = + AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper, + layers); + std::vector codecs = + GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "AV1"); + transceiver->SetCodecPreferences(codecs); + + // Opt-in to spec-compliant simulcast by explicitly setting the + // `scalability_mode`. + rtc::scoped_refptr 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 report = GetStats(local_pc_wrapper); + std::vector outbound_rtps = + report->GetStatsOfType(); + 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