blob: c46bd04ed7372b1f9858ddbadc140adcc443574a [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
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +000032} // namespace
33
34namespace webrtc {
35
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +000036namespace paced_sender {
37struct Packet {
38 Packet(uint32_t ssrc, uint16_t seq_number, int64_t capture_time_ms,
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +000039 int64_t enqueue_time_ms, int length_in_bytes, bool retransmission)
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +000040 : ssrc_(ssrc),
41 sequence_number_(seq_number),
42 capture_time_ms_(capture_time_ms),
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +000043 enqueue_time_ms_(enqueue_time_ms),
stefan@webrtc.org9b82f5a2013-11-13 15:29:21 +000044 bytes_(length_in_bytes),
45 retransmission_(retransmission) {
pwestin@webrtc.org52aa0192013-04-25 17:35:56 +000046 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +000047 uint32_t ssrc_;
48 uint16_t sequence_number_;
49 int64_t capture_time_ms_;
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +000050 int64_t enqueue_time_ms_;
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +000051 int bytes_;
stefan@webrtc.org9b82f5a2013-11-13 15:29:21 +000052 bool retransmission_;
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +000053};
54
55// STL list style class which prevents duplicates in the list.
56class PacketList {
57 public:
58 PacketList() {};
59
60 bool empty() const {
61 return packet_list_.empty();
62 }
63
64 Packet front() const {
65 return packet_list_.front();
66 }
67
68 void pop_front() {
69 Packet& packet = packet_list_.front();
70 uint16_t sequence_number = packet.sequence_number_;
71 packet_list_.pop_front();
72 sequence_number_set_.erase(sequence_number);
73 }
74
75 void push_back(const Packet& packet) {
76 if (sequence_number_set_.find(packet.sequence_number_) ==
77 sequence_number_set_.end()) {
78 // Don't insert duplicates.
79 packet_list_.push_back(packet);
80 sequence_number_set_.insert(packet.sequence_number_);
81 }
82 }
83
84 private:
85 std::list<Packet> packet_list_;
86 std::set<uint16_t> sequence_number_set_;
87};
88
89class IntervalBudget {
90 public:
91 explicit IntervalBudget(int initial_target_rate_kbps)
92 : target_rate_kbps_(initial_target_rate_kbps),
93 bytes_remaining_(0) {}
94
95 void set_target_rate_kbps(int target_rate_kbps) {
96 target_rate_kbps_ = target_rate_kbps;
97 }
98
99 void IncreaseBudget(int delta_time_ms) {
100 int bytes = target_rate_kbps_ * delta_time_ms / 8;
101 if (bytes_remaining_ < 0) {
102 // We overused last interval, compensate this interval.
103 bytes_remaining_ = bytes_remaining_ + bytes;
104 } else {
105 // If we underused last interval we can't use it this interval.
106 bytes_remaining_ = bytes;
107 }
108 }
109
110 void UseBudget(int bytes) {
111 bytes_remaining_ = std::max(bytes_remaining_ - bytes,
stefan@webrtc.orgef2d5542013-11-21 14:37:11 +0000112 -500 * target_rate_kbps_ / 8);
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000113 }
114
115 int bytes_remaining() const { return bytes_remaining_; }
116
117 private:
118 int target_rate_kbps_;
119 int bytes_remaining_;
120};
121} // namespace paced_sender
pwestin@webrtc.org52aa0192013-04-25 17:35:56 +0000122
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000123PacedSender::PacedSender(Callback* callback, int target_bitrate_kbps,
124 float pace_multiplier)
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000125 : callback_(callback),
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000126 pace_multiplier_(pace_multiplier),
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000127 enabled_(false),
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000128 paused_(false),
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000129 max_queue_length_ms_(kDefaultMaxQueueLengthMs),
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000130 critsect_(CriticalSectionWrapper::CreateCriticalSection()),
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000131 media_budget_(new paced_sender::IntervalBudget(
132 pace_multiplier_ * target_bitrate_kbps)),
stefan@webrtc.orgb2c8a952013-09-06 13:58:01 +0000133 padding_budget_(new paced_sender::IntervalBudget(0)),
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000134 // No padding until UpdateBitrate is called.
135 pad_up_to_bitrate_budget_(new paced_sender::IntervalBudget(0)),
pwestin@webrtc.org52b4e882013-05-02 19:02:17 +0000136 time_last_update_(TickTime::Now()),
137 capture_time_ms_last_queued_(0),
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000138 capture_time_ms_last_sent_(0),
139 high_priority_packets_(new paced_sender::PacketList),
140 normal_priority_packets_(new paced_sender::PacketList),
141 low_priority_packets_(new paced_sender::PacketList) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000142 UpdateBytesPerInterval(kMinPacketLimitMs);
143}
144
145PacedSender::~PacedSender() {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000146}
147
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000148void PacedSender::Pause() {
149 CriticalSectionScoped cs(critsect_.get());
150 paused_ = true;
151}
152
153void PacedSender::Resume() {
154 CriticalSectionScoped cs(critsect_.get());
155 paused_ = false;
156}
157
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000158void PacedSender::SetStatus(bool enable) {
159 CriticalSectionScoped cs(critsect_.get());
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000160 enabled_ = enable;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000161}
162
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000163bool PacedSender::Enabled() const {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000164 CriticalSectionScoped cs(critsect_.get());
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000165 return enabled_;
166}
167
168void PacedSender::UpdateBitrate(int target_bitrate_kbps,
stefan@webrtc.orgb2c8a952013-09-06 13:58:01 +0000169 int max_padding_bitrate_kbps,
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000170 int pad_up_to_bitrate_kbps) {
171 CriticalSectionScoped cs(critsect_.get());
172 media_budget_->set_target_rate_kbps(pace_multiplier_ * target_bitrate_kbps);
stefan@webrtc.orgb2c8a952013-09-06 13:58:01 +0000173 padding_budget_->set_target_rate_kbps(max_padding_bitrate_kbps);
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000174 pad_up_to_bitrate_budget_->set_target_rate_kbps(pad_up_to_bitrate_kbps);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000175}
176
177bool PacedSender::SendPacket(Priority priority, uint32_t ssrc,
stefan@webrtc.org9b82f5a2013-11-13 15:29:21 +0000178 uint16_t sequence_number, int64_t capture_time_ms, int bytes,
179 bool retransmission) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000180 CriticalSectionScoped cs(critsect_.get());
181
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000182 if (!enabled_) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000183 return true; // We can send now.
184 }
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000185 if (capture_time_ms < 0) {
186 capture_time_ms = TickTime::MillisecondTimestamp();
187 }
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000188 if (priority != kHighPriority &&
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000189 capture_time_ms > capture_time_ms_last_queued_) {
190 capture_time_ms_last_queued_ = capture_time_ms;
191 TRACE_EVENT_ASYNC_BEGIN1("webrtc_rtp", "PacedSend", capture_time_ms,
192 "capture_time_ms", capture_time_ms);
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000193 }
stefan@webrtc.org8ad3ec92013-06-04 09:52:46 +0000194 paced_sender::PacketList* packet_list = NULL;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000195 switch (priority) {
196 case kHighPriority:
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000197 packet_list = high_priority_packets_.get();
198 break;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000199 case kNormalPriority:
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000200 packet_list = normal_priority_packets_.get();
201 break;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000202 case kLowPriority:
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000203 packet_list = low_priority_packets_.get();
204 break;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000205 }
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000206 packet_list->push_back(paced_sender::Packet(ssrc,
207 sequence_number,
208 capture_time_ms,
209 TickTime::MillisecondTimestamp(),
210 bytes,
stefan@webrtc.org9b82f5a2013-11-13 15:29:21 +0000211 retransmission));
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000212 return false;
213}
214
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000215void PacedSender::set_max_queue_length_ms(int max_queue_length_ms) {
216 CriticalSectionScoped cs(critsect_.get());
217 max_queue_length_ms_ = max_queue_length_ms;
218}
219
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000220int PacedSender::QueueInMs() const {
221 CriticalSectionScoped cs(critsect_.get());
222 int64_t now_ms = TickTime::MillisecondTimestamp();
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000223 int64_t oldest_packet_enqueue_time = now_ms;
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000224 if (!high_priority_packets_->empty()) {
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000225 oldest_packet_enqueue_time = std::min(
226 oldest_packet_enqueue_time,
227 high_priority_packets_->front().enqueue_time_ms_);
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000228 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000229 if (!normal_priority_packets_->empty()) {
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000230 oldest_packet_enqueue_time = std::min(
231 oldest_packet_enqueue_time,
232 normal_priority_packets_->front().enqueue_time_ms_);
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000233 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000234 if (!low_priority_packets_->empty()) {
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000235 oldest_packet_enqueue_time = std::min(
236 oldest_packet_enqueue_time,
237 low_priority_packets_->front().enqueue_time_ms_);
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000238 }
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000239 return now_ms - oldest_packet_enqueue_time;
stefan@webrtc.orgbfacda62013-03-27 16:36:01 +0000240}
241
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000242int32_t PacedSender::TimeUntilNextProcess() {
243 CriticalSectionScoped cs(critsect_.get());
244 int64_t elapsed_time_ms =
245 (TickTime::Now() - time_last_update_).Milliseconds();
246 if (elapsed_time_ms <= 0) {
247 return kMinPacketLimitMs;
248 }
249 if (elapsed_time_ms >= kMinPacketLimitMs) {
250 return 0;
251 }
252 return kMinPacketLimitMs - elapsed_time_ms;
253}
254
255int32_t PacedSender::Process() {
256 TickTime now = TickTime::Now();
257 CriticalSectionScoped cs(critsect_.get());
258 int elapsed_time_ms = (now - time_last_update_).Milliseconds();
259 time_last_update_ = now;
stefan@webrtc.org80865fd2013-08-09 11:31:23 +0000260 if (!enabled_) {
261 return 0;
262 }
stefan@webrtc.org8ccb9f92013-06-19 14:13:42 +0000263 if (!paused_) {
264 if (elapsed_time_ms > 0) {
265 uint32_t delta_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms);
266 UpdateBytesPerInterval(delta_time_ms);
267 }
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000268 paced_sender::PacketList* packet_list;
269 while (ShouldSendNextPacket(&packet_list)) {
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000270 if (!SendPacketFromList(packet_list))
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000271 return 0;
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000272 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000273 if (high_priority_packets_->empty() &&
274 normal_priority_packets_->empty() &&
275 low_priority_packets_->empty() &&
276 padding_budget_->bytes_remaining() > 0 &&
277 pad_up_to_bitrate_budget_->bytes_remaining() > 0) {
278 int padding_needed = std::min(
279 padding_budget_->bytes_remaining(),
280 pad_up_to_bitrate_budget_->bytes_remaining());
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000281 critsect_->Leave();
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000282 int bytes_sent = callback_->TimeToSendPadding(padding_needed);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000283 critsect_->Enter();
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000284 media_budget_->UseBudget(bytes_sent);
285 padding_budget_->UseBudget(bytes_sent);
286 pad_up_to_bitrate_budget_->UseBudget(bytes_sent);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000287 }
288 }
289 return 0;
290}
291
292// MUST have critsect_ when calling.
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000293bool PacedSender::SendPacketFromList(paced_sender::PacketList* packet_list) {
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000294 paced_sender::Packet packet = GetNextPacketFromList(packet_list);
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000295 critsect_->Leave();
296
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000297 const bool success = callback_->TimeToSendPacket(packet.ssrc_,
298 packet.sequence_number_,
299 packet.capture_time_ms_,
300 packet.retransmission_);
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000301 critsect_->Enter();
302 // If packet cannot be sent then keep it in packet list and exit early.
303 // There's no need to send more packets.
304 if (!success) {
305 return false;
306 }
307 packet_list->pop_front();
308 const bool last_packet = packet_list->empty() ||
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000309 packet_list->front().capture_time_ms_ > packet.capture_time_ms_;
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000310 if (packet_list != high_priority_packets_.get()) {
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000311 if (packet.capture_time_ms_ > capture_time_ms_last_sent_) {
312 capture_time_ms_last_sent_ = packet.capture_time_ms_;
313 } else if (packet.capture_time_ms_ == capture_time_ms_last_sent_ &&
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000314 last_packet) {
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000315 TRACE_EVENT_ASYNC_END0("webrtc_rtp", "PacedSend",
316 packet.capture_time_ms_);
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000317 }
318 }
319 return true;
320}
321
322// MUST have critsect_ when calling.
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000323void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) {
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000324 media_budget_->IncreaseBudget(delta_time_ms);
325 padding_budget_->IncreaseBudget(delta_time_ms);
326 pad_up_to_bitrate_budget_->IncreaseBudget(delta_time_ms);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000327}
328
329// MUST have critsect_ when calling.
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000330bool PacedSender::ShouldSendNextPacket(paced_sender::PacketList** packet_list) {
stefan@webrtc.orgb627f672013-11-28 14:00:09 +0000331 *packet_list = NULL;
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000332 if (media_budget_->bytes_remaining() <= 0) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000333 // All bytes consumed for this interval.
334 // Check if we have not sent in a too long time.
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000335 if ((TickTime::Now() - time_last_send_).Milliseconds() >
336 kMaxQueueTimeWithoutSendingMs) {
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000337 if (!high_priority_packets_->empty()) {
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000338 *packet_list = high_priority_packets_.get();
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000339 return true;
340 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000341 if (!normal_priority_packets_->empty()) {
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000342 *packet_list = normal_priority_packets_.get();
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000343 return true;
344 }
345 }
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000346 // Send any old packets to avoid queuing for too long.
347 if (max_queue_length_ms_ >= 0 && QueueInMs() > max_queue_length_ms_) {
348 int64_t high_priority_capture_time = -1;
349 if (!high_priority_packets_->empty()) {
350 high_priority_capture_time =
351 high_priority_packets_->front().capture_time_ms_;
352 *packet_list = high_priority_packets_.get();
353 }
stefan@webrtc.orgb627f672013-11-28 14:00:09 +0000354 if (!normal_priority_packets_->empty() &&
355 (high_priority_capture_time == -1 || high_priority_capture_time >
356 normal_priority_packets_->front().capture_time_ms_)) {
stefan@webrtc.org19a40ff2013-11-27 14:16:20 +0000357 *packet_list = normal_priority_packets_.get();
358 }
359 if (*packet_list)
360 return true;
361 }
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000362 return false;
363 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000364 if (!high_priority_packets_->empty()) {
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000365 *packet_list = high_priority_packets_.get();
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000366 return true;
367 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000368 if (!normal_priority_packets_->empty()) {
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000369 *packet_list = normal_priority_packets_.get();
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000370 return true;
371 }
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000372 if (!low_priority_packets_->empty()) {
hclam@chromium.org2e402ce2013-06-20 20:18:31 +0000373 *packet_list = low_priority_packets_.get();
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000374 return true;
375 }
376 return false;
377}
378
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000379paced_sender::Packet PacedSender::GetNextPacketFromList(
380 paced_sender::PacketList* packets) {
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000381 paced_sender::Packet packet = packets->front();
382 UpdateMediaBytesSent(packet.bytes_);
stefan@webrtc.orgdd393e72013-12-13 22:03:27 +0000383 return packet;
pwestin@webrtc.orgdb418562013-03-22 23:39:29 +0000384}
385
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000386// MUST have critsect_ when calling.
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000387void PacedSender::UpdateMediaBytesSent(int num_bytes) {
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000388 time_last_send_ = TickTime::Now();
stefan@webrtc.orgc3cc3752013-06-04 09:36:56 +0000389 media_budget_->UseBudget(num_bytes);
390 pad_up_to_bitrate_budget_->UseBudget(num_bytes);
pwestin@webrtc.orgb5180172012-11-09 20:56:23 +0000391}
392
393} // namespace webrtc