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