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