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