Rename current flexfec implementation flexfec_03
As per the comment in https://webrtc-review.googlesource.com/c/src/+/303240 on the flexfec_header_reader_writer2.h, renaming this file to flexfec_header_reader_writer.h and renaming the current implementation to flexfec_03_header_reader_writer.h as it is based on the 03 draft of the RFC. Change-Id: I80cb2aba6225ec7cd989a134c3204d1db0ac6f7c Bug: webrtc:15002 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/307600 Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/main@{#40231}
This commit is contained in:
parent
43df03db38
commit
ade07ca45e
@ -170,10 +170,10 @@ rtc_library("rtp_rtcp") {
|
||||
"source/fec_private_tables_bursty.h",
|
||||
"source/fec_private_tables_random.cc",
|
||||
"source/fec_private_tables_random.h",
|
||||
"source/flexfec_03_header_reader_writer.cc",
|
||||
"source/flexfec_03_header_reader_writer.h",
|
||||
"source/flexfec_header_reader_writer.cc",
|
||||
"source/flexfec_header_reader_writer.h",
|
||||
"source/flexfec_header_reader_writer2.cc",
|
||||
"source/flexfec_header_reader_writer2.h",
|
||||
"source/flexfec_receiver.cc",
|
||||
"source/flexfec_sender.cc",
|
||||
"source/forward_error_correction.cc",
|
||||
@ -552,7 +552,7 @@ if (rtc_include_tests) {
|
||||
"source/byte_io_unittest.cc",
|
||||
"source/capture_clock_offset_updater_unittest.cc",
|
||||
"source/fec_private_tables_bursty_unittest.cc",
|
||||
"source/flexfec_header_reader_writer2_unittest.cc",
|
||||
"source/flexfec_03_header_reader_writer_unittest.cc",
|
||||
"source/flexfec_header_reader_writer_unittest.cc",
|
||||
"source/flexfec_receiver_unittest.cc",
|
||||
"source/flexfec_sender_unittest.cc",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
@ -8,7 +8,7 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/rtp_rtcp/source/flexfec_header_reader_writer2.h"
|
||||
#include "modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -37,10 +37,10 @@ constexpr size_t kMaxFecPackets = kMaxMediaPackets;
|
||||
constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14};
|
||||
|
||||
// Size (in bytes) of part of header which is not packet mask specific.
|
||||
constexpr size_t kBaseHeaderSize = 8;
|
||||
constexpr size_t kBaseHeaderSize = 12;
|
||||
|
||||
// Size (in bytes) of part of header which is stream specific.
|
||||
constexpr size_t kStreamSpecificHeaderSize = 2;
|
||||
constexpr size_t kStreamSpecificHeaderSize = 6;
|
||||
|
||||
// Size (in bytes) of header, given the single stream packet mask size, i.e.
|
||||
// the number of K-bits set.
|
||||
@ -61,9 +61,9 @@ constexpr size_t kPacketMaskOffset =
|
||||
kBaseHeaderSize + kStreamSpecificHeaderSize;
|
||||
|
||||
// Here we count the K-bits as belonging to the packet mask.
|
||||
// This can be used in conjunction with FlexfecHeaderWriter::MinPacketMaskSize,
|
||||
// which calculates a bound on the needed packet mask size including K-bits,
|
||||
// given a packet mask without K-bits.
|
||||
// This can be used in conjunction with
|
||||
// Flexfec03HeaderWriter::MinPacketMaskSize, which calculates a bound on the
|
||||
// needed packet mask size including K-bits, given a packet mask without K-bits.
|
||||
size_t FlexfecHeaderSize(size_t packet_mask_size) {
|
||||
RTC_DCHECK_LE(packet_mask_size, kFlexfecPacketMaskSizes[2]);
|
||||
if (packet_mask_size <= kFlexfecPacketMaskSizes[0]) {
|
||||
@ -76,21 +76,15 @@ size_t FlexfecHeaderSize(size_t packet_mask_size) {
|
||||
|
||||
} // namespace
|
||||
|
||||
FlexfecHeaderReader2::FlexfecHeaderReader2()
|
||||
Flexfec03HeaderReader::Flexfec03HeaderReader()
|
||||
: FecHeaderReader(kMaxTrackedMediaPackets, kMaxFecPackets) {}
|
||||
|
||||
FlexfecHeaderReader2::~FlexfecHeaderReader2() = default;
|
||||
Flexfec03HeaderReader::~Flexfec03HeaderReader() = default;
|
||||
|
||||
// TODO(brandtr): Update this function when we support flexible masks,
|
||||
// and retransmissions.
|
||||
bool FlexfecHeaderReader2::ReadFecHeader(
|
||||
// retransmissions, and/or several protected SSRCs.
|
||||
bool Flexfec03HeaderReader::ReadFecHeader(
|
||||
ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const {
|
||||
// Protected ssrcs should already be populated from RTP header.
|
||||
if (fec_packet->protected_streams.empty()) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Discarding FlexFEC packet with no protected sources.";
|
||||
return false;
|
||||
}
|
||||
if (fec_packet->pkt->data.size() <=
|
||||
kBaseHeaderSize + kStreamSpecificHeaderSize) {
|
||||
RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
|
||||
@ -111,103 +105,100 @@ bool FlexfecHeaderReader2::ReadFecHeader(
|
||||
"not yet support this, thus discarding packet.";
|
||||
return false;
|
||||
}
|
||||
uint8_t ssrc_count = ByteReader<uint8_t>::ReadBigEndian(&data[8]);
|
||||
if (ssrc_count != 1) {
|
||||
RTC_LOG(LS_INFO)
|
||||
<< "FlexFEC packet protecting multiple media SSRCs. We do not "
|
||||
"yet support this, thus discarding packet.";
|
||||
return false;
|
||||
}
|
||||
uint32_t protected_ssrc = ByteReader<uint32_t>::ReadBigEndian(&data[12]);
|
||||
uint16_t seq_num_base = ByteReader<uint16_t>::ReadBigEndian(&data[16]);
|
||||
|
||||
// First seq_num will be in byte index 8
|
||||
// Parse the FlexFEC packet mask and remove the interleaved K-bits.
|
||||
// (See FEC header schematic in flexfec_header_reader_writer.h.)
|
||||
size_t byte_index = 8;
|
||||
for (size_t i = 0; i < fec_packet->protected_streams.size(); ++i) {
|
||||
if (fec_packet->pkt->data.size() < byte_index + kStreamSpecificHeaderSize) {
|
||||
RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
|
||||
// We store the packed packet mask in-band, which "destroys" the standards
|
||||
// compliance of the header. That is fine though, since the code that
|
||||
// reads from the header (from this point and onwards) is aware of this.
|
||||
// TODO(brandtr): When the FEC packet classes have been refactored, store
|
||||
// the packed packet masks out-of-band, thus leaving the FlexFEC header as is.
|
||||
//
|
||||
// We treat the mask parts as unsigned integers with host order endianness
|
||||
// in order to simplify the bit shifting between bytes.
|
||||
if (fec_packet->pkt->data.size() < kHeaderSizes[0]) {
|
||||
RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
|
||||
return false;
|
||||
}
|
||||
uint8_t* const packet_mask = data + kPacketMaskOffset;
|
||||
bool k_bit0 = (packet_mask[0] & 0x80) != 0;
|
||||
uint16_t mask_part0 = ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
|
||||
// Shift away K-bit 0, implicitly clearing the last bit.
|
||||
mask_part0 <<= 1;
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&packet_mask[0], mask_part0);
|
||||
size_t packet_mask_size;
|
||||
if (k_bit0) {
|
||||
// The first K-bit is set, and the packet mask is thus only 2 bytes long.
|
||||
// We have now read the entire FEC header, and the rest of the packet
|
||||
// is payload.
|
||||
packet_mask_size = kFlexfecPacketMaskSizes[0];
|
||||
} else {
|
||||
if (fec_packet->pkt->data.size() < kHeaderSizes[1]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fec_packet->protected_streams[i].seq_num_base =
|
||||
ByteReader<uint16_t>::ReadBigEndian(&data[byte_index]);
|
||||
byte_index += kStreamSpecificHeaderSize;
|
||||
|
||||
// Parse the FlexFEC packet mask and remove the interleaved K-bits.
|
||||
// (See FEC header schematic in flexfec_header_reader_writer.h.)
|
||||
// We store the packed packet mask in-band, which "destroys" the standards
|
||||
// compliance of the header. That is fine though, since the code that
|
||||
// reads from the header (from this point and onwards) is aware of this.
|
||||
// TODO(brandtr): When the FEC packet classes have been refactored, store
|
||||
// the packed packet masks out-of-band, thus leaving the FlexFEC header as
|
||||
// is.
|
||||
//
|
||||
// We treat the mask parts as unsigned integers with host order endianness
|
||||
// in order to simplify the bit shifting between bytes.
|
||||
if (fec_packet->pkt->data.size() <
|
||||
(byte_index + kFlexfecPacketMaskSizes[0])) {
|
||||
RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
|
||||
return false;
|
||||
}
|
||||
fec_packet->protected_streams[i].packet_mask_offset = byte_index;
|
||||
bool k_bit0 = (data[byte_index] & 0x80) != 0;
|
||||
uint16_t mask_part0 =
|
||||
ByteReader<uint16_t>::ReadBigEndian(&data[byte_index]);
|
||||
// Shift away K-bit 0, implicitly clearing the last bit.
|
||||
mask_part0 <<= 1;
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&data[byte_index], mask_part0);
|
||||
byte_index += kFlexfecPacketMaskSizes[0];
|
||||
if (k_bit0) {
|
||||
// The first K-bit is set, and the packet mask is thus only 2 bytes long.
|
||||
// We have finished reading the properties for current ssrc.
|
||||
fec_packet->protected_streams[i].packet_mask_size =
|
||||
kFlexfecPacketMaskSizes[0];
|
||||
bool k_bit1 = (packet_mask[2] & 0x80) != 0;
|
||||
// We have already shifted the first two bytes of the packet mask one step
|
||||
// to the left, thus removing K-bit 0. We will now shift the next four bytes
|
||||
// of the packet mask two steps to the left. (One step for the removed
|
||||
// K-bit 0, and one step for the to be removed K-bit 1).
|
||||
uint8_t bit15 = (packet_mask[2] >> 6) & 0x01;
|
||||
packet_mask[1] |= bit15;
|
||||
uint32_t mask_part1 = ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]);
|
||||
// Shift away K-bit 1 and bit 15, implicitly clearing the last two bits.
|
||||
mask_part1 <<= 2;
|
||||
ByteWriter<uint32_t>::WriteBigEndian(&packet_mask[2], mask_part1);
|
||||
if (k_bit1) {
|
||||
// The first K-bit is clear, but the second K-bit is set. The packet
|
||||
// mask is thus 6 bytes long. We have now read the entire FEC header,
|
||||
// and the rest of the packet is payload.
|
||||
packet_mask_size = kFlexfecPacketMaskSizes[1];
|
||||
} else {
|
||||
if (fec_packet->pkt->data.size() <
|
||||
(byte_index + kFlexfecPacketMaskSizes[1] -
|
||||
kFlexfecPacketMaskSizes[0])) {
|
||||
if (fec_packet->pkt->data.size() < kHeaderSizes[2]) {
|
||||
RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
|
||||
return false;
|
||||
}
|
||||
bool k_bit1 = (data[byte_index] & 0x80) != 0;
|
||||
// We have already shifted the first two bytes of the packet mask one step
|
||||
// to the left, thus removing K-bit 0. We will now shift the next four
|
||||
// bytes of the packet mask two steps to the left. (One step for the
|
||||
// removed K-bit 0, and one step for the to be removed K-bit 1).
|
||||
uint8_t bit15 = (data[byte_index] >> 6) & 0x01;
|
||||
data[byte_index - 1] |= bit15;
|
||||
uint32_t mask_part1 =
|
||||
ByteReader<uint32_t>::ReadBigEndian(&data[byte_index]);
|
||||
// Shift away K-bit 1 and bit 15, implicitly clearing the last two bits.
|
||||
mask_part1 <<= 2;
|
||||
ByteWriter<uint32_t>::WriteBigEndian(&data[byte_index], mask_part1);
|
||||
byte_index += kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0];
|
||||
if (k_bit1) {
|
||||
// The first K-bit is clear, but the second K-bit is set. The packet
|
||||
// mask is thus 6 bytes long. We have finished reading the properties
|
||||
// for current ssrc.
|
||||
fec_packet->protected_streams[i].packet_mask_size =
|
||||
kFlexfecPacketMaskSizes[1];
|
||||
bool k_bit2 = (packet_mask[6] & 0x80) != 0;
|
||||
if (k_bit2) {
|
||||
// The first and second K-bits are clear, but the third K-bit is set.
|
||||
// The packet mask is thus 14 bytes long. We have now read the entire
|
||||
// FEC header, and the rest of the packet is payload.
|
||||
packet_mask_size = kFlexfecPacketMaskSizes[2];
|
||||
} else {
|
||||
if (fec_packet->pkt->data.size() <
|
||||
(byte_index + kFlexfecPacketMaskSizes[2] -
|
||||
kFlexfecPacketMaskSizes[1])) {
|
||||
RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
|
||||
return false;
|
||||
}
|
||||
fec_packet->protected_streams[i].packet_mask_size =
|
||||
kFlexfecPacketMaskSizes[2];
|
||||
// At this point, K-bits 0 and 1 have been removed, and the front-most
|
||||
// part of the FlexFEC packet mask has been packed accordingly. We will
|
||||
// now shift the remaning part of the packet mask two steps to the left.
|
||||
// This corresponds to the (in total) two K-bits, which have been
|
||||
// removed.
|
||||
uint8_t tail_bits = (data[byte_index] >> 6) & 0x03;
|
||||
data[byte_index - 1] |= tail_bits;
|
||||
uint64_t mask_part2 =
|
||||
ByteReader<uint64_t>::ReadBigEndian(&data[byte_index]);
|
||||
// Shift away bit 46, and bit 47, which were copied to the previous
|
||||
// part of the mask, implicitly clearing the last two bits.
|
||||
mask_part2 <<= 2;
|
||||
ByteWriter<uint64_t>::WriteBigEndian(&data[byte_index], mask_part2);
|
||||
byte_index += kFlexfecPacketMaskSizes[2] - kFlexfecPacketMaskSizes[1];
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Discarding FlexFEC packet with malformed header.";
|
||||
return false;
|
||||
}
|
||||
// At this point, K-bits 0 and 1 have been removed, and the front-most
|
||||
// part of the FlexFEC packet mask has been packed accordingly. We will
|
||||
// now shift the remaning part of the packet mask three steps to the left.
|
||||
// This corresponds to the (in total) three K-bits, which have been
|
||||
// removed.
|
||||
uint8_t tail_bits = (packet_mask[6] >> 5) & 0x03;
|
||||
packet_mask[5] |= tail_bits;
|
||||
uint64_t mask_part2 =
|
||||
ByteReader<uint64_t>::ReadBigEndian(&packet_mask[6]);
|
||||
// Shift away K-bit 2, bit 46, and bit 47, implicitly clearing the last
|
||||
// three bits.
|
||||
mask_part2 <<= 3;
|
||||
ByteWriter<uint64_t>::WriteBigEndian(&packet_mask[6], mask_part2);
|
||||
}
|
||||
}
|
||||
|
||||
fec_packet->fec_header_size = byte_index;
|
||||
|
||||
// Store "ULPFECized" packet mask info.
|
||||
fec_packet->fec_header_size = FlexfecHeaderSize(packet_mask_size);
|
||||
fec_packet->protected_streams = {{.ssrc = protected_ssrc,
|
||||
.seq_num_base = seq_num_base,
|
||||
.packet_mask_offset = kPacketMaskOffset,
|
||||
.packet_mask_size = packet_mask_size}};
|
||||
// In FlexFEC, all media packets are protected in their entirety.
|
||||
fec_packet->protection_length =
|
||||
fec_packet->pkt->data.size() - fec_packet->fec_header_size;
|
||||
@ -215,13 +206,13 @@ bool FlexfecHeaderReader2::ReadFecHeader(
|
||||
return true;
|
||||
}
|
||||
|
||||
FlexfecHeaderWriter2::FlexfecHeaderWriter2()
|
||||
Flexfec03HeaderWriter::Flexfec03HeaderWriter()
|
||||
: FecHeaderWriter(kMaxMediaPackets, kMaxFecPackets, kHeaderSizes[2]) {}
|
||||
|
||||
FlexfecHeaderWriter2::~FlexfecHeaderWriter2() = default;
|
||||
Flexfec03HeaderWriter::~Flexfec03HeaderWriter() = default;
|
||||
|
||||
size_t FlexfecHeaderWriter2::MinPacketMaskSize(const uint8_t* packet_mask,
|
||||
size_t packet_mask_size) const {
|
||||
size_t Flexfec03HeaderWriter::MinPacketMaskSize(const uint8_t* packet_mask,
|
||||
size_t packet_mask_size) const {
|
||||
if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear &&
|
||||
(packet_mask[1] & 0x01) == 0) {
|
||||
// Packet mask is 16 bits long, with bit 15 clear.
|
||||
@ -246,7 +237,7 @@ size_t FlexfecHeaderWriter2::MinPacketMaskSize(const uint8_t* packet_mask,
|
||||
return kFlexfecPacketMaskSizes[2];
|
||||
}
|
||||
|
||||
size_t FlexfecHeaderWriter2::FecHeaderSize(size_t packet_mask_size) const {
|
||||
size_t Flexfec03HeaderWriter::FecHeaderSize(size_t packet_mask_size) const {
|
||||
return FlexfecHeaderSize(packet_mask_size);
|
||||
}
|
||||
|
||||
@ -257,7 +248,7 @@ size_t FlexfecHeaderWriter2::FecHeaderSize(size_t packet_mask_size) const {
|
||||
//
|
||||
// TODO(brandtr): Update this function when we support offset-based masks,
|
||||
// retransmissions, and protecting multiple SSRCs.
|
||||
void FlexfecHeaderWriter2::FinalizeFecHeader(
|
||||
void Flexfec03HeaderWriter::FinalizeFecHeader(
|
||||
uint32_t media_ssrc,
|
||||
uint16_t seq_num_base,
|
||||
const uint8_t* packet_mask,
|
||||
88
modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h
Normal file
88
modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_RTP_RTCP_SOURCE_FLEXFEC_03_HEADER_READER_WRITER_H_
|
||||
#define MODULES_RTP_RTCP_SOURCE_FLEXFEC_03_HEADER_READER_WRITER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "modules/rtp_rtcp/source/forward_error_correction.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// FlexFEC header, minimum 20 bytes.
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 0 |R|F|P|X| CC |M| PT recovery | length recovery |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 4 | TS recovery |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 8 | SSRCCount | reserved |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// 12 | SSRC_i |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 16 | SN base_i |k| Mask [0-14] |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 20 |k| Mask [15-45] (optional) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 24 |k| |
|
||||
// +-+ Mask [46-108] (optional) |
|
||||
// 28 | |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// : ... next in SSRC_i ... :
|
||||
//
|
||||
//
|
||||
// FlexFEC header in 'inflexible' mode (F = 1), 20 bytes.
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 0 |0|1|P|X| CC |M| PT recovery | length recovery |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 4 | TS recovery |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 8 | SSRCCount | reserved |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 12 | SSRC_i |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 16 | SN base_i | M (columns) | N (rows) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
class Flexfec03HeaderReader : public FecHeaderReader {
|
||||
public:
|
||||
Flexfec03HeaderReader();
|
||||
~Flexfec03HeaderReader() override;
|
||||
|
||||
bool ReadFecHeader(
|
||||
ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const override;
|
||||
};
|
||||
|
||||
class Flexfec03HeaderWriter : public FecHeaderWriter {
|
||||
public:
|
||||
Flexfec03HeaderWriter();
|
||||
~Flexfec03HeaderWriter() override;
|
||||
|
||||
size_t MinPacketMaskSize(const uint8_t* packet_mask,
|
||||
size_t packet_mask_size) const override;
|
||||
|
||||
size_t FecHeaderSize(size_t packet_mask_row_size) const override;
|
||||
|
||||
void FinalizeFecHeader(
|
||||
uint32_t media_ssrc,
|
||||
uint16_t seq_num_base,
|
||||
const uint8_t* packet_mask,
|
||||
size_t packet_mask_size,
|
||||
ForwardErrorCorrection::Packet* fec_packet) const override;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_RTP_RTCP_SOURCE_FLEXFEC_03_HEADER_READER_WRITER_H_
|
||||
@ -0,0 +1,565 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "modules/rtp_rtcp/source/byte_io.h"
|
||||
#include "modules/rtp_rtcp/source/forward_error_correction.h"
|
||||
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/random.h"
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
using Packet = ForwardErrorCorrection::Packet;
|
||||
using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket;
|
||||
using ::testing::ElementsAreArray;
|
||||
using ::testing::make_tuple;
|
||||
using ::testing::SizeIs;
|
||||
|
||||
// General. Assume single-stream protection.
|
||||
constexpr uint32_t kMediaSsrc = 1254983;
|
||||
constexpr uint16_t kMediaStartSeqNum = 825;
|
||||
constexpr size_t kMediaPacketLength = 1234;
|
||||
constexpr uint32_t kFlexfecSsrc = 52142;
|
||||
|
||||
constexpr size_t kFlexfecHeaderSizes[] = {20, 24, 32};
|
||||
constexpr size_t kFlexfecPacketMaskOffset = 18;
|
||||
constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14};
|
||||
constexpr size_t kFlexfecMaxPacketSize = kFlexfecPacketMaskSizes[2];
|
||||
|
||||
// Reader tests.
|
||||
constexpr uint8_t kNoRBit = 0 << 7;
|
||||
constexpr uint8_t kNoFBit = 0 << 6;
|
||||
constexpr uint8_t kPtRecovery = 123;
|
||||
constexpr uint8_t kLengthRecov[] = {0xab, 0xcd};
|
||||
constexpr uint8_t kTsRecovery[] = {0x01, 0x23, 0x45, 0x67};
|
||||
constexpr uint8_t kSsrcCount = 1;
|
||||
constexpr uint8_t kReservedBits = 0x00;
|
||||
constexpr uint8_t kProtSsrc[] = {0x11, 0x22, 0x33, 0x44};
|
||||
constexpr uint8_t kSnBase[] = {0xaa, 0xbb};
|
||||
constexpr uint8_t kPayloadBits = 0x00;
|
||||
|
||||
std::unique_ptr<uint8_t[]> GeneratePacketMask(size_t packet_mask_size,
|
||||
uint64_t seed) {
|
||||
Random random(seed);
|
||||
std::unique_ptr<uint8_t[]> packet_mask(new uint8_t[kFlexfecMaxPacketSize]);
|
||||
memset(packet_mask.get(), 0, kFlexfecMaxPacketSize);
|
||||
for (size_t i = 0; i < packet_mask_size; ++i) {
|
||||
packet_mask[i] = random.Rand<uint8_t>();
|
||||
}
|
||||
return packet_mask;
|
||||
}
|
||||
|
||||
void ClearBit(size_t index, uint8_t* packet_mask) {
|
||||
packet_mask[index / 8] &= ~(1 << (7 - index % 8));
|
||||
}
|
||||
|
||||
void SetBit(size_t index, uint8_t* packet_mask) {
|
||||
packet_mask[index / 8] |= (1 << (7 - index % 8));
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<Packet> WriteHeader(const uint8_t* packet_mask,
|
||||
size_t packet_mask_size) {
|
||||
Flexfec03HeaderWriter writer;
|
||||
rtc::scoped_refptr<Packet> written_packet(new Packet());
|
||||
written_packet->data.SetSize(kMediaPacketLength);
|
||||
uint8_t* data = written_packet->data.MutableData();
|
||||
for (size_t i = 0; i < written_packet->data.size(); ++i) {
|
||||
data[i] = i; // Actual content doesn't matter.
|
||||
}
|
||||
writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, packet_mask,
|
||||
packet_mask_size, written_packet.get());
|
||||
return written_packet;
|
||||
}
|
||||
|
||||
std::unique_ptr<ReceivedFecPacket> ReadHeader(const Packet& written_packet) {
|
||||
Flexfec03HeaderReader reader;
|
||||
std::unique_ptr<ReceivedFecPacket> read_packet(new ReceivedFecPacket());
|
||||
read_packet->ssrc = kFlexfecSsrc;
|
||||
read_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
|
||||
read_packet->pkt->data = written_packet.data;
|
||||
EXPECT_TRUE(reader.ReadFecHeader(read_packet.get()));
|
||||
return read_packet;
|
||||
}
|
||||
|
||||
void VerifyReadHeaders(size_t expected_fec_header_size,
|
||||
const uint8_t* expected_packet_mask,
|
||||
size_t expected_packet_mask_size,
|
||||
const ReceivedFecPacket& read_packet) {
|
||||
EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size);
|
||||
EXPECT_EQ(ByteReader<uint32_t>::ReadBigEndian(kProtSsrc),
|
||||
read_packet.protected_streams[0].ssrc);
|
||||
EXPECT_EQ(ByteReader<uint16_t>::ReadBigEndian(kSnBase),
|
||||
read_packet.protected_streams[0].seq_num_base);
|
||||
auto packet_mask_offset = read_packet.protected_streams[0].packet_mask_offset;
|
||||
EXPECT_EQ(kFlexfecPacketMaskOffset, packet_mask_offset);
|
||||
EXPECT_EQ(expected_packet_mask_size,
|
||||
read_packet.protected_streams[0].packet_mask_size);
|
||||
EXPECT_EQ(read_packet.pkt->data.size() - expected_fec_header_size,
|
||||
read_packet.protection_length);
|
||||
// Ensure that the K-bits are removed and the packet mask has been packed.
|
||||
EXPECT_THAT(
|
||||
make_tuple(read_packet.pkt->data.cdata() + packet_mask_offset,
|
||||
read_packet.protected_streams[0].packet_mask_size),
|
||||
ElementsAreArray(expected_packet_mask, expected_packet_mask_size));
|
||||
}
|
||||
|
||||
void VerifyFinalizedHeaders(const uint8_t* expected_packet_mask,
|
||||
size_t expected_packet_mask_size,
|
||||
const Packet& written_packet) {
|
||||
const uint8_t* packet = written_packet.data.cdata();
|
||||
EXPECT_EQ(0x00, packet[0] & 0x80); // F bit clear.
|
||||
EXPECT_EQ(0x00, packet[0] & 0x40); // R bit clear.
|
||||
EXPECT_EQ(0x01, packet[8]); // SSRCCount = 1.
|
||||
EXPECT_EQ(kMediaSsrc, ByteReader<uint32_t>::ReadBigEndian(packet + 12));
|
||||
EXPECT_EQ(kMediaStartSeqNum,
|
||||
ByteReader<uint16_t>::ReadBigEndian(packet + 16));
|
||||
EXPECT_THAT(
|
||||
make_tuple(packet + kFlexfecPacketMaskOffset, expected_packet_mask_size),
|
||||
ElementsAreArray(expected_packet_mask, expected_packet_mask_size));
|
||||
}
|
||||
|
||||
void VerifyWrittenAndReadHeaders(size_t expected_fec_header_size,
|
||||
const uint8_t* expected_packet_mask,
|
||||
size_t expected_packet_mask_size,
|
||||
const Packet& written_packet,
|
||||
const ReceivedFecPacket& read_packet) {
|
||||
EXPECT_EQ(kFlexfecSsrc, read_packet.ssrc);
|
||||
EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size);
|
||||
ASSERT_THAT(read_packet.protected_streams, SizeIs(1));
|
||||
EXPECT_EQ(read_packet.protected_streams[0].ssrc, kMediaSsrc);
|
||||
EXPECT_EQ(read_packet.protected_streams[0].seq_num_base, kMediaStartSeqNum);
|
||||
EXPECT_EQ(read_packet.protected_streams[0].packet_mask_offset,
|
||||
kFlexfecPacketMaskOffset);
|
||||
ASSERT_EQ(read_packet.protected_streams[0].packet_mask_size,
|
||||
expected_packet_mask_size);
|
||||
EXPECT_EQ(written_packet.data.size() - expected_fec_header_size,
|
||||
read_packet.protection_length);
|
||||
// Verify that the call to ReadFecHeader did normalize the packet masks.
|
||||
EXPECT_THAT(
|
||||
make_tuple(read_packet.pkt->data.cdata() + kFlexfecPacketMaskOffset,
|
||||
read_packet.protected_streams[0].packet_mask_size),
|
||||
ElementsAreArray(expected_packet_mask, expected_packet_mask_size));
|
||||
// Verify that the call to ReadFecHeader did not tamper with the payload.
|
||||
EXPECT_THAT(
|
||||
make_tuple(read_packet.pkt->data.cdata() + read_packet.fec_header_size,
|
||||
read_packet.pkt->data.size() - read_packet.fec_header_size),
|
||||
ElementsAreArray(written_packet.data.cdata() + expected_fec_header_size,
|
||||
written_packet.data.size() - expected_fec_header_size));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(Flexfec03HeaderReaderTest, ReadsHeaderWithKBit0Set) {
|
||||
constexpr uint8_t kKBit0 = 1 << 7;
|
||||
constexpr size_t kExpectedPacketMaskSize = 2;
|
||||
constexpr size_t kExpectedFecHeaderSize = 20;
|
||||
// clang-format off
|
||||
constexpr uint8_t kFlexfecPktMask[] = {kKBit0 | 0x08, 0x81};
|
||||
constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02};
|
||||
// clang-format on
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kNoRBit | kNoFBit, kPtRecovery, kLengthRecov[0], kLengthRecov[1],
|
||||
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
|
||||
kSsrcCount, kReservedBits, kReservedBits, kReservedBits,
|
||||
kProtSsrc[0], kProtSsrc[1], kProtSsrc[2], kProtSsrc[3],
|
||||
kSnBase[0], kSnBase[1], kFlexfecPktMask[0], kFlexfecPktMask[1],
|
||||
kPayloadBits, kPayloadBits, kPayloadBits, kPayloadBits};
|
||||
const size_t packet_length = sizeof(kPacketData);
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
|
||||
read_packet.pkt->data.SetData(kPacketData, packet_length);
|
||||
|
||||
Flexfec03HeaderReader reader;
|
||||
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
|
||||
|
||||
VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
|
||||
kExpectedPacketMaskSize, read_packet);
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderReaderTest, ReadsHeaderWithKBit1Set) {
|
||||
constexpr uint8_t kKBit0 = 0 << 7;
|
||||
constexpr uint8_t kKBit1 = 1 << 7;
|
||||
constexpr size_t kExpectedPacketMaskSize = 6;
|
||||
constexpr size_t kExpectedFecHeaderSize = 24;
|
||||
// clang-format off
|
||||
constexpr uint8_t kFlxfecPktMsk[] = {kKBit0 | 0x48, 0x81,
|
||||
kKBit1 | 0x02, 0x11, 0x00, 0x21};
|
||||
constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02,
|
||||
0x08, 0x44, 0x00, 0x84};
|
||||
// clang-format on
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kNoRBit | kNoFBit, kPtRecovery, kLengthRecov[0], kLengthRecov[1],
|
||||
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
|
||||
kSsrcCount, kReservedBits, kReservedBits, kReservedBits,
|
||||
kProtSsrc[0], kProtSsrc[1], kProtSsrc[2], kProtSsrc[3],
|
||||
kSnBase[0], kSnBase[1], kFlxfecPktMsk[0], kFlxfecPktMsk[1],
|
||||
kFlxfecPktMsk[2], kFlxfecPktMsk[3], kFlxfecPktMsk[4], kFlxfecPktMsk[5],
|
||||
kPayloadBits, kPayloadBits, kPayloadBits, kPayloadBits};
|
||||
const size_t packet_length = sizeof(kPacketData);
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
|
||||
read_packet.pkt->data.SetData(kPacketData, packet_length);
|
||||
|
||||
Flexfec03HeaderReader reader;
|
||||
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
|
||||
|
||||
VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
|
||||
kExpectedPacketMaskSize, read_packet);
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderReaderTest, ReadsHeaderWithKBit2Set) {
|
||||
constexpr uint8_t kKBit0 = 0 << 7;
|
||||
constexpr uint8_t kKBit1 = 0 << 7;
|
||||
constexpr uint8_t kKBit2 = 1 << 7;
|
||||
constexpr size_t kExpectedPacketMaskSize = 14;
|
||||
constexpr size_t kExpectedFecHeaderSize = 32;
|
||||
// clang-format off
|
||||
constexpr uint8_t kFlxfcPktMsk[] = {kKBit0 | 0x48, 0x81,
|
||||
kKBit1 | 0x02, 0x11, 0x00, 0x21,
|
||||
kKBit2 | 0x01, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x11, 0x11};
|
||||
constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02,
|
||||
0x08, 0x44, 0x00, 0x84,
|
||||
0x08, 0x88, 0x88, 0x88,
|
||||
0x88, 0x88, 0x88, 0x88};
|
||||
// clang-format on
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kNoRBit | kNoFBit, kPtRecovery, kLengthRecov[0], kLengthRecov[1],
|
||||
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
|
||||
kSsrcCount, kReservedBits, kReservedBits, kReservedBits,
|
||||
kProtSsrc[0], kProtSsrc[1], kProtSsrc[2], kProtSsrc[3],
|
||||
kSnBase[0], kSnBase[1], kFlxfcPktMsk[0], kFlxfcPktMsk[1],
|
||||
kFlxfcPktMsk[2], kFlxfcPktMsk[3], kFlxfcPktMsk[4], kFlxfcPktMsk[5],
|
||||
kFlxfcPktMsk[6], kFlxfcPktMsk[7], kFlxfcPktMsk[8], kFlxfcPktMsk[9],
|
||||
kFlxfcPktMsk[10], kFlxfcPktMsk[11], kFlxfcPktMsk[12], kFlxfcPktMsk[13],
|
||||
kPayloadBits, kPayloadBits, kPayloadBits, kPayloadBits};
|
||||
const size_t packet_length = sizeof(kPacketData);
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
|
||||
read_packet.pkt->data.SetData(kPacketData, packet_length);
|
||||
|
||||
Flexfec03HeaderReader reader;
|
||||
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
|
||||
|
||||
VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
|
||||
kExpectedPacketMaskSize, read_packet);
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderReaderTest,
|
||||
ReadPacketWithoutStreamSpecificHeaderShouldFail) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
|
||||
|
||||
// Simulate short received packet.
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.ssrc = kFlexfecSsrc;
|
||||
read_packet.pkt = std::move(written_packet);
|
||||
read_packet.pkt->data.SetSize(12);
|
||||
|
||||
Flexfec03HeaderReader reader;
|
||||
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderReaderTest, ReadShortPacketWithKBit0SetShouldFail) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
|
||||
|
||||
// Simulate short received packet.
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.ssrc = kFlexfecSsrc;
|
||||
read_packet.pkt = std::move(written_packet);
|
||||
read_packet.pkt->data.SetSize(18);
|
||||
|
||||
Flexfec03HeaderReader reader;
|
||||
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderReaderTest, ReadShortPacketWithKBit1SetShouldFail) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
SetBit(15, packet_mask.get()); // This expands the packet mask "once".
|
||||
auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
|
||||
|
||||
// Simulate short received packet.
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.ssrc = kFlexfecSsrc;
|
||||
read_packet.pkt = std::move(written_packet);
|
||||
read_packet.pkt->data.SetSize(20);
|
||||
|
||||
Flexfec03HeaderReader reader;
|
||||
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderReaderTest, ReadShortPacketWithKBit2SetShouldFail) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
SetBit(47, packet_mask.get()); // This expands the packet mask "twice".
|
||||
auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
|
||||
|
||||
// Simulate short received packet.
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.ssrc = kFlexfecSsrc;
|
||||
read_packet.pkt = std::move(written_packet);
|
||||
read_packet.pkt->data.SetSize(24);
|
||||
|
||||
Flexfec03HeaderReader reader;
|
||||
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderWriterTest, FinalizesHeaderWithKBit0Set) {
|
||||
constexpr size_t kExpectedPacketMaskSize = 2;
|
||||
constexpr uint8_t kFlexfecPacketMask[] = {0x88, 0x81};
|
||||
constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02};
|
||||
Packet written_packet;
|
||||
written_packet.data.SetSize(kMediaPacketLength);
|
||||
uint8_t* data = written_packet.data.MutableData();
|
||||
for (size_t i = 0; i < written_packet.data.size(); ++i) {
|
||||
data[i] = i;
|
||||
}
|
||||
|
||||
Flexfec03HeaderWriter writer;
|
||||
writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
|
||||
sizeof(kUlpfecPacketMask), &written_packet);
|
||||
|
||||
VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
|
||||
written_packet);
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderWriterTest, FinalizesHeaderWithKBit1Set) {
|
||||
constexpr size_t kExpectedPacketMaskSize = 6;
|
||||
constexpr uint8_t kFlexfecPacketMask[] = {0x48, 0x81, 0x82, 0x11, 0x00, 0x21};
|
||||
constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, 0x08, 0x44, 0x00, 0x84};
|
||||
Packet written_packet;
|
||||
written_packet.data.SetSize(kMediaPacketLength);
|
||||
uint8_t* data = written_packet.data.MutableData();
|
||||
for (size_t i = 0; i < written_packet.data.size(); ++i) {
|
||||
data[i] = i;
|
||||
}
|
||||
|
||||
Flexfec03HeaderWriter writer;
|
||||
writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
|
||||
sizeof(kUlpfecPacketMask), &written_packet);
|
||||
|
||||
VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
|
||||
written_packet);
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderWriterTest, FinalizesHeaderWithKBit2Set) {
|
||||
constexpr size_t kExpectedPacketMaskSize = 14;
|
||||
constexpr uint8_t kFlexfecPacketMask[] = {
|
||||
0x11, 0x11, // K-bit 0 clear.
|
||||
0x11, 0x11, 0x11, 0x10, // K-bit 1 clear.
|
||||
0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // K-bit 2 set.
|
||||
};
|
||||
constexpr uint8_t kUlpfecPacketMask[] = {0x22, 0x22, 0x44, 0x44, 0x44, 0x41};
|
||||
Packet written_packet;
|
||||
written_packet.data.SetSize(kMediaPacketLength);
|
||||
uint8_t* data = written_packet.data.MutableData();
|
||||
for (size_t i = 0; i < written_packet.data.size(); ++i) {
|
||||
data[i] = i;
|
||||
}
|
||||
|
||||
Flexfec03HeaderWriter writer;
|
||||
writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
|
||||
sizeof(kUlpfecPacketMask), &written_packet);
|
||||
|
||||
VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
|
||||
written_packet);
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderWriterTest, ContractsShortUlpfecPacketMaskWithBit15Clear) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
ClearBit(15, packet_mask.get());
|
||||
|
||||
Flexfec03HeaderWriter writer;
|
||||
size_t min_packet_mask_size =
|
||||
writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
|
||||
|
||||
EXPECT_EQ(kFlexfecPacketMaskSizes[0], min_packet_mask_size);
|
||||
EXPECT_EQ(kFlexfecHeaderSizes[0], writer.FecHeaderSize(min_packet_mask_size));
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderWriterTest, ExpandsShortUlpfecPacketMaskWithBit15Set) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
SetBit(15, packet_mask.get());
|
||||
|
||||
Flexfec03HeaderWriter writer;
|
||||
size_t min_packet_mask_size =
|
||||
writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
|
||||
|
||||
EXPECT_EQ(kFlexfecPacketMaskSizes[1], min_packet_mask_size);
|
||||
EXPECT_EQ(kFlexfecHeaderSizes[1], writer.FecHeaderSize(min_packet_mask_size));
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderWriterTest,
|
||||
ContractsLongUlpfecPacketMaskWithBit46ClearBit47Clear) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
ClearBit(46, packet_mask.get());
|
||||
ClearBit(47, packet_mask.get());
|
||||
|
||||
Flexfec03HeaderWriter writer;
|
||||
size_t min_packet_mask_size =
|
||||
writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
|
||||
|
||||
EXPECT_EQ(kFlexfecPacketMaskSizes[1], min_packet_mask_size);
|
||||
EXPECT_EQ(kFlexfecHeaderSizes[1], writer.FecHeaderSize(min_packet_mask_size));
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderWriterTest,
|
||||
ExpandsLongUlpfecPacketMaskWithBit46SetBit47Clear) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
SetBit(46, packet_mask.get());
|
||||
ClearBit(47, packet_mask.get());
|
||||
|
||||
Flexfec03HeaderWriter writer;
|
||||
size_t min_packet_mask_size =
|
||||
writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
|
||||
|
||||
EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size);
|
||||
EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size));
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderWriterTest,
|
||||
ExpandsLongUlpfecPacketMaskWithBit46ClearBit47Set) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
ClearBit(46, packet_mask.get());
|
||||
SetBit(47, packet_mask.get());
|
||||
|
||||
Flexfec03HeaderWriter writer;
|
||||
size_t min_packet_mask_size =
|
||||
writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
|
||||
|
||||
EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size);
|
||||
EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size));
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderWriterTest,
|
||||
ExpandsLongUlpfecPacketMaskWithBit46SetBit47Set) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
SetBit(46, packet_mask.get());
|
||||
SetBit(47, packet_mask.get());
|
||||
|
||||
Flexfec03HeaderWriter writer;
|
||||
size_t min_packet_mask_size =
|
||||
writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
|
||||
|
||||
EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size);
|
||||
EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size));
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderReaderWriterTest,
|
||||
WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Clear) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
ClearBit(15, packet_mask.get());
|
||||
|
||||
auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
|
||||
auto read_packet = ReadHeader(*written_packet);
|
||||
|
||||
VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[0], packet_mask.get(),
|
||||
kFlexfecPacketMaskSizes[0], *written_packet,
|
||||
*read_packet);
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderReaderWriterTest,
|
||||
WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Set) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
SetBit(15, packet_mask.get());
|
||||
|
||||
auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
|
||||
auto read_packet = ReadHeader(*written_packet);
|
||||
|
||||
VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[1], packet_mask.get(),
|
||||
kFlexfecPacketMaskSizes[1], *written_packet,
|
||||
*read_packet);
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderReaderWriterTest,
|
||||
WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Clear) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
ClearBit(46, packet_mask.get());
|
||||
ClearBit(47, packet_mask.get());
|
||||
|
||||
auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
|
||||
auto read_packet = ReadHeader(*written_packet);
|
||||
|
||||
VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[1], packet_mask.get(),
|
||||
kFlexfecPacketMaskSizes[1], *written_packet,
|
||||
*read_packet);
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderReaderWriterTest,
|
||||
WriteAndReadLargeUlpfecPacketHeaderWithMaskBit46SetBit47Clear) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
SetBit(46, packet_mask.get());
|
||||
ClearBit(47, packet_mask.get());
|
||||
|
||||
auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
|
||||
auto read_packet = ReadHeader(*written_packet);
|
||||
|
||||
VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(),
|
||||
kFlexfecPacketMaskSizes[2], *written_packet,
|
||||
*read_packet);
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderReaderWriterTest,
|
||||
WriteAndReadLargeUlpfecPacketHeaderMaskWithBit46ClearBit47Set) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
ClearBit(46, packet_mask.get());
|
||||
SetBit(47, packet_mask.get());
|
||||
|
||||
auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
|
||||
auto read_packet = ReadHeader(*written_packet);
|
||||
|
||||
VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(),
|
||||
kFlexfecPacketMaskSizes[2], *written_packet,
|
||||
*read_packet);
|
||||
}
|
||||
|
||||
TEST(Flexfec03HeaderReaderWriterTest,
|
||||
WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Set) {
|
||||
const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
|
||||
auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
|
||||
SetBit(46, packet_mask.get());
|
||||
SetBit(47, packet_mask.get());
|
||||
|
||||
auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
|
||||
auto read_packet = ReadHeader(*written_packet);
|
||||
|
||||
VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(),
|
||||
kFlexfecPacketMaskSizes[2], *written_packet,
|
||||
*read_packet);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
* Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
@ -37,10 +37,10 @@ constexpr size_t kMaxFecPackets = kMaxMediaPackets;
|
||||
constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14};
|
||||
|
||||
// Size (in bytes) of part of header which is not packet mask specific.
|
||||
constexpr size_t kBaseHeaderSize = 12;
|
||||
constexpr size_t kBaseHeaderSize = 8;
|
||||
|
||||
// Size (in bytes) of part of header which is stream specific.
|
||||
constexpr size_t kStreamSpecificHeaderSize = 6;
|
||||
constexpr size_t kStreamSpecificHeaderSize = 2;
|
||||
|
||||
// Size (in bytes) of header, given the single stream packet mask size, i.e.
|
||||
// the number of K-bits set.
|
||||
@ -82,9 +82,15 @@ FlexfecHeaderReader::FlexfecHeaderReader()
|
||||
FlexfecHeaderReader::~FlexfecHeaderReader() = default;
|
||||
|
||||
// TODO(brandtr): Update this function when we support flexible masks,
|
||||
// retransmissions, and/or several protected SSRCs.
|
||||
// and retransmissions.
|
||||
bool FlexfecHeaderReader::ReadFecHeader(
|
||||
ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const {
|
||||
// Protected ssrcs should already be populated from RTP header.
|
||||
if (fec_packet->protected_streams.empty()) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Discarding FlexFEC packet with no protected sources.";
|
||||
return false;
|
||||
}
|
||||
if (fec_packet->pkt->data.size() <=
|
||||
kBaseHeaderSize + kStreamSpecificHeaderSize) {
|
||||
RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
|
||||
@ -105,100 +111,103 @@ bool FlexfecHeaderReader::ReadFecHeader(
|
||||
"not yet support this, thus discarding packet.";
|
||||
return false;
|
||||
}
|
||||
uint8_t ssrc_count = ByteReader<uint8_t>::ReadBigEndian(&data[8]);
|
||||
if (ssrc_count != 1) {
|
||||
RTC_LOG(LS_INFO)
|
||||
<< "FlexFEC packet protecting multiple media SSRCs. We do not "
|
||||
"yet support this, thus discarding packet.";
|
||||
return false;
|
||||
}
|
||||
uint32_t protected_ssrc = ByteReader<uint32_t>::ReadBigEndian(&data[12]);
|
||||
uint16_t seq_num_base = ByteReader<uint16_t>::ReadBigEndian(&data[16]);
|
||||
|
||||
// Parse the FlexFEC packet mask and remove the interleaved K-bits.
|
||||
// First seq_num will be in byte index 8
|
||||
// (See FEC header schematic in flexfec_header_reader_writer.h.)
|
||||
// We store the packed packet mask in-band, which "destroys" the standards
|
||||
// compliance of the header. That is fine though, since the code that
|
||||
// reads from the header (from this point and onwards) is aware of this.
|
||||
// TODO(brandtr): When the FEC packet classes have been refactored, store
|
||||
// the packed packet masks out-of-band, thus leaving the FlexFEC header as is.
|
||||
//
|
||||
// We treat the mask parts as unsigned integers with host order endianness
|
||||
// in order to simplify the bit shifting between bytes.
|
||||
if (fec_packet->pkt->data.size() < kHeaderSizes[0]) {
|
||||
RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
|
||||
return false;
|
||||
}
|
||||
uint8_t* const packet_mask = data + kPacketMaskOffset;
|
||||
bool k_bit0 = (packet_mask[0] & 0x80) != 0;
|
||||
uint16_t mask_part0 = ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
|
||||
// Shift away K-bit 0, implicitly clearing the last bit.
|
||||
mask_part0 <<= 1;
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&packet_mask[0], mask_part0);
|
||||
size_t packet_mask_size;
|
||||
if (k_bit0) {
|
||||
// The first K-bit is set, and the packet mask is thus only 2 bytes long.
|
||||
// We have now read the entire FEC header, and the rest of the packet
|
||||
// is payload.
|
||||
packet_mask_size = kFlexfecPacketMaskSizes[0];
|
||||
} else {
|
||||
if (fec_packet->pkt->data.size() < kHeaderSizes[1]) {
|
||||
size_t byte_index = 8;
|
||||
for (size_t i = 0; i < fec_packet->protected_streams.size(); ++i) {
|
||||
if (fec_packet->pkt->data.size() < byte_index + kStreamSpecificHeaderSize) {
|
||||
RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
|
||||
return false;
|
||||
}
|
||||
bool k_bit1 = (packet_mask[2] & 0x80) != 0;
|
||||
// We have already shifted the first two bytes of the packet mask one step
|
||||
// to the left, thus removing K-bit 0. We will now shift the next four bytes
|
||||
// of the packet mask two steps to the left. (One step for the removed
|
||||
// K-bit 0, and one step for the to be removed K-bit 1).
|
||||
uint8_t bit15 = (packet_mask[2] >> 6) & 0x01;
|
||||
packet_mask[1] |= bit15;
|
||||
uint32_t mask_part1 = ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]);
|
||||
// Shift away K-bit 1 and bit 15, implicitly clearing the last two bits.
|
||||
mask_part1 <<= 2;
|
||||
ByteWriter<uint32_t>::WriteBigEndian(&packet_mask[2], mask_part1);
|
||||
if (k_bit1) {
|
||||
// The first K-bit is clear, but the second K-bit is set. The packet
|
||||
// mask is thus 6 bytes long. We have now read the entire FEC header,
|
||||
// and the rest of the packet is payload.
|
||||
packet_mask_size = kFlexfecPacketMaskSizes[1];
|
||||
|
||||
fec_packet->protected_streams[i].seq_num_base =
|
||||
ByteReader<uint16_t>::ReadBigEndian(&data[byte_index]);
|
||||
byte_index += kStreamSpecificHeaderSize;
|
||||
|
||||
// Parse the FlexFEC packet mask and remove the interleaved K-bits.
|
||||
// (See FEC header schematic in flexfec_header_reader_writer.h.)
|
||||
// We store the packed packet mask in-band, which "destroys" the standards
|
||||
// compliance of the header. That is fine though, since the code that
|
||||
// reads from the header (from this point and onwards) is aware of this.
|
||||
// TODO(brandtr): When the FEC packet classes have been refactored, store
|
||||
// the packed packet masks out-of-band, thus leaving the FlexFEC header as
|
||||
// is.
|
||||
//
|
||||
// We treat the mask parts as unsigned integers with host order endianness
|
||||
// in order to simplify the bit shifting between bytes.
|
||||
if (fec_packet->pkt->data.size() <
|
||||
(byte_index + kFlexfecPacketMaskSizes[0])) {
|
||||
RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
|
||||
return false;
|
||||
}
|
||||
fec_packet->protected_streams[i].packet_mask_offset = byte_index;
|
||||
bool k_bit0 = (data[byte_index] & 0x80) != 0;
|
||||
uint16_t mask_part0 =
|
||||
ByteReader<uint16_t>::ReadBigEndian(&data[byte_index]);
|
||||
// Shift away K-bit 0, implicitly clearing the last bit.
|
||||
mask_part0 <<= 1;
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&data[byte_index], mask_part0);
|
||||
byte_index += kFlexfecPacketMaskSizes[0];
|
||||
if (k_bit0) {
|
||||
// The first K-bit is set, and the packet mask is thus only 2 bytes long.
|
||||
// We have finished reading the properties for current ssrc.
|
||||
fec_packet->protected_streams[i].packet_mask_size =
|
||||
kFlexfecPacketMaskSizes[0];
|
||||
} else {
|
||||
if (fec_packet->pkt->data.size() < kHeaderSizes[2]) {
|
||||
RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
|
||||
if (fec_packet->pkt->data.size() <
|
||||
(byte_index + kFlexfecPacketMaskSizes[1] -
|
||||
kFlexfecPacketMaskSizes[0])) {
|
||||
return false;
|
||||
}
|
||||
bool k_bit2 = (packet_mask[6] & 0x80) != 0;
|
||||
if (k_bit2) {
|
||||
// The first and second K-bits are clear, but the third K-bit is set.
|
||||
// The packet mask is thus 14 bytes long. We have now read the entire
|
||||
// FEC header, and the rest of the packet is payload.
|
||||
packet_mask_size = kFlexfecPacketMaskSizes[2];
|
||||
bool k_bit1 = (data[byte_index] & 0x80) != 0;
|
||||
// We have already shifted the first two bytes of the packet mask one step
|
||||
// to the left, thus removing K-bit 0. We will now shift the next four
|
||||
// bytes of the packet mask two steps to the left. (One step for the
|
||||
// removed K-bit 0, and one step for the to be removed K-bit 1).
|
||||
uint8_t bit15 = (data[byte_index] >> 6) & 0x01;
|
||||
data[byte_index - 1] |= bit15;
|
||||
uint32_t mask_part1 =
|
||||
ByteReader<uint32_t>::ReadBigEndian(&data[byte_index]);
|
||||
// Shift away K-bit 1 and bit 15, implicitly clearing the last two bits.
|
||||
mask_part1 <<= 2;
|
||||
ByteWriter<uint32_t>::WriteBigEndian(&data[byte_index], mask_part1);
|
||||
byte_index += kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0];
|
||||
if (k_bit1) {
|
||||
// The first K-bit is clear, but the second K-bit is set. The packet
|
||||
// mask is thus 6 bytes long. We have finished reading the properties
|
||||
// for current ssrc.
|
||||
fec_packet->protected_streams[i].packet_mask_size =
|
||||
kFlexfecPacketMaskSizes[1];
|
||||
} else {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Discarding FlexFEC packet with malformed header.";
|
||||
return false;
|
||||
if (fec_packet->pkt->data.size() <
|
||||
(byte_index + kFlexfecPacketMaskSizes[2] -
|
||||
kFlexfecPacketMaskSizes[1])) {
|
||||
RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
|
||||
return false;
|
||||
}
|
||||
fec_packet->protected_streams[i].packet_mask_size =
|
||||
kFlexfecPacketMaskSizes[2];
|
||||
// At this point, K-bits 0 and 1 have been removed, and the front-most
|
||||
// part of the FlexFEC packet mask has been packed accordingly. We will
|
||||
// now shift the remaning part of the packet mask two steps to the left.
|
||||
// This corresponds to the (in total) two K-bits, which have been
|
||||
// removed.
|
||||
uint8_t tail_bits = (data[byte_index] >> 6) & 0x03;
|
||||
data[byte_index - 1] |= tail_bits;
|
||||
uint64_t mask_part2 =
|
||||
ByteReader<uint64_t>::ReadBigEndian(&data[byte_index]);
|
||||
// Shift away bit 46, and bit 47, which were copied to the previous
|
||||
// part of the mask, implicitly clearing the last two bits.
|
||||
mask_part2 <<= 2;
|
||||
ByteWriter<uint64_t>::WriteBigEndian(&data[byte_index], mask_part2);
|
||||
byte_index += kFlexfecPacketMaskSizes[2] - kFlexfecPacketMaskSizes[1];
|
||||
}
|
||||
// At this point, K-bits 0 and 1 have been removed, and the front-most
|
||||
// part of the FlexFEC packet mask has been packed accordingly. We will
|
||||
// now shift the remaning part of the packet mask three steps to the left.
|
||||
// This corresponds to the (in total) three K-bits, which have been
|
||||
// removed.
|
||||
uint8_t tail_bits = (packet_mask[6] >> 5) & 0x03;
|
||||
packet_mask[5] |= tail_bits;
|
||||
uint64_t mask_part2 =
|
||||
ByteReader<uint64_t>::ReadBigEndian(&packet_mask[6]);
|
||||
// Shift away K-bit 2, bit 46, and bit 47, implicitly clearing the last
|
||||
// three bits.
|
||||
mask_part2 <<= 3;
|
||||
ByteWriter<uint64_t>::WriteBigEndian(&packet_mask[6], mask_part2);
|
||||
}
|
||||
}
|
||||
|
||||
// Store "ULPFECized" packet mask info.
|
||||
fec_packet->fec_header_size = FlexfecHeaderSize(packet_mask_size);
|
||||
fec_packet->protected_streams = {{.ssrc = protected_ssrc,
|
||||
.seq_num_base = seq_num_base,
|
||||
.packet_mask_offset = kPacketMaskOffset,
|
||||
.packet_mask_size = packet_mask_size}};
|
||||
fec_packet->fec_header_size = byte_index;
|
||||
|
||||
// In FlexFEC, all media packets are protected in their entirety.
|
||||
fec_packet->protection_length =
|
||||
fec_packet->pkt->data.size() - fec_packet->fec_header_size;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
* Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
@ -18,43 +18,25 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// FlexFEC header, minimum 20 bytes.
|
||||
// FlexFEC header in flexible mode (R=0, F=0), minimum 12 bytes.
|
||||
// https://datatracker.ietf.org/doc/html/rfc8627#section-4.2.2.1
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 0 |R|F|P|X| CC |M| PT recovery | length recovery |
|
||||
// 0 |0|0|P|X| CC |M| PT recovery | length recovery |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 4 | TS recovery |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 8 | SSRCCount | reserved |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// 12 | SSRC_i |
|
||||
// 8 | SN base_i |k| Mask [0-14] |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 16 | SN base_i |k| Mask [0-14] |
|
||||
// 12 |k| Mask [15-45] (optional) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 20 |k| Mask [15-45] (optional) |
|
||||
// 16 | Mask [46-109] (optional) |
|
||||
// 20 | |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 24 |k| |
|
||||
// +-+ Mask [46-108] (optional) |
|
||||
// 28 | |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// : ... next in SSRC_i ... :
|
||||
// | ... next SN base and Mask for CSRC_i in CSRC list ... |
|
||||
//
|
||||
//
|
||||
// FlexFEC header in 'inflexible' mode (F = 1), 20 bytes.
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 0 |0|1|P|X| CC |M| PT recovery | length recovery |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 4 | TS recovery |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 8 | SSRCCount | reserved |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 12 | SSRC_i |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 16 | SN base_i | M (columns) | N (rows) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
class FlexfecHeaderReader : public FecHeaderReader {
|
||||
public:
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_RTP_RTCP_SOURCE_FLEXFEC_HEADER_READER_WRITER2_H_
|
||||
#define MODULES_RTP_RTCP_SOURCE_FLEXFEC_HEADER_READER_WRITER2_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "modules/rtp_rtcp/source/forward_error_correction.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// FlexFEC header in flexible mode (R=0, F=0), minimum 12 bytes.
|
||||
// https://datatracker.ietf.org/doc/html/rfc8627#section-4.2.2.1
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 0 |0|0|P|X| CC |M| PT recovery | length recovery |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 4 | TS recovery |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 8 | SN base_i |k| Mask [0-14] |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 12 |k| Mask [15-45] (optional) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 16 | Mask [46-109] (optional) |
|
||||
// 20 | |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | ... next SN base and Mask for CSRC_i in CSRC list ... |
|
||||
//
|
||||
|
||||
class FlexfecHeaderReader2 : public FecHeaderReader {
|
||||
public:
|
||||
FlexfecHeaderReader2();
|
||||
~FlexfecHeaderReader2() override;
|
||||
|
||||
bool ReadFecHeader(
|
||||
ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const override;
|
||||
};
|
||||
|
||||
class FlexfecHeaderWriter2 : public FecHeaderWriter {
|
||||
public:
|
||||
FlexfecHeaderWriter2();
|
||||
~FlexfecHeaderWriter2() override;
|
||||
|
||||
size_t MinPacketMaskSize(const uint8_t* packet_mask,
|
||||
size_t packet_mask_size) const override;
|
||||
|
||||
size_t FecHeaderSize(size_t packet_mask_row_size) const override;
|
||||
|
||||
void FinalizeFecHeader(
|
||||
uint32_t media_ssrc,
|
||||
uint16_t seq_num_base,
|
||||
const uint8_t* packet_mask,
|
||||
size_t packet_mask_size,
|
||||
ForwardErrorCorrection::Packet* fec_packet) const override;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_RTP_RTCP_SOURCE_FLEXFEC_HEADER_READER_WRITER2_H_
|
||||
@ -1,644 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/rtp_rtcp/source/flexfec_header_reader_writer2.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "api/make_ref_counted.h"
|
||||
#include "modules/rtp_rtcp/source/byte_io.h"
|
||||
#include "modules/rtp_rtcp/source/forward_error_correction.h"
|
||||
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/random.h"
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
using Packet = ForwardErrorCorrection::Packet;
|
||||
using ProtectedStream = ForwardErrorCorrection::ProtectedStream;
|
||||
using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket;
|
||||
using ::testing::ElementsAreArray;
|
||||
|
||||
constexpr uint8_t kMask0[] = {0xAB, 0xCD}; // First K bit is set.
|
||||
constexpr uint8_t kMask1[] = {0x12, 0x34, // First K bit cleared.
|
||||
0xF6, 0x78, 0x9A, 0xBC}; // Second K bit set.
|
||||
constexpr uint8_t kMask2[] = {0x12, 0x34, // First K bit cleared.
|
||||
0x56, 0x78, 0x9A, 0xBC, // Second K bit cleared.
|
||||
0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};
|
||||
|
||||
// Reader tests.
|
||||
constexpr uint8_t kFlexible = 0b00 << 6;
|
||||
constexpr uint8_t kPtRecovery = 123;
|
||||
constexpr uint8_t kLengthRecovery[] = {0xab, 0xcd};
|
||||
constexpr uint8_t kTsRecovery[] = {0x01, 0x23, 0x45, 0x67};
|
||||
constexpr uint8_t kSnBases[4][2] = {{0x01, 0x02},
|
||||
{0x03, 0x04},
|
||||
{0x05, 0x06},
|
||||
{0x07, 0x08}};
|
||||
constexpr uint8_t kPayloadBits = 0x00;
|
||||
|
||||
struct FecPacketStreamProperties {
|
||||
ProtectedStream stream;
|
||||
rtc::ArrayView<const uint8_t> mask;
|
||||
};
|
||||
|
||||
void VerifyReadHeaders(size_t expected_fec_header_size,
|
||||
const ReceivedFecPacket& read_packet,
|
||||
std::vector<FecPacketStreamProperties> expected) {
|
||||
EXPECT_EQ(read_packet.fec_header_size, expected_fec_header_size);
|
||||
const size_t protected_streams_num = read_packet.protected_streams.size();
|
||||
EXPECT_EQ(protected_streams_num, expected.size());
|
||||
for (size_t i = 0; i < protected_streams_num; ++i) {
|
||||
SCOPED_TRACE(i);
|
||||
ProtectedStream protected_stream = read_packet.protected_streams[i];
|
||||
EXPECT_EQ(protected_stream.ssrc, expected[i].stream.ssrc);
|
||||
EXPECT_EQ(protected_stream.seq_num_base, expected[i].stream.seq_num_base);
|
||||
EXPECT_EQ(protected_stream.packet_mask_offset,
|
||||
expected[i].stream.packet_mask_offset);
|
||||
EXPECT_EQ(protected_stream.packet_mask_size,
|
||||
expected[i].stream.packet_mask_size);
|
||||
// Ensure that the K-bits are removed and the packet mask has been packed.
|
||||
EXPECT_THAT(rtc::MakeArrayView(read_packet.pkt->data.cdata() +
|
||||
protected_stream.packet_mask_offset,
|
||||
protected_stream.packet_mask_size),
|
||||
ElementsAreArray(expected[i].mask));
|
||||
}
|
||||
EXPECT_EQ(read_packet.pkt->data.size() - expected_fec_header_size,
|
||||
read_packet.protection_length);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(FlexfecHeaderReader2Test, ReadsHeaderWithKBit0SetSingleStream) {
|
||||
constexpr uint8_t kKBit0 = 1 << 7;
|
||||
constexpr size_t kExpectedFecHeaderSize = 12;
|
||||
constexpr uint16_t kSnBase = 0x0102;
|
||||
constexpr uint8_t kFlexfecPktMask[] = {kKBit0 | 0x08, 0x81};
|
||||
constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02};
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
|
||||
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
|
||||
kSnBase >> 8, kSnBase & 0xFF, kFlexfecPktMask[0], kFlexfecPktMask[1],
|
||||
kPayloadBits, kPayloadBits, kPayloadBits, kPayloadBits};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
read_packet.pkt->data.SetData(kPacketData);
|
||||
read_packet.protected_streams = {{.ssrc = 0x01}};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
|
||||
|
||||
std::vector<FecPacketStreamProperties> expected = {
|
||||
{.stream = {.ssrc = 0x01,
|
||||
.seq_num_base = kSnBase,
|
||||
.packet_mask_offset = 10,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask)},
|
||||
.mask = kUlpfecPacketMask}};
|
||||
|
||||
VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
|
||||
}
|
||||
|
||||
TEST(FlexfecHeaderReader2Test, ReadsHeaderWithKBit1SetSingleStream) {
|
||||
constexpr uint8_t kKBit0 = 0 << 7;
|
||||
constexpr uint8_t kKBit1 = 1 << 7;
|
||||
constexpr size_t kExpectedFecHeaderSize = 16;
|
||||
constexpr uint16_t kSnBase = 0x0102;
|
||||
constexpr uint8_t kFlexfecPktMask[] = {kKBit0 | 0x48, 0x81, //
|
||||
kKBit1 | 0x02, 0x11, 0x00, 0x21};
|
||||
constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, //
|
||||
0x08, 0x44, 0x00, 0x84};
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kFlexible, kPtRecovery, kLengthRecovery[0],
|
||||
kLengthRecovery[1], kTsRecovery[0], kTsRecovery[1],
|
||||
kTsRecovery[2], kTsRecovery[3], kSnBase >> 8,
|
||||
kSnBase & 0xFF, kFlexfecPktMask[0], kFlexfecPktMask[1],
|
||||
kFlexfecPktMask[2], kFlexfecPktMask[3], kFlexfecPktMask[4],
|
||||
kFlexfecPktMask[5], kPayloadBits, kPayloadBits,
|
||||
kPayloadBits, kPayloadBits};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
read_packet.pkt->data.SetData(kPacketData);
|
||||
read_packet.protected_streams = {{.ssrc = 0x01}};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
|
||||
|
||||
std::vector<FecPacketStreamProperties> expected = {
|
||||
{.stream = {.ssrc = 0x01,
|
||||
.seq_num_base = kSnBase,
|
||||
.packet_mask_offset = 10,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask)},
|
||||
.mask = kUlpfecPacketMask}};
|
||||
|
||||
VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
|
||||
}
|
||||
|
||||
TEST(FlexfecHeaderReader2Test, ReadsHeaderWithNoKBitsSetSingleStream) {
|
||||
constexpr uint8_t kKBit0 = 0 << 7;
|
||||
constexpr uint8_t kKBit1 = 0 << 7;
|
||||
constexpr size_t kExpectedFecHeaderSize = 24;
|
||||
constexpr uint16_t kSnBase = 0x0102;
|
||||
constexpr uint8_t kFlexfecPacketMask[] = {kKBit0 | 0x48, 0x81, //
|
||||
kKBit1 | 0x02, 0x11, 0x00, 0x21, //
|
||||
0x01, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x11, 0x11};
|
||||
constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, //
|
||||
0x08, 0x44, 0x00, 0x84, //
|
||||
0x04, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44};
|
||||
constexpr uint8_t kPacketData[] = {kFlexible,
|
||||
kPtRecovery,
|
||||
kLengthRecovery[0],
|
||||
kLengthRecovery[1],
|
||||
kTsRecovery[0],
|
||||
kTsRecovery[1],
|
||||
kTsRecovery[2],
|
||||
kTsRecovery[3],
|
||||
kSnBase >> 8,
|
||||
kSnBase & 0xFF,
|
||||
kFlexfecPacketMask[0],
|
||||
kFlexfecPacketMask[1],
|
||||
kFlexfecPacketMask[2],
|
||||
kFlexfecPacketMask[3],
|
||||
kFlexfecPacketMask[4],
|
||||
kFlexfecPacketMask[5],
|
||||
kFlexfecPacketMask[6],
|
||||
kFlexfecPacketMask[7],
|
||||
kFlexfecPacketMask[8],
|
||||
kFlexfecPacketMask[9],
|
||||
kFlexfecPacketMask[10],
|
||||
kFlexfecPacketMask[11],
|
||||
kFlexfecPacketMask[12],
|
||||
kFlexfecPacketMask[13],
|
||||
kPayloadBits,
|
||||
kPayloadBits,
|
||||
kPayloadBits,
|
||||
kPayloadBits};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
read_packet.pkt->data.SetData(kPacketData);
|
||||
read_packet.protected_streams = {{.ssrc = 0x01}};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
|
||||
|
||||
std::vector<FecPacketStreamProperties> expected = {
|
||||
{.stream = {.ssrc = 0x01,
|
||||
.seq_num_base = kSnBase,
|
||||
.packet_mask_offset = 10,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask)},
|
||||
.mask = kUlpfecPacketMask}};
|
||||
|
||||
VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
|
||||
}
|
||||
|
||||
TEST(FlexfecHeaderReader2Test, ReadsHeaderWithKBit0Set2Streams) {
|
||||
constexpr uint8_t kKBit0 = 1 << 7;
|
||||
constexpr size_t kExpectedFecHeaderSize = 16;
|
||||
constexpr uint16_t kSnBase0 = 0x0102;
|
||||
constexpr uint16_t kSnBase1 = 0x0304;
|
||||
constexpr uint8_t kFlexfecPktMask1[] = {kKBit0 | 0x08, 0x81};
|
||||
constexpr uint8_t kUlpfecPacketMask1[] = {0x11, 0x02};
|
||||
constexpr uint8_t kFlexfecPktMask2[] = {kKBit0 | 0x04, 0x41};
|
||||
constexpr uint8_t kUlpfecPacketMask2[] = {0x08, 0x82};
|
||||
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
|
||||
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
|
||||
kSnBase0 >> 8, kSnBase0 & 0xFF, kFlexfecPktMask1[0], kFlexfecPktMask1[1],
|
||||
kSnBase1 >> 8, kSnBase1 & 0xFF, kFlexfecPktMask2[0], kFlexfecPktMask2[1],
|
||||
kPayloadBits, kPayloadBits, kPayloadBits, kPayloadBits};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
read_packet.pkt->data.SetData(kPacketData);
|
||||
read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
|
||||
|
||||
std::vector<FecPacketStreamProperties> expected = {
|
||||
{.stream = {.ssrc = 0x01,
|
||||
.seq_num_base = kSnBase0,
|
||||
.packet_mask_offset = 10,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask1)},
|
||||
.mask = kUlpfecPacketMask1},
|
||||
{.stream = {.ssrc = 0x02,
|
||||
.seq_num_base = kSnBase1,
|
||||
.packet_mask_offset = 14,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask2)},
|
||||
.mask = kUlpfecPacketMask2},
|
||||
};
|
||||
|
||||
VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
|
||||
}
|
||||
|
||||
TEST(FlexfecHeaderReader2Test, ReadsHeaderWithKBit1Set2Streams) {
|
||||
constexpr uint8_t kKBit0 = 0 << 7;
|
||||
constexpr uint8_t kKBit1 = 1 << 7;
|
||||
constexpr size_t kExpectedFecHeaderSize = 24;
|
||||
constexpr uint16_t kSnBase0 = 0x0102;
|
||||
constexpr uint16_t kSnBase1 = 0x0304;
|
||||
constexpr uint8_t kFlexfecPktMask1[] = {kKBit0 | 0x48, 0x81, //
|
||||
kKBit1 | 0x02, 0x11, 0x00, 0x21};
|
||||
constexpr uint8_t kUlpfecPacketMask1[] = {0x91, 0x02, //
|
||||
0x08, 0x44, 0x00, 0x84};
|
||||
constexpr uint8_t kFlexfecPktMask2[] = {kKBit0 | 0x57, 0x82, //
|
||||
kKBit1 | 0x04, 0x33, 0x00, 0x51};
|
||||
constexpr uint8_t kUlpfecPacketMask2[] = {0xAF, 0x04, //
|
||||
0x10, 0xCC, 0x01, 0x44};
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kFlexible, kPtRecovery, kLengthRecovery[0],
|
||||
kLengthRecovery[1], kTsRecovery[0], kTsRecovery[1],
|
||||
kTsRecovery[2], kTsRecovery[3], kSnBase0 >> 8,
|
||||
kSnBase0 & 0xFF, kFlexfecPktMask1[0], kFlexfecPktMask1[1],
|
||||
kFlexfecPktMask1[2], kFlexfecPktMask1[3], kFlexfecPktMask1[4],
|
||||
kFlexfecPktMask1[5], kSnBase1 >> 8, kSnBase1 & 0xFF,
|
||||
kFlexfecPktMask2[0], kFlexfecPktMask2[1], kFlexfecPktMask2[2],
|
||||
kFlexfecPktMask2[3], kFlexfecPktMask2[4], kFlexfecPktMask2[5],
|
||||
kPayloadBits, kPayloadBits, kPayloadBits,
|
||||
kPayloadBits};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
read_packet.pkt->data.SetData(kPacketData);
|
||||
read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
|
||||
|
||||
std::vector<FecPacketStreamProperties> expected = {
|
||||
{.stream = {.ssrc = 0x01,
|
||||
.seq_num_base = kSnBase0,
|
||||
.packet_mask_offset = 10,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask1)},
|
||||
.mask = kUlpfecPacketMask1},
|
||||
{.stream = {.ssrc = 0x02,
|
||||
.seq_num_base = kSnBase1,
|
||||
.packet_mask_offset = 18,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask2)},
|
||||
.mask = kUlpfecPacketMask2},
|
||||
};
|
||||
|
||||
VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
|
||||
}
|
||||
|
||||
TEST(FlexfecHeaderReader2Test, ReadsHeaderWithNoKBitsSet2Streams) {
|
||||
constexpr uint8_t kKBit0 = 0 << 7;
|
||||
constexpr uint8_t kKBit1 = 0 << 7;
|
||||
constexpr size_t kExpectedFecHeaderSize = 40;
|
||||
constexpr uint16_t kSnBase0 = 0x0102;
|
||||
constexpr uint16_t kSnBase1 = 0x0304;
|
||||
constexpr uint8_t kFlexfecPktMask1[] = {kKBit0 | 0x48, 0x81, //
|
||||
kKBit1 | 0x02, 0x11, 0x00, 0x21, //
|
||||
0x01, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x11, 0x11};
|
||||
constexpr uint8_t kUlpfecPacketMask1[] = {0x91, 0x02, //
|
||||
0x08, 0x44, 0x00, 0x84, //
|
||||
0x04, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44};
|
||||
constexpr uint8_t kFlexfecPktMask2[] = {kKBit0 | 0x32, 0x84, //
|
||||
kKBit1 | 0x05, 0x23, 0x00, 0x55, //
|
||||
0xA3, 0x22, 0x22, 0x22,
|
||||
0x22, 0x22, 0x22, 0x35};
|
||||
constexpr uint8_t kUlpfecPacketMask2[] = {0x65, 0x08, //
|
||||
0x14, 0x8C, 0x01, 0x56, //
|
||||
0x8C, 0x88, 0x88, 0x88,
|
||||
0x88, 0x88, 0x88, 0xD4};
|
||||
|
||||
constexpr uint8_t kPacketData[] = {kFlexible,
|
||||
kPtRecovery,
|
||||
kLengthRecovery[0],
|
||||
kLengthRecovery[1],
|
||||
kTsRecovery[0],
|
||||
kTsRecovery[1],
|
||||
kTsRecovery[2],
|
||||
kTsRecovery[3],
|
||||
kSnBase0 >> 8,
|
||||
kSnBase0 & 0xFF,
|
||||
kFlexfecPktMask1[0],
|
||||
kFlexfecPktMask1[1],
|
||||
kFlexfecPktMask1[2],
|
||||
kFlexfecPktMask1[3],
|
||||
kFlexfecPktMask1[4],
|
||||
kFlexfecPktMask1[5],
|
||||
kFlexfecPktMask1[6],
|
||||
kFlexfecPktMask1[7],
|
||||
kFlexfecPktMask1[8],
|
||||
kFlexfecPktMask1[9],
|
||||
kFlexfecPktMask1[10],
|
||||
kFlexfecPktMask1[11],
|
||||
kFlexfecPktMask1[12],
|
||||
kFlexfecPktMask1[13],
|
||||
kSnBase1 >> 8,
|
||||
kSnBase1 & 0xFF,
|
||||
kFlexfecPktMask2[0],
|
||||
kFlexfecPktMask2[1],
|
||||
kFlexfecPktMask2[2],
|
||||
kFlexfecPktMask2[3],
|
||||
kFlexfecPktMask2[4],
|
||||
kFlexfecPktMask2[5],
|
||||
kFlexfecPktMask2[6],
|
||||
kFlexfecPktMask2[7],
|
||||
kFlexfecPktMask2[8],
|
||||
kFlexfecPktMask2[9],
|
||||
kFlexfecPktMask2[10],
|
||||
kFlexfecPktMask2[11],
|
||||
kFlexfecPktMask2[12],
|
||||
kFlexfecPktMask2[13],
|
||||
kPayloadBits,
|
||||
kPayloadBits,
|
||||
kPayloadBits,
|
||||
kPayloadBits};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
read_packet.pkt->data.SetData(kPacketData);
|
||||
read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
|
||||
|
||||
std::vector<FecPacketStreamProperties> expected = {
|
||||
{.stream = {.ssrc = 0x01,
|
||||
.seq_num_base = kSnBase0,
|
||||
.packet_mask_offset = 10,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask1)},
|
||||
.mask = kUlpfecPacketMask1},
|
||||
{.stream = {.ssrc = 0x02,
|
||||
.seq_num_base = kSnBase1,
|
||||
.packet_mask_offset = 26,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask2)},
|
||||
.mask = kUlpfecPacketMask2},
|
||||
};
|
||||
|
||||
VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
|
||||
}
|
||||
|
||||
TEST(FlexfecHeaderReader2Test, ReadsHeaderWithMultipleStreamsMultipleMasks) {
|
||||
constexpr uint8_t kBit0 = 0 << 7;
|
||||
constexpr uint8_t kBit1 = 1 << 7;
|
||||
constexpr size_t kExpectedFecHeaderSize = 44;
|
||||
constexpr uint16_t kSnBase0 = 0x0102;
|
||||
constexpr uint16_t kSnBase1 = 0x0304;
|
||||
constexpr uint16_t kSnBase2 = 0x0506;
|
||||
constexpr uint16_t kSnBase3 = 0x0708;
|
||||
constexpr uint8_t kFlexfecPacketMask1[] = {kBit1 | 0x29, 0x91};
|
||||
constexpr uint8_t kUlpfecPacketMask1[] = {0x53, 0x22};
|
||||
constexpr uint8_t kFlexfecPacketMask2[] = {kBit0 | 0x32, 0xA1, //
|
||||
kBit1 | 0x02, 0x11, 0x00, 0x21};
|
||||
constexpr uint8_t kUlpfecPacketMask2[] = {0x65, 0x42, //
|
||||
0x08, 0x44, 0x00, 0x84};
|
||||
constexpr uint8_t kFlexfecPacketMask3[] = {kBit0 | 0x48, 0x81, //
|
||||
kBit0 | 0x02, 0x11, 0x00, 0x21, //
|
||||
0x01, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x11, 0x11};
|
||||
constexpr uint8_t kUlpfecPacketMask3[] = {0x91, 0x02, //
|
||||
0x08, 0x44, 0x00, 0x84, //
|
||||
0x04, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44};
|
||||
constexpr uint8_t kFlexfecPacketMask4[] = {kBit0 | 0x32, 0x84, //
|
||||
kBit1 | 0x05, 0x23, 0x00, 0x55};
|
||||
constexpr uint8_t kUlpfecPacketMask4[] = {0x65, 0x08, //
|
||||
0x14, 0x8C, 0x01, 0x54};
|
||||
constexpr uint8_t kPacketData[] = {kFlexible,
|
||||
kPtRecovery,
|
||||
kLengthRecovery[0],
|
||||
kLengthRecovery[1],
|
||||
kTsRecovery[0],
|
||||
kTsRecovery[1],
|
||||
kTsRecovery[2],
|
||||
kTsRecovery[3],
|
||||
kSnBase0 >> 8,
|
||||
kSnBase0 & 0xFF,
|
||||
kFlexfecPacketMask1[0],
|
||||
kFlexfecPacketMask1[1],
|
||||
kSnBase1 >> 8,
|
||||
kSnBase1 & 0xFF,
|
||||
kFlexfecPacketMask2[0],
|
||||
kFlexfecPacketMask2[1],
|
||||
kFlexfecPacketMask2[2],
|
||||
kFlexfecPacketMask2[3],
|
||||
kFlexfecPacketMask2[4],
|
||||
kFlexfecPacketMask2[5],
|
||||
kSnBase2 >> 8,
|
||||
kSnBase2 & 0xFF,
|
||||
kFlexfecPacketMask3[0],
|
||||
kFlexfecPacketMask3[1],
|
||||
kFlexfecPacketMask3[2],
|
||||
kFlexfecPacketMask3[3],
|
||||
kFlexfecPacketMask3[4],
|
||||
kFlexfecPacketMask3[5],
|
||||
kFlexfecPacketMask3[6],
|
||||
kFlexfecPacketMask3[7],
|
||||
kFlexfecPacketMask3[8],
|
||||
kFlexfecPacketMask3[9],
|
||||
kFlexfecPacketMask3[10],
|
||||
kFlexfecPacketMask3[11],
|
||||
kFlexfecPacketMask3[12],
|
||||
kFlexfecPacketMask3[13],
|
||||
kSnBase3 >> 8,
|
||||
kSnBase3 & 0xFF,
|
||||
kFlexfecPacketMask4[0],
|
||||
kFlexfecPacketMask4[1],
|
||||
kFlexfecPacketMask4[2],
|
||||
kFlexfecPacketMask4[3],
|
||||
kFlexfecPacketMask4[4],
|
||||
kFlexfecPacketMask4[5],
|
||||
kPayloadBits,
|
||||
kPayloadBits,
|
||||
kPayloadBits,
|
||||
kPayloadBits};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
read_packet.pkt->data.SetData(kPacketData);
|
||||
read_packet.protected_streams = {
|
||||
{.ssrc = 0x01}, {.ssrc = 0x02}, {.ssrc = 0x03}, {.ssrc = 0x04}};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
|
||||
|
||||
std::vector<FecPacketStreamProperties> expected = {
|
||||
{.stream = {.ssrc = 0x01,
|
||||
.seq_num_base = kSnBase0,
|
||||
.packet_mask_offset = 10,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask1)},
|
||||
.mask = kUlpfecPacketMask1},
|
||||
{.stream = {.ssrc = 0x02,
|
||||
.seq_num_base = kSnBase1,
|
||||
.packet_mask_offset = 14,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask2)},
|
||||
.mask = kUlpfecPacketMask2},
|
||||
{.stream = {.ssrc = 0x03,
|
||||
.seq_num_base = kSnBase2,
|
||||
.packet_mask_offset = 22,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask3)},
|
||||
.mask = kUlpfecPacketMask3},
|
||||
{.stream = {.ssrc = 0x04,
|
||||
.seq_num_base = kSnBase3,
|
||||
.packet_mask_offset = 38,
|
||||
.packet_mask_size = std::size(kUlpfecPacketMask4)},
|
||||
.mask = kUlpfecPacketMask4},
|
||||
};
|
||||
|
||||
VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
|
||||
}
|
||||
|
||||
TEST(FlexfecHeaderReader2Test, ReadPacketWithoutProtectedSsrcsShouldFail) {
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
|
||||
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3]};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
read_packet.pkt->data.SetData(kPacketData);
|
||||
// No protected ssrcs.
|
||||
read_packet.protected_streams = {};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
|
||||
}
|
||||
|
||||
TEST(FlexfecHeaderReader2Test,
|
||||
ReadPacketWithoutStreamSpecificHeaderShouldFail) {
|
||||
// Simulate short received packet.
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
|
||||
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3]};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
read_packet.pkt->data.SetData(kPacketData);
|
||||
read_packet.protected_streams = {{.ssrc = 0x01}};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
|
||||
}
|
||||
|
||||
TEST(FlexfecHeaderReader2Test, ReadShortPacketWithKBit0SetShouldFail) {
|
||||
// Simulate short received packet.
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
|
||||
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
|
||||
kSnBases[0][0], kSnBases[0][1], kMask0[0], kMask0[1]};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
// Expected to have 2 bytes of mask but length of packet misses 1 byte.
|
||||
read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 1);
|
||||
read_packet.protected_streams = {{.ssrc = 0x01}};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
|
||||
}
|
||||
|
||||
TEST(FlexfecHeaderReader2Test, ReadShortPacketWithKBit1SetShouldFail) {
|
||||
// Simulate short received packet.
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
|
||||
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
|
||||
kSnBases[0][0], kSnBases[0][1], kMask1[0], kMask1[1],
|
||||
kMask1[2], kMask1[3], kMask1[4], kMask1[5]};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
// Expected to have 6 bytes of mask but length of packet misses 2 bytes.
|
||||
read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 2);
|
||||
read_packet.protected_streams = {{.ssrc = 0x01}};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
|
||||
}
|
||||
|
||||
TEST(FlexfecHeaderReader2Test, ReadShortPacketWithKBit1ClearedShouldFail) {
|
||||
// Simulate short received packet.
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
|
||||
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
|
||||
kSnBases[0][0], kSnBases[0][1], kMask2[0], kMask2[1],
|
||||
kMask2[2], kMask2[3], kMask2[4], kMask2[5],
|
||||
kMask2[6], kMask2[7], kMask2[8], kMask2[9],
|
||||
kMask2[10], kMask2[11], kMask2[12], kMask2[13]};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
// Expected to have 14 bytes of mask but length of packet misses 2 bytes.
|
||||
read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 2);
|
||||
read_packet.protected_streams = {{.ssrc = 0x01}};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
|
||||
}
|
||||
|
||||
TEST(FlexfecHeaderReader2Test, ReadShortPacketMultipleStreamsShouldFail) {
|
||||
// Simulate short received packet with 2 protected ssrcs.
|
||||
constexpr uint8_t kPacketData[] = {
|
||||
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
|
||||
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
|
||||
kSnBases[0][0], kSnBases[0][1], kMask0[0], kMask0[1],
|
||||
kSnBases[1][0], kSnBases[1][1], kMask2[0], kMask2[1],
|
||||
kMask2[2], kMask2[3], kMask2[4], kMask2[5],
|
||||
kMask2[6], kMask2[7], kMask2[8], kMask2[9],
|
||||
kMask2[10], kMask2[11], kMask2[12], kMask2[13]};
|
||||
ReceivedFecPacket read_packet;
|
||||
read_packet.pkt = rtc::make_ref_counted<Packet>();
|
||||
// Subtract 2 bytes from length, so the read will fail on parsing second
|
||||
read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 2);
|
||||
read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
|
||||
|
||||
FlexfecHeaderReader2 reader;
|
||||
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
|
||||
}
|
||||
|
||||
// TODO(bugs.webrtc.org/15002): reimplement and add tests for multi stream cases
|
||||
// after updating the Writer code.
|
||||
|
||||
TEST(FlexfecHeaderWriter2Test, FinalizesHeaderWithKBit0Set) {}
|
||||
|
||||
TEST(FlexfecHeaderWriter2Test, FinalizesHeaderWithKBit1Set) {}
|
||||
|
||||
TEST(FlexfecHeaderWriter2Test, FinalizesHeaderWithKBit2Set) {}
|
||||
|
||||
TEST(FlexfecHeaderWriter2Test, ContractsShortUlpfecPacketMaskWithBit15Clear) {}
|
||||
|
||||
TEST(FlexfecHeaderWriter2Test, ExpandsShortUlpfecPacketMaskWithBit15Set) {}
|
||||
|
||||
TEST(FlexfecHeaderWriter2Test,
|
||||
ContractsLongUlpfecPacketMaskWithBit46ClearBit47Clear) {}
|
||||
|
||||
TEST(FlexfecHeaderWriter2Test,
|
||||
ExpandsLongUlpfecPacketMaskWithBit46SetBit47Clear) {}
|
||||
|
||||
TEST(FlexfecHeaderWriter2Test,
|
||||
ExpandsLongUlpfecPacketMaskWithBit46ClearBit47Set) {}
|
||||
|
||||
TEST(FlexfecHeaderWriter2Test,
|
||||
ExpandsLongUlpfecPacketMaskWithBit46SetBit47Set) {}
|
||||
|
||||
TEST(FlexfecHeaderReaderWriter2Test,
|
||||
WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Clear) {}
|
||||
|
||||
TEST(FlexfecHeaderReaderWriter2Test,
|
||||
WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Set) {}
|
||||
|
||||
TEST(FlexfecHeaderReaderWriter2Test,
|
||||
WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Clear) {}
|
||||
|
||||
TEST(FlexfecHeaderReaderWriter2Test,
|
||||
WriteAndReadLargeUlpfecPacketHeaderWithMaskBit46SetBit47Clear) {}
|
||||
|
||||
TEST(FlexfecHeaderReaderWriter2Test,
|
||||
WriteAndReadLargeUlpfecPacketHeaderMaskWithBit46ClearBit47Set) {}
|
||||
|
||||
TEST(FlexfecHeaderReaderWriter2Test,
|
||||
WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Set) {}
|
||||
|
||||
} // namespace webrtc
|
||||
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,7 @@
|
||||
#include "modules/include/module_common_types_public.h"
|
||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "modules/rtp_rtcp/source/byte_io.h"
|
||||
#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h"
|
||||
#include "modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h"
|
||||
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
|
||||
#include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h"
|
||||
#include "rtc_base/checks.h"
|
||||
@ -99,8 +99,10 @@ std::unique_ptr<ForwardErrorCorrection> ForwardErrorCorrection::CreateUlpfec(
|
||||
std::unique_ptr<ForwardErrorCorrection> ForwardErrorCorrection::CreateFlexfec(
|
||||
uint32_t ssrc,
|
||||
uint32_t protected_media_ssrc) {
|
||||
std::unique_ptr<FecHeaderReader> fec_header_reader(new FlexfecHeaderReader());
|
||||
std::unique_ptr<FecHeaderWriter> fec_header_writer(new FlexfecHeaderWriter());
|
||||
std::unique_ptr<FecHeaderReader> fec_header_reader(
|
||||
new Flexfec03HeaderReader());
|
||||
std::unique_ptr<FecHeaderWriter> fec_header_writer(
|
||||
new Flexfec03HeaderWriter());
|
||||
return std::unique_ptr<ForwardErrorCorrection>(new ForwardErrorCorrection(
|
||||
std::move(fec_header_reader), std::move(fec_header_writer), ssrc,
|
||||
protected_media_ssrc));
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
#include "absl/algorithm/container.h"
|
||||
#include "modules/rtp_rtcp/source/byte_io.h"
|
||||
#include "modules/rtp_rtcp/source/fec_test_helper.h"
|
||||
#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h"
|
||||
#include "modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h"
|
||||
#include "modules/rtp_rtcp/source/forward_error_correction.h"
|
||||
#include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h"
|
||||
#include "rtc_base/random.h"
|
||||
@ -177,8 +177,8 @@ class FlexfecForwardErrorCorrection : public ForwardErrorCorrection {
|
||||
|
||||
FlexfecForwardErrorCorrection()
|
||||
: ForwardErrorCorrection(
|
||||
std::unique_ptr<FecHeaderReader>(new FlexfecHeaderReader()),
|
||||
std::unique_ptr<FecHeaderWriter>(new FlexfecHeaderWriter()),
|
||||
std::unique_ptr<FecHeaderReader>(new Flexfec03HeaderReader()),
|
||||
std::unique_ptr<FecHeaderWriter>(new Flexfec03HeaderWriter()),
|
||||
kFecSsrc,
|
||||
kMediaSsrc) {}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user