rtp_fec_unittest.cc (46198B)
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 <cstddef> 12 #include <cstdint> 13 #include <cstring> 14 #include <list> 15 #include <memory> 16 #include <utility> 17 #include <vector> 18 19 #include "absl/algorithm/container.h" 20 #include "modules/include/module_fec_types.h" 21 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" 22 #include "modules/rtp_rtcp/source/byte_io.h" 23 #include "modules/rtp_rtcp/source/fec_test_helper.h" 24 #include "modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h" 25 #include "modules/rtp_rtcp/source/forward_error_correction.h" 26 #include "modules/rtp_rtcp/source/forward_error_correction_internal.h" 27 #include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h" 28 #include "rtc_base/checks.h" 29 #include "rtc_base/random.h" 30 #include "test/gtest.h" 31 32 namespace webrtc { 33 34 namespace { 35 36 // Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum. 37 constexpr size_t kTransportOverhead = 28; 38 39 constexpr uint32_t kMediaSsrc = 83542; 40 constexpr uint32_t kFlexfecSsrc = 43245; 41 42 constexpr size_t kMaxMediaPackets = 48; 43 44 // Deep copies `src` to `dst`, but only keeps every Nth packet. 45 void DeepCopyEveryNthPacket(const ForwardErrorCorrection::PacketList& src, 46 int n, 47 ForwardErrorCorrection::PacketList* dst) { 48 RTC_DCHECK_GT(n, 0); 49 int i = 0; 50 for (const auto& packet : src) { 51 if (i % n == 0) { 52 dst->emplace_back(new ForwardErrorCorrection::Packet(*packet)); 53 } 54 ++i; 55 } 56 } 57 58 } // namespace 59 60 using ::testing::Types; 61 62 template <typename ForwardErrorCorrectionType> 63 class RtpFecTest : public ::testing::Test { 64 protected: 65 RtpFecTest() 66 : random_(0xabcdef123456), 67 media_packet_generator_( 68 kRtpHeaderSize, // Minimum packet size. 69 IP_PACKET_SIZE - kRtpHeaderSize - kTransportOverhead - 70 fec_.MaxPacketOverhead(), // Maximum packet size. 71 kMediaSsrc, 72 &random_) {} 73 74 // Construct `received_packets_`: a subset of the media and FEC packets. 75 // 76 // Media packet "i" is lost if media_loss_mask_[i] = 1, received if 77 // media_loss_mask_[i] = 0. 78 // FEC packet "i" is lost if fec_loss_mask_[i] = 1, received if 79 // fec_loss_mask_[i] = 0. 80 void NetworkReceivedPackets(int* media_loss_mask, int* fec_loss_mask); 81 82 // Add packet from `packet_list` to list of received packets, using the 83 // `loss_mask`. 84 // The `packet_list` may be a media packet list (is_fec = false), or a 85 // FEC packet list (is_fec = true). 86 template <typename T> 87 void ReceivedPackets(const T& packet_list, int* loss_mask, bool is_fec); 88 89 // Check for complete recovery after FEC decoding. 90 bool IsRecoveryComplete(); 91 92 ForwardErrorCorrectionType fec_; 93 94 Random random_; 95 test::fec::MediaPacketGenerator media_packet_generator_; 96 97 ForwardErrorCorrection::PacketList media_packets_; 98 std::list<ForwardErrorCorrection::Packet*> generated_fec_packets_; 99 std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>> 100 received_packets_; 101 ForwardErrorCorrection::RecoveredPacketList recovered_packets_; 102 103 int media_loss_mask_[kUlpfecMaxMediaPackets]; 104 int fec_loss_mask_[kUlpfecMaxMediaPackets]; 105 }; 106 107 template <typename ForwardErrorCorrectionType> 108 void RtpFecTest<ForwardErrorCorrectionType>::NetworkReceivedPackets( 109 int* media_loss_mask, 110 int* fec_loss_mask) { 111 constexpr bool kFecPacket = true; 112 this->received_packets_.clear(); 113 ReceivedPackets(media_packets_, media_loss_mask, !kFecPacket); 114 ReceivedPackets(generated_fec_packets_, fec_loss_mask, kFecPacket); 115 } 116 117 template <typename ForwardErrorCorrectionType> 118 template <typename PacketListType> 119 void RtpFecTest<ForwardErrorCorrectionType>::ReceivedPackets( 120 const PacketListType& packet_list, 121 int* loss_mask, 122 bool is_fec) { 123 uint16_t fec_seq_num = ForwardErrorCorrectionType::GetFirstFecSeqNum( 124 media_packet_generator_.GetNextSeqNum()); 125 int packet_idx = 0; 126 127 for (const auto& packet : packet_list) { 128 if (loss_mask[packet_idx] == 0) { 129 std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet( 130 new ForwardErrorCorrection::ReceivedPacket()); 131 received_packet->pkt = new ForwardErrorCorrection::Packet(); 132 received_packet->pkt->data = packet->data; 133 received_packet->is_fec = is_fec; 134 if (!is_fec) { 135 received_packet->ssrc = kMediaSsrc; 136 // For media packets, the sequence number is obtained from the 137 // RTP header as written by MediaPacketGenerator::ConstructMediaPackets. 138 received_packet->seq_num = 139 ByteReader<uint16_t>::ReadBigEndian(packet->data.data() + 2); 140 } else { 141 received_packet->ssrc = ForwardErrorCorrectionType::kFecSsrc; 142 // For FEC packets, we simulate the sequence numbers differently 143 // depending on if ULPFEC or FlexFEC is used. See the definition of 144 // ForwardErrorCorrectionType::GetFirstFecSeqNum. 145 received_packet->seq_num = fec_seq_num; 146 } 147 received_packets_.push_back(std::move(received_packet)); 148 } 149 packet_idx++; 150 // Sequence number of FEC packets are defined as increment by 1 from 151 // last media packet in frame. 152 if (is_fec) 153 fec_seq_num++; 154 } 155 } 156 157 template <typename ForwardErrorCorrectionType> 158 bool RtpFecTest<ForwardErrorCorrectionType>::IsRecoveryComplete() { 159 // We must have equally many recovered packets as original packets and all 160 // recovered packets must be identical to the corresponding original packets. 161 return absl::c_equal( 162 media_packets_, recovered_packets_, 163 [](const std::unique_ptr<ForwardErrorCorrection::Packet>& media_packet, 164 const std::unique_ptr<ForwardErrorCorrection::RecoveredPacket>& 165 recovered_packet) { 166 if (media_packet->data.size() != recovered_packet->pkt->data.size()) { 167 return false; 168 } 169 if (memcmp(media_packet->data.cdata(), 170 recovered_packet->pkt->data.cdata(), 171 media_packet->data.size()) != 0) { 172 return false; 173 } 174 return true; 175 }); 176 } 177 178 // Define gTest typed test to loop over both ULPFEC and FlexFEC. 179 // Since the tests now are parameterized, we need to access 180 // member variables using `this`, thereby enforcing runtime 181 // resolution. 182 183 class FlexfecForwardErrorCorrection : public ForwardErrorCorrection { 184 public: 185 static constexpr uint32_t kFecSsrc = kFlexfecSsrc; 186 187 FlexfecForwardErrorCorrection() 188 : ForwardErrorCorrection( 189 std::unique_ptr<FecHeaderReader>(new Flexfec03HeaderReader()), 190 std::unique_ptr<FecHeaderWriter>(new Flexfec03HeaderWriter()), 191 kFecSsrc, 192 kMediaSsrc) {} 193 194 // For FlexFEC we let the FEC packet sequence numbers be independent of 195 // the media packet sequence numbers. 196 static uint16_t GetFirstFecSeqNum(uint16_t /* next_media_seq_num */) { 197 Random random(0xbe110); 198 return random.Rand<uint16_t>(); 199 } 200 }; 201 202 class UlpfecForwardErrorCorrection : public ForwardErrorCorrection { 203 public: 204 static constexpr uint32_t kFecSsrc = kMediaSsrc; 205 206 UlpfecForwardErrorCorrection() 207 : ForwardErrorCorrection( 208 std::unique_ptr<FecHeaderReader>(new UlpfecHeaderReader()), 209 std::unique_ptr<FecHeaderWriter>(new UlpfecHeaderWriter()), 210 kFecSsrc, 211 kMediaSsrc) {} 212 213 // For ULPFEC we assume that the FEC packets are subsequent to the media 214 // packets in terms of sequence number. 215 static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) { 216 return next_media_seq_num; 217 } 218 }; 219 220 using FecTypes = 221 Types<FlexfecForwardErrorCorrection, UlpfecForwardErrorCorrection>; 222 TYPED_TEST_SUITE(RtpFecTest, FecTypes); 223 224 TYPED_TEST(RtpFecTest, WillProtectMediaPacketsWithLargeSequenceNumberGap) { 225 constexpr int kNumImportantPackets = 0; 226 constexpr bool kUseUnequalProtection = false; 227 constexpr int kNumMediaPackets = 2; 228 constexpr uint8_t kProtectionFactor = 127; 229 230 this->media_packets_ = 231 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); 232 233 // Create |kMaxMediaPackets - 1| sequence number difference. 234 ByteWriter<uint16_t>::WriteBigEndian( 235 this->media_packets_.front()->data.MutableData() + 2, 1); 236 ByteWriter<uint16_t>::WriteBigEndian( 237 this->media_packets_.back()->data.MutableData() + 2, kMaxMediaPackets); 238 239 EXPECT_EQ( 240 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 241 kNumImportantPackets, kUseUnequalProtection, 242 kFecMaskBursty, &this->generated_fec_packets_)); 243 EXPECT_EQ(1u, this->generated_fec_packets_.size()); 244 } 245 246 TYPED_TEST(RtpFecTest, 247 WillNotProtectMediaPacketsWithTooLargeSequenceNumberGap) { 248 constexpr int kNumImportantPackets = 0; 249 constexpr bool kUseUnequalProtection = false; 250 constexpr int kNumMediaPackets = 2; 251 constexpr uint8_t kProtectionFactor = 127; 252 253 this->media_packets_ = 254 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); 255 256 // Create `kMaxMediaPackets` sequence number difference. 257 ByteWriter<uint16_t>::WriteBigEndian( 258 this->media_packets_.front()->data.MutableData() + 2, 1); 259 ByteWriter<uint16_t>::WriteBigEndian( 260 this->media_packets_.back()->data.MutableData() + 2, 261 kMaxMediaPackets + 1); 262 263 EXPECT_EQ( 264 -1, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 265 kNumImportantPackets, kUseUnequalProtection, 266 kFecMaskBursty, &this->generated_fec_packets_)); 267 EXPECT_TRUE(this->generated_fec_packets_.empty()); 268 } 269 270 TYPED_TEST(RtpFecTest, FecRecoveryNoLoss) { 271 constexpr int kNumImportantPackets = 0; 272 constexpr bool kUseUnequalProtection = false; 273 constexpr int kNumMediaPackets = 4; 274 constexpr uint8_t kProtectionFactor = 60; 275 276 this->media_packets_ = 277 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); 278 279 EXPECT_EQ( 280 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 281 kNumImportantPackets, kUseUnequalProtection, 282 kFecMaskBursty, &this->generated_fec_packets_)); 283 284 // Expect 1 FEC packet. 285 EXPECT_EQ(1u, this->generated_fec_packets_.size()); 286 287 // No packets lost. 288 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 289 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 290 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 291 292 for (const auto& received_packet : this->received_packets_) { 293 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 294 } 295 296 // No packets lost, expect complete recovery. 297 EXPECT_TRUE(this->IsRecoveryComplete()); 298 } 299 300 TYPED_TEST(RtpFecTest, FecRecoveryWithLoss) { 301 constexpr int kNumImportantPackets = 0; 302 constexpr bool kUseUnequalProtection = false; 303 constexpr int kNumMediaPackets = 4; 304 constexpr uint8_t kProtectionFactor = 60; 305 306 this->media_packets_ = 307 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); 308 309 EXPECT_EQ( 310 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 311 kNumImportantPackets, kUseUnequalProtection, 312 kFecMaskBursty, &this->generated_fec_packets_)); 313 314 // Expect 1 FEC packet. 315 EXPECT_EQ(1u, this->generated_fec_packets_.size()); 316 317 // 1 media packet lost 318 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 319 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 320 this->media_loss_mask_[3] = 1; 321 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 322 323 for (const auto& received_packet : this->received_packets_) { 324 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 325 } 326 327 // One packet lost, one FEC packet, expect complete recovery. 328 EXPECT_TRUE(this->IsRecoveryComplete()); 329 this->recovered_packets_.clear(); 330 331 // 2 media packets lost. 332 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 333 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 334 this->media_loss_mask_[1] = 1; 335 this->media_loss_mask_[3] = 1; 336 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 337 338 for (const auto& received_packet : this->received_packets_) { 339 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 340 } 341 342 // 2 packets lost, one FEC packet, cannot get complete recovery. 343 EXPECT_FALSE(this->IsRecoveryComplete()); 344 } 345 346 // Verify that we don't use an old FEC packet for FEC decoding. 347 TYPED_TEST(RtpFecTest, NoFecRecoveryWithOldFecPacket) { 348 constexpr int kNumImportantPackets = 0; 349 constexpr bool kUseUnequalProtection = false; 350 constexpr uint8_t kProtectionFactor = 20; 351 352 // Two frames: first frame (old) with two media packets and 1 FEC packet. 353 // Third frame (new) with 3 media packets, and no FEC packets. 354 // 355 // #0(media) #1(media) #2(FEC) ----Frame 1----- 356 // #32767(media) 32768(media) 32769(media) ----Frame 2----- 357 // #65535(media) #0(media) #1(media). ----Frame 3----- 358 // If we lose either packet 0 or 1 of third frame, FEC decoding should not 359 // try to decode using "old" FEC packet #2. 360 361 // Construct media packets for first frame, starting at sequence number 0. 362 this->media_packets_ = 363 this->media_packet_generator_.ConstructMediaPackets(2, 0); 364 365 EXPECT_EQ( 366 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 367 kNumImportantPackets, kUseUnequalProtection, 368 kFecMaskBursty, &this->generated_fec_packets_)); 369 // Expect 1 FEC packet. 370 EXPECT_EQ(1u, this->generated_fec_packets_.size()); 371 // Add FEC packet (seq#2) of this first frame to received list (i.e., assume 372 // the two media packet were lost). 373 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 374 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, 375 true); 376 377 // Construct media packets for second frame, with sequence number wrap. 378 this->media_packets_ = 379 this->media_packet_generator_.ConstructMediaPackets(3, 32767); 380 381 // Expect 3 media packets for this frame. 382 EXPECT_EQ(3u, this->media_packets_.size()); 383 384 // No packets lost 385 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 386 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); 387 388 // Construct media packets for third frame, with sequence number wrap. 389 this->media_packets_ = 390 this->media_packet_generator_.ConstructMediaPackets(3, 65535); 391 392 // Expect 3 media packets for this frame. 393 EXPECT_EQ(3u, this->media_packets_.size()); 394 395 // Second media packet lost (seq#0). 396 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 397 this->media_loss_mask_[1] = 1; 398 // Add packets #65535, and #1 to received list. 399 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); 400 401 for (const auto& received_packet : this->received_packets_) { 402 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 403 } 404 405 // Expect that no decoding is done to get missing packet (seq#0) of third 406 // frame, using old FEC packet (seq#2) from first (old) frame. So number of 407 // recovered packets is 5 (0 from first frame, three from second frame, and 2 408 // for the third frame, with no packets recovered via FEC). 409 EXPECT_EQ(5u, this->recovered_packets_.size()); 410 EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size()); 411 } 412 413 // Verify we can still recover frame if sequence number wrap occurs within 414 // the frame and FEC packet following wrap is received after media packets. 415 TYPED_TEST(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameRecovery) { 416 constexpr int kNumImportantPackets = 0; 417 constexpr bool kUseUnequalProtection = false; 418 constexpr uint8_t kProtectionFactor = 20; 419 420 // One frame, with sequence number wrap in media packets. 421 // -----Frame 1---- 422 // #65534(media) #65535(media) #0(media) #1(FEC). 423 this->media_packets_ = 424 this->media_packet_generator_.ConstructMediaPackets(3, 65534); 425 426 EXPECT_EQ( 427 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 428 kNumImportantPackets, kUseUnequalProtection, 429 kFecMaskBursty, &this->generated_fec_packets_)); 430 431 // Expect 1 FEC packet. 432 EXPECT_EQ(1u, this->generated_fec_packets_.size()); 433 434 // Lose one media packet (seq# 65535). 435 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 436 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 437 this->media_loss_mask_[1] = 1; 438 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); 439 // Add FEC packet to received list following the media packets. 440 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, 441 true); 442 443 for (const auto& received_packet : this->received_packets_) { 444 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 445 } 446 447 // Expect 3 media packets in recovered list, and complete recovery. 448 // Wrap-around won't remove FEC packet, as it follows the wrap. 449 EXPECT_EQ(3u, this->recovered_packets_.size()); 450 EXPECT_TRUE(this->IsRecoveryComplete()); 451 } 452 453 // Sequence number wrap occurs within the ULPFEC packets for the frame. 454 // Same problem will occur if wrap is within media packets but ULPFEC packet is 455 // received before the media packets. This may be improved if timing information 456 // is used to detect old ULPFEC packets. 457 458 // TODO(nisse): There's some logic to discard ULPFEC packets at wrap-around, 459 // however, that is not actually exercised by this test: When the first FEC 460 // packet is processed, it results in full recovery of one media packet and the 461 // FEC packet is forgotten. And then the wraparound isn't noticed when the next 462 // FEC packet is received. We should fix wraparound handling, which currently 463 // appears broken, and then figure out how to test it properly. 464 using RtpFecTestUlpfecOnly = RtpFecTest<UlpfecForwardErrorCorrection>; 465 TEST_F(RtpFecTestUlpfecOnly, FecRecoveryWithSeqNumGapOneFrameRecovery) { 466 constexpr int kNumImportantPackets = 0; 467 constexpr bool kUseUnequalProtection = false; 468 constexpr uint8_t kProtectionFactor = 200; 469 470 // 1 frame: 3 media packets and 2 FEC packets. 471 // Sequence number wrap in FEC packets. 472 // -----Frame 1---- 473 // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC). 474 this->media_packets_ = 475 this->media_packet_generator_.ConstructMediaPackets(3, 65532); 476 477 EXPECT_EQ( 478 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 479 kNumImportantPackets, kUseUnequalProtection, 480 kFecMaskBursty, &this->generated_fec_packets_)); 481 482 // Expect 2 FEC packets. 483 EXPECT_EQ(2u, this->generated_fec_packets_.size()); 484 485 // Lose the last two media packets (seq# 65533, 65534). 486 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 487 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 488 this->media_loss_mask_[1] = 1; 489 this->media_loss_mask_[2] = 1; 490 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); 491 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, 492 true); 493 494 for (const auto& received_packet : this->received_packets_) { 495 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 496 } 497 498 // The two FEC packets are received and should allow for complete recovery, 499 // but because of the wrap the first FEC packet will be discarded, and only 500 // one media packet is recoverable. So expect 2 media packets on recovered 501 // list and no complete recovery. 502 EXPECT_EQ(3u, this->recovered_packets_.size()); 503 EXPECT_EQ(this->recovered_packets_.size(), this->media_packets_.size()); 504 EXPECT_TRUE(this->IsRecoveryComplete()); 505 } 506 507 // TODO(brandtr): This test mimics the one above, ensuring that the recovery 508 // strategy of FlexFEC matches the recovery strategy of ULPFEC. Since FlexFEC 509 // does not share the sequence number space with the media, however, having a 510 // matching recovery strategy may be suboptimal. Study this further. 511 // TODO(nisse): In this test, recovery based on the first FEC packet fails with 512 // the log message "The recovered packet had a length larger than a typical IP 513 // packet, and is thus dropped." This is probably not intended, and needs 514 // investigation. 515 using RtpFecTestFlexfecOnly = RtpFecTest<FlexfecForwardErrorCorrection>; 516 TEST_F(RtpFecTestFlexfecOnly, FecRecoveryWithSeqNumGapOneFrameNoRecovery) { 517 constexpr int kNumImportantPackets = 0; 518 constexpr bool kUseUnequalProtection = false; 519 constexpr uint8_t kProtectionFactor = 200; 520 521 // 1 frame: 3 media packets and 2 FEC packets. 522 // Sequence number wrap in FEC packets. 523 // -----Frame 1---- 524 // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC). 525 this->media_packets_ = 526 this->media_packet_generator_.ConstructMediaPackets(3, 65532); 527 528 EXPECT_EQ( 529 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 530 kNumImportantPackets, kUseUnequalProtection, 531 kFecMaskBursty, &this->generated_fec_packets_)); 532 533 // Expect 2 FEC packets. 534 EXPECT_EQ(2u, this->generated_fec_packets_.size()); 535 536 // Overwrite the sequence numbers generated by ConstructMediaPackets, 537 // to make sure that we do have a wrap. 538 auto it = this->generated_fec_packets_.begin(); 539 ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data.MutableData()[2], 65535); 540 ++it; 541 ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data.MutableData()[2], 0); 542 543 // Lose the last two media packets (seq# 65533, 65534). 544 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 545 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 546 this->media_loss_mask_[1] = 1; 547 this->media_loss_mask_[2] = 1; 548 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); 549 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, 550 true); 551 552 for (const auto& received_packet : this->received_packets_) { 553 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 554 } 555 556 // The two FEC packets are received and should allow for complete recovery, 557 // but because of the wrap the first FEC packet will be discarded, and only 558 // one media packet is recoverable. So expect 2 media packets on recovered 559 // list and no complete recovery. 560 EXPECT_EQ(2u, this->recovered_packets_.size()); 561 EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size()); 562 EXPECT_FALSE(this->IsRecoveryComplete()); 563 } 564 565 // Verify we can still recover frame if media packets are reordered. 566 TYPED_TEST(RtpFecTest, FecRecoveryWithMediaOutOfOrder) { 567 constexpr int kNumImportantPackets = 0; 568 constexpr bool kUseUnequalProtection = false; 569 constexpr uint8_t kProtectionFactor = 20; 570 571 // One frame: 3 media packets, 1 FEC packet. 572 // -----Frame 1---- 573 // #0(media) #1(media) #2(media) #3(FEC). 574 this->media_packets_ = 575 this->media_packet_generator_.ConstructMediaPackets(3, 0); 576 577 EXPECT_EQ( 578 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 579 kNumImportantPackets, kUseUnequalProtection, 580 kFecMaskBursty, &this->generated_fec_packets_)); 581 582 // Expect 1 FEC packet. 583 EXPECT_EQ(1u, this->generated_fec_packets_.size()); 584 585 // Lose one media packet (seq# 1). 586 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 587 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 588 this->media_loss_mask_[1] = 1; 589 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 590 591 // Reorder received media packets. 592 auto it0 = this->received_packets_.begin(); 593 auto it1 = this->received_packets_.begin(); 594 it1++; 595 std::swap(*it0, *it1); 596 597 for (const auto& received_packet : this->received_packets_) { 598 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 599 } 600 601 // Expect 3 media packets in recovered list, and complete recovery. 602 EXPECT_EQ(3u, this->recovered_packets_.size()); 603 EXPECT_TRUE(this->IsRecoveryComplete()); 604 } 605 606 // Verify we can still recover frame if FEC is received before media packets. 607 TYPED_TEST(RtpFecTest, FecRecoveryWithFecOutOfOrder) { 608 constexpr int kNumImportantPackets = 0; 609 constexpr bool kUseUnequalProtection = false; 610 constexpr uint8_t kProtectionFactor = 20; 611 612 // One frame: 3 media packets, 1 FEC packet. 613 // -----Frame 1---- 614 // #0(media) #1(media) #2(media) #3(FEC). 615 this->media_packets_ = 616 this->media_packet_generator_.ConstructMediaPackets(3, 0); 617 618 EXPECT_EQ( 619 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 620 kNumImportantPackets, kUseUnequalProtection, 621 kFecMaskBursty, &this->generated_fec_packets_)); 622 623 // Expect 1 FEC packet. 624 EXPECT_EQ(1u, this->generated_fec_packets_.size()); 625 626 // Lose one media packet (seq# 1). 627 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 628 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 629 this->media_loss_mask_[1] = 1; 630 // Add FEC packet to received list before the media packets. 631 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, 632 true); 633 // Add media packets to received list. 634 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); 635 636 for (const auto& received_packet : this->received_packets_) { 637 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 638 } 639 640 // Expect 3 media packets in recovered list, and complete recovery. 641 EXPECT_EQ(3u, this->recovered_packets_.size()); 642 EXPECT_TRUE(this->IsRecoveryComplete()); 643 } 644 645 // Test 50% protection with random mask type: Two cases are considered: 646 // a 50% non-consecutive loss which can be fully recovered, and a 50% 647 // consecutive loss which cannot be fully recovered. 648 TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percRandomMask) { 649 constexpr int kNumImportantPackets = 0; 650 constexpr bool kUseUnequalProtection = false; 651 constexpr int kNumMediaPackets = 4; 652 constexpr uint8_t kProtectionFactor = 255; 653 654 // Packet Mask for (4,4,0) code, from random mask table. 655 // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0) 656 657 // media#0 media#1 media#2 media#3 658 // fec#0: 1 1 0 0 659 // fec#1: 1 0 1 0 660 // fec#2: 0 0 1 1 661 // fec#3: 0 1 0 1 662 // 663 664 this->media_packets_ = 665 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); 666 667 EXPECT_EQ( 668 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 669 kNumImportantPackets, kUseUnequalProtection, 670 kFecMaskRandom, &this->generated_fec_packets_)); 671 672 // Expect 4 FEC packets. 673 EXPECT_EQ(4u, this->generated_fec_packets_.size()); 674 675 // 4 packets lost: 3 media packets (0, 2, 3), and one FEC packet (0) lost. 676 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 677 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 678 this->fec_loss_mask_[0] = 1; 679 this->media_loss_mask_[0] = 1; 680 this->media_loss_mask_[2] = 1; 681 this->media_loss_mask_[3] = 1; 682 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 683 684 for (const auto& received_packet : this->received_packets_) { 685 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 686 } 687 688 // With media packet#1 and FEC packets #1, #2, #3, expect complete recovery. 689 EXPECT_TRUE(this->IsRecoveryComplete()); 690 this->recovered_packets_.clear(); 691 692 // 4 consecutive packets lost: media packets 0, 1, 2, 3. 693 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 694 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 695 this->media_loss_mask_[0] = 1; 696 this->media_loss_mask_[1] = 1; 697 this->media_loss_mask_[2] = 1; 698 this->media_loss_mask_[3] = 1; 699 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 700 701 for (const auto& received_packet : this->received_packets_) { 702 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 703 } 704 705 // Cannot get complete recovery for this loss configuration with random mask. 706 EXPECT_FALSE(this->IsRecoveryComplete()); 707 } 708 709 // Test 50% protection with bursty type: Three cases are considered: 710 // two 50% consecutive losses which can be fully recovered, and one 711 // non-consecutive which cannot be fully recovered. 712 TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) { 713 constexpr int kNumImportantPackets = 0; 714 constexpr bool kUseUnequalProtection = false; 715 constexpr int kNumMediaPackets = 4; 716 constexpr uint8_t kProtectionFactor = 255; 717 718 // Packet Mask for (4,4,0) code, from bursty mask table. 719 // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0) 720 721 // media#0 media#1 media#2 media#3 722 // fec#0: 1 0 0 0 723 // fec#1: 1 1 0 0 724 // fec#2: 0 1 1 0 725 // fec#3: 0 0 1 1 726 // 727 728 this->media_packets_ = 729 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); 730 731 EXPECT_EQ( 732 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 733 kNumImportantPackets, kUseUnequalProtection, 734 kFecMaskBursty, &this->generated_fec_packets_)); 735 736 // Expect 4 FEC packets. 737 EXPECT_EQ(4u, this->generated_fec_packets_.size()); 738 739 // 4 consecutive packets lost: media packets 0,1,2,3. 740 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 741 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 742 this->media_loss_mask_[0] = 1; 743 this->media_loss_mask_[1] = 1; 744 this->media_loss_mask_[2] = 1; 745 this->media_loss_mask_[3] = 1; 746 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 747 748 for (const auto& received_packet : this->received_packets_) { 749 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 750 } 751 752 // Expect complete recovery for consecutive packet loss <= 50%. 753 EXPECT_TRUE(this->IsRecoveryComplete()); 754 this->recovered_packets_.clear(); 755 756 // 4 consecutive packets lost: media packets 1,2, 3, and FEC packet 0. 757 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 758 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 759 this->fec_loss_mask_[0] = 1; 760 this->media_loss_mask_[1] = 1; 761 this->media_loss_mask_[2] = 1; 762 this->media_loss_mask_[3] = 1; 763 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 764 765 for (const auto& received_packet : this->received_packets_) { 766 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 767 } 768 769 // Expect complete recovery for consecutive packet loss <= 50%. 770 EXPECT_TRUE(this->IsRecoveryComplete()); 771 this->recovered_packets_.clear(); 772 773 // 4 packets lost (non-consecutive loss): media packets 0, 3, and FEC# 0, 3. 774 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 775 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 776 this->fec_loss_mask_[0] = 1; 777 this->fec_loss_mask_[3] = 1; 778 this->media_loss_mask_[0] = 1; 779 this->media_loss_mask_[3] = 1; 780 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 781 782 for (const auto& received_packet : this->received_packets_) { 783 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 784 } 785 786 // Cannot get complete recovery for this loss configuration. 787 EXPECT_FALSE(this->IsRecoveryComplete()); 788 } 789 790 TYPED_TEST(RtpFecTest, FecRecoveryNoLossUep) { 791 constexpr int kNumImportantPackets = 2; 792 constexpr bool kUseUnequalProtection = true; 793 constexpr int kNumMediaPackets = 4; 794 constexpr uint8_t kProtectionFactor = 60; 795 796 this->media_packets_ = 797 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); 798 799 EXPECT_EQ( 800 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 801 kNumImportantPackets, kUseUnequalProtection, 802 kFecMaskBursty, &this->generated_fec_packets_)); 803 804 // Expect 1 FEC packet. 805 EXPECT_EQ(1u, this->generated_fec_packets_.size()); 806 807 // No packets lost. 808 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 809 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 810 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 811 812 for (const auto& received_packet : this->received_packets_) { 813 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 814 } 815 816 // No packets lost, expect complete recovery. 817 EXPECT_TRUE(this->IsRecoveryComplete()); 818 } 819 820 TYPED_TEST(RtpFecTest, FecRecoveryWithLossUep) { 821 constexpr int kNumImportantPackets = 2; 822 constexpr bool kUseUnequalProtection = true; 823 constexpr int kNumMediaPackets = 4; 824 constexpr uint8_t kProtectionFactor = 60; 825 826 this->media_packets_ = 827 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); 828 829 EXPECT_EQ( 830 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 831 kNumImportantPackets, kUseUnequalProtection, 832 kFecMaskBursty, &this->generated_fec_packets_)); 833 834 // Expect 1 FEC packet. 835 EXPECT_EQ(1u, this->generated_fec_packets_.size()); 836 837 // 1 media packet lost. 838 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 839 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 840 this->media_loss_mask_[3] = 1; 841 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 842 843 for (const auto& received_packet : this->received_packets_) { 844 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 845 } 846 847 // One packet lost, one FEC packet, expect complete recovery. 848 EXPECT_TRUE(this->IsRecoveryComplete()); 849 this->recovered_packets_.clear(); 850 851 // 2 media packets lost. 852 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 853 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 854 this->media_loss_mask_[1] = 1; 855 this->media_loss_mask_[3] = 1; 856 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 857 858 for (const auto& received_packet : this->received_packets_) { 859 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 860 } 861 862 // 2 packets lost, one FEC packet, cannot get complete recovery. 863 EXPECT_FALSE(this->IsRecoveryComplete()); 864 } 865 866 // Test 50% protection with random mask type for UEP on. 867 TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) { 868 constexpr int kNumImportantPackets = 1; 869 constexpr bool kUseUnequalProtection = true; 870 constexpr int kNumMediaPackets = 4; 871 constexpr uint8_t kProtectionFactor = 255; 872 873 // Packet Mask for (4,4,1) code, from random mask table. 874 // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 1) 875 876 // media#0 media#1 media#2 media#3 877 // fec#0: 1 0 0 0 878 // fec#1: 1 1 0 0 879 // fec#2: 1 0 1 1 880 // fec#3: 0 1 1 0 881 // 882 883 this->media_packets_ = 884 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); 885 886 EXPECT_EQ( 887 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, 888 kNumImportantPackets, kUseUnequalProtection, 889 kFecMaskRandom, &this->generated_fec_packets_)); 890 891 // Expect 4 FEC packets. 892 EXPECT_EQ(4u, this->generated_fec_packets_.size()); 893 894 // 4 packets lost: 3 media packets and FEC packet#1 lost. 895 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 896 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 897 this->fec_loss_mask_[1] = 1; 898 this->media_loss_mask_[0] = 1; 899 this->media_loss_mask_[2] = 1; 900 this->media_loss_mask_[3] = 1; 901 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 902 903 for (const auto& received_packet : this->received_packets_) { 904 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 905 } 906 907 // With media packet#3 and FEC packets #0, #1, #3, expect complete recovery. 908 EXPECT_TRUE(this->IsRecoveryComplete()); 909 this->recovered_packets_.clear(); 910 911 // 5 packets lost: 4 media packets and one FEC packet#2 lost. 912 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 913 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 914 this->fec_loss_mask_[2] = 1; 915 this->media_loss_mask_[0] = 1; 916 this->media_loss_mask_[1] = 1; 917 this->media_loss_mask_[2] = 1; 918 this->media_loss_mask_[3] = 1; 919 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 920 921 for (const auto& received_packet : this->received_packets_) { 922 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 923 } 924 925 // Cannot get complete recovery for this loss configuration. 926 EXPECT_FALSE(this->IsRecoveryComplete()); 927 } 928 929 TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePackets) { 930 constexpr int kNumImportantPackets = 0; 931 constexpr bool kUseUnequalProtection = false; 932 constexpr int kNumMediaPackets = 5; 933 constexpr uint8_t kProtectionFactor = 60; 934 935 this->media_packets_ = 936 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); 937 938 // Create a new temporary packet list for generating FEC packets. 939 // This list should have every other packet removed. 940 ForwardErrorCorrection::PacketList protected_media_packets; 941 DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets); 942 943 EXPECT_EQ( 944 0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor, 945 kNumImportantPackets, kUseUnequalProtection, 946 kFecMaskBursty, &this->generated_fec_packets_)); 947 948 // Expect 1 FEC packet. 949 EXPECT_EQ(1u, this->generated_fec_packets_.size()); 950 951 // 1 protected media packet lost 952 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 953 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 954 this->media_loss_mask_[2] = 1; 955 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 956 957 for (const auto& received_packet : this->received_packets_) { 958 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 959 } 960 961 // One packet lost, one FEC packet, expect complete recovery. 962 EXPECT_TRUE(this->IsRecoveryComplete()); 963 this->recovered_packets_.clear(); 964 965 // Unprotected packet lost. 966 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 967 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 968 this->media_loss_mask_[1] = 1; 969 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 970 971 for (const auto& received_packet : this->received_packets_) { 972 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 973 } 974 975 // Unprotected packet lost. Recovery not possible. 976 EXPECT_FALSE(this->IsRecoveryComplete()); 977 this->recovered_packets_.clear(); 978 979 // 2 media packets lost. 980 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 981 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 982 this->media_loss_mask_[0] = 1; 983 this->media_loss_mask_[2] = 1; 984 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 985 986 for (const auto& received_packet : this->received_packets_) { 987 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 988 } 989 990 // 2 protected packets lost, one FEC packet, cannot get complete recovery. 991 EXPECT_FALSE(this->IsRecoveryComplete()); 992 } 993 994 TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) { 995 constexpr int kNumImportantPackets = 0; 996 constexpr bool kUseUnequalProtection = false; 997 constexpr int kNumMediaPackets = 21; 998 uint8_t kProtectionFactor = 127; 999 1000 this->media_packets_ = 1001 this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); 1002 1003 // Create a new temporary packet list for generating FEC packets. 1004 // This list should have every other packet removed. 1005 ForwardErrorCorrection::PacketList protected_media_packets; 1006 DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets); 1007 1008 // Zero column insertion will have to extend the size of the packet 1009 // mask since the number of actual packets are 21, while the number 1010 // of protected packets are 11. 1011 EXPECT_EQ( 1012 0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor, 1013 kNumImportantPackets, kUseUnequalProtection, 1014 kFecMaskBursty, &this->generated_fec_packets_)); 1015 1016 // Expect 5 FEC packet. 1017 EXPECT_EQ(5u, this->generated_fec_packets_.size()); 1018 1019 // Last protected media packet lost 1020 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 1021 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 1022 this->media_loss_mask_[kNumMediaPackets - 1] = 1; 1023 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 1024 1025 for (const auto& received_packet : this->received_packets_) { 1026 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 1027 } 1028 1029 // One packet lost, one FEC packet, expect complete recovery. 1030 EXPECT_TRUE(this->IsRecoveryComplete()); 1031 this->recovered_packets_.clear(); 1032 1033 // Last unprotected packet lost. 1034 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 1035 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 1036 this->media_loss_mask_[kNumMediaPackets - 2] = 1; 1037 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 1038 1039 for (const auto& received_packet : this->received_packets_) { 1040 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 1041 } 1042 1043 // Unprotected packet lost. Recovery not possible. 1044 EXPECT_FALSE(this->IsRecoveryComplete()); 1045 this->recovered_packets_.clear(); 1046 1047 // 6 media packets lost. 1048 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 1049 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 1050 this->media_loss_mask_[kNumMediaPackets - 11] = 1; 1051 this->media_loss_mask_[kNumMediaPackets - 9] = 1; 1052 this->media_loss_mask_[kNumMediaPackets - 7] = 1; 1053 this->media_loss_mask_[kNumMediaPackets - 5] = 1; 1054 this->media_loss_mask_[kNumMediaPackets - 3] = 1; 1055 this->media_loss_mask_[kNumMediaPackets - 1] = 1; 1056 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 1057 1058 for (const auto& received_packet : this->received_packets_) { 1059 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 1060 } 1061 1062 // 5 protected packets lost, one FEC packet, cannot get complete recovery. 1063 EXPECT_FALSE(this->IsRecoveryComplete()); 1064 } 1065 1066 TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) { 1067 constexpr int kNumImportantPackets = 0; 1068 constexpr bool kUseUnequalProtection = false; 1069 constexpr int kNumMediaPackets = 21; 1070 uint8_t kProtectionFactor = 127; 1071 1072 this->media_packets_ = this->media_packet_generator_.ConstructMediaPackets( 1073 kNumMediaPackets, 0xFFFF - 5); 1074 1075 // Create a new temporary packet list for generating FEC packets. 1076 // This list should have every other packet removed. 1077 ForwardErrorCorrection::PacketList protected_media_packets; 1078 DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets); 1079 1080 // Zero column insertion will have to extend the size of the packet 1081 // mask since the number of actual packets are 21, while the number 1082 // of protected packets are 11. 1083 EXPECT_EQ( 1084 0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor, 1085 kNumImportantPackets, kUseUnequalProtection, 1086 kFecMaskBursty, &this->generated_fec_packets_)); 1087 1088 // Expect 5 FEC packet. 1089 EXPECT_EQ(5u, this->generated_fec_packets_.size()); 1090 1091 // Last protected media packet lost 1092 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 1093 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 1094 this->media_loss_mask_[kNumMediaPackets - 1] = 1; 1095 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 1096 1097 for (const auto& received_packet : this->received_packets_) { 1098 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 1099 } 1100 1101 // One packet lost, one FEC packet, expect complete recovery. 1102 EXPECT_TRUE(this->IsRecoveryComplete()); 1103 this->recovered_packets_.clear(); 1104 1105 // Last unprotected packet lost. 1106 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 1107 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 1108 this->media_loss_mask_[kNumMediaPackets - 2] = 1; 1109 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 1110 1111 for (const auto& received_packet : this->received_packets_) { 1112 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 1113 } 1114 1115 // Unprotected packet lost. Recovery not possible. 1116 EXPECT_FALSE(this->IsRecoveryComplete()); 1117 this->recovered_packets_.clear(); 1118 1119 // 6 media packets lost. 1120 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); 1121 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); 1122 this->media_loss_mask_[kNumMediaPackets - 11] = 1; 1123 this->media_loss_mask_[kNumMediaPackets - 9] = 1; 1124 this->media_loss_mask_[kNumMediaPackets - 7] = 1; 1125 this->media_loss_mask_[kNumMediaPackets - 5] = 1; 1126 this->media_loss_mask_[kNumMediaPackets - 3] = 1; 1127 this->media_loss_mask_[kNumMediaPackets - 1] = 1; 1128 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); 1129 1130 for (const auto& received_packet : this->received_packets_) { 1131 this->fec_.DecodeFec(*received_packet, &this->recovered_packets_); 1132 } 1133 1134 // 5 protected packets lost, one FEC packet, cannot get complete recovery. 1135 EXPECT_FALSE(this->IsRecoveryComplete()); 1136 } 1137 1138 } // namespace webrtc