diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index ac7d0f884a..fcd7b23938 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -2145,7 +2145,8 @@ WebRtcVideoSendChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig( for (const webrtc::RtpEncodingParameters& encoding : rtp_parameters_.encodings) { if (encoding.scalability_mode.has_value() && - encoding.scale_resolution_down_by.has_value()) { + (encoding.scale_resolution_down_by.has_value() || + encoding.requested_resolution.has_value())) { legacy_scalability_mode = false; break; } diff --git a/pc/peer_connection_encodings_integrationtest.cc b/pc/peer_connection_encodings_integrationtest.cc index a497acb61c..0400b92182 100644 --- a/pc/peer_connection_encodings_integrationtest.cc +++ b/pc/peer_connection_encodings_integrationtest.cc @@ -2041,7 +2041,8 @@ TEST_F(PeerConnectionEncodingsIntegrationTest, } // Tests that use the standard path (specifying both `scalability_mode` and -// `scale_resolution_down_by`) should pass for all codecs. +// `scale_resolution_down_by` or `requested_resolution`) should pass for all +// codecs. class PeerConnectionEncodingsIntegrationParameterizedTest : public PeerConnectionEncodingsIntegrationTest, public ::testing::WithParamInterface { @@ -2111,6 +2112,7 @@ TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest, AllLayersInactive) { EXPECT_EQ(*outbound_rtps[2]->bytes_sent, 0u); } +// Configure 4:2:1 using `scale_resolution_down_by`. TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest, Simulcast) { rtc::scoped_refptr local_pc_wrapper = CreatePc(); if (SkipTestDueToAv1Missing(local_pc_wrapper)) { @@ -2120,7 +2122,7 @@ TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest, Simulcast) { ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); std::vector layers = - CreateLayers({"f", "h", "q"}, /*active=*/true); + CreateLayers({"q", "h", "f"}, /*active=*/true); rtc::scoped_refptr transceiver = AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper, layers); @@ -2158,7 +2160,73 @@ TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest, Simulcast) { 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}})); + local_pc_wrapper, {{"q", 320, 180}, {"h", 640, 360}, {"f", 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(mime_type_)); + EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[1]), + StrCaseEq(mime_type_)); + EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[2]), + 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")); +} + +// Configure 4:2:1 using `requested_resolution`. +TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest, + SimulcastWithRequestedResolution) { + rtc::scoped_refptr local_pc_wrapper = CreatePc(); + if (SkipTestDueToAv1Missing(local_pc_wrapper)) { + return; + } + rtc::scoped_refptr remote_pc_wrapper = CreatePc(); + ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper); + + std::vector layers = + CreateLayers({"q", "h", "f"}, /*active=*/true); + rtc::scoped_refptr transceiver = + AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper, + layers); + std::vector codecs = + GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, codec_name_); + transceiver->SetCodecPreferences(codecs); + + 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].requested_resolution = {.width = 320, .height = 180}; + parameters.encodings[1].scalability_mode = "L1T3"; + parameters.encodings[1].requested_resolution = {.width = 640, .height = 360}; + parameters.encodings[2].scalability_mode = "L1T3"; + parameters.encodings[2].requested_resolution = {.width = 1280, .height = 720}; + sender->SetParameters(parameters); + + NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper); + 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, {{"q", 320, 180}, {"h", 640, 360}, {"f", 1280, 720}})); // Verify codec and scalability mode. rtc::scoped_refptr report = GetStats(local_pc_wrapper); std::vector outbound_rtps =