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 <list>
14 #include <memory>
15 #include <utility>
16 #include <vector>
17
18 #include "modules/rtp_rtcp/source/byte_io.h"
19 #include "modules/rtp_rtcp/source/fec_test_helper.h"
20 #include "modules/rtp_rtcp/source/forward_error_correction.h"
21 #include "test/gtest.h"
22
23 namespace webrtc {
24
25 namespace {
26 using test::fec::AugmentedPacket;
27 using test::fec::AugmentedPacketGenerator;
28
29 constexpr int kFecPayloadType = 96;
30 constexpr int kRedPayloadType = 97;
31 constexpr uint32_t kMediaSsrc = 835424;
32 } // namespace
33
VerifyHeader(uint16_t seq_num,uint32_t timestamp,int red_payload_type,int fec_payload_type,bool marker_bit,const rtc::CopyOnWriteBuffer & data)34 void VerifyHeader(uint16_t seq_num,
35 uint32_t timestamp,
36 int red_payload_type,
37 int fec_payload_type,
38 bool marker_bit,
39 const rtc::CopyOnWriteBuffer& data) {
40 // Marker bit not set.
41 EXPECT_EQ(marker_bit ? 0x80 : 0, data[1] & 0x80);
42 EXPECT_EQ(red_payload_type, data[1] & 0x7F);
43 EXPECT_EQ(seq_num, (data[2] << 8) + data[3]);
44 uint32_t parsed_timestamp =
45 (data[4] << 24) + (data[5] << 16) + (data[6] << 8) + data[7];
46 EXPECT_EQ(timestamp, parsed_timestamp);
47 EXPECT_EQ(static_cast<uint8_t>(fec_payload_type), data[kRtpHeaderSize]);
48 }
49
50 class UlpfecGeneratorTest : public ::testing::Test {
51 protected:
UlpfecGeneratorTest()52 UlpfecGeneratorTest()
53 : fake_clock_(1),
54 ulpfec_generator_(kRedPayloadType, kFecPayloadType, &fake_clock_),
55 packet_generator_(kMediaSsrc) {}
56
57 SimulatedClock fake_clock_;
58 UlpfecGenerator ulpfec_generator_;
59 AugmentedPacketGenerator packet_generator_;
60 };
61
62 // Verifies bug found via fuzzing, where a gap in the packet sequence caused us
63 // to move past the end of the current FEC packet mask byte without moving to
64 // the next byte. That likely caused us to repeatedly read from the same byte,
65 // and if that byte didn't protect packets we would generate empty FEC.
TEST_F(UlpfecGeneratorTest,NoEmptyFecWithSeqNumGaps)66 TEST_F(UlpfecGeneratorTest, NoEmptyFecWithSeqNumGaps) {
67 struct Packet {
68 size_t header_size;
69 size_t payload_size;
70 uint16_t seq_num;
71 bool marker_bit;
72 };
73 std::vector<Packet> protected_packets;
74 protected_packets.push_back({15, 3, 41, 0});
75 protected_packets.push_back({14, 1, 43, 0});
76 protected_packets.push_back({19, 0, 48, 0});
77 protected_packets.push_back({19, 0, 50, 0});
78 protected_packets.push_back({14, 3, 51, 0});
79 protected_packets.push_back({13, 8, 52, 0});
80 protected_packets.push_back({19, 2, 53, 0});
81 protected_packets.push_back({12, 3, 54, 0});
82 protected_packets.push_back({21, 0, 55, 0});
83 protected_packets.push_back({13, 3, 57, 1});
84 FecProtectionParams params = {117, 3, kFecMaskBursty};
85 ulpfec_generator_.SetProtectionParameters(params, params);
86 for (Packet p : protected_packets) {
87 RtpPacketToSend packet(nullptr);
88 packet.SetMarker(p.marker_bit);
89 packet.AllocateExtension(RTPExtensionType::kRtpExtensionMid,
90 p.header_size - packet.headers_size());
91 packet.SetSequenceNumber(p.seq_num);
92 packet.AllocatePayload(p.payload_size);
93 ulpfec_generator_.AddPacketAndGenerateFec(packet);
94
95 std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
96 ulpfec_generator_.GetFecPackets();
97 if (!p.marker_bit) {
98 EXPECT_TRUE(fec_packets.empty());
99 } else {
100 EXPECT_FALSE(fec_packets.empty());
101 }
102 }
103 }
104
TEST_F(UlpfecGeneratorTest,OneFrameFec)105 TEST_F(UlpfecGeneratorTest, OneFrameFec) {
106 // The number of media packets (|kNumPackets|), number of frames (one for
107 // this test), and the protection factor (|params->fec_rate|) are set to make
108 // sure the conditions for generating FEC are satisfied. This means:
109 // (1) protection factor is high enough so that actual overhead over 1 frame
110 // of packets is within |kMaxExcessOverhead|, and (2) the total number of
111 // media packets for 1 frame is at least |minimum_media_packets_fec_|.
112 constexpr size_t kNumPackets = 4;
113 FecProtectionParams params = {15, 3, kFecMaskRandom};
114 packet_generator_.NewFrame(kNumPackets);
115 // Expecting one FEC packet.
116 ulpfec_generator_.SetProtectionParameters(params, params);
117 uint32_t last_timestamp = 0;
118 for (size_t i = 0; i < kNumPackets; ++i) {
119 std::unique_ptr<AugmentedPacket> packet =
120 packet_generator_.NextPacket(i, 10);
121 RtpPacketToSend rtp_packet(nullptr);
122 EXPECT_TRUE(rtp_packet.Parse(packet->data.data(), packet->data.size()));
123 ulpfec_generator_.AddPacketAndGenerateFec(rtp_packet);
124 last_timestamp = packet->header.timestamp;
125 }
126 std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
127 ulpfec_generator_.GetFecPackets();
128 EXPECT_EQ(fec_packets.size(), 1u);
129 uint16_t seq_num = packet_generator_.NextPacketSeqNum();
130 fec_packets[0]->SetSequenceNumber(seq_num);
131 EXPECT_TRUE(ulpfec_generator_.GetFecPackets().empty());
132
133 EXPECT_EQ(fec_packets[0]->headers_size(), kRtpHeaderSize);
134
135 VerifyHeader(seq_num, last_timestamp, kRedPayloadType, kFecPayloadType, false,
136 fec_packets[0]->Buffer());
137 }
138
TEST_F(UlpfecGeneratorTest,TwoFrameFec)139 TEST_F(UlpfecGeneratorTest, TwoFrameFec) {
140 // The number of media packets/frame (|kNumPackets|), the number of frames
141 // (|kNumFrames|), and the protection factor (|params->fec_rate|) are set to
142 // make sure the conditions for generating FEC are satisfied. This means:
143 // (1) protection factor is high enough so that actual overhead over
144 // |kNumFrames| is within |kMaxExcessOverhead|, and (2) the total number of
145 // media packets for |kNumFrames| frames is at least
146 // |minimum_media_packets_fec_|.
147 constexpr size_t kNumPackets = 2;
148 constexpr size_t kNumFrames = 2;
149
150 FecProtectionParams params = {15, 3, kFecMaskRandom};
151 // Expecting one FEC packet.
152 ulpfec_generator_.SetProtectionParameters(params, params);
153 uint32_t last_timestamp = 0;
154 for (size_t i = 0; i < kNumFrames; ++i) {
155 packet_generator_.NewFrame(kNumPackets);
156 for (size_t j = 0; j < kNumPackets; ++j) {
157 std::unique_ptr<AugmentedPacket> packet =
158 packet_generator_.NextPacket(i * kNumPackets + j, 10);
159 RtpPacketToSend rtp_packet(nullptr);
160 EXPECT_TRUE(rtp_packet.Parse(packet->data.data(), packet->data.size()));
161 ulpfec_generator_.AddPacketAndGenerateFec(rtp_packet);
162 last_timestamp = packet->header.timestamp;
163 }
164 }
165 std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
166 ulpfec_generator_.GetFecPackets();
167 EXPECT_EQ(fec_packets.size(), 1u);
168 const uint16_t seq_num = packet_generator_.NextPacketSeqNum();
169 fec_packets[0]->SetSequenceNumber(seq_num);
170 VerifyHeader(seq_num, last_timestamp, kRedPayloadType, kFecPayloadType, false,
171 fec_packets[0]->Buffer());
172 }
173
TEST_F(UlpfecGeneratorTest,MixedMediaRtpHeaderLengths)174 TEST_F(UlpfecGeneratorTest, MixedMediaRtpHeaderLengths) {
175 constexpr size_t kShortRtpHeaderLength = 12;
176 constexpr size_t kLongRtpHeaderLength = 16;
177
178 // Only one frame required to generate FEC.
179 FecProtectionParams params = {127, 1, kFecMaskRandom};
180 ulpfec_generator_.SetProtectionParameters(params, params);
181
182 // Fill up internal buffer with media packets with short RTP header length.
183 packet_generator_.NewFrame(kUlpfecMaxMediaPackets + 1);
184 for (size_t i = 0; i < kUlpfecMaxMediaPackets; ++i) {
185 std::unique_ptr<AugmentedPacket> packet =
186 packet_generator_.NextPacket(i, 10);
187 RtpPacketToSend rtp_packet(nullptr);
188 EXPECT_TRUE(rtp_packet.Parse(packet->data.data(), packet->data.size()));
189 EXPECT_EQ(rtp_packet.headers_size(), kShortRtpHeaderLength);
190 ulpfec_generator_.AddPacketAndGenerateFec(rtp_packet);
191 EXPECT_TRUE(ulpfec_generator_.GetFecPackets().empty());
192 }
193
194 // Kick off FEC generation with media packet with long RTP header length.
195 // Since the internal buffer is full, this packet will not be protected.
196 std::unique_ptr<AugmentedPacket> packet =
197 packet_generator_.NextPacket(kUlpfecMaxMediaPackets, 10);
198 RtpPacketToSend rtp_packet(nullptr);
199 EXPECT_TRUE(rtp_packet.Parse(packet->data.data(), packet->data.size()));
200 EXPECT_TRUE(rtp_packet.SetPayloadSize(0) != nullptr);
201 const uint32_t csrcs[]{1};
202 rtp_packet.SetCsrcs(csrcs);
203
204 EXPECT_EQ(rtp_packet.headers_size(), kLongRtpHeaderLength);
205
206 ulpfec_generator_.AddPacketAndGenerateFec(rtp_packet);
207 std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
208 ulpfec_generator_.GetFecPackets();
209 EXPECT_FALSE(fec_packets.empty());
210
211 // Ensure that the RED header is placed correctly, i.e. the correct
212 // RTP header length was used in the RED packet creation.
213 uint16_t seq_num = packet_generator_.NextPacketSeqNum();
214 for (const auto& fec_packet : fec_packets) {
215 fec_packet->SetSequenceNumber(seq_num++);
216 EXPECT_EQ(kFecPayloadType, fec_packet->data()[kShortRtpHeaderLength]);
217 }
218 }
219
220 } // namespace webrtc
221