From fb65d23d7365ce96467a2b19960c8f42a83c2cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Bostr=C3=B6m?= Date: Tue, 11 Apr 2023 15:32:40 +0200 Subject: [PATCH] Parameterize PeerConnectionEncodingsIntegrationTest for standard paths. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL introduces PeerConnectionEncodingsIntegrationParameterizedTest, which is based on PeerConnectionEncodingsIntegrationTest but covers all codecs using INSTANTIATE_TEST_SUITE_P (VP8, VP9, H264, AV1). This applies to all standard paths, which in the case of VP9 and AV1 requires opting in to it by specifying scalabilityMode and scaleResolutionDownBy. They are also limited to L1Tx because the other codecs don't support SVC. The VP9-only tests continue to run as TEST_F with PeerConnectionEncodingsIntegrationTest. Bug: webrtc:15079 Change-Id: I3429c90f2f79ff60adad0b33975bccdda31ce6d9 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/300900 Reviewed-by: Ilya Nikolaevskiy Commit-Queue: Henrik Boström Cr-Commit-Position: refs/heads/main@{#39808} --- ...er_connection_encodings_integrationtest.cc | 256 +++++------------- 1 file changed, 73 insertions(+), 183 deletions(-) diff --git a/pc/peer_connection_encodings_integrationtest.cc b/pc/peer_connection_encodings_integrationtest.cc index 5ae970b21f..ca84df6902 100644 --- a/pc/peer_connection_encodings_integrationtest.cc +++ b/pc/peer_connection_encodings_integrationtest.cc @@ -48,7 +48,18 @@ namespace webrtc { namespace { constexpr TimeDelta kDefaultTimeout = TimeDelta::Seconds(5); -constexpr TimeDelta kLongTimeoutForRampingUp = TimeDelta::Seconds(30); +// Most tests pass in 20-30 seconds, but some tests take longer such as AV1 +// requiring additional ramp-up time (https://crbug.com/webrtc/15006) or SVC +// (LxTx_KEY) being slower than simulcast to send top spatial layer. +// TODO(https://crbug.com/webrtc/15076): Remove need for long rampup timeouts by +// using simulated time. +constexpr TimeDelta kLongTimeoutForRampingUp = TimeDelta::Minutes(1); + +struct StringParamToString { + std::string operator()(const ::testing::TestParamInfo& info) { + return info.param; + } +}; // RTX, RED and FEC are reliability mechanisms used in combinations with other // codecs, but are not themselves a specific codec. Typically you don't want to @@ -355,7 +366,7 @@ class PeerConnectionEncodingsIntegrationTest : public ::testing::Test { }; TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingOneEncodings_VP8_DefaultsToL1T1) { + VP8_SingleEncodingDefaultsToL1T1) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); rtc::scoped_refptr remote_pc_wrapper = CreatePc(); ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); @@ -389,48 +400,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, } TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingThreeEncodings_VP8_Simulcast) { - rtc::scoped_refptr local_pc_wrapper = CreatePc(); - 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, "VP8"); - transceiver->SetCodecPreferences(codecs); - - NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers); - local_pc_wrapper->WaitForConnection(); - remote_pc_wrapper->WaitForConnection(); - - // Wait until media is flowing on all three layers. - // Ramp up time is needed before all three layers are sending. - ASSERT_TRUE_WAIT(HasOutboundRtpBytesSent(local_pc_wrapper, 3u), - kLongTimeoutForRampingUp.ms()); - EXPECT_TRUE(OutboundRtpResolutionsAreLessThanOrEqualToExpectations( - local_pc_wrapper, {{"f", 320, 180}, {"h", 640, 360}, {"q", 1280, 720}})); - // 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/VP8")); - EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[1]), - StrCaseEq("video/VP8")); - EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[2]), - StrCaseEq("video/VP8")); - 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")); -} - -TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingOneEncoding_VP8_RejectsSVCWhenNotPossibleAndDefaultsToL1T1) { + VP8_RejectsSvcAndDefaultsToL1T1) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); rtc::scoped_refptr remote_pc_wrapper = CreatePc(); ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); @@ -479,7 +449,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, } TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingOneEncoding_VP8_FallbackFromSVCResultsInL1T2) { + VP8_FallbackFromSvcResultsInL1T2) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); rtc::scoped_refptr remote_pc_wrapper = CreatePc(); ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); @@ -536,58 +506,13 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, EXPECT_THAT(*outbound_rtps[0]->scalability_mode, StrEq("L1T2")); } -#if defined(WEBRTC_USE_H264) - -TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingThreeEncodings_H264_Simulcast) { - rtc::scoped_refptr local_pc_wrapper = CreatePc(); - 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, "H264"); - transceiver->SetCodecPreferences(codecs); - - NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers); - local_pc_wrapper->WaitForConnection(); - remote_pc_wrapper->WaitForConnection(); - - // Wait until media is flowing on all three layers. - // Ramp up time is needed before all three layers are sending. - ASSERT_TRUE_WAIT(HasOutboundRtpBytesSent(local_pc_wrapper, 3u), - kLongTimeoutForRampingUp.ms()); - EXPECT_TRUE(OutboundRtpResolutionsAreLessThanOrEqualToExpectations( - local_pc_wrapper, {{"f", 320, 180}, {"h", 640, 360}, {"q", 1280, 720}})); - // 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/H264")); - EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[1]), - StrCaseEq("video/H264")); - EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[2]), - StrCaseEq("video/H264")); - 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")); -} - -#endif // defined(WEBRTC_USE_H264) - // The legacy SVC path is triggered when VP9 us used, but `scalability_mode` has // not been specified. // TODO(https://crbug.com/webrtc/14889): When legacy VP9 SVC path has been // deprecated and removed, update this test to assert that simulcast is used // (i.e. VP9 is not treated differently than VP8). TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingThreeEncodings_VP9_LegacySVC) { + VP9_LegacySvcWhenScalabilityModeNotSpecified) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); rtc::scoped_refptr remote_pc_wrapper = CreatePc(); ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); @@ -613,7 +538,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, // Ramp up time may be significant. ASSERT_TRUE_WAIT(HasOutboundRtpWithRidAndScalabilityMode( local_pc_wrapper, "f", "L3T3_KEY", 720), - (2 * kLongTimeoutForRampingUp).ms()); + kLongTimeoutForRampingUp.ms()); // Despite SVC being used on a single RTP stream, GetParameters() returns the // three encodings that we configured earlier (this is not spec-compliant but @@ -632,7 +557,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, // outcome is the same as for the legacy SVC case except that we only have one // encoding in GetParameters(). TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingOneEncoding_VP9_StandardSVC) { + VP9_StandardSvcWithOnlyOneEncoding) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); rtc::scoped_refptr remote_pc_wrapper = CreatePc(); ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); @@ -685,7 +610,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, // the same as above except we end up with two inactive RTP streams which are // observable in GetStats(). TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingThreeEncodings_VP9_StandardSVC) { + VP9_StandardSvcWithSingleActiveEncoding) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); rtc::scoped_refptr remote_pc_wrapper = CreatePc(); ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); @@ -720,7 +645,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, // Ramp up time is significant. ASSERT_TRUE_WAIT(HasOutboundRtpWithRidAndScalabilityMode( local_pc_wrapper, "f", "L3T3_KEY", 720), - (2 * kLongTimeoutForRampingUp).ms()); + kLongTimeoutForRampingUp.ms()); // GetParameters() is consistent with what we asked for and got. parameters = sender->GetParameters(); @@ -731,75 +656,11 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, EXPECT_FALSE(parameters.encodings[2].scalability_mode.has_value()); } -TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingThreeEncodings_VP9_Simulcast) { - rtc::scoped_refptr local_pc_wrapper = CreatePc(); - 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, "VP9"); - transceiver->SetCodecPreferences(codecs); - - // Opt-in to spec-compliant simulcast by explicitly setting the - // `scalability_mode` and `scale_resolution_down_by` parameters. - rtc::scoped_refptr sender = transceiver->sender(); - RtpParameters parameters = sender->GetParameters(); - ASSERT_THAT(parameters.encodings, SizeIs(3)); - parameters.encodings[0].scalability_mode = "L1T3"; - parameters.encodings[0].scale_resolution_down_by = 4; - parameters.encodings[1].scalability_mode = "L1T3"; - parameters.encodings[1].scale_resolution_down_by = 2; - parameters.encodings[2].scalability_mode = "L1T3"; - parameters.encodings[2].scale_resolution_down_by = 1; - 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_THAT(parameters.encodings, SizeIs(3)); - 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. - ASSERT_TRUE_WAIT(HasOutboundRtpBytesSent(local_pc_wrapper, 3u), - kLongTimeoutForRampingUp.ms()); - EXPECT_TRUE(OutboundRtpResolutionsAreLessThanOrEqualToExpectations( - local_pc_wrapper, {{"f", 320, 180}, {"h", 640, 360}, {"q", 1280, 720}})); - // 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/VP9")); - EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[1]), - StrCaseEq("video/VP9")); - EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[2]), - StrCaseEq("video/VP9")); - 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")); -} - // Exercise common path where `scalability_mode` is not specified until after // negotiation, requring us to recreate the stream when the number of streams // changes from 1 (legacy SVC) to 3 (standard simulcast). TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingThreeEncodings_VP9_FromLegacyToSingleActiveWithScalability) { + VP9_SwitchFromLegacySvcToStandardSingleActiveEncodingSvc) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); rtc::scoped_refptr remote_pc_wrapper = CreatePc(); ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); @@ -842,7 +703,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, // Ramp up time may be significant. ASSERT_TRUE_WAIT(HasOutboundRtpWithRidAndScalabilityMode( local_pc_wrapper, "f", "L2T2_KEY", 720 / 2), - (2 * kLongTimeoutForRampingUp).ms()); + kLongTimeoutForRampingUp.ms()); // GetParameters() does not report any fallback. parameters = sender->GetParameters(); @@ -854,7 +715,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, } TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingThreeEncodings_VP9_LegacySVC_AllLayersInactive) { + VP9_AllLayersInactive_LegacySvc) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); rtc::scoped_refptr remote_pc_wrapper = CreatePc(); ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); @@ -891,7 +752,7 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, } TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingThreeEncodings_VP9_StandardSVC_AllLayersInactive) { + VP9_AllLayersInactive_StandardSvc) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); rtc::scoped_refptr remote_pc_wrapper = CreatePc(); ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); @@ -931,8 +792,10 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, EXPECT_EQ(*outbound_rtps[2]->bytes_sent, 0u); } -TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingThreeEncodings_VP9_StandardL1T3_AllLayersInactive) { +// TODO(https://crbug.com/webrtc/15080): This test is not codec-specific, so +// make use of TEST_P below and make this a +// PeerConnectionEncodingsIntegrationParameterizedTest. +TEST_F(PeerConnectionEncodingsIntegrationTest, VP9_AllLayersInactive_L1T3) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); rtc::scoped_refptr remote_pc_wrapper = CreatePc(); ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); @@ -972,13 +835,37 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, EXPECT_EQ(*outbound_rtps[2]->bytes_sent, 0u); } -TEST_F(PeerConnectionEncodingsIntegrationTest, - SendingThreeEncodings_AV1_Simulcast) { +// Tests that use the standard path (specifying both `scalability_mode` and +// `scale_resolution_down_by`) should pass for all codecs. +class PeerConnectionEncodingsIntegrationParameterizedTest + : public PeerConnectionEncodingsIntegrationTest, + public ::testing::WithParamInterface { + public: + PeerConnectionEncodingsIntegrationParameterizedTest() + : codec_name_(GetParam()), mime_type_("video/" + codec_name_) {} + + // Work-around for the fact that whether or not AV1 is supported is not known + // at compile-time so we have to skip tests early if missing. + // TODO(https://crbug.com/webrtc/15011): Increase availability of AV1 or make + // it possible to check support at compile-time. + bool SkipTestDueToAv1Missing( + rtc::scoped_refptr local_pc_wrapper) { + if (codec_name_ == "AV1" && + !HasSenderVideoCodecCapability(local_pc_wrapper, "AV1")) { + RTC_LOG(LS_WARNING) << "\n***\nAV1 is not available, skipping test.\n***"; + return true; + } + return false; + } + + protected: + const std::string codec_name_; // E.g. "VP9" + const std::string mime_type_; // E.g. "video/VP9" +}; + +TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest, Simulcast) { 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***"; + if (SkipTestDueToAv1Missing(local_pc_wrapper)) { return; } rtc::scoped_refptr remote_pc_wrapper = CreatePc(); @@ -990,11 +877,9 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper, layers); std::vector codecs = - GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "AV1"); + GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, codec_name_); 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_THAT(parameters.encodings, SizeIs(3)); @@ -1022,13 +907,8 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, // 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. ASSERT_TRUE_WAIT(HasOutboundRtpBytesSent(local_pc_wrapper, 3u), - (2 * kLongTimeoutForRampingUp).ms()); + kLongTimeoutForRampingUp.ms()); EXPECT_TRUE(OutboundRtpResolutionsAreLessThanOrEqualToExpectations( local_pc_wrapper, {{"f", 320, 180}, {"h", 640, 360}, {"q", 1280, 720}})); // Verify codec and scalability mode. @@ -1037,14 +917,24 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, report->GetStatsOfType(); ASSERT_THAT(outbound_rtps, SizeIs(3u)); EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]), - StrCaseEq("video/AV1")); + StrCaseEq(mime_type_)); EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[1]), - StrCaseEq("video/AV1")); + StrCaseEq(mime_type_)); EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[2]), - StrCaseEq("video/AV1")); + StrCaseEq(mime_type_)); 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")); } +INSTANTIATE_TEST_SUITE_P(StandardPath, + PeerConnectionEncodingsIntegrationParameterizedTest, + ::testing::Values("VP8", + "VP9", +#if defined(WEBRTC_USE_H264) + "H264", +#endif // defined(WEBRTC_USE_H264) + "AV1"), + StringParamToString()); + } // namespace webrtc