• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <vector>
19 
20 #include "absl/types/optional.h"
21 #include "modules/include/module_common_types_public.h"
22 #include "rtc_base/gtest_prod_util.h"
23 
24 //
25 // The NackTracker class keeps track of the lost packets, an estimate of
26 // time-to-play for each packet is also given.
27 //
28 // Every time a packet is pushed into NetEq, LastReceivedPacket() has to be
29 // called to update the NACK list.
30 //
31 // Every time 10ms audio is pulled from NetEq LastDecodedPacket() should be
32 // called, and time-to-play is updated at that moment.
33 //
34 // If packet N is received, any packet prior to N which has not arrived is
35 // considered lost, and should be labeled as "missing" (the size of
36 // the list might be limited and older packet eliminated from the list).
37 //
38 // The NackTracker class has to know about the sample rate of the packets to
39 // compute time-to-play. So sample rate should be set as soon as the first
40 // packet is received. If there is a change in the receive codec (sender changes
41 // codec) then NackTracker should be reset. This is because NetEQ would flush
42 // its buffer and re-transmission is meaning less for old packet. Therefore, in
43 // that case, after reset the sampling rate has to be updated.
44 //
45 // Thread Safety
46 // =============
47 // Please note that this class in not thread safe. The class must be protected
48 // if different APIs are called from different threads.
49 //
50 namespace webrtc {
51 
52 class NackTracker {
53  public:
54   // A limit for the size of the NACK list.
55   static const size_t kNackListSizeLimit = 500;  // 10 seconds for 20 ms frame
56                                                  // packets.
57   NackTracker();
58   ~NackTracker();
59 
60   // Set a maximum for the size of the NACK list. If the last received packet
61   // has sequence number of N, then NACK list will not contain any element
62   // with sequence number earlier than N - `max_nack_list_size`.
63   //
64   // The largest maximum size is defined by `kNackListSizeLimit`
65   void SetMaxNackListSize(size_t max_nack_list_size);
66 
67   // Set the sampling rate.
68   //
69   // If associated sampling rate of the received packets is changed, call this
70   // function to update sampling rate. Note that if there is any change in
71   // received codec then NetEq will flush its buffer and NACK has to be reset.
72   // After Reset() is called sampling rate has to be set.
73   void UpdateSampleRate(int sample_rate_hz);
74 
75   // Update the sequence number and the timestamp of the last decoded RTP. This
76   // API should be called every time 10 ms audio is pulled from NetEq.
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.
GetPacketLossRateForTest()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     Config();
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 {
NackElementNackElement121     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:
operator()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   // This function subtracts 10 ms of time-to-play for all packets in NACK list.
153   // This is called when 10 ms elapsed with no new RTP packet decoded.
154   void UpdateEstimatedPlayoutTimeBy10ms();
155 
156   // Returns a valid number of samples per packet given the current received
157   // sequence number and timestamp or nullopt of none could be computed.
158   absl::optional<int> GetSamplesPerPacket(
159       uint16_t sequence_number_current_received_rtp,
160       uint32_t timestamp_current_received_rtp) const;
161 
162   // Given the `sequence_number_current_received_rtp` of currently received RTP
163   // update the list. Packets that are older than the received packet are added
164   // to the nack list.
165   void UpdateList(uint16_t sequence_number_current_received_rtp,
166                   uint32_t timestamp_current_received_rtp);
167 
168   // Packets which have sequence number older that
169   // `sequence_num_last_received_rtp_` - `max_nack_list_size_` are removed
170   // from the NACK list.
171   void LimitNackListSize();
172 
173   // Estimate timestamp of a missing packet given its sequence number.
174   uint32_t EstimateTimestamp(uint16_t sequence_number, int samples_per_packet);
175 
176   // Compute time-to-play given a timestamp.
177   int64_t TimeToPlay(uint32_t timestamp) const;
178 
179   // Updates the estimated packet lost rate.
180   void UpdatePacketLossRate(int packets_lost);
181 
182   const Config config_;
183 
184   // Valid if a packet is received.
185   uint16_t sequence_num_last_received_rtp_;
186   uint32_t timestamp_last_received_rtp_;
187   bool any_rtp_received_;  // If any packet received.
188 
189   // Valid if a packet is decoded.
190   uint16_t sequence_num_last_decoded_rtp_;
191   uint32_t timestamp_last_decoded_rtp_;
192   bool any_rtp_decoded_;  // If any packet decoded.
193 
194   int sample_rate_khz_;  // Sample rate in kHz.
195 
196   // A list of missing packets to be retransmitted. Components of the list
197   // contain the sequence number of missing packets and the estimated time that
198   // each pack is going to be played out.
199   NackList nack_list_;
200 
201   // NACK list will not keep track of missing packets prior to
202   // `sequence_num_last_received_rtp_` - `max_nack_list_size_`.
203   size_t max_nack_list_size_;
204 
205   // Current estimate of the packet loss rate in Q30.
206   uint32_t packet_loss_rate_ = 0;
207 };
208 
209 }  // namespace webrtc
210 
211 #endif  // MODULES_AUDIO_CODING_NETEQ_NACK_TRACKER_H_
212