mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 1 | /* |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 2 | * 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.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 10 | |
| 11 | #include <algorithm> |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 12 | #include <iterator> |
| 13 | #include <list> |
kwiberg | 6e27acd | 2016-04-27 08:19:58 | [diff] [blame] | 14 | #include <memory> |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 15 | #include <set> |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 16 | |
| 17 | #include "testing/gtest/include/gtest/gtest.h" |
| 18 | #include "webrtc/common_types.h" |
Henrik Kjellander | 36a14b5 | 2015-11-04 07:31:52 | [diff] [blame] | 19 | #include "webrtc/modules/rtp_rtcp/include/receive_statistics.h" |
| 20 | #include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h" |
| 21 | #include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h" |
| 22 | #include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h" |
| 23 | #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h" |
| 24 | #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" |
pbos | d5bdda3 | 2015-09-28 16:59:31 | [diff] [blame] | 25 | #include "webrtc/transport.h" |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 26 | |
danilchap | 090af54 | 2015-12-10 20:39:08 | [diff] [blame] | 27 | namespace webrtc { |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 28 | |
| 29 | const int kVideoNackListSize = 30; |
pbos@webrtc.org | b57da65 | 2013-04-08 11:08:41 | [diff] [blame] | 30 | const uint32_t kTestSsrc = 3456; |
| 31 | const uint16_t kTestSequenceNumber = 2345; |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 32 | const uint32_t kTestNumberOfPackets = 1350; |
| 33 | const int kTestNumberOfRtxPackets = 149; |
| 34 | const int kNumFrames = 30; |
Shao Changbin | 0f07171 | 2015-04-21 12:24:50 | [diff] [blame] | 35 | const int kPayloadType = 123; |
| 36 | const int kRtxPayloadType = 98; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 37 | |
danilchap | 3bf825b | 2015-12-10 10:39:40 | [diff] [blame] | 38 | class VerifyingRtxReceiver : public NullRtpData { |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 39 | public: |
| 40 | VerifyingRtxReceiver() {} |
| 41 | |
kjellander@webrtc.org | 860ac53 | 2015-03-04 12:58:35 | [diff] [blame] | 42 | int32_t OnReceivedPayloadData( |
pbos@webrtc.org | b57da65 | 2013-04-08 11:08:41 | [diff] [blame] | 43 | const uint8_t* data, |
Peter Boström | c9da01c | 2016-06-14 10:52:54 | [diff] [blame] | 44 | size_t size, |
kjellander@webrtc.org | 860ac53 | 2015-03-04 12:58:35 | [diff] [blame] | 45 | const webrtc::WebRtcRTPHeader* rtp_header) override { |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 46 | if (!sequence_numbers_.empty()) |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 47 | EXPECT_EQ(kTestSsrc, rtp_header->header.ssrc); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 48 | sequence_numbers_.push_back(rtp_header->header.sequenceNumber); |
| 49 | return 0; |
| 50 | } |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 51 | std::list<uint16_t> sequence_numbers_; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 52 | }; |
| 53 | |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 54 | class TestRtpFeedback : public NullRtpFeedback { |
| 55 | public: |
danilchap | 9bcfdee | 2015-12-15 10:54:47 | [diff] [blame] | 56 | explicit TestRtpFeedback(RtpRtcp* rtp_rtcp) : rtp_rtcp_(rtp_rtcp) {} |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 57 | virtual ~TestRtpFeedback() {} |
| 58 | |
Peter Boström | 00a7fa4 | 2015-09-17 21:03:57 | [diff] [blame] | 59 | void OnIncomingSSRCChanged(const uint32_t ssrc) override { |
stefan@webrtc.org | a20e2d4 | 2013-08-21 20:58:21 | [diff] [blame] | 60 | rtp_rtcp_->SetRemoteSSRC(ssrc); |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 61 | } |
| 62 | |
| 63 | private: |
| 64 | RtpRtcp* rtp_rtcp_; |
| 65 | }; |
| 66 | |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 67 | class RtxLoopBackTransport : public webrtc::Transport { |
| 68 | public: |
| 69 | explicit RtxLoopBackTransport(uint32_t rtx_ssrc) |
| 70 | : count_(0), |
| 71 | packet_loss_(0), |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 72 | consecutive_drop_start_(0), |
| 73 | consecutive_drop_end_(0), |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 74 | rtx_ssrc_(rtx_ssrc), |
| 75 | count_rtx_ssrc_(0), |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 76 | rtp_payload_registry_(NULL), |
| 77 | rtp_receiver_(NULL), |
stefan@webrtc.org | db74c61 | 2013-09-06 13:40:11 | [diff] [blame] | 78 | module_(NULL) {} |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 79 | |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 80 | void SetSendModule(RtpRtcp* rtpRtcpModule, |
| 81 | RTPPayloadRegistry* rtp_payload_registry, |
| 82 | RtpReceiver* receiver) { |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 83 | module_ = rtpRtcpModule; |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 84 | rtp_payload_registry_ = rtp_payload_registry; |
| 85 | rtp_receiver_ = receiver; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 86 | } |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 87 | |
danilchap | 3bf825b | 2015-12-10 10:39:40 | [diff] [blame] | 88 | void DropEveryNthPacket(int n) { packet_loss_ = n; } |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 89 | |
| 90 | void DropConsecutivePackets(int start, int total) { |
| 91 | consecutive_drop_start_ = start; |
| 92 | consecutive_drop_end_ = start + total; |
| 93 | packet_loss_ = 0; |
| 94 | } |
| 95 | |
stefan | eb16b93 | 2015-10-02 10:39:33 | [diff] [blame] | 96 | bool SendRtp(const uint8_t* data, |
| 97 | size_t len, |
| 98 | const PacketOptions& options) override { |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 99 | count_++; |
danilchap | 3bf825b | 2015-12-10 10:39:40 | [diff] [blame] | 100 | const unsigned char* ptr = static_cast<const unsigned char*>(data); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 101 | uint32_t ssrc = (ptr[8] << 24) + (ptr[9] << 16) + (ptr[10] << 8) + ptr[11]; |
danilchap | 3bf825b | 2015-12-10 10:39:40 | [diff] [blame] | 102 | if (ssrc == rtx_ssrc_) |
| 103 | count_rtx_ssrc_++; |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 104 | uint16_t sequence_number = (ptr[2] << 8) + ptr[3]; |
pkasting@chromium.org | 0ab923a | 2014-11-20 22:28:14 | [diff] [blame] | 105 | size_t packet_length = len; |
pbos | 2c58add | 2015-11-17 01:19:34 | [diff] [blame] | 106 | uint8_t restored_packet[1500]; |
stefan@webrtc.org | 6696fba | 2013-05-29 12:12:51 | [diff] [blame] | 107 | RTPHeader header; |
kwiberg | 6e27acd | 2016-04-27 08:19:58 | [diff] [blame] | 108 | std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create()); |
stefan@webrtc.org | db74c61 | 2013-09-06 13:40:11 | [diff] [blame] | 109 | if (!parser->Parse(ptr, len, &header)) { |
pbos | d5bdda3 | 2015-09-28 16:59:31 | [diff] [blame] | 110 | return false; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 111 | } |
terelius | e2c9853 | 2015-09-17 10:19:45 | [diff] [blame] | 112 | |
| 113 | if (!rtp_payload_registry_->IsRtx(header)) { |
| 114 | // Don't store retransmitted packets since we compare it to the list |
| 115 | // created by the receiver. |
| 116 | expected_sequence_numbers_.insert(expected_sequence_numbers_.end(), |
| 117 | sequence_number); |
| 118 | } |
| 119 | if (packet_loss_ > 0) { |
| 120 | if ((count_ % packet_loss_) == 0) { |
pbos | d5bdda3 | 2015-09-28 16:59:31 | [diff] [blame] | 121 | return true; |
terelius | e2c9853 | 2015-09-17 10:19:45 | [diff] [blame] | 122 | } |
| 123 | } else if (count_ >= consecutive_drop_start_ && |
| 124 | count_ < consecutive_drop_end_) { |
pbos | d5bdda3 | 2015-09-28 16:59:31 | [diff] [blame] | 125 | return true; |
terelius | e2c9853 | 2015-09-17 10:19:45 | [diff] [blame] | 126 | } |
stefan@webrtc.org | db74c61 | 2013-09-06 13:40:11 | [diff] [blame] | 127 | if (rtp_payload_registry_->IsRtx(header)) { |
| 128 | // Remove the RTX header and parse the original RTP header. |
| 129 | EXPECT_TRUE(rtp_payload_registry_->RestoreOriginalPacket( |
noahric | 95c84b7 | 2015-10-14 18:29:49 | [diff] [blame] | 130 | restored_packet, ptr, &packet_length, rtp_receiver_->SSRC(), header)); |
| 131 | if (!parser->Parse(restored_packet, packet_length, &header)) { |
pbos | d5bdda3 | 2015-09-28 16:59:31 | [diff] [blame] | 132 | return false; |
stefan@webrtc.org | db74c61 | 2013-09-06 13:40:11 | [diff] [blame] | 133 | } |
pbos | 2c58add | 2015-11-17 01:19:34 | [diff] [blame] | 134 | ptr = restored_packet; |
Shao Changbin | 0f07171 | 2015-04-21 12:24:50 | [diff] [blame] | 135 | } else { |
| 136 | rtp_payload_registry_->SetIncomingPayloadType(header); |
stefan@webrtc.org | db74c61 | 2013-09-06 13:40:11 | [diff] [blame] | 137 | } |
Shao Changbin | 0f07171 | 2015-04-21 12:24:50 | [diff] [blame] | 138 | |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 139 | PayloadUnion payload_specific; |
| 140 | if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType, |
stefan@webrtc.org | db74c61 | 2013-09-06 13:40:11 | [diff] [blame] | 141 | &payload_specific)) { |
pbos | d5bdda3 | 2015-09-28 16:59:31 | [diff] [blame] | 142 | return false; |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 143 | } |
pbos | 2c58add | 2015-11-17 01:19:34 | [diff] [blame] | 144 | if (!rtp_receiver_->IncomingRtpPacket(header, ptr + header.headerLength, |
| 145 | packet_length - header.headerLength, |
| 146 | payload_specific, true)) { |
pbos | d5bdda3 | 2015-09-28 16:59:31 | [diff] [blame] | 147 | return false; |
stefan@webrtc.org | 6696fba | 2013-05-29 12:12:51 | [diff] [blame] | 148 | } |
pbos | d5bdda3 | 2015-09-28 16:59:31 | [diff] [blame] | 149 | return true; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 150 | } |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 151 | |
pbos | d5bdda3 | 2015-09-28 16:59:31 | [diff] [blame] | 152 | bool SendRtcp(const uint8_t* data, size_t len) override { |
| 153 | return module_->IncomingRtcpPacket((const uint8_t*)data, len) == 0; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 154 | } |
| 155 | int count_; |
| 156 | int packet_loss_; |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 157 | int consecutive_drop_start_; |
| 158 | int consecutive_drop_end_; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 159 | uint32_t rtx_ssrc_; |
| 160 | int count_rtx_ssrc_; |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 161 | RTPPayloadRegistry* rtp_payload_registry_; |
| 162 | RtpReceiver* rtp_receiver_; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 163 | RtpRtcp* module_; |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 164 | std::set<uint16_t> expected_sequence_numbers_; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 165 | }; |
| 166 | |
stefan@webrtc.org | 0b5c7f1 | 2013-03-18 15:00:50 | [diff] [blame] | 167 | class RtpRtcpRtxNackTest : public ::testing::Test { |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 168 | protected: |
stefan@webrtc.org | 0b5c7f1 | 2013-03-18 15:00:50 | [diff] [blame] | 169 | RtpRtcpRtxNackTest() |
andresp@webrtc.org | 9968131 | 2014-04-08 11:06:12 | [diff] [blame] | 170 | : rtp_payload_registry_(RTPPayloadStrategy::CreateStrategy(false)), |
aluebs | b78878b | 2016-07-08 18:01:59 | [diff] [blame] | 171 | rtp_rtcp_module_(NULL), |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 172 | transport_(kTestSsrc + 1), |
| 173 | receiver_(), |
| 174 | payload_data_length(sizeof(payload_data)), |
aluebs | b78878b | 2016-07-08 18:01:59 | [diff] [blame] | 175 | fake_clock(123456) {} |
stefan@webrtc.org | 0b5c7f1 | 2013-03-18 15:00:50 | [diff] [blame] | 176 | ~RtpRtcpRtxNackTest() {} |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 177 | |
kjellander@webrtc.org | 860ac53 | 2015-03-04 12:58:35 | [diff] [blame] | 178 | void SetUp() override { |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 179 | RtpRtcp::Configuration configuration; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 180 | configuration.audio = false; |
| 181 | configuration.clock = &fake_clock; |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 182 | receive_statistics_.reset(ReceiveStatistics::Create(&fake_clock)); |
| 183 | configuration.receive_statistics = receive_statistics_.get(); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 184 | configuration.outgoing_transport = &transport_; |
| 185 | rtp_rtcp_module_ = RtpRtcp::CreateRtpRtcp(configuration); |
| 186 | |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 187 | rtp_feedback_.reset(new TestRtpFeedback(rtp_rtcp_module_)); |
| 188 | |
| 189 | rtp_receiver_.reset(RtpReceiver::CreateVideoReceiver( |
danilchap | 3bf825b | 2015-12-10 10:39:40 | [diff] [blame] | 190 | &fake_clock, &receiver_, rtp_feedback_.get(), &rtp_payload_registry_)); |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 191 | |
stefan@webrtc.org | 903e746 | 2014-06-05 08:25:29 | [diff] [blame] | 192 | rtp_rtcp_module_->SetSSRC(kTestSsrc); |
pbos | ba01e95 | 2015-10-02 09:36:56 | [diff] [blame] | 193 | rtp_rtcp_module_->SetRTCPStatus(RtcpMode::kCompound); |
pbos@webrtc.org | f377da9 | 2014-12-19 13:49:55 | [diff] [blame] | 194 | rtp_rtcp_module_->SetStorePacketsStatus(true, 600); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 195 | EXPECT_EQ(0, rtp_rtcp_module_->SetSendingStatus(true)); |
pbos@webrtc.org | f377da9 | 2014-12-19 13:49:55 | [diff] [blame] | 196 | rtp_rtcp_module_->SetSequenceNumber(kTestSequenceNumber); |
| 197 | rtp_rtcp_module_->SetStartTimestamp(111111); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 198 | |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 199 | transport_.SetSendModule(rtp_rtcp_module_, &rtp_payload_registry_, |
| 200 | rtp_receiver_.get()); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 201 | |
| 202 | VideoCodec video_codec; |
| 203 | memset(&video_codec, 0, sizeof(video_codec)); |
Shao Changbin | 0f07171 | 2015-04-21 12:24:50 | [diff] [blame] | 204 | video_codec.plType = kPayloadType; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 205 | memcpy(video_codec.plName, "I420", 5); |
| 206 | |
| 207 | EXPECT_EQ(0, rtp_rtcp_module_->RegisterSendPayload(video_codec)); |
Shao Changbin | 0f07171 | 2015-04-21 12:24:50 | [diff] [blame] | 208 | rtp_rtcp_module_->SetRtxSendPayloadType(kRtxPayloadType, kPayloadType); |
danilchap | 3bf825b | 2015-12-10 10:39:40 | [diff] [blame] | 209 | EXPECT_EQ(0, rtp_receiver_->RegisterReceivePayload( |
| 210 | video_codec.plName, video_codec.plType, 90000, 0, |
| 211 | video_codec.maxBitrate)); |
Shao Changbin | 0f07171 | 2015-04-21 12:24:50 | [diff] [blame] | 212 | rtp_payload_registry_.SetRtxPayloadType(kRtxPayloadType, kPayloadType); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 213 | |
pkasting@chromium.org | 0ab923a | 2014-11-20 22:28:14 | [diff] [blame] | 214 | for (size_t n = 0; n < payload_data_length; n++) { |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 215 | payload_data[n] = n % 10; |
| 216 | } |
| 217 | } |
| 218 | |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 219 | int BuildNackList(uint16_t* nack_list) { |
| 220 | receiver_.sequence_numbers_.sort(); |
| 221 | std::list<uint16_t> missing_sequence_numbers; |
danilchap | 3bf825b | 2015-12-10 10:39:40 | [diff] [blame] | 222 | std::list<uint16_t>::iterator it = receiver_.sequence_numbers_.begin(); |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 223 | |
| 224 | while (it != receiver_.sequence_numbers_.end()) { |
| 225 | uint16_t sequence_number_1 = *it; |
| 226 | ++it; |
| 227 | if (it != receiver_.sequence_numbers_.end()) { |
| 228 | uint16_t sequence_number_2 = *it; |
| 229 | // Add all missing sequence numbers to list |
danilchap | 3bf825b | 2015-12-10 10:39:40 | [diff] [blame] | 230 | for (uint16_t i = sequence_number_1 + 1; i < sequence_number_2; ++i) { |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 231 | missing_sequence_numbers.push_back(i); |
| 232 | } |
| 233 | } |
| 234 | } |
| 235 | int n = 0; |
| 236 | for (it = missing_sequence_numbers.begin(); |
danilchap | 3bf825b | 2015-12-10 10:39:40 | [diff] [blame] | 237 | it != missing_sequence_numbers.end(); ++it) { |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 238 | nack_list[n++] = (*it); |
| 239 | } |
| 240 | return n; |
| 241 | } |
| 242 | |
| 243 | bool ExpectedPacketsReceived() { |
| 244 | std::list<uint16_t> received_sorted; |
| 245 | std::copy(receiver_.sequence_numbers_.begin(), |
| 246 | receiver_.sequence_numbers_.end(), |
| 247 | std::back_inserter(received_sorted)); |
| 248 | received_sorted.sort(); |
terelius | e2c9853 | 2015-09-17 10:19:45 | [diff] [blame] | 249 | return received_sorted.size() == |
| 250 | transport_.expected_sequence_numbers_.size() && |
| 251 | std::equal(received_sorted.begin(), received_sorted.end(), |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 252 | transport_.expected_sequence_numbers_.begin()); |
| 253 | } |
| 254 | |
| 255 | void RunRtxTest(RtxMode rtx_method, int loss) { |
stefan@webrtc.org | 903e746 | 2014-06-05 08:25:29 | [diff] [blame] | 256 | rtp_payload_registry_.SetRtxSsrc(kTestSsrc + 1); |
pbos@webrtc.org | 4b0399b | 2015-01-13 14:15:15 | [diff] [blame] | 257 | rtp_rtcp_module_->SetRtxSendStatus(rtx_method); |
stefan@webrtc.org | 903e746 | 2014-06-05 08:25:29 | [diff] [blame] | 258 | rtp_rtcp_module_->SetRtxSsrc(kTestSsrc + 1); |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 259 | transport_.DropEveryNthPacket(loss); |
| 260 | uint32_t timestamp = 3000; |
| 261 | uint16_t nack_list[kVideoNackListSize]; |
| 262 | for (int frame = 0; frame < kNumFrames; ++frame) { |
Shao Changbin | 0f07171 | 2015-04-21 12:24:50 | [diff] [blame] | 263 | EXPECT_EQ(0, rtp_rtcp_module_->SendOutgoingData( |
| 264 | webrtc::kVideoFrameDelta, kPayloadType, timestamp, |
| 265 | timestamp / 90, payload_data, payload_data_length)); |
sprang@webrtc.org | bbf5cad | 2015-01-29 09:09:17 | [diff] [blame] | 266 | // Min required delay until retransmit = 5 + RTT ms (RTT = 0). |
| 267 | fake_clock.AdvanceTimeMilliseconds(5); |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 268 | int length = BuildNackList(nack_list); |
| 269 | if (length > 0) |
| 270 | rtp_rtcp_module_->SendNACK(nack_list, length); |
sprang@webrtc.org | bbf5cad | 2015-01-29 09:09:17 | [diff] [blame] | 271 | fake_clock.AdvanceTimeMilliseconds(28); // 33ms - 5ms delay. |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 272 | rtp_rtcp_module_->Process(); |
| 273 | // Prepare next frame. |
| 274 | timestamp += 3000; |
| 275 | } |
| 276 | receiver_.sequence_numbers_.sort(); |
| 277 | } |
| 278 | |
kjellander@webrtc.org | 860ac53 | 2015-03-04 12:58:35 | [diff] [blame] | 279 | void TearDown() override { delete rtp_rtcp_module_; } |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 280 | |
kwiberg | 6e27acd | 2016-04-27 08:19:58 | [diff] [blame] | 281 | std::unique_ptr<ReceiveStatistics> receive_statistics_; |
wu@webrtc.org | 7fc75bb | 2013-08-15 23:38:54 | [diff] [blame] | 282 | RTPPayloadRegistry rtp_payload_registry_; |
kwiberg | 6e27acd | 2016-04-27 08:19:58 | [diff] [blame] | 283 | std::unique_ptr<RtpReceiver> rtp_receiver_; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 284 | RtpRtcp* rtp_rtcp_module_; |
kwiberg | 6e27acd | 2016-04-27 08:19:58 | [diff] [blame] | 285 | std::unique_ptr<TestRtpFeedback> rtp_feedback_; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 286 | RtxLoopBackTransport transport_; |
| 287 | VerifyingRtxReceiver receiver_; |
danilchap | 3bf825b | 2015-12-10 10:39:40 | [diff] [blame] | 288 | uint8_t payload_data[65000]; |
pkasting@chromium.org | 0ab923a | 2014-11-20 22:28:14 | [diff] [blame] | 289 | size_t payload_data_length; |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 290 | SimulatedClock fake_clock; |
| 291 | }; |
| 292 | |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 293 | TEST_F(RtpRtcpRtxNackTest, LongNackList) { |
| 294 | const int kNumPacketsToDrop = 900; |
| 295 | const int kNumRequiredRtcp = 4; |
pbos@webrtc.org | b57da65 | 2013-04-08 11:08:41 | [diff] [blame] | 296 | uint32_t timestamp = 3000; |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 297 | uint16_t nack_list[kNumPacketsToDrop]; |
| 298 | // Disable StorePackets to be able to set a larger packet history. |
pbos@webrtc.org | f377da9 | 2014-12-19 13:49:55 | [diff] [blame] | 299 | rtp_rtcp_module_->SetStorePacketsStatus(false, 0); |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 300 | // Enable StorePackets with a packet history of 2000 packets. |
pbos@webrtc.org | f377da9 | 2014-12-19 13:49:55 | [diff] [blame] | 301 | rtp_rtcp_module_->SetStorePacketsStatus(true, 2000); |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 302 | // Drop 900 packets from the second one so that we get a NACK list which is |
| 303 | // big enough to require 4 RTCP packets to be fully transmitted to the sender. |
| 304 | transport_.DropConsecutivePackets(2, kNumPacketsToDrop); |
| 305 | // Send 30 frames which at the default size is roughly what we need to get |
| 306 | // enough packets. |
| 307 | for (int frame = 0; frame < kNumFrames; ++frame) { |
Shao Changbin | 0f07171 | 2015-04-21 12:24:50 | [diff] [blame] | 308 | EXPECT_EQ(0, rtp_rtcp_module_->SendOutgoingData( |
| 309 | webrtc::kVideoFrameDelta, kPayloadType, timestamp, |
| 310 | timestamp / 90, payload_data, payload_data_length)); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 311 | // Prepare next frame. |
| 312 | timestamp += 3000; |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 313 | fake_clock.AdvanceTimeMilliseconds(33); |
| 314 | rtp_rtcp_module_->Process(); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 315 | } |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 316 | EXPECT_FALSE(transport_.expected_sequence_numbers_.empty()); |
| 317 | EXPECT_FALSE(receiver_.sequence_numbers_.empty()); |
| 318 | size_t last_receive_count = receiver_.sequence_numbers_.size(); |
| 319 | int length = BuildNackList(nack_list); |
| 320 | for (int i = 0; i < kNumRequiredRtcp - 1; ++i) { |
| 321 | rtp_rtcp_module_->SendNACK(nack_list, length); |
| 322 | EXPECT_GT(receiver_.sequence_numbers_.size(), last_receive_count); |
| 323 | last_receive_count = receiver_.sequence_numbers_.size(); |
| 324 | EXPECT_FALSE(ExpectedPacketsReceived()); |
| 325 | } |
| 326 | rtp_rtcp_module_->SendNACK(nack_list, length); |
| 327 | EXPECT_GT(receiver_.sequence_numbers_.size(), last_receive_count); |
| 328 | EXPECT_TRUE(ExpectedPacketsReceived()); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 329 | } |
| 330 | |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 331 | TEST_F(RtpRtcpRtxNackTest, RtxNack) { |
| 332 | RunRtxTest(kRtxRetransmitted, 10); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 333 | EXPECT_EQ(kTestSequenceNumber, *(receiver_.sequence_numbers_.begin())); |
| 334 | EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1, |
danilchap | 3bf825b | 2015-12-10 10:39:40 | [diff] [blame] | 335 | *(receiver_.sequence_numbers_.rbegin())); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 336 | EXPECT_EQ(kTestNumberOfPackets, receiver_.sequence_numbers_.size()); |
| 337 | EXPECT_EQ(kTestNumberOfRtxPackets, transport_.count_rtx_ssrc_); |
mikhal@webrtc.org | b960975 | 2013-05-15 20:17:43 | [diff] [blame] | 338 | EXPECT_TRUE(ExpectedPacketsReceived()); |
mikhal@webrtc.org | 946d240 | 2013-03-15 23:21:52 | [diff] [blame] | 339 | } |
danilchap | 090af54 | 2015-12-10 20:39:08 | [diff] [blame] | 340 | |
| 341 | } // namespace webrtc |