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
13#include "testing/gtest/include/gtest/gtest.h"
14#include "webrtc/base/random.h"
15#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
16#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
17
18using webrtc::ForwardErrorCorrection;
19
20// Minimum RTP header size in bytes.
21const uint8_t kRtpHeaderSize = 12;
22
23// Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum.
24const uint8_t kTransportOverhead = 28;
25
26// Maximum number of media packets used in the FEC (RFC 5109).
27const uint8_t kMaxNumberMediaPackets = ForwardErrorCorrection::kMaxMediaPackets;
28
29typedef std::list<ForwardErrorCorrection::Packet*> PacketList;
30typedef std::list<ForwardErrorCorrection::ReceivedPacket*> ReceivedPacketList;
31typedef std::list<ForwardErrorCorrection::RecoveredPacket*> RecoveredPacketList;
32
33template <typename T> void ClearList(std::list<T*>* my_list) {
34  T* packet = NULL;
35  while (!my_list->empty()) {
36    packet = my_list->front();
37    delete packet;
38    my_list->pop_front();
39  }
40}
41
42class RtpFecTest : public ::testing::Test {
43 protected:
44  RtpFecTest()
45      : random_(0xfec133700742),
46        fec_(new ForwardErrorCorrection()),
47        ssrc_(random_.Rand<uint32_t>()),
48        fec_seq_num_(0) {}
49
50  webrtc::Random random_;
51  ForwardErrorCorrection* fec_;
52  int ssrc_;
53  uint16_t fec_seq_num_;
54
55  PacketList media_packet_list_;
56  PacketList fec_packet_list_;
57  ReceivedPacketList received_packet_list_;
58  RecoveredPacketList recovered_packet_list_;
59
60  // Media packet "i" is lost if media_loss_mask_[i] = 1,
61  // received if media_loss_mask_[i] = 0.
62  int media_loss_mask_[kMaxNumberMediaPackets];
63
64  // FEC packet "i" is lost if fec_loss_mask_[i] = 1,
65  // received if fec_loss_mask_[i] = 0.
66  int fec_loss_mask_[kMaxNumberMediaPackets];
67
68  // Construct the media packet list, up to |num_media_packets| packets.
69  // Returns the next sequence number after the last media packet.
70  // (this will be the sequence of the first FEC packet)
71  int ConstructMediaPacketsSeqNum(int num_media_packets, int start_seq_num);
72  int ConstructMediaPackets(int num_media_packets);
73
74  // Construct the received packet list: a subset of the media and FEC packets.
75  void NetworkReceivedPackets();
76
77  // Add packet from |packet_list| to list of received packets, using the
78  // |loss_mask|.
79  // The |packet_list| may be a media packet list (is_fec = false), or a
80  // FEC packet list (is_fec = true).
81  void ReceivedPackets(const PacketList& packet_list, int* loss_mask,
82                       bool is_fec);
83
84  // Check for complete recovery after FEC decoding.
85  bool IsRecoveryComplete();
86
87  // Delete the received packets.
88  void FreeRecoveredPacketList();
89
90  // Delete the media and FEC packets.
91  void TearDown();
92};
93
94TEST_F(RtpFecTest, FecRecoveryNoLoss) {
95  const int kNumImportantPackets = 0;
96  const bool kUseUnequalProtection = false;
97  const int kNumMediaPackets = 4;
98  uint8_t kProtectionFactor = 60;
99
100  fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
101
102  EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
103                                 kNumImportantPackets, kUseUnequalProtection,
104                                 webrtc::kFecMaskBursty, &fec_packet_list_));
105
106  // Expect 1 FEC packet.
107  EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
108
109  // No packets lost.
110  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
111  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
112  NetworkReceivedPackets();
113
114  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
115                               &recovered_packet_list_));
116
117  // No packets lost, expect complete recovery.
118  EXPECT_TRUE(IsRecoveryComplete());
119}
120
121TEST_F(RtpFecTest, FecRecoveryWithLoss) {
122  const int kNumImportantPackets = 0;
123  const bool kUseUnequalProtection = false;
124  const int kNumMediaPackets = 4;
125  uint8_t kProtectionFactor = 60;
126
127  fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
128
129  EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
130                                 kNumImportantPackets, kUseUnequalProtection,
131                                 webrtc::kFecMaskBursty, &fec_packet_list_));
132
133  // Expect 1 FEC packet.
134  EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
135
136  // 1 media packet lost
137  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
138  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
139  media_loss_mask_[3] = 1;
140  NetworkReceivedPackets();
141
142  EXPECT_EQ(0,
143            fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
144
145  // One packet lost, one FEC packet, expect complete recovery.
146  EXPECT_TRUE(IsRecoveryComplete());
147  FreeRecoveredPacketList();
148
149  // 2 media packets lost.
150  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
151  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
152  media_loss_mask_[1] = 1;
153  media_loss_mask_[3] = 1;
154  NetworkReceivedPackets();
155
156  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
157                               &recovered_packet_list_));
158
159  // 2 packets lost, one FEC packet, cannot get complete recovery.
160  EXPECT_FALSE(IsRecoveryComplete());
161}
162
163// Verify that we don't use an old FEC packet for FEC decoding.
164TEST_F(RtpFecTest, FecRecoveryWithSeqNumGapTwoFrames) {
165  const int kNumImportantPackets = 0;
166  const bool kUseUnequalProtection = false;
167  uint8_t kProtectionFactor = 20;
168
169  // Two frames: first frame (old) with two media packets and 1 FEC packet.
170  // Second frame (new) with 3 media packets, and no FEC packets.
171  //       ---Frame 1----                     ----Frame 2------
172  //  #0(media) #1(media) #2(FEC)     #65535(media) #0(media) #1(media).
173  // If we lose either packet 0 or 1 of second frame, FEC decoding should not
174  // try to decode using "old" FEC packet #2.
175
176  // Construct media packets for first frame, starting at sequence number 0.
177  fec_seq_num_ = ConstructMediaPacketsSeqNum(2, 0);
178
179  EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
180                                 kNumImportantPackets, kUseUnequalProtection,
181                                 webrtc::kFecMaskBursty, &fec_packet_list_));
182  // Expect 1 FEC packet.
183  EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
184  // Add FEC packet (seq#2) of this first frame to received list (i.e., assume
185  // the two media packet were lost).
186  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
187  ReceivedPackets(fec_packet_list_, fec_loss_mask_, true);
188
189  // Construct media packets for second frame, with sequence number wrap.
190  ClearList(&media_packet_list_);
191  fec_seq_num_ = ConstructMediaPacketsSeqNum(3, 65535);
192
193  // Expect 3 media packets for this frame.
194  EXPECT_EQ(3, static_cast<int>(media_packet_list_.size()));
195
196  // Second media packet lost (seq#0).
197  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
198  media_loss_mask_[1] = 1;
199  // Add packets #65535, and #1 to received list.
200  ReceivedPackets(media_packet_list_, media_loss_mask_, false);
201
202  EXPECT_EQ(0,
203            fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
204
205  // Expect that no decoding is done to get missing packet (seq#0) of second
206  // frame, using old FEC packet (seq#2) from first (old) frame. So number of
207  // recovered packets is 2, and not equal to number of media packets (=3).
208  EXPECT_EQ(2, static_cast<int>(recovered_packet_list_.size()));
209  EXPECT_TRUE(recovered_packet_list_.size() != media_packet_list_.size());
210  FreeRecoveredPacketList();
211}
212
213// Verify we can still recovery frame if sequence number wrap occurs within
214// the frame and FEC packet following wrap is received after media packets.
215TEST_F(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameRecovery) {
216  const int kNumImportantPackets = 0;
217  const bool kUseUnequalProtection = false;
218  uint8_t kProtectionFactor = 20;
219
220  // One frame, with sequence number wrap in media packets.
221  //         -----Frame 1----
222  //  #65534(media) #65535(media) #0(media) #1(FEC).
223  fec_seq_num_ = ConstructMediaPacketsSeqNum(3, 65534);
224
225  EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
226                                 kNumImportantPackets, kUseUnequalProtection,
227                                 webrtc::kFecMaskBursty, &fec_packet_list_));
228
229  // Expect 1 FEC packet.
230  EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
231
232  // Lose one media packet (seq# 65535).
233  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
234  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
235  media_loss_mask_[1] = 1;
236  ReceivedPackets(media_packet_list_, media_loss_mask_, false);
237  // Add FEC packet to received list following the media packets.
238  ReceivedPackets(fec_packet_list_, fec_loss_mask_, true);
239
240  EXPECT_EQ(0,
241            fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
242
243  // Expect 3 media packets in recovered list, and complete recovery.
244  // Wrap-around won't remove FEC packet, as it follows the wrap.
245  EXPECT_EQ(3, static_cast<int>(recovered_packet_list_.size()));
246  EXPECT_TRUE(IsRecoveryComplete());
247  FreeRecoveredPacketList();
248}
249
250// Sequence number wrap occurs within the FEC packets for the frame.
251// In this case we will discard FEC packet and full recovery is not expected.
252// Same problem will occur if wrap is within media packets but FEC packet is
253// received before the media packets. This may be improved if timing information
254// is used to detect old FEC packets.
255// TODO(marpan): Update test if wrap-around handling changes in FEC decoding.
256TEST_F(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameNoRecovery) {
257  const int kNumImportantPackets = 0;
258  const bool kUseUnequalProtection = false;
259  uint8_t kProtectionFactor = 200;
260
261  // 1 frame: 3 media packets and 2 FEC packets.
262  // Sequence number wrap in FEC packets.
263  //           -----Frame 1----
264  // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC).
265  fec_seq_num_ = ConstructMediaPacketsSeqNum(3, 65532);
266
267  EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
268                                 kNumImportantPackets, kUseUnequalProtection,
269                                 webrtc::kFecMaskBursty, &fec_packet_list_));
270
271  // Expect 2 FEC packets.
272  EXPECT_EQ(2, static_cast<int>(fec_packet_list_.size()));
273
274  // Lose the last two media packets (seq# 65533, 65534).
275  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
276  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
277  media_loss_mask_[1] = 1;
278  media_loss_mask_[2] = 1;
279  ReceivedPackets(media_packet_list_, media_loss_mask_, false);
280  ReceivedPackets(fec_packet_list_, fec_loss_mask_, true);
281
282  EXPECT_EQ(0,
283            fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
284
285  // The two FEC packets are received and should allow for complete recovery,
286  // but because of the wrap the second FEC packet will be discarded, and only
287  // one media packet is recoverable. So exepct 2 media packets on recovered
288  // list and no complete recovery.
289  EXPECT_EQ(2, static_cast<int>(recovered_packet_list_.size()));
290  EXPECT_TRUE(recovered_packet_list_.size() != media_packet_list_.size());
291  EXPECT_FALSE(IsRecoveryComplete());
292  FreeRecoveredPacketList();
293}
294
295// Verify we can still recovery frame if FEC is received before media packets.
296TEST_F(RtpFecTest, FecRecoveryWithFecOutOfOrder) {
297  const int kNumImportantPackets = 0;
298  const bool kUseUnequalProtection = false;
299  uint8_t kProtectionFactor = 20;
300
301  // One frame: 3 media packets, 1 FEC packet.
302  //         -----Frame 1----
303  //  #0(media) #1(media) #2(media) #3(FEC).
304  fec_seq_num_ = ConstructMediaPacketsSeqNum(3, 0);
305
306  EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
307                                 kNumImportantPackets, kUseUnequalProtection,
308                                 webrtc::kFecMaskBursty, &fec_packet_list_));
309
310  // Expect 1 FEC packet.
311  EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
312
313  // Lose one media packet (seq# 1).
314  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
315  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
316  media_loss_mask_[1] = 1;
317  // Add FEC packet to received list before the media packets.
318  ReceivedPackets(fec_packet_list_, fec_loss_mask_, true);
319  // Add media packets to received list.
320  ReceivedPackets(media_packet_list_, media_loss_mask_, false);
321
322  EXPECT_EQ(0,
323            fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
324
325  // Expect 3 media packets in recovered list, and complete recovery.
326  EXPECT_EQ(3, static_cast<int>(recovered_packet_list_.size()));
327  EXPECT_TRUE(IsRecoveryComplete());
328  FreeRecoveredPacketList();
329}
330
331// Test 50% protection with random mask type: Two cases are considered:
332// a 50% non-consecutive loss which can be fully recovered, and a 50%
333// consecutive loss which cannot be fully recovered.
334TEST_F(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
335  const int kNumImportantPackets = 0;
336  const bool kUseUnequalProtection = false;
337  const int kNumMediaPackets = 4;
338  const uint8_t kProtectionFactor = 255;
339
340  // Packet Mask for (4,4,0) code, from random mask table.
341  // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
342
343  //         media#0   media#1  media#2    media#3
344  // fec#0:    1          1        0          0
345  // fec#1:    1          0        1          0
346  // fec#2:    0          0        1          1
347  // fec#3:    0          1        0          1
348  //
349
350  fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
351
352  EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
353                                 kNumImportantPackets, kUseUnequalProtection,
354                                 webrtc::kFecMaskRandom, &fec_packet_list_));
355
356  // Expect 4 FEC packets.
357  EXPECT_EQ(4, static_cast<int>(fec_packet_list_.size()));
358
359  // 4 packets lost: 3 media packets (0, 2, 3), and one FEC packet (0) lost.
360  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
361  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
362  fec_loss_mask_[0] = 1;
363  media_loss_mask_[0] = 1;
364  media_loss_mask_[2] = 1;
365  media_loss_mask_[3] = 1;
366  NetworkReceivedPackets();
367
368  EXPECT_EQ(0,
369            fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
370
371  // With media packet#1 and FEC packets #1, #2, #3, expect complete recovery.
372  EXPECT_TRUE(IsRecoveryComplete());
373  FreeRecoveredPacketList();
374
375  // 4 consecutive packets lost: media packets 0, 1, 2, 3.
376  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
377  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
378  media_loss_mask_[0] = 1;
379  media_loss_mask_[1] = 1;
380  media_loss_mask_[2] = 1;
381  media_loss_mask_[3] = 1;
382  NetworkReceivedPackets();
383
384  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
385                               &recovered_packet_list_));
386
387  // Cannot get complete recovery for this loss configuration with random mask.
388  EXPECT_FALSE(IsRecoveryComplete());
389}
390
391// Test 50% protection with bursty type: Three cases are considered:
392// two 50% consecutive losses which can be fully recovered, and one
393// non-consecutive which cannot be fully recovered.
394TEST_F(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
395  const int kNumImportantPackets = 0;
396  const bool kUseUnequalProtection = false;
397  const int kNumMediaPackets = 4;
398  const uint8_t kProtectionFactor = 255;
399
400  // Packet Mask for (4,4,0) code, from bursty mask table.
401  // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
402
403  //         media#0   media#1  media#2    media#3
404  // fec#0:    1          0        0          0
405  // fec#1:    1          1        0          0
406  // fec#2:    0          1        1          0
407  // fec#3:    0          0        1          1
408  //
409
410  fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
411
412  EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
413                                 kNumImportantPackets, kUseUnequalProtection,
414                                 webrtc::kFecMaskBursty, &fec_packet_list_));
415
416  // Expect 4 FEC packets.
417  EXPECT_EQ(4, static_cast<int>(fec_packet_list_.size()));
418
419  // 4 consecutive packets lost: media packets 0,1,2,3.
420  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
421  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
422  media_loss_mask_[0] = 1;
423  media_loss_mask_[1] = 1;
424  media_loss_mask_[2] = 1;
425  media_loss_mask_[3] = 1;
426  NetworkReceivedPackets();
427
428  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
429                               &recovered_packet_list_));
430
431  // Expect complete recovery for consecutive packet loss <= 50%.
432  EXPECT_TRUE(IsRecoveryComplete());
433  FreeRecoveredPacketList();
434
435  // 4 consecutive packets lost: media packets 1,2, 3, and FEC packet 0.
436  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
437  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
438  fec_loss_mask_[0] = 1;
439  media_loss_mask_[1] = 1;
440  media_loss_mask_[2] = 1;
441  media_loss_mask_[3] = 1;
442  NetworkReceivedPackets();
443
444  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
445                               &recovered_packet_list_));
446
447  // Expect complete recovery for consecutive packet loss <= 50%.
448  EXPECT_TRUE(IsRecoveryComplete());
449  FreeRecoveredPacketList();
450
451  // 4 packets lost (non-consecutive loss): media packets 0, 3, and FEC# 0, 3.
452  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
453  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
454  fec_loss_mask_[0] = 1;
455  fec_loss_mask_[3] = 1;
456  media_loss_mask_[0] = 1;
457  media_loss_mask_[3] = 1;
458  NetworkReceivedPackets();
459
460  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
461                               &recovered_packet_list_));
462
463  // Cannot get complete recovery for this loss configuration.
464  EXPECT_FALSE(IsRecoveryComplete());
465}
466
467TEST_F(RtpFecTest, FecRecoveryNoLossUep) {
468  const int kNumImportantPackets = 2;
469  const bool kUseUnequalProtection = true;
470  const int kNumMediaPackets = 4;
471  const uint8_t kProtectionFactor = 60;
472
473  fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
474
475  EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
476                                 kNumImportantPackets, kUseUnequalProtection,
477                                 webrtc::kFecMaskBursty, &fec_packet_list_));
478
479  // Expect 1 FEC packet.
480  EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
481
482  // No packets lost.
483  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
484  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
485  NetworkReceivedPackets();
486
487  EXPECT_EQ(0,
488            fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
489
490  // No packets lost, expect complete recovery.
491  EXPECT_TRUE(IsRecoveryComplete());
492}
493
494TEST_F(RtpFecTest, FecRecoveryWithLossUep) {
495  const int kNumImportantPackets = 2;
496  const bool kUseUnequalProtection = true;
497  const int kNumMediaPackets = 4;
498  const uint8_t kProtectionFactor = 60;
499
500  fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
501
502  EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
503                                 kNumImportantPackets, kUseUnequalProtection,
504                                 webrtc::kFecMaskBursty, &fec_packet_list_));
505
506  // Expect 1 FEC packet.
507  EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
508
509  // 1 media packet lost.
510  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
511  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
512  media_loss_mask_[3] = 1;
513  NetworkReceivedPackets();
514
515  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
516                               &recovered_packet_list_));
517
518  // One packet lost, one FEC packet, expect complete recovery.
519  EXPECT_TRUE(IsRecoveryComplete());
520  FreeRecoveredPacketList();
521
522  // 2 media packets lost.
523  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
524  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
525  media_loss_mask_[1] = 1;
526  media_loss_mask_[3] = 1;
527  NetworkReceivedPackets();
528
529  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
530                               &recovered_packet_list_));
531
532  // 2 packets lost, one FEC packet, cannot get complete recovery.
533  EXPECT_FALSE(IsRecoveryComplete());
534}
535
536// Test 50% protection with random mask type for UEP on.
537TEST_F(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
538  const int kNumImportantPackets = 1;
539  const bool kUseUnequalProtection = true;
540  const int kNumMediaPackets = 4;
541  const uint8_t kProtectionFactor = 255;
542
543  // Packet Mask for (4,4,1) code, from random mask table.
544  // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 1)
545
546  //         media#0   media#1  media#2    media#3
547  // fec#0:    1          0        0          0
548  // fec#1:    1          1        0          0
549  // fec#2:    1          0        1          1
550  // fec#3:    0          1        1          0
551  //
552
553  fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
554
555  EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
556                                 kNumImportantPackets, kUseUnequalProtection,
557                                 webrtc::kFecMaskRandom, &fec_packet_list_));
558
559  // Expect 4 FEC packets.
560  EXPECT_EQ(4, static_cast<int>(fec_packet_list_.size()));
561
562  // 4 packets lost: 3 media packets and FEC packet#1 lost.
563  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
564  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
565  fec_loss_mask_[1] = 1;
566  media_loss_mask_[0] = 1;
567  media_loss_mask_[2] = 1;
568  media_loss_mask_[3] = 1;
569  NetworkReceivedPackets();
570
571  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
572                               &recovered_packet_list_));
573
574  // With media packet#3 and FEC packets #0, #1, #3, expect complete recovery.
575  EXPECT_TRUE(IsRecoveryComplete());
576  FreeRecoveredPacketList();
577
578  // 5 packets lost: 4 media packets and one FEC packet#2 lost.
579  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
580  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
581  fec_loss_mask_[2] = 1;
582  media_loss_mask_[0] = 1;
583  media_loss_mask_[1] = 1;
584  media_loss_mask_[2] = 1;
585  media_loss_mask_[3] = 1;
586  NetworkReceivedPackets();
587
588  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
589                               &recovered_packet_list_));
590
591  // Cannot get complete recovery for this loss configuration.
592  EXPECT_FALSE(IsRecoveryComplete());
593}
594
595TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
596  const int kNumImportantPackets = 0;
597  const bool kUseUnequalProtection = false;
598  const int kNumMediaPackets = 5;
599  uint8_t kProtectionFactor = 60;
600
601  fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
602
603  // Create a new temporary packet list for generating FEC packets.
604  // This list should have every other packet removed.
605  PacketList protected_media_packets;
606  int i = 0;
607  for (PacketList::iterator it = media_packet_list_.begin();
608       it != media_packet_list_.end(); ++it, ++i) {
609    if (i % 2 == 0) protected_media_packets.push_back(*it);
610  }
611
612  EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets, kProtectionFactor,
613                                 kNumImportantPackets, kUseUnequalProtection,
614                                 webrtc::kFecMaskBursty, &fec_packet_list_));
615
616  // Expect 1 FEC packet.
617  EXPECT_EQ(1, static_cast<int>(fec_packet_list_.size()));
618
619  // 1 protected media packet lost
620  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
621  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
622  media_loss_mask_[2] = 1;
623  NetworkReceivedPackets();
624
625  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
626                               &recovered_packet_list_));
627
628  // One packet lost, one FEC packet, expect complete recovery.
629  EXPECT_TRUE(IsRecoveryComplete());
630  FreeRecoveredPacketList();
631
632  // Unprotected packet lost.
633  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
634  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
635  media_loss_mask_[1] = 1;
636  NetworkReceivedPackets();
637
638  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
639                               &recovered_packet_list_));
640
641  // Unprotected packet lost. Recovery not possible.
642  EXPECT_FALSE(IsRecoveryComplete());
643  FreeRecoveredPacketList();
644
645  // 2 media packets lost.
646  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
647  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
648  media_loss_mask_[0] = 1;
649  media_loss_mask_[2] = 1;
650  NetworkReceivedPackets();
651
652  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
653                               &recovered_packet_list_));
654
655  // 2 protected packets lost, one FEC packet, cannot get complete recovery.
656  EXPECT_FALSE(IsRecoveryComplete());
657}
658
659TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
660  const int kNumImportantPackets = 0;
661  const bool kUseUnequalProtection = false;
662  const int kNumMediaPackets = 21;
663  uint8_t kProtectionFactor = 127;
664
665  fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
666
667  // Create a new temporary packet list for generating FEC packets.
668  // This list should have every other packet removed.
669  PacketList protected_media_packets;
670  int i = 0;
671  for (PacketList::iterator it = media_packet_list_.begin();
672       it != media_packet_list_.end(); ++it, ++i) {
673    if (i % 2 == 0) protected_media_packets.push_back(*it);
674  }
675
676  // Zero column insertion will have to extend the size of the packet
677  // mask since the number of actual packets are 21, while the number
678  // of protected packets are 11.
679  EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets, kProtectionFactor,
680                                 kNumImportantPackets, kUseUnequalProtection,
681                                 webrtc::kFecMaskBursty, &fec_packet_list_));
682
683  // Expect 5 FEC packet.
684  EXPECT_EQ(5, static_cast<int>(fec_packet_list_.size()));
685
686  // Last protected media packet lost
687  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
688  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
689  media_loss_mask_[kNumMediaPackets - 1] = 1;
690  NetworkReceivedPackets();
691
692  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
693                               &recovered_packet_list_));
694
695  // One packet lost, one FEC packet, expect complete recovery.
696  EXPECT_TRUE(IsRecoveryComplete());
697  FreeRecoveredPacketList();
698
699  // Last unprotected packet lost.
700  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
701  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
702  media_loss_mask_[kNumMediaPackets - 2] = 1;
703  NetworkReceivedPackets();
704
705  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
706                               &recovered_packet_list_));
707
708  // Unprotected packet lost. Recovery not possible.
709  EXPECT_FALSE(IsRecoveryComplete());
710  FreeRecoveredPacketList();
711
712  // 6 media packets lost.
713  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
714  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
715  media_loss_mask_[kNumMediaPackets - 11] = 1;
716  media_loss_mask_[kNumMediaPackets - 9] = 1;
717  media_loss_mask_[kNumMediaPackets - 7] = 1;
718  media_loss_mask_[kNumMediaPackets - 5] = 1;
719  media_loss_mask_[kNumMediaPackets - 3] = 1;
720  media_loss_mask_[kNumMediaPackets - 1] = 1;
721  NetworkReceivedPackets();
722
723  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
724                               &recovered_packet_list_));
725
726  // 5 protected packets lost, one FEC packet, cannot get complete recovery.
727  EXPECT_FALSE(IsRecoveryComplete());
728}
729
730TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
731  const int kNumImportantPackets = 0;
732  const bool kUseUnequalProtection = false;
733  const int kNumMediaPackets = 21;
734  uint8_t kProtectionFactor = 127;
735
736  fec_seq_num_ = ConstructMediaPacketsSeqNum(kNumMediaPackets, 0xFFFF - 5);
737
738  // Create a new temporary packet list for generating FEC packets.
739  // This list should have every other packet removed.
740  PacketList protected_media_packets;
741  int i = 0;
742  for (PacketList::iterator it = media_packet_list_.begin();
743       it != media_packet_list_.end(); ++it, ++i) {
744    if (i % 2 == 0) protected_media_packets.push_back(*it);
745  }
746
747  // Zero column insertion will have to extend the size of the packet
748  // mask since the number of actual packets are 21, while the number
749  // of protected packets are 11.
750  EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets, kProtectionFactor,
751                                 kNumImportantPackets, kUseUnequalProtection,
752                                 webrtc::kFecMaskBursty, &fec_packet_list_));
753
754  // Expect 5 FEC packet.
755  EXPECT_EQ(5, static_cast<int>(fec_packet_list_.size()));
756
757  // Last protected media packet lost
758  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
759  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
760  media_loss_mask_[kNumMediaPackets - 1] = 1;
761  NetworkReceivedPackets();
762
763  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
764                               &recovered_packet_list_));
765
766  // One packet lost, one FEC packet, expect complete recovery.
767  EXPECT_TRUE(IsRecoveryComplete());
768  FreeRecoveredPacketList();
769
770  // Last unprotected packet lost.
771  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
772  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
773  media_loss_mask_[kNumMediaPackets - 2] = 1;
774  NetworkReceivedPackets();
775
776  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
777                               &recovered_packet_list_));
778
779  // Unprotected packet lost. Recovery not possible.
780  EXPECT_FALSE(IsRecoveryComplete());
781  FreeRecoveredPacketList();
782
783  // 6 media packets lost.
784  memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
785  memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
786  media_loss_mask_[kNumMediaPackets - 11] = 1;
787  media_loss_mask_[kNumMediaPackets - 9] = 1;
788  media_loss_mask_[kNumMediaPackets - 7] = 1;
789  media_loss_mask_[kNumMediaPackets - 5] = 1;
790  media_loss_mask_[kNumMediaPackets - 3] = 1;
791  media_loss_mask_[kNumMediaPackets - 1] = 1;
792  NetworkReceivedPackets();
793
794  EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
795                               &recovered_packet_list_));
796
797  // 5 protected packets lost, one FEC packet, cannot get complete recovery.
798  EXPECT_FALSE(IsRecoveryComplete());
799}
800
801void RtpFecTest::TearDown() {
802  fec_->ResetState(&recovered_packet_list_);
803  delete fec_;
804  FreeRecoveredPacketList();
805  ClearList(&media_packet_list_);
806  EXPECT_TRUE(media_packet_list_.empty());
807}
808
809void RtpFecTest::FreeRecoveredPacketList() {
810  ClearList(&recovered_packet_list_);
811}
812
813bool RtpFecTest::IsRecoveryComplete() {
814  // Check that the number of media and recovered packets are equal.
815  if (media_packet_list_.size() != recovered_packet_list_.size()) {
816    return false;
817  }
818
819  ForwardErrorCorrection::Packet* media_packet;
820  ForwardErrorCorrection::RecoveredPacket* recovered_packet;
821
822  bool recovery = true;
823
824  PacketList::iterator media_packet_list_item = media_packet_list_.begin();
825  RecoveredPacketList::iterator recovered_packet_list_item =
826      recovered_packet_list_.begin();
827  while (media_packet_list_item != media_packet_list_.end()) {
828    if (recovered_packet_list_item == recovered_packet_list_.end()) {
829      return false;
830    }
831    media_packet = *media_packet_list_item;
832    recovered_packet = *recovered_packet_list_item;
833    if (recovered_packet->pkt->length != media_packet->length) {
834      return false;
835    }
836    if (memcmp(recovered_packet->pkt->data, media_packet->data,
837               media_packet->length) != 0) {
838      return false;
839    }
840    media_packet_list_item++;
841    recovered_packet_list_item++;
842  }
843  return recovery;
844}
845
846void RtpFecTest::NetworkReceivedPackets() {
847  const bool kFecPacket = true;
848  ReceivedPackets(media_packet_list_, media_loss_mask_, !kFecPacket);
849  ReceivedPackets(fec_packet_list_, fec_loss_mask_, kFecPacket);
850}
851
852void RtpFecTest::ReceivedPackets(const PacketList& packet_list, int* loss_mask,
853                                 bool is_fec) {
854  ForwardErrorCorrection::Packet* packet;
855  ForwardErrorCorrection::ReceivedPacket* received_packet;
856  int seq_num = fec_seq_num_;
857  int packet_idx = 0;
858
859  PacketList::const_iterator packet_list_item = packet_list.begin();
860
861  while (packet_list_item != packet_list.end()) {
862    packet = *packet_list_item;
863    if (loss_mask[packet_idx] == 0) {
864      received_packet = new ForwardErrorCorrection::ReceivedPacket;
865      received_packet->pkt = new ForwardErrorCorrection::Packet;
866      received_packet_list_.push_back(received_packet);
867      received_packet->pkt->length = packet->length;
868      memcpy(received_packet->pkt->data, packet->data, packet->length);
869      received_packet->is_fec = is_fec;
870      if (!is_fec) {
871        // For media packets, the sequence number and marker bit is
872        // obtained from RTP header. These were set in ConstructMediaPackets().
873        received_packet->seq_num =
874            webrtc::ByteReader<uint16_t>::ReadBigEndian(&packet->data[2]);
875      } else {
876        // The sequence number, marker bit, and ssrc number are defined in the
877        // RTP header of the FEC packet, which is not constructed in this test.
878        // So we set these values below based on the values generated in
879        // ConstructMediaPackets().
880        received_packet->seq_num = seq_num;
881        // The ssrc value for FEC packets is set to the one used for the
882        // media packets in ConstructMediaPackets().
883        received_packet->ssrc = ssrc_;
884      }
885    }
886    packet_idx++;
887    packet_list_item++;
888    // Sequence number of FEC packets are defined as increment by 1 from
889    // last media packet in frame.
890    if (is_fec) seq_num++;
891  }
892}
893
894int RtpFecTest::ConstructMediaPacketsSeqNum(int num_media_packets,
895                                            int start_seq_num) {
896  assert(num_media_packets > 0);
897  ForwardErrorCorrection::Packet* media_packet = NULL;
898  int sequence_number = start_seq_num;
899  int time_stamp = random_.Rand<int>();
900
901  for (int i = 0; i < num_media_packets; ++i) {
902    media_packet = new ForwardErrorCorrection::Packet;
903    media_packet_list_.push_back(media_packet);
904    const uint32_t kMinPacketSize = kRtpHeaderSize;
905    const uint32_t kMaxPacketSize = IP_PACKET_SIZE - kRtpHeaderSize -
906                                    kTransportOverhead -
907                                    ForwardErrorCorrection::PacketOverhead();
908    media_packet->length = random_.Rand(kMinPacketSize, kMaxPacketSize);
909
910    // Generate random values for the first 2 bytes
911    media_packet->data[0] = random_.Rand<uint8_t>();
912    media_packet->data[1] = random_.Rand<uint8_t>();
913
914    // The first two bits are assumed to be 10 by the FEC encoder.
915    // In fact the FEC decoder will set the two first bits to 10 regardless of
916    // what they actually were. Set the first two bits to 10 so that a memcmp
917    // can be performed for the whole restored packet.
918    media_packet->data[0] |= 0x80;
919    media_packet->data[0] &= 0xbf;
920
921    // FEC is applied to a whole frame.
922    // A frame is signaled by multiple packets without the marker bit set
923    // followed by the last packet of the frame for which the marker bit is set.
924    // Only push one (fake) frame to the FEC.
925    media_packet->data[1] &= 0x7f;
926
927    webrtc::ByteWriter<uint16_t>::WriteBigEndian(&media_packet->data[2],
928                                                 sequence_number);
929    webrtc::ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[4],
930                                                 time_stamp);
931    webrtc::ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[8], ssrc_);
932
933    // Generate random values for payload.
934    for (size_t j = 12; j < media_packet->length; ++j) {
935      media_packet->data[j] = random_.Rand<uint8_t>();
936    }
937    sequence_number++;
938  }
939  // Last packet, set marker bit.
940  assert(media_packet != NULL);
941  media_packet->data[1] |= 0x80;
942  return sequence_number;
943}
944
945int RtpFecTest::ConstructMediaPackets(int num_media_packets) {
946  return ConstructMediaPacketsSeqNum(num_media_packets, random_.Rand<int>());
947}
948