blob: 3951cf024580fcd02a7f04d2f9f3c669fc6ac2b1 [file] [log] [blame]
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +00001/*
2 * Copyright (c) 2012 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/pacing/paced_sender.h"
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000012
jbauchd2a22962016-02-08 23:18:25 -080013#include <algorithm>
Sebastian Jansson916ae082018-10-26 13:10:23 +020014#include <utility>
Erik Språngf6468d22019-07-05 16:53:43 +020015#include <vector>
pbos@webrtc.org03c817e2014-07-07 10:20:35 +000016
Karl Wiberg918f50c2018-07-05 11:40:33 +020017#include "absl/memory/memory.h"
Danil Chapovalov83bbe912019-08-07 12:24:53 +020018#include "api/rtc_event_log/rtc_event_log.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/pacing/bitrate_prober.h"
20#include "modules/pacing/interval_budget.h"
21#include "modules/utility/include/process_thread.h"
22#include "rtc_base/checks.h"
23#include "rtc_base/logging.h"
Erik Språng425d6aa2019-07-29 16:38:27 +020024#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "system_wrappers/include/clock.h"
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000026
Per Kjellander7ef34f82019-02-22 13:09:32 +010027namespace webrtc {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000028namespace {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000029// Time limit in milliseconds between packet bursts.
Christoffer Rodbroe2e00002018-12-20 15:46:03 +010030const int64_t kDefaultMinPacketLimitMs = 5;
Sebastian Jansson45d9c1d2018-03-09 12:48:01 +010031const int64_t kCongestedPacketIntervalMs = 500;
32const int64_t kPausedProcessIntervalMs = kCongestedPacketIntervalMs;
Sebastian Janssone5d8c572018-02-28 08:53:06 +010033const int64_t kMaxElapsedTimeMs = 2000;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000034
35// Upper cap on process interval, in case process has not been called in a long
36// time.
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +000037const int64_t kMaxIntervalTimeMs = 30;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000038
Per Kjellander7ef34f82019-02-22 13:09:32 +010039bool IsDisabled(const WebRtcKeyValueConfig& field_trials,
40 absl::string_view key) {
41 return field_trials.Lookup(key).find("Disabled") == 0;
42}
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000043
Per Kjellander7ef34f82019-02-22 13:09:32 +010044bool IsEnabled(const WebRtcKeyValueConfig& field_trials,
45 absl::string_view key) {
46 return field_trials.Lookup(key).find("Enabled") == 0;
47}
48
Erik Språng58ee1872019-06-18 16:20:11 +020049int GetPriorityForType(RtpPacketToSend::Type type) {
50 switch (type) {
51 case RtpPacketToSend::Type::kAudio:
52 // Audio is always prioritized over other packet types.
53 return 0;
54 case RtpPacketToSend::Type::kRetransmission:
55 // Send retransmissions before new media.
56 return 1;
57 case RtpPacketToSend::Type::kVideo:
58 // Video has "normal" priority, in the old speak.
59 return 2;
60 case RtpPacketToSend::Type::kForwardErrorCorrection:
Erik Språng97b6c752019-07-25 09:16:34 +020061 // Send redundancy concurrently to video. If it is delayed it might have a
62 // lower chance of being useful.
63 return 2;
Erik Språng58ee1872019-06-18 16:20:11 +020064 case RtpPacketToSend::Type::kPadding:
65 // Packets that are in themselves likely useless, only sent to keep the
66 // BWE high.
Erik Språng97b6c752019-07-25 09:16:34 +020067 return 3;
Erik Språng58ee1872019-06-18 16:20:11 +020068 }
69}
70
Per Kjellander7ef34f82019-02-22 13:09:32 +010071} // namespace
sprang0a43fef2015-11-20 09:00:37 -080072const int64_t PacedSender::kMaxQueueLengthMs = 2000;
Sebastian Janssonea86bb72018-02-14 16:53:38 +000073const float PacedSender::kDefaultPaceMultiplier = 2.5f;
stefan@webrtc.org88e0dda2014-07-04 09:20:42 +000074
Sebastian Janssonaa01f272019-01-30 11:28:59 +010075PacedSender::PacedSender(Clock* clock,
Erik Språnge7942432019-06-12 13:30:02 +020076 PacketRouter* packet_router,
Per Kjellander7ef34f82019-02-22 13:09:32 +010077 RtcEventLog* event_log,
78 const WebRtcKeyValueConfig* field_trials)
stefan@webrtc.org88e0dda2014-07-04 09:20:42 +000079 : clock_(clock),
Erik Språnge7942432019-06-12 13:30:02 +020080 packet_router_(packet_router),
Per Kjellander5b698732019-04-15 12:36:33 +020081 fallback_field_trials_(
82 !field_trials ? absl::make_unique<FieldTrialBasedConfig>() : nullptr),
83 field_trials_(field_trials ? field_trials : fallback_field_trials_.get()),
Per Kjellander5b698732019-04-15 12:36:33 +020084 drain_large_queues_(
85 !IsDisabled(*field_trials_, "WebRTC-Pacer-DrainQueue")),
Sebastian Janssonc235a8d2018-06-15 14:46:11 +020086 send_padding_if_silent_(
Per Kjellander5b698732019-04-15 12:36:33 +020087 IsEnabled(*field_trials_, "WebRTC-Pacer-PadInSilence")),
88 pace_audio_(!IsDisabled(*field_trials_, "WebRTC-Pacer-BlockAudio")),
Christoffer Rodbroe2e00002018-12-20 15:46:03 +010089 min_packet_limit_ms_("", kDefaultMinPacketLimitMs),
Erik Språng96816752018-09-04 18:40:19 +020090 last_timestamp_ms_(clock_->TimeInMilliseconds()),
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +000091 paused_(false),
Sebastian Jansson03914462018-10-11 20:22:03 +020092 media_budget_(0),
93 padding_budget_(0),
Per Kjellander5b698732019-04-15 12:36:33 +020094 prober_(*field_trials_),
philipelb61927c2017-02-28 07:05:23 -080095 probing_send_failure_(false),
Erik Språng425d6aa2019-07-29 16:38:27 +020096 pacing_bitrate_(DataRate::Zero()),
Sebastian Janssona1630f82018-02-21 13:39:26 +010097 time_last_process_us_(clock->TimeInMicroseconds()),
98 last_send_time_us_(clock->TimeInMicroseconds()),
Erik Språng7702c8a2019-07-30 22:36:02 +020099 packets_(clock->TimeInMicroseconds(), field_trials),
sprang89c4a7e2017-06-30 13:27:40 -0700100 packet_counter_(0),
Erik Språng425d6aa2019-07-29 16:38:27 +0200101 congestion_window_size_(DataSize::PlusInfinity()),
102 outstanding_data_(DataSize::Zero()),
103 process_thread_(nullptr),
Alex Narest78609d52017-10-20 10:37:47 +0200104 queue_time_limit(kMaxQueueLengthMs),
Erik Språngf6468d22019-07-05 16:53:43 +0200105 account_for_audio_(false),
106 legacy_packet_referencing_(
Erik Språngc4f047d2019-07-19 13:34:11 +0200107 IsEnabled(*field_trials_, "WebRTC-Pacer-LegacyPacketReferencing")) {
Christoffer Rodbroe2e00002018-12-20 15:46:03 +0100108 if (!drain_large_queues_) {
Sebastian Jansson0601d682018-06-25 19:23:05 +0200109 RTC_LOG(LS_WARNING) << "Pacer queues will not be drained,"
110 "pushback experiment must be enabled.";
Christoffer Rodbroe2e00002018-12-20 15:46:03 +0100111 }
112 ParseFieldTrial({&min_packet_limit_ms_},
Per Kjellander5b698732019-04-15 12:36:33 +0200113 field_trials_->Lookup("WebRTC-Pacer-MinPacketLimitMs"));
Christoffer Rodbroe2e00002018-12-20 15:46:03 +0100114 UpdateBudgetWithElapsedTime(min_packet_limit_ms_);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000115}
116
stefan@webrtc.org89fd1e82014-07-15 16:40:38 +0000117PacedSender::~PacedSender() {}
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000118
Erik Språng425d6aa2019-07-29 16:38:27 +0200119void PacedSender::CreateProbeCluster(DataRate bitrate, int cluster_id) {
kthelgason6bfe49c2017-03-30 01:14:41 -0700120 rtc::CritScope cs(&critsect_);
Erik Språng425d6aa2019-07-29 16:38:27 +0200121 prober_.CreateProbeCluster(bitrate.bps(), TimeMilliseconds(), cluster_id);
philipeleb680ea2016-08-17 11:11:59 +0200122}
123
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000124void PacedSender::Pause() {
tommi919dce22017-03-15 07:45:36 -0700125 {
kthelgason6bfe49c2017-03-30 01:14:41 -0700126 rtc::CritScope cs(&critsect_);
stefan9e117c5e12017-08-16 08:16:25 -0700127 if (!paused_)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100128 RTC_LOG(LS_INFO) << "PacedSender paused.";
tommi919dce22017-03-15 07:45:36 -0700129 paused_ = true;
Sebastian Jansson60570dc2018-09-13 17:11:06 +0200130 packets_.SetPauseState(true, TimeMilliseconds());
tommi919dce22017-03-15 07:45:36 -0700131 }
Sebastian Jansson439f0bc2018-02-20 10:46:39 +0100132 rtc::CritScope cs(&process_thread_lock_);
tommi919dce22017-03-15 07:45:36 -0700133 // Tell the process thread to call our TimeUntilNextProcess() method to get
134 // a new (longer) estimate for when to call Process().
135 if (process_thread_)
136 process_thread_->WakeUp(this);
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000137}
138
139void PacedSender::Resume() {
tommi919dce22017-03-15 07:45:36 -0700140 {
kthelgason6bfe49c2017-03-30 01:14:41 -0700141 rtc::CritScope cs(&critsect_);
stefan9e117c5e12017-08-16 08:16:25 -0700142 if (paused_)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100143 RTC_LOG(LS_INFO) << "PacedSender resumed.";
tommi919dce22017-03-15 07:45:36 -0700144 paused_ = false;
Sebastian Jansson60570dc2018-09-13 17:11:06 +0200145 packets_.SetPauseState(false, TimeMilliseconds());
tommi919dce22017-03-15 07:45:36 -0700146 }
Sebastian Jansson439f0bc2018-02-20 10:46:39 +0100147 rtc::CritScope cs(&process_thread_lock_);
tommi919dce22017-03-15 07:45:36 -0700148 // Tell the process thread to call our TimeUntilNextProcess() method to
149 // refresh the estimate for when to call Process().
150 if (process_thread_)
151 process_thread_->WakeUp(this);
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000152}
153
Erik Språng425d6aa2019-07-29 16:38:27 +0200154void PacedSender::SetCongestionWindow(DataSize congestion_window_size) {
Sebastian Jansson45d9c1d2018-03-09 12:48:01 +0100155 rtc::CritScope cs(&critsect_);
Erik Språng425d6aa2019-07-29 16:38:27 +0200156 congestion_window_size_ = congestion_window_size;
Sebastian Jansson45d9c1d2018-03-09 12:48:01 +0100157}
158
Erik Språng425d6aa2019-07-29 16:38:27 +0200159void PacedSender::UpdateOutstandingData(DataSize outstanding_data) {
Sebastian Jansson45d9c1d2018-03-09 12:48:01 +0100160 rtc::CritScope cs(&critsect_);
Erik Språng425d6aa2019-07-29 16:38:27 +0200161 outstanding_data_ = outstanding_data;
Sebastian Jansson45d9c1d2018-03-09 12:48:01 +0100162}
163
164bool PacedSender::Congested() const {
Erik Språng425d6aa2019-07-29 16:38:27 +0200165 if (congestion_window_size_.IsFinite()) {
166 return outstanding_data_ >= congestion_window_size_;
167 }
168 return false;
Sebastian Jansson45d9c1d2018-03-09 12:48:01 +0100169}
170
Erik Språng96816752018-09-04 18:40:19 +0200171int64_t PacedSender::TimeMilliseconds() const {
172 int64_t time_ms = clock_->TimeInMilliseconds();
173 if (time_ms < last_timestamp_ms_) {
174 RTC_LOG(LS_WARNING)
175 << "Non-monotonic clock behavior observed. Previous timestamp: "
176 << last_timestamp_ms_ << ", new timestamp: " << time_ms;
177 RTC_DCHECK_GE(time_ms, last_timestamp_ms_);
178 time_ms = last_timestamp_ms_;
179 }
180 last_timestamp_ms_ = time_ms;
181 return time_ms;
182}
183
stefan@webrtc.orge9f0f592015-02-16 15:47:51 +0000184void PacedSender::SetProbingEnabled(bool enabled) {
kthelgason6bfe49c2017-03-30 01:14:41 -0700185 rtc::CritScope cs(&critsect_);
Elad Alon44b1fa42017-10-17 14:17:54 +0200186 RTC_CHECK_EQ(0, packet_counter_);
Sebastian Jansson03914462018-10-11 20:22:03 +0200187 prober_.SetEnabled(enabled);
stefan@webrtc.orge9f0f592015-02-16 15:47:51 +0000188}
189
Erik Språng425d6aa2019-07-29 16:38:27 +0200190void PacedSender::SetPacingRates(DataRate pacing_rate, DataRate padding_rate) {
Sebastian Jansson439f0bc2018-02-20 10:46:39 +0100191 rtc::CritScope cs(&critsect_);
Erik Språng425d6aa2019-07-29 16:38:27 +0200192 RTC_DCHECK_GT(pacing_rate, DataRate::Zero());
193 pacing_bitrate_ = pacing_rate;
194 padding_budget_.set_target_rate_kbps(padding_rate.kbps());
Evan Shrubsolefee13e82019-02-26 15:25:52 +0100195
196 RTC_LOG(LS_VERBOSE) << "bwe:pacer_updated pacing_kbps="
Erik Språng425d6aa2019-07-29 16:38:27 +0200197 << pacing_bitrate_.kbps()
198 << " padding_budget_kbps=" << padding_rate.kbps();
Sebastian Jansson439f0bc2018-02-20 10:46:39 +0100199}
200
Peter Boströme23e7372015-10-08 11:44:14 +0200201void PacedSender::InsertPacket(RtpPacketSender::Priority priority,
202 uint32_t ssrc,
203 uint16_t sequence_number,
204 int64_t capture_time_ms,
205 size_t bytes,
206 bool retransmission) {
kthelgason6bfe49c2017-03-30 01:14:41 -0700207 rtc::CritScope cs(&critsect_);
Erik Språng425d6aa2019-07-29 16:38:27 +0200208 RTC_DCHECK(pacing_bitrate_ > DataRate::Zero())
Sebastian Jansson439f0bc2018-02-20 10:46:39 +0100209 << "SetPacingRate must be called before InsertPacket.";
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000210
Erik Språng96816752018-09-04 18:40:19 +0200211 int64_t now_ms = TimeMilliseconds();
Sebastian Jansson03914462018-10-11 20:22:03 +0200212 prober_.OnIncomingPacket(bytes);
Peter Boström0453ef82016-02-16 16:23:08 +0100213
sprang0a43fef2015-11-20 09:00:37 -0800214 if (capture_time_ms < 0)
Erik Språngad113e52015-11-26 16:26:12 +0100215 capture_time_ms = now_ms;
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000216
Erik Språng58ee1872019-06-18 16:20:11 +0200217 RtpPacketToSend::Type type;
218 switch (priority) {
Erik Språngaa59eca2019-07-24 14:52:55 +0200219 case RtpPacketSender::kHighPriority:
Erik Språng58ee1872019-06-18 16:20:11 +0200220 type = RtpPacketToSend::Type::kAudio;
221 break;
Erik Språngaa59eca2019-07-24 14:52:55 +0200222 case RtpPacketSender::kNormalPriority:
Erik Språng58ee1872019-06-18 16:20:11 +0200223 type = RtpPacketToSend::Type::kRetransmission;
224 break;
225 default:
226 type = RtpPacketToSend::Type::kVideo;
227 }
228 packets_.Push(GetPriorityForType(type), type, ssrc, sequence_number,
229 capture_time_ms, now_ms, bytes, retransmission,
230 packet_counter_++);
231}
232
233void PacedSender::EnqueuePacket(std::unique_ptr<RtpPacketToSend> packet) {
234 rtc::CritScope cs(&critsect_);
Erik Språng425d6aa2019-07-29 16:38:27 +0200235 RTC_DCHECK(pacing_bitrate_ > DataRate::Zero())
Erik Språng58ee1872019-06-18 16:20:11 +0200236 << "SetPacingRate must be called before InsertPacket.";
237
238 int64_t now_ms = TimeMilliseconds();
239 prober_.OnIncomingPacket(packet->payload_size());
240
241 if (packet->capture_time_ms() < 0) {
242 packet->set_capture_time_ms(now_ms);
243 }
244
245 RTC_CHECK(packet->packet_type());
246 int priority = GetPriorityForType(*packet->packet_type());
247 packets_.Push(priority, now_ms, packet_counter_++, std::move(packet));
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000248}
249
Alex Narest78609d52017-10-20 10:37:47 +0200250void PacedSender::SetAccountForAudioPackets(bool account_for_audio) {
251 rtc::CritScope cs(&critsect_);
252 account_for_audio_ = account_for_audio;
253}
254
Erik Språng425d6aa2019-07-29 16:38:27 +0200255TimeDelta PacedSender::ExpectedQueueTime() const {
kthelgason6bfe49c2017-03-30 01:14:41 -0700256 rtc::CritScope cs(&critsect_);
Erik Språng425d6aa2019-07-29 16:38:27 +0200257 RTC_DCHECK_GT(pacing_bitrate_, DataRate::Zero());
258 return TimeDelta::ms(
259 (QueueSizeData().bytes() * 8 * rtc::kNumMillisecsPerSec) /
260 pacing_bitrate_.bps());
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000261}
262
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000263size_t PacedSender::QueueSizePackets() const {
kthelgason6bfe49c2017-03-30 01:14:41 -0700264 rtc::CritScope cs(&critsect_);
Sebastian Jansson60570dc2018-09-13 17:11:06 +0200265 return packets_.SizeInPackets();
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000266}
267
Erik Språng425d6aa2019-07-29 16:38:27 +0200268DataSize PacedSender::QueueSizeData() const {
Christoffer Rodbroc610e262019-01-08 10:49:19 +0100269 rtc::CritScope cs(&critsect_);
Erik Språng425d6aa2019-07-29 16:38:27 +0200270 return DataSize::bytes(packets_.SizeInBytes());
Christoffer Rodbroc610e262019-01-08 10:49:19 +0100271}
272
Erik Språng425d6aa2019-07-29 16:38:27 +0200273absl::optional<Timestamp> PacedSender::FirstSentPacketTime() const {
asaperssonfc5e81c2017-04-19 23:28:53 -0700274 rtc::CritScope cs(&critsect_);
Erik Språng425d6aa2019-07-29 16:38:27 +0200275 return first_sent_packet_time_;
asaperssonfc5e81c2017-04-19 23:28:53 -0700276}
277
Erik Språng425d6aa2019-07-29 16:38:27 +0200278TimeDelta PacedSender::OldestPacketWaitTime() const {
kthelgason6bfe49c2017-03-30 01:14:41 -0700279 rtc::CritScope cs(&critsect_);
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000280
Sebastian Jansson60570dc2018-09-13 17:11:06 +0200281 int64_t oldest_packet = packets_.OldestEnqueueTimeMs();
Erik Språng425d6aa2019-07-29 16:38:27 +0200282 if (oldest_packet == 0) {
283 return TimeDelta::Zero();
284 }
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000285
Erik Språng425d6aa2019-07-29 16:38:27 +0200286 return TimeDelta::ms(TimeMilliseconds() - oldest_packet);
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000287}
288
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +0000289int64_t PacedSender::TimeUntilNextProcess() {
kthelgason6bfe49c2017-03-30 01:14:41 -0700290 rtc::CritScope cs(&critsect_);
Sebastian Janssona1630f82018-02-21 13:39:26 +0100291 int64_t elapsed_time_us =
292 clock_->TimeInMicroseconds() - time_last_process_us_;
stefan9e117c5e12017-08-16 08:16:25 -0700293 int64_t elapsed_time_ms = (elapsed_time_us + 500) / 1000;
294 // When paused we wake up every 500 ms to send a padding packet to ensure
295 // we won't get stuck in the paused state due to no feedback being received.
tommi919dce22017-03-15 07:45:36 -0700296 if (paused_)
Sebastian Jansson45d9c1d2018-03-09 12:48:01 +0100297 return std::max<int64_t>(kPausedProcessIntervalMs - elapsed_time_ms, 0);
tommi919dce22017-03-15 07:45:36 -0700298
Sebastian Jansson03914462018-10-11 20:22:03 +0200299 if (prober_.IsProbing()) {
300 int64_t ret = prober_.TimeUntilNextProbe(TimeMilliseconds());
philipelb61927c2017-02-28 07:05:23 -0800301 if (ret > 0 || (ret == 0 && !probing_send_failure_))
stefan@webrtc.orge9f0f592015-02-16 15:47:51 +0000302 return ret;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000303 }
Christoffer Rodbroe2e00002018-12-20 15:46:03 +0100304 return std::max<int64_t>(min_packet_limit_ms_ - elapsed_time_ms, 0);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000305}
306
Sebastian Jansson916ae082018-10-26 13:10:23 +0200307int64_t PacedSender::UpdateTimeAndGetElapsedMs(int64_t now_us) {
Sebastian Janssonb544f6c2018-06-04 19:02:41 +0200308 int64_t elapsed_time_ms = (now_us - time_last_process_us_ + 500) / 1000;
Sebastian Janssona1630f82018-02-21 13:39:26 +0100309 time_last_process_us_ = now_us;
Sebastian Janssone5d8c572018-02-28 08:53:06 +0100310 if (elapsed_time_ms > kMaxElapsedTimeMs) {
311 RTC_LOG(LS_WARNING) << "Elapsed time (" << elapsed_time_ms
312 << " ms) longer than expected, limiting to "
313 << kMaxElapsedTimeMs << " ms";
314 elapsed_time_ms = kMaxElapsedTimeMs;
315 }
Sebastian Jansson916ae082018-10-26 13:10:23 +0200316 return elapsed_time_ms;
317}
318
319bool PacedSender::ShouldSendKeepalive(int64_t now_us) const {
Sebastian Janssonc235a8d2018-06-15 14:46:11 +0200320 if (send_padding_if_silent_ || paused_ || Congested()) {
321 // We send a padding packet every 500 ms to ensure we won't get stuck in
322 // congested state due to no feedback being received.
Sebastian Janssonb544f6c2018-06-04 19:02:41 +0200323 int64_t elapsed_since_last_send_us = now_us - last_send_time_us_;
324 if (elapsed_since_last_send_us >= kCongestedPacketIntervalMs * 1000) {
Sebastian Jansson682c6492018-04-12 13:08:22 +0200325 // We can not send padding unless a normal packet has first been sent. If
326 // we do, timestamps get messed up.
327 if (packet_counter_ > 0) {
Sebastian Jansson916ae082018-10-26 13:10:23 +0200328 return true;
Sebastian Jansson682c6492018-04-12 13:08:22 +0200329 }
Sebastian Janssona1630f82018-02-21 13:39:26 +0100330 }
stefan9e117c5e12017-08-16 08:16:25 -0700331 }
Sebastian Jansson916ae082018-10-26 13:10:23 +0200332 return false;
333}
334
335void PacedSender::Process() {
336 rtc::CritScope cs(&critsect_);
337 int64_t now_us = clock_->TimeInMicroseconds();
338 int64_t elapsed_time_ms = UpdateTimeAndGetElapsedMs(now_us);
339 if (ShouldSendKeepalive(now_us)) {
Erik Språngf6468d22019-07-05 16:53:43 +0200340 if (legacy_packet_referencing_) {
341 critsect_.Leave();
342 size_t bytes_sent =
343 packet_router_->TimeToSendPadding(1, PacedPacketInfo());
344 critsect_.Enter();
345 OnPaddingSent(bytes_sent);
346 } else {
Erik Språngb88fd312019-07-15 19:28:31 +0200347 size_t keepalive_bytes_sent = 0;
Erik Språngf6468d22019-07-05 16:53:43 +0200348 critsect_.Leave();
349 std::vector<std::unique_ptr<RtpPacketToSend>> keepalive_packets =
350 packet_router_->GeneratePadding(1);
Erik Språngf6468d22019-07-05 16:53:43 +0200351 for (auto& packet : keepalive_packets) {
Erik Språngb88fd312019-07-15 19:28:31 +0200352 keepalive_bytes_sent += packet->payload_size() + packet->padding_size();
353 packet_router_->SendPacket(std::move(packet), PacedPacketInfo());
Erik Språngf6468d22019-07-05 16:53:43 +0200354 }
Erik Språngb88fd312019-07-15 19:28:31 +0200355 critsect_.Enter();
356 OnPaddingSent(keepalive_bytes_sent);
Erik Språngf6468d22019-07-05 16:53:43 +0200357 }
Sebastian Jansson916ae082018-10-26 13:10:23 +0200358 }
359
Sebastian Janssonc235a8d2018-06-15 14:46:11 +0200360 if (paused_)
361 return;
stefan9e117c5e12017-08-16 08:16:25 -0700362
363 if (elapsed_time_ms > 0) {
Erik Språng425d6aa2019-07-29 16:38:27 +0200364 int target_bitrate_kbps = pacing_bitrate_.kbps();
Sebastian Jansson60570dc2018-09-13 17:11:06 +0200365 size_t queue_size_bytes = packets_.SizeInBytes();
sprang0a43fef2015-11-20 09:00:37 -0800366 if (queue_size_bytes > 0) {
367 // Assuming equal size packets and input/output rate, the average packet
368 // has avg_time_left_ms left to get queue_size_bytes out of the queue, if
369 // time constraint shall be met. Determine bitrate needed for that.
Sebastian Jansson60570dc2018-09-13 17:11:06 +0200370 packets_.UpdateQueueTime(TimeMilliseconds());
Sebastian Jansson0601d682018-06-25 19:23:05 +0200371 if (drain_large_queues_) {
372 int64_t avg_time_left_ms = std::max<int64_t>(
Sebastian Jansson60570dc2018-09-13 17:11:06 +0200373 1, queue_time_limit - packets_.AverageQueueTimeMs());
Sebastian Jansson0601d682018-06-25 19:23:05 +0200374 int min_bitrate_needed_kbps =
375 static_cast<int>(queue_size_bytes * 8 / avg_time_left_ms);
Evan Shrubsolefee13e82019-02-26 15:25:52 +0100376 if (min_bitrate_needed_kbps > target_bitrate_kbps) {
Sebastian Jansson0601d682018-06-25 19:23:05 +0200377 target_bitrate_kbps = min_bitrate_needed_kbps;
Evan Shrubsolefee13e82019-02-26 15:25:52 +0100378 RTC_LOG(LS_VERBOSE) << "bwe:large_pacing_queue pacing_rate_kbps="
379 << target_bitrate_kbps;
380 }
Sebastian Jansson0601d682018-06-25 19:23:05 +0200381 }
sprang0a43fef2015-11-20 09:00:37 -0800382 }
383
Sebastian Jansson03914462018-10-11 20:22:03 +0200384 media_budget_.set_target_rate_kbps(target_bitrate_kbps);
isheriff31687812016-10-04 08:43:09 -0700385 UpdateBudgetWithElapsedTime(elapsed_time_ms);
stefan@webrtc.org80865fd2013-08-09 11:31:23 +0000386 }
philipela1ed0b32016-06-01 06:31:17 -0700387
Sebastian Jansson03914462018-10-11 20:22:03 +0200388 bool is_probing = prober_.IsProbing();
philipelc7bf32a2017-02-17 03:59:43 -0800389 PacedPacketInfo pacing_info;
Erik Språngf6468d22019-07-05 16:53:43 +0200390 absl::optional<size_t> recommended_probe_size;
isheriffcc5903e2016-10-04 08:29:38 -0700391 if (is_probing) {
Sebastian Jansson03914462018-10-11 20:22:03 +0200392 pacing_info = prober_.CurrentCluster();
393 recommended_probe_size = prober_.RecommendedMinProbeSize();
isheriffcc5903e2016-10-04 08:29:38 -0700394 }
Erik Språngf6468d22019-07-05 16:53:43 +0200395
396 size_t bytes_sent = 0;
Sebastian Jansson916ae082018-10-26 13:10:23 +0200397 // The paused state is checked in the loop since it leaves the critical
398 // section allowing the paused state to be changed from other code.
Erik Språngf6468d22019-07-05 16:53:43 +0200399 while (!paused_) {
Erik Språng58ee1872019-06-18 16:20:11 +0200400 auto* packet = GetPendingPacket(pacing_info);
Erik Språngf6468d22019-07-05 16:53:43 +0200401 if (packet == nullptr) {
402 // No packet available to send, check if we should send padding.
403 if (!legacy_packet_referencing_) {
404 size_t padding_bytes_to_add =
405 PaddingBytesToAdd(recommended_probe_size, bytes_sent);
406 if (padding_bytes_to_add > 0) {
407 critsect_.Leave();
408 std::vector<std::unique_ptr<RtpPacketToSend>> padding_packets =
409 packet_router_->GeneratePadding(padding_bytes_to_add);
410 critsect_.Enter();
411 if (padding_packets.empty()) {
412 // No padding packets were generated, quite send loop.
413 break;
414 }
415 for (auto& packet : padding_packets) {
416 EnqueuePacket(std::move(packet));
417 }
418 // Continue loop to send the padding that was just added.
419 continue;
420 }
421 }
422
423 // Can't fetch new packet and no padding to send, exit send loop.
Sebastian Jansson916ae082018-10-26 13:10:23 +0200424 break;
Erik Språngf6468d22019-07-05 16:53:43 +0200425 }
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100426
Erik Språng58ee1872019-06-18 16:20:11 +0200427 std::unique_ptr<RtpPacketToSend> rtp_packet = packet->ReleasePacket();
428 const bool owned_rtp_packet = rtp_packet != nullptr;
Erik Språng58ee1872019-06-18 16:20:11 +0200429 RtpPacketSendResult success;
Erik Språngf6468d22019-07-05 16:53:43 +0200430
Erik Språng58ee1872019-06-18 16:20:11 +0200431 if (rtp_packet != nullptr) {
Erik Språngf6468d22019-07-05 16:53:43 +0200432 critsect_.Leave();
Erik Språng58ee1872019-06-18 16:20:11 +0200433 packet_router_->SendPacket(std::move(rtp_packet), pacing_info);
Erik Språngf6468d22019-07-05 16:53:43 +0200434 critsect_.Enter();
Erik Språng58ee1872019-06-18 16:20:11 +0200435 success = RtpPacketSendResult::kSuccess;
436 } else {
Erik Språngf6468d22019-07-05 16:53:43 +0200437 critsect_.Leave();
Erik Språng58ee1872019-06-18 16:20:11 +0200438 success = packet_router_->TimeToSendPacket(
439 packet->ssrc(), packet->sequence_number(), packet->capture_time_ms(),
440 packet->is_retransmission(), pacing_info);
Erik Språngf6468d22019-07-05 16:53:43 +0200441 critsect_.Enter();
Erik Språng58ee1872019-06-18 16:20:11 +0200442 }
443
Erik Språngd2879622019-05-10 08:29:01 -0700444 if (success == RtpPacketSendResult::kSuccess ||
445 success == RtpPacketSendResult::kPacketNotFound) {
446 // Packet sent or invalid packet, remove it from queue.
447 // TODO(webrtc:8052): Don't consume media budget on kInvalid.
Erik Språng58ee1872019-06-18 16:20:11 +0200448 bytes_sent += packet->size_in_bytes();
Sebastian Janssona1630f82018-02-21 13:39:26 +0100449 // Send succeeded, remove it from the queue.
Mirko Bonadei05cf6be2019-01-31 21:38:12 +0100450 OnPacketSent(packet);
Erik Språngf6468d22019-07-05 16:53:43 +0200451 if (recommended_probe_size && bytes_sent > *recommended_probe_size)
isheriffcc5903e2016-10-04 08:29:38 -0700452 break;
Erik Språng58ee1872019-06-18 16:20:11 +0200453 } else if (owned_rtp_packet) {
454 // Send failed, but we can't put it back in the queue, remove it without
455 // consuming budget.
456 packets_.FinalizePop();
457 break;
Peter Boströme23e7372015-10-08 11:44:14 +0200458 } else {
459 // Send failed, put it back into the queue.
Erik Språng58ee1872019-06-18 16:20:11 +0200460 packets_.CancelPop();
isheriffcc5903e2016-10-04 08:29:38 -0700461 break;
Peter Boströme23e7372015-10-08 11:44:14 +0200462 }
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000463 }
Peter Boströme23e7372015-10-08 11:44:14 +0200464
Erik Språngf6468d22019-07-05 16:53:43 +0200465 if (legacy_packet_referencing_ && packets_.Empty() && !Congested()) {
isheriffcc5903e2016-10-04 08:29:38 -0700466 // We can not send padding unless a normal packet has first been sent. If we
467 // do, timestamps get messed up.
468 if (packet_counter_ > 0) {
Erik Språngf6468d22019-07-05 16:53:43 +0200469 int padding_needed = static_cast<int>(
470 recommended_probe_size ? (*recommended_probe_size - bytes_sent)
471 : padding_budget_.bytes_remaining());
Sebastian Jansson439f0bc2018-02-20 10:46:39 +0100472 if (padding_needed > 0) {
Erik Språngf6468d22019-07-05 16:53:43 +0200473 size_t padding_sent = 0;
Sebastian Jansson916ae082018-10-26 13:10:23 +0200474 critsect_.Leave();
Erik Språngf6468d22019-07-05 16:53:43 +0200475 padding_sent =
Erik Språnge7942432019-06-12 13:30:02 +0200476 packet_router_->TimeToSendPadding(padding_needed, pacing_info);
Sebastian Jansson916ae082018-10-26 13:10:23 +0200477 critsect_.Enter();
478 bytes_sent += padding_sent;
479 OnPaddingSent(padding_sent);
Sebastian Jansson439f0bc2018-02-20 10:46:39 +0100480 }
isheriffcc5903e2016-10-04 08:29:38 -0700481 }
perkj71ee44c2016-06-15 00:47:53 -0700482 }
Erik Språngf6468d22019-07-05 16:53:43 +0200483
philipelb61927c2017-02-28 07:05:23 -0800484 if (is_probing) {
485 probing_send_failure_ = bytes_sent == 0;
486 if (!probing_send_failure_)
Sebastian Jansson03914462018-10-11 20:22:03 +0200487 prober_.ProbeSent(TimeMilliseconds(), bytes_sent);
philipelb61927c2017-02-28 07:05:23 -0800488 }
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000489}
490
tommi919dce22017-03-15 07:45:36 -0700491void PacedSender::ProcessThreadAttached(ProcessThread* process_thread) {
Karl Wiberg43432732018-05-23 11:13:31 +0200492 RTC_LOG(LS_INFO) << "ProcessThreadAttached 0x" << process_thread;
Sebastian Jansson439f0bc2018-02-20 10:46:39 +0100493 rtc::CritScope cs(&process_thread_lock_);
tommi919dce22017-03-15 07:45:36 -0700494 process_thread_ = process_thread;
495}
496
Erik Språngf6468d22019-07-05 16:53:43 +0200497size_t PacedSender::PaddingBytesToAdd(
498 absl::optional<size_t> recommended_probe_size,
499 size_t bytes_sent) {
500 if (!packets_.Empty()) {
501 // Actual payload available, no need to add padding.
502 return 0;
503 }
504
505 if (Congested()) {
506 // Don't add padding if congested, even if requested for probing.
507 return 0;
508 }
509
510 if (packet_counter_ == 0) {
511 // We can not send padding unless a normal packet has first been sent. If we
512 // do, timestamps get messed up.
513 return 0;
514 }
515
516 if (recommended_probe_size) {
517 if (*recommended_probe_size > bytes_sent) {
518 return *recommended_probe_size - bytes_sent;
519 }
520 return 0;
521 }
522
523 return padding_budget_.bytes_remaining();
524}
525
Erik Språng58ee1872019-06-18 16:20:11 +0200526RoundRobinPacketQueue::QueuedPacket* PacedSender::GetPendingPacket(
Sebastian Jansson916ae082018-10-26 13:10:23 +0200527 const PacedPacketInfo& pacing_info) {
Erik Språngf6468d22019-07-05 16:53:43 +0200528 if (packets_.Empty()) {
529 return nullptr;
530 }
531
Sebastian Jansson916ae082018-10-26 13:10:23 +0200532 // Since we need to release the lock in order to send, we first pop the
533 // element from the priority queue but keep it in storage, so that we can
534 // reinsert it if send fails.
Erik Språng58ee1872019-06-18 16:20:11 +0200535 RoundRobinPacketQueue::QueuedPacket* packet = packets_.BeginPop();
536 bool audio_packet = packet->type() == RtpPacketToSend::Type::kAudio;
Sebastian Jansson470a5ea2019-01-23 12:37:49 +0100537 bool apply_pacing = !audio_packet || pace_audio_;
Sebastian Jansson03914462018-10-11 20:22:03 +0200538 if (apply_pacing && (Congested() || (media_budget_.bytes_remaining() == 0 &&
Sebastian Janssonce4829a2018-06-15 14:47:35 +0200539 pacing_info.probe_cluster_id ==
540 PacedPacketInfo::kNotAProbe))) {
Erik Språng58ee1872019-06-18 16:20:11 +0200541 packets_.CancelPop();
Sebastian Jansson916ae082018-10-26 13:10:23 +0200542 return nullptr;
terelius8b70faf2016-08-01 09:47:31 -0700543 }
Sebastian Jansson916ae082018-10-26 13:10:23 +0200544 return packet;
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000545}
546
Erik Språng58ee1872019-06-18 16:20:11 +0200547void PacedSender::OnPacketSent(RoundRobinPacketQueue::QueuedPacket* packet) {
Erik Språng425d6aa2019-07-29 16:38:27 +0200548 if (!first_sent_packet_time_) {
549 first_sent_packet_time_ = Timestamp::ms(TimeMilliseconds());
550 }
Erik Språng58ee1872019-06-18 16:20:11 +0200551 bool audio_packet = packet->type() == RtpPacketToSend::Type::kAudio;
Sebastian Jansson916ae082018-10-26 13:10:23 +0200552 if (!audio_packet || account_for_audio_) {
553 // Update media bytes sent.
Erik Språng58ee1872019-06-18 16:20:11 +0200554 UpdateBudgetWithBytesSent(packet->size_in_bytes());
Sebastian Jansson916ae082018-10-26 13:10:23 +0200555 last_send_time_us_ = clock_->TimeInMicroseconds();
556 }
557 // Send succeeded, remove it from the queue.
Erik Språng58ee1872019-06-18 16:20:11 +0200558 packets_.FinalizePop();
Sebastian Jansson916ae082018-10-26 13:10:23 +0200559}
sprang@webrtc.orgdcebf2d2014-11-04 16:27:16 +0000560
Sebastian Jansson916ae082018-10-26 13:10:23 +0200561void PacedSender::OnPaddingSent(size_t bytes_sent) {
Stefan Holmer01b48882015-05-05 10:21:24 +0200562 if (bytes_sent > 0) {
isheriff31687812016-10-04 08:43:09 -0700563 UpdateBudgetWithBytesSent(bytes_sent);
Stefan Holmer01b48882015-05-05 10:21:24 +0200564 }
Sebastian Janssonc235a8d2018-06-15 14:46:11 +0200565 last_send_time_us_ = clock_->TimeInMicroseconds();
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000566}
567
isheriff31687812016-10-04 08:43:09 -0700568void PacedSender::UpdateBudgetWithElapsedTime(int64_t delta_time_ms) {
Sebastian Janssona1630f82018-02-21 13:39:26 +0100569 delta_time_ms = std::min(kMaxIntervalTimeMs, delta_time_ms);
Sebastian Jansson03914462018-10-11 20:22:03 +0200570 media_budget_.IncreaseBudget(delta_time_ms);
571 padding_budget_.IncreaseBudget(delta_time_ms);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000572}
isheriff31687812016-10-04 08:43:09 -0700573
574void PacedSender::UpdateBudgetWithBytesSent(size_t bytes_sent) {
Erik Språng425d6aa2019-07-29 16:38:27 +0200575 outstanding_data_ += DataSize::bytes(bytes_sent);
Sebastian Jansson03914462018-10-11 20:22:03 +0200576 media_budget_.UseBudget(bytes_sent);
577 padding_budget_.UseBudget(bytes_sent);
isheriff31687812016-10-04 08:43:09 -0700578}
sprang89c4a7e2017-06-30 13:27:40 -0700579
Erik Språng425d6aa2019-07-29 16:38:27 +0200580void PacedSender::SetQueueTimeLimit(TimeDelta limit) {
sprang89c4a7e2017-06-30 13:27:40 -0700581 rtc::CritScope cs(&critsect_);
Erik Språng425d6aa2019-07-29 16:38:27 +0200582 queue_time_limit = limit.ms();
sprang89c4a7e2017-06-30 13:27:40 -0700583}
584
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000585} // namespace webrtc