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
11cbd78ae09f44b003a9969536b78f08cd1ff513e8pbos@webrtc.org#include "webrtc/modules/rtp_rtcp/source/producer_fec.h"
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
13cbd78ae09f44b003a9969536b78f08cd1ff513e8pbos@webrtc.org#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
14cbd78ae09f44b003a9969536b78f08cd1ff513e8pbos@webrtc.org#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
15b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
16b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc {
17b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
18b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgenum { kREDForFECHeaderLength = 1 };
19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// This controls the maximum amount of excess overhead (actual - target)
20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// allowed in order to trigger GenerateFEC(), before |params_.max_fec_frames|
21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// is reached. Overhead here is defined as relative to number of media packets.
22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgenum { kMaxExcessOverhead = 50 };  // Q8.
23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// This is the minimum number of media packets required (above some protection
24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// level) in order to trigger GenerateFEC(), before |params_.max_fec_frames| is
25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// reached.
26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgenum { kMinimumMediaPackets = 4 };
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Threshold on the received FEC protection level, above which we enforce at
28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// least |kMinimumMediaPackets| packets for the FEC code. Below this
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// threshold |kMinimumMediaPackets| is set to default value of 1.
30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgenum { kHighProtectionThreshold = 80 };  // Corresponds to ~30 overhead, range
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// is 0 to 255, where 255 corresponds to 100% overhead (relative to number of
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// media packets).
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgstruct RtpPacket {
35b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org  uint16_t rtpHeaderLength;
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  ForwardErrorCorrection::Packet* pkt;
37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org};
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgRedPacket::RedPacket(int length)
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    : data_(new uint8_t[length]),
41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      length_(length),
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      header_length_(0) {
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgRedPacket::~RedPacket() {
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  delete [] data_;
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid RedPacket::CreateHeader(const uint8_t* rtp_header, int header_length,
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             int red_pl_type, int pl_type) {
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(header_length + kREDForFECHeaderLength <= length_);
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  memcpy(data_, rtp_header, header_length);
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Replace payload type.
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  data_[1] &= 0x80;
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  data_[1] += red_pl_type;
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Add RED header
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // f-bit always 0
58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  data_[header_length] = pl_type;
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  header_length_ = header_length + kREDForFECHeaderLength;
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid RedPacket::SetSeqNum(int seq_num) {
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(seq_num >= 0 && seq_num < (1<<16));
646aae61c2c693fa3425c73c420e7046e95486b592pbos@webrtc.org  RtpUtility::AssignUWord16ToBuffer(&data_[2], seq_num);
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid RedPacket::AssignPayload(const uint8_t* payload, int length) {
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(header_length_ + length <= length_);
69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  memcpy(data_ + header_length_, payload, length);
70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid RedPacket::ClearMarkerBit() {
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  data_[1] &= 0x7F;
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orguint8_t* RedPacket::data() const {
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return data_;
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint RedPacket::length() const {
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return length_;
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgProducerFec::ProducerFec(ForwardErrorCorrection* fec)
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    : fec_(fec),
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      media_packets_fec_(),
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      fec_packets_(),
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      num_frames_(0),
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      incomplete_frame_(false),
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      num_first_partition_(0),
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      minimum_media_packets_fec_(1),
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      params_(),
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      new_params_() {
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  memset(&params_, 0, sizeof(params_));
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  memset(&new_params_, 0, sizeof(new_params_));
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgProducerFec::~ProducerFec() {
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  DeletePackets();
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ProducerFec::SetFecParameters(const FecProtectionParams* params,
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                   int num_first_partition) {
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Number of first partition packets cannot exceed kMaxMediaPackets
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(params->fec_rate >= 0 && params->fec_rate < 256);
106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (num_first_partition >
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets)) {
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      num_first_partition =
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          ForwardErrorCorrection::kMaxMediaPackets;
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Store the new params and apply them for the next set of FEC packets being
112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // produced.
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  new_params_ = *params;
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  num_first_partition_ = num_first_partition;
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (params->fec_rate > kHighProtectionThreshold) {
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    minimum_media_packets_fec_ = kMinimumMediaPackets;
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  } else {
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    minimum_media_packets_fec_ = 1;
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgRedPacket* ProducerFec::BuildRedPacket(const uint8_t* data_buffer,
123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       int payload_length,
124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       int rtp_header_length,
125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       int red_pl_type) {
126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  RedPacket* red_packet = new RedPacket(payload_length +
127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        kREDForFECHeaderLength +
128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        rtp_header_length);
129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int pl_type = data_buffer[1] & 0x7f;
130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  red_packet->CreateHeader(data_buffer, rtp_header_length,
131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                           red_pl_type, pl_type);
132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  red_packet->AssignPayload(data_buffer + rtp_header_length, payload_length);
133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return red_packet;
134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint ProducerFec::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                            int payload_length,
138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                            int rtp_header_length) {
139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(fec_packets_.empty());
140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (media_packets_fec_.empty()) {
141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    params_ = new_params_;
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  incomplete_frame_ = true;
144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false;
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (media_packets_fec_.size() < ForwardErrorCorrection::kMaxMediaPackets) {
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Generic FEC can only protect up to kMaxMediaPackets packets.
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ForwardErrorCorrection::Packet* packet = new ForwardErrorCorrection::Packet;
148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    packet->length = payload_length + rtp_header_length;
149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memcpy(packet->data, data_buffer, packet->length);
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    media_packets_fec_.push_back(packet);
151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (marker_bit) {
153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ++num_frames_;
154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    incomplete_frame_ = false;
155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Produce FEC over at most |params_.max_fec_frames| frames, or as soon as:
157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // (1) the excess overhead (actual overhead - requested/target overhead) is
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // less than |kMaxExcessOverhead|, and
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // (2) at least |minimum_media_packets_fec_| media packets is reached.
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!incomplete_frame_ &&
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      (num_frames_ == params_.max_fec_frames ||
162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) {
163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(num_first_partition_ <=
164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org           static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets));
165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int ret = fec_->GenerateFEC(media_packets_fec_,
166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                params_.fec_rate,
167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                num_first_partition_,
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                params_.use_uep_protection,
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                params_.fec_mask_type,
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                &fec_packets_);
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (fec_packets_.empty()) {
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      num_frames_ = 0;
173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      DeletePackets();
174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return ret;
176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return 0;
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Returns true if the excess overhead (actual - target) for the FEC is below
181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// the amount |kMaxExcessOverhead|. This effects the lower protection level
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// cases and low number of media packets/frame. The target overhead is given by
183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// |params_.fec_rate|, and is only achievable in the limit of large number of
184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// media packets.
185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool ProducerFec::ExcessOverheadBelowMax() {
186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return ((Overhead() - params_.fec_rate) < kMaxExcessOverhead);
187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Returns true if the media packet list for the FEC is at least
190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// |minimum_media_packets_fec_|. This condition tries to capture the effect
191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// that, for the same amount of protection/overhead, longer codes
192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// (e.g. (2k,2m) vs (k,m)) are generally more effective at recovering losses.
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool ProducerFec::MinimumMediaPacketsReached() {
194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  float avg_num_packets_frame = static_cast<float>(media_packets_fec_.size()) /
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                num_frames_;
196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (avg_num_packets_frame < 2.0f) {
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return (static_cast<int>(media_packets_fec_.size()) >=
198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      minimum_media_packets_fec_);
199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  } else {
200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // For larger rates (more packets/frame), increase the threshold.
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (static_cast<int>(media_packets_fec_.size()) >=
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        minimum_media_packets_fec_ + 1);
203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool ProducerFec::FecAvailable() const {
207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return (fec_packets_.size() > 0);
208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgRedPacket* ProducerFec::GetFecPacket(int red_pl_type,
211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                     int fec_pl_type,
212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                     uint16_t seq_num,
213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                     int rtp_header_length) {
214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (fec_packets_.empty())
215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return NULL;
216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Build FEC packet. The FEC packets in |fec_packets_| doesn't
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // have RTP headers, so we're reusing the header from the last
218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // media packet.
219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  ForwardErrorCorrection::Packet* packet_to_send = fec_packets_.front();
220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  ForwardErrorCorrection::Packet* last_media_packet = media_packets_fec_.back();
221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  RedPacket* return_packet = new RedPacket(packet_to_send->length +
222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                           kREDForFECHeaderLength +
223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                           rtp_header_length);
224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return_packet->CreateHeader(last_media_packet->data,
225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                              rtp_header_length,
226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                              red_pl_type,
227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                              fec_pl_type);
228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return_packet->SetSeqNum(seq_num);
229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return_packet->ClearMarkerBit();
230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return_packet->AssignPayload(packet_to_send->data, packet_to_send->length);
231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  fec_packets_.pop_front();
232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (fec_packets_.empty()) {
233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Done with all the FEC packets. Reset for next run.
234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    DeletePackets();
235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    num_frames_ = 0;
236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return return_packet;
238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint ProducerFec::Overhead() const {
241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Overhead is defined as relative to the number of media packets, and not
242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // relative to total number of packets. This definition is inhereted from the
243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // protection factor produced by video_coding module and how the FEC
244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // generation is implemented.
245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(!media_packets_fec_.empty());
246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int num_fec_packets = fec_->GetNumberOfFecPackets(media_packets_fec_.size(),
247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                    params_.fec_rate);
248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Return the overhead in Q8.
249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return (num_fec_packets << 8) / media_packets_fec_.size();
250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid ProducerFec::DeletePackets() {
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  while (!media_packets_fec_.empty()) {
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    delete media_packets_fec_.front();
255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    media_packets_fec_.pop_front();
256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(media_packets_fec_.empty());
258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}  // namespace webrtc
261