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