Updated comments and renaming of variables in ForwardErrorCorrection.

This CL should have no changes to functionality.

BUG=webrtc:5654

Review-Url: https://codereview.webrtc.org/2107703002
Cr-Commit-Position: refs/heads/master@{#13690}
This commit is contained in:
brandtr 2016-08-09 03:29:51 -07:00 committed by Commit bot
parent 09abaa0c7d
commit 3e2d6ac0c0
2 changed files with 166 additions and 173 deletions

View File

@ -138,8 +138,8 @@ int ForwardErrorCorrection::GenerateFec(const PacketList& media_packets,
}
}
int num_fec_packets =
GetNumberOfFecPackets(num_media_packets, protection_factor);
int num_fec_packets = GetNumberOfFecPackets(num_media_packets,
protection_factor);
if (num_fec_packets == 0) {
return 0;
}
@ -438,51 +438,50 @@ void ForwardErrorCorrection::GenerateFecUlpHeaders(
void ForwardErrorCorrection::ResetState(
RecoveredPacketList* recovered_packets) {
// Free the memory for any existing recovered packets, if the user hasn't.
// Free the memory for any existing recovered packets, if the caller hasn't.
recovered_packets->clear();
received_fec_packets_.clear();
}
void ForwardErrorCorrection::InsertMediaPacket(
ReceivedPacket* rx_packet,
ReceivedPacket* received_packet,
RecoveredPacketList* recovered_packets) {
// Search for duplicate packets.
for (const auto& recovered_packet : *recovered_packets) {
if (rx_packet->seq_num == recovered_packet->seq_num) {
if (received_packet->seq_num == recovered_packet->seq_num) {
// Duplicate packet, no need to add to list.
// Delete duplicate media packet data.
rx_packet->pkt = nullptr;
received_packet->pkt = nullptr;
return;
}
}
std::unique_ptr<RecoveredPacket> recovered_packet_to_insert(
new RecoveredPacket());
// This "recovered packet" was not recovered using parity packets.
recovered_packet_to_insert->was_recovered = false;
// This media packet has already been passed on.
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;
RecoveredPacket* recovered_packet_to_insert_ptr =
recovered_packet_to_insert.get();
std::unique_ptr<RecoveredPacket> recovered_packet(new RecoveredPacket());
// This "recovered packet" was not recovered using parity packets.
recovered_packet->was_recovered = false;
// This media packet has already been passed on.
recovered_packet->returned = true;
recovered_packet->seq_num = received_packet->seq_num;
recovered_packet->pkt = received_packet->pkt;
recovered_packet->pkt->length = received_packet->pkt->length;
RecoveredPacket* recovered_packet_ptr = recovered_packet.get();
// TODO(holmer): Consider replacing this with a binary search for the right
// position, and then just insert the new packet. Would get rid of the sort.
recovered_packets->push_back(std::move(recovered_packet_to_insert));
recovered_packets->push_back(std::move(recovered_packet));
recovered_packets->sort(SortablePacket::LessThan());
UpdateCoveringFecPackets(recovered_packet_to_insert_ptr);
UpdateCoveringFecPackets(recovered_packet_ptr);
}
void ForwardErrorCorrection::UpdateCoveringFecPackets(RecoveredPacket* packet) {
for (auto& fec_packet : received_fec_packets_) {
// Is this FEC packet protecting the media packet |packet|?
auto protected_it = std::lower_bound(fec_packet->protected_pkt_list.begin(),
fec_packet->protected_pkt_list.end(),
auto protected_it = std::lower_bound(fec_packet->protected_packets.begin(),
fec_packet->protected_packets.end(),
packet,
SortablePacket::LessThan());
if (protected_it != fec_packet->protected_pkt_list.end() &&
if (protected_it != fec_packet->protected_packets.end() &&
(*protected_it)->seq_num == packet->seq_num) {
// Found an FEC packet which is protecting |packet|.
(*protected_it)->pkt = packet->pkt;
@ -491,28 +490,30 @@ void ForwardErrorCorrection::UpdateCoveringFecPackets(RecoveredPacket* packet) {
}
void ForwardErrorCorrection::InsertFecPacket(
ReceivedPacket* rx_packet,
ReceivedPacket* received_packet,
const RecoveredPacketList* recovered_packets) {
// Check for duplicate.
for (const auto& existing_fec_packet : received_fec_packets_) {
if (rx_packet->seq_num == existing_fec_packet->seq_num) {
if (received_packet->seq_num == existing_fec_packet->seq_num) {
// Delete duplicate FEC packet data.
rx_packet->pkt = nullptr;
received_packet->pkt = nullptr;
return;
}
}
std::unique_ptr<ReceivedFecPacket> fec_packet(new ReceivedFecPacket());
fec_packet->pkt = rx_packet->pkt;
fec_packet->seq_num = rx_packet->seq_num;
fec_packet->ssrc = rx_packet->ssrc;
fec_packet->pkt = received_packet->pkt;
fec_packet->seq_num = received_packet->seq_num;
fec_packet->ssrc = received_packet->ssrc;
const uint16_t seq_num_base =
ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[2]);
const uint16_t maskSizeBytes = (fec_packet->pkt->data[0] & 0x40)
? kMaskSizeLBitSet
: kMaskSizeLBitClear; // L bit set?
const uint16_t mask_size_bytes = (fec_packet->pkt->data[0] & 0x40)
? kMaskSizeLBitSet
: kMaskSizeLBitClear; // L bit set?
for (uint16_t byte_idx = 0; byte_idx < maskSizeBytes; ++byte_idx) {
// Parse erasure code mask from ULP header and represent as protected packets.
for (uint16_t byte_idx = 0; byte_idx < mask_size_bytes; ++byte_idx) {
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))) {
@ -522,13 +523,13 @@ void ForwardErrorCorrection::InsertFecPacket(
protected_packet->seq_num =
static_cast<uint16_t>(seq_num_base + (byte_idx << 3) + bit_idx);
protected_packet->pkt = nullptr;
fec_packet->protected_pkt_list.push_back(std::move(protected_packet));
fec_packet->protected_packets.push_back(std::move(protected_packet));
}
}
}
if (fec_packet->protected_pkt_list.empty()) {
if (fec_packet->protected_packets.empty()) {
// All-zero packet mask; we can discard this FEC packet.
LOG(LS_WARNING) << "FEC packet has an all-zero packet mask.";
LOG(LS_WARNING) << "Received FEC packet has an all-zero packet mask.";
} else {
AssignRecoveredPackets(fec_packet.get(), recovered_packets);
// TODO(holmer): Consider replacing this with a binary search for the right
@ -545,7 +546,7 @@ void ForwardErrorCorrection::InsertFecPacket(
void ForwardErrorCorrection::AssignRecoveredPackets(
ReceivedFecPacket* fec_packet,
const RecoveredPacketList* recovered_packets) {
ProtectedPacketList* protected_packets = &fec_packet->protected_pkt_list;
ProtectedPacketList* protected_packets = &fec_packet->protected_packets;
std::vector<RecoveredPacket*> recovered_protected_packets;
// Find intersection between the (sorted) containers |protected_packets|
@ -573,7 +574,7 @@ void ForwardErrorCorrection::InsertPackets(
ReceivedPacketList* received_packets,
RecoveredPacketList* recovered_packets) {
while (!received_packets->empty()) {
ReceivedPacket* rx_packet = received_packets->front().get();
ReceivedPacket* received_packet = received_packets->front().get();
// Check for discarding oldest FEC packet, to avoid wrong FEC decoding from
// sequence number wrap-around. Detection of old FEC packet is based on
@ -584,18 +585,17 @@ void ForwardErrorCorrection::InsertPackets(
// thresholding (e.g., to distinguish between wrap-around and reordering).
if (!received_fec_packets_.empty()) {
uint16_t seq_num_diff =
abs(static_cast<int>(rx_packet->seq_num) -
abs(static_cast<int>(received_packet->seq_num) -
static_cast<int>(received_fec_packets_.front()->seq_num));
if (seq_num_diff > 0x3fff) {
received_fec_packets_.pop_front();
}
}
if (rx_packet->is_fec) {
InsertFecPacket(rx_packet, recovered_packets);
if (received_packet->is_fec) {
InsertFecPacket(received_packet, recovered_packets);
} else {
// Insert packet at the end of |recoveredPacketList|.
InsertMediaPacket(rx_packet, recovered_packets);
InsertMediaPacket(received_packet, recovered_packets);
}
// Delete the received packet "wrapper".
received_packets->pop_front();
@ -606,7 +606,7 @@ void ForwardErrorCorrection::InsertPackets(
bool ForwardErrorCorrection::StartPacketRecovery(
const ReceivedFecPacket* fec_packet,
RecoveredPacket* recovered) {
RecoveredPacket* recovered_packet) {
// This is the first packet which we try to recover with.
const uint16_t ulp_header_size = fec_packet->pkt->data[0] & 0x40
? kUlpHeaderSizeLBitSet
@ -617,74 +617,77 @@ bool ForwardErrorCorrection::StartPacketRecovery(
<< "Truncated FEC packet doesn't contain room for ULP header.";
return false;
}
recovered->pkt = new Packet();
memset(recovered->pkt->data, 0, IP_PACKET_SIZE);
recovered->returned = false;
recovered->was_recovered = true;
recovered_packet->pkt = new Packet();
memset(recovered_packet->pkt->data, 0, IP_PACKET_SIZE);
recovered_packet->returned = false;
recovered_packet->was_recovered = true;
uint16_t protection_length =
ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[10]);
if (protection_length >
std::min(
sizeof(recovered->pkt->data) - kRtpHeaderSize,
sizeof(recovered_packet->pkt->data) - kRtpHeaderSize,
sizeof(fec_packet->pkt->data) - kFecHeaderSize - ulp_header_size)) {
LOG(LS_WARNING) << "Incorrect FEC protection length, dropping.";
return false;
}
// Copy FEC payload, skipping the ULP header.
memcpy(&recovered->pkt->data[kRtpHeaderSize],
memcpy(&recovered_packet->pkt->data[kRtpHeaderSize],
&fec_packet->pkt->data[kFecHeaderSize + ulp_header_size],
protection_length);
// Copy the length recovery field.
memcpy(recovered->length_recovery, &fec_packet->pkt->data[8], 2);
memcpy(recovered_packet->length_recovery, &fec_packet->pkt->data[8], 2);
// Copy the first 2 bytes of the FEC header.
memcpy(recovered->pkt->data, fec_packet->pkt->data, 2);
memcpy(recovered_packet->pkt->data, fec_packet->pkt->data, 2);
// Copy the 5th to 8th bytes of the FEC header.
memcpy(&recovered->pkt->data[4], &fec_packet->pkt->data[4], 4);
memcpy(&recovered_packet->pkt->data[4], &fec_packet->pkt->data[4], 4);
// Set the SSRC field.
ByteWriter<uint32_t>::WriteBigEndian(&recovered->pkt->data[8],
ByteWriter<uint32_t>::WriteBigEndian(&recovered_packet->pkt->data[8],
fec_packet->ssrc);
return true;
}
bool ForwardErrorCorrection::FinishPacketRecovery(RecoveredPacket* recovered) {
bool ForwardErrorCorrection::FinishPacketRecovery(
RecoveredPacket* recovered_packet) {
// Set the RTP version to 2.
recovered->pkt->data[0] |= 0x80; // Set the 1st bit.
recovered->pkt->data[0] &= 0xbf; // Clear the 2nd bit.
recovered_packet->pkt->data[0] |= 0x80; // Set the 1st bit.
recovered_packet->pkt->data[0] &= 0xbf; // Clear the 2nd bit.
// Set the SN field.
ByteWriter<uint16_t>::WriteBigEndian(&recovered->pkt->data[2],
recovered->seq_num);
ByteWriter<uint16_t>::WriteBigEndian(&recovered_packet->pkt->data[2],
recovered_packet->seq_num);
// Recover the packet length.
recovered->pkt->length =
ByteReader<uint16_t>::ReadBigEndian(recovered->length_recovery) +
recovered_packet->pkt->length =
ByteReader<uint16_t>::ReadBigEndian(recovered_packet->length_recovery) +
kRtpHeaderSize;
if (recovered->pkt->length > sizeof(recovered->pkt->data) - kRtpHeaderSize)
if (recovered_packet->pkt->length >
sizeof(recovered_packet->pkt->data) - kRtpHeaderSize) {
return false;
}
return true;
}
void ForwardErrorCorrection::XorPackets(const Packet* src_packet,
RecoveredPacket* dst_packet) {
void ForwardErrorCorrection::XorPackets(const Packet* src,
RecoveredPacket* dst) {
// XOR with the first 2 bytes of the RTP header.
for (uint32_t i = 0; i < 2; ++i) {
dst_packet->pkt->data[i] ^= src_packet->data[i];
dst->pkt->data[i] ^= src->data[i];
}
// XOR with the 5th to 8th bytes of the RTP header.
for (uint32_t i = 4; i < 8; ++i) {
dst_packet->pkt->data[i] ^= src_packet->data[i];
dst->pkt->data[i] ^= src->data[i];
}
// XOR with the network-ordered payload size.
uint8_t media_payload_length[2];
ByteWriter<uint16_t>::WriteBigEndian(media_payload_length,
src_packet->length - kRtpHeaderSize);
dst_packet->length_recovery[0] ^= media_payload_length[0];
dst_packet->length_recovery[1] ^= media_payload_length[1];
src->length - kRtpHeaderSize);
dst->length_recovery[0] ^= media_payload_length[0];
dst->length_recovery[1] ^= media_payload_length[1];
// XOR with RTP payload.
// TODO(marpan/ajm): Are we doing more XORs than required here?
for (size_t i = kRtpHeaderSize; i < src_packet->length; ++i) {
dst_packet->pkt->data[i] ^= src_packet->data[i];
for (size_t i = kRtpHeaderSize; i < src->length; ++i) {
dst->pkt->data[i] ^= src->data[i];
}
}
@ -693,7 +696,7 @@ bool ForwardErrorCorrection::RecoverPacket(
RecoveredPacket* rec_packet_to_insert) {
if (!StartPacketRecovery(fec_packet, rec_packet_to_insert))
return false;
for (const auto& protected_packet : fec_packet->protected_pkt_list) {
for (const auto& protected_packet : fec_packet->protected_packets) {
if (protected_packet->pkt == nullptr) {
// This is the packet we're recovering.
rec_packet_to_insert->seq_num = protected_packet->seq_num;
@ -753,7 +756,7 @@ void ForwardErrorCorrection::AttemptRecover(
int ForwardErrorCorrection::NumCoveredPacketsMissing(
const ReceivedFecPacket* fec_packet) {
int packets_missing = 0;
for (const auto& protected_packet : fec_packet->protected_pkt_list) {
for (const auto& protected_packet : fec_packet->protected_packets) {
if (protected_packet->pkt == nullptr) {
++packets_missing;
if (packets_missing > 1) {

View File

@ -70,19 +70,9 @@ class ForwardErrorCorrection {
uint16_t seq_num;
};
// 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
// determine frame completion. If set, we assume a FEC stream, and the
// following assumptions must hold:
// The received list parameter of DecodeFec() references structs of this type.
//
// 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.
// 2. All FEC packets have a sequence number base equal to the first media
// packet in the corresponding frame.
//
// The ssrc member is needed to ensure we can restore the SSRC field of
// The ssrc member is needed to ensure that we can restore the SSRC field of
// recovered packets. In most situations this could be retrieved from other
// media packets, but in the case of an FEC packet protecting a single
// missing media packet, we have no other means of obtaining it.
@ -99,7 +89,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() references structs of
// this type.
// TODO(holmer): Refactor into a proper class.
class RecoveredPacket : public SortablePacket {
@ -124,88 +114,85 @@ class ForwardErrorCorrection {
ForwardErrorCorrection();
virtual ~ForwardErrorCorrection();
/**
* Generates a list of FEC packets from supplied media packets.
*
* \param[in] mediaPacketList List of media packets to protect, of type
* #Packet. All packets must belong to the
* same frame and the list must not be empty.
* \param[in] protectionFactor FEC protection overhead in the [0, 255]
* domain. To obtain 100% overhead, or an
* equal number of FEC packets as media
* packets, use 255.
* \param[in] numImportantPackets The number of "important" packets in the
* frame. These packets may receive greater
* protection than the remaining packets. The
* important packets must be located at the
* start of the media packet list. For codecs
* with data partitioning, the important
* packets may correspond to first partition
* packets.
* \param[in] useUnequalProtection Parameter to enable/disable unequal
* protection (UEP) across packets. Enabling
* UEP will allocate more protection to the
* numImportantPackets from the start of the
* mediaPacketList.
* \param[in] fec_mask_type The type of packet mask used in the FEC.
* Random or bursty type may be selected. The
* bursty type is only defined up to 12 media
* packets. If the number of media packets is
* above 12, the packets masks from the
* random table will be selected.
* \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().
*
* \return 0 on success, -1 on failure.
*/
//
// Generates a list of FEC packets from supplied media packets.
//
// Input: media_packets List of media packets to protect, of type
// Packet. All packets must belong to the
// same frame and the list must not be empty.
// Input: protection_factor FEC protection overhead in the [0, 255]
// domain. To obtain 100% overhead, or an
// equal number of FEC packets as
// media packets, use 255.
// Input: num_important_packets The number of "important" packets in the
// frame. These packets may receive greater
// protection than the remaining packets.
// The important packets must be located at the
// start of the media packet list. For codecs
// with data partitioning, the important
// packets may correspond to first partition
// packets.
// Input: use_unequal_protection Parameter to enable/disable unequal
// protection (UEP) across packets. Enabling
// UEP will allocate more protection to the
// num_important_packets from the start of the
// media_packets.
// Input: fec_mask_type The type of packet mask used in the FEC.
// Random or bursty type may be selected. The
// bursty type is only defined up to 12 media
// packets. If the number of media packets is
// above 12, the packet masks from the random
// table will be selected.
// Output: fec_packets List of pointers to generated 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().
//
// Returns 0 on success, -1 on failure.
//
int GenerateFec(const PacketList& media_packets,
uint8_t protection_factor, int num_important_packets,
bool use_unequal_protection, FecMaskType fec_mask_type,
std::list<Packet*>* fec_packets);
/**
* Decodes a list of media and FEC packets. It will parse the input received
* packet list, storing FEC packets internally and inserting media packets to
* the output recovered packet list. The recovered list will be sorted by
* 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.
*
* 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.
*
* \param[in] receivedPacketList List of new received packets, of type
* #ReceivedPacket, belonging to a single
* frame. At output the list will be empty,
* with packets either stored internally,
* or accessible through the recovered list.
* \param[out] recoveredPacketList List of recovered media packets, of type
* #RecoveredPacket, belonging to a single
* frame. The memory available through the
* list will be valid until the next call to
* DecodeFec().
*
* \return 0 on success, -1 on failure.
*/
//
// Decodes a list of received media and FEC packets. It will parse the
// |received_packets|, storing FEC packets internally, and move
// media packets to |recovered_packets|. The recovered list will be
// sorted by ascending sequence number and have duplicates removed.
// The function should be called as new packets arrive, and
// |recovered_packets| will be progressively assembled with each call.
// When the function returns, |received_packets| will be empty.
//
// The caller will allocate packets submitted through |received_packets|.
// The function will handle allocation of recovered packets.
//
// Input: received_packets List of new received packets, of type
// ReceivedPacket, belonging to a single
// frame. At output the list will be empty,
// with packets either stored internally,
// or accessible through the recovered list.
// Output: recovered_packets List of recovered media packets, of type
// RecoveredPacket, belonging to a single
// frame. The memory available through the
// list will be valid until the next call to
// DecodeFec().
//
// Returns 0 on success, -1 on failure.
//
int DecodeFec(ReceivedPacketList* received_packets,
RecoveredPacketList* recovered_packets);
// Get the number of FEC packets, given the number of media packets and the
// protection factor.
// Get the number of generated FEC packets, given the number of media packets
// and the protection factor.
int GetNumberOfFecPackets(int num_media_packets, int protection_factor);
// Gets the size in bytes of the FEC/ULP headers, which must be accounted for
// as packet overhead.
// \return Packet overhead in bytes.
// as packet overhead. Returns the packet overhead in bytes.
static size_t PacketOverhead();
// Reset internal states from last frame and clears |recovered_packets|.
// Reset internal states from last frame and clear |recovered_packets|.
// Frees all memory allocated by this class.
void ResetState(RecoveredPacketList* recovered_packets);
@ -225,7 +212,7 @@ class ForwardErrorCorrection {
// TODO(holmer): Refactor into a proper class.
class ReceivedFecPacket : public ForwardErrorCorrection::SortablePacket {
public:
ProtectedPacketList protected_pkt_list;
ProtectedPacketList protected_packets;
uint32_t ssrc; // SSRC of the current frame.
rtc::scoped_refptr<ForwardErrorCorrection::Packet> pkt;
};
@ -271,12 +258,13 @@ class ForwardErrorCorrection {
uint8_t* packet_mask, int num_fec_packets,
bool l_bit);
// Insert received packets into FEC or recovered list.
// Inserts the |received_packets| into the internal received FEC packet list
// or into |recovered_packets|.
void InsertPackets(ReceivedPacketList* received_packets,
RecoveredPacketList* recovered_packets);
// Insert media packet into recovered packet list. We delete duplicates.
void InsertMediaPacket(ReceivedPacket* rx_packet,
// Inserts the |received_packet| into |recovered_packets|. Deletes duplicates.
void InsertMediaPacket(ReceivedPacket* received_packet,
RecoveredPacketList* recovered_packets);
// Assigns pointers to the recovered packet from all FEC packets which cover
@ -286,43 +274,45 @@ class ForwardErrorCorrection {
// packets covered by the FEC packet.
void UpdateCoveringFecPackets(RecoveredPacket* packet);
// Insert packet into FEC list. We delete duplicates.
void InsertFecPacket(ReceivedPacket* rx_packet,
// Insert |received_packet| into internal FEC list. Deletes duplicates.
void InsertFecPacket(ReceivedPacket* received_packet,
const RecoveredPacketList* recovered_packets);
// Assigns pointers to already recovered packets covered by this FEC packet.
// Assigns pointers to already recovered packets covered by |fec_packet|.
static void AssignRecoveredPackets(
ReceivedFecPacket* fec_packet,
const RecoveredPacketList* recovered_packets);
// Insert into recovered list in correct position.
// Insert |rec_packet_to_insert| into |recovered_packets| in correct position.
void InsertRecoveredPacket(RecoveredPacket* rec_packet_to_insert,
RecoveredPacketList* recovered_packets);
// Attempt to recover missing packets.
// Attempt to recover missing packets, using the internally stored
// received FEC packets.
void AttemptRecover(RecoveredPacketList* recovered_packets);
// Initializes the packet recovery using the FEC packet.
// Initializes packet recovery using the received |fec_packet|.
static bool StartPacketRecovery(const ReceivedFecPacket* fec_packet,
RecoveredPacket* recovered);
RecoveredPacket* recovered_packet);
// 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);
// Performs XOR between |src| and |dst| and stores the result in |dst|.
static void XorPackets(const Packet* src, RecoveredPacket* dst);
// Finish up the recovery of a packet.
static bool FinishPacketRecovery(RecoveredPacket* recovered);
static bool FinishPacketRecovery(RecoveredPacket* recovered_packet);
// Recover a missing packet.
bool RecoverPacket(const ReceivedFecPacket* fec_packet,
RecoveredPacket* rec_packet_to_insert);
// Get the number of missing media packets which are covered by this
// FEC packet. An FEC packet can recover at most one packet, and if zero
// packets are missing the FEC packet can be discarded.
// This function returns 2 when two or more packets are missing.
// Get the number of missing media packets which are covered by |fec_packet|.
// An FEC packet can recover at most one packet, and if zero packets are
// missing the FEC packet can be discarded. This function returns 2 when two
// or more packets are missing.
static int NumCoveredPacketsMissing(const ReceivedFecPacket* fec_packet);
// Discards old packets in |recovered_packets|, which are no longer relevant
// for recovering lost packets.
static void DiscardOldRecoveredPackets(
RecoveredPacketList* recovered_packets);
static uint16_t ParseSequenceNumber(uint8_t* packet);