Only compare sequence numbers from the same SSRC in ForwardErrorCorrection.

Prior to this CL, the ForwardErrorCorrection state would be reset whenever
the difference in sequence numbers of the last recovered media packet
and the new packet (media or FEC) was too large. This comparison did not
take into account that FlexFEC uses a different SSRC for the FEC packets,
meaning that the the state would be reset very frequently when FlexFEC
is used. This should not have led to any major problems, except for a
decreased decoding efficiency.

This CL verifies that whenever we compare sequence numbers in
ForwardErrorCorrection, they do indeed belong to the same SSRC.

BUG=webrtc:5654

Review-Url: https://codereview.webrtc.org/2893293003
Cr-Commit-Position: refs/heads/master@{#18399}
This commit is contained in:
brandtr 2017-06-02 00:58:11 -07:00 committed by Commit Bot
parent cbd3ee3e77
commit 1476a9d789
7 changed files with 194 additions and 110 deletions

View File

@ -78,7 +78,7 @@ ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets(
RTC_DCHECK(media_packet);
media_packet->data[1] |= 0x80;
fec_seq_num_ = seq_num;
next_seq_num_ = seq_num;
return media_packets;
}
@ -88,8 +88,8 @@ ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets(
return ConstructMediaPackets(num_media_packets, random_->Rand<uint16_t>());
}
uint16_t MediaPacketGenerator::GetFecSeqNum() {
return fec_seq_num_;
uint16_t MediaPacketGenerator::GetNextSeqNum() {
return next_seq_num_;
}
AugmentedPacketGenerator::AugmentedPacketGenerator(uint32_t ssrc)

View File

@ -49,7 +49,7 @@ class MediaPacketGenerator {
ForwardErrorCorrection::PacketList ConstructMediaPackets(
int num_media_packets);
uint16_t GetFecSeqNum();
uint16_t GetNextSeqNum();
private:
uint32_t min_packet_size_;
@ -58,7 +58,7 @@ class MediaPacketGenerator {
Random* random_;
ForwardErrorCorrection::PacketList media_packets_;
uint16_t fec_seq_num_;
uint16_t next_seq_num_;
};
// This class generates media packets with a certain structure of the payload.

View File

@ -54,6 +54,11 @@ template <typename S, typename T>
bool ForwardErrorCorrection::SortablePacket::LessThan::operator() (
const S& first,
const T& second) {
// TODO(brandtr): Try to add a DCHECK here, verifying that
// first->ssrc == second->ssrc. Currently, it is hard to do so
// because we are unable to reliably set the ssrc member on the
// ProtectedPacket's. These always belong to the media SSRC, but
// we may not know the media SSRC when they are created.
return IsNewerSequenceNumber(second->seq_num, first->seq_num);
}
@ -337,6 +342,7 @@ void ForwardErrorCorrection::InsertMediaPacket(
ReceivedPacket* received_packet) {
// Search for duplicate packets.
for (const auto& recovered_packet : *recovered_packets) {
RTC_DCHECK_EQ(received_packet->ssrc, recovered_packet->ssrc);
if (received_packet->seq_num == recovered_packet->seq_num) {
// Duplicate packet, no need to add to list.
// Delete duplicate media packet data.
@ -349,6 +355,7 @@ void ForwardErrorCorrection::InsertMediaPacket(
recovered_packet->was_recovered = false;
// This media packet has already been passed on.
recovered_packet->returned = true;
recovered_packet->ssrc = received_packet->ssrc;
recovered_packet->seq_num = received_packet->seq_num;
recovered_packet->pkt = received_packet->pkt;
recovered_packet->pkt->length = received_packet->pkt->length;
@ -380,6 +387,7 @@ void ForwardErrorCorrection::InsertFecPacket(
ReceivedPacket* received_packet) {
// Check for duplicate.
for (const auto& existing_fec_packet : received_fec_packets_) {
RTC_DCHECK_EQ(received_packet->ssrc, existing_fec_packet->ssrc);
if (received_packet->seq_num == existing_fec_packet->seq_num) {
// Delete duplicate FEC packet data.
received_packet->pkt = nullptr;
@ -388,8 +396,8 @@ void ForwardErrorCorrection::InsertFecPacket(
}
std::unique_ptr<ReceivedFecPacket> fec_packet(new ReceivedFecPacket());
fec_packet->pkt = received_packet->pkt;
fec_packet->seq_num = received_packet->seq_num;
fec_packet->ssrc = received_packet->ssrc;
fec_packet->seq_num = received_packet->seq_num;
// Parse ULPFEC/FlexFEC header specific info.
bool ret = fec_header_reader_->ReadFecHeader(fec_packet.get());
if (!ret) {
@ -419,11 +427,6 @@ void ForwardErrorCorrection::InsertFecPacket(
AssignRecoveredPackets(recovered_packets, fec_packet.get());
// TODO(holmer): Consider replacing this with a binary search for the right
// position, and then just insert the new packet. Would get rid of the sort.
//
// For correct decoding, |received_fec_packets_| does not necessarily
// need to be sorted by sequence number (see decoding algorithm in
// AttemptRecover()). By keeping it sorted we try to recover the
// oldest lost packets first, however.
received_fec_packets_.push_back(std::move(fec_packet));
received_fec_packets_.sort(SortablePacket::LessThan());
const size_t max_fec_packets = fec_header_reader_->MaxFecPackets();
@ -467,19 +470,31 @@ void ForwardErrorCorrection::InsertPackets(
while (!received_packets->empty()) {
ReceivedPacket* received_packet = received_packets->front().get();
// Check for discarding oldest FEC packet, to avoid wrong FEC decoding from
// sequence number wrap-around. Detection of old FEC packet is based on
// sequence number difference of received packet and oldest packet in FEC
// packet list.
// Discard old FEC packets such that the sequence numbers in
// |received_fec_packets_| span at most 1/2 of the sequence number space.
// This is important for keeping |received_fec_packets_| sorted, and may
// also reduce the possibility of incorrect decoding due to sequence number
// wrap-around.
// TODO(marpan/holmer): We should be able to improve detection/discarding of
// old FEC packets based on timestamp information or better sequence number
// thresholding (e.g., to distinguish between wrap-around and reordering).
if (!received_fec_packets_.empty()) {
uint16_t seq_num_diff =
abs(static_cast<int>(received_packet->seq_num) -
static_cast<int>(received_fec_packets_.front()->seq_num));
if (seq_num_diff > 0x3fff) {
received_fec_packets_.pop_front();
if (!received_fec_packets_.empty() &&
received_packet->ssrc == received_fec_packets_.front()->ssrc) {
// It only makes sense to detect wrap-around when |received_packet|
// and |front_received_fec_packet| belong to the same sequence number
// space, i.e., the same SSRC. This happens when |received_packet|
// is a FEC packet, or if |received_packet| is a media packet and
// RED+ULPFEC is used.
auto it = received_fec_packets_.begin();
while (it != received_fec_packets_.end()) {
uint16_t seq_num_diff = abs(static_cast<int>(received_packet->seq_num) -
static_cast<int>((*it)->seq_num));
if (seq_num_diff > 0x3fff) {
it = received_fec_packets_.erase(it);
} else {
// No need to keep iterating, since |received_fec_packets_| is sorted.
break;
}
}
}
@ -549,6 +564,7 @@ bool ForwardErrorCorrection::FinishPacketRecovery(
// Set the SSRC field.
ByteWriter<uint32_t>::WriteBigEndian(&recovered_packet->pkt->data[8],
fec_packet.protected_ssrc);
recovered_packet->ssrc = fec_packet.protected_ssrc;
return true;
}
@ -684,21 +700,34 @@ uint32_t ForwardErrorCorrection::ParseSsrc(uint8_t* packet) {
int ForwardErrorCorrection::DecodeFec(
ReceivedPacketList* received_packets,
RecoveredPacketList* recovered_packets) {
// TODO(marpan/ajm): can we check for multiple ULP headers, and return an
// error?
RTC_DCHECK(received_packets);
RTC_DCHECK(recovered_packets);
const size_t max_media_packets = fec_header_reader_->MaxMediaPackets();
if (recovered_packets->size() == max_media_packets) {
const unsigned int seq_num_diff =
abs(static_cast<int>(received_packets->front()->seq_num) -
static_cast<int>(recovered_packets->back()->seq_num));
if (seq_num_diff > max_media_packets) {
// A big gap in sequence numbers. The old recovered packets
// are now useless, so it's safe to do a reset.
ResetState(recovered_packets);
const RecoveredPacket* back_recovered_packet =
recovered_packets->back().get();
for (const auto& received_packet : *received_packets) {
if (received_packet->ssrc == back_recovered_packet->ssrc) {
const unsigned int seq_num_diff =
abs(static_cast<int>(received_packet->seq_num) -
static_cast<int>(back_recovered_packet->seq_num));
if (seq_num_diff > max_media_packets) {
// A big gap in sequence numbers. The old recovered packets
// are now useless, so it's safe to do a reset.
LOG(LS_INFO) << "Big gap in media/ULPFEC sequence numbers. No need "
"to keep the old packets in the FEC buffers, thus "
"resetting them.";
ResetState(recovered_packets);
break;
}
}
}
}
InsertPackets(received_packets, recovered_packets);
AttemptRecovery(recovered_packets);
return 0;
}

View File

@ -62,29 +62,25 @@ class ForwardErrorCorrection {
class SortablePacket {
public:
// Functor which returns true if the sequence number of |first|
// is < the sequence number of |second|.
// is < the sequence number of |second|. Should only ever be called for
// packets belonging to the same SSRC.
struct LessThan {
template <typename S, typename T>
bool operator() (const S& first, const T& second);
};
uint32_t ssrc;
uint16_t seq_num;
};
// The received list parameter of DecodeFec() references structs of this type.
//
// The ssrc member is needed to ensure that we can restore the SSRC field of
// recovered packets. In most situations this could be retrieved from other
// media packets, but in the case of an FEC packet protecting a single
// missing media packet, we have no other means of obtaining it.
// TODO(holmer): Refactor into a proper class.
class ReceivedPacket : public SortablePacket {
public:
ReceivedPacket();
~ReceivedPacket();
uint32_t ssrc; // SSRC of the current frame. Must be set for FEC
// packets, but not required for media packets.
bool is_fec; // Set to true if this is an FEC packet and false
// otherwise.
rtc::scoped_refptr<Packet> pkt; // Pointer to the packet storage.
@ -109,7 +105,7 @@ class ForwardErrorCorrection {
// Used to link media packets to their protecting FEC packets.
//
// TODO(holmer): Refactor into a proper class.
class ProtectedPacket : public ForwardErrorCorrection::SortablePacket {
class ProtectedPacket : public SortablePacket {
public:
ProtectedPacket();
~ProtectedPacket();
@ -122,7 +118,7 @@ class ForwardErrorCorrection {
// Used for internal storage of received FEC packets in a list.
//
// TODO(holmer): Refactor into a proper class.
class ReceivedFecPacket : public ForwardErrorCorrection::SortablePacket {
class ReceivedFecPacket : public SortablePacket {
public:
ReceivedFecPacket();
~ReceivedFecPacket();

View File

@ -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,35 @@ 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())) {}
// 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())) {}
// 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 +375,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 +415,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 +504,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 +1028,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

View File

@ -90,6 +90,7 @@ int32_t UlpfecReceiverImpl::AddReceivedRedPacket(
// Get payload type from RED header and sequence number from RTP header.
uint8_t payload_type = incoming_rtp_packet[header.headerLength] & 0x7f;
received_packet->is_fec = payload_type == ulpfec_payload_type;
received_packet->ssrc = header.ssrc;
received_packet->seq_num = header.sequenceNumber;
uint16_t block_length = 0;
@ -155,6 +156,7 @@ int32_t UlpfecReceiverImpl::AddReceivedRedPacket(
second_received_packet->pkt = new ForwardErrorCorrection::Packet;
second_received_packet->is_fec = true;
second_received_packet->ssrc = header.ssrc;
second_received_packet->seq_num = header.sequenceNumber;
++packet_counter_.num_fec_packets;

View File

@ -78,13 +78,7 @@ void ReceivePackets(
}
}
// Too slow to finish before timeout on iOS. See webrtc:4755.
#if defined(WEBRTC_IOS)
#define MAYBE_FecTest DISABLED_FecTest
#else
#define MAYBE_FecTest FecTest
#endif
TEST(FecTest, MAYBE_FecTest) {
void RunTest(bool use_flexfec) {
// TODO(marpan): Split this function into subroutines/helper functions.
enum { kMaxNumberMediaPackets = 48 };
enum { kMaxNumberFecPackets = 48 };
@ -107,8 +101,13 @@ TEST(FecTest, MAYBE_FecTest) {
ASSERT_EQ(12, kMaxMediaPackets[1]) << "Max media packets for bursty mode not "
<< "equal to 12.";
std::unique_ptr<ForwardErrorCorrection> fec =
ForwardErrorCorrection::CreateUlpfec();
std::unique_ptr<ForwardErrorCorrection> fec;
if (use_flexfec) {
fec = ForwardErrorCorrection::CreateFlexfec();
} else {
fec = ForwardErrorCorrection::CreateUlpfec();
}
ForwardErrorCorrection::PacketList media_packet_list;
std::list<ForwardErrorCorrection::Packet*> fec_packet_list;
ForwardErrorCorrection::ReceivedPacketList to_decode_list;
@ -138,7 +137,16 @@ TEST(FecTest, MAYBE_FecTest) {
uint16_t seq_num = 0;
uint32_t timestamp = random.Rand<uint32_t>();
const uint32_t ssrc = random.Rand(1u, 0xfffffffe);
const uint32_t media_ssrc = random.Rand(1u, 0xfffffffe);
uint32_t fec_ssrc;
uint16_t fec_seq_num_offset;
if (use_flexfec) {
fec_ssrc = random.Rand(1u, 0xfffffffe);
fec_seq_num_offset = random.Rand<uint16_t>();
} else {
fec_ssrc = media_ssrc;
fec_seq_num_offset = 0;
}
// Loop over the mask types: random and bursty.
for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes;
@ -268,7 +276,7 @@ TEST(FecTest, MAYBE_FecTest) {
ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[4],
timestamp);
ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[8],
ssrc);
media_ssrc);
// Generate random values for payload
for (size_t j = 12; j < media_packet->length; ++j) {
media_packet->data[j] = random.Rand<uint8_t>();
@ -302,6 +310,7 @@ TEST(FecTest, MAYBE_FecTest) {
received_packet->pkt->length = media_packet->length;
memcpy(received_packet->pkt->data, media_packet->data,
media_packet->length);
received_packet->ssrc = media_ssrc;
received_packet->seq_num =
ByteReader<uint16_t>::ReadBigEndian(&media_packet->data[2]);
received_packet->is_fec = false;
@ -323,9 +332,9 @@ TEST(FecTest, MAYBE_FecTest) {
received_packet->pkt->length = fec_packet->length;
memcpy(received_packet->pkt->data, fec_packet->data,
fec_packet->length);
received_packet->seq_num = seq_num;
received_packet->seq_num = fec_seq_num_offset + seq_num;
received_packet->is_fec = true;
received_packet->ssrc = ssrc;
received_packet->ssrc = fec_ssrc;
received_packet_list.push_back(std::move(received_packet));
fec_mask_list.push_back(fec_packet_masks[fec_packet_idx]);
@ -453,5 +462,21 @@ TEST(FecTest, MAYBE_FecTest) {
<< "Recovered packet list is not empty";
}
// Too slow to finish before timeout on iOS. See webrtc:4755.
#if defined(WEBRTC_IOS)
#define MAYBE_UlpecTest DISABLED_UlpecTest
#define MAYBE_FlexfecTest DISABLED_FlexfecTest
#else
#define MAYBE_UlpecTest UlpecTest
#define MAYBE_FlexfecTest FlexfecTest
#endif
TEST(FecTest, MAYBE_UlpecTest) {
RunTest(false);
}
TEST(FecTest, MAYBE_FlexfecTest) {
RunTest(true);
}
} // namespace test
} // namespace webrtc