tor-browser

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

packet_buffer.cc (8305B)


      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 // This is the implementation of the PacketBuffer class. It is mostly based on
     12 // an STL list. The list is kept sorted at all times so that the next packet to
     13 // decode is at the beginning of the list.
     14 
     15 #include "modules/audio_coding/neteq/packet_buffer.h"
     16 
     17 #include <algorithm>
     18 #include <cstddef>
     19 #include <cstdint>
     20 #include <list>
     21 #include <memory>
     22 #include <optional>
     23 #include <utility>
     24 
     25 #include "api/audio_codecs/audio_decoder.h"
     26 #include "api/neteq/tick_timer.h"
     27 #include "modules/audio_coding/neteq/decoder_database.h"
     28 #include "modules/audio_coding/neteq/packet.h"
     29 #include "modules/audio_coding/neteq/statistics_calculator.h"
     30 #include "rtc_base/checks.h"
     31 #include "rtc_base/logging.h"
     32 #include "rtc_base/numerics/safe_conversions.h"
     33 
     34 namespace webrtc {
     35 namespace {
     36 // Predicate used when inserting packets in the buffer list.
     37 // Operator() returns true when `packet` goes before `new_packet`.
     38 class NewTimestampIsLarger {
     39 public:
     40  explicit NewTimestampIsLarger(const Packet& new_packet)
     41      : new_packet_(new_packet) {}
     42  bool operator()(const Packet& packet) { return (new_packet_ >= packet); }
     43 
     44 private:
     45  const Packet& new_packet_;
     46 };
     47 
     48 }  // namespace
     49 
     50 PacketBuffer::PacketBuffer(size_t max_number_of_packets,
     51                           const TickTimer* tick_timer,
     52                           StatisticsCalculator* stats)
     53    : max_number_of_packets_(max_number_of_packets),
     54      tick_timer_(tick_timer),
     55      stats_(stats) {}
     56 
     57 // Destructor. All packets in the buffer will be destroyed.
     58 PacketBuffer::~PacketBuffer() {
     59  buffer_.clear();
     60 }
     61 
     62 // Flush the buffer. All packets in the buffer will be destroyed.
     63 void PacketBuffer::Flush() {
     64  for (auto& p : buffer_) {
     65    LogPacketDiscarded(p.priority.codec_level);
     66  }
     67  buffer_.clear();
     68  stats_->FlushedPacketBuffer();
     69 }
     70 
     71 bool PacketBuffer::Empty() const {
     72  return buffer_.empty();
     73 }
     74 
     75 int PacketBuffer::InsertPacket(Packet&& packet) {
     76  if (packet.empty()) {
     77    RTC_LOG(LS_WARNING) << "InsertPacket invalid packet";
     78    return kInvalidPacket;
     79  }
     80 
     81  RTC_DCHECK_GE(packet.priority.codec_level, 0);
     82  RTC_DCHECK_GE(packet.priority.red_level, 0);
     83 
     84  int return_val = kOK;
     85 
     86  packet.waiting_time = tick_timer_->GetNewStopwatch();
     87 
     88  if (buffer_.size() >= max_number_of_packets_) {
     89    // Buffer is full.
     90    Flush();
     91    return_val = kFlushed;
     92    RTC_LOG(LS_WARNING) << "Packet buffer flushed.";
     93  }
     94 
     95  // Get an iterator pointing to the place in the buffer where the new packet
     96  // should be inserted. The list is searched from the back, since the most
     97  // likely case is that the new packet should be near the end of the list.
     98  PacketList::reverse_iterator rit = std::find_if(
     99      buffer_.rbegin(), buffer_.rend(), NewTimestampIsLarger(packet));
    100 
    101  // The new packet is to be inserted to the right of `rit`. If it has the same
    102  // timestamp as `rit`, which has a higher priority, do not insert the new
    103  // packet to list.
    104  if (rit != buffer_.rend() && packet.timestamp == rit->timestamp) {
    105    LogPacketDiscarded(packet.priority.codec_level);
    106    return return_val;
    107  }
    108 
    109  // The new packet is to be inserted to the left of `it`. If it has the same
    110  // timestamp as `it`, which has a lower priority, replace `it` with the new
    111  // packet.
    112  PacketList::iterator it = rit.base();
    113  if (it != buffer_.end() && packet.timestamp == it->timestamp) {
    114    LogPacketDiscarded(it->priority.codec_level);
    115    it = buffer_.erase(it);
    116  }
    117  buffer_.insert(it, std::move(packet));  // Insert the packet at that position.
    118 
    119  return return_val;
    120 }
    121 
    122 int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
    123  if (Empty()) {
    124    return kBufferEmpty;
    125  }
    126  if (!next_timestamp) {
    127    return kInvalidPointer;
    128  }
    129  *next_timestamp = buffer_.front().timestamp;
    130  return kOK;
    131 }
    132 
    133 int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
    134                                      uint32_t* next_timestamp) const {
    135  if (Empty()) {
    136    return kBufferEmpty;
    137  }
    138  if (!next_timestamp) {
    139    return kInvalidPointer;
    140  }
    141  PacketList::const_iterator it;
    142  for (it = buffer_.begin(); it != buffer_.end(); ++it) {
    143    if (it->timestamp >= timestamp) {
    144      // Found a packet matching the search.
    145      *next_timestamp = it->timestamp;
    146      return kOK;
    147    }
    148  }
    149  return kNotFound;
    150 }
    151 
    152 const Packet* PacketBuffer::PeekNextPacket() const {
    153  return buffer_.empty() ? nullptr : &buffer_.front();
    154 }
    155 
    156 std::optional<Packet> PacketBuffer::GetNextPacket() {
    157  if (Empty()) {
    158    // Buffer is empty.
    159    return std::nullopt;
    160  }
    161 
    162  std::optional<Packet> packet(std::move(buffer_.front()));
    163  // Assert that the packet sanity checks in InsertPacket method works.
    164  RTC_DCHECK(!packet->empty());
    165  buffer_.pop_front();
    166 
    167  return packet;
    168 }
    169 
    170 int PacketBuffer::DiscardNextPacket() {
    171  if (Empty()) {
    172    return kBufferEmpty;
    173  }
    174  // Assert that the packet sanity checks in InsertPacket method works.
    175  const Packet& packet = buffer_.front();
    176  RTC_DCHECK(!packet.empty());
    177  LogPacketDiscarded(packet.priority.codec_level);
    178  buffer_.pop_front();
    179  return kOK;
    180 }
    181 
    182 void PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
    183                                     uint32_t horizon_samples) {
    184  buffer_.remove_if([this, timestamp_limit, horizon_samples](const Packet& p) {
    185    if (timestamp_limit == p.timestamp ||
    186        !IsObsoleteTimestamp(p.timestamp, timestamp_limit, horizon_samples)) {
    187      return false;
    188    }
    189    LogPacketDiscarded(p.priority.codec_level);
    190    return true;
    191  });
    192 }
    193 
    194 void PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
    195  DiscardOldPackets(timestamp_limit, 0);
    196 }
    197 
    198 void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) {
    199  buffer_.remove_if([this, payload_type](const Packet& p) {
    200    if (p.payload_type != payload_type) {
    201      return false;
    202    }
    203    LogPacketDiscarded(p.priority.codec_level);
    204    return true;
    205  });
    206 }
    207 
    208 size_t PacketBuffer::NumPacketsInBuffer() const {
    209  return buffer_.size();
    210 }
    211 
    212 size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
    213  size_t num_samples = 0;
    214  size_t last_duration = last_decoded_length;
    215  for (const Packet& packet : buffer_) {
    216    if (packet.frame) {
    217      // TODO(hlundin): Verify that it's fine to count all packets and remove
    218      // this check.
    219      if (packet.priority != Packet::Priority(0, 0)) {
    220        continue;
    221      }
    222      size_t duration = packet.frame->Duration();
    223      if (duration > 0) {
    224        last_duration = duration;  // Save the most up-to-date (valid) duration.
    225      }
    226    }
    227    num_samples += last_duration;
    228  }
    229  return num_samples;
    230 }
    231 
    232 size_t PacketBuffer::GetSpanSamples(size_t last_decoded_length,
    233                                    size_t sample_rate,
    234                                    bool count_waiting_time) const {
    235  if (buffer_.empty()) {
    236    return 0;
    237  }
    238 
    239  size_t span = buffer_.back().timestamp - buffer_.front().timestamp;
    240  size_t waiting_time_samples = dchecked_cast<size_t>(
    241      buffer_.back().waiting_time->ElapsedMs() * (sample_rate / 1000));
    242  if (count_waiting_time) {
    243    span += waiting_time_samples;
    244  } else if (buffer_.back().frame && buffer_.back().frame->Duration() > 0) {
    245    size_t duration = buffer_.back().frame->Duration();
    246    if (buffer_.back().frame->IsDtxPacket()) {
    247      duration = std::max(duration, waiting_time_samples);
    248    }
    249    span += duration;
    250  } else {
    251    span += last_decoded_length;
    252  }
    253  return span;
    254 }
    255 
    256 bool PacketBuffer::ContainsDtxOrCngPacket(
    257    const DecoderDatabase* decoder_database) const {
    258  RTC_DCHECK(decoder_database);
    259  for (const Packet& packet : buffer_) {
    260    if ((packet.frame && packet.frame->IsDtxPacket()) ||
    261        decoder_database->IsComfortNoise(packet.payload_type)) {
    262      return true;
    263    }
    264  }
    265  return false;
    266 }
    267 
    268 void PacketBuffer::LogPacketDiscarded(int codec_level) {
    269  if (codec_level > 0) {
    270    stats_->SecondaryPacketsDiscarded(1);
    271  } else {
    272    stats_->PacketsDiscarded(1);
    273  }
    274 }
    275 
    276 }  // namespace webrtc