blob: 89d68e1a6add8fedefba01536ddd300f841eafbf [file] [log] [blame]
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +00001/*
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +00002* 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
aleloia8eb7562016-11-28 07:02:13 -080017#include "webrtc/api/call/transport.h"
nissef54573b2017-09-13 07:13:57 -070018#include "webrtc/call/rtp_stream_receiver_controller.h"
19#include "webrtc/call/rtx_receive_stream.h"
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000020#include "webrtc/common_types.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010021#include "webrtc/modules/rtp_rtcp/include/receive_statistics.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010022#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
23#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
nissef54573b2017-09-13 07:13:57 -070024#include "webrtc/modules/rtp_rtcp/source/rtp_packet_received.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020025#include "webrtc/rtc_base/rate_limiter.h"
kwibergac9f8762016-09-30 22:29:43 -070026#include "webrtc/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
nissef54573b2017-09-13 07:13:57 -070065 void SetSendModule(RtpRtcp* rtpRtcpModule) {
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000066 module_ = rtpRtcpModule;
67 }
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +000068
danilchap162abd32015-12-10 02:39:40 -080069 void DropEveryNthPacket(int n) { packet_loss_ = n; }
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +000070
71 void DropConsecutivePackets(int start, int total) {
72 consecutive_drop_start_ = start;
73 consecutive_drop_end_ = start + total;
74 packet_loss_ = 0;
75 }
76
stefan1d8a5062015-10-02 03:39:33 -070077 bool SendRtp(const uint8_t* data,
78 size_t len,
79 const PacketOptions& options) override {
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +000080 count_++;
nissef54573b2017-09-13 07:13:57 -070081 RtpPacketReceived packet;
82 if (!packet.Parse(data, len))
nissea6468532017-09-08 05:00:54 -070083 return false;
nissef54573b2017-09-13 07:13:57 -070084 if (packet.Ssrc() == rtx_ssrc_) {
85 count_rtx_ssrc_++;
86 } else {
87 // For non-RTX packets only.
tereliuse64fbce2015-09-17 03:19:45 -070088 expected_sequence_numbers_.insert(expected_sequence_numbers_.end(),
nissef54573b2017-09-13 07:13:57 -070089 packet.SequenceNumber());
tereliuse64fbce2015-09-17 03:19:45 -070090 }
91 if (packet_loss_ > 0) {
92 if ((count_ % packet_loss_) == 0) {
pbos2d566682015-09-28 09:59:31 -070093 return true;
tereliuse64fbce2015-09-17 03:19:45 -070094 }
95 } else if (count_ >= consecutive_drop_start_ &&
96 count_ < consecutive_drop_end_) {
pbos2d566682015-09-28 09:59:31 -070097 return true;
tereliuse64fbce2015-09-17 03:19:45 -070098 }
nissef54573b2017-09-13 07:13:57 -070099 EXPECT_TRUE(stream_receiver_controller_.OnRtpPacket(packet));
pbos2d566682015-09-28 09:59:31 -0700100 return true;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000101 }
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000102
pbos2d566682015-09-28 09:59:31 -0700103 bool SendRtcp(const uint8_t* data, size_t len) override {
nisse479d3d72017-09-13 07:53:37 -0700104 module_->IncomingRtcpPacket((const uint8_t*)data, len);
105 return true;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000106 }
107 int count_;
108 int packet_loss_;
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000109 int consecutive_drop_start_;
110 int consecutive_drop_end_;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000111 uint32_t rtx_ssrc_;
112 int count_rtx_ssrc_;
113 RtpRtcp* module_;
nissef54573b2017-09-13 07:13:57 -0700114 RtpStreamReceiverController stream_receiver_controller_;
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000115 std::set<uint16_t> expected_sequence_numbers_;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000116};
117
stefan@webrtc.org41211462013-03-18 15:00:50 +0000118class RtpRtcpRtxNackTest : public ::testing::Test {
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000119 protected:
stefan@webrtc.org41211462013-03-18 15:00:50 +0000120 RtpRtcpRtxNackTest()
magjedf3feeff2016-11-25 06:40:25 -0800121 : rtp_rtcp_module_(nullptr),
nissef54573b2017-09-13 07:13:57 -0700122 transport_(kTestRtxSsrc),
123 rtx_stream_(&media_stream_,
124 rtx_associated_payload_types_,
125 kTestSsrc),
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000126 payload_data_length(sizeof(payload_data)),
sprangcd349d92016-07-13 09:11:28 -0700127 fake_clock(123456),
Erik Språng737336d2016-07-29 12:59:36 +0200128 retransmission_rate_limiter_(&fake_clock, kMaxRttMs) {}
stefan@webrtc.org41211462013-03-18 15:00:50 +0000129 ~RtpRtcpRtxNackTest() {}
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000130
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000131 void SetUp() override {
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000132 RtpRtcp::Configuration configuration;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000133 configuration.audio = false;
134 configuration.clock = &fake_clock;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000135 receive_statistics_.reset(ReceiveStatistics::Create(&fake_clock));
136 configuration.receive_statistics = receive_statistics_.get();
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000137 configuration.outgoing_transport = &transport_;
Erik Språng737336d2016-07-29 12:59:36 +0200138 configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000139 rtp_rtcp_module_ = RtpRtcp::CreateRtpRtcp(configuration);
140
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000141 rtp_rtcp_module_->SetSSRC(kTestSsrc);
pbosda903ea2015-10-02 02:36:56 -0700142 rtp_rtcp_module_->SetRTCPStatus(RtcpMode::kCompound);
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000143 rtp_rtcp_module_->SetStorePacketsStatus(true, 600);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000144 EXPECT_EQ(0, rtp_rtcp_module_->SetSendingStatus(true));
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000145 rtp_rtcp_module_->SetSequenceNumber(kTestSequenceNumber);
146 rtp_rtcp_module_->SetStartTimestamp(111111);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000147
nissef54573b2017-09-13 07:13:57 -0700148 // Used for NACK processing.
149 // TODO(nisse): Unclear on which side? It's confusing to use a
150 // single rtp_rtcp module for both send and receive side.
151 rtp_rtcp_module_->SetRemoteSSRC(kTestSsrc);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000152
nissef54573b2017-09-13 07:13:57 -0700153 rtp_rtcp_module_->RegisterVideoSendPayload(kPayloadType, "video");
Shao Changbine62202f2015-04-21 20:24:50 +0800154 rtp_rtcp_module_->SetRtxSendPayloadType(kRtxPayloadType, kPayloadType);
nissef54573b2017-09-13 07:13:57 -0700155 transport_.SetSendModule(rtp_rtcp_module_);
156 media_receiver_ = transport_.stream_receiver_controller_.CreateReceiver(
157 kTestSsrc, &media_stream_);
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000158
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000159 for (size_t n = 0; n < payload_data_length; n++) {
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000160 payload_data[n] = n % 10;
161 }
162 }
163
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000164 int BuildNackList(uint16_t* nack_list) {
nissef54573b2017-09-13 07:13:57 -0700165 media_stream_.sequence_numbers_.sort();
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000166 std::list<uint16_t> missing_sequence_numbers;
nissef54573b2017-09-13 07:13:57 -0700167 std::list<uint16_t>::iterator it = media_stream_.sequence_numbers_.begin();
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000168
nissef54573b2017-09-13 07:13:57 -0700169 while (it != media_stream_.sequence_numbers_.end()) {
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000170 uint16_t sequence_number_1 = *it;
171 ++it;
nissef54573b2017-09-13 07:13:57 -0700172 if (it != media_stream_.sequence_numbers_.end()) {
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000173 uint16_t sequence_number_2 = *it;
174 // Add all missing sequence numbers to list
danilchap162abd32015-12-10 02:39:40 -0800175 for (uint16_t i = sequence_number_1 + 1; i < sequence_number_2; ++i) {
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000176 missing_sequence_numbers.push_back(i);
177 }
178 }
179 }
180 int n = 0;
181 for (it = missing_sequence_numbers.begin();
danilchap162abd32015-12-10 02:39:40 -0800182 it != missing_sequence_numbers.end(); ++it) {
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000183 nack_list[n++] = (*it);
184 }
185 return n;
186 }
187
188 bool ExpectedPacketsReceived() {
189 std::list<uint16_t> received_sorted;
nissef54573b2017-09-13 07:13:57 -0700190 std::copy(media_stream_.sequence_numbers_.begin(),
191 media_stream_.sequence_numbers_.end(),
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000192 std::back_inserter(received_sorted));
193 received_sorted.sort();
tereliuse64fbce2015-09-17 03:19:45 -0700194 return received_sorted.size() ==
195 transport_.expected_sequence_numbers_.size() &&
196 std::equal(received_sorted.begin(), received_sorted.end(),
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000197 transport_.expected_sequence_numbers_.begin());
198 }
199
200 void RunRtxTest(RtxMode rtx_method, int loss) {
nissef54573b2017-09-13 07:13:57 -0700201 rtx_receiver_ = transport_.stream_receiver_controller_.CreateReceiver(
202 kTestRtxSsrc, &rtx_stream_);
pbos@webrtc.org0b0c2412015-01-13 14:15:15 +0000203 rtp_rtcp_module_->SetRtxSendStatus(rtx_method);
nissef54573b2017-09-13 07:13:57 -0700204 rtp_rtcp_module_->SetRtxSsrc(kTestRtxSsrc);
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000205 transport_.DropEveryNthPacket(loss);
206 uint32_t timestamp = 3000;
207 uint16_t nack_list[kVideoNackListSize];
208 for (int frame = 0; frame < kNumFrames; ++frame) {
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700209 EXPECT_TRUE(rtp_rtcp_module_->SendOutgoingData(
210 webrtc::kVideoFrameDelta, kPayloadType, timestamp, timestamp / 90,
211 payload_data, payload_data_length, nullptr, nullptr, nullptr));
sprang@webrtc.org43c88392015-01-29 09:09:17 +0000212 // Min required delay until retransmit = 5 + RTT ms (RTT = 0).
213 fake_clock.AdvanceTimeMilliseconds(5);
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000214 int length = BuildNackList(nack_list);
215 if (length > 0)
216 rtp_rtcp_module_->SendNACK(nack_list, length);
sprang@webrtc.org43c88392015-01-29 09:09:17 +0000217 fake_clock.AdvanceTimeMilliseconds(28); // 33ms - 5ms delay.
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000218 rtp_rtcp_module_->Process();
219 // Prepare next frame.
220 timestamp += 3000;
221 }
nissef54573b2017-09-13 07:13:57 -0700222 media_stream_.sequence_numbers_.sort();
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000223 }
224
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000225 void TearDown() override { delete rtp_rtcp_module_; }
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000226
kwiberg84be5112016-04-27 01:19:58 -0700227 std::unique_ptr<ReceiveStatistics> receive_statistics_;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000228 RtpRtcp* rtp_rtcp_module_;
229 RtxLoopBackTransport transport_;
nissef54573b2017-09-13 07:13:57 -0700230 const std::map<int, int> rtx_associated_payload_types_ =
231 {{kRtxPayloadType, kPayloadType}};
232 VerifyingMediaStream media_stream_;
233 RtxReceiveStream rtx_stream_;
danilchap162abd32015-12-10 02:39:40 -0800234 uint8_t payload_data[65000];
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000235 size_t payload_data_length;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000236 SimulatedClock fake_clock;
Erik Språng737336d2016-07-29 12:59:36 +0200237 RateLimiter retransmission_rate_limiter_;
nissef54573b2017-09-13 07:13:57 -0700238 std::unique_ptr<RtpStreamReceiverInterface> media_receiver_;
239 std::unique_ptr<RtpStreamReceiverInterface> rtx_receiver_;
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000240};
241
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000242TEST_F(RtpRtcpRtxNackTest, LongNackList) {
243 const int kNumPacketsToDrop = 900;
244 const int kNumRequiredRtcp = 4;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000245 uint32_t timestamp = 3000;
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000246 uint16_t nack_list[kNumPacketsToDrop];
247 // Disable StorePackets to be able to set a larger packet history.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000248 rtp_rtcp_module_->SetStorePacketsStatus(false, 0);
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000249 // Enable StorePackets with a packet history of 2000 packets.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000250 rtp_rtcp_module_->SetStorePacketsStatus(true, 2000);
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000251 // Drop 900 packets from the second one so that we get a NACK list which is
252 // big enough to require 4 RTCP packets to be fully transmitted to the sender.
253 transport_.DropConsecutivePackets(2, kNumPacketsToDrop);
254 // Send 30 frames which at the default size is roughly what we need to get
255 // enough packets.
256 for (int frame = 0; frame < kNumFrames; ++frame) {
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700257 EXPECT_TRUE(rtp_rtcp_module_->SendOutgoingData(
258 webrtc::kVideoFrameDelta, kPayloadType, timestamp, timestamp / 90,
259 payload_data, payload_data_length, nullptr, nullptr, nullptr));
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000260 // Prepare next frame.
261 timestamp += 3000;
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000262 fake_clock.AdvanceTimeMilliseconds(33);
263 rtp_rtcp_module_->Process();
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000264 }
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000265 EXPECT_FALSE(transport_.expected_sequence_numbers_.empty());
nissef54573b2017-09-13 07:13:57 -0700266 EXPECT_FALSE(media_stream_.sequence_numbers_.empty());
267 size_t last_receive_count = media_stream_.sequence_numbers_.size();
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000268 int length = BuildNackList(nack_list);
269 for (int i = 0; i < kNumRequiredRtcp - 1; ++i) {
270 rtp_rtcp_module_->SendNACK(nack_list, length);
nissef54573b2017-09-13 07:13:57 -0700271 EXPECT_GT(media_stream_.sequence_numbers_.size(), last_receive_count);
272 last_receive_count = media_stream_.sequence_numbers_.size();
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000273 EXPECT_FALSE(ExpectedPacketsReceived());
274 }
275 rtp_rtcp_module_->SendNACK(nack_list, length);
nissef54573b2017-09-13 07:13:57 -0700276 EXPECT_GT(media_stream_.sequence_numbers_.size(), last_receive_count);
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000277 EXPECT_TRUE(ExpectedPacketsReceived());
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000278}
279
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000280TEST_F(RtpRtcpRtxNackTest, RtxNack) {
281 RunRtxTest(kRtxRetransmitted, 10);
nissef54573b2017-09-13 07:13:57 -0700282 EXPECT_EQ(kTestSequenceNumber, *(media_stream_.sequence_numbers_.begin()));
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000283 EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1,
nissef54573b2017-09-13 07:13:57 -0700284 *(media_stream_.sequence_numbers_.rbegin()));
285 EXPECT_EQ(kTestNumberOfPackets, media_stream_.sequence_numbers_.size());
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000286 EXPECT_EQ(kTestNumberOfRtxPackets, transport_.count_rtx_ssrc_);
mikhal@webrtc.org6cfa3902013-05-15 20:17:43 +0000287 EXPECT_TRUE(ExpectedPacketsReceived());
mikhal@webrtc.orgbda7f302013-03-15 23:21:52 +0000288}
danilchap6a6f0892015-12-10 12:39:08 -0800289
290} // namespace webrtc