blob: 1abed150f193758d5bd91310d4b8dff84b4d2ece [file] [log] [blame]
marpan@webrtc.orgb783a552012-02-04 02:46:35 +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
Rasmus Brandtae4f7672016-07-07 09:40:51 +020011#include <algorithm>
marpan@webrtc.orgb783a552012-02-04 02:46:35 +000012#include <list>
brandtrece4aba2016-09-20 23:16:28 -070013#include <memory>
marpan@webrtc.orgb783a552012-02-04 02:46:35 +000014
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "modules/rtp_rtcp/source/byte_io.h"
16#include "modules/rtp_rtcp/source/fec_test_helper.h"
17#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h"
18#include "modules/rtp_rtcp/source/forward_error_correction.h"
19#include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h"
20#include "rtc_base/basictypes.h"
21#include "rtc_base/random.h"
22#include "test/gtest.h"
marpan@webrtc.orgb783a552012-02-04 02:46:35 +000023
brandtrece4aba2016-09-20 23:16:28 -070024namespace webrtc {
marpan@webrtc.orgb783a552012-02-04 02:46:35 +000025
brandtrece4aba2016-09-20 23:16:28 -070026namespace {
marpan@webrtc.orgb783a552012-02-04 02:46:35 +000027
28// Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum.
brandtrece4aba2016-09-20 23:16:28 -070029constexpr size_t kTransportOverhead = 28;
marpan@webrtc.orgb783a552012-02-04 02:46:35 +000030
brandtrece4aba2016-09-20 23:16:28 -070031constexpr uint32_t kMediaSsrc = 83542;
brandtr0496de22016-10-03 00:43:25 -070032constexpr uint32_t kFlexfecSsrc = 43245;
marpan@webrtc.orgb783a552012-02-04 02:46:35 +000033
Rasmus Brandtd73ba122017-12-07 10:22:49 +010034constexpr size_t kMaxMediaPackets = 48;
35
brandtrece4aba2016-09-20 23:16:28 -070036// Deep copies |src| to |dst|, but only keeps every Nth packet.
37void DeepCopyEveryNthPacket(const ForwardErrorCorrection::PacketList& src,
38 int n,
39 ForwardErrorCorrection::PacketList* dst) {
40 RTC_DCHECK_GT(n, 0);
41 int i = 0;
42 for (const auto& packet : src) {
43 if (i % n == 0) {
44 dst->emplace_back(new ForwardErrorCorrection::Packet(*packet));
45 }
46 ++i;
47 }
48}
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +000049
brandtrece4aba2016-09-20 23:16:28 -070050} // namespace
51
52using ::testing::Types;
53
54template <typename ForwardErrorCorrectionType>
marpan@webrtc.orgb783a552012-02-04 02:46:35 +000055class RtpFecTest : public ::testing::Test {
56 protected:
57 RtpFecTest()
brandtrece4aba2016-09-20 23:16:28 -070058 : random_(0xabcdef123456),
59 media_packet_generator_(
60 kRtpHeaderSize, // Minimum packet size.
61 IP_PACKET_SIZE - kRtpHeaderSize - kTransportOverhead -
62 fec_.MaxPacketOverhead(), // Maximum packet size.
63 kMediaSsrc,
64 &random_) {}
marpan@webrtc.orgb783a552012-02-04 02:46:35 +000065
brandtrece4aba2016-09-20 23:16:28 -070066 // Construct |received_packets_|: a subset of the media and FEC packets.
brandtrd90fa0b2016-08-09 06:57:14 -070067 //
68 // Media packet "i" is lost if media_loss_mask_[i] = 1, received if
69 // media_loss_mask_[i] = 0.
70 // FEC packet "i" is lost if fec_loss_mask_[i] = 1, received if
71 // fec_loss_mask_[i] = 0.
72 void NetworkReceivedPackets(int* media_loss_mask, int* fec_loss_mask);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +000073
74 // Add packet from |packet_list| to list of received packets, using the
75 // |loss_mask|.
76 // The |packet_list| may be a media packet list (is_fec = false), or a
77 // FEC packet list (is_fec = true).
brandtr35c480c2016-08-09 01:23:23 -070078 template <typename T>
79 void ReceivedPackets(const T& packet_list, int* loss_mask, bool is_fec);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +000080
81 // Check for complete recovery after FEC decoding.
82 bool IsRecoveryComplete();
83
brandtrece4aba2016-09-20 23:16:28 -070084 ForwardErrorCorrectionType fec_;
brandtrd90fa0b2016-08-09 06:57:14 -070085
brandtrece4aba2016-09-20 23:16:28 -070086 Random random_;
87 test::fec::MediaPacketGenerator media_packet_generator_;
brandtrd90fa0b2016-08-09 06:57:14 -070088
brandtrece4aba2016-09-20 23:16:28 -070089 ForwardErrorCorrection::PacketList media_packets_;
90 std::list<ForwardErrorCorrection::Packet*> generated_fec_packets_;
nissea5f043f2017-09-18 07:58:59 -070091 std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>>
92 received_packets_;
brandtrece4aba2016-09-20 23:16:28 -070093 ForwardErrorCorrection::RecoveredPacketList recovered_packets_;
brandtrd90fa0b2016-08-09 06:57:14 -070094
Rasmus Brandt78db1582016-09-21 09:19:34 +020095 int media_loss_mask_[kUlpfecMaxMediaPackets];
96 int fec_loss_mask_[kUlpfecMaxMediaPackets];
marpan@webrtc.orgb783a552012-02-04 02:46:35 +000097};
98
Rasmus Brandtea7beb92016-09-21 12:01:19 +020099template <typename ForwardErrorCorrectionType>
100void RtpFecTest<ForwardErrorCorrectionType>::NetworkReceivedPackets(
101 int* media_loss_mask,
102 int* fec_loss_mask) {
103 constexpr bool kFecPacket = true;
nissea5f043f2017-09-18 07:58:59 -0700104 this->received_packets_.clear();
Rasmus Brandtea7beb92016-09-21 12:01:19 +0200105 ReceivedPackets(media_packets_, media_loss_mask, !kFecPacket);
106 ReceivedPackets(generated_fec_packets_, fec_loss_mask, kFecPacket);
107}
108
109template <typename ForwardErrorCorrectionType>
110template <typename PacketListType>
111void RtpFecTest<ForwardErrorCorrectionType>::ReceivedPackets(
112 const PacketListType& packet_list,
113 int* loss_mask,
114 bool is_fec) {
brandtrd726a3f2017-06-29 02:45:35 -0700115 uint16_t fec_seq_num = ForwardErrorCorrectionType::GetFirstFecSeqNum(
116 media_packet_generator_.GetNextSeqNum());
Rasmus Brandtea7beb92016-09-21 12:01:19 +0200117 int packet_idx = 0;
118
119 for (const auto& packet : packet_list) {
120 if (loss_mask[packet_idx] == 0) {
121 std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet(
122 new ForwardErrorCorrection::ReceivedPacket());
123 received_packet->pkt = new ForwardErrorCorrection::Packet();
124 received_packet->pkt->length = packet->length;
125 memcpy(received_packet->pkt->data, packet->data, packet->length);
126 received_packet->is_fec = is_fec;
127 if (!is_fec) {
brandtrd726a3f2017-06-29 02:45:35 -0700128 received_packet->ssrc = kMediaSsrc;
129 // For media packets, the sequence number is obtained from the
130 // RTP header as written by MediaPacketGenerator::ConstructMediaPackets.
Rasmus Brandtea7beb92016-09-21 12:01:19 +0200131 received_packet->seq_num =
132 ByteReader<uint16_t>::ReadBigEndian(&packet->data[2]);
133 } else {
brandtrd726a3f2017-06-29 02:45:35 -0700134 received_packet->ssrc = ForwardErrorCorrectionType::kFecSsrc;
135 // For FEC packets, we simulate the sequence numbers differently
136 // depending on if ULPFEC or FlexFEC is used. See the definition of
137 // ForwardErrorCorrectionType::GetFirstFecSeqNum.
Rasmus Brandtea7beb92016-09-21 12:01:19 +0200138 received_packet->seq_num = fec_seq_num;
Rasmus Brandtea7beb92016-09-21 12:01:19 +0200139 }
140 received_packets_.push_back(std::move(received_packet));
141 }
142 packet_idx++;
143 // Sequence number of FEC packets are defined as increment by 1 from
144 // last media packet in frame.
145 if (is_fec)
146 fec_seq_num++;
147 }
148}
149
150template <typename ForwardErrorCorrectionType>
151bool RtpFecTest<ForwardErrorCorrectionType>::IsRecoveryComplete() {
152 // We must have equally many recovered packets as original packets.
153 if (recovered_packets_.size() != media_packets_.size()) {
154 return false;
155 }
156
157 // All recovered packets must be identical to the corresponding
158 // original packets.
brandtr0496de22016-10-03 00:43:25 -0700159 auto cmp = [](
160 const std::unique_ptr<ForwardErrorCorrection::Packet>& media_packet,
161 const std::unique_ptr<ForwardErrorCorrection::RecoveredPacket>&
162 recovered_packet) {
Rasmus Brandtea7beb92016-09-21 12:01:19 +0200163 if (media_packet->length != recovered_packet->pkt->length) {
164 return false;
165 }
brandtr0496de22016-10-03 00:43:25 -0700166 if (memcmp(media_packet->data, recovered_packet->pkt->data,
Rasmus Brandtea7beb92016-09-21 12:01:19 +0200167 media_packet->length) != 0) {
168 return false;
169 }
170 return true;
171 };
172 return std::equal(media_packets_.cbegin(), media_packets_.cend(),
173 recovered_packets_.cbegin(), cmp);
174}
175
brandtrece4aba2016-09-20 23:16:28 -0700176// Define gTest typed test to loop over both ULPFEC and FlexFEC.
177// Since the tests now are parameterized, we need to access
178// member variables using |this|, thereby enforcing runtime
179// resolution.
Rasmus Brandtea7beb92016-09-21 12:01:19 +0200180
brandtr0496de22016-10-03 00:43:25 -0700181class FlexfecForwardErrorCorrection : public ForwardErrorCorrection {
182 public:
brandtrd726a3f2017-06-29 02:45:35 -0700183 static const uint32_t kFecSsrc = kFlexfecSsrc;
184
brandtr0496de22016-10-03 00:43:25 -0700185 FlexfecForwardErrorCorrection()
186 : ForwardErrorCorrection(
187 std::unique_ptr<FecHeaderReader>(new FlexfecHeaderReader()),
brandtrd726a3f2017-06-29 02:45:35 -0700188 std::unique_ptr<FecHeaderWriter>(new FlexfecHeaderWriter()),
189 kFecSsrc,
190 kMediaSsrc) {}
191
192 // For FlexFEC we let the FEC packet sequence numbers be independent of
193 // the media packet sequence numbers.
194 static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) {
195 Random random(0xbe110);
196 return random.Rand<uint16_t>();
197 }
brandtr0496de22016-10-03 00:43:25 -0700198};
199
Rasmus Brandtea7beb92016-09-21 12:01:19 +0200200class UlpfecForwardErrorCorrection : public ForwardErrorCorrection {
201 public:
brandtrd726a3f2017-06-29 02:45:35 -0700202 static const uint32_t kFecSsrc = kMediaSsrc;
203
Rasmus Brandtea7beb92016-09-21 12:01:19 +0200204 UlpfecForwardErrorCorrection()
205 : ForwardErrorCorrection(
206 std::unique_ptr<FecHeaderReader>(new UlpfecHeaderReader()),
brandtrd726a3f2017-06-29 02:45:35 -0700207 std::unique_ptr<FecHeaderWriter>(new UlpfecHeaderWriter()),
208 kFecSsrc,
209 kMediaSsrc) {}
210
211 // For ULPFEC we assume that the FEC packets are subsequent to the media
212 // packets in terms of sequence number.
213 static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) {
214 return next_media_seq_num;
215 }
Rasmus Brandtea7beb92016-09-21 12:01:19 +0200216};
217
brandtr0496de22016-10-03 00:43:25 -0700218using FecTypes =
219 Types<FlexfecForwardErrorCorrection, UlpfecForwardErrorCorrection>;
brandtrece4aba2016-09-20 23:16:28 -0700220TYPED_TEST_CASE(RtpFecTest, FecTypes);
221
Rasmus Brandtd73ba122017-12-07 10:22:49 +0100222TYPED_TEST(RtpFecTest, WillProtectMediaPacketsWithLargeSequenceNumberGap) {
223 constexpr int kNumImportantPackets = 0;
224 constexpr bool kUseUnequalProtection = false;
225 constexpr int kNumMediaPackets = 2;
226 constexpr uint8_t kProtectionFactor = 127;
227
228 this->media_packets_ =
229 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
230
231 // Create |kMaxMediaPackets - 1| sequence number difference.
232 ByteWriter<uint16_t>::WriteBigEndian(&this->media_packets_.front()->data[2],
233 1);
234 ByteWriter<uint16_t>::WriteBigEndian(&this->media_packets_.back()->data[2],
235 kMaxMediaPackets);
236
237 EXPECT_EQ(
238 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
239 kNumImportantPackets, kUseUnequalProtection,
240 kFecMaskBursty, &this->generated_fec_packets_));
241 EXPECT_EQ(1u, this->generated_fec_packets_.size());
242}
243
244TYPED_TEST(RtpFecTest,
245 WillNotProtectMediaPacketsWithTooLargeSequenceNumberGap) {
246 constexpr int kNumImportantPackets = 0;
247 constexpr bool kUseUnequalProtection = false;
248 constexpr int kNumMediaPackets = 2;
249 constexpr uint8_t kProtectionFactor = 127;
250
251 this->media_packets_ =
252 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
253
254 // Create |kMaxMediaPackets| sequence number difference.
255 ByteWriter<uint16_t>::WriteBigEndian(&this->media_packets_.front()->data[2],
256 1);
257 ByteWriter<uint16_t>::WriteBigEndian(&this->media_packets_.back()->data[2],
258 kMaxMediaPackets + 1);
259
260 EXPECT_EQ(
261 -1, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
262 kNumImportantPackets, kUseUnequalProtection,
263 kFecMaskBursty, &this->generated_fec_packets_));
264 EXPECT_TRUE(this->generated_fec_packets_.empty());
265}
266
brandtrece4aba2016-09-20 23:16:28 -0700267TYPED_TEST(RtpFecTest, FecRecoveryNoLoss) {
brandtrd90fa0b2016-08-09 06:57:14 -0700268 constexpr int kNumImportantPackets = 0;
269 constexpr bool kUseUnequalProtection = false;
270 constexpr int kNumMediaPackets = 4;
271 constexpr uint8_t kProtectionFactor = 60;
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000272
brandtrece4aba2016-09-20 23:16:28 -0700273 this->media_packets_ =
274 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000275
brandtrece4aba2016-09-20 23:16:28 -0700276 EXPECT_EQ(
277 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
278 kNumImportantPackets, kUseUnequalProtection,
279 kFecMaskBursty, &this->generated_fec_packets_));
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000280
281 // Expect 1 FEC packet.
brandtrece4aba2016-09-20 23:16:28 -0700282 EXPECT_EQ(1u, this->generated_fec_packets_.size());
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000283
284 // No packets lost.
brandtrece4aba2016-09-20 23:16:28 -0700285 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
286 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
287 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000288
nissea5f043f2017-09-18 07:58:59 -0700289 for (const auto& received_packet : this->received_packets_) {
290 this->fec_.DecodeFec(*received_packet,
291 &this->recovered_packets_);
292 }
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000293
294 // No packets lost, expect complete recovery.
brandtrece4aba2016-09-20 23:16:28 -0700295 EXPECT_TRUE(this->IsRecoveryComplete());
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000296}
297
brandtrece4aba2016-09-20 23:16:28 -0700298TYPED_TEST(RtpFecTest, FecRecoveryWithLoss) {
brandtrd90fa0b2016-08-09 06:57:14 -0700299 constexpr int kNumImportantPackets = 0;
300 constexpr bool kUseUnequalProtection = false;
301 constexpr int kNumMediaPackets = 4;
302 constexpr uint8_t kProtectionFactor = 60;
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000303
brandtrece4aba2016-09-20 23:16:28 -0700304 this->media_packets_ =
305 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000306
brandtrece4aba2016-09-20 23:16:28 -0700307 EXPECT_EQ(
308 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
309 kNumImportantPackets, kUseUnequalProtection,
310 kFecMaskBursty, &this->generated_fec_packets_));
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000311
312 // Expect 1 FEC packet.
brandtrece4aba2016-09-20 23:16:28 -0700313 EXPECT_EQ(1u, this->generated_fec_packets_.size());
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000314
315 // 1 media packet lost
brandtrece4aba2016-09-20 23:16:28 -0700316 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
317 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
318 this->media_loss_mask_[3] = 1;
319 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000320
nissea5f043f2017-09-18 07:58:59 -0700321 for (const auto& received_packet : this->received_packets_) {
322 this->fec_.DecodeFec(*received_packet,
323 &this->recovered_packets_);
324 }
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000325
326 // One packet lost, one FEC packet, expect complete recovery.
brandtrece4aba2016-09-20 23:16:28 -0700327 EXPECT_TRUE(this->IsRecoveryComplete());
328 this->recovered_packets_.clear();
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000329
330 // 2 media packets lost.
brandtrece4aba2016-09-20 23:16:28 -0700331 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
332 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
333 this->media_loss_mask_[1] = 1;
334 this->media_loss_mask_[3] = 1;
335 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000336
nissea5f043f2017-09-18 07:58:59 -0700337 for (const auto& received_packet : this->received_packets_) {
338 this->fec_.DecodeFec(*received_packet,
339 &this->recovered_packets_);
340 }
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000341
342 // 2 packets lost, one FEC packet, cannot get complete recovery.
brandtrece4aba2016-09-20 23:16:28 -0700343 EXPECT_FALSE(this->IsRecoveryComplete());
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000344}
345
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000346// Verify that we don't use an old FEC packet for FEC decoding.
Niels Möller958288a2017-10-02 13:51:36 +0200347TYPED_TEST(RtpFecTest, NoFecRecoveryWithOldFecPacket) {
brandtrd90fa0b2016-08-09 06:57:14 -0700348 constexpr int kNumImportantPackets = 0;
349 constexpr bool kUseUnequalProtection = false;
350 constexpr uint8_t kProtectionFactor = 20;
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000351
352 // Two frames: first frame (old) with two media packets and 1 FEC packet.
Niels Möller958288a2017-10-02 13:51:36 +0200353 // Third frame (new) with 3 media packets, and no FEC packets.
354 //
355 // #0(media) #1(media) #2(FEC) ----Frame 1-----
356 // #32767(media) 32768(media) 32769(media) ----Frame 2-----
357 // #65535(media) #0(media) #1(media). ----Frame 3-----
358 // If we lose either packet 0 or 1 of third frame, FEC decoding should not
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000359 // try to decode using "old" FEC packet #2.
360
361 // Construct media packets for first frame, starting at sequence number 0.
brandtrece4aba2016-09-20 23:16:28 -0700362 this->media_packets_ =
363 this->media_packet_generator_.ConstructMediaPackets(2, 0);
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000364
brandtrece4aba2016-09-20 23:16:28 -0700365 EXPECT_EQ(
366 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
367 kNumImportantPackets, kUseUnequalProtection,
368 kFecMaskBursty, &this->generated_fec_packets_));
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000369 // Expect 1 FEC packet.
brandtrece4aba2016-09-20 23:16:28 -0700370 EXPECT_EQ(1u, this->generated_fec_packets_.size());
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000371 // Add FEC packet (seq#2) of this first frame to received list (i.e., assume
372 // the two media packet were lost).
brandtrece4aba2016-09-20 23:16:28 -0700373 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
374 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
375 true);
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000376
377 // Construct media packets for second frame, with sequence number wrap.
brandtrece4aba2016-09-20 23:16:28 -0700378 this->media_packets_ =
Niels Möller958288a2017-10-02 13:51:36 +0200379 this->media_packet_generator_.ConstructMediaPackets(3, 32767);
380
381 // Expect 3 media packets for this frame.
382 EXPECT_EQ(3u, this->media_packets_.size());
383
384 // No packets lost
385 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
386 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
387
388 // Construct media packets for third frame, with sequence number wrap.
389 this->media_packets_ =
brandtrece4aba2016-09-20 23:16:28 -0700390 this->media_packet_generator_.ConstructMediaPackets(3, 65535);
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000391
392 // Expect 3 media packets for this frame.
brandtrece4aba2016-09-20 23:16:28 -0700393 EXPECT_EQ(3u, this->media_packets_.size());
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000394
395 // Second media packet lost (seq#0).
brandtrece4aba2016-09-20 23:16:28 -0700396 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
397 this->media_loss_mask_[1] = 1;
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000398 // Add packets #65535, and #1 to received list.
brandtrece4aba2016-09-20 23:16:28 -0700399 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000400
nissea5f043f2017-09-18 07:58:59 -0700401 for (const auto& received_packet : this->received_packets_) {
402 this->fec_.DecodeFec(*received_packet,
403 &this->recovered_packets_);
404 }
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000405
Niels Möller958288a2017-10-02 13:51:36 +0200406 // Expect that no decoding is done to get missing packet (seq#0) of third
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000407 // frame, using old FEC packet (seq#2) from first (old) frame. So number of
Niels Möller958288a2017-10-02 13:51:36 +0200408 // recovered packets is 5 (0 from first frame, three from second frame, and 2
409 // for the third frame, with no packets recovered via FEC).
410 EXPECT_EQ(5u, this->recovered_packets_.size());
brandtrece4aba2016-09-20 23:16:28 -0700411 EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size());
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000412}
413
brandtrd90fa0b2016-08-09 06:57:14 -0700414// Verify we can still recover frame if sequence number wrap occurs within
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000415// the frame and FEC packet following wrap is received after media packets.
brandtrece4aba2016-09-20 23:16:28 -0700416TYPED_TEST(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameRecovery) {
brandtrd90fa0b2016-08-09 06:57:14 -0700417 constexpr int kNumImportantPackets = 0;
418 constexpr bool kUseUnequalProtection = false;
419 constexpr uint8_t kProtectionFactor = 20;
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000420
421 // One frame, with sequence number wrap in media packets.
422 // -----Frame 1----
423 // #65534(media) #65535(media) #0(media) #1(FEC).
brandtrece4aba2016-09-20 23:16:28 -0700424 this->media_packets_ =
425 this->media_packet_generator_.ConstructMediaPackets(3, 65534);
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000426
brandtrece4aba2016-09-20 23:16:28 -0700427 EXPECT_EQ(
428 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
429 kNumImportantPackets, kUseUnequalProtection,
430 kFecMaskBursty, &this->generated_fec_packets_));
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000431
432 // Expect 1 FEC packet.
brandtrece4aba2016-09-20 23:16:28 -0700433 EXPECT_EQ(1u, this->generated_fec_packets_.size());
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000434
435 // Lose one media packet (seq# 65535).
brandtrece4aba2016-09-20 23:16:28 -0700436 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
437 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
438 this->media_loss_mask_[1] = 1;
439 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000440 // Add FEC packet to received list following the media packets.
brandtrece4aba2016-09-20 23:16:28 -0700441 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
442 true);
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000443
nissea5f043f2017-09-18 07:58:59 -0700444 for (const auto& received_packet : this->received_packets_) {
445 this->fec_.DecodeFec(*received_packet,
446 &this->recovered_packets_);
447 }
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000448
449 // Expect 3 media packets in recovered list, and complete recovery.
450 // Wrap-around won't remove FEC packet, as it follows the wrap.
brandtrece4aba2016-09-20 23:16:28 -0700451 EXPECT_EQ(3u, this->recovered_packets_.size());
452 EXPECT_TRUE(this->IsRecoveryComplete());
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000453}
454
brandtrd726a3f2017-06-29 02:45:35 -0700455// Sequence number wrap occurs within the ULPFEC packets for the frame.
brandtrd726a3f2017-06-29 02:45:35 -0700456// Same problem will occur if wrap is within media packets but ULPFEC packet is
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000457// received before the media packets. This may be improved if timing information
brandtrd726a3f2017-06-29 02:45:35 -0700458// is used to detect old ULPFEC packets.
nissea5f043f2017-09-18 07:58:59 -0700459
460// TODO(nisse): There's some logic to discard ULPFEC packets at wrap-around,
461// however, that is not actually exercised by this test: When the first FEC
462// packet is processed, it results in full recovery of one media packet and the
463// FEC packet is forgotten. And then the wraparound isn't noticed when the next
464// FEC packet is received. We should fix wraparound handling, which currently
465// appears broken, and then figure out how to test it properly.
brandtrd726a3f2017-06-29 02:45:35 -0700466using RtpFecTestUlpfecOnly = RtpFecTest<UlpfecForwardErrorCorrection>;
nissea5f043f2017-09-18 07:58:59 -0700467TEST_F(RtpFecTestUlpfecOnly, FecRecoveryWithSeqNumGapOneFrameRecovery) {
brandtrd90fa0b2016-08-09 06:57:14 -0700468 constexpr int kNumImportantPackets = 0;
469 constexpr bool kUseUnequalProtection = false;
470 constexpr uint8_t kProtectionFactor = 200;
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000471
472 // 1 frame: 3 media packets and 2 FEC packets.
473 // Sequence number wrap in FEC packets.
474 // -----Frame 1----
475 // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC).
brandtrece4aba2016-09-20 23:16:28 -0700476 this->media_packets_ =
477 this->media_packet_generator_.ConstructMediaPackets(3, 65532);
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000478
brandtrece4aba2016-09-20 23:16:28 -0700479 EXPECT_EQ(
480 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
481 kNumImportantPackets, kUseUnequalProtection,
482 kFecMaskBursty, &this->generated_fec_packets_));
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000483
484 // Expect 2 FEC packets.
brandtrece4aba2016-09-20 23:16:28 -0700485 EXPECT_EQ(2u, this->generated_fec_packets_.size());
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000486
487 // Lose the last two media packets (seq# 65533, 65534).
brandtrece4aba2016-09-20 23:16:28 -0700488 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
489 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
490 this->media_loss_mask_[1] = 1;
491 this->media_loss_mask_[2] = 1;
492 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
493 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
494 true);
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000495
nissea5f043f2017-09-18 07:58:59 -0700496 for (const auto& received_packet : this->received_packets_) {
497 this->fec_.DecodeFec(*received_packet,
498 &this->recovered_packets_);
499 }
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000500
501 // The two FEC packets are received and should allow for complete recovery,
brandtrd726a3f2017-06-29 02:45:35 -0700502 // but because of the wrap the first FEC packet will be discarded, and only
503 // one media packet is recoverable. So expect 2 media packets on recovered
504 // list and no complete recovery.
nissea5f043f2017-09-18 07:58:59 -0700505 EXPECT_EQ(3u, this->recovered_packets_.size());
506 EXPECT_EQ(this->recovered_packets_.size(), this->media_packets_.size());
507 EXPECT_TRUE(this->IsRecoveryComplete());
brandtrd726a3f2017-06-29 02:45:35 -0700508}
509
510// TODO(brandtr): This test mimics the one above, ensuring that the recovery
511// strategy of FlexFEC matches the recovery strategy of ULPFEC. Since FlexFEC
512// does not share the sequence number space with the media, however, having a
513// matching recovery strategy may be suboptimal. Study this further.
nissea5f043f2017-09-18 07:58:59 -0700514// TODO(nisse): In this test, recovery based on the first FEC packet fails with
515// the log message "The recovered packet had a length larger than a typical IP
516// packet, and is thus dropped." This is probably not intended, and needs
517// investigation.
brandtrd726a3f2017-06-29 02:45:35 -0700518using RtpFecTestFlexfecOnly = RtpFecTest<FlexfecForwardErrorCorrection>;
519TEST_F(RtpFecTestFlexfecOnly, FecRecoveryWithSeqNumGapOneFrameNoRecovery) {
520 constexpr int kNumImportantPackets = 0;
521 constexpr bool kUseUnequalProtection = false;
522 constexpr uint8_t kProtectionFactor = 200;
523
524 // 1 frame: 3 media packets and 2 FEC packets.
525 // Sequence number wrap in FEC packets.
526 // -----Frame 1----
527 // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC).
528 this->media_packets_ =
529 this->media_packet_generator_.ConstructMediaPackets(3, 65532);
530
531 EXPECT_EQ(
532 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
533 kNumImportantPackets, kUseUnequalProtection,
534 kFecMaskBursty, &this->generated_fec_packets_));
535
536 // Expect 2 FEC packets.
537 EXPECT_EQ(2u, this->generated_fec_packets_.size());
538
539 // Overwrite the sequence numbers generated by ConstructMediaPackets,
540 // to make sure that we do have a wrap.
541 auto it = this->generated_fec_packets_.begin();
542 ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data[2], 65535);
543 ++it;
544 ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data[2], 0);
545
546 // Lose the last two media packets (seq# 65533, 65534).
547 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
548 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
549 this->media_loss_mask_[1] = 1;
550 this->media_loss_mask_[2] = 1;
551 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
552 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
553 true);
554
nissea5f043f2017-09-18 07:58:59 -0700555 for (const auto& received_packet : this->received_packets_) {
556 this->fec_.DecodeFec(*received_packet,
557 &this->recovered_packets_);
558 }
brandtrd726a3f2017-06-29 02:45:35 -0700559
560 // The two FEC packets are received and should allow for complete recovery,
561 // but because of the wrap the first FEC packet will be discarded, and only
562 // one media packet is recoverable. So expect 2 media packets on recovered
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000563 // list and no complete recovery.
brandtrece4aba2016-09-20 23:16:28 -0700564 EXPECT_EQ(2u, this->recovered_packets_.size());
565 EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size());
566 EXPECT_FALSE(this->IsRecoveryComplete());
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000567}
568
brandtrd90fa0b2016-08-09 06:57:14 -0700569// Verify we can still recover frame if media packets are reordered.
brandtrece4aba2016-09-20 23:16:28 -0700570TYPED_TEST(RtpFecTest, FecRecoveryWithMediaOutOfOrder) {
brandtrd90fa0b2016-08-09 06:57:14 -0700571 constexpr int kNumImportantPackets = 0;
572 constexpr bool kUseUnequalProtection = false;
573 constexpr uint8_t kProtectionFactor = 20;
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000574
575 // One frame: 3 media packets, 1 FEC packet.
576 // -----Frame 1----
577 // #0(media) #1(media) #2(media) #3(FEC).
brandtrece4aba2016-09-20 23:16:28 -0700578 this->media_packets_ =
579 this->media_packet_generator_.ConstructMediaPackets(3, 0);
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000580
brandtrece4aba2016-09-20 23:16:28 -0700581 EXPECT_EQ(
582 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
583 kNumImportantPackets, kUseUnequalProtection,
584 kFecMaskBursty, &this->generated_fec_packets_));
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000585
586 // Expect 1 FEC packet.
brandtrece4aba2016-09-20 23:16:28 -0700587 EXPECT_EQ(1u, this->generated_fec_packets_.size());
brandtrd90fa0b2016-08-09 06:57:14 -0700588
589 // Lose one media packet (seq# 1).
brandtrece4aba2016-09-20 23:16:28 -0700590 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
591 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
592 this->media_loss_mask_[1] = 1;
593 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
brandtrd90fa0b2016-08-09 06:57:14 -0700594
595 // Reorder received media packets.
brandtrece4aba2016-09-20 23:16:28 -0700596 auto it0 = this->received_packets_.begin();
brandtrd726a3f2017-06-29 02:45:35 -0700597 auto it1 = this->received_packets_.begin();
598 it1++;
599 std::swap(*it0, *it1);
brandtrd90fa0b2016-08-09 06:57:14 -0700600
nissea5f043f2017-09-18 07:58:59 -0700601 for (const auto& received_packet : this->received_packets_) {
602 this->fec_.DecodeFec(*received_packet,
603 &this->recovered_packets_);
604 }
brandtrd90fa0b2016-08-09 06:57:14 -0700605
606 // Expect 3 media packets in recovered list, and complete recovery.
brandtrece4aba2016-09-20 23:16:28 -0700607 EXPECT_EQ(3u, this->recovered_packets_.size());
608 EXPECT_TRUE(this->IsRecoveryComplete());
brandtrd90fa0b2016-08-09 06:57:14 -0700609}
610
611// Verify we can still recover frame if FEC is received before media packets.
brandtrece4aba2016-09-20 23:16:28 -0700612TYPED_TEST(RtpFecTest, FecRecoveryWithFecOutOfOrder) {
brandtrd90fa0b2016-08-09 06:57:14 -0700613 constexpr int kNumImportantPackets = 0;
614 constexpr bool kUseUnequalProtection = false;
615 constexpr uint8_t kProtectionFactor = 20;
616
617 // One frame: 3 media packets, 1 FEC packet.
618 // -----Frame 1----
619 // #0(media) #1(media) #2(media) #3(FEC).
brandtrece4aba2016-09-20 23:16:28 -0700620 this->media_packets_ =
621 this->media_packet_generator_.ConstructMediaPackets(3, 0);
brandtrd90fa0b2016-08-09 06:57:14 -0700622
brandtrece4aba2016-09-20 23:16:28 -0700623 EXPECT_EQ(
624 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
625 kNumImportantPackets, kUseUnequalProtection,
626 kFecMaskBursty, &this->generated_fec_packets_));
brandtrd90fa0b2016-08-09 06:57:14 -0700627
628 // Expect 1 FEC packet.
brandtrece4aba2016-09-20 23:16:28 -0700629 EXPECT_EQ(1u, this->generated_fec_packets_.size());
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000630
631 // Lose one media packet (seq# 1).
brandtrece4aba2016-09-20 23:16:28 -0700632 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
633 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
634 this->media_loss_mask_[1] = 1;
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000635 // Add FEC packet to received list before the media packets.
brandtrece4aba2016-09-20 23:16:28 -0700636 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
637 true);
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000638 // Add media packets to received list.
brandtrece4aba2016-09-20 23:16:28 -0700639 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000640
nissea5f043f2017-09-18 07:58:59 -0700641 for (const auto& received_packet : this->received_packets_) {
642 this->fec_.DecodeFec(*received_packet,
643 &this->recovered_packets_);
644 }
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000645
646 // Expect 3 media packets in recovered list, and complete recovery.
brandtrece4aba2016-09-20 23:16:28 -0700647 EXPECT_EQ(3u, this->recovered_packets_.size());
648 EXPECT_TRUE(this->IsRecoveryComplete());
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000649}
650
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000651// Test 50% protection with random mask type: Two cases are considered:
652// a 50% non-consecutive loss which can be fully recovered, and a 50%
653// consecutive loss which cannot be fully recovered.
brandtrece4aba2016-09-20 23:16:28 -0700654TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
brandtrd90fa0b2016-08-09 06:57:14 -0700655 constexpr int kNumImportantPackets = 0;
656 constexpr bool kUseUnequalProtection = false;
657 constexpr int kNumMediaPackets = 4;
658 constexpr uint8_t kProtectionFactor = 255;
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000659
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000660 // Packet Mask for (4,4,0) code, from random mask table.
661 // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000662
663 // media#0 media#1 media#2 media#3
664 // fec#0: 1 1 0 0
665 // fec#1: 1 0 1 0
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000666 // fec#2: 0 0 1 1
667 // fec#3: 0 1 0 1
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000668 //
669
brandtrece4aba2016-09-20 23:16:28 -0700670 this->media_packets_ =
671 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000672
brandtrece4aba2016-09-20 23:16:28 -0700673 EXPECT_EQ(
674 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
675 kNumImportantPackets, kUseUnequalProtection,
676 kFecMaskRandom, &this->generated_fec_packets_));
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000677
678 // Expect 4 FEC packets.
brandtrece4aba2016-09-20 23:16:28 -0700679 EXPECT_EQ(4u, this->generated_fec_packets_.size());
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000680
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000681 // 4 packets lost: 3 media packets (0, 2, 3), and one FEC packet (0) lost.
brandtrece4aba2016-09-20 23:16:28 -0700682 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
683 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
684 this->fec_loss_mask_[0] = 1;
685 this->media_loss_mask_[0] = 1;
686 this->media_loss_mask_[2] = 1;
687 this->media_loss_mask_[3] = 1;
688 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000689
nissea5f043f2017-09-18 07:58:59 -0700690 for (const auto& received_packet : this->received_packets_) {
691 this->fec_.DecodeFec(*received_packet,
692 &this->recovered_packets_);
693 }
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000694
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000695 // With media packet#1 and FEC packets #1, #2, #3, expect complete recovery.
brandtrece4aba2016-09-20 23:16:28 -0700696 EXPECT_TRUE(this->IsRecoveryComplete());
697 this->recovered_packets_.clear();
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000698
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000699 // 4 consecutive packets lost: media packets 0, 1, 2, 3.
brandtrece4aba2016-09-20 23:16:28 -0700700 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
701 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
702 this->media_loss_mask_[0] = 1;
703 this->media_loss_mask_[1] = 1;
704 this->media_loss_mask_[2] = 1;
705 this->media_loss_mask_[3] = 1;
706 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000707
nissea5f043f2017-09-18 07:58:59 -0700708 for (const auto& received_packet : this->received_packets_) {
709 this->fec_.DecodeFec(*received_packet,
710 &this->recovered_packets_);
711 }
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000712
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000713 // Cannot get complete recovery for this loss configuration with random mask.
brandtrece4aba2016-09-20 23:16:28 -0700714 EXPECT_FALSE(this->IsRecoveryComplete());
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000715}
716
717// Test 50% protection with bursty type: Three cases are considered:
718// two 50% consecutive losses which can be fully recovered, and one
719// non-consecutive which cannot be fully recovered.
brandtrece4aba2016-09-20 23:16:28 -0700720TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
brandtrd90fa0b2016-08-09 06:57:14 -0700721 constexpr int kNumImportantPackets = 0;
722 constexpr bool kUseUnequalProtection = false;
723 constexpr int kNumMediaPackets = 4;
724 constexpr uint8_t kProtectionFactor = 255;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000725
726 // Packet Mask for (4,4,0) code, from bursty mask table.
727 // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
728
729 // media#0 media#1 media#2 media#3
730 // fec#0: 1 0 0 0
731 // fec#1: 1 1 0 0
732 // fec#2: 0 1 1 0
733 // fec#3: 0 0 1 1
734 //
735
brandtrece4aba2016-09-20 23:16:28 -0700736 this->media_packets_ =
737 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000738
brandtrece4aba2016-09-20 23:16:28 -0700739 EXPECT_EQ(
740 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
741 kNumImportantPackets, kUseUnequalProtection,
742 kFecMaskBursty, &this->generated_fec_packets_));
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000743
744 // Expect 4 FEC packets.
brandtrece4aba2016-09-20 23:16:28 -0700745 EXPECT_EQ(4u, this->generated_fec_packets_.size());
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000746
747 // 4 consecutive packets lost: media packets 0,1,2,3.
brandtrece4aba2016-09-20 23:16:28 -0700748 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
749 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
750 this->media_loss_mask_[0] = 1;
751 this->media_loss_mask_[1] = 1;
752 this->media_loss_mask_[2] = 1;
753 this->media_loss_mask_[3] = 1;
754 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000755
nissea5f043f2017-09-18 07:58:59 -0700756 for (const auto& received_packet : this->received_packets_) {
757 this->fec_.DecodeFec(*received_packet,
758 &this->recovered_packets_);
759 }
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000760
761 // Expect complete recovery for consecutive packet loss <= 50%.
brandtrece4aba2016-09-20 23:16:28 -0700762 EXPECT_TRUE(this->IsRecoveryComplete());
763 this->recovered_packets_.clear();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000764
765 // 4 consecutive packets lost: media packets 1,2, 3, and FEC packet 0.
brandtrece4aba2016-09-20 23:16:28 -0700766 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
767 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
768 this->fec_loss_mask_[0] = 1;
769 this->media_loss_mask_[1] = 1;
770 this->media_loss_mask_[2] = 1;
771 this->media_loss_mask_[3] = 1;
772 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000773
nissea5f043f2017-09-18 07:58:59 -0700774 for (const auto& received_packet : this->received_packets_) {
775 this->fec_.DecodeFec(*received_packet,
776 &this->recovered_packets_);
777 }
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000778
779 // Expect complete recovery for consecutive packet loss <= 50%.
brandtrece4aba2016-09-20 23:16:28 -0700780 EXPECT_TRUE(this->IsRecoveryComplete());
781 this->recovered_packets_.clear();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000782
783 // 4 packets lost (non-consecutive loss): media packets 0, 3, and FEC# 0, 3.
brandtrece4aba2016-09-20 23:16:28 -0700784 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
785 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
786 this->fec_loss_mask_[0] = 1;
787 this->fec_loss_mask_[3] = 1;
788 this->media_loss_mask_[0] = 1;
789 this->media_loss_mask_[3] = 1;
790 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000791
nissea5f043f2017-09-18 07:58:59 -0700792 for (const auto& received_packet : this->received_packets_) {
793 this->fec_.DecodeFec(*received_packet,
794 &this->recovered_packets_);
795 }
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000796
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000797 // Cannot get complete recovery for this loss configuration.
brandtrece4aba2016-09-20 23:16:28 -0700798 EXPECT_FALSE(this->IsRecoveryComplete());
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000799}
800
brandtrece4aba2016-09-20 23:16:28 -0700801TYPED_TEST(RtpFecTest, FecRecoveryNoLossUep) {
brandtrd90fa0b2016-08-09 06:57:14 -0700802 constexpr int kNumImportantPackets = 2;
803 constexpr bool kUseUnequalProtection = true;
804 constexpr int kNumMediaPackets = 4;
805 constexpr uint8_t kProtectionFactor = 60;
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000806
brandtrece4aba2016-09-20 23:16:28 -0700807 this->media_packets_ =
808 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000809
brandtrece4aba2016-09-20 23:16:28 -0700810 EXPECT_EQ(
811 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
812 kNumImportantPackets, kUseUnequalProtection,
813 kFecMaskBursty, &this->generated_fec_packets_));
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000814
815 // Expect 1 FEC packet.
brandtrece4aba2016-09-20 23:16:28 -0700816 EXPECT_EQ(1u, this->generated_fec_packets_.size());
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000817
818 // No packets lost.
brandtrece4aba2016-09-20 23:16:28 -0700819 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
820 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
821 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000822
nissea5f043f2017-09-18 07:58:59 -0700823 for (const auto& received_packet : this->received_packets_) {
824 this->fec_.DecodeFec(*received_packet,
825 &this->recovered_packets_);
826 }
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000827
828 // No packets lost, expect complete recovery.
brandtrece4aba2016-09-20 23:16:28 -0700829 EXPECT_TRUE(this->IsRecoveryComplete());
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000830}
831
brandtrece4aba2016-09-20 23:16:28 -0700832TYPED_TEST(RtpFecTest, FecRecoveryWithLossUep) {
brandtrd90fa0b2016-08-09 06:57:14 -0700833 constexpr int kNumImportantPackets = 2;
834 constexpr bool kUseUnequalProtection = true;
835 constexpr int kNumMediaPackets = 4;
836 constexpr uint8_t kProtectionFactor = 60;
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000837
brandtrece4aba2016-09-20 23:16:28 -0700838 this->media_packets_ =
839 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000840
brandtrece4aba2016-09-20 23:16:28 -0700841 EXPECT_EQ(
842 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
843 kNumImportantPackets, kUseUnequalProtection,
844 kFecMaskBursty, &this->generated_fec_packets_));
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000845
846 // Expect 1 FEC packet.
brandtrece4aba2016-09-20 23:16:28 -0700847 EXPECT_EQ(1u, this->generated_fec_packets_.size());
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000848
849 // 1 media packet lost.
brandtrece4aba2016-09-20 23:16:28 -0700850 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
851 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
852 this->media_loss_mask_[3] = 1;
853 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000854
nissea5f043f2017-09-18 07:58:59 -0700855 for (const auto& received_packet : this->received_packets_) {
856 this->fec_.DecodeFec(*received_packet,
857 &this->recovered_packets_);
858 }
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000859
860 // One packet lost, one FEC packet, expect complete recovery.
brandtrece4aba2016-09-20 23:16:28 -0700861 EXPECT_TRUE(this->IsRecoveryComplete());
862 this->recovered_packets_.clear();
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000863
864 // 2 media packets lost.
brandtrece4aba2016-09-20 23:16:28 -0700865 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
866 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
867 this->media_loss_mask_[1] = 1;
868 this->media_loss_mask_[3] = 1;
869 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000870
nissea5f043f2017-09-18 07:58:59 -0700871 for (const auto& received_packet : this->received_packets_) {
872 this->fec_.DecodeFec(*received_packet,
873 &this->recovered_packets_);
874 }
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000875
876 // 2 packets lost, one FEC packet, cannot get complete recovery.
brandtrece4aba2016-09-20 23:16:28 -0700877 EXPECT_FALSE(this->IsRecoveryComplete());
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000878}
879
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000880// Test 50% protection with random mask type for UEP on.
brandtrece4aba2016-09-20 23:16:28 -0700881TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
brandtrd90fa0b2016-08-09 06:57:14 -0700882 constexpr int kNumImportantPackets = 1;
883 constexpr bool kUseUnequalProtection = true;
884 constexpr int kNumMediaPackets = 4;
885 constexpr uint8_t kProtectionFactor = 255;
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000886
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000887 // Packet Mask for (4,4,1) code, from random mask table.
888 // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 1)
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000889
890 // media#0 media#1 media#2 media#3
891 // fec#0: 1 0 0 0
892 // fec#1: 1 1 0 0
893 // fec#2: 1 0 1 1
894 // fec#3: 0 1 1 0
895 //
896
brandtrece4aba2016-09-20 23:16:28 -0700897 this->media_packets_ =
898 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000899
brandtrece4aba2016-09-20 23:16:28 -0700900 EXPECT_EQ(
901 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
902 kNumImportantPackets, kUseUnequalProtection,
903 kFecMaskRandom, &this->generated_fec_packets_));
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000904
905 // Expect 4 FEC packets.
brandtrece4aba2016-09-20 23:16:28 -0700906 EXPECT_EQ(4u, this->generated_fec_packets_.size());
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000907
908 // 4 packets lost: 3 media packets and FEC packet#1 lost.
brandtrece4aba2016-09-20 23:16:28 -0700909 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
910 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
911 this->fec_loss_mask_[1] = 1;
912 this->media_loss_mask_[0] = 1;
913 this->media_loss_mask_[2] = 1;
914 this->media_loss_mask_[3] = 1;
915 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000916
nissea5f043f2017-09-18 07:58:59 -0700917 for (const auto& received_packet : this->received_packets_) {
918 this->fec_.DecodeFec(*received_packet,
919 &this->recovered_packets_);
920 }
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000921
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000922 // With media packet#3 and FEC packets #0, #1, #3, expect complete recovery.
brandtrece4aba2016-09-20 23:16:28 -0700923 EXPECT_TRUE(this->IsRecoveryComplete());
924 this->recovered_packets_.clear();
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000925
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000926 // 5 packets lost: 4 media packets and one FEC packet#2 lost.
brandtrece4aba2016-09-20 23:16:28 -0700927 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
928 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
929 this->fec_loss_mask_[2] = 1;
930 this->media_loss_mask_[0] = 1;
931 this->media_loss_mask_[1] = 1;
932 this->media_loss_mask_[2] = 1;
933 this->media_loss_mask_[3] = 1;
934 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000935
nissea5f043f2017-09-18 07:58:59 -0700936 for (const auto& received_packet : this->received_packets_) {
937 this->fec_.DecodeFec(*received_packet,
938 &this->recovered_packets_);
939 }
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000940
941 // Cannot get complete recovery for this loss configuration.
brandtrece4aba2016-09-20 23:16:28 -0700942 EXPECT_FALSE(this->IsRecoveryComplete());
marpan@webrtc.orgb783a552012-02-04 02:46:35 +0000943}
944
brandtrece4aba2016-09-20 23:16:28 -0700945TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePackets) {
brandtrd90fa0b2016-08-09 06:57:14 -0700946 constexpr int kNumImportantPackets = 0;
947 constexpr bool kUseUnequalProtection = false;
948 constexpr int kNumMediaPackets = 5;
949 constexpr uint8_t kProtectionFactor = 60;
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000950
brandtrece4aba2016-09-20 23:16:28 -0700951 this->media_packets_ =
952 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000953
954 // Create a new temporary packet list for generating FEC packets.
955 // This list should have every other packet removed.
brandtrece4aba2016-09-20 23:16:28 -0700956 ForwardErrorCorrection::PacketList protected_media_packets;
957 DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000958
brandtrece4aba2016-09-20 23:16:28 -0700959 EXPECT_EQ(
960 0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor,
961 kNumImportantPackets, kUseUnequalProtection,
962 kFecMaskBursty, &this->generated_fec_packets_));
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000963
964 // Expect 1 FEC packet.
brandtrece4aba2016-09-20 23:16:28 -0700965 EXPECT_EQ(1u, this->generated_fec_packets_.size());
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000966
967 // 1 protected media packet lost
brandtrece4aba2016-09-20 23:16:28 -0700968 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
969 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
970 this->media_loss_mask_[2] = 1;
971 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000972
nissea5f043f2017-09-18 07:58:59 -0700973 for (const auto& received_packet : this->received_packets_) {
974 this->fec_.DecodeFec(*received_packet,
975 &this->recovered_packets_);
976 }
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000977
978 // One packet lost, one FEC packet, expect complete recovery.
brandtrece4aba2016-09-20 23:16:28 -0700979 EXPECT_TRUE(this->IsRecoveryComplete());
980 this->recovered_packets_.clear();
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000981
982 // Unprotected packet lost.
brandtrece4aba2016-09-20 23:16:28 -0700983 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
984 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
985 this->media_loss_mask_[1] = 1;
986 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000987
nissea5f043f2017-09-18 07:58:59 -0700988 for (const auto& received_packet : this->received_packets_) {
989 this->fec_.DecodeFec(*received_packet,
990 &this->recovered_packets_);
991 }
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000992
993 // Unprotected packet lost. Recovery not possible.
brandtrece4aba2016-09-20 23:16:28 -0700994 EXPECT_FALSE(this->IsRecoveryComplete());
995 this->recovered_packets_.clear();
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000996
997 // 2 media packets lost.
brandtrece4aba2016-09-20 23:16:28 -0700998 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
999 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1000 this->media_loss_mask_[0] = 1;
1001 this->media_loss_mask_[2] = 1;
1002 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001003
nissea5f043f2017-09-18 07:58:59 -07001004 for (const auto& received_packet : this->received_packets_) {
1005 this->fec_.DecodeFec(*received_packet,
1006 &this->recovered_packets_);
1007 }
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001008
1009 // 2 protected packets lost, one FEC packet, cannot get complete recovery.
brandtrece4aba2016-09-20 23:16:28 -07001010 EXPECT_FALSE(this->IsRecoveryComplete());
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001011}
1012
brandtrece4aba2016-09-20 23:16:28 -07001013TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
brandtrd90fa0b2016-08-09 06:57:14 -07001014 constexpr int kNumImportantPackets = 0;
1015 constexpr bool kUseUnequalProtection = false;
1016 constexpr int kNumMediaPackets = 21;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +00001017 uint8_t kProtectionFactor = 127;
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001018
brandtrece4aba2016-09-20 23:16:28 -07001019 this->media_packets_ =
1020 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001021
1022 // Create a new temporary packet list for generating FEC packets.
1023 // This list should have every other packet removed.
brandtrece4aba2016-09-20 23:16:28 -07001024 ForwardErrorCorrection::PacketList protected_media_packets;
1025 DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001026
1027 // Zero column insertion will have to extend the size of the packet
1028 // mask since the number of actual packets are 21, while the number
1029 // of protected packets are 11.
brandtrece4aba2016-09-20 23:16:28 -07001030 EXPECT_EQ(
1031 0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor,
1032 kNumImportantPackets, kUseUnequalProtection,
1033 kFecMaskBursty, &this->generated_fec_packets_));
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001034
1035 // Expect 5 FEC packet.
brandtrece4aba2016-09-20 23:16:28 -07001036 EXPECT_EQ(5u, this->generated_fec_packets_.size());
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001037
1038 // Last protected media packet lost
brandtrece4aba2016-09-20 23:16:28 -07001039 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1040 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1041 this->media_loss_mask_[kNumMediaPackets - 1] = 1;
1042 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001043
nissea5f043f2017-09-18 07:58:59 -07001044 for (const auto& received_packet : this->received_packets_) {
1045 this->fec_.DecodeFec(*received_packet,
1046 &this->recovered_packets_);
1047 }
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001048
1049 // One packet lost, one FEC packet, expect complete recovery.
brandtrece4aba2016-09-20 23:16:28 -07001050 EXPECT_TRUE(this->IsRecoveryComplete());
1051 this->recovered_packets_.clear();
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001052
1053 // Last unprotected packet lost.
brandtrece4aba2016-09-20 23:16:28 -07001054 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1055 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1056 this->media_loss_mask_[kNumMediaPackets - 2] = 1;
1057 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001058
nissea5f043f2017-09-18 07:58:59 -07001059 for (const auto& received_packet : this->received_packets_) {
1060 this->fec_.DecodeFec(*received_packet,
1061 &this->recovered_packets_);
1062 }
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001063
1064 // Unprotected packet lost. Recovery not possible.
brandtrece4aba2016-09-20 23:16:28 -07001065 EXPECT_FALSE(this->IsRecoveryComplete());
1066 this->recovered_packets_.clear();
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001067
1068 // 6 media packets lost.
brandtrece4aba2016-09-20 23:16:28 -07001069 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1070 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1071 this->media_loss_mask_[kNumMediaPackets - 11] = 1;
1072 this->media_loss_mask_[kNumMediaPackets - 9] = 1;
1073 this->media_loss_mask_[kNumMediaPackets - 7] = 1;
1074 this->media_loss_mask_[kNumMediaPackets - 5] = 1;
1075 this->media_loss_mask_[kNumMediaPackets - 3] = 1;
1076 this->media_loss_mask_[kNumMediaPackets - 1] = 1;
1077 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001078
nissea5f043f2017-09-18 07:58:59 -07001079 for (const auto& received_packet : this->received_packets_) {
1080 this->fec_.DecodeFec(*received_packet,
1081 &this->recovered_packets_);
1082 }
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001083
1084 // 5 protected packets lost, one FEC packet, cannot get complete recovery.
brandtrece4aba2016-09-20 23:16:28 -07001085 EXPECT_FALSE(this->IsRecoveryComplete());
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001086}
1087
brandtrece4aba2016-09-20 23:16:28 -07001088TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
brandtrd90fa0b2016-08-09 06:57:14 -07001089 constexpr int kNumImportantPackets = 0;
1090 constexpr bool kUseUnequalProtection = false;
1091 constexpr int kNumMediaPackets = 21;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +00001092 uint8_t kProtectionFactor = 127;
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001093
brandtrece4aba2016-09-20 23:16:28 -07001094 this->media_packets_ = this->media_packet_generator_.ConstructMediaPackets(
1095 kNumMediaPackets, 0xFFFF - 5);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001096
1097 // Create a new temporary packet list for generating FEC packets.
1098 // This list should have every other packet removed.
brandtrece4aba2016-09-20 23:16:28 -07001099 ForwardErrorCorrection::PacketList protected_media_packets;
1100 DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001101
1102 // Zero column insertion will have to extend the size of the packet
1103 // mask since the number of actual packets are 21, while the number
1104 // of protected packets are 11.
brandtrece4aba2016-09-20 23:16:28 -07001105 EXPECT_EQ(
1106 0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor,
1107 kNumImportantPackets, kUseUnequalProtection,
1108 kFecMaskBursty, &this->generated_fec_packets_));
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001109
1110 // Expect 5 FEC packet.
brandtrece4aba2016-09-20 23:16:28 -07001111 EXPECT_EQ(5u, this->generated_fec_packets_.size());
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001112
1113 // Last protected media packet lost
brandtrece4aba2016-09-20 23:16:28 -07001114 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1115 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1116 this->media_loss_mask_[kNumMediaPackets - 1] = 1;
1117 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001118
nissea5f043f2017-09-18 07:58:59 -07001119 for (const auto& received_packet : this->received_packets_) {
1120 this->fec_.DecodeFec(*received_packet,
1121 &this->recovered_packets_);
1122 }
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001123
1124 // One packet lost, one FEC packet, expect complete recovery.
brandtrece4aba2016-09-20 23:16:28 -07001125 EXPECT_TRUE(this->IsRecoveryComplete());
1126 this->recovered_packets_.clear();
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001127
1128 // Last unprotected packet lost.
brandtrece4aba2016-09-20 23:16:28 -07001129 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1130 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1131 this->media_loss_mask_[kNumMediaPackets - 2] = 1;
1132 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001133
nissea5f043f2017-09-18 07:58:59 -07001134 for (const auto& received_packet : this->received_packets_) {
1135 this->fec_.DecodeFec(*received_packet,
1136 &this->recovered_packets_);
1137 }
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001138
1139 // Unprotected packet lost. Recovery not possible.
brandtrece4aba2016-09-20 23:16:28 -07001140 EXPECT_FALSE(this->IsRecoveryComplete());
1141 this->recovered_packets_.clear();
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001142
1143 // 6 media packets lost.
brandtrece4aba2016-09-20 23:16:28 -07001144 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1145 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1146 this->media_loss_mask_[kNumMediaPackets - 11] = 1;
1147 this->media_loss_mask_[kNumMediaPackets - 9] = 1;
1148 this->media_loss_mask_[kNumMediaPackets - 7] = 1;
1149 this->media_loss_mask_[kNumMediaPackets - 5] = 1;
1150 this->media_loss_mask_[kNumMediaPackets - 3] = 1;
1151 this->media_loss_mask_[kNumMediaPackets - 1] = 1;
1152 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001153
nissea5f043f2017-09-18 07:58:59 -07001154 for (const auto& received_packet : this->received_packets_) {
1155 this->fec_.DecodeFec(*received_packet,
1156 &this->recovered_packets_);
1157 }
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001158
1159 // 5 protected packets lost, one FEC packet, cannot get complete recovery.
brandtrece4aba2016-09-20 23:16:28 -07001160 EXPECT_FALSE(this->IsRecoveryComplete());
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00001161}
1162
brandtrece4aba2016-09-20 23:16:28 -07001163} // namespace webrtc