blob: 1001b33a90a02968df9504fc369a4aafeb717809 [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 }
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +000085 if (paused_) {
86 // Queue all packets when we are paused.
87 switch (priority) {
88 case kHighPriority:
89 high_priority_packets_.push_back(
90 Packet(ssrc, sequence_number, capture_time_ms, bytes));
91 break;
92 case kNormalPriority:
93 case kLowPriority:
94 // Queue the low priority packets in the normal priority queue when we
95 // are paused to avoid starvation.
96 normal_priority_packets_.push_back(
97 Packet(ssrc, sequence_number, capture_time_ms, bytes));
98 break;
99 }
100 return false;
101 }
102
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000103 switch (priority) {
104 case kHighPriority:
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000105 if (high_priority_packets_.empty() &&
106 bytes_remaining_interval_ > 0) {
107 UpdateState(bytes);
108 return true; // We can send now.
109 }
110 high_priority_packets_.push_back(
111 Packet(ssrc, sequence_number, capture_time_ms, bytes));
112 return false;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000113 case kNormalPriority:
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000114 if (high_priority_packets_.empty() &&
115 normal_priority_packets_.empty() &&
116 bytes_remaining_interval_ > 0) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000117 UpdateState(bytes);
118 return true; // We can send now.
119 }
120 normal_priority_packets_.push_back(
121 Packet(ssrc, sequence_number, capture_time_ms, bytes));
122 return false;
123 case kLowPriority:
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000124 if (high_priority_packets_.empty() &&
125 normal_priority_packets_.empty() &&
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000126 low_priority_packets_.empty() &&
127 bytes_remaining_interval_ > 0) {
128 UpdateState(bytes);
129 return true; // We can send now.
130 }
131 low_priority_packets_.push_back(
132 Packet(ssrc, sequence_number, capture_time_ms, bytes));
133 return false;
134 }
135 return false;
136}
137
138int32_t PacedSender::TimeUntilNextProcess() {
139 CriticalSectionScoped cs(critsect_.get());
140 int64_t elapsed_time_ms =
141 (TickTime::Now() - time_last_update_).Milliseconds();
142 if (elapsed_time_ms <= 0) {
143 return kMinPacketLimitMs;
144 }
145 if (elapsed_time_ms >= kMinPacketLimitMs) {
146 return 0;
147 }
148 return kMinPacketLimitMs - elapsed_time_ms;
149}
150
151int32_t PacedSender::Process() {
152 TickTime now = TickTime::Now();
153 CriticalSectionScoped cs(critsect_.get());
154 int elapsed_time_ms = (now - time_last_update_).Milliseconds();
155 time_last_update_ = now;
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000156 if (!paused_ && elapsed_time_ms > 0) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000157 uint32_t delta_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms);
158 UpdateBytesPerInterval(delta_time_ms);
159 uint32_t ssrc;
160 uint16_t sequence_number;
161 int64_t capture_time_ms;
162 while (GetNextPacket(&ssrc, &sequence_number, &capture_time_ms)) {
163 critsect_->Leave();
164 callback_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms);
165 critsect_->Enter();
166 }
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000167 if (high_priority_packets_.empty() &&
168 normal_priority_packets_.empty() &&
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000169 low_priority_packets_.empty() &&
170 padding_bytes_remaining_interval_ > 0) {
171 critsect_->Leave();
172 callback_->TimeToSendPadding(padding_bytes_remaining_interval_);
173 critsect_->Enter();
174 padding_bytes_remaining_interval_ = 0;
175 bytes_remaining_interval_ -= padding_bytes_remaining_interval_;
176 }
177 }
178 return 0;
179}
180
181// MUST have critsect_ when calling.
182void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) {
183 uint32_t bytes_per_interval = target_bitrate_kbytes_per_s_ * delta_time_ms;
184
185 if (bytes_remaining_interval_ < 0) {
186 // We overused last interval, compensate this interval.
187 bytes_remaining_interval_ += kBytesPerIntervalMargin * bytes_per_interval;
188 } else {
189 // If we underused last interval we can't use it this interval.
190 bytes_remaining_interval_ = kBytesPerIntervalMargin * bytes_per_interval;
191 }
192 if (padding_bytes_remaining_interval_ < 0) {
193 // We overused last interval, compensate this interval.
194 padding_bytes_remaining_interval_ += bytes_per_interval;
195 } else {
196 // If we underused last interval we can't use it this interval.
197 padding_bytes_remaining_interval_ = bytes_per_interval;
198 }
199}
200
201// MUST have critsect_ when calling.
202bool PacedSender::GetNextPacket(uint32_t* ssrc, uint16_t* sequence_number,
203 int64_t* capture_time_ms) {
204 if (bytes_remaining_interval_ <= 0) {
205 // All bytes consumed for this interval.
206 // Check if we have not sent in a too long time.
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000207 if ((TickTime::Now() - time_last_send_).Milliseconds() >
208 kMaxQueueTimeWithoutSendingMs) {
209 if (!high_priority_packets_.empty()) {
210 GetNextPacketFromList(&high_priority_packets_, ssrc, sequence_number,
211 capture_time_ms);
212 return true;
213 }
214 if (!normal_priority_packets_.empty()) {
215 GetNextPacketFromList(&normal_priority_packets_, ssrc, sequence_number,
216 capture_time_ms);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000217 return true;
218 }
219 }
220 return false;
221 }
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000222 if (!high_priority_packets_.empty()) {
223 GetNextPacketFromList(&high_priority_packets_, ssrc, sequence_number,
224 capture_time_ms);
225 return true;
226 }
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000227 if (!normal_priority_packets_.empty()) {
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000228 GetNextPacketFromList(&normal_priority_packets_, ssrc, sequence_number,
229 capture_time_ms);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000230 return true;
231 }
232 if (!low_priority_packets_.empty()) {
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000233 GetNextPacketFromList(&low_priority_packets_, ssrc, sequence_number,
234 capture_time_ms);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000235 return true;
236 }
237 return false;
238}
239
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000240void PacedSender::GetNextPacketFromList(std::list<Packet>* list,
241 uint32_t* ssrc, uint16_t* sequence_number, int64_t* capture_time_ms) {
242 Packet packet = list->front();
243 UpdateState(packet.bytes_);
244 *sequence_number = packet.sequence_number_;
245 *ssrc = packet.ssrc_;
246 *capture_time_ms = packet.capture_time_ms_;
247 list->pop_front();
248}
249
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000250// MUST have critsect_ when calling.
251void PacedSender::UpdateState(int num_bytes) {
252 time_last_send_ = TickTime::Now();
253 bytes_remaining_interval_ -= num_bytes;
254 padding_bytes_remaining_interval_ -= num_bytes;
255}
256
257} // namespace webrtc