diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc index 0cdaa88cf3..79509f34c6 100644 --- a/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc +++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc @@ -49,17 +49,6 @@ constexpr size_t kHeaderSizes[] = { kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[1], kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[2]}; -// We currently only support single-stream protection. -// TODO(brandtr): Update this when we support multistream protection. -constexpr uint8_t kSsrcCount = 1; - -// There are three reserved bytes that MUST be set to zero in the header. -constexpr uint32_t kReservedBits = 0; - -// TODO(brandtr): Update this when we support multistream protection. -constexpr size_t kPacketMaskOffset = - kBaseHeaderSize + kStreamSpecificHeaderSize; - // Here we count the K-bits as belonging to the packet mask. // This can be used in conjunction with FlexfecHeaderWriter::MinPacketMaskSize, // which calculates a bound on the needed packet mask size including K-bits, @@ -255,78 +244,84 @@ size_t FlexfecHeaderWriter::FecHeaderSize(size_t packet_mask_size) const { // FecHeaderSize(), so in this function we can be sure that we are // writing in space that is intended for the header. // -// TODO(brandtr): Update this function when we support offset-based masks, -// retransmissions, and protecting multiple SSRCs. +// TODO(brandtr): Update this function when we support offset-based masks +// and retransmissions. void FlexfecHeaderWriter::FinalizeFecHeader( rtc::ArrayView protected_streams, ForwardErrorCorrection::Packet& fec_packet) const { - // TODO(bugs.webrtc.org/15002): Iterate over all streams and update FlexFEC - // header accordingly. - RTC_CHECK_EQ(protected_streams.size(), 1); - uint32_t media_ssrc = protected_streams[0].ssrc; - uint16_t seq_num_base = protected_streams[0].seq_num_base; - const uint8_t* packet_mask = protected_streams[0].packet_mask.data(); - size_t packet_mask_size = protected_streams[0].packet_mask.size(); - uint8_t* data = fec_packet.data.MutableData(); - data[0] &= 0x7f; // Clear R bit. - data[0] &= 0xbf; // Clear F bit. - ByteWriter::WriteBigEndian(&data[8], kSsrcCount); - ByteWriter::WriteBigEndian(&data[9], kReservedBits); - ByteWriter::WriteBigEndian(&data[12], media_ssrc); - ByteWriter::WriteBigEndian(&data[16], seq_num_base); - // Adapt ULPFEC packet mask to FlexFEC header. - // - // We treat the mask parts as unsigned integers with host order endianness - // in order to simplify the bit shifting between bytes. - uint8_t* const written_packet_mask = data + kPacketMaskOffset; - if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) { - // The packet mask is 48 bits long. - uint16_t tmp_mask_part0 = - ByteReader::ReadBigEndian(&packet_mask[0]); - uint32_t tmp_mask_part1 = - ByteReader::ReadBigEndian(&packet_mask[2]); + *data &= 0x7f; // Clear R bit. + *data &= 0xbf; // Clear F bit. - tmp_mask_part0 >>= 1; // Shift, thus clearing K-bit 0. - ByteWriter::WriteBigEndian(&written_packet_mask[0], - tmp_mask_part0); - tmp_mask_part1 >>= 2; // Shift, thus clearing K-bit 1 and bit 15. - ByteWriter::WriteBigEndian(&written_packet_mask[2], - tmp_mask_part1); - bool bit15 = (packet_mask[1] & 0x01) != 0; - if (bit15) - written_packet_mask[2] |= 0x40; // Set bit 15. - bool bit46 = (packet_mask[5] & 0x02) != 0; - bool bit47 = (packet_mask[5] & 0x01) != 0; - if (!bit46 && !bit47) { - written_packet_mask[2] |= 0x80; // Set K-bit 1. - } else { - memset(&written_packet_mask[6], 0, 8); // Clear all trailing bits. - written_packet_mask[6] |= 0x80; // Set K-bit 2. - if (bit46) - written_packet_mask[6] |= 0x40; // Set bit 46. - if (bit47) - written_packet_mask[6] |= 0x20; // Set bit 47. - } - } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) { - // The packet mask is 16 bits long. - uint16_t tmp_mask_part0 = - ByteReader::ReadBigEndian(&packet_mask[0]); + // First seq_num will be in byte index 8 + // (See FEC header schematic in flexfec_header_reader_writer.h.) + uint8_t* write_at = data + 8; + for (const ProtectedStream& protected_stream : protected_streams) { + ByteWriter::WriteBigEndian(write_at, + protected_stream.seq_num_base); + write_at += kStreamSpecificHeaderSize; + // Adapt ULPFEC packet mask to FlexFEC header. + // + // We treat the mask parts as unsigned integers with host order endianness + // in order to simplify the bit shifting between bytes. + if (protected_stream.packet_mask.size() == kUlpfecPacketMaskSizeLBitSet) { + // The packet mask is 48 bits long. + uint16_t tmp_mask_part0 = + ByteReader::ReadBigEndian(&protected_stream.packet_mask[0]); + uint32_t tmp_mask_part1 = + ByteReader::ReadBigEndian(&protected_stream.packet_mask[2]); - tmp_mask_part0 >>= 1; // Shift, thus clearing K-bit 0. - ByteWriter::WriteBigEndian(&written_packet_mask[0], - tmp_mask_part0); - bool bit15 = (packet_mask[1] & 0x01) != 0; - if (!bit15) { - written_packet_mask[0] |= 0x80; // Set K-bit 0. + tmp_mask_part0 >>= 1; // Shift, thus clearing K-bit 0. + ByteWriter::WriteBigEndian(write_at, tmp_mask_part0); + write_at += kFlexfecPacketMaskSizes[0]; + tmp_mask_part1 >>= 2; // Shift, thus clearing K-bit 1 and bit 15. + ByteWriter::WriteBigEndian(write_at, tmp_mask_part1); + + bool bit15 = (protected_stream.packet_mask[1] & 0x01) != 0; + if (bit15) + *write_at |= 0x40; // Set bit 15. + + bool bit46 = (protected_stream.packet_mask[5] & 0x02) != 0; + bool bit47 = (protected_stream.packet_mask[5] & 0x01) != 0; + if (!bit46 && !bit47) { + *write_at |= 0x80; // Set K-bit 1. + write_at += kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0]; + } else { + write_at += kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0]; + // Clear all trailing bits. + memset(write_at, 0, + kFlexfecPacketMaskSizes[2] - kFlexfecPacketMaskSizes[1]); + if (bit46) + *write_at |= 0x80; // Set bit 46. + if (bit47) + *write_at |= 0x40; // Set bit 47. + write_at += kFlexfecPacketMaskSizes[2] - kFlexfecPacketMaskSizes[1]; + } + } else if (protected_stream.packet_mask.size() == + kUlpfecPacketMaskSizeLBitClear) { + // The packet mask is 16 bits long. + uint16_t tmp_mask_part0 = + ByteReader::ReadBigEndian(&protected_stream.packet_mask[0]); + + tmp_mask_part0 >>= 1; // Shift, thus clearing K-bit 0. + ByteWriter::WriteBigEndian(write_at, tmp_mask_part0); + bool bit15 = (protected_stream.packet_mask[1] & 0x01) != 0; + if (!bit15) { + *write_at |= 0x80; // Set K-bit 0. + write_at += kFlexfecPacketMaskSizes[0]; + } else { + write_at += kFlexfecPacketMaskSizes[0]; + // Clear all trailing bits. + memset(write_at, 0U, + kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0]); + *write_at |= 0x80; // Set K-bit 1. + *write_at |= 0x40; // Set bit 15. + write_at += kFlexfecPacketMaskSizes[1] - kFlexfecPacketMaskSizes[0]; + } } else { - memset(&written_packet_mask[2], 0U, 4); // Clear all trailing bits. - written_packet_mask[2] |= 0x80; // Set K-bit 1. - written_packet_mask[2] |= 0x40; // Set bit 15. + RTC_DCHECK_NOTREACHED() << "Incorrect packet mask size: " + << protected_stream.packet_mask.size() << "."; } - } else { - RTC_DCHECK_NOTREACHED() - << "Incorrect packet mask size: " << packet_mask_size << "."; } } 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 16ecbe5c90..6995ba3871 100644 --- a/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc +++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc @@ -33,6 +33,7 @@ namespace { using Packet = ForwardErrorCorrection::Packet; using ProtectedStream = ForwardErrorCorrection::ProtectedStream; using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket; +using ::testing::Each; using ::testing::ElementsAreArray; constexpr uint8_t kMask0[] = {0xAB, 0xCD}; // First K bit is set. @@ -42,6 +43,8 @@ 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}; +constexpr size_t kMediaPacketLength = 1234; + // Reader tests. constexpr uint8_t kFlexible = 0b00 << 6; constexpr uint8_t kPtRecovery = 123; @@ -53,14 +56,34 @@ constexpr uint8_t kSnBases[4][2] = {{0x01, 0x02}, {0x07, 0x08}}; constexpr uint8_t kPayloadBits = 0x00; -struct FecPacketStreamProperties { +struct FecPacketStreamReadProperties { ProtectedStream stream; rtc::ArrayView mask; }; +struct FecPacketStreamWriteProperties { + size_t byte_index; + uint16_t seq_num_base; + rtc::ArrayView mask; +}; + +Packet WritePacket( + std::vector 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 expected) { + 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()); @@ -83,6 +106,84 @@ void VerifyReadHeaders(size_t expected_fec_header_size, read_packet.protection_length); } +void VerifyFinalizedHeaders( + const Packet& written_packet, + std::vector 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::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 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(); + 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, ReadsHeaderWithKBit0SetSingleStream) { @@ -104,7 +205,7 @@ TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit0SetSingleStream) { FlexfecHeaderReader reader; EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - std::vector expected = { + std::vector expected = { {.stream = {.ssrc = 0x01, .seq_num_base = kSnBase, .packet_mask_offset = 10, @@ -139,7 +240,7 @@ TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit1SetSingleStream) { FlexfecHeaderReader reader; EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - std::vector expected = { + std::vector expected = { {.stream = {.ssrc = 0x01, .seq_num_base = kSnBase, .packet_mask_offset = 10, @@ -198,7 +299,7 @@ TEST(FlexfecHeaderReaderTest, ReadsHeaderWithNoKBitsSetSingleStream) { FlexfecHeaderReader reader; EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - std::vector expected = { + std::vector expected = { {.stream = {.ssrc = 0x01, .seq_num_base = kSnBase, .packet_mask_offset = 10, @@ -232,7 +333,7 @@ TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit0Set2Streams) { FlexfecHeaderReader reader; EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - std::vector expected = { + std::vector expected = { {.stream = {.ssrc = 0x01, .seq_num_base = kSnBase0, .packet_mask_offset = 10, @@ -281,7 +382,7 @@ TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit1Set2Streams) { FlexfecHeaderReader reader; EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - std::vector expected = { + std::vector expected = { {.stream = {.ssrc = 0x01, .seq_num_base = kSnBase0, .packet_mask_offset = 10, @@ -372,7 +473,7 @@ TEST(FlexfecHeaderReaderTest, ReadsHeaderWithNoKBitsSet2Streams) { FlexfecHeaderReader reader; EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - std::vector expected = { + std::vector expected = { {.stream = {.ssrc = 0x01, .seq_num_base = kSnBase0, .packet_mask_offset = 10, @@ -471,7 +572,7 @@ TEST(FlexfecHeaderReaderTest, ReadsHeaderWithMultipleStreamsMultipleMasks) { FlexfecHeaderReader reader; EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); - std::vector expected = { + std::vector expected = { {.stream = {.ssrc = 0x01, .seq_num_base = kSnBase0, .packet_mask_offset = 10, @@ -597,14 +698,113 @@ TEST(FlexfecHeaderReaderTest, ReadShortPacketMultipleStreamsShouldFail) { EXPECT_FALSE(reader.ReadFecHeader(&read_packet)); } +TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit0SetSingleStream) { + constexpr uint8_t kFlexfecPacketMask[] = {0x88, 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 expected = { + {.byte_index = 8, + .seq_num_base = kMediaStartSeqNum, + .mask = kFlexfecPacketMask}}; + + VerifyFinalizedHeaders(written_packet, expected); +} + +TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit1SetSingleStream) { + constexpr uint8_t kFlexfecPacketMask[] = {0x48, 0x81, 0x82, 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 expected = { + {.byte_index = 8, + .seq_num_base = kMediaStartSeqNum, + .mask = kFlexfecPacketMask}}; + + VerifyFinalizedHeaders(written_packet, expected); +} + +TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithNoKBitsSetSingleStream) { + constexpr uint8_t kFlexfecPacketMask[] = { + 0x11, 0x11, // K-bit 0 clear. + 0x11, 0x11, 0x11, 0x10, // K-bit 1 clear. + 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 expected = { + {.byte_index = 8, + .seq_num_base = kMediaStartSeqNum, + .mask = kFlexfecPacketMask}}; + + VerifyFinalizedHeaders(written_packet, expected); +} + +TEST(FlexfecHeaderWriterTest, FinalizesHeaderMultipleStreamsMultipleMasks) { + constexpr uint8_t kFlexfecPacketMask1[] = { + 0x11, 0x11, // K-bit 0 clear. + 0x11, 0x11, 0x11, 0x10, // K-bit 1 clear. + 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[] = {0x88, 0x81}; + constexpr uint8_t kUlpfecPacketMask2[] = {0x11, 0x02}; + constexpr uint16_t kMediaStartSeqNum2 = 2345; + constexpr uint8_t kFlexfecPacketMask3[] = {0x48, 0x81, 0x82, + 0x11, 0x00, 0x21}; + constexpr uint8_t kUlpfecPacketMask3[] = {0x91, 0x02, 0x08, 0x44, 0x00, 0x84}; + constexpr uint16_t kMediaStartSeqNum3 = 3456; + constexpr uint8_t kFlexfecPacketMask4[] = { + 0x55, 0xAA, // K-bit 0 clear. + 0x22, 0xAB, 0xCD, 0xEF, // K-bit 1 clear. + 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 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 Writer code. - -TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit0Set) {} - -TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit1Set) {} - -TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit2Set) {} +// after updating the MinPacketMaskSize and FecHeaderSize functions. TEST(FlexfecHeaderWriterTest, ContractsShortUlpfecPacketMaskWithBit15Clear) {} @@ -623,21 +823,107 @@ TEST(FlexfecHeaderWriterTest, ExpandsLongUlpfecPacketMaskWithBit46SetBit47Set) { } TEST(FlexfecHeaderReaderWriterTest, - WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Clear) {} + 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, - WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Set) {} + 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, - WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Clear) {} + 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, - WriteAndReadLargeUlpfecPacketHeaderWithMaskBit46SetBit47Clear) {} + 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; -TEST(FlexfecHeaderReaderWriterTest, - WriteAndReadLargeUlpfecPacketHeaderMaskWithBit46ClearBit47Set) {} + VerifyWrittenAndReadHeaders({{.ssrc = 0x01, + .seq_num_base = kMediaStartSeqNum, + .packet_mask = kUlpfecPacketMask}}, + kExpectedHeaderSize); +} -TEST(FlexfecHeaderReaderWriterTest, - WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Set) {} +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