Change ReceivedFecPacket to have list of ssrcs, seq nums and masks.

This change replaces ReceivedFecPacket FEC header fields with vectors (for protected ssrcs, sequence numbers and masks), which is needed to support protection of multiple ssrcs in the same FEC packet (as part of the flexfec RFC - https://datatracker.ietf.org/doc/html/rfc8627).

Bug: webrtc:15002
Change-Id: I82c54203fcfec10c760f34f805cc6308562e3df1
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/303200
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Rasmus Brandt <brandtr@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40075}
This commit is contained in:
Yosef Twaik 2023-05-04 18:19:54 +03:00 committed by WebRTC LUCI CQ
parent 3a4cfdf344
commit f3de65aebe
6 changed files with 84 additions and 60 deletions

View File

@ -195,11 +195,10 @@ bool FlexfecHeaderReader::ReadFecHeader(
// Store "ULPFECized" packet mask info. // Store "ULPFECized" packet mask info.
fec_packet->fec_header_size = FlexfecHeaderSize(packet_mask_size); fec_packet->fec_header_size = FlexfecHeaderSize(packet_mask_size);
fec_packet->protected_ssrc = protected_ssrc; fec_packet->protected_streams = {{.ssrc = protected_ssrc,
fec_packet->seq_num_base = seq_num_base; .seq_num_base = seq_num_base,
fec_packet->packet_mask_offset = kPacketMaskOffset; .packet_mask_offset = kPacketMaskOffset,
fec_packet->packet_mask_size = packet_mask_size; .packet_mask_size = packet_mask_size}};
// In FlexFEC, all media packets are protected in their entirety. // In FlexFEC, all media packets are protected in their entirety.
fec_packet->protection_length = fec_packet->protection_length =
fec_packet->pkt->data.size() - fec_packet->fec_header_size; fec_packet->pkt->data.size() - fec_packet->fec_header_size;

View File

@ -30,6 +30,9 @@ namespace {
using Packet = ForwardErrorCorrection::Packet; using Packet = ForwardErrorCorrection::Packet;
using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket; using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket;
using ::testing::ElementsAreArray;
using ::testing::make_tuple;
using ::testing::SizeIs;
// General. Assume single-stream protection. // General. Assume single-stream protection.
constexpr uint32_t kMediaSsrc = 1254983; constexpr uint32_t kMediaSsrc = 1254983;
@ -103,20 +106,20 @@ void VerifyReadHeaders(size_t expected_fec_header_size,
const ReceivedFecPacket& read_packet) { const ReceivedFecPacket& read_packet) {
EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size); EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size);
EXPECT_EQ(ByteReader<uint32_t>::ReadBigEndian(kProtSsrc), EXPECT_EQ(ByteReader<uint32_t>::ReadBigEndian(kProtSsrc),
read_packet.protected_ssrc); read_packet.protected_streams[0].ssrc);
EXPECT_EQ(ByteReader<uint16_t>::ReadBigEndian(kSnBase), EXPECT_EQ(ByteReader<uint16_t>::ReadBigEndian(kSnBase),
read_packet.seq_num_base); read_packet.protected_streams[0].seq_num_base);
const size_t packet_mask_offset = read_packet.packet_mask_offset; auto packet_mask_offset = read_packet.protected_streams[0].packet_mask_offset;
EXPECT_EQ(kFlexfecPacketMaskOffset, packet_mask_offset); EXPECT_EQ(kFlexfecPacketMaskOffset, packet_mask_offset);
EXPECT_EQ(expected_packet_mask_size, read_packet.packet_mask_size); 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, EXPECT_EQ(read_packet.pkt->data.size() - expected_fec_header_size,
read_packet.protection_length); read_packet.protection_length);
// Ensure that the K-bits are removed and the packet mask has been packed. // Ensure that the K-bits are removed and the packet mask has been packed.
EXPECT_THAT( EXPECT_THAT(
::testing::make_tuple(read_packet.pkt->data.cdata() + packet_mask_offset, make_tuple(read_packet.pkt->data.cdata() + packet_mask_offset,
read_packet.packet_mask_size), read_packet.protected_streams[0].packet_mask_size),
::testing::ElementsAreArray(expected_packet_mask, ElementsAreArray(expected_packet_mask, expected_packet_mask_size));
expected_packet_mask_size));
} }
void VerifyFinalizedHeaders(const uint8_t* expected_packet_mask, void VerifyFinalizedHeaders(const uint8_t* expected_packet_mask,
@ -129,10 +132,9 @@ void VerifyFinalizedHeaders(const uint8_t* expected_packet_mask,
EXPECT_EQ(kMediaSsrc, ByteReader<uint32_t>::ReadBigEndian(packet + 12)); EXPECT_EQ(kMediaSsrc, ByteReader<uint32_t>::ReadBigEndian(packet + 12));
EXPECT_EQ(kMediaStartSeqNum, EXPECT_EQ(kMediaStartSeqNum,
ByteReader<uint16_t>::ReadBigEndian(packet + 16)); ByteReader<uint16_t>::ReadBigEndian(packet + 16));
EXPECT_THAT(::testing::make_tuple(packet + kFlexfecPacketMaskOffset, EXPECT_THAT(
expected_packet_mask_size), make_tuple(packet + kFlexfecPacketMaskOffset, expected_packet_mask_size),
::testing::ElementsAreArray(expected_packet_mask, ElementsAreArray(expected_packet_mask, expected_packet_mask_size));
expected_packet_mask_size));
} }
void VerifyWrittenAndReadHeaders(size_t expected_fec_header_size, void VerifyWrittenAndReadHeaders(size_t expected_fec_header_size,
@ -142,24 +144,25 @@ void VerifyWrittenAndReadHeaders(size_t expected_fec_header_size,
const ReceivedFecPacket& read_packet) { const ReceivedFecPacket& read_packet) {
EXPECT_EQ(kFlexfecSsrc, read_packet.ssrc); EXPECT_EQ(kFlexfecSsrc, read_packet.ssrc);
EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size); EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size);
EXPECT_EQ(kMediaSsrc, read_packet.protected_ssrc); ASSERT_THAT(read_packet.protected_streams, SizeIs(1));
EXPECT_EQ(kMediaStartSeqNum, read_packet.seq_num_base); EXPECT_EQ(read_packet.protected_streams[0].ssrc, kMediaSsrc);
EXPECT_EQ(kFlexfecPacketMaskOffset, read_packet.packet_mask_offset); EXPECT_EQ(read_packet.protected_streams[0].seq_num_base, kMediaStartSeqNum);
ASSERT_EQ(expected_packet_mask_size, read_packet.packet_mask_size); 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, EXPECT_EQ(written_packet.data.size() - expected_fec_header_size,
read_packet.protection_length); read_packet.protection_length);
// Verify that the call to ReadFecHeader did normalize the packet masks. // Verify that the call to ReadFecHeader did normalize the packet masks.
EXPECT_THAT(::testing::make_tuple( EXPECT_THAT(
read_packet.pkt->data.cdata() + kFlexfecPacketMaskOffset, make_tuple(read_packet.pkt->data.cdata() + kFlexfecPacketMaskOffset,
read_packet.packet_mask_size), read_packet.protected_streams[0].packet_mask_size),
::testing::ElementsAreArray(expected_packet_mask, ElementsAreArray(expected_packet_mask, expected_packet_mask_size));
expected_packet_mask_size));
// Verify that the call to ReadFecHeader did not tamper with the payload. // Verify that the call to ReadFecHeader did not tamper with the payload.
EXPECT_THAT(::testing::make_tuple( EXPECT_THAT(
read_packet.pkt->data.cdata() + read_packet.fec_header_size, make_tuple(read_packet.pkt->data.cdata() + read_packet.fec_header_size,
read_packet.pkt->data.size() - read_packet.fec_header_size), read_packet.pkt->data.size() - read_packet.fec_header_size),
::testing::ElementsAreArray( ElementsAreArray(written_packet.data.cdata() + expected_fec_header_size,
written_packet.data.cdata() + expected_fec_header_size,
written_packet.data.size() - expected_fec_header_size)); written_packet.data.size() - expected_fec_header_size));
} }

View File

@ -407,24 +407,29 @@ void ForwardErrorCorrection::InsertFecPacket(
return; return;
} }
// TODO(brandtr): Update here when we support multistream protection. RTC_CHECK_EQ(fec_packet->protected_streams.size(), 1);
if (fec_packet->protected_ssrc != protected_media_ssrc_) {
if (fec_packet->protected_streams[0].ssrc != protected_media_ssrc_) {
RTC_LOG(LS_INFO) RTC_LOG(LS_INFO)
<< "Received FEC packet is protecting an unknown media SSRC; dropping."; << "Received FEC packet is protecting an unknown media SSRC; dropping.";
return; return;
} }
if (fec_packet->packet_mask_offset + fec_packet->packet_mask_size > if (fec_packet->protected_streams[0].packet_mask_offset +
fec_packet->protected_streams[0].packet_mask_size >
fec_packet->pkt->data.size()) { fec_packet->pkt->data.size()) {
RTC_LOG(LS_INFO) << "Received corrupted FEC packet; dropping."; RTC_LOG(LS_INFO) << "Received corrupted FEC packet; dropping.";
return; return;
} }
// Parse packet mask from header and represent as protected packets. // Parse packet mask from header and represent as protected packets.
for (uint16_t byte_idx = 0; byte_idx < fec_packet->packet_mask_size; for (uint16_t byte_idx = 0;
byte_idx < fec_packet->protected_streams[0].packet_mask_size;
++byte_idx) { ++byte_idx) {
uint8_t packet_mask = uint8_t packet_mask =
fec_packet->pkt->data[fec_packet->packet_mask_offset + byte_idx]; fec_packet->pkt
->data[fec_packet->protected_streams[0].packet_mask_offset +
byte_idx];
for (uint16_t bit_idx = 0; bit_idx < 8; ++bit_idx) { for (uint16_t bit_idx = 0; bit_idx < 8; ++bit_idx) {
if (packet_mask & (1 << (7 - bit_idx))) { if (packet_mask & (1 << (7 - bit_idx))) {
std::unique_ptr<ProtectedPacket> protected_packet( std::unique_ptr<ProtectedPacket> protected_packet(
@ -432,7 +437,8 @@ void ForwardErrorCorrection::InsertFecPacket(
// This wraps naturally with the sequence number. // This wraps naturally with the sequence number.
protected_packet->ssrc = protected_media_ssrc_; protected_packet->ssrc = protected_media_ssrc_;
protected_packet->seq_num = static_cast<uint16_t>( protected_packet->seq_num = static_cast<uint16_t>(
fec_packet->seq_num_base + (byte_idx << 3) + bit_idx); fec_packet->protected_streams[0].seq_num_base + (byte_idx << 3) +
bit_idx);
protected_packet->pkt = nullptr; protected_packet->pkt = nullptr;
fec_packet->protected_packets.push_back(std::move(protected_packet)); fec_packet->protected_packets.push_back(std::move(protected_packet));
} }
@ -583,8 +589,7 @@ bool ForwardErrorCorrection::FinishPacketRecovery(
// Set the SN field. // Set the SN field.
ByteWriter<uint16_t>::WriteBigEndian(&data[2], recovered_packet->seq_num); ByteWriter<uint16_t>::WriteBigEndian(&data[2], recovered_packet->seq_num);
// Set the SSRC field. // Set the SSRC field.
ByteWriter<uint32_t>::WriteBigEndian(&data[8], fec_packet.protected_ssrc); ByteWriter<uint32_t>::WriteBigEndian(&data[8], recovered_packet->ssrc);
recovered_packet->ssrc = fec_packet.protected_ssrc;
return true; return true;
} }
@ -640,6 +645,7 @@ bool ForwardErrorCorrection::RecoverPacket(const ReceivedFecPacket& fec_packet,
if (protected_packet->pkt == nullptr) { if (protected_packet->pkt == nullptr) {
// This is the packet we're recovering. // This is the packet we're recovering.
recovered_packet->seq_num = protected_packet->seq_num; recovered_packet->seq_num = protected_packet->seq_num;
recovered_packet->ssrc = protected_packet->ssrc;
} else { } else {
XorHeaders(*protected_packet->pkt, recovered_packet->pkt.get()); XorHeaders(*protected_packet->pkt, recovered_packet->pkt.get());
XorPayloads(*protected_packet->pkt, XorPayloads(*protected_packet->pkt,

View File

@ -18,6 +18,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "absl/container/inlined_vector.h"
#include "api/scoped_refptr.h" #include "api/scoped_refptr.h"
#include "api/units/timestamp.h" #include "api/units/timestamp.h"
#include "modules/include/module_fec_types.h" #include "modules/include/module_fec_types.h"
@ -118,11 +119,23 @@ class ForwardErrorCorrection {
using ProtectedPacketList = std::list<std::unique_ptr<ProtectedPacket>>; using ProtectedPacketList = std::list<std::unique_ptr<ProtectedPacket>>;
struct ProtectedStream {
uint32_t ssrc = 0;
uint16_t seq_num_base = 0;
size_t packet_mask_offset = 0; // Relative start of FEC header.
size_t packet_mask_size = 0;
};
// Used for internal storage of received FEC packets in a list. // Used for internal storage of received FEC packets in a list.
// //
// TODO(holmer): Refactor into a proper class. // TODO(holmer): Refactor into a proper class.
class ReceivedFecPacket : public SortablePacket { class ReceivedFecPacket : public SortablePacket {
public: public:
// SSRC count is limited by 4 bits of CSRC count in RTP header (max 15).
// Since most of the time number of SSRCs will be low (probably 1 most of
// the time) setting this value to 4 for optimization.
static constexpr size_t kInlinedSsrcsVectorSize = 4;
ReceivedFecPacket(); ReceivedFecPacket();
~ReceivedFecPacket(); ~ReceivedFecPacket();
@ -132,10 +145,8 @@ class ForwardErrorCorrection {
uint32_t ssrc; uint32_t ssrc;
// FEC header fields. // FEC header fields.
size_t fec_header_size; size_t fec_header_size;
uint32_t protected_ssrc; absl::InlinedVector<ProtectedStream, kInlinedSsrcsVectorSize>
uint16_t seq_num_base; protected_streams;
size_t packet_mask_offset; // Relative start of FEC header.
size_t packet_mask_size;
size_t protection_length; size_t protection_length;
// Raw data. // Raw data.
rtc::scoped_refptr<ForwardErrorCorrection::Packet> pkt; rtc::scoped_refptr<ForwardErrorCorrection::Packet> pkt;

View File

@ -71,10 +71,10 @@ bool UlpfecHeaderReader::ReadFecHeader(
l_bit ? kUlpfecPacketMaskSizeLBitSet : kUlpfecPacketMaskSizeLBitClear; l_bit ? kUlpfecPacketMaskSizeLBitSet : kUlpfecPacketMaskSizeLBitClear;
fec_packet->fec_header_size = UlpfecHeaderSize(packet_mask_size); fec_packet->fec_header_size = UlpfecHeaderSize(packet_mask_size);
uint16_t seq_num_base = ByteReader<uint16_t>::ReadBigEndian(&data[2]); uint16_t seq_num_base = ByteReader<uint16_t>::ReadBigEndian(&data[2]);
fec_packet->protected_ssrc = fec_packet->ssrc; // Due to RED. fec_packet->protected_streams = {{.ssrc = fec_packet->ssrc, // Due to RED.
fec_packet->seq_num_base = seq_num_base; .seq_num_base = seq_num_base,
fec_packet->packet_mask_offset = kPacketMaskOffset; .packet_mask_offset = kPacketMaskOffset,
fec_packet->packet_mask_size = packet_mask_size; .packet_mask_size = packet_mask_size}};
fec_packet->protection_length = fec_packet->protection_length =
ByteReader<uint16_t>::ReadBigEndian(&data[10]); ByteReader<uint16_t>::ReadBigEndian(&data[10]);

View File

@ -21,6 +21,7 @@
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h" #include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/random.h" #include "rtc_base/random.h"
#include "test/gmock.h"
#include "test/gtest.h" #include "test/gtest.h"
namespace webrtc { namespace webrtc {
@ -29,6 +30,7 @@ namespace {
using Packet = ForwardErrorCorrection::Packet; using Packet = ForwardErrorCorrection::Packet;
using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket; using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket;
using ::testing::SizeIs;
constexpr uint32_t kMediaSsrc = 1254983; constexpr uint32_t kMediaSsrc = 1254983;
constexpr uint16_t kMediaStartSeqNum = 825; constexpr uint16_t kMediaStartSeqNum = 825;
@ -79,16 +81,19 @@ void VerifyHeaders(size_t expected_fec_header_size,
const ReceivedFecPacket& read_packet) { const ReceivedFecPacket& read_packet) {
EXPECT_EQ(kMediaSsrc, read_packet.ssrc); EXPECT_EQ(kMediaSsrc, read_packet.ssrc);
EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size); EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size);
EXPECT_EQ(kMediaSsrc, read_packet.protected_ssrc); ASSERT_THAT(read_packet.protected_streams, SizeIs(1));
EXPECT_EQ(kMediaStartSeqNum, read_packet.seq_num_base); EXPECT_EQ(read_packet.protected_streams[0].ssrc, kMediaSsrc);
EXPECT_EQ(kUlpfecPacketMaskOffset, read_packet.packet_mask_offset); EXPECT_EQ(read_packet.protected_streams[0].seq_num_base, kMediaStartSeqNum);
ASSERT_EQ(expected_packet_mask_size, read_packet.packet_mask_size); EXPECT_EQ(read_packet.protected_streams[0].packet_mask_offset,
kUlpfecPacketMaskOffset);
ASSERT_EQ(read_packet.protected_streams[0].packet_mask_size,
expected_packet_mask_size);
EXPECT_EQ(written_packet.data.size() - expected_fec_header_size, EXPECT_EQ(written_packet.data.size() - expected_fec_header_size,
read_packet.protection_length); read_packet.protection_length);
EXPECT_EQ(0, memcmp(expected_packet_mask, EXPECT_EQ(0, memcmp(expected_packet_mask,
read_packet.pkt->data.MutableData() + read_packet.pkt->data.MutableData() +
read_packet.packet_mask_offset, read_packet.protected_streams[0].packet_mask_offset,
read_packet.packet_mask_size)); read_packet.protected_streams[0].packet_mask_size));
// Verify that the call to ReadFecHeader did not tamper with the payload. // Verify that the call to ReadFecHeader did not tamper with the payload.
EXPECT_EQ(0, memcmp(written_packet.data.data() + expected_fec_header_size, EXPECT_EQ(0, memcmp(written_packet.data.data() + expected_fec_header_size,
read_packet.pkt->data.cdata() + expected_fec_header_size, read_packet.pkt->data.cdata() + expected_fec_header_size,
@ -114,9 +119,9 @@ TEST(UlpfecHeaderReaderTest, ReadsSmallHeader) {
EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
EXPECT_EQ(14U, read_packet.fec_header_size); EXPECT_EQ(14U, read_packet.fec_header_size);
EXPECT_EQ(0xabcdU, read_packet.seq_num_base); EXPECT_EQ(0xabcdU, read_packet.protected_streams[0].seq_num_base);
EXPECT_EQ(12U, read_packet.packet_mask_offset); EXPECT_EQ(12U, read_packet.protected_streams[0].packet_mask_offset);
EXPECT_EQ(2U, read_packet.packet_mask_size); EXPECT_EQ(2U, read_packet.protected_streams[0].packet_mask_size);
EXPECT_EQ(0x1122U, read_packet.protection_length); EXPECT_EQ(0x1122U, read_packet.protection_length);
} }
@ -138,9 +143,9 @@ TEST(UlpfecHeaderReaderTest, ReadsLargeHeader) {
EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
EXPECT_EQ(18U, read_packet.fec_header_size); EXPECT_EQ(18U, read_packet.fec_header_size);
EXPECT_EQ(0xabcdU, read_packet.seq_num_base); EXPECT_EQ(0xabcdU, read_packet.protected_streams[0].seq_num_base);
EXPECT_EQ(12U, read_packet.packet_mask_offset); EXPECT_EQ(12U, read_packet.protected_streams[0].packet_mask_offset);
EXPECT_EQ(6U, read_packet.packet_mask_size); EXPECT_EQ(6U, read_packet.protected_streams[0].packet_mask_size);
EXPECT_EQ(0x1122U, read_packet.protection_length); EXPECT_EQ(0x1122U, read_packet.protection_length);
} }