OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 ReceivedPackets(media_packets_, media_loss_mask, !kFecPacket); | 101 ReceivedPackets(media_packets_, media_loss_mask, !kFecPacket); |
102 ReceivedPackets(generated_fec_packets_, fec_loss_mask, kFecPacket); | 102 ReceivedPackets(generated_fec_packets_, fec_loss_mask, kFecPacket); |
103 } | 103 } |
104 | 104 |
105 template <typename ForwardErrorCorrectionType> | 105 template <typename ForwardErrorCorrectionType> |
106 template <typename PacketListType> | 106 template <typename PacketListType> |
107 void RtpFecTest<ForwardErrorCorrectionType>::ReceivedPackets( | 107 void RtpFecTest<ForwardErrorCorrectionType>::ReceivedPackets( |
108 const PacketListType& packet_list, | 108 const PacketListType& packet_list, |
109 int* loss_mask, | 109 int* loss_mask, |
110 bool is_fec) { | 110 bool is_fec) { |
111 uint16_t fec_seq_num = media_packet_generator_.GetFecSeqNum(); | 111 uint16_t fec_seq_num = ForwardErrorCorrectionType::GetFirstFecSeqNum( |
| 112 media_packet_generator_.GetNextSeqNum()); |
112 int packet_idx = 0; | 113 int packet_idx = 0; |
113 | 114 |
114 for (const auto& packet : packet_list) { | 115 for (const auto& packet : packet_list) { |
115 if (loss_mask[packet_idx] == 0) { | 116 if (loss_mask[packet_idx] == 0) { |
116 std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet( | 117 std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet( |
117 new ForwardErrorCorrection::ReceivedPacket()); | 118 new ForwardErrorCorrection::ReceivedPacket()); |
118 received_packet->pkt = new ForwardErrorCorrection::Packet(); | 119 received_packet->pkt = new ForwardErrorCorrection::Packet(); |
119 received_packet->pkt->length = packet->length; | 120 received_packet->pkt->length = packet->length; |
120 memcpy(received_packet->pkt->data, packet->data, packet->length); | 121 memcpy(received_packet->pkt->data, packet->data, packet->length); |
121 received_packet->is_fec = is_fec; | 122 received_packet->is_fec = is_fec; |
122 if (!is_fec) { | 123 if (!is_fec) { |
123 // For media packets, the sequence number and marker bit is | 124 received_packet->ssrc = kMediaSsrc; |
124 // obtained from RTP header. These were set in ConstructMediaPackets(). | 125 // For media packets, the sequence number is obtained from the |
| 126 // RTP header as written by MediaPacketGenerator::ConstructMediaPackets. |
125 received_packet->seq_num = | 127 received_packet->seq_num = |
126 ByteReader<uint16_t>::ReadBigEndian(&packet->data[2]); | 128 ByteReader<uint16_t>::ReadBigEndian(&packet->data[2]); |
127 } else { | 129 } else { |
128 // The sequence number, marker bit, and ssrc number are defined in the | 130 received_packet->ssrc = ForwardErrorCorrectionType::kFecSsrc; |
129 // RTP header of the FEC packet, which is not constructed in this test. | 131 // For FEC packets, we simulate the sequence numbers differently |
130 // So we set these values below based on the values generated in | 132 // depending on if ULPFEC or FlexFEC is used. See the definition of |
131 // ConstructMediaPackets(). | 133 // ForwardErrorCorrectionType::GetFirstFecSeqNum. |
132 received_packet->seq_num = fec_seq_num; | 134 received_packet->seq_num = fec_seq_num; |
133 // The ssrc value for FEC packets is set to the one used for the | |
134 // media packets in ConstructMediaPackets(). | |
135 received_packet->ssrc = kMediaSsrc; | |
136 } | 135 } |
137 received_packets_.push_back(std::move(received_packet)); | 136 received_packets_.push_back(std::move(received_packet)); |
138 } | 137 } |
139 packet_idx++; | 138 packet_idx++; |
140 // Sequence number of FEC packets are defined as increment by 1 from | 139 // Sequence number of FEC packets are defined as increment by 1 from |
141 // last media packet in frame. | 140 // last media packet in frame. |
142 if (is_fec) | 141 if (is_fec) |
143 fec_seq_num++; | 142 fec_seq_num++; |
144 } | 143 } |
145 } | 144 } |
(...skipping 24 matching lines...) Expand all Loading... |
170 recovered_packets_.cbegin(), cmp); | 169 recovered_packets_.cbegin(), cmp); |
171 } | 170 } |
172 | 171 |
173 // Define gTest typed test to loop over both ULPFEC and FlexFEC. | 172 // Define gTest typed test to loop over both ULPFEC and FlexFEC. |
174 // Since the tests now are parameterized, we need to access | 173 // Since the tests now are parameterized, we need to access |
175 // member variables using |this|, thereby enforcing runtime | 174 // member variables using |this|, thereby enforcing runtime |
176 // resolution. | 175 // resolution. |
177 | 176 |
178 class FlexfecForwardErrorCorrection : public ForwardErrorCorrection { | 177 class FlexfecForwardErrorCorrection : public ForwardErrorCorrection { |
179 public: | 178 public: |
| 179 static const uint32_t kFecSsrc = kFlexfecSsrc; |
| 180 |
180 FlexfecForwardErrorCorrection() | 181 FlexfecForwardErrorCorrection() |
181 : ForwardErrorCorrection( | 182 : ForwardErrorCorrection( |
182 std::unique_ptr<FecHeaderReader>(new FlexfecHeaderReader()), | 183 std::unique_ptr<FecHeaderReader>(new FlexfecHeaderReader()), |
183 std::unique_ptr<FecHeaderWriter>(new FlexfecHeaderWriter())) {} | 184 std::unique_ptr<FecHeaderWriter>(new FlexfecHeaderWriter()), |
| 185 kFecSsrc, |
| 186 kMediaSsrc) {} |
| 187 |
| 188 // For FlexFEC we let the FEC packet sequence numbers be independent of |
| 189 // the media packet sequence numbers. |
| 190 static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) { |
| 191 Random random(0xbe110); |
| 192 return random.Rand<uint16_t>(); |
| 193 } |
184 }; | 194 }; |
185 | 195 |
186 class UlpfecForwardErrorCorrection : public ForwardErrorCorrection { | 196 class UlpfecForwardErrorCorrection : public ForwardErrorCorrection { |
187 public: | 197 public: |
| 198 static const uint32_t kFecSsrc = kMediaSsrc; |
| 199 |
188 UlpfecForwardErrorCorrection() | 200 UlpfecForwardErrorCorrection() |
189 : ForwardErrorCorrection( | 201 : ForwardErrorCorrection( |
190 std::unique_ptr<FecHeaderReader>(new UlpfecHeaderReader()), | 202 std::unique_ptr<FecHeaderReader>(new UlpfecHeaderReader()), |
191 std::unique_ptr<FecHeaderWriter>(new UlpfecHeaderWriter())) {} | 203 std::unique_ptr<FecHeaderWriter>(new UlpfecHeaderWriter()), |
| 204 kFecSsrc, |
| 205 kMediaSsrc) {} |
| 206 |
| 207 // For ULPFEC we assume that the FEC packets are subsequent to the media |
| 208 // packets in terms of sequence number. |
| 209 static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) { |
| 210 return next_media_seq_num; |
| 211 } |
192 }; | 212 }; |
193 | 213 |
194 using FecTypes = | 214 using FecTypes = |
195 Types<FlexfecForwardErrorCorrection, UlpfecForwardErrorCorrection>; | 215 Types<FlexfecForwardErrorCorrection, UlpfecForwardErrorCorrection>; |
196 TYPED_TEST_CASE(RtpFecTest, FecTypes); | 216 TYPED_TEST_CASE(RtpFecTest, FecTypes); |
197 | 217 |
198 TYPED_TEST(RtpFecTest, FecRecoveryNoLoss) { | 218 TYPED_TEST(RtpFecTest, FecRecoveryNoLoss) { |
199 constexpr int kNumImportantPackets = 0; | 219 constexpr int kNumImportantPackets = 0; |
200 constexpr bool kUseUnequalProtection = false; | 220 constexpr bool kUseUnequalProtection = false; |
201 constexpr int kNumMediaPackets = 4; | 221 constexpr int kNumMediaPackets = 4; |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
352 | 372 |
353 EXPECT_EQ(0, this->fec_.DecodeFec(&this->received_packets_, | 373 EXPECT_EQ(0, this->fec_.DecodeFec(&this->received_packets_, |
354 &this->recovered_packets_)); | 374 &this->recovered_packets_)); |
355 | 375 |
356 // Expect 3 media packets in recovered list, and complete recovery. | 376 // Expect 3 media packets in recovered list, and complete recovery. |
357 // Wrap-around won't remove FEC packet, as it follows the wrap. | 377 // Wrap-around won't remove FEC packet, as it follows the wrap. |
358 EXPECT_EQ(3u, this->recovered_packets_.size()); | 378 EXPECT_EQ(3u, this->recovered_packets_.size()); |
359 EXPECT_TRUE(this->IsRecoveryComplete()); | 379 EXPECT_TRUE(this->IsRecoveryComplete()); |
360 } | 380 } |
361 | 381 |
362 // Sequence number wrap occurs within the FEC packets for the frame. | 382 // Sequence number wrap occurs within the ULPFEC packets for the frame. |
363 // In this case we will discard FEC packet and full recovery is not expected. | 383 // In this case we will discard ULPFEC packet and full recovery is not expected. |
364 // Same problem will occur if wrap is within media packets but FEC packet is | 384 // Same problem will occur if wrap is within media packets but ULPFEC packet is |
365 // received before the media packets. This may be improved if timing information | 385 // received before the media packets. This may be improved if timing information |
366 // is used to detect old FEC packets. | 386 // is used to detect old ULPFEC packets. |
367 // TODO(marpan): Update test if wrap-around handling changes in FEC decoding. | 387 // TODO(marpan): Update test if wrap-around handling changes in FEC decoding. |
368 TYPED_TEST(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameNoRecovery) { | 388 using RtpFecTestUlpfecOnly = RtpFecTest<UlpfecForwardErrorCorrection>; |
| 389 TEST_F(RtpFecTestUlpfecOnly, FecRecoveryWithSeqNumGapOneFrameNoRecovery) { |
369 constexpr int kNumImportantPackets = 0; | 390 constexpr int kNumImportantPackets = 0; |
370 constexpr bool kUseUnequalProtection = false; | 391 constexpr bool kUseUnequalProtection = false; |
371 constexpr uint8_t kProtectionFactor = 200; | 392 constexpr uint8_t kProtectionFactor = 200; |
372 | 393 |
373 // 1 frame: 3 media packets and 2 FEC packets. | 394 // 1 frame: 3 media packets and 2 FEC packets. |
374 // Sequence number wrap in FEC packets. | 395 // Sequence number wrap in FEC packets. |
375 // -----Frame 1---- | 396 // -----Frame 1---- |
376 // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC). | 397 // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC). |
377 this->media_packets_ = | 398 this->media_packets_ = |
378 this->media_packet_generator_.ConstructMediaPackets(3, 65532); | 399 this->media_packet_generator_.ConstructMediaPackets(3, 65532); |
(...skipping 12 matching lines...) Expand all Loading... |
391 this->media_loss_mask_[1] = 1; | 412 this->media_loss_mask_[1] = 1; |
392 this->media_loss_mask_[2] = 1; | 413 this->media_loss_mask_[2] = 1; |
393 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); | 414 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); |
394 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, | 415 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, |
395 true); | 416 true); |
396 | 417 |
397 EXPECT_EQ(0, this->fec_.DecodeFec(&this->received_packets_, | 418 EXPECT_EQ(0, this->fec_.DecodeFec(&this->received_packets_, |
398 &this->recovered_packets_)); | 419 &this->recovered_packets_)); |
399 | 420 |
400 // The two FEC packets are received and should allow for complete recovery, | 421 // The two FEC packets are received and should allow for complete recovery, |
401 // but because of the wrap the second FEC packet will be discarded, and only | 422 // but because of the wrap the first FEC packet will be discarded, and only |
402 // one media packet is recoverable. So exepct 2 media packets on recovered | 423 // one media packet is recoverable. So expect 2 media packets on recovered |
403 // list and no complete recovery. | 424 // list and no complete recovery. |
404 EXPECT_EQ(2u, this->recovered_packets_.size()); | 425 EXPECT_EQ(2u, this->recovered_packets_.size()); |
405 EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size()); | 426 EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size()); |
| 427 EXPECT_FALSE(this->IsRecoveryComplete()); |
| 428 } |
| 429 |
| 430 // TODO(brandtr): This test mimics the one above, ensuring that the recovery |
| 431 // strategy of FlexFEC matches the recovery strategy of ULPFEC. Since FlexFEC |
| 432 // does not share the sequence number space with the media, however, having a |
| 433 // matching recovery strategy may be suboptimal. Study this further. |
| 434 using RtpFecTestFlexfecOnly = RtpFecTest<FlexfecForwardErrorCorrection>; |
| 435 TEST_F(RtpFecTestFlexfecOnly, FecRecoveryWithSeqNumGapOneFrameNoRecovery) { |
| 436 constexpr int kNumImportantPackets = 0; |
| 437 constexpr bool kUseUnequalProtection = false; |
| 438 constexpr uint8_t kProtectionFactor = 200; |
| 439 |
| 440 // 1 frame: 3 media packets and 2 FEC packets. |
| 441 // Sequence number wrap in FEC packets. |
| 442 // -----Frame 1---- |
| 443 // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC). |
| 444 this->media_packets_ = |
| 445 this->media_packet_generator_.ConstructMediaPackets(3, 65532); |
| 446 |
| 447 EXPECT_EQ( |
| 448 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, |
| 449 kNumImportantPackets, kUseUnequalProtection, |
| 450 kFecMaskBursty, &this->generated_fec_packets_)); |
| 451 |
| 452 // Expect 2 FEC packets. |
| 453 EXPECT_EQ(2u, this->generated_fec_packets_.size()); |
| 454 |
| 455 // Overwrite the sequence numbers generated by ConstructMediaPackets, |
| 456 // to make sure that we do have a wrap. |
| 457 auto it = this->generated_fec_packets_.begin(); |
| 458 ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data[2], 65535); |
| 459 ++it; |
| 460 ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data[2], 0); |
| 461 |
| 462 // Lose the last two media packets (seq# 65533, 65534). |
| 463 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); |
| 464 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); |
| 465 this->media_loss_mask_[1] = 1; |
| 466 this->media_loss_mask_[2] = 1; |
| 467 this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); |
| 468 this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, |
| 469 true); |
| 470 |
| 471 EXPECT_EQ(0, this->fec_.DecodeFec(&this->received_packets_, |
| 472 &this->recovered_packets_)); |
| 473 |
| 474 // The two FEC packets are received and should allow for complete recovery, |
| 475 // but because of the wrap the first FEC packet will be discarded, and only |
| 476 // one media packet is recoverable. So expect 2 media packets on recovered |
| 477 // list and no complete recovery. |
| 478 EXPECT_EQ(2u, this->recovered_packets_.size()); |
| 479 EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size()); |
406 EXPECT_FALSE(this->IsRecoveryComplete()); | 480 EXPECT_FALSE(this->IsRecoveryComplete()); |
407 } | 481 } |
408 | 482 |
409 // Verify we can still recover frame if media packets are reordered. | 483 // Verify we can still recover frame if media packets are reordered. |
410 TYPED_TEST(RtpFecTest, FecRecoveryWithMediaOutOfOrder) { | 484 TYPED_TEST(RtpFecTest, FecRecoveryWithMediaOutOfOrder) { |
411 constexpr int kNumImportantPackets = 0; | 485 constexpr int kNumImportantPackets = 0; |
412 constexpr bool kUseUnequalProtection = false; | 486 constexpr bool kUseUnequalProtection = false; |
413 constexpr uint8_t kProtectionFactor = 20; | 487 constexpr uint8_t kProtectionFactor = 20; |
414 | 488 |
415 // One frame: 3 media packets, 1 FEC packet. | 489 // One frame: 3 media packets, 1 FEC packet. |
(...skipping 11 matching lines...) Expand all Loading... |
427 EXPECT_EQ(1u, this->generated_fec_packets_.size()); | 501 EXPECT_EQ(1u, this->generated_fec_packets_.size()); |
428 | 502 |
429 // Lose one media packet (seq# 1). | 503 // Lose one media packet (seq# 1). |
430 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); | 504 memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); |
431 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); | 505 memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); |
432 this->media_loss_mask_[1] = 1; | 506 this->media_loss_mask_[1] = 1; |
433 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); | 507 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); |
434 | 508 |
435 // Reorder received media packets. | 509 // Reorder received media packets. |
436 auto it0 = this->received_packets_.begin(); | 510 auto it0 = this->received_packets_.begin(); |
437 auto it2 = this->received_packets_.begin(); | 511 auto it1 = this->received_packets_.begin(); |
438 it2++; | 512 it1++; |
439 std::swap(*it0, *it2); | 513 std::swap(*it0, *it1); |
440 | 514 |
441 EXPECT_EQ(0, this->fec_.DecodeFec(&this->received_packets_, | 515 EXPECT_EQ(0, this->fec_.DecodeFec(&this->received_packets_, |
442 &this->recovered_packets_)); | 516 &this->recovered_packets_)); |
443 | 517 |
444 // Expect 3 media packets in recovered list, and complete recovery. | 518 // Expect 3 media packets in recovered list, and complete recovery. |
445 EXPECT_EQ(3u, this->recovered_packets_.size()); | 519 EXPECT_EQ(3u, this->recovered_packets_.size()); |
446 EXPECT_TRUE(this->IsRecoveryComplete()); | 520 EXPECT_TRUE(this->IsRecoveryComplete()); |
447 } | 521 } |
448 | 522 |
449 // Verify we can still recover frame if FEC is received before media packets. | 523 // Verify we can still recover frame if FEC is received before media packets. |
(...skipping 501 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
951 this->media_loss_mask_[kNumMediaPackets - 1] = 1; | 1025 this->media_loss_mask_[kNumMediaPackets - 1] = 1; |
952 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); | 1026 this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); |
953 | 1027 |
954 EXPECT_EQ(0, this->fec_.DecodeFec(&this->received_packets_, | 1028 EXPECT_EQ(0, this->fec_.DecodeFec(&this->received_packets_, |
955 &this->recovered_packets_)); | 1029 &this->recovered_packets_)); |
956 | 1030 |
957 // 5 protected packets lost, one FEC packet, cannot get complete recovery. | 1031 // 5 protected packets lost, one FEC packet, cannot get complete recovery. |
958 EXPECT_FALSE(this->IsRecoveryComplete()); | 1032 EXPECT_FALSE(this->IsRecoveryComplete()); |
959 } | 1033 } |
960 | 1034 |
961 // 'using' directive needed for compiler to be happy. | |
962 using RtpFecTestWithFlexfec = RtpFecTest<FlexfecForwardErrorCorrection>; | |
963 TEST_F(RtpFecTestWithFlexfec, | |
964 FecRecoveryWithLossAndDifferentMediaAndFlexfecSsrcs) { | |
965 constexpr int kNumImportantPackets = 0; | |
966 constexpr bool kUseUnequalProtection = false; | |
967 constexpr int kNumMediaPackets = 4; | |
968 constexpr uint8_t kProtectionFactor = 60; | |
969 | |
970 media_packets_ = | |
971 media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); | |
972 | |
973 EXPECT_EQ(0, fec_.EncodeFec(media_packets_, kProtectionFactor, | |
974 kNumImportantPackets, kUseUnequalProtection, | |
975 kFecMaskBursty, &generated_fec_packets_)); | |
976 | |
977 // Expect 1 FEC packet. | |
978 EXPECT_EQ(1u, generated_fec_packets_.size()); | |
979 | |
980 // 1 media packet lost | |
981 memset(media_loss_mask_, 0, sizeof(media_loss_mask_)); | |
982 memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_)); | |
983 media_loss_mask_[3] = 1; | |
984 NetworkReceivedPackets(media_loss_mask_, fec_loss_mask_); | |
985 | |
986 // Simulate FlexFEC packet received on different SSRC. | |
987 auto it = received_packets_.begin(); | |
988 ++it; | |
989 ++it; | |
990 ++it; // Now at the FEC packet. | |
991 (*it)->ssrc = kFlexfecSsrc; | |
992 | |
993 EXPECT_EQ(0, fec_.DecodeFec(&received_packets_, &recovered_packets_)); | |
994 | |
995 // One packet lost, one FEC packet, expect complete recovery. | |
996 EXPECT_TRUE(IsRecoveryComplete()); | |
997 } | |
998 | |
999 } // namespace webrtc | 1035 } // namespace webrtc |
OLD | NEW |