tor-browser

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

nack_tracker.h (8359B)


      1 /*
      2 *  Copyright (c) 2013 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 #ifndef MODULES_AUDIO_CODING_NETEQ_NACK_TRACKER_H_
     12 #define MODULES_AUDIO_CODING_NETEQ_NACK_TRACKER_H_
     13 
     14 #include <stddef.h>
     15 #include <stdint.h>
     16 
     17 #include <map>
     18 #include <optional>
     19 #include <vector>
     20 
     21 #include "api/field_trials_view.h"
     22 #include "modules/include/module_common_types_public.h"
     23 #include "rtc_base/gtest_prod_util.h"
     24 
     25 //
     26 // The NackTracker class keeps track of the lost packets, an estimate of
     27 // time-to-play for each packet is also given.
     28 //
     29 // Every time a packet is pushed into NetEq, LastReceivedPacket() has to be
     30 // called to update the NACK list.
     31 //
     32 // Every time 10ms audio is pulled from NetEq LastDecodedPacket() should be
     33 // called, and time-to-play is updated at that moment.
     34 //
     35 // If packet N is received, any packet prior to N which has not arrived is
     36 // considered lost, and should be labeled as "missing" (the size of
     37 // the list might be limited and older packet eliminated from the list).
     38 //
     39 // The NackTracker class has to know about the sample rate of the packets to
     40 // compute time-to-play. So sample rate should be set as soon as the first
     41 // packet is received. If there is a change in the receive codec (sender changes
     42 // codec) then NackTracker should be reset. This is because NetEQ would flush
     43 // its buffer and re-transmission is meaning less for old packet. Therefore, in
     44 // that case, after reset the sampling rate has to be updated.
     45 //
     46 // Thread Safety
     47 // =============
     48 // Please note that this class in not thread safe. The class must be protected
     49 // if different APIs are called from different threads.
     50 //
     51 namespace webrtc {
     52 
     53 class NackTracker {
     54 public:
     55  // A limit for the size of the NACK list.
     56  static const size_t kNackListSizeLimit = 500;  // 10 seconds for 20 ms frame
     57                                                 // packets.
     58  explicit NackTracker(const FieldTrialsView& field_trials);
     59  ~NackTracker();
     60 
     61  // Set a maximum for the size of the NACK list. If the last received packet
     62  // has sequence number of N, then NACK list will not contain any element
     63  // with sequence number earlier than N - `max_nack_list_size`.
     64  //
     65  // The largest maximum size is defined by `kNackListSizeLimit`
     66  void SetMaxNackListSize(size_t max_nack_list_size);
     67 
     68  // Set the sampling rate.
     69  //
     70  // If associated sampling rate of the received packets is changed, call this
     71  // function to update sampling rate. Note that if there is any change in
     72  // received codec then NetEq will flush its buffer and NACK has to be reset.
     73  // After Reset() is called sampling rate has to be set.
     74  void UpdateSampleRate(int sample_rate_hz);
     75 
     76  // Update the sequence number and the timestamp of the last decoded RTP.
     77  void UpdateLastDecodedPacket(uint16_t sequence_number, uint32_t timestamp);
     78 
     79  // Update the sequence number and the timestamp of the last received RTP. This
     80  // API should be called every time a packet pushed into ACM.
     81  void UpdateLastReceivedPacket(uint16_t sequence_number, uint32_t timestamp);
     82 
     83  // Get a list of "missing" packets which have expected time-to-play larger
     84  // than the given round-trip-time (in milliseconds).
     85  // Note: Late packets are not included.
     86  // Calling this method multiple times may give different results, since the
     87  // internal nack list may get flushed if never_nack_multiple_times_ is true.
     88  std::vector<uint16_t> GetNackList(int64_t round_trip_time_ms);
     89 
     90  // Reset to default values. The NACK list is cleared.
     91  // `max_nack_list_size_` preserves its value.
     92  void Reset();
     93 
     94  // Returns the estimated packet loss rate in Q30, for testing only.
     95  uint32_t GetPacketLossRateForTest() { return packet_loss_rate_; }
     96 
     97 private:
     98  // This test need to access the private method GetNackList().
     99  FRIEND_TEST_ALL_PREFIXES(NackTrackerTest, EstimateTimestampAndTimeToPlay);
    100 
    101  // Options that can be configured via field trial.
    102  struct Config {
    103    explicit Config(const FieldTrialsView& field_trials);
    104 
    105    // The exponential decay factor used to estimate the packet loss rate.
    106    double packet_loss_forget_factor = 0.996;
    107    // How many additional ms we are willing to wait (at most) for nacked
    108    // packets for each additional percentage of packet loss.
    109    int ms_per_loss_percent = 20;
    110    // If true, never nack packets more than once.
    111    bool never_nack_multiple_times = false;
    112    // Only nack if the RTT is valid.
    113    bool require_valid_rtt = false;
    114    // Default RTT to use unless `require_valid_rtt` is set.
    115    int default_rtt_ms = 100;
    116    // Do not nack if the loss rate is above this value.
    117    double max_loss_rate = 1.0;
    118  };
    119 
    120  struct NackElement {
    121    NackElement(int64_t initial_time_to_play_ms, uint32_t initial_timestamp)
    122        : time_to_play_ms(initial_time_to_play_ms),
    123          estimated_timestamp(initial_timestamp) {}
    124 
    125    // Estimated time (ms) left for this packet to be decoded. This estimate is
    126    // updated every time jitter buffer decodes a packet.
    127    int64_t time_to_play_ms;
    128 
    129    // A guess about the timestamp of the missing packet, it is used for
    130    // estimation of `time_to_play_ms`. The estimate might be slightly wrong if
    131    // there has been frame-size change since the last received packet and the
    132    // missing packet. However, the risk of this is low, and in case of such
    133    // errors, there will be a minor misestimation in time-to-play of missing
    134    // packets. This will have a very minor effect on NACK performance.
    135    uint32_t estimated_timestamp;
    136  };
    137 
    138  class NackListCompare {
    139   public:
    140    bool operator()(uint16_t sequence_number_old,
    141                    uint16_t sequence_number_new) const {
    142      return IsNewerSequenceNumber(sequence_number_new, sequence_number_old);
    143    }
    144  };
    145 
    146  typedef std::map<uint16_t, NackElement, NackListCompare> NackList;
    147 
    148  // This API is used only for testing to assess whether time-to-play is
    149  // computed correctly.
    150  NackList GetNackList() const;
    151 
    152  // Returns a valid number of samples per packet given the current received
    153  // sequence number and timestamp or nullopt of none could be computed.
    154  std::optional<int> GetSamplesPerPacket(
    155      uint16_t sequence_number_current_received_rtp,
    156      uint32_t timestamp_current_received_rtp) const;
    157 
    158  // Given the `sequence_number_current_received_rtp` of currently received RTP
    159  // update the list. Packets that are older than the received packet are added
    160  // to the nack list.
    161  void UpdateList(uint16_t sequence_number_current_received_rtp,
    162                  uint32_t timestamp_current_received_rtp);
    163 
    164  // Packets which have sequence number older that
    165  // `sequence_num_last_received_rtp_` - `max_nack_list_size_` are removed
    166  // from the NACK list.
    167  void LimitNackListSize();
    168 
    169  // Estimate timestamp of a missing packet given its sequence number.
    170  uint32_t EstimateTimestamp(uint16_t sequence_number, int samples_per_packet);
    171 
    172  // Compute time-to-play given a timestamp.
    173  int64_t TimeToPlay(uint32_t timestamp) const;
    174 
    175  // Updates the estimated packet lost rate.
    176  void UpdatePacketLossRate(int packets_lost);
    177 
    178  const Config config_;
    179 
    180  // Valid if a packet is received.
    181  uint16_t sequence_num_last_received_rtp_;
    182  uint32_t timestamp_last_received_rtp_;
    183  bool any_rtp_received_;  // If any packet received.
    184 
    185  // Valid if a packet is decoded.
    186  uint16_t sequence_num_last_decoded_rtp_;
    187  uint32_t timestamp_last_decoded_rtp_;
    188  bool any_rtp_decoded_;  // If any packet decoded.
    189 
    190  int sample_rate_khz_;  // Sample rate in kHz.
    191 
    192  // A list of missing packets to be retransmitted. Components of the list
    193  // contain the sequence number of missing packets and the estimated time that
    194  // each pack is going to be played out.
    195  NackList nack_list_;
    196 
    197  // NACK list will not keep track of missing packets prior to
    198  // `sequence_num_last_received_rtp_` - `max_nack_list_size_`.
    199  size_t max_nack_list_size_;
    200 
    201  // Current estimate of the packet loss rate in Q30.
    202  uint32_t packet_loss_rate_ = 0;
    203 };
    204 
    205 }  // namespace webrtc
    206 
    207 #endif  // MODULES_AUDIO_CODING_NETEQ_NACK_TRACKER_H_