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