blob: 4f3fbd3ad2f5a268488cf47aeab17e65d8497928 [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
15#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
16
17namespace {
18// Multiplicative factor that is applied to the target bitrate to calculate the
19// number of bytes that can be transmitted per interval.
20// Increasing this factor will result in lower delays in cases of bitrate
21// overshoots from the encoder.
22const float kBytesPerIntervalMargin = 1.5f;
23
24// Time limit in milliseconds between packet bursts.
25const int kMinPacketLimitMs = 5;
26
27// Upper cap on process interval, in case process has not been called in a long
28// time.
29const int kMaxIntervalTimeMs = 30;
30
31// Max time that the first packet in the queue can sit in the queue if no
32// packets are sent, regardless of buffer state. In practice only in effect at
33// low bitrates (less than 320 kbits/s).
34const int kMaxQueueTimeWithoutSendingMs = 30;
35} // namespace
36
37namespace webrtc {
38
39PacedSender::PacedSender(Callback* callback, int target_bitrate_kbps)
40 : callback_(callback),
41 enable_(false),
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +000042 paused_(false),
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000043 critsect_(CriticalSectionWrapper::CreateCriticalSection()),
44 target_bitrate_kbytes_per_s_(target_bitrate_kbps >> 3), // Divide by 8.
45 bytes_remaining_interval_(0),
46 padding_bytes_remaining_interval_(0),
47 time_last_update_(TickTime::Now()) {
48 UpdateBytesPerInterval(kMinPacketLimitMs);
49}
50
51PacedSender::~PacedSender() {
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +000052 high_priority_packets_.clear();
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000053 normal_priority_packets_.clear();
54 low_priority_packets_.clear();
55}
56
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +000057void PacedSender::Pause() {
58 CriticalSectionScoped cs(critsect_.get());
59 paused_ = true;
60}
61
62void PacedSender::Resume() {
63 CriticalSectionScoped cs(critsect_.get());
64 paused_ = false;
65}
66
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000067void PacedSender::SetStatus(bool enable) {
68 CriticalSectionScoped cs(critsect_.get());
69 enable_ = enable;
70}
71
72void PacedSender::UpdateBitrate(int target_bitrate_kbps) {
73 CriticalSectionScoped cs(critsect_.get());
74 target_bitrate_kbytes_per_s_ = target_bitrate_kbps >> 3; // Divide by 8.
75}
76
77bool PacedSender::SendPacket(Priority priority, uint32_t ssrc,
78 uint16_t sequence_number, int64_t capture_time_ms, int bytes) {
79 CriticalSectionScoped cs(critsect_.get());
80
81 if (!enable_) {
82 UpdateState(bytes);
83 return true; // We can send now.
84 }
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +000085 if (capture_time_ms < 0) {
86 capture_time_ms = TickTime::MillisecondTimestamp();
87 }
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +000088 if (paused_) {
89 // Queue all packets when we are paused.
90 switch (priority) {
91 case kHighPriority:
92 high_priority_packets_.push_back(
93 Packet(ssrc, sequence_number, capture_time_ms, bytes));
94 break;
95 case kNormalPriority:
96 case kLowPriority:
97 // Queue the low priority packets in the normal priority queue when we
98 // are paused to avoid starvation.
99 normal_priority_packets_.push_back(
100 Packet(ssrc, sequence_number, capture_time_ms, bytes));
101 break;
102 }
103 return false;
104 }
105
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000106 switch (priority) {
107 case kHighPriority:
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000108 if (high_priority_packets_.empty() &&
109 bytes_remaining_interval_ > 0) {
110 UpdateState(bytes);
111 return true; // We can send now.
112 }
113 high_priority_packets_.push_back(
114 Packet(ssrc, sequence_number, capture_time_ms, bytes));
115 return false;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000116 case kNormalPriority:
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000117 if (high_priority_packets_.empty() &&
118 normal_priority_packets_.empty() &&
119 bytes_remaining_interval_ > 0) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000120 UpdateState(bytes);
121 return true; // We can send now.
122 }
123 normal_priority_packets_.push_back(
124 Packet(ssrc, sequence_number, capture_time_ms, bytes));
125 return false;
126 case kLowPriority:
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000127 if (high_priority_packets_.empty() &&
128 normal_priority_packets_.empty() &&
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000129 low_priority_packets_.empty() &&
130 bytes_remaining_interval_ > 0) {
131 UpdateState(bytes);
132 return true; // We can send now.
133 }
134 low_priority_packets_.push_back(
135 Packet(ssrc, sequence_number, capture_time_ms, bytes));
136 return false;
137 }
138 return false;
139}
140
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000141int PacedSender::QueueInMs() const {
142 CriticalSectionScoped cs(critsect_.get());
143 int64_t now_ms = TickTime::MillisecondTimestamp();
144 int64_t oldest_packet_capture_time = now_ms;
145 if (!high_priority_packets_.empty()) {
146 oldest_packet_capture_time = std::min(
147 oldest_packet_capture_time,
148 high_priority_packets_.front().capture_time_ms_);
149 }
150 if (!normal_priority_packets_.empty()) {
151 oldest_packet_capture_time = std::min(
152 oldest_packet_capture_time,
153 normal_priority_packets_.front().capture_time_ms_);
154 }
155 if (!low_priority_packets_.empty()) {
156 oldest_packet_capture_time = std::min(
157 oldest_packet_capture_time,
158 low_priority_packets_.front().capture_time_ms_);
159 }
160 return now_ms - oldest_packet_capture_time;
161}
162
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000163int32_t PacedSender::TimeUntilNextProcess() {
164 CriticalSectionScoped cs(critsect_.get());
165 int64_t elapsed_time_ms =
166 (TickTime::Now() - time_last_update_).Milliseconds();
167 if (elapsed_time_ms <= 0) {
168 return kMinPacketLimitMs;
169 }
170 if (elapsed_time_ms >= kMinPacketLimitMs) {
171 return 0;
172 }
173 return kMinPacketLimitMs - elapsed_time_ms;
174}
175
176int32_t PacedSender::Process() {
177 TickTime now = TickTime::Now();
178 CriticalSectionScoped cs(critsect_.get());
179 int elapsed_time_ms = (now - time_last_update_).Milliseconds();
180 time_last_update_ = now;
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000181 if (!paused_ && elapsed_time_ms > 0) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000182 uint32_t delta_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms);
183 UpdateBytesPerInterval(delta_time_ms);
184 uint32_t ssrc;
185 uint16_t sequence_number;
186 int64_t capture_time_ms;
187 while (GetNextPacket(&ssrc, &sequence_number, &capture_time_ms)) {
188 critsect_->Leave();
189 callback_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms);
190 critsect_->Enter();
191 }
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000192 if (high_priority_packets_.empty() &&
193 normal_priority_packets_.empty() &&
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000194 low_priority_packets_.empty() &&
195 padding_bytes_remaining_interval_ > 0) {
196 critsect_->Leave();
197 callback_->TimeToSendPadding(padding_bytes_remaining_interval_);
198 critsect_->Enter();
199 padding_bytes_remaining_interval_ = 0;
200 bytes_remaining_interval_ -= padding_bytes_remaining_interval_;
201 }
202 }
203 return 0;
204}
205
206// MUST have critsect_ when calling.
207void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) {
208 uint32_t bytes_per_interval = target_bitrate_kbytes_per_s_ * delta_time_ms;
209
210 if (bytes_remaining_interval_ < 0) {
211 // We overused last interval, compensate this interval.
212 bytes_remaining_interval_ += kBytesPerIntervalMargin * bytes_per_interval;
213 } else {
214 // If we underused last interval we can't use it this interval.
215 bytes_remaining_interval_ = kBytesPerIntervalMargin * bytes_per_interval;
216 }
217 if (padding_bytes_remaining_interval_ < 0) {
218 // We overused last interval, compensate this interval.
219 padding_bytes_remaining_interval_ += bytes_per_interval;
220 } else {
221 // If we underused last interval we can't use it this interval.
222 padding_bytes_remaining_interval_ = bytes_per_interval;
223 }
224}
225
226// MUST have critsect_ when calling.
227bool PacedSender::GetNextPacket(uint32_t* ssrc, uint16_t* sequence_number,
228 int64_t* capture_time_ms) {
229 if (bytes_remaining_interval_ <= 0) {
230 // All bytes consumed for this interval.
231 // Check if we have not sent in a too long time.
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000232 if ((TickTime::Now() - time_last_send_).Milliseconds() >
233 kMaxQueueTimeWithoutSendingMs) {
234 if (!high_priority_packets_.empty()) {
235 GetNextPacketFromList(&high_priority_packets_, ssrc, sequence_number,
236 capture_time_ms);
237 return true;
238 }
239 if (!normal_priority_packets_.empty()) {
240 GetNextPacketFromList(&normal_priority_packets_, ssrc, sequence_number,
241 capture_time_ms);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000242 return true;
243 }
244 }
245 return false;
246 }
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000247 if (!high_priority_packets_.empty()) {
248 GetNextPacketFromList(&high_priority_packets_, ssrc, sequence_number,
249 capture_time_ms);
250 return true;
251 }
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000252 if (!normal_priority_packets_.empty()) {
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000253 GetNextPacketFromList(&normal_priority_packets_, ssrc, sequence_number,
254 capture_time_ms);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000255 return true;
256 }
257 if (!low_priority_packets_.empty()) {
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000258 GetNextPacketFromList(&low_priority_packets_, ssrc, sequence_number,
259 capture_time_ms);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000260 return true;
261 }
262 return false;
263}
264
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000265void PacedSender::GetNextPacketFromList(std::list<Packet>* list,
266 uint32_t* ssrc, uint16_t* sequence_number, int64_t* capture_time_ms) {
267 Packet packet = list->front();
268 UpdateState(packet.bytes_);
269 *sequence_number = packet.sequence_number_;
270 *ssrc = packet.ssrc_;
271 *capture_time_ms = packet.capture_time_ms_;
272 list->pop_front();
273}
274
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000275// MUST have critsect_ when calling.
276void PacedSender::UpdateState(int num_bytes) {
277 time_last_send_ = TickTime::Now();
278 bytes_remaining_interval_ -= num_bytes;
279 padding_bytes_remaining_interval_ -= num_bytes;
280}
281
282} // namespace webrtc