tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ulpfec_generator_unittest.cc (11173B)


      1 /*
      2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #include "modules/rtp_rtcp/source/ulpfec_generator.h"
     12 
     13 #include <cstddef>
     14 #include <cstdint>
     15 #include <memory>
     16 #include <vector>
     17 
     18 #include "api/environment/environment.h"
     19 #include "api/environment/environment_factory.h"
     20 #include "modules/include/module_fec_types.h"
     21 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
     22 #include "modules/rtp_rtcp/source/fec_test_helper.h"
     23 #include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
     24 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
     25 #include "rtc_base/copy_on_write_buffer.h"
     26 #include "system_wrappers/include/clock.h"
     27 #include "test/gtest.h"
     28 
     29 namespace webrtc {
     30 
     31 namespace {
     32 using test::fec::AugmentedPacketGenerator;
     33 
     34 constexpr int kFecPayloadType = 96;
     35 constexpr int kRedPayloadType = 97;
     36 constexpr uint32_t kMediaSsrc = 835424;
     37 }  // namespace
     38 
     39 void VerifyHeader(uint16_t seq_num,
     40                  uint32_t timestamp,
     41                  int red_payload_type,
     42                  int fec_payload_type,
     43                  bool marker_bit,
     44                  const CopyOnWriteBuffer& data) {
     45  // Marker bit not set.
     46  EXPECT_EQ(marker_bit ? 0x80 : 0, data[1] & 0x80);
     47  EXPECT_EQ(red_payload_type, data[1] & 0x7F);
     48  EXPECT_EQ(seq_num, (data[2] << 8) + data[3]);
     49  uint32_t parsed_timestamp =
     50      (data[4] << 24) + (data[5] << 16) + (data[6] << 8) + data[7];
     51  EXPECT_EQ(timestamp, parsed_timestamp);
     52  EXPECT_EQ(static_cast<uint8_t>(fec_payload_type), data[kRtpHeaderSize]);
     53 }
     54 
     55 class UlpfecGeneratorTest : public ::testing::Test {
     56 protected:
     57  UlpfecGeneratorTest()
     58      : env_(CreateEnvironment(std::make_unique<SimulatedClock>(1))),
     59        ulpfec_generator_(env_, kRedPayloadType, kFecPayloadType),
     60        packet_generator_(kMediaSsrc) {}
     61 
     62  const Environment env_;
     63  UlpfecGenerator ulpfec_generator_;
     64  AugmentedPacketGenerator packet_generator_;
     65 };
     66 
     67 // Verifies bug found via fuzzing, where a gap in the packet sequence caused us
     68 // to move past the end of the current FEC packet mask byte without moving to
     69 // the next byte. That likely caused us to repeatedly read from the same byte,
     70 // and if that byte didn't protect packets we would generate empty FEC.
     71 TEST_F(UlpfecGeneratorTest, NoEmptyFecWithSeqNumGaps) {
     72  struct Packet {
     73    size_t header_size;
     74    size_t payload_size;
     75    uint16_t seq_num;
     76    bool marker_bit;
     77  };
     78  std::vector<Packet> protected_packets;
     79  protected_packets.push_back({15, 3, 41, 0});
     80  protected_packets.push_back({14, 1, 43, 0});
     81  protected_packets.push_back({19, 0, 48, 0});
     82  protected_packets.push_back({19, 0, 50, 0});
     83  protected_packets.push_back({14, 3, 51, 0});
     84  protected_packets.push_back({13, 8, 52, 0});
     85  protected_packets.push_back({19, 2, 53, 0});
     86  protected_packets.push_back({12, 3, 54, 0});
     87  protected_packets.push_back({21, 0, 55, 0});
     88  protected_packets.push_back({13, 3, 57, 1});
     89  FecProtectionParams params = {
     90      .fec_rate = 117, .max_fec_frames = 3, .fec_mask_type = kFecMaskBursty};
     91  ulpfec_generator_.SetProtectionParameters(params, params);
     92  for (Packet p : protected_packets) {
     93    RtpPacketToSend packet(nullptr);
     94    packet.SetMarker(p.marker_bit);
     95    packet.AllocateExtension(RTPExtensionType::kRtpExtensionMid,
     96                             p.header_size - packet.headers_size());
     97    packet.SetSequenceNumber(p.seq_num);
     98    packet.AllocatePayload(p.payload_size);
     99    ulpfec_generator_.AddPacketAndGenerateFec(packet);
    100 
    101    std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
    102        ulpfec_generator_.GetFecPackets();
    103    if (!p.marker_bit) {
    104      EXPECT_TRUE(fec_packets.empty());
    105    } else {
    106      EXPECT_FALSE(fec_packets.empty());
    107    }
    108  }
    109 }
    110 
    111 TEST_F(UlpfecGeneratorTest, OneFrameFec) {
    112  // The number of media packets (`kNumPackets`), number of frames (one for
    113  // this test), and the protection factor (|params->fec_rate|) are set to make
    114  // sure the conditions for generating FEC are satisfied. This means:
    115  // (1) protection factor is high enough so that actual overhead over 1 frame
    116  // of packets is within `kMaxExcessOverhead`, and (2) the total number of
    117  // media packets for 1 frame is at least `minimum_media_packets_fec_`.
    118  constexpr size_t kNumPackets = 4;
    119  FecProtectionParams params = {
    120      .fec_rate = 15, .max_fec_frames = 3, .fec_mask_type = kFecMaskRandom};
    121  packet_generator_.NewFrame(kNumPackets);
    122  // Expecting one FEC packet.
    123  ulpfec_generator_.SetProtectionParameters(params, params);
    124  uint32_t last_timestamp = 0;
    125  for (size_t i = 0; i < kNumPackets; ++i) {
    126    RtpPacketToSend rtp_packet =
    127        packet_generator_.NextPacket<RtpPacketToSend>(i, 10);
    128    ulpfec_generator_.AddPacketAndGenerateFec(rtp_packet);
    129    last_timestamp = rtp_packet.Timestamp();
    130  }
    131  std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
    132      ulpfec_generator_.GetFecPackets();
    133  EXPECT_EQ(fec_packets.size(), 1u);
    134  uint16_t seq_num = packet_generator_.NextPacketSeqNum();
    135  fec_packets[0]->SetSequenceNumber(seq_num);
    136  EXPECT_TRUE(ulpfec_generator_.GetFecPackets().empty());
    137 
    138  EXPECT_EQ(fec_packets[0]->headers_size(), kRtpHeaderSize);
    139 
    140  VerifyHeader(seq_num, last_timestamp, kRedPayloadType, kFecPayloadType, false,
    141               fec_packets[0]->Buffer());
    142 }
    143 
    144 TEST_F(UlpfecGeneratorTest, TwoFrameFec) {
    145  // The number of media packets/frame (`kNumPackets`), the number of frames
    146  // (`kNumFrames`), and the protection factor (|params->fec_rate|) are set to
    147  // make sure the conditions for generating FEC are satisfied. This means:
    148  // (1) protection factor is high enough so that actual overhead over
    149  // `kNumFrames` is within `kMaxExcessOverhead`, and (2) the total number of
    150  // media packets for `kNumFrames` frames is at least
    151  // `minimum_media_packets_fec_`.
    152  constexpr size_t kNumPackets = 2;
    153  constexpr size_t kNumFrames = 2;
    154 
    155  FecProtectionParams params = {
    156      .fec_rate = 15, .max_fec_frames = 3, .fec_mask_type = kFecMaskRandom};
    157  // Expecting one FEC packet.
    158  ulpfec_generator_.SetProtectionParameters(params, params);
    159  uint32_t last_timestamp = 0;
    160  for (size_t i = 0; i < kNumFrames; ++i) {
    161    packet_generator_.NewFrame(kNumPackets);
    162    for (size_t j = 0; j < kNumPackets; ++j) {
    163      RtpPacketToSend rtp_packet =
    164          packet_generator_.NextPacket<RtpPacketToSend>(i * kNumPackets + j,
    165                                                        10);
    166      ulpfec_generator_.AddPacketAndGenerateFec(rtp_packet);
    167      last_timestamp = rtp_packet.Timestamp();
    168    }
    169  }
    170  std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
    171      ulpfec_generator_.GetFecPackets();
    172  EXPECT_EQ(fec_packets.size(), 1u);
    173  const uint16_t seq_num = packet_generator_.NextPacketSeqNum();
    174  fec_packets[0]->SetSequenceNumber(seq_num);
    175  VerifyHeader(seq_num, last_timestamp, kRedPayloadType, kFecPayloadType, false,
    176               fec_packets[0]->Buffer());
    177 }
    178 
    179 TEST_F(UlpfecGeneratorTest, MixedMediaRtpHeaderLengths) {
    180  constexpr size_t kShortRtpHeaderLength = 12;
    181  constexpr size_t kLongRtpHeaderLength = 16;
    182 
    183  // Only one frame required to generate FEC.
    184  FecProtectionParams params = {
    185      .fec_rate = 127, .max_fec_frames = 1, .fec_mask_type = kFecMaskRandom};
    186  ulpfec_generator_.SetProtectionParameters(params, params);
    187 
    188  // Fill up internal buffer with media packets with short RTP header length.
    189  packet_generator_.NewFrame(kUlpfecMaxMediaPackets + 1);
    190  for (size_t i = 0; i < kUlpfecMaxMediaPackets; ++i) {
    191    RtpPacketToSend rtp_packet =
    192        packet_generator_.NextPacket<RtpPacketToSend>(i, 10);
    193    EXPECT_EQ(rtp_packet.headers_size(), kShortRtpHeaderLength);
    194    ulpfec_generator_.AddPacketAndGenerateFec(rtp_packet);
    195    EXPECT_TRUE(ulpfec_generator_.GetFecPackets().empty());
    196  }
    197 
    198  // Kick off FEC generation with media packet with long RTP header length.
    199  // Since the internal buffer is full, this packet will not be protected.
    200  RtpPacketToSend rtp_packet =
    201      packet_generator_.NextPacket<RtpPacketToSend>(kUlpfecMaxMediaPackets, 10);
    202  EXPECT_TRUE(rtp_packet.SetPayloadSize(0) != nullptr);
    203  const uint32_t csrcs[]{1};
    204  rtp_packet.SetCsrcs(csrcs);
    205 
    206  EXPECT_EQ(rtp_packet.headers_size(), kLongRtpHeaderLength);
    207 
    208  ulpfec_generator_.AddPacketAndGenerateFec(rtp_packet);
    209  std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
    210      ulpfec_generator_.GetFecPackets();
    211  EXPECT_FALSE(fec_packets.empty());
    212 
    213  // Ensure that the RED header is placed correctly, i.e. the correct
    214  // RTP header length was used in the RED packet creation.
    215  uint16_t seq_num = packet_generator_.NextPacketSeqNum();
    216  for (const auto& fec_packet : fec_packets) {
    217    fec_packet->SetSequenceNumber(seq_num++);
    218    EXPECT_EQ(kFecPayloadType, fec_packet->data()[kShortRtpHeaderLength]);
    219  }
    220 }
    221 
    222 TEST_F(UlpfecGeneratorTest, UpdatesProtectionParameters) {
    223  const FecProtectionParams kKeyFrameParams = {
    224      .fec_rate = 25, .max_fec_frames = 2, .fec_mask_type = kFecMaskRandom};
    225  const FecProtectionParams kDeltaFrameParams = {
    226      .fec_rate = 25, .max_fec_frames = 5, .fec_mask_type = kFecMaskRandom};
    227 
    228  ulpfec_generator_.SetProtectionParameters(kDeltaFrameParams, kKeyFrameParams);
    229 
    230  // No params applied yet.
    231  EXPECT_EQ(ulpfec_generator_.CurrentParams().max_fec_frames, 0);
    232 
    233  // Helper function to add a single-packet frame market as either key-frame
    234  // or delta-frame.
    235  auto add_frame = [&](bool is_keyframe) {
    236    packet_generator_.NewFrame(1);
    237    RtpPacketToSend rtp_packet =
    238        packet_generator_.NextPacket<RtpPacketToSend>(0, 10);
    239    rtp_packet.set_is_key_frame(is_keyframe);
    240    ulpfec_generator_.AddPacketAndGenerateFec(rtp_packet);
    241  };
    242 
    243  // Add key-frame, keyframe params should apply, no FEC generated yet.
    244  add_frame(true);
    245  EXPECT_EQ(ulpfec_generator_.CurrentParams().max_fec_frames, 2);
    246  EXPECT_TRUE(ulpfec_generator_.GetFecPackets().empty());
    247 
    248  // Add delta-frame, generated FEC packet. Params will not be updated until
    249  // next added packet though.
    250  add_frame(false);
    251  EXPECT_EQ(ulpfec_generator_.CurrentParams().max_fec_frames, 2);
    252  EXPECT_FALSE(ulpfec_generator_.GetFecPackets().empty());
    253 
    254  // Add delta-frame, now params get updated.
    255  add_frame(false);
    256  EXPECT_EQ(ulpfec_generator_.CurrentParams().max_fec_frames, 5);
    257  EXPECT_TRUE(ulpfec_generator_.GetFecPackets().empty());
    258 
    259  // Add yet another delta-frame.
    260  add_frame(false);
    261  EXPECT_EQ(ulpfec_generator_.CurrentParams().max_fec_frames, 5);
    262  EXPECT_TRUE(ulpfec_generator_.GetFecPackets().empty());
    263 
    264  // Add key-frame, params immediately switch to key-frame ones. The two
    265  // buffered frames plus the key-frame is protected and fec emitted,
    266  // even though the frame count is technically over the keyframe frame count
    267  // threshold.
    268  add_frame(true);
    269  EXPECT_EQ(ulpfec_generator_.CurrentParams().max_fec_frames, 2);
    270  EXPECT_FALSE(ulpfec_generator_.GetFecPackets().empty());
    271 }
    272 
    273 }  // namespace webrtc