• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
11 #include <list>
12 #include <memory>
13 
14 #include "absl/algorithm/container.h"
15 #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/random.h"
21 #include "test/gtest.h"
22 
23 namespace webrtc {
24 
25 namespace {
26 
27 // Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum.
28 constexpr size_t kTransportOverhead = 28;
29 
30 constexpr uint32_t kMediaSsrc = 83542;
31 constexpr uint32_t kFlexfecSsrc = 43245;
32 
33 constexpr size_t kMaxMediaPackets = 48;
34 
35 // Deep copies |src| to |dst|, but only keeps every Nth packet.
DeepCopyEveryNthPacket(const ForwardErrorCorrection::PacketList & src,int n,ForwardErrorCorrection::PacketList * dst)36 void DeepCopyEveryNthPacket(const ForwardErrorCorrection::PacketList& src,
37                             int n,
38                             ForwardErrorCorrection::PacketList* dst) {
39   RTC_DCHECK_GT(n, 0);
40   int i = 0;
41   for (const auto& packet : src) {
42     if (i % n == 0) {
43       dst->emplace_back(new ForwardErrorCorrection::Packet(*packet));
44     }
45     ++i;
46   }
47 }
48 
49 }  // namespace
50 
51 using ::testing::Types;
52 
53 template <typename ForwardErrorCorrectionType>
54 class RtpFecTest : public ::testing::Test {
55  protected:
RtpFecTest()56   RtpFecTest()
57       : random_(0xabcdef123456),
58         media_packet_generator_(
59             kRtpHeaderSize,  // Minimum packet size.
60             IP_PACKET_SIZE - kRtpHeaderSize - kTransportOverhead -
61                 fec_.MaxPacketOverhead(),  // Maximum packet size.
62             kMediaSsrc,
63             &random_) {}
64 
65   // Construct |received_packets_|: a subset of the media and FEC packets.
66   //
67   // Media packet "i" is lost if media_loss_mask_[i] = 1, received if
68   // media_loss_mask_[i] = 0.
69   // FEC packet "i" is lost if fec_loss_mask_[i] = 1, received if
70   // fec_loss_mask_[i] = 0.
71   void NetworkReceivedPackets(int* media_loss_mask, int* fec_loss_mask);
72 
73   // Add packet from |packet_list| to list of received packets, using the
74   // |loss_mask|.
75   // The |packet_list| may be a media packet list (is_fec = false), or a
76   // FEC packet list (is_fec = true).
77   template <typename T>
78   void ReceivedPackets(const T& packet_list, int* loss_mask, bool is_fec);
79 
80   // Check for complete recovery after FEC decoding.
81   bool IsRecoveryComplete();
82 
83   ForwardErrorCorrectionType fec_;
84 
85   Random random_;
86   test::fec::MediaPacketGenerator media_packet_generator_;
87 
88   ForwardErrorCorrection::PacketList media_packets_;
89   std::list<ForwardErrorCorrection::Packet*> generated_fec_packets_;
90   std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>>
91       received_packets_;
92   ForwardErrorCorrection::RecoveredPacketList recovered_packets_;
93 
94   int media_loss_mask_[kUlpfecMaxMediaPackets];
95   int fec_loss_mask_[kUlpfecMaxMediaPackets];
96 };
97 
98 template <typename ForwardErrorCorrectionType>
NetworkReceivedPackets(int * media_loss_mask,int * fec_loss_mask)99 void RtpFecTest<ForwardErrorCorrectionType>::NetworkReceivedPackets(
100     int* media_loss_mask,
101     int* fec_loss_mask) {
102   constexpr bool kFecPacket = true;
103   this->received_packets_.clear();
104   ReceivedPackets(media_packets_, media_loss_mask, !kFecPacket);
105   ReceivedPackets(generated_fec_packets_, fec_loss_mask, kFecPacket);
106 }
107 
108 template <typename ForwardErrorCorrectionType>
109 template <typename PacketListType>
ReceivedPackets(const PacketListType & packet_list,int * loss_mask,bool is_fec)110 void RtpFecTest<ForwardErrorCorrectionType>::ReceivedPackets(
111     const PacketListType& packet_list,
112     int* loss_mask,
113     bool is_fec) {
114   uint16_t fec_seq_num = ForwardErrorCorrectionType::GetFirstFecSeqNum(
115       media_packet_generator_.GetNextSeqNum());
116   int packet_idx = 0;
117 
118   for (const auto& packet : packet_list) {
119     if (loss_mask[packet_idx] == 0) {
120       std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet(
121           new ForwardErrorCorrection::ReceivedPacket());
122       received_packet->pkt = new ForwardErrorCorrection::Packet();
123       received_packet->pkt->data = packet->data;
124       received_packet->is_fec = is_fec;
125       if (!is_fec) {
126         received_packet->ssrc = kMediaSsrc;
127         // For media packets, the sequence number is obtained from the
128         // RTP header as written by MediaPacketGenerator::ConstructMediaPackets.
129         received_packet->seq_num =
130             ByteReader<uint16_t>::ReadBigEndian(&packet->data[2]);
131       } else {
132         received_packet->ssrc = ForwardErrorCorrectionType::kFecSsrc;
133         // For FEC packets, we simulate the sequence numbers differently
134         // depending on if ULPFEC or FlexFEC is used. See the definition of
135         // ForwardErrorCorrectionType::GetFirstFecSeqNum.
136         received_packet->seq_num = fec_seq_num;
137       }
138       received_packets_.push_back(std::move(received_packet));
139     }
140     packet_idx++;
141     // Sequence number of FEC packets are defined as increment by 1 from
142     // last media packet in frame.
143     if (is_fec)
144       fec_seq_num++;
145   }
146 }
147 
148 template <typename ForwardErrorCorrectionType>
IsRecoveryComplete()149 bool RtpFecTest<ForwardErrorCorrectionType>::IsRecoveryComplete() {
150   // We must have equally many recovered packets as original packets and all
151   // recovered packets must be identical to the corresponding original packets.
152   return absl::c_equal(
153       media_packets_, recovered_packets_,
154       [](const std::unique_ptr<ForwardErrorCorrection::Packet>& media_packet,
155          const std::unique_ptr<ForwardErrorCorrection::RecoveredPacket>&
156              recovered_packet) {
157         if (media_packet->data.size() != recovered_packet->pkt->data.size()) {
158           return false;
159         }
160         if (memcmp(media_packet->data.cdata(),
161                    recovered_packet->pkt->data.cdata(),
162                    media_packet->data.size()) != 0) {
163           return false;
164         }
165         return true;
166       });
167 }
168 
169 // Define gTest typed test to loop over both ULPFEC and FlexFEC.
170 // Since the tests now are parameterized, we need to access
171 // member variables using |this|, thereby enforcing runtime
172 // resolution.
173 
174 class FlexfecForwardErrorCorrection : public ForwardErrorCorrection {
175  public:
176   static const uint32_t kFecSsrc = kFlexfecSsrc;
177 
FlexfecForwardErrorCorrection()178   FlexfecForwardErrorCorrection()
179       : ForwardErrorCorrection(
180             std::unique_ptr<FecHeaderReader>(new FlexfecHeaderReader()),
181             std::unique_ptr<FecHeaderWriter>(new FlexfecHeaderWriter()),
182             kFecSsrc,
183             kMediaSsrc) {}
184 
185   // For FlexFEC we let the FEC packet sequence numbers be independent of
186   // the media packet sequence numbers.
GetFirstFecSeqNum(uint16_t next_media_seq_num)187   static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) {
188     Random random(0xbe110);
189     return random.Rand<uint16_t>();
190   }
191 };
192 
193 class UlpfecForwardErrorCorrection : public ForwardErrorCorrection {
194  public:
195   static const uint32_t kFecSsrc = kMediaSsrc;
196 
UlpfecForwardErrorCorrection()197   UlpfecForwardErrorCorrection()
198       : ForwardErrorCorrection(
199             std::unique_ptr<FecHeaderReader>(new UlpfecHeaderReader()),
200             std::unique_ptr<FecHeaderWriter>(new UlpfecHeaderWriter()),
201             kFecSsrc,
202             kMediaSsrc) {}
203 
204   // For ULPFEC we assume that the FEC packets are subsequent to the media
205   // packets in terms of sequence number.
GetFirstFecSeqNum(uint16_t next_media_seq_num)206   static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) {
207     return next_media_seq_num;
208   }
209 };
210 
211 using FecTypes =
212     Types<FlexfecForwardErrorCorrection, UlpfecForwardErrorCorrection>;
213 TYPED_TEST_SUITE(RtpFecTest, FecTypes);
214 
TYPED_TEST(RtpFecTest,WillProtectMediaPacketsWithLargeSequenceNumberGap)215 TYPED_TEST(RtpFecTest, WillProtectMediaPacketsWithLargeSequenceNumberGap) {
216   constexpr int kNumImportantPackets = 0;
217   constexpr bool kUseUnequalProtection = false;
218   constexpr int kNumMediaPackets = 2;
219   constexpr uint8_t kProtectionFactor = 127;
220 
221   this->media_packets_ =
222       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
223 
224   // Create |kMaxMediaPackets - 1| sequence number difference.
225   ByteWriter<uint16_t>::WriteBigEndian(&this->media_packets_.front()->data[2],
226                                        1);
227   ByteWriter<uint16_t>::WriteBigEndian(&this->media_packets_.back()->data[2],
228                                        kMaxMediaPackets);
229 
230   EXPECT_EQ(
231       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
232                               kNumImportantPackets, kUseUnequalProtection,
233                               kFecMaskBursty, &this->generated_fec_packets_));
234   EXPECT_EQ(1u, this->generated_fec_packets_.size());
235 }
236 
TYPED_TEST(RtpFecTest,WillNotProtectMediaPacketsWithTooLargeSequenceNumberGap)237 TYPED_TEST(RtpFecTest,
238            WillNotProtectMediaPacketsWithTooLargeSequenceNumberGap) {
239   constexpr int kNumImportantPackets = 0;
240   constexpr bool kUseUnequalProtection = false;
241   constexpr int kNumMediaPackets = 2;
242   constexpr uint8_t kProtectionFactor = 127;
243 
244   this->media_packets_ =
245       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
246 
247   // Create |kMaxMediaPackets| sequence number difference.
248   ByteWriter<uint16_t>::WriteBigEndian(&this->media_packets_.front()->data[2],
249                                        1);
250   ByteWriter<uint16_t>::WriteBigEndian(&this->media_packets_.back()->data[2],
251                                        kMaxMediaPackets + 1);
252 
253   EXPECT_EQ(
254       -1, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
255                                kNumImportantPackets, kUseUnequalProtection,
256                                kFecMaskBursty, &this->generated_fec_packets_));
257   EXPECT_TRUE(this->generated_fec_packets_.empty());
258 }
259 
TYPED_TEST(RtpFecTest,FecRecoveryNoLoss)260 TYPED_TEST(RtpFecTest, FecRecoveryNoLoss) {
261   constexpr int kNumImportantPackets = 0;
262   constexpr bool kUseUnequalProtection = false;
263   constexpr int kNumMediaPackets = 4;
264   constexpr uint8_t kProtectionFactor = 60;
265 
266   this->media_packets_ =
267       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
268 
269   EXPECT_EQ(
270       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
271                               kNumImportantPackets, kUseUnequalProtection,
272                               kFecMaskBursty, &this->generated_fec_packets_));
273 
274   // Expect 1 FEC packet.
275   EXPECT_EQ(1u, this->generated_fec_packets_.size());
276 
277   // No packets lost.
278   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
279   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
280   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
281 
282   for (const auto& received_packet : this->received_packets_) {
283     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
284   }
285 
286   // No packets lost, expect complete recovery.
287   EXPECT_TRUE(this->IsRecoveryComplete());
288 }
289 
TYPED_TEST(RtpFecTest,FecRecoveryWithLoss)290 TYPED_TEST(RtpFecTest, FecRecoveryWithLoss) {
291   constexpr int kNumImportantPackets = 0;
292   constexpr bool kUseUnequalProtection = false;
293   constexpr int kNumMediaPackets = 4;
294   constexpr uint8_t kProtectionFactor = 60;
295 
296   this->media_packets_ =
297       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
298 
299   EXPECT_EQ(
300       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
301                               kNumImportantPackets, kUseUnequalProtection,
302                               kFecMaskBursty, &this->generated_fec_packets_));
303 
304   // Expect 1 FEC packet.
305   EXPECT_EQ(1u, this->generated_fec_packets_.size());
306 
307   // 1 media packet lost
308   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
309   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
310   this->media_loss_mask_[3] = 1;
311   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
312 
313   for (const auto& received_packet : this->received_packets_) {
314     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
315   }
316 
317   // One packet lost, one FEC packet, expect complete recovery.
318   EXPECT_TRUE(this->IsRecoveryComplete());
319   this->recovered_packets_.clear();
320 
321   // 2 media packets lost.
322   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
323   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
324   this->media_loss_mask_[1] = 1;
325   this->media_loss_mask_[3] = 1;
326   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
327 
328   for (const auto& received_packet : this->received_packets_) {
329     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
330   }
331 
332   // 2 packets lost, one FEC packet, cannot get complete recovery.
333   EXPECT_FALSE(this->IsRecoveryComplete());
334 }
335 
336 // Verify that we don't use an old FEC packet for FEC decoding.
TYPED_TEST(RtpFecTest,NoFecRecoveryWithOldFecPacket)337 TYPED_TEST(RtpFecTest, NoFecRecoveryWithOldFecPacket) {
338   constexpr int kNumImportantPackets = 0;
339   constexpr bool kUseUnequalProtection = false;
340   constexpr uint8_t kProtectionFactor = 20;
341 
342   // Two frames: first frame (old) with two media packets and 1 FEC packet.
343   // Third frame (new) with 3 media packets, and no FEC packets.
344   //
345   //  #0(media) #1(media) #2(FEC)              ----Frame 1-----
346   //  #32767(media) 32768(media) 32769(media)  ----Frame 2-----
347   //  #65535(media) #0(media) #1(media).       ----Frame 3-----
348   // If we lose either packet 0 or 1 of third frame, FEC decoding should not
349   // try to decode using "old" FEC packet #2.
350 
351   // Construct media packets for first frame, starting at sequence number 0.
352   this->media_packets_ =
353       this->media_packet_generator_.ConstructMediaPackets(2, 0);
354 
355   EXPECT_EQ(
356       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
357                               kNumImportantPackets, kUseUnequalProtection,
358                               kFecMaskBursty, &this->generated_fec_packets_));
359   // Expect 1 FEC packet.
360   EXPECT_EQ(1u, this->generated_fec_packets_.size());
361   // Add FEC packet (seq#2) of this first frame to received list (i.e., assume
362   // the two media packet were lost).
363   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
364   this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
365                         true);
366 
367   // Construct media packets for second frame, with sequence number wrap.
368   this->media_packets_ =
369       this->media_packet_generator_.ConstructMediaPackets(3, 32767);
370 
371   // Expect 3 media packets for this frame.
372   EXPECT_EQ(3u, this->media_packets_.size());
373 
374   // No packets lost
375   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
376   this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
377 
378   // Construct media packets for third frame, with sequence number wrap.
379   this->media_packets_ =
380       this->media_packet_generator_.ConstructMediaPackets(3, 65535);
381 
382   // Expect 3 media packets for this frame.
383   EXPECT_EQ(3u, this->media_packets_.size());
384 
385   // Second media packet lost (seq#0).
386   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
387   this->media_loss_mask_[1] = 1;
388   // Add packets #65535, and #1 to received list.
389   this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
390 
391   for (const auto& received_packet : this->received_packets_) {
392     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
393   }
394 
395   // Expect that no decoding is done to get missing packet (seq#0) of third
396   // frame, using old FEC packet (seq#2) from first (old) frame. So number of
397   // recovered packets is 5 (0 from first frame, three from second frame, and 2
398   // for the third frame, with no packets recovered via FEC).
399   EXPECT_EQ(5u, this->recovered_packets_.size());
400   EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size());
401 }
402 
403 // Verify we can still recover frame if sequence number wrap occurs within
404 // the frame and FEC packet following wrap is received after media packets.
TYPED_TEST(RtpFecTest,FecRecoveryWithSeqNumGapOneFrameRecovery)405 TYPED_TEST(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameRecovery) {
406   constexpr int kNumImportantPackets = 0;
407   constexpr bool kUseUnequalProtection = false;
408   constexpr uint8_t kProtectionFactor = 20;
409 
410   // One frame, with sequence number wrap in media packets.
411   //         -----Frame 1----
412   //  #65534(media) #65535(media) #0(media) #1(FEC).
413   this->media_packets_ =
414       this->media_packet_generator_.ConstructMediaPackets(3, 65534);
415 
416   EXPECT_EQ(
417       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
418                               kNumImportantPackets, kUseUnequalProtection,
419                               kFecMaskBursty, &this->generated_fec_packets_));
420 
421   // Expect 1 FEC packet.
422   EXPECT_EQ(1u, this->generated_fec_packets_.size());
423 
424   // Lose one media packet (seq# 65535).
425   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
426   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
427   this->media_loss_mask_[1] = 1;
428   this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
429   // Add FEC packet to received list following the media packets.
430   this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
431                         true);
432 
433   for (const auto& received_packet : this->received_packets_) {
434     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
435   }
436 
437   // Expect 3 media packets in recovered list, and complete recovery.
438   // Wrap-around won't remove FEC packet, as it follows the wrap.
439   EXPECT_EQ(3u, this->recovered_packets_.size());
440   EXPECT_TRUE(this->IsRecoveryComplete());
441 }
442 
443 // Sequence number wrap occurs within the ULPFEC packets for the frame.
444 // Same problem will occur if wrap is within media packets but ULPFEC packet is
445 // received before the media packets. This may be improved if timing information
446 // is used to detect old ULPFEC packets.
447 
448 // TODO(nisse): There's some logic to discard ULPFEC packets at wrap-around,
449 // however, that is not actually exercised by this test: When the first FEC
450 // packet is processed, it results in full recovery of one media packet and the
451 // FEC packet is forgotten. And then the wraparound isn't noticed when the next
452 // FEC packet is received. We should fix wraparound handling, which currently
453 // appears broken, and then figure out how to test it properly.
454 using RtpFecTestUlpfecOnly = RtpFecTest<UlpfecForwardErrorCorrection>;
TEST_F(RtpFecTestUlpfecOnly,FecRecoveryWithSeqNumGapOneFrameRecovery)455 TEST_F(RtpFecTestUlpfecOnly, FecRecoveryWithSeqNumGapOneFrameRecovery) {
456   constexpr int kNumImportantPackets = 0;
457   constexpr bool kUseUnequalProtection = false;
458   constexpr uint8_t kProtectionFactor = 200;
459 
460   // 1 frame: 3 media packets and 2 FEC packets.
461   // Sequence number wrap in FEC packets.
462   //           -----Frame 1----
463   // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC).
464   this->media_packets_ =
465       this->media_packet_generator_.ConstructMediaPackets(3, 65532);
466 
467   EXPECT_EQ(
468       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
469                               kNumImportantPackets, kUseUnequalProtection,
470                               kFecMaskBursty, &this->generated_fec_packets_));
471 
472   // Expect 2 FEC packets.
473   EXPECT_EQ(2u, this->generated_fec_packets_.size());
474 
475   // Lose the last two media packets (seq# 65533, 65534).
476   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
477   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
478   this->media_loss_mask_[1] = 1;
479   this->media_loss_mask_[2] = 1;
480   this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
481   this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
482                         true);
483 
484   for (const auto& received_packet : this->received_packets_) {
485     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
486   }
487 
488   // The two FEC packets are received and should allow for complete recovery,
489   // but because of the wrap the first FEC packet will be discarded, and only
490   // one media packet is recoverable. So expect 2 media packets on recovered
491   // list and no complete recovery.
492   EXPECT_EQ(3u, this->recovered_packets_.size());
493   EXPECT_EQ(this->recovered_packets_.size(), this->media_packets_.size());
494   EXPECT_TRUE(this->IsRecoveryComplete());
495 }
496 
497 // TODO(brandtr): This test mimics the one above, ensuring that the recovery
498 // strategy of FlexFEC matches the recovery strategy of ULPFEC. Since FlexFEC
499 // does not share the sequence number space with the media, however, having a
500 // matching recovery strategy may be suboptimal. Study this further.
501 // TODO(nisse): In this test, recovery based on the first FEC packet fails with
502 // the log message "The recovered packet had a length larger than a typical IP
503 // packet, and is thus dropped." This is probably not intended, and needs
504 // investigation.
505 using RtpFecTestFlexfecOnly = RtpFecTest<FlexfecForwardErrorCorrection>;
TEST_F(RtpFecTestFlexfecOnly,FecRecoveryWithSeqNumGapOneFrameNoRecovery)506 TEST_F(RtpFecTestFlexfecOnly, FecRecoveryWithSeqNumGapOneFrameNoRecovery) {
507   constexpr int kNumImportantPackets = 0;
508   constexpr bool kUseUnequalProtection = false;
509   constexpr uint8_t kProtectionFactor = 200;
510 
511   // 1 frame: 3 media packets and 2 FEC packets.
512   // Sequence number wrap in FEC packets.
513   //           -----Frame 1----
514   // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC).
515   this->media_packets_ =
516       this->media_packet_generator_.ConstructMediaPackets(3, 65532);
517 
518   EXPECT_EQ(
519       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
520                               kNumImportantPackets, kUseUnequalProtection,
521                               kFecMaskBursty, &this->generated_fec_packets_));
522 
523   // Expect 2 FEC packets.
524   EXPECT_EQ(2u, this->generated_fec_packets_.size());
525 
526   // Overwrite the sequence numbers generated by ConstructMediaPackets,
527   // to make sure that we do have a wrap.
528   auto it = this->generated_fec_packets_.begin();
529   ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data[2], 65535);
530   ++it;
531   ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data[2], 0);
532 
533   // Lose the last two media packets (seq# 65533, 65534).
534   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
535   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
536   this->media_loss_mask_[1] = 1;
537   this->media_loss_mask_[2] = 1;
538   this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
539   this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
540                         true);
541 
542   for (const auto& received_packet : this->received_packets_) {
543     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
544   }
545 
546   // The two FEC packets are received and should allow for complete recovery,
547   // but because of the wrap the first FEC packet will be discarded, and only
548   // one media packet is recoverable. So expect 2 media packets on recovered
549   // list and no complete recovery.
550   EXPECT_EQ(2u, this->recovered_packets_.size());
551   EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size());
552   EXPECT_FALSE(this->IsRecoveryComplete());
553 }
554 
555 // Verify we can still recover frame if media packets are reordered.
TYPED_TEST(RtpFecTest,FecRecoveryWithMediaOutOfOrder)556 TYPED_TEST(RtpFecTest, FecRecoveryWithMediaOutOfOrder) {
557   constexpr int kNumImportantPackets = 0;
558   constexpr bool kUseUnequalProtection = false;
559   constexpr uint8_t kProtectionFactor = 20;
560 
561   // One frame: 3 media packets, 1 FEC packet.
562   //         -----Frame 1----
563   //  #0(media) #1(media) #2(media) #3(FEC).
564   this->media_packets_ =
565       this->media_packet_generator_.ConstructMediaPackets(3, 0);
566 
567   EXPECT_EQ(
568       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
569                               kNumImportantPackets, kUseUnequalProtection,
570                               kFecMaskBursty, &this->generated_fec_packets_));
571 
572   // Expect 1 FEC packet.
573   EXPECT_EQ(1u, this->generated_fec_packets_.size());
574 
575   // Lose one media packet (seq# 1).
576   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
577   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
578   this->media_loss_mask_[1] = 1;
579   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
580 
581   // Reorder received media packets.
582   auto it0 = this->received_packets_.begin();
583   auto it1 = this->received_packets_.begin();
584   it1++;
585   std::swap(*it0, *it1);
586 
587   for (const auto& received_packet : this->received_packets_) {
588     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
589   }
590 
591   // Expect 3 media packets in recovered list, and complete recovery.
592   EXPECT_EQ(3u, this->recovered_packets_.size());
593   EXPECT_TRUE(this->IsRecoveryComplete());
594 }
595 
596 // Verify we can still recover frame if FEC is received before media packets.
TYPED_TEST(RtpFecTest,FecRecoveryWithFecOutOfOrder)597 TYPED_TEST(RtpFecTest, FecRecoveryWithFecOutOfOrder) {
598   constexpr int kNumImportantPackets = 0;
599   constexpr bool kUseUnequalProtection = false;
600   constexpr uint8_t kProtectionFactor = 20;
601 
602   // One frame: 3 media packets, 1 FEC packet.
603   //         -----Frame 1----
604   //  #0(media) #1(media) #2(media) #3(FEC).
605   this->media_packets_ =
606       this->media_packet_generator_.ConstructMediaPackets(3, 0);
607 
608   EXPECT_EQ(
609       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
610                               kNumImportantPackets, kUseUnequalProtection,
611                               kFecMaskBursty, &this->generated_fec_packets_));
612 
613   // Expect 1 FEC packet.
614   EXPECT_EQ(1u, this->generated_fec_packets_.size());
615 
616   // Lose one media packet (seq# 1).
617   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
618   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
619   this->media_loss_mask_[1] = 1;
620   // Add FEC packet to received list before the media packets.
621   this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
622                         true);
623   // Add media packets to received list.
624   this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
625 
626   for (const auto& received_packet : this->received_packets_) {
627     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
628   }
629 
630   // Expect 3 media packets in recovered list, and complete recovery.
631   EXPECT_EQ(3u, this->recovered_packets_.size());
632   EXPECT_TRUE(this->IsRecoveryComplete());
633 }
634 
635 // Test 50% protection with random mask type: Two cases are considered:
636 // a 50% non-consecutive loss which can be fully recovered, and a 50%
637 // consecutive loss which cannot be fully recovered.
TYPED_TEST(RtpFecTest,FecRecoveryWithLoss50percRandomMask)638 TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
639   constexpr int kNumImportantPackets = 0;
640   constexpr bool kUseUnequalProtection = false;
641   constexpr int kNumMediaPackets = 4;
642   constexpr uint8_t kProtectionFactor = 255;
643 
644   // Packet Mask for (4,4,0) code, from random mask table.
645   // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
646 
647   //         media#0   media#1  media#2    media#3
648   // fec#0:    1          1        0          0
649   // fec#1:    1          0        1          0
650   // fec#2:    0          0        1          1
651   // fec#3:    0          1        0          1
652   //
653 
654   this->media_packets_ =
655       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
656 
657   EXPECT_EQ(
658       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
659                               kNumImportantPackets, kUseUnequalProtection,
660                               kFecMaskRandom, &this->generated_fec_packets_));
661 
662   // Expect 4 FEC packets.
663   EXPECT_EQ(4u, this->generated_fec_packets_.size());
664 
665   // 4 packets lost: 3 media packets (0, 2, 3), and one FEC packet (0) lost.
666   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
667   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
668   this->fec_loss_mask_[0] = 1;
669   this->media_loss_mask_[0] = 1;
670   this->media_loss_mask_[2] = 1;
671   this->media_loss_mask_[3] = 1;
672   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
673 
674   for (const auto& received_packet : this->received_packets_) {
675     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
676   }
677 
678   // With media packet#1 and FEC packets #1, #2, #3, expect complete recovery.
679   EXPECT_TRUE(this->IsRecoveryComplete());
680   this->recovered_packets_.clear();
681 
682   // 4 consecutive packets lost: media packets 0, 1, 2, 3.
683   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
684   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
685   this->media_loss_mask_[0] = 1;
686   this->media_loss_mask_[1] = 1;
687   this->media_loss_mask_[2] = 1;
688   this->media_loss_mask_[3] = 1;
689   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
690 
691   for (const auto& received_packet : this->received_packets_) {
692     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
693   }
694 
695   // Cannot get complete recovery for this loss configuration with random mask.
696   EXPECT_FALSE(this->IsRecoveryComplete());
697 }
698 
699 // Test 50% protection with bursty type: Three cases are considered:
700 // two 50% consecutive losses which can be fully recovered, and one
701 // non-consecutive which cannot be fully recovered.
TYPED_TEST(RtpFecTest,FecRecoveryWithLoss50percBurstyMask)702 TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
703   constexpr int kNumImportantPackets = 0;
704   constexpr bool kUseUnequalProtection = false;
705   constexpr int kNumMediaPackets = 4;
706   constexpr uint8_t kProtectionFactor = 255;
707 
708   // Packet Mask for (4,4,0) code, from bursty mask table.
709   // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
710 
711   //         media#0   media#1  media#2    media#3
712   // fec#0:    1          0        0          0
713   // fec#1:    1          1        0          0
714   // fec#2:    0          1        1          0
715   // fec#3:    0          0        1          1
716   //
717 
718   this->media_packets_ =
719       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
720 
721   EXPECT_EQ(
722       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
723                               kNumImportantPackets, kUseUnequalProtection,
724                               kFecMaskBursty, &this->generated_fec_packets_));
725 
726   // Expect 4 FEC packets.
727   EXPECT_EQ(4u, this->generated_fec_packets_.size());
728 
729   // 4 consecutive packets lost: media packets 0,1,2,3.
730   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
731   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
732   this->media_loss_mask_[0] = 1;
733   this->media_loss_mask_[1] = 1;
734   this->media_loss_mask_[2] = 1;
735   this->media_loss_mask_[3] = 1;
736   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
737 
738   for (const auto& received_packet : this->received_packets_) {
739     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
740   }
741 
742   // Expect complete recovery for consecutive packet loss <= 50%.
743   EXPECT_TRUE(this->IsRecoveryComplete());
744   this->recovered_packets_.clear();
745 
746   // 4 consecutive packets lost: media packets 1,2, 3, and FEC packet 0.
747   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
748   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
749   this->fec_loss_mask_[0] = 1;
750   this->media_loss_mask_[1] = 1;
751   this->media_loss_mask_[2] = 1;
752   this->media_loss_mask_[3] = 1;
753   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
754 
755   for (const auto& received_packet : this->received_packets_) {
756     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
757   }
758 
759   // Expect complete recovery for consecutive packet loss <= 50%.
760   EXPECT_TRUE(this->IsRecoveryComplete());
761   this->recovered_packets_.clear();
762 
763   // 4 packets lost (non-consecutive loss): media packets 0, 3, and FEC# 0, 3.
764   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
765   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
766   this->fec_loss_mask_[0] = 1;
767   this->fec_loss_mask_[3] = 1;
768   this->media_loss_mask_[0] = 1;
769   this->media_loss_mask_[3] = 1;
770   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
771 
772   for (const auto& received_packet : this->received_packets_) {
773     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
774   }
775 
776   // Cannot get complete recovery for this loss configuration.
777   EXPECT_FALSE(this->IsRecoveryComplete());
778 }
779 
TYPED_TEST(RtpFecTest,FecRecoveryNoLossUep)780 TYPED_TEST(RtpFecTest, FecRecoveryNoLossUep) {
781   constexpr int kNumImportantPackets = 2;
782   constexpr bool kUseUnequalProtection = true;
783   constexpr int kNumMediaPackets = 4;
784   constexpr uint8_t kProtectionFactor = 60;
785 
786   this->media_packets_ =
787       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
788 
789   EXPECT_EQ(
790       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
791                               kNumImportantPackets, kUseUnequalProtection,
792                               kFecMaskBursty, &this->generated_fec_packets_));
793 
794   // Expect 1 FEC packet.
795   EXPECT_EQ(1u, this->generated_fec_packets_.size());
796 
797   // No packets lost.
798   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
799   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
800   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
801 
802   for (const auto& received_packet : this->received_packets_) {
803     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
804   }
805 
806   // No packets lost, expect complete recovery.
807   EXPECT_TRUE(this->IsRecoveryComplete());
808 }
809 
TYPED_TEST(RtpFecTest,FecRecoveryWithLossUep)810 TYPED_TEST(RtpFecTest, FecRecoveryWithLossUep) {
811   constexpr int kNumImportantPackets = 2;
812   constexpr bool kUseUnequalProtection = true;
813   constexpr int kNumMediaPackets = 4;
814   constexpr uint8_t kProtectionFactor = 60;
815 
816   this->media_packets_ =
817       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
818 
819   EXPECT_EQ(
820       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
821                               kNumImportantPackets, kUseUnequalProtection,
822                               kFecMaskBursty, &this->generated_fec_packets_));
823 
824   // Expect 1 FEC packet.
825   EXPECT_EQ(1u, this->generated_fec_packets_.size());
826 
827   // 1 media packet lost.
828   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
829   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
830   this->media_loss_mask_[3] = 1;
831   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
832 
833   for (const auto& received_packet : this->received_packets_) {
834     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
835   }
836 
837   // One packet lost, one FEC packet, expect complete recovery.
838   EXPECT_TRUE(this->IsRecoveryComplete());
839   this->recovered_packets_.clear();
840 
841   // 2 media packets lost.
842   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
843   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
844   this->media_loss_mask_[1] = 1;
845   this->media_loss_mask_[3] = 1;
846   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
847 
848   for (const auto& received_packet : this->received_packets_) {
849     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
850   }
851 
852   // 2 packets lost, one FEC packet, cannot get complete recovery.
853   EXPECT_FALSE(this->IsRecoveryComplete());
854 }
855 
856 // Test 50% protection with random mask type for UEP on.
TYPED_TEST(RtpFecTest,FecRecoveryWithLoss50percUepRandomMask)857 TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
858   constexpr int kNumImportantPackets = 1;
859   constexpr bool kUseUnequalProtection = true;
860   constexpr int kNumMediaPackets = 4;
861   constexpr uint8_t kProtectionFactor = 255;
862 
863   // Packet Mask for (4,4,1) code, from random mask table.
864   // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 1)
865 
866   //         media#0   media#1  media#2    media#3
867   // fec#0:    1          0        0          0
868   // fec#1:    1          1        0          0
869   // fec#2:    1          0        1          1
870   // fec#3:    0          1        1          0
871   //
872 
873   this->media_packets_ =
874       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
875 
876   EXPECT_EQ(
877       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
878                               kNumImportantPackets, kUseUnequalProtection,
879                               kFecMaskRandom, &this->generated_fec_packets_));
880 
881   // Expect 4 FEC packets.
882   EXPECT_EQ(4u, this->generated_fec_packets_.size());
883 
884   // 4 packets lost: 3 media packets and FEC packet#1 lost.
885   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
886   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
887   this->fec_loss_mask_[1] = 1;
888   this->media_loss_mask_[0] = 1;
889   this->media_loss_mask_[2] = 1;
890   this->media_loss_mask_[3] = 1;
891   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
892 
893   for (const auto& received_packet : this->received_packets_) {
894     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
895   }
896 
897   // With media packet#3 and FEC packets #0, #1, #3, expect complete recovery.
898   EXPECT_TRUE(this->IsRecoveryComplete());
899   this->recovered_packets_.clear();
900 
901   // 5 packets lost: 4 media packets and one FEC packet#2 lost.
902   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
903   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
904   this->fec_loss_mask_[2] = 1;
905   this->media_loss_mask_[0] = 1;
906   this->media_loss_mask_[1] = 1;
907   this->media_loss_mask_[2] = 1;
908   this->media_loss_mask_[3] = 1;
909   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
910 
911   for (const auto& received_packet : this->received_packets_) {
912     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
913   }
914 
915   // Cannot get complete recovery for this loss configuration.
916   EXPECT_FALSE(this->IsRecoveryComplete());
917 }
918 
TYPED_TEST(RtpFecTest,FecRecoveryNonConsecutivePackets)919 TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePackets) {
920   constexpr int kNumImportantPackets = 0;
921   constexpr bool kUseUnequalProtection = false;
922   constexpr int kNumMediaPackets = 5;
923   constexpr uint8_t kProtectionFactor = 60;
924 
925   this->media_packets_ =
926       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
927 
928   // Create a new temporary packet list for generating FEC packets.
929   // This list should have every other packet removed.
930   ForwardErrorCorrection::PacketList protected_media_packets;
931   DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets);
932 
933   EXPECT_EQ(
934       0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor,
935                               kNumImportantPackets, kUseUnequalProtection,
936                               kFecMaskBursty, &this->generated_fec_packets_));
937 
938   // Expect 1 FEC packet.
939   EXPECT_EQ(1u, this->generated_fec_packets_.size());
940 
941   // 1 protected media packet lost
942   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
943   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
944   this->media_loss_mask_[2] = 1;
945   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
946 
947   for (const auto& received_packet : this->received_packets_) {
948     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
949   }
950 
951   // One packet lost, one FEC packet, expect complete recovery.
952   EXPECT_TRUE(this->IsRecoveryComplete());
953   this->recovered_packets_.clear();
954 
955   // Unprotected packet lost.
956   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
957   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
958   this->media_loss_mask_[1] = 1;
959   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
960 
961   for (const auto& received_packet : this->received_packets_) {
962     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
963   }
964 
965   // Unprotected packet lost. Recovery not possible.
966   EXPECT_FALSE(this->IsRecoveryComplete());
967   this->recovered_packets_.clear();
968 
969   // 2 media packets lost.
970   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
971   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
972   this->media_loss_mask_[0] = 1;
973   this->media_loss_mask_[2] = 1;
974   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
975 
976   for (const auto& received_packet : this->received_packets_) {
977     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
978   }
979 
980   // 2 protected packets lost, one FEC packet, cannot get complete recovery.
981   EXPECT_FALSE(this->IsRecoveryComplete());
982 }
983 
TYPED_TEST(RtpFecTest,FecRecoveryNonConsecutivePacketsExtension)984 TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
985   constexpr int kNumImportantPackets = 0;
986   constexpr bool kUseUnequalProtection = false;
987   constexpr int kNumMediaPackets = 21;
988   uint8_t kProtectionFactor = 127;
989 
990   this->media_packets_ =
991       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
992 
993   // Create a new temporary packet list for generating FEC packets.
994   // This list should have every other packet removed.
995   ForwardErrorCorrection::PacketList protected_media_packets;
996   DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets);
997 
998   // Zero column insertion will have to extend the size of the packet
999   // mask since the number of actual packets are 21, while the number
1000   // of protected packets are 11.
1001   EXPECT_EQ(
1002       0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor,
1003                               kNumImportantPackets, kUseUnequalProtection,
1004                               kFecMaskBursty, &this->generated_fec_packets_));
1005 
1006   // Expect 5 FEC packet.
1007   EXPECT_EQ(5u, this->generated_fec_packets_.size());
1008 
1009   // Last protected media packet lost
1010   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1011   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1012   this->media_loss_mask_[kNumMediaPackets - 1] = 1;
1013   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
1014 
1015   for (const auto& received_packet : this->received_packets_) {
1016     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
1017   }
1018 
1019   // One packet lost, one FEC packet, expect complete recovery.
1020   EXPECT_TRUE(this->IsRecoveryComplete());
1021   this->recovered_packets_.clear();
1022 
1023   // Last unprotected packet lost.
1024   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1025   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1026   this->media_loss_mask_[kNumMediaPackets - 2] = 1;
1027   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
1028 
1029   for (const auto& received_packet : this->received_packets_) {
1030     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
1031   }
1032 
1033   // Unprotected packet lost. Recovery not possible.
1034   EXPECT_FALSE(this->IsRecoveryComplete());
1035   this->recovered_packets_.clear();
1036 
1037   // 6 media packets lost.
1038   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1039   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1040   this->media_loss_mask_[kNumMediaPackets - 11] = 1;
1041   this->media_loss_mask_[kNumMediaPackets - 9] = 1;
1042   this->media_loss_mask_[kNumMediaPackets - 7] = 1;
1043   this->media_loss_mask_[kNumMediaPackets - 5] = 1;
1044   this->media_loss_mask_[kNumMediaPackets - 3] = 1;
1045   this->media_loss_mask_[kNumMediaPackets - 1] = 1;
1046   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
1047 
1048   for (const auto& received_packet : this->received_packets_) {
1049     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
1050   }
1051 
1052   // 5 protected packets lost, one FEC packet, cannot get complete recovery.
1053   EXPECT_FALSE(this->IsRecoveryComplete());
1054 }
1055 
TYPED_TEST(RtpFecTest,FecRecoveryNonConsecutivePacketsWrap)1056 TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
1057   constexpr int kNumImportantPackets = 0;
1058   constexpr bool kUseUnequalProtection = false;
1059   constexpr int kNumMediaPackets = 21;
1060   uint8_t kProtectionFactor = 127;
1061 
1062   this->media_packets_ = this->media_packet_generator_.ConstructMediaPackets(
1063       kNumMediaPackets, 0xFFFF - 5);
1064 
1065   // Create a new temporary packet list for generating FEC packets.
1066   // This list should have every other packet removed.
1067   ForwardErrorCorrection::PacketList protected_media_packets;
1068   DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets);
1069 
1070   // Zero column insertion will have to extend the size of the packet
1071   // mask since the number of actual packets are 21, while the number
1072   // of protected packets are 11.
1073   EXPECT_EQ(
1074       0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor,
1075                               kNumImportantPackets, kUseUnequalProtection,
1076                               kFecMaskBursty, &this->generated_fec_packets_));
1077 
1078   // Expect 5 FEC packet.
1079   EXPECT_EQ(5u, this->generated_fec_packets_.size());
1080 
1081   // Last protected media packet lost
1082   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1083   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1084   this->media_loss_mask_[kNumMediaPackets - 1] = 1;
1085   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
1086 
1087   for (const auto& received_packet : this->received_packets_) {
1088     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
1089   }
1090 
1091   // One packet lost, one FEC packet, expect complete recovery.
1092   EXPECT_TRUE(this->IsRecoveryComplete());
1093   this->recovered_packets_.clear();
1094 
1095   // Last unprotected packet lost.
1096   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1097   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1098   this->media_loss_mask_[kNumMediaPackets - 2] = 1;
1099   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
1100 
1101   for (const auto& received_packet : this->received_packets_) {
1102     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
1103   }
1104 
1105   // Unprotected packet lost. Recovery not possible.
1106   EXPECT_FALSE(this->IsRecoveryComplete());
1107   this->recovered_packets_.clear();
1108 
1109   // 6 media packets lost.
1110   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1111   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1112   this->media_loss_mask_[kNumMediaPackets - 11] = 1;
1113   this->media_loss_mask_[kNumMediaPackets - 9] = 1;
1114   this->media_loss_mask_[kNumMediaPackets - 7] = 1;
1115   this->media_loss_mask_[kNumMediaPackets - 5] = 1;
1116   this->media_loss_mask_[kNumMediaPackets - 3] = 1;
1117   this->media_loss_mask_[kNumMediaPackets - 1] = 1;
1118   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
1119 
1120   for (const auto& received_packet : this->received_packets_) {
1121     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
1122   }
1123 
1124   // 5 protected packets lost, one FEC packet, cannot get complete recovery.
1125   EXPECT_FALSE(this->IsRecoveryComplete());
1126 }
1127 
1128 }  // namespace webrtc
1129