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}
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
index cab7bec..80c5f6b 100644
--- a/modules/rtp_rtcp/BUILD.gn
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -170,10 +170,10 @@
"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 @@
"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",
diff --git a/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.cc b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.cc
new file mode 100644
index 0000000..ddf8e32
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.cc
@@ -0,0 +1,319 @@
+/*
+ * 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 "api/scoped_refptr.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+namespace {
+
+// Maximum number of media packets that can be protected in one batch.
+constexpr size_t kMaxMediaPackets = 48; // Since we are reusing ULPFEC masks.
+
+// Maximum number of media packets tracked by FEC decoder.
+// Maintain a sufficiently larger tracking window than `kMaxMediaPackets`
+// to account for packet reordering in pacer/ network.
+constexpr size_t kMaxTrackedMediaPackets = 4 * kMaxMediaPackets;
+
+// Maximum number of FEC packets stored inside ForwardErrorCorrection.
+constexpr size_t kMaxFecPackets = kMaxMediaPackets;
+
+// Size (in bytes) of packet masks, given number of K bits set.
+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;
+
+// Size (in bytes) of part of header which is stream specific.
+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.
+constexpr size_t kHeaderSizes[] = {
+ kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[0],
+ kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[1],
+ kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[2]};
+
+// We currently only support single-stream protection.
+// TODO(brandtr): Update this when we support multistream protection.
+constexpr uint8_t kSsrcCount = 1;
+
+// There are three reserved bytes that MUST be set to zero in the header.
+constexpr uint32_t kReservedBits = 0;
+
+// TODO(brandtr): Update this when we support multistream protection.
+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
+// 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]) {
+ return kHeaderSizes[0];
+ } else if (packet_mask_size <= kFlexfecPacketMaskSizes[1]) {
+ return kHeaderSizes[1];
+ }
+ return kHeaderSizes[2];
+}
+
+} // namespace
+
+Flexfec03HeaderReader::Flexfec03HeaderReader()
+ : FecHeaderReader(kMaxTrackedMediaPackets, kMaxFecPackets) {}
+
+Flexfec03HeaderReader::~Flexfec03HeaderReader() = default;
+
+// TODO(brandtr): Update this function when we support flexible masks,
+// retransmissions, and/or several protected SSRCs.
+bool Flexfec03HeaderReader::ReadFecHeader(
+ ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const {
+ if (fec_packet->pkt->data.size() <=
+ kBaseHeaderSize + kStreamSpecificHeaderSize) {
+ RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
+ return false;
+ }
+ uint8_t* const data = fec_packet->pkt->data.MutableData();
+ bool r_bit = (data[0] & 0x80) != 0;
+ if (r_bit) {
+ RTC_LOG(LS_INFO)
+ << "FlexFEC packet with retransmission bit set. We do not yet "
+ "support this, thus discarding the packet.";
+ return false;
+ }
+ bool f_bit = (data[0] & 0x40) != 0;
+ if (f_bit) {
+ RTC_LOG(LS_INFO)
+ << "FlexFEC packet with inflexible generator matrix. We do "
+ "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.
+ // (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]) {
+ 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];
+ } else {
+ if (fec_packet->pkt->data.size() < kHeaderSizes[2]) {
+ RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
+ 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];
+ } else {
+ 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);
+ }
+ }
+
+ // 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;
+
+ return true;
+}
+
+Flexfec03HeaderWriter::Flexfec03HeaderWriter()
+ : FecHeaderWriter(kMaxMediaPackets, kMaxFecPackets, kHeaderSizes[2]) {}
+
+Flexfec03HeaderWriter::~Flexfec03HeaderWriter() = default;
+
+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.
+ // It can be used as is.
+ return kFlexfecPacketMaskSizes[0];
+ } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) {
+ // Packet mask is 16 bits long, with bit 15 set.
+ // We must expand the packet mask with zeros in the FlexFEC header.
+ return kFlexfecPacketMaskSizes[1];
+ } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet &&
+ (packet_mask[5] & 0x03) == 0) {
+ // Packet mask is 48 bits long, with bits 46 and 47 clear.
+ // It can be used as is.
+ return kFlexfecPacketMaskSizes[1];
+ } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) {
+ // Packet mask is 48 bits long, with at least one of bits 46 and 47 set.
+ // We must expand it with zeros.
+ return kFlexfecPacketMaskSizes[2];
+ }
+ RTC_DCHECK_NOTREACHED() << "Incorrect packet mask size: " << packet_mask_size
+ << ".";
+ return kFlexfecPacketMaskSizes[2];
+}
+
+size_t Flexfec03HeaderWriter::FecHeaderSize(size_t packet_mask_size) const {
+ return FlexfecHeaderSize(packet_mask_size);
+}
+
+// This function adapts the precomputed ULPFEC packet masks to the
+// FlexFEC header standard. Note that the header size is computed by
+// FecHeaderSize(), so in this function we can be sure that we are
+// writing in space that is intended for the header.
+//
+// TODO(brandtr): Update this function when we support offset-based masks,
+// retransmissions, and protecting multiple SSRCs.
+void Flexfec03HeaderWriter::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 {
+ uint8_t* data = fec_packet->data.MutableData();
+ data[0] &= 0x7f; // Clear R bit.
+ data[0] &= 0xbf; // Clear F bit.
+ ByteWriter<uint8_t>::WriteBigEndian(&data[8], kSsrcCount);
+ ByteWriter<uint32_t, 3>::WriteBigEndian(&data[9], kReservedBits);
+ ByteWriter<uint32_t>::WriteBigEndian(&data[12], media_ssrc);
+ ByteWriter<uint16_t>::WriteBigEndian(&data[16], seq_num_base);
+ // Adapt ULPFEC packet mask to FlexFEC header.
+ //
+ // We treat the mask parts as unsigned integers with host order endianness
+ // in order to simplify the bit shifting between bytes.
+ uint8_t* const written_packet_mask = data + kPacketMaskOffset;
+ if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) {
+ // The packet mask is 48 bits long.
+ uint16_t tmp_mask_part0 =
+ ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
+ uint32_t tmp_mask_part1 =
+ ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]);
+
+ tmp_mask_part0 >>= 1; // Shift, thus clearing K-bit 0.
+ ByteWriter<uint16_t>::WriteBigEndian(&written_packet_mask[0],
+ tmp_mask_part0);
+ tmp_mask_part1 >>= 2; // Shift, thus clearing K-bit 1 and bit 15.
+ ByteWriter<uint32_t>::WriteBigEndian(&written_packet_mask[2],
+ tmp_mask_part1);
+ bool bit15 = (packet_mask[1] & 0x01) != 0;
+ if (bit15)
+ written_packet_mask[2] |= 0x40; // Set bit 15.
+ bool bit46 = (packet_mask[5] & 0x02) != 0;
+ bool bit47 = (packet_mask[5] & 0x01) != 0;
+ if (!bit46 && !bit47) {
+ written_packet_mask[2] |= 0x80; // Set K-bit 1.
+ } else {
+ memset(&written_packet_mask[6], 0, 8); // Clear all trailing bits.
+ written_packet_mask[6] |= 0x80; // Set K-bit 2.
+ if (bit46)
+ written_packet_mask[6] |= 0x40; // Set bit 46.
+ if (bit47)
+ written_packet_mask[6] |= 0x20; // Set bit 47.
+ }
+ } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) {
+ // The packet mask is 16 bits long.
+ uint16_t tmp_mask_part0 =
+ ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
+
+ tmp_mask_part0 >>= 1; // Shift, thus clearing K-bit 0.
+ ByteWriter<uint16_t>::WriteBigEndian(&written_packet_mask[0],
+ tmp_mask_part0);
+ bool bit15 = (packet_mask[1] & 0x01) != 0;
+ if (!bit15) {
+ written_packet_mask[0] |= 0x80; // Set K-bit 0.
+ } else {
+ memset(&written_packet_mask[2], 0U, 4); // Clear all trailing bits.
+ written_packet_mask[2] |= 0x80; // Set K-bit 1.
+ written_packet_mask[2] |= 0x40; // Set bit 15.
+ }
+ } else {
+ RTC_DCHECK_NOTREACHED()
+ << "Incorrect packet mask size: " << packet_mask_size << ".";
+ }
+}
+
+} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h
new file mode 100644
index 0000000..c5e965e
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h
@@ -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_
diff --git a/modules/rtp_rtcp/source/flexfec_03_header_reader_writer_unittest.cc b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer_unittest.cc
new file mode 100644
index 0000000..e58e1b4
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer_unittest.cc
@@ -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
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
index 7a7bff7..b659682 100644
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
+++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
@@ -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 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() = 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 @@
"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;
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer.h b/modules/rtp_rtcp/source/flexfec_header_reader_writer.h
index d305c4c..a49702b 100644
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer.h
+++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer.h
@@ -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:
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer2.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer2.cc
deleted file mode 100644
index a6ac68b..0000000
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer2.cc
+++ /dev/null
@@ -1,328 +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 "api/scoped_refptr.h"
-#include "modules/rtp_rtcp/source/byte_io.h"
-#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-
-namespace webrtc {
-
-namespace {
-
-// Maximum number of media packets that can be protected in one batch.
-constexpr size_t kMaxMediaPackets = 48; // Since we are reusing ULPFEC masks.
-
-// Maximum number of media packets tracked by FEC decoder.
-// Maintain a sufficiently larger tracking window than `kMaxMediaPackets`
-// to account for packet reordering in pacer/ network.
-constexpr size_t kMaxTrackedMediaPackets = 4 * kMaxMediaPackets;
-
-// Maximum number of FEC packets stored inside ForwardErrorCorrection.
-constexpr size_t kMaxFecPackets = kMaxMediaPackets;
-
-// Size (in bytes) of packet masks, given number of K bits set.
-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;
-
-// Size (in bytes) of part of header which is stream specific.
-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.
-constexpr size_t kHeaderSizes[] = {
- kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[0],
- kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[1],
- kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[2]};
-
-// We currently only support single-stream protection.
-// TODO(brandtr): Update this when we support multistream protection.
-constexpr uint8_t kSsrcCount = 1;
-
-// There are three reserved bytes that MUST be set to zero in the header.
-constexpr uint32_t kReservedBits = 0;
-
-// TODO(brandtr): Update this when we support multistream protection.
-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.
-size_t FlexfecHeaderSize(size_t packet_mask_size) {
- RTC_DCHECK_LE(packet_mask_size, kFlexfecPacketMaskSizes[2]);
- if (packet_mask_size <= kFlexfecPacketMaskSizes[0]) {
- return kHeaderSizes[0];
- } else if (packet_mask_size <= kFlexfecPacketMaskSizes[1]) {
- return kHeaderSizes[1];
- }
- return kHeaderSizes[2];
-}
-
-} // namespace
-
-FlexfecHeaderReader2::FlexfecHeaderReader2()
- : FecHeaderReader(kMaxTrackedMediaPackets, kMaxFecPackets) {}
-
-FlexfecHeaderReader2::~FlexfecHeaderReader2() = default;
-
-// TODO(brandtr): Update this function when we support flexible masks,
-// and retransmissions.
-bool FlexfecHeaderReader2::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.";
- return false;
- }
- uint8_t* const data = fec_packet->pkt->data.MutableData();
- bool r_bit = (data[0] & 0x80) != 0;
- if (r_bit) {
- RTC_LOG(LS_INFO)
- << "FlexFEC packet with retransmission bit set. We do not yet "
- "support this, thus discarding the packet.";
- return false;
- }
- bool f_bit = (data[0] & 0x40) != 0;
- if (f_bit) {
- RTC_LOG(LS_INFO)
- << "FlexFEC packet with inflexible generator matrix. We do "
- "not yet support this, thus discarding packet.";
- return false;
- }
-
- // First seq_num will be in byte index 8
- // (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.";
- 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];
- } else {
- if (fec_packet->pkt->data.size() <
- (byte_index + kFlexfecPacketMaskSizes[1] -
- kFlexfecPacketMaskSizes[0])) {
- 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];
- } 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];
- }
- }
- }
-
- 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;
-
- return true;
-}
-
-FlexfecHeaderWriter2::FlexfecHeaderWriter2()
- : FecHeaderWriter(kMaxMediaPackets, kMaxFecPackets, kHeaderSizes[2]) {}
-
-FlexfecHeaderWriter2::~FlexfecHeaderWriter2() = default;
-
-size_t FlexfecHeaderWriter2::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.
- // It can be used as is.
- return kFlexfecPacketMaskSizes[0];
- } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) {
- // Packet mask is 16 bits long, with bit 15 set.
- // We must expand the packet mask with zeros in the FlexFEC header.
- return kFlexfecPacketMaskSizes[1];
- } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet &&
- (packet_mask[5] & 0x03) == 0) {
- // Packet mask is 48 bits long, with bits 46 and 47 clear.
- // It can be used as is.
- return kFlexfecPacketMaskSizes[1];
- } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) {
- // Packet mask is 48 bits long, with at least one of bits 46 and 47 set.
- // We must expand it with zeros.
- return kFlexfecPacketMaskSizes[2];
- }
- RTC_DCHECK_NOTREACHED() << "Incorrect packet mask size: " << packet_mask_size
- << ".";
- return kFlexfecPacketMaskSizes[2];
-}
-
-size_t FlexfecHeaderWriter2::FecHeaderSize(size_t packet_mask_size) const {
- return FlexfecHeaderSize(packet_mask_size);
-}
-
-// This function adapts the precomputed ULPFEC packet masks to the
-// FlexFEC header standard. Note that the header size is computed by
-// FecHeaderSize(), so in this function we can be sure that we are
-// writing in space that is intended for the header.
-//
-// TODO(brandtr): Update this function when we support offset-based masks,
-// retransmissions, and protecting multiple SSRCs.
-void FlexfecHeaderWriter2::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 {
- uint8_t* data = fec_packet->data.MutableData();
- data[0] &= 0x7f; // Clear R bit.
- data[0] &= 0xbf; // Clear F bit.
- ByteWriter<uint8_t>::WriteBigEndian(&data[8], kSsrcCount);
- ByteWriter<uint32_t, 3>::WriteBigEndian(&data[9], kReservedBits);
- ByteWriter<uint32_t>::WriteBigEndian(&data[12], media_ssrc);
- ByteWriter<uint16_t>::WriteBigEndian(&data[16], seq_num_base);
- // Adapt ULPFEC packet mask to FlexFEC header.
- //
- // We treat the mask parts as unsigned integers with host order endianness
- // in order to simplify the bit shifting between bytes.
- uint8_t* const written_packet_mask = data + kPacketMaskOffset;
- if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) {
- // The packet mask is 48 bits long.
- uint16_t tmp_mask_part0 =
- ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
- uint32_t tmp_mask_part1 =
- ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]);
-
- tmp_mask_part0 >>= 1; // Shift, thus clearing K-bit 0.
- ByteWriter<uint16_t>::WriteBigEndian(&written_packet_mask[0],
- tmp_mask_part0);
- tmp_mask_part1 >>= 2; // Shift, thus clearing K-bit 1 and bit 15.
- ByteWriter<uint32_t>::WriteBigEndian(&written_packet_mask[2],
- tmp_mask_part1);
- bool bit15 = (packet_mask[1] & 0x01) != 0;
- if (bit15)
- written_packet_mask[2] |= 0x40; // Set bit 15.
- bool bit46 = (packet_mask[5] & 0x02) != 0;
- bool bit47 = (packet_mask[5] & 0x01) != 0;
- if (!bit46 && !bit47) {
- written_packet_mask[2] |= 0x80; // Set K-bit 1.
- } else {
- memset(&written_packet_mask[6], 0, 8); // Clear all trailing bits.
- written_packet_mask[6] |= 0x80; // Set K-bit 2.
- if (bit46)
- written_packet_mask[6] |= 0x40; // Set bit 46.
- if (bit47)
- written_packet_mask[6] |= 0x20; // Set bit 47.
- }
- } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) {
- // The packet mask is 16 bits long.
- uint16_t tmp_mask_part0 =
- ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
-
- tmp_mask_part0 >>= 1; // Shift, thus clearing K-bit 0.
- ByteWriter<uint16_t>::WriteBigEndian(&written_packet_mask[0],
- tmp_mask_part0);
- bool bit15 = (packet_mask[1] & 0x01) != 0;
- if (!bit15) {
- written_packet_mask[0] |= 0x80; // Set K-bit 0.
- } else {
- memset(&written_packet_mask[2], 0U, 4); // Clear all trailing bits.
- written_packet_mask[2] |= 0x80; // Set K-bit 1.
- written_packet_mask[2] |= 0x40; // Set bit 15.
- }
- } else {
- RTC_DCHECK_NOTREACHED()
- << "Incorrect packet mask size: " << packet_mask_size << ".";
- }
-}
-
-} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer2.h b/modules/rtp_rtcp/source/flexfec_header_reader_writer2.h
deleted file mode 100644
index 7b9a052..0000000
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer2.h
+++ /dev/null
@@ -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_
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer2_unittest.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer2_unittest.cc
deleted file mode 100644
index 7c83240..0000000
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer2_unittest.cc
+++ /dev/null
@@ -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
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc
index 5487510..16ecbe5 100644
--- a/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc
+++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc
@@ -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
@@ -14,8 +14,10 @@
#include <memory>
#include <utility>
+#include <vector>
-#include "api/scoped_refptr.h"
+#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"
@@ -29,535 +31,613 @@
namespace {
using Packet = ForwardErrorCorrection::Packet;
+using ProtectedStream = ForwardErrorCorrection::ProtectedStream;
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];
+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 kNoRBit = 0 << 7;
-constexpr uint8_t kNoFBit = 0 << 6;
+constexpr uint8_t kFlexible = 0b00 << 6;
constexpr uint8_t kPtRecovery = 123;
-constexpr uint8_t kLengthRecov[] = {0xab, 0xcd};
+constexpr uint8_t kLengthRecovery[] = {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 kSnBases[4][2] = {{0x01, 0x02},
+ {0x03, 0x04},
+ {0x05, 0x06},
+ {0x07, 0x08}};
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) {
- FlexfecHeaderWriter 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) {
- FlexfecHeaderReader 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;
-}
+struct FecPacketStreamProperties {
+ ProtectedStream stream;
+ rtc::ArrayView<const uint8_t> mask;
+};
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);
+ 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);
- // 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(FlexfecHeaderReaderTest, ReadsHeaderWithKBit0Set) {
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit0SetSingleStream) {
constexpr uint8_t kKBit0 = 1 << 7;
- constexpr size_t kExpectedPacketMaskSize = 2;
- constexpr size_t kExpectedFecHeaderSize = 20;
- // clang-format off
+ constexpr size_t kExpectedFecHeaderSize = 12;
+ constexpr uint16_t kSnBase = 0x0102;
constexpr uint8_t kFlexfecPktMask[] = {kKBit0 | 0x08, 0x81};
- constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02};
- // clang-format on
+ constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02};
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);
+ 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::scoped_refptr<Packet>(new Packet());
- read_packet.pkt->data.SetData(kPacketData, packet_length);
+ read_packet.pkt = rtc::make_ref_counted<Packet>();
+ read_packet.pkt->data.SetData(kPacketData);
+ read_packet.protected_streams = {{.ssrc = 0x01}};
FlexfecHeaderReader reader;
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
- VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
- kExpectedPacketMaskSize, 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(FlexfecHeaderReaderTest, ReadsHeaderWithKBit1Set) {
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit1SetSingleStream) {
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 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[] = {
- 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);
+ 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::scoped_refptr<Packet>(new Packet());
- read_packet.pkt->data.SetData(kPacketData, packet_length);
+ read_packet.pkt = rtc::make_ref_counted<Packet>();
+ read_packet.pkt->data.SetData(kPacketData);
+ read_packet.protected_streams = {{.ssrc = 0x01}};
FlexfecHeaderReader reader;
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
- VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
- kExpectedPacketMaskSize, 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(FlexfecHeaderReaderTest, ReadsHeaderWithKBit2Set) {
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithNoKBitsSetSingleStream) {
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);
+ 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::scoped_refptr<Packet>(new Packet());
- read_packet.pkt->data.SetData(kPacketData, packet_length);
+ read_packet.pkt = rtc::make_ref_counted<Packet>();
+ read_packet.pkt->data.SetData(kPacketData);
+ read_packet.protected_streams = {{.ssrc = 0x01}};
FlexfecHeaderReader reader;
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
- VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
- kExpectedPacketMaskSize, 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(FlexfecHeaderReaderTest, 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}};
+
+ FlexfecHeaderReader 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(FlexfecHeaderReaderTest, 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}};
+
+ FlexfecHeaderReader 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(FlexfecHeaderReaderTest, 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}};
+
+ FlexfecHeaderReader 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(FlexfecHeaderReaderTest, 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}};
+
+ FlexfecHeaderReader 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(FlexfecHeaderReaderTest, 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 = {};
+
+ FlexfecHeaderReader reader;
+ EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
}
TEST(FlexfecHeaderReaderTest, 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.
+ constexpr uint8_t kPacketData[] = {
+ kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
+ kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3]};
ReceivedFecPacket read_packet;
- read_packet.ssrc = kFlexfecSsrc;
- read_packet.pkt = std::move(written_packet);
- read_packet.pkt->data.SetSize(12);
+ read_packet.pkt = rtc::make_ref_counted<Packet>();
+ read_packet.pkt->data.SetData(kPacketData);
+ read_packet.protected_streams = {{.ssrc = 0x01}};
FlexfecHeaderReader reader;
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
}
TEST(FlexfecHeaderReaderTest, 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.
+ 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.ssrc = kFlexfecSsrc;
- read_packet.pkt = std::move(written_packet);
- read_packet.pkt->data.SetSize(18);
+ 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}};
FlexfecHeaderReader reader;
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
}
TEST(FlexfecHeaderReaderTest, 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.
+ 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.ssrc = kFlexfecSsrc;
- read_packet.pkt = std::move(written_packet);
- read_packet.pkt->data.SetSize(20);
+ 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}};
FlexfecHeaderReader reader;
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
}
-TEST(FlexfecHeaderReaderTest, 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);
-
+TEST(FlexfecHeaderReaderTest, 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.ssrc = kFlexfecSsrc;
- read_packet.pkt = std::move(written_packet);
- read_packet.pkt->data.SetSize(24);
+ 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}};
FlexfecHeaderReader reader;
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
}
-TEST(FlexfecHeaderWriterTest, 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;
- }
+TEST(FlexfecHeaderReaderTest, 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}};
- FlexfecHeaderWriter writer;
- writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
- sizeof(kUlpfecPacketMask), &written_packet);
-
- VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
- written_packet);
+ FlexfecHeaderReader reader;
+ EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
}
-TEST(FlexfecHeaderWriterTest, 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;
- }
+// TODO(bugs.webrtc.org/15002): reimplement and add tests for multi stream cases
+// after updating the Writer code.
- FlexfecHeaderWriter writer;
- writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
- sizeof(kUlpfecPacketMask), &written_packet);
+TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit0Set) {}
- VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
- written_packet);
-}
+TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit1Set) {}
-TEST(FlexfecHeaderWriterTest, 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;
- }
+TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit2Set) {}
- FlexfecHeaderWriter writer;
- writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
- sizeof(kUlpfecPacketMask), &written_packet);
+TEST(FlexfecHeaderWriterTest, ContractsShortUlpfecPacketMaskWithBit15Clear) {}
- VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
- written_packet);
-}
-
-TEST(FlexfecHeaderWriterTest, ContractsShortUlpfecPacketMaskWithBit15Clear) {
- const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
- auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
- ClearBit(15, packet_mask.get());
-
- FlexfecHeaderWriter 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(FlexfecHeaderWriterTest, ExpandsShortUlpfecPacketMaskWithBit15Set) {
- const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
- auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
- SetBit(15, packet_mask.get());
-
- FlexfecHeaderWriter 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(FlexfecHeaderWriterTest, ExpandsShortUlpfecPacketMaskWithBit15Set) {}
TEST(FlexfecHeaderWriterTest,
- 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());
-
- FlexfecHeaderWriter 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));
-}
+ ContractsLongUlpfecPacketMaskWithBit46ClearBit47Clear) {}
TEST(FlexfecHeaderWriterTest,
- 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());
-
- FlexfecHeaderWriter 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));
-}
+ ExpandsLongUlpfecPacketMaskWithBit46SetBit47Clear) {}
TEST(FlexfecHeaderWriterTest,
- 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());
-
- FlexfecHeaderWriter 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));
-}
+ ExpandsLongUlpfecPacketMaskWithBit46ClearBit47Set) {}
TEST(FlexfecHeaderWriterTest, 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());
-
- FlexfecHeaderWriter 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(FlexfecHeaderReaderWriterTest,
- 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);
-}
+ WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Clear) {}
TEST(FlexfecHeaderReaderWriterTest,
- 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);
-}
+ WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Set) {}
TEST(FlexfecHeaderReaderWriterTest,
- 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);
-}
+ WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Clear) {}
TEST(FlexfecHeaderReaderWriterTest,
- 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);
-}
+ WriteAndReadLargeUlpfecPacketHeaderWithMaskBit46SetBit47Clear) {}
TEST(FlexfecHeaderReaderWriterTest,
- 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);
-}
+ WriteAndReadLargeUlpfecPacketHeaderMaskWithBit46ClearBit47Set) {}
TEST(FlexfecHeaderReaderWriterTest,
- 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);
-}
+ WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Set) {}
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/forward_error_correction.cc b/modules/rtp_rtcp/source/forward_error_correction.cc
index ada9742..750c800 100644
--- a/modules/rtp_rtcp/source/forward_error_correction.cc
+++ b/modules/rtp_rtcp/source/forward_error_correction.cc
@@ -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::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));
diff --git a/modules/rtp_rtcp/source/rtp_fec_unittest.cc b/modules/rtp_rtcp/source/rtp_fec_unittest.cc
index 2c01a0d..7e5aef7 100644
--- a/modules/rtp_rtcp/source/rtp_fec_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_fec_unittest.cc
@@ -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 @@
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) {}