webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc
Yosef Twaik 75a3ba216e Reverse the kbits logic according to RFC
The updated Flexfec RFC states that a kbit of "0" means this is the last block of the mask, whereas in the 03 draft, "0" meant there's another block.
Reversing the logic in the updated RFC parser to fix.


Bug: webrtc:15002
Change-Id: I40e4c950b09ddf2db9da6c01908737282161bf1c
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/327580
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41174}
2023-11-16 18:33:13 +00:00

918 lines
42 KiB
C++

/*
* 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_writer.h"
#include <string.h>
#include <memory>
#include <utility>
#include <vector>
#include "api/array_view.h"
#include "api/make_ref_counted.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/forward_error_correction.h"
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
#include "rtc_base/checks.h"
#include "rtc_base/random.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
using Packet = ForwardErrorCorrection::Packet;
using ProtectedStream = ForwardErrorCorrection::ProtectedStream;
using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket;
using ::testing::Each;
using ::testing::ElementsAreArray;
constexpr uint8_t kKBit = 1 << 7;
constexpr uint8_t kMask0[] = {0x2B, 0xCD}; // First K bit is cleared.
constexpr uint8_t kMask1[] = {0x92, 0x34, // First K bit set.
0x76, 0x78, 0x9A, 0xBC}; // Second K bit cleared.
constexpr uint8_t kMask2[] = {0x92, 0x34, // First K bit set.
0xD6, 0x78, 0x9A, 0xBC, // Second K bit set.
0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};
constexpr size_t kMediaPacketLength = 1234;
// 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 FecPacketStreamReadProperties {
ProtectedStream stream;
rtc::ArrayView<const uint8_t> mask;
};
struct FecPacketStreamWriteProperties {
size_t byte_index;
uint16_t seq_num_base;
rtc::ArrayView<const uint8_t> mask;
};
Packet WritePacket(
std::vector<FecHeaderWriter::ProtectedStream> protected_streams) {
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;
}
FlexfecHeaderWriter writer;
writer.FinalizeFecHeader(protected_streams, written_packet);
return written_packet;
}
void VerifyReadHeaders(size_t expected_fec_header_size,
const ReceivedFecPacket& read_packet,
std::vector<FecPacketStreamReadProperties> 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);
}
void VerifyFinalizedHeaders(
const Packet& written_packet,
std::vector<FecPacketStreamWriteProperties> expected) {
const uint8_t* packet = written_packet.data.data();
EXPECT_EQ(packet[0] & 0x80, 0x00); // F bit clear.
EXPECT_EQ(packet[0] & 0x40, 0x00); // R bit clear.
for (size_t i = 0; i < expected.size(); ++i) {
SCOPED_TRACE(i);
// Verify value of seq_num_base.
EXPECT_EQ(
ByteReader<uint16_t>::ReadBigEndian(packet + expected[i].byte_index),
expected[i].seq_num_base);
// Verify mask.
EXPECT_THAT(rtc::MakeArrayView(packet + expected[i].byte_index + 2,
expected[i].mask.size()),
ElementsAreArray(expected[i].mask));
}
}
void VerifyWrittenAndReadHeaders(
std::vector<FecHeaderWriter::ProtectedStream> write_protected_streams,
uint16_t expected_header_size) {
// Write FEC Header.
Packet written_packet = WritePacket(write_protected_streams);
// Read FEC Header using written data.
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
read_packet.pkt->data = written_packet.data;
for (const FecHeaderWriter::ProtectedStream& stream :
write_protected_streams) {
read_packet.protected_streams.push_back({.ssrc = stream.ssrc});
}
FlexfecHeaderReader reader;
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
// Verify header contents.
EXPECT_EQ(read_packet.fec_header_size, expected_header_size);
EXPECT_EQ(read_packet.protected_streams.size(),
write_protected_streams.size());
for (size_t i = 0; i < write_protected_streams.size(); ++i) {
SCOPED_TRACE(i);
EXPECT_EQ(read_packet.protected_streams[i].seq_num_base,
write_protected_streams[i].seq_num_base);
size_t mask_write_size = write_protected_streams[i].packet_mask.size();
// Read mask returned may be larger than the mask that was sent to the
// writer; That is ok as long as the specified part of the mask matches, and
// the rest is 0s.
FlexfecHeaderWriter writer;
size_t expected_mask_read_size = writer.MinPacketMaskSize(
write_protected_streams[i].packet_mask.data(), mask_write_size);
EXPECT_EQ(read_packet.protected_streams[i].packet_mask_size,
expected_mask_read_size);
const uint8_t* read_mask_ptr =
read_packet.pkt->data.cdata() +
read_packet.protected_streams[i].packet_mask_offset;
// Verify actual mask bits.
EXPECT_THAT(rtc::MakeArrayView(read_mask_ptr, mask_write_size),
ElementsAreArray(write_protected_streams[i].packet_mask));
// If read mask size is larger than written mask size, verify all other bits
// are 0.
EXPECT_THAT(rtc::MakeArrayView(read_mask_ptr + mask_write_size,
expected_mask_read_size - mask_write_size),
Each(0));
}
// Verify that the call to ReadFecHeader did not tamper with the payload.
EXPECT_THAT(
rtc::MakeArrayView(
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_header_size,
written_packet.data.size() - expected_header_size));
}
} // namespace
TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit0ClearSingleStream) {
constexpr size_t kExpectedFecHeaderSize = 12;
constexpr uint16_t kSnBase = 0x0102;
constexpr uint8_t kFlexfecPktMask[] = {0x08, 0x81};
constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02};
constexpr uint8_t kPacketData[] = {
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
kSnBase >> 8, kSnBase & 0xFF, kFlexfecPktMask[0], kFlexfecPktMask[1],
kPayloadBits, kPayloadBits, kPayloadBits, kPayloadBits};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
read_packet.pkt->data.SetData(kPacketData);
read_packet.protected_streams = {{.ssrc = 0x01}};
FlexfecHeaderReader reader;
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
std::vector<FecPacketStreamReadProperties> 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, ReadsHeaderWithKBit1ClearSingleStream) {
constexpr size_t kExpectedFecHeaderSize = 16;
constexpr uint16_t kSnBase = 0x0102;
constexpr uint8_t kFlexfecPktMask[] = {kKBit | 0x48, 0x81, //
0x02, 0x11, 0x00, 0x21};
constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, //
0x08, 0x44, 0x00, 0x84};
constexpr uint8_t kPacketData[] = {
kFlexible, kPtRecovery, kLengthRecovery[0],
kLengthRecovery[1], kTsRecovery[0], kTsRecovery[1],
kTsRecovery[2], kTsRecovery[3], kSnBase >> 8,
kSnBase & 0xFF, kFlexfecPktMask[0], kFlexfecPktMask[1],
kFlexfecPktMask[2], kFlexfecPktMask[3], kFlexfecPktMask[4],
kFlexfecPktMask[5], kPayloadBits, kPayloadBits,
kPayloadBits, kPayloadBits};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
read_packet.pkt->data.SetData(kPacketData);
read_packet.protected_streams = {{.ssrc = 0x01}};
FlexfecHeaderReader reader;
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
std::vector<FecPacketStreamReadProperties> 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, ReadsHeaderWithBothKBitsSetSingleStream) {
constexpr size_t kExpectedFecHeaderSize = 24;
constexpr uint16_t kSnBase = 0x0102;
constexpr uint8_t kFlexfecPacketMask[] = {kKBit | 0x48, 0x81, //
kKBit | 0x02, 0x11, 0x00, 0x21, //
0x01, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11};
constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, //
0x08, 0x44, 0x00, 0x84, //
0x04, 0x44, 0x44, 0x44,
0x44, 0x44, 0x44, 0x44};
constexpr uint8_t kPacketData[] = {kFlexible,
kPtRecovery,
kLengthRecovery[0],
kLengthRecovery[1],
kTsRecovery[0],
kTsRecovery[1],
kTsRecovery[2],
kTsRecovery[3],
kSnBase >> 8,
kSnBase & 0xFF,
kFlexfecPacketMask[0],
kFlexfecPacketMask[1],
kFlexfecPacketMask[2],
kFlexfecPacketMask[3],
kFlexfecPacketMask[4],
kFlexfecPacketMask[5],
kFlexfecPacketMask[6],
kFlexfecPacketMask[7],
kFlexfecPacketMask[8],
kFlexfecPacketMask[9],
kFlexfecPacketMask[10],
kFlexfecPacketMask[11],
kFlexfecPacketMask[12],
kFlexfecPacketMask[13],
kPayloadBits,
kPayloadBits,
kPayloadBits,
kPayloadBits};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
read_packet.pkt->data.SetData(kPacketData);
read_packet.protected_streams = {{.ssrc = 0x01}};
FlexfecHeaderReader reader;
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
std::vector<FecPacketStreamReadProperties> 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, ReadsHeaderWithKBit0Clear2Streams) {
constexpr size_t kExpectedFecHeaderSize = 16;
constexpr uint16_t kSnBase0 = 0x0102;
constexpr uint16_t kSnBase1 = 0x0304;
constexpr uint8_t kFlexfecPktMask1[] = {0x08, 0x81};
constexpr uint8_t kUlpfecPacketMask1[] = {0x11, 0x02};
constexpr uint8_t kFlexfecPktMask2[] = {0x04, 0x41};
constexpr uint8_t kUlpfecPacketMask2[] = {0x08, 0x82};
constexpr uint8_t kPacketData[] = {
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
kSnBase0 >> 8, kSnBase0 & 0xFF, kFlexfecPktMask1[0], kFlexfecPktMask1[1],
kSnBase1 >> 8, kSnBase1 & 0xFF, kFlexfecPktMask2[0], kFlexfecPktMask2[1],
kPayloadBits, kPayloadBits, kPayloadBits, kPayloadBits};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
read_packet.pkt->data.SetData(kPacketData);
read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
FlexfecHeaderReader reader;
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
std::vector<FecPacketStreamReadProperties> 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, ReadsHeaderWithKBit1Clear2Streams) {
constexpr size_t kExpectedFecHeaderSize = 24;
constexpr uint16_t kSnBase0 = 0x0102;
constexpr uint16_t kSnBase1 = 0x0304;
constexpr uint8_t kFlexfecPktMask1[] = {kKBit | 0x48, 0x81, //
0x02, 0x11, 0x00, 0x21};
constexpr uint8_t kUlpfecPacketMask1[] = {0x91, 0x02, //
0x08, 0x44, 0x00, 0x84};
constexpr uint8_t kFlexfecPktMask2[] = {kKBit | 0x57, 0x82, //
0x04, 0x33, 0x00, 0x51};
constexpr uint8_t kUlpfecPacketMask2[] = {0xAF, 0x04, //
0x10, 0xCC, 0x01, 0x44};
constexpr uint8_t kPacketData[] = {
kFlexible, kPtRecovery, kLengthRecovery[0],
kLengthRecovery[1], kTsRecovery[0], kTsRecovery[1],
kTsRecovery[2], kTsRecovery[3], kSnBase0 >> 8,
kSnBase0 & 0xFF, kFlexfecPktMask1[0], kFlexfecPktMask1[1],
kFlexfecPktMask1[2], kFlexfecPktMask1[3], kFlexfecPktMask1[4],
kFlexfecPktMask1[5], kSnBase1 >> 8, kSnBase1 & 0xFF,
kFlexfecPktMask2[0], kFlexfecPktMask2[1], kFlexfecPktMask2[2],
kFlexfecPktMask2[3], kFlexfecPktMask2[4], kFlexfecPktMask2[5],
kPayloadBits, kPayloadBits, kPayloadBits,
kPayloadBits};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
read_packet.pkt->data.SetData(kPacketData);
read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
FlexfecHeaderReader reader;
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
std::vector<FecPacketStreamReadProperties> 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, ReadsHeaderWithBothKBitsSet2Streams) {
constexpr size_t kExpectedFecHeaderSize = 40;
constexpr uint16_t kSnBase0 = 0x0102;
constexpr uint16_t kSnBase1 = 0x0304;
constexpr uint8_t kFlexfecPktMask1[] = {kKBit | 0x48, 0x81, //
kKBit | 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[] = {kKBit | 0x32, 0x84, //
kKBit | 0x05, 0x23, 0x00, 0x55, //
0xA3, 0x22, 0x22, 0x22,
0x22, 0x22, 0x22, 0x35};
constexpr uint8_t kUlpfecPacketMask2[] = {0x65, 0x08, //
0x14, 0x8C, 0x01, 0x56, //
0x8C, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0xD4};
constexpr uint8_t kPacketData[] = {kFlexible,
kPtRecovery,
kLengthRecovery[0],
kLengthRecovery[1],
kTsRecovery[0],
kTsRecovery[1],
kTsRecovery[2],
kTsRecovery[3],
kSnBase0 >> 8,
kSnBase0 & 0xFF,
kFlexfecPktMask1[0],
kFlexfecPktMask1[1],
kFlexfecPktMask1[2],
kFlexfecPktMask1[3],
kFlexfecPktMask1[4],
kFlexfecPktMask1[5],
kFlexfecPktMask1[6],
kFlexfecPktMask1[7],
kFlexfecPktMask1[8],
kFlexfecPktMask1[9],
kFlexfecPktMask1[10],
kFlexfecPktMask1[11],
kFlexfecPktMask1[12],
kFlexfecPktMask1[13],
kSnBase1 >> 8,
kSnBase1 & 0xFF,
kFlexfecPktMask2[0],
kFlexfecPktMask2[1],
kFlexfecPktMask2[2],
kFlexfecPktMask2[3],
kFlexfecPktMask2[4],
kFlexfecPktMask2[5],
kFlexfecPktMask2[6],
kFlexfecPktMask2[7],
kFlexfecPktMask2[8],
kFlexfecPktMask2[9],
kFlexfecPktMask2[10],
kFlexfecPktMask2[11],
kFlexfecPktMask2[12],
kFlexfecPktMask2[13],
kPayloadBits,
kPayloadBits,
kPayloadBits,
kPayloadBits};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
read_packet.pkt->data.SetData(kPacketData);
read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
FlexfecHeaderReader reader;
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
std::vector<FecPacketStreamReadProperties> 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 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[] = {0x29, 0x91};
constexpr uint8_t kUlpfecPacketMask1[] = {0x53, 0x22};
constexpr uint8_t kFlexfecPacketMask2[] = {kKBit | 0x32, 0xA1, //
0x02, 0x11, 0x00, 0x21};
constexpr uint8_t kUlpfecPacketMask2[] = {0x65, 0x42, //
0x08, 0x44, 0x00, 0x84};
constexpr uint8_t kFlexfecPacketMask3[] = {kKBit | 0x48, 0x81, //
kKBit | 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[] = {kKBit | 0x32, 0x84, //
0x05, 0x23, 0x00, 0x55};
constexpr uint8_t kUlpfecPacketMask4[] = {0x65, 0x08, //
0x14, 0x8C, 0x01, 0x54};
constexpr uint8_t kPacketData[] = {kFlexible,
kPtRecovery,
kLengthRecovery[0],
kLengthRecovery[1],
kTsRecovery[0],
kTsRecovery[1],
kTsRecovery[2],
kTsRecovery[3],
kSnBase0 >> 8,
kSnBase0 & 0xFF,
kFlexfecPacketMask1[0],
kFlexfecPacketMask1[1],
kSnBase1 >> 8,
kSnBase1 & 0xFF,
kFlexfecPacketMask2[0],
kFlexfecPacketMask2[1],
kFlexfecPacketMask2[2],
kFlexfecPacketMask2[3],
kFlexfecPacketMask2[4],
kFlexfecPacketMask2[5],
kSnBase2 >> 8,
kSnBase2 & 0xFF,
kFlexfecPacketMask3[0],
kFlexfecPacketMask3[1],
kFlexfecPacketMask3[2],
kFlexfecPacketMask3[3],
kFlexfecPacketMask3[4],
kFlexfecPacketMask3[5],
kFlexfecPacketMask3[6],
kFlexfecPacketMask3[7],
kFlexfecPacketMask3[8],
kFlexfecPacketMask3[9],
kFlexfecPacketMask3[10],
kFlexfecPacketMask3[11],
kFlexfecPacketMask3[12],
kFlexfecPacketMask3[13],
kSnBase3 >> 8,
kSnBase3 & 0xFF,
kFlexfecPacketMask4[0],
kFlexfecPacketMask4[1],
kFlexfecPacketMask4[2],
kFlexfecPacketMask4[3],
kFlexfecPacketMask4[4],
kFlexfecPacketMask4[5],
kPayloadBits,
kPayloadBits,
kPayloadBits,
kPayloadBits};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
read_packet.pkt->data.SetData(kPacketData);
read_packet.protected_streams = {
{.ssrc = 0x01}, {.ssrc = 0x02}, {.ssrc = 0x03}, {.ssrc = 0x04}};
FlexfecHeaderReader reader;
EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
std::vector<FecPacketStreamReadProperties> expected = {
{.stream = {.ssrc = 0x01,
.seq_num_base = kSnBase0,
.packet_mask_offset = 10,
.packet_mask_size = std::size(kUlpfecPacketMask1)},
.mask = kUlpfecPacketMask1},
{.stream = {.ssrc = 0x02,
.seq_num_base = kSnBase1,
.packet_mask_offset = 14,
.packet_mask_size = std::size(kUlpfecPacketMask2)},
.mask = kUlpfecPacketMask2},
{.stream = {.ssrc = 0x03,
.seq_num_base = kSnBase2,
.packet_mask_offset = 22,
.packet_mask_size = std::size(kUlpfecPacketMask3)},
.mask = kUlpfecPacketMask3},
{.stream = {.ssrc = 0x04,
.seq_num_base = kSnBase3,
.packet_mask_offset = 38,
.packet_mask_size = std::size(kUlpfecPacketMask4)},
.mask = kUlpfecPacketMask4},
};
VerifyReadHeaders(kExpectedFecHeaderSize, read_packet, expected);
}
TEST(FlexfecHeaderReaderTest, ReadPacketWithoutProtectedSsrcsShouldFail) {
constexpr uint8_t kPacketData[] = {
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3]};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
read_packet.pkt->data.SetData(kPacketData);
// No protected ssrcs.
read_packet.protected_streams = {};
FlexfecHeaderReader reader;
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
}
TEST(FlexfecHeaderReaderTest, ReadPacketWithoutStreamSpecificHeaderShouldFail) {
// Simulate short received packet.
constexpr uint8_t kPacketData[] = {
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3]};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
read_packet.pkt->data.SetData(kPacketData);
read_packet.protected_streams = {{.ssrc = 0x01}};
FlexfecHeaderReader reader;
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
}
TEST(FlexfecHeaderReaderTest, ReadShortPacketWithKBit0SetShouldFail) {
// Simulate short received packet.
constexpr uint8_t kPacketData[] = {
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
kSnBases[0][0], kSnBases[0][1], kMask0[0], kMask0[1]};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
// Expected to have 2 bytes of mask but length of packet misses 1 byte.
read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 1);
read_packet.protected_streams = {{.ssrc = 0x01}};
FlexfecHeaderReader reader;
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
}
TEST(FlexfecHeaderReaderTest, ReadShortPacketWithKBit1ClearShouldFail) {
// Simulate short received packet.
constexpr uint8_t kPacketData[] = {
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
kSnBases[0][0], kSnBases[0][1], kMask1[0], kMask1[1],
kMask1[2], kMask1[3], kMask1[4], kMask1[5]};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
// Expected to have 6 bytes of mask but length of packet misses 2 bytes.
read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 2);
read_packet.protected_streams = {{.ssrc = 0x01}};
FlexfecHeaderReader reader;
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
}
TEST(FlexfecHeaderReaderTest, 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], kMask2[0], kMask2[1],
kMask2[2], kMask2[3], kMask2[4], kMask2[5],
kMask2[6], kMask2[7], kMask2[8], kMask2[9],
kMask2[10], kMask2[11], kMask2[12], kMask2[13]};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
// Expected to have 14 bytes of mask but length of packet misses 2 bytes.
read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 2);
read_packet.protected_streams = {{.ssrc = 0x01}};
FlexfecHeaderReader reader;
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
}
TEST(FlexfecHeaderReaderTest, ReadShortPacketMultipleStreamsShouldFail) {
// Simulate short received packet with 2 protected ssrcs.
constexpr uint8_t kPacketData[] = {
kFlexible, kPtRecovery, kLengthRecovery[0], kLengthRecovery[1],
kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3],
kSnBases[0][0], kSnBases[0][1], kMask0[0], kMask0[1],
kSnBases[1][0], kSnBases[1][1], kMask2[0], kMask2[1],
kMask2[2], kMask2[3], kMask2[4], kMask2[5],
kMask2[6], kMask2[7], kMask2[8], kMask2[9],
kMask2[10], kMask2[11], kMask2[12], kMask2[13]};
ReceivedFecPacket read_packet;
read_packet.pkt = rtc::make_ref_counted<Packet>();
// Subtract 2 bytes from length, so the read will fail on parsing second
read_packet.pkt->data.SetData(kPacketData, sizeof(kPacketData) - 2);
read_packet.protected_streams = {{.ssrc = 0x01}, {.ssrc = 0x02}};
FlexfecHeaderReader reader;
EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
}
TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit0ClearSingleStream) {
constexpr uint8_t kFlexfecPacketMask[] = {0x08, 0x81};
constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02};
constexpr uint16_t kMediaStartSeqNum = 1234;
Packet written_packet = WritePacket({{.ssrc = 0x01,
.seq_num_base = kMediaStartSeqNum,
.packet_mask = kUlpfecPacketMask}});
std::vector<FecPacketStreamWriteProperties> expected = {
{.byte_index = 8,
.seq_num_base = kMediaStartSeqNum,
.mask = kFlexfecPacketMask}};
VerifyFinalizedHeaders(written_packet, expected);
}
TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit1ClearSingleStream) {
constexpr uint8_t kFlexfecPacketMask[] = {0xC8, 0x81, 0x02, 0x11, 0x00, 0x21};
constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, 0x08, 0x44, 0x00, 0x84};
constexpr uint16_t kMediaStartSeqNum = 1234;
Packet written_packet = WritePacket({{.ssrc = 0x01,
.seq_num_base = kMediaStartSeqNum,
.packet_mask = kUlpfecPacketMask}});
std::vector<FecPacketStreamWriteProperties> expected = {
{.byte_index = 8,
.seq_num_base = kMediaStartSeqNum,
.mask = kFlexfecPacketMask}};
VerifyFinalizedHeaders(written_packet, expected);
}
TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithBothKBitsSetSingleStream) {
constexpr uint8_t kFlexfecPacketMask[] = {
0x91, 0x11, // K-bit 0 set.
0x91, 0x11, 0x11, 0x10, // K-bit 1 set.
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 //
};
constexpr uint8_t kUlpfecPacketMask[] = {0x22, 0x22, 0x44, 0x44, 0x44, 0x41};
constexpr uint16_t kMediaStartSeqNum = 1234;
Packet written_packet = WritePacket({{.ssrc = 0x01,
.seq_num_base = kMediaStartSeqNum,
.packet_mask = kUlpfecPacketMask}});
std::vector<FecPacketStreamWriteProperties> expected = {
{.byte_index = 8,
.seq_num_base = kMediaStartSeqNum,
.mask = kFlexfecPacketMask}};
VerifyFinalizedHeaders(written_packet, expected);
}
TEST(FlexfecHeaderWriterTest, FinalizesHeaderMultipleStreamsMultipleMasks) {
constexpr uint8_t kFlexfecPacketMask1[] = {
0x91, 0x11, // K-bit 0 set.
0x91, 0x11, 0x11, 0x10, // K-bit 1 set.
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 //
};
constexpr uint8_t kUlpfecPacketMask1[] = {0x22, 0x22, 0x44, 0x44, 0x44, 0x41};
constexpr uint16_t kMediaStartSeqNum1 = 1234;
constexpr uint8_t kFlexfecPacketMask2[] = {0x08, 0x81};
constexpr uint8_t kUlpfecPacketMask2[] = {0x11, 0x02};
constexpr uint16_t kMediaStartSeqNum2 = 2345;
constexpr uint8_t kFlexfecPacketMask3[] = {0xC8, 0x81, 0x02,
0x11, 0x00, 0x21};
constexpr uint8_t kUlpfecPacketMask3[] = {0x91, 0x02, 0x08, 0x44, 0x00, 0x84};
constexpr uint16_t kMediaStartSeqNum3 = 3456;
constexpr uint8_t kFlexfecPacketMask4[] = {
0xD5, 0xAA, // K-bit 0 set.
0xA2, 0xAB, 0xCD, 0xEF, // K-bit 1 set.
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 //
};
constexpr uint8_t kUlpfecPacketMask4[] = {0xAB, 0x54, 0x8A, 0xAF, 0x37, 0xBF};
constexpr uint16_t kMediaStartSeqNum4 = 4567;
Packet written_packet = WritePacket({{.ssrc = 0x01,
.seq_num_base = kMediaStartSeqNum1,
.packet_mask = kUlpfecPacketMask1},
{.ssrc = 0x02,
.seq_num_base = kMediaStartSeqNum2,
.packet_mask = kUlpfecPacketMask2},
{.ssrc = 0x03,
.seq_num_base = kMediaStartSeqNum3,
.packet_mask = kUlpfecPacketMask3},
{.ssrc = 0x04,
.seq_num_base = kMediaStartSeqNum4,
.packet_mask = kUlpfecPacketMask4}});
std::vector<FecPacketStreamWriteProperties> expected = {
{.byte_index = 8,
.seq_num_base = kMediaStartSeqNum1,
.mask = kFlexfecPacketMask1},
{.byte_index = 24,
.seq_num_base = kMediaStartSeqNum2,
.mask = kFlexfecPacketMask2},
{.byte_index = 28,
.seq_num_base = kMediaStartSeqNum3,
.mask = kFlexfecPacketMask3},
{.byte_index = 36,
.seq_num_base = kMediaStartSeqNum4,
.mask = kFlexfecPacketMask4}};
VerifyFinalizedHeaders(written_packet, expected);
}
// TODO(bugs.webrtc.org/15002): reimplement and add tests for multi stream cases
// after updating the MinPacketMaskSize and FecHeaderSize functions.
TEST(FlexfecHeaderWriterTest, ContractsShortUlpfecPacketMaskWithBit15Clear) {}
TEST(FlexfecHeaderWriterTest, ExpandsShortUlpfecPacketMaskWithBit15Set) {}
TEST(FlexfecHeaderWriterTest,
ContractsLongUlpfecPacketMaskWithBit46ClearBit47Clear) {}
TEST(FlexfecHeaderWriterTest,
ExpandsLongUlpfecPacketMaskWithBit46SetBit47Clear) {}
TEST(FlexfecHeaderWriterTest,
ExpandsLongUlpfecPacketMaskWithBit46ClearBit47Set) {}
TEST(FlexfecHeaderWriterTest, ExpandsLongUlpfecPacketMaskWithBit46SetBit47Set) {
}
TEST(FlexfecHeaderReaderWriterTest,
WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15ClearSingleStream) {
constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02}; // Bit 15 clear.
constexpr uint16_t kMediaStartSeqNum = 1234;
constexpr uint16_t kExpectedHeaderSize = 12;
VerifyWrittenAndReadHeaders({{.ssrc = 0x01,
.seq_num_base = kMediaStartSeqNum,
.packet_mask = kUlpfecPacketMask}},
kExpectedHeaderSize);
}
TEST(FlexfecHeaderReaderWriterTest,
WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15SetSingleStream) {
constexpr uint8_t kUlpfecPacketMask[] = {0xAA, 0xFF}; // Bit 15 set.
constexpr uint16_t kMediaStartSeqNum = 1234;
constexpr uint16_t kExpectedHeaderSize = 16;
VerifyWrittenAndReadHeaders({{.ssrc = 0x01,
.seq_num_base = kMediaStartSeqNum,
.packet_mask = kUlpfecPacketMask}},
kExpectedHeaderSize);
}
TEST(FlexfecHeaderReaderWriterTest,
WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47ClearSingleStream) {
constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, 0x08, 0x44,
0x00, 0x84}; // Bits 46, 47 clear.
constexpr uint16_t kMediaStartSeqNum = 1234;
constexpr uint16_t kExpectedHeaderSize = 16;
VerifyWrittenAndReadHeaders({{.ssrc = 0x01,
.seq_num_base = kMediaStartSeqNum,
.packet_mask = kUlpfecPacketMask}},
kExpectedHeaderSize);
}
TEST(
FlexfecHeaderReaderWriterTest,
WriteAndReadLargeUlpfecPacketHeaderWithMaskBit46SetBit47ClearSingleStream) {
constexpr uint8_t kUlpfecPacketMask[] = {
0x91, 0x02, 0x08, 0x44, 0x00, 0x86}; // Bit 46 set, bit 47 clear.
constexpr uint16_t kMediaStartSeqNum = 1234;
constexpr uint16_t kExpectedHeaderSize = 24;
VerifyWrittenAndReadHeaders({{.ssrc = 0x01,
.seq_num_base = kMediaStartSeqNum,
.packet_mask = kUlpfecPacketMask}},
kExpectedHeaderSize);
}
TEST(
FlexfecHeaderReaderWriterTest,
WriteAndReadLargeUlpfecPacketHeaderMaskWithBit46ClearBit47SetSingleStream) {
constexpr uint8_t kUlpfecPacketMask[] = {
0x91, 0x02, 0x08, 0x44, 0x00, 0x85}; // Bit 46 clear, bit 47 set.
constexpr uint16_t kMediaStartSeqNum = 1234;
constexpr uint16_t kExpectedHeaderSize = 24;
VerifyWrittenAndReadHeaders({{.ssrc = 0x01,
.seq_num_base = kMediaStartSeqNum,
.packet_mask = kUlpfecPacketMask}},
kExpectedHeaderSize);
}
TEST(FlexfecHeaderReaderWriterTest,
WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47SetSingleStream) {
constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, 0x08, 0x44,
0x00, 0x87}; // Bits 46, 47 set.
constexpr uint16_t kMediaStartSeqNum = 1234;
constexpr uint16_t kExpectedHeaderSize = 24;
VerifyWrittenAndReadHeaders({{.ssrc = 0x01,
.seq_num_base = kMediaStartSeqNum,
.packet_mask = kUlpfecPacketMask}},
kExpectedHeaderSize);
}
TEST(FlexfecHeaderReaderWriterTest, WriteAndReadMultipleStreamsMultipleMasks) {
constexpr uint8_t kUlpfecPacketMask1[] = {0x11, 0x02};
constexpr uint16_t kMediaStartSeqNum1 = 1234;
constexpr uint8_t kUlpfecPacketMask2[] = {0x91, 0x02, 0x08, 0x44, 0x00, 0x84};
constexpr uint16_t kMediaStartSeqNum2 = 2345;
constexpr uint8_t kUlpfecPacketMask3[] = {0xAA, 0xFF};
constexpr uint16_t kMediaStartSeqNum3 = 3456;
constexpr uint8_t kUlpfecPacketMask4[] = {0x91, 0x02, 0x08, 0x44, 0x00, 0x87};
constexpr uint16_t kMediaStartSeqNum4 = 4567;
constexpr uint16_t kExpectedHeaderSize = 44;
VerifyWrittenAndReadHeaders({{.ssrc = 0x01,
.seq_num_base = kMediaStartSeqNum1,
.packet_mask = kUlpfecPacketMask1},
{.ssrc = 0x02,
.seq_num_base = kMediaStartSeqNum2,
.packet_mask = kUlpfecPacketMask2},
{.ssrc = 0x03,
.seq_num_base = kMediaStartSeqNum3,
.packet_mask = kUlpfecPacketMask3},
{.ssrc = 0x04,
.seq_num_base = kMediaStartSeqNum4,
.packet_mask = kUlpfecPacketMask4}},
kExpectedHeaderSize);
}
} // namespace webrtc