OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 10 matching lines...) Loading... |
21 | 21 |
22 #include <list> | 22 #include <list> |
23 | 23 |
24 #include "testing/gtest/include/gtest/gtest.h" | 24 #include "testing/gtest/include/gtest/gtest.h" |
25 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" | 25 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" |
26 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h" | 26 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h" |
27 | 27 |
28 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" | 28 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
29 #include "webrtc/test/testsupport/fileutils.h" | 29 #include "webrtc/test/testsupport/fileutils.h" |
30 | 30 |
31 //#define VERBOSE_OUTPUT | 31 // #define VERBOSE_OUTPUT |
32 | 32 |
33 namespace webrtc { | 33 namespace webrtc { |
34 namespace fec_private_tables { | 34 namespace fec_private_tables { |
35 extern const uint8_t** kPacketMaskBurstyTbl[12]; | 35 extern const uint8_t** kPacketMaskBurstyTbl[12]; |
36 } | 36 } |
37 namespace test { | 37 namespace test { |
38 using fec_private_tables::kPacketMaskBurstyTbl; | 38 using fec_private_tables::kPacketMaskBurstyTbl; |
39 | 39 |
40 void ReceivePackets( | 40 void ReceivePackets( |
41 ForwardErrorCorrection::ReceivedPacketList* toDecodeList, | 41 ForwardErrorCorrection::ReceivedPacketList* toDecodeList, |
42 ForwardErrorCorrection::ReceivedPacketList* receivedPacketList, | 42 ForwardErrorCorrection::ReceivedPacketList* receivedPacketList, |
43 uint32_t numPacketsToDecode, float reorderRate, float duplicateRate) { | 43 uint32_t numPacketsToDecode, |
| 44 float reorderRate, |
| 45 float duplicateRate) { |
44 assert(toDecodeList->empty()); | 46 assert(toDecodeList->empty()); |
45 assert(numPacketsToDecode <= receivedPacketList->size()); | 47 assert(numPacketsToDecode <= receivedPacketList->size()); |
46 | 48 |
47 ForwardErrorCorrection::ReceivedPacketList::iterator it; | 49 ForwardErrorCorrection::ReceivedPacketList::iterator it; |
48 for (uint32_t i = 0; i < numPacketsToDecode; i++) { | 50 for (uint32_t i = 0; i < numPacketsToDecode; i++) { |
49 it = receivedPacketList->begin(); | 51 it = receivedPacketList->begin(); |
50 // Reorder packets. | 52 // Reorder packets. |
51 float randomVariable = static_cast<float>(rand()) / RAND_MAX; | 53 float randomVariable = static_cast<float>(rand()) / RAND_MAX; |
52 while (randomVariable < reorderRate) { | 54 while (randomVariable < reorderRate) { |
53 ++it; | 55 ++it; |
(...skipping 19 matching lines...) Loading... |
73 | 75 |
74 toDecodeList->push_back(duplicatePacket); | 76 toDecodeList->push_back(duplicatePacket); |
75 randomVariable = static_cast<float>(rand()) / RAND_MAX; | 77 randomVariable = static_cast<float>(rand()) / RAND_MAX; |
76 } | 78 } |
77 receivedPacketList->erase(it); | 79 receivedPacketList->erase(it); |
78 } | 80 } |
79 } | 81 } |
80 | 82 |
81 TEST(FecTest, FecTest) { | 83 TEST(FecTest, FecTest) { |
82 // TODO(marpan): Split this function into subroutines/helper functions. | 84 // TODO(marpan): Split this function into subroutines/helper functions. |
83 enum { | 85 enum { kMaxNumberMediaPackets = 48 }; |
84 kMaxNumberMediaPackets = 48 | 86 enum { kMaxNumberFecPackets = 48 }; |
85 }; | |
86 enum { | |
87 kMaxNumberFecPackets = 48 | |
88 }; | |
89 | 87 |
90 const uint32_t kNumMaskBytesL0 = 2; | 88 const uint32_t kNumMaskBytesL0 = 2; |
91 const uint32_t kNumMaskBytesL1 = 6; | 89 const uint32_t kNumMaskBytesL1 = 6; |
92 | 90 |
93 // FOR UEP | 91 // FOR UEP |
94 const bool kUseUnequalProtection = true; | 92 const bool kUseUnequalProtection = true; |
95 | 93 |
96 // FEC mask types. | 94 // FEC mask types. |
97 const FecMaskType kMaskTypes[] = { kFecMaskRandom, kFecMaskBursty }; | 95 const FecMaskType kMaskTypes[] = {kFecMaskRandom, kFecMaskBursty}; |
98 const int kNumFecMaskTypes = sizeof(kMaskTypes) / sizeof(*kMaskTypes); | 96 const int kNumFecMaskTypes = sizeof(kMaskTypes) / sizeof(*kMaskTypes); |
99 | 97 |
100 // Maximum number of media packets allowed for the mask type. | 98 // Maximum number of media packets allowed for the mask type. |
101 const uint16_t kMaxMediaPackets[] = {kMaxNumberMediaPackets, | 99 const uint16_t kMaxMediaPackets[] = { |
| 100 kMaxNumberMediaPackets, |
102 sizeof(kPacketMaskBurstyTbl) / sizeof(*kPacketMaskBurstyTbl)}; | 101 sizeof(kPacketMaskBurstyTbl) / sizeof(*kPacketMaskBurstyTbl)}; |
103 | 102 |
104 ASSERT_EQ(12, kMaxMediaPackets[1]) << "Max media packets for bursty mode not " | 103 ASSERT_EQ(12, kMaxMediaPackets[1]) << "Max media packets for bursty mode not " |
105 << "equal to 12."; | 104 << "equal to 12."; |
106 | 105 |
107 ForwardErrorCorrection fec; | 106 ForwardErrorCorrection fec; |
108 ForwardErrorCorrection::PacketList mediaPacketList; | 107 ForwardErrorCorrection::PacketList mediaPacketList; |
109 ForwardErrorCorrection::PacketList fecPacketList; | 108 ForwardErrorCorrection::PacketList fecPacketList; |
110 ForwardErrorCorrection::ReceivedPacketList toDecodeList; | 109 ForwardErrorCorrection::ReceivedPacketList toDecodeList; |
111 ForwardErrorCorrection::ReceivedPacketList receivedPacketList; | 110 ForwardErrorCorrection::ReceivedPacketList receivedPacketList; |
112 ForwardErrorCorrection::RecoveredPacketList recoveredPacketList; | 111 ForwardErrorCorrection::RecoveredPacketList recoveredPacketList; |
113 std::list<uint8_t*> fecMaskList; | 112 std::list<uint8_t*> fecMaskList; |
114 | 113 |
115 ForwardErrorCorrection::Packet* mediaPacket = NULL; | 114 ForwardErrorCorrection::Packet* mediaPacket = NULL; |
116 // Running over only one loss rate to limit execution time. | 115 // Running over only one loss rate to limit execution time. |
117 const float lossRate[] = { 0.5f }; | 116 const float lossRate[] = {0.5f}; |
118 const uint32_t lossRateSize = sizeof(lossRate) / sizeof(*lossRate); | 117 const uint32_t lossRateSize = sizeof(lossRate) / sizeof(*lossRate); |
119 const float reorderRate = 0.1f; | 118 const float reorderRate = 0.1f; |
120 const float duplicateRate = 0.1f; | 119 const float duplicateRate = 0.1f; |
121 | 120 |
122 uint8_t mediaLossMask[kMaxNumberMediaPackets]; | 121 uint8_t mediaLossMask[kMaxNumberMediaPackets]; |
123 uint8_t fecLossMask[kMaxNumberFecPackets]; | 122 uint8_t fecLossMask[kMaxNumberFecPackets]; |
124 uint8_t fecPacketMasks[kMaxNumberFecPackets][kMaxNumberMediaPackets]; | 123 uint8_t fecPacketMasks[kMaxNumberFecPackets][kMaxNumberMediaPackets]; |
125 | 124 |
126 // Seed the random number generator, storing the seed to file in order to | 125 // Seed the random number generator, storing the seed to file in order to |
127 // reproduce past results. | 126 // reproduce past results. |
128 const unsigned int randomSeed = static_cast<unsigned int>(time(NULL)); | 127 const unsigned int randomSeed = static_cast<unsigned int>(time(NULL)); |
129 srand(randomSeed); | 128 srand(randomSeed); |
130 std::string filename = webrtc::test::OutputPath() + "randomSeedLog.txt"; | 129 std::string filename = webrtc::test::OutputPath() + "randomSeedLog.txt"; |
131 FILE* randomSeedFile = fopen(filename.c_str(), "a"); | 130 FILE* randomSeedFile = fopen(filename.c_str(), "a"); |
132 fprintf(randomSeedFile, "%u\n", randomSeed); | 131 fprintf(randomSeedFile, "%u\n", randomSeed); |
133 fclose(randomSeedFile); | 132 fclose(randomSeedFile); |
134 randomSeedFile = NULL; | 133 randomSeedFile = NULL; |
135 | 134 |
136 uint16_t seqNum = 0; | 135 uint16_t seqNum = 0; |
137 uint32_t timeStamp = static_cast<uint32_t>(rand()); | 136 uint32_t timeStamp = static_cast<uint32_t>(rand()); |
138 const uint32_t ssrc = static_cast<uint32_t>(rand()); | 137 const uint32_t ssrc = static_cast<uint32_t>(rand()); |
139 | 138 |
140 // Loop over the mask types: random and bursty. | 139 // Loop over the mask types: random and bursty. |
141 for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes; | 140 for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes; |
142 ++mask_type_idx) { | 141 ++mask_type_idx) { |
143 | |
144 for (uint32_t lossRateIdx = 0; lossRateIdx < lossRateSize; ++lossRateIdx) { | 142 for (uint32_t lossRateIdx = 0; lossRateIdx < lossRateSize; ++lossRateIdx) { |
145 | |
146 printf("Loss rate: %.2f, Mask type %d \n", lossRate[lossRateIdx], | 143 printf("Loss rate: %.2f, Mask type %d \n", lossRate[lossRateIdx], |
147 mask_type_idx); | 144 mask_type_idx); |
148 | 145 |
149 const uint32_t packetMaskMax = kMaxMediaPackets[mask_type_idx]; | 146 const uint32_t packetMaskMax = kMaxMediaPackets[mask_type_idx]; |
150 uint8_t* packetMask = new uint8_t[packetMaskMax * kNumMaskBytesL1]; | 147 uint8_t* packetMask = new uint8_t[packetMaskMax * kNumMaskBytesL1]; |
151 | 148 |
152 FecMaskType fec_mask_type = kMaskTypes[mask_type_idx]; | 149 FecMaskType fec_mask_type = kMaskTypes[mask_type_idx]; |
153 | 150 |
154 for (uint32_t numMediaPackets = 1; numMediaPackets <= packetMaskMax; | 151 for (uint32_t numMediaPackets = 1; numMediaPackets <= packetMaskMax; |
155 numMediaPackets++) { | 152 numMediaPackets++) { |
156 internal::PacketMaskTable mask_table(fec_mask_type, numMediaPackets); | 153 internal::PacketMaskTable mask_table(fec_mask_type, numMediaPackets); |
157 | 154 |
158 for (uint32_t numFecPackets = 1; | 155 for (uint32_t numFecPackets = 1; |
159 numFecPackets <= numMediaPackets && numFecPackets <= packetMaskMax; | 156 numFecPackets <= numMediaPackets && numFecPackets <= packetMaskMax; |
160 numFecPackets++) { | 157 numFecPackets++) { |
161 | |
162 // Loop over numImpPackets: usually <= (0.3*numMediaPackets). | 158 // Loop over numImpPackets: usually <= (0.3*numMediaPackets). |
163 // For this test we check up to ~ (numMediaPackets / 4). | 159 // For this test we check up to ~ (numMediaPackets / 4). |
164 uint32_t maxNumImpPackets = numMediaPackets / 4 + 1; | 160 uint32_t maxNumImpPackets = numMediaPackets / 4 + 1; |
165 for (uint32_t numImpPackets = 0; numImpPackets <= maxNumImpPackets && | 161 for (uint32_t numImpPackets = 0; numImpPackets <= maxNumImpPackets && |
166 numImpPackets <= packetMaskMax; | 162 numImpPackets <= packetMaskMax; |
167 numImpPackets++) { | 163 numImpPackets++) { |
168 | |
169 uint8_t protectionFactor = | 164 uint8_t protectionFactor = |
170 static_cast<uint8_t>(numFecPackets * 255 / numMediaPackets); | 165 static_cast<uint8_t>(numFecPackets * 255 / numMediaPackets); |
171 | 166 |
172 const uint32_t maskBytesPerFecPacket = | 167 const uint32_t maskBytesPerFecPacket = |
173 (numMediaPackets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0; | 168 (numMediaPackets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0; |
174 | 169 |
175 memset(packetMask, 0, numMediaPackets * maskBytesPerFecPacket); | 170 memset(packetMask, 0, numMediaPackets * maskBytesPerFecPacket); |
176 | 171 |
177 // Transfer packet masks from bit-mask to byte-mask. | 172 // Transfer packet masks from bit-mask to byte-mask. |
178 internal::GeneratePacketMasks(numMediaPackets, numFecPackets, | 173 internal::GeneratePacketMasks(numMediaPackets, numFecPackets, |
179 numImpPackets, kUseUnequalProtection, | 174 numImpPackets, kUseUnequalProtection, |
180 mask_table, packetMask); | 175 mask_table, packetMask); |
181 | 176 |
182 #ifdef VERBOSE_OUTPUT | 177 #ifdef VERBOSE_OUTPUT |
183 printf("%u media packets, %u FEC packets, %u numImpPackets, " | 178 printf( |
184 "loss rate = %.2f \n", | 179 "%u media packets, %u FEC packets, %u numImpPackets, " |
185 numMediaPackets, numFecPackets, numImpPackets, | 180 "loss rate = %.2f \n", |
186 lossRate[lossRateIdx]); | 181 numMediaPackets, numFecPackets, numImpPackets, |
| 182 lossRate[lossRateIdx]); |
187 printf("Packet mask matrix \n"); | 183 printf("Packet mask matrix \n"); |
188 #endif | 184 #endif |
189 | 185 |
190 for (uint32_t i = 0; i < numFecPackets; i++) { | 186 for (uint32_t i = 0; i < numFecPackets; i++) { |
191 for (uint32_t j = 0; j < numMediaPackets; j++) { | 187 for (uint32_t j = 0; j < numMediaPackets; j++) { |
192 const uint8_t byteMask = | 188 const uint8_t byteMask = |
193 packetMask[i * maskBytesPerFecPacket + j / 8]; | 189 packetMask[i * maskBytesPerFecPacket + j / 8]; |
194 const uint32_t bitPosition = (7 - j % 8); | 190 const uint32_t bitPosition = (7 - j % 8); |
195 fecPacketMasks[i][j] = | 191 fecPacketMasks[i][j] = |
196 (byteMask & (1 << bitPosition)) >> bitPosition; | 192 (byteMask & (1 << bitPosition)) >> bitPosition; |
(...skipping 184 matching lines...) Loading... |
381 for (uint32_t i = 0; i < numMediaPackets; ++i) { | 377 for (uint32_t i = 0; i < numMediaPackets; ++i) { |
382 printf("%u ", mediaLossMask[i]); | 378 printf("%u ", mediaLossMask[i]); |
383 } | 379 } |
384 printf("\n\n"); | 380 printf("\n\n"); |
385 #endif | 381 #endif |
386 // For error-checking frame completion. | 382 // For error-checking frame completion. |
387 bool fecPacketReceived = false; | 383 bool fecPacketReceived = false; |
388 while (!receivedPacketList.empty()) { | 384 while (!receivedPacketList.empty()) { |
389 uint32_t numPacketsToDecode = static_cast<uint32_t>( | 385 uint32_t numPacketsToDecode = static_cast<uint32_t>( |
390 (static_cast<float>(rand()) / RAND_MAX) * | 386 (static_cast<float>(rand()) / RAND_MAX) * |
391 receivedPacketList.size() + 0.5); | 387 receivedPacketList.size() + |
| 388 0.5); |
392 if (numPacketsToDecode < 1) { | 389 if (numPacketsToDecode < 1) { |
393 numPacketsToDecode = 1; | 390 numPacketsToDecode = 1; |
394 } | 391 } |
395 ReceivePackets(&toDecodeList, &receivedPacketList, | 392 ReceivePackets(&toDecodeList, &receivedPacketList, |
396 numPacketsToDecode, reorderRate, duplicateRate); | 393 numPacketsToDecode, reorderRate, duplicateRate); |
397 | 394 |
398 if (fecPacketReceived == false) { | 395 if (fecPacketReceived == false) { |
399 ForwardErrorCorrection::ReceivedPacketList::iterator | 396 ForwardErrorCorrection::ReceivedPacketList::iterator |
400 toDecodeIt = toDecodeList.begin(); | 397 toDecodeIt = toDecodeList.begin(); |
401 while (toDecodeIt != toDecodeList.end()) { | 398 while (toDecodeIt != toDecodeList.end()) { |
402 receivedPacket = *toDecodeIt; | 399 receivedPacket = *toDecodeIt; |
403 if (receivedPacket->is_fec) { | 400 if (receivedPacket->is_fec) { |
404 fecPacketReceived = true; | 401 fecPacketReceived = true; |
405 } | 402 } |
406 ++toDecodeIt; | 403 ++toDecodeIt; |
407 } | 404 } |
408 } | 405 } |
409 ASSERT_EQ(0, fec.DecodeFEC(&toDecodeList, &recoveredPacketList)) | 406 ASSERT_EQ(0, fec.DecodeFEC(&toDecodeList, &recoveredPacketList)) |
410 << "DecodeFEC() failed"; | 407 << "DecodeFEC() failed"; |
411 ASSERT_TRUE(toDecodeList.empty()) | 408 ASSERT_TRUE(toDecodeList.empty()) |
412 << "Received packet list is not empty."; | 409 << "Received packet list is not empty."; |
413 } | 410 } |
414 mediaPacketListItem = mediaPacketList.begin(); | 411 mediaPacketListItem = mediaPacketList.begin(); |
415 mediaPacketIdx = 0; | 412 mediaPacketIdx = 0; |
416 while (mediaPacketListItem != mediaPacketList.end()) { | 413 while (mediaPacketListItem != mediaPacketList.end()) { |
417 if (mediaLossMask[mediaPacketIdx] == 1) { | 414 if (mediaLossMask[mediaPacketIdx] == 1) { |
418 // Should have recovered this packet. | 415 // Should have recovered this packet. |
419 ForwardErrorCorrection::RecoveredPacketList::iterator | 416 ForwardErrorCorrection::RecoveredPacketList::iterator |
420 recoveredPacketListItem = recoveredPacketList.begin(); | 417 recoveredPacketListItem = recoveredPacketList.begin(); |
421 | 418 |
422 ASSERT_FALSE( | 419 ASSERT_FALSE(recoveredPacketListItem == |
423 recoveredPacketListItem == recoveredPacketList.end()) | 420 recoveredPacketList.end()) |
424 << "Insufficient number of recovered packets."; | 421 << "Insufficient number of recovered packets."; |
425 mediaPacket = *mediaPacketListItem; | 422 mediaPacket = *mediaPacketListItem; |
426 ForwardErrorCorrection::RecoveredPacket* recoveredPacket = | 423 ForwardErrorCorrection::RecoveredPacket* recoveredPacket = |
427 *recoveredPacketListItem; | 424 *recoveredPacketListItem; |
428 | 425 |
429 ASSERT_EQ(recoveredPacket->pkt->length, mediaPacket->length) | 426 ASSERT_EQ(recoveredPacket->pkt->length, mediaPacket->length) |
430 << "Recovered packet length not identical to original " | 427 << "Recovered packet length not identical to original " |
431 << "media packet"; | 428 << "media packet"; |
432 ASSERT_EQ(0, memcmp(recoveredPacket->pkt->data, | 429 ASSERT_EQ(0, memcmp(recoveredPacket->pkt->data, |
433 mediaPacket->data, mediaPacket->length)) | 430 mediaPacket->data, mediaPacket->length)) |
434 << "Recovered packet payload not identical to original " | 431 << "Recovered packet payload not identical to original " |
(...skipping 19 matching lines...) Loading... |
454 | 451 |
455 fecPacketListItem = fecPacketList.begin(); | 452 fecPacketListItem = fecPacketList.begin(); |
456 while (fecPacketListItem != fecPacketList.end()) { | 453 while (fecPacketListItem != fecPacketList.end()) { |
457 ++fecPacketListItem; | 454 ++fecPacketListItem; |
458 fecPacketList.pop_front(); | 455 fecPacketList.pop_front(); |
459 } | 456 } |
460 | 457 |
461 // Delete received packets we didn't pass to DecodeFEC(), due to | 458 // Delete received packets we didn't pass to DecodeFEC(), due to |
462 // early frame completion. | 459 // early frame completion. |
463 ForwardErrorCorrection::ReceivedPacketList::iterator | 460 ForwardErrorCorrection::ReceivedPacketList::iterator |
464 receivedPacketIt = receivedPacketList.begin(); | 461 receivedPacketIt = receivedPacketList.begin(); |
465 while (receivedPacketIt != receivedPacketList.end()) { | 462 while (receivedPacketIt != receivedPacketList.end()) { |
466 receivedPacket = *receivedPacketIt; | 463 receivedPacket = *receivedPacketIt; |
467 delete receivedPacket; | 464 delete receivedPacket; |
468 ++receivedPacketIt; | 465 ++receivedPacketIt; |
469 receivedPacketList.pop_front(); | 466 receivedPacketList.pop_front(); |
470 } | 467 } |
471 assert(receivedPacketList.empty()); | 468 assert(receivedPacketList.empty()); |
472 | 469 |
473 while (!fecMaskList.empty()) { | 470 while (!fecMaskList.empty()) { |
474 fecMaskList.pop_front(); | 471 fecMaskList.pop_front(); |
475 } | 472 } |
476 timeStamp += 90000 / 30; | 473 timeStamp += 90000 / 30; |
477 } // loop over numImpPackets | 474 } // loop over numImpPackets |
478 } // loop over FecPackets | 475 } // loop over FecPackets |
479 } // loop over numMediaPackets | 476 } // loop over numMediaPackets |
480 delete[] packetMask; | 477 delete[] packetMask; |
481 } // loop over loss rates | 478 } // loop over loss rates |
482 } // loop over mask types | 479 } // loop over mask types |
483 | 480 |
484 // Have DecodeFEC free allocated memory. | 481 // Have DecodeFEC free allocated memory. |
485 fec.ResetState(&recoveredPacketList); | 482 fec.ResetState(&recoveredPacketList); |
486 ASSERT_TRUE(recoveredPacketList.empty()) | 483 ASSERT_TRUE(recoveredPacketList.empty()) |
487 << "Recovered packet list is not empty"; | 484 << "Recovered packet list is not empty"; |
488 } | 485 } |
489 | 486 |
490 } // namespace test | 487 } // namespace test |
491 } // namespace webrtc | 488 } // namespace webrtc |
OLD | NEW |