| 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 |
| 11 /* | 11 /* |
| 12 * Test application for core FEC algorithm. Calls encoding and decoding | 12 * Test application for core FEC algorithm. Calls encoding and decoding |
| 13 * functions in ForwardErrorCorrection directly. | 13 * functions in ForwardErrorCorrection directly. |
| 14 */ | 14 */ |
| 15 | 15 |
| 16 #include <assert.h> | |
| 17 #include <stdio.h> | |
| 18 #include <stdlib.h> | |
| 19 #include <string.h> | 16 #include <string.h> |
| 20 #include <time.h> | 17 #include <time.h> |
| 21 | 18 |
| 22 #include <list> | 19 #include <list> |
| 23 | 20 |
| 24 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
| 25 #include "webrtc/base/random.h" | 22 #include "webrtc/base/random.h" |
| 26 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" | 23 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
| 27 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" | 24 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" |
| 28 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h" | 25 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h" |
| 29 #include "webrtc/test/testsupport/fileutils.h" | 26 #include "webrtc/test/testsupport/fileutils.h" |
| 30 | 27 |
| 31 // #define VERBOSE_OUTPUT | 28 // #define VERBOSE_OUTPUT |
| 32 | 29 |
| 33 namespace webrtc { | 30 namespace webrtc { |
| 34 namespace fec_private_tables { | 31 namespace fec_private_tables { |
| 35 extern const uint8_t** kPacketMaskBurstyTbl[12]; | 32 extern const uint8_t** kPacketMaskBurstyTbl[12]; |
| 36 } | 33 } |
| 37 namespace test { | 34 namespace test { |
| 38 using fec_private_tables::kPacketMaskBurstyTbl; | 35 using fec_private_tables::kPacketMaskBurstyTbl; |
| 39 | 36 |
| 40 void ReceivePackets( | 37 void ReceivePackets( |
| 41 ForwardErrorCorrection::ReceivedPacketList* toDecodeList, | 38 ForwardErrorCorrection::ReceivedPacketList* to_decode_list, |
| 42 ForwardErrorCorrection::ReceivedPacketList* receivedPacketList, | 39 ForwardErrorCorrection::ReceivedPacketList* received_packet_list, |
| 43 size_t numPacketsToDecode, | 40 size_t num_packets_to_decode, |
| 44 float reorderRate, | 41 float reorder_rate, |
| 45 float duplicateRate, | 42 float duplicate_rate, |
| 46 Random* random) { | 43 Random* random) { |
| 47 assert(toDecodeList->empty()); | 44 RTC_DCHECK(to_decode_list->empty()); |
| 48 assert(numPacketsToDecode <= receivedPacketList->size()); | 45 RTC_DCHECK_LE(num_packets_to_decode, received_packet_list->size()); |
| 49 | 46 |
| 50 ForwardErrorCorrection::ReceivedPacketList::iterator it; | 47 for (size_t i = 0; i < num_packets_to_decode; i++) { |
| 51 for (size_t i = 0; i < numPacketsToDecode; i++) { | 48 auto it = received_packet_list->begin(); |
| 52 it = receivedPacketList->begin(); | |
| 53 // Reorder packets. | 49 // Reorder packets. |
| 54 float randomVariable = random->Rand<float>(); | 50 float random_variable = random->Rand<float>(); |
| 55 while (randomVariable < reorderRate) { | 51 while (random_variable < reorder_rate) { |
| 56 ++it; | 52 ++it; |
| 57 if (it == receivedPacketList->end()) { | 53 if (it == received_packet_list->end()) { |
| 58 --it; | 54 --it; |
| 59 break; | 55 break; |
| 60 } | 56 } |
| 61 randomVariable = random->Rand<float>(); | 57 random_variable = random->Rand<float>(); |
| 62 } | 58 } |
| 63 ForwardErrorCorrection::ReceivedPacket* receivedPacket = *it; | 59 ForwardErrorCorrection::ReceivedPacket* received_packet = *it; |
| 64 toDecodeList->push_back(receivedPacket); | 60 to_decode_list->push_back(received_packet); |
| 65 | 61 |
| 66 // Duplicate packets. | 62 // Duplicate packets. |
| 67 randomVariable = random->Rand<float>(); | 63 random_variable = random->Rand<float>(); |
| 68 while (randomVariable < duplicateRate) { | 64 while (random_variable < duplicate_rate) { |
| 69 ForwardErrorCorrection::ReceivedPacket* duplicatePacket = | 65 ForwardErrorCorrection::ReceivedPacket* duplicate_packet = |
| 70 new ForwardErrorCorrection::ReceivedPacket; | 66 new ForwardErrorCorrection::ReceivedPacket(); |
| 71 *duplicatePacket = *receivedPacket; | 67 *duplicate_packet = *received_packet; |
| 72 duplicatePacket->pkt = new ForwardErrorCorrection::Packet; | 68 duplicate_packet->pkt = new ForwardErrorCorrection::Packet(); |
| 73 memcpy(duplicatePacket->pkt->data, receivedPacket->pkt->data, | 69 memcpy(duplicate_packet->pkt->data, received_packet->pkt->data, |
| 74 receivedPacket->pkt->length); | 70 received_packet->pkt->length); |
| 75 duplicatePacket->pkt->length = receivedPacket->pkt->length; | 71 duplicate_packet->pkt->length = received_packet->pkt->length; |
| 76 | 72 |
| 77 toDecodeList->push_back(duplicatePacket); | 73 to_decode_list->push_back(duplicate_packet); |
| 78 randomVariable = random->Rand<float>(); | 74 random_variable = random->Rand<float>(); |
| 79 } | 75 } |
| 80 receivedPacketList->erase(it); | 76 received_packet_list->erase(it); |
| 81 } | 77 } |
| 82 } | 78 } |
| 83 | 79 |
| 84 // Too slow to finish before timeout on iOS. See webrtc:4755. | 80 // Too slow to finish before timeout on iOS. See webrtc:4755. |
| 85 #if defined(WEBRTC_IOS) | 81 #if defined(WEBRTC_IOS) |
| 86 #define MAYBE_FecTest DISABLED_FecTest | 82 #define MAYBE_FecTest DISABLED_FecTest |
| 87 #else | 83 #else |
| 88 #define MAYBE_FecTest FecTest | 84 #define MAYBE_FecTest FecTest |
| 89 #endif | 85 #endif |
| 90 TEST(FecTest, MAYBE_FecTest) { | 86 TEST(FecTest, MAYBE_FecTest) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 104 | 100 |
| 105 // Maximum number of media packets allowed for the mask type. | 101 // Maximum number of media packets allowed for the mask type. |
| 106 const uint16_t kMaxMediaPackets[] = { | 102 const uint16_t kMaxMediaPackets[] = { |
| 107 kMaxNumberMediaPackets, | 103 kMaxNumberMediaPackets, |
| 108 sizeof(kPacketMaskBurstyTbl) / sizeof(*kPacketMaskBurstyTbl)}; | 104 sizeof(kPacketMaskBurstyTbl) / sizeof(*kPacketMaskBurstyTbl)}; |
| 109 | 105 |
| 110 ASSERT_EQ(12, kMaxMediaPackets[1]) << "Max media packets for bursty mode not " | 106 ASSERT_EQ(12, kMaxMediaPackets[1]) << "Max media packets for bursty mode not " |
| 111 << "equal to 12."; | 107 << "equal to 12."; |
| 112 | 108 |
| 113 ForwardErrorCorrection fec; | 109 ForwardErrorCorrection fec; |
| 114 ForwardErrorCorrection::PacketList mediaPacketList; | 110 ForwardErrorCorrection::PacketList media_packet_list; |
| 115 ForwardErrorCorrection::PacketList fecPacketList; | 111 ForwardErrorCorrection::PacketList fec_packet_list; |
| 116 ForwardErrorCorrection::ReceivedPacketList toDecodeList; | 112 ForwardErrorCorrection::ReceivedPacketList to_decode_list; |
| 117 ForwardErrorCorrection::ReceivedPacketList receivedPacketList; | 113 ForwardErrorCorrection::ReceivedPacketList received_packet_list; |
| 118 ForwardErrorCorrection::RecoveredPacketList recoveredPacketList; | 114 ForwardErrorCorrection::RecoveredPacketList recovered_packet_list; |
| 119 std::list<uint8_t*> fecMaskList; | 115 std::list<uint8_t*> fec_mask_list; |
| 120 | 116 |
| 121 ForwardErrorCorrection::Packet* mediaPacket = NULL; | 117 ForwardErrorCorrection::Packet* media_packet = nullptr; |
| 122 // Running over only one loss rate to limit execution time. | 118 // Running over only one loss rate to limit execution time. |
| 123 const float lossRate[] = {0.5f}; | 119 const float loss_rate[] = {0.5f}; |
| 124 const uint32_t lossRateSize = sizeof(lossRate) / sizeof(*lossRate); | 120 const uint32_t loss_rate_size = sizeof(loss_rate) / sizeof(*loss_rate); |
| 125 const float reorderRate = 0.1f; | 121 const float reorder_rate = 0.1f; |
| 126 const float duplicateRate = 0.1f; | 122 const float duplicate_rate = 0.1f; |
| 127 | 123 |
| 128 uint8_t mediaLossMask[kMaxNumberMediaPackets]; | 124 uint8_t media_loss_mask[kMaxNumberMediaPackets]; |
| 129 uint8_t fecLossMask[kMaxNumberFecPackets]; | 125 uint8_t fec_loss_mask[kMaxNumberFecPackets]; |
| 130 uint8_t fecPacketMasks[kMaxNumberFecPackets][kMaxNumberMediaPackets]; | 126 uint8_t fec_packet_masks[kMaxNumberFecPackets][kMaxNumberMediaPackets]; |
| 131 | 127 |
| 132 // Seed the random number generator, storing the seed to file in order to | 128 // Seed the random number generator, storing the seed to file in order to |
| 133 // reproduce past results. | 129 // reproduce past results. |
| 134 const unsigned int randomSeed = static_cast<unsigned int>(time(NULL)); | 130 const unsigned int random_seed = static_cast<unsigned int>(time(nullptr)); |
| 135 Random random(randomSeed); | 131 Random random(random_seed); |
| 136 std::string filename = webrtc::test::OutputPath() + "randomSeedLog.txt"; | 132 std::string filename = webrtc::test::OutputPath() + "randomSeedLog.txt"; |
| 137 FILE* randomSeedFile = fopen(filename.c_str(), "a"); | 133 FILE* random_seed_file = fopen(filename.c_str(), "a"); |
| 138 fprintf(randomSeedFile, "%u\n", randomSeed); | 134 fprintf(random_seed_file, "%u\n", random_seed); |
| 139 fclose(randomSeedFile); | 135 fclose(random_seed_file); |
| 140 randomSeedFile = NULL; | 136 random_seed_file = nullptr; |
| 141 | 137 |
| 142 uint16_t seqNum = 0; | 138 uint16_t seq_num = 0; |
| 143 uint32_t timeStamp = random.Rand<uint32_t>(); | 139 uint32_t timestamp = random.Rand<uint32_t>(); |
| 144 const uint32_t ssrc = random.Rand(1u, 0xfffffffe); | 140 const uint32_t ssrc = random.Rand(1u, 0xfffffffe); |
| 145 | 141 |
| 146 // Loop over the mask types: random and bursty. | 142 // Loop over the mask types: random and bursty. |
| 147 for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes; | 143 for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes; |
| 148 ++mask_type_idx) { | 144 ++mask_type_idx) { |
| 149 for (uint32_t lossRateIdx = 0; lossRateIdx < lossRateSize; ++lossRateIdx) { | 145 for (uint32_t loss_rate_idx = 0; loss_rate_idx < loss_rate_size; |
| 150 printf("Loss rate: %.2f, Mask type %d \n", lossRate[lossRateIdx], | 146 ++loss_rate_idx) { |
| 147 printf("Loss rate: %.2f, Mask type %d \n", loss_rate[loss_rate_idx], |
| 151 mask_type_idx); | 148 mask_type_idx); |
| 152 | 149 |
| 153 const uint32_t packetMaskMax = kMaxMediaPackets[mask_type_idx]; | 150 const uint32_t packet_mask_max = kMaxMediaPackets[mask_type_idx]; |
| 154 uint8_t* packetMask = new uint8_t[packetMaskMax * kNumMaskBytesL1]; | 151 std::unique_ptr<uint8_t[]> packet_mask( |
| 152 new uint8_t[packet_mask_max * kNumMaskBytesL1]); |
| 155 | 153 |
| 156 FecMaskType fec_mask_type = kMaskTypes[mask_type_idx]; | 154 FecMaskType fec_mask_type = kMaskTypes[mask_type_idx]; |
| 157 | 155 |
| 158 for (uint32_t numMediaPackets = 1; numMediaPackets <= packetMaskMax; | 156 for (uint32_t num_media_packets = 1; num_media_packets <= packet_mask_max; |
| 159 numMediaPackets++) { | 157 num_media_packets++) { |
| 160 internal::PacketMaskTable mask_table(fec_mask_type, numMediaPackets); | 158 internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets); |
| 161 | 159 |
| 162 for (uint32_t numFecPackets = 1; | 160 for (uint32_t num_fec_packets = 1; |
| 163 numFecPackets <= numMediaPackets && numFecPackets <= packetMaskMax; | 161 num_fec_packets <= num_media_packets && |
| 164 numFecPackets++) { | 162 num_fec_packets <= packet_mask_max; |
| 165 // Loop over numImpPackets: usually <= (0.3*numMediaPackets). | 163 num_fec_packets++) { |
| 166 // For this test we check up to ~ (numMediaPackets / 4). | 164 // Loop over num_imp_packets: usually <= (0.3*num_media_packets). |
| 167 uint32_t maxNumImpPackets = numMediaPackets / 4 + 1; | 165 // For this test we check up to ~ (num_media_packets / 4). |
| 168 for (uint32_t numImpPackets = 0; numImpPackets <= maxNumImpPackets && | 166 uint32_t max_num_imp_packets = num_media_packets / 4 + 1; |
| 169 numImpPackets <= packetMaskMax; | 167 for (uint32_t num_imp_packets = 0; |
| 170 numImpPackets++) { | 168 num_imp_packets <= max_num_imp_packets && |
| 171 uint8_t protectionFactor = | 169 num_imp_packets <= packet_mask_max; |
| 172 static_cast<uint8_t>(numFecPackets * 255 / numMediaPackets); | 170 num_imp_packets++) { |
| 171 uint8_t protection_factor = |
| 172 static_cast<uint8_t>(num_fec_packets * 255 / num_media_packets); |
| 173 | 173 |
| 174 const uint32_t maskBytesPerFecPacket = | 174 const uint32_t mask_bytes_per_fec_packet = |
| 175 (numMediaPackets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0; | 175 (num_media_packets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0; |
| 176 | 176 |
| 177 memset(packetMask, 0, numMediaPackets * maskBytesPerFecPacket); | 177 memset(packet_mask.get(), 0, |
| 178 num_media_packets * mask_bytes_per_fec_packet); |
| 178 | 179 |
| 179 // Transfer packet masks from bit-mask to byte-mask. | 180 // Transfer packet masks from bit-mask to byte-mask. |
| 180 internal::GeneratePacketMasks(numMediaPackets, numFecPackets, | 181 internal::GeneratePacketMasks(num_media_packets, num_fec_packets, |
| 181 numImpPackets, kUseUnequalProtection, | 182 num_imp_packets, |
| 182 mask_table, packetMask); | 183 kUseUnequalProtection, |
| 184 mask_table, packet_mask.get()); |
| 183 | 185 |
| 184 #ifdef VERBOSE_OUTPUT | 186 #ifdef VERBOSE_OUTPUT |
| 185 printf( | 187 printf( |
| 186 "%u media packets, %u FEC packets, %u numImpPackets, " | 188 "%u media packets, %u FEC packets, %u num_imp_packets, " |
| 187 "loss rate = %.2f \n", | 189 "loss rate = %.2f \n", |
| 188 numMediaPackets, numFecPackets, numImpPackets, | 190 num_media_packets, num_fec_packets, num_imp_packets, |
| 189 lossRate[lossRateIdx]); | 191 loss_rate[loss_rate_idx]); |
| 190 printf("Packet mask matrix \n"); | 192 printf("Packet mask matrix \n"); |
| 191 #endif | 193 #endif |
| 192 | 194 |
| 193 for (uint32_t i = 0; i < numFecPackets; i++) { | 195 for (uint32_t i = 0; i < num_fec_packets; i++) { |
| 194 for (uint32_t j = 0; j < numMediaPackets; j++) { | 196 for (uint32_t j = 0; j < num_media_packets; j++) { |
| 195 const uint8_t byteMask = | 197 const uint8_t byte_mask = |
| 196 packetMask[i * maskBytesPerFecPacket + j / 8]; | 198 packet_mask[i * mask_bytes_per_fec_packet + j / 8]; |
| 197 const uint32_t bitPosition = (7 - j % 8); | 199 const uint32_t bit_position = (7 - j % 8); |
| 198 fecPacketMasks[i][j] = | 200 fec_packet_masks[i][j] = |
| 199 (byteMask & (1 << bitPosition)) >> bitPosition; | 201 (byte_mask & (1 << bit_position)) >> bit_position; |
| 200 #ifdef VERBOSE_OUTPUT | 202 #ifdef VERBOSE_OUTPUT |
| 201 printf("%u ", fecPacketMasks[i][j]); | 203 printf("%u ", fec_packet_masks[i][j]); |
| 202 #endif | 204 #endif |
| 203 } | 205 } |
| 204 #ifdef VERBOSE_OUTPUT | 206 #ifdef VERBOSE_OUTPUT |
| 205 printf("\n"); | 207 printf("\n"); |
| 206 #endif | 208 #endif |
| 207 } | 209 } |
| 208 #ifdef VERBOSE_OUTPUT | 210 #ifdef VERBOSE_OUTPUT |
| 209 printf("\n"); | 211 printf("\n"); |
| 210 #endif | 212 #endif |
| 211 // Check for all zero rows or columns: indicates incorrect mask. | 213 // Check for all zero rows or columns: indicates incorrect mask. |
| 212 uint32_t rowLimit = numMediaPackets; | 214 uint32_t row_limit = num_media_packets; |
| 213 for (uint32_t i = 0; i < numFecPackets; ++i) { | 215 for (uint32_t i = 0; i < num_fec_packets; ++i) { |
| 214 uint32_t rowSum = 0; | 216 uint32_t row_sum = 0; |
| 215 for (uint32_t j = 0; j < rowLimit; ++j) { | 217 for (uint32_t j = 0; j < row_limit; ++j) { |
| 216 rowSum += fecPacketMasks[i][j]; | 218 row_sum += fec_packet_masks[i][j]; |
| 217 } | 219 } |
| 218 ASSERT_NE(0u, rowSum) << "Row is all zero " << i; | 220 ASSERT_NE(0u, row_sum) << "Row is all zero " << i; |
| 219 } | 221 } |
| 220 for (uint32_t j = 0; j < rowLimit; ++j) { | 222 for (uint32_t j = 0; j < row_limit; ++j) { |
| 221 uint32_t columnSum = 0; | 223 uint32_t column_sum = 0; |
| 222 for (uint32_t i = 0; i < numFecPackets; ++i) { | 224 for (uint32_t i = 0; i < num_fec_packets; ++i) { |
| 223 columnSum += fecPacketMasks[i][j]; | 225 column_sum += fec_packet_masks[i][j]; |
| 224 } | 226 } |
| 225 ASSERT_NE(0u, columnSum) << "Column is all zero " << j; | 227 ASSERT_NE(0u, column_sum) << "Column is all zero " << j; |
| 226 } | 228 } |
| 227 | 229 |
| 228 // Construct media packets. | 230 // Construct media packets. |
| 229 // Reset the sequence number here for each FEC code/mask tested | 231 // Reset the sequence number here for each FEC code/mask tested |
| 230 // below, to avoid sequence number wrap-around. In actual decoding, | 232 // below, to avoid sequence number wrap-around. In actual decoding, |
| 231 // old FEC packets in list are dropped if sequence number wrap | 233 // old FEC packets in list are dropped if sequence number wrap |
| 232 // around is detected. This case is currently not handled below. | 234 // around is detected. This case is currently not handled below. |
| 233 seqNum = 0; | 235 seq_num = 0; |
| 234 for (uint32_t i = 0; i < numMediaPackets; ++i) { | 236 for (uint32_t i = 0; i < num_media_packets; ++i) { |
| 235 mediaPacket = new ForwardErrorCorrection::Packet; | 237 media_packet = new ForwardErrorCorrection::Packet(); |
| 236 mediaPacketList.push_back(mediaPacket); | 238 media_packet_list.push_back(media_packet); |
| 237 const uint32_t kMinPacketSize = 12; | 239 const uint32_t kMinPacketSize = 12; |
| 238 const uint32_t kMaxPacketSize = static_cast<uint32_t>( | 240 const uint32_t kMaxPacketSize = static_cast<uint32_t>( |
| 239 IP_PACKET_SIZE - 12 - 28 - | 241 IP_PACKET_SIZE - 12 - 28 - |
| 240 ForwardErrorCorrection::PacketOverhead()); | 242 ForwardErrorCorrection::PacketOverhead()); |
| 241 mediaPacket->length = random.Rand(kMinPacketSize, kMaxPacketSize); | 243 media_packet->length = random.Rand(kMinPacketSize, |
| 244 kMaxPacketSize); |
| 242 | 245 |
| 243 // Generate random values for the first 2 bytes. | 246 // Generate random values for the first 2 bytes. |
| 244 mediaPacket->data[0] = random.Rand<uint8_t>(); | 247 media_packet->data[0] = random.Rand<uint8_t>(); |
| 245 mediaPacket->data[1] = random.Rand<uint8_t>(); | 248 media_packet->data[1] = random.Rand<uint8_t>(); |
| 246 | 249 |
| 247 // The first two bits are assumed to be 10 by the | 250 // The first two bits are assumed to be 10 by the |
| 248 // FEC encoder. In fact the FEC decoder will set the | 251 // FEC encoder. In fact the FEC decoder will set the |
| 249 // two first bits to 10 regardless of what they | 252 // two first bits to 10 regardless of what they |
| 250 // actually were. Set the first two bits to 10 | 253 // actually were. Set the first two bits to 10 |
| 251 // so that a memcmp can be performed for the | 254 // so that a memcmp can be performed for the |
| 252 // whole restored packet. | 255 // whole restored packet. |
| 253 mediaPacket->data[0] |= 0x80; | 256 media_packet->data[0] |= 0x80; |
| 254 mediaPacket->data[0] &= 0xbf; | 257 media_packet->data[0] &= 0xbf; |
| 255 | 258 |
| 256 // FEC is applied to a whole frame. | 259 // FEC is applied to a whole frame. |
| 257 // A frame is signaled by multiple packets without | 260 // A frame is signaled by multiple packets without |
| 258 // the marker bit set followed by the last packet of | 261 // the marker bit set followed by the last packet of |
| 259 // the frame for which the marker bit is set. | 262 // the frame for which the marker bit is set. |
| 260 // Only push one (fake) frame to the FEC. | 263 // Only push one (fake) frame to the FEC. |
| 261 mediaPacket->data[1] &= 0x7f; | 264 media_packet->data[1] &= 0x7f; |
| 262 | 265 |
| 263 ByteWriter<uint16_t>::WriteBigEndian(&mediaPacket->data[2], | 266 ByteWriter<uint16_t>::WriteBigEndian(&media_packet->data[2], |
| 264 seqNum); | 267 seq_num); |
| 265 ByteWriter<uint32_t>::WriteBigEndian(&mediaPacket->data[4], | 268 ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[4], |
| 266 timeStamp); | 269 timestamp); |
| 267 ByteWriter<uint32_t>::WriteBigEndian(&mediaPacket->data[8], ssrc); | 270 ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[8], |
| 271 ssrc); |
| 268 // Generate random values for payload | 272 // Generate random values for payload |
| 269 for (size_t j = 12; j < mediaPacket->length; ++j) { | 273 for (size_t j = 12; j < media_packet->length; ++j) { |
| 270 mediaPacket->data[j] = random.Rand<uint8_t>(); | 274 media_packet->data[j] = random.Rand<uint8_t>(); |
| 271 } | 275 } |
| 272 seqNum++; | 276 seq_num++; |
| 273 } | 277 } |
| 274 mediaPacket->data[1] |= 0x80; | 278 media_packet->data[1] |= 0x80; |
| 275 | 279 |
| 276 ASSERT_EQ(0, fec.GenerateFEC(mediaPacketList, protectionFactor, | 280 ASSERT_EQ(0, fec.GenerateFec(media_packet_list, protection_factor, |
| 277 numImpPackets, kUseUnequalProtection, | 281 num_imp_packets, kUseUnequalProtection, |
| 278 fec_mask_type, &fecPacketList)) | 282 fec_mask_type, &fec_packet_list)) |
| 279 << "GenerateFEC() failed"; | 283 << "GenerateFec() failed"; |
| 280 | 284 |
| 281 ASSERT_EQ(numFecPackets, fecPacketList.size()) | 285 ASSERT_EQ(num_fec_packets, fec_packet_list.size()) |
| 282 << "We requested " << numFecPackets << " FEC packets, but " | 286 << "We requested " << num_fec_packets << " FEC packets, but " |
| 283 << "GenerateFEC() produced " << fecPacketList.size(); | 287 << "GenerateFec() produced " << fec_packet_list.size(); |
| 284 memset(mediaLossMask, 0, sizeof(mediaLossMask)); | 288 |
| 285 ForwardErrorCorrection::PacketList::iterator mediaPacketListItem = | 289 memset(media_loss_mask, 0, sizeof(media_loss_mask)); |
| 286 mediaPacketList.begin(); | 290 uint32_t media_packet_idx = 0; |
| 287 ForwardErrorCorrection::ReceivedPacket* receivedPacket; | 291 for (auto* media_packet : media_packet_list) { |
| 288 uint32_t mediaPacketIdx = 0; | |
| 289 | |
| 290 while (mediaPacketListItem != mediaPacketList.end()) { | |
| 291 mediaPacket = *mediaPacketListItem; | |
| 292 // We want a value between 0 and 1. | 292 // We want a value between 0 and 1. |
| 293 const float lossRandomVariable = random.Rand<float>(); | 293 const float loss_random_variable = random.Rand<float>(); |
| 294 | 294 |
| 295 if (lossRandomVariable >= lossRate[lossRateIdx]) { | 295 if (loss_random_variable >= loss_rate[loss_rate_idx]) { |
| 296 mediaLossMask[mediaPacketIdx] = 1; | 296 media_loss_mask[media_packet_idx] = 1; |
| 297 receivedPacket = new ForwardErrorCorrection::ReceivedPacket; | 297 auto received_packet = |
| 298 receivedPacket->pkt = new ForwardErrorCorrection::Packet; | 298 new ForwardErrorCorrection::ReceivedPacket(); |
| 299 receivedPacketList.push_back(receivedPacket); | 299 received_packet->pkt = new ForwardErrorCorrection::Packet(); |
| 300 | 300 received_packet_list.push_back(received_packet); |
| 301 receivedPacket->pkt->length = mediaPacket->length; | 301 |
| 302 memcpy(receivedPacket->pkt->data, mediaPacket->data, | 302 received_packet->pkt->length = media_packet->length; |
| 303 mediaPacket->length); | 303 memcpy(received_packet->pkt->data, media_packet->data, |
| 304 receivedPacket->seq_num = | 304 media_packet->length); |
| 305 ByteReader<uint16_t>::ReadBigEndian(&mediaPacket->data[2]); | 305 received_packet->seq_num = |
| 306 receivedPacket->is_fec = false; | 306 ByteReader<uint16_t>::ReadBigEndian(&media_packet->data[2]); |
| 307 } | 307 received_packet->is_fec = false; |
| 308 mediaPacketIdx++; | 308 } |
| 309 ++mediaPacketListItem; | 309 media_packet_idx++; |
| 310 } | 310 } |
| 311 memset(fecLossMask, 0, sizeof(fecLossMask)); | 311 |
| 312 ForwardErrorCorrection::PacketList::iterator fecPacketListItem = | 312 memset(fec_loss_mask, 0, sizeof(fec_loss_mask)); |
| 313 fecPacketList.begin(); | 313 uint32_t fec_packet_idx = 0; |
| 314 ForwardErrorCorrection::Packet* fecPacket; | 314 for (auto* fec_packet : fec_packet_list) { |
| 315 uint32_t fecPacketIdx = 0; | 315 const float loss_random_variable = random.Rand<float>(); |
| 316 while (fecPacketListItem != fecPacketList.end()) { | 316 if (loss_random_variable >= loss_rate[loss_rate_idx]) { |
| 317 fecPacket = *fecPacketListItem; | 317 fec_loss_mask[fec_packet_idx] = 1; |
| 318 const float lossRandomVariable = random.Rand<float>(); | 318 auto received_packet = |
| 319 if (lossRandomVariable >= lossRate[lossRateIdx]) { | 319 new ForwardErrorCorrection::ReceivedPacket(); |
| 320 fecLossMask[fecPacketIdx] = 1; | 320 received_packet->pkt = new ForwardErrorCorrection::Packet(); |
| 321 receivedPacket = new ForwardErrorCorrection::ReceivedPacket; | 321 |
| 322 receivedPacket->pkt = new ForwardErrorCorrection::Packet; | 322 received_packet_list.push_back(received_packet); |
| 323 | 323 |
| 324 receivedPacketList.push_back(receivedPacket); | 324 received_packet->pkt->length = fec_packet->length; |
| 325 | 325 memcpy(received_packet->pkt->data, fec_packet->data, |
| 326 receivedPacket->pkt->length = fecPacket->length; | 326 fec_packet->length); |
| 327 memcpy(receivedPacket->pkt->data, fecPacket->data, | 327 |
| 328 fecPacket->length); | 328 received_packet->seq_num = seq_num; |
| 329 | 329 received_packet->is_fec = true; |
| 330 receivedPacket->seq_num = seqNum; | 330 received_packet->ssrc = ssrc; |
| 331 receivedPacket->is_fec = true; | 331 |
| 332 receivedPacket->ssrc = ssrc; | 332 fec_mask_list.push_back(fec_packet_masks[fec_packet_idx]); |
| 333 | 333 } |
| 334 fecMaskList.push_back(fecPacketMasks[fecPacketIdx]); | 334 ++fec_packet_idx; |
| 335 } | 335 ++seq_num; |
| 336 ++fecPacketIdx; | |
| 337 ++seqNum; | |
| 338 ++fecPacketListItem; | |
| 339 } | 336 } |
| 340 | 337 |
| 341 #ifdef VERBOSE_OUTPUT | 338 #ifdef VERBOSE_OUTPUT |
| 342 printf("Media loss mask:\n"); | 339 printf("Media loss mask:\n"); |
| 343 for (uint32_t i = 0; i < numMediaPackets; i++) { | 340 for (uint32_t i = 0; i < num_media_packets; i++) { |
| 344 printf("%u ", mediaLossMask[i]); | 341 printf("%u ", media_loss_mask[i]); |
| 345 } | 342 } |
| 346 printf("\n\n"); | 343 printf("\n\n"); |
| 347 | 344 |
| 348 printf("FEC loss mask:\n"); | 345 printf("FEC loss mask:\n"); |
| 349 for (uint32_t i = 0; i < numFecPackets; i++) { | 346 for (uint32_t i = 0; i < num_fec_packets; i++) { |
| 350 printf("%u ", fecLossMask[i]); | 347 printf("%u ", fec_loss_mask[i]); |
| 351 } | 348 } |
| 352 printf("\n\n"); | 349 printf("\n\n"); |
| 353 #endif | 350 #endif |
| 354 | 351 |
| 355 std::list<uint8_t*>::iterator fecMaskIt = fecMaskList.begin(); | 352 auto fec_mask_it = fec_mask_list.begin(); |
| 356 uint8_t* fecMask; | 353 while (fec_mask_it != fec_mask_list.end()) { |
| 357 while (fecMaskIt != fecMaskList.end()) { | 354 uint32_t hamming_dist = 0; |
| 358 fecMask = *fecMaskIt; | 355 uint32_t recovery_position = 0; |
| 359 uint32_t hammingDist = 0; | 356 for (uint32_t i = 0; i < num_media_packets; i++) { |
| 360 uint32_t recoveryPosition = 0; | 357 if (media_loss_mask[i] == 0 && (*fec_mask_it)[i] == 1) { |
| 361 for (uint32_t i = 0; i < numMediaPackets; i++) { | 358 recovery_position = i; |
| 362 if (mediaLossMask[i] == 0 && fecMask[i] == 1) { | 359 ++hamming_dist; |
| 363 recoveryPosition = i; | |
| 364 ++hammingDist; | |
| 365 } | 360 } |
| 366 } | 361 } |
| 367 std::list<uint8_t*>::iterator itemToDelete = fecMaskIt; | 362 auto item_to_delete = fec_mask_it; |
| 368 ++fecMaskIt; | 363 ++fec_mask_it; |
| 369 | 364 |
| 370 if (hammingDist == 1) { | 365 if (hamming_dist == 1) { |
| 371 // Recovery possible. Restart search. | 366 // Recovery possible. Restart search. |
| 372 mediaLossMask[recoveryPosition] = 1; | 367 media_loss_mask[recovery_position] = 1; |
| 373 fecMaskIt = fecMaskList.begin(); | 368 fec_mask_it = fec_mask_list.begin(); |
| 374 } else if (hammingDist == 0) { | 369 } else if (hamming_dist == 0) { |
| 375 // FEC packet cannot provide further recovery. | 370 // FEC packet cannot provide further recovery. |
| 376 fecMaskList.erase(itemToDelete); | 371 fec_mask_list.erase(item_to_delete); |
| 377 } | 372 } |
| 378 } | 373 } |
| 379 #ifdef VERBOSE_OUTPUT | 374 #ifdef VERBOSE_OUTPUT |
| 380 printf("Recovery mask:\n"); | 375 printf("Recovery mask:\n"); |
| 381 for (uint32_t i = 0; i < numMediaPackets; ++i) { | 376 for (uint32_t i = 0; i < num_media_packets; ++i) { |
| 382 printf("%u ", mediaLossMask[i]); | 377 printf("%u ", media_loss_mask[i]); |
| 383 } | 378 } |
| 384 printf("\n\n"); | 379 printf("\n\n"); |
| 385 #endif | 380 #endif |
| 386 // For error-checking frame completion. | 381 // For error-checking frame completion. |
| 387 bool fecPacketReceived = false; | 382 bool fec_packet_received = false; |
| 388 while (!receivedPacketList.empty()) { | 383 while (!received_packet_list.empty()) { |
| 389 size_t numPacketsToDecode = random.Rand( | 384 size_t num_packets_to_decode = random.Rand( |
| 390 1u, static_cast<uint32_t>(receivedPacketList.size())); | 385 1u, static_cast<uint32_t>(received_packet_list.size())); |
| 391 ReceivePackets(&toDecodeList, &receivedPacketList, | 386 ReceivePackets(&to_decode_list, &received_packet_list, |
| 392 numPacketsToDecode, reorderRate, duplicateRate, | 387 num_packets_to_decode, reorder_rate, |
| 393 &random); | 388 duplicate_rate, &random); |
| 394 | 389 |
| 395 if (fecPacketReceived == false) { | 390 if (fec_packet_received == false) { |
| 396 ForwardErrorCorrection::ReceivedPacketList::iterator | 391 for (auto* received_packet : to_decode_list) { |
| 397 toDecodeIt = toDecodeList.begin(); | 392 if (received_packet->is_fec) { |
| 398 while (toDecodeIt != toDecodeList.end()) { | 393 fec_packet_received = true; |
| 399 receivedPacket = *toDecodeIt; | |
| 400 if (receivedPacket->is_fec) { | |
| 401 fecPacketReceived = true; | |
| 402 } | 394 } |
| 403 ++toDecodeIt; | |
| 404 } | 395 } |
| 405 } | 396 } |
| 406 ASSERT_EQ(0, fec.DecodeFEC(&toDecodeList, &recoveredPacketList)) | 397 ASSERT_EQ(0, fec.DecodeFec(&to_decode_list, |
| 407 << "DecodeFEC() failed"; | 398 &recovered_packet_list)) |
| 408 ASSERT_TRUE(toDecodeList.empty()) | 399 << "DecodeFec() failed"; |
| 400 ASSERT_TRUE(to_decode_list.empty()) |
| 409 << "Received packet list is not empty."; | 401 << "Received packet list is not empty."; |
| 410 } | 402 } |
| 411 mediaPacketListItem = mediaPacketList.begin(); | 403 media_packet_idx = 0; |
| 412 mediaPacketIdx = 0; | 404 for (auto* media_packet : media_packet_list) { |
| 413 while (mediaPacketListItem != mediaPacketList.end()) { | 405 if (media_loss_mask[media_packet_idx] == 1) { |
| 414 if (mediaLossMask[mediaPacketIdx] == 1) { | |
| 415 // Should have recovered this packet. | 406 // Should have recovered this packet. |
| 416 ForwardErrorCorrection::RecoveredPacketList::iterator | 407 auto recovered_packet_list_it = recovered_packet_list.cbegin(); |
| 417 recoveredPacketListItem = recoveredPacketList.begin(); | 408 |
| 418 | 409 ASSERT_FALSE(recovered_packet_list_it == |
| 419 ASSERT_FALSE(recoveredPacketListItem == | 410 recovered_packet_list.end()) |
| 420 recoveredPacketList.end()) | |
| 421 << "Insufficient number of recovered packets."; | 411 << "Insufficient number of recovered packets."; |
| 422 mediaPacket = *mediaPacketListItem; | 412 ForwardErrorCorrection::RecoveredPacket* recovered_packet = |
| 423 ForwardErrorCorrection::RecoveredPacket* recoveredPacket = | 413 *recovered_packet_list_it; |
| 424 *recoveredPacketListItem; | 414 |
| 425 | 415 ASSERT_EQ(recovered_packet->pkt->length, media_packet->length) |
| 426 ASSERT_EQ(recoveredPacket->pkt->length, mediaPacket->length) | |
| 427 << "Recovered packet length not identical to original " | 416 << "Recovered packet length not identical to original " |
| 428 << "media packet"; | 417 << "media packet"; |
| 429 ASSERT_EQ(0, memcmp(recoveredPacket->pkt->data, | 418 ASSERT_EQ(0, memcmp(recovered_packet->pkt->data, |
| 430 mediaPacket->data, mediaPacket->length)) | 419 media_packet->data, media_packet->length)) |
| 431 << "Recovered packet payload not identical to original " | 420 << "Recovered packet payload not identical to original " |
| 432 << "media packet"; | 421 << "media packet"; |
| 433 delete recoveredPacket; | 422 delete recovered_packet; |
| 434 recoveredPacketList.pop_front(); | 423 recovered_packet_list.pop_front(); |
| 435 } | 424 } |
| 436 ++mediaPacketIdx; | 425 ++media_packet_idx; |
| 437 ++mediaPacketListItem; | 426 } |
| 438 } | 427 fec.ResetState(&recovered_packet_list); |
| 439 fec.ResetState(&recoveredPacketList); | 428 ASSERT_TRUE(recovered_packet_list.empty()) |
| 440 ASSERT_TRUE(recoveredPacketList.empty()) | |
| 441 << "Excessive number of recovered packets.\t size is: " | 429 << "Excessive number of recovered packets.\t size is: " |
| 442 << recoveredPacketList.size(); | 430 << recovered_packet_list.size(); |
| 443 // -- Teardown -- | 431 // -- Teardown -- |
| 444 mediaPacketListItem = mediaPacketList.begin(); | 432 auto media_packet_list_it = media_packet_list.begin(); |
| 445 while (mediaPacketListItem != mediaPacketList.end()) { | 433 while (media_packet_list_it != media_packet_list.end()) { |
| 446 delete *mediaPacketListItem; | 434 delete *media_packet_list_it; |
| 447 ++mediaPacketListItem; | 435 ++media_packet_list_it; |
| 448 mediaPacketList.pop_front(); | 436 media_packet_list.pop_front(); |
| 449 } | 437 } |
| 450 assert(mediaPacketList.empty()); | 438 RTC_DCHECK(media_packet_list.empty()); |
| 451 | 439 |
| 452 fecPacketListItem = fecPacketList.begin(); | 440 // Clear FEC packet list, so we don't pass in a non-empty |
| 453 while (fecPacketListItem != fecPacketList.end()) { | 441 // list in the next call to DecodeFec(). |
| 454 ++fecPacketListItem; | 442 fec_packet_list.clear(); |
| 455 fecPacketList.pop_front(); | 443 |
| 456 } | 444 // Delete received packets we didn't pass to DecodeFec(), due to |
| 457 | |
| 458 // Delete received packets we didn't pass to DecodeFEC(), due to | |
| 459 // early frame completion. | 445 // early frame completion. |
| 460 ForwardErrorCorrection::ReceivedPacketList::iterator | 446 auto received_packet_it = received_packet_list.cbegin(); |
| 461 receivedPacketIt = receivedPacketList.begin(); | 447 while (received_packet_it != received_packet_list.end()) { |
| 462 while (receivedPacketIt != receivedPacketList.end()) { | 448 delete *received_packet_it; |
| 463 receivedPacket = *receivedPacketIt; | 449 ++received_packet_it; |
| 464 delete receivedPacket; | 450 received_packet_list.pop_front(); |
| 465 ++receivedPacketIt; | 451 } |
| 466 receivedPacketList.pop_front(); | 452 RTC_DCHECK(received_packet_list.empty()); |
| 467 } | 453 |
| 468 assert(receivedPacketList.empty()); | 454 while (!fec_mask_list.empty()) { |
| 469 | 455 fec_mask_list.pop_front(); |
| 470 while (!fecMaskList.empty()) { | 456 } |
| 471 fecMaskList.pop_front(); | 457 timestamp += 90000 / 30; |
| 472 } | 458 } // loop over num_imp_packets |
| 473 timeStamp += 90000 / 30; | |
| 474 } // loop over numImpPackets | |
| 475 } // loop over FecPackets | 459 } // loop over FecPackets |
| 476 } // loop over numMediaPackets | 460 } // loop over num_media_packets |
| 477 delete[] packetMask; | |
| 478 } // loop over loss rates | 461 } // loop over loss rates |
| 479 } // loop over mask types | 462 } // loop over mask types |
| 480 | 463 |
| 481 // Have DecodeFEC free allocated memory. | 464 // Have DecodeFec free allocated memory. |
| 482 fec.ResetState(&recoveredPacketList); | 465 fec.ResetState(&recovered_packet_list); |
| 483 ASSERT_TRUE(recoveredPacketList.empty()) | 466 ASSERT_TRUE(recovered_packet_list.empty()) |
| 484 << "Recovered packet list is not empty"; | 467 << "Recovered packet list is not empty"; |
| 485 } | 468 } |
| 486 | 469 |
| 487 } // namespace test | 470 } // namespace test |
| 488 } // namespace webrtc | 471 } // namespace webrtc |
| OLD | NEW |