blob: 425c0c279a66b85bd9117950a7764bb2f174680b [file] [log] [blame]
Sebastian Janssonc5017132018-02-02 15:24:161/*
2 * Copyright 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "modules/video_coding/codecs/vp8/include/vp8.h"
12#include "system_wrappers/include/sleep.h"
13#include "test/call_test.h"
14#include "test/field_trial.h"
Niels Möller4db138e2018-04-19 07:04:1315#include "test/function_video_encoder_factory.h"
Sebastian Janssonc5017132018-02-02 15:24:1616#include "test/gtest.h"
17#include "test/rtcp_packet_parser.h"
18
19namespace webrtc {
20class RetransmissionEndToEndTest
21 : public test::CallTest,
22 public testing::WithParamInterface<std::string> {
23 public:
24 RetransmissionEndToEndTest() : field_trial_(GetParam()) {}
25
26 virtual ~RetransmissionEndToEndTest() {
27 EXPECT_EQ(nullptr, video_send_stream_);
28 EXPECT_TRUE(video_receive_streams_.empty());
29 }
30
31 protected:
32 void DecodesRetransmittedFrame(bool enable_rtx, bool enable_red);
33 void ReceivesPliAndRecovers(int rtp_history_ms);
34
35 private:
36 private:
37 test::ScopedFieldTrials field_trial_;
38};
39
40INSTANTIATE_TEST_CASE_P(RoundRobin,
41 RetransmissionEndToEndTest,
42 ::testing::Values("WebRTC-RoundRobinPacing/Disabled/",
43 "WebRTC-RoundRobinPacing/Enabled/"));
44
45TEST_P(RetransmissionEndToEndTest, ReceivesAndRetransmitsNack) {
46 static const int kNumberOfNacksToObserve = 2;
47 static const int kLossBurstSize = 2;
48 static const int kPacketsBetweenLossBursts = 9;
49 class NackObserver : public test::EndToEndTest {
50 public:
51 NackObserver()
52 : EndToEndTest(kLongTimeoutMs),
53 sent_rtp_packets_(0),
54 packets_left_to_drop_(0),
55 nacks_left_(kNumberOfNacksToObserve) {}
56
57 private:
58 Action OnSendRtp(const uint8_t* packet, size_t length) override {
59 rtc::CritScope lock(&crit_);
60 RTPHeader header;
61 EXPECT_TRUE(parser_->Parse(packet, length, &header));
62
63 // Never drop retransmitted packets.
64 if (dropped_packets_.find(header.sequenceNumber) !=
65 dropped_packets_.end()) {
66 retransmitted_packets_.insert(header.sequenceNumber);
67 return SEND_PACKET;
68 }
69
70 if (nacks_left_ <= 0 &&
71 retransmitted_packets_.size() == dropped_packets_.size()) {
72 observation_complete_.Set();
73 }
74
75 ++sent_rtp_packets_;
76
77 // Enough NACKs received, stop dropping packets.
78 if (nacks_left_ <= 0)
79 return SEND_PACKET;
80
81 // Check if it's time for a new loss burst.
82 if (sent_rtp_packets_ % kPacketsBetweenLossBursts == 0)
83 packets_left_to_drop_ = kLossBurstSize;
84
85 // Never drop padding packets as those won't be retransmitted.
86 if (packets_left_to_drop_ > 0 && header.paddingLength == 0) {
87 --packets_left_to_drop_;
88 dropped_packets_.insert(header.sequenceNumber);
89 return DROP_PACKET;
90 }
91
92 return SEND_PACKET;
93 }
94
95 Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
96 rtc::CritScope lock(&crit_);
97 test::RtcpPacketParser parser;
98 EXPECT_TRUE(parser.Parse(packet, length));
99 nacks_left_ -= parser.nack()->num_packets();
100 return SEND_PACKET;
101 }
102
103 void ModifyVideoConfigs(
104 VideoSendStream::Config* send_config,
105 std::vector<VideoReceiveStream::Config>* receive_configs,
106 VideoEncoderConfig* encoder_config) override {
107 send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
108 (*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
109 }
110
111 void PerformTest() override {
112 EXPECT_TRUE(Wait())
113 << "Timed out waiting for packets to be NACKed, retransmitted and "
114 "rendered.";
115 }
116
117 rtc::CriticalSection crit_;
118 std::set<uint16_t> dropped_packets_;
119 std::set<uint16_t> retransmitted_packets_;
120 uint64_t sent_rtp_packets_;
121 int packets_left_to_drop_;
122 int nacks_left_ RTC_GUARDED_BY(&crit_);
123 } test;
124
125 RunBaseTest(&test);
126}
127
128TEST_P(RetransmissionEndToEndTest, ReceivesNackAndRetransmitsAudio) {
129 class NackObserver : public test::EndToEndTest {
130 public:
131 NackObserver()
132 : EndToEndTest(kLongTimeoutMs),
133 local_ssrc_(0),
134 remote_ssrc_(0),
135 receive_transport_(nullptr) {}
136
137 private:
138 size_t GetNumVideoStreams() const override { return 0; }
139 size_t GetNumAudioStreams() const override { return 1; }
140
141 test::PacketTransport* CreateReceiveTransport(
142 test::SingleThreadedTaskQueueForTesting* task_queue) override {
143 test::PacketTransport* receive_transport = new test::PacketTransport(
144 task_queue, nullptr, this, test::PacketTransport::kReceiver,
145 payload_type_map_, FakeNetworkPipe::Config());
146 receive_transport_ = receive_transport;
147 return receive_transport;
148 }
149
150 Action OnSendRtp(const uint8_t* packet, size_t length) override {
151 RTPHeader header;
152 EXPECT_TRUE(parser_->Parse(packet, length, &header));
153
154 if (!sequence_number_to_retransmit_) {
155 sequence_number_to_retransmit_ = header.sequenceNumber;
156
157 // Don't ask for retransmission straight away, may be deduped in pacer.
158 } else if (header.sequenceNumber == *sequence_number_to_retransmit_) {
159 observation_complete_.Set();
160 } else {
161 // Send a NACK as often as necessary until retransmission is received.
162 rtcp::Nack nack;
163 nack.SetSenderSsrc(local_ssrc_);
164 nack.SetMediaSsrc(remote_ssrc_);
165 uint16_t nack_list[] = {*sequence_number_to_retransmit_};
166 nack.SetPacketIds(nack_list, 1);
167 rtc::Buffer buffer = nack.Build();
168
169 EXPECT_TRUE(receive_transport_->SendRtcp(buffer.data(), buffer.size()));
170 }
171
172 return SEND_PACKET;
173 }
174
175 void ModifyAudioConfigs(
176 AudioSendStream::Config* send_config,
177 std::vector<AudioReceiveStream::Config>* receive_configs) override {
178 send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
179 (*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
180 local_ssrc_ = (*receive_configs)[0].rtp.local_ssrc;
181 remote_ssrc_ = (*receive_configs)[0].rtp.remote_ssrc;
182 }
183
184 void PerformTest() override {
185 EXPECT_TRUE(Wait())
186 << "Timed out waiting for packets to be NACKed, retransmitted and "
187 "rendered.";
188 }
189
190 uint32_t local_ssrc_;
191 uint32_t remote_ssrc_;
192 Transport* receive_transport_;
193 rtc::Optional<uint16_t> sequence_number_to_retransmit_;
194 } test;
195
196 RunBaseTest(&test);
197}
198
199TEST_P(RetransmissionEndToEndTest,
200 StopSendingKeyframeRequestsForInactiveStream) {
201 class KeyframeRequestObserver : public test::EndToEndTest {
202 public:
203 explicit KeyframeRequestObserver(
204 test::SingleThreadedTaskQueueForTesting* task_queue)
205 : clock_(Clock::GetRealTimeClock()), task_queue_(task_queue) {}
206
207 void OnVideoStreamsCreated(
208 VideoSendStream* send_stream,
209 const std::vector<VideoReceiveStream*>& receive_streams) override {
210 RTC_DCHECK_EQ(1, receive_streams.size());
211 send_stream_ = send_stream;
212 receive_stream_ = receive_streams[0];
213 }
214
215 void PerformTest() override {
216 bool frame_decoded = false;
217 int64_t start_time = clock_->TimeInMilliseconds();
218 while (clock_->TimeInMilliseconds() - start_time <= 5000) {
219 if (receive_stream_->GetStats().frames_decoded > 0) {
220 frame_decoded = true;
221 break;
222 }
223 SleepMs(100);
224 }
225 ASSERT_TRUE(frame_decoded);
226 task_queue_->SendTask([this]() { send_stream_->Stop(); });
227 SleepMs(10000);
228 ASSERT_EQ(
229 1U, receive_stream_->GetStats().rtcp_packet_type_counts.pli_packets);
230 }
231
232 private:
233 Clock* clock_;
234 VideoSendStream* send_stream_;
235 VideoReceiveStream* receive_stream_;
236 test::SingleThreadedTaskQueueForTesting* const task_queue_;
237 } test(&task_queue_);
238
239 RunBaseTest(&test);
240}
241
242void RetransmissionEndToEndTest::ReceivesPliAndRecovers(int rtp_history_ms) {
243 static const int kPacketsToDrop = 1;
244
245 class PliObserver : public test::EndToEndTest,
246 public rtc::VideoSinkInterface<VideoFrame> {
247 public:
248 explicit PliObserver(int rtp_history_ms)
249 : EndToEndTest(kLongTimeoutMs),
250 rtp_history_ms_(rtp_history_ms),
251 nack_enabled_(rtp_history_ms > 0),
252 highest_dropped_timestamp_(0),
253 frames_to_drop_(0),
254 received_pli_(false) {}
255
256 private:
257 Action OnSendRtp(const uint8_t* packet, size_t length) override {
258 rtc::CritScope lock(&crit_);
259 RTPHeader header;
260 EXPECT_TRUE(parser_->Parse(packet, length, &header));
261
262 // Drop all retransmitted packets to force a PLI.
263 if (header.timestamp <= highest_dropped_timestamp_)
264 return DROP_PACKET;
265
266 if (frames_to_drop_ > 0) {
267 highest_dropped_timestamp_ = header.timestamp;
268 --frames_to_drop_;
269 return DROP_PACKET;
270 }
271
272 return SEND_PACKET;
273 }
274
275 Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
276 rtc::CritScope lock(&crit_);
277 test::RtcpPacketParser parser;
278 EXPECT_TRUE(parser.Parse(packet, length));
279 if (!nack_enabled_)
280 EXPECT_EQ(0, parser.nack()->num_packets());
281 if (parser.pli()->num_packets() > 0)
282 received_pli_ = true;
283 return SEND_PACKET;
284 }
285
286 void OnFrame(const VideoFrame& video_frame) override {
287 rtc::CritScope lock(&crit_);
288 if (received_pli_ &&
289 video_frame.timestamp() > highest_dropped_timestamp_) {
290 observation_complete_.Set();
291 }
292 if (!received_pli_)
293 frames_to_drop_ = kPacketsToDrop;
294 }
295
296 void ModifyVideoConfigs(
297 VideoSendStream::Config* send_config,
298 std::vector<VideoReceiveStream::Config>* receive_configs,
299 VideoEncoderConfig* encoder_config) override {
300 send_config->rtp.nack.rtp_history_ms = rtp_history_ms_;
301 (*receive_configs)[0].rtp.nack.rtp_history_ms = rtp_history_ms_;
302 (*receive_configs)[0].renderer = this;
303 }
304
305 void PerformTest() override {
306 EXPECT_TRUE(Wait()) << "Timed out waiting for PLI to be "
307 "received and a frame to be "
308 "rendered afterwards.";
309 }
310
311 rtc::CriticalSection crit_;
312 int rtp_history_ms_;
313 bool nack_enabled_;
314 uint32_t highest_dropped_timestamp_ RTC_GUARDED_BY(&crit_);
315 int frames_to_drop_ RTC_GUARDED_BY(&crit_);
316 bool received_pli_ RTC_GUARDED_BY(&crit_);
317 } test(rtp_history_ms);
318
319 RunBaseTest(&test);
320}
321
322TEST_P(RetransmissionEndToEndTest, ReceivesPliAndRecoversWithNack) {
323 ReceivesPliAndRecovers(1000);
324}
325
326TEST_P(RetransmissionEndToEndTest, ReceivesPliAndRecoversWithoutNack) {
327 ReceivesPliAndRecovers(0);
328}
329// This test drops second RTP packet with a marker bit set, makes sure it's
330// retransmitted and renders. Retransmission SSRCs are also checked.
331void RetransmissionEndToEndTest::DecodesRetransmittedFrame(bool enable_rtx,
332 bool enable_red) {
333 static const int kDroppedFrameNumber = 10;
334 class RetransmissionObserver : public test::EndToEndTest,
335 public rtc::VideoSinkInterface<VideoFrame> {
336 public:
337 RetransmissionObserver(bool enable_rtx, bool enable_red)
338 : EndToEndTest(kDefaultTimeoutMs),
339 payload_type_(GetPayloadType(false, enable_red)),
340 retransmission_ssrc_(enable_rtx ? kSendRtxSsrcs[0]
341 : kVideoSendSsrcs[0]),
342 retransmission_payload_type_(GetPayloadType(enable_rtx, enable_red)),
Niels Möller4db138e2018-04-19 07:04:13343 encoder_factory_([]() { return VP8Encoder::Create(); }),
Sebastian Janssonc5017132018-02-02 15:24:16344 marker_bits_observed_(0),
345 retransmitted_timestamp_(0) {}
346
347 private:
348 Action OnSendRtp(const uint8_t* packet, size_t length) override {
349 rtc::CritScope lock(&crit_);
350 RTPHeader header;
351 EXPECT_TRUE(parser_->Parse(packet, length, &header));
352
353 // Ignore padding-only packets over RTX.
354 if (header.payloadType != payload_type_) {
355 EXPECT_EQ(retransmission_ssrc_, header.ssrc);
356 if (length == header.headerLength + header.paddingLength)
357 return SEND_PACKET;
358 }
359
360 if (header.timestamp == retransmitted_timestamp_) {
361 EXPECT_EQ(retransmission_ssrc_, header.ssrc);
362 EXPECT_EQ(retransmission_payload_type_, header.payloadType);
363 return SEND_PACKET;
364 }
365
366 // Found the final packet of the frame to inflict loss to, drop this and
367 // expect a retransmission.
368 if (header.payloadType == payload_type_ && header.markerBit &&
369 ++marker_bits_observed_ == kDroppedFrameNumber) {
370 // This should be the only dropped packet.
371 EXPECT_EQ(0u, retransmitted_timestamp_);
372 retransmitted_timestamp_ = header.timestamp;
373 if (std::find(rendered_timestamps_.begin(), rendered_timestamps_.end(),
374 retransmitted_timestamp_) != rendered_timestamps_.end()) {
375 // Frame was rendered before last packet was scheduled for sending.
376 // This is extremly rare but possible scenario because prober able to
377 // resend packet before it was send.
378 // TODO(danilchap): Remove this corner case when prober would not be
379 // able to sneak in between packet saved to history for resending and
380 // pacer notified about existance of that packet for sending.
381 // See https://bugs.chromium.org/p/webrtc/issues/detail?id=5540 for
382 // details.
383 observation_complete_.Set();
384 }
385 return DROP_PACKET;
386 }
387
388 return SEND_PACKET;
389 }
390
391 void OnFrame(const VideoFrame& frame) override {
392 EXPECT_EQ(kVideoRotation_90, frame.rotation());
393 {
394 rtc::CritScope lock(&crit_);
395 if (frame.timestamp() == retransmitted_timestamp_)
396 observation_complete_.Set();
397 rendered_timestamps_.push_back(frame.timestamp());
398 }
399 orig_renderer_->OnFrame(frame);
400 }
401
402 void ModifyVideoConfigs(
403 VideoSendStream::Config* send_config,
404 std::vector<VideoReceiveStream::Config>* receive_configs,
405 VideoEncoderConfig* encoder_config) override {
406 send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
407
408 // Insert ourselves into the rendering pipeline.
409 RTC_DCHECK(!orig_renderer_);
410 orig_renderer_ = (*receive_configs)[0].renderer;
411 RTC_DCHECK(orig_renderer_);
412 (*receive_configs)[0].disable_prerenderer_smoothing = true;
413 (*receive_configs)[0].renderer = this;
414
415 (*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
416
417 if (payload_type_ == kRedPayloadType) {
418 send_config->rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
419 send_config->rtp.ulpfec.red_payload_type = kRedPayloadType;
420 if (retransmission_ssrc_ == kSendRtxSsrcs[0])
421 send_config->rtp.ulpfec.red_rtx_payload_type = kRtxRedPayloadType;
422 (*receive_configs)[0].rtp.ulpfec_payload_type =
423 send_config->rtp.ulpfec.ulpfec_payload_type;
424 (*receive_configs)[0].rtp.red_payload_type =
425 send_config->rtp.ulpfec.red_payload_type;
426 }
427
428 if (retransmission_ssrc_ == kSendRtxSsrcs[0]) {
429 send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
430 send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
431 (*receive_configs)[0].rtp.rtx_ssrc = kSendRtxSsrcs[0];
432 (*receive_configs)[0]
433 .rtp.rtx_associated_payload_types[(payload_type_ == kRedPayloadType)
434 ? kRtxRedPayloadType
435 : kSendRtxPayloadType] =
436 payload_type_;
437 }
438 // Configure encoding and decoding with VP8, since generic packetization
439 // doesn't support FEC with NACK.
440 RTC_DCHECK_EQ(1, (*receive_configs)[0].decoders.size());
Niels Möller4db138e2018-04-19 07:04:13441 send_config->encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 13:36:51442 send_config->rtp.payload_name = "VP8";
443 encoder_config->codec_type = kVideoCodecVP8;
Sebastian Janssonc5017132018-02-02 15:24:16444 (*receive_configs)[0].decoders[0].payload_name = "VP8";
445 }
446
447 void OnFrameGeneratorCapturerCreated(
448 test::FrameGeneratorCapturer* frame_generator_capturer) override {
449 frame_generator_capturer->SetFakeRotation(kVideoRotation_90);
450 }
451
452 void PerformTest() override {
453 EXPECT_TRUE(Wait())
454 << "Timed out while waiting for retransmission to render.";
455 }
456
457 int GetPayloadType(bool use_rtx, bool use_fec) {
458 if (use_fec) {
459 if (use_rtx)
460 return kRtxRedPayloadType;
461 return kRedPayloadType;
462 }
463 if (use_rtx)
464 return kSendRtxPayloadType;
465 return kFakeVideoSendPayloadType;
466 }
467
468 rtc::CriticalSection crit_;
469 rtc::VideoSinkInterface<VideoFrame>* orig_renderer_ = nullptr;
470 const int payload_type_;
471 const uint32_t retransmission_ssrc_;
472 const int retransmission_payload_type_;
Niels Möller4db138e2018-04-19 07:04:13473 test::FunctionVideoEncoderFactory encoder_factory_;
Sebastian Janssonc5017132018-02-02 15:24:16474 const std::string payload_name_;
475 int marker_bits_observed_;
476 uint32_t retransmitted_timestamp_ RTC_GUARDED_BY(&crit_);
477 std::vector<uint32_t> rendered_timestamps_ RTC_GUARDED_BY(&crit_);
478 } test(enable_rtx, enable_red);
479
480 RunBaseTest(&test);
481}
482
483TEST_P(RetransmissionEndToEndTest, DecodesRetransmittedFrame) {
484 DecodesRetransmittedFrame(false, false);
485}
486
487TEST_P(RetransmissionEndToEndTest, DecodesRetransmittedFrameOverRtx) {
488 DecodesRetransmittedFrame(true, false);
489}
490
491TEST_P(RetransmissionEndToEndTest, DecodesRetransmittedFrameByRed) {
492 DecodesRetransmittedFrame(false, true);
493}
494
495TEST_P(RetransmissionEndToEndTest, DecodesRetransmittedFrameByRedOverRtx) {
496 DecodesRetransmittedFrame(true, true);
497}
498
499} // namespace webrtc