blob: 1d2c7006e487240b37042e82e0c8b6981e0f1ada [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
pwestin@webrtc.org52aa0192013-04-25 17:35:56 +000039bool PacedSender::PacketList::empty() const {
40 return packet_list_.empty();
41}
42
43PacedSender::Packet PacedSender::PacketList::front() const {
44 return packet_list_.front();
45}
46
47void PacedSender::PacketList::pop_front() {
48 PacedSender::Packet& packet = packet_list_.front();
49 packet_list_.pop_front();
50 sequence_number_set_.erase(packet.sequence_number_);
51}
52
53void PacedSender::PacketList::push_back(const PacedSender::Packet& packet) {
54 if (sequence_number_set_.find(packet.sequence_number_) ==
55 sequence_number_set_.end()) {
56 // Don't insert duplicates.
57 packet_list_.push_back(packet);
58 sequence_number_set_.insert(packet.sequence_number_);
59 }
60}
61
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000062PacedSender::PacedSender(Callback* callback, int target_bitrate_kbps)
63 : callback_(callback),
64 enable_(false),
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +000065 paused_(false),
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000066 critsect_(CriticalSectionWrapper::CreateCriticalSection()),
67 target_bitrate_kbytes_per_s_(target_bitrate_kbps >> 3), // Divide by 8.
68 bytes_remaining_interval_(0),
69 padding_bytes_remaining_interval_(0),
70 time_last_update_(TickTime::Now()) {
71 UpdateBytesPerInterval(kMinPacketLimitMs);
72}
73
74PacedSender::~PacedSender() {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000075}
76
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +000077void PacedSender::Pause() {
78 CriticalSectionScoped cs(critsect_.get());
79 paused_ = true;
80}
81
82void PacedSender::Resume() {
83 CriticalSectionScoped cs(critsect_.get());
84 paused_ = false;
85}
86
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000087void PacedSender::SetStatus(bool enable) {
88 CriticalSectionScoped cs(critsect_.get());
89 enable_ = enable;
90}
91
92void PacedSender::UpdateBitrate(int target_bitrate_kbps) {
93 CriticalSectionScoped cs(critsect_.get());
94 target_bitrate_kbytes_per_s_ = target_bitrate_kbps >> 3; // Divide by 8.
95}
96
97bool PacedSender::SendPacket(Priority priority, uint32_t ssrc,
98 uint16_t sequence_number, int64_t capture_time_ms, int bytes) {
99 CriticalSectionScoped cs(critsect_.get());
100
101 if (!enable_) {
102 UpdateState(bytes);
103 return true; // We can send now.
104 }
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000105 if (capture_time_ms < 0) {
106 capture_time_ms = TickTime::MillisecondTimestamp();
107 }
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000108 if (paused_) {
109 // Queue all packets when we are paused.
110 switch (priority) {
111 case kHighPriority:
112 high_priority_packets_.push_back(
113 Packet(ssrc, sequence_number, capture_time_ms, bytes));
114 break;
115 case kNormalPriority:
116 case kLowPriority:
117 // Queue the low priority packets in the normal priority queue when we
118 // are paused to avoid starvation.
119 normal_priority_packets_.push_back(
120 Packet(ssrc, sequence_number, capture_time_ms, bytes));
121 break;
122 }
123 return false;
124 }
125
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000126 switch (priority) {
127 case kHighPriority:
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000128 if (high_priority_packets_.empty() &&
129 bytes_remaining_interval_ > 0) {
130 UpdateState(bytes);
131 return true; // We can send now.
132 }
133 high_priority_packets_.push_back(
134 Packet(ssrc, sequence_number, capture_time_ms, bytes));
135 return false;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000136 case kNormalPriority:
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000137 if (high_priority_packets_.empty() &&
138 normal_priority_packets_.empty() &&
139 bytes_remaining_interval_ > 0) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000140 UpdateState(bytes);
141 return true; // We can send now.
142 }
143 normal_priority_packets_.push_back(
144 Packet(ssrc, sequence_number, capture_time_ms, bytes));
145 return false;
146 case kLowPriority:
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000147 if (high_priority_packets_.empty() &&
148 normal_priority_packets_.empty() &&
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000149 low_priority_packets_.empty() &&
150 bytes_remaining_interval_ > 0) {
151 UpdateState(bytes);
152 return true; // We can send now.
153 }
154 low_priority_packets_.push_back(
155 Packet(ssrc, sequence_number, capture_time_ms, bytes));
156 return false;
157 }
158 return false;
159}
160
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000161int PacedSender::QueueInMs() const {
162 CriticalSectionScoped cs(critsect_.get());
163 int64_t now_ms = TickTime::MillisecondTimestamp();
164 int64_t oldest_packet_capture_time = now_ms;
165 if (!high_priority_packets_.empty()) {
166 oldest_packet_capture_time = std::min(
167 oldest_packet_capture_time,
168 high_priority_packets_.front().capture_time_ms_);
169 }
170 if (!normal_priority_packets_.empty()) {
171 oldest_packet_capture_time = std::min(
172 oldest_packet_capture_time,
173 normal_priority_packets_.front().capture_time_ms_);
174 }
175 if (!low_priority_packets_.empty()) {
176 oldest_packet_capture_time = std::min(
177 oldest_packet_capture_time,
178 low_priority_packets_.front().capture_time_ms_);
179 }
180 return now_ms - oldest_packet_capture_time;
181}
182
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000183int32_t PacedSender::TimeUntilNextProcess() {
184 CriticalSectionScoped cs(critsect_.get());
185 int64_t elapsed_time_ms =
186 (TickTime::Now() - time_last_update_).Milliseconds();
187 if (elapsed_time_ms <= 0) {
188 return kMinPacketLimitMs;
189 }
190 if (elapsed_time_ms >= kMinPacketLimitMs) {
191 return 0;
192 }
193 return kMinPacketLimitMs - elapsed_time_ms;
194}
195
196int32_t PacedSender::Process() {
197 TickTime now = TickTime::Now();
198 CriticalSectionScoped cs(critsect_.get());
199 int elapsed_time_ms = (now - time_last_update_).Milliseconds();
200 time_last_update_ = now;
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000201 if (!paused_ && elapsed_time_ms > 0) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000202 uint32_t delta_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms);
203 UpdateBytesPerInterval(delta_time_ms);
204 uint32_t ssrc;
205 uint16_t sequence_number;
206 int64_t capture_time_ms;
207 while (GetNextPacket(&ssrc, &sequence_number, &capture_time_ms)) {
208 critsect_->Leave();
209 callback_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms);
210 critsect_->Enter();
211 }
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000212 if (high_priority_packets_.empty() &&
213 normal_priority_packets_.empty() &&
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000214 low_priority_packets_.empty() &&
215 padding_bytes_remaining_interval_ > 0) {
216 critsect_->Leave();
217 callback_->TimeToSendPadding(padding_bytes_remaining_interval_);
218 critsect_->Enter();
219 padding_bytes_remaining_interval_ = 0;
220 bytes_remaining_interval_ -= padding_bytes_remaining_interval_;
221 }
222 }
223 return 0;
224}
225
226// MUST have critsect_ when calling.
227void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) {
228 uint32_t bytes_per_interval = target_bitrate_kbytes_per_s_ * delta_time_ms;
229
230 if (bytes_remaining_interval_ < 0) {
231 // We overused last interval, compensate this interval.
232 bytes_remaining_interval_ += kBytesPerIntervalMargin * bytes_per_interval;
233 } else {
234 // If we underused last interval we can't use it this interval.
235 bytes_remaining_interval_ = kBytesPerIntervalMargin * bytes_per_interval;
236 }
237 if (padding_bytes_remaining_interval_ < 0) {
238 // We overused last interval, compensate this interval.
239 padding_bytes_remaining_interval_ += bytes_per_interval;
240 } else {
241 // If we underused last interval we can't use it this interval.
242 padding_bytes_remaining_interval_ = bytes_per_interval;
243 }
244}
245
246// MUST have critsect_ when calling.
247bool PacedSender::GetNextPacket(uint32_t* ssrc, uint16_t* sequence_number,
248 int64_t* capture_time_ms) {
249 if (bytes_remaining_interval_ <= 0) {
250 // All bytes consumed for this interval.
251 // Check if we have not sent in a too long time.
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000252 if ((TickTime::Now() - time_last_send_).Milliseconds() >
253 kMaxQueueTimeWithoutSendingMs) {
254 if (!high_priority_packets_.empty()) {
255 GetNextPacketFromList(&high_priority_packets_, ssrc, sequence_number,
256 capture_time_ms);
257 return true;
258 }
259 if (!normal_priority_packets_.empty()) {
260 GetNextPacketFromList(&normal_priority_packets_, ssrc, sequence_number,
261 capture_time_ms);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000262 return true;
263 }
264 }
265 return false;
266 }
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000267 if (!high_priority_packets_.empty()) {
268 GetNextPacketFromList(&high_priority_packets_, ssrc, sequence_number,
269 capture_time_ms);
270 return true;
271 }
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000272 if (!normal_priority_packets_.empty()) {
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000273 GetNextPacketFromList(&normal_priority_packets_, ssrc, sequence_number,
274 capture_time_ms);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000275 return true;
276 }
277 if (!low_priority_packets_.empty()) {
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000278 GetNextPacketFromList(&low_priority_packets_, ssrc, sequence_number,
279 capture_time_ms);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000280 return true;
281 }
282 return false;
283}
284
pwestin@webrtc.org52aa0192013-04-25 17:35:56 +0000285void PacedSender::GetNextPacketFromList(PacketList* list,
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000286 uint32_t* ssrc, uint16_t* sequence_number, int64_t* capture_time_ms) {
287 Packet packet = list->front();
288 UpdateState(packet.bytes_);
289 *sequence_number = packet.sequence_number_;
290 *ssrc = packet.ssrc_;
291 *capture_time_ms = packet.capture_time_ms_;
292 list->pop_front();
293}
294
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000295// MUST have critsect_ when calling.
296void PacedSender::UpdateState(int num_bytes) {
297 time_last_send_ = TickTime::Now();
298 bytes_remaining_interval_ -= num_bytes;
299 padding_bytes_remaining_interval_ -= num_bytes;
300}
301
302} // namespace webrtc