blob: 7ecec76474641ccba9ec3dbd97f5f921f346f302 [file] [log] [blame]
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +00001/*
Yves Gerey665174f2018-06-19 15:03:05 +02002 * Copyright (c) 2013 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 */
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000010
11#include <algorithm>
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +000012#include <iterator>
13#include <list>
kwiberg84be5112016-04-27 01:19:58 -070014#include <memory>
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +000015#include <set>
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000016
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "api/call/transport.h"
18#include "call/rtp_stream_receiver_controller.h"
19#include "call/rtx_receive_stream.h"
Mirko Bonadei71207422017-09-15 13:58:09 +020020#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "modules/rtp_rtcp/include/receive_statistics.h"
22#include "modules/rtp_rtcp/include/rtp_rtcp.h"
23#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
24#include "modules/rtp_rtcp/source/rtp_packet_received.h"
25#include "rtc_base/rate_limiter.h"
26#include "test/gtest.h"
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000027
danilchap6a6f0892015-12-10 12:39:08 -080028namespace webrtc {
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +000029
30const int kVideoNackListSize = 30;
pbos@webrtc.org2f446732013-04-08 11:08:41 +000031const uint32_t kTestSsrc = 3456;
nissef54573b2017-09-13 07:13:57 -070032const uint32_t kTestRtxSsrc = kTestSsrc + 1;
pbos@webrtc.org2f446732013-04-08 11:08:41 +000033const uint16_t kTestSequenceNumber = 2345;
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +000034const uint32_t kTestNumberOfPackets = 1350;
35const int kTestNumberOfRtxPackets = 149;
36const int kNumFrames = 30;
Shao Changbine62202f2015-04-21 20:24:50 +080037const int kPayloadType = 123;
38const int kRtxPayloadType = 98;
sprangcd349d92016-07-13 09:11:28 -070039const int64_t kMaxRttMs = 1000;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000040
nissef54573b2017-09-13 07:13:57 -070041class VerifyingMediaStream : public RtpPacketSinkInterface {
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000042 public:
nissef54573b2017-09-13 07:13:57 -070043 VerifyingMediaStream() {}
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000044
nissef54573b2017-09-13 07:13:57 -070045 void OnRtpPacket(const RtpPacketReceived& packet) override {
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +000046 if (!sequence_numbers_.empty())
nissef54573b2017-09-13 07:13:57 -070047 EXPECT_EQ(kTestSsrc, packet.Ssrc());
48
49 sequence_numbers_.push_back(packet.SequenceNumber());
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000050 }
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +000051 std::list<uint16_t> sequence_numbers_;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000052};
53
54class RtxLoopBackTransport : public webrtc::Transport {
55 public:
56 explicit RtxLoopBackTransport(uint32_t rtx_ssrc)
57 : count_(0),
58 packet_loss_(0),
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +000059 consecutive_drop_start_(0),
60 consecutive_drop_end_(0),
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000061 rtx_ssrc_(rtx_ssrc),
62 count_rtx_ssrc_(0),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +000063 module_(NULL) {}
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +000064
Yves Gerey665174f2018-06-19 15:03:05 +020065 void SetSendModule(RtpRtcp* rtpRtcpModule) { module_ = rtpRtcpModule; }
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +000066
danilchap162abd32015-12-10 02:39:40 -080067 void DropEveryNthPacket(int n) { packet_loss_ = n; }
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +000068
69 void DropConsecutivePackets(int start, int total) {
70 consecutive_drop_start_ = start;
71 consecutive_drop_end_ = start + total;
72 packet_loss_ = 0;
73 }
74
stefan1d8a5062015-10-02 03:39:33 -070075 bool SendRtp(const uint8_t* data,
76 size_t len,
77 const PacketOptions& options) override {
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000078 count_++;
nissef54573b2017-09-13 07:13:57 -070079 RtpPacketReceived packet;
80 if (!packet.Parse(data, len))
nissea6468532017-09-08 05:00:54 -070081 return false;
nissef54573b2017-09-13 07:13:57 -070082 if (packet.Ssrc() == rtx_ssrc_) {
83 count_rtx_ssrc_++;
84 } else {
85 // For non-RTX packets only.
tereliuse64fbce2015-09-17 03:19:45 -070086 expected_sequence_numbers_.insert(expected_sequence_numbers_.end(),
nissef54573b2017-09-13 07:13:57 -070087 packet.SequenceNumber());
tereliuse64fbce2015-09-17 03:19:45 -070088 }
89 if (packet_loss_ > 0) {
90 if ((count_ % packet_loss_) == 0) {
pbos2d566682015-09-28 09:59:31 -070091 return true;
tereliuse64fbce2015-09-17 03:19:45 -070092 }
93 } else if (count_ >= consecutive_drop_start_ &&
94 count_ < consecutive_drop_end_) {
pbos2d566682015-09-28 09:59:31 -070095 return true;
tereliuse64fbce2015-09-17 03:19:45 -070096 }
nissef54573b2017-09-13 07:13:57 -070097 EXPECT_TRUE(stream_receiver_controller_.OnRtpPacket(packet));
pbos2d566682015-09-28 09:59:31 -070098 return true;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000099 }
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000100
pbos2d566682015-09-28 09:59:31 -0700101 bool SendRtcp(const uint8_t* data, size_t len) override {
nisse479d3d72017-09-13 07:53:37 -0700102 module_->IncomingRtcpPacket((const uint8_t*)data, len);
103 return true;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000104 }
105 int count_;
106 int packet_loss_;
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000107 int consecutive_drop_start_;
108 int consecutive_drop_end_;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000109 uint32_t rtx_ssrc_;
110 int count_rtx_ssrc_;
111 RtpRtcp* module_;
nissef54573b2017-09-13 07:13:57 -0700112 RtpStreamReceiverController stream_receiver_controller_;
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000113 std::set<uint16_t> expected_sequence_numbers_;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000114};
115
stefan@webrtc.org41211462013-03-18 15:00:50 +0000116class RtpRtcpRtxNackTest : public ::testing::Test {
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000117 protected:
stefan@webrtc.org41211462013-03-18 15:00:50 +0000118 RtpRtcpRtxNackTest()
magjedf3feeff2016-11-25 06:40:25 -0800119 : rtp_rtcp_module_(nullptr),
nissef54573b2017-09-13 07:13:57 -0700120 transport_(kTestRtxSsrc),
Yves Gerey665174f2018-06-19 15:03:05 +0200121 rtx_stream_(&media_stream_, rtx_associated_payload_types_, kTestSsrc),
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000122 payload_data_length(sizeof(payload_data)),
sprangcd349d92016-07-13 09:11:28 -0700123 fake_clock(123456),
Erik Språng737336d2016-07-29 12:59:36 +0200124 retransmission_rate_limiter_(&fake_clock, kMaxRttMs) {}
Danil Chapovalovdd7e2842018-03-09 15:37:03 +0000125 ~RtpRtcpRtxNackTest() override {}
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000126
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000127 void SetUp() override {
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000128 RtpRtcp::Configuration configuration;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000129 configuration.audio = false;
130 configuration.clock = &fake_clock;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000131 receive_statistics_.reset(ReceiveStatistics::Create(&fake_clock));
132 configuration.receive_statistics = receive_statistics_.get();
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000133 configuration.outgoing_transport = &transport_;
Erik Språng737336d2016-07-29 12:59:36 +0200134 configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000135 rtp_rtcp_module_ = RtpRtcp::CreateRtpRtcp(configuration);
136
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000137 rtp_rtcp_module_->SetSSRC(kTestSsrc);
pbosda903ea2015-10-02 02:36:56 -0700138 rtp_rtcp_module_->SetRTCPStatus(RtcpMode::kCompound);
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000139 rtp_rtcp_module_->SetStorePacketsStatus(true, 600);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000140 EXPECT_EQ(0, rtp_rtcp_module_->SetSendingStatus(true));
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000141 rtp_rtcp_module_->SetSequenceNumber(kTestSequenceNumber);
142 rtp_rtcp_module_->SetStartTimestamp(111111);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000143
nissef54573b2017-09-13 07:13:57 -0700144 // Used for NACK processing.
145 // TODO(nisse): Unclear on which side? It's confusing to use a
146 // single rtp_rtcp module for both send and receive side.
147 rtp_rtcp_module_->SetRemoteSSRC(kTestSsrc);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000148
nissef54573b2017-09-13 07:13:57 -0700149 rtp_rtcp_module_->RegisterVideoSendPayload(kPayloadType, "video");
Shao Changbine62202f2015-04-21 20:24:50 +0800150 rtp_rtcp_module_->SetRtxSendPayloadType(kRtxPayloadType, kPayloadType);
nissef54573b2017-09-13 07:13:57 -0700151 transport_.SetSendModule(rtp_rtcp_module_);
152 media_receiver_ = transport_.stream_receiver_controller_.CreateReceiver(
153 kTestSsrc, &media_stream_);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000154
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000155 for (size_t n = 0; n < payload_data_length; n++) {
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000156 payload_data[n] = n % 10;
157 }
158 }
159
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000160 int BuildNackList(uint16_t* nack_list) {
nissef54573b2017-09-13 07:13:57 -0700161 media_stream_.sequence_numbers_.sort();
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000162 std::list<uint16_t> missing_sequence_numbers;
nissef54573b2017-09-13 07:13:57 -0700163 std::list<uint16_t>::iterator it = media_stream_.sequence_numbers_.begin();
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000164
nissef54573b2017-09-13 07:13:57 -0700165 while (it != media_stream_.sequence_numbers_.end()) {
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000166 uint16_t sequence_number_1 = *it;
167 ++it;
nissef54573b2017-09-13 07:13:57 -0700168 if (it != media_stream_.sequence_numbers_.end()) {
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000169 uint16_t sequence_number_2 = *it;
170 // Add all missing sequence numbers to list
danilchap162abd32015-12-10 02:39:40 -0800171 for (uint16_t i = sequence_number_1 + 1; i < sequence_number_2; ++i) {
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000172 missing_sequence_numbers.push_back(i);
173 }
174 }
175 }
176 int n = 0;
177 for (it = missing_sequence_numbers.begin();
danilchap162abd32015-12-10 02:39:40 -0800178 it != missing_sequence_numbers.end(); ++it) {
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000179 nack_list[n++] = (*it);
180 }
181 return n;
182 }
183
184 bool ExpectedPacketsReceived() {
185 std::list<uint16_t> received_sorted;
nissef54573b2017-09-13 07:13:57 -0700186 std::copy(media_stream_.sequence_numbers_.begin(),
187 media_stream_.sequence_numbers_.end(),
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000188 std::back_inserter(received_sorted));
189 received_sorted.sort();
tereliuse64fbce2015-09-17 03:19:45 -0700190 return received_sorted.size() ==
191 transport_.expected_sequence_numbers_.size() &&
192 std::equal(received_sorted.begin(), received_sorted.end(),
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000193 transport_.expected_sequence_numbers_.begin());
194 }
195
196 void RunRtxTest(RtxMode rtx_method, int loss) {
nissef54573b2017-09-13 07:13:57 -0700197 rtx_receiver_ = transport_.stream_receiver_controller_.CreateReceiver(
198 kTestRtxSsrc, &rtx_stream_);
pbos@webrtc.org0b0c2412015-01-13 14:15:15 +0000199 rtp_rtcp_module_->SetRtxSendStatus(rtx_method);
nissef54573b2017-09-13 07:13:57 -0700200 rtp_rtcp_module_->SetRtxSsrc(kTestRtxSsrc);
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000201 transport_.DropEveryNthPacket(loss);
202 uint32_t timestamp = 3000;
203 uint16_t nack_list[kVideoNackListSize];
204 for (int frame = 0; frame < kNumFrames; ++frame) {
Sami Kalliomäki426a80c2018-08-08 11:37:59 +0200205 RTPVideoHeader video_header;
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700206 EXPECT_TRUE(rtp_rtcp_module_->SendOutgoingData(
207 webrtc::kVideoFrameDelta, kPayloadType, timestamp, timestamp / 90,
Sami Kalliomäki426a80c2018-08-08 11:37:59 +0200208 payload_data, payload_data_length, nullptr, &video_header, nullptr));
sprang@webrtc.org43c88392015-01-29 09:09:17 +0000209 // Min required delay until retransmit = 5 + RTT ms (RTT = 0).
210 fake_clock.AdvanceTimeMilliseconds(5);
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000211 int length = BuildNackList(nack_list);
212 if (length > 0)
213 rtp_rtcp_module_->SendNACK(nack_list, length);
sprang@webrtc.org43c88392015-01-29 09:09:17 +0000214 fake_clock.AdvanceTimeMilliseconds(28); // 33ms - 5ms delay.
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000215 rtp_rtcp_module_->Process();
216 // Prepare next frame.
217 timestamp += 3000;
218 }
nissef54573b2017-09-13 07:13:57 -0700219 media_stream_.sequence_numbers_.sort();
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000220 }
221
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000222 void TearDown() override { delete rtp_rtcp_module_; }
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000223
kwiberg84be5112016-04-27 01:19:58 -0700224 std::unique_ptr<ReceiveStatistics> receive_statistics_;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000225 RtpRtcp* rtp_rtcp_module_;
226 RtxLoopBackTransport transport_;
Yves Gerey665174f2018-06-19 15:03:05 +0200227 const std::map<int, int> rtx_associated_payload_types_ = {
228 {kRtxPayloadType, kPayloadType}};
nissef54573b2017-09-13 07:13:57 -0700229 VerifyingMediaStream media_stream_;
230 RtxReceiveStream rtx_stream_;
danilchap162abd32015-12-10 02:39:40 -0800231 uint8_t payload_data[65000];
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000232 size_t payload_data_length;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000233 SimulatedClock fake_clock;
Erik Språng737336d2016-07-29 12:59:36 +0200234 RateLimiter retransmission_rate_limiter_;
nissef54573b2017-09-13 07:13:57 -0700235 std::unique_ptr<RtpStreamReceiverInterface> media_receiver_;
236 std::unique_ptr<RtpStreamReceiverInterface> rtx_receiver_;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000237};
238
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000239TEST_F(RtpRtcpRtxNackTest, LongNackList) {
240 const int kNumPacketsToDrop = 900;
241 const int kNumRequiredRtcp = 4;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000242 uint32_t timestamp = 3000;
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000243 uint16_t nack_list[kNumPacketsToDrop];
244 // Disable StorePackets to be able to set a larger packet history.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000245 rtp_rtcp_module_->SetStorePacketsStatus(false, 0);
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000246 // Enable StorePackets with a packet history of 2000 packets.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000247 rtp_rtcp_module_->SetStorePacketsStatus(true, 2000);
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000248 // Drop 900 packets from the second one so that we get a NACK list which is
249 // big enough to require 4 RTCP packets to be fully transmitted to the sender.
250 transport_.DropConsecutivePackets(2, kNumPacketsToDrop);
251 // Send 30 frames which at the default size is roughly what we need to get
252 // enough packets.
253 for (int frame = 0; frame < kNumFrames; ++frame) {
Sami Kalliomäki426a80c2018-08-08 11:37:59 +0200254 RTPVideoHeader video_header;
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700255 EXPECT_TRUE(rtp_rtcp_module_->SendOutgoingData(
256 webrtc::kVideoFrameDelta, kPayloadType, timestamp, timestamp / 90,
Sami Kalliomäki426a80c2018-08-08 11:37:59 +0200257 payload_data, payload_data_length, nullptr, &video_header, nullptr));
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000258 // Prepare next frame.
259 timestamp += 3000;
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000260 fake_clock.AdvanceTimeMilliseconds(33);
261 rtp_rtcp_module_->Process();
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000262 }
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000263 EXPECT_FALSE(transport_.expected_sequence_numbers_.empty());
nissef54573b2017-09-13 07:13:57 -0700264 EXPECT_FALSE(media_stream_.sequence_numbers_.empty());
265 size_t last_receive_count = media_stream_.sequence_numbers_.size();
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000266 int length = BuildNackList(nack_list);
267 for (int i = 0; i < kNumRequiredRtcp - 1; ++i) {
268 rtp_rtcp_module_->SendNACK(nack_list, length);
nissef54573b2017-09-13 07:13:57 -0700269 EXPECT_GT(media_stream_.sequence_numbers_.size(), last_receive_count);
270 last_receive_count = media_stream_.sequence_numbers_.size();
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000271 EXPECT_FALSE(ExpectedPacketsReceived());
272 }
273 rtp_rtcp_module_->SendNACK(nack_list, length);
nissef54573b2017-09-13 07:13:57 -0700274 EXPECT_GT(media_stream_.sequence_numbers_.size(), last_receive_count);
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000275 EXPECT_TRUE(ExpectedPacketsReceived());
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000276}
277
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000278TEST_F(RtpRtcpRtxNackTest, RtxNack) {
279 RunRtxTest(kRtxRetransmitted, 10);
nissef54573b2017-09-13 07:13:57 -0700280 EXPECT_EQ(kTestSequenceNumber, *(media_stream_.sequence_numbers_.begin()));
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000281 EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1,
nissef54573b2017-09-13 07:13:57 -0700282 *(media_stream_.sequence_numbers_.rbegin()));
283 EXPECT_EQ(kTestNumberOfPackets, media_stream_.sequence_numbers_.size());
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000284 EXPECT_EQ(kTestNumberOfRtxPackets, transport_.count_rtx_ssrc_);
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000285 EXPECT_TRUE(ExpectedPacketsReceived());
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000286}
danilchap6a6f0892015-12-10 12:39:08 -0800287
288} // namespace webrtc