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