blob: 4663c917b158aa3748635d645f81ad0eeb95d615 [file] [log] [blame]
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +00001/*
2 * Copyright (c) 2012 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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "modules/rtp_rtcp/include/ulpfec_receiver.h"
12
phoglund@webrtc.org9919ad52013-05-16 15:06:28 +000013#include <string.h>
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000014
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000015#include <list>
kwiberg84be5112016-04-27 01:19:58 -070016#include <memory>
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000017
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h"
Yves Gerey665174f2018-06-19 15:03:05 +020019#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "modules/rtp_rtcp/source/byte_io.h"
21#include "modules/rtp_rtcp/source/fec_test_helper.h"
22#include "modules/rtp_rtcp/source/forward_error_correction.h"
23#include "test/gmock.h"
24#include "test/gtest.h"
Tommi25eb47c2019-08-29 16:39:05 +020025#include "test/rtp_header_parser.h"
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000026
brandtrece4aba2016-09-20 23:16:28 -070027namespace webrtc {
28
29namespace {
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000030using ::testing::_;
31using ::testing::Args;
32using ::testing::ElementsAreArray;
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000033
brandtr0aabdac2016-10-03 06:36:43 -070034using test::fec::AugmentedPacket;
brandtr71ca7472016-10-03 05:11:26 -070035using Packet = ForwardErrorCorrection::Packet;
brandtr71ca7472016-10-03 05:11:26 -070036using test::fec::UlpfecPacketGenerator;
37
38constexpr int kFecPayloadType = 96;
brandtr0aabdac2016-10-03 06:36:43 -070039constexpr uint32_t kMediaSsrc = 835424;
nisse30e89312017-05-29 08:16:37 -070040
41class NullRecoveredPacketReceiver : public RecoveredPacketReceiver {
42 public:
43 void OnRecoveredPacket(const uint8_t* packet, size_t length) override {}
44};
45
brandtr71ca7472016-10-03 05:11:26 -070046} // namespace
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000047
brandtrd55c3f62016-10-31 04:51:33 -070048class UlpfecReceiverTest : public ::testing::Test {
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000049 protected:
brandtrd55c3f62016-10-31 04:51:33 -070050 UlpfecReceiverTest()
brandtrd726a3f2017-06-29 02:45:35 -070051 : fec_(ForwardErrorCorrection::CreateUlpfec(kMediaSsrc)),
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +020052 receiver_fec_(UlpfecReceiver::Create(kMediaSsrc,
53 &recovered_packet_receiver_,
54 {})),
brandtr0aabdac2016-10-03 06:36:43 -070055 packet_generator_(kMediaSsrc) {}
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000056
brandtra2ece732016-10-04 00:00:06 -070057 // Generates |num_fec_packets| FEC packets, given |media_packets|.
brandtr71ca7472016-10-03 05:11:26 -070058 void EncodeFec(const ForwardErrorCorrection::PacketList& media_packets,
59 size_t num_fec_packets,
brandtra2ece732016-10-04 00:00:06 -070060 std::list<ForwardErrorCorrection::Packet*>* fec_packets);
stefan@webrtc.org7adab092012-02-09 12:34:52 +000061
brandtra2ece732016-10-04 00:00:06 -070062 // Generates |num_media_packets| corresponding to a single frame.
63 void PacketizeFrame(size_t num_media_packets,
64 size_t frame_offset,
65 std::list<AugmentedPacket*>* augmented_packets,
66 ForwardErrorCorrection::PacketList* packets);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000067
brandtra2ece732016-10-04 00:00:06 -070068 // Build a media packet using |packet_generator_| and add it
69 // to the receiver.
70 void BuildAndAddRedMediaPacket(AugmentedPacket* packet);
71
72 // Build a FEC packet using |packet_generator_| and add it
73 // to the receiver.
74 void BuildAndAddRedFecPacket(Packet* packet);
75
nisse30e89312017-05-29 08:16:37 -070076 // Ensure that |recovered_packet_receiver_| will be called correctly
brandtra2ece732016-10-04 00:00:06 -070077 // and that the recovered packet will be identical to the lost packet.
brandtr0aabdac2016-10-03 06:36:43 -070078 void VerifyReconstructedMediaPacket(const AugmentedPacket& packet,
brandtra2ece732016-10-04 00:00:06 -070079 size_t times);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000080
pbos2bad88d2015-07-06 03:09:08 -070081 void InjectGarbagePacketLength(size_t fec_garbage_offset);
brandtra2ece732016-10-04 00:00:06 -070082
pbos70d5c472015-06-29 07:22:04 -070083 static void SurvivesMaliciousPacket(const uint8_t* data,
84 size_t length,
85 uint8_t ulpfec_payload_type);
86
nisse30e89312017-05-29 08:16:37 -070087 MockRecoveredPacketReceiver recovered_packet_receiver_;
Rasmus Brandt78db1582016-09-21 09:19:34 +020088 std::unique_ptr<ForwardErrorCorrection> fec_;
brandtrd55c3f62016-10-31 04:51:33 -070089 std::unique_ptr<UlpfecReceiver> receiver_fec_;
brandtr0aabdac2016-10-03 06:36:43 -070090 UlpfecPacketGenerator packet_generator_;
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000091};
92
brandtrd55c3f62016-10-31 04:51:33 -070093void UlpfecReceiverTest::EncodeFec(
brandtra2ece732016-10-04 00:00:06 -070094 const ForwardErrorCorrection::PacketList& media_packets,
95 size_t num_fec_packets,
96 std::list<ForwardErrorCorrection::Packet*>* fec_packets) {
97 const uint8_t protection_factor =
98 num_fec_packets * 255 / media_packets.size();
99 // Unequal protection is turned off, and the number of important
100 // packets is thus irrelevant.
101 constexpr int kNumImportantPackets = 0;
102 constexpr bool kUseUnequalProtection = false;
103 constexpr FecMaskType kFecMaskType = kFecMaskBursty;
104 EXPECT_EQ(
105 0, fec_->EncodeFec(media_packets, protection_factor, kNumImportantPackets,
106 kUseUnequalProtection, kFecMaskType, fec_packets));
107 ASSERT_EQ(num_fec_packets, fec_packets->size());
108}
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000109
brandtrd55c3f62016-10-31 04:51:33 -0700110void UlpfecReceiverTest::PacketizeFrame(
brandtra2ece732016-10-04 00:00:06 -0700111 size_t num_media_packets,
112 size_t frame_offset,
113 std::list<AugmentedPacket*>* augmented_packets,
114 ForwardErrorCorrection::PacketList* packets) {
115 packet_generator_.NewFrame(num_media_packets);
116 for (size_t i = 0; i < num_media_packets; ++i) {
117 std::unique_ptr<AugmentedPacket> next_packet(
118 packet_generator_.NextPacket(frame_offset + i, kRtpHeaderSize + 10));
119 augmented_packets->push_back(next_packet.get());
120 packets->push_back(std::move(next_packet));
121 }
122}
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000123
brandtrd55c3f62016-10-31 04:51:33 -0700124void UlpfecReceiverTest::BuildAndAddRedMediaPacket(AugmentedPacket* packet) {
brandtra2ece732016-10-04 00:00:06 -0700125 std::unique_ptr<AugmentedPacket> red_packet(
126 packet_generator_.BuildMediaRedPacket(*packet));
127 EXPECT_EQ(0, receiver_fec_->AddReceivedRedPacket(
Ilya Nikolaevskiya5d952f2019-09-03 11:07:37 +0200128 red_packet->header, red_packet->data.cdata(),
129 red_packet->data.size(), kFecPayloadType));
brandtra2ece732016-10-04 00:00:06 -0700130}
131
brandtrd55c3f62016-10-31 04:51:33 -0700132void UlpfecReceiverTest::BuildAndAddRedFecPacket(Packet* packet) {
brandtra2ece732016-10-04 00:00:06 -0700133 std::unique_ptr<AugmentedPacket> red_packet(
134 packet_generator_.BuildUlpfecRedPacket(*packet));
135 EXPECT_EQ(0, receiver_fec_->AddReceivedRedPacket(
Ilya Nikolaevskiya5d952f2019-09-03 11:07:37 +0200136 red_packet->header, red_packet->data.cdata(),
137 red_packet->data.size(), kFecPayloadType));
brandtra2ece732016-10-04 00:00:06 -0700138}
139
brandtrd55c3f62016-10-31 04:51:33 -0700140void UlpfecReceiverTest::VerifyReconstructedMediaPacket(
brandtra2ece732016-10-04 00:00:06 -0700141 const AugmentedPacket& packet,
142 size_t times) {
143 // Verify that the content of the reconstructed packet is equal to the
144 // content of |packet|, and that the same content is received |times| number
145 // of times in a row.
Ilya Nikolaevskiya5d952f2019-09-03 11:07:37 +0200146 EXPECT_CALL(recovered_packet_receiver_,
147 OnRecoveredPacket(_, packet.data.size()))
148 .With(
149 Args<0, 1>(ElementsAreArray(packet.data.cdata(), packet.data.size())))
nisse30e89312017-05-29 08:16:37 -0700150 .Times(times);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000151}
152
brandtrd55c3f62016-10-31 04:51:33 -0700153void UlpfecReceiverTest::InjectGarbagePacketLength(size_t fec_garbage_offset) {
nisse30e89312017-05-29 08:16:37 -0700154 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _));
pbos2bad88d2015-07-06 03:09:08 -0700155
brandtr71ca7472016-10-03 05:11:26 -0700156 const size_t kNumFecPackets = 1;
brandtr0aabdac2016-10-03 06:36:43 -0700157 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200158 ForwardErrorCorrection::PacketList media_packets;
brandtra2ece732016-10-04 00:00:06 -0700159 PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
brandtr35c480c2016-08-09 01:23:23 -0700160 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700161 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
pbos2bad88d2015-07-06 03:09:08 -0700162 ByteWriter<uint16_t>::WriteBigEndian(
163 &fec_packets.front()->data[fec_garbage_offset], 0x4711);
164
165 // Inject first media packet, then first FEC packet, skipping the second media
166 // packet to cause a recovery from the FEC packet.
brandtr0aabdac2016-10-03 06:36:43 -0700167 BuildAndAddRedMediaPacket(augmented_media_packets.front());
pbos2bad88d2015-07-06 03:09:08 -0700168 BuildAndAddRedFecPacket(fec_packets.front());
169 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
170
171 FecPacketCounter counter = receiver_fec_->GetPacketCounter();
brandtr71ca7472016-10-03 05:11:26 -0700172 EXPECT_EQ(2U, counter.num_packets);
173 EXPECT_EQ(1U, counter.num_fec_packets);
174 EXPECT_EQ(0U, counter.num_recovered_packets);
pbos2bad88d2015-07-06 03:09:08 -0700175}
176
brandtrd55c3f62016-10-31 04:51:33 -0700177void UlpfecReceiverTest::SurvivesMaliciousPacket(const uint8_t* data,
178 size_t length,
179 uint8_t ulpfec_payload_type) {
180 RTPHeader header;
Tommi25eb47c2019-08-29 16:39:05 +0200181 std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::CreateForTest());
brandtra2ece732016-10-04 00:00:06 -0700182 ASSERT_TRUE(parser->Parse(data, length, &header));
183
nisse30e89312017-05-29 08:16:37 -0700184 NullRecoveredPacketReceiver null_callback;
brandtrd55c3f62016-10-31 04:51:33 -0700185 std::unique_ptr<UlpfecReceiver> receiver_fec(
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +0200186 UlpfecReceiver::Create(kMediaSsrc, &null_callback, {}));
brandtra2ece732016-10-04 00:00:06 -0700187
188 receiver_fec->AddReceivedRedPacket(header, data, length, ulpfec_payload_type);
189}
190
brandtrd55c3f62016-10-31 04:51:33 -0700191TEST_F(UlpfecReceiverTest, TwoMediaOneFec) {
brandtra2ece732016-10-04 00:00:06 -0700192 constexpr size_t kNumFecPackets = 1u;
193 std::list<AugmentedPacket*> augmented_media_packets;
194 ForwardErrorCorrection::PacketList media_packets;
195 PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
196 std::list<ForwardErrorCorrection::Packet*> fec_packets;
197 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
198
asapersson0c43f772016-11-30 01:42:26 -0800199 FecPacketCounter counter = receiver_fec_->GetPacketCounter();
200 EXPECT_EQ(0u, counter.num_packets);
201 EXPECT_EQ(-1, counter.first_packet_time_ms);
202
brandtra2ece732016-10-04 00:00:06 -0700203 // Recovery
204 auto it = augmented_media_packets.begin();
205 BuildAndAddRedMediaPacket(*it);
206 VerifyReconstructedMediaPacket(**it, 1);
207 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
asapersson0c43f772016-11-30 01:42:26 -0800208 counter = receiver_fec_->GetPacketCounter();
209 EXPECT_EQ(1u, counter.num_packets);
210 EXPECT_EQ(0u, counter.num_fec_packets);
211 EXPECT_EQ(0u, counter.num_recovered_packets);
212 const int64_t first_packet_time_ms = counter.first_packet_time_ms;
213 EXPECT_NE(-1, first_packet_time_ms);
214
brandtra2ece732016-10-04 00:00:06 -0700215 // Drop one media packet.
216 auto fec_it = fec_packets.begin();
217 BuildAndAddRedFecPacket(*fec_it);
218 ++it;
219 VerifyReconstructedMediaPacket(**it, 1);
220 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
221
asapersson0c43f772016-11-30 01:42:26 -0800222 counter = receiver_fec_->GetPacketCounter();
brandtra2ece732016-10-04 00:00:06 -0700223 EXPECT_EQ(2u, counter.num_packets);
224 EXPECT_EQ(1u, counter.num_fec_packets);
225 EXPECT_EQ(1u, counter.num_recovered_packets);
asapersson0c43f772016-11-30 01:42:26 -0800226 EXPECT_EQ(first_packet_time_ms, counter.first_packet_time_ms);
brandtra2ece732016-10-04 00:00:06 -0700227}
228
brandtrd55c3f62016-10-31 04:51:33 -0700229TEST_F(UlpfecReceiverTest, InjectGarbageFecHeaderLengthRecovery) {
pbos2bad88d2015-07-06 03:09:08 -0700230 // Byte offset 8 is the 'length recovery' field of the FEC header.
231 InjectGarbagePacketLength(8);
232}
233
brandtrd55c3f62016-10-31 04:51:33 -0700234TEST_F(UlpfecReceiverTest, InjectGarbageFecLevelHeaderProtectionLength) {
pbos2bad88d2015-07-06 03:09:08 -0700235 // Byte offset 10 is the 'protection length' field in the first FEC level
236 // header.
237 InjectGarbagePacketLength(10);
238}
239
brandtrd55c3f62016-10-31 04:51:33 -0700240TEST_F(UlpfecReceiverTest, TwoMediaTwoFec) {
brandtr71ca7472016-10-03 05:11:26 -0700241 const size_t kNumFecPackets = 2;
brandtr0aabdac2016-10-03 06:36:43 -0700242 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200243 ForwardErrorCorrection::PacketList media_packets;
brandtra2ece732016-10-04 00:00:06 -0700244 PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
brandtr35c480c2016-08-09 01:23:23 -0700245 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700246 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000247
248 // Recovery
249 // Drop both media packets.
brandtr0aabdac2016-10-03 06:36:43 -0700250 auto it = augmented_media_packets.begin();
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200251 auto fec_it = fec_packets.begin();
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000252 BuildAndAddRedFecPacket(*fec_it);
brandtr71ca7472016-10-03 05:11:26 -0700253 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000254 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000255 ++fec_it;
256 BuildAndAddRedFecPacket(*fec_it);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000257 ++it;
brandtr71ca7472016-10-03 05:11:26 -0700258 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000259 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000260}
261
brandtrd55c3f62016-10-31 04:51:33 -0700262TEST_F(UlpfecReceiverTest, TwoFramesOneFec) {
brandtr71ca7472016-10-03 05:11:26 -0700263 const size_t kNumFecPackets = 1;
brandtr0aabdac2016-10-03 06:36:43 -0700264 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200265 ForwardErrorCorrection::PacketList media_packets;
brandtra2ece732016-10-04 00:00:06 -0700266 PacketizeFrame(1, 0, &augmented_media_packets, &media_packets);
267 PacketizeFrame(1, 1, &augmented_media_packets, &media_packets);
brandtr35c480c2016-08-09 01:23:23 -0700268 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700269 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000270
271 // Recovery
brandtr0aabdac2016-10-03 06:36:43 -0700272 auto it = augmented_media_packets.begin();
273 BuildAndAddRedMediaPacket(augmented_media_packets.front());
brandtr71ca7472016-10-03 05:11:26 -0700274 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000275 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000276 // Drop one media packet.
277 BuildAndAddRedFecPacket(fec_packets.front());
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000278 ++it;
brandtr71ca7472016-10-03 05:11:26 -0700279 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000280 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000281}
282
brandtrd55c3f62016-10-31 04:51:33 -0700283TEST_F(UlpfecReceiverTest, OneCompleteOneUnrecoverableFrame) {
brandtr71ca7472016-10-03 05:11:26 -0700284 const size_t kNumFecPackets = 1;
brandtr0aabdac2016-10-03 06:36:43 -0700285 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200286 ForwardErrorCorrection::PacketList media_packets;
brandtra2ece732016-10-04 00:00:06 -0700287 PacketizeFrame(1, 0, &augmented_media_packets, &media_packets);
288 PacketizeFrame(2, 1, &augmented_media_packets, &media_packets);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000289
brandtr35c480c2016-08-09 01:23:23 -0700290 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700291 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000292
293 // Recovery
brandtr0aabdac2016-10-03 06:36:43 -0700294 auto it = augmented_media_packets.begin();
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000295 BuildAndAddRedMediaPacket(*it); // First frame: one packet.
brandtr71ca7472016-10-03 05:11:26 -0700296 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000297 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000298 ++it;
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000299 BuildAndAddRedMediaPacket(*it); // First packet of second frame.
brandtr71ca7472016-10-03 05:11:26 -0700300 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000301 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000302}
303
brandtrd55c3f62016-10-31 04:51:33 -0700304TEST_F(UlpfecReceiverTest, MaxFramesOneFec) {
brandtr71ca7472016-10-03 05:11:26 -0700305 const size_t kNumFecPackets = 1;
306 const size_t kNumMediaPackets = 48;
brandtr0aabdac2016-10-03 06:36:43 -0700307 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200308 ForwardErrorCorrection::PacketList media_packets;
brandtr71ca7472016-10-03 05:11:26 -0700309 for (size_t i = 0; i < kNumMediaPackets; ++i) {
brandtra2ece732016-10-04 00:00:06 -0700310 PacketizeFrame(1, i, &augmented_media_packets, &media_packets);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000311 }
brandtr35c480c2016-08-09 01:23:23 -0700312 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700313 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000314
315 // Recovery
brandtr0aabdac2016-10-03 06:36:43 -0700316 auto it = augmented_media_packets.begin();
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000317 ++it; // Drop first packet.
brandtr0aabdac2016-10-03 06:36:43 -0700318 for (; it != augmented_media_packets.end(); ++it) {
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000319 BuildAndAddRedMediaPacket(*it);
brandtr71ca7472016-10-03 05:11:26 -0700320 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000321 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000322 }
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000323 BuildAndAddRedFecPacket(fec_packets.front());
brandtr0aabdac2016-10-03 06:36:43 -0700324 it = augmented_media_packets.begin();
brandtr71ca7472016-10-03 05:11:26 -0700325 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000326 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000327}
328
brandtrd55c3f62016-10-31 04:51:33 -0700329TEST_F(UlpfecReceiverTest, TooManyFrames) {
brandtr71ca7472016-10-03 05:11:26 -0700330 const size_t kNumFecPackets = 1;
331 const size_t kNumMediaPackets = 49;
brandtr0aabdac2016-10-03 06:36:43 -0700332 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200333 ForwardErrorCorrection::PacketList media_packets;
brandtr71ca7472016-10-03 05:11:26 -0700334 for (size_t i = 0; i < kNumMediaPackets; ++i) {
brandtra2ece732016-10-04 00:00:06 -0700335 PacketizeFrame(1, i, &augmented_media_packets, &media_packets);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000336 }
brandtr35c480c2016-08-09 01:23:23 -0700337 std::list<ForwardErrorCorrection::Packet*> fec_packets;
Rasmus Brandt78db1582016-09-21 09:19:34 +0200338 EXPECT_EQ(-1, fec_->EncodeFec(media_packets,
339 kNumFecPackets * 255 / kNumMediaPackets, 0,
340 false, kFecMaskBursty, &fec_packets));
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000341}
342
brandtrd55c3f62016-10-31 04:51:33 -0700343TEST_F(UlpfecReceiverTest, PacketNotDroppedTooEarly) {
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000344 // 1 frame with 2 media packets and one FEC packet. One media packet missing.
345 // Delay the FEC packet.
brandtr71ca7472016-10-03 05:11:26 -0700346 Packet* delayed_fec = nullptr;
347 const size_t kNumFecPacketsBatch1 = 1;
348 const size_t kNumMediaPacketsBatch1 = 2;
brandtr0aabdac2016-10-03 06:36:43 -0700349 std::list<AugmentedPacket*> augmented_media_packets_batch1;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200350 ForwardErrorCorrection::PacketList media_packets_batch1;
brandtra2ece732016-10-04 00:00:06 -0700351 PacketizeFrame(kNumMediaPacketsBatch1, 0, &augmented_media_packets_batch1,
352 &media_packets_batch1);
brandtr35c480c2016-08-09 01:23:23 -0700353 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700354 EncodeFec(media_packets_batch1, kNumFecPacketsBatch1, &fec_packets);
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000355
brandtr0aabdac2016-10-03 06:36:43 -0700356 BuildAndAddRedMediaPacket(augmented_media_packets_batch1.front());
Yves Gerey665174f2018-06-19 15:03:05 +0200357 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000358 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000359 delayed_fec = fec_packets.front();
360
361 // Fill the FEC decoder. No packets should be dropped.
brandtr71ca7472016-10-03 05:11:26 -0700362 const size_t kNumMediaPacketsBatch2 = 46;
brandtr0aabdac2016-10-03 06:36:43 -0700363 std::list<AugmentedPacket*> augmented_media_packets_batch2;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200364 ForwardErrorCorrection::PacketList media_packets_batch2;
brandtr71ca7472016-10-03 05:11:26 -0700365 for (size_t i = 0; i < kNumMediaPacketsBatch2; ++i) {
brandtra2ece732016-10-04 00:00:06 -0700366 PacketizeFrame(1, i, &augmented_media_packets_batch2,
367 &media_packets_batch2);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000368 }
brandtr0aabdac2016-10-03 06:36:43 -0700369 for (auto it = augmented_media_packets_batch2.begin();
370 it != augmented_media_packets_batch2.end(); ++it) {
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000371 BuildAndAddRedMediaPacket(*it);
Yves Gerey665174f2018-06-19 15:03:05 +0200372 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000373 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000374 }
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000375
376 // Add the delayed FEC packet. One packet should be reconstructed.
377 BuildAndAddRedFecPacket(delayed_fec);
Yves Gerey665174f2018-06-19 15:03:05 +0200378 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000379 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000380}
381
brandtrd55c3f62016-10-31 04:51:33 -0700382TEST_F(UlpfecReceiverTest, PacketDroppedWhenTooOld) {
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000383 // 1 frame with 2 media packets and one FEC packet. One media packet missing.
384 // Delay the FEC packet.
brandtr71ca7472016-10-03 05:11:26 -0700385 Packet* delayed_fec = nullptr;
386 const size_t kNumFecPacketsBatch1 = 1;
387 const size_t kNumMediaPacketsBatch1 = 2;
brandtr0aabdac2016-10-03 06:36:43 -0700388 std::list<AugmentedPacket*> augmented_media_packets_batch1;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200389 ForwardErrorCorrection::PacketList media_packets_batch1;
brandtra2ece732016-10-04 00:00:06 -0700390 PacketizeFrame(kNumMediaPacketsBatch1, 0, &augmented_media_packets_batch1,
391 &media_packets_batch1);
brandtr35c480c2016-08-09 01:23:23 -0700392 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700393 EncodeFec(media_packets_batch1, kNumFecPacketsBatch1, &fec_packets);
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000394
brandtr0aabdac2016-10-03 06:36:43 -0700395 BuildAndAddRedMediaPacket(augmented_media_packets_batch1.front());
Yves Gerey665174f2018-06-19 15:03:05 +0200396 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000397 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000398 delayed_fec = fec_packets.front();
399
400 // Fill the FEC decoder and force the last packet to be dropped.
brandtr71ca7472016-10-03 05:11:26 -0700401 const size_t kNumMediaPacketsBatch2 = 48;
brandtr0aabdac2016-10-03 06:36:43 -0700402 std::list<AugmentedPacket*> augmented_media_packets_batch2;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200403 ForwardErrorCorrection::PacketList media_packets_batch2;
brandtr71ca7472016-10-03 05:11:26 -0700404 for (size_t i = 0; i < kNumMediaPacketsBatch2; ++i) {
brandtra2ece732016-10-04 00:00:06 -0700405 PacketizeFrame(1, i, &augmented_media_packets_batch2,
406 &media_packets_batch2);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000407 }
brandtr0aabdac2016-10-03 06:36:43 -0700408 for (auto it = augmented_media_packets_batch2.begin();
409 it != augmented_media_packets_batch2.end(); ++it) {
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000410 BuildAndAddRedMediaPacket(*it);
Yves Gerey665174f2018-06-19 15:03:05 +0200411 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000412 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000413 }
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000414
415 // Add the delayed FEC packet. No packet should be reconstructed since the
416 // first media packet of that frame has been dropped due to being too old.
417 BuildAndAddRedFecPacket(delayed_fec);
nisse30e89312017-05-29 08:16:37 -0700418 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(0);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000419 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000420}
421
brandtrd55c3f62016-10-31 04:51:33 -0700422TEST_F(UlpfecReceiverTest, OldFecPacketDropped) {
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000423 // 49 frames with 2 media packets and one FEC packet. All media packets
424 // missing.
brandtr71ca7472016-10-03 05:11:26 -0700425 const size_t kNumMediaPackets = 49 * 2;
brandtr0aabdac2016-10-03 06:36:43 -0700426 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200427 ForwardErrorCorrection::PacketList media_packets;
brandtr71ca7472016-10-03 05:11:26 -0700428 for (size_t i = 0; i < kNumMediaPackets / 2; ++i) {
brandtr0aabdac2016-10-03 06:36:43 -0700429 std::list<AugmentedPacket*> frame_augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200430 ForwardErrorCorrection::PacketList frame_media_packets;
brandtr35c480c2016-08-09 01:23:23 -0700431 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtra2ece732016-10-04 00:00:06 -0700432 PacketizeFrame(2, 0, &frame_augmented_media_packets, &frame_media_packets);
brandtr71ca7472016-10-03 05:11:26 -0700433 EncodeFec(frame_media_packets, 1, &fec_packets);
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200434 for (auto it = fec_packets.begin(); it != fec_packets.end(); ++it) {
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000435 // Only FEC packets inserted. No packets recoverable at this time.
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000436 BuildAndAddRedFecPacket(*it);
nisse30e89312017-05-29 08:16:37 -0700437 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(0);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000438 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000439 }
brandtr35c480c2016-08-09 01:23:23 -0700440 // Move unique_ptr's to media_packets for lifetime management.
441 media_packets.insert(media_packets.end(),
442 std::make_move_iterator(frame_media_packets.begin()),
443 std::make_move_iterator(frame_media_packets.end()));
brandtr0aabdac2016-10-03 06:36:43 -0700444 augmented_media_packets.insert(augmented_media_packets.end(),
445 frame_augmented_media_packets.begin(),
446 frame_augmented_media_packets.end());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000447 }
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000448 // Insert the oldest media packet. The corresponding FEC packet is too old
brandtr71ca7472016-10-03 05:11:26 -0700449 // and should have been dropped. Only the media packet we inserted will be
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000450 // returned.
brandtr0aabdac2016-10-03 06:36:43 -0700451 BuildAndAddRedMediaPacket(augmented_media_packets.front());
Yves Gerey665174f2018-06-19 15:03:05 +0200452 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000453 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000454}
455
brandtrd55c3f62016-10-31 04:51:33 -0700456TEST_F(UlpfecReceiverTest, TruncatedPacketWithFBitSet) {
457 const uint8_t kTruncatedPacket[] = {0x80, 0x2a, 0x68, 0x71, 0x29, 0xa1, 0x27,
458 0x3a, 0x29, 0x12, 0x2a, 0x98, 0xe0, 0x29};
pbos70d5c472015-06-29 07:22:04 -0700459
460 SurvivesMaliciousPacket(kTruncatedPacket, sizeof(kTruncatedPacket), 100);
461}
462
brandtrd55c3f62016-10-31 04:51:33 -0700463TEST_F(UlpfecReceiverTest,
464 TruncatedPacketWithFBitSetEndingAfterFirstRedHeader) {
465 const uint8_t kPacket[] = {
466 0x89, 0x27, 0x3a, 0x83, 0x27, 0x3a, 0x3a, 0xf3, 0x67, 0xbe, 0x2a,
467 0xa9, 0x27, 0x54, 0x3a, 0x3a, 0x2a, 0x67, 0x3a, 0xf3, 0x67, 0xbe,
468 0x2a, 0x27, 0xe6, 0xf6, 0x03, 0x3e, 0x29, 0x27, 0x21, 0x27, 0x2a,
469 0x29, 0x21, 0x4b, 0x29, 0x3a, 0x28, 0x29, 0xbf, 0x29, 0x2a, 0x26,
470 0x29, 0xae, 0x27, 0xa6, 0xf6, 0x00, 0x03, 0x3e};
pbos2e43b262015-06-30 01:32:40 -0700471 SurvivesMaliciousPacket(kPacket, sizeof(kPacket), 100);
472}
473
brandtrd55c3f62016-10-31 04:51:33 -0700474TEST_F(UlpfecReceiverTest, TruncatedPacketWithoutDataPastFirstBlock) {
475 const uint8_t kPacket[] = {
476 0x82, 0x38, 0x92, 0x38, 0x92, 0x38, 0xde, 0x2a, 0x11, 0xc8, 0xa3, 0xc4,
477 0x82, 0x38, 0x2a, 0x21, 0x2a, 0x28, 0x92, 0x38, 0x92, 0x00, 0x00, 0x0a,
478 0x3a, 0xc8, 0xa3, 0x3a, 0x27, 0xc4, 0x2a, 0x21, 0x2a, 0x28};
pbos2e43b262015-06-30 01:32:40 -0700479 SurvivesMaliciousPacket(kPacket, sizeof(kPacket), 100);
480}
481
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000482} // namespace webrtc