Add API layer tests for SVC reject and SVC fallback paths.

Attempting to SVC can fail for two reasons:
1. If codec preferences does not contain a codec that supports SVC,
   setParameters() rejects, leaving scalabilityMode undefined.
2. If codec preferences does contain a codec that support SVC,
   setParameters() accepts the scalabilityMode, but if a codec is
   configured in response to negotiation that does not support SVC,
   fallback happens.

In the 1) path, undefined scalabilityMode results in VP8 L1T1.
In the 2) path, SVC fallback results in scalabilityMode being set to
L1T2, resulting in VP8 L1T2.

Whether we fail late or early resulting in different configurations may
not be obvious so its good to test these.

Bug: webrtc:14884
Change-Id: Ic5502b90c1628310a7a78ade2ad9fa0d81d91502
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/295872
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Evan Shrubsole <eshr@webrtc.org>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39474}
This commit is contained in:
Henrik Boström 2023-03-03 17:50:47 +01:00 committed by WebRTC LUCI CQ
parent e16942b5f1
commit 6b539c8361

View File

@ -1154,6 +1154,109 @@ TEST_F(PeerConnectionSimulcastWithMediaFlowTests,
EXPECT_THAT(*outbound_rtps[2]->scalability_mode, StrEq("L1T3"));
}
TEST_F(PeerConnectionSimulcastWithMediaFlowTests,
SendingOneEncoding_VP8_RejectsSVCWhenNotPossibleAndDefaultsToL1T1) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<SimulcastLayer> layers = CreateLayers({"f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
// Restricting codecs restricts what SetParameters() will accept or reject.
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(local_pc_wrapper, "VP8");
transceiver->SetCodecPreferences(codecs);
// Attempt SVC (L3T3_KEY). This is not possible because only VP8 is up for
// negotiation and VP8 does not support it.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
parameters.encodings[0].scalability_mode = "L3T3_KEY";
EXPECT_FALSE(sender->SetParameters(parameters).ok());
// `scalability_mode` remains unset because SetParameters() failed.
parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
EXPECT_THAT(parameters.encodings[0].scalability_mode, Eq(absl::nullopt));
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait until media is flowing.
EXPECT_TRUE_WAIT(HasOutboundRtpBytesSent(local_pc_wrapper, 1u),
kDefaultTimeout.ms());
// When `scalability_mode` is not set, VP8 defaults to L1T1.
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRTPStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRTPStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(1u));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]),
StrCaseEq("video/VP8"));
EXPECT_THAT(*outbound_rtps[0]->scalability_mode, StrEq("L1T1"));
// GetParameters() confirms `scalability_mode` is still not set.
parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
EXPECT_THAT(parameters.encodings[0].scalability_mode, Eq(absl::nullopt));
}
TEST_F(PeerConnectionSimulcastWithMediaFlowTests,
SendingOneEncoding_VP8_FallbackFromSVCResultsInL1T2) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<SimulcastLayer> layers = CreateLayers({"f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
// Verify test assumption that VP8 is first in the list, but don't modify the
// codec preferences because we want the sender to think SVC is a possibility.
std::vector<RtpCodecCapability> codecs =
local_pc_wrapper->pc_factory()
->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
.codecs;
EXPECT_THAT(codecs[0].name, StrCaseEq("VP8"));
// Attempt SVC (L3T3_KEY), which is not possible with VP8, but the sender does
// not yet know which codec we'll use so the parameters will be accepted.
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
RtpParameters parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
parameters.encodings[0].scalability_mode = "L3T3_KEY";
EXPECT_TRUE(sender->SetParameters(parameters).ok());
// Verify fallback has not happened yet.
parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
EXPECT_THAT(parameters.encodings[0].scalability_mode,
Optional(std::string("L3T3_KEY")));
// Negotiate, this results in VP8 being picked and fallback happening.
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper, layers);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// `scalaiblity_mode` is assigned the fallback value "L1T2" which is different
// than the default of absl::nullopt.
parameters = sender->GetParameters();
ASSERT_EQ(parameters.encodings.size(), 1u);
EXPECT_THAT(parameters.encodings[0].scalability_mode,
Optional(std::string("L1T2")));
// Wait until media is flowing, no significant time needed because we only
// have one layer.
EXPECT_TRUE_WAIT(HasOutboundRtpBytesSent(local_pc_wrapper, 1u),
kDefaultTimeout.ms());
// GetStats() confirms "L1T2" is used which is different than the "L1T1"
// default or the "L3T3_KEY" that was attempted.
rtc::scoped_refptr<const RTCStatsReport> report = GetStats(local_pc_wrapper);
std::vector<const RTCOutboundRTPStreamStats*> outbound_rtps =
report->GetStatsOfType<RTCOutboundRTPStreamStats>();
ASSERT_THAT(outbound_rtps, SizeIs(1u));
EXPECT_THAT(GetCurrentCodecMimeType(report, *outbound_rtps[0]),
StrCaseEq("video/VP8"));
EXPECT_THAT(*outbound_rtps[0]->scalability_mode, StrEq("L1T2"));
}
#if defined(WEBRTC_USE_H264)
TEST_F(PeerConnectionSimulcastWithMediaFlowTests,