Style updates for ForwardErrorCorrection and related classes.
This CL mainly updates the FEC code to use more C++11 features and to be more in line with the style guide. These changes should have no impact on the functionality provided by the FEC. Summary of style fixes: - Use range-based for loops, where applicable. - Use auto type deduction for iterator type names. - Use RTC_DCHECK instead of assert. - Rename FEC to Fec, where applicable. - Update test_fec.cc to use variable_names rather than variableNames. - Avoid redefining the PacketList types outside ForwardErrorCorrection. Another minor change is that storage for the packet masks, as these are generated, now is provided by a member variable, rather than being dynamically allocated on every call to GenerateFec. BUG=webrtc:5654 R=danilchap@webrtc.org, stefan@webrtc.org Review URL: https://codereview.webrtc.org/2080553003 . Cr-Commit-Position: refs/heads/master@{#13403}
This commit is contained in:
parent
9b522f8d04
commit
ae4f7674e4
@ -10,10 +10,9 @@
|
||||
|
||||
#include "webrtc/modules/rtp_rtcp/source/fec_receiver_impl.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h"
|
||||
@ -89,8 +88,8 @@ int32_t FecReceiverImpl::AddReceivedRedPacket(
|
||||
// we remove the RED header
|
||||
|
||||
std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet(
|
||||
new ForwardErrorCorrection::ReceivedPacket);
|
||||
received_packet->pkt = new ForwardErrorCorrection::Packet;
|
||||
new ForwardErrorCorrection::ReceivedPacket());
|
||||
received_packet->pkt = new ForwardErrorCorrection::Packet();
|
||||
|
||||
// get payload type from RED header
|
||||
uint8_t payload_type =
|
||||
@ -159,8 +158,8 @@ int32_t FecReceiverImpl::AddReceivedRedPacket(
|
||||
|
||||
received_packet->pkt->length = blockLength;
|
||||
|
||||
second_received_packet.reset(new ForwardErrorCorrection::ReceivedPacket);
|
||||
second_received_packet->pkt = new ForwardErrorCorrection::Packet;
|
||||
second_received_packet.reset(new ForwardErrorCorrection::ReceivedPacket());
|
||||
second_received_packet->pkt = new ForwardErrorCorrection::Packet();
|
||||
|
||||
second_received_packet->is_fec = true;
|
||||
second_received_packet->seq_num = header.sequenceNumber;
|
||||
@ -231,19 +230,19 @@ int32_t FecReceiverImpl::ProcessReceivedFec() {
|
||||
}
|
||||
crit_sect_.Enter();
|
||||
}
|
||||
if (fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_) != 0) {
|
||||
if (fec_->DecodeFec(&received_packet_list_, &recovered_packet_list_) != 0) {
|
||||
crit_sect_.Leave();
|
||||
return -1;
|
||||
}
|
||||
assert(received_packet_list_.empty());
|
||||
RTC_DCHECK(received_packet_list_.empty());
|
||||
}
|
||||
// Send any recovered media packets to VCM.
|
||||
ForwardErrorCorrection::RecoveredPacketList::iterator it =
|
||||
recovered_packet_list_.begin();
|
||||
for (; it != recovered_packet_list_.end(); ++it) {
|
||||
if ((*it)->returned) // Already sent to the VCM and the jitter buffer.
|
||||
for(auto* recovered_packet : recovered_packet_list_) {
|
||||
if (recovered_packet->returned) {
|
||||
// Already sent to the VCM and the jitter buffer.
|
||||
continue;
|
||||
ForwardErrorCorrection::Packet* packet = (*it)->pkt;
|
||||
}
|
||||
ForwardErrorCorrection::Packet* packet = recovered_packet->pkt;
|
||||
++packet_counter_.num_recovered_packets;
|
||||
crit_sect_.Leave();
|
||||
if (!recovered_packet_callback_->OnRecoveredPacket(packet->data,
|
||||
@ -251,7 +250,7 @@ int32_t FecReceiverImpl::ProcessReceivedFec() {
|
||||
return -1;
|
||||
}
|
||||
crit_sect_.Enter();
|
||||
(*it)->returned = true;
|
||||
recovered_packet->returned = true;
|
||||
}
|
||||
crit_sect_.Leave();
|
||||
return 0;
|
||||
|
||||
@ -38,11 +38,11 @@ class ReceiverFecTest : public ::testing::Test {
|
||||
generator_.reset(new FrameGenerator());
|
||||
}
|
||||
|
||||
void GenerateFEC(std::list<Packet*>* media_packets,
|
||||
std::list<Packet*>* fec_packets,
|
||||
void GenerateFec(ForwardErrorCorrection::PacketList* media_packets,
|
||||
ForwardErrorCorrection::PacketList* fec_packets,
|
||||
unsigned int num_fec_packets) {
|
||||
uint8_t protection_factor = num_fec_packets * 255 / media_packets->size();
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(*media_packets, protection_factor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(*media_packets, protection_factor,
|
||||
0, false, kFecMaskBursty, fec_packets));
|
||||
ASSERT_EQ(num_fec_packets, fec_packets->size());
|
||||
}
|
||||
@ -50,7 +50,7 @@ class ReceiverFecTest : public ::testing::Test {
|
||||
void GenerateFrame(int num_media_packets,
|
||||
int frame_offset,
|
||||
std::list<test::RawRtpPacket*>* media_rtp_packets,
|
||||
std::list<Packet*>* media_packets) {
|
||||
ForwardErrorCorrection::PacketList* media_packets) {
|
||||
generator_->NewFrame(num_media_packets);
|
||||
for (int i = 0; i < num_media_packets; ++i) {
|
||||
media_rtp_packets->push_back(
|
||||
@ -97,7 +97,7 @@ class ReceiverFecTest : public ::testing::Test {
|
||||
std::unique_ptr<FrameGenerator> generator_;
|
||||
};
|
||||
|
||||
void DeletePackets(std::list<Packet*>* packets) {
|
||||
void DeletePackets(ForwardErrorCorrection::PacketList* packets) {
|
||||
while (!packets->empty()) {
|
||||
delete packets->front();
|
||||
packets->pop_front();
|
||||
@ -107,18 +107,18 @@ void DeletePackets(std::list<Packet*>* packets) {
|
||||
TEST_F(ReceiverFecTest, TwoMediaOneFec) {
|
||||
const unsigned int kNumFecPackets = 1u;
|
||||
std::list<test::RawRtpPacket*> media_rtp_packets;
|
||||
std::list<Packet*> media_packets;
|
||||
ForwardErrorCorrection::PacketList media_packets;
|
||||
GenerateFrame(2, 0, &media_rtp_packets, &media_packets);
|
||||
std::list<Packet*> fec_packets;
|
||||
GenerateFEC(&media_packets, &fec_packets, kNumFecPackets);
|
||||
ForwardErrorCorrection::PacketList fec_packets;
|
||||
GenerateFec(&media_packets, &fec_packets, kNumFecPackets);
|
||||
|
||||
// Recovery
|
||||
std::list<test::RawRtpPacket*>::iterator it = media_rtp_packets.begin();
|
||||
auto it = media_rtp_packets.begin();
|
||||
BuildAndAddRedMediaPacket(*it);
|
||||
VerifyReconstructedMediaPacket(*it, 1);
|
||||
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
|
||||
// Drop one media packet.
|
||||
std::list<Packet*>::iterator fec_it = fec_packets.begin();
|
||||
auto fec_it = fec_packets.begin();
|
||||
BuildAndAddRedFecPacket(*fec_it);
|
||||
++it;
|
||||
VerifyReconstructedMediaPacket(*it, 1);
|
||||
@ -138,10 +138,10 @@ void ReceiverFecTest::InjectGarbagePacketLength(size_t fec_garbage_offset) {
|
||||
|
||||
const unsigned int kNumFecPackets = 1u;
|
||||
std::list<test::RawRtpPacket*> media_rtp_packets;
|
||||
std::list<Packet*> media_packets;
|
||||
ForwardErrorCorrection::PacketList media_packets;
|
||||
GenerateFrame(2, 0, &media_rtp_packets, &media_packets);
|
||||
std::list<Packet*> fec_packets;
|
||||
GenerateFEC(&media_packets, &fec_packets, kNumFecPackets);
|
||||
ForwardErrorCorrection::PacketList fec_packets;
|
||||
GenerateFec(&media_packets, &fec_packets, kNumFecPackets);
|
||||
ByteWriter<uint16_t>::WriteBigEndian(
|
||||
&fec_packets.front()->data[fec_garbage_offset], 0x4711);
|
||||
|
||||
@ -173,15 +173,15 @@ TEST_F(ReceiverFecTest, InjectGarbageFecLevelHeaderProtectionLength) {
|
||||
TEST_F(ReceiverFecTest, TwoMediaTwoFec) {
|
||||
const unsigned int kNumFecPackets = 2u;
|
||||
std::list<test::RawRtpPacket*> media_rtp_packets;
|
||||
std::list<Packet*> media_packets;
|
||||
ForwardErrorCorrection::PacketList media_packets;
|
||||
GenerateFrame(2, 0, &media_rtp_packets, &media_packets);
|
||||
std::list<Packet*> fec_packets;
|
||||
GenerateFEC(&media_packets, &fec_packets, kNumFecPackets);
|
||||
ForwardErrorCorrection::PacketList fec_packets;
|
||||
GenerateFec(&media_packets, &fec_packets, kNumFecPackets);
|
||||
|
||||
// Recovery
|
||||
// Drop both media packets.
|
||||
std::list<test::RawRtpPacket*>::iterator it = media_rtp_packets.begin();
|
||||
std::list<Packet*>::iterator fec_it = fec_packets.begin();
|
||||
auto it = media_rtp_packets.begin();
|
||||
auto fec_it = fec_packets.begin();
|
||||
BuildAndAddRedFecPacket(*fec_it);
|
||||
VerifyReconstructedMediaPacket(*it, 1);
|
||||
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
|
||||
@ -197,14 +197,14 @@ TEST_F(ReceiverFecTest, TwoMediaTwoFec) {
|
||||
TEST_F(ReceiverFecTest, TwoFramesOneFec) {
|
||||
const unsigned int kNumFecPackets = 1u;
|
||||
std::list<test::RawRtpPacket*> media_rtp_packets;
|
||||
std::list<Packet*> media_packets;
|
||||
ForwardErrorCorrection::PacketList media_packets;
|
||||
GenerateFrame(1, 0, &media_rtp_packets, &media_packets);
|
||||
GenerateFrame(1, 1, &media_rtp_packets, &media_packets);
|
||||
std::list<Packet*> fec_packets;
|
||||
GenerateFEC(&media_packets, &fec_packets, kNumFecPackets);
|
||||
ForwardErrorCorrection::PacketList fec_packets;
|
||||
GenerateFec(&media_packets, &fec_packets, kNumFecPackets);
|
||||
|
||||
// Recovery
|
||||
std::list<test::RawRtpPacket*>::iterator it = media_rtp_packets.begin();
|
||||
auto it = media_rtp_packets.begin();
|
||||
BuildAndAddRedMediaPacket(media_rtp_packets.front());
|
||||
VerifyReconstructedMediaPacket(*it, 1);
|
||||
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
|
||||
@ -220,15 +220,15 @@ TEST_F(ReceiverFecTest, TwoFramesOneFec) {
|
||||
TEST_F(ReceiverFecTest, OneCompleteOneUnrecoverableFrame) {
|
||||
const unsigned int kNumFecPackets = 1u;
|
||||
std::list<test::RawRtpPacket*> media_rtp_packets;
|
||||
std::list<Packet*> media_packets;
|
||||
ForwardErrorCorrection::PacketList media_packets;
|
||||
GenerateFrame(1, 0, &media_rtp_packets, &media_packets);
|
||||
GenerateFrame(2, 1, &media_rtp_packets, &media_packets);
|
||||
|
||||
std::list<Packet*> fec_packets;
|
||||
GenerateFEC(&media_packets, &fec_packets, kNumFecPackets);
|
||||
ForwardErrorCorrection::PacketList fec_packets;
|
||||
GenerateFec(&media_packets, &fec_packets, kNumFecPackets);
|
||||
|
||||
// Recovery
|
||||
std::list<test::RawRtpPacket*>::iterator it = media_rtp_packets.begin();
|
||||
auto it = media_rtp_packets.begin();
|
||||
BuildAndAddRedMediaPacket(*it); // First frame: one packet.
|
||||
VerifyReconstructedMediaPacket(*it, 1);
|
||||
EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
|
||||
@ -244,15 +244,15 @@ TEST_F(ReceiverFecTest, MaxFramesOneFec) {
|
||||
const unsigned int kNumFecPackets = 1u;
|
||||
const unsigned int kNumMediaPackets = 48u;
|
||||
std::list<test::RawRtpPacket*> media_rtp_packets;
|
||||
std::list<Packet*> media_packets;
|
||||
ForwardErrorCorrection::PacketList media_packets;
|
||||
for (unsigned int i = 0; i < kNumMediaPackets; ++i) {
|
||||
GenerateFrame(1, i, &media_rtp_packets, &media_packets);
|
||||
}
|
||||
std::list<Packet*> fec_packets;
|
||||
GenerateFEC(&media_packets, &fec_packets, kNumFecPackets);
|
||||
ForwardErrorCorrection::PacketList fec_packets;
|
||||
GenerateFec(&media_packets, &fec_packets, kNumFecPackets);
|
||||
|
||||
// Recovery
|
||||
std::list<test::RawRtpPacket*>::iterator it = media_rtp_packets.begin();
|
||||
auto it = media_rtp_packets.begin();
|
||||
++it; // Drop first packet.
|
||||
for (; it != media_rtp_packets.end(); ++it) {
|
||||
BuildAndAddRedMediaPacket(*it);
|
||||
@ -271,12 +271,12 @@ TEST_F(ReceiverFecTest, TooManyFrames) {
|
||||
const unsigned int kNumFecPackets = 1u;
|
||||
const unsigned int kNumMediaPackets = 49u;
|
||||
std::list<test::RawRtpPacket*> media_rtp_packets;
|
||||
std::list<Packet*> media_packets;
|
||||
ForwardErrorCorrection::PacketList media_packets;
|
||||
for (unsigned int i = 0; i < kNumMediaPackets; ++i) {
|
||||
GenerateFrame(1, i, &media_rtp_packets, &media_packets);
|
||||
}
|
||||
std::list<Packet*> fec_packets;
|
||||
EXPECT_EQ(-1, fec_->GenerateFEC(media_packets,
|
||||
ForwardErrorCorrection::PacketList fec_packets;
|
||||
EXPECT_EQ(-1, fec_->GenerateFec(media_packets,
|
||||
kNumFecPackets * 255 / kNumMediaPackets, 0,
|
||||
false, kFecMaskBursty, &fec_packets));
|
||||
|
||||
@ -290,11 +290,11 @@ TEST_F(ReceiverFecTest, PacketNotDroppedTooEarly) {
|
||||
const unsigned int kNumFecPacketsBatch1 = 1u;
|
||||
const unsigned int kNumMediaPacketsBatch1 = 2u;
|
||||
std::list<test::RawRtpPacket*> media_rtp_packets_batch1;
|
||||
std::list<Packet*> media_packets_batch1;
|
||||
ForwardErrorCorrection::PacketList media_packets_batch1;
|
||||
GenerateFrame(kNumMediaPacketsBatch1, 0, &media_rtp_packets_batch1,
|
||||
&media_packets_batch1);
|
||||
std::list<Packet*> fec_packets;
|
||||
GenerateFEC(&media_packets_batch1, &fec_packets, kNumFecPacketsBatch1);
|
||||
ForwardErrorCorrection::PacketList fec_packets;
|
||||
GenerateFec(&media_packets_batch1, &fec_packets, kNumFecPacketsBatch1);
|
||||
|
||||
BuildAndAddRedMediaPacket(media_rtp_packets_batch1.front());
|
||||
EXPECT_CALL(rtp_data_callback_, OnRecoveredPacket(_, _))
|
||||
@ -305,12 +305,11 @@ TEST_F(ReceiverFecTest, PacketNotDroppedTooEarly) {
|
||||
// Fill the FEC decoder. No packets should be dropped.
|
||||
const unsigned int kNumMediaPacketsBatch2 = 46u;
|
||||
std::list<test::RawRtpPacket*> media_rtp_packets_batch2;
|
||||
std::list<Packet*> media_packets_batch2;
|
||||
ForwardErrorCorrection::PacketList media_packets_batch2;
|
||||
for (unsigned int i = 0; i < kNumMediaPacketsBatch2; ++i) {
|
||||
GenerateFrame(1, i, &media_rtp_packets_batch2, &media_packets_batch2);
|
||||
}
|
||||
for (std::list<test::RawRtpPacket*>::iterator it =
|
||||
media_rtp_packets_batch2.begin();
|
||||
for (auto it = media_rtp_packets_batch2.begin();
|
||||
it != media_rtp_packets_batch2.end(); ++it) {
|
||||
BuildAndAddRedMediaPacket(*it);
|
||||
EXPECT_CALL(rtp_data_callback_, OnRecoveredPacket(_, _))
|
||||
@ -335,11 +334,11 @@ TEST_F(ReceiverFecTest, PacketDroppedWhenTooOld) {
|
||||
const unsigned int kNumFecPacketsBatch1 = 1u;
|
||||
const unsigned int kNumMediaPacketsBatch1 = 2u;
|
||||
std::list<test::RawRtpPacket*> media_rtp_packets_batch1;
|
||||
std::list<Packet*> media_packets_batch1;
|
||||
ForwardErrorCorrection::PacketList media_packets_batch1;
|
||||
GenerateFrame(kNumMediaPacketsBatch1, 0, &media_rtp_packets_batch1,
|
||||
&media_packets_batch1);
|
||||
std::list<Packet*> fec_packets;
|
||||
GenerateFEC(&media_packets_batch1, &fec_packets, kNumFecPacketsBatch1);
|
||||
ForwardErrorCorrection::PacketList fec_packets;
|
||||
GenerateFec(&media_packets_batch1, &fec_packets, kNumFecPacketsBatch1);
|
||||
|
||||
BuildAndAddRedMediaPacket(media_rtp_packets_batch1.front());
|
||||
EXPECT_CALL(rtp_data_callback_, OnRecoveredPacket(_, _))
|
||||
@ -350,12 +349,11 @@ TEST_F(ReceiverFecTest, PacketDroppedWhenTooOld) {
|
||||
// Fill the FEC decoder and force the last packet to be dropped.
|
||||
const unsigned int kNumMediaPacketsBatch2 = 48u;
|
||||
std::list<test::RawRtpPacket*> media_rtp_packets_batch2;
|
||||
std::list<Packet*> media_packets_batch2;
|
||||
ForwardErrorCorrection::PacketList media_packets_batch2;
|
||||
for (unsigned int i = 0; i < kNumMediaPacketsBatch2; ++i) {
|
||||
GenerateFrame(1, i, &media_rtp_packets_batch2, &media_packets_batch2);
|
||||
}
|
||||
for (std::list<test::RawRtpPacket*>::iterator it =
|
||||
media_rtp_packets_batch2.begin();
|
||||
for (auto it = media_rtp_packets_batch2.begin();
|
||||
it != media_rtp_packets_batch2.end(); ++it) {
|
||||
BuildAndAddRedMediaPacket(*it);
|
||||
EXPECT_CALL(rtp_data_callback_, OnRecoveredPacket(_, _))
|
||||
@ -379,15 +377,14 @@ TEST_F(ReceiverFecTest, OldFecPacketDropped) {
|
||||
// missing.
|
||||
const unsigned int kNumMediaPackets = 49 * 2;
|
||||
std::list<test::RawRtpPacket*> media_rtp_packets;
|
||||
std::list<Packet*> media_packets;
|
||||
ForwardErrorCorrection::PacketList media_packets;
|
||||
for (unsigned int i = 0; i < kNumMediaPackets / 2; ++i) {
|
||||
std::list<test::RawRtpPacket*> frame_media_rtp_packets;
|
||||
std::list<Packet*> frame_media_packets;
|
||||
std::list<Packet*> fec_packets;
|
||||
ForwardErrorCorrection::PacketList frame_media_packets;
|
||||
ForwardErrorCorrection::PacketList fec_packets;
|
||||
GenerateFrame(2, 0, &frame_media_rtp_packets, &frame_media_packets);
|
||||
GenerateFEC(&frame_media_packets, &fec_packets, 1);
|
||||
for (std::list<Packet*>::iterator it = fec_packets.begin();
|
||||
it != fec_packets.end(); ++it) {
|
||||
GenerateFec(&frame_media_packets, &fec_packets, 1);
|
||||
for (auto it = fec_packets.begin(); it != fec_packets.end(); ++it) {
|
||||
// Only FEC packets inserted. No packets recoverable at this time.
|
||||
BuildAndAddRedFecPacket(*it);
|
||||
EXPECT_CALL(rtp_data_callback_, OnRecoveredPacket(_, _))
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
|
||||
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
@ -26,18 +25,19 @@
|
||||
namespace webrtc {
|
||||
|
||||
// FEC header size in bytes.
|
||||
const uint8_t kFecHeaderSize = 10;
|
||||
constexpr size_t kFecHeaderSize = 10;
|
||||
|
||||
// ULP header size in bytes (L bit is set).
|
||||
const uint8_t kUlpHeaderSizeLBitSet = (2 + kMaskSizeLBitSet);
|
||||
constexpr size_t kUlpHeaderSizeLBitSet = (2 + kMaskSizeLBitSet);
|
||||
|
||||
// ULP header size in bytes (L bit is cleared).
|
||||
const uint8_t kUlpHeaderSizeLBitClear = (2 + kMaskSizeLBitClear);
|
||||
constexpr size_t kUlpHeaderSizeLBitClear = (2 + kMaskSizeLBitClear);
|
||||
|
||||
// Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum.
|
||||
const uint8_t kTransportOverhead = 28;
|
||||
constexpr size_t kTransportOverhead = 28;
|
||||
|
||||
enum { kMaxFecPackets = ForwardErrorCorrection::kMaxMediaPackets };
|
||||
// Maximum number of FEC packets stored internally.
|
||||
constexpr size_t kMaxFecPackets = ForwardErrorCorrection::kMaxMediaPackets;
|
||||
|
||||
int32_t ForwardErrorCorrection::Packet::AddRef() {
|
||||
return ++ref_count_;
|
||||
@ -85,8 +85,8 @@ ForwardErrorCorrection::RecoveredPacket::RecoveredPacket() {}
|
||||
ForwardErrorCorrection::RecoveredPacket::~RecoveredPacket() {}
|
||||
|
||||
ForwardErrorCorrection::ForwardErrorCorrection()
|
||||
: generated_fec_packets_(kMaxMediaPackets), fec_packet_received_(false) {}
|
||||
|
||||
: generated_fec_packets_(kMaxMediaPackets), fec_packet_list_(),
|
||||
packet_mask_(), tmp_packet_mask_() {}
|
||||
ForwardErrorCorrection::~ForwardErrorCorrection() {}
|
||||
|
||||
// Input packet
|
||||
@ -106,18 +106,21 @@ ForwardErrorCorrection::~ForwardErrorCorrection() {}
|
||||
// | FEC Level 0 Payload |
|
||||
// | |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
int32_t ForwardErrorCorrection::GenerateFEC(const PacketList& media_packet_list,
|
||||
uint8_t protection_factor,
|
||||
int num_important_packets,
|
||||
bool use_unequal_protection,
|
||||
FecMaskType fec_mask_type,
|
||||
PacketList* fec_packet_list) {
|
||||
//
|
||||
// Note that any potential RED headers are added/removed before calling
|
||||
// GenerateFec() or DecodeFec().
|
||||
int ForwardErrorCorrection::GenerateFec(const PacketList& media_packet_list,
|
||||
uint8_t protection_factor,
|
||||
int num_important_packets,
|
||||
bool use_unequal_protection,
|
||||
FecMaskType fec_mask_type,
|
||||
PacketList* fec_packet_list) {
|
||||
const uint16_t num_media_packets = media_packet_list.size();
|
||||
// Sanity check arguments.
|
||||
assert(num_media_packets > 0);
|
||||
assert(num_important_packets >= 0 &&
|
||||
num_important_packets <= num_media_packets);
|
||||
assert(fec_packet_list->empty());
|
||||
RTC_DCHECK_GT(num_media_packets, 0);
|
||||
RTC_DCHECK_GE(num_important_packets, 0);
|
||||
RTC_DCHECK_LE(num_important_packets, num_media_packets);
|
||||
RTC_DCHECK(fec_packet_list->empty());
|
||||
|
||||
if (num_media_packets > kMaxMediaPackets) {
|
||||
LOG(LS_WARNING) << "Can't protect " << num_media_packets
|
||||
@ -130,7 +133,7 @@ int32_t ForwardErrorCorrection::GenerateFEC(const PacketList& media_packet_list,
|
||||
|
||||
// Do some error checking on the media packets.
|
||||
for (Packet* media_packet : media_packet_list) {
|
||||
assert(media_packet);
|
||||
RTC_DCHECK(media_packet);
|
||||
|
||||
if (media_packet->length < kRtpHeaderSize) {
|
||||
LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes "
|
||||
@ -163,29 +166,26 @@ int32_t ForwardErrorCorrection::GenerateFEC(const PacketList& media_packet_list,
|
||||
const internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets);
|
||||
|
||||
// -- Generate packet masks --
|
||||
// Always allocate space for a large mask.
|
||||
std::unique_ptr<uint8_t[]> packet_mask(
|
||||
new uint8_t[num_fec_packets * kMaskSizeLBitSet]);
|
||||
memset(packet_mask.get(), 0, num_fec_packets * num_mask_bytes);
|
||||
memset(packet_mask_, 0, num_fec_packets * num_mask_bytes);
|
||||
internal::GeneratePacketMasks(num_media_packets, num_fec_packets,
|
||||
num_important_packets, use_unequal_protection,
|
||||
mask_table, packet_mask.get());
|
||||
mask_table, packet_mask_);
|
||||
|
||||
int num_mask_bits = InsertZerosInBitMasks(
|
||||
media_packet_list, packet_mask.get(), num_mask_bytes, num_fec_packets);
|
||||
media_packet_list, packet_mask_, num_mask_bytes, num_fec_packets);
|
||||
|
||||
if (num_mask_bits < 0) {
|
||||
return -1;
|
||||
}
|
||||
l_bit = (num_mask_bits > 8 * kMaskSizeLBitClear);
|
||||
l_bit = (static_cast<size_t>(num_mask_bits) > 8 * kMaskSizeLBitClear);
|
||||
if (l_bit) {
|
||||
num_mask_bytes = kMaskSizeLBitSet;
|
||||
}
|
||||
|
||||
GenerateFecBitStrings(media_packet_list, packet_mask.get(), num_fec_packets,
|
||||
l_bit);
|
||||
GenerateFecUlpHeaders(media_packet_list, packet_mask.get(), l_bit,
|
||||
num_fec_packets);
|
||||
GenerateFecBitStrings(media_packet_list, packet_mask_,
|
||||
num_fec_packets, l_bit);
|
||||
GenerateFecUlpHeaders(media_packet_list, packet_mask_,
|
||||
num_fec_packets, l_bit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -198,7 +198,7 @@ int ForwardErrorCorrection::GetNumberOfFecPackets(int num_media_packets,
|
||||
if (protection_factor > 0 && num_fec_packets == 0) {
|
||||
num_fec_packets = 1;
|
||||
}
|
||||
assert(num_fec_packets <= num_media_packets);
|
||||
RTC_DCHECK_LE(num_fec_packets, num_media_packets);
|
||||
return num_fec_packets;
|
||||
}
|
||||
|
||||
@ -207,9 +207,7 @@ void ForwardErrorCorrection::GenerateFecBitStrings(
|
||||
uint8_t* packet_mask,
|
||||
int num_fec_packets,
|
||||
bool l_bit) {
|
||||
if (media_packet_list.empty()) {
|
||||
return;
|
||||
}
|
||||
RTC_DCHECK(!media_packet_list.empty());
|
||||
uint8_t media_payload_length[2];
|
||||
const int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear;
|
||||
const uint16_t ulp_header_size =
|
||||
@ -219,7 +217,7 @@ void ForwardErrorCorrection::GenerateFecBitStrings(
|
||||
|
||||
for (int i = 0; i < num_fec_packets; ++i) {
|
||||
Packet* const fec_packet = &generated_fec_packets_[i];
|
||||
PacketList::const_iterator media_list_it = media_packet_list.begin();
|
||||
auto media_list_it = media_packet_list.cbegin();
|
||||
uint32_t pkt_mask_idx = i * num_mask_bytes;
|
||||
uint32_t media_pkt_idx = 0;
|
||||
uint16_t fec_packet_length = 0;
|
||||
@ -237,9 +235,10 @@ void ForwardErrorCorrection::GenerateFecBitStrings(
|
||||
fec_packet_length = media_packet->length + fec_rtp_offset;
|
||||
// On the first protected packet, we don't need to XOR.
|
||||
if (fec_packet->length == 0) {
|
||||
// Copy the first 2 bytes of the RTP header.
|
||||
memcpy(fec_packet->data, media_packet->data, 2);
|
||||
// Copy the 5th to 8th bytes of the RTP header.
|
||||
// Copy the first 2 bytes of the RTP header. Note that the E and L
|
||||
// bits are overwritten in GenerateFecUlpHeaders.
|
||||
memcpy(&fec_packet->data[0], &media_packet->data[0], 2);
|
||||
// Copy the 5th to 8th bytes of the RTP header (timestamp).
|
||||
memcpy(&fec_packet->data[4], &media_packet->data[4], 4);
|
||||
// Copy network-ordered payload size.
|
||||
memcpy(&fec_packet->data[8], media_payload_length, 2);
|
||||
@ -291,7 +290,6 @@ int ForwardErrorCorrection::InsertZerosInBitMasks(
|
||||
uint8_t* packet_mask,
|
||||
int num_mask_bytes,
|
||||
int num_fec_packets) {
|
||||
uint8_t* new_mask = NULL;
|
||||
if (media_packets.size() <= 1) {
|
||||
return media_packets.size();
|
||||
}
|
||||
@ -313,15 +311,14 @@ int ForwardErrorCorrection::InsertZerosInBitMasks(
|
||||
if (media_packets.size() + total_missing_seq_nums > 8 * kMaskSizeLBitClear) {
|
||||
new_mask_bytes = kMaskSizeLBitSet;
|
||||
}
|
||||
new_mask = new uint8_t[num_fec_packets * kMaskSizeLBitSet];
|
||||
memset(new_mask, 0, num_fec_packets * kMaskSizeLBitSet);
|
||||
memset(tmp_packet_mask_, 0, num_fec_packets * kMaskSizeLBitSet);
|
||||
|
||||
PacketList::const_iterator it = media_packets.begin();
|
||||
auto it = media_packets.cbegin();
|
||||
uint16_t prev_seq_num = first_seq_num;
|
||||
++it;
|
||||
|
||||
// Insert the first column.
|
||||
CopyColumn(new_mask, new_mask_bytes, packet_mask, num_mask_bytes,
|
||||
CopyColumn(tmp_packet_mask_, new_mask_bytes, packet_mask, num_mask_bytes,
|
||||
num_fec_packets, 0, 0);
|
||||
int new_bit_index = 1;
|
||||
int old_bit_index = 1;
|
||||
@ -335,11 +332,11 @@ int ForwardErrorCorrection::InsertZerosInBitMasks(
|
||||
const int zeros_to_insert =
|
||||
static_cast<uint16_t>(seq_num - prev_seq_num - 1);
|
||||
if (zeros_to_insert > 0) {
|
||||
InsertZeroColumns(zeros_to_insert, new_mask, new_mask_bytes,
|
||||
InsertZeroColumns(zeros_to_insert, tmp_packet_mask_, new_mask_bytes,
|
||||
num_fec_packets, new_bit_index);
|
||||
}
|
||||
new_bit_index += zeros_to_insert;
|
||||
CopyColumn(new_mask, new_mask_bytes, packet_mask, num_mask_bytes,
|
||||
CopyColumn(tmp_packet_mask_, new_mask_bytes, packet_mask, num_mask_bytes,
|
||||
num_fec_packets, new_bit_index, old_bit_index);
|
||||
++new_bit_index;
|
||||
++old_bit_index;
|
||||
@ -349,12 +346,11 @@ int ForwardErrorCorrection::InsertZerosInBitMasks(
|
||||
// We didn't fill the last byte. Shift bits to correct position.
|
||||
for (uint16_t row = 0; row < num_fec_packets; ++row) {
|
||||
int new_byte_index = row * new_mask_bytes + new_bit_index / 8;
|
||||
new_mask[new_byte_index] <<= (7 - (new_bit_index % 8));
|
||||
tmp_packet_mask_[new_byte_index] <<= (7 - (new_bit_index % 8));
|
||||
}
|
||||
}
|
||||
// Replace the old mask with the new.
|
||||
memcpy(packet_mask, new_mask, kMaskSizeLBitSet * num_fec_packets);
|
||||
delete[] new_mask;
|
||||
memcpy(packet_mask, tmp_packet_mask_, kMaskSizeLBitSet * num_fec_packets);
|
||||
return new_bit_index;
|
||||
}
|
||||
|
||||
@ -393,8 +389,8 @@ void ForwardErrorCorrection::CopyColumn(uint8_t* new_mask,
|
||||
void ForwardErrorCorrection::GenerateFecUlpHeaders(
|
||||
const PacketList& media_packet_list,
|
||||
uint8_t* packet_mask,
|
||||
bool l_bit,
|
||||
int num_fec_packets) {
|
||||
int num_fec_packets,
|
||||
bool l_bit) {
|
||||
// -- Generate FEC and ULP headers --
|
||||
//
|
||||
// FEC Header, 10 bytes
|
||||
@ -416,13 +412,14 @@ void ForwardErrorCorrection::GenerateFecUlpHeaders(
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | mask cont. (present only when L = 1) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
PacketList::const_iterator media_list_it = media_packet_list.begin();
|
||||
Packet* media_packet = *media_list_it;
|
||||
assert(media_packet != NULL);
|
||||
int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear;
|
||||
const uint16_t ulp_header_size =
|
||||
l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear;
|
||||
|
||||
RTC_DCHECK(!media_packet_list.empty());
|
||||
Packet* first_media_packet = media_packet_list.front();
|
||||
RTC_DCHECK(first_media_packet);
|
||||
uint16_t seq_num = ParseSequenceNumber(first_media_packet->data);
|
||||
for (int i = 0; i < num_fec_packets; ++i) {
|
||||
Packet* const fec_packet = &generated_fec_packets_[i];
|
||||
// -- FEC header --
|
||||
@ -432,10 +429,10 @@ void ForwardErrorCorrection::GenerateFecUlpHeaders(
|
||||
} else {
|
||||
fec_packet->data[0] |= 0x40; // Set the L bit.
|
||||
}
|
||||
// Two byte sequence number from first RTP packet to SN base.
|
||||
// Sequence number from first media packet used as SN base.
|
||||
// We use the same sequence number base for every FEC packet,
|
||||
// but that's not required in general.
|
||||
memcpy(&fec_packet->data[2], &media_packet->data[2], 2);
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->data[2], seq_num);
|
||||
|
||||
// -- ULP header --
|
||||
// Copy the payload size to the protection length field.
|
||||
@ -452,72 +449,67 @@ void ForwardErrorCorrection::GenerateFecUlpHeaders(
|
||||
|
||||
void ForwardErrorCorrection::ResetState(
|
||||
RecoveredPacketList* recovered_packet_list) {
|
||||
fec_packet_received_ = false;
|
||||
|
||||
// Free the memory for any existing recovered packets, if the user hasn't.
|
||||
while (!recovered_packet_list->empty()) {
|
||||
delete recovered_packet_list->front();
|
||||
recovered_packet_list->pop_front();
|
||||
}
|
||||
assert(recovered_packet_list->empty());
|
||||
RTC_DCHECK(recovered_packet_list->empty());
|
||||
|
||||
// Free the FEC packet list.
|
||||
while (!fec_packet_list_.empty()) {
|
||||
FecPacketList::iterator fec_packet_list_it = fec_packet_list_.begin();
|
||||
FecPacket* fec_packet = *fec_packet_list_it;
|
||||
ProtectedPacketList::iterator protected_packet_list_it;
|
||||
protected_packet_list_it = fec_packet->protected_pkt_list.begin();
|
||||
FecPacket* fec_packet = fec_packet_list_.front();
|
||||
auto protected_packet_list_it = fec_packet->protected_pkt_list.begin();
|
||||
while (protected_packet_list_it != fec_packet->protected_pkt_list.end()) {
|
||||
delete *protected_packet_list_it;
|
||||
protected_packet_list_it =
|
||||
fec_packet->protected_pkt_list.erase(protected_packet_list_it);
|
||||
}
|
||||
assert(fec_packet->protected_pkt_list.empty());
|
||||
RTC_DCHECK(fec_packet->protected_pkt_list.empty());
|
||||
delete fec_packet;
|
||||
fec_packet_list_.pop_front();
|
||||
}
|
||||
assert(fec_packet_list_.empty());
|
||||
RTC_DCHECK(fec_packet_list_.empty());
|
||||
}
|
||||
|
||||
void ForwardErrorCorrection::InsertMediaPacket(
|
||||
ReceivedPacket* rx_packet,
|
||||
RecoveredPacketList* recovered_packet_list) {
|
||||
RecoveredPacketList::iterator recovered_packet_list_it =
|
||||
recovered_packet_list->begin();
|
||||
auto recovered_packet_list_it = recovered_packet_list->cbegin();
|
||||
|
||||
// Search for duplicate packets.
|
||||
while (recovered_packet_list_it != recovered_packet_list->end()) {
|
||||
if (rx_packet->seq_num == (*recovered_packet_list_it)->seq_num) {
|
||||
// Duplicate packet, no need to add to list.
|
||||
// Delete duplicate media packet data.
|
||||
rx_packet->pkt = NULL;
|
||||
rx_packet->pkt = nullptr;
|
||||
return;
|
||||
}
|
||||
recovered_packet_list_it++;
|
||||
++recovered_packet_list_it;
|
||||
}
|
||||
RecoveredPacket* recoverd_packet_to_insert = new RecoveredPacket;
|
||||
recoverd_packet_to_insert->was_recovered = false;
|
||||
RecoveredPacket* recovered_packet_to_insert = new RecoveredPacket();
|
||||
recovered_packet_to_insert->was_recovered = false;
|
||||
// Inserted Media packet is already sent to VCM.
|
||||
recoverd_packet_to_insert->returned = true;
|
||||
recoverd_packet_to_insert->seq_num = rx_packet->seq_num;
|
||||
recoverd_packet_to_insert->pkt = rx_packet->pkt;
|
||||
recoverd_packet_to_insert->pkt->length = rx_packet->pkt->length;
|
||||
recovered_packet_to_insert->returned = true;
|
||||
recovered_packet_to_insert->seq_num = rx_packet->seq_num;
|
||||
recovered_packet_to_insert->pkt = rx_packet->pkt;
|
||||
recovered_packet_to_insert->pkt->length = rx_packet->pkt->length;
|
||||
|
||||
// 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.
|
||||
recovered_packet_list->push_back(recoverd_packet_to_insert);
|
||||
recovered_packet_list->push_back(recovered_packet_to_insert);
|
||||
recovered_packet_list->sort(SortablePacket::LessThan);
|
||||
UpdateCoveringFECPackets(recoverd_packet_to_insert);
|
||||
UpdateCoveringFecPackets(recovered_packet_to_insert);
|
||||
}
|
||||
|
||||
void ForwardErrorCorrection::UpdateCoveringFECPackets(RecoveredPacket* packet) {
|
||||
for (FecPacketList::iterator it = fec_packet_list_.begin();
|
||||
it != fec_packet_list_.end(); ++it) {
|
||||
void ForwardErrorCorrection::UpdateCoveringFecPackets(RecoveredPacket* packet) {
|
||||
for (auto* fec_packet : fec_packet_list_) {
|
||||
// Is this FEC packet protecting the media packet |packet|?
|
||||
ProtectedPacketList::iterator protected_it = std::lower_bound(
|
||||
(*it)->protected_pkt_list.begin(), (*it)->protected_pkt_list.end(),
|
||||
packet, SortablePacket::LessThan);
|
||||
if (protected_it != (*it)->protected_pkt_list.end() &&
|
||||
auto protected_it = std::lower_bound(fec_packet->protected_pkt_list.begin(),
|
||||
fec_packet->protected_pkt_list.end(),
|
||||
packet,
|
||||
SortablePacket::LessThan);
|
||||
if (protected_it != fec_packet->protected_pkt_list.end() &&
|
||||
(*protected_it)->seq_num == packet->seq_num) {
|
||||
// Found an FEC packet which is protecting |packet|.
|
||||
(*protected_it)->pkt = packet->pkt;
|
||||
@ -525,22 +517,18 @@ void ForwardErrorCorrection::UpdateCoveringFECPackets(RecoveredPacket* packet) {
|
||||
}
|
||||
}
|
||||
|
||||
void ForwardErrorCorrection::InsertFECPacket(
|
||||
void ForwardErrorCorrection::InsertFecPacket(
|
||||
ReceivedPacket* rx_packet,
|
||||
const RecoveredPacketList* recovered_packet_list) {
|
||||
fec_packet_received_ = true;
|
||||
|
||||
// Check for duplicate.
|
||||
FecPacketList::iterator fec_packet_list_it = fec_packet_list_.begin();
|
||||
while (fec_packet_list_it != fec_packet_list_.end()) {
|
||||
if (rx_packet->seq_num == (*fec_packet_list_it)->seq_num) {
|
||||
for (auto* fec_packet : fec_packet_list_) {
|
||||
if (rx_packet->seq_num == fec_packet->seq_num) {
|
||||
// Delete duplicate FEC packet data.
|
||||
rx_packet->pkt = NULL;
|
||||
rx_packet->pkt = nullptr;
|
||||
return;
|
||||
}
|
||||
fec_packet_list_it++;
|
||||
}
|
||||
FecPacket* fec_packet = new FecPacket;
|
||||
FecPacket* fec_packet = new FecPacket();
|
||||
fec_packet->pkt = rx_packet->pkt;
|
||||
fec_packet->seq_num = rx_packet->seq_num;
|
||||
fec_packet->ssrc = rx_packet->ssrc;
|
||||
@ -555,12 +543,12 @@ void ForwardErrorCorrection::InsertFECPacket(
|
||||
uint8_t packet_mask = fec_packet->pkt->data[12 + byte_idx];
|
||||
for (uint16_t bit_idx = 0; bit_idx < 8; ++bit_idx) {
|
||||
if (packet_mask & (1 << (7 - bit_idx))) {
|
||||
ProtectedPacket* protected_packet = new ProtectedPacket;
|
||||
ProtectedPacket* protected_packet = new ProtectedPacket();
|
||||
fec_packet->protected_pkt_list.push_back(protected_packet);
|
||||
// This wraps naturally with the sequence number.
|
||||
protected_packet->seq_num =
|
||||
static_cast<uint16_t>(seq_num_base + (byte_idx << 3) + bit_idx);
|
||||
protected_packet->pkt = NULL;
|
||||
protected_packet->pkt = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -575,10 +563,10 @@ void ForwardErrorCorrection::InsertFECPacket(
|
||||
fec_packet_list_.push_back(fec_packet);
|
||||
fec_packet_list_.sort(SortablePacket::LessThan);
|
||||
if (fec_packet_list_.size() > kMaxFecPackets) {
|
||||
DiscardFECPacket(fec_packet_list_.front());
|
||||
DiscardFecPacket(fec_packet_list_.front());
|
||||
fec_packet_list_.pop_front();
|
||||
}
|
||||
assert(fec_packet_list_.size() <= kMaxFecPackets);
|
||||
RTC_DCHECK_LE(fec_packet_list_.size(), kMaxFecPackets);
|
||||
}
|
||||
}
|
||||
|
||||
@ -590,14 +578,14 @@ void ForwardErrorCorrection::AssignRecoveredPackets(
|
||||
ProtectedPacketList* not_recovered = &fec_packet->protected_pkt_list;
|
||||
RecoveredPacketList already_recovered;
|
||||
std::set_intersection(
|
||||
recovered_packets->begin(), recovered_packets->end(),
|
||||
not_recovered->begin(), not_recovered->end(),
|
||||
recovered_packets->cbegin(), recovered_packets->cend(),
|
||||
not_recovered->cbegin(), not_recovered->cend(),
|
||||
std::inserter(already_recovered, already_recovered.end()),
|
||||
SortablePacket::LessThan);
|
||||
// Set the FEC pointers to all recovered packets so that we don't have to
|
||||
// search for them when we are doing recovery.
|
||||
ProtectedPacketList::iterator not_recovered_it = not_recovered->begin();
|
||||
for (RecoveredPacketList::iterator it = already_recovered.begin();
|
||||
auto not_recovered_it = not_recovered->cbegin();
|
||||
for (auto it = already_recovered.cbegin();
|
||||
it != already_recovered.end(); ++it) {
|
||||
// Search for the next recovered packet in |not_recovered|.
|
||||
while ((*not_recovered_it)->seq_num != (*it)->seq_num)
|
||||
@ -624,13 +612,13 @@ void ForwardErrorCorrection::InsertPackets(
|
||||
abs(static_cast<int>(rx_packet->seq_num) -
|
||||
static_cast<int>(fec_packet_list_.front()->seq_num));
|
||||
if (seq_num_diff > 0x3fff) {
|
||||
DiscardFECPacket(fec_packet_list_.front());
|
||||
DiscardFecPacket(fec_packet_list_.front());
|
||||
fec_packet_list_.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
if (rx_packet->is_fec) {
|
||||
InsertFECPacket(rx_packet, recovered_packet_list);
|
||||
InsertFecPacket(rx_packet, recovered_packet_list);
|
||||
} else {
|
||||
// Insert packet at the end of |recoveredPacketList|.
|
||||
InsertMediaPacket(rx_packet, recovered_packet_list);
|
||||
@ -639,12 +627,12 @@ void ForwardErrorCorrection::InsertPackets(
|
||||
delete rx_packet;
|
||||
received_packet_list->pop_front();
|
||||
}
|
||||
assert(received_packet_list->empty());
|
||||
RTC_DCHECK(received_packet_list->empty());
|
||||
DiscardOldPackets(recovered_packet_list);
|
||||
}
|
||||
|
||||
bool ForwardErrorCorrection::InitRecovery(const FecPacket* fec_packet,
|
||||
RecoveredPacket* recovered) {
|
||||
bool ForwardErrorCorrection::StartPacketRecovery(const FecPacket* fec_packet,
|
||||
RecoveredPacket* recovered) {
|
||||
// This is the first packet which we try to recover with.
|
||||
const uint16_t ulp_header_size = fec_packet->pkt->data[0] & 0x40
|
||||
? kUlpHeaderSizeLBitSet
|
||||
@ -655,7 +643,7 @@ bool ForwardErrorCorrection::InitRecovery(const FecPacket* fec_packet,
|
||||
<< "Truncated FEC packet doesn't contain room for ULP header.";
|
||||
return false;
|
||||
}
|
||||
recovered->pkt = new Packet;
|
||||
recovered->pkt = new Packet();
|
||||
memset(recovered->pkt->data, 0, IP_PACKET_SIZE);
|
||||
recovered->returned = false;
|
||||
recovered->was_recovered = true;
|
||||
@ -684,7 +672,7 @@ bool ForwardErrorCorrection::InitRecovery(const FecPacket* fec_packet,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ForwardErrorCorrection::FinishRecovery(RecoveredPacket* recovered) {
|
||||
bool ForwardErrorCorrection::FinishPacketRecovery(RecoveredPacket* recovered) {
|
||||
// Set the RTP version to 2.
|
||||
recovered->pkt->data[0] |= 0x80; // Set the 1st bit.
|
||||
recovered->pkt->data[0] &= 0xbf; // Clear the 2nd bit.
|
||||
@ -729,27 +717,24 @@ void ForwardErrorCorrection::XorPackets(const Packet* src_packet,
|
||||
bool ForwardErrorCorrection::RecoverPacket(
|
||||
const FecPacket* fec_packet,
|
||||
RecoveredPacket* rec_packet_to_insert) {
|
||||
if (!InitRecovery(fec_packet, rec_packet_to_insert))
|
||||
if (!StartPacketRecovery(fec_packet, rec_packet_to_insert))
|
||||
return false;
|
||||
ProtectedPacketList::const_iterator protected_it =
|
||||
fec_packet->protected_pkt_list.begin();
|
||||
while (protected_it != fec_packet->protected_pkt_list.end()) {
|
||||
if ((*protected_it)->pkt == NULL) {
|
||||
for (const auto* protected_packet : fec_packet->protected_pkt_list) {
|
||||
if (protected_packet->pkt == nullptr) {
|
||||
// This is the packet we're recovering.
|
||||
rec_packet_to_insert->seq_num = (*protected_it)->seq_num;
|
||||
rec_packet_to_insert->seq_num = protected_packet->seq_num;
|
||||
} else {
|
||||
XorPackets((*protected_it)->pkt, rec_packet_to_insert);
|
||||
XorPackets(protected_packet->pkt, rec_packet_to_insert);
|
||||
}
|
||||
++protected_it;
|
||||
}
|
||||
if (!FinishRecovery(rec_packet_to_insert))
|
||||
if (!FinishPacketRecovery(rec_packet_to_insert))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ForwardErrorCorrection::AttemptRecover(
|
||||
RecoveredPacketList* recovered_packet_list) {
|
||||
FecPacketList::iterator fec_packet_list_it = fec_packet_list_.begin();
|
||||
auto fec_packet_list_it = fec_packet_list_.begin();
|
||||
while (fec_packet_list_it != fec_packet_list_.end()) {
|
||||
// Search for each FEC packet's protected media packets.
|
||||
int packets_missing = NumCoveredPacketsMissing(*fec_packet_list_it);
|
||||
@ -757,11 +742,11 @@ void ForwardErrorCorrection::AttemptRecover(
|
||||
// We can only recover one packet with an FEC packet.
|
||||
if (packets_missing == 1) {
|
||||
// Recovery possible.
|
||||
RecoveredPacket* packet_to_insert = new RecoveredPacket;
|
||||
packet_to_insert->pkt = NULL;
|
||||
RecoveredPacket* packet_to_insert = new RecoveredPacket();
|
||||
packet_to_insert->pkt = nullptr;
|
||||
if (!RecoverPacket(*fec_packet_list_it, packet_to_insert)) {
|
||||
// Can't recover using this packet, drop it.
|
||||
DiscardFECPacket(*fec_packet_list_it);
|
||||
DiscardFecPacket(*fec_packet_list_it);
|
||||
fec_packet_list_it = fec_packet_list_.erase(fec_packet_list_it);
|
||||
delete packet_to_insert;
|
||||
continue;
|
||||
@ -774,9 +759,9 @@ void ForwardErrorCorrection::AttemptRecover(
|
||||
// the sort.
|
||||
recovered_packet_list->push_back(packet_to_insert);
|
||||
recovered_packet_list->sort(SortablePacket::LessThan);
|
||||
UpdateCoveringFECPackets(packet_to_insert);
|
||||
UpdateCoveringFecPackets(packet_to_insert);
|
||||
DiscardOldPackets(recovered_packet_list);
|
||||
DiscardFECPacket(*fec_packet_list_it);
|
||||
DiscardFecPacket(*fec_packet_list_it);
|
||||
fec_packet_list_it = fec_packet_list_.erase(fec_packet_list_it);
|
||||
|
||||
// A packet has been recovered. We need to check the FEC list again, as
|
||||
@ -786,7 +771,7 @@ void ForwardErrorCorrection::AttemptRecover(
|
||||
} else if (packets_missing == 0) {
|
||||
// Either all protected packets arrived or have been recovered. We can
|
||||
// discard this FEC packet.
|
||||
DiscardFECPacket(*fec_packet_list_it);
|
||||
DiscardFecPacket(*fec_packet_list_it);
|
||||
fec_packet_list_it = fec_packet_list_.erase(fec_packet_list_it);
|
||||
} else {
|
||||
fec_packet_list_it++;
|
||||
@ -797,10 +782,8 @@ void ForwardErrorCorrection::AttemptRecover(
|
||||
int ForwardErrorCorrection::NumCoveredPacketsMissing(
|
||||
const FecPacket* fec_packet) {
|
||||
int packets_missing = 0;
|
||||
ProtectedPacketList::const_iterator it =
|
||||
fec_packet->protected_pkt_list.begin();
|
||||
for (; it != fec_packet->protected_pkt_list.end(); ++it) {
|
||||
if ((*it)->pkt == NULL) {
|
||||
for (const auto* protected_packet : fec_packet->protected_pkt_list) {
|
||||
if (protected_packet->pkt == nullptr) {
|
||||
++packets_missing;
|
||||
if (packets_missing > 1) {
|
||||
break; // We can't recover more than one packet.
|
||||
@ -810,12 +793,12 @@ int ForwardErrorCorrection::NumCoveredPacketsMissing(
|
||||
return packets_missing;
|
||||
}
|
||||
|
||||
void ForwardErrorCorrection::DiscardFECPacket(FecPacket* fec_packet) {
|
||||
void ForwardErrorCorrection::DiscardFecPacket(FecPacket* fec_packet) {
|
||||
while (!fec_packet->protected_pkt_list.empty()) {
|
||||
delete fec_packet->protected_pkt_list.front();
|
||||
fec_packet->protected_pkt_list.pop_front();
|
||||
}
|
||||
assert(fec_packet->protected_pkt_list.empty());
|
||||
RTC_DCHECK(fec_packet->protected_pkt_list.empty());
|
||||
delete fec_packet;
|
||||
}
|
||||
|
||||
@ -827,14 +810,14 @@ void ForwardErrorCorrection::DiscardOldPackets(
|
||||
delete packet;
|
||||
recovered_packet_list->pop_front();
|
||||
}
|
||||
assert(recovered_packet_list->size() <= kMaxMediaPackets);
|
||||
RTC_DCHECK(recovered_packet_list->size() <= kMaxMediaPackets);
|
||||
}
|
||||
|
||||
uint16_t ForwardErrorCorrection::ParseSequenceNumber(uint8_t* packet) {
|
||||
return (packet[2] << 8) + packet[3];
|
||||
}
|
||||
|
||||
int32_t ForwardErrorCorrection::DecodeFEC(
|
||||
int ForwardErrorCorrection::DecodeFec(
|
||||
ReceivedPacketList* received_packet_list,
|
||||
RecoveredPacketList* recovered_packet_list) {
|
||||
// TODO(marpan/ajm): can we check for multiple ULP headers, and return an
|
||||
|
||||
@ -11,12 +11,15 @@
|
||||
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_
|
||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/refcount.h"
|
||||
#include "webrtc/base/scoped_ref_ptr.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -31,7 +34,7 @@ class FecPacket;
|
||||
class ForwardErrorCorrection {
|
||||
public:
|
||||
// Maximum number of media packets we can protect
|
||||
static const unsigned int kMaxMediaPackets = 48u;
|
||||
static constexpr size_t kMaxMediaPackets = 48u;
|
||||
|
||||
// TODO(holmer): As a next step all these struct-like packet classes should be
|
||||
// refactored into proper classes, and their members should be made private.
|
||||
@ -49,7 +52,7 @@ class ForwardErrorCorrection {
|
||||
// reaches zero.
|
||||
virtual int32_t Release();
|
||||
|
||||
size_t length; // Length of packet in bytes.
|
||||
size_t length; // Length of packet in bytes.
|
||||
uint8_t data[IP_PACKET_SIZE]; // Packet data.
|
||||
|
||||
private:
|
||||
@ -66,17 +69,17 @@ class ForwardErrorCorrection {
|
||||
uint16_t seq_num;
|
||||
};
|
||||
|
||||
// The received list parameter of #DecodeFEC() must reference structs of this
|
||||
// The received list parameter of #DecodeFec() must reference structs of this
|
||||
// type. The last_media_pkt_in_frame is not required to be used for correct
|
||||
// recovery, but will reduce delay by allowing #DecodeFEC() to pre-emptively
|
||||
// recovery, but will reduce delay by allowing #DecodeFec() to pre-emptively
|
||||
// determine frame completion. If set, we assume a FEC stream, and the
|
||||
// following assumptions must hold:\n
|
||||
// following assumptions must hold:
|
||||
//
|
||||
// 1. The media packets in a frame have contiguous sequence numbers, i.e. the
|
||||
// frame's FEC packets have sequence numbers either lower than the first
|
||||
// media packet or higher than the last media packet.\n
|
||||
// media packet or higher than the last media packet.
|
||||
// 2. All FEC packets have a sequence number base equal to the first media
|
||||
// packet in the corresponding frame.\n
|
||||
// packet in the corresponding frame.
|
||||
//
|
||||
// The ssrc member is needed to ensure we can restore the SSRC field of
|
||||
// recovered packets. In most situations this could be retrieved from other
|
||||
@ -95,7 +98,7 @@ class ForwardErrorCorrection {
|
||||
rtc::scoped_refptr<Packet> pkt; // Pointer to the packet storage.
|
||||
};
|
||||
|
||||
// The recovered list parameter of #DecodeFEC() will reference structs of
|
||||
// The recovered list parameter of #DecodeFec() will reference structs of
|
||||
// this type.
|
||||
// TODO(holmer): Refactor into a proper class.
|
||||
class RecoveredPacket : public SortablePacket {
|
||||
@ -118,7 +121,6 @@ class ForwardErrorCorrection {
|
||||
typedef std::list<RecoveredPacket*> RecoveredPacketList;
|
||||
|
||||
ForwardErrorCorrection();
|
||||
|
||||
virtual ~ForwardErrorCorrection();
|
||||
|
||||
/**
|
||||
@ -153,14 +155,14 @@ class ForwardErrorCorrection {
|
||||
* \param[out] fecPacketList List of FEC packets, of type #Packet. Must
|
||||
* be empty on entry. The memory available
|
||||
* through the list will be valid until the
|
||||
* next call to GenerateFEC().
|
||||
* next call to GenerateFec().
|
||||
*
|
||||
* \return 0 on success, -1 on failure.
|
||||
*/
|
||||
int32_t GenerateFEC(const PacketList& media_packet_list,
|
||||
uint8_t protection_factor, int num_important_packets,
|
||||
bool use_unequal_protection, FecMaskType fec_mask_type,
|
||||
PacketList* fec_packet_list);
|
||||
int GenerateFec(const PacketList& media_packet_list,
|
||||
uint8_t protection_factor, int num_important_packets,
|
||||
bool use_unequal_protection, FecMaskType fec_mask_type,
|
||||
PacketList* fec_packet_list);
|
||||
|
||||
/**
|
||||
* Decodes a list of media and FEC packets. It will parse the input received
|
||||
@ -169,13 +171,13 @@ class ForwardErrorCorrection {
|
||||
* ascending sequence number and have duplicates removed. The function
|
||||
* should be called as new packets arrive, with the recovered list being
|
||||
* progressively assembled with each call. The received packet list will be
|
||||
* empty at output.\n
|
||||
* empty at output.
|
||||
*
|
||||
* The user will allocate packets submitted through the received list. The
|
||||
* function will handle allocation of recovered packets and optionally
|
||||
* deleting of all packet memory. The user may delete the recovered list
|
||||
* packets, in which case they must remove deleted packets from the
|
||||
* recovered list.\n
|
||||
* recovered list.
|
||||
*
|
||||
* \param[in] receivedPacketList List of new received packets, of type
|
||||
* #ReceivedPacket, belonging to a single
|
||||
@ -186,12 +188,12 @@ class ForwardErrorCorrection {
|
||||
* #RecoveredPacket, belonging to a single
|
||||
* frame. The memory available through the
|
||||
* list will be valid until the next call to
|
||||
* DecodeFEC().
|
||||
* DecodeFec().
|
||||
*
|
||||
* \return 0 on success, -1 on failure.
|
||||
*/
|
||||
int32_t DecodeFEC(ReceivedPacketList* received_packet_list,
|
||||
RecoveredPacketList* recovered_packet_list);
|
||||
int DecodeFec(ReceivedPacketList* received_packet_list,
|
||||
RecoveredPacketList* recovered_packet_list);
|
||||
|
||||
// Get the number of FEC packets, given the number of media packets and the
|
||||
// protection factor.
|
||||
@ -209,10 +211,6 @@ class ForwardErrorCorrection {
|
||||
private:
|
||||
typedef std::list<FecPacket*> FecPacketList;
|
||||
|
||||
void GenerateFecUlpHeaders(const PacketList& media_packet_list,
|
||||
uint8_t* packet_mask, bool l_bit,
|
||||
int num_fec_packets);
|
||||
|
||||
// Analyzes |media_packets| for holes in the sequence and inserts zero columns
|
||||
// into the |packet_mask| where those holes are found. Zero columns means that
|
||||
// those packets will have no protection.
|
||||
@ -244,6 +242,10 @@ class ForwardErrorCorrection {
|
||||
int num_fec_packets, int new_bit_index,
|
||||
int old_bit_index);
|
||||
|
||||
void GenerateFecUlpHeaders(const PacketList& media_packet_list,
|
||||
uint8_t* packet_mask, int num_fec_packets,
|
||||
bool l_bit);
|
||||
|
||||
void GenerateFecBitStrings(const PacketList& media_packet_list,
|
||||
uint8_t* packet_mask, int num_fec_packets,
|
||||
bool l_bit);
|
||||
@ -261,10 +263,10 @@ class ForwardErrorCorrection {
|
||||
// Note: This reduces the complexity when we want to try to recover a packet
|
||||
// since we don't have to find the intersection between recovered packets and
|
||||
// packets covered by the FEC packet.
|
||||
void UpdateCoveringFECPackets(RecoveredPacket* packet);
|
||||
void UpdateCoveringFecPackets(RecoveredPacket* packet);
|
||||
|
||||
// Insert packet into FEC list. We delete duplicates.
|
||||
void InsertFECPacket(ReceivedPacket* rx_packet,
|
||||
void InsertFecPacket(ReceivedPacket* rx_packet,
|
||||
const RecoveredPacketList* recovered_packet_list);
|
||||
|
||||
// Assigns pointers to already recovered packets covered by this FEC packet.
|
||||
@ -279,15 +281,15 @@ class ForwardErrorCorrection {
|
||||
void AttemptRecover(RecoveredPacketList* recovered_packet_list);
|
||||
|
||||
// Initializes the packet recovery using the FEC packet.
|
||||
static bool InitRecovery(const FecPacket* fec_packet,
|
||||
RecoveredPacket* recovered);
|
||||
static bool StartPacketRecovery(const FecPacket* fec_packet,
|
||||
RecoveredPacket* recovered);
|
||||
|
||||
// Performs XOR between |src_packet| and |dst_packet| and stores the result
|
||||
// in |dst_packet|.
|
||||
static void XorPackets(const Packet* src_packet, RecoveredPacket* dst_packet);
|
||||
|
||||
// Finish up the recovery of a packet.
|
||||
static bool FinishRecovery(RecoveredPacket* recovered);
|
||||
static bool FinishPacketRecovery(RecoveredPacket* recovered);
|
||||
|
||||
// Recover a missing packet.
|
||||
bool RecoverPacket(const FecPacket* fec_packet,
|
||||
@ -299,13 +301,18 @@ class ForwardErrorCorrection {
|
||||
// This function returns 2 when two or more packets are missing.
|
||||
static int NumCoveredPacketsMissing(const FecPacket* fec_packet);
|
||||
|
||||
static void DiscardFECPacket(FecPacket* fec_packet);
|
||||
static void DiscardFecPacket(FecPacket* fec_packet);
|
||||
static void DiscardOldPackets(RecoveredPacketList* recovered_packet_list);
|
||||
static uint16_t ParseSequenceNumber(uint8_t* packet);
|
||||
|
||||
std::vector<Packet> generated_fec_packets_;
|
||||
FecPacketList fec_packet_list_;
|
||||
bool fec_packet_received_;
|
||||
|
||||
// Arrays used to avoid dynamically allocating memory when generating
|
||||
// the packet masks in the ULPFEC headers.
|
||||
// (There are never more than |kMaxMediaPackets| FEC packets generated.)
|
||||
uint8_t packet_mask_[kMaxMediaPackets * kMaskSizeLBitSet];
|
||||
uint8_t tmp_packet_mask_[kMaxMediaPackets * kMaskSizeLBitSet];
|
||||
};
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_
|
||||
|
||||
@ -11,15 +11,15 @@
|
||||
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_INTERNAL_H_
|
||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_INTERNAL_H_
|
||||
|
||||
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Packet mask size in bytes (L bit is set).
|
||||
static const int kMaskSizeLBitSet = 6;
|
||||
constexpr size_t kMaskSizeLBitSet = 6;
|
||||
// Packet mask size in bytes (L bit is cleared).
|
||||
static const int kMaskSizeLBitClear = 2;
|
||||
constexpr size_t kMaskSizeLBitClear = 2;
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
@ -18,11 +18,11 @@ namespace webrtc {
|
||||
|
||||
enum { kREDForFECHeaderLength = 1 };
|
||||
// This controls the maximum amount of excess overhead (actual - target)
|
||||
// allowed in order to trigger GenerateFEC(), before |params_.max_fec_frames|
|
||||
// allowed in order to trigger GenerateFec(), before |params_.max_fec_frames|
|
||||
// is reached. Overhead here is defined as relative to number of media packets.
|
||||
enum { kMaxExcessOverhead = 50 }; // Q8.
|
||||
// This is the minimum number of media packets required (above some protection
|
||||
// level) in order to trigger GenerateFEC(), before |params_.max_fec_frames| is
|
||||
// level) in order to trigger GenerateFec(), before |params_.max_fec_frames| is
|
||||
// reached.
|
||||
enum { kMinimumMediaPackets = 4 };
|
||||
// Threshold on the received FEC protection level, above which we enforce at
|
||||
@ -139,7 +139,8 @@ int ProducerFec::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
|
||||
const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false;
|
||||
if (media_packets_fec_.size() < ForwardErrorCorrection::kMaxMediaPackets) {
|
||||
// Generic FEC can only protect up to kMaxMediaPackets packets.
|
||||
ForwardErrorCorrection::Packet* packet = new ForwardErrorCorrection::Packet;
|
||||
ForwardErrorCorrection::Packet* packet =
|
||||
new ForwardErrorCorrection::Packet();
|
||||
packet->length = payload_length + rtp_header_length;
|
||||
memcpy(packet->data, data_buffer, packet->length);
|
||||
media_packets_fec_.push_back(packet);
|
||||
@ -159,7 +160,7 @@ int ProducerFec::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
|
||||
static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets));
|
||||
// TODO(pbos): Consider whether unequal protection should be enabled or not,
|
||||
// it is currently always disabled.
|
||||
int ret = fec_->GenerateFEC(media_packets_fec_, params_.fec_rate,
|
||||
int ret = fec_->GenerateFec(media_packets_fec_, params_.fec_rate,
|
||||
num_first_partition_, false,
|
||||
params_.fec_mask_type, &fec_packets_);
|
||||
if (fec_packets_.empty()) {
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_PRODUCER_FEC_H_
|
||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_PRODUCER_FEC_H_
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
|
||||
@ -72,8 +71,8 @@ class ProducerFec {
|
||||
void DeletePackets();
|
||||
int Overhead() const;
|
||||
ForwardErrorCorrection* fec_;
|
||||
std::list<ForwardErrorCorrection::Packet*> media_packets_fec_;
|
||||
std::list<ForwardErrorCorrection::Packet*> fec_packets_;
|
||||
ForwardErrorCorrection::PacketList media_packets_fec_;
|
||||
ForwardErrorCorrection::PacketList fec_packets_;
|
||||
int num_frames_;
|
||||
int num_first_partition_;
|
||||
int minimum_media_packets_fec_;
|
||||
|
||||
@ -44,7 +44,7 @@ class ProducerFecTest : public ::testing::Test {
|
||||
virtual void SetUp() {
|
||||
fec_ = new ForwardErrorCorrection();
|
||||
producer_ = new ProducerFec(fec_);
|
||||
generator_ = new FrameGenerator;
|
||||
generator_ = new FrameGenerator();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
@ -99,7 +100,7 @@ TEST_F(RtpFecTest, FecRecoveryNoLoss) {
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(media_packet_list_, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty, &fec_packet_list_));
|
||||
|
||||
@ -111,7 +112,7 @@ TEST_F(RtpFecTest, FecRecoveryNoLoss) {
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// No packets lost, expect complete recovery.
|
||||
@ -126,7 +127,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss) {
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(media_packet_list_, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty, &fec_packet_list_));
|
||||
|
||||
@ -140,7 +141,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss) {
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0,
|
||||
fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
|
||||
fec_->DecodeFec(&received_packet_list_, &recovered_packet_list_));
|
||||
|
||||
// One packet lost, one FEC packet, expect complete recovery.
|
||||
EXPECT_TRUE(IsRecoveryComplete());
|
||||
@ -153,7 +154,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss) {
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// 2 packets lost, one FEC packet, cannot get complete recovery.
|
||||
@ -176,7 +177,7 @@ TEST_F(RtpFecTest, FecRecoveryWithSeqNumGapTwoFrames) {
|
||||
// Construct media packets for first frame, starting at sequence number 0.
|
||||
fec_seq_num_ = ConstructMediaPacketsSeqNum(2, 0);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(media_packet_list_, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty, &fec_packet_list_));
|
||||
// Expect 1 FEC packet.
|
||||
@ -200,7 +201,7 @@ TEST_F(RtpFecTest, FecRecoveryWithSeqNumGapTwoFrames) {
|
||||
ReceivedPackets(media_packet_list_, media_loss_mask_, false);
|
||||
|
||||
EXPECT_EQ(0,
|
||||
fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
|
||||
fec_->DecodeFec(&received_packet_list_, &recovered_packet_list_));
|
||||
|
||||
// Expect that no decoding is done to get missing packet (seq#0) of second
|
||||
// frame, using old FEC packet (seq#2) from first (old) frame. So number of
|
||||
@ -222,7 +223,7 @@ TEST_F(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameRecovery) {
|
||||
// #65534(media) #65535(media) #0(media) #1(FEC).
|
||||
fec_seq_num_ = ConstructMediaPacketsSeqNum(3, 65534);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(media_packet_list_, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty, &fec_packet_list_));
|
||||
|
||||
@ -238,7 +239,7 @@ TEST_F(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameRecovery) {
|
||||
ReceivedPackets(fec_packet_list_, fec_loss_mask_, true);
|
||||
|
||||
EXPECT_EQ(0,
|
||||
fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
|
||||
fec_->DecodeFec(&received_packet_list_, &recovered_packet_list_));
|
||||
|
||||
// Expect 3 media packets in recovered list, and complete recovery.
|
||||
// Wrap-around won't remove FEC packet, as it follows the wrap.
|
||||
@ -264,7 +265,7 @@ TEST_F(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameNoRecovery) {
|
||||
// #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC).
|
||||
fec_seq_num_ = ConstructMediaPacketsSeqNum(3, 65532);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(media_packet_list_, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty, &fec_packet_list_));
|
||||
|
||||
@ -280,7 +281,7 @@ TEST_F(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameNoRecovery) {
|
||||
ReceivedPackets(fec_packet_list_, fec_loss_mask_, true);
|
||||
|
||||
EXPECT_EQ(0,
|
||||
fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
|
||||
fec_->DecodeFec(&received_packet_list_, &recovered_packet_list_));
|
||||
|
||||
// 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
|
||||
@ -303,7 +304,7 @@ TEST_F(RtpFecTest, FecRecoveryWithFecOutOfOrder) {
|
||||
// #0(media) #1(media) #2(media) #3(FEC).
|
||||
fec_seq_num_ = ConstructMediaPacketsSeqNum(3, 0);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(media_packet_list_, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty, &fec_packet_list_));
|
||||
|
||||
@ -320,7 +321,7 @@ TEST_F(RtpFecTest, FecRecoveryWithFecOutOfOrder) {
|
||||
ReceivedPackets(media_packet_list_, media_loss_mask_, false);
|
||||
|
||||
EXPECT_EQ(0,
|
||||
fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
|
||||
fec_->DecodeFec(&received_packet_list_, &recovered_packet_list_));
|
||||
|
||||
// Expect 3 media packets in recovered list, and complete recovery.
|
||||
EXPECT_EQ(3, static_cast<int>(recovered_packet_list_.size()));
|
||||
@ -349,7 +350,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(media_packet_list_, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskRandom, &fec_packet_list_));
|
||||
|
||||
@ -366,7 +367,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0,
|
||||
fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
|
||||
fec_->DecodeFec(&received_packet_list_, &recovered_packet_list_));
|
||||
|
||||
// With media packet#1 and FEC packets #1, #2, #3, expect complete recovery.
|
||||
EXPECT_TRUE(IsRecoveryComplete());
|
||||
@ -381,7 +382,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// Cannot get complete recovery for this loss configuration with random mask.
|
||||
@ -409,7 +410,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(media_packet_list_, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty, &fec_packet_list_));
|
||||
|
||||
@ -425,7 +426,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// Expect complete recovery for consecutive packet loss <= 50%.
|
||||
@ -441,7 +442,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// Expect complete recovery for consecutive packet loss <= 50%.
|
||||
@ -457,7 +458,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// Cannot get complete recovery for this loss configuration.
|
||||
@ -472,7 +473,7 @@ TEST_F(RtpFecTest, FecRecoveryNoLossUep) {
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(media_packet_list_, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty, &fec_packet_list_));
|
||||
|
||||
@ -485,7 +486,7 @@ TEST_F(RtpFecTest, FecRecoveryNoLossUep) {
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0,
|
||||
fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_));
|
||||
fec_->DecodeFec(&received_packet_list_, &recovered_packet_list_));
|
||||
|
||||
// No packets lost, expect complete recovery.
|
||||
EXPECT_TRUE(IsRecoveryComplete());
|
||||
@ -499,7 +500,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLossUep) {
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(media_packet_list_, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty, &fec_packet_list_));
|
||||
|
||||
@ -512,7 +513,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLossUep) {
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// One packet lost, one FEC packet, expect complete recovery.
|
||||
@ -526,7 +527,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLossUep) {
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// 2 packets lost, one FEC packet, cannot get complete recovery.
|
||||
@ -552,7 +553,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(media_packet_list_, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskRandom, &fec_packet_list_));
|
||||
|
||||
@ -568,7 +569,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// With media packet#3 and FEC packets #0, #1, #3, expect complete recovery.
|
||||
@ -585,7 +586,7 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// Cannot get complete recovery for this loss configuration.
|
||||
@ -604,12 +605,12 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
|
||||
// This list should have every other packet removed.
|
||||
PacketList protected_media_packets;
|
||||
int i = 0;
|
||||
for (PacketList::iterator it = media_packet_list_.begin();
|
||||
it != media_packet_list_.end(); ++it, ++i) {
|
||||
for (auto it = media_packet_list_.begin(); it != media_packet_list_.end();
|
||||
++it, ++i) {
|
||||
if (i % 2 == 0) protected_media_packets.push_back(*it);
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(protected_media_packets, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty, &fec_packet_list_));
|
||||
|
||||
@ -622,7 +623,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
|
||||
media_loss_mask_[2] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// One packet lost, one FEC packet, expect complete recovery.
|
||||
@ -635,7 +636,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
|
||||
media_loss_mask_[1] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// Unprotected packet lost. Recovery not possible.
|
||||
@ -649,7 +650,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
|
||||
media_loss_mask_[2] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// 2 protected packets lost, one FEC packet, cannot get complete recovery.
|
||||
@ -668,15 +669,15 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
|
||||
// This list should have every other packet removed.
|
||||
PacketList protected_media_packets;
|
||||
int i = 0;
|
||||
for (PacketList::iterator it = media_packet_list_.begin();
|
||||
it != media_packet_list_.end(); ++it, ++i) {
|
||||
for (auto it = media_packet_list_.begin(); it != media_packet_list_.end();
|
||||
++it, ++i) {
|
||||
if (i % 2 == 0) protected_media_packets.push_back(*it);
|
||||
}
|
||||
|
||||
// Zero column insertion will have to extend the size of the packet
|
||||
// mask since the number of actual packets are 21, while the number
|
||||
// of protected packets are 11.
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(protected_media_packets, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty, &fec_packet_list_));
|
||||
|
||||
@ -689,7 +690,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
|
||||
media_loss_mask_[kNumMediaPackets - 1] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// One packet lost, one FEC packet, expect complete recovery.
|
||||
@ -702,7 +703,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
|
||||
media_loss_mask_[kNumMediaPackets - 2] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// Unprotected packet lost. Recovery not possible.
|
||||
@ -720,7 +721,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
|
||||
media_loss_mask_[kNumMediaPackets - 1] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// 5 protected packets lost, one FEC packet, cannot get complete recovery.
|
||||
@ -739,15 +740,15 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
|
||||
// This list should have every other packet removed.
|
||||
PacketList protected_media_packets;
|
||||
int i = 0;
|
||||
for (PacketList::iterator it = media_packet_list_.begin();
|
||||
it != media_packet_list_.end(); ++it, ++i) {
|
||||
for (auto it = media_packet_list_.begin(); it != media_packet_list_.end();
|
||||
++it, ++i) {
|
||||
if (i % 2 == 0) protected_media_packets.push_back(*it);
|
||||
}
|
||||
|
||||
// Zero column insertion will have to extend the size of the packet
|
||||
// mask since the number of actual packets are 21, while the number
|
||||
// of protected packets are 11.
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets, kProtectionFactor,
|
||||
EXPECT_EQ(0, fec_->GenerateFec(protected_media_packets, kProtectionFactor,
|
||||
kNumImportantPackets, kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty, &fec_packet_list_));
|
||||
|
||||
@ -760,7 +761,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
|
||||
media_loss_mask_[kNumMediaPackets - 1] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// One packet lost, one FEC packet, expect complete recovery.
|
||||
@ -773,7 +774,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
|
||||
media_loss_mask_[kNumMediaPackets - 2] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// Unprotected packet lost. Recovery not possible.
|
||||
@ -791,7 +792,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
|
||||
media_loss_mask_[kNumMediaPackets - 1] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
EXPECT_EQ(0, fec_->DecodeFec(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// 5 protected packets lost, one FEC packet, cannot get complete recovery.
|
||||
@ -811,36 +812,27 @@ void RtpFecTest::FreeRecoveredPacketList() {
|
||||
}
|
||||
|
||||
bool RtpFecTest::IsRecoveryComplete() {
|
||||
// Check that the number of media and recovered packets are equal.
|
||||
if (media_packet_list_.size() != recovered_packet_list_.size()) {
|
||||
// We must have equally many recovered packets as original packets.
|
||||
if (recovered_packet_list_.size() != media_packet_list_.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ForwardErrorCorrection::Packet* media_packet;
|
||||
ForwardErrorCorrection::RecoveredPacket* recovered_packet;
|
||||
|
||||
bool recovery = true;
|
||||
|
||||
PacketList::iterator media_packet_list_item = media_packet_list_.begin();
|
||||
RecoveredPacketList::iterator recovered_packet_list_item =
|
||||
recovered_packet_list_.begin();
|
||||
while (media_packet_list_item != media_packet_list_.end()) {
|
||||
if (recovered_packet_list_item == recovered_packet_list_.end()) {
|
||||
// All recovered packets must be identical to the corresponding
|
||||
// original packets.
|
||||
auto cmp = [](ForwardErrorCorrection::Packet* media_packet,
|
||||
ForwardErrorCorrection::RecoveredPacket* recovered_packet) {
|
||||
if (media_packet->length != recovered_packet->pkt->length) {
|
||||
return false;
|
||||
}
|
||||
media_packet = *media_packet_list_item;
|
||||
recovered_packet = *recovered_packet_list_item;
|
||||
if (recovered_packet->pkt->length != media_packet->length) {
|
||||
return false;
|
||||
}
|
||||
if (memcmp(recovered_packet->pkt->data, media_packet->data,
|
||||
if (memcmp(media_packet->data,
|
||||
recovered_packet->pkt->data,
|
||||
media_packet->length) != 0) {
|
||||
return false;
|
||||
}
|
||||
media_packet_list_item++;
|
||||
recovered_packet_list_item++;
|
||||
}
|
||||
return recovery;
|
||||
return true;
|
||||
};
|
||||
return std::equal(media_packet_list_.cbegin(), media_packet_list_.cend(),
|
||||
recovered_packet_list_.cbegin(), cmp);
|
||||
}
|
||||
|
||||
void RtpFecTest::NetworkReceivedPackets() {
|
||||
@ -851,18 +843,13 @@ void RtpFecTest::NetworkReceivedPackets() {
|
||||
|
||||
void RtpFecTest::ReceivedPackets(const PacketList& packet_list, int* loss_mask,
|
||||
bool is_fec) {
|
||||
ForwardErrorCorrection::Packet* packet;
|
||||
ForwardErrorCorrection::ReceivedPacket* received_packet;
|
||||
int seq_num = fec_seq_num_;
|
||||
int packet_idx = 0;
|
||||
|
||||
PacketList::const_iterator packet_list_item = packet_list.begin();
|
||||
|
||||
while (packet_list_item != packet_list.end()) {
|
||||
packet = *packet_list_item;
|
||||
for (const auto* packet : packet_list) {
|
||||
if (loss_mask[packet_idx] == 0) {
|
||||
received_packet = new ForwardErrorCorrection::ReceivedPacket;
|
||||
received_packet->pkt = new ForwardErrorCorrection::Packet;
|
||||
auto received_packet = new ForwardErrorCorrection::ReceivedPacket();
|
||||
received_packet->pkt = new ForwardErrorCorrection::Packet();
|
||||
received_packet_list_.push_back(received_packet);
|
||||
received_packet->pkt->length = packet->length;
|
||||
memcpy(received_packet->pkt->data, packet->data, packet->length);
|
||||
@ -884,7 +871,6 @@ void RtpFecTest::ReceivedPackets(const PacketList& packet_list, int* loss_mask,
|
||||
}
|
||||
}
|
||||
packet_idx++;
|
||||
packet_list_item++;
|
||||
// Sequence number of FEC packets are defined as increment by 1 from
|
||||
// last media packet in frame.
|
||||
if (is_fec) seq_num++;
|
||||
@ -893,13 +879,13 @@ void RtpFecTest::ReceivedPackets(const PacketList& packet_list, int* loss_mask,
|
||||
|
||||
int RtpFecTest::ConstructMediaPacketsSeqNum(int num_media_packets,
|
||||
int start_seq_num) {
|
||||
assert(num_media_packets > 0);
|
||||
RTC_DCHECK_GT(num_media_packets, 0);
|
||||
ForwardErrorCorrection::Packet* media_packet = NULL;
|
||||
int sequence_number = start_seq_num;
|
||||
int time_stamp = random_.Rand<int>();
|
||||
|
||||
for (int i = 0; i < num_media_packets; ++i) {
|
||||
media_packet = new ForwardErrorCorrection::Packet;
|
||||
media_packet = new ForwardErrorCorrection::Packet();
|
||||
media_packet_list_.push_back(media_packet);
|
||||
const uint32_t kMinPacketSize = kRtpHeaderSize;
|
||||
const uint32_t kMaxPacketSize = IP_PACKET_SIZE - kRtpHeaderSize -
|
||||
@ -937,7 +923,7 @@ int RtpFecTest::ConstructMediaPacketsSeqNum(int num_media_packets,
|
||||
sequence_number++;
|
||||
}
|
||||
// Last packet, set marker bit.
|
||||
assert(media_packet != NULL);
|
||||
RTC_DCHECK(media_packet);
|
||||
media_packet->data[1] |= 0x80;
|
||||
return sequence_number;
|
||||
}
|
||||
|
||||
@ -13,9 +13,6 @@
|
||||
* functions in ForwardErrorCorrection directly.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
@ -38,46 +35,45 @@ namespace test {
|
||||
using fec_private_tables::kPacketMaskBurstyTbl;
|
||||
|
||||
void ReceivePackets(
|
||||
ForwardErrorCorrection::ReceivedPacketList* toDecodeList,
|
||||
ForwardErrorCorrection::ReceivedPacketList* receivedPacketList,
|
||||
size_t numPacketsToDecode,
|
||||
float reorderRate,
|
||||
float duplicateRate,
|
||||
ForwardErrorCorrection::ReceivedPacketList* to_decode_list,
|
||||
ForwardErrorCorrection::ReceivedPacketList* received_packet_list,
|
||||
size_t num_packets_to_decode,
|
||||
float reorder_rate,
|
||||
float duplicate_rate,
|
||||
Random* random) {
|
||||
assert(toDecodeList->empty());
|
||||
assert(numPacketsToDecode <= receivedPacketList->size());
|
||||
RTC_DCHECK(to_decode_list->empty());
|
||||
RTC_DCHECK_LE(num_packets_to_decode, received_packet_list->size());
|
||||
|
||||
ForwardErrorCorrection::ReceivedPacketList::iterator it;
|
||||
for (size_t i = 0; i < numPacketsToDecode; i++) {
|
||||
it = receivedPacketList->begin();
|
||||
for (size_t i = 0; i < num_packets_to_decode; i++) {
|
||||
auto it = received_packet_list->begin();
|
||||
// Reorder packets.
|
||||
float randomVariable = random->Rand<float>();
|
||||
while (randomVariable < reorderRate) {
|
||||
float random_variable = random->Rand<float>();
|
||||
while (random_variable < reorder_rate) {
|
||||
++it;
|
||||
if (it == receivedPacketList->end()) {
|
||||
if (it == received_packet_list->end()) {
|
||||
--it;
|
||||
break;
|
||||
}
|
||||
randomVariable = random->Rand<float>();
|
||||
random_variable = random->Rand<float>();
|
||||
}
|
||||
ForwardErrorCorrection::ReceivedPacket* receivedPacket = *it;
|
||||
toDecodeList->push_back(receivedPacket);
|
||||
ForwardErrorCorrection::ReceivedPacket* received_packet = *it;
|
||||
to_decode_list->push_back(received_packet);
|
||||
|
||||
// Duplicate packets.
|
||||
randomVariable = random->Rand<float>();
|
||||
while (randomVariable < duplicateRate) {
|
||||
ForwardErrorCorrection::ReceivedPacket* duplicatePacket =
|
||||
new ForwardErrorCorrection::ReceivedPacket;
|
||||
*duplicatePacket = *receivedPacket;
|
||||
duplicatePacket->pkt = new ForwardErrorCorrection::Packet;
|
||||
memcpy(duplicatePacket->pkt->data, receivedPacket->pkt->data,
|
||||
receivedPacket->pkt->length);
|
||||
duplicatePacket->pkt->length = receivedPacket->pkt->length;
|
||||
random_variable = random->Rand<float>();
|
||||
while (random_variable < duplicate_rate) {
|
||||
ForwardErrorCorrection::ReceivedPacket* duplicate_packet =
|
||||
new ForwardErrorCorrection::ReceivedPacket();
|
||||
*duplicate_packet = *received_packet;
|
||||
duplicate_packet->pkt = new ForwardErrorCorrection::Packet();
|
||||
memcpy(duplicate_packet->pkt->data, received_packet->pkt->data,
|
||||
received_packet->pkt->length);
|
||||
duplicate_packet->pkt->length = received_packet->pkt->length;
|
||||
|
||||
toDecodeList->push_back(duplicatePacket);
|
||||
randomVariable = random->Rand<float>();
|
||||
to_decode_list->push_back(duplicate_packet);
|
||||
random_variable = random->Rand<float>();
|
||||
}
|
||||
receivedPacketList->erase(it);
|
||||
received_packet_list->erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,94 +107,100 @@ TEST(FecTest, MAYBE_FecTest) {
|
||||
<< "equal to 12.";
|
||||
|
||||
ForwardErrorCorrection fec;
|
||||
ForwardErrorCorrection::PacketList mediaPacketList;
|
||||
ForwardErrorCorrection::PacketList fecPacketList;
|
||||
ForwardErrorCorrection::ReceivedPacketList toDecodeList;
|
||||
ForwardErrorCorrection::ReceivedPacketList receivedPacketList;
|
||||
ForwardErrorCorrection::RecoveredPacketList recoveredPacketList;
|
||||
std::list<uint8_t*> fecMaskList;
|
||||
ForwardErrorCorrection::PacketList media_packet_list;
|
||||
ForwardErrorCorrection::PacketList fec_packet_list;
|
||||
ForwardErrorCorrection::ReceivedPacketList to_decode_list;
|
||||
ForwardErrorCorrection::ReceivedPacketList received_packet_list;
|
||||
ForwardErrorCorrection::RecoveredPacketList recovered_packet_list;
|
||||
std::list<uint8_t*> fec_mask_list;
|
||||
|
||||
ForwardErrorCorrection::Packet* mediaPacket = NULL;
|
||||
ForwardErrorCorrection::Packet* media_packet = nullptr;
|
||||
// Running over only one loss rate to limit execution time.
|
||||
const float lossRate[] = {0.5f};
|
||||
const uint32_t lossRateSize = sizeof(lossRate) / sizeof(*lossRate);
|
||||
const float reorderRate = 0.1f;
|
||||
const float duplicateRate = 0.1f;
|
||||
const float loss_rate[] = {0.5f};
|
||||
const uint32_t loss_rate_size = sizeof(loss_rate) / sizeof(*loss_rate);
|
||||
const float reorder_rate = 0.1f;
|
||||
const float duplicate_rate = 0.1f;
|
||||
|
||||
uint8_t mediaLossMask[kMaxNumberMediaPackets];
|
||||
uint8_t fecLossMask[kMaxNumberFecPackets];
|
||||
uint8_t fecPacketMasks[kMaxNumberFecPackets][kMaxNumberMediaPackets];
|
||||
uint8_t media_loss_mask[kMaxNumberMediaPackets];
|
||||
uint8_t fec_loss_mask[kMaxNumberFecPackets];
|
||||
uint8_t fec_packet_masks[kMaxNumberFecPackets][kMaxNumberMediaPackets];
|
||||
|
||||
// Seed the random number generator, storing the seed to file in order to
|
||||
// reproduce past results.
|
||||
const unsigned int randomSeed = static_cast<unsigned int>(time(NULL));
|
||||
Random random(randomSeed);
|
||||
const unsigned int random_seed = static_cast<unsigned int>(time(nullptr));
|
||||
Random random(random_seed);
|
||||
std::string filename = webrtc::test::OutputPath() + "randomSeedLog.txt";
|
||||
FILE* randomSeedFile = fopen(filename.c_str(), "a");
|
||||
fprintf(randomSeedFile, "%u\n", randomSeed);
|
||||
fclose(randomSeedFile);
|
||||
randomSeedFile = NULL;
|
||||
FILE* random_seed_file = fopen(filename.c_str(), "a");
|
||||
fprintf(random_seed_file, "%u\n", random_seed);
|
||||
fclose(random_seed_file);
|
||||
random_seed_file = nullptr;
|
||||
|
||||
uint16_t seqNum = 0;
|
||||
uint32_t timeStamp = random.Rand<uint32_t>();
|
||||
uint16_t seq_num = 0;
|
||||
uint32_t timestamp = random.Rand<uint32_t>();
|
||||
const uint32_t ssrc = random.Rand(1u, 0xfffffffe);
|
||||
|
||||
// Loop over the mask types: random and bursty.
|
||||
for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes;
|
||||
++mask_type_idx) {
|
||||
for (uint32_t lossRateIdx = 0; lossRateIdx < lossRateSize; ++lossRateIdx) {
|
||||
printf("Loss rate: %.2f, Mask type %d \n", lossRate[lossRateIdx],
|
||||
for (uint32_t loss_rate_idx = 0; loss_rate_idx < loss_rate_size;
|
||||
++loss_rate_idx) {
|
||||
printf("Loss rate: %.2f, Mask type %d \n", loss_rate[loss_rate_idx],
|
||||
mask_type_idx);
|
||||
|
||||
const uint32_t packetMaskMax = kMaxMediaPackets[mask_type_idx];
|
||||
uint8_t* packetMask = new uint8_t[packetMaskMax * kNumMaskBytesL1];
|
||||
const uint32_t packet_mask_max = kMaxMediaPackets[mask_type_idx];
|
||||
std::unique_ptr<uint8_t[]> packet_mask(
|
||||
new uint8_t[packet_mask_max * kNumMaskBytesL1]);
|
||||
|
||||
FecMaskType fec_mask_type = kMaskTypes[mask_type_idx];
|
||||
|
||||
for (uint32_t numMediaPackets = 1; numMediaPackets <= packetMaskMax;
|
||||
numMediaPackets++) {
|
||||
internal::PacketMaskTable mask_table(fec_mask_type, numMediaPackets);
|
||||
for (uint32_t num_media_packets = 1; num_media_packets <= packet_mask_max;
|
||||
num_media_packets++) {
|
||||
internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets);
|
||||
|
||||
for (uint32_t numFecPackets = 1;
|
||||
numFecPackets <= numMediaPackets && numFecPackets <= packetMaskMax;
|
||||
numFecPackets++) {
|
||||
// Loop over numImpPackets: usually <= (0.3*numMediaPackets).
|
||||
// For this test we check up to ~ (numMediaPackets / 4).
|
||||
uint32_t maxNumImpPackets = numMediaPackets / 4 + 1;
|
||||
for (uint32_t numImpPackets = 0; numImpPackets <= maxNumImpPackets &&
|
||||
numImpPackets <= packetMaskMax;
|
||||
numImpPackets++) {
|
||||
uint8_t protectionFactor =
|
||||
static_cast<uint8_t>(numFecPackets * 255 / numMediaPackets);
|
||||
for (uint32_t num_fec_packets = 1;
|
||||
num_fec_packets <= num_media_packets &&
|
||||
num_fec_packets <= packet_mask_max;
|
||||
num_fec_packets++) {
|
||||
// Loop over num_imp_packets: usually <= (0.3*num_media_packets).
|
||||
// For this test we check up to ~ (num_media_packets / 4).
|
||||
uint32_t max_num_imp_packets = num_media_packets / 4 + 1;
|
||||
for (uint32_t num_imp_packets = 0;
|
||||
num_imp_packets <= max_num_imp_packets &&
|
||||
num_imp_packets <= packet_mask_max;
|
||||
num_imp_packets++) {
|
||||
uint8_t protection_factor =
|
||||
static_cast<uint8_t>(num_fec_packets * 255 / num_media_packets);
|
||||
|
||||
const uint32_t maskBytesPerFecPacket =
|
||||
(numMediaPackets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0;
|
||||
const uint32_t mask_bytes_per_fec_packet =
|
||||
(num_media_packets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0;
|
||||
|
||||
memset(packetMask, 0, numMediaPackets * maskBytesPerFecPacket);
|
||||
memset(packet_mask.get(), 0,
|
||||
num_media_packets * mask_bytes_per_fec_packet);
|
||||
|
||||
// Transfer packet masks from bit-mask to byte-mask.
|
||||
internal::GeneratePacketMasks(numMediaPackets, numFecPackets,
|
||||
numImpPackets, kUseUnequalProtection,
|
||||
mask_table, packetMask);
|
||||
internal::GeneratePacketMasks(num_media_packets, num_fec_packets,
|
||||
num_imp_packets,
|
||||
kUseUnequalProtection,
|
||||
mask_table, packet_mask.get());
|
||||
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf(
|
||||
"%u media packets, %u FEC packets, %u numImpPackets, "
|
||||
"%u media packets, %u FEC packets, %u num_imp_packets, "
|
||||
"loss rate = %.2f \n",
|
||||
numMediaPackets, numFecPackets, numImpPackets,
|
||||
lossRate[lossRateIdx]);
|
||||
num_media_packets, num_fec_packets, num_imp_packets,
|
||||
loss_rate[loss_rate_idx]);
|
||||
printf("Packet mask matrix \n");
|
||||
#endif
|
||||
|
||||
for (uint32_t i = 0; i < numFecPackets; i++) {
|
||||
for (uint32_t j = 0; j < numMediaPackets; j++) {
|
||||
const uint8_t byteMask =
|
||||
packetMask[i * maskBytesPerFecPacket + j / 8];
|
||||
const uint32_t bitPosition = (7 - j % 8);
|
||||
fecPacketMasks[i][j] =
|
||||
(byteMask & (1 << bitPosition)) >> bitPosition;
|
||||
for (uint32_t i = 0; i < num_fec_packets; i++) {
|
||||
for (uint32_t j = 0; j < num_media_packets; j++) {
|
||||
const uint8_t byte_mask =
|
||||
packet_mask[i * mask_bytes_per_fec_packet + j / 8];
|
||||
const uint32_t bit_position = (7 - j % 8);
|
||||
fec_packet_masks[i][j] =
|
||||
(byte_mask & (1 << bit_position)) >> bit_position;
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf("%u ", fecPacketMasks[i][j]);
|
||||
printf("%u ", fec_packet_masks[i][j]);
|
||||
#endif
|
||||
}
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
@ -209,20 +211,20 @@ TEST(FecTest, MAYBE_FecTest) {
|
||||
printf("\n");
|
||||
#endif
|
||||
// Check for all zero rows or columns: indicates incorrect mask.
|
||||
uint32_t rowLimit = numMediaPackets;
|
||||
for (uint32_t i = 0; i < numFecPackets; ++i) {
|
||||
uint32_t rowSum = 0;
|
||||
for (uint32_t j = 0; j < rowLimit; ++j) {
|
||||
rowSum += fecPacketMasks[i][j];
|
||||
uint32_t row_limit = num_media_packets;
|
||||
for (uint32_t i = 0; i < num_fec_packets; ++i) {
|
||||
uint32_t row_sum = 0;
|
||||
for (uint32_t j = 0; j < row_limit; ++j) {
|
||||
row_sum += fec_packet_masks[i][j];
|
||||
}
|
||||
ASSERT_NE(0u, rowSum) << "Row is all zero " << i;
|
||||
ASSERT_NE(0u, row_sum) << "Row is all zero " << i;
|
||||
}
|
||||
for (uint32_t j = 0; j < rowLimit; ++j) {
|
||||
uint32_t columnSum = 0;
|
||||
for (uint32_t i = 0; i < numFecPackets; ++i) {
|
||||
columnSum += fecPacketMasks[i][j];
|
||||
for (uint32_t j = 0; j < row_limit; ++j) {
|
||||
uint32_t column_sum = 0;
|
||||
for (uint32_t i = 0; i < num_fec_packets; ++i) {
|
||||
column_sum += fec_packet_masks[i][j];
|
||||
}
|
||||
ASSERT_NE(0u, columnSum) << "Column is all zero " << j;
|
||||
ASSERT_NE(0u, column_sum) << "Column is all zero " << j;
|
||||
}
|
||||
|
||||
// Construct media packets.
|
||||
@ -230,19 +232,20 @@ TEST(FecTest, MAYBE_FecTest) {
|
||||
// below, to avoid sequence number wrap-around. In actual decoding,
|
||||
// old FEC packets in list are dropped if sequence number wrap
|
||||
// around is detected. This case is currently not handled below.
|
||||
seqNum = 0;
|
||||
for (uint32_t i = 0; i < numMediaPackets; ++i) {
|
||||
mediaPacket = new ForwardErrorCorrection::Packet;
|
||||
mediaPacketList.push_back(mediaPacket);
|
||||
seq_num = 0;
|
||||
for (uint32_t i = 0; i < num_media_packets; ++i) {
|
||||
media_packet = new ForwardErrorCorrection::Packet();
|
||||
media_packet_list.push_back(media_packet);
|
||||
const uint32_t kMinPacketSize = 12;
|
||||
const uint32_t kMaxPacketSize = static_cast<uint32_t>(
|
||||
IP_PACKET_SIZE - 12 - 28 -
|
||||
ForwardErrorCorrection::PacketOverhead());
|
||||
mediaPacket->length = random.Rand(kMinPacketSize, kMaxPacketSize);
|
||||
media_packet->length = random.Rand(kMinPacketSize,
|
||||
kMaxPacketSize);
|
||||
|
||||
// Generate random values for the first 2 bytes.
|
||||
mediaPacket->data[0] = random.Rand<uint8_t>();
|
||||
mediaPacket->data[1] = random.Rand<uint8_t>();
|
||||
media_packet->data[0] = random.Rand<uint8_t>();
|
||||
media_packet->data[1] = random.Rand<uint8_t>();
|
||||
|
||||
// The first two bits are assumed to be 10 by the
|
||||
// FEC encoder. In fact the FEC decoder will set the
|
||||
@ -250,237 +253,217 @@ TEST(FecTest, MAYBE_FecTest) {
|
||||
// actually were. Set the first two bits to 10
|
||||
// so that a memcmp can be performed for the
|
||||
// whole restored packet.
|
||||
mediaPacket->data[0] |= 0x80;
|
||||
mediaPacket->data[0] &= 0xbf;
|
||||
media_packet->data[0] |= 0x80;
|
||||
media_packet->data[0] &= 0xbf;
|
||||
|
||||
// FEC is applied to a whole frame.
|
||||
// A frame is signaled by multiple packets without
|
||||
// the marker bit set followed by the last packet of
|
||||
// the frame for which the marker bit is set.
|
||||
// Only push one (fake) frame to the FEC.
|
||||
mediaPacket->data[1] &= 0x7f;
|
||||
media_packet->data[1] &= 0x7f;
|
||||
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&mediaPacket->data[2],
|
||||
seqNum);
|
||||
ByteWriter<uint32_t>::WriteBigEndian(&mediaPacket->data[4],
|
||||
timeStamp);
|
||||
ByteWriter<uint32_t>::WriteBigEndian(&mediaPacket->data[8], ssrc);
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&media_packet->data[2],
|
||||
seq_num);
|
||||
ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[4],
|
||||
timestamp);
|
||||
ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[8],
|
||||
ssrc);
|
||||
// Generate random values for payload
|
||||
for (size_t j = 12; j < mediaPacket->length; ++j) {
|
||||
mediaPacket->data[j] = random.Rand<uint8_t>();
|
||||
for (size_t j = 12; j < media_packet->length; ++j) {
|
||||
media_packet->data[j] = random.Rand<uint8_t>();
|
||||
}
|
||||
seqNum++;
|
||||
seq_num++;
|
||||
}
|
||||
mediaPacket->data[1] |= 0x80;
|
||||
media_packet->data[1] |= 0x80;
|
||||
|
||||
ASSERT_EQ(0, fec.GenerateFEC(mediaPacketList, protectionFactor,
|
||||
numImpPackets, kUseUnequalProtection,
|
||||
fec_mask_type, &fecPacketList))
|
||||
<< "GenerateFEC() failed";
|
||||
ASSERT_EQ(0, fec.GenerateFec(media_packet_list, protection_factor,
|
||||
num_imp_packets, kUseUnequalProtection,
|
||||
fec_mask_type, &fec_packet_list))
|
||||
<< "GenerateFec() failed";
|
||||
|
||||
ASSERT_EQ(numFecPackets, fecPacketList.size())
|
||||
<< "We requested " << numFecPackets << " FEC packets, but "
|
||||
<< "GenerateFEC() produced " << fecPacketList.size();
|
||||
memset(mediaLossMask, 0, sizeof(mediaLossMask));
|
||||
ForwardErrorCorrection::PacketList::iterator mediaPacketListItem =
|
||||
mediaPacketList.begin();
|
||||
ForwardErrorCorrection::ReceivedPacket* receivedPacket;
|
||||
uint32_t mediaPacketIdx = 0;
|
||||
ASSERT_EQ(num_fec_packets, fec_packet_list.size())
|
||||
<< "We requested " << num_fec_packets << " FEC packets, but "
|
||||
<< "GenerateFec() produced " << fec_packet_list.size();
|
||||
|
||||
while (mediaPacketListItem != mediaPacketList.end()) {
|
||||
mediaPacket = *mediaPacketListItem;
|
||||
memset(media_loss_mask, 0, sizeof(media_loss_mask));
|
||||
uint32_t media_packet_idx = 0;
|
||||
for (auto* media_packet : media_packet_list) {
|
||||
// We want a value between 0 and 1.
|
||||
const float lossRandomVariable = random.Rand<float>();
|
||||
const float loss_random_variable = random.Rand<float>();
|
||||
|
||||
if (lossRandomVariable >= lossRate[lossRateIdx]) {
|
||||
mediaLossMask[mediaPacketIdx] = 1;
|
||||
receivedPacket = new ForwardErrorCorrection::ReceivedPacket;
|
||||
receivedPacket->pkt = new ForwardErrorCorrection::Packet;
|
||||
receivedPacketList.push_back(receivedPacket);
|
||||
if (loss_random_variable >= loss_rate[loss_rate_idx]) {
|
||||
media_loss_mask[media_packet_idx] = 1;
|
||||
auto received_packet =
|
||||
new ForwardErrorCorrection::ReceivedPacket();
|
||||
received_packet->pkt = new ForwardErrorCorrection::Packet();
|
||||
received_packet_list.push_back(received_packet);
|
||||
|
||||
receivedPacket->pkt->length = mediaPacket->length;
|
||||
memcpy(receivedPacket->pkt->data, mediaPacket->data,
|
||||
mediaPacket->length);
|
||||
receivedPacket->seq_num =
|
||||
ByteReader<uint16_t>::ReadBigEndian(&mediaPacket->data[2]);
|
||||
receivedPacket->is_fec = false;
|
||||
received_packet->pkt->length = media_packet->length;
|
||||
memcpy(received_packet->pkt->data, media_packet->data,
|
||||
media_packet->length);
|
||||
received_packet->seq_num =
|
||||
ByteReader<uint16_t>::ReadBigEndian(&media_packet->data[2]);
|
||||
received_packet->is_fec = false;
|
||||
}
|
||||
mediaPacketIdx++;
|
||||
++mediaPacketListItem;
|
||||
media_packet_idx++;
|
||||
}
|
||||
memset(fecLossMask, 0, sizeof(fecLossMask));
|
||||
ForwardErrorCorrection::PacketList::iterator fecPacketListItem =
|
||||
fecPacketList.begin();
|
||||
ForwardErrorCorrection::Packet* fecPacket;
|
||||
uint32_t fecPacketIdx = 0;
|
||||
while (fecPacketListItem != fecPacketList.end()) {
|
||||
fecPacket = *fecPacketListItem;
|
||||
const float lossRandomVariable = random.Rand<float>();
|
||||
if (lossRandomVariable >= lossRate[lossRateIdx]) {
|
||||
fecLossMask[fecPacketIdx] = 1;
|
||||
receivedPacket = new ForwardErrorCorrection::ReceivedPacket;
|
||||
receivedPacket->pkt = new ForwardErrorCorrection::Packet;
|
||||
|
||||
receivedPacketList.push_back(receivedPacket);
|
||||
memset(fec_loss_mask, 0, sizeof(fec_loss_mask));
|
||||
uint32_t fec_packet_idx = 0;
|
||||
for (auto* fec_packet : fec_packet_list) {
|
||||
const float loss_random_variable = random.Rand<float>();
|
||||
if (loss_random_variable >= loss_rate[loss_rate_idx]) {
|
||||
fec_loss_mask[fec_packet_idx] = 1;
|
||||
auto received_packet =
|
||||
new ForwardErrorCorrection::ReceivedPacket();
|
||||
received_packet->pkt = new ForwardErrorCorrection::Packet();
|
||||
|
||||
receivedPacket->pkt->length = fecPacket->length;
|
||||
memcpy(receivedPacket->pkt->data, fecPacket->data,
|
||||
fecPacket->length);
|
||||
received_packet_list.push_back(received_packet);
|
||||
|
||||
receivedPacket->seq_num = seqNum;
|
||||
receivedPacket->is_fec = true;
|
||||
receivedPacket->ssrc = ssrc;
|
||||
received_packet->pkt->length = fec_packet->length;
|
||||
memcpy(received_packet->pkt->data, fec_packet->data,
|
||||
fec_packet->length);
|
||||
|
||||
fecMaskList.push_back(fecPacketMasks[fecPacketIdx]);
|
||||
received_packet->seq_num = seq_num;
|
||||
received_packet->is_fec = true;
|
||||
received_packet->ssrc = ssrc;
|
||||
|
||||
fec_mask_list.push_back(fec_packet_masks[fec_packet_idx]);
|
||||
}
|
||||
++fecPacketIdx;
|
||||
++seqNum;
|
||||
++fecPacketListItem;
|
||||
++fec_packet_idx;
|
||||
++seq_num;
|
||||
}
|
||||
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf("Media loss mask:\n");
|
||||
for (uint32_t i = 0; i < numMediaPackets; i++) {
|
||||
printf("%u ", mediaLossMask[i]);
|
||||
for (uint32_t i = 0; i < num_media_packets; i++) {
|
||||
printf("%u ", media_loss_mask[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
printf("FEC loss mask:\n");
|
||||
for (uint32_t i = 0; i < numFecPackets; i++) {
|
||||
printf("%u ", fecLossMask[i]);
|
||||
for (uint32_t i = 0; i < num_fec_packets; i++) {
|
||||
printf("%u ", fec_loss_mask[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
#endif
|
||||
|
||||
std::list<uint8_t*>::iterator fecMaskIt = fecMaskList.begin();
|
||||
uint8_t* fecMask;
|
||||
while (fecMaskIt != fecMaskList.end()) {
|
||||
fecMask = *fecMaskIt;
|
||||
uint32_t hammingDist = 0;
|
||||
uint32_t recoveryPosition = 0;
|
||||
for (uint32_t i = 0; i < numMediaPackets; i++) {
|
||||
if (mediaLossMask[i] == 0 && fecMask[i] == 1) {
|
||||
recoveryPosition = i;
|
||||
++hammingDist;
|
||||
auto fec_mask_it = fec_mask_list.begin();
|
||||
while (fec_mask_it != fec_mask_list.end()) {
|
||||
uint32_t hamming_dist = 0;
|
||||
uint32_t recovery_position = 0;
|
||||
for (uint32_t i = 0; i < num_media_packets; i++) {
|
||||
if (media_loss_mask[i] == 0 && (*fec_mask_it)[i] == 1) {
|
||||
recovery_position = i;
|
||||
++hamming_dist;
|
||||
}
|
||||
}
|
||||
std::list<uint8_t*>::iterator itemToDelete = fecMaskIt;
|
||||
++fecMaskIt;
|
||||
auto item_to_delete = fec_mask_it;
|
||||
++fec_mask_it;
|
||||
|
||||
if (hammingDist == 1) {
|
||||
if (hamming_dist == 1) {
|
||||
// Recovery possible. Restart search.
|
||||
mediaLossMask[recoveryPosition] = 1;
|
||||
fecMaskIt = fecMaskList.begin();
|
||||
} else if (hammingDist == 0) {
|
||||
media_loss_mask[recovery_position] = 1;
|
||||
fec_mask_it = fec_mask_list.begin();
|
||||
} else if (hamming_dist == 0) {
|
||||
// FEC packet cannot provide further recovery.
|
||||
fecMaskList.erase(itemToDelete);
|
||||
fec_mask_list.erase(item_to_delete);
|
||||
}
|
||||
}
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf("Recovery mask:\n");
|
||||
for (uint32_t i = 0; i < numMediaPackets; ++i) {
|
||||
printf("%u ", mediaLossMask[i]);
|
||||
for (uint32_t i = 0; i < num_media_packets; ++i) {
|
||||
printf("%u ", media_loss_mask[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
#endif
|
||||
// For error-checking frame completion.
|
||||
bool fecPacketReceived = false;
|
||||
while (!receivedPacketList.empty()) {
|
||||
size_t numPacketsToDecode = random.Rand(
|
||||
1u, static_cast<uint32_t>(receivedPacketList.size()));
|
||||
ReceivePackets(&toDecodeList, &receivedPacketList,
|
||||
numPacketsToDecode, reorderRate, duplicateRate,
|
||||
&random);
|
||||
bool fec_packet_received = false;
|
||||
while (!received_packet_list.empty()) {
|
||||
size_t num_packets_to_decode = random.Rand(
|
||||
1u, static_cast<uint32_t>(received_packet_list.size()));
|
||||
ReceivePackets(&to_decode_list, &received_packet_list,
|
||||
num_packets_to_decode, reorder_rate,
|
||||
duplicate_rate, &random);
|
||||
|
||||
if (fecPacketReceived == false) {
|
||||
ForwardErrorCorrection::ReceivedPacketList::iterator
|
||||
toDecodeIt = toDecodeList.begin();
|
||||
while (toDecodeIt != toDecodeList.end()) {
|
||||
receivedPacket = *toDecodeIt;
|
||||
if (receivedPacket->is_fec) {
|
||||
fecPacketReceived = true;
|
||||
if (fec_packet_received == false) {
|
||||
for (auto* received_packet : to_decode_list) {
|
||||
if (received_packet->is_fec) {
|
||||
fec_packet_received = true;
|
||||
}
|
||||
++toDecodeIt;
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(0, fec.DecodeFEC(&toDecodeList, &recoveredPacketList))
|
||||
<< "DecodeFEC() failed";
|
||||
ASSERT_TRUE(toDecodeList.empty())
|
||||
ASSERT_EQ(0, fec.DecodeFec(&to_decode_list,
|
||||
&recovered_packet_list))
|
||||
<< "DecodeFec() failed";
|
||||
ASSERT_TRUE(to_decode_list.empty())
|
||||
<< "Received packet list is not empty.";
|
||||
}
|
||||
mediaPacketListItem = mediaPacketList.begin();
|
||||
mediaPacketIdx = 0;
|
||||
while (mediaPacketListItem != mediaPacketList.end()) {
|
||||
if (mediaLossMask[mediaPacketIdx] == 1) {
|
||||
media_packet_idx = 0;
|
||||
for (auto* media_packet : media_packet_list) {
|
||||
if (media_loss_mask[media_packet_idx] == 1) {
|
||||
// Should have recovered this packet.
|
||||
ForwardErrorCorrection::RecoveredPacketList::iterator
|
||||
recoveredPacketListItem = recoveredPacketList.begin();
|
||||
auto recovered_packet_list_it = recovered_packet_list.cbegin();
|
||||
|
||||
ASSERT_FALSE(recoveredPacketListItem ==
|
||||
recoveredPacketList.end())
|
||||
ASSERT_FALSE(recovered_packet_list_it ==
|
||||
recovered_packet_list.end())
|
||||
<< "Insufficient number of recovered packets.";
|
||||
mediaPacket = *mediaPacketListItem;
|
||||
ForwardErrorCorrection::RecoveredPacket* recoveredPacket =
|
||||
*recoveredPacketListItem;
|
||||
ForwardErrorCorrection::RecoveredPacket* recovered_packet =
|
||||
*recovered_packet_list_it;
|
||||
|
||||
ASSERT_EQ(recoveredPacket->pkt->length, mediaPacket->length)
|
||||
ASSERT_EQ(recovered_packet->pkt->length, media_packet->length)
|
||||
<< "Recovered packet length not identical to original "
|
||||
<< "media packet";
|
||||
ASSERT_EQ(0, memcmp(recoveredPacket->pkt->data,
|
||||
mediaPacket->data, mediaPacket->length))
|
||||
ASSERT_EQ(0, memcmp(recovered_packet->pkt->data,
|
||||
media_packet->data, media_packet->length))
|
||||
<< "Recovered packet payload not identical to original "
|
||||
<< "media packet";
|
||||
delete recoveredPacket;
|
||||
recoveredPacketList.pop_front();
|
||||
delete recovered_packet;
|
||||
recovered_packet_list.pop_front();
|
||||
}
|
||||
++mediaPacketIdx;
|
||||
++mediaPacketListItem;
|
||||
++media_packet_idx;
|
||||
}
|
||||
fec.ResetState(&recoveredPacketList);
|
||||
ASSERT_TRUE(recoveredPacketList.empty())
|
||||
fec.ResetState(&recovered_packet_list);
|
||||
ASSERT_TRUE(recovered_packet_list.empty())
|
||||
<< "Excessive number of recovered packets.\t size is: "
|
||||
<< recoveredPacketList.size();
|
||||
<< recovered_packet_list.size();
|
||||
// -- Teardown --
|
||||
mediaPacketListItem = mediaPacketList.begin();
|
||||
while (mediaPacketListItem != mediaPacketList.end()) {
|
||||
delete *mediaPacketListItem;
|
||||
++mediaPacketListItem;
|
||||
mediaPacketList.pop_front();
|
||||
auto media_packet_list_it = media_packet_list.begin();
|
||||
while (media_packet_list_it != media_packet_list.end()) {
|
||||
delete *media_packet_list_it;
|
||||
++media_packet_list_it;
|
||||
media_packet_list.pop_front();
|
||||
}
|
||||
assert(mediaPacketList.empty());
|
||||
RTC_DCHECK(media_packet_list.empty());
|
||||
|
||||
fecPacketListItem = fecPacketList.begin();
|
||||
while (fecPacketListItem != fecPacketList.end()) {
|
||||
++fecPacketListItem;
|
||||
fecPacketList.pop_front();
|
||||
}
|
||||
// Clear FEC packet list, so we don't pass in a non-empty
|
||||
// list in the next call to DecodeFec().
|
||||
fec_packet_list.clear();
|
||||
|
||||
// Delete received packets we didn't pass to DecodeFEC(), due to
|
||||
// Delete received packets we didn't pass to DecodeFec(), due to
|
||||
// early frame completion.
|
||||
ForwardErrorCorrection::ReceivedPacketList::iterator
|
||||
receivedPacketIt = receivedPacketList.begin();
|
||||
while (receivedPacketIt != receivedPacketList.end()) {
|
||||
receivedPacket = *receivedPacketIt;
|
||||
delete receivedPacket;
|
||||
++receivedPacketIt;
|
||||
receivedPacketList.pop_front();
|
||||
auto received_packet_it = received_packet_list.cbegin();
|
||||
while (received_packet_it != received_packet_list.end()) {
|
||||
delete *received_packet_it;
|
||||
++received_packet_it;
|
||||
received_packet_list.pop_front();
|
||||
}
|
||||
assert(receivedPacketList.empty());
|
||||
RTC_DCHECK(received_packet_list.empty());
|
||||
|
||||
while (!fecMaskList.empty()) {
|
||||
fecMaskList.pop_front();
|
||||
while (!fec_mask_list.empty()) {
|
||||
fec_mask_list.pop_front();
|
||||
}
|
||||
timeStamp += 90000 / 30;
|
||||
} // loop over numImpPackets
|
||||
timestamp += 90000 / 30;
|
||||
} // loop over num_imp_packets
|
||||
} // loop over FecPackets
|
||||
} // loop over numMediaPackets
|
||||
delete[] packetMask;
|
||||
} // loop over num_media_packets
|
||||
} // loop over loss rates
|
||||
} // loop over mask types
|
||||
|
||||
// Have DecodeFEC free allocated memory.
|
||||
fec.ResetState(&recoveredPacketList);
|
||||
ASSERT_TRUE(recoveredPacketList.empty())
|
||||
// Have DecodeFec free allocated memory.
|
||||
fec.ResetState(&recovered_packet_list);
|
||||
ASSERT_TRUE(recovered_packet_list.empty())
|
||||
<< "Recovered packet list is not empty";
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user