1 /* 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 11 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" 12 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include <algorithm> 17 #include <iterator> 18 19 #include "webrtc/base/checks.h" 20 #include "webrtc/base/logging.h" 21 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" 22 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" 23 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h" 24 25 namespace webrtc { 26 27 // FEC header size in bytes. 28 const uint8_t kFecHeaderSize = 10; 29 30 // ULP header size in bytes (L bit is set). 31 const uint8_t kUlpHeaderSizeLBitSet = (2 + kMaskSizeLBitSet); 32 33 // ULP header size in bytes (L bit is cleared). 34 const uint8_t kUlpHeaderSizeLBitClear = (2 + kMaskSizeLBitClear); 35 36 // Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum. 37 const uint8_t kTransportOverhead = 28; 38 39 enum { kMaxFecPackets = ForwardErrorCorrection::kMaxMediaPackets }; 40 41 int32_t ForwardErrorCorrection::Packet::AddRef() { 42 return ++ref_count_; 43 } 44 45 int32_t ForwardErrorCorrection::Packet::Release() { 46 int32_t ref_count; 47 ref_count = --ref_count_; 48 if (ref_count == 0) 49 delete this; 50 return ref_count; 51 } 52 53 // Used to link media packets to their protecting FEC packets. 54 // 55 // TODO(holmer): Refactor into a proper class. 56 class ProtectedPacket : public ForwardErrorCorrection::SortablePacket { 57 public: 58 rtc::scoped_refptr<ForwardErrorCorrection::Packet> pkt; 59 }; 60 61 typedef std::list<ProtectedPacket*> ProtectedPacketList; 62 63 // 64 // Used for internal storage of FEC packets in a list. 65 // 66 // TODO(holmer): Refactor into a proper class. 67 class FecPacket : public ForwardErrorCorrection::SortablePacket { 68 public: 69 ProtectedPacketList protected_pkt_list; 70 uint32_t ssrc; // SSRC of the current frame. 71 rtc::scoped_refptr<ForwardErrorCorrection::Packet> pkt; 72 }; 73 74 bool ForwardErrorCorrection::SortablePacket::LessThan( 75 const SortablePacket* first, 76 const SortablePacket* second) { 77 return IsNewerSequenceNumber(second->seq_num, first->seq_num); 78 } 79 80 ForwardErrorCorrection::ReceivedPacket::ReceivedPacket() {} 81 ForwardErrorCorrection::ReceivedPacket::~ReceivedPacket() {} 82 83 ForwardErrorCorrection::RecoveredPacket::RecoveredPacket() {} 84 ForwardErrorCorrection::RecoveredPacket::~RecoveredPacket() {} 85 86 ForwardErrorCorrection::ForwardErrorCorrection() 87 : generated_fec_packets_(kMaxMediaPackets), fec_packet_received_(false) {} 88 89 ForwardErrorCorrection::~ForwardErrorCorrection() {} 90 91 // Input packet 92 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 93 // | RTP Header (12 octets) | 94 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 95 // | RTP Payload | 96 // | | 97 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 98 99 // Output packet 100 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 101 // | FEC Header (10 octets) | 102 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 103 // | FEC Level 0 Header | 104 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 105 // | FEC Level 0 Payload | 106 // | | 107 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 108 int32_t ForwardErrorCorrection::GenerateFEC(const PacketList& media_packet_list, 109 uint8_t protection_factor, 110 int num_important_packets, 111 bool use_unequal_protection, 112 FecMaskType fec_mask_type, 113 PacketList* fec_packet_list) { 114 const uint16_t num_media_packets = media_packet_list.size(); 115 // Sanity check arguments. 116 assert(num_media_packets > 0); 117 assert(num_important_packets >= 0 && 118 num_important_packets <= num_media_packets); 119 assert(fec_packet_list->empty()); 120 121 if (num_media_packets > kMaxMediaPackets) { 122 LOG(LS_WARNING) << "Can't protect " << num_media_packets 123 << " media packets per frame. Max is " << kMaxMediaPackets; 124 return -1; 125 } 126 127 bool l_bit = (num_media_packets > 8 * kMaskSizeLBitClear); 128 int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; 129 130 // Do some error checking on the media packets. 131 for (Packet* media_packet : media_packet_list) { 132 assert(media_packet); 133 134 if (media_packet->length < kRtpHeaderSize) { 135 LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes " 136 << "is smaller than RTP header."; 137 return -1; 138 } 139 140 // Ensure our FEC packets will fit in a typical MTU. 141 if (media_packet->length + PacketOverhead() + kTransportOverhead > 142 IP_PACKET_SIZE) { 143 LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes " 144 << "with overhead is larger than " << IP_PACKET_SIZE; 145 } 146 } 147 148 int num_fec_packets = 149 GetNumberOfFecPackets(num_media_packets, protection_factor); 150 if (num_fec_packets == 0) { 151 return 0; 152 } 153 154 // Prepare FEC packets by setting them to 0. 155 for (int i = 0; i < num_fec_packets; ++i) { 156 memset(generated_fec_packets_[i].data, 0, IP_PACKET_SIZE); 157 generated_fec_packets_[i].length = 0; // Use this as a marker for untouched 158 // packets. 159 fec_packet_list->push_back(&generated_fec_packets_[i]); 160 } 161 162 const internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets); 163 164 // -- Generate packet masks -- 165 // Always allocate space for a large mask. 166 rtc::scoped_ptr<uint8_t[]> packet_mask( 167 new uint8_t[num_fec_packets * kMaskSizeLBitSet]); 168 memset(packet_mask.get(), 0, num_fec_packets * num_mask_bytes); 169 internal::GeneratePacketMasks(num_media_packets, num_fec_packets, 170 num_important_packets, use_unequal_protection, 171 mask_table, packet_mask.get()); 172 173 int num_mask_bits = InsertZerosInBitMasks( 174 media_packet_list, packet_mask.get(), num_mask_bytes, num_fec_packets); 175 176 if (num_mask_bits < 0) { 177 return -1; 178 } 179 l_bit = (num_mask_bits > 8 * kMaskSizeLBitClear); 180 if (l_bit) { 181 num_mask_bytes = kMaskSizeLBitSet; 182 } 183 184 GenerateFecBitStrings(media_packet_list, packet_mask.get(), num_fec_packets, 185 l_bit); 186 GenerateFecUlpHeaders(media_packet_list, packet_mask.get(), l_bit, 187 num_fec_packets); 188 189 return 0; 190 } 191 192 int ForwardErrorCorrection::GetNumberOfFecPackets(int num_media_packets, 193 int protection_factor) { 194 // Result in Q0 with an unsigned round. 195 int num_fec_packets = (num_media_packets * protection_factor + (1 << 7)) >> 8; 196 // Generate at least one FEC packet if we need protection. 197 if (protection_factor > 0 && num_fec_packets == 0) { 198 num_fec_packets = 1; 199 } 200 assert(num_fec_packets <= num_media_packets); 201 return num_fec_packets; 202 } 203 204 void ForwardErrorCorrection::GenerateFecBitStrings( 205 const PacketList& media_packet_list, 206 uint8_t* packet_mask, 207 int num_fec_packets, 208 bool l_bit) { 209 if (media_packet_list.empty()) { 210 return; 211 } 212 uint8_t media_payload_length[2]; 213 const int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; 214 const uint16_t ulp_header_size = 215 l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear; 216 const uint16_t fec_rtp_offset = 217 kFecHeaderSize + ulp_header_size - kRtpHeaderSize; 218 219 for (int i = 0; i < num_fec_packets; ++i) { 220 Packet* const fec_packet = &generated_fec_packets_[i]; 221 PacketList::const_iterator media_list_it = media_packet_list.begin(); 222 uint32_t pkt_mask_idx = i * num_mask_bytes; 223 uint32_t media_pkt_idx = 0; 224 uint16_t fec_packet_length = 0; 225 uint16_t prev_seq_num = ParseSequenceNumber((*media_list_it)->data); 226 while (media_list_it != media_packet_list.end()) { 227 // Each FEC packet has a multiple byte mask. Determine if this media 228 // packet should be included in FEC packet i. 229 if (packet_mask[pkt_mask_idx] & (1 << (7 - media_pkt_idx))) { 230 Packet* media_packet = *media_list_it; 231 232 // Assign network-ordered media payload length. 233 ByteWriter<uint16_t>::WriteBigEndian( 234 media_payload_length, media_packet->length - kRtpHeaderSize); 235 236 fec_packet_length = media_packet->length + fec_rtp_offset; 237 // On the first protected packet, we don't need to XOR. 238 if (fec_packet->length == 0) { 239 // Copy the first 2 bytes of the RTP header. 240 memcpy(fec_packet->data, media_packet->data, 2); 241 // Copy the 5th to 8th bytes of the RTP header. 242 memcpy(&fec_packet->data[4], &media_packet->data[4], 4); 243 // Copy network-ordered payload size. 244 memcpy(&fec_packet->data[8], media_payload_length, 2); 245 246 // Copy RTP payload, leaving room for the ULP header. 247 memcpy(&fec_packet->data[kFecHeaderSize + ulp_header_size], 248 &media_packet->data[kRtpHeaderSize], 249 media_packet->length - kRtpHeaderSize); 250 } else { 251 // XOR with the first 2 bytes of the RTP header. 252 fec_packet->data[0] ^= media_packet->data[0]; 253 fec_packet->data[1] ^= media_packet->data[1]; 254 255 // XOR with the 5th to 8th bytes of the RTP header. 256 for (uint32_t j = 4; j < 8; ++j) { 257 fec_packet->data[j] ^= media_packet->data[j]; 258 } 259 260 // XOR with the network-ordered payload size. 261 fec_packet->data[8] ^= media_payload_length[0]; 262 fec_packet->data[9] ^= media_payload_length[1]; 263 264 // XOR with RTP payload, leaving room for the ULP header. 265 for (int32_t j = kFecHeaderSize + ulp_header_size; 266 j < fec_packet_length; j++) { 267 fec_packet->data[j] ^= media_packet->data[j - fec_rtp_offset]; 268 } 269 } 270 if (fec_packet_length > fec_packet->length) { 271 fec_packet->length = fec_packet_length; 272 } 273 } 274 media_list_it++; 275 if (media_list_it != media_packet_list.end()) { 276 uint16_t seq_num = ParseSequenceNumber((*media_list_it)->data); 277 media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num); 278 prev_seq_num = seq_num; 279 } 280 pkt_mask_idx += media_pkt_idx / 8; 281 media_pkt_idx %= 8; 282 } 283 RTC_DCHECK_GT(fec_packet->length, 0u) 284 << "Packet mask is wrong or poorly designed."; 285 } 286 } 287 288 int ForwardErrorCorrection::InsertZerosInBitMasks( 289 const PacketList& media_packets, 290 uint8_t* packet_mask, 291 int num_mask_bytes, 292 int num_fec_packets) { 293 uint8_t* new_mask = NULL; 294 if (media_packets.size() <= 1) { 295 return media_packets.size(); 296 } 297 int last_seq_num = ParseSequenceNumber(media_packets.back()->data); 298 int first_seq_num = ParseSequenceNumber(media_packets.front()->data); 299 int total_missing_seq_nums = 300 static_cast<uint16_t>(last_seq_num - first_seq_num) - 301 media_packets.size() + 1; 302 if (total_missing_seq_nums == 0) { 303 // All sequence numbers are covered by the packet mask. No zero insertion 304 // required. 305 return media_packets.size(); 306 } 307 // We can only protect 8 * kMaskSizeLBitSet packets. 308 if (total_missing_seq_nums + media_packets.size() > 8 * kMaskSizeLBitSet) 309 return -1; 310 // Allocate the new mask. 311 int new_mask_bytes = kMaskSizeLBitClear; 312 if (media_packets.size() + total_missing_seq_nums > 8 * kMaskSizeLBitClear) { 313 new_mask_bytes = kMaskSizeLBitSet; 314 } 315 new_mask = new uint8_t[num_fec_packets * kMaskSizeLBitSet]; 316 memset(new_mask, 0, num_fec_packets * kMaskSizeLBitSet); 317 318 PacketList::const_iterator it = media_packets.begin(); 319 uint16_t prev_seq_num = first_seq_num; 320 ++it; 321 322 // Insert the first column. 323 CopyColumn(new_mask, new_mask_bytes, packet_mask, num_mask_bytes, 324 num_fec_packets, 0, 0); 325 int new_bit_index = 1; 326 int old_bit_index = 1; 327 // Insert zeros in the bit mask for every hole in the sequence. 328 for (; it != media_packets.end(); ++it) { 329 if (new_bit_index == 8 * kMaskSizeLBitSet) { 330 // We can only cover up to 48 packets. 331 break; 332 } 333 uint16_t seq_num = ParseSequenceNumber((*it)->data); 334 const int zeros_to_insert = 335 static_cast<uint16_t>(seq_num - prev_seq_num - 1); 336 if (zeros_to_insert > 0) { 337 InsertZeroColumns(zeros_to_insert, new_mask, new_mask_bytes, 338 num_fec_packets, new_bit_index); 339 } 340 new_bit_index += zeros_to_insert; 341 CopyColumn(new_mask, new_mask_bytes, packet_mask, num_mask_bytes, 342 num_fec_packets, new_bit_index, old_bit_index); 343 ++new_bit_index; 344 ++old_bit_index; 345 prev_seq_num = seq_num; 346 } 347 if (new_bit_index % 8 != 0) { 348 // We didn't fill the last byte. Shift bits to correct position. 349 for (uint16_t row = 0; row < num_fec_packets; ++row) { 350 int new_byte_index = row * new_mask_bytes + new_bit_index / 8; 351 new_mask[new_byte_index] <<= (7 - (new_bit_index % 8)); 352 } 353 } 354 // Replace the old mask with the new. 355 memcpy(packet_mask, new_mask, kMaskSizeLBitSet * num_fec_packets); 356 delete[] new_mask; 357 return new_bit_index; 358 } 359 360 void ForwardErrorCorrection::InsertZeroColumns(int num_zeros, 361 uint8_t* new_mask, 362 int new_mask_bytes, 363 int num_fec_packets, 364 int new_bit_index) { 365 for (uint16_t row = 0; row < num_fec_packets; ++row) { 366 const int new_byte_index = row * new_mask_bytes + new_bit_index / 8; 367 const int max_shifts = (7 - (new_bit_index % 8)); 368 new_mask[new_byte_index] <<= std::min(num_zeros, max_shifts); 369 } 370 } 371 372 void ForwardErrorCorrection::CopyColumn(uint8_t* new_mask, 373 int new_mask_bytes, 374 uint8_t* old_mask, 375 int old_mask_bytes, 376 int num_fec_packets, 377 int new_bit_index, 378 int old_bit_index) { 379 // Copy column from the old mask to the beginning of the new mask and shift it 380 // out from the old mask. 381 for (uint16_t row = 0; row < num_fec_packets; ++row) { 382 int new_byte_index = row * new_mask_bytes + new_bit_index / 8; 383 int old_byte_index = row * old_mask_bytes + old_bit_index / 8; 384 new_mask[new_byte_index] |= ((old_mask[old_byte_index] & 0x80) >> 7); 385 if (new_bit_index % 8 != 7) { 386 new_mask[new_byte_index] <<= 1; 387 } 388 old_mask[old_byte_index] <<= 1; 389 } 390 } 391 392 void ForwardErrorCorrection::GenerateFecUlpHeaders( 393 const PacketList& media_packet_list, 394 uint8_t* packet_mask, 395 bool l_bit, 396 int num_fec_packets) { 397 // -- Generate FEC and ULP headers -- 398 // 399 // FEC Header, 10 bytes 400 // 0 1 2 3 401 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 402 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 403 // |E|L|P|X| CC |M| PT recovery | SN base | 404 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 405 // | TS recovery | 406 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 407 // | length recovery | 408 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 409 // 410 // ULP Header, 4 bytes (for L = 0) 411 // 0 1 2 3 412 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 413 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 414 // | Protection Length | mask | 415 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 416 // | mask cont. (present only when L = 1) | 417 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 418 PacketList::const_iterator media_list_it = media_packet_list.begin(); 419 Packet* media_packet = *media_list_it; 420 assert(media_packet != NULL); 421 int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; 422 const uint16_t ulp_header_size = 423 l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear; 424 425 for (int i = 0; i < num_fec_packets; ++i) { 426 Packet* const fec_packet = &generated_fec_packets_[i]; 427 // -- FEC header -- 428 fec_packet->data[0] &= 0x7f; // Set E to zero. 429 if (l_bit == 0) { 430 fec_packet->data[0] &= 0xbf; // Clear the L bit. 431 } else { 432 fec_packet->data[0] |= 0x40; // Set the L bit. 433 } 434 // Two byte sequence number from first RTP packet to SN base. 435 // We use the same sequence number base for every FEC packet, 436 // but that's not required in general. 437 memcpy(&fec_packet->data[2], &media_packet->data[2], 2); 438 439 // -- ULP header -- 440 // Copy the payload size to the protection length field. 441 // (We protect the entire packet.) 442 ByteWriter<uint16_t>::WriteBigEndian( 443 &fec_packet->data[10], 444 fec_packet->length - kFecHeaderSize - ulp_header_size); 445 446 // Copy the packet mask. 447 memcpy(&fec_packet->data[12], &packet_mask[i * num_mask_bytes], 448 num_mask_bytes); 449 } 450 } 451 452 void ForwardErrorCorrection::ResetState( 453 RecoveredPacketList* recovered_packet_list) { 454 fec_packet_received_ = false; 455 456 // Free the memory for any existing recovered packets, if the user hasn't. 457 while (!recovered_packet_list->empty()) { 458 delete recovered_packet_list->front(); 459 recovered_packet_list->pop_front(); 460 } 461 assert(recovered_packet_list->empty()); 462 463 // Free the FEC packet list. 464 while (!fec_packet_list_.empty()) { 465 FecPacketList::iterator fec_packet_list_it = fec_packet_list_.begin(); 466 FecPacket* fec_packet = *fec_packet_list_it; 467 ProtectedPacketList::iterator protected_packet_list_it; 468 protected_packet_list_it = fec_packet->protected_pkt_list.begin(); 469 while (protected_packet_list_it != fec_packet->protected_pkt_list.end()) { 470 delete *protected_packet_list_it; 471 protected_packet_list_it = 472 fec_packet->protected_pkt_list.erase(protected_packet_list_it); 473 } 474 assert(fec_packet->protected_pkt_list.empty()); 475 delete fec_packet; 476 fec_packet_list_.pop_front(); 477 } 478 assert(fec_packet_list_.empty()); 479 } 480 481 void ForwardErrorCorrection::InsertMediaPacket( 482 ReceivedPacket* rx_packet, 483 RecoveredPacketList* recovered_packet_list) { 484 RecoveredPacketList::iterator recovered_packet_list_it = 485 recovered_packet_list->begin(); 486 487 // Search for duplicate packets. 488 while (recovered_packet_list_it != recovered_packet_list->end()) { 489 if (rx_packet->seq_num == (*recovered_packet_list_it)->seq_num) { 490 // Duplicate packet, no need to add to list. 491 // Delete duplicate media packet data. 492 rx_packet->pkt = NULL; 493 return; 494 } 495 recovered_packet_list_it++; 496 } 497 RecoveredPacket* recoverd_packet_to_insert = new RecoveredPacket; 498 recoverd_packet_to_insert->was_recovered = false; 499 // Inserted Media packet is already sent to VCM. 500 recoverd_packet_to_insert->returned = true; 501 recoverd_packet_to_insert->seq_num = rx_packet->seq_num; 502 recoverd_packet_to_insert->pkt = rx_packet->pkt; 503 recoverd_packet_to_insert->pkt->length = rx_packet->pkt->length; 504 505 // TODO(holmer): Consider replacing this with a binary search for the right 506 // position, and then just insert the new packet. Would get rid of the sort. 507 recovered_packet_list->push_back(recoverd_packet_to_insert); 508 recovered_packet_list->sort(SortablePacket::LessThan); 509 UpdateCoveringFECPackets(recoverd_packet_to_insert); 510 } 511 512 void ForwardErrorCorrection::UpdateCoveringFECPackets(RecoveredPacket* packet) { 513 for (FecPacketList::iterator it = fec_packet_list_.begin(); 514 it != fec_packet_list_.end(); ++it) { 515 // Is this FEC packet protecting the media packet |packet|? 516 ProtectedPacketList::iterator protected_it = std::lower_bound( 517 (*it)->protected_pkt_list.begin(), (*it)->protected_pkt_list.end(), 518 packet, SortablePacket::LessThan); 519 if (protected_it != (*it)->protected_pkt_list.end() && 520 (*protected_it)->seq_num == packet->seq_num) { 521 // Found an FEC packet which is protecting |packet|. 522 (*protected_it)->pkt = packet->pkt; 523 } 524 } 525 } 526 527 void ForwardErrorCorrection::InsertFECPacket( 528 ReceivedPacket* rx_packet, 529 const RecoveredPacketList* recovered_packet_list) { 530 fec_packet_received_ = true; 531 532 // Check for duplicate. 533 FecPacketList::iterator fec_packet_list_it = fec_packet_list_.begin(); 534 while (fec_packet_list_it != fec_packet_list_.end()) { 535 if (rx_packet->seq_num == (*fec_packet_list_it)->seq_num) { 536 // Delete duplicate FEC packet data. 537 rx_packet->pkt = NULL; 538 return; 539 } 540 fec_packet_list_it++; 541 } 542 FecPacket* fec_packet = new FecPacket; 543 fec_packet->pkt = rx_packet->pkt; 544 fec_packet->seq_num = rx_packet->seq_num; 545 fec_packet->ssrc = rx_packet->ssrc; 546 547 const uint16_t seq_num_base = 548 ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[2]); 549 const uint16_t maskSizeBytes = (fec_packet->pkt->data[0] & 0x40) 550 ? kMaskSizeLBitSet 551 : kMaskSizeLBitClear; // L bit set? 552 553 for (uint16_t byte_idx = 0; byte_idx < maskSizeBytes; ++byte_idx) { 554 uint8_t packet_mask = fec_packet->pkt->data[12 + byte_idx]; 555 for (uint16_t bit_idx = 0; bit_idx < 8; ++bit_idx) { 556 if (packet_mask & (1 << (7 - bit_idx))) { 557 ProtectedPacket* protected_packet = new ProtectedPacket; 558 fec_packet->protected_pkt_list.push_back(protected_packet); 559 // This wraps naturally with the sequence number. 560 protected_packet->seq_num = 561 static_cast<uint16_t>(seq_num_base + (byte_idx << 3) + bit_idx); 562 protected_packet->pkt = NULL; 563 } 564 } 565 } 566 if (fec_packet->protected_pkt_list.empty()) { 567 // All-zero packet mask; we can discard this FEC packet. 568 LOG(LS_WARNING) << "FEC packet has an all-zero packet mask."; 569 delete fec_packet; 570 } else { 571 AssignRecoveredPackets(fec_packet, recovered_packet_list); 572 // TODO(holmer): Consider replacing this with a binary search for the right 573 // position, and then just insert the new packet. Would get rid of the sort. 574 fec_packet_list_.push_back(fec_packet); 575 fec_packet_list_.sort(SortablePacket::LessThan); 576 if (fec_packet_list_.size() > kMaxFecPackets) { 577 DiscardFECPacket(fec_packet_list_.front()); 578 fec_packet_list_.pop_front(); 579 } 580 assert(fec_packet_list_.size() <= kMaxFecPackets); 581 } 582 } 583 584 void ForwardErrorCorrection::AssignRecoveredPackets( 585 FecPacket* fec_packet, 586 const RecoveredPacketList* recovered_packets) { 587 // Search for missing packets which have arrived or have been recovered by 588 // another FEC packet. 589 ProtectedPacketList* not_recovered = &fec_packet->protected_pkt_list; 590 RecoveredPacketList already_recovered; 591 std::set_intersection( 592 recovered_packets->begin(), recovered_packets->end(), 593 not_recovered->begin(), not_recovered->end(), 594 std::inserter(already_recovered, already_recovered.end()), 595 SortablePacket::LessThan); 596 // Set the FEC pointers to all recovered packets so that we don't have to 597 // search for them when we are doing recovery. 598 ProtectedPacketList::iterator not_recovered_it = not_recovered->begin(); 599 for (RecoveredPacketList::iterator it = already_recovered.begin(); 600 it != already_recovered.end(); ++it) { 601 // Search for the next recovered packet in |not_recovered|. 602 while ((*not_recovered_it)->seq_num != (*it)->seq_num) 603 ++not_recovered_it; 604 (*not_recovered_it)->pkt = (*it)->pkt; 605 } 606 } 607 608 void ForwardErrorCorrection::InsertPackets( 609 ReceivedPacketList* received_packet_list, 610 RecoveredPacketList* recovered_packet_list) { 611 while (!received_packet_list->empty()) { 612 ReceivedPacket* rx_packet = received_packet_list->front(); 613 614 // Check for discarding oldest FEC packet, to avoid wrong FEC decoding from 615 // sequence number wrap-around. Detection of old FEC packet is based on 616 // sequence number difference of received packet and oldest packet in FEC 617 // packet list. 618 // TODO(marpan/holmer): We should be able to improve detection/discarding of 619 // old FEC packets based on timestamp information or better sequence number 620 // thresholding (e.g., to distinguish between wrap-around and reordering). 621 if (!fec_packet_list_.empty()) { 622 uint16_t seq_num_diff = 623 abs(static_cast<int>(rx_packet->seq_num) - 624 static_cast<int>(fec_packet_list_.front()->seq_num)); 625 if (seq_num_diff > 0x3fff) { 626 DiscardFECPacket(fec_packet_list_.front()); 627 fec_packet_list_.pop_front(); 628 } 629 } 630 631 if (rx_packet->is_fec) { 632 InsertFECPacket(rx_packet, recovered_packet_list); 633 } else { 634 // Insert packet at the end of |recoveredPacketList|. 635 InsertMediaPacket(rx_packet, recovered_packet_list); 636 } 637 // Delete the received packet "wrapper", but not the packet data. 638 delete rx_packet; 639 received_packet_list->pop_front(); 640 } 641 assert(received_packet_list->empty()); 642 DiscardOldPackets(recovered_packet_list); 643 } 644 645 bool ForwardErrorCorrection::InitRecovery(const FecPacket* fec_packet, 646 RecoveredPacket* recovered) { 647 // This is the first packet which we try to recover with. 648 const uint16_t ulp_header_size = fec_packet->pkt->data[0] & 0x40 649 ? kUlpHeaderSizeLBitSet 650 : kUlpHeaderSizeLBitClear; // L bit set? 651 if (fec_packet->pkt->length < 652 static_cast<size_t>(kFecHeaderSize + ulp_header_size)) { 653 LOG(LS_WARNING) 654 << "Truncated FEC packet doesn't contain room for ULP header."; 655 return false; 656 } 657 recovered->pkt = new Packet; 658 memset(recovered->pkt->data, 0, IP_PACKET_SIZE); 659 recovered->returned = false; 660 recovered->was_recovered = true; 661 uint16_t protection_length = 662 ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[10]); 663 if (protection_length > 664 std::min( 665 sizeof(recovered->pkt->data) - kRtpHeaderSize, 666 sizeof(fec_packet->pkt->data) - kFecHeaderSize - ulp_header_size)) { 667 LOG(LS_WARNING) << "Incorrect FEC protection length, dropping."; 668 return false; 669 } 670 // Copy FEC payload, skipping the ULP header. 671 memcpy(&recovered->pkt->data[kRtpHeaderSize], 672 &fec_packet->pkt->data[kFecHeaderSize + ulp_header_size], 673 protection_length); 674 // Copy the length recovery field. 675 memcpy(recovered->length_recovery, &fec_packet->pkt->data[8], 2); 676 // Copy the first 2 bytes of the FEC header. 677 memcpy(recovered->pkt->data, fec_packet->pkt->data, 2); 678 // Copy the 5th to 8th bytes of the FEC header. 679 memcpy(&recovered->pkt->data[4], &fec_packet->pkt->data[4], 4); 680 // Set the SSRC field. 681 ByteWriter<uint32_t>::WriteBigEndian(&recovered->pkt->data[8], 682 fec_packet->ssrc); 683 return true; 684 } 685 686 bool ForwardErrorCorrection::FinishRecovery(RecoveredPacket* recovered) { 687 // Set the RTP version to 2. 688 recovered->pkt->data[0] |= 0x80; // Set the 1st bit. 689 recovered->pkt->data[0] &= 0xbf; // Clear the 2nd bit. 690 691 // Set the SN field. 692 ByteWriter<uint16_t>::WriteBigEndian(&recovered->pkt->data[2], 693 recovered->seq_num); 694 // Recover the packet length. 695 recovered->pkt->length = 696 ByteReader<uint16_t>::ReadBigEndian(recovered->length_recovery) + 697 kRtpHeaderSize; 698 if (recovered->pkt->length > sizeof(recovered->pkt->data) - kRtpHeaderSize) 699 return false; 700 701 return true; 702 } 703 704 void ForwardErrorCorrection::XorPackets(const Packet* src_packet, 705 RecoveredPacket* dst_packet) { 706 // XOR with the first 2 bytes of the RTP header. 707 for (uint32_t i = 0; i < 2; ++i) { 708 dst_packet->pkt->data[i] ^= src_packet->data[i]; 709 } 710 // XOR with the 5th to 8th bytes of the RTP header. 711 for (uint32_t i = 4; i < 8; ++i) { 712 dst_packet->pkt->data[i] ^= src_packet->data[i]; 713 } 714 // XOR with the network-ordered payload size. 715 uint8_t media_payload_length[2]; 716 ByteWriter<uint16_t>::WriteBigEndian(media_payload_length, 717 src_packet->length - kRtpHeaderSize); 718 dst_packet->length_recovery[0] ^= media_payload_length[0]; 719 dst_packet->length_recovery[1] ^= media_payload_length[1]; 720 721 // XOR with RTP payload. 722 // TODO(marpan/ajm): Are we doing more XORs than required here? 723 for (size_t i = kRtpHeaderSize; i < src_packet->length; ++i) { 724 dst_packet->pkt->data[i] ^= src_packet->data[i]; 725 } 726 } 727 728 bool ForwardErrorCorrection::RecoverPacket( 729 const FecPacket* fec_packet, 730 RecoveredPacket* rec_packet_to_insert) { 731 if (!InitRecovery(fec_packet, rec_packet_to_insert)) 732 return false; 733 ProtectedPacketList::const_iterator protected_it = 734 fec_packet->protected_pkt_list.begin(); 735 while (protected_it != fec_packet->protected_pkt_list.end()) { 736 if ((*protected_it)->pkt == NULL) { 737 // This is the packet we're recovering. 738 rec_packet_to_insert->seq_num = (*protected_it)->seq_num; 739 } else { 740 XorPackets((*protected_it)->pkt, rec_packet_to_insert); 741 } 742 ++protected_it; 743 } 744 if (!FinishRecovery(rec_packet_to_insert)) 745 return false; 746 return true; 747 } 748 749 void ForwardErrorCorrection::AttemptRecover( 750 RecoveredPacketList* recovered_packet_list) { 751 FecPacketList::iterator fec_packet_list_it = fec_packet_list_.begin(); 752 while (fec_packet_list_it != fec_packet_list_.end()) { 753 // Search for each FEC packet's protected media packets. 754 int packets_missing = NumCoveredPacketsMissing(*fec_packet_list_it); 755 756 // We can only recover one packet with an FEC packet. 757 if (packets_missing == 1) { 758 // Recovery possible. 759 RecoveredPacket* packet_to_insert = new RecoveredPacket; 760 packet_to_insert->pkt = NULL; 761 if (!RecoverPacket(*fec_packet_list_it, packet_to_insert)) { 762 // Can't recover using this packet, drop it. 763 DiscardFECPacket(*fec_packet_list_it); 764 fec_packet_list_it = fec_packet_list_.erase(fec_packet_list_it); 765 delete packet_to_insert; 766 continue; 767 } 768 769 // Add recovered packet to the list of recovered packets and update any 770 // FEC packets covering this packet with a pointer to the data. 771 // TODO(holmer): Consider replacing this with a binary search for the 772 // right position, and then just insert the new packet. Would get rid of 773 // the sort. 774 recovered_packet_list->push_back(packet_to_insert); 775 recovered_packet_list->sort(SortablePacket::LessThan); 776 UpdateCoveringFECPackets(packet_to_insert); 777 DiscardOldPackets(recovered_packet_list); 778 DiscardFECPacket(*fec_packet_list_it); 779 fec_packet_list_it = fec_packet_list_.erase(fec_packet_list_it); 780 781 // A packet has been recovered. We need to check the FEC list again, as 782 // this may allow additional packets to be recovered. 783 // Restart for first FEC packet. 784 fec_packet_list_it = fec_packet_list_.begin(); 785 } else if (packets_missing == 0) { 786 // Either all protected packets arrived or have been recovered. We can 787 // discard this FEC packet. 788 DiscardFECPacket(*fec_packet_list_it); 789 fec_packet_list_it = fec_packet_list_.erase(fec_packet_list_it); 790 } else { 791 fec_packet_list_it++; 792 } 793 } 794 } 795 796 int ForwardErrorCorrection::NumCoveredPacketsMissing( 797 const FecPacket* fec_packet) { 798 int packets_missing = 0; 799 ProtectedPacketList::const_iterator it = 800 fec_packet->protected_pkt_list.begin(); 801 for (; it != fec_packet->protected_pkt_list.end(); ++it) { 802 if ((*it)->pkt == NULL) { 803 ++packets_missing; 804 if (packets_missing > 1) { 805 break; // We can't recover more than one packet. 806 } 807 } 808 } 809 return packets_missing; 810 } 811 812 void ForwardErrorCorrection::DiscardFECPacket(FecPacket* fec_packet) { 813 while (!fec_packet->protected_pkt_list.empty()) { 814 delete fec_packet->protected_pkt_list.front(); 815 fec_packet->protected_pkt_list.pop_front(); 816 } 817 assert(fec_packet->protected_pkt_list.empty()); 818 delete fec_packet; 819 } 820 821 void ForwardErrorCorrection::DiscardOldPackets( 822 RecoveredPacketList* recovered_packet_list) { 823 while (recovered_packet_list->size() > kMaxMediaPackets) { 824 ForwardErrorCorrection::RecoveredPacket* packet = 825 recovered_packet_list->front(); 826 delete packet; 827 recovered_packet_list->pop_front(); 828 } 829 assert(recovered_packet_list->size() <= kMaxMediaPackets); 830 } 831 832 uint16_t ForwardErrorCorrection::ParseSequenceNumber(uint8_t* packet) { 833 return (packet[2] << 8) + packet[3]; 834 } 835 836 int32_t ForwardErrorCorrection::DecodeFEC( 837 ReceivedPacketList* received_packet_list, 838 RecoveredPacketList* recovered_packet_list) { 839 // TODO(marpan/ajm): can we check for multiple ULP headers, and return an 840 // error? 841 if (recovered_packet_list->size() == kMaxMediaPackets) { 842 const unsigned int seq_num_diff = 843 abs(static_cast<int>(received_packet_list->front()->seq_num) - 844 static_cast<int>(recovered_packet_list->back()->seq_num)); 845 if (seq_num_diff > kMaxMediaPackets) { 846 // A big gap in sequence numbers. The old recovered packets 847 // are now useless, so it's safe to do a reset. 848 ResetState(recovered_packet_list); 849 } 850 } 851 InsertPackets(received_packet_list, recovered_packet_list); 852 AttemptRecover(recovered_packet_list); 853 return 0; 854 } 855 856 size_t ForwardErrorCorrection::PacketOverhead() { 857 return kFecHeaderSize + kUlpHeaderSizeLBitSet; 858 } 859 } // namespace webrtc 860