1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/* 2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * 4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Use of this source code is governed by a BSD-style license 5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * that can be found in the LICENSE file in the root of the source 6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * tree. An additional intellectual property rights grant can be found 7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * in the file PATENTS. All contributing project authors may 8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * be found in the AUTHORS file in the root of the source tree. 9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */ 10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 114efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" 12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 133f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org#include <assert.h> 14b1d7931d9f5480350739fb268d48a46055079b07stefan@webrtc.org#include <stdlib.h> 153f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org#include <string.h> 163f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org 17b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <algorithm> 18b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <iterator> 19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 203e4cdeca70f8a9499fb746fa4e9a094a449dda86sprang@webrtc.org#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h" 214efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org#include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h" 224efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" 2399681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org#include "webrtc/system_wrappers/interface/logging.h" 24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc { 26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// FEC header size in bytes. 28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgconst uint8_t kFecHeaderSize = 10; 29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ULP header size in bytes (L bit is set). 31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgconst uint8_t kUlpHeaderSizeLBitSet = (2 + kMaskSizeLBitSet); 32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// ULP header size in bytes (L bit is cleared). 34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgconst uint8_t kUlpHeaderSizeLBitClear = (2 + kMaskSizeLBitClear); 35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum. 37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgconst uint8_t kTransportOverhead = 28; 38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 394efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.orgenum { 404efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org kMaxFecPackets = ForwardErrorCorrection::kMaxMediaPackets 414efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org}; 42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 439d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.orgint32_t ForwardErrorCorrection::Packet::AddRef() { return ++ref_count_; } 449d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.org 459d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.orgint32_t ForwardErrorCorrection::Packet::Release() { 469d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.org int32_t ref_count; 479d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.org ref_count = --ref_count_; 489d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.org if (ref_count == 0) 499d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.org delete this; 509d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.org return ref_count; 519d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.org} 529d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.org 53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Used to link media packets to their protecting FEC packets. 54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// 55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// TODO(holmer): Refactor into a proper class. 56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgclass ProtectedPacket : public ForwardErrorCorrection::SortablePacket { 57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org public: 58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org scoped_refptr<ForwardErrorCorrection::Packet> pkt; 59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}; 60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgtypedef std::list<ProtectedPacket*> ProtectedPacketList; 62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// 64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Used for internal storage of FEC packets in a list. 65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// 66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// TODO(holmer): Refactor into a proper class. 67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgclass FecPacket : public ForwardErrorCorrection::SortablePacket { 68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org public: 694efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org ProtectedPacketList protected_pkt_list; 704efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint32_t ssrc; // SSRC of the current frame. 714efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org scoped_refptr<ForwardErrorCorrection::Packet> pkt; 72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}; 73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool ForwardErrorCorrection::SortablePacket::LessThan( 754efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const SortablePacket* first, const SortablePacket* second) { 764efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org return IsNewerSequenceNumber(second->seq_num, first->seq_num); 77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 799d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.orgForwardErrorCorrection::ReceivedPacket::ReceivedPacket() {} 809d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.orgForwardErrorCorrection::ReceivedPacket::~ReceivedPacket() {} 819d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.org 829d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.orgForwardErrorCorrection::RecoveredPacket::RecoveredPacket() {} 839d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.orgForwardErrorCorrection::RecoveredPacket::~RecoveredPacket() {} 849d71e286a6c8fa79d30fc6f55e0e6071de5d37e3pbos@webrtc.org 8599681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.orgForwardErrorCorrection::ForwardErrorCorrection() 8699681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org : generated_fec_packets_(kMaxMediaPackets), 874efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_received_(false) {} 88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 894efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.orgForwardErrorCorrection::~ForwardErrorCorrection() {} 90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Input packet 92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// | RTP Header (12 octets) | 94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// | RTP Payload | 96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// | | 97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Output packet 100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// | FEC Header (10 octets) | 102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// | FEC Level 0 Header | 104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// | FEC Level 0 Payload | 106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// | | 107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1084efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.orgint32_t ForwardErrorCorrection::GenerateFEC(const PacketList& media_packet_list, 1094efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint8_t protection_factor, 1104efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org int num_important_packets, 1114efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org bool use_unequal_protection, 1124efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org FecMaskType fec_mask_type, 1134efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org PacketList* fec_packet_list) { 1144efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const uint16_t num_media_packets = media_packet_list.size(); 11599681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org 11699681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org // Sanity check arguments. 11799681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org assert(num_media_packets > 0); 11899681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org assert(num_important_packets >= 0 && 11999681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org num_important_packets <= num_media_packets); 12099681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org assert(fec_packet_list->empty()); 121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1224efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (num_media_packets > kMaxMediaPackets) { 12399681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org LOG(LS_WARNING) << "Can't protect " << num_media_packets 12499681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org << " media packets per frame. Max is " << kMaxMediaPackets; 125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 12899681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org bool l_bit = (num_media_packets > 8 * kMaskSizeLBitClear); 12999681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org int num_maskBytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; 13099681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org 131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Do some error checking on the media packets. 1324efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org PacketList::const_iterator media_list_it = media_packet_list.begin(); 1334efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while (media_list_it != media_packet_list.end()) { 1344efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org Packet* media_packet = *media_list_it; 1354efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org assert(media_packet); 136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1374efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (media_packet->length < kRtpHeaderSize) { 13899681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes " 13999681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org << "is smaller than RTP header."; 140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Ensure our FEC packets will fit in a typical MTU. 1444efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (media_packet->length + PacketOverhead() + kTransportOverhead > 145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org IP_PACKET_SIZE) { 14699681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes " 14799681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org << "with overhead is larger than " << IP_PACKET_SIZE; 148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1494efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org media_list_it++; 150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1524efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org int num_fec_packets = 1534efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org GetNumberOfFecPackets(num_media_packets, protection_factor); 1544efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (num_fec_packets == 0) { 155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Prepare FEC packets by setting them to 0. 1594efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org for (int i = 0; i < num_fec_packets; ++i) { 1604efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org memset(generated_fec_packets_[i].data, 0, IP_PACKET_SIZE); 1614efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org generated_fec_packets_[i].length = 0; // Use this as a marker for untouched 1624efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org // packets. 1634efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_list->push_back(&generated_fec_packets_[i]); 164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1664efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets); 167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // -- Generate packet masks -- 169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Always allocate space for a large mask. 1704efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint8_t* packet_mask = new uint8_t[num_fec_packets * kMaskSizeLBitSet]; 1714efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org memset(packet_mask, 0, num_fec_packets * num_maskBytes); 1724efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org internal::GeneratePacketMasks(num_media_packets, num_fec_packets, 1734efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org num_important_packets, use_unequal_protection, 1744efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org mask_table, packet_mask); 175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1764efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org int num_maskBits = InsertZerosInBitMasks(media_packet_list, packet_mask, 1774efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org num_maskBytes, num_fec_packets); 178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1794efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org l_bit = (num_maskBits > 8 * kMaskSizeLBitClear); 180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1814efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (num_maskBits < 0) { 1824efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org delete[] packet_mask; 183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return -1; 184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1854efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (l_bit) { 1864efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org num_maskBytes = kMaskSizeLBitSet; 187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1894efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org GenerateFecBitStrings(media_packet_list, packet_mask, num_fec_packets, l_bit); 1904efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org GenerateFecUlpHeaders(media_packet_list, packet_mask, l_bit, num_fec_packets); 191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1924efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org delete[] packet_mask; 193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 1964efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.orgint ForwardErrorCorrection::GetNumberOfFecPackets(int num_media_packets, 1974efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org int protection_factor) { 198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Result in Q0 with an unsigned round. 1994efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org int num_fec_packets = (num_media_packets * protection_factor + (1 << 7)) >> 8; 200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Generate at least one FEC packet if we need protection. 2014efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (protection_factor > 0 && num_fec_packets == 0) { 2024efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org num_fec_packets = 1; 203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2044efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org assert(num_fec_packets <= num_media_packets); 2054efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org return num_fec_packets; 206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::GenerateFecBitStrings( 2094efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const PacketList& media_packet_list, uint8_t* packet_mask, 2104efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org int num_fec_packets, bool l_bit) { 2114efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (media_packet_list.empty()) { 212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return; 213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2144efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint8_t media_payload_length[2]; 2154efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const int num_maskBytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; 2164efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const uint16_t ulp_header_size = 2174efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear; 2184efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const uint16_t fec_rtp_offset = 2194efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org kFecHeaderSize + ulp_header_size - kRtpHeaderSize; 2204efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org 2214efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org for (int i = 0; i < num_fec_packets; ++i) { 2224efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org PacketList::const_iterator media_list_it = media_packet_list.begin(); 2234efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint32_t pkt_mask_idx = i * num_maskBytes; 2244efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint32_t media_pkt_idx = 0; 2254efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint16_t fec_packet_length = 0; 2264efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint16_t prev_seq_num = ParseSequenceNumber((*media_list_it)->data); 2274efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while (media_list_it != media_packet_list.end()) { 228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Each FEC packet has a multiple byte mask. 2294efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (packet_mask[pkt_mask_idx] & (1 << (7 - media_pkt_idx))) { 2304efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org Packet* media_packet = *media_list_it; 231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Assign network-ordered media payload length. 2336aae61c2c693fa3425c73c420e7046e95486b592pbos@webrtc.org RtpUtility::AssignUWord16ToBuffer( 2344efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org media_payload_length, media_packet->length - kRtpHeaderSize); 235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2364efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_length = media_packet->length + fec_rtp_offset; 237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // On the first protected packet, we don't need to XOR. 2384efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (generated_fec_packets_[i].length == 0) { 239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Copy the first 2 bytes of the RTP header. 2404efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org memcpy(generated_fec_packets_[i].data, media_packet->data, 2); 241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Copy the 5th to 8th bytes of the RTP header. 2424efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org memcpy(&generated_fec_packets_[i].data[4], &media_packet->data[4], 4); 243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Copy network-ordered payload size. 2444efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org memcpy(&generated_fec_packets_[i].data[8], media_payload_length, 2); 245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Copy RTP payload, leaving room for the ULP header. 2474efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org memcpy( 2484efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org &generated_fec_packets_[i].data[kFecHeaderSize + ulp_header_size], 2494efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org &media_packet->data[kRtpHeaderSize], 2504efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org media_packet->length - kRtpHeaderSize); 251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else { 252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // XOR with the first 2 bytes of the RTP header. 2534efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org generated_fec_packets_[i].data[0] ^= media_packet->data[0]; 2544efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org generated_fec_packets_[i].data[1] ^= media_packet->data[1]; 255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // XOR with the 5th to 8th bytes of the RTP header. 2574efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org for (uint32_t j = 4; j < 8; ++j) { 2584efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org generated_fec_packets_[i].data[j] ^= media_packet->data[j]; 259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // XOR with the network-ordered payload size. 2624efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org generated_fec_packets_[i].data[8] ^= media_payload_length[0]; 2634efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org generated_fec_packets_[i].data[9] ^= media_payload_length[1]; 264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // XOR with RTP payload, leaving room for the ULP header. 2664efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org for (int32_t j = kFecHeaderSize + ulp_header_size; 2674efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org j < fec_packet_length; j++) { 2684efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org generated_fec_packets_[i].data[j] ^= 2694efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org media_packet->data[j - fec_rtp_offset]; 270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2724efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (fec_packet_length > generated_fec_packets_[i].length) { 2734efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org generated_fec_packets_[i].length = fec_packet_length; 274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2764efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org media_list_it++; 2774efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (media_list_it != media_packet_list.end()) { 2784efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint16_t seq_num = ParseSequenceNumber((*media_list_it)->data); 2794efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num); 2804efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org prev_seq_num = seq_num; 281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2824efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (media_pkt_idx == 8) { 283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Switch to the next mask byte. 2844efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org media_pkt_idx = 0; 2854efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org pkt_mask_idx++; 286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2884efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org assert(generated_fec_packets_[i].length); 289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org //Note: This shouldn't happen: means packet mask is wrong or poorly designed 290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint ForwardErrorCorrection::InsertZerosInBitMasks( 2944efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const PacketList& media_packets, uint8_t* packet_mask, int num_mask_bytes, 295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int num_fec_packets) { 296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org uint8_t* new_mask = NULL; 297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (media_packets.size() <= 1) { 298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return media_packets.size(); 299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int last_seq_num = ParseSequenceNumber(media_packets.back()->data); 301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int first_seq_num = ParseSequenceNumber(media_packets.front()->data); 3024efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org int total_missing_seq_nums = 3034efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org static_cast<uint16_t>(last_seq_num - first_seq_num) - 3044efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org media_packets.size() + 1; 305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (total_missing_seq_nums == 0) { 306b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // All sequence numbers are covered by the packet mask. No zero insertion 307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // required. 308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return media_packets.size(); 309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Allocate the new mask. 311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int new_mask_bytes = kMaskSizeLBitClear; 312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (media_packets.size() + total_missing_seq_nums > 8 * kMaskSizeLBitClear) { 313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org new_mask_bytes = kMaskSizeLBitSet; 314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org new_mask = new uint8_t[num_fec_packets * kMaskSizeLBitSet]; 316b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(new_mask, 0, num_fec_packets * kMaskSizeLBitSet); 317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 318b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org PacketList::const_iterator it = media_packets.begin(); 319b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org uint16_t prev_seq_num = first_seq_num; 320b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ++it; 321b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 322b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Insert the first column. 323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CopyColumn(new_mask, new_mask_bytes, packet_mask, num_mask_bytes, 324b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org num_fec_packets, 0, 0); 325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int new_bit_index = 1; 326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int old_bit_index = 1; 327b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Insert zeros in the bit mask for every hole in the sequence. 328b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org for (; it != media_packets.end(); ++it) { 329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (new_bit_index == 8 * kMaskSizeLBitSet) { 330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We can only cover up to 48 packets. 331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org break; 332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org uint16_t seq_num = ParseSequenceNumber((*it)->data); 334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const int zeros_to_insert = 335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org static_cast<uint16_t>(seq_num - prev_seq_num - 1); 336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (zeros_to_insert > 0) { 337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org InsertZeroColumns(zeros_to_insert, new_mask, new_mask_bytes, 338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org num_fec_packets, new_bit_index); 339b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 340b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org new_bit_index += zeros_to_insert; 341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org CopyColumn(new_mask, new_mask_bytes, packet_mask, num_mask_bytes, 342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org num_fec_packets, new_bit_index, old_bit_index); 343b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ++new_bit_index; 344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ++old_bit_index; 345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org prev_seq_num = seq_num; 346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (new_bit_index % 8 != 0) { 348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We didn't fill the last byte. Shift bits to correct position. 349b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org for (uint16_t row = 0; row < num_fec_packets; ++row) { 350b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int new_byte_index = row * new_mask_bytes + new_bit_index / 8; 351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org new_mask[new_byte_index] <<= (7 - (new_bit_index % 8)); 352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Replace the old mask with the new. 355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memcpy(packet_mask, new_mask, kMaskSizeLBitSet * num_fec_packets); 3564efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org delete[] new_mask; 357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return new_bit_index; 358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3604efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.orgvoid ForwardErrorCorrection::InsertZeroColumns(int num_zeros, uint8_t* new_mask, 361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int new_mask_bytes, 362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int num_fec_packets, 363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int new_bit_index) { 364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org for (uint16_t row = 0; row < num_fec_packets; ++row) { 365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const int new_byte_index = row * new_mask_bytes + new_bit_index / 8; 366b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const int max_shifts = (7 - (new_bit_index % 8)); 367b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org new_mask[new_byte_index] <<= std::min(num_zeros, max_shifts); 368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 369b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3714efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.orgvoid ForwardErrorCorrection::CopyColumn(uint8_t* new_mask, int new_mask_bytes, 3724efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint8_t* old_mask, int old_mask_bytes, 3734efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org int num_fec_packets, int new_bit_index, 374b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int old_bit_index) { 375b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Copy column from the old mask to the beginning of the new mask and shift it 376b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // out from the old mask. 377b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org for (uint16_t row = 0; row < num_fec_packets; ++row) { 378b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int new_byte_index = row * new_mask_bytes + new_bit_index / 8; 379b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int old_byte_index = row * old_mask_bytes + old_bit_index / 8; 380b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org new_mask[new_byte_index] |= ((old_mask[old_byte_index] & 0x80) >> 7); 381b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (new_bit_index % 8 != 7) { 382b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org new_mask[new_byte_index] <<= 1; 383b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 384b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org old_mask[old_byte_index] <<= 1; 385b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 386b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 387b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 388b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::GenerateFecUlpHeaders( 3894efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const PacketList& media_packet_list, uint8_t* packet_mask, bool l_bit, 3904efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org int num_fec_packets) { 391b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // -- Generate FEC and ULP headers -- 392b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 393b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // FEC Header, 10 bytes 394b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 0 1 2 3 395b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 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 396b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 397b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // |E|L|P|X| CC |M| PT recovery | SN base | 398b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 399b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // | TS recovery | 400b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 401b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // | length recovery | 402b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 403b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 404b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // ULP Header, 4 bytes (for L = 0) 405b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 0 1 2 3 406b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // 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 407b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 408b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // | Protection Length | mask | 409b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 410b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // | mask cont. (present only when L = 1) | 411b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4124efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org PacketList::const_iterator media_list_it = media_packet_list.begin(); 4134efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org Packet* media_packet = *media_list_it; 4144efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org assert(media_packet != NULL); 4154efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org int num_maskBytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; 4164efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const uint16_t ulp_header_size = 4174efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear; 4184efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org 4194efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org for (int i = 0; i < num_fec_packets; ++i) { 420b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // -- FEC header -- 4214efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org generated_fec_packets_[i].data[0] &= 0x7f; // Set E to zero. 4224efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (l_bit == 0) { 4234efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org generated_fec_packets_[i].data[0] &= 0xbf; // Clear the L bit. 424b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else { 4254efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org generated_fec_packets_[i].data[0] |= 0x40; // Set the L bit. 426b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Two byte sequence number from first RTP packet to SN base. 428b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We use the same sequence number base for every FEC packet, 429b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // but that's not required in general. 4304efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org memcpy(&generated_fec_packets_[i].data[2], &media_packet->data[2], 2); 431b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 432b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // -- ULP header -- 433b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Copy the payload size to the protection length field. 434b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // (We protect the entire packet.) 4356aae61c2c693fa3425c73c420e7046e95486b592pbos@webrtc.org RtpUtility::AssignUWord16ToBuffer( 4364efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org &generated_fec_packets_[i].data[10], 4374efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org generated_fec_packets_[i].length - kFecHeaderSize - ulp_header_size); 438b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 439b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Copy the packet mask. 4404efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org memcpy(&generated_fec_packets_[i].data[12], &packet_mask[i * num_maskBytes], 4414efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org num_maskBytes); 442b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 443b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 444b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 445b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::ResetState( 4464efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org RecoveredPacketList* recovered_packet_list) { 4474efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_received_ = false; 448b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 449b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Free the memory for any existing recovered packets, if the user hasn't. 4504efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while (!recovered_packet_list->empty()) { 4514efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org delete recovered_packet_list->front(); 4524efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recovered_packet_list->pop_front(); 453b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 4544efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org assert(recovered_packet_list->empty()); 455b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 456b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Free the FEC packet list. 4574efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while (!fec_packet_list_.empty()) { 4584efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org FecPacketList::iterator fec_packet_list_it = fec_packet_list_.begin(); 4594efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org FecPacket* fec_packet = *fec_packet_list_it; 4604efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org ProtectedPacketList::iterator protected_packet_list_it; 4614efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org protected_packet_list_it = fec_packet->protected_pkt_list.begin(); 4624efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while (protected_packet_list_it != fec_packet->protected_pkt_list.end()) { 4634efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org delete* protected_packet_list_it; 4644efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org protected_packet_list_it = 4654efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet->protected_pkt_list.erase(protected_packet_list_it); 466b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 4674efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org assert(fec_packet->protected_pkt_list.empty()); 4684efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org delete fec_packet; 4694efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_list_.pop_front(); 470b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 4714efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org assert(fec_packet_list_.empty()); 472b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 473b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 474b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::InsertMediaPacket( 4754efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org ReceivedPacket* rx_packet, RecoveredPacketList* recovered_packet_list) { 4764efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org RecoveredPacketList::iterator recovered_packet_list_it = 4774efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recovered_packet_list->begin(); 478b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 479b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Search for duplicate packets. 4804efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while (recovered_packet_list_it != recovered_packet_list->end()) { 4814efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (rx_packet->seq_num == (*recovered_packet_list_it)->seq_num) { 482b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Duplicate packet, no need to add to list. 483b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Delete duplicate media packet data. 4844efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org rx_packet->pkt = NULL; 485b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return; 486b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 4874efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recovered_packet_list_it++; 488b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 4894efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org RecoveredPacket* recoverd_packet_to_insert = new RecoveredPacket; 4904efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recoverd_packet_to_insert->was_recovered = false; 491b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Inserted Media packet is already sent to VCM. 4924efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recoverd_packet_to_insert->returned = true; 4934efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recoverd_packet_to_insert->seq_num = rx_packet->seq_num; 4944efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recoverd_packet_to_insert->pkt = rx_packet->pkt; 4954efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recoverd_packet_to_insert->pkt->length = rx_packet->pkt->length; 496b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 497b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(holmer): Consider replacing this with a binary search for the right 498b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // position, and then just insert the new packet. Would get rid of the sort. 4994efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recovered_packet_list->push_back(recoverd_packet_to_insert); 5004efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recovered_packet_list->sort(SortablePacket::LessThan); 5014efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org UpdateCoveringFECPackets(recoverd_packet_to_insert); 502b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 503b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 504b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::UpdateCoveringFECPackets(RecoveredPacket* packet) { 5054efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org for (FecPacketList::iterator it = fec_packet_list_.begin(); 5064efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org it != fec_packet_list_.end(); ++it) { 507b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Is this FEC packet protecting the media packet |packet|? 508b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ProtectedPacketList::iterator protected_it = std::lower_bound( 5094efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org (*it)->protected_pkt_list.begin(), (*it)->protected_pkt_list.end(), 5104efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org packet, SortablePacket::LessThan); 5114efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (protected_it != (*it)->protected_pkt_list.end() && 5124efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org (*protected_it)->seq_num == packet->seq_num) { 513b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Found an FEC packet which is protecting |packet|. 514b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org (*protected_it)->pkt = packet->pkt; 515b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 516b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 517b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 518b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 519b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::InsertFECPacket( 5204efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org ReceivedPacket* rx_packet, 5214efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const RecoveredPacketList* recovered_packet_list) { 5224efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_received_ = true; 523b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 524b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Check for duplicate. 5254efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org FecPacketList::iterator fec_packet_list_it = fec_packet_list_.begin(); 5264efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while (fec_packet_list_it != fec_packet_list_.end()) { 5274efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (rx_packet->seq_num == (*fec_packet_list_it)->seq_num) { 528b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Delete duplicate FEC packet data. 5294efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org rx_packet->pkt = NULL; 530b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return; 531b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 5324efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_list_it++; 5334efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org } 5344efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org FecPacket* fec_packet = new FecPacket; 5354efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet->pkt = rx_packet->pkt; 5364efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet->seq_num = rx_packet->seq_num; 5374efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet->ssrc = rx_packet->ssrc; 5384efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org 5394efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const uint16_t seq_num_base = 5406aae61c2c693fa3425c73c420e7046e95486b592pbos@webrtc.org RtpUtility::BufferToUWord16(&fec_packet->pkt->data[2]); 5414efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const uint16_t maskSizeBytes = 5424efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org (fec_packet->pkt->data[0] & 0x40) ? kMaskSizeLBitSet 5434efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org : kMaskSizeLBitClear; // L bit set? 5444efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org 5454efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org for (uint16_t byte_idx = 0; byte_idx < maskSizeBytes; ++byte_idx) { 5464efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint8_t packet_mask = fec_packet->pkt->data[12 + byte_idx]; 5474efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org for (uint16_t bit_idx = 0; bit_idx < 8; ++bit_idx) { 5484efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (packet_mask & (1 << (7 - bit_idx))) { 5494efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org ProtectedPacket* protected_packet = new ProtectedPacket; 5504efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet->protected_pkt_list.push_back(protected_packet); 551b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // This wraps naturally with the sequence number. 5524efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org protected_packet->seq_num = 5534efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org static_cast<uint16_t>(seq_num_base + (byte_idx << 3) + bit_idx); 5544efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org protected_packet->pkt = NULL; 555b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 556b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 557b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 5584efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (fec_packet->protected_pkt_list.empty()) { 559b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // All-zero packet mask; we can discard this FEC packet. 56099681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org LOG(LS_WARNING) << "FEC packet has an all-zero packet mask."; 5614efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org delete fec_packet; 562b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else { 5634efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org AssignRecoveredPackets(fec_packet, recovered_packet_list); 564b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(holmer): Consider replacing this with a binary search for the right 565b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // position, and then just insert the new packet. Would get rid of the sort. 5664efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_list_.push_back(fec_packet); 5674efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_list_.sort(SortablePacket::LessThan); 5684efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (fec_packet_list_.size() > kMaxFecPackets) { 5694efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org DiscardFECPacket(fec_packet_list_.front()); 5704efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_list_.pop_front(); 571b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 5724efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org assert(fec_packet_list_.size() <= kMaxFecPackets); 573b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 574b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 575b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 576b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::AssignRecoveredPackets( 5774efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org FecPacket* fec_packet, const RecoveredPacketList* recovered_packets) { 578b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Search for missing packets which have arrived or have been recovered by 579b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // another FEC packet. 5804efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org ProtectedPacketList* not_recovered = &fec_packet->protected_pkt_list; 581b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org RecoveredPacketList already_recovered; 582b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org std::set_intersection( 583b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org recovered_packets->begin(), recovered_packets->end(), 584b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org not_recovered->begin(), not_recovered->end(), 585b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org std::inserter(already_recovered, already_recovered.end()), 586b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org SortablePacket::LessThan); 587b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Set the FEC pointers to all recovered packets so that we don't have to 588b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // search for them when we are doing recovery. 589b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ProtectedPacketList::iterator not_recovered_it = not_recovered->begin(); 590b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org for (RecoveredPacketList::iterator it = already_recovered.begin(); 5914efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org it != already_recovered.end(); ++it) { 592b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Search for the next recovered packet in |not_recovered|. 5934efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while ((*not_recovered_it)->seq_num != (*it)->seq_num) 594b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ++not_recovered_it; 595b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org (*not_recovered_it)->pkt = (*it)->pkt; 596b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 597b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 598b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 599b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::InsertPackets( 6004efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org ReceivedPacketList* received_packet_list, 6014efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org RecoveredPacketList* recovered_packet_list) { 602b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 6034efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while (!received_packet_list->empty()) { 6044efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org ReceivedPacket* rx_packet = received_packet_list->front(); 605b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 6060da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org // Check for discarding oldest FEC packet, to avoid wrong FEC decoding from 6070da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org // sequence number wrap-around. Detection of old FEC packet is based on 6080da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org // sequence number difference of received packet and oldest packet in FEC 6090da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org // packet list. 6100da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org // TODO(marpan/holmer): We should be able to improve detection/discarding of 6110da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org // old FEC packets based on timestamp information or better sequence number 6120da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org // thresholding (e.g., to distinguish between wrap-around and reordering). 6130da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org if (!fec_packet_list_.empty()) { 6140da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org uint16_t seq_num_diff = abs( 6150da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org static_cast<int>(rx_packet->seq_num) - 6160da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org static_cast<int>(fec_packet_list_.front()->seq_num)); 6170da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org if (seq_num_diff > 0x3fff) { 6180da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org DiscardFECPacket(fec_packet_list_.front()); 6190da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org fec_packet_list_.pop_front(); 6200da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org } 6210da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org } 6220da4394577384f7edaa3ec3003bd41ec398d4b24marpan@webrtc.org 6234efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (rx_packet->is_fec) { 6244efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org InsertFECPacket(rx_packet, recovered_packet_list); 625b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else { 626b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Insert packet at the end of |recoveredPacketList|. 6274efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org InsertMediaPacket(rx_packet, recovered_packet_list); 628b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 629b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Delete the received packet "wrapper", but not the packet data. 6304efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org delete rx_packet; 6314efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org received_packet_list->pop_front(); 632b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 6334efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org assert(received_packet_list->empty()); 6344efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org DiscardOldPackets(recovered_packet_list); 635b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 636b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 6374efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.orgvoid ForwardErrorCorrection::InitRecovery(const FecPacket* fec_packet, 6384efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org RecoveredPacket* recovered) { 639b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // This is the first packet which we try to recover with. 6404efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const uint16_t ulp_header_size = 6414efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet->pkt->data[0] & 0x40 ? kUlpHeaderSizeLBitSet 6424efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org : kUlpHeaderSizeLBitClear; // L bit set? 643b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org recovered->pkt = new Packet; 644b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memset(recovered->pkt->data, 0, IP_PACKET_SIZE); 645b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org recovered->returned = false; 6464efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recovered->was_recovered = true; 6474efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint8_t protection_length[2]; 648b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Copy the protection length from the ULP header. 6494efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org memcpy(protection_length, &fec_packet->pkt->data[10], 2); 650b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Copy FEC payload, skipping the ULP header. 651b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memcpy(&recovered->pkt->data[kRtpHeaderSize], 6524efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org &fec_packet->pkt->data[kFecHeaderSize + ulp_header_size], 6536aae61c2c693fa3425c73c420e7046e95486b592pbos@webrtc.org RtpUtility::BufferToUWord16(protection_length)); 654b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Copy the length recovery field. 655b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memcpy(recovered->length_recovery, &fec_packet->pkt->data[8], 2); 656b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Copy the first 2 bytes of the FEC header. 657b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memcpy(recovered->pkt->data, fec_packet->pkt->data, 2); 658b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Copy the 5th to 8th bytes of the FEC header. 659b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org memcpy(&recovered->pkt->data[4], &fec_packet->pkt->data[4], 4); 660b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Set the SSRC field. 6616aae61c2c693fa3425c73c420e7046e95486b592pbos@webrtc.org RtpUtility::AssignUWord32ToBuffer(&recovered->pkt->data[8], fec_packet->ssrc); 662b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 663b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 664b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::FinishRecovery(RecoveredPacket* recovered) { 665b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Set the RTP version to 2. 666b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org recovered->pkt->data[0] |= 0x80; // Set the 1st bit. 667b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org recovered->pkt->data[0] &= 0xbf; // Clear the 2nd bit. 668b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 669b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Set the SN field. 6706aae61c2c693fa3425c73c420e7046e95486b592pbos@webrtc.org RtpUtility::AssignUWord16ToBuffer(&recovered->pkt->data[2], 6716aae61c2c693fa3425c73c420e7046e95486b592pbos@webrtc.org recovered->seq_num); 672b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Recover the packet length. 6734efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recovered->pkt->length = 6746aae61c2c693fa3425c73c420e7046e95486b592pbos@webrtc.org RtpUtility::BufferToUWord16(recovered->length_recovery) + kRtpHeaderSize; 675b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 676b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 677b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::XorPackets(const Packet* src_packet, 678b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org RecoveredPacket* dst_packet) { 679b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // XOR with the first 2 bytes of the RTP header. 6804efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org for (uint32_t i = 0; i < 2; ++i) { 681b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org dst_packet->pkt->data[i] ^= src_packet->data[i]; 682b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 683b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // XOR with the 5th to 8th bytes of the RTP header. 6844efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org for (uint32_t i = 4; i < 8; ++i) { 685b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org dst_packet->pkt->data[i] ^= src_packet->data[i]; 686b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 687b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // XOR with the network-ordered payload size. 6884efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org uint8_t media_payload_length[2]; 6896aae61c2c693fa3425c73c420e7046e95486b592pbos@webrtc.org RtpUtility::AssignUWord16ToBuffer(media_payload_length, 6906aae61c2c693fa3425c73c420e7046e95486b592pbos@webrtc.org src_packet->length - kRtpHeaderSize); 6914efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org dst_packet->length_recovery[0] ^= media_payload_length[0]; 6924efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org dst_packet->length_recovery[1] ^= media_payload_length[1]; 693b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 694b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // XOR with RTP payload. 695b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(marpan/ajm): Are we doing more XORs than required here? 6964efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org for (int32_t i = kRtpHeaderSize; i < src_packet->length; ++i) { 697b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org dst_packet->pkt->data[i] ^= src_packet->data[i]; 698b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 699b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 700b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 701b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::RecoverPacket( 7024efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const FecPacket* fec_packet, RecoveredPacket* rec_packet_to_insert) { 7034efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org InitRecovery(fec_packet, rec_packet_to_insert); 704b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ProtectedPacketList::const_iterator protected_it = 7054efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet->protected_pkt_list.begin(); 7064efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while (protected_it != fec_packet->protected_pkt_list.end()) { 707b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if ((*protected_it)->pkt == NULL) { 708b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // This is the packet we're recovering. 7094efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org rec_packet_to_insert->seq_num = (*protected_it)->seq_num; 710b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else { 7114efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org XorPackets((*protected_it)->pkt, rec_packet_to_insert); 712b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 713b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ++protected_it; 714b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 7154efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org FinishRecovery(rec_packet_to_insert); 716b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 717b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 718b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::AttemptRecover( 7194efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org RecoveredPacketList* recovered_packet_list) { 7204efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org FecPacketList::iterator fec_packet_list_it = fec_packet_list_.begin(); 7214efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while (fec_packet_list_it != fec_packet_list_.end()) { 722b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Search for each FEC packet's protected media packets. 7234efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org int packets_missing = NumCoveredPacketsMissing(*fec_packet_list_it); 724b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 725b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // We can only recover one packet with an FEC packet. 7264efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (packets_missing == 1) { 727b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Recovery possible. 7284efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org RecoveredPacket* packet_to_insert = new RecoveredPacket; 7294efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org packet_to_insert->pkt = NULL; 7304efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org RecoverPacket(*fec_packet_list_it, packet_to_insert); 731b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 732b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Add recovered packet to the list of recovered packets and update any 733b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // FEC packets covering this packet with a pointer to the data. 734b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(holmer): Consider replacing this with a binary search for the 735b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // right position, and then just insert the new packet. Would get rid of 736b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // the sort. 7374efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recovered_packet_list->push_back(packet_to_insert); 7384efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recovered_packet_list->sort(SortablePacket::LessThan); 7394efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org UpdateCoveringFECPackets(packet_to_insert); 7404efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org DiscardOldPackets(recovered_packet_list); 7414efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org DiscardFECPacket(*fec_packet_list_it); 7424efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_list_it = fec_packet_list_.erase(fec_packet_list_it); 743b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 744b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // A packet has been recovered. We need to check the FEC list again, as 745b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // this may allow additional packets to be recovered. 746b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // Restart for first FEC packet. 7474efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_list_it = fec_packet_list_.begin(); 748b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else if (packets_missing == 0) { 7494efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org // Either all protected packets arrived or have been recovered. We can 7504efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org // discard this FEC packet. 7514efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org DiscardFECPacket(*fec_packet_list_it); 7524efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_list_it = fec_packet_list_.erase(fec_packet_list_it); 753b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } else { 7544efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet_list_it++; 755b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 756b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 757b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 758b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 759b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint ForwardErrorCorrection::NumCoveredPacketsMissing( 760b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org const FecPacket* fec_packet) { 761b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int packets_missing = 0; 7624efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org ProtectedPacketList::const_iterator it = 7634efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet->protected_pkt_list.begin(); 7644efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org for (; it != fec_packet->protected_pkt_list.end(); ++it) { 765b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if ((*it)->pkt == NULL) { 766b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ++packets_missing; 767b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (packets_missing > 1) { 768b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org break; // We can't recover more than one packet. 769b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 770b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 771b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 772b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return packets_missing; 773b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 774b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 775b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::DiscardFECPacket(FecPacket* fec_packet) { 7764efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while (!fec_packet->protected_pkt_list.empty()) { 7774efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org delete fec_packet->protected_pkt_list.front(); 7784efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org fec_packet->protected_pkt_list.pop_front(); 779b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 7804efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org assert(fec_packet->protected_pkt_list.empty()); 781b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete fec_packet; 782b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 783b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 784b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ForwardErrorCorrection::DiscardOldPackets( 7854efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org RecoveredPacketList* recovered_packet_list) { 7864efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org while (recovered_packet_list->size() > kMaxMediaPackets) { 787b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ForwardErrorCorrection::RecoveredPacket* packet = 7884efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recovered_packet_list->front(); 789b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org delete packet; 7904efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org recovered_packet_list->pop_front(); 791b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 7924efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org assert(recovered_packet_list->size() <= kMaxMediaPackets); 793b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 794b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 795b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orguint16_t ForwardErrorCorrection::ParseSequenceNumber(uint8_t* packet) { 796b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return (packet[2] << 8) + packet[3]; 797b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 798b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 799b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint32_t ForwardErrorCorrection::DecodeFEC( 8004efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org ReceivedPacketList* received_packet_list, 8014efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org RecoveredPacketList* recovered_packet_list) { 802b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // TODO(marpan/ajm): can we check for multiple ULP headers, and return an 803b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // error? 8044efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org if (recovered_packet_list->size() == kMaxMediaPackets) { 8054efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org const unsigned int seq_num_diff = 8064efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org abs(static_cast<int>(received_packet_list->front()->seq_num) - 8074efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org static_cast<int>(recovered_packet_list->back()->seq_num)); 808b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (seq_num_diff > kMaxMediaPackets) { 809b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // A big gap in sequence numbers. The old recovered packets 810b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // are now useless, so it's safe to do a reset. 8114efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org ResetState(recovered_packet_list); 812b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 813b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 8144efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org InsertPackets(received_packet_list, recovered_packet_list); 8154efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org AttemptRecover(recovered_packet_list); 816b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return 0; 817b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 818b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 819b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orguint16_t ForwardErrorCorrection::PacketOverhead() { 820b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return kFecHeaderSize + kUlpHeaderSizeLBitSet; 821b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org} 8224efbd60660e657ff449dfa7c16f8d4dee5c6e453phoglund@webrtc.org} // namespace webrtc 823