xref: /aosp_15_r20/external/webrtc/modules/rtp_rtcp/source/rtp_fec_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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.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(
226       this->media_packets_.front()->data.MutableData() + 2, 1);
227   ByteWriter<uint16_t>::WriteBigEndian(
228       this->media_packets_.back()->data.MutableData() + 2, 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(
249       this->media_packets_.front()->data.MutableData() + 2, 1);
250   ByteWriter<uint16_t>::WriteBigEndian(
251       this->media_packets_.back()->data.MutableData() + 2,
252       kMaxMediaPackets + 1);
253 
254   EXPECT_EQ(
255       -1, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
256                                kNumImportantPackets, kUseUnequalProtection,
257                                kFecMaskBursty, &this->generated_fec_packets_));
258   EXPECT_TRUE(this->generated_fec_packets_.empty());
259 }
260 
TYPED_TEST(RtpFecTest,FecRecoveryNoLoss)261 TYPED_TEST(RtpFecTest, FecRecoveryNoLoss) {
262   constexpr int kNumImportantPackets = 0;
263   constexpr bool kUseUnequalProtection = false;
264   constexpr int kNumMediaPackets = 4;
265   constexpr uint8_t kProtectionFactor = 60;
266 
267   this->media_packets_ =
268       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
269 
270   EXPECT_EQ(
271       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
272                               kNumImportantPackets, kUseUnequalProtection,
273                               kFecMaskBursty, &this->generated_fec_packets_));
274 
275   // Expect 1 FEC packet.
276   EXPECT_EQ(1u, this->generated_fec_packets_.size());
277 
278   // No packets lost.
279   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
280   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
281   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
282 
283   for (const auto& received_packet : this->received_packets_) {
284     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
285   }
286 
287   // No packets lost, expect complete recovery.
288   EXPECT_TRUE(this->IsRecoveryComplete());
289 }
290 
TYPED_TEST(RtpFecTest,FecRecoveryWithLoss)291 TYPED_TEST(RtpFecTest, FecRecoveryWithLoss) {
292   constexpr int kNumImportantPackets = 0;
293   constexpr bool kUseUnequalProtection = false;
294   constexpr int kNumMediaPackets = 4;
295   constexpr uint8_t kProtectionFactor = 60;
296 
297   this->media_packets_ =
298       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
299 
300   EXPECT_EQ(
301       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
302                               kNumImportantPackets, kUseUnequalProtection,
303                               kFecMaskBursty, &this->generated_fec_packets_));
304 
305   // Expect 1 FEC packet.
306   EXPECT_EQ(1u, this->generated_fec_packets_.size());
307 
308   // 1 media packet lost
309   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
310   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
311   this->media_loss_mask_[3] = 1;
312   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
313 
314   for (const auto& received_packet : this->received_packets_) {
315     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
316   }
317 
318   // One packet lost, one FEC packet, expect complete recovery.
319   EXPECT_TRUE(this->IsRecoveryComplete());
320   this->recovered_packets_.clear();
321 
322   // 2 media packets lost.
323   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
324   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
325   this->media_loss_mask_[1] = 1;
326   this->media_loss_mask_[3] = 1;
327   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
328 
329   for (const auto& received_packet : this->received_packets_) {
330     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
331   }
332 
333   // 2 packets lost, one FEC packet, cannot get complete recovery.
334   EXPECT_FALSE(this->IsRecoveryComplete());
335 }
336 
337 // Verify that we don't use an old FEC packet for FEC decoding.
TYPED_TEST(RtpFecTest,NoFecRecoveryWithOldFecPacket)338 TYPED_TEST(RtpFecTest, NoFecRecoveryWithOldFecPacket) {
339   constexpr int kNumImportantPackets = 0;
340   constexpr bool kUseUnequalProtection = false;
341   constexpr uint8_t kProtectionFactor = 20;
342 
343   // Two frames: first frame (old) with two media packets and 1 FEC packet.
344   // Third frame (new) with 3 media packets, and no FEC packets.
345   //
346   //  #0(media) #1(media) #2(FEC)              ----Frame 1-----
347   //  #32767(media) 32768(media) 32769(media)  ----Frame 2-----
348   //  #65535(media) #0(media) #1(media).       ----Frame 3-----
349   // If we lose either packet 0 or 1 of third frame, FEC decoding should not
350   // try to decode using "old" FEC packet #2.
351 
352   // Construct media packets for first frame, starting at sequence number 0.
353   this->media_packets_ =
354       this->media_packet_generator_.ConstructMediaPackets(2, 0);
355 
356   EXPECT_EQ(
357       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
358                               kNumImportantPackets, kUseUnequalProtection,
359                               kFecMaskBursty, &this->generated_fec_packets_));
360   // Expect 1 FEC packet.
361   EXPECT_EQ(1u, this->generated_fec_packets_.size());
362   // Add FEC packet (seq#2) of this first frame to received list (i.e., assume
363   // the two media packet were lost).
364   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
365   this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
366                         true);
367 
368   // Construct media packets for second frame, with sequence number wrap.
369   this->media_packets_ =
370       this->media_packet_generator_.ConstructMediaPackets(3, 32767);
371 
372   // Expect 3 media packets for this frame.
373   EXPECT_EQ(3u, this->media_packets_.size());
374 
375   // No packets lost
376   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
377   this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
378 
379   // Construct media packets for third frame, with sequence number wrap.
380   this->media_packets_ =
381       this->media_packet_generator_.ConstructMediaPackets(3, 65535);
382 
383   // Expect 3 media packets for this frame.
384   EXPECT_EQ(3u, this->media_packets_.size());
385 
386   // Second media packet lost (seq#0).
387   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
388   this->media_loss_mask_[1] = 1;
389   // Add packets #65535, and #1 to received list.
390   this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
391 
392   for (const auto& received_packet : this->received_packets_) {
393     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
394   }
395 
396   // Expect that no decoding is done to get missing packet (seq#0) of third
397   // frame, using old FEC packet (seq#2) from first (old) frame. So number of
398   // recovered packets is 5 (0 from first frame, three from second frame, and 2
399   // for the third frame, with no packets recovered via FEC).
400   EXPECT_EQ(5u, this->recovered_packets_.size());
401   EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size());
402 }
403 
404 // Verify we can still recover frame if sequence number wrap occurs within
405 // the frame and FEC packet following wrap is received after media packets.
TYPED_TEST(RtpFecTest,FecRecoveryWithSeqNumGapOneFrameRecovery)406 TYPED_TEST(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameRecovery) {
407   constexpr int kNumImportantPackets = 0;
408   constexpr bool kUseUnequalProtection = false;
409   constexpr uint8_t kProtectionFactor = 20;
410 
411   // One frame, with sequence number wrap in media packets.
412   //         -----Frame 1----
413   //  #65534(media) #65535(media) #0(media) #1(FEC).
414   this->media_packets_ =
415       this->media_packet_generator_.ConstructMediaPackets(3, 65534);
416 
417   EXPECT_EQ(
418       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
419                               kNumImportantPackets, kUseUnequalProtection,
420                               kFecMaskBursty, &this->generated_fec_packets_));
421 
422   // Expect 1 FEC packet.
423   EXPECT_EQ(1u, this->generated_fec_packets_.size());
424 
425   // Lose one media packet (seq# 65535).
426   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
427   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
428   this->media_loss_mask_[1] = 1;
429   this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
430   // Add FEC packet to received list following the media packets.
431   this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
432                         true);
433 
434   for (const auto& received_packet : this->received_packets_) {
435     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
436   }
437 
438   // Expect 3 media packets in recovered list, and complete recovery.
439   // Wrap-around won't remove FEC packet, as it follows the wrap.
440   EXPECT_EQ(3u, this->recovered_packets_.size());
441   EXPECT_TRUE(this->IsRecoveryComplete());
442 }
443 
444 // Sequence number wrap occurs within the ULPFEC packets for the frame.
445 // Same problem will occur if wrap is within media packets but ULPFEC packet is
446 // received before the media packets. This may be improved if timing information
447 // is used to detect old ULPFEC packets.
448 
449 // TODO(nisse): There's some logic to discard ULPFEC packets at wrap-around,
450 // however, that is not actually exercised by this test: When the first FEC
451 // packet is processed, it results in full recovery of one media packet and the
452 // FEC packet is forgotten. And then the wraparound isn't noticed when the next
453 // FEC packet is received. We should fix wraparound handling, which currently
454 // appears broken, and then figure out how to test it properly.
455 using RtpFecTestUlpfecOnly = RtpFecTest<UlpfecForwardErrorCorrection>;
TEST_F(RtpFecTestUlpfecOnly,FecRecoveryWithSeqNumGapOneFrameRecovery)456 TEST_F(RtpFecTestUlpfecOnly, FecRecoveryWithSeqNumGapOneFrameRecovery) {
457   constexpr int kNumImportantPackets = 0;
458   constexpr bool kUseUnequalProtection = false;
459   constexpr uint8_t kProtectionFactor = 200;
460 
461   // 1 frame: 3 media packets and 2 FEC packets.
462   // Sequence number wrap in FEC packets.
463   //           -----Frame 1----
464   // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC).
465   this->media_packets_ =
466       this->media_packet_generator_.ConstructMediaPackets(3, 65532);
467 
468   EXPECT_EQ(
469       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
470                               kNumImportantPackets, kUseUnequalProtection,
471                               kFecMaskBursty, &this->generated_fec_packets_));
472 
473   // Expect 2 FEC packets.
474   EXPECT_EQ(2u, this->generated_fec_packets_.size());
475 
476   // Lose the last two media packets (seq# 65533, 65534).
477   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
478   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
479   this->media_loss_mask_[1] = 1;
480   this->media_loss_mask_[2] = 1;
481   this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
482   this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
483                         true);
484 
485   for (const auto& received_packet : this->received_packets_) {
486     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
487   }
488 
489   // The two FEC packets are received and should allow for complete recovery,
490   // but because of the wrap the first FEC packet will be discarded, and only
491   // one media packet is recoverable. So expect 2 media packets on recovered
492   // list and no complete recovery.
493   EXPECT_EQ(3u, this->recovered_packets_.size());
494   EXPECT_EQ(this->recovered_packets_.size(), this->media_packets_.size());
495   EXPECT_TRUE(this->IsRecoveryComplete());
496 }
497 
498 // TODO(brandtr): This test mimics the one above, ensuring that the recovery
499 // strategy of FlexFEC matches the recovery strategy of ULPFEC. Since FlexFEC
500 // does not share the sequence number space with the media, however, having a
501 // matching recovery strategy may be suboptimal. Study this further.
502 // TODO(nisse): In this test, recovery based on the first FEC packet fails with
503 // the log message "The recovered packet had a length larger than a typical IP
504 // packet, and is thus dropped." This is probably not intended, and needs
505 // investigation.
506 using RtpFecTestFlexfecOnly = RtpFecTest<FlexfecForwardErrorCorrection>;
TEST_F(RtpFecTestFlexfecOnly,FecRecoveryWithSeqNumGapOneFrameNoRecovery)507 TEST_F(RtpFecTestFlexfecOnly, FecRecoveryWithSeqNumGapOneFrameNoRecovery) {
508   constexpr int kNumImportantPackets = 0;
509   constexpr bool kUseUnequalProtection = false;
510   constexpr uint8_t kProtectionFactor = 200;
511 
512   // 1 frame: 3 media packets and 2 FEC packets.
513   // Sequence number wrap in FEC packets.
514   //           -----Frame 1----
515   // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC).
516   this->media_packets_ =
517       this->media_packet_generator_.ConstructMediaPackets(3, 65532);
518 
519   EXPECT_EQ(
520       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
521                               kNumImportantPackets, kUseUnequalProtection,
522                               kFecMaskBursty, &this->generated_fec_packets_));
523 
524   // Expect 2 FEC packets.
525   EXPECT_EQ(2u, this->generated_fec_packets_.size());
526 
527   // Overwrite the sequence numbers generated by ConstructMediaPackets,
528   // to make sure that we do have a wrap.
529   auto it = this->generated_fec_packets_.begin();
530   ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data.MutableData()[2], 65535);
531   ++it;
532   ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data.MutableData()[2], 0);
533 
534   // Lose the last two media packets (seq# 65533, 65534).
535   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
536   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
537   this->media_loss_mask_[1] = 1;
538   this->media_loss_mask_[2] = 1;
539   this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
540   this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
541                         true);
542 
543   for (const auto& received_packet : this->received_packets_) {
544     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
545   }
546 
547   // The two FEC packets are received and should allow for complete recovery,
548   // but because of the wrap the first FEC packet will be discarded, and only
549   // one media packet is recoverable. So expect 2 media packets on recovered
550   // list and no complete recovery.
551   EXPECT_EQ(2u, this->recovered_packets_.size());
552   EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size());
553   EXPECT_FALSE(this->IsRecoveryComplete());
554 }
555 
556 // Verify we can still recover frame if media packets are reordered.
TYPED_TEST(RtpFecTest,FecRecoveryWithMediaOutOfOrder)557 TYPED_TEST(RtpFecTest, FecRecoveryWithMediaOutOfOrder) {
558   constexpr int kNumImportantPackets = 0;
559   constexpr bool kUseUnequalProtection = false;
560   constexpr uint8_t kProtectionFactor = 20;
561 
562   // One frame: 3 media packets, 1 FEC packet.
563   //         -----Frame 1----
564   //  #0(media) #1(media) #2(media) #3(FEC).
565   this->media_packets_ =
566       this->media_packet_generator_.ConstructMediaPackets(3, 0);
567 
568   EXPECT_EQ(
569       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
570                               kNumImportantPackets, kUseUnequalProtection,
571                               kFecMaskBursty, &this->generated_fec_packets_));
572 
573   // Expect 1 FEC packet.
574   EXPECT_EQ(1u, this->generated_fec_packets_.size());
575 
576   // Lose one media packet (seq# 1).
577   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
578   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
579   this->media_loss_mask_[1] = 1;
580   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
581 
582   // Reorder received media packets.
583   auto it0 = this->received_packets_.begin();
584   auto it1 = this->received_packets_.begin();
585   it1++;
586   std::swap(*it0, *it1);
587 
588   for (const auto& received_packet : this->received_packets_) {
589     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
590   }
591 
592   // Expect 3 media packets in recovered list, and complete recovery.
593   EXPECT_EQ(3u, this->recovered_packets_.size());
594   EXPECT_TRUE(this->IsRecoveryComplete());
595 }
596 
597 // Verify we can still recover frame if FEC is received before media packets.
TYPED_TEST(RtpFecTest,FecRecoveryWithFecOutOfOrder)598 TYPED_TEST(RtpFecTest, FecRecoveryWithFecOutOfOrder) {
599   constexpr int kNumImportantPackets = 0;
600   constexpr bool kUseUnequalProtection = false;
601   constexpr uint8_t kProtectionFactor = 20;
602 
603   // One frame: 3 media packets, 1 FEC packet.
604   //         -----Frame 1----
605   //  #0(media) #1(media) #2(media) #3(FEC).
606   this->media_packets_ =
607       this->media_packet_generator_.ConstructMediaPackets(3, 0);
608 
609   EXPECT_EQ(
610       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
611                               kNumImportantPackets, kUseUnequalProtection,
612                               kFecMaskBursty, &this->generated_fec_packets_));
613 
614   // Expect 1 FEC packet.
615   EXPECT_EQ(1u, this->generated_fec_packets_.size());
616 
617   // Lose one media packet (seq# 1).
618   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
619   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
620   this->media_loss_mask_[1] = 1;
621   // Add FEC packet to received list before the media packets.
622   this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
623                         true);
624   // Add media packets to received list.
625   this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
626 
627   for (const auto& received_packet : this->received_packets_) {
628     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
629   }
630 
631   // Expect 3 media packets in recovered list, and complete recovery.
632   EXPECT_EQ(3u, this->recovered_packets_.size());
633   EXPECT_TRUE(this->IsRecoveryComplete());
634 }
635 
636 // Test 50% protection with random mask type: Two cases are considered:
637 // a 50% non-consecutive loss which can be fully recovered, and a 50%
638 // consecutive loss which cannot be fully recovered.
TYPED_TEST(RtpFecTest,FecRecoveryWithLoss50percRandomMask)639 TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
640   constexpr int kNumImportantPackets = 0;
641   constexpr bool kUseUnequalProtection = false;
642   constexpr int kNumMediaPackets = 4;
643   constexpr uint8_t kProtectionFactor = 255;
644 
645   // Packet Mask for (4,4,0) code, from random mask table.
646   // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
647 
648   //         media#0   media#1  media#2    media#3
649   // fec#0:    1          1        0          0
650   // fec#1:    1          0        1          0
651   // fec#2:    0          0        1          1
652   // fec#3:    0          1        0          1
653   //
654 
655   this->media_packets_ =
656       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
657 
658   EXPECT_EQ(
659       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
660                               kNumImportantPackets, kUseUnequalProtection,
661                               kFecMaskRandom, &this->generated_fec_packets_));
662 
663   // Expect 4 FEC packets.
664   EXPECT_EQ(4u, this->generated_fec_packets_.size());
665 
666   // 4 packets lost: 3 media packets (0, 2, 3), and one FEC packet (0) lost.
667   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
668   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
669   this->fec_loss_mask_[0] = 1;
670   this->media_loss_mask_[0] = 1;
671   this->media_loss_mask_[2] = 1;
672   this->media_loss_mask_[3] = 1;
673   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
674 
675   for (const auto& received_packet : this->received_packets_) {
676     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
677   }
678 
679   // With media packet#1 and FEC packets #1, #2, #3, expect complete recovery.
680   EXPECT_TRUE(this->IsRecoveryComplete());
681   this->recovered_packets_.clear();
682 
683   // 4 consecutive packets lost: media packets 0, 1, 2, 3.
684   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
685   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
686   this->media_loss_mask_[0] = 1;
687   this->media_loss_mask_[1] = 1;
688   this->media_loss_mask_[2] = 1;
689   this->media_loss_mask_[3] = 1;
690   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
691 
692   for (const auto& received_packet : this->received_packets_) {
693     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
694   }
695 
696   // Cannot get complete recovery for this loss configuration with random mask.
697   EXPECT_FALSE(this->IsRecoveryComplete());
698 }
699 
700 // Test 50% protection with bursty type: Three cases are considered:
701 // two 50% consecutive losses which can be fully recovered, and one
702 // non-consecutive which cannot be fully recovered.
TYPED_TEST(RtpFecTest,FecRecoveryWithLoss50percBurstyMask)703 TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
704   constexpr int kNumImportantPackets = 0;
705   constexpr bool kUseUnequalProtection = false;
706   constexpr int kNumMediaPackets = 4;
707   constexpr uint8_t kProtectionFactor = 255;
708 
709   // Packet Mask for (4,4,0) code, from bursty mask table.
710   // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
711 
712   //         media#0   media#1  media#2    media#3
713   // fec#0:    1          0        0          0
714   // fec#1:    1          1        0          0
715   // fec#2:    0          1        1          0
716   // fec#3:    0          0        1          1
717   //
718 
719   this->media_packets_ =
720       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
721 
722   EXPECT_EQ(
723       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
724                               kNumImportantPackets, kUseUnequalProtection,
725                               kFecMaskBursty, &this->generated_fec_packets_));
726 
727   // Expect 4 FEC packets.
728   EXPECT_EQ(4u, this->generated_fec_packets_.size());
729 
730   // 4 consecutive packets lost: media packets 0,1,2,3.
731   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
732   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
733   this->media_loss_mask_[0] = 1;
734   this->media_loss_mask_[1] = 1;
735   this->media_loss_mask_[2] = 1;
736   this->media_loss_mask_[3] = 1;
737   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
738 
739   for (const auto& received_packet : this->received_packets_) {
740     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
741   }
742 
743   // Expect complete recovery for consecutive packet loss <= 50%.
744   EXPECT_TRUE(this->IsRecoveryComplete());
745   this->recovered_packets_.clear();
746 
747   // 4 consecutive packets lost: media packets 1,2, 3, and FEC packet 0.
748   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->fec_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_);
755 
756   for (const auto& received_packet : this->received_packets_) {
757     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
758   }
759 
760   // Expect complete recovery for consecutive packet loss <= 50%.
761   EXPECT_TRUE(this->IsRecoveryComplete());
762   this->recovered_packets_.clear();
763 
764   // 4 packets lost (non-consecutive loss): media packets 0, 3, and FEC# 0, 3.
765   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
766   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
767   this->fec_loss_mask_[0] = 1;
768   this->fec_loss_mask_[3] = 1;
769   this->media_loss_mask_[0] = 1;
770   this->media_loss_mask_[3] = 1;
771   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
772 
773   for (const auto& received_packet : this->received_packets_) {
774     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
775   }
776 
777   // Cannot get complete recovery for this loss configuration.
778   EXPECT_FALSE(this->IsRecoveryComplete());
779 }
780 
TYPED_TEST(RtpFecTest,FecRecoveryNoLossUep)781 TYPED_TEST(RtpFecTest, FecRecoveryNoLossUep) {
782   constexpr int kNumImportantPackets = 2;
783   constexpr bool kUseUnequalProtection = true;
784   constexpr int kNumMediaPackets = 4;
785   constexpr uint8_t kProtectionFactor = 60;
786 
787   this->media_packets_ =
788       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
789 
790   EXPECT_EQ(
791       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
792                               kNumImportantPackets, kUseUnequalProtection,
793                               kFecMaskBursty, &this->generated_fec_packets_));
794 
795   // Expect 1 FEC packet.
796   EXPECT_EQ(1u, this->generated_fec_packets_.size());
797 
798   // No packets lost.
799   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
800   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
801   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
802 
803   for (const auto& received_packet : this->received_packets_) {
804     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
805   }
806 
807   // No packets lost, expect complete recovery.
808   EXPECT_TRUE(this->IsRecoveryComplete());
809 }
810 
TYPED_TEST(RtpFecTest,FecRecoveryWithLossUep)811 TYPED_TEST(RtpFecTest, FecRecoveryWithLossUep) {
812   constexpr int kNumImportantPackets = 2;
813   constexpr bool kUseUnequalProtection = true;
814   constexpr int kNumMediaPackets = 4;
815   constexpr uint8_t kProtectionFactor = 60;
816 
817   this->media_packets_ =
818       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
819 
820   EXPECT_EQ(
821       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
822                               kNumImportantPackets, kUseUnequalProtection,
823                               kFecMaskBursty, &this->generated_fec_packets_));
824 
825   // Expect 1 FEC packet.
826   EXPECT_EQ(1u, this->generated_fec_packets_.size());
827 
828   // 1 media packet lost.
829   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
830   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
831   this->media_loss_mask_[3] = 1;
832   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
833 
834   for (const auto& received_packet : this->received_packets_) {
835     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
836   }
837 
838   // One packet lost, one FEC packet, expect complete recovery.
839   EXPECT_TRUE(this->IsRecoveryComplete());
840   this->recovered_packets_.clear();
841 
842   // 2 media packets lost.
843   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
844   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
845   this->media_loss_mask_[1] = 1;
846   this->media_loss_mask_[3] = 1;
847   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
848 
849   for (const auto& received_packet : this->received_packets_) {
850     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
851   }
852 
853   // 2 packets lost, one FEC packet, cannot get complete recovery.
854   EXPECT_FALSE(this->IsRecoveryComplete());
855 }
856 
857 // Test 50% protection with random mask type for UEP on.
TYPED_TEST(RtpFecTest,FecRecoveryWithLoss50percUepRandomMask)858 TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
859   constexpr int kNumImportantPackets = 1;
860   constexpr bool kUseUnequalProtection = true;
861   constexpr int kNumMediaPackets = 4;
862   constexpr uint8_t kProtectionFactor = 255;
863 
864   // Packet Mask for (4,4,1) code, from random mask table.
865   // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 1)
866 
867   //         media#0   media#1  media#2    media#3
868   // fec#0:    1          0        0          0
869   // fec#1:    1          1        0          0
870   // fec#2:    1          0        1          1
871   // fec#3:    0          1        1          0
872   //
873 
874   this->media_packets_ =
875       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
876 
877   EXPECT_EQ(
878       0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
879                               kNumImportantPackets, kUseUnequalProtection,
880                               kFecMaskRandom, &this->generated_fec_packets_));
881 
882   // Expect 4 FEC packets.
883   EXPECT_EQ(4u, this->generated_fec_packets_.size());
884 
885   // 4 packets lost: 3 media packets and FEC packet#1 lost.
886   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
887   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
888   this->fec_loss_mask_[1] = 1;
889   this->media_loss_mask_[0] = 1;
890   this->media_loss_mask_[2] = 1;
891   this->media_loss_mask_[3] = 1;
892   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
893 
894   for (const auto& received_packet : this->received_packets_) {
895     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
896   }
897 
898   // With media packet#3 and FEC packets #0, #1, #3, expect complete recovery.
899   EXPECT_TRUE(this->IsRecoveryComplete());
900   this->recovered_packets_.clear();
901 
902   // 5 packets lost: 4 media packets and one FEC packet#2 lost.
903   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
904   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
905   this->fec_loss_mask_[2] = 1;
906   this->media_loss_mask_[0] = 1;
907   this->media_loss_mask_[1] = 1;
908   this->media_loss_mask_[2] = 1;
909   this->media_loss_mask_[3] = 1;
910   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
911 
912   for (const auto& received_packet : this->received_packets_) {
913     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
914   }
915 
916   // Cannot get complete recovery for this loss configuration.
917   EXPECT_FALSE(this->IsRecoveryComplete());
918 }
919 
TYPED_TEST(RtpFecTest,FecRecoveryNonConsecutivePackets)920 TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePackets) {
921   constexpr int kNumImportantPackets = 0;
922   constexpr bool kUseUnequalProtection = false;
923   constexpr int kNumMediaPackets = 5;
924   constexpr uint8_t kProtectionFactor = 60;
925 
926   this->media_packets_ =
927       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
928 
929   // Create a new temporary packet list for generating FEC packets.
930   // This list should have every other packet removed.
931   ForwardErrorCorrection::PacketList protected_media_packets;
932   DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets);
933 
934   EXPECT_EQ(
935       0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor,
936                               kNumImportantPackets, kUseUnequalProtection,
937                               kFecMaskBursty, &this->generated_fec_packets_));
938 
939   // Expect 1 FEC packet.
940   EXPECT_EQ(1u, this->generated_fec_packets_.size());
941 
942   // 1 protected media packet lost
943   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
944   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
945   this->media_loss_mask_[2] = 1;
946   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
947 
948   for (const auto& received_packet : this->received_packets_) {
949     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
950   }
951 
952   // One packet lost, one FEC packet, expect complete recovery.
953   EXPECT_TRUE(this->IsRecoveryComplete());
954   this->recovered_packets_.clear();
955 
956   // Unprotected packet lost.
957   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
958   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
959   this->media_loss_mask_[1] = 1;
960   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
961 
962   for (const auto& received_packet : this->received_packets_) {
963     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
964   }
965 
966   // Unprotected packet lost. Recovery not possible.
967   EXPECT_FALSE(this->IsRecoveryComplete());
968   this->recovered_packets_.clear();
969 
970   // 2 media packets lost.
971   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
972   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
973   this->media_loss_mask_[0] = 1;
974   this->media_loss_mask_[2] = 1;
975   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
976 
977   for (const auto& received_packet : this->received_packets_) {
978     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
979   }
980 
981   // 2 protected packets lost, one FEC packet, cannot get complete recovery.
982   EXPECT_FALSE(this->IsRecoveryComplete());
983 }
984 
TYPED_TEST(RtpFecTest,FecRecoveryNonConsecutivePacketsExtension)985 TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
986   constexpr int kNumImportantPackets = 0;
987   constexpr bool kUseUnequalProtection = false;
988   constexpr int kNumMediaPackets = 21;
989   uint8_t kProtectionFactor = 127;
990 
991   this->media_packets_ =
992       this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
993 
994   // Create a new temporary packet list for generating FEC packets.
995   // This list should have every other packet removed.
996   ForwardErrorCorrection::PacketList protected_media_packets;
997   DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets);
998 
999   // Zero column insertion will have to extend the size of the packet
1000   // mask since the number of actual packets are 21, while the number
1001   // of protected packets are 11.
1002   EXPECT_EQ(
1003       0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor,
1004                               kNumImportantPackets, kUseUnequalProtection,
1005                               kFecMaskBursty, &this->generated_fec_packets_));
1006 
1007   // Expect 5 FEC packet.
1008   EXPECT_EQ(5u, this->generated_fec_packets_.size());
1009 
1010   // Last protected media packet lost
1011   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1012   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1013   this->media_loss_mask_[kNumMediaPackets - 1] = 1;
1014   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
1015 
1016   for (const auto& received_packet : this->received_packets_) {
1017     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
1018   }
1019 
1020   // One packet lost, one FEC packet, expect complete recovery.
1021   EXPECT_TRUE(this->IsRecoveryComplete());
1022   this->recovered_packets_.clear();
1023 
1024   // Last unprotected packet lost.
1025   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1026   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1027   this->media_loss_mask_[kNumMediaPackets - 2] = 1;
1028   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
1029 
1030   for (const auto& received_packet : this->received_packets_) {
1031     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
1032   }
1033 
1034   // Unprotected packet lost. Recovery not possible.
1035   EXPECT_FALSE(this->IsRecoveryComplete());
1036   this->recovered_packets_.clear();
1037 
1038   // 6 media packets lost.
1039   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 - 11] = 1;
1042   this->media_loss_mask_[kNumMediaPackets - 9] = 1;
1043   this->media_loss_mask_[kNumMediaPackets - 7] = 1;
1044   this->media_loss_mask_[kNumMediaPackets - 5] = 1;
1045   this->media_loss_mask_[kNumMediaPackets - 3] = 1;
1046   this->media_loss_mask_[kNumMediaPackets - 1] = 1;
1047   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
1048 
1049   for (const auto& received_packet : this->received_packets_) {
1050     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
1051   }
1052 
1053   // 5 protected packets lost, one FEC packet, cannot get complete recovery.
1054   EXPECT_FALSE(this->IsRecoveryComplete());
1055 }
1056 
TYPED_TEST(RtpFecTest,FecRecoveryNonConsecutivePacketsWrap)1057 TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
1058   constexpr int kNumImportantPackets = 0;
1059   constexpr bool kUseUnequalProtection = false;
1060   constexpr int kNumMediaPackets = 21;
1061   uint8_t kProtectionFactor = 127;
1062 
1063   this->media_packets_ = this->media_packet_generator_.ConstructMediaPackets(
1064       kNumMediaPackets, 0xFFFF - 5);
1065 
1066   // Create a new temporary packet list for generating FEC packets.
1067   // This list should have every other packet removed.
1068   ForwardErrorCorrection::PacketList protected_media_packets;
1069   DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets);
1070 
1071   // Zero column insertion will have to extend the size of the packet
1072   // mask since the number of actual packets are 21, while the number
1073   // of protected packets are 11.
1074   EXPECT_EQ(
1075       0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor,
1076                               kNumImportantPackets, kUseUnequalProtection,
1077                               kFecMaskBursty, &this->generated_fec_packets_));
1078 
1079   // Expect 5 FEC packet.
1080   EXPECT_EQ(5u, this->generated_fec_packets_.size());
1081 
1082   // Last protected media packet lost
1083   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1084   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1085   this->media_loss_mask_[kNumMediaPackets - 1] = 1;
1086   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
1087 
1088   for (const auto& received_packet : this->received_packets_) {
1089     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
1090   }
1091 
1092   // One packet lost, one FEC packet, expect complete recovery.
1093   EXPECT_TRUE(this->IsRecoveryComplete());
1094   this->recovered_packets_.clear();
1095 
1096   // Last unprotected packet lost.
1097   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1098   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1099   this->media_loss_mask_[kNumMediaPackets - 2] = 1;
1100   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
1101 
1102   for (const auto& received_packet : this->received_packets_) {
1103     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
1104   }
1105 
1106   // Unprotected packet lost. Recovery not possible.
1107   EXPECT_FALSE(this->IsRecoveryComplete());
1108   this->recovered_packets_.clear();
1109 
1110   // 6 media packets lost.
1111   memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
1112   memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
1113   this->media_loss_mask_[kNumMediaPackets - 11] = 1;
1114   this->media_loss_mask_[kNumMediaPackets - 9] = 1;
1115   this->media_loss_mask_[kNumMediaPackets - 7] = 1;
1116   this->media_loss_mask_[kNumMediaPackets - 5] = 1;
1117   this->media_loss_mask_[kNumMediaPackets - 3] = 1;
1118   this->media_loss_mask_[kNumMediaPackets - 1] = 1;
1119   this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
1120 
1121   for (const auto& received_packet : this->received_packets_) {
1122     this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
1123   }
1124 
1125   // 5 protected packets lost, one FEC packet, cannot get complete recovery.
1126   EXPECT_FALSE(this->IsRecoveryComplete());
1127 }
1128 
1129 }  // namespace webrtc
1130