blob: 16629ac57dc6da39621e2b8ad27d9b04689a9d4f [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
11#include "webrtc/modules/pacing/include/paced_sender.h"
12
13#include <assert.h>
14
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +000015#include "webrtc/modules/interface/module_common_types.h"
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000016#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +000017#include "webrtc/system_wrappers/interface/trace_event.h"
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000018
19namespace {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000020// Time limit in milliseconds between packet bursts.
21const int kMinPacketLimitMs = 5;
22
23// Upper cap on process interval, in case process has not been called in a long
24// time.
25const int kMaxIntervalTimeMs = 30;
26
27// Max time that the first packet in the queue can sit in the queue if no
28// packets are sent, regardless of buffer state. In practice only in effect at
29// low bitrates (less than 320 kbits/s).
30const int kMaxQueueTimeWithoutSendingMs = 30;
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +000031
32// Max padding bytes per second.
33const int kMaxPaddingKbps = 800;
34
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000035} // namespace
36
37namespace webrtc {
38
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +000039namespace paced_sender {
40struct Packet {
41 Packet(uint32_t ssrc, uint16_t seq_number, int64_t capture_time_ms,
42 int length_in_bytes)
43 : ssrc_(ssrc),
44 sequence_number_(seq_number),
45 capture_time_ms_(capture_time_ms),
46 bytes_(length_in_bytes) {
pwestin@webrtc.org52aa0192013-04-25 17:35:56 +000047 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +000048 uint32_t ssrc_;
49 uint16_t sequence_number_;
50 int64_t capture_time_ms_;
51 int bytes_;
52};
53
54// STL list style class which prevents duplicates in the list.
55class PacketList {
56 public:
57 PacketList() {};
58
59 bool empty() const {
60 return packet_list_.empty();
61 }
62
63 Packet front() const {
64 return packet_list_.front();
65 }
66
67 void pop_front() {
68 Packet& packet = packet_list_.front();
69 uint16_t sequence_number = packet.sequence_number_;
70 packet_list_.pop_front();
71 sequence_number_set_.erase(sequence_number);
72 }
73
74 void push_back(const Packet& packet) {
75 if (sequence_number_set_.find(packet.sequence_number_) ==
76 sequence_number_set_.end()) {
77 // Don't insert duplicates.
78 packet_list_.push_back(packet);
79 sequence_number_set_.insert(packet.sequence_number_);
80 }
81 }
82
83 private:
84 std::list<Packet> packet_list_;
85 std::set<uint16_t> sequence_number_set_;
86};
87
88class IntervalBudget {
89 public:
90 explicit IntervalBudget(int initial_target_rate_kbps)
91 : target_rate_kbps_(initial_target_rate_kbps),
92 bytes_remaining_(0) {}
93
94 void set_target_rate_kbps(int target_rate_kbps) {
95 target_rate_kbps_ = target_rate_kbps;
96 }
97
98 void IncreaseBudget(int delta_time_ms) {
99 int bytes = target_rate_kbps_ * delta_time_ms / 8;
100 if (bytes_remaining_ < 0) {
101 // We overused last interval, compensate this interval.
102 bytes_remaining_ = bytes_remaining_ + bytes;
103 } else {
104 // If we underused last interval we can't use it this interval.
105 bytes_remaining_ = bytes;
106 }
107 }
108
109 void UseBudget(int bytes) {
110 bytes_remaining_ = std::max(bytes_remaining_ - bytes,
111 -100 * target_rate_kbps_ / 8);
112 }
113
114 int bytes_remaining() const { return bytes_remaining_; }
115
116 private:
117 int target_rate_kbps_;
118 int bytes_remaining_;
119};
120} // namespace paced_sender
pwestin@webrtc.org52aa0192013-04-25 17:35:56 +0000121
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000122PacedSender::PacedSender(Callback* callback, int target_bitrate_kbps,
123 float pace_multiplier)
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000124 : callback_(callback),
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000125 pace_multiplier_(pace_multiplier),
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000126 enabled_(false),
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000127 paused_(false),
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000128 critsect_(CriticalSectionWrapper::CreateCriticalSection()),
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000129 media_budget_(new paced_sender::IntervalBudget(
130 pace_multiplier_ * target_bitrate_kbps)),
131 padding_budget_(new paced_sender::IntervalBudget(kMaxPaddingKbps)),
132 // No padding until UpdateBitrate is called.
133 pad_up_to_bitrate_budget_(new paced_sender::IntervalBudget(0)),
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000134 time_last_update_(TickTime::Now()),
135 capture_time_ms_last_queued_(0),
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000136 capture_time_ms_last_sent_(0),
137 high_priority_packets_(new paced_sender::PacketList),
138 normal_priority_packets_(new paced_sender::PacketList),
139 low_priority_packets_(new paced_sender::PacketList) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000140 UpdateBytesPerInterval(kMinPacketLimitMs);
141}
142
143PacedSender::~PacedSender() {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000144}
145
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000146void PacedSender::Pause() {
147 CriticalSectionScoped cs(critsect_.get());
148 paused_ = true;
149}
150
151void PacedSender::Resume() {
152 CriticalSectionScoped cs(critsect_.get());
153 paused_ = false;
154}
155
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000156void PacedSender::SetStatus(bool enable) {
157 CriticalSectionScoped cs(critsect_.get());
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000158 enabled_ = enable;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000159}
160
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000161bool PacedSender::Enabled() const {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000162 CriticalSectionScoped cs(critsect_.get());
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000163 return enabled_;
164}
165
166void PacedSender::UpdateBitrate(int target_bitrate_kbps,
167 int pad_up_to_bitrate_kbps) {
168 CriticalSectionScoped cs(critsect_.get());
169 media_budget_->set_target_rate_kbps(pace_multiplier_ * target_bitrate_kbps);
170 pad_up_to_bitrate_budget_->set_target_rate_kbps(pad_up_to_bitrate_kbps);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000171}
172
173bool PacedSender::SendPacket(Priority priority, uint32_t ssrc,
174 uint16_t sequence_number, int64_t capture_time_ms, int bytes) {
175 CriticalSectionScoped cs(critsect_.get());
176
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000177 if (!enabled_) {
178 UpdateMediaBytesSent(bytes);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000179 return true; // We can send now.
180 }
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000181 if (capture_time_ms < 0) {
182 capture_time_ms = TickTime::MillisecondTimestamp();
183 }
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000184 if (paused_) {
185 // Queue all packets when we are paused.
186 switch (priority) {
187 case kHighPriority:
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000188 high_priority_packets_->push_back(paced_sender::Packet(ssrc,
189 sequence_number,
190 capture_time_ms,
191 bytes));
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000192 break;
193 case kNormalPriority:
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000194 if (capture_time_ms > capture_time_ms_last_queued_) {
195 capture_time_ms_last_queued_ = capture_time_ms;
196 TRACE_EVENT_ASYNC_BEGIN1("webrtc_rtp", "PacedSend", capture_time_ms,
197 "capture_time_ms", capture_time_ms);
198 }
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000199 case kLowPriority:
200 // Queue the low priority packets in the normal priority queue when we
201 // are paused to avoid starvation.
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000202 normal_priority_packets_->push_back(paced_sender::Packet(
203 ssrc, sequence_number, capture_time_ms, bytes));
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000204 break;
205 }
206 return false;
207 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000208 paced_sender::PacketList* packet_list;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000209 switch (priority) {
210 case kHighPriority:
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000211 packet_list = high_priority_packets_.get();
212 break;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000213 case kNormalPriority:
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000214 packet_list = normal_priority_packets_.get();
215 break;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000216 case kLowPriority:
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000217 packet_list = low_priority_packets_.get();
218 break;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000219 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000220 if (packet_list->empty() &&
221 media_budget_->bytes_remaining() > 0) {
222 UpdateMediaBytesSent(bytes);
223 return true; // We can send now.
224 }
225 packet_list->push_back(paced_sender::Packet(ssrc, sequence_number,
226 capture_time_ms, bytes));
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000227 return false;
228}
229
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000230int PacedSender::QueueInMs() const {
231 CriticalSectionScoped cs(critsect_.get());
232 int64_t now_ms = TickTime::MillisecondTimestamp();
233 int64_t oldest_packet_capture_time = now_ms;
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000234 if (!high_priority_packets_->empty()) {
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000235 oldest_packet_capture_time = std::min(
236 oldest_packet_capture_time,
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000237 high_priority_packets_->front().capture_time_ms_);
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000238 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000239 if (!normal_priority_packets_->empty()) {
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000240 oldest_packet_capture_time = std::min(
241 oldest_packet_capture_time,
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000242 normal_priority_packets_->front().capture_time_ms_);
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000243 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000244 if (!low_priority_packets_->empty()) {
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000245 oldest_packet_capture_time = std::min(
246 oldest_packet_capture_time,
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000247 low_priority_packets_->front().capture_time_ms_);
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000248 }
249 return now_ms - oldest_packet_capture_time;
250}
251
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000252int32_t PacedSender::TimeUntilNextProcess() {
253 CriticalSectionScoped cs(critsect_.get());
254 int64_t elapsed_time_ms =
255 (TickTime::Now() - time_last_update_).Milliseconds();
256 if (elapsed_time_ms <= 0) {
257 return kMinPacketLimitMs;
258 }
259 if (elapsed_time_ms >= kMinPacketLimitMs) {
260 return 0;
261 }
262 return kMinPacketLimitMs - elapsed_time_ms;
263}
264
265int32_t PacedSender::Process() {
266 TickTime now = TickTime::Now();
267 CriticalSectionScoped cs(critsect_.get());
268 int elapsed_time_ms = (now - time_last_update_).Milliseconds();
269 time_last_update_ = now;
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000270 if (!paused_ && elapsed_time_ms > 0) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000271 uint32_t delta_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms);
272 UpdateBytesPerInterval(delta_time_ms);
273 uint32_t ssrc;
274 uint16_t sequence_number;
275 int64_t capture_time_ms;
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000276 Priority priority;
277 bool last_packet;
278 while (GetNextPacket(&ssrc, &sequence_number, &capture_time_ms,
279 &priority, &last_packet)) {
280 if (priority == kNormalPriority) {
281 if (capture_time_ms > capture_time_ms_last_sent_) {
282 capture_time_ms_last_sent_ = capture_time_ms;
283 } else if (capture_time_ms == capture_time_ms_last_sent_ &&
284 last_packet) {
285 TRACE_EVENT_ASYNC_END0("webrtc_rtp", "PacedSend", capture_time_ms);
286 }
287 }
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000288 critsect_->Leave();
289 callback_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms);
290 critsect_->Enter();
291 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000292 if (high_priority_packets_->empty() &&
293 normal_priority_packets_->empty() &&
294 low_priority_packets_->empty() &&
295 padding_budget_->bytes_remaining() > 0 &&
296 pad_up_to_bitrate_budget_->bytes_remaining() > 0) {
297 int padding_needed = std::min(
298 padding_budget_->bytes_remaining(),
299 pad_up_to_bitrate_budget_->bytes_remaining());
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000300 critsect_->Leave();
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000301 int bytes_sent = callback_->TimeToSendPadding(padding_needed);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000302 critsect_->Enter();
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000303 media_budget_->UseBudget(bytes_sent);
304 padding_budget_->UseBudget(bytes_sent);
305 pad_up_to_bitrate_budget_->UseBudget(bytes_sent);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000306 }
307 }
308 return 0;
309}
310
311// MUST have critsect_ when calling.
312void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) {
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000313 media_budget_->IncreaseBudget(delta_time_ms);
314 padding_budget_->IncreaseBudget(delta_time_ms);
315 pad_up_to_bitrate_budget_->IncreaseBudget(delta_time_ms);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000316}
317
318// MUST have critsect_ when calling.
319bool PacedSender::GetNextPacket(uint32_t* ssrc, uint16_t* sequence_number,
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000320 int64_t* capture_time_ms, Priority* priority,
321 bool* last_packet) {
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000322 if (media_budget_->bytes_remaining() <= 0) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000323 // All bytes consumed for this interval.
324 // Check if we have not sent in a too long time.
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000325 if ((TickTime::Now() - time_last_send_).Milliseconds() >
326 kMaxQueueTimeWithoutSendingMs) {
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000327 if (!high_priority_packets_->empty()) {
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000328 *priority = kHighPriority;
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000329 GetNextPacketFromList(high_priority_packets_.get(), ssrc,
330 sequence_number, capture_time_ms, last_packet);
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000331 return true;
332 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000333 if (!normal_priority_packets_->empty()) {
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000334 *priority = kNormalPriority;
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000335 GetNextPacketFromList(normal_priority_packets_.get(), ssrc,
336 sequence_number, capture_time_ms, last_packet);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000337 return true;
338 }
339 }
340 return false;
341 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000342 if (!high_priority_packets_->empty()) {
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000343 *priority = kHighPriority;
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000344 GetNextPacketFromList(high_priority_packets_.get(), ssrc, sequence_number,
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000345 capture_time_ms, last_packet);
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000346 return true;
347 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000348 if (!normal_priority_packets_->empty()) {
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000349 *priority = kNormalPriority;
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000350 GetNextPacketFromList(normal_priority_packets_.get(), ssrc,
351 sequence_number, capture_time_ms, last_packet);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000352 return true;
353 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000354 if (!low_priority_packets_->empty()) {
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000355 *priority = kLowPriority;
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000356 GetNextPacketFromList(low_priority_packets_.get(), ssrc, sequence_number,
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000357 capture_time_ms, last_packet);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000358 return true;
359 }
360 return false;
361}
362
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000363void PacedSender::GetNextPacketFromList(paced_sender::PacketList* packets,
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000364 uint32_t* ssrc, uint16_t* sequence_number, int64_t* capture_time_ms,
365 bool* last_packet) {
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000366 paced_sender::Packet packet = packets->front();
367 UpdateMediaBytesSent(packet.bytes_);
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000368 *sequence_number = packet.sequence_number_;
369 *ssrc = packet.ssrc_;
370 *capture_time_ms = packet.capture_time_ms_;
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000371 packets->pop_front();
372 *last_packet = packets->empty() ||
373 packets->front().capture_time_ms_ > *capture_time_ms;
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000374}
375
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000376// MUST have critsect_ when calling.
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000377void PacedSender::UpdateMediaBytesSent(int num_bytes) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000378 time_last_send_ = TickTime::Now();
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000379 media_budget_->UseBudget(num_bytes);
380 pad_up_to_bitrate_budget_->UseBudget(num_bytes);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000381}
382
383} // namespace webrtc