blob: cd1798bbea97058d298dcad7d08c7e5978dd2087 [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/include/rtp_header_parser.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h"
Yves Gerey665174f2018-06-19 15:03:05 +020020#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "modules/rtp_rtcp/source/byte_io.h"
22#include "modules/rtp_rtcp/source/fec_test_helper.h"
23#include "modules/rtp_rtcp/source/forward_error_correction.h"
24#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;
wu@webrtc.org822fbd82013-08-15 23:38:54 +000033using ::testing::Return;
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000034
brandtr0aabdac2016-10-03 06:36:43 -070035using test::fec::AugmentedPacket;
brandtr71ca7472016-10-03 05:11:26 -070036using Packet = ForwardErrorCorrection::Packet;
brandtr71ca7472016-10-03 05:11:26 -070037using test::fec::UlpfecPacketGenerator;
38
39constexpr int kFecPayloadType = 96;
brandtr0aabdac2016-10-03 06:36:43 -070040constexpr uint32_t kMediaSsrc = 835424;
nisse30e89312017-05-29 08:16:37 -070041
42class NullRecoveredPacketReceiver : public RecoveredPacketReceiver {
43 public:
44 void OnRecoveredPacket(const uint8_t* packet, size_t length) override {}
45};
46
brandtr71ca7472016-10-03 05:11:26 -070047} // namespace
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000048
brandtrd55c3f62016-10-31 04:51:33 -070049class UlpfecReceiverTest : public ::testing::Test {
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000050 protected:
brandtrd55c3f62016-10-31 04:51:33 -070051 UlpfecReceiverTest()
brandtrd726a3f2017-06-29 02:45:35 -070052 : fec_(ForwardErrorCorrection::CreateUlpfec(kMediaSsrc)),
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +020053 receiver_fec_(UlpfecReceiver::Create(kMediaSsrc,
54 &recovered_packet_receiver_,
55 {})),
brandtr0aabdac2016-10-03 06:36:43 -070056 packet_generator_(kMediaSsrc) {}
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000057
brandtra2ece732016-10-04 00:00:06 -070058 // Generates |num_fec_packets| FEC packets, given |media_packets|.
brandtr71ca7472016-10-03 05:11:26 -070059 void EncodeFec(const ForwardErrorCorrection::PacketList& media_packets,
60 size_t num_fec_packets,
brandtra2ece732016-10-04 00:00:06 -070061 std::list<ForwardErrorCorrection::Packet*>* fec_packets);
stefan@webrtc.org7adab092012-02-09 12:34:52 +000062
brandtra2ece732016-10-04 00:00:06 -070063 // Generates |num_media_packets| corresponding to a single frame.
64 void PacketizeFrame(size_t num_media_packets,
65 size_t frame_offset,
66 std::list<AugmentedPacket*>* augmented_packets,
67 ForwardErrorCorrection::PacketList* packets);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +000068
brandtra2ece732016-10-04 00:00:06 -070069 // Build a media packet using |packet_generator_| and add it
70 // to the receiver.
71 void BuildAndAddRedMediaPacket(AugmentedPacket* packet);
72
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
brandtrd55c3f62016-10-31 04:51:33 -0700125void UlpfecReceiverTest::BuildAndAddRedMediaPacket(AugmentedPacket* packet) {
brandtra2ece732016-10-04 00:00:06 -0700126 std::unique_ptr<AugmentedPacket> red_packet(
127 packet_generator_.BuildMediaRedPacket(*packet));
128 EXPECT_EQ(0, receiver_fec_->AddReceivedRedPacket(
Niels Möller70a83942019-03-12 09:54:30 +0100129 red_packet->header, red_packet->data, red_packet->length,
130 kFecPayloadType));
brandtra2ece732016-10-04 00:00:06 -0700131}
132
brandtrd55c3f62016-10-31 04:51:33 -0700133void UlpfecReceiverTest::BuildAndAddRedFecPacket(Packet* packet) {
brandtra2ece732016-10-04 00:00:06 -0700134 std::unique_ptr<AugmentedPacket> red_packet(
135 packet_generator_.BuildUlpfecRedPacket(*packet));
136 EXPECT_EQ(0, receiver_fec_->AddReceivedRedPacket(
Niels Möller70a83942019-03-12 09:54:30 +0100137 red_packet->header, red_packet->data, red_packet->length,
138 kFecPayloadType));
brandtra2ece732016-10-04 00:00:06 -0700139}
140
brandtrd55c3f62016-10-31 04:51:33 -0700141void UlpfecReceiverTest::VerifyReconstructedMediaPacket(
brandtra2ece732016-10-04 00:00:06 -0700142 const AugmentedPacket& packet,
143 size_t times) {
144 // Verify that the content of the reconstructed packet is equal to the
145 // content of |packet|, and that the same content is received |times| number
146 // of times in a row.
nisse30e89312017-05-29 08:16:37 -0700147 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, packet.length))
brandtra2ece732016-10-04 00:00:06 -0700148 .With(Args<0, 1>(ElementsAreArray(packet.data, packet.length)))
nisse30e89312017-05-29 08:16:37 -0700149 .Times(times);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000150}
151
brandtrd55c3f62016-10-31 04:51:33 -0700152void UlpfecReceiverTest::InjectGarbagePacketLength(size_t fec_garbage_offset) {
nisse30e89312017-05-29 08:16:37 -0700153 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _));
pbos2bad88d2015-07-06 03:09:08 -0700154
brandtr71ca7472016-10-03 05:11:26 -0700155 const size_t kNumFecPackets = 1;
brandtr0aabdac2016-10-03 06:36:43 -0700156 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200157 ForwardErrorCorrection::PacketList media_packets;
brandtra2ece732016-10-04 00:00:06 -0700158 PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
brandtr35c480c2016-08-09 01:23:23 -0700159 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700160 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
pbos2bad88d2015-07-06 03:09:08 -0700161 ByteWriter<uint16_t>::WriteBigEndian(
162 &fec_packets.front()->data[fec_garbage_offset], 0x4711);
163
164 // Inject first media packet, then first FEC packet, skipping the second media
165 // packet to cause a recovery from the FEC packet.
brandtr0aabdac2016-10-03 06:36:43 -0700166 BuildAndAddRedMediaPacket(augmented_media_packets.front());
pbos2bad88d2015-07-06 03:09:08 -0700167 BuildAndAddRedFecPacket(fec_packets.front());
168 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
169
170 FecPacketCounter counter = receiver_fec_->GetPacketCounter();
brandtr71ca7472016-10-03 05:11:26 -0700171 EXPECT_EQ(2U, counter.num_packets);
172 EXPECT_EQ(1U, counter.num_fec_packets);
173 EXPECT_EQ(0U, counter.num_recovered_packets);
pbos2bad88d2015-07-06 03:09:08 -0700174}
175
brandtrd55c3f62016-10-31 04:51:33 -0700176void UlpfecReceiverTest::SurvivesMaliciousPacket(const uint8_t* data,
177 size_t length,
178 uint8_t ulpfec_payload_type) {
179 RTPHeader header;
180 std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
brandtra2ece732016-10-04 00:00:06 -0700181 ASSERT_TRUE(parser->Parse(data, length, &header));
182
nisse30e89312017-05-29 08:16:37 -0700183 NullRecoveredPacketReceiver null_callback;
brandtrd55c3f62016-10-31 04:51:33 -0700184 std::unique_ptr<UlpfecReceiver> receiver_fec(
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +0200185 UlpfecReceiver::Create(kMediaSsrc, &null_callback, {}));
brandtra2ece732016-10-04 00:00:06 -0700186
187 receiver_fec->AddReceivedRedPacket(header, data, length, ulpfec_payload_type);
188}
189
brandtrd55c3f62016-10-31 04:51:33 -0700190TEST_F(UlpfecReceiverTest, TwoMediaOneFec) {
brandtra2ece732016-10-04 00:00:06 -0700191 constexpr size_t kNumFecPackets = 1u;
192 std::list<AugmentedPacket*> augmented_media_packets;
193 ForwardErrorCorrection::PacketList media_packets;
194 PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
195 std::list<ForwardErrorCorrection::Packet*> fec_packets;
196 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
197
asapersson0c43f772016-11-30 01:42:26 -0800198 FecPacketCounter counter = receiver_fec_->GetPacketCounter();
199 EXPECT_EQ(0u, counter.num_packets);
200 EXPECT_EQ(-1, counter.first_packet_time_ms);
201
brandtra2ece732016-10-04 00:00:06 -0700202 // Recovery
203 auto it = augmented_media_packets.begin();
204 BuildAndAddRedMediaPacket(*it);
205 VerifyReconstructedMediaPacket(**it, 1);
206 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
asapersson0c43f772016-11-30 01:42:26 -0800207 counter = receiver_fec_->GetPacketCounter();
208 EXPECT_EQ(1u, counter.num_packets);
209 EXPECT_EQ(0u, counter.num_fec_packets);
210 EXPECT_EQ(0u, counter.num_recovered_packets);
211 const int64_t first_packet_time_ms = counter.first_packet_time_ms;
212 EXPECT_NE(-1, first_packet_time_ms);
213
brandtra2ece732016-10-04 00:00:06 -0700214 // Drop one media packet.
215 auto fec_it = fec_packets.begin();
216 BuildAndAddRedFecPacket(*fec_it);
217 ++it;
218 VerifyReconstructedMediaPacket(**it, 1);
219 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
220
asapersson0c43f772016-11-30 01:42:26 -0800221 counter = receiver_fec_->GetPacketCounter();
brandtra2ece732016-10-04 00:00:06 -0700222 EXPECT_EQ(2u, counter.num_packets);
223 EXPECT_EQ(1u, counter.num_fec_packets);
224 EXPECT_EQ(1u, counter.num_recovered_packets);
asapersson0c43f772016-11-30 01:42:26 -0800225 EXPECT_EQ(first_packet_time_ms, counter.first_packet_time_ms);
brandtra2ece732016-10-04 00:00:06 -0700226}
227
brandtrd55c3f62016-10-31 04:51:33 -0700228TEST_F(UlpfecReceiverTest, InjectGarbageFecHeaderLengthRecovery) {
pbos2bad88d2015-07-06 03:09:08 -0700229 // Byte offset 8 is the 'length recovery' field of the FEC header.
230 InjectGarbagePacketLength(8);
231}
232
brandtrd55c3f62016-10-31 04:51:33 -0700233TEST_F(UlpfecReceiverTest, InjectGarbageFecLevelHeaderProtectionLength) {
pbos2bad88d2015-07-06 03:09:08 -0700234 // Byte offset 10 is the 'protection length' field in the first FEC level
235 // header.
236 InjectGarbagePacketLength(10);
237}
238
brandtrd55c3f62016-10-31 04:51:33 -0700239TEST_F(UlpfecReceiverTest, TwoMediaTwoFec) {
brandtr71ca7472016-10-03 05:11:26 -0700240 const size_t kNumFecPackets = 2;
brandtr0aabdac2016-10-03 06:36:43 -0700241 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200242 ForwardErrorCorrection::PacketList media_packets;
brandtra2ece732016-10-04 00:00:06 -0700243 PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
brandtr35c480c2016-08-09 01:23:23 -0700244 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700245 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000246
247 // Recovery
248 // Drop both media packets.
brandtr0aabdac2016-10-03 06:36:43 -0700249 auto it = augmented_media_packets.begin();
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200250 auto fec_it = fec_packets.begin();
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000251 BuildAndAddRedFecPacket(*fec_it);
brandtr71ca7472016-10-03 05:11:26 -0700252 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000253 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000254 ++fec_it;
255 BuildAndAddRedFecPacket(*fec_it);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000256 ++it;
brandtr71ca7472016-10-03 05:11:26 -0700257 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000258 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000259}
260
brandtrd55c3f62016-10-31 04:51:33 -0700261TEST_F(UlpfecReceiverTest, TwoFramesOneFec) {
brandtr71ca7472016-10-03 05:11:26 -0700262 const size_t kNumFecPackets = 1;
brandtr0aabdac2016-10-03 06:36:43 -0700263 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200264 ForwardErrorCorrection::PacketList media_packets;
brandtra2ece732016-10-04 00:00:06 -0700265 PacketizeFrame(1, 0, &augmented_media_packets, &media_packets);
266 PacketizeFrame(1, 1, &augmented_media_packets, &media_packets);
brandtr35c480c2016-08-09 01:23:23 -0700267 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700268 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000269
270 // Recovery
brandtr0aabdac2016-10-03 06:36:43 -0700271 auto it = augmented_media_packets.begin();
272 BuildAndAddRedMediaPacket(augmented_media_packets.front());
brandtr71ca7472016-10-03 05:11:26 -0700273 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000274 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000275 // Drop one media packet.
276 BuildAndAddRedFecPacket(fec_packets.front());
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000277 ++it;
brandtr71ca7472016-10-03 05:11:26 -0700278 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000279 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000280}
281
brandtrd55c3f62016-10-31 04:51:33 -0700282TEST_F(UlpfecReceiverTest, OneCompleteOneUnrecoverableFrame) {
brandtr71ca7472016-10-03 05:11:26 -0700283 const size_t kNumFecPackets = 1;
brandtr0aabdac2016-10-03 06:36:43 -0700284 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200285 ForwardErrorCorrection::PacketList media_packets;
brandtra2ece732016-10-04 00:00:06 -0700286 PacketizeFrame(1, 0, &augmented_media_packets, &media_packets);
287 PacketizeFrame(2, 1, &augmented_media_packets, &media_packets);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000288
brandtr35c480c2016-08-09 01:23:23 -0700289 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700290 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000291
292 // Recovery
brandtr0aabdac2016-10-03 06:36:43 -0700293 auto it = augmented_media_packets.begin();
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000294 BuildAndAddRedMediaPacket(*it); // First frame: one packet.
brandtr71ca7472016-10-03 05:11:26 -0700295 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000296 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000297 ++it;
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000298 BuildAndAddRedMediaPacket(*it); // First packet of second frame.
brandtr71ca7472016-10-03 05:11:26 -0700299 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000300 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000301}
302
brandtrd55c3f62016-10-31 04:51:33 -0700303TEST_F(UlpfecReceiverTest, MaxFramesOneFec) {
brandtr71ca7472016-10-03 05:11:26 -0700304 const size_t kNumFecPackets = 1;
305 const size_t kNumMediaPackets = 48;
brandtr0aabdac2016-10-03 06:36:43 -0700306 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200307 ForwardErrorCorrection::PacketList media_packets;
brandtr71ca7472016-10-03 05:11:26 -0700308 for (size_t i = 0; i < kNumMediaPackets; ++i) {
brandtra2ece732016-10-04 00:00:06 -0700309 PacketizeFrame(1, i, &augmented_media_packets, &media_packets);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000310 }
brandtr35c480c2016-08-09 01:23:23 -0700311 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700312 EncodeFec(media_packets, kNumFecPackets, &fec_packets);
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000313
314 // Recovery
brandtr0aabdac2016-10-03 06:36:43 -0700315 auto it = augmented_media_packets.begin();
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000316 ++it; // Drop first packet.
brandtr0aabdac2016-10-03 06:36:43 -0700317 for (; it != augmented_media_packets.end(); ++it) {
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000318 BuildAndAddRedMediaPacket(*it);
brandtr71ca7472016-10-03 05:11:26 -0700319 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000320 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000321 }
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000322 BuildAndAddRedFecPacket(fec_packets.front());
brandtr0aabdac2016-10-03 06:36:43 -0700323 it = augmented_media_packets.begin();
brandtr71ca7472016-10-03 05:11:26 -0700324 VerifyReconstructedMediaPacket(**it, 1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000325 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000326}
327
brandtrd55c3f62016-10-31 04:51:33 -0700328TEST_F(UlpfecReceiverTest, TooManyFrames) {
brandtr71ca7472016-10-03 05:11:26 -0700329 const size_t kNumFecPackets = 1;
330 const size_t kNumMediaPackets = 49;
brandtr0aabdac2016-10-03 06:36:43 -0700331 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200332 ForwardErrorCorrection::PacketList media_packets;
brandtr71ca7472016-10-03 05:11:26 -0700333 for (size_t i = 0; i < kNumMediaPackets; ++i) {
brandtra2ece732016-10-04 00:00:06 -0700334 PacketizeFrame(1, i, &augmented_media_packets, &media_packets);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000335 }
brandtr35c480c2016-08-09 01:23:23 -0700336 std::list<ForwardErrorCorrection::Packet*> fec_packets;
Rasmus Brandt78db1582016-09-21 09:19:34 +0200337 EXPECT_EQ(-1, fec_->EncodeFec(media_packets,
338 kNumFecPackets * 255 / kNumMediaPackets, 0,
339 false, kFecMaskBursty, &fec_packets));
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000340}
341
brandtrd55c3f62016-10-31 04:51:33 -0700342TEST_F(UlpfecReceiverTest, PacketNotDroppedTooEarly) {
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000343 // 1 frame with 2 media packets and one FEC packet. One media packet missing.
344 // Delay the FEC packet.
brandtr71ca7472016-10-03 05:11:26 -0700345 Packet* delayed_fec = nullptr;
346 const size_t kNumFecPacketsBatch1 = 1;
347 const size_t kNumMediaPacketsBatch1 = 2;
brandtr0aabdac2016-10-03 06:36:43 -0700348 std::list<AugmentedPacket*> augmented_media_packets_batch1;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200349 ForwardErrorCorrection::PacketList media_packets_batch1;
brandtra2ece732016-10-04 00:00:06 -0700350 PacketizeFrame(kNumMediaPacketsBatch1, 0, &augmented_media_packets_batch1,
351 &media_packets_batch1);
brandtr35c480c2016-08-09 01:23:23 -0700352 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700353 EncodeFec(media_packets_batch1, kNumFecPacketsBatch1, &fec_packets);
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000354
brandtr0aabdac2016-10-03 06:36:43 -0700355 BuildAndAddRedMediaPacket(augmented_media_packets_batch1.front());
Yves Gerey665174f2018-06-19 15:03:05 +0200356 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000357 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000358 delayed_fec = fec_packets.front();
359
360 // Fill the FEC decoder. No packets should be dropped.
brandtr71ca7472016-10-03 05:11:26 -0700361 const size_t kNumMediaPacketsBatch2 = 46;
brandtr0aabdac2016-10-03 06:36:43 -0700362 std::list<AugmentedPacket*> augmented_media_packets_batch2;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200363 ForwardErrorCorrection::PacketList media_packets_batch2;
brandtr71ca7472016-10-03 05:11:26 -0700364 for (size_t i = 0; i < kNumMediaPacketsBatch2; ++i) {
brandtra2ece732016-10-04 00:00:06 -0700365 PacketizeFrame(1, i, &augmented_media_packets_batch2,
366 &media_packets_batch2);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000367 }
brandtr0aabdac2016-10-03 06:36:43 -0700368 for (auto it = augmented_media_packets_batch2.begin();
369 it != augmented_media_packets_batch2.end(); ++it) {
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000370 BuildAndAddRedMediaPacket(*it);
Yves Gerey665174f2018-06-19 15:03:05 +0200371 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000372 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000373 }
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000374
375 // Add the delayed FEC packet. One packet should be reconstructed.
376 BuildAndAddRedFecPacket(delayed_fec);
Yves Gerey665174f2018-06-19 15:03:05 +0200377 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000378 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000379}
380
brandtrd55c3f62016-10-31 04:51:33 -0700381TEST_F(UlpfecReceiverTest, PacketDroppedWhenTooOld) {
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000382 // 1 frame with 2 media packets and one FEC packet. One media packet missing.
383 // Delay the FEC packet.
brandtr71ca7472016-10-03 05:11:26 -0700384 Packet* delayed_fec = nullptr;
385 const size_t kNumFecPacketsBatch1 = 1;
386 const size_t kNumMediaPacketsBatch1 = 2;
brandtr0aabdac2016-10-03 06:36:43 -0700387 std::list<AugmentedPacket*> augmented_media_packets_batch1;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200388 ForwardErrorCorrection::PacketList media_packets_batch1;
brandtra2ece732016-10-04 00:00:06 -0700389 PacketizeFrame(kNumMediaPacketsBatch1, 0, &augmented_media_packets_batch1,
390 &media_packets_batch1);
brandtr35c480c2016-08-09 01:23:23 -0700391 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtr71ca7472016-10-03 05:11:26 -0700392 EncodeFec(media_packets_batch1, kNumFecPacketsBatch1, &fec_packets);
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000393
brandtr0aabdac2016-10-03 06:36:43 -0700394 BuildAndAddRedMediaPacket(augmented_media_packets_batch1.front());
Yves Gerey665174f2018-06-19 15:03:05 +0200395 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000396 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000397 delayed_fec = fec_packets.front();
398
399 // Fill the FEC decoder and force the last packet to be dropped.
brandtr71ca7472016-10-03 05:11:26 -0700400 const size_t kNumMediaPacketsBatch2 = 48;
brandtr0aabdac2016-10-03 06:36:43 -0700401 std::list<AugmentedPacket*> augmented_media_packets_batch2;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200402 ForwardErrorCorrection::PacketList media_packets_batch2;
brandtr71ca7472016-10-03 05:11:26 -0700403 for (size_t i = 0; i < kNumMediaPacketsBatch2; ++i) {
brandtra2ece732016-10-04 00:00:06 -0700404 PacketizeFrame(1, i, &augmented_media_packets_batch2,
405 &media_packets_batch2);
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000406 }
brandtr0aabdac2016-10-03 06:36:43 -0700407 for (auto it = augmented_media_packets_batch2.begin();
408 it != augmented_media_packets_batch2.end(); ++it) {
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000409 BuildAndAddRedMediaPacket(*it);
Yves Gerey665174f2018-06-19 15:03:05 +0200410 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000411 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000412 }
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000413
414 // Add the delayed FEC packet. No packet should be reconstructed since the
415 // first media packet of that frame has been dropped due to being too old.
416 BuildAndAddRedFecPacket(delayed_fec);
nisse30e89312017-05-29 08:16:37 -0700417 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(0);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000418 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000419}
420
brandtrd55c3f62016-10-31 04:51:33 -0700421TEST_F(UlpfecReceiverTest, OldFecPacketDropped) {
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000422 // 49 frames with 2 media packets and one FEC packet. All media packets
423 // missing.
brandtr71ca7472016-10-03 05:11:26 -0700424 const size_t kNumMediaPackets = 49 * 2;
brandtr0aabdac2016-10-03 06:36:43 -0700425 std::list<AugmentedPacket*> augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200426 ForwardErrorCorrection::PacketList media_packets;
brandtr71ca7472016-10-03 05:11:26 -0700427 for (size_t i = 0; i < kNumMediaPackets / 2; ++i) {
brandtr0aabdac2016-10-03 06:36:43 -0700428 std::list<AugmentedPacket*> frame_augmented_media_packets;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200429 ForwardErrorCorrection::PacketList frame_media_packets;
brandtr35c480c2016-08-09 01:23:23 -0700430 std::list<ForwardErrorCorrection::Packet*> fec_packets;
brandtra2ece732016-10-04 00:00:06 -0700431 PacketizeFrame(2, 0, &frame_augmented_media_packets, &frame_media_packets);
brandtr71ca7472016-10-03 05:11:26 -0700432 EncodeFec(frame_media_packets, 1, &fec_packets);
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200433 for (auto it = fec_packets.begin(); it != fec_packets.end(); ++it) {
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000434 // Only FEC packets inserted. No packets recoverable at this time.
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000435 BuildAndAddRedFecPacket(*it);
nisse30e89312017-05-29 08:16:37 -0700436 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(0);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000437 EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000438 }
brandtr35c480c2016-08-09 01:23:23 -0700439 // Move unique_ptr's to media_packets for lifetime management.
440 media_packets.insert(media_packets.end(),
441 std::make_move_iterator(frame_media_packets.begin()),
442 std::make_move_iterator(frame_media_packets.end()));
brandtr0aabdac2016-10-03 06:36:43 -0700443 augmented_media_packets.insert(augmented_media_packets.end(),
444 frame_augmented_media_packets.begin(),
445 frame_augmented_media_packets.end());
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000446 }
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000447 // Insert the oldest media packet. The corresponding FEC packet is too old
brandtr71ca7472016-10-03 05:11:26 -0700448 // and should have been dropped. Only the media packet we inserted will be
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000449 // returned.
brandtr0aabdac2016-10-03 06:36:43 -0700450 BuildAndAddRedMediaPacket(augmented_media_packets.front());
Yves Gerey665174f2018-06-19 15:03:05 +0200451 EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
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, TruncatedPacketWithFBitSet) {
456 const uint8_t kTruncatedPacket[] = {0x80, 0x2a, 0x68, 0x71, 0x29, 0xa1, 0x27,
457 0x3a, 0x29, 0x12, 0x2a, 0x98, 0xe0, 0x29};
pbos70d5c472015-06-29 07:22:04 -0700458
459 SurvivesMaliciousPacket(kTruncatedPacket, sizeof(kTruncatedPacket), 100);
460}
461
brandtrd55c3f62016-10-31 04:51:33 -0700462TEST_F(UlpfecReceiverTest,
463 TruncatedPacketWithFBitSetEndingAfterFirstRedHeader) {
464 const uint8_t kPacket[] = {
465 0x89, 0x27, 0x3a, 0x83, 0x27, 0x3a, 0x3a, 0xf3, 0x67, 0xbe, 0x2a,
466 0xa9, 0x27, 0x54, 0x3a, 0x3a, 0x2a, 0x67, 0x3a, 0xf3, 0x67, 0xbe,
467 0x2a, 0x27, 0xe6, 0xf6, 0x03, 0x3e, 0x29, 0x27, 0x21, 0x27, 0x2a,
468 0x29, 0x21, 0x4b, 0x29, 0x3a, 0x28, 0x29, 0xbf, 0x29, 0x2a, 0x26,
469 0x29, 0xae, 0x27, 0xa6, 0xf6, 0x00, 0x03, 0x3e};
pbos2e43b262015-06-30 01:32:40 -0700470 SurvivesMaliciousPacket(kPacket, sizeof(kPacket), 100);
471}
472
brandtrd55c3f62016-10-31 04:51:33 -0700473TEST_F(UlpfecReceiverTest, TruncatedPacketWithoutDataPastFirstBlock) {
474 const uint8_t kPacket[] = {
475 0x82, 0x38, 0x92, 0x38, 0x92, 0x38, 0xde, 0x2a, 0x11, 0xc8, 0xa3, 0xc4,
476 0x82, 0x38, 0x2a, 0x21, 0x2a, 0x28, 0x92, 0x38, 0x92, 0x00, 0x00, 0x0a,
477 0x3a, 0xc8, 0xa3, 0x3a, 0x27, 0xc4, 0x2a, 0x21, 0x2a, 0x28};
pbos2e43b262015-06-30 01:32:40 -0700478 SurvivesMaliciousPacket(kPacket, sizeof(kPacket), 100);
479}
480
stefan@webrtc.org2fd1e1e2012-01-30 09:03:37 +0000481} // namespace webrtc