| Index: webrtc/modules/rtp_rtcp/source/rtp_fec_unittest.cc
|
| diff --git a/webrtc/modules/rtp_rtcp/source/rtp_fec_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_fec_unittest.cc
|
| index a1c60c8d1622c629f453e1121f7bd540691f0220..11b6849ef012d09bb6b53f62ebf2972c3cceb135 100644
|
| --- a/webrtc/modules/rtp_rtcp/source/rtp_fec_unittest.cc
|
| +++ b/webrtc/modules/rtp_rtcp/source/rtp_fec_unittest.cc
|
| @@ -108,7 +108,8 @@ void RtpFecTest<ForwardErrorCorrectionType>::ReceivedPackets(
|
| const PacketListType& packet_list,
|
| int* loss_mask,
|
| bool is_fec) {
|
| - uint16_t fec_seq_num = media_packet_generator_.GetFecSeqNum();
|
| + uint16_t fec_seq_num = ForwardErrorCorrectionType::GetFirstFecSeqNum(
|
| + media_packet_generator_.GetNextSeqNum());
|
| int packet_idx = 0;
|
|
|
| for (const auto& packet : packet_list) {
|
| @@ -120,19 +121,17 @@ void RtpFecTest<ForwardErrorCorrectionType>::ReceivedPackets(
|
| memcpy(received_packet->pkt->data, packet->data, packet->length);
|
| received_packet->is_fec = is_fec;
|
| if (!is_fec) {
|
| - // For media packets, the sequence number and marker bit is
|
| - // obtained from RTP header. These were set in ConstructMediaPackets().
|
| + received_packet->ssrc = kMediaSsrc;
|
| + // For media packets, the sequence number is obtained from the
|
| + // RTP header as written by MediaPacketGenerator::ConstructMediaPackets.
|
| received_packet->seq_num =
|
| ByteReader<uint16_t>::ReadBigEndian(&packet->data[2]);
|
| } else {
|
| - // The sequence number, marker bit, and ssrc number are defined in the
|
| - // RTP header of the FEC packet, which is not constructed in this test.
|
| - // So we set these values below based on the values generated in
|
| - // ConstructMediaPackets().
|
| + received_packet->ssrc = ForwardErrorCorrectionType::kFecSsrc;
|
| + // For FEC packets, we simulate the sequence numbers differently
|
| + // depending on if ULPFEC or FlexFEC is used. See the definition of
|
| + // ForwardErrorCorrectionType::GetFirstFecSeqNum.
|
| received_packet->seq_num = fec_seq_num;
|
| - // The ssrc value for FEC packets is set to the one used for the
|
| - // media packets in ConstructMediaPackets().
|
| - received_packet->ssrc = kMediaSsrc;
|
| }
|
| received_packets_.push_back(std::move(received_packet));
|
| }
|
| @@ -177,18 +176,39 @@ bool RtpFecTest<ForwardErrorCorrectionType>::IsRecoveryComplete() {
|
|
|
| class FlexfecForwardErrorCorrection : public ForwardErrorCorrection {
|
| public:
|
| + static const uint32_t kFecSsrc = kFlexfecSsrc;
|
| +
|
| FlexfecForwardErrorCorrection()
|
| : ForwardErrorCorrection(
|
| std::unique_ptr<FecHeaderReader>(new FlexfecHeaderReader()),
|
| - std::unique_ptr<FecHeaderWriter>(new FlexfecHeaderWriter())) {}
|
| + std::unique_ptr<FecHeaderWriter>(new FlexfecHeaderWriter()),
|
| + kFecSsrc,
|
| + kMediaSsrc) {}
|
| +
|
| + // For FlexFEC we let the FEC packet sequence numbers be independent of
|
| + // the media packet sequence numbers.
|
| + static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) {
|
| + Random random(0xbe110);
|
| + return random.Rand<uint16_t>();
|
| + }
|
| };
|
|
|
| class UlpfecForwardErrorCorrection : public ForwardErrorCorrection {
|
| public:
|
| + static const uint32_t kFecSsrc = kMediaSsrc;
|
| +
|
| UlpfecForwardErrorCorrection()
|
| : ForwardErrorCorrection(
|
| std::unique_ptr<FecHeaderReader>(new UlpfecHeaderReader()),
|
| - std::unique_ptr<FecHeaderWriter>(new UlpfecHeaderWriter())) {}
|
| + std::unique_ptr<FecHeaderWriter>(new UlpfecHeaderWriter()),
|
| + kFecSsrc,
|
| + kMediaSsrc) {}
|
| +
|
| + // For ULPFEC we assume that the FEC packets are subsequent to the media
|
| + // packets in terms of sequence number.
|
| + static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) {
|
| + return next_media_seq_num;
|
| + }
|
| };
|
|
|
| using FecTypes =
|
| @@ -359,13 +379,14 @@ TYPED_TEST(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameRecovery) {
|
| EXPECT_TRUE(this->IsRecoveryComplete());
|
| }
|
|
|
| -// Sequence number wrap occurs within the FEC packets for the frame.
|
| -// In this case we will discard FEC packet and full recovery is not expected.
|
| -// Same problem will occur if wrap is within media packets but FEC packet is
|
| +// Sequence number wrap occurs within the ULPFEC packets for the frame.
|
| +// In this case we will discard ULPFEC packet and full recovery is not expected.
|
| +// Same problem will occur if wrap is within media packets but ULPFEC packet is
|
| // received before the media packets. This may be improved if timing information
|
| -// is used to detect old FEC packets.
|
| +// is used to detect old ULPFEC packets.
|
| // TODO(marpan): Update test if wrap-around handling changes in FEC decoding.
|
| -TYPED_TEST(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameNoRecovery) {
|
| +using RtpFecTestUlpfecOnly = RtpFecTest<UlpfecForwardErrorCorrection>;
|
| +TEST_F(RtpFecTestUlpfecOnly, FecRecoveryWithSeqNumGapOneFrameNoRecovery) {
|
| constexpr int kNumImportantPackets = 0;
|
| constexpr bool kUseUnequalProtection = false;
|
| constexpr uint8_t kProtectionFactor = 200;
|
| @@ -398,8 +419,61 @@ TYPED_TEST(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameNoRecovery) {
|
| &this->recovered_packets_));
|
|
|
| // The two FEC packets are received and should allow for complete recovery,
|
| - // but because of the wrap the second FEC packet will be discarded, and only
|
| - // one media packet is recoverable. So exepct 2 media packets on recovered
|
| + // but because of the wrap the first FEC packet will be discarded, and only
|
| + // one media packet is recoverable. So expect 2 media packets on recovered
|
| + // list and no complete recovery.
|
| + EXPECT_EQ(2u, this->recovered_packets_.size());
|
| + EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size());
|
| + EXPECT_FALSE(this->IsRecoveryComplete());
|
| +}
|
| +
|
| +// TODO(brandtr): This test mimics the one above, ensuring that the recovery
|
| +// strategy of FlexFEC matches the recovery strategy of ULPFEC. Since FlexFEC
|
| +// does not share the sequence number space with the media, however, having a
|
| +// matching recovery strategy may be suboptimal. Study this further.
|
| +using RtpFecTestFlexfecOnly = RtpFecTest<FlexfecForwardErrorCorrection>;
|
| +TEST_F(RtpFecTestFlexfecOnly, FecRecoveryWithSeqNumGapOneFrameNoRecovery) {
|
| + constexpr int kNumImportantPackets = 0;
|
| + constexpr bool kUseUnequalProtection = false;
|
| + constexpr uint8_t kProtectionFactor = 200;
|
| +
|
| + // 1 frame: 3 media packets and 2 FEC packets.
|
| + // Sequence number wrap in FEC packets.
|
| + // -----Frame 1----
|
| + // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC).
|
| + this->media_packets_ =
|
| + this->media_packet_generator_.ConstructMediaPackets(3, 65532);
|
| +
|
| + EXPECT_EQ(
|
| + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
|
| + kNumImportantPackets, kUseUnequalProtection,
|
| + kFecMaskBursty, &this->generated_fec_packets_));
|
| +
|
| + // Expect 2 FEC packets.
|
| + EXPECT_EQ(2u, this->generated_fec_packets_.size());
|
| +
|
| + // Overwrite the sequence numbers generated by ConstructMediaPackets,
|
| + // to make sure that we do have a wrap.
|
| + auto it = this->generated_fec_packets_.begin();
|
| + ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data[2], 65535);
|
| + ++it;
|
| + ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data[2], 0);
|
| +
|
| + // Lose the last two media packets (seq# 65533, 65534).
|
| + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
|
| + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
|
| + this->media_loss_mask_[1] = 1;
|
| + this->media_loss_mask_[2] = 1;
|
| + this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
|
| + this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
|
| + true);
|
| +
|
| + EXPECT_EQ(0, this->fec_.DecodeFec(&this->received_packets_,
|
| + &this->recovered_packets_));
|
| +
|
| + // The two FEC packets are received and should allow for complete recovery,
|
| + // but because of the wrap the first FEC packet will be discarded, and only
|
| + // one media packet is recoverable. So expect 2 media packets on recovered
|
| // list and no complete recovery.
|
| EXPECT_EQ(2u, this->recovered_packets_.size());
|
| EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size());
|
| @@ -434,9 +508,9 @@ TYPED_TEST(RtpFecTest, FecRecoveryWithMediaOutOfOrder) {
|
|
|
| // Reorder received media packets.
|
| auto it0 = this->received_packets_.begin();
|
| - auto it2 = this->received_packets_.begin();
|
| - it2++;
|
| - std::swap(*it0, *it2);
|
| + auto it1 = this->received_packets_.begin();
|
| + it1++;
|
| + std::swap(*it0, *it1);
|
|
|
| EXPECT_EQ(0, this->fec_.DecodeFec(&this->received_packets_,
|
| &this->recovered_packets_));
|
| @@ -958,42 +1032,4 @@ TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
|
| EXPECT_FALSE(this->IsRecoveryComplete());
|
| }
|
|
|
| -// 'using' directive needed for compiler to be happy.
|
| -using RtpFecTestWithFlexfec = RtpFecTest<FlexfecForwardErrorCorrection>;
|
| -TEST_F(RtpFecTestWithFlexfec,
|
| - FecRecoveryWithLossAndDifferentMediaAndFlexfecSsrcs) {
|
| - constexpr int kNumImportantPackets = 0;
|
| - constexpr bool kUseUnequalProtection = false;
|
| - constexpr int kNumMediaPackets = 4;
|
| - constexpr uint8_t kProtectionFactor = 60;
|
| -
|
| - media_packets_ =
|
| - media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
|
| -
|
| - EXPECT_EQ(0, fec_.EncodeFec(media_packets_, kProtectionFactor,
|
| - kNumImportantPackets, kUseUnequalProtection,
|
| - kFecMaskBursty, &generated_fec_packets_));
|
| -
|
| - // Expect 1 FEC packet.
|
| - EXPECT_EQ(1u, generated_fec_packets_.size());
|
| -
|
| - // 1 media packet lost
|
| - memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
| - memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
| - media_loss_mask_[3] = 1;
|
| - NetworkReceivedPackets(media_loss_mask_, fec_loss_mask_);
|
| -
|
| - // Simulate FlexFEC packet received on different SSRC.
|
| - auto it = received_packets_.begin();
|
| - ++it;
|
| - ++it;
|
| - ++it; // Now at the FEC packet.
|
| - (*it)->ssrc = kFlexfecSsrc;
|
| -
|
| - EXPECT_EQ(0, fec_.DecodeFec(&received_packets_, &recovered_packets_));
|
| -
|
| - // One packet lost, one FEC packet, expect complete recovery.
|
| - EXPECT_TRUE(IsRecoveryComplete());
|
| -}
|
| -
|
| } // namespace webrtc
|
|
|