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