Index: webrtc/video/video_send_stream_tests.cc |
diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc |
index 00aa2a901815cb4b0be6296e55e7ade6dae09364..01267735e073a2e35677d4aef72686caa26f6cf1 100644 |
--- a/webrtc/video/video_send_stream_tests.cc |
+++ b/webrtc/video/video_send_stream_tests.cc |
@@ -308,48 +308,55 @@ class FakeReceiveStatistics : public NullReceiveStatistics { |
StatisticianMap stats_map_; |
}; |
-class FecObserver : public test::SendTest { |
+class FecObserver : public test::EndToEndTest { |
public: |
- explicit FecObserver(bool header_extensions_enabled) |
- : SendTest(VideoSendStreamTest::kDefaultTimeoutMs), |
+ FecObserver(bool header_extensions_enabled, |
+ bool use_nack, |
+ bool expect_red, |
+ const std::string& codec) |
+ : EndToEndTest(VideoSendStreamTest::kDefaultTimeoutMs), |
+ payload_name_(codec), |
+ use_nack_(use_nack), |
+ expect_red_(expect_red), |
send_count_(0), |
received_media_(false), |
received_fec_(false), |
- header_extensions_enabled_(header_extensions_enabled) {} |
+ header_extensions_enabled_(header_extensions_enabled) { |
+ if (codec == "H264") { |
+ encoder_.reset(new test::FakeH264Encoder(Clock::GetRealTimeClock())); |
+ } else if (codec == "VP8") { |
+ encoder_.reset(VideoEncoder::Create(VideoEncoder::EncoderType::kVp8)); |
+ } else if (codec == "VP9") { |
+ encoder_.reset(VideoEncoder::Create(VideoEncoder::EncoderType::kVp9)); |
+ } else { |
+ RTC_NOTREACHED(); |
+ } |
+ } |
private: |
Action OnSendRtp(const uint8_t* packet, size_t length) override { |
RTPHeader header; |
EXPECT_TRUE(parser_->Parse(packet, length, &header)); |
- // Send lossy receive reports to trigger FEC enabling. |
- if (send_count_++ % 2 != 0) { |
- // Receive statistics reporting having lost 50% of the packets. |
- FakeReceiveStatistics lossy_receive_stats( |
- VideoSendStreamTest::kVideoSendSsrcs[0], header.sequenceNumber, |
- send_count_ / 2, 127); |
- RTCPSender rtcp_sender(false, Clock::GetRealTimeClock(), |
- &lossy_receive_stats, nullptr, nullptr, |
- transport_adapter_.get()); |
- |
- rtcp_sender.SetRTCPStatus(RtcpMode::kReducedSize); |
- rtcp_sender.SetRemoteSSRC(VideoSendStreamTest::kVideoSendSsrcs[0]); |
- |
- RTCPSender::FeedbackState feedback_state; |
- |
- EXPECT_EQ(0, rtcp_sender.SendRTCP(feedback_state, kRtcpRr)); |
- } |
- |
+ ++send_count_; |
int encapsulated_payload_type = -1; |
if (header.payloadType == VideoSendStreamTest::kRedPayloadType) { |
+ EXPECT_TRUE(expect_red_); |
encapsulated_payload_type = static_cast<int>(packet[header.headerLength]); |
if (encapsulated_payload_type != |
- VideoSendStreamTest::kFakeVideoSendPayloadType) |
+ VideoSendStreamTest::kFakeVideoSendPayloadType) { |
EXPECT_EQ(VideoSendStreamTest::kUlpfecPayloadType, |
encapsulated_payload_type); |
+ } |
} else { |
EXPECT_EQ(VideoSendStreamTest::kFakeVideoSendPayloadType, |
header.payloadType); |
+ if (static_cast<size_t>(header.headerLength + header.paddingLength) < |
+ length) { |
+ // Not padding-only, media received outside of RED. |
+ EXPECT_FALSE(expect_red_); |
+ received_media_ = true; |
+ } |
} |
if (header_extensions_enabled_) { |
@@ -379,14 +386,27 @@ class FecObserver : public test::SendTest { |
} |
} |
- if (received_media_ && received_fec_ && send_count_ > 100) |
- observation_complete_.Set(); |
+ if (send_count_ > 100 && received_media_) { |
+ if (received_fec_ || !expect_red_) |
+ observation_complete_.Set(); |
+ } |
prev_header_ = header; |
return SEND_PACKET; |
} |
+ test::PacketTransport* CreateSendTransport(Call* sender_call) override { |
+ // At low RTT (< kLowRttNackMs) -> NACK only, no FEC. |
+ // Configure some network delay. |
+ const int kNetworkDelayMs = 100; |
+ FakeNetworkPipe::Config config; |
+ config.loss_percent = 50; |
+ config.queue_delay_ms = kNetworkDelayMs; |
+ return new test::PacketTransport(sender_call, this, |
+ test::PacketTransport::kSender, config); |
+ } |
+ |
void ModifyVideoConfigs( |
VideoSendStream::Config* send_config, |
std::vector<VideoReceiveStream::Config>* receive_configs, |
@@ -394,10 +414,17 @@ class FecObserver : public test::SendTest { |
transport_adapter_.reset( |
new internal::TransportAdapter(send_config->send_transport)); |
transport_adapter_->Enable(); |
+ if (use_nack_) { |
+ send_config->rtp.nack.rtp_history_ms = |
+ (*receive_configs)[0].rtp.nack.rtp_history_ms = |
+ VideoSendStreamTest::kNackRtpHistoryMs; |
+ } |
+ send_config->encoder_settings.encoder = encoder_.get(); |
+ send_config->encoder_settings.payload_name = payload_name_; |
send_config->rtp.fec.red_payload_type = |
- VideoSendStreamTest::kRedPayloadType; |
+ VideoSendStreamTest::kRedPayloadType; |
send_config->rtp.fec.ulpfec_payload_type = |
- VideoSendStreamTest::kUlpfecPayloadType; |
+ VideoSendStreamTest::kUlpfecPayloadType; |
if (header_extensions_enabled_) { |
send_config->rtp.extensions.push_back(RtpExtension( |
RtpExtension::kAbsSendTime, test::kAbsSendTimeExtensionId)); |
@@ -405,6 +432,10 @@ class FecObserver : public test::SendTest { |
RtpExtension(RtpExtension::kTransportSequenceNumber, |
test::kTransportSequenceNumberExtensionId)); |
} |
+ (*receive_configs)[0].rtp.fec.red_payload_type = |
+ send_config->rtp.fec.red_payload_type; |
+ (*receive_configs)[0].rtp.fec.ulpfec_payload_type = |
+ send_config->rtp.fec.ulpfec_payload_type; |
} |
void PerformTest() override { |
@@ -412,6 +443,10 @@ class FecObserver : public test::SendTest { |
} |
rtc::scoped_ptr<internal::TransportAdapter> transport_adapter_; |
+ rtc::scoped_ptr<VideoEncoder> encoder_; |
+ const std::string payload_name_; |
+ const bool use_nack_; |
+ const bool expect_red_; |
int send_count_; |
bool received_media_; |
bool received_fec_; |
@@ -420,14 +455,37 @@ class FecObserver : public test::SendTest { |
}; |
TEST_F(VideoSendStreamTest, SupportsFecWithExtensions) { |
- FecObserver test(true); |
- |
+ FecObserver test(true, false, true, "VP8"); |
RunBaseTest(&test); |
} |
TEST_F(VideoSendStreamTest, SupportsFecWithoutExtensions) { |
- FecObserver test(false); |
+ FecObserver test(false, false, true, "VP8"); |
+ RunBaseTest(&test); |
+} |
+ |
+// The FEC scheme used is not efficient for H264, so we should not use RED/FEC |
+// since we'll still have to re-request FEC packets, effectively wasting |
+// bandwidth since the receiver has to wait for FEC retransmissions to determine |
+// that the received state is actually decodable. |
+TEST_F(VideoSendStreamTest, DoesNotUtilizeRedForH264WithNackEnabled) { |
+ FecObserver test(false, true, false, "H264"); |
+ RunBaseTest(&test); |
+} |
+ |
+// Without retransmissions FEC for H264 is fine. |
+TEST_F(VideoSendStreamTest, DoesUtilizeRedForH264WithoutNackEnabled) { |
+ FecObserver test(false, false, true, "H264"); |
+ RunBaseTest(&test); |
+} |
+ |
+TEST_F(VideoSendStreamTest, DoesUtilizeRedForVp8WithNackEnabled) { |
+ FecObserver test(false, true, true, "VP8"); |
+ RunBaseTest(&test); |
+} |
+TEST_F(VideoSendStreamTest, DoesUtilizeRedForVp9WithNackEnabled) { |
+ FecObserver test(false, true, true, "VP9"); |
RunBaseTest(&test); |
} |