tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ulpfec_generator.cc (10248B)


      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/ulpfec_generator.h"
     12 
     13 #include <cstdint>
     14 #include <cstring>
     15 #include <memory>
     16 #include <utility>
     17 #include <vector>
     18 
     19 #include "api/environment/environment.h"
     20 #include "api/units/data_rate.h"
     21 #include "api/units/time_delta.h"
     22 #include "modules/include/module_fec_types.h"
     23 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
     24 #include "modules/rtp_rtcp/source/forward_error_correction.h"
     25 #include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
     26 #include "rtc_base/checks.h"
     27 #include "rtc_base/race_checker.h"
     28 #include "rtc_base/synchronization/mutex.h"
     29 
     30 namespace webrtc {
     31 
     32 namespace {
     33 
     34 constexpr size_t kRedForFecHeaderLength = 1;
     35 
     36 // This controls the maximum amount of excess overhead (actual - target)
     37 // allowed in order to trigger EncodeFec(), before `params_.max_fec_frames`
     38 // is reached. Overhead here is defined as relative to number of media packets.
     39 constexpr int kMaxExcessOverhead = 50;  // Q8.
     40 
     41 // This is the minimum number of media packets required (above some protection
     42 // level) in order to trigger EncodeFec(), before `params_.max_fec_frames` is
     43 // reached.
     44 constexpr size_t kMinMediaPackets = 4;
     45 
     46 // Threshold on the received FEC protection level, above which we enforce at
     47 // least `kMinMediaPackets` packets for the FEC code. Below this
     48 // threshold `kMinMediaPackets` is set to default value of 1.
     49 //
     50 // The range is between 0 and 255, where 255 corresponds to 100% overhead
     51 // (relative to the number of protected media packets).
     52 constexpr uint8_t kHighProtectionThreshold = 80;
     53 
     54 // This threshold is used to adapt the `kMinMediaPackets` threshold, based
     55 // on the average number of packets per frame seen so far. When there are few
     56 // packets per frame (as given by this threshold), at least
     57 // `kMinMediaPackets` + 1 packets are sent to the FEC code.
     58 constexpr float kMinMediaPacketsAdaptationThreshold = 2.0f;
     59 
     60 // At construction time, we don't know the SSRC that is used for the generated
     61 // FEC packets, but we still need to give it to the ForwardErrorCorrection ctor
     62 // to be used in the decoding.
     63 // TODO(brandtr): Get rid of this awkwardness by splitting
     64 // ForwardErrorCorrection in two objects -- one encoder and one decoder.
     65 constexpr uint32_t kUnknownSsrc = 0;
     66 
     67 }  // namespace
     68 
     69 UlpfecGenerator::Params::Params() = default;
     70 UlpfecGenerator::Params::Params(FecProtectionParams delta_params,
     71                                FecProtectionParams keyframe_params)
     72    : delta_params(delta_params), keyframe_params(keyframe_params) {}
     73 
     74 UlpfecGenerator::UlpfecGenerator(const Environment& env,
     75                                 int red_payload_type,
     76                                 int ulpfec_payload_type)
     77    : env_(env),
     78      red_payload_type_(red_payload_type),
     79      ulpfec_payload_type_(ulpfec_payload_type),
     80      fec_(ForwardErrorCorrection::CreateUlpfec(kUnknownSsrc)),
     81      num_protected_frames_(0),
     82      min_num_media_packets_(1),
     83      media_contains_keyframe_(false),
     84      fec_bitrate_(/*max_window_size=*/TimeDelta::Seconds(1)) {}
     85 
     86 // Used by FlexFecSender, payload types are unused.
     87 UlpfecGenerator::UlpfecGenerator(const Environment& env,
     88                                 std::unique_ptr<ForwardErrorCorrection> fec)
     89    : env_(env),
     90      red_payload_type_(0),
     91      ulpfec_payload_type_(0),
     92      fec_(std::move(fec)),
     93      num_protected_frames_(0),
     94      min_num_media_packets_(1),
     95      media_contains_keyframe_(false),
     96      fec_bitrate_(/*max_window_size=*/TimeDelta::Seconds(1)) {}
     97 
     98 UlpfecGenerator::~UlpfecGenerator() = default;
     99 
    100 void UlpfecGenerator::SetProtectionParameters(
    101    const FecProtectionParams& delta_params,
    102    const FecProtectionParams& key_params) {
    103  RTC_DCHECK_GE(delta_params.fec_rate, 0);
    104  RTC_DCHECK_LE(delta_params.fec_rate, 255);
    105  RTC_DCHECK_GE(key_params.fec_rate, 0);
    106  RTC_DCHECK_LE(key_params.fec_rate, 255);
    107  // Store the new params and apply them for the next set of FEC packets being
    108  // produced.
    109  MutexLock lock(&mutex_);
    110  pending_params_.emplace(delta_params, key_params);
    111 }
    112 
    113 void UlpfecGenerator::AddPacketAndGenerateFec(const RtpPacketToSend& packet) {
    114  RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
    115  RTC_DCHECK(generated_fec_packets_.empty());
    116 
    117  {
    118    MutexLock lock(&mutex_);
    119    if (pending_params_) {
    120      current_params_ = *pending_params_;
    121      pending_params_.reset();
    122 
    123      if (CurrentParams().fec_rate > kHighProtectionThreshold) {
    124        min_num_media_packets_ = kMinMediaPackets;
    125      } else {
    126        min_num_media_packets_ = 1;
    127      }
    128    }
    129  }
    130 
    131  if (packet.is_key_frame()) {
    132    media_contains_keyframe_ = true;
    133  }
    134  const bool complete_frame = packet.Marker();
    135  if (media_packets_.size() < kUlpfecMaxMediaPackets) {
    136    // Our packet masks can only protect up to `kUlpfecMaxMediaPackets` packets.
    137    auto fec_packet = std::make_unique<ForwardErrorCorrection::Packet>();
    138    fec_packet->data = packet.Buffer();
    139    media_packets_.push_back(std::move(fec_packet));
    140 
    141    // Keep a copy of the last RTP packet, so we can copy the RTP header
    142    // from it when creating newly generated ULPFEC+RED packets.
    143    RTC_DCHECK_GE(packet.headers_size(), kRtpHeaderSize);
    144    last_media_packet_ = packet;
    145  }
    146 
    147  if (complete_frame) {
    148    ++num_protected_frames_;
    149  }
    150 
    151  auto params = CurrentParams();
    152 
    153  // Produce FEC over at most `params_.max_fec_frames` frames, or as soon as:
    154  // (1) the excess overhead (actual overhead - requested/target overhead) is
    155  // less than `kMaxExcessOverhead`, and
    156  // (2) at least `min_num_media_packets_` media packets is reached.
    157  if (complete_frame &&
    158      (num_protected_frames_ >= params.max_fec_frames ||
    159       (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) {
    160    // We are not using Unequal Protection feature of the parity erasure code.
    161    constexpr int kNumImportantPackets = 0;
    162    constexpr bool kUseUnequalProtection = false;
    163    fec_->EncodeFec(media_packets_, params.fec_rate, kNumImportantPackets,
    164                    kUseUnequalProtection, params.fec_mask_type,
    165                    &generated_fec_packets_);
    166    if (generated_fec_packets_.empty()) {
    167      ResetState();
    168    }
    169  }
    170 }
    171 
    172 bool UlpfecGenerator::ExcessOverheadBelowMax() const {
    173  RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
    174 
    175  return ((Overhead() - CurrentParams().fec_rate) < kMaxExcessOverhead);
    176 }
    177 
    178 bool UlpfecGenerator::MinimumMediaPacketsReached() const {
    179  RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
    180  float average_num_packets_per_frame =
    181      static_cast<float>(media_packets_.size()) / num_protected_frames_;
    182  int num_media_packets = static_cast<int>(media_packets_.size());
    183  if (average_num_packets_per_frame < kMinMediaPacketsAdaptationThreshold) {
    184    return num_media_packets >= min_num_media_packets_;
    185  } else {
    186    // For larger rates (more packets/frame), increase the threshold.
    187    // TODO(brandtr): Investigate what impact this adaptation has.
    188    return num_media_packets >= min_num_media_packets_ + 1;
    189  }
    190 }
    191 
    192 const FecProtectionParams& UlpfecGenerator::CurrentParams() const {
    193  RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
    194  return media_contains_keyframe_ ? current_params_.keyframe_params
    195                                  : current_params_.delta_params;
    196 }
    197 
    198 size_t UlpfecGenerator::MaxPacketOverhead() const {
    199  RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
    200  return fec_->MaxPacketOverhead();
    201 }
    202 
    203 std::vector<std::unique_ptr<RtpPacketToSend>> UlpfecGenerator::GetFecPackets() {
    204  RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
    205  if (generated_fec_packets_.empty()) {
    206    return std::vector<std::unique_ptr<RtpPacketToSend>>();
    207  }
    208 
    209  // Wrap FEC packet (including FEC headers) in a RED packet. Since the
    210  // FEC packets in `generated_fec_packets_` don't have RTP headers, we
    211  // reuse the header from the last media packet.
    212  RTC_CHECK(last_media_packet_.has_value());
    213  last_media_packet_->SetPayloadSize(0);
    214 
    215  std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets;
    216  fec_packets.reserve(generated_fec_packets_.size());
    217 
    218  size_t total_fec_size_bytes = 0;
    219  for (const auto* fec_packet : generated_fec_packets_) {
    220    std::unique_ptr<RtpPacketToSend> red_packet =
    221        std::make_unique<RtpPacketToSend>(*last_media_packet_);
    222    red_packet->SetPayloadType(red_payload_type_);
    223    red_packet->SetMarker(false);
    224    uint8_t* payload_buffer = red_packet->SetPayloadSize(
    225        kRedForFecHeaderLength + fec_packet->data.size());
    226    // Primary RED header with F bit unset.
    227    // See https://tools.ietf.org/html/rfc2198#section-3
    228    payload_buffer[0] = ulpfec_payload_type_;  // RED header.
    229    memcpy(&payload_buffer[1], fec_packet->data.data(),
    230           fec_packet->data.size());
    231    total_fec_size_bytes += red_packet->size();
    232    red_packet->set_packet_type(RtpPacketMediaType::kForwardErrorCorrection);
    233    red_packet->set_allow_retransmission(false);
    234    red_packet->set_is_red(true);
    235    red_packet->set_fec_protect_packet(false);
    236    fec_packets.push_back(std::move(red_packet));
    237  }
    238 
    239  ResetState();
    240 
    241  MutexLock lock(&mutex_);
    242  fec_bitrate_.Update(total_fec_size_bytes, env_.clock().CurrentTime());
    243 
    244  return fec_packets;
    245 }
    246 
    247 DataRate UlpfecGenerator::CurrentFecRate() const {
    248  MutexLock lock(&mutex_);
    249  return fec_bitrate_.Rate(env_.clock().CurrentTime())
    250      .value_or(DataRate::Zero());
    251 }
    252 
    253 int UlpfecGenerator::Overhead() const {
    254  RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
    255  RTC_DCHECK(!media_packets_.empty());
    256  int num_fec_packets = ForwardErrorCorrection::NumFecPackets(
    257      media_packets_.size(), CurrentParams().fec_rate);
    258 
    259  // Return the overhead in Q8.
    260  return (num_fec_packets << 8) / media_packets_.size();
    261 }
    262 
    263 void UlpfecGenerator::ResetState() {
    264  RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
    265  media_packets_.clear();
    266  last_media_packet_.reset();
    267  generated_fec_packets_.clear();
    268  num_protected_frames_ = 0;
    269  media_contains_keyframe_ = false;
    270 }
    271 
    272 }  // namespace webrtc