2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
15 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
17 using webrtc::ForwardErrorCorrection;
19 // Minimum RTP header size in bytes.
20 const uint8_t kRtpHeaderSize = 12;
22 // Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum.
23 const uint8_t kTransportOverhead = 28;
25 // Maximum number of media packets used in the FEC (RFC 5109).
26 const uint8_t kMaxNumberMediaPackets = ForwardErrorCorrection::kMaxMediaPackets;
28 typedef std::list<ForwardErrorCorrection::Packet*> PacketList;
29 typedef std::list<ForwardErrorCorrection::ReceivedPacket*> ReceivedPacketList;
30 typedef std::list<ForwardErrorCorrection::RecoveredPacket*> RecoveredPacketList;
32 template <typename T> void ClearList(std::list<T*>* my_list) {
34 while (!my_list->empty()) {
35 packet = my_list->front();
41 class RtpFecTest : public ::testing::Test {
44 : fec_(new ForwardErrorCorrection()), ssrc_(rand()), fec_seq_num_(0) {}
46 ForwardErrorCorrection* fec_;
48 uint16_t fec_seq_num_;
50 PacketList media_packet_list_;
51 PacketList fec_packet_list_;
52 ReceivedPacketList received_packet_list_;
53 RecoveredPacketList recovered_packet_list_;
55 // Media packet "i" is lost if media_loss_mask_[i] = 1,
56 // received if media_loss_mask_[i] = 0.
57 int media_loss_mask_[kMaxNumberMediaPackets];
59 // FEC packet "i" is lost if fec_loss_mask_[i] = 1,
60 // received if fec_loss_mask_[i] = 0.
61 int fec_loss_mask_[kMaxNumberMediaPackets];
63 // Construct the media packet list, up to |num_media_packets| packets.
64 // Returns the next sequence number after the last media packet.
65 // (this will be the sequence of the first FEC packet)
66 int ConstructMediaPacketsSeqNum(int num_media_packets, int start_seq_num);
67 int ConstructMediaPackets(int num_media_packets);
69 // Construct the received packet list: a subset of the media and FEC packets.
70 void NetworkReceivedPackets();
72 // Add packet from |packet_list| to list of received packets, using the
74 // The |packet_list| may be a media packet list (is_fec = false), or a
75 // FEC packet list (is_fec = true).
76 void ReceivedPackets(const PacketList& packet_list, int* loss_mask,
79 // Check for complete recovery after FEC decoding.
80 bool IsRecoveryComplete();
82 // Delete the received packets.
83 void FreeRecoveredPacketList();
85 // Delete the media and FEC packets.
89 TEST_F(RtpFecTest, FecRecoveryNoLoss) {
90 const int kNumImportantPackets = 0;
91 const bool kUseUnequalProtection = false;
92 const int kNumMediaPackets = 4;
93 uint8_t kProtectionFactor = 60;
95 fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
97 EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
98 kNumImportantPackets, kUseUnequalProtection,
99 webrtc::kFecMaskBursty, &fec_packet_list_));
101 // Expect 1 FEC packet.
102 EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
105 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
106 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
107 NetworkReceivedPackets();
109 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
110 &recovered_packet_list_));
112 // No packets lost, expect complete recovery.
113 EXPECT_TRUE(IsRecoveryComplete());
116 TEST_F(RtpFecTest, FecRecoveryWithLoss) {
117 const int kNumImportantPackets = 0;
118 const bool kUseUnequalProtection = false;
119 const int kNumMediaPackets = 4;
120 uint8_t kProtectionFactor = 60;
122 fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
124 EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
125 kNumImportantPackets, kUseUnequalProtection,
126 webrtc::kFecMaskBursty, &fec_packet_list_));
128 // Expect 1 FEC packet.
129 EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
131 // 1 media packet lost
132 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
133 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
134 media_loss_mask_[3] = 1;
135 NetworkReceivedPackets();
138 fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
140 // One packet lost, one FEC packet, expect complete recovery.
141 EXPECT_TRUE(IsRecoveryComplete());
142 FreeRecoveredPacketList();
144 // 2 media packets lost.
145 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
146 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
147 media_loss_mask_[1] = 1;
148 media_loss_mask_[3] = 1;
149 NetworkReceivedPackets();
151 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
152 &recovered_packet_list_));
154 // 2 packets lost, one FEC packet, cannot get complete recovery.
155 EXPECT_FALSE(IsRecoveryComplete());
158 // Test 50% protection with random mask type: Two cases are considered:
159 // a 50% non-consecutive loss which can be fully recovered, and a 50%
160 // consecutive loss which cannot be fully recovered.
161 TEST_F(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
162 const int kNumImportantPackets = 0;
163 const bool kUseUnequalProtection = false;
164 const int kNumMediaPackets = 4;
165 const uint8_t kProtectionFactor = 255;
167 // Packet Mask for (4,4,0) code, from random mask table.
168 // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
170 // media#0 media#1 media#2 media#3
177 fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
179 EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
180 kNumImportantPackets, kUseUnequalProtection,
181 webrtc::kFecMaskRandom, &fec_packet_list_));
183 // Expect 4 FEC packets.
184 EXPECT_EQ(4, static_cast<int>(fec_packet_list_.size()));
186 // 4 packets lost: 3 media packets (0, 2, 3), and one FEC packet (0) lost.
187 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
188 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
189 fec_loss_mask_[0] = 1;
190 media_loss_mask_[0] = 1;
191 media_loss_mask_[2] = 1;
192 media_loss_mask_[3] = 1;
193 NetworkReceivedPackets();
196 fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
198 // With media packet#1 and FEC packets #1, #2, #3, expect complete recovery.
199 EXPECT_TRUE(IsRecoveryComplete());
200 FreeRecoveredPacketList();
202 // 4 consecutive packets lost: media packets 0, 1, 2, 3.
203 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
204 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
205 media_loss_mask_[0] = 1;
206 media_loss_mask_[1] = 1;
207 media_loss_mask_[2] = 1;
208 media_loss_mask_[3] = 1;
209 NetworkReceivedPackets();
211 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
212 &recovered_packet_list_));
214 // Cannot get complete recovery for this loss configuration with random mask.
215 EXPECT_FALSE(IsRecoveryComplete());
218 // Test 50% protection with bursty type: Three cases are considered:
219 // two 50% consecutive losses which can be fully recovered, and one
220 // non-consecutive which cannot be fully recovered.
221 TEST_F(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
222 const int kNumImportantPackets = 0;
223 const bool kUseUnequalProtection = false;
224 const int kNumMediaPackets = 4;
225 const uint8_t kProtectionFactor = 255;
227 // Packet Mask for (4,4,0) code, from bursty mask table.
228 // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
230 // media#0 media#1 media#2 media#3
237 fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
239 EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
240 kNumImportantPackets, kUseUnequalProtection,
241 webrtc::kFecMaskBursty, &fec_packet_list_));
243 // Expect 4 FEC packets.
244 EXPECT_EQ(4, static_cast<int>(fec_packet_list_.size()));
246 // 4 consecutive packets lost: media packets 0,1,2,3.
247 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
248 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
249 media_loss_mask_[0] = 1;
250 media_loss_mask_[1] = 1;
251 media_loss_mask_[2] = 1;
252 media_loss_mask_[3] = 1;
253 NetworkReceivedPackets();
255 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
256 &recovered_packet_list_));
258 // Expect complete recovery for consecutive packet loss <= 50%.
259 EXPECT_TRUE(IsRecoveryComplete());
260 FreeRecoveredPacketList();
262 // 4 consecutive packets lost: media packets 1,2, 3, and FEC packet 0.
263 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
264 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
265 fec_loss_mask_[0] = 1;
266 media_loss_mask_[1] = 1;
267 media_loss_mask_[2] = 1;
268 media_loss_mask_[3] = 1;
269 NetworkReceivedPackets();
271 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
272 &recovered_packet_list_));
274 // Expect complete recovery for consecutive packet loss <= 50%.
275 EXPECT_TRUE(IsRecoveryComplete());
276 FreeRecoveredPacketList();
278 // 4 packets lost (non-consecutive loss): media packets 0, 3, and FEC# 0, 3.
279 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
280 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
281 fec_loss_mask_[0] = 1;
282 fec_loss_mask_[3] = 1;
283 media_loss_mask_[0] = 1;
284 media_loss_mask_[3] = 1;
285 NetworkReceivedPackets();
287 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
288 &recovered_packet_list_));
290 // Cannot get complete recovery for this loss configuration.
291 EXPECT_FALSE(IsRecoveryComplete());
294 TEST_F(RtpFecTest, FecRecoveryNoLossUep) {
295 const int kNumImportantPackets = 2;
296 const bool kUseUnequalProtection = true;
297 const int kNumMediaPackets = 4;
298 const uint8_t kProtectionFactor = 60;
300 fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
302 EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
303 kNumImportantPackets, kUseUnequalProtection,
304 webrtc::kFecMaskBursty, &fec_packet_list_));
306 // Expect 1 FEC packet.
307 EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
310 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
311 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
312 NetworkReceivedPackets();
315 fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
317 // No packets lost, expect complete recovery.
318 EXPECT_TRUE(IsRecoveryComplete());
321 TEST_F(RtpFecTest, FecRecoveryWithLossUep) {
322 const int kNumImportantPackets = 2;
323 const bool kUseUnequalProtection = true;
324 const int kNumMediaPackets = 4;
325 const uint8_t kProtectionFactor = 60;
327 fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
329 EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
330 kNumImportantPackets, kUseUnequalProtection,
331 webrtc::kFecMaskBursty, &fec_packet_list_));
333 // Expect 1 FEC packet.
334 EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
336 // 1 media packet lost.
337 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
338 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
339 media_loss_mask_[3] = 1;
340 NetworkReceivedPackets();
342 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
343 &recovered_packet_list_));
345 // One packet lost, one FEC packet, expect complete recovery.
346 EXPECT_TRUE(IsRecoveryComplete());
347 FreeRecoveredPacketList();
349 // 2 media packets lost.
350 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
351 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
352 media_loss_mask_[1] = 1;
353 media_loss_mask_[3] = 1;
354 NetworkReceivedPackets();
356 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
357 &recovered_packet_list_));
359 // 2 packets lost, one FEC packet, cannot get complete recovery.
360 EXPECT_FALSE(IsRecoveryComplete());
363 // Test 50% protection with random mask type for UEP on.
364 TEST_F(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
365 const int kNumImportantPackets = 1;
366 const bool kUseUnequalProtection = true;
367 const int kNumMediaPackets = 4;
368 const uint8_t kProtectionFactor = 255;
370 // Packet Mask for (4,4,1) code, from random mask table.
371 // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 1)
373 // media#0 media#1 media#2 media#3
380 fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
382 EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
383 kNumImportantPackets, kUseUnequalProtection,
384 webrtc::kFecMaskRandom, &fec_packet_list_));
386 // Expect 4 FEC packets.
387 EXPECT_EQ(4, static_cast<int>(fec_packet_list_.size()));
389 // 4 packets lost: 3 media packets and FEC packet#1 lost.
390 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
391 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
392 fec_loss_mask_[1] = 1;
393 media_loss_mask_[0] = 1;
394 media_loss_mask_[2] = 1;
395 media_loss_mask_[3] = 1;
396 NetworkReceivedPackets();
398 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
399 &recovered_packet_list_));
401 // With media packet#3 and FEC packets #0, #1, #3, expect complete recovery.
402 EXPECT_TRUE(IsRecoveryComplete());
403 FreeRecoveredPacketList();
405 // 5 packets lost: 4 media packets and one FEC packet#2 lost.
406 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
407 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
408 fec_loss_mask_[2] = 1;
409 media_loss_mask_[0] = 1;
410 media_loss_mask_[1] = 1;
411 media_loss_mask_[2] = 1;
412 media_loss_mask_[3] = 1;
413 NetworkReceivedPackets();
415 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
416 &recovered_packet_list_));
418 // Cannot get complete recovery for this loss configuration.
419 EXPECT_FALSE(IsRecoveryComplete());
422 TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
423 const int kNumImportantPackets = 0;
424 const bool kUseUnequalProtection = false;
425 const int kNumMediaPackets = 5;
426 uint8_t kProtectionFactor = 60;
428 fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
430 // Create a new temporary packet list for generating FEC packets.
431 // This list should have every other packet removed.
432 PacketList protected_media_packets;
434 for (PacketList::iterator it = media_packet_list_.begin();
435 it != media_packet_list_.end(); ++it, ++i) {
436 if (i % 2 == 0) protected_media_packets.push_back(*it);
439 EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets, kProtectionFactor,
440 kNumImportantPackets, kUseUnequalProtection,
441 webrtc::kFecMaskBursty, &fec_packet_list_));
443 // Expect 1 FEC packet.
444 EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
446 // 1 protected media packet lost
447 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
448 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
449 media_loss_mask_[2] = 1;
450 NetworkReceivedPackets();
452 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
453 &recovered_packet_list_));
455 // One packet lost, one FEC packet, expect complete recovery.
456 EXPECT_TRUE(IsRecoveryComplete());
457 FreeRecoveredPacketList();
459 // Unprotected packet lost.
460 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
461 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
462 media_loss_mask_[1] = 1;
463 NetworkReceivedPackets();
465 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
466 &recovered_packet_list_));
468 // Unprotected packet lost. Recovery not possible.
469 EXPECT_FALSE(IsRecoveryComplete());
470 FreeRecoveredPacketList();
472 // 2 media packets lost.
473 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
474 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
475 media_loss_mask_[0] = 1;
476 media_loss_mask_[2] = 1;
477 NetworkReceivedPackets();
479 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
480 &recovered_packet_list_));
482 // 2 protected packets lost, one FEC packet, cannot get complete recovery.
483 EXPECT_FALSE(IsRecoveryComplete());
486 TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
487 const int kNumImportantPackets = 0;
488 const bool kUseUnequalProtection = false;
489 const int kNumMediaPackets = 21;
490 uint8_t kProtectionFactor = 127;
492 fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
494 // Create a new temporary packet list for generating FEC packets.
495 // This list should have every other packet removed.
496 PacketList protected_media_packets;
498 for (PacketList::iterator it = media_packet_list_.begin();
499 it != media_packet_list_.end(); ++it, ++i) {
500 if (i % 2 == 0) protected_media_packets.push_back(*it);
503 // Zero column insertion will have to extend the size of the packet
504 // mask since the number of actual packets are 21, while the number
505 // of protected packets are 11.
506 EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets, kProtectionFactor,
507 kNumImportantPackets, kUseUnequalProtection,
508 webrtc::kFecMaskBursty, &fec_packet_list_));
510 // Expect 5 FEC packet.
511 EXPECT_EQ(5, static_cast<int>(fec_packet_list_.size()));
513 // Last protected media packet lost
514 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
515 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
516 media_loss_mask_[kNumMediaPackets - 1] = 1;
517 NetworkReceivedPackets();
519 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
520 &recovered_packet_list_));
522 // One packet lost, one FEC packet, expect complete recovery.
523 EXPECT_TRUE(IsRecoveryComplete());
524 FreeRecoveredPacketList();
526 // Last unprotected packet lost.
527 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
528 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
529 media_loss_mask_[kNumMediaPackets - 2] = 1;
530 NetworkReceivedPackets();
532 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
533 &recovered_packet_list_));
535 // Unprotected packet lost. Recovery not possible.
536 EXPECT_FALSE(IsRecoveryComplete());
537 FreeRecoveredPacketList();
539 // 6 media packets lost.
540 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
541 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
542 media_loss_mask_[kNumMediaPackets - 11] = 1;
543 media_loss_mask_[kNumMediaPackets - 9] = 1;
544 media_loss_mask_[kNumMediaPackets - 7] = 1;
545 media_loss_mask_[kNumMediaPackets - 5] = 1;
546 media_loss_mask_[kNumMediaPackets - 3] = 1;
547 media_loss_mask_[kNumMediaPackets - 1] = 1;
548 NetworkReceivedPackets();
550 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
551 &recovered_packet_list_));
553 // 5 protected packets lost, one FEC packet, cannot get complete recovery.
554 EXPECT_FALSE(IsRecoveryComplete());
557 TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
558 const int kNumImportantPackets = 0;
559 const bool kUseUnequalProtection = false;
560 const int kNumMediaPackets = 21;
561 uint8_t kProtectionFactor = 127;
563 fec_seq_num_ = ConstructMediaPacketsSeqNum(kNumMediaPackets, 0xFFFF - 5);
565 // Create a new temporary packet list for generating FEC packets.
566 // This list should have every other packet removed.
567 PacketList protected_media_packets;
569 for (PacketList::iterator it = media_packet_list_.begin();
570 it != media_packet_list_.end(); ++it, ++i) {
571 if (i % 2 == 0) protected_media_packets.push_back(*it);
574 // Zero column insertion will have to extend the size of the packet
575 // mask since the number of actual packets are 21, while the number
576 // of protected packets are 11.
577 EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets, kProtectionFactor,
578 kNumImportantPackets, kUseUnequalProtection,
579 webrtc::kFecMaskBursty, &fec_packet_list_));
581 // Expect 5 FEC packet.
582 EXPECT_EQ(5, static_cast<int>(fec_packet_list_.size()));
584 // Last protected media packet lost
585 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
586 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
587 media_loss_mask_[kNumMediaPackets - 1] = 1;
588 NetworkReceivedPackets();
590 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
591 &recovered_packet_list_));
593 // One packet lost, one FEC packet, expect complete recovery.
594 EXPECT_TRUE(IsRecoveryComplete());
595 FreeRecoveredPacketList();
597 // Last unprotected packet lost.
598 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
599 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
600 media_loss_mask_[kNumMediaPackets - 2] = 1;
601 NetworkReceivedPackets();
603 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
604 &recovered_packet_list_));
606 // Unprotected packet lost. Recovery not possible.
607 EXPECT_FALSE(IsRecoveryComplete());
608 FreeRecoveredPacketList();
610 // 6 media packets lost.
611 memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
612 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
613 media_loss_mask_[kNumMediaPackets - 11] = 1;
614 media_loss_mask_[kNumMediaPackets - 9] = 1;
615 media_loss_mask_[kNumMediaPackets - 7] = 1;
616 media_loss_mask_[kNumMediaPackets - 5] = 1;
617 media_loss_mask_[kNumMediaPackets - 3] = 1;
618 media_loss_mask_[kNumMediaPackets - 1] = 1;
619 NetworkReceivedPackets();
621 EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
622 &recovered_packet_list_));
624 // 5 protected packets lost, one FEC packet, cannot get complete recovery.
625 EXPECT_FALSE(IsRecoveryComplete());
628 // TODO(marpan): Add more test cases.
630 void RtpFecTest::TearDown() {
631 fec_->ResetState(&recovered_packet_list_);
633 FreeRecoveredPacketList();
634 ClearList(&media_packet_list_);
635 EXPECT_TRUE(media_packet_list_.empty());
638 void RtpFecTest::FreeRecoveredPacketList() {
639 ClearList(&recovered_packet_list_);
642 bool RtpFecTest::IsRecoveryComplete() {
643 // Check that the number of media and recovered packets are equal.
644 if (media_packet_list_.size() != recovered_packet_list_.size()) {
648 ForwardErrorCorrection::Packet* media_packet;
649 ForwardErrorCorrection::RecoveredPacket* recovered_packet;
651 bool recovery = true;
653 PacketList::iterator media_packet_list_item = media_packet_list_.begin();
654 RecoveredPacketList::iterator recovered_packet_list_item =
655 recovered_packet_list_.begin();
656 while (media_packet_list_item != media_packet_list_.end()) {
657 if (recovered_packet_list_item == recovered_packet_list_.end()) {
660 media_packet = *media_packet_list_item;
661 recovered_packet = *recovered_packet_list_item;
662 if (recovered_packet->pkt->length != media_packet->length) {
665 if (memcmp(recovered_packet->pkt->data, media_packet->data,
666 media_packet->length) != 0) {
669 media_packet_list_item++;
670 recovered_packet_list_item++;
675 void RtpFecTest::NetworkReceivedPackets() {
676 const bool kFecPacket = true;
677 ReceivedPackets(media_packet_list_, media_loss_mask_, !kFecPacket);
678 ReceivedPackets(fec_packet_list_, fec_loss_mask_, kFecPacket);
681 void RtpFecTest::ReceivedPackets(const PacketList& packet_list, int* loss_mask,
683 ForwardErrorCorrection::Packet* packet;
684 ForwardErrorCorrection::ReceivedPacket* received_packet;
685 int seq_num = fec_seq_num_;
688 PacketList::const_iterator packet_list_item = packet_list.begin();
690 while (packet_list_item != packet_list.end()) {
691 packet = *packet_list_item;
692 if (loss_mask[packet_idx] == 0) {
693 received_packet = new ForwardErrorCorrection::ReceivedPacket;
694 received_packet->pkt = new ForwardErrorCorrection::Packet;
695 received_packet_list_.push_back(received_packet);
696 received_packet->pkt->length = packet->length;
697 memcpy(received_packet->pkt->data, packet->data, packet->length);
698 received_packet->is_fec = is_fec;
700 // For media packets, the sequence number and marker bit is
701 // obtained from RTP header. These were set in ConstructMediaPackets().
702 received_packet->seq_num =
703 webrtc::ModuleRTPUtility::BufferToUWord16(&packet->data[2]);
705 // The sequence number, marker bit, and ssrc number are defined in the
706 // RTP header of the FEC packet, which is not constructed in this test.
707 // So we set these values below based on the values generated in
708 // ConstructMediaPackets().
709 received_packet->seq_num = seq_num;
710 // The ssrc value for FEC packets is set to the one used for the
711 // media packets in ConstructMediaPackets().
712 received_packet->ssrc = ssrc_;
717 // Sequence number of FEC packets are defined as increment by 1 from
718 // last media packet in frame.
719 if (is_fec) seq_num++;
723 int RtpFecTest::ConstructMediaPacketsSeqNum(int num_media_packets,
725 assert(num_media_packets > 0);
726 ForwardErrorCorrection::Packet* media_packet = NULL;
727 int sequence_number = start_seq_num;
728 int time_stamp = rand();
730 for (int i = 0; i < num_media_packets; ++i) {
731 media_packet = new ForwardErrorCorrection::Packet;
732 media_packet_list_.push_back(media_packet);
733 media_packet->length = static_cast<uint16_t>(
734 (static_cast<float>(rand()) / RAND_MAX) *
735 (IP_PACKET_SIZE - kRtpHeaderSize - kTransportOverhead -
736 ForwardErrorCorrection::PacketOverhead()));
738 if (media_packet->length < kRtpHeaderSize) {
739 media_packet->length = kRtpHeaderSize;
741 // Generate random values for the first 2 bytes
742 media_packet->data[0] = static_cast<uint8_t>(rand() % 256);
743 media_packet->data[1] = static_cast<uint8_t>(rand() % 256);
745 // The first two bits are assumed to be 10 by the FEC encoder.
746 // In fact the FEC decoder will set the two first bits to 10 regardless of
747 // what they actually were. Set the first two bits to 10 so that a memcmp
748 // can be performed for the whole restored packet.
749 media_packet->data[0] |= 0x80;
750 media_packet->data[0] &= 0xbf;
752 // FEC is applied to a whole frame.
753 // A frame is signaled by multiple packets without the marker bit set
754 // followed by the last packet of the frame for which the marker bit is set.
755 // Only push one (fake) frame to the FEC.
756 media_packet->data[1] &= 0x7f;
758 webrtc::ModuleRTPUtility::AssignUWord16ToBuffer(&media_packet->data[2],
760 webrtc::ModuleRTPUtility::AssignUWord32ToBuffer(&media_packet->data[4],
762 webrtc::ModuleRTPUtility::AssignUWord32ToBuffer(&media_packet->data[8],
765 // Generate random values for payload.
766 for (int j = 12; j < media_packet->length; ++j) {
767 media_packet->data[j] = static_cast<uint8_t>(rand() % 256);
771 // Last packet, set marker bit.
772 assert(media_packet != NULL);
773 media_packet->data[1] |= 0x80;
774 return sequence_number;
777 int RtpFecTest::ConstructMediaPackets(int num_media_packets) {
778 return ConstructMediaPacketsSeqNum(num_media_packets, rand());