tor-browser

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

flexfec_receiver.cc (7998B)


      1 /*
      2 *  Copyright (c) 2016 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/include/flexfec_receiver.h"
     12 
     13 #include <cstdint>
     14 #include <cstring>
     15 #include <memory>
     16 
     17 #include "api/scoped_refptr.h"
     18 #include "api/sequence_checker.h"
     19 #include "api/units/time_delta.h"
     20 #include "api/units/timestamp.h"
     21 #include "modules/rtp_rtcp/include/recovered_packet_receiver.h"
     22 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
     23 #include "modules/rtp_rtcp/source/forward_error_correction.h"
     24 #include "modules/rtp_rtcp/source/rtp_packet_received.h"
     25 #include "modules/rtp_rtcp/source/ulpfec_receiver.h"
     26 #include "rtc_base/checks.h"
     27 #include "rtc_base/logging.h"
     28 
     29 namespace webrtc {
     30 
     31 namespace {
     32 
     33 // Minimum header size (in bytes) of a well-formed non-singular FlexFEC packet.
     34 constexpr size_t kMinFlexfecHeaderSize = 20;
     35 
     36 // How often to log the recovered packets to the text log.
     37 constexpr TimeDelta kPacketLogInterval = TimeDelta::Seconds(10);
     38 
     39 }  // namespace
     40 
     41 /* Mozilla: Avoid this since it could use GetRealTimeClock().
     42 FlexfecReceiver::FlexfecReceiver(
     43    uint32_t ssrc,
     44    uint32_t protected_media_ssrc,
     45    RecoveredPacketReceiver* recovered_packet_receiver)
     46    : FlexfecReceiver(Clock::GetRealTimeClock(),
     47                      ssrc,
     48                      protected_media_ssrc,
     49                      recovered_packet_receiver) {}
     50 */
     51 
     52 FlexfecReceiver::FlexfecReceiver(
     53    Clock* clock,
     54    uint32_t ssrc,
     55    uint32_t protected_media_ssrc,
     56    RecoveredPacketReceiver* recovered_packet_receiver)
     57    : ssrc_(ssrc),
     58      protected_media_ssrc_(protected_media_ssrc),
     59      erasure_code_(
     60          ForwardErrorCorrection::CreateFlexfec(ssrc, protected_media_ssrc)),
     61      recovered_packet_receiver_(recovered_packet_receiver),
     62      clock_(clock) {
     63  // It's OK to create this object on a different thread/task queue than
     64  // the one used during main operation.
     65  sequence_checker_.Detach();
     66 }
     67 
     68 FlexfecReceiver::~FlexfecReceiver() = default;
     69 
     70 void FlexfecReceiver::OnRtpPacket(const RtpPacketReceived& packet) {
     71  RTC_DCHECK_RUN_ON(&sequence_checker_);
     72 
     73  // If this packet was recovered, it might be originating from
     74  // ProcessReceivedPacket in this object. To avoid lifetime issues with
     75  // `recovered_packets_`, we therefore break the cycle here.
     76  // This might reduce decoding efficiency a bit, since we can't disambiguate
     77  // recovered packets by RTX from recovered packets by FlexFEC.
     78  if (packet.recovered())
     79    return;
     80 
     81  std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet =
     82      AddReceivedPacket(packet);
     83  if (!received_packet)
     84    return;
     85 
     86  ProcessReceivedPacket(*received_packet);
     87 }
     88 
     89 FecPacketCounter FlexfecReceiver::GetPacketCounter() const {
     90  RTC_DCHECK_RUN_ON(&sequence_checker_);
     91  return packet_counter_;
     92 }
     93 
     94 // TODO(eladalon): Consider using packet.recovered() to avoid processing
     95 // recovered packets here.
     96 std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>
     97 FlexfecReceiver::AddReceivedPacket(const RtpPacketReceived& packet) {
     98  RTC_DCHECK_RUN_ON(&sequence_checker_);
     99 
    100  // RTP packets with a full base header (12 bytes), but without payload,
    101  // could conceivably be useful in the decoding. Therefore we check
    102  // with a non-strict inequality here.
    103  RTC_DCHECK_GE(packet.size(), kRtpHeaderSize);
    104 
    105  // Demultiplex based on SSRC, and insert into erasure code decoder.
    106  std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet(
    107      new ForwardErrorCorrection::ReceivedPacket());
    108  received_packet->seq_num = packet.SequenceNumber();
    109  received_packet->ssrc = packet.Ssrc();
    110  received_packet->extensions = packet.extension_manager();
    111  if (received_packet->ssrc == ssrc_) {
    112    // This is a FlexFEC packet.
    113    if (packet.payload_size() < kMinFlexfecHeaderSize) {
    114      RTC_LOG(LS_WARNING) << "Truncated FlexFEC packet, discarding.";
    115      return nullptr;
    116    }
    117    received_packet->is_fec = true;
    118    ++packet_counter_.num_fec_packets;
    119 
    120    // Insert packet payload into erasure code.
    121    received_packet->pkt = scoped_refptr<ForwardErrorCorrection::Packet>(
    122        new ForwardErrorCorrection::Packet());
    123    received_packet->pkt->data =
    124        packet.Buffer().Slice(packet.headers_size(), packet.payload_size());
    125  } else {
    126    // This is a media packet, or a FlexFEC packet belonging to some
    127    // other FlexFEC stream.
    128    if (received_packet->ssrc != protected_media_ssrc_) {
    129      return nullptr;
    130    }
    131    received_packet->is_fec = false;
    132 
    133    // Insert entire packet into erasure code.
    134    // Create a copy and fill with zeros all mutable extensions.
    135    received_packet->pkt = scoped_refptr<ForwardErrorCorrection::Packet>(
    136        new ForwardErrorCorrection::Packet());
    137    RtpPacketReceived packet_copy(packet);
    138    packet_copy.ZeroMutableExtensions();
    139    received_packet->pkt->data = packet_copy.Buffer();
    140  }
    141 
    142  ++packet_counter_.num_packets;
    143 
    144  return received_packet;
    145 }
    146 
    147 // Note that the implementation of this member function and the implementation
    148 // in UlpfecReceiver::ProcessReceivedFec() are slightly different.
    149 // This implementation only returns _recovered_ media packets through the
    150 // callback, whereas the implementation in UlpfecReceiver returns _all inserted_
    151 // media packets through the callback. The latter behaviour makes sense
    152 // for ULPFEC, since the ULPFEC receiver is owned by the RtpVideoStreamReceiver.
    153 // Here, however, the received media pipeline is more decoupled from the
    154 // FlexFEC decoder, and we therefore do not interfere with the reception
    155 // of non-recovered media packets.
    156 void FlexfecReceiver::ProcessReceivedPacket(
    157    const ForwardErrorCorrection::ReceivedPacket& received_packet) {
    158  RTC_DCHECK_RUN_ON(&sequence_checker_);
    159 
    160  // Decode.
    161  ForwardErrorCorrection::DecodeFecResult decode_result =
    162      erasure_code_->DecodeFec(received_packet, &recovered_packets_);
    163 
    164  if (decode_result.num_recovered_packets == 0) {
    165    return;
    166  }
    167 
    168  // Return recovered packets through callback.
    169  for (const auto& recovered_packet : recovered_packets_) {
    170    RTC_CHECK(recovered_packet);
    171    if (recovered_packet->returned) {
    172      continue;
    173    }
    174    ++packet_counter_.num_recovered_packets;
    175    // Set this flag first, since OnRecoveredPacket may end up here
    176    // again, with the same packet.
    177    recovered_packet->returned = true;
    178    RTC_CHECK_GE(recovered_packet->pkt->data.size(), kRtpHeaderSize);
    179 
    180    RtpPacketReceived parsed_packet(&received_packet.extensions);
    181    if (!parsed_packet.Parse(recovered_packet->pkt->data)) {
    182      continue;
    183    }
    184    parsed_packet.set_recovered(true);
    185 
    186    // TODO(brandtr): Update here when we support protecting audio packets too.
    187    parsed_packet.set_payload_type_frequency(kVideoPayloadTypeFrequency);
    188    recovered_packet_receiver_->OnRecoveredPacket(parsed_packet);
    189 
    190    // Periodically log the incoming packets at LS_INFO.
    191    Timestamp now = clock_->CurrentTime();
    192    bool should_log_periodically =
    193        now - last_recovered_packet_ > kPacketLogInterval;
    194    if (RTC_LOG_CHECK_LEVEL(LS_VERBOSE) || should_log_periodically) {
    195      LoggingSeverity level = should_log_periodically ? LS_INFO : LS_VERBOSE;
    196      RTC_LOG_V(level) << "Recovered media packet with SSRC: "
    197                       << parsed_packet.Ssrc() << " seq "
    198                       << parsed_packet.SequenceNumber() << " recovered length "
    199                       << recovered_packet->pkt->data.size()
    200                       << " received length "
    201                       << received_packet.pkt->data.size()
    202                       << " from FlexFEC stream with SSRC: " << ssrc_;
    203      if (should_log_periodically) {
    204        last_recovered_packet_ = now;
    205      }
    206    }
    207  }
    208 }
    209 
    210 }  // namespace webrtc