blob: 04cc5b52e8f085503e84e0dae126677436a9235c [file] [log] [blame]
turaj@webrtc.org7959e162013-09-12 18:30:26 +00001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_coding/neteq/nack_tracker.h"
turaj@webrtc.org7959e162013-09-12 18:30:26 +000012
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <cstdint>
14#include <utility>
turaj@webrtc.org7959e162013-09-12 18:30:26 +000015
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/checks.h"
Ivo Creusen3a9640a2021-09-10 11:45:47 +000017#include "rtc_base/experiments/struct_parameters_parser.h"
18#include "rtc_base/logging.h"
19#include "system_wrappers/include/field_trial.h"
turaj@webrtc.org7959e162013-09-12 18:30:26 +000020
21namespace webrtc {
turaj@webrtc.org7959e162013-09-12 18:30:26 +000022namespace {
23
24const int kDefaultSampleRateKhz = 48;
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +020025const int kMaxPacketSizeMs = 120;
Ivo Creusen3a9640a2021-09-10 11:45:47 +000026constexpr char kNackTrackerConfigFieldTrial[] =
27 "WebRTC-Audio-NetEqNackTrackerConfig";
turaj@webrtc.org7959e162013-09-12 18:30:26 +000028
29} // namespace
30
Ivo Creusen3a9640a2021-09-10 11:45:47 +000031NackTracker::Config::Config() {
32 auto parser = StructParametersParser::Create(
33 "packet_loss_forget_factor", &packet_loss_forget_factor,
34 "ms_per_loss_percent", &ms_per_loss_percent, "never_nack_multiple_times",
Jakob Ivarssone1bbef12021-11-25 15:34:57 +010035 &never_nack_multiple_times, "require_valid_rtt", &require_valid_rtt,
36 "max_loss_rate", &max_loss_rate);
Ivo Creusen3a9640a2021-09-10 11:45:47 +000037 parser->Parse(
38 webrtc::field_trial::FindFullName(kNackTrackerConfigFieldTrial));
39 RTC_LOG(LS_INFO) << "Nack tracker config:"
40 " packet_loss_forget_factor="
41 << packet_loss_forget_factor
42 << " ms_per_loss_percent=" << ms_per_loss_percent
Jakob Ivarssone1bbef12021-11-25 15:34:57 +010043 << " never_nack_multiple_times=" << never_nack_multiple_times
44 << " require_valid_rtt=" << require_valid_rtt
45 << " max_loss_rate=" << max_loss_rate;
Ivo Creusen3a9640a2021-09-10 11:45:47 +000046}
47
Ivo Creusenbc503c92021-09-14 15:17:23 +000048NackTracker::NackTracker()
49 : sequence_num_last_received_rtp_(0),
turaj@webrtc.org7959e162013-09-12 18:30:26 +000050 timestamp_last_received_rtp_(0),
51 any_rtp_received_(false),
52 sequence_num_last_decoded_rtp_(0),
53 timestamp_last_decoded_rtp_(0),
54 any_rtp_decoded_(false),
55 sample_rate_khz_(kDefaultSampleRateKhz),
turaj@webrtc.org7959e162013-09-12 18:30:26 +000056 max_nack_list_size_(kNackListSizeLimit) {}
57
henrik.lundin91951862016-06-08 06:43:41 -070058NackTracker::~NackTracker() = default;
Karl Wiberg2519c452015-04-07 16:12:57 +020059
henrik.lundin91951862016-06-08 06:43:41 -070060void NackTracker::UpdateSampleRate(int sample_rate_hz) {
Mirko Bonadei25ab3222021-07-08 20:08:20 +020061 RTC_DCHECK_GT(sample_rate_hz, 0);
turaj@webrtc.org7959e162013-09-12 18:30:26 +000062 sample_rate_khz_ = sample_rate_hz / 1000;
63}
64
henrik.lundin91951862016-06-08 06:43:41 -070065void NackTracker::UpdateLastReceivedPacket(uint16_t sequence_number,
66 uint32_t timestamp) {
turaj@webrtc.org7959e162013-09-12 18:30:26 +000067 // Just record the value of sequence number and timestamp if this is the
68 // first packet.
69 if (!any_rtp_received_) {
70 sequence_num_last_received_rtp_ = sequence_number;
71 timestamp_last_received_rtp_ = timestamp;
72 any_rtp_received_ = true;
73 // If no packet is decoded, to have a reasonable estimate of time-to-play
74 // use the given values.
75 if (!any_rtp_decoded_) {
76 sequence_num_last_decoded_rtp_ = sequence_number;
77 timestamp_last_decoded_rtp_ = timestamp;
78 }
79 return;
80 }
81
82 if (sequence_number == sequence_num_last_received_rtp_)
83 return;
84
85 // Received RTP should not be in the list.
86 nack_list_.erase(sequence_number);
87
88 // If this is an old sequence number, no more action is required, return.
89 if (IsNewerSequenceNumber(sequence_num_last_received_rtp_, sequence_number))
90 return;
91
Ivo Creusen3a9640a2021-09-10 11:45:47 +000092 UpdatePacketLossRate(sequence_number - sequence_num_last_received_rtp_ - 1);
93
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +020094 UpdateList(sequence_number, timestamp);
turaj@webrtc.org7959e162013-09-12 18:30:26 +000095
96 sequence_num_last_received_rtp_ = sequence_number;
97 timestamp_last_received_rtp_ = timestamp;
98 LimitNackListSize();
99}
100
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200101absl::optional<int> NackTracker::GetSamplesPerPacket(
henrik.lundin91951862016-06-08 06:43:41 -0700102 uint16_t sequence_number_current_received_rtp,
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200103 uint32_t timestamp_current_received_rtp) const {
henrik.lundin48ed9302015-10-29 05:36:24 -0700104 uint32_t timestamp_increase =
105 timestamp_current_received_rtp - timestamp_last_received_rtp_;
106 uint16_t sequence_num_increase =
107 sequence_number_current_received_rtp - sequence_num_last_received_rtp_;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000108
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200109 int samples_per_packet = timestamp_increase / sequence_num_increase;
110 if (samples_per_packet == 0 ||
111 samples_per_packet > kMaxPacketSizeMs * sample_rate_khz_) {
112 // Not a valid samples per packet.
113 return absl::nullopt;
114 }
115 return samples_per_packet;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000116}
117
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200118void NackTracker::UpdateList(uint16_t sequence_number_current_received_rtp,
119 uint32_t timestamp_current_received_rtp) {
Ivo Creusenbc503c92021-09-14 15:17:23 +0000120 if (!IsNewerSequenceNumber(sequence_number_current_received_rtp,
121 sequence_num_last_received_rtp_ + 1)) {
122 return;
123 }
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200124 RTC_DCHECK(!any_rtp_decoded_ ||
125 IsNewerSequenceNumber(sequence_number_current_received_rtp,
126 sequence_num_last_decoded_rtp_));
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000127
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200128 absl::optional<int> samples_per_packet = GetSamplesPerPacket(
129 sequence_number_current_received_rtp, timestamp_current_received_rtp);
130 if (!samples_per_packet) {
131 return;
132 }
133
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000134 for (uint16_t n = sequence_num_last_received_rtp_ + 1;
henrik.lundin48ed9302015-10-29 05:36:24 -0700135 IsNewerSequenceNumber(sequence_number_current_received_rtp, n); ++n) {
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200136 uint32_t timestamp = EstimateTimestamp(n, *samples_per_packet);
Ivo Creusenbc503c92021-09-14 15:17:23 +0000137 NackElement nack_element(TimeToPlay(timestamp), timestamp);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000138 nack_list_.insert(nack_list_.end(), std::make_pair(n, nack_element));
139 }
140}
141
Ivo Creusenbc503c92021-09-14 15:17:23 +0000142uint32_t NackTracker::EstimateTimestamp(uint16_t sequence_num,
143 int samples_per_packet) {
144 uint16_t sequence_num_diff = sequence_num - sequence_num_last_received_rtp_;
145 return sequence_num_diff * samples_per_packet + timestamp_last_received_rtp_;
146}
147
henrik.lundin91951862016-06-08 06:43:41 -0700148void NackTracker::UpdateEstimatedPlayoutTimeBy10ms() {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000149 while (!nack_list_.empty() &&
henrik.lundin48ed9302015-10-29 05:36:24 -0700150 nack_list_.begin()->second.time_to_play_ms <= 10)
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000151 nack_list_.erase(nack_list_.begin());
152
153 for (NackList::iterator it = nack_list_.begin(); it != nack_list_.end(); ++it)
154 it->second.time_to_play_ms -= 10;
155}
156
henrik.lundin91951862016-06-08 06:43:41 -0700157void NackTracker::UpdateLastDecodedPacket(uint16_t sequence_number,
158 uint32_t timestamp) {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000159 if (IsNewerSequenceNumber(sequence_number, sequence_num_last_decoded_rtp_) ||
160 !any_rtp_decoded_) {
161 sequence_num_last_decoded_rtp_ = sequence_number;
162 timestamp_last_decoded_rtp_ = timestamp;
163 // Packets in the list with sequence numbers less than the
164 // sequence number of the decoded RTP should be removed from the lists.
165 // They will be discarded by the jitter buffer if they arrive.
henrik.lundin48ed9302015-10-29 05:36:24 -0700166 nack_list_.erase(nack_list_.begin(),
167 nack_list_.upper_bound(sequence_num_last_decoded_rtp_));
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000168
169 // Update estimated time-to-play.
170 for (NackList::iterator it = nack_list_.begin(); it != nack_list_.end();
henrik.lundin48ed9302015-10-29 05:36:24 -0700171 ++it)
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000172 it->second.time_to_play_ms = TimeToPlay(it->second.estimated_timestamp);
173 } else {
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200174 RTC_DCHECK_EQ(sequence_number, sequence_num_last_decoded_rtp_);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000175
176 // Same sequence number as before. 10 ms is elapsed, update estimations for
177 // time-to-play.
178 UpdateEstimatedPlayoutTimeBy10ms();
179
180 // Update timestamp for better estimate of time-to-play, for packets which
181 // are added to NACK list later on.
182 timestamp_last_decoded_rtp_ += sample_rate_khz_ * 10;
183 }
184 any_rtp_decoded_ = true;
185}
186
henrik.lundin91951862016-06-08 06:43:41 -0700187NackTracker::NackList NackTracker::GetNackList() const {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000188 return nack_list_;
189}
190
henrik.lundin91951862016-06-08 06:43:41 -0700191void NackTracker::Reset() {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000192 nack_list_.clear();
193
194 sequence_num_last_received_rtp_ = 0;
195 timestamp_last_received_rtp_ = 0;
196 any_rtp_received_ = false;
197 sequence_num_last_decoded_rtp_ = 0;
198 timestamp_last_decoded_rtp_ = 0;
199 any_rtp_decoded_ = false;
200 sample_rate_khz_ = kDefaultSampleRateKhz;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000201}
202
henrik.lundin91951862016-06-08 06:43:41 -0700203void NackTracker::SetMaxNackListSize(size_t max_nack_list_size) {
kwibergaf476c72016-11-28 15:21:39 -0800204 RTC_CHECK_GT(max_nack_list_size, 0);
henrik.lundin48ed9302015-10-29 05:36:24 -0700205 // Ugly hack to get around the problem of passing static consts by reference.
henrik.lundin91951862016-06-08 06:43:41 -0700206 const size_t kNackListSizeLimitLocal = NackTracker::kNackListSizeLimit;
henrik.lundin48ed9302015-10-29 05:36:24 -0700207 RTC_CHECK_LE(max_nack_list_size, kNackListSizeLimitLocal);
208
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000209 max_nack_list_size_ = max_nack_list_size;
210 LimitNackListSize();
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000211}
212
henrik.lundin91951862016-06-08 06:43:41 -0700213void NackTracker::LimitNackListSize() {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000214 uint16_t limit = sequence_num_last_received_rtp_ -
henrik.lundin48ed9302015-10-29 05:36:24 -0700215 static_cast<uint16_t>(max_nack_list_size_) - 1;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000216 nack_list_.erase(nack_list_.begin(), nack_list_.upper_bound(limit));
217}
218
henrik.lundin91951862016-06-08 06:43:41 -0700219int64_t NackTracker::TimeToPlay(uint32_t timestamp) const {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000220 uint32_t timestamp_increase = timestamp - timestamp_last_decoded_rtp_;
221 return timestamp_increase / sample_rate_khz_;
222}
223
224// We don't erase elements with time-to-play shorter than round-trip-time.
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000225std::vector<uint16_t> NackTracker::GetNackList(int64_t round_trip_time_ms) {
henrik.lundin48ed9302015-10-29 05:36:24 -0700226 RTC_DCHECK_GE(round_trip_time_ms, 0);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000227 std::vector<uint16_t> sequence_numbers;
Jakob Ivarsson4d5eb652022-03-30 16:26:19 +0200228 if (round_trip_time_ms == 0) {
229 if (config_.require_valid_rtt) {
230 return sequence_numbers;
231 } else {
232 round_trip_time_ms = config_.default_rtt_ms;
233 }
Jakob Ivarssone1bbef12021-11-25 15:34:57 +0100234 }
235 if (packet_loss_rate_ >
236 static_cast<uint32_t>(config_.max_loss_rate * (1 << 30))) {
237 return sequence_numbers;
238 }
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000239 // The estimated packet loss is between 0 and 1, so we need to multiply by 100
240 // here.
241 int max_wait_ms =
242 100.0 * config_.ms_per_loss_percent * packet_loss_rate_ / (1 << 30);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000243 for (NackList::const_iterator it = nack_list_.begin(); it != nack_list_.end();
henrik.lundin48ed9302015-10-29 05:36:24 -0700244 ++it) {
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000245 int64_t time_since_packet_ms =
246 (timestamp_last_received_rtp_ - it->second.estimated_timestamp) /
247 sample_rate_khz_;
Ivo Creusenbc503c92021-09-14 15:17:23 +0000248 if (it->second.time_to_play_ms > round_trip_time_ms ||
249 time_since_packet_ms + round_trip_time_ms < max_wait_ms)
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000250 sequence_numbers.push_back(it->first);
251 }
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000252 if (config_.never_nack_multiple_times) {
253 nack_list_.clear();
254 }
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000255 return sequence_numbers;
256}
257
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000258void NackTracker::UpdatePacketLossRate(int packets_lost) {
259 const uint64_t alpha_q30 = (1 << 30) * config_.packet_loss_forget_factor;
260 // Exponential filter.
261 packet_loss_rate_ = (alpha_q30 * packet_loss_rate_) >> 30;
262 for (int i = 0; i < packets_lost; ++i) {
263 packet_loss_rate_ =
264 ((alpha_q30 * packet_loss_rate_) >> 30) + ((1 << 30) - alpha_q30);
265 }
266}
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000267} // namespace webrtc