xref: /aosp_15_r20/external/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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 "modules/rtp_rtcp/source/forward_error_correction.h"
12 
13 #include <string.h>
14 
15 #include <algorithm>
16 #include <utility>
17 
18 #include "absl/algorithm/container.h"
19 #include "modules/include/module_common_types_public.h"
20 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
21 #include "modules/rtp_rtcp/source/byte_io.h"
22 #include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h"
23 #include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
24 #include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h"
25 #include "rtc_base/checks.h"
26 #include "rtc_base/logging.h"
27 #include "rtc_base/numerics/mod_ops.h"
28 
29 namespace webrtc {
30 
31 namespace {
32 // Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum.
33 constexpr size_t kTransportOverhead = 28;
34 
35 constexpr uint16_t kOldSequenceThreshold = 0x3fff;
36 }  // namespace
37 
Packet()38 ForwardErrorCorrection::Packet::Packet() : data(0), ref_count_(0) {}
39 ForwardErrorCorrection::Packet::~Packet() = default;
40 
AddRef()41 int32_t ForwardErrorCorrection::Packet::AddRef() {
42   return ++ref_count_;
43 }
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 // This comparator is used to compare std::unique_ptr's pointing to
54 // subclasses of SortablePackets. It needs to be parametric since
55 // the std::unique_ptr's are not covariant w.r.t. the types that
56 // they are pointing to.
57 template <typename S, typename T>
operator ()(const S & first,const T & second)58 bool ForwardErrorCorrection::SortablePacket::LessThan::operator()(
59     const S& first,
60     const T& second) {
61   RTC_DCHECK_EQ(first->ssrc, second->ssrc);
62   return IsNewerSequenceNumber(second->seq_num, first->seq_num);
63 }
64 
65 ForwardErrorCorrection::ReceivedPacket::ReceivedPacket() = default;
66 ForwardErrorCorrection::ReceivedPacket::~ReceivedPacket() = default;
67 
68 ForwardErrorCorrection::RecoveredPacket::RecoveredPacket() = default;
69 ForwardErrorCorrection::RecoveredPacket::~RecoveredPacket() = default;
70 
71 ForwardErrorCorrection::ProtectedPacket::ProtectedPacket() = default;
72 ForwardErrorCorrection::ProtectedPacket::~ProtectedPacket() = default;
73 
74 ForwardErrorCorrection::ReceivedFecPacket::ReceivedFecPacket() = default;
75 ForwardErrorCorrection::ReceivedFecPacket::~ReceivedFecPacket() = default;
76 
ForwardErrorCorrection(std::unique_ptr<FecHeaderReader> fec_header_reader,std::unique_ptr<FecHeaderWriter> fec_header_writer,uint32_t ssrc,uint32_t protected_media_ssrc)77 ForwardErrorCorrection::ForwardErrorCorrection(
78     std::unique_ptr<FecHeaderReader> fec_header_reader,
79     std::unique_ptr<FecHeaderWriter> fec_header_writer,
80     uint32_t ssrc,
81     uint32_t protected_media_ssrc)
82     : ssrc_(ssrc),
83       protected_media_ssrc_(protected_media_ssrc),
84       fec_header_reader_(std::move(fec_header_reader)),
85       fec_header_writer_(std::move(fec_header_writer)),
86       generated_fec_packets_(fec_header_writer_->MaxFecPackets()),
87       packet_mask_size_(0) {}
88 
89 ForwardErrorCorrection::~ForwardErrorCorrection() = default;
90 
CreateUlpfec(uint32_t ssrc)91 std::unique_ptr<ForwardErrorCorrection> ForwardErrorCorrection::CreateUlpfec(
92     uint32_t ssrc) {
93   std::unique_ptr<FecHeaderReader> fec_header_reader(new UlpfecHeaderReader());
94   std::unique_ptr<FecHeaderWriter> fec_header_writer(new UlpfecHeaderWriter());
95   return std::unique_ptr<ForwardErrorCorrection>(new ForwardErrorCorrection(
96       std::move(fec_header_reader), std::move(fec_header_writer), ssrc, ssrc));
97 }
98 
CreateFlexfec(uint32_t ssrc,uint32_t protected_media_ssrc)99 std::unique_ptr<ForwardErrorCorrection> ForwardErrorCorrection::CreateFlexfec(
100     uint32_t ssrc,
101     uint32_t protected_media_ssrc) {
102   std::unique_ptr<FecHeaderReader> fec_header_reader(new FlexfecHeaderReader());
103   std::unique_ptr<FecHeaderWriter> fec_header_writer(new FlexfecHeaderWriter());
104   return std::unique_ptr<ForwardErrorCorrection>(new ForwardErrorCorrection(
105       std::move(fec_header_reader), std::move(fec_header_writer), ssrc,
106       protected_media_ssrc));
107 }
108 
EncodeFec(const PacketList & media_packets,uint8_t protection_factor,int num_important_packets,bool use_unequal_protection,FecMaskType fec_mask_type,std::list<Packet * > * fec_packets)109 int ForwardErrorCorrection::EncodeFec(const PacketList& media_packets,
110                                       uint8_t protection_factor,
111                                       int num_important_packets,
112                                       bool use_unequal_protection,
113                                       FecMaskType fec_mask_type,
114                                       std::list<Packet*>* fec_packets) {
115   const size_t num_media_packets = media_packets.size();
116 
117   // Sanity check arguments.
118   RTC_DCHECK_GT(num_media_packets, 0);
119   RTC_DCHECK_GE(num_important_packets, 0);
120   RTC_DCHECK_LE(num_important_packets, num_media_packets);
121   RTC_DCHECK(fec_packets->empty());
122   const size_t max_media_packets = fec_header_writer_->MaxMediaPackets();
123   if (num_media_packets > max_media_packets) {
124     RTC_LOG(LS_WARNING) << "Can't protect " << num_media_packets
125                         << " media packets per frame. Max is "
126                         << max_media_packets << ".";
127     return -1;
128   }
129 
130   // Error check the media packets.
131   for (const auto& media_packet : media_packets) {
132     RTC_DCHECK(media_packet);
133     if (media_packet->data.size() < kRtpHeaderSize) {
134       RTC_LOG(LS_WARNING) << "Media packet " << media_packet->data.size()
135                           << " bytes "
136                              "is smaller than RTP header.";
137       return -1;
138     }
139     // Ensure the FEC packets will fit in a typical MTU.
140     if (media_packet->data.size() + MaxPacketOverhead() + kTransportOverhead >
141         IP_PACKET_SIZE) {
142       RTC_LOG(LS_WARNING) << "Media packet " << media_packet->data.size()
143                           << " bytes "
144                              "with overhead is larger than "
145                           << IP_PACKET_SIZE << " bytes.";
146     }
147   }
148 
149   // Prepare generated FEC packets.
150   int num_fec_packets = NumFecPackets(num_media_packets, protection_factor);
151   if (num_fec_packets == 0) {
152     return 0;
153   }
154   for (int i = 0; i < num_fec_packets; ++i) {
155     generated_fec_packets_[i].data.EnsureCapacity(IP_PACKET_SIZE);
156     memset(generated_fec_packets_[i].data.MutableData(), 0, IP_PACKET_SIZE);
157     // Use this as a marker for untouched packets.
158     generated_fec_packets_[i].data.SetSize(0);
159     fec_packets->push_back(&generated_fec_packets_[i]);
160   }
161 
162   internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets);
163   packet_mask_size_ = internal::PacketMaskSize(num_media_packets);
164   memset(packet_masks_, 0, num_fec_packets * packet_mask_size_);
165   internal::GeneratePacketMasks(num_media_packets, num_fec_packets,
166                                 num_important_packets, use_unequal_protection,
167                                 &mask_table, packet_masks_);
168 
169   // Adapt packet masks to missing media packets.
170   int num_mask_bits = InsertZerosInPacketMasks(media_packets, num_fec_packets);
171   if (num_mask_bits < 0) {
172     RTC_LOG(LS_INFO) << "Due to sequence number gaps, cannot protect media "
173                         "packets with a single block of FEC packets.";
174     fec_packets->clear();
175     return -1;
176   }
177   packet_mask_size_ = internal::PacketMaskSize(num_mask_bits);
178 
179   // Write FEC packets to `generated_fec_packets_`.
180   GenerateFecPayloads(media_packets, num_fec_packets);
181   // TODO(brandtr): Generalize this when multistream protection support is
182   // added.
183   const uint32_t media_ssrc = ParseSsrc(media_packets.front()->data.data());
184   const uint16_t seq_num_base =
185       ParseSequenceNumber(media_packets.front()->data.data());
186   FinalizeFecHeaders(num_fec_packets, media_ssrc, seq_num_base);
187 
188   return 0;
189 }
190 
NumFecPackets(int num_media_packets,int protection_factor)191 int ForwardErrorCorrection::NumFecPackets(int num_media_packets,
192                                           int protection_factor) {
193   // Result in Q0 with an unsigned round.
194   int num_fec_packets = (num_media_packets * protection_factor + (1 << 7)) >> 8;
195   // Generate at least one FEC packet if we need protection.
196   if (protection_factor > 0 && num_fec_packets == 0) {
197     num_fec_packets = 1;
198   }
199   RTC_DCHECK_LE(num_fec_packets, num_media_packets);
200   return num_fec_packets;
201 }
202 
GenerateFecPayloads(const PacketList & media_packets,size_t num_fec_packets)203 void ForwardErrorCorrection::GenerateFecPayloads(
204     const PacketList& media_packets,
205     size_t num_fec_packets) {
206   RTC_DCHECK(!media_packets.empty());
207   for (size_t i = 0; i < num_fec_packets; ++i) {
208     Packet* const fec_packet = &generated_fec_packets_[i];
209     size_t pkt_mask_idx = i * packet_mask_size_;
210     const size_t min_packet_mask_size = fec_header_writer_->MinPacketMaskSize(
211         &packet_masks_[pkt_mask_idx], packet_mask_size_);
212     const size_t fec_header_size =
213         fec_header_writer_->FecHeaderSize(min_packet_mask_size);
214 
215     size_t media_pkt_idx = 0;
216     auto media_packets_it = media_packets.cbegin();
217     uint16_t prev_seq_num =
218         ParseSequenceNumber((*media_packets_it)->data.data());
219     while (media_packets_it != media_packets.end()) {
220       Packet* const media_packet = media_packets_it->get();
221       // Should `media_packet` be protected by `fec_packet`?
222       if (packet_masks_[pkt_mask_idx] & (1 << (7 - media_pkt_idx))) {
223         size_t media_payload_length =
224             media_packet->data.size() - kRtpHeaderSize;
225 
226         size_t fec_packet_length = fec_header_size + media_payload_length;
227         if (fec_packet_length > fec_packet->data.size()) {
228           // Recall that XORing with zero (which the FEC packets are prefilled
229           // with) is the identity operator, thus all prior XORs are
230           // still correct even though we expand the packet length here.
231           fec_packet->data.SetSize(fec_packet_length);
232         }
233         XorHeaders(*media_packet, fec_packet);
234         XorPayloads(*media_packet, media_payload_length, fec_header_size,
235                     fec_packet);
236       }
237       media_packets_it++;
238       if (media_packets_it != media_packets.end()) {
239         uint16_t seq_num =
240             ParseSequenceNumber((*media_packets_it)->data.data());
241         media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num);
242         prev_seq_num = seq_num;
243       }
244       pkt_mask_idx += media_pkt_idx / 8;
245       media_pkt_idx %= 8;
246     }
247     RTC_DCHECK_GT(fec_packet->data.size(), 0)
248         << "Packet mask is wrong or poorly designed.";
249   }
250 }
251 
InsertZerosInPacketMasks(const PacketList & media_packets,size_t num_fec_packets)252 int ForwardErrorCorrection::InsertZerosInPacketMasks(
253     const PacketList& media_packets,
254     size_t num_fec_packets) {
255   size_t num_media_packets = media_packets.size();
256   if (num_media_packets <= 1) {
257     return num_media_packets;
258   }
259   uint16_t last_seq_num =
260       ParseSequenceNumber(media_packets.back()->data.data());
261   uint16_t first_seq_num =
262       ParseSequenceNumber(media_packets.front()->data.data());
263   size_t total_missing_seq_nums =
264       static_cast<uint16_t>(last_seq_num - first_seq_num) - num_media_packets +
265       1;
266   if (total_missing_seq_nums == 0) {
267     // All sequence numbers are covered by the packet mask.
268     // No zero insertion required.
269     return num_media_packets;
270   }
271   const size_t max_media_packets = fec_header_writer_->MaxMediaPackets();
272   if (total_missing_seq_nums + num_media_packets > max_media_packets) {
273     return -1;
274   }
275   // Allocate the new mask.
276   size_t tmp_packet_mask_size =
277       internal::PacketMaskSize(total_missing_seq_nums + num_media_packets);
278   memset(tmp_packet_masks_, 0, num_fec_packets * tmp_packet_mask_size);
279 
280   auto media_packets_it = media_packets.cbegin();
281   uint16_t prev_seq_num = first_seq_num;
282   ++media_packets_it;
283 
284   // Insert the first column.
285   internal::CopyColumn(tmp_packet_masks_, tmp_packet_mask_size, packet_masks_,
286                        packet_mask_size_, num_fec_packets, 0, 0);
287   size_t new_bit_index = 1;
288   size_t old_bit_index = 1;
289   // Insert zeros in the bit mask for every hole in the sequence.
290   while (media_packets_it != media_packets.end()) {
291     if (new_bit_index == max_media_packets) {
292       // We can only cover up to 48 packets.
293       break;
294     }
295     uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data.data());
296     const int num_zeros_to_insert =
297         static_cast<uint16_t>(seq_num - prev_seq_num - 1);
298     if (num_zeros_to_insert > 0) {
299       internal::InsertZeroColumns(num_zeros_to_insert, tmp_packet_masks_,
300                                   tmp_packet_mask_size, num_fec_packets,
301                                   new_bit_index);
302     }
303     new_bit_index += num_zeros_to_insert;
304     internal::CopyColumn(tmp_packet_masks_, tmp_packet_mask_size, packet_masks_,
305                          packet_mask_size_, num_fec_packets, new_bit_index,
306                          old_bit_index);
307     ++new_bit_index;
308     ++old_bit_index;
309     prev_seq_num = seq_num;
310     ++media_packets_it;
311   }
312   if (new_bit_index % 8 != 0) {
313     // We didn't fill the last byte. Shift bits to correct position.
314     for (uint16_t row = 0; row < num_fec_packets; ++row) {
315       int new_byte_index = row * tmp_packet_mask_size + new_bit_index / 8;
316       tmp_packet_masks_[new_byte_index] <<= (7 - (new_bit_index % 8));
317     }
318   }
319   // Replace the old mask with the new.
320   memcpy(packet_masks_, tmp_packet_masks_,
321          num_fec_packets * tmp_packet_mask_size);
322   return new_bit_index;
323 }
324 
FinalizeFecHeaders(size_t num_fec_packets,uint32_t media_ssrc,uint16_t seq_num_base)325 void ForwardErrorCorrection::FinalizeFecHeaders(size_t num_fec_packets,
326                                                 uint32_t media_ssrc,
327                                                 uint16_t seq_num_base) {
328   for (size_t i = 0; i < num_fec_packets; ++i) {
329     fec_header_writer_->FinalizeFecHeader(
330         media_ssrc, seq_num_base, &packet_masks_[i * packet_mask_size_],
331         packet_mask_size_, &generated_fec_packets_[i]);
332   }
333 }
334 
ResetState(RecoveredPacketList * recovered_packets)335 void ForwardErrorCorrection::ResetState(
336     RecoveredPacketList* recovered_packets) {
337   // Free the memory for any existing recovered packets, if the caller hasn't.
338   recovered_packets->clear();
339   received_fec_packets_.clear();
340 }
341 
InsertMediaPacket(RecoveredPacketList * recovered_packets,const ReceivedPacket & received_packet)342 void ForwardErrorCorrection::InsertMediaPacket(
343     RecoveredPacketList* recovered_packets,
344     const ReceivedPacket& received_packet) {
345   RTC_DCHECK_EQ(received_packet.ssrc, protected_media_ssrc_);
346 
347   // Search for duplicate packets.
348   for (const auto& recovered_packet : *recovered_packets) {
349     RTC_DCHECK_EQ(recovered_packet->ssrc, received_packet.ssrc);
350     if (recovered_packet->seq_num == received_packet.seq_num) {
351       // Duplicate packet, no need to add to list.
352       return;
353     }
354   }
355 
356   std::unique_ptr<RecoveredPacket> recovered_packet(new RecoveredPacket());
357   // This "recovered packet" was not recovered using parity packets.
358   recovered_packet->was_recovered = false;
359   // This media packet has already been passed on.
360   recovered_packet->returned = true;
361   recovered_packet->ssrc = received_packet.ssrc;
362   recovered_packet->seq_num = received_packet.seq_num;
363   recovered_packet->pkt = received_packet.pkt;
364   // TODO(holmer): Consider replacing this with a binary search for the right
365   // position, and then just insert the new packet. Would get rid of the sort.
366   RecoveredPacket* recovered_packet_ptr = recovered_packet.get();
367   recovered_packets->push_back(std::move(recovered_packet));
368   recovered_packets->sort(SortablePacket::LessThan());
369   UpdateCoveringFecPackets(*recovered_packet_ptr);
370 }
371 
UpdateCoveringFecPackets(const RecoveredPacket & packet)372 void ForwardErrorCorrection::UpdateCoveringFecPackets(
373     const RecoveredPacket& packet) {
374   for (auto& fec_packet : received_fec_packets_) {
375     // Is this FEC packet protecting the media packet `packet`?
376     auto protected_it = absl::c_lower_bound(
377         fec_packet->protected_packets, &packet, SortablePacket::LessThan());
378     if (protected_it != fec_packet->protected_packets.end() &&
379         (*protected_it)->seq_num == packet.seq_num) {
380       // Found an FEC packet which is protecting `packet`.
381       (*protected_it)->pkt = packet.pkt;
382     }
383   }
384 }
385 
InsertFecPacket(const RecoveredPacketList & recovered_packets,const ReceivedPacket & received_packet)386 void ForwardErrorCorrection::InsertFecPacket(
387     const RecoveredPacketList& recovered_packets,
388     const ReceivedPacket& received_packet) {
389   RTC_DCHECK_EQ(received_packet.ssrc, ssrc_);
390 
391   // Check for duplicate.
392   for (const auto& existing_fec_packet : received_fec_packets_) {
393     RTC_DCHECK_EQ(existing_fec_packet->ssrc, received_packet.ssrc);
394     if (existing_fec_packet->seq_num == received_packet.seq_num) {
395       // Drop duplicate FEC packet data.
396       return;
397     }
398   }
399 
400   std::unique_ptr<ReceivedFecPacket> fec_packet(new ReceivedFecPacket());
401   fec_packet->pkt = received_packet.pkt;
402   fec_packet->ssrc = received_packet.ssrc;
403   fec_packet->seq_num = received_packet.seq_num;
404   // Parse ULPFEC/FlexFEC header specific info.
405   bool ret = fec_header_reader_->ReadFecHeader(fec_packet.get());
406   if (!ret) {
407     return;
408   }
409 
410   // TODO(brandtr): Update here when we support multistream protection.
411   if (fec_packet->protected_ssrc != protected_media_ssrc_) {
412     RTC_LOG(LS_INFO)
413         << "Received FEC packet is protecting an unknown media SSRC; dropping.";
414     return;
415   }
416 
417   if (fec_packet->packet_mask_offset + fec_packet->packet_mask_size >
418       fec_packet->pkt->data.size()) {
419     RTC_LOG(LS_INFO) << "Received corrupted FEC packet; dropping.";
420     return;
421   }
422 
423   // Parse packet mask from header and represent as protected packets.
424   for (uint16_t byte_idx = 0; byte_idx < fec_packet->packet_mask_size;
425        ++byte_idx) {
426     uint8_t packet_mask =
427         fec_packet->pkt->data[fec_packet->packet_mask_offset + byte_idx];
428     for (uint16_t bit_idx = 0; bit_idx < 8; ++bit_idx) {
429       if (packet_mask & (1 << (7 - bit_idx))) {
430         std::unique_ptr<ProtectedPacket> protected_packet(
431             new ProtectedPacket());
432         // This wraps naturally with the sequence number.
433         protected_packet->ssrc = protected_media_ssrc_;
434         protected_packet->seq_num = static_cast<uint16_t>(
435             fec_packet->seq_num_base + (byte_idx << 3) + bit_idx);
436         protected_packet->pkt = nullptr;
437         fec_packet->protected_packets.push_back(std::move(protected_packet));
438       }
439     }
440   }
441 
442   if (fec_packet->protected_packets.empty()) {
443     // All-zero packet mask; we can discard this FEC packet.
444     RTC_LOG(LS_WARNING) << "Received FEC packet has an all-zero packet mask.";
445   } else {
446     AssignRecoveredPackets(recovered_packets, fec_packet.get());
447     // TODO(holmer): Consider replacing this with a binary search for the right
448     // position, and then just insert the new packet. Would get rid of the sort.
449     received_fec_packets_.push_back(std::move(fec_packet));
450     received_fec_packets_.sort(SortablePacket::LessThan());
451     const size_t max_fec_packets = fec_header_reader_->MaxFecPackets();
452     if (received_fec_packets_.size() > max_fec_packets) {
453       received_fec_packets_.pop_front();
454     }
455     RTC_DCHECK_LE(received_fec_packets_.size(), max_fec_packets);
456   }
457 }
458 
AssignRecoveredPackets(const RecoveredPacketList & recovered_packets,ReceivedFecPacket * fec_packet)459 void ForwardErrorCorrection::AssignRecoveredPackets(
460     const RecoveredPacketList& recovered_packets,
461     ReceivedFecPacket* fec_packet) {
462   ProtectedPacketList* protected_packets = &fec_packet->protected_packets;
463   std::vector<RecoveredPacket*> recovered_protected_packets;
464 
465   // Find intersection between the (sorted) containers `protected_packets`
466   // and `recovered_packets`, i.e. all protected packets that have already
467   // been recovered. Update the corresponding protected packets to point to
468   // the recovered packets.
469   auto it_p = protected_packets->cbegin();
470   auto it_r = recovered_packets.cbegin();
471   SortablePacket::LessThan less_than;
472   while (it_p != protected_packets->end() && it_r != recovered_packets.end()) {
473     if (less_than(*it_p, *it_r)) {
474       ++it_p;
475     } else if (less_than(*it_r, *it_p)) {
476       ++it_r;
477     } else {  // *it_p == *it_r.
478       // This protected packet has already been recovered.
479       (*it_p)->pkt = (*it_r)->pkt;
480       ++it_p;
481       ++it_r;
482     }
483   }
484 }
485 
InsertPacket(const ReceivedPacket & received_packet,RecoveredPacketList * recovered_packets)486 void ForwardErrorCorrection::InsertPacket(
487     const ReceivedPacket& received_packet,
488     RecoveredPacketList* recovered_packets) {
489   // Discard old FEC packets such that the sequence numbers in
490   // `received_fec_packets_` span at most 1/2 of the sequence number space.
491   // This is important for keeping `received_fec_packets_` sorted, and may
492   // also reduce the possibility of incorrect decoding due to sequence number
493   // wrap-around.
494   if (!received_fec_packets_.empty() &&
495       received_packet.ssrc == received_fec_packets_.front()->ssrc) {
496     // It only makes sense to detect wrap-around when `received_packet`
497     // and `front_received_fec_packet` belong to the same sequence number
498     // space, i.e., the same SSRC. This happens when `received_packet`
499     // is a FEC packet, or if `received_packet` is a media packet and
500     // RED+ULPFEC is used.
501     auto it = received_fec_packets_.begin();
502     while (it != received_fec_packets_.end()) {
503       uint16_t seq_num_diff = MinDiff(received_packet.seq_num, (*it)->seq_num);
504       if (seq_num_diff > kOldSequenceThreshold) {
505         it = received_fec_packets_.erase(it);
506       } else {
507         // No need to keep iterating, since `received_fec_packets_` is sorted.
508         break;
509       }
510     }
511   }
512 
513   if (received_packet.is_fec) {
514     InsertFecPacket(*recovered_packets, received_packet);
515   } else {
516     InsertMediaPacket(recovered_packets, received_packet);
517   }
518 
519   DiscardOldRecoveredPackets(recovered_packets);
520 }
521 
StartPacketRecovery(const ReceivedFecPacket & fec_packet,RecoveredPacket * recovered_packet)522 bool ForwardErrorCorrection::StartPacketRecovery(
523     const ReceivedFecPacket& fec_packet,
524     RecoveredPacket* recovered_packet) {
525   // Ensure pkt is initialized.
526   recovered_packet->pkt = new Packet();
527   // Sanity check packet length.
528   if (fec_packet.pkt->data.size() <
529       fec_packet.fec_header_size + fec_packet.protection_length) {
530     RTC_LOG(LS_WARNING)
531         << "The FEC packet is truncated: it does not contain enough room "
532            "for its own header.";
533     return false;
534   }
535   if (fec_packet.protection_length >
536       std::min(size_t{IP_PACKET_SIZE - kRtpHeaderSize},
537                IP_PACKET_SIZE - fec_packet.fec_header_size)) {
538     RTC_LOG(LS_WARNING) << "Incorrect protection length, dropping FEC packet.";
539     return false;
540   }
541   // Initialize recovered packet data.
542   recovered_packet->pkt->data.EnsureCapacity(IP_PACKET_SIZE);
543   recovered_packet->pkt->data.SetSize(fec_packet.protection_length +
544                                       kRtpHeaderSize);
545   recovered_packet->returned = false;
546   recovered_packet->was_recovered = true;
547   // Copy bytes corresponding to minimum RTP header size.
548   // Note that the sequence number and SSRC fields will be overwritten
549   // at the end of packet recovery.
550   memcpy(recovered_packet->pkt->data.MutableData(),
551          fec_packet.pkt->data.cdata(), kRtpHeaderSize);
552   // Copy remaining FEC payload.
553   if (fec_packet.protection_length > 0) {
554     memcpy(recovered_packet->pkt->data.MutableData() + kRtpHeaderSize,
555            fec_packet.pkt->data.cdata() + fec_packet.fec_header_size,
556            fec_packet.protection_length);
557   }
558   return true;
559 }
560 
FinishPacketRecovery(const ReceivedFecPacket & fec_packet,RecoveredPacket * recovered_packet)561 bool ForwardErrorCorrection::FinishPacketRecovery(
562     const ReceivedFecPacket& fec_packet,
563     RecoveredPacket* recovered_packet) {
564   uint8_t* data = recovered_packet->pkt->data.MutableData();
565   // Set the RTP version to 2.
566   data[0] |= 0x80;  // Set the 1st bit.
567   data[0] &= 0xbf;  // Clear the 2nd bit.
568   // Recover the packet length, from temporary location.
569   const size_t new_size =
570       ByteReader<uint16_t>::ReadBigEndian(&data[2]) + kRtpHeaderSize;
571   if (new_size > size_t{IP_PACKET_SIZE - kRtpHeaderSize}) {
572     RTC_LOG(LS_WARNING) << "The recovered packet had a length larger than a "
573                            "typical IP packet, and is thus dropped.";
574     return false;
575   }
576   recovered_packet->pkt->data.SetSize(new_size);
577   // Set the SN field.
578   ByteWriter<uint16_t>::WriteBigEndian(&data[2], recovered_packet->seq_num);
579   // Set the SSRC field.
580   ByteWriter<uint32_t>::WriteBigEndian(&data[8], fec_packet.protected_ssrc);
581   recovered_packet->ssrc = fec_packet.protected_ssrc;
582   return true;
583 }
584 
XorHeaders(const Packet & src,Packet * dst)585 void ForwardErrorCorrection::XorHeaders(const Packet& src, Packet* dst) {
586   uint8_t* dst_data = dst->data.MutableData();
587   const uint8_t* src_data = src.data.cdata();
588   // XOR the first 2 bytes of the header: V, P, X, CC, M, PT fields.
589   dst_data[0] ^= src_data[0];
590   dst_data[1] ^= src_data[1];
591 
592   // XOR the length recovery field.
593   uint8_t src_payload_length_network_order[2];
594   ByteWriter<uint16_t>::WriteBigEndian(src_payload_length_network_order,
595                                        src.data.size() - kRtpHeaderSize);
596   dst_data[2] ^= src_payload_length_network_order[0];
597   dst_data[3] ^= src_payload_length_network_order[1];
598 
599   // XOR the 5th to 8th bytes of the header: the timestamp field.
600   dst_data[4] ^= src_data[4];
601   dst_data[5] ^= src_data[5];
602   dst_data[6] ^= src_data[6];
603   dst_data[7] ^= src_data[7];
604 
605   // Skip the 9th to 12th bytes of the header.
606 }
607 
XorPayloads(const Packet & src,size_t payload_length,size_t dst_offset,Packet * dst)608 void ForwardErrorCorrection::XorPayloads(const Packet& src,
609                                          size_t payload_length,
610                                          size_t dst_offset,
611                                          Packet* dst) {
612   // XOR the payload.
613   RTC_DCHECK_LE(kRtpHeaderSize + payload_length, src.data.size());
614   RTC_DCHECK_LE(dst_offset + payload_length, dst->data.capacity());
615   if (dst_offset + payload_length > dst->data.size()) {
616     dst->data.SetSize(dst_offset + payload_length);
617   }
618   uint8_t* dst_data = dst->data.MutableData();
619   const uint8_t* src_data = src.data.cdata();
620   for (size_t i = 0; i < payload_length; ++i) {
621     dst_data[dst_offset + i] ^= src_data[kRtpHeaderSize + i];
622   }
623 }
624 
RecoverPacket(const ReceivedFecPacket & fec_packet,RecoveredPacket * recovered_packet)625 bool ForwardErrorCorrection::RecoverPacket(const ReceivedFecPacket& fec_packet,
626                                            RecoveredPacket* recovered_packet) {
627   if (!StartPacketRecovery(fec_packet, recovered_packet)) {
628     return false;
629   }
630   for (const auto& protected_packet : fec_packet.protected_packets) {
631     if (protected_packet->pkt == nullptr) {
632       // This is the packet we're recovering.
633       recovered_packet->seq_num = protected_packet->seq_num;
634     } else {
635       XorHeaders(*protected_packet->pkt, recovered_packet->pkt.get());
636       XorPayloads(*protected_packet->pkt,
637                   protected_packet->pkt->data.size() - kRtpHeaderSize,
638                   kRtpHeaderSize, recovered_packet->pkt.get());
639     }
640   }
641   if (!FinishPacketRecovery(fec_packet, recovered_packet)) {
642     return false;
643   }
644   return true;
645 }
646 
AttemptRecovery(RecoveredPacketList * recovered_packets)647 void ForwardErrorCorrection::AttemptRecovery(
648     RecoveredPacketList* recovered_packets) {
649   auto fec_packet_it = received_fec_packets_.begin();
650   while (fec_packet_it != received_fec_packets_.end()) {
651     // Search for each FEC packet's protected media packets.
652     int packets_missing = NumCoveredPacketsMissing(**fec_packet_it);
653 
654     // We can only recover one packet with an FEC packet.
655     if (packets_missing == 1) {
656       // Recovery possible.
657       std::unique_ptr<RecoveredPacket> recovered_packet(new RecoveredPacket());
658       recovered_packet->pkt = nullptr;
659       if (!RecoverPacket(**fec_packet_it, recovered_packet.get())) {
660         // Can't recover using this packet, drop it.
661         fec_packet_it = received_fec_packets_.erase(fec_packet_it);
662         continue;
663       }
664 
665       auto* recovered_packet_ptr = recovered_packet.get();
666       // Add recovered packet to the list of recovered packets and update any
667       // FEC packets covering this packet with a pointer to the data.
668       // TODO(holmer): Consider replacing this with a binary search for the
669       // right position, and then just insert the new packet. Would get rid of
670       // the sort.
671       recovered_packets->push_back(std::move(recovered_packet));
672       recovered_packets->sort(SortablePacket::LessThan());
673       UpdateCoveringFecPackets(*recovered_packet_ptr);
674       DiscardOldRecoveredPackets(recovered_packets);
675       fec_packet_it = received_fec_packets_.erase(fec_packet_it);
676 
677       // A packet has been recovered. We need to check the FEC list again, as
678       // this may allow additional packets to be recovered.
679       // Restart for first FEC packet.
680       fec_packet_it = received_fec_packets_.begin();
681     } else if (packets_missing == 0 ||
682                IsOldFecPacket(**fec_packet_it, recovered_packets)) {
683       // Either all protected packets arrived or have been recovered, or the FEC
684       // packet is old. We can discard this FEC packet.
685       fec_packet_it = received_fec_packets_.erase(fec_packet_it);
686     } else {
687       fec_packet_it++;
688     }
689   }
690 }
691 
NumCoveredPacketsMissing(const ReceivedFecPacket & fec_packet)692 int ForwardErrorCorrection::NumCoveredPacketsMissing(
693     const ReceivedFecPacket& fec_packet) {
694   int packets_missing = 0;
695   for (const auto& protected_packet : fec_packet.protected_packets) {
696     if (protected_packet->pkt == nullptr) {
697       ++packets_missing;
698       if (packets_missing > 1) {
699         break;  // We can't recover more than one packet.
700       }
701     }
702   }
703   return packets_missing;
704 }
705 
DiscardOldRecoveredPackets(RecoveredPacketList * recovered_packets)706 void ForwardErrorCorrection::DiscardOldRecoveredPackets(
707     RecoveredPacketList* recovered_packets) {
708   const size_t max_media_packets = fec_header_reader_->MaxMediaPackets();
709   while (recovered_packets->size() > max_media_packets) {
710     recovered_packets->pop_front();
711   }
712   RTC_DCHECK_LE(recovered_packets->size(), max_media_packets);
713 }
714 
IsOldFecPacket(const ReceivedFecPacket & fec_packet,const RecoveredPacketList * recovered_packets)715 bool ForwardErrorCorrection::IsOldFecPacket(
716     const ReceivedFecPacket& fec_packet,
717     const RecoveredPacketList* recovered_packets) {
718   if (recovered_packets->empty()) {
719     return false;
720   }
721 
722   const uint16_t back_recovered_seq_num = recovered_packets->back()->seq_num;
723   const uint16_t last_protected_seq_num =
724       fec_packet.protected_packets.back()->seq_num;
725 
726   // FEC packet is old if its last protected sequence number is much
727   // older than the latest protected sequence number received.
728   return (MinDiff(back_recovered_seq_num, last_protected_seq_num) >
729           kOldSequenceThreshold);
730 }
731 
ParseSequenceNumber(const uint8_t * packet)732 uint16_t ForwardErrorCorrection::ParseSequenceNumber(const uint8_t* packet) {
733   return (packet[2] << 8) + packet[3];
734 }
735 
ParseSsrc(const uint8_t * packet)736 uint32_t ForwardErrorCorrection::ParseSsrc(const uint8_t* packet) {
737   return (packet[8] << 24) + (packet[9] << 16) + (packet[10] << 8) + packet[11];
738 }
739 
DecodeFec(const ReceivedPacket & received_packet,RecoveredPacketList * recovered_packets)740 void ForwardErrorCorrection::DecodeFec(const ReceivedPacket& received_packet,
741                                        RecoveredPacketList* recovered_packets) {
742   RTC_DCHECK(recovered_packets);
743 
744   const size_t max_media_packets = fec_header_reader_->MaxMediaPackets();
745   if (recovered_packets->size() == max_media_packets) {
746     const RecoveredPacket* back_recovered_packet =
747         recovered_packets->back().get();
748 
749     if (received_packet.ssrc == back_recovered_packet->ssrc) {
750       const unsigned int seq_num_diff =
751           MinDiff(received_packet.seq_num, back_recovered_packet->seq_num);
752       if (seq_num_diff > max_media_packets) {
753         // A big gap in sequence numbers. The old recovered packets
754         // are now useless, so it's safe to do a reset.
755         RTC_LOG(LS_INFO) << "Big gap in media/ULPFEC sequence numbers. No need "
756                             "to keep the old packets in the FEC buffers, thus "
757                             "resetting them.";
758         ResetState(recovered_packets);
759       }
760     }
761   }
762 
763   InsertPacket(received_packet, recovered_packets);
764   AttemptRecovery(recovered_packets);
765 }
766 
MaxPacketOverhead() const767 size_t ForwardErrorCorrection::MaxPacketOverhead() const {
768   return fec_header_writer_->MaxPacketOverhead();
769 }
770 
FecHeaderReader(size_t max_media_packets,size_t max_fec_packets)771 FecHeaderReader::FecHeaderReader(size_t max_media_packets,
772                                  size_t max_fec_packets)
773     : max_media_packets_(max_media_packets),
774       max_fec_packets_(max_fec_packets) {}
775 
776 FecHeaderReader::~FecHeaderReader() = default;
777 
MaxMediaPackets() const778 size_t FecHeaderReader::MaxMediaPackets() const {
779   return max_media_packets_;
780 }
781 
MaxFecPackets() const782 size_t FecHeaderReader::MaxFecPackets() const {
783   return max_fec_packets_;
784 }
785 
FecHeaderWriter(size_t max_media_packets,size_t max_fec_packets,size_t max_packet_overhead)786 FecHeaderWriter::FecHeaderWriter(size_t max_media_packets,
787                                  size_t max_fec_packets,
788                                  size_t max_packet_overhead)
789     : max_media_packets_(max_media_packets),
790       max_fec_packets_(max_fec_packets),
791       max_packet_overhead_(max_packet_overhead) {}
792 
793 FecHeaderWriter::~FecHeaderWriter() = default;
794 
MaxMediaPackets() const795 size_t FecHeaderWriter::MaxMediaPackets() const {
796   return max_media_packets_;
797 }
798 
MaxFecPackets() const799 size_t FecHeaderWriter::MaxFecPackets() const {
800   return max_fec_packets_;
801 }
802 
MaxPacketOverhead() const803 size_t FecHeaderWriter::MaxPacketOverhead() const {
804   return max_packet_overhead_;
805 }
806 
807 }  // namespace webrtc
808