blob: cc6512d7d4c2f1ff1f127e35b8ec1656ac20ae5f [file] [log] [blame]
marpan@webrtc.orgcdba1a82012-01-31 00:36:14 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
marpan@webrtc.orgcdba1a82012-01-31 00:36:14 +00004 * 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/*
12 * Test application for core FEC algorithm. Calls encoding and decoding
13 * functions in ForwardErrorCorrection directly.
niklase@google.com470e71d2011-07-07 08:21:25 +000014 */
15
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000016#include <string.h>
17#include <time.h>
18
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +000019#include <list>
niklase@google.com470e71d2011-07-07 08:21:25 +000020
danilchap47a740b2015-12-15 00:30:07 -080021#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000022#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
23#include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020024#include "webrtc/rtc_base/random.h"
kwibergac9f8762016-09-30 22:29:43 -070025#include "webrtc/test/gtest.h"
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000026#include "webrtc/test/testsupport/fileutils.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000027
danilchap40f349f2015-12-14 06:39:33 -080028// #define VERBOSE_OUTPUT
niklase@google.com470e71d2011-07-07 08:21:25 +000029
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +000030namespace webrtc {
danilchap6a6f0892015-12-10 12:39:08 -080031namespace fec_private_tables {
32extern const uint8_t** kPacketMaskBurstyTbl[12];
33}
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +000034namespace test {
danilchap6a6f0892015-12-10 12:39:08 -080035using fec_private_tables::kPacketMaskBurstyTbl;
niklase@google.com470e71d2011-07-07 08:21:25 +000036
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +000037void ReceivePackets(
Rasmus Brandtae4f7672016-07-07 09:40:51 +020038 ForwardErrorCorrection::ReceivedPacketList* to_decode_list,
39 ForwardErrorCorrection::ReceivedPacketList* received_packet_list,
40 size_t num_packets_to_decode,
41 float reorder_rate,
42 float duplicate_rate,
danilchap47a740b2015-12-15 00:30:07 -080043 Random* random) {
Rasmus Brandtae4f7672016-07-07 09:40:51 +020044 RTC_DCHECK(to_decode_list->empty());
45 RTC_DCHECK_LE(num_packets_to_decode, received_packet_list->size());
niklase@google.com470e71d2011-07-07 08:21:25 +000046
Rasmus Brandtae4f7672016-07-07 09:40:51 +020047 for (size_t i = 0; i < num_packets_to_decode; i++) {
48 auto it = received_packet_list->begin();
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +000049 // Reorder packets.
Rasmus Brandtae4f7672016-07-07 09:40:51 +020050 float random_variable = random->Rand<float>();
51 while (random_variable < reorder_rate) {
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +000052 ++it;
Rasmus Brandtae4f7672016-07-07 09:40:51 +020053 if (it == received_packet_list->end()) {
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +000054 --it;
55 break;
56 }
Rasmus Brandtae4f7672016-07-07 09:40:51 +020057 random_variable = random->Rand<float>();
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +000058 }
brandtr35c480c2016-08-09 01:23:23 -070059 to_decode_list->push_back(std::move(*it));
60 received_packet_list->erase(it);
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +000061
62 // Duplicate packets.
brandtr35c480c2016-08-09 01:23:23 -070063 ForwardErrorCorrection::ReceivedPacket* received_packet =
64 to_decode_list->back().get();
Rasmus Brandtae4f7672016-07-07 09:40:51 +020065 random_variable = random->Rand<float>();
66 while (random_variable < duplicate_rate) {
brandtr35c480c2016-08-09 01:23:23 -070067 std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> duplicate_packet(
68 new ForwardErrorCorrection::ReceivedPacket());
Rasmus Brandtae4f7672016-07-07 09:40:51 +020069 *duplicate_packet = *received_packet;
70 duplicate_packet->pkt = new ForwardErrorCorrection::Packet();
71 memcpy(duplicate_packet->pkt->data, received_packet->pkt->data,
72 received_packet->pkt->length);
73 duplicate_packet->pkt->length = received_packet->pkt->length;
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +000074
brandtr35c480c2016-08-09 01:23:23 -070075 to_decode_list->push_back(std::move(duplicate_packet));
Rasmus Brandtae4f7672016-07-07 09:40:51 +020076 random_variable = random->Rand<float>();
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +000077 }
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +000078 }
79}
80
brandtrd726a3f2017-06-29 02:45:35 -070081void RunTest(bool use_flexfec) {
marpan@webrtc.org8866bb12012-06-05 16:42:20 +000082 // TODO(marpan): Split this function into subroutines/helper functions.
danilchap40f349f2015-12-14 06:39:33 -080083 enum { kMaxNumberMediaPackets = 48 };
84 enum { kMaxNumberFecPackets = 48 };
marpan@webrtc.org040cb712011-11-04 22:57:56 +000085
pbos@webrtc.org2f446732013-04-08 11:08:41 +000086 const uint32_t kNumMaskBytesL0 = 2;
87 const uint32_t kNumMaskBytesL1 = 6;
niklase@google.com470e71d2011-07-07 08:21:25 +000088
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +000089 // FOR UEP
90 const bool kUseUnequalProtection = true;
niklase@google.com470e71d2011-07-07 08:21:25 +000091
marpan@webrtc.org8866bb12012-06-05 16:42:20 +000092 // FEC mask types.
danilchap40f349f2015-12-14 06:39:33 -080093 const FecMaskType kMaskTypes[] = {kFecMaskRandom, kFecMaskBursty};
marpan@webrtc.org8866bb12012-06-05 16:42:20 +000094 const int kNumFecMaskTypes = sizeof(kMaskTypes) / sizeof(*kMaskTypes);
pbos@webrtc.org3004c792013-05-07 12:36:21 +000095
marpan@webrtc.org8866bb12012-06-05 16:42:20 +000096 // Maximum number of media packets allowed for the mask type.
danilchap40f349f2015-12-14 06:39:33 -080097 const uint16_t kMaxMediaPackets[] = {
98 kMaxNumberMediaPackets,
marpan@webrtc.org8866bb12012-06-05 16:42:20 +000099 sizeof(kPacketMaskBurstyTbl) / sizeof(*kPacketMaskBurstyTbl)};
pbos@webrtc.org3004c792013-05-07 12:36:21 +0000100
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +0000101 ASSERT_EQ(12, kMaxMediaPackets[1]) << "Max media packets for bursty mode not "
102 << "equal to 12.";
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000103
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200104 ForwardErrorCorrection::PacketList media_packet_list;
brandtr35c480c2016-08-09 01:23:23 -0700105 std::list<ForwardErrorCorrection::Packet*> fec_packet_list;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200106 ForwardErrorCorrection::ReceivedPacketList to_decode_list;
107 ForwardErrorCorrection::ReceivedPacketList received_packet_list;
108 ForwardErrorCorrection::RecoveredPacketList recovered_packet_list;
109 std::list<uint8_t*> fec_mask_list;
niklase@google.com470e71d2011-07-07 08:21:25 +0000110
brandtra25a6952017-08-01 05:01:07 -0700111 // Running over only two loss rates to limit execution time.
112 const float loss_rate[] = {0.05f, 0.01f};
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200113 const uint32_t loss_rate_size = sizeof(loss_rate) / sizeof(*loss_rate);
114 const float reorder_rate = 0.1f;
115 const float duplicate_rate = 0.1f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000116
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200117 uint8_t media_loss_mask[kMaxNumberMediaPackets];
118 uint8_t fec_loss_mask[kMaxNumberFecPackets];
119 uint8_t fec_packet_masks[kMaxNumberFecPackets][kMaxNumberMediaPackets];
niklase@google.com470e71d2011-07-07 08:21:25 +0000120
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000121 // Seed the random number generator, storing the seed to file in order to
122 // reproduce past results.
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200123 const unsigned int random_seed = static_cast<unsigned int>(time(nullptr));
124 Random random(random_seed);
marpan@webrtc.orgcdba1a82012-01-31 00:36:14 +0000125 std::string filename = webrtc::test::OutputPath() + "randomSeedLog.txt";
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200126 FILE* random_seed_file = fopen(filename.c_str(), "a");
127 fprintf(random_seed_file, "%u\n", random_seed);
128 fclose(random_seed_file);
129 random_seed_file = nullptr;
marpan@webrtc.org040cb712011-11-04 22:57:56 +0000130
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200131 uint16_t seq_num = 0;
132 uint32_t timestamp = random.Rand<uint32_t>();
brandtrd726a3f2017-06-29 02:45:35 -0700133 const uint32_t media_ssrc = random.Rand(1u, 0xfffffffe);
134 uint32_t fec_ssrc;
135 uint16_t fec_seq_num_offset;
136 if (use_flexfec) {
137 fec_ssrc = random.Rand(1u, 0xfffffffe);
brandtrfa856782017-06-30 07:22:15 -0700138 fec_seq_num_offset = random.Rand(0, 1 << 15);
brandtrd726a3f2017-06-29 02:45:35 -0700139 } else {
140 fec_ssrc = media_ssrc;
141 fec_seq_num_offset = 0;
142 }
143
144 std::unique_ptr<ForwardErrorCorrection> fec;
145 if (use_flexfec) {
146 fec = ForwardErrorCorrection::CreateFlexfec(fec_ssrc, media_ssrc);
147 } else {
148 RTC_DCHECK_EQ(media_ssrc, fec_ssrc);
149 fec = ForwardErrorCorrection::CreateUlpfec(fec_ssrc);
150 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000151
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000152 // Loop over the mask types: random and bursty.
153 for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes;
phoglund@webrtc.org9919ad52013-05-16 15:06:28 +0000154 ++mask_type_idx) {
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200155 for (uint32_t loss_rate_idx = 0; loss_rate_idx < loss_rate_size;
156 ++loss_rate_idx) {
157 printf("Loss rate: %.2f, Mask type %d \n", loss_rate[loss_rate_idx],
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000158 mask_type_idx);
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000159
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200160 const uint32_t packet_mask_max = kMaxMediaPackets[mask_type_idx];
161 std::unique_ptr<uint8_t[]> packet_mask(
162 new uint8_t[packet_mask_max * kNumMaskBytesL1]);
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000163
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000164 FecMaskType fec_mask_type = kMaskTypes[mask_type_idx];
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000165
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200166 for (uint32_t num_media_packets = 1; num_media_packets <= packet_mask_max;
167 num_media_packets++) {
168 internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets);
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000169
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200170 for (uint32_t num_fec_packets = 1;
171 num_fec_packets <= num_media_packets &&
172 num_fec_packets <= packet_mask_max;
173 num_fec_packets++) {
174 // Loop over num_imp_packets: usually <= (0.3*num_media_packets).
175 // For this test we check up to ~ (num_media_packets / 4).
176 uint32_t max_num_imp_packets = num_media_packets / 4 + 1;
177 for (uint32_t num_imp_packets = 0;
178 num_imp_packets <= max_num_imp_packets &&
179 num_imp_packets <= packet_mask_max;
180 num_imp_packets++) {
181 uint8_t protection_factor =
182 static_cast<uint8_t>(num_fec_packets * 255 / num_media_packets);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000183
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200184 const uint32_t mask_bytes_per_fec_packet =
185 (num_media_packets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000186
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200187 memset(packet_mask.get(), 0,
188 num_media_packets * mask_bytes_per_fec_packet);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000189
190 // Transfer packet masks from bit-mask to byte-mask.
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200191 internal::GeneratePacketMasks(num_media_packets, num_fec_packets,
192 num_imp_packets,
193 kUseUnequalProtection,
194 mask_table, packet_mask.get());
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000195
196#ifdef VERBOSE_OUTPUT
danilchap40f349f2015-12-14 06:39:33 -0800197 printf(
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200198 "%u media packets, %u FEC packets, %u num_imp_packets, "
danilchap40f349f2015-12-14 06:39:33 -0800199 "loss rate = %.2f \n",
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200200 num_media_packets, num_fec_packets, num_imp_packets,
201 loss_rate[loss_rate_idx]);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000202 printf("Packet mask matrix \n");
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000203#endif
204
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200205 for (uint32_t i = 0; i < num_fec_packets; i++) {
206 for (uint32_t j = 0; j < num_media_packets; j++) {
207 const uint8_t byte_mask =
208 packet_mask[i * mask_bytes_per_fec_packet + j / 8];
209 const uint32_t bit_position = (7 - j % 8);
210 fec_packet_masks[i][j] =
211 (byte_mask & (1 << bit_position)) >> bit_position;
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000212#ifdef VERBOSE_OUTPUT
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200213 printf("%u ", fec_packet_masks[i][j]);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000214#endif
215 }
216#ifdef VERBOSE_OUTPUT
217 printf("\n");
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000218#endif
219 }
220#ifdef VERBOSE_OUTPUT
221 printf("\n");
222#endif
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000223 // Check for all zero rows or columns: indicates incorrect mask.
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200224 uint32_t row_limit = num_media_packets;
225 for (uint32_t i = 0; i < num_fec_packets; ++i) {
226 uint32_t row_sum = 0;
227 for (uint32_t j = 0; j < row_limit; ++j) {
228 row_sum += fec_packet_masks[i][j];
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000229 }
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200230 ASSERT_NE(0u, row_sum) << "Row is all zero " << i;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000231 }
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200232 for (uint32_t j = 0; j < row_limit; ++j) {
233 uint32_t column_sum = 0;
234 for (uint32_t i = 0; i < num_fec_packets; ++i) {
235 column_sum += fec_packet_masks[i][j];
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000236 }
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200237 ASSERT_NE(0u, column_sum) << "Column is all zero " << j;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000238 }
239
240 // Construct media packets.
marpan@webrtc.orgc8364532014-07-03 16:49:30 +0000241 // Reset the sequence number here for each FEC code/mask tested
242 // below, to avoid sequence number wrap-around. In actual decoding,
243 // old FEC packets in list are dropped if sequence number wrap
244 // around is detected. This case is currently not handled below.
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200245 seq_num = 0;
246 for (uint32_t i = 0; i < num_media_packets; ++i) {
brandtr35c480c2016-08-09 01:23:23 -0700247 std::unique_ptr<ForwardErrorCorrection::Packet> media_packet(
248 new ForwardErrorCorrection::Packet());
danilchap47a740b2015-12-15 00:30:07 -0800249 const uint32_t kMinPacketSize = 12;
250 const uint32_t kMaxPacketSize = static_cast<uint32_t>(
Rasmus Brandt78db1582016-09-21 09:19:34 +0200251 IP_PACKET_SIZE - 12 - 28 - fec->MaxPacketOverhead());
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200252 media_packet->length = random.Rand(kMinPacketSize,
253 kMaxPacketSize);
danilchap47a740b2015-12-15 00:30:07 -0800254
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000255 // Generate random values for the first 2 bytes.
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200256 media_packet->data[0] = random.Rand<uint8_t>();
257 media_packet->data[1] = random.Rand<uint8_t>();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000258
259 // The first two bits are assumed to be 10 by the
260 // FEC encoder. In fact the FEC decoder will set the
261 // two first bits to 10 regardless of what they
262 // actually were. Set the first two bits to 10
263 // so that a memcmp can be performed for the
264 // whole restored packet.
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200265 media_packet->data[0] |= 0x80;
266 media_packet->data[0] &= 0xbf;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000267
268 // FEC is applied to a whole frame.
269 // A frame is signaled by multiple packets without
270 // the marker bit set followed by the last packet of
271 // the frame for which the marker bit is set.
272 // Only push one (fake) frame to the FEC.
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200273 media_packet->data[1] &= 0x7f;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000274
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200275 ByteWriter<uint16_t>::WriteBigEndian(&media_packet->data[2],
276 seq_num);
277 ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[4],
278 timestamp);
279 ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[8],
brandtrd726a3f2017-06-29 02:45:35 -0700280 media_ssrc);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000281 // Generate random values for payload
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200282 for (size_t j = 12; j < media_packet->length; ++j) {
283 media_packet->data[j] = random.Rand<uint8_t>();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000284 }
brandtr35c480c2016-08-09 01:23:23 -0700285 media_packet_list.push_back(std::move(media_packet));
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200286 seq_num++;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000287 }
brandtr35c480c2016-08-09 01:23:23 -0700288 media_packet_list.back()->data[1] |= 0x80;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000289
Rasmus Brandt78db1582016-09-21 09:19:34 +0200290 ASSERT_EQ(0, fec->EncodeFec(media_packet_list, protection_factor,
291 num_imp_packets, kUseUnequalProtection,
292 fec_mask_type, &fec_packet_list))
brandtrece4aba2016-09-20 23:16:28 -0700293 << "EncodeFec() failed";
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000294
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200295 ASSERT_EQ(num_fec_packets, fec_packet_list.size())
296 << "We requested " << num_fec_packets << " FEC packets, but "
brandtrece4aba2016-09-20 23:16:28 -0700297 << "EncodeFec() produced " << fec_packet_list.size();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000298
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200299 memset(media_loss_mask, 0, sizeof(media_loss_mask));
300 uint32_t media_packet_idx = 0;
brandtr35c480c2016-08-09 01:23:23 -0700301 for (const auto& media_packet : media_packet_list) {
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000302 // We want a value between 0 and 1.
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200303 const float loss_random_variable = random.Rand<float>();
niklase@google.com470e71d2011-07-07 08:21:25 +0000304
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200305 if (loss_random_variable >= loss_rate[loss_rate_idx]) {
306 media_loss_mask[media_packet_idx] = 1;
brandtr35c480c2016-08-09 01:23:23 -0700307 std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>
308 received_packet(
309 new ForwardErrorCorrection::ReceivedPacket());
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200310 received_packet->pkt = new ForwardErrorCorrection::Packet();
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200311 received_packet->pkt->length = media_packet->length;
312 memcpy(received_packet->pkt->data, media_packet->data,
313 media_packet->length);
brandtrd726a3f2017-06-29 02:45:35 -0700314 received_packet->ssrc = media_ssrc;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200315 received_packet->seq_num =
316 ByteReader<uint16_t>::ReadBigEndian(&media_packet->data[2]);
317 received_packet->is_fec = false;
brandtr35c480c2016-08-09 01:23:23 -0700318 received_packet_list.push_back(std::move(received_packet));
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000319 }
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200320 media_packet_idx++;
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000321 }
marpan@webrtc.org63b50f62011-12-08 19:05:39 +0000322
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200323 memset(fec_loss_mask, 0, sizeof(fec_loss_mask));
324 uint32_t fec_packet_idx = 0;
325 for (auto* fec_packet : fec_packet_list) {
326 const float loss_random_variable = random.Rand<float>();
327 if (loss_random_variable >= loss_rate[loss_rate_idx]) {
328 fec_loss_mask[fec_packet_idx] = 1;
brandtr35c480c2016-08-09 01:23:23 -0700329 std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>
330 received_packet(
331 new ForwardErrorCorrection::ReceivedPacket());
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200332 received_packet->pkt = new ForwardErrorCorrection::Packet();
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200333 received_packet->pkt->length = fec_packet->length;
334 memcpy(received_packet->pkt->data, fec_packet->data,
335 fec_packet->length);
brandtrd726a3f2017-06-29 02:45:35 -0700336 received_packet->seq_num = fec_seq_num_offset + seq_num;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200337 received_packet->is_fec = true;
brandtrd726a3f2017-06-29 02:45:35 -0700338 received_packet->ssrc = fec_ssrc;
brandtr35c480c2016-08-09 01:23:23 -0700339 received_packet_list.push_back(std::move(received_packet));
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200340
341 fec_mask_list.push_back(fec_packet_masks[fec_packet_idx]);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000342 }
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200343 ++fec_packet_idx;
344 ++seq_num;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000345 }
346
347#ifdef VERBOSE_OUTPUT
348 printf("Media loss mask:\n");
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200349 for (uint32_t i = 0; i < num_media_packets; i++) {
350 printf("%u ", media_loss_mask[i]);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000351 }
352 printf("\n\n");
353
354 printf("FEC loss mask:\n");
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200355 for (uint32_t i = 0; i < num_fec_packets; i++) {
356 printf("%u ", fec_loss_mask[i]);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000357 }
358 printf("\n\n");
359#endif
360
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200361 auto fec_mask_it = fec_mask_list.begin();
362 while (fec_mask_it != fec_mask_list.end()) {
363 uint32_t hamming_dist = 0;
364 uint32_t recovery_position = 0;
365 for (uint32_t i = 0; i < num_media_packets; i++) {
366 if (media_loss_mask[i] == 0 && (*fec_mask_it)[i] == 1) {
367 recovery_position = i;
368 ++hamming_dist;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000369 }
370 }
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200371 auto item_to_delete = fec_mask_it;
372 ++fec_mask_it;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000373
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200374 if (hamming_dist == 1) {
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000375 // Recovery possible. Restart search.
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200376 media_loss_mask[recovery_position] = 1;
377 fec_mask_it = fec_mask_list.begin();
378 } else if (hamming_dist == 0) {
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000379 // FEC packet cannot provide further recovery.
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200380 fec_mask_list.erase(item_to_delete);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000381 }
382 }
383#ifdef VERBOSE_OUTPUT
384 printf("Recovery mask:\n");
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200385 for (uint32_t i = 0; i < num_media_packets; ++i) {
386 printf("%u ", media_loss_mask[i]);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000387 }
388 printf("\n\n");
389#endif
390 // For error-checking frame completion.
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200391 bool fec_packet_received = false;
392 while (!received_packet_list.empty()) {
393 size_t num_packets_to_decode = random.Rand(
394 1u, static_cast<uint32_t>(received_packet_list.size()));
395 ReceivePackets(&to_decode_list, &received_packet_list,
396 num_packets_to_decode, reorder_rate,
397 duplicate_rate, &random);
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000398
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200399 if (fec_packet_received == false) {
brandtr35c480c2016-08-09 01:23:23 -0700400 for (const auto& received_packet : to_decode_list) {
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200401 if (received_packet->is_fec) {
402 fec_packet_received = true;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000403 }
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000404 }
405 }
brandtrece4aba2016-09-20 23:16:28 -0700406 ASSERT_EQ(0,
Rasmus Brandt78db1582016-09-21 09:19:34 +0200407 fec->DecodeFec(&to_decode_list, &recovered_packet_list))
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200408 << "DecodeFec() failed";
409 ASSERT_TRUE(to_decode_list.empty())
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +0000410 << "Received packet list is not empty.";
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000411 }
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200412 media_packet_idx = 0;
brandtr35c480c2016-08-09 01:23:23 -0700413 for (const auto& media_packet : media_packet_list) {
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200414 if (media_loss_mask[media_packet_idx] == 1) {
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000415 // Should have recovered this packet.
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200416 auto recovered_packet_list_it = recovered_packet_list.cbegin();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000417
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200418 ASSERT_FALSE(recovered_packet_list_it ==
419 recovered_packet_list.end())
danilchap40f349f2015-12-14 06:39:33 -0800420 << "Insufficient number of recovered packets.";
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200421 ForwardErrorCorrection::RecoveredPacket* recovered_packet =
brandtr35c480c2016-08-09 01:23:23 -0700422 recovered_packet_list_it->get();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000423
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200424 ASSERT_EQ(recovered_packet->pkt->length, media_packet->length)
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +0000425 << "Recovered packet length not identical to original "
426 << "media packet";
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200427 ASSERT_EQ(0, memcmp(recovered_packet->pkt->data,
428 media_packet->data, media_packet->length))
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +0000429 << "Recovered packet payload not identical to original "
430 << "media packet";
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200431 recovered_packet_list.pop_front();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000432 }
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200433 ++media_packet_idx;
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000434 }
Rasmus Brandt78db1582016-09-21 09:19:34 +0200435 fec->ResetState(&recovered_packet_list);
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200436 ASSERT_TRUE(recovered_packet_list.empty())
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +0000437 << "Excessive number of recovered packets.\t size is: "
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200438 << recovered_packet_list.size();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000439 // -- Teardown --
brandtr35c480c2016-08-09 01:23:23 -0700440 media_packet_list.clear();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000441
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200442 // Clear FEC packet list, so we don't pass in a non-empty
443 // list in the next call to DecodeFec().
444 fec_packet_list.clear();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000445
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200446 // Delete received packets we didn't pass to DecodeFec(), due to
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000447 // early frame completion.
brandtr35c480c2016-08-09 01:23:23 -0700448 received_packet_list.clear();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000449
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200450 while (!fec_mask_list.empty()) {
451 fec_mask_list.pop_front();
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000452 }
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200453 timestamp += 90000 / 30;
454 } // loop over num_imp_packets
danilchap40f349f2015-12-14 06:39:33 -0800455 } // loop over FecPackets
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200456 } // loop over num_media_packets
marpan@webrtc.org8866bb12012-06-05 16:42:20 +0000457 } // loop over loss rates
danilchap40f349f2015-12-14 06:39:33 -0800458 } // loop over mask types
marpan@webrtc.org63b50f62011-12-08 19:05:39 +0000459
brandtr35c480c2016-08-09 01:23:23 -0700460 // Have DecodeFec clear the recovered packet list.
Rasmus Brandt78db1582016-09-21 09:19:34 +0200461 fec->ResetState(&recovered_packet_list);
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200462 ASSERT_TRUE(recovered_packet_list.empty())
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +0000463 << "Recovered packet list is not empty";
niklase@google.com470e71d2011-07-07 08:21:25 +0000464}
465
brandtra25a6952017-08-01 05:01:07 -0700466TEST(FecTest, UlpfecTest) {
brandtrd726a3f2017-06-29 02:45:35 -0700467 RunTest(false);
468}
469
brandtra25a6952017-08-01 05:01:07 -0700470TEST(FecTest, FlexfecTest) {
brandtrd726a3f2017-06-29 02:45:35 -0700471 RunTest(true);
472}
473
kjellander@webrtc.org22bbbdf2013-06-12 11:55:05 +0000474} // namespace test
475} // namespace webrtc