blob: 9663c31d14fd77bea78d09a53dd397dc6074311d [file] [log] [blame]
Tommid3807da2020-05-22 17:36:36 +02001/*
2 * Copyright (c) 2016 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
Markus Handell06a2bf02021-07-22 15:09:39 +020011#include "modules/video_coding/nack_requester.h"
Tommid3807da2020-05-22 17:36:36 +020012
13#include <algorithm>
14#include <limits>
15
Markus Handell0e62f7a2021-07-20 13:32:02 +020016#include "api/sequence_checker.h"
17#include "api/task_queue/task_queue_base.h"
Tommid3807da2020-05-22 17:36:36 +020018#include "api/units/timestamp.h"
Tommid3807da2020-05-22 17:36:36 +020019#include "rtc_base/checks.h"
20#include "rtc_base/experiments/field_trial_parser.h"
21#include "rtc_base/logging.h"
Tommi63673fe2020-05-27 12:55:38 +020022#include "rtc_base/task_queue.h"
Tommid3807da2020-05-22 17:36:36 +020023
24namespace webrtc {
25
26namespace {
Erik Språng609aef32022-07-01 16:46:56 +020027constexpr int kMaxPacketAge = 10'000;
28constexpr int kMaxNackPackets = 1000;
29constexpr TimeDelta kDefaultRtt = TimeDelta::Millis(100);
30constexpr int kMaxNackRetries = 10;
31constexpr int kMaxReorderedPackets = 128;
32constexpr int kNumReorderingBuckets = 10;
33constexpr TimeDelta kDefaultSendNackDelay = TimeDelta::Zero();
Tommid3807da2020-05-22 17:36:36 +020034
Erik Språng609aef32022-07-01 16:46:56 +020035TimeDelta GetSendNackDelay(const FieldTrialsView& field_trials) {
Tommid3807da2020-05-22 17:36:36 +020036 int64_t delay_ms = strtol(
Jonas Orelande02f9ee2022-03-25 12:43:14 +010037 field_trials.Lookup("WebRTC-SendNackDelayMs").c_str(), nullptr, 10);
Tommid3807da2020-05-22 17:36:36 +020038 if (delay_ms > 0 && delay_ms <= 20) {
39 RTC_LOG(LS_INFO) << "SendNackDelay is set to " << delay_ms;
Erik Språng609aef32022-07-01 16:46:56 +020040 return TimeDelta::Millis(delay_ms);
Tommid3807da2020-05-22 17:36:36 +020041 }
Erik Språng609aef32022-07-01 16:46:56 +020042 return kDefaultSendNackDelay;
Tommid3807da2020-05-22 17:36:36 +020043}
44} // namespace
45
Markus Handell0e62f7a2021-07-20 13:32:02 +020046constexpr TimeDelta NackPeriodicProcessor::kUpdateInterval;
47
48NackPeriodicProcessor::NackPeriodicProcessor(TimeDelta update_interval)
49 : update_interval_(update_interval) {}
50
51NackPeriodicProcessor::~NackPeriodicProcessor() {}
52
Markus Handell06a2bf02021-07-22 15:09:39 +020053void NackPeriodicProcessor::RegisterNackModule(NackRequesterBase* module) {
Markus Handell0e62f7a2021-07-20 13:32:02 +020054 RTC_DCHECK_RUN_ON(&sequence_);
55 modules_.push_back(module);
56 if (modules_.size() != 1)
57 return;
58 repeating_task_ = RepeatingTaskHandle::DelayedStart(
59 TaskQueueBase::Current(), update_interval_, [this] {
60 RTC_DCHECK_RUN_ON(&sequence_);
61 ProcessNackModules();
62 return update_interval_;
63 });
64}
65
Markus Handell06a2bf02021-07-22 15:09:39 +020066void NackPeriodicProcessor::UnregisterNackModule(NackRequesterBase* module) {
Markus Handell0e62f7a2021-07-20 13:32:02 +020067 RTC_DCHECK_RUN_ON(&sequence_);
68 auto it = std::find(modules_.begin(), modules_.end(), module);
69 RTC_DCHECK(it != modules_.end());
70 modules_.erase(it);
71 if (modules_.empty())
72 repeating_task_.Stop();
73}
74
75// RTC_RUN_ON(sequence_)
76void NackPeriodicProcessor::ProcessNackModules() {
Markus Handell06a2bf02021-07-22 15:09:39 +020077 for (NackRequesterBase* module : modules_)
Markus Handell0e62f7a2021-07-20 13:32:02 +020078 module->ProcessNacks();
79}
80
81ScopedNackPeriodicProcessorRegistration::
Markus Handell06a2bf02021-07-22 15:09:39 +020082 ScopedNackPeriodicProcessorRegistration(NackRequesterBase* module,
Markus Handell0e62f7a2021-07-20 13:32:02 +020083 NackPeriodicProcessor* processor)
84 : module_(module), processor_(processor) {
85 processor_->RegisterNackModule(module_);
86}
87
88ScopedNackPeriodicProcessorRegistration::
89 ~ScopedNackPeriodicProcessorRegistration() {
90 processor_->UnregisterNackModule(module_);
91}
Tommi63673fe2020-05-27 12:55:38 +020092
Markus Handell06a2bf02021-07-22 15:09:39 +020093NackRequester::NackInfo::NackInfo()
Erik Språng609aef32022-07-01 16:46:56 +020094 : seq_num(0),
95 send_at_seq_num(0),
96 created_at_time(Timestamp::MinusInfinity()),
97 sent_at_time(Timestamp::MinusInfinity()),
98 retries(0) {}
Tommid3807da2020-05-22 17:36:36 +020099
Markus Handell06a2bf02021-07-22 15:09:39 +0200100NackRequester::NackInfo::NackInfo(uint16_t seq_num,
101 uint16_t send_at_seq_num,
Erik Språng609aef32022-07-01 16:46:56 +0200102 Timestamp created_at_time)
Tommid3807da2020-05-22 17:36:36 +0200103 : seq_num(seq_num),
104 send_at_seq_num(send_at_seq_num),
105 created_at_time(created_at_time),
Erik Språng609aef32022-07-01 16:46:56 +0200106 sent_at_time(Timestamp::MinusInfinity()),
Tommid3807da2020-05-22 17:36:36 +0200107 retries(0) {}
108
Markus Handell06a2bf02021-07-22 15:09:39 +0200109NackRequester::NackRequester(TaskQueueBase* current_queue,
110 NackPeriodicProcessor* periodic_processor,
111 Clock* clock,
112 NackSender* nack_sender,
Jonas Orelande02f9ee2022-03-25 12:43:14 +0100113 KeyFrameRequestSender* keyframe_request_sender,
Jonas Orelande62c2f22022-03-29 11:04:48 +0200114 const FieldTrialsView& field_trials)
Tommi63673fe2020-05-27 12:55:38 +0200115 : worker_thread_(current_queue),
Tommi63673fe2020-05-27 12:55:38 +0200116 clock_(clock),
Tommid3807da2020-05-22 17:36:36 +0200117 nack_sender_(nack_sender),
118 keyframe_request_sender_(keyframe_request_sender),
119 reordering_histogram_(kNumReorderingBuckets, kMaxReorderedPackets),
120 initialized_(false),
Erik Språng609aef32022-07-01 16:46:56 +0200121 rtt_(kDefaultRtt),
Tommid3807da2020-05-22 17:36:36 +0200122 newest_seq_num_(0),
Erik Språng609aef32022-07-01 16:46:56 +0200123 send_nack_delay_(GetSendNackDelay(field_trials)),
Markus Handell0e62f7a2021-07-20 13:32:02 +0200124 processor_registration_(this, periodic_processor) {
Tommid3807da2020-05-22 17:36:36 +0200125 RTC_DCHECK(clock_);
126 RTC_DCHECK(nack_sender_);
127 RTC_DCHECK(keyframe_request_sender_);
Tommi63673fe2020-05-27 12:55:38 +0200128 RTC_DCHECK(worker_thread_);
129 RTC_DCHECK(worker_thread_->IsCurrent());
Tommi63673fe2020-05-27 12:55:38 +0200130}
131
Markus Handell06a2bf02021-07-22 15:09:39 +0200132NackRequester::~NackRequester() {
Tommi63673fe2020-05-27 12:55:38 +0200133 RTC_DCHECK_RUN_ON(worker_thread_);
Markus Handell0e62f7a2021-07-20 13:32:02 +0200134}
135
Markus Handell06a2bf02021-07-22 15:09:39 +0200136void NackRequester::ProcessNacks() {
Markus Handell0e62f7a2021-07-20 13:32:02 +0200137 RTC_DCHECK_RUN_ON(worker_thread_);
138 std::vector<uint16_t> nack_batch = GetNackBatch(kTimeOnly);
139 if (!nack_batch.empty()) {
140 // This batch of NACKs is triggered externally; there is no external
141 // initiator who can batch them with other feedback messages.
142 nack_sender_->SendNack(nack_batch, /*buffering_allowed=*/false);
143 }
Tommid3807da2020-05-22 17:36:36 +0200144}
145
Markus Handell06a2bf02021-07-22 15:09:39 +0200146int NackRequester::OnReceivedPacket(uint16_t seq_num, bool is_keyframe) {
Tommi63673fe2020-05-27 12:55:38 +0200147 RTC_DCHECK_RUN_ON(worker_thread_);
Tommid3807da2020-05-22 17:36:36 +0200148 return OnReceivedPacket(seq_num, is_keyframe, false);
149}
150
Markus Handell06a2bf02021-07-22 15:09:39 +0200151int NackRequester::OnReceivedPacket(uint16_t seq_num,
152 bool is_keyframe,
153 bool is_recovered) {
Tommi63673fe2020-05-27 12:55:38 +0200154 RTC_DCHECK_RUN_ON(worker_thread_);
Tommid3807da2020-05-22 17:36:36 +0200155 // TODO(philipel): When the packet includes information whether it is
156 // retransmitted or not, use that value instead. For
157 // now set it to true, which will cause the reordering
158 // statistics to never be updated.
159 bool is_retransmitted = true;
160
161 if (!initialized_) {
162 newest_seq_num_ = seq_num;
163 if (is_keyframe)
164 keyframe_list_.insert(seq_num);
165 initialized_ = true;
166 return 0;
167 }
168
Artem Titovdcd7fc72021-08-09 13:02:57 +0200169 // Since the `newest_seq_num_` is a packet we have actually received we know
Tommid3807da2020-05-22 17:36:36 +0200170 // that packet has never been Nacked.
171 if (seq_num == newest_seq_num_)
172 return 0;
173
174 if (AheadOf(newest_seq_num_, seq_num)) {
175 // An out of order packet has been received.
176 auto nack_list_it = nack_list_.find(seq_num);
177 int nacks_sent_for_packet = 0;
178 if (nack_list_it != nack_list_.end()) {
179 nacks_sent_for_packet = nack_list_it->second.retries;
180 nack_list_.erase(nack_list_it);
181 }
182 if (!is_retransmitted)
183 UpdateReorderingStatistics(seq_num);
184 return nacks_sent_for_packet;
185 }
186
187 // Keep track of new keyframes.
188 if (is_keyframe)
189 keyframe_list_.insert(seq_num);
190
191 // And remove old ones so we don't accumulate keyframes.
192 auto it = keyframe_list_.lower_bound(seq_num - kMaxPacketAge);
193 if (it != keyframe_list_.begin())
194 keyframe_list_.erase(keyframe_list_.begin(), it);
195
196 if (is_recovered) {
197 recovered_list_.insert(seq_num);
198
199 // Remove old ones so we don't accumulate recovered packets.
200 auto it = recovered_list_.lower_bound(seq_num - kMaxPacketAge);
201 if (it != recovered_list_.begin())
202 recovered_list_.erase(recovered_list_.begin(), it);
203
204 // Do not send nack for packets recovered by FEC or RTX.
205 return 0;
206 }
207
208 AddPacketsToNack(newest_seq_num_ + 1, seq_num);
209 newest_seq_num_ = seq_num;
210
211 // Are there any nacks that are waiting for this seq_num.
212 std::vector<uint16_t> nack_batch = GetNackBatch(kSeqNumOnly);
213 if (!nack_batch.empty()) {
214 // This batch of NACKs is triggered externally; the initiator can
215 // batch them with other feedback messages.
216 nack_sender_->SendNack(nack_batch, /*buffering_allowed=*/true);
217 }
218
219 return 0;
220}
221
Markus Handell06a2bf02021-07-22 15:09:39 +0200222void NackRequester::ClearUpTo(uint16_t seq_num) {
Tommi63673fe2020-05-27 12:55:38 +0200223 // Called via RtpVideoStreamReceiver2::FrameContinuous on the network thread.
224 worker_thread_->PostTask(ToQueuedTask(task_safety_, [seq_num, this]() {
225 RTC_DCHECK_RUN_ON(worker_thread_);
226 nack_list_.erase(nack_list_.begin(), nack_list_.lower_bound(seq_num));
227 keyframe_list_.erase(keyframe_list_.begin(),
228 keyframe_list_.lower_bound(seq_num));
229 recovered_list_.erase(recovered_list_.begin(),
230 recovered_list_.lower_bound(seq_num));
231 }));
Tommid3807da2020-05-22 17:36:36 +0200232}
233
Markus Handell06a2bf02021-07-22 15:09:39 +0200234void NackRequester::UpdateRtt(int64_t rtt_ms) {
Tommi63673fe2020-05-27 12:55:38 +0200235 RTC_DCHECK_RUN_ON(worker_thread_);
Erik Språng609aef32022-07-01 16:46:56 +0200236 rtt_ = TimeDelta::Millis(rtt_ms);
Tommid3807da2020-05-22 17:36:36 +0200237}
238
Markus Handell06a2bf02021-07-22 15:09:39 +0200239bool NackRequester::RemovePacketsUntilKeyFrame() {
Tommi63673fe2020-05-27 12:55:38 +0200240 // Called on worker_thread_.
Tommid3807da2020-05-22 17:36:36 +0200241 while (!keyframe_list_.empty()) {
242 auto it = nack_list_.lower_bound(*keyframe_list_.begin());
243
244 if (it != nack_list_.begin()) {
245 // We have found a keyframe that actually is newer than at least one
246 // packet in the nack list.
247 nack_list_.erase(nack_list_.begin(), it);
248 return true;
249 }
250
251 // If this keyframe is so old it does not remove any packets from the list,
252 // remove it from the list of keyframes and try the next keyframe.
253 keyframe_list_.erase(keyframe_list_.begin());
254 }
255 return false;
256}
257
Markus Handell06a2bf02021-07-22 15:09:39 +0200258void NackRequester::AddPacketsToNack(uint16_t seq_num_start,
259 uint16_t seq_num_end) {
Tommi63673fe2020-05-27 12:55:38 +0200260 // Called on worker_thread_.
Tommid3807da2020-05-22 17:36:36 +0200261 // Remove old packets.
262 auto it = nack_list_.lower_bound(seq_num_end - kMaxPacketAge);
263 nack_list_.erase(nack_list_.begin(), it);
264
265 // If the nack list is too large, remove packets from the nack list until
266 // the latest first packet of a keyframe. If the list is still too large,
267 // clear it and request a keyframe.
268 uint16_t num_new_nacks = ForwardDiff(seq_num_start, seq_num_end);
269 if (nack_list_.size() + num_new_nacks > kMaxNackPackets) {
270 while (RemovePacketsUntilKeyFrame() &&
271 nack_list_.size() + num_new_nacks > kMaxNackPackets) {
272 }
273
274 if (nack_list_.size() + num_new_nacks > kMaxNackPackets) {
275 nack_list_.clear();
276 RTC_LOG(LS_WARNING) << "NACK list full, clearing NACK"
277 " list and requesting keyframe.";
278 keyframe_request_sender_->RequestKeyFrame();
279 return;
280 }
281 }
282
283 for (uint16_t seq_num = seq_num_start; seq_num != seq_num_end; ++seq_num) {
284 // Do not send nack for packets that are already recovered by FEC or RTX
285 if (recovered_list_.find(seq_num) != recovered_list_.end())
286 continue;
287 NackInfo nack_info(seq_num, seq_num + WaitNumberOfPackets(0.5),
Erik Språng609aef32022-07-01 16:46:56 +0200288 clock_->CurrentTime());
Tommid3807da2020-05-22 17:36:36 +0200289 RTC_DCHECK(nack_list_.find(seq_num) == nack_list_.end());
290 nack_list_[seq_num] = nack_info;
291 }
292}
293
Markus Handell06a2bf02021-07-22 15:09:39 +0200294std::vector<uint16_t> NackRequester::GetNackBatch(NackFilterOptions options) {
Tommi63673fe2020-05-27 12:55:38 +0200295 // Called on worker_thread_.
296
Tommid3807da2020-05-22 17:36:36 +0200297 bool consider_seq_num = options != kTimeOnly;
298 bool consider_timestamp = options != kSeqNumOnly;
299 Timestamp now = clock_->CurrentTime();
300 std::vector<uint16_t> nack_batch;
301 auto it = nack_list_.begin();
302 while (it != nack_list_.end()) {
Erik Språng609aef32022-07-01 16:46:56 +0200303 bool delay_timed_out = now - it->second.created_at_time >= send_nack_delay_;
304 bool nack_on_rtt_passed = now - it->second.sent_at_time >= rtt_;
Tommid3807da2020-05-22 17:36:36 +0200305 bool nack_on_seq_num_passed =
Erik Språng609aef32022-07-01 16:46:56 +0200306 it->second.sent_at_time.IsInfinite() &&
Tommid3807da2020-05-22 17:36:36 +0200307 AheadOrAt(newest_seq_num_, it->second.send_at_seq_num);
308 if (delay_timed_out && ((consider_seq_num && nack_on_seq_num_passed) ||
309 (consider_timestamp && nack_on_rtt_passed))) {
310 nack_batch.emplace_back(it->second.seq_num);
311 ++it->second.retries;
Erik Språng609aef32022-07-01 16:46:56 +0200312 it->second.sent_at_time = now;
Tommid3807da2020-05-22 17:36:36 +0200313 if (it->second.retries >= kMaxNackRetries) {
314 RTC_LOG(LS_WARNING) << "Sequence number " << it->second.seq_num
315 << " removed from NACK list due to max retries.";
316 it = nack_list_.erase(it);
317 } else {
318 ++it;
319 }
320 continue;
321 }
322 ++it;
323 }
324 return nack_batch;
325}
326
Markus Handell06a2bf02021-07-22 15:09:39 +0200327void NackRequester::UpdateReorderingStatistics(uint16_t seq_num) {
Tommi63673fe2020-05-27 12:55:38 +0200328 // Running on worker_thread_.
Tommid3807da2020-05-22 17:36:36 +0200329 RTC_DCHECK(AheadOf(newest_seq_num_, seq_num));
330 uint16_t diff = ReverseDiff(newest_seq_num_, seq_num);
331 reordering_histogram_.Add(diff);
332}
333
Markus Handell06a2bf02021-07-22 15:09:39 +0200334int NackRequester::WaitNumberOfPackets(float probability) const {
Tommi63673fe2020-05-27 12:55:38 +0200335 // Called on worker_thread_;
Tommid3807da2020-05-22 17:36:36 +0200336 if (reordering_histogram_.NumValues() == 0)
337 return 0;
338 return reordering_histogram_.InverseCdf(probability);
339}
340
341} // namespace webrtc