nack_tracker.cc (9192B)
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 #include "modules/audio_coding/neteq/nack_tracker.h" 12 13 #include <cstddef> 14 #include <cstdint> 15 #include <optional> 16 #include <utility> 17 #include <vector> 18 19 #include "api/field_trials_view.h" 20 #include "modules/include/module_common_types_public.h" 21 #include "rtc_base/checks.h" 22 #include "rtc_base/experiments/struct_parameters_parser.h" 23 #include "rtc_base/logging.h" 24 25 namespace webrtc { 26 namespace { 27 28 const int kDefaultSampleRateKhz = 48; 29 const int kMaxPacketSizeMs = 120; 30 constexpr char kNackTrackerConfigFieldTrial[] = 31 "WebRTC-Audio-NetEqNackTrackerConfig"; 32 33 } // namespace 34 35 NackTracker::Config::Config(const FieldTrialsView& field_trials) { 36 auto parser = StructParametersParser::Create( 37 "packet_loss_forget_factor", &packet_loss_forget_factor, 38 "ms_per_loss_percent", &ms_per_loss_percent, "never_nack_multiple_times", 39 &never_nack_multiple_times, "require_valid_rtt", &require_valid_rtt, 40 "max_loss_rate", &max_loss_rate); 41 parser->Parse(field_trials.Lookup(kNackTrackerConfigFieldTrial)); 42 RTC_LOG(LS_INFO) << "Nack tracker config:" 43 " packet_loss_forget_factor=" 44 << packet_loss_forget_factor 45 << " ms_per_loss_percent=" << ms_per_loss_percent 46 << " never_nack_multiple_times=" << never_nack_multiple_times 47 << " require_valid_rtt=" << require_valid_rtt 48 << " max_loss_rate=" << max_loss_rate; 49 } 50 51 NackTracker::NackTracker(const FieldTrialsView& field_trials) 52 : config_(field_trials), 53 sequence_num_last_received_rtp_(0), 54 timestamp_last_received_rtp_(0), 55 any_rtp_received_(false), 56 sequence_num_last_decoded_rtp_(0), 57 timestamp_last_decoded_rtp_(0), 58 any_rtp_decoded_(false), 59 sample_rate_khz_(kDefaultSampleRateKhz), 60 max_nack_list_size_(kNackListSizeLimit) {} 61 62 NackTracker::~NackTracker() = default; 63 64 void NackTracker::UpdateSampleRate(int sample_rate_hz) { 65 RTC_DCHECK_GT(sample_rate_hz, 0); 66 sample_rate_khz_ = sample_rate_hz / 1000; 67 } 68 69 void NackTracker::UpdateLastReceivedPacket(uint16_t sequence_number, 70 uint32_t timestamp) { 71 // Just record the value of sequence number and timestamp if this is the 72 // first packet. 73 if (!any_rtp_received_) { 74 sequence_num_last_received_rtp_ = sequence_number; 75 timestamp_last_received_rtp_ = timestamp; 76 any_rtp_received_ = true; 77 // If no packet is decoded, to have a reasonable estimate of time-to-play 78 // use the given values. 79 if (!any_rtp_decoded_) { 80 sequence_num_last_decoded_rtp_ = sequence_number; 81 timestamp_last_decoded_rtp_ = timestamp; 82 } 83 return; 84 } 85 86 if (sequence_number == sequence_num_last_received_rtp_) 87 return; 88 89 // Received RTP should not be in the list. 90 nack_list_.erase(sequence_number); 91 92 // If this is an old sequence number, no more action is required, return. 93 if (IsNewerSequenceNumber(sequence_num_last_received_rtp_, sequence_number)) 94 return; 95 96 UpdatePacketLossRate(sequence_number - sequence_num_last_received_rtp_ - 1); 97 98 UpdateList(sequence_number, timestamp); 99 100 sequence_num_last_received_rtp_ = sequence_number; 101 timestamp_last_received_rtp_ = timestamp; 102 LimitNackListSize(); 103 } 104 105 std::optional<int> NackTracker::GetSamplesPerPacket( 106 uint16_t sequence_number_current_received_rtp, 107 uint32_t timestamp_current_received_rtp) const { 108 uint32_t timestamp_increase = 109 timestamp_current_received_rtp - timestamp_last_received_rtp_; 110 uint16_t sequence_num_increase = 111 sequence_number_current_received_rtp - sequence_num_last_received_rtp_; 112 113 int samples_per_packet = timestamp_increase / sequence_num_increase; 114 if (samples_per_packet == 0 || 115 samples_per_packet > kMaxPacketSizeMs * sample_rate_khz_) { 116 // Not a valid samples per packet. 117 return std::nullopt; 118 } 119 return samples_per_packet; 120 } 121 122 void NackTracker::UpdateList(uint16_t sequence_number_current_received_rtp, 123 uint32_t timestamp_current_received_rtp) { 124 if (!IsNewerSequenceNumber(sequence_number_current_received_rtp, 125 sequence_num_last_received_rtp_ + 1)) { 126 return; 127 } 128 RTC_DCHECK(!any_rtp_decoded_ || 129 IsNewerSequenceNumber(sequence_number_current_received_rtp, 130 sequence_num_last_decoded_rtp_)); 131 132 std::optional<int> samples_per_packet = GetSamplesPerPacket( 133 sequence_number_current_received_rtp, timestamp_current_received_rtp); 134 if (!samples_per_packet) { 135 return; 136 } 137 138 for (uint16_t n = sequence_num_last_received_rtp_ + 1; 139 IsNewerSequenceNumber(sequence_number_current_received_rtp, n); ++n) { 140 uint32_t timestamp = EstimateTimestamp(n, *samples_per_packet); 141 NackElement nack_element(TimeToPlay(timestamp), timestamp); 142 nack_list_.insert(nack_list_.end(), std::make_pair(n, nack_element)); 143 } 144 } 145 146 uint32_t NackTracker::EstimateTimestamp(uint16_t sequence_num, 147 int samples_per_packet) { 148 uint16_t sequence_num_diff = sequence_num - sequence_num_last_received_rtp_; 149 return sequence_num_diff * samples_per_packet + timestamp_last_received_rtp_; 150 } 151 152 void NackTracker::UpdateLastDecodedPacket(uint16_t sequence_number, 153 uint32_t timestamp) { 154 any_rtp_decoded_ = true; 155 sequence_num_last_decoded_rtp_ = sequence_number; 156 timestamp_last_decoded_rtp_ = timestamp; 157 // Packets in the list with sequence numbers less than the 158 // sequence number of the decoded RTP should be removed from the lists. 159 // They will be discarded by the jitter buffer if they arrive. 160 nack_list_.erase(nack_list_.begin(), 161 nack_list_.upper_bound(sequence_num_last_decoded_rtp_)); 162 163 // Update estimated time-to-play. 164 for (NackList::iterator it = nack_list_.begin(); it != nack_list_.end(); 165 ++it) { 166 it->second.time_to_play_ms = TimeToPlay(it->second.estimated_timestamp); 167 } 168 } 169 170 NackTracker::NackList NackTracker::GetNackList() const { 171 return nack_list_; 172 } 173 174 void NackTracker::Reset() { 175 nack_list_.clear(); 176 177 sequence_num_last_received_rtp_ = 0; 178 timestamp_last_received_rtp_ = 0; 179 any_rtp_received_ = false; 180 sequence_num_last_decoded_rtp_ = 0; 181 timestamp_last_decoded_rtp_ = 0; 182 any_rtp_decoded_ = false; 183 sample_rate_khz_ = kDefaultSampleRateKhz; 184 } 185 186 void NackTracker::SetMaxNackListSize(size_t max_nack_list_size) { 187 RTC_CHECK_GT(max_nack_list_size, 0); 188 // Ugly hack to get around the problem of passing static consts by reference. 189 const size_t kNackListSizeLimitLocal = NackTracker::kNackListSizeLimit; 190 RTC_CHECK_LE(max_nack_list_size, kNackListSizeLimitLocal); 191 192 max_nack_list_size_ = max_nack_list_size; 193 LimitNackListSize(); 194 } 195 196 void NackTracker::LimitNackListSize() { 197 uint16_t limit = sequence_num_last_received_rtp_ - 198 static_cast<uint16_t>(max_nack_list_size_) - 1; 199 nack_list_.erase(nack_list_.begin(), nack_list_.upper_bound(limit)); 200 } 201 202 int64_t NackTracker::TimeToPlay(uint32_t timestamp) const { 203 uint32_t timestamp_increase = timestamp - timestamp_last_decoded_rtp_; 204 return timestamp_increase / sample_rate_khz_; 205 } 206 207 // We don't erase elements with time-to-play shorter than round-trip-time. 208 std::vector<uint16_t> NackTracker::GetNackList(int64_t round_trip_time_ms) { 209 RTC_DCHECK_GE(round_trip_time_ms, 0); 210 std::vector<uint16_t> sequence_numbers; 211 if (round_trip_time_ms == 0) { 212 if (config_.require_valid_rtt) { 213 return sequence_numbers; 214 } else { 215 round_trip_time_ms = config_.default_rtt_ms; 216 } 217 } 218 if (packet_loss_rate_ > 219 static_cast<uint32_t>(config_.max_loss_rate * (1 << 30))) { 220 return sequence_numbers; 221 } 222 // The estimated packet loss is between 0 and 1, so we need to multiply by 100 223 // here. 224 int max_wait_ms = 225 100.0 * config_.ms_per_loss_percent * packet_loss_rate_ / (1 << 30); 226 for (NackList::const_iterator it = nack_list_.begin(); it != nack_list_.end(); 227 ++it) { 228 int64_t time_since_packet_ms = 229 (timestamp_last_received_rtp_ - it->second.estimated_timestamp) / 230 sample_rate_khz_; 231 if (it->second.time_to_play_ms > round_trip_time_ms || 232 time_since_packet_ms + round_trip_time_ms < max_wait_ms) 233 sequence_numbers.push_back(it->first); 234 } 235 if (config_.never_nack_multiple_times) { 236 nack_list_.clear(); 237 } 238 return sequence_numbers; 239 } 240 241 void NackTracker::UpdatePacketLossRate(int packets_lost) { 242 const uint64_t alpha_q30 = (1 << 30) * config_.packet_loss_forget_factor; 243 // Exponential filter. 244 packet_loss_rate_ = (alpha_q30 * packet_loss_rate_) >> 30; 245 for (int i = 0; i < packets_lost; ++i) { 246 packet_loss_rate_ = 247 ((alpha_q30 * packet_loss_rate_) >> 30) + ((1 << 30) - alpha_q30); 248 } 249 } 250 } // namespace webrtc