blob: 53d363de679f42259765fc6f4d4654db027b75ad [file] [log] [blame]
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +00001/*
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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "modules/rtp_rtcp/include/ulpfec_receiver.h"
12
phoglund@webrtc.org9919ad52013-05-16 15:06:28 +000013#include <string.h>
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000014
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000015#include <list>
kwiberg84be5112016-04-27 01:19:58 -070016#include <memory>
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000017
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h"
Yves Gerey665174f2018-06-19 15:03:05 +020019#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "modules/rtp_rtcp/source/byte_io.h"
21#include "modules/rtp_rtcp/source/fec_test_helper.h"
22#include "modules/rtp_rtcp/source/forward_error_correction.h"
Artem Titov68173942020-03-11 12:59:07 +010023#include "modules/rtp_rtcp/source/rtp_packet_received.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "test/gmock.h"
25#include "test/gtest.h"
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000026
brandtrece4aba2016-09-20 23:16:28 -070027namespace webrtc {
28
29namespace {
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000030using ::testing::_;
31using ::testing::Args;
32using ::testing::ElementsAreArray;
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000033
brandtr0aabdac2016-10-03 06:36:43 -070034using test::fec::AugmentedPacket;
brandtr71ca7472016-10-03 05:11:26 -070035using Packet = ForwardErrorCorrection::Packet;
brandtr71ca7472016-10-03 05:11:26 -070036using test::fec::UlpfecPacketGenerator;
37
38constexpr int kFecPayloadType = 96;
brandtr0aabdac2016-10-03 06:36:43 -070039constexpr uint32_t kMediaSsrc = 835424;
nisse30e89312017-05-29 08:16:37 -070040
41class NullRecoveredPacketReceiver : public RecoveredPacketReceiver {
42 public:
43 void OnRecoveredPacket(const uint8_t* packet, size_t length) override {}
44};
45
brandtr71ca7472016-10-03 05:11:26 -070046} // namespace
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000047
brandtrd55c3f62016-10-31 04:51:33 -070048class UlpfecReceiverTest : public ::testing::Test {
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000049 protected:
brandtrd55c3f62016-10-31 04:51:33 -070050 UlpfecReceiverTest()
brandtrd726a3f2017-06-29 02:45:35 -070051 : fec_(ForwardErrorCorrection::CreateUlpfec(kMediaSsrc)),
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +020052 receiver_fec_(UlpfecReceiver::Create(kMediaSsrc,
53 &recovered_packet_receiver_,
54 {})),
brandtr0aabdac2016-10-03 06:36:43 -070055 packet_generator_(kMediaSsrc) {}
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000056
brandtra2ece732016-10-04 00:00:06 -070057 // Generates |num_fec_packets| FEC packets, given |media_packets|.
brandtr71ca7472016-10-03 05:11:26 -070058 void EncodeFec(const ForwardErrorCorrection::PacketList& media_packets,
59 size_t num_fec_packets,
brandtra2ece732016-10-04 00:00:06 -070060 std::list<ForwardErrorCorrection::Packet*>* fec_packets);
stefan@webrtc.org7adab092012-02-09 12:34:52 +000061
brandtra2ece732016-10-04 00:00:06 -070062 // Generates |num_media_packets| corresponding to a single frame.
63 void PacketizeFrame(size_t num_media_packets,
64 size_t frame_offset,
65 std::list<AugmentedPacket*>* augmented_packets,
66 ForwardErrorCorrection::PacketList* packets);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000067
brandtra2ece732016-10-04 00:00:06 -070068 // Build a media packet using |packet_generator_| and add it
69 // to the receiver.
Artem Titov68173942020-03-11 12:59:07 +010070 void BuildAndAddRedMediaPacket(AugmentedPacket* packet,
71 bool is_recovered = false);
brandtra2ece732016-10-04 00:00:06 -070072
73 // Build a FEC packet using |packet_generator_| and add it
74 // to the receiver.
75 void BuildAndAddRedFecPacket(Packet* packet);
76
nisse30e89312017-05-29 08:16:37 -070077 // Ensure that |recovered_packet_receiver_| will be called correctly
brandtra2ece732016-10-04 00:00:06 -070078 // and that the recovered packet will be identical to the lost packet.
brandtr0aabdac2016-10-03 06:36:43 -070079 void VerifyReconstructedMediaPacket(const AugmentedPacket& packet,
brandtra2ece732016-10-04 00:00:06 -070080 size_t times);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000081
pbos2bad88d2015-07-06 03:09:08 -070082 void InjectGarbagePacketLength(size_t fec_garbage_offset);
brandtra2ece732016-10-04 00:00:06 -070083
pbos70d5c472015-06-29 07:22:04 -070084 static void SurvivesMaliciousPacket(const uint8_t* data,
85 size_t length,
86 uint8_t ulpfec_payload_type);
87
nisse30e89312017-05-29 08:16:37 -070088 MockRecoveredPacketReceiver recovered_packet_receiver_;
Rasmus Brandt78db1582016-09-21 09:19:34 +020089 std::unique_ptr<ForwardErrorCorrection> fec_;
brandtrd55c3f62016-10-31 04:51:33 -070090 std::unique_ptr<UlpfecReceiver> receiver_fec_;
brandtr0aabdac2016-10-03 06:36:43 -070091 UlpfecPacketGenerator packet_generator_;
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000092};
93
brandtrd55c3f62016-10-31 04:51:33 -070094void UlpfecReceiverTest::EncodeFec(
brandtra2ece732016-10-04 00:00:06 -070095 const ForwardErrorCorrection::PacketList& media_packets,
96 size_t num_fec_packets,
97 std::list<ForwardErrorCorrection::Packet*>* fec_packets) {
98 const uint8_t protection_factor =
99 num_fec_packets * 255 / media_packets.size();
100 // Unequal protection is turned off, and the number of important
101 // packets is thus irrelevant.
102 constexpr int kNumImportantPackets = 0;
103 constexpr bool kUseUnequalProtection = false;
104 constexpr FecMaskType kFecMaskType = kFecMaskBursty;
105 EXPECT_EQ(
106 0, fec_->EncodeFec(media_packets, protection_factor, kNumImportantPackets,
107 kUseUnequalProtection, kFecMaskType, fec_packets));
108 ASSERT_EQ(num_fec_packets, fec_packets->size());
109}
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000110
brandtrd55c3f62016-10-31 04:51:33 -0700111void UlpfecReceiverTest::PacketizeFrame(
brandtra2ece732016-10-04 00:00:06 -0700112 size_t num_media_packets,
113 size_t frame_offset,
114 std::list<AugmentedPacket*>* augmented_packets,
115 ForwardErrorCorrection::PacketList* packets) {
116 packet_generator_.NewFrame(num_media_packets);
117 for (size_t i = 0; i < num_media_packets; ++i) {
118 std::unique_ptr<AugmentedPacket> next_packet(
119 packet_generator_.NextPacket(frame_offset + i, kRtpHeaderSize + 10));
120 augmented_packets->push_back(next_packet.get());
121 packets->push_back(std::move(next_packet));
122 }
123}
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000124
Artem Titov68173942020-03-11 12:59:07 +0100125void UlpfecReceiverTest::BuildAndAddRedMediaPacket(AugmentedPacket* packet,
126 bool is_recovered) {
127 RtpPacketReceived red_packet =
128 packet_generator_.BuildMediaRedPacket(*packet, is_recovered);
Danil Chapovalov04fd2152019-09-20 11:40:12 +0200129 EXPECT_TRUE(receiver_fec_->AddReceivedRedPacket(red_packet, kFecPayloadType));
brandtra2ece732016-10-04 00:00:06 -0700130}
131
brandtrd55c3f62016-10-31 04:51:33 -0700132void UlpfecReceiverTest::BuildAndAddRedFecPacket(Packet* packet) {
Artem Titov68173942020-03-11 12:59:07 +0100133 RtpPacketReceived red_packet =
134 packet_generator_.BuildUlpfecRedPacket(*packet);
Danil Chapovalov04fd2152019-09-20 11:40:12 +0200135 EXPECT_TRUE(receiver_fec_->AddReceivedRedPacket(red_packet, kFecPayloadType));
brandtra2ece732016-10-04 00:00:06 -0700136}
137
brandtrd55c3f62016-10-31 04:51:33 -0700138void UlpfecReceiverTest::VerifyReconstructedMediaPacket(
brandtra2ece732016-10-04 00:00:06 -0700139 const AugmentedPacket& packet,
140 size_t times) {
141 // Verify that the content of the reconstructed packet is equal to the
142 // content of |packet|, and that the same content is received |times| number
143 // of times in a row.
Ilya Nikolaevskiya5d952f2019-09-03 11:07:37 +0200144 EXPECT_CALL(recovered_packet_receiver_,
145 OnRecoveredPacket(_, packet.data.size()))
146 .With(
147 Args<0, 1>(ElementsAreArray(packet.data.cdata(), packet.data.size())))
nisse30e89312017-05-29 08:16:37 -0700148 .Times(times);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000149}
150
brandtrd55c3f62016-10-31 04:51:33 -0700151void UlpfecReceiverTest::InjectGarbagePacketLength(size_t fec_garbage_offset) {
nisse30e89312017-05-29 08:16:37 -0700152 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _));
pbos2bad88d2015-07-06 03:09:08 -0700153
brandtr71ca7472016-10-03 05:11:26 -0700154 const size_t kNumFecPackets = 1;
brandtr0aabdac2016-10-03 06:36:43 -0700155 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200156 ForwardErrorCorrection::PacketList media_packets;
brandtra2ece732016-10-04 00:00:06 -0700157 PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
brandtr35c480c2016-08-09 01:23:23 -0700158 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700159 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
pbos2bad88d2015-07-06 03:09:08 -0700160 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalove15dc582021-01-07 15:24:05 +0100161 fec_packets.front()->data.MutableData() + fec_garbage_offset, 0x4711);
pbos2bad88d2015-07-06 03:09:08 -0700162
163 // Inject first media packet, then first FEC packet, skipping the second media
164 // packet to cause a recovery from the FEC packet.
brandtr0aabdac2016-10-03 06:36:43 -0700165 BuildAndAddRedMediaPacket(augmented_media_packets.front());
pbos2bad88d2015-07-06 03:09:08 -0700166 BuildAndAddRedFecPacket(fec_packets.front());
167 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
168
169 FecPacketCounter counter = receiver_fec_->GetPacketCounter();
brandtr71ca7472016-10-03 05:11:26 -0700170 EXPECT_EQ(2U, counter.num_packets);
171 EXPECT_EQ(1U, counter.num_fec_packets);
172 EXPECT_EQ(0U, counter.num_recovered_packets);
pbos2bad88d2015-07-06 03:09:08 -0700173}
174
brandtrd55c3f62016-10-31 04:51:33 -0700175void UlpfecReceiverTest::SurvivesMaliciousPacket(const uint8_t* data,
176 size_t length,
177 uint8_t ulpfec_payload_type) {
nisse30e89312017-05-29 08:16:37 -0700178 NullRecoveredPacketReceiver null_callback;
brandtrd55c3f62016-10-31 04:51:33 -0700179 std::unique_ptr<UlpfecReceiver> receiver_fec(
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +0200180 UlpfecReceiver::Create(kMediaSsrc, &null_callback, {}));
brandtra2ece732016-10-04 00:00:06 -0700181
Artem Titov68173942020-03-11 12:59:07 +0100182 RtpPacketReceived rtp_packet;
Danil Chapovalov04fd2152019-09-20 11:40:12 +0200183 ASSERT_TRUE(rtp_packet.Parse(data, length));
184 receiver_fec->AddReceivedRedPacket(rtp_packet, ulpfec_payload_type);
brandtra2ece732016-10-04 00:00:06 -0700185}
186
brandtrd55c3f62016-10-31 04:51:33 -0700187TEST_F(UlpfecReceiverTest, TwoMediaOneFec) {
brandtra2ece732016-10-04 00:00:06 -0700188 constexpr size_t kNumFecPackets = 1u;
189 std::list<AugmentedPacket*> augmented_media_packets;
190 ForwardErrorCorrection::PacketList media_packets;
191 PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
192 std::list<ForwardErrorCorrection::Packet*> fec_packets;
193 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
194
asapersson0c43f772016-11-30 01:42:26 -0800195 FecPacketCounter counter = receiver_fec_->GetPacketCounter();
196 EXPECT_EQ(0u, counter.num_packets);
197 EXPECT_EQ(-1, counter.first_packet_time_ms);
198
brandtra2ece732016-10-04 00:00:06 -0700199 // Recovery
200 auto it = augmented_media_packets.begin();
201 BuildAndAddRedMediaPacket(*it);
202 VerifyReconstructedMediaPacket(**it, 1);
203 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
asapersson0c43f772016-11-30 01:42:26 -0800204 counter = receiver_fec_->GetPacketCounter();
205 EXPECT_EQ(1u, counter.num_packets);
206 EXPECT_EQ(0u, counter.num_fec_packets);
207 EXPECT_EQ(0u, counter.num_recovered_packets);
208 const int64_t first_packet_time_ms = counter.first_packet_time_ms;
209 EXPECT_NE(-1, first_packet_time_ms);
210
brandtra2ece732016-10-04 00:00:06 -0700211 // Drop one media packet.
212 auto fec_it = fec_packets.begin();
213 BuildAndAddRedFecPacket(*fec_it);
214 ++it;
215 VerifyReconstructedMediaPacket(**it, 1);
216 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
217
asapersson0c43f772016-11-30 01:42:26 -0800218 counter = receiver_fec_->GetPacketCounter();
brandtra2ece732016-10-04 00:00:06 -0700219 EXPECT_EQ(2u, counter.num_packets);
220 EXPECT_EQ(1u, counter.num_fec_packets);
221 EXPECT_EQ(1u, counter.num_recovered_packets);
asapersson0c43f772016-11-30 01:42:26 -0800222 EXPECT_EQ(first_packet_time_ms, counter.first_packet_time_ms);
brandtra2ece732016-10-04 00:00:06 -0700223}
224
Artem Titov68173942020-03-11 12:59:07 +0100225TEST_F(UlpfecReceiverTest, TwoMediaOneFecNotUsesRecoveredPackets) {
226 constexpr size_t kNumFecPackets = 1u;
227 std::list<AugmentedPacket*> augmented_media_packets;
228 ForwardErrorCorrection::PacketList media_packets;
229 PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
230 std::list<ForwardErrorCorrection::Packet*> fec_packets;
231 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
232
233 FecPacketCounter counter = receiver_fec_->GetPacketCounter();
234 EXPECT_EQ(0u, counter.num_packets);
235 EXPECT_EQ(-1, counter.first_packet_time_ms);
236
237 // Recovery
238 auto it = augmented_media_packets.begin();
239 BuildAndAddRedMediaPacket(*it, /*is_recovered=*/true);
240 VerifyReconstructedMediaPacket(**it, 1);
241 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
242 counter = receiver_fec_->GetPacketCounter();
243 EXPECT_EQ(1u, counter.num_packets);
244 EXPECT_EQ(0u, counter.num_fec_packets);
245 EXPECT_EQ(0u, counter.num_recovered_packets);
246 const int64_t first_packet_time_ms = counter.first_packet_time_ms;
247 EXPECT_NE(-1, first_packet_time_ms);
248
249 // Drop one media packet.
250 auto fec_it = fec_packets.begin();
251 BuildAndAddRedFecPacket(*fec_it);
252 ++it;
253 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
254
255 counter = receiver_fec_->GetPacketCounter();
256 EXPECT_EQ(2u, counter.num_packets);
257 EXPECT_EQ(1u, counter.num_fec_packets);
258 EXPECT_EQ(0u, counter.num_recovered_packets);
259 EXPECT_EQ(first_packet_time_ms, counter.first_packet_time_ms);
260}
261
brandtrd55c3f62016-10-31 04:51:33 -0700262TEST_F(UlpfecReceiverTest, InjectGarbageFecHeaderLengthRecovery) {
pbos2bad88d2015-07-06 03:09:08 -0700263 // Byte offset 8 is the 'length recovery' field of the FEC header.
264 InjectGarbagePacketLength(8);
265}
266
brandtrd55c3f62016-10-31 04:51:33 -0700267TEST_F(UlpfecReceiverTest, InjectGarbageFecLevelHeaderProtectionLength) {
pbos2bad88d2015-07-06 03:09:08 -0700268 // Byte offset 10 is the 'protection length' field in the first FEC level
269 // header.
270 InjectGarbagePacketLength(10);
271}
272
brandtrd55c3f62016-10-31 04:51:33 -0700273TEST_F(UlpfecReceiverTest, TwoMediaTwoFec) {
brandtr71ca7472016-10-03 05:11:26 -0700274 const size_t kNumFecPackets = 2;
brandtr0aabdac2016-10-03 06:36:43 -0700275 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200276 ForwardErrorCorrection::PacketList media_packets;
brandtra2ece732016-10-04 00:00:06 -0700277 PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
brandtr35c480c2016-08-09 01:23:23 -0700278 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700279 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000280
281 // Recovery
282 // Drop both media packets.
brandtr0aabdac2016-10-03 06:36:43 -0700283 auto it = augmented_media_packets.begin();
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200284 auto fec_it = fec_packets.begin();
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000285 BuildAndAddRedFecPacket(*fec_it);
brandtr71ca7472016-10-03 05:11:26 -0700286 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000287 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000288 ++fec_it;
289 BuildAndAddRedFecPacket(*fec_it);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000290 ++it;
brandtr71ca7472016-10-03 05:11:26 -0700291 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000292 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000293}
294
brandtrd55c3f62016-10-31 04:51:33 -0700295TEST_F(UlpfecReceiverTest, TwoFramesOneFec) {
brandtr71ca7472016-10-03 05:11:26 -0700296 const size_t kNumFecPackets = 1;
brandtr0aabdac2016-10-03 06:36:43 -0700297 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200298 ForwardErrorCorrection::PacketList media_packets;
brandtra2ece732016-10-04 00:00:06 -0700299 PacketizeFrame(1, 0, &augmented_media_packets, &media_packets);
300 PacketizeFrame(1, 1, &augmented_media_packets, &media_packets);
brandtr35c480c2016-08-09 01:23:23 -0700301 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700302 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000303
304 // Recovery
brandtr0aabdac2016-10-03 06:36:43 -0700305 auto it = augmented_media_packets.begin();
306 BuildAndAddRedMediaPacket(augmented_media_packets.front());
brandtr71ca7472016-10-03 05:11:26 -0700307 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000308 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000309 // Drop one media packet.
310 BuildAndAddRedFecPacket(fec_packets.front());
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000311 ++it;
brandtr71ca7472016-10-03 05:11:26 -0700312 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000313 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000314}
315
brandtrd55c3f62016-10-31 04:51:33 -0700316TEST_F(UlpfecReceiverTest, OneCompleteOneUnrecoverableFrame) {
brandtr71ca7472016-10-03 05:11:26 -0700317 const size_t kNumFecPackets = 1;
brandtr0aabdac2016-10-03 06:36:43 -0700318 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200319 ForwardErrorCorrection::PacketList media_packets;
brandtra2ece732016-10-04 00:00:06 -0700320 PacketizeFrame(1, 0, &augmented_media_packets, &media_packets);
321 PacketizeFrame(2, 1, &augmented_media_packets, &media_packets);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000322
brandtr35c480c2016-08-09 01:23:23 -0700323 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700324 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000325
326 // Recovery
brandtr0aabdac2016-10-03 06:36:43 -0700327 auto it = augmented_media_packets.begin();
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000328 BuildAndAddRedMediaPacket(*it); // First frame: one packet.
brandtr71ca7472016-10-03 05:11:26 -0700329 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000330 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000331 ++it;
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000332 BuildAndAddRedMediaPacket(*it); // First packet of second frame.
brandtr71ca7472016-10-03 05:11:26 -0700333 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000334 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000335}
336
brandtrd55c3f62016-10-31 04:51:33 -0700337TEST_F(UlpfecReceiverTest, MaxFramesOneFec) {
brandtr71ca7472016-10-03 05:11:26 -0700338 const size_t kNumFecPackets = 1;
339 const size_t kNumMediaPackets = 48;
brandtr0aabdac2016-10-03 06:36:43 -0700340 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200341 ForwardErrorCorrection::PacketList media_packets;
brandtr71ca7472016-10-03 05:11:26 -0700342 for (size_t i = 0; i < kNumMediaPackets; ++i) {
brandtra2ece732016-10-04 00:00:06 -0700343 PacketizeFrame(1, i, &augmented_media_packets, &media_packets);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000344 }
brandtr35c480c2016-08-09 01:23:23 -0700345 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700346 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000347
348 // Recovery
brandtr0aabdac2016-10-03 06:36:43 -0700349 auto it = augmented_media_packets.begin();
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000350 ++it; // Drop first packet.
brandtr0aabdac2016-10-03 06:36:43 -0700351 for (; it != augmented_media_packets.end(); ++it) {
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000352 BuildAndAddRedMediaPacket(*it);
brandtr71ca7472016-10-03 05:11:26 -0700353 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000354 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000355 }
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000356 BuildAndAddRedFecPacket(fec_packets.front());
brandtr0aabdac2016-10-03 06:36:43 -0700357 it = augmented_media_packets.begin();
brandtr71ca7472016-10-03 05:11:26 -0700358 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000359 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000360}
361
brandtrd55c3f62016-10-31 04:51:33 -0700362TEST_F(UlpfecReceiverTest, TooManyFrames) {
brandtr71ca7472016-10-03 05:11:26 -0700363 const size_t kNumFecPackets = 1;
364 const size_t kNumMediaPackets = 49;
brandtr0aabdac2016-10-03 06:36:43 -0700365 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200366 ForwardErrorCorrection::PacketList media_packets;
brandtr71ca7472016-10-03 05:11:26 -0700367 for (size_t i = 0; i < kNumMediaPackets; ++i) {
brandtra2ece732016-10-04 00:00:06 -0700368 PacketizeFrame(1, i, &augmented_media_packets, &media_packets);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000369 }
brandtr35c480c2016-08-09 01:23:23 -0700370 std::list<ForwardErrorCorrection::Packet*> fec_packets;
Rasmus Brandt78db1582016-09-21 09:19:34 +0200371 EXPECT_EQ(-1, fec_->EncodeFec(media_packets,
372 kNumFecPackets * 255 / kNumMediaPackets, 0,
373 false, kFecMaskBursty, &fec_packets));
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000374}
375
brandtrd55c3f62016-10-31 04:51:33 -0700376TEST_F(UlpfecReceiverTest, PacketNotDroppedTooEarly) {
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000377 // 1 frame with 2 media packets and one FEC packet. One media packet missing.
378 // Delay the FEC packet.
brandtr71ca7472016-10-03 05:11:26 -0700379 Packet* delayed_fec = nullptr;
380 const size_t kNumFecPacketsBatch1 = 1;
381 const size_t kNumMediaPacketsBatch1 = 2;
brandtr0aabdac2016-10-03 06:36:43 -0700382 std::list<AugmentedPacket*> augmented_media_packets_batch1;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200383 ForwardErrorCorrection::PacketList media_packets_batch1;
brandtra2ece732016-10-04 00:00:06 -0700384 PacketizeFrame(kNumMediaPacketsBatch1, 0, &augmented_media_packets_batch1,
385 &media_packets_batch1);
brandtr35c480c2016-08-09 01:23:23 -0700386 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700387 EncodeFec(media_packets_batch1, kNumFecPacketsBatch1, &fec_packets);
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000388
brandtr0aabdac2016-10-03 06:36:43 -0700389 BuildAndAddRedMediaPacket(augmented_media_packets_batch1.front());
Yves Gerey665174f2018-06-19 15:03:05 +0200390 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000391 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000392 delayed_fec = fec_packets.front();
393
394 // Fill the FEC decoder. No packets should be dropped.
Harsh Maniar085eceb2021-04-21 01:21:53 -0700395 const size_t kNumMediaPacketsBatch2 = 191;
brandtr0aabdac2016-10-03 06:36:43 -0700396 std::list<AugmentedPacket*> augmented_media_packets_batch2;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200397 ForwardErrorCorrection::PacketList media_packets_batch2;
brandtr71ca7472016-10-03 05:11:26 -0700398 for (size_t i = 0; i < kNumMediaPacketsBatch2; ++i) {
brandtra2ece732016-10-04 00:00:06 -0700399 PacketizeFrame(1, i, &augmented_media_packets_batch2,
400 &media_packets_batch2);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000401 }
brandtr0aabdac2016-10-03 06:36:43 -0700402 for (auto it = augmented_media_packets_batch2.begin();
403 it != augmented_media_packets_batch2.end(); ++it) {
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000404 BuildAndAddRedMediaPacket(*it);
Yves Gerey665174f2018-06-19 15:03:05 +0200405 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000406 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000407 }
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000408
409 // Add the delayed FEC packet. One packet should be reconstructed.
410 BuildAndAddRedFecPacket(delayed_fec);
Yves Gerey665174f2018-06-19 15:03:05 +0200411 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000412 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000413}
414
brandtrd55c3f62016-10-31 04:51:33 -0700415TEST_F(UlpfecReceiverTest, PacketDroppedWhenTooOld) {
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000416 // 1 frame with 2 media packets and one FEC packet. One media packet missing.
417 // Delay the FEC packet.
brandtr71ca7472016-10-03 05:11:26 -0700418 Packet* delayed_fec = nullptr;
419 const size_t kNumFecPacketsBatch1 = 1;
420 const size_t kNumMediaPacketsBatch1 = 2;
brandtr0aabdac2016-10-03 06:36:43 -0700421 std::list<AugmentedPacket*> augmented_media_packets_batch1;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200422 ForwardErrorCorrection::PacketList media_packets_batch1;
brandtra2ece732016-10-04 00:00:06 -0700423 PacketizeFrame(kNumMediaPacketsBatch1, 0, &augmented_media_packets_batch1,
424 &media_packets_batch1);
brandtr35c480c2016-08-09 01:23:23 -0700425 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700426 EncodeFec(media_packets_batch1, kNumFecPacketsBatch1, &fec_packets);
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000427
brandtr0aabdac2016-10-03 06:36:43 -0700428 BuildAndAddRedMediaPacket(augmented_media_packets_batch1.front());
Yves Gerey665174f2018-06-19 15:03:05 +0200429 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000430 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000431 delayed_fec = fec_packets.front();
432
433 // Fill the FEC decoder and force the last packet to be dropped.
Harsh Maniar085eceb2021-04-21 01:21:53 -0700434 const size_t kNumMediaPacketsBatch2 = 192;
brandtr0aabdac2016-10-03 06:36:43 -0700435 std::list<AugmentedPacket*> augmented_media_packets_batch2;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200436 ForwardErrorCorrection::PacketList media_packets_batch2;
brandtr71ca7472016-10-03 05:11:26 -0700437 for (size_t i = 0; i < kNumMediaPacketsBatch2; ++i) {
brandtra2ece732016-10-04 00:00:06 -0700438 PacketizeFrame(1, i, &augmented_media_packets_batch2,
439 &media_packets_batch2);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000440 }
brandtr0aabdac2016-10-03 06:36:43 -0700441 for (auto it = augmented_media_packets_batch2.begin();
442 it != augmented_media_packets_batch2.end(); ++it) {
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000443 BuildAndAddRedMediaPacket(*it);
Yves Gerey665174f2018-06-19 15:03:05 +0200444 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000445 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000446 }
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000447
448 // Add the delayed FEC packet. No packet should be reconstructed since the
449 // first media packet of that frame has been dropped due to being too old.
450 BuildAndAddRedFecPacket(delayed_fec);
nisse30e89312017-05-29 08:16:37 -0700451 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(0);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000452 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000453}
454
brandtrd55c3f62016-10-31 04:51:33 -0700455TEST_F(UlpfecReceiverTest, OldFecPacketDropped) {
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000456 // 49 frames with 2 media packets and one FEC packet. All media packets
457 // missing.
brandtr71ca7472016-10-03 05:11:26 -0700458 const size_t kNumMediaPackets = 49 * 2;
brandtr0aabdac2016-10-03 06:36:43 -0700459 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200460 ForwardErrorCorrection::PacketList media_packets;
brandtr71ca7472016-10-03 05:11:26 -0700461 for (size_t i = 0; i < kNumMediaPackets / 2; ++i) {
brandtr0aabdac2016-10-03 06:36:43 -0700462 std::list<AugmentedPacket*> frame_augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200463 ForwardErrorCorrection::PacketList frame_media_packets;
brandtr35c480c2016-08-09 01:23:23 -0700464 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtra2ece732016-10-04 00:00:06 -0700465 PacketizeFrame(2, 0, &frame_augmented_media_packets, &frame_media_packets);
brandtr71ca7472016-10-03 05:11:26 -0700466 EncodeFec(frame_media_packets, 1, &fec_packets);
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200467 for (auto it = fec_packets.begin(); it != fec_packets.end(); ++it) {
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000468 // Only FEC packets inserted. No packets recoverable at this time.
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000469 BuildAndAddRedFecPacket(*it);
nisse30e89312017-05-29 08:16:37 -0700470 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(0);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000471 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000472 }
brandtr35c480c2016-08-09 01:23:23 -0700473 // Move unique_ptr's to media_packets for lifetime management.
474 media_packets.insert(media_packets.end(),
475 std::make_move_iterator(frame_media_packets.begin()),
476 std::make_move_iterator(frame_media_packets.end()));
brandtr0aabdac2016-10-03 06:36:43 -0700477 augmented_media_packets.insert(augmented_media_packets.end(),
478 frame_augmented_media_packets.begin(),
479 frame_augmented_media_packets.end());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000480 }
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000481 // Insert the oldest media packet. The corresponding FEC packet is too old
brandtr71ca7472016-10-03 05:11:26 -0700482 // and should have been dropped. Only the media packet we inserted will be
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000483 // returned.
brandtr0aabdac2016-10-03 06:36:43 -0700484 BuildAndAddRedMediaPacket(augmented_media_packets.front());
Yves Gerey665174f2018-06-19 15:03:05 +0200485 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000486 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000487}
488
brandtrd55c3f62016-10-31 04:51:33 -0700489TEST_F(UlpfecReceiverTest, TruncatedPacketWithFBitSet) {
490 const uint8_t kTruncatedPacket[] = {0x80, 0x2a, 0x68, 0x71, 0x29, 0xa1, 0x27,
491 0x3a, 0x29, 0x12, 0x2a, 0x98, 0xe0, 0x29};
pbos70d5c472015-06-29 07:22:04 -0700492
493 SurvivesMaliciousPacket(kTruncatedPacket, sizeof(kTruncatedPacket), 100);
494}
495
brandtrd55c3f62016-10-31 04:51:33 -0700496TEST_F(UlpfecReceiverTest,
497 TruncatedPacketWithFBitSetEndingAfterFirstRedHeader) {
498 const uint8_t kPacket[] = {
499 0x89, 0x27, 0x3a, 0x83, 0x27, 0x3a, 0x3a, 0xf3, 0x67, 0xbe, 0x2a,
500 0xa9, 0x27, 0x54, 0x3a, 0x3a, 0x2a, 0x67, 0x3a, 0xf3, 0x67, 0xbe,
501 0x2a, 0x27, 0xe6, 0xf6, 0x03, 0x3e, 0x29, 0x27, 0x21, 0x27, 0x2a,
502 0x29, 0x21, 0x4b, 0x29, 0x3a, 0x28, 0x29, 0xbf, 0x29, 0x2a, 0x26,
503 0x29, 0xae, 0x27, 0xa6, 0xf6, 0x00, 0x03, 0x3e};
pbos2e43b262015-06-30 01:32:40 -0700504 SurvivesMaliciousPacket(kPacket, sizeof(kPacket), 100);
505}
506
brandtrd55c3f62016-10-31 04:51:33 -0700507TEST_F(UlpfecReceiverTest, TruncatedPacketWithoutDataPastFirstBlock) {
508 const uint8_t kPacket[] = {
509 0x82, 0x38, 0x92, 0x38, 0x92, 0x38, 0xde, 0x2a, 0x11, 0xc8, 0xa3, 0xc4,
510 0x82, 0x38, 0x2a, 0x21, 0x2a, 0x28, 0x92, 0x38, 0x92, 0x00, 0x00, 0x0a,
511 0x3a, 0xc8, 0xa3, 0x3a, 0x27, 0xc4, 0x2a, 0x21, 0x2a, 0x28};
pbos2e43b262015-06-30 01:32:40 -0700512 SurvivesMaliciousPacket(kPacket, sizeof(kPacket), 100);
513}
514
Erik Språngf19aec82021-03-16 19:24:58 +0100515TEST_F(UlpfecReceiverTest, MediaWithPadding) {
516 const size_t kNumFecPackets = 1;
517 std::list<AugmentedPacket*> augmented_media_packets;
518 ForwardErrorCorrection::PacketList media_packets;
519 PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
520
521 // Append four bytes of padding to the first media packet.
522 const uint8_t kPadding[] = {0, 0, 0, 4};
523 augmented_media_packets.front()->data.AppendData(kPadding);
524 augmented_media_packets.front()->data.MutableData()[0] |= 1 << 5; // P bit.
525 augmented_media_packets.front()->header.paddingLength = 4;
526
527 std::list<ForwardErrorCorrection::Packet*> fec_packets;
528 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
529
530 auto it = augmented_media_packets.begin();
531 BuildAndAddRedMediaPacket(augmented_media_packets.front());
532
533 VerifyReconstructedMediaPacket(**it, 1);
534 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
535
536 BuildAndAddRedFecPacket(fec_packets.front());
537 ++it;
538 VerifyReconstructedMediaPacket(**it, 1);
539 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
540}
541
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000542} // namespace webrtc