From ade07ca45e722141090348f0b3d9951bfaac96ca Mon Sep 17 00:00:00 2001 From: Yosef Twaik Date: Sun, 4 Jun 2023 16:16:01 +0300 Subject: [PATCH] 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 Commit-Queue: Danil Chapovalov Cr-Commit-Position: refs/heads/main@{#40231} --- modules/rtp_rtcp/BUILD.gn | 6 +- ....cc => flexfec_03_header_reader_writer.cc} | 207 ++-- .../source/flexfec_03_header_reader_writer.h | 88 ++ ...lexfec_03_header_reader_writer_unittest.cc | 565 +++++++++++ .../source/flexfec_header_reader_writer.cc | 181 ++-- .../source/flexfec_header_reader_writer.h | 38 +- .../source/flexfec_header_reader_writer2.h | 70 -- .../flexfec_header_reader_writer2_unittest.cc | 644 ------------ .../flexfec_header_reader_writer_unittest.cc | 932 ++++++++++-------- .../source/forward_error_correction.cc | 8 +- modules/rtp_rtcp/source/rtp_fec_unittest.cc | 6 +- 11 files changed, 1374 insertions(+), 1371 deletions(-) rename modules/rtp_rtcp/source/{flexfec_header_reader_writer2.cc => flexfec_03_header_reader_writer.cc} (59%) create mode 100644 modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h create mode 100644 modules/rtp_rtcp/source/flexfec_03_header_reader_writer_unittest.cc delete mode 100644 modules/rtp_rtcp/source/flexfec_header_reader_writer2.h delete mode 100644 modules/rtp_rtcp/source/flexfec_header_reader_writer2_unittest.cc diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn index cab7bec915..80c5f6bc71 100644 --- a/modules/rtp_rtcp/BUILD.gn +++ b/modules/rtp_rtcp/BUILD.gn @@ -170,10 +170,10 @@ rtc_library("rtp_rtcp") { "source/fec_private_tables_bursty.h", "source/fec_private_tables_random.cc", "source/fec_private_tables_random.h", + "source/flexfec_03_header_reader_writer.cc", + "source/flexfec_03_header_reader_writer.h", "source/flexfec_header_reader_writer.cc", "source/flexfec_header_reader_writer.h", - "source/flexfec_header_reader_writer2.cc", - "source/flexfec_header_reader_writer2.h", "source/flexfec_receiver.cc", "source/flexfec_sender.cc", "source/forward_error_correction.cc", @@ -552,7 +552,7 @@ if (rtc_include_tests) { "source/byte_io_unittest.cc", "source/capture_clock_offset_updater_unittest.cc", "source/fec_private_tables_bursty_unittest.cc", - "source/flexfec_header_reader_writer2_unittest.cc", + "source/flexfec_03_header_reader_writer_unittest.cc", "source/flexfec_header_reader_writer_unittest.cc", "source/flexfec_receiver_unittest.cc", "source/flexfec_sender_unittest.cc", diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer2.cc b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.cc similarity index 59% rename from modules/rtp_rtcp/source/flexfec_header_reader_writer2.cc rename to modules/rtp_rtcp/source/flexfec_03_header_reader_writer.cc index a6ac68b74b..ddf8e32f85 100644 --- a/modules/rtp_rtcp/source/flexfec_header_reader_writer2.cc +++ b/modules/rtp_rtcp/source/flexfec_03_header_reader_writer.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved. + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "modules/rtp_rtcp/source/flexfec_header_reader_writer2.h" +#include "modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h" #include @@ -37,10 +37,10 @@ constexpr size_t kMaxFecPackets = kMaxMediaPackets; constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14}; // Size (in bytes) of part of header which is not packet mask specific. -constexpr size_t kBaseHeaderSize = 8; +constexpr size_t kBaseHeaderSize = 12; // Size (in bytes) of part of header which is stream specific. -constexpr size_t kStreamSpecificHeaderSize = 2; +constexpr size_t kStreamSpecificHeaderSize = 6; // Size (in bytes) of header, given the single stream packet mask size, i.e. // the number of K-bits set. @@ -61,9 +61,9 @@ constexpr size_t kPacketMaskOffset = kBaseHeaderSize + kStreamSpecificHeaderSize; // Here we count the K-bits as belonging to the packet mask. -// This can be used in conjunction with FlexfecHeaderWriter::MinPacketMaskSize, -// which calculates a bound on the needed packet mask size including K-bits, -// given a packet mask without K-bits. +// This can be used in conjunction with +// Flexfec03HeaderWriter::MinPacketMaskSize, which calculates a bound on the +// needed packet mask size including K-bits, given a packet mask without K-bits. size_t FlexfecHeaderSize(size_t packet_mask_size) { RTC_DCHECK_LE(packet_mask_size, kFlexfecPacketMaskSizes[2]); if (packet_mask_size <= kFlexfecPacketMaskSizes[0]) { @@ -76,21 +76,15 @@ size_t FlexfecHeaderSize(size_t packet_mask_size) { } // namespace -FlexfecHeaderReader2::FlexfecHeaderReader2() +Flexfec03HeaderReader::Flexfec03HeaderReader() : FecHeaderReader(kMaxTrackedMediaPackets, kMaxFecPackets) {} -FlexfecHeaderReader2::~FlexfecHeaderReader2() = default; +Flexfec03HeaderReader::~Flexfec03HeaderReader() = default; // TODO(brandtr): Update this function when we support flexible masks, -// and retransmissions. -bool FlexfecHeaderReader2::ReadFecHeader( +// retransmissions, and/or several protected SSRCs. +bool Flexfec03HeaderReader::ReadFecHeader( ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const { - // Protected ssrcs should already be populated from RTP header. - if (fec_packet->protected_streams.empty()) { - RTC_LOG(LS_WARNING) - << "Discarding FlexFEC packet with no protected sources."; - return false; - } if (fec_packet->pkt->data.size() <= kBaseHeaderSize + kStreamSpecificHeaderSize) { RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet."; @@ -111,103 +105,100 @@ bool FlexfecHeaderReader2::ReadFecHeader( "not yet support this, thus discarding packet."; return false; } + uint8_t ssrc_count = ByteReader::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::ReadBigEndian(&data[12]); + uint16_t seq_num_base = ByteReader::ReadBigEndian(&data[16]); - // First seq_num will be in byte index 8 + // Parse the FlexFEC packet mask and remove the interleaved K-bits. // (See FEC header schematic in flexfec_header_reader_writer.h.) - size_t byte_index = 8; - for (size_t i = 0; i < fec_packet->protected_streams.size(); ++i) { - if (fec_packet->pkt->data.size() < byte_index + kStreamSpecificHeaderSize) { - RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet."; + // We store the packed packet mask in-band, which "destroys" the standards + // compliance of the header. That is fine though, since the code that + // reads from the header (from this point and onwards) is aware of this. + // TODO(brandtr): When the FEC packet classes have been refactored, store + // the packed packet masks out-of-band, thus leaving the FlexFEC header as is. + // + // We treat the mask parts as unsigned integers with host order endianness + // in order to simplify the bit shifting between bytes. + if (fec_packet->pkt->data.size() < kHeaderSizes[0]) { + RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet."; + return false; + } + uint8_t* const packet_mask = data + kPacketMaskOffset; + bool k_bit0 = (packet_mask[0] & 0x80) != 0; + uint16_t mask_part0 = ByteReader::ReadBigEndian(&packet_mask[0]); + // Shift away K-bit 0, implicitly clearing the last bit. + mask_part0 <<= 1; + ByteWriter::WriteBigEndian(&packet_mask[0], mask_part0); + size_t packet_mask_size; + if (k_bit0) { + // The first K-bit is set, and the packet mask is thus only 2 bytes long. + // We have now read the entire FEC header, and the rest of the packet + // is payload. + packet_mask_size = kFlexfecPacketMaskSizes[0]; + } else { + if (fec_packet->pkt->data.size() < kHeaderSizes[1]) { return false; } - - fec_packet->protected_streams[i].seq_num_base = - ByteReader::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::ReadBigEndian(&data[byte_index]); - // Shift away K-bit 0, implicitly clearing the last bit. - mask_part0 <<= 1; - ByteWriter::WriteBigEndian(&data[byte_index], mask_part0); - byte_index += kFlexfecPacketMaskSizes[0]; - if (k_bit0) { - // The first K-bit is set, and the packet mask is thus only 2 bytes long. - // We have finished reading the properties for current ssrc. - fec_packet->protected_streams[i].packet_mask_size = - kFlexfecPacketMaskSizes[0]; + bool k_bit1 = (packet_mask[2] & 0x80) != 0; + // We have already shifted the first two bytes of the packet mask one step + // to the left, thus removing K-bit 0. We will now shift the next four bytes + // of the packet mask two steps to the left. (One step for the removed + // K-bit 0, and one step for the to be removed K-bit 1). + uint8_t bit15 = (packet_mask[2] >> 6) & 0x01; + packet_mask[1] |= bit15; + uint32_t mask_part1 = ByteReader::ReadBigEndian(&packet_mask[2]); + // Shift away K-bit 1 and bit 15, implicitly clearing the last two bits. + mask_part1 <<= 2; + ByteWriter::WriteBigEndian(&packet_mask[2], mask_part1); + if (k_bit1) { + // The first K-bit is clear, but the second K-bit is set. The packet + // mask is thus 6 bytes long. We have now read the entire FEC header, + // and the rest of the packet is payload. + packet_mask_size = kFlexfecPacketMaskSizes[1]; } else { - if (fec_packet->pkt->data.size() < - (byte_index + kFlexfecPacketMaskSizes[1] - - kFlexfecPacketMaskSizes[0])) { + if (fec_packet->pkt->data.size() < kHeaderSizes[2]) { + RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet."; return false; } - bool k_bit1 = (data[byte_index] & 0x80) != 0; - // We have already shifted the first two bytes of the packet mask one step - // to the left, thus removing K-bit 0. We will now shift the next four - // bytes of the packet mask two steps to the left. (One step for the - // removed K-bit 0, and one step for the to be removed K-bit 1). - uint8_t bit15 = (data[byte_index] >> 6) & 0x01; - data[byte_index - 1] |= bit15; - uint32_t mask_part1 = - ByteReader::ReadBigEndian(&data[byte_index]); - // Shift away K-bit 1 and bit 15, implicitly clearing the last two bits. - mask_part1 <<= 2; - ByteWriter::WriteBigEndian(&data[byte_index], mask_part1); - byte_index += kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0]; - if (k_bit1) { - // The first K-bit is clear, but the second K-bit is set. The packet - // mask is thus 6 bytes long. We have finished reading the properties - // for current ssrc. - fec_packet->protected_streams[i].packet_mask_size = - kFlexfecPacketMaskSizes[1]; + bool k_bit2 = (packet_mask[6] & 0x80) != 0; + if (k_bit2) { + // The first and second K-bits are clear, but the third K-bit is set. + // The packet mask is thus 14 bytes long. We have now read the entire + // FEC header, and the rest of the packet is payload. + packet_mask_size = kFlexfecPacketMaskSizes[2]; } else { - if (fec_packet->pkt->data.size() < - (byte_index + kFlexfecPacketMaskSizes[2] - - kFlexfecPacketMaskSizes[1])) { - RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet."; - return false; - } - fec_packet->protected_streams[i].packet_mask_size = - kFlexfecPacketMaskSizes[2]; - // At this point, K-bits 0 and 1 have been removed, and the front-most - // part of the FlexFEC packet mask has been packed accordingly. We will - // now shift the remaning part of the packet mask two steps to the left. - // This corresponds to the (in total) two K-bits, which have been - // removed. - uint8_t tail_bits = (data[byte_index] >> 6) & 0x03; - data[byte_index - 1] |= tail_bits; - uint64_t mask_part2 = - ByteReader::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::WriteBigEndian(&data[byte_index], mask_part2); - byte_index += kFlexfecPacketMaskSizes[2] - kFlexfecPacketMaskSizes[1]; + RTC_LOG(LS_WARNING) + << "Discarding FlexFEC packet with malformed header."; + return false; } + // At this point, K-bits 0 and 1 have been removed, and the front-most + // part of the FlexFEC packet mask has been packed accordingly. We will + // now shift the remaning part of the packet mask three steps to the left. + // This corresponds to the (in total) three K-bits, which have been + // removed. + uint8_t tail_bits = (packet_mask[6] >> 5) & 0x03; + packet_mask[5] |= tail_bits; + uint64_t mask_part2 = + ByteReader::ReadBigEndian(&packet_mask[6]); + // Shift away K-bit 2, bit 46, and bit 47, implicitly clearing the last + // three bits. + mask_part2 <<= 3; + ByteWriter::WriteBigEndian(&packet_mask[6], mask_part2); } } - fec_packet->fec_header_size = byte_index; - + // Store "ULPFECized" packet mask info. + fec_packet->fec_header_size = FlexfecHeaderSize(packet_mask_size); + fec_packet->protected_streams = {{.ssrc = protected_ssrc, + .seq_num_base = seq_num_base, + .packet_mask_offset = kPacketMaskOffset, + .packet_mask_size = packet_mask_size}}; // In FlexFEC, all media packets are protected in their entirety. fec_packet->protection_length = fec_packet->pkt->data.size() - fec_packet->fec_header_size; @@ -215,13 +206,13 @@ bool FlexfecHeaderReader2::ReadFecHeader( return true; } -FlexfecHeaderWriter2::FlexfecHeaderWriter2() +Flexfec03HeaderWriter::Flexfec03HeaderWriter() : FecHeaderWriter(kMaxMediaPackets, kMaxFecPackets, kHeaderSizes[2]) {} -FlexfecHeaderWriter2::~FlexfecHeaderWriter2() = default; +Flexfec03HeaderWriter::~Flexfec03HeaderWriter() = default; -size_t FlexfecHeaderWriter2::MinPacketMaskSize(const uint8_t* packet_mask, - size_t packet_mask_size) const { +size_t Flexfec03HeaderWriter::MinPacketMaskSize(const uint8_t* packet_mask, + size_t packet_mask_size) const { if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear && (packet_mask[1] & 0x01) == 0) { // Packet mask is 16 bits long, with bit 15 clear. @@ -246,7 +237,7 @@ size_t FlexfecHeaderWriter2::MinPacketMaskSize(const uint8_t* packet_mask, return kFlexfecPacketMaskSizes[2]; } -size_t FlexfecHeaderWriter2::FecHeaderSize(size_t packet_mask_size) const { +size_t Flexfec03HeaderWriter::FecHeaderSize(size_t packet_mask_size) const { return FlexfecHeaderSize(packet_mask_size); } @@ -257,7 +248,7 @@ size_t FlexfecHeaderWriter2::FecHeaderSize(size_t packet_mask_size) const { // // TODO(brandtr): Update this function when we support offset-based masks, // retransmissions, and protecting multiple SSRCs. -void FlexfecHeaderWriter2::FinalizeFecHeader( +void Flexfec03HeaderWriter::FinalizeFecHeader( uint32_t media_ssrc, uint16_t seq_num_base, const uint8_t* packet_mask, 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 0000000000..c5e965eb26 --- /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 +#include + +#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 0000000000..e58e1b4590 --- /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 + +#include +#include + +#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 GeneratePacketMask(size_t packet_mask_size, + uint64_t seed) { + Random random(seed); + std::unique_ptr 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(); + } + 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 WriteHeader(const uint8_t* packet_mask, + size_t packet_mask_size) { + Flexfec03HeaderWriter writer; + rtc::scoped_refptr 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 ReadHeader(const Packet& written_packet) { + Flexfec03HeaderReader reader; + std::unique_ptr read_packet(new ReceivedFecPacket()); + read_packet->ssrc = kFlexfecSsrc; + read_packet->pkt = rtc::scoped_refptr(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::ReadBigEndian(kProtSsrc), + read_packet.protected_streams[0].ssrc); + EXPECT_EQ(ByteReader::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::ReadBigEndian(packet + 12)); + EXPECT_EQ(kMediaStartSeqNum, + ByteReader::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(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(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(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 7a7bff70e3..b6596824fc 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 kMaxFecPackets = kMaxMediaPackets; constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14}; // Size (in bytes) of part of header which is not packet mask specific. -constexpr size_t kBaseHeaderSize = 12; +constexpr size_t kBaseHeaderSize = 8; // Size (in bytes) of part of header which is stream specific. -constexpr size_t kStreamSpecificHeaderSize = 6; +constexpr size_t kStreamSpecificHeaderSize = 2; // Size (in bytes) of header, given the single stream packet mask size, i.e. // the number of K-bits set. @@ -82,9 +82,15 @@ FlexfecHeaderReader::FlexfecHeaderReader() FlexfecHeaderReader::~FlexfecHeaderReader() = default; // TODO(brandtr): Update this function when we support flexible masks, -// retransmissions, and/or several protected SSRCs. +// and retransmissions. bool FlexfecHeaderReader::ReadFecHeader( ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const { + // Protected ssrcs should already be populated from RTP header. + if (fec_packet->protected_streams.empty()) { + RTC_LOG(LS_WARNING) + << "Discarding FlexFEC packet with no protected sources."; + return false; + } if (fec_packet->pkt->data.size() <= kBaseHeaderSize + kStreamSpecificHeaderSize) { RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet."; @@ -105,100 +111,103 @@ bool FlexfecHeaderReader::ReadFecHeader( "not yet support this, thus discarding packet."; return false; } - uint8_t ssrc_count = ByteReader::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::ReadBigEndian(&data[12]); - uint16_t seq_num_base = ByteReader::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::ReadBigEndian(&packet_mask[0]); - // Shift away K-bit 0, implicitly clearing the last bit. - mask_part0 <<= 1; - ByteWriter::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::ReadBigEndian(&packet_mask[2]); - // Shift away K-bit 1 and bit 15, implicitly clearing the last two bits. - mask_part1 <<= 2; - ByteWriter::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::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::ReadBigEndian(&data[byte_index]); + // Shift away K-bit 0, implicitly clearing the last bit. + mask_part0 <<= 1; + ByteWriter::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::ReadBigEndian(&data[byte_index]); + // Shift away K-bit 1 and bit 15, implicitly clearing the last two bits. + mask_part1 <<= 2; + ByteWriter::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::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::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::ReadBigEndian(&packet_mask[6]); - // Shift away K-bit 2, bit 46, and bit 47, implicitly clearing the last - // three bits. - mask_part2 <<= 3; - ByteWriter::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 d305c4c288..a49702b210 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.h b/modules/rtp_rtcp/source/flexfec_header_reader_writer2.h deleted file mode 100644 index 7b9a052509..0000000000 --- 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 -#include - -#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 7c8324017e..0000000000 --- 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 - -#include -#include -#include - -#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 mask; -}; - -void VerifyReadHeaders(size_t expected_fec_header_size, - const ReceivedFecPacket& read_packet, - std::vector 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(); - read_packet.pkt->data.SetData(kPacketData); - read_packet.protected_streams = {{.ssrc = 0x01}}; - - FlexfecHeaderReader2 reader; - EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - - std::vector 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(); - read_packet.pkt->data.SetData(kPacketData); - read_packet.protected_streams = {{.ssrc = 0x01}}; - - FlexfecHeaderReader2 reader; - EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - - std::vector 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(); - read_packet.pkt->data.SetData(kPacketData); - read_packet.protected_streams = {{.ssrc = 0x01}}; - - FlexfecHeaderReader2 reader; - EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - - std::vector 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(); - read_packet.pkt->data.SetData(kPacketData); - read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}}; - - FlexfecHeaderReader2 reader; - EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - - std::vector 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(); - read_packet.pkt->data.SetData(kPacketData); - read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}}; - - FlexfecHeaderReader2 reader; - EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - - std::vector 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(); - read_packet.pkt->data.SetData(kPacketData); - read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}}; - - FlexfecHeaderReader2 reader; - EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - - std::vector 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(); - 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 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(); - 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(); - 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(); - // 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(); - // 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(); - // 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(); - // 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 54875105c0..16ecbe5c90 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 #include +#include -#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 webrtc { 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 GeneratePacketMask(size_t packet_mask_size, - uint64_t seed) { - Random random(seed); - std::unique_ptr 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(); - } - 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 WriteHeader(const uint8_t* packet_mask, - size_t packet_mask_size) { - FlexfecHeaderWriter writer; - rtc::scoped_refptr 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 ReadHeader(const Packet& written_packet) { - FlexfecHeaderReader reader; - std::unique_ptr read_packet(new ReceivedFecPacket()); - read_packet->ssrc = kFlexfecSsrc; - read_packet->pkt = rtc::scoped_refptr(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 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::ReadBigEndian(kProtSsrc), - read_packet.protected_streams[0].ssrc); - EXPECT_EQ(ByteReader::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 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::ReadBigEndian(packet + 12)); - EXPECT_EQ(kMediaStartSeqNum, - ByteReader::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(new Packet()); - read_packet.pkt->data.SetData(kPacketData, packet_length); + read_packet.pkt = rtc::make_ref_counted(); + 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 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(new Packet()); - read_packet.pkt->data.SetData(kPacketData, packet_length); + read_packet.pkt = rtc::make_ref_counted(); + 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 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(new Packet()); - read_packet.pkt->data.SetData(kPacketData, packet_length); + read_packet.pkt = rtc::make_ref_counted(); + 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 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(); + read_packet.pkt->data.SetData(kPacketData); + read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}}; + + FlexfecHeaderReader reader; + EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); + + std::vector 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(); + read_packet.pkt->data.SetData(kPacketData); + read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}}; + + FlexfecHeaderReader reader; + EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); + + std::vector 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(); + read_packet.pkt->data.SetData(kPacketData); + read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}}; + + FlexfecHeaderReader reader; + EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); + + std::vector 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(); + 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 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(); + 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(); + 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(); + // 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(); + // 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(); + // 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(); + // 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 ada9742b2d..750c800757 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::CreateUlpfec( std::unique_ptr ForwardErrorCorrection::CreateFlexfec( uint32_t ssrc, uint32_t protected_media_ssrc) { - std::unique_ptr fec_header_reader(new FlexfecHeaderReader()); - std::unique_ptr fec_header_writer(new FlexfecHeaderWriter()); + std::unique_ptr fec_header_reader( + new Flexfec03HeaderReader()); + std::unique_ptr fec_header_writer( + new Flexfec03HeaderWriter()); return std::unique_ptr(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 2c01a0d40a..7e5aef7634 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 @@ class FlexfecForwardErrorCorrection : public ForwardErrorCorrection { FlexfecForwardErrorCorrection() : ForwardErrorCorrection( - std::unique_ptr(new FlexfecHeaderReader()), - std::unique_ptr(new FlexfecHeaderWriter()), + std::unique_ptr(new Flexfec03HeaderReader()), + std::unique_ptr(new Flexfec03HeaderWriter()), kFecSsrc, kMediaSsrc) {}