2012-11-09 20:56:23 +00:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
|
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "webrtc/modules/pacing/include/paced_sender.h"
|
|
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
2013-05-02 19:02:17 +00:00
|
|
|
#include "webrtc/modules/interface/module_common_types.h"
|
2012-11-09 20:56:23 +00:00
|
|
|
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
|
2013-05-02 19:02:17 +00:00
|
|
|
#include "webrtc/system_wrappers/interface/trace_event.h"
|
2012-11-09 20:56:23 +00:00
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
// Time limit in milliseconds between packet bursts.
|
|
|
|
|
const int kMinPacketLimitMs = 5;
|
|
|
|
|
|
|
|
|
|
// Upper cap on process interval, in case process has not been called in a long
|
|
|
|
|
// time.
|
|
|
|
|
const int kMaxIntervalTimeMs = 30;
|
|
|
|
|
|
|
|
|
|
// Max time that the first packet in the queue can sit in the queue if no
|
|
|
|
|
// packets are sent, regardless of buffer state. In practice only in effect at
|
|
|
|
|
// low bitrates (less than 320 kbits/s).
|
|
|
|
|
const int kMaxQueueTimeWithoutSendingMs = 30;
|
2013-06-04 09:36:56 +00:00
|
|
|
|
2012-11-09 20:56:23 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
namespace webrtc {
|
|
|
|
|
|
2013-06-04 09:36:56 +00:00
|
|
|
namespace paced_sender {
|
|
|
|
|
struct Packet {
|
|
|
|
|
Packet(uint32_t ssrc, uint16_t seq_number, int64_t capture_time_ms,
|
|
|
|
|
int length_in_bytes)
|
|
|
|
|
: ssrc_(ssrc),
|
|
|
|
|
sequence_number_(seq_number),
|
|
|
|
|
capture_time_ms_(capture_time_ms),
|
|
|
|
|
bytes_(length_in_bytes) {
|
|
|
|
|
}
|
|
|
|
|
uint32_t ssrc_;
|
|
|
|
|
uint16_t sequence_number_;
|
|
|
|
|
int64_t capture_time_ms_;
|
|
|
|
|
int bytes_;
|
|
|
|
|
};
|
2013-04-25 17:35:56 +00:00
|
|
|
|
2013-06-04 09:36:56 +00:00
|
|
|
// STL list style class which prevents duplicates in the list.
|
|
|
|
|
class PacketList {
|
|
|
|
|
public:
|
|
|
|
|
PacketList() {};
|
2013-04-25 17:35:56 +00:00
|
|
|
|
2013-06-04 09:36:56 +00:00
|
|
|
bool empty() const {
|
|
|
|
|
return packet_list_.empty();
|
|
|
|
|
}
|
2013-04-25 17:35:56 +00:00
|
|
|
|
2013-06-04 09:36:56 +00:00
|
|
|
Packet front() const {
|
|
|
|
|
return packet_list_.front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pop_front() {
|
|
|
|
|
Packet& packet = packet_list_.front();
|
|
|
|
|
uint16_t sequence_number = packet.sequence_number_;
|
|
|
|
|
packet_list_.pop_front();
|
|
|
|
|
sequence_number_set_.erase(sequence_number);
|
2013-04-25 17:35:56 +00:00
|
|
|
}
|
2013-06-04 09:36:56 +00:00
|
|
|
|
|
|
|
|
void push_back(const Packet& packet) {
|
|
|
|
|
if (sequence_number_set_.find(packet.sequence_number_) ==
|
|
|
|
|
sequence_number_set_.end()) {
|
|
|
|
|
// Don't insert duplicates.
|
|
|
|
|
packet_list_.push_back(packet);
|
|
|
|
|
sequence_number_set_.insert(packet.sequence_number_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::list<Packet> packet_list_;
|
|
|
|
|
std::set<uint16_t> sequence_number_set_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class IntervalBudget {
|
|
|
|
|
public:
|
|
|
|
|
explicit IntervalBudget(int initial_target_rate_kbps)
|
|
|
|
|
: target_rate_kbps_(initial_target_rate_kbps),
|
|
|
|
|
bytes_remaining_(0) {}
|
|
|
|
|
|
|
|
|
|
void set_target_rate_kbps(int target_rate_kbps) {
|
|
|
|
|
target_rate_kbps_ = target_rate_kbps;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IncreaseBudget(int delta_time_ms) {
|
|
|
|
|
int bytes = target_rate_kbps_ * delta_time_ms / 8;
|
|
|
|
|
if (bytes_remaining_ < 0) {
|
|
|
|
|
// We overused last interval, compensate this interval.
|
|
|
|
|
bytes_remaining_ = bytes_remaining_ + bytes;
|
|
|
|
|
} else {
|
|
|
|
|
// If we underused last interval we can't use it this interval.
|
|
|
|
|
bytes_remaining_ = bytes;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UseBudget(int bytes) {
|
|
|
|
|
bytes_remaining_ = std::max(bytes_remaining_ - bytes,
|
|
|
|
|
-100 * target_rate_kbps_ / 8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int bytes_remaining() const { return bytes_remaining_; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
int target_rate_kbps_;
|
|
|
|
|
int bytes_remaining_;
|
|
|
|
|
};
|
|
|
|
|
} // namespace paced_sender
|
2013-04-25 17:35:56 +00:00
|
|
|
|
2013-05-02 19:02:17 +00:00
|
|
|
PacedSender::PacedSender(Callback* callback, int target_bitrate_kbps,
|
|
|
|
|
float pace_multiplier)
|
2012-11-09 20:56:23 +00:00
|
|
|
: callback_(callback),
|
2013-05-02 19:02:17 +00:00
|
|
|
pace_multiplier_(pace_multiplier),
|
2013-06-04 09:36:56 +00:00
|
|
|
enabled_(false),
|
2013-03-22 23:39:29 +00:00
|
|
|
paused_(false),
|
2012-11-09 20:56:23 +00:00
|
|
|
critsect_(CriticalSectionWrapper::CreateCriticalSection()),
|
2013-06-04 09:36:56 +00:00
|
|
|
media_budget_(new paced_sender::IntervalBudget(
|
|
|
|
|
pace_multiplier_ * target_bitrate_kbps)),
|
2013-09-06 13:58:01 +00:00
|
|
|
padding_budget_(new paced_sender::IntervalBudget(0)),
|
2013-06-04 09:36:56 +00:00
|
|
|
// No padding until UpdateBitrate is called.
|
|
|
|
|
pad_up_to_bitrate_budget_(new paced_sender::IntervalBudget(0)),
|
2013-05-02 19:02:17 +00:00
|
|
|
time_last_update_(TickTime::Now()),
|
|
|
|
|
capture_time_ms_last_queued_(0),
|
2013-06-04 09:36:56 +00:00
|
|
|
capture_time_ms_last_sent_(0),
|
|
|
|
|
high_priority_packets_(new paced_sender::PacketList),
|
|
|
|
|
normal_priority_packets_(new paced_sender::PacketList),
|
|
|
|
|
low_priority_packets_(new paced_sender::PacketList) {
|
2012-11-09 20:56:23 +00:00
|
|
|
UpdateBytesPerInterval(kMinPacketLimitMs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PacedSender::~PacedSender() {
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-22 23:39:29 +00:00
|
|
|
void PacedSender::Pause() {
|
|
|
|
|
CriticalSectionScoped cs(critsect_.get());
|
|
|
|
|
paused_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PacedSender::Resume() {
|
|
|
|
|
CriticalSectionScoped cs(critsect_.get());
|
|
|
|
|
paused_ = false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-09 20:56:23 +00:00
|
|
|
void PacedSender::SetStatus(bool enable) {
|
|
|
|
|
CriticalSectionScoped cs(critsect_.get());
|
2013-06-04 09:36:56 +00:00
|
|
|
enabled_ = enable;
|
2012-11-09 20:56:23 +00:00
|
|
|
}
|
|
|
|
|
|
2013-06-04 09:36:56 +00:00
|
|
|
bool PacedSender::Enabled() const {
|
2012-11-09 20:56:23 +00:00
|
|
|
CriticalSectionScoped cs(critsect_.get());
|
2013-06-04 09:36:56 +00:00
|
|
|
return enabled_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PacedSender::UpdateBitrate(int target_bitrate_kbps,
|
2013-09-06 13:58:01 +00:00
|
|
|
int max_padding_bitrate_kbps,
|
2013-06-04 09:36:56 +00:00
|
|
|
int pad_up_to_bitrate_kbps) {
|
|
|
|
|
CriticalSectionScoped cs(critsect_.get());
|
|
|
|
|
media_budget_->set_target_rate_kbps(pace_multiplier_ * target_bitrate_kbps);
|
2013-09-06 13:58:01 +00:00
|
|
|
padding_budget_->set_target_rate_kbps(max_padding_bitrate_kbps);
|
2013-06-04 09:36:56 +00:00
|
|
|
pad_up_to_bitrate_budget_->set_target_rate_kbps(pad_up_to_bitrate_kbps);
|
2012-11-09 20:56:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PacedSender::SendPacket(Priority priority, uint32_t ssrc,
|
|
|
|
|
uint16_t sequence_number, int64_t capture_time_ms, int bytes) {
|
|
|
|
|
CriticalSectionScoped cs(critsect_.get());
|
|
|
|
|
|
2013-06-04 09:36:56 +00:00
|
|
|
if (!enabled_) {
|
2012-11-09 20:56:23 +00:00
|
|
|
return true; // We can send now.
|
|
|
|
|
}
|
2013-03-27 16:36:01 +00:00
|
|
|
if (capture_time_ms < 0) {
|
|
|
|
|
capture_time_ms = TickTime::MillisecondTimestamp();
|
|
|
|
|
}
|
2013-06-20 20:18:31 +00:00
|
|
|
if (priority != kHighPriority &&
|
2013-06-19 14:13:42 +00:00
|
|
|
capture_time_ms > capture_time_ms_last_queued_) {
|
|
|
|
|
capture_time_ms_last_queued_ = capture_time_ms;
|
|
|
|
|
TRACE_EVENT_ASYNC_BEGIN1("webrtc_rtp", "PacedSend", capture_time_ms,
|
|
|
|
|
"capture_time_ms", capture_time_ms);
|
2013-03-22 23:39:29 +00:00
|
|
|
}
|
2013-06-04 09:52:46 +00:00
|
|
|
paced_sender::PacketList* packet_list = NULL;
|
2012-11-09 20:56:23 +00:00
|
|
|
switch (priority) {
|
|
|
|
|
case kHighPriority:
|
2013-06-04 09:36:56 +00:00
|
|
|
packet_list = high_priority_packets_.get();
|
|
|
|
|
break;
|
2012-11-09 20:56:23 +00:00
|
|
|
case kNormalPriority:
|
2013-06-04 09:36:56 +00:00
|
|
|
packet_list = normal_priority_packets_.get();
|
|
|
|
|
break;
|
2012-11-09 20:56:23 +00:00
|
|
|
case kLowPriority:
|
2013-06-04 09:36:56 +00:00
|
|
|
packet_list = low_priority_packets_.get();
|
|
|
|
|
break;
|
2012-11-09 20:56:23 +00:00
|
|
|
}
|
2013-06-04 09:36:56 +00:00
|
|
|
packet_list->push_back(paced_sender::Packet(ssrc, sequence_number,
|
|
|
|
|
capture_time_ms, bytes));
|
2012-11-09 20:56:23 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-27 16:36:01 +00:00
|
|
|
int PacedSender::QueueInMs() const {
|
|
|
|
|
CriticalSectionScoped cs(critsect_.get());
|
|
|
|
|
int64_t now_ms = TickTime::MillisecondTimestamp();
|
|
|
|
|
int64_t oldest_packet_capture_time = now_ms;
|
2013-06-04 09:36:56 +00:00
|
|
|
if (!high_priority_packets_->empty()) {
|
2013-03-27 16:36:01 +00:00
|
|
|
oldest_packet_capture_time = std::min(
|
|
|
|
|
oldest_packet_capture_time,
|
2013-06-04 09:36:56 +00:00
|
|
|
high_priority_packets_->front().capture_time_ms_);
|
2013-03-27 16:36:01 +00:00
|
|
|
}
|
2013-06-04 09:36:56 +00:00
|
|
|
if (!normal_priority_packets_->empty()) {
|
2013-03-27 16:36:01 +00:00
|
|
|
oldest_packet_capture_time = std::min(
|
|
|
|
|
oldest_packet_capture_time,
|
2013-06-04 09:36:56 +00:00
|
|
|
normal_priority_packets_->front().capture_time_ms_);
|
2013-03-27 16:36:01 +00:00
|
|
|
}
|
2013-06-04 09:36:56 +00:00
|
|
|
if (!low_priority_packets_->empty()) {
|
2013-03-27 16:36:01 +00:00
|
|
|
oldest_packet_capture_time = std::min(
|
|
|
|
|
oldest_packet_capture_time,
|
2013-06-04 09:36:56 +00:00
|
|
|
low_priority_packets_->front().capture_time_ms_);
|
2013-03-27 16:36:01 +00:00
|
|
|
}
|
|
|
|
|
return now_ms - oldest_packet_capture_time;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-09 20:56:23 +00:00
|
|
|
int32_t PacedSender::TimeUntilNextProcess() {
|
|
|
|
|
CriticalSectionScoped cs(critsect_.get());
|
|
|
|
|
int64_t elapsed_time_ms =
|
|
|
|
|
(TickTime::Now() - time_last_update_).Milliseconds();
|
|
|
|
|
if (elapsed_time_ms <= 0) {
|
|
|
|
|
return kMinPacketLimitMs;
|
|
|
|
|
}
|
|
|
|
|
if (elapsed_time_ms >= kMinPacketLimitMs) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return kMinPacketLimitMs - elapsed_time_ms;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t PacedSender::Process() {
|
|
|
|
|
TickTime now = TickTime::Now();
|
|
|
|
|
CriticalSectionScoped cs(critsect_.get());
|
|
|
|
|
int elapsed_time_ms = (now - time_last_update_).Milliseconds();
|
|
|
|
|
time_last_update_ = now;
|
2013-08-09 11:31:23 +00:00
|
|
|
if (!enabled_) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2013-06-19 14:13:42 +00:00
|
|
|
if (!paused_) {
|
|
|
|
|
if (elapsed_time_ms > 0) {
|
|
|
|
|
uint32_t delta_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms);
|
|
|
|
|
UpdateBytesPerInterval(delta_time_ms);
|
|
|
|
|
}
|
2012-11-09 20:56:23 +00:00
|
|
|
uint32_t ssrc;
|
|
|
|
|
uint16_t sequence_number;
|
|
|
|
|
int64_t capture_time_ms;
|
2013-06-20 20:18:31 +00:00
|
|
|
paced_sender::PacketList* packet_list;
|
|
|
|
|
while (ShouldSendNextPacket(&packet_list)) {
|
|
|
|
|
GetNextPacketFromList(packet_list, &ssrc, &sequence_number,
|
|
|
|
|
&capture_time_ms);
|
|
|
|
|
critsect_->Leave();
|
|
|
|
|
|
|
|
|
|
const bool success = callback_->TimeToSendPacket(ssrc, sequence_number,
|
|
|
|
|
capture_time_ms);
|
2013-06-20 23:01:39 +00:00
|
|
|
critsect_->Enter();
|
2013-08-09 11:31:23 +00:00
|
|
|
// If packet cannot be sent then keep it in packet list and exit early.
|
2013-06-20 20:18:31 +00:00
|
|
|
// There's no need to send more packets.
|
|
|
|
|
if (!success) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
packet_list->pop_front();
|
|
|
|
|
const bool last_packet = packet_list->empty() ||
|
|
|
|
|
packet_list->front().capture_time_ms_ > capture_time_ms;
|
|
|
|
|
if (packet_list != high_priority_packets_.get()) {
|
2013-05-02 19:02:17 +00:00
|
|
|
if (capture_time_ms > capture_time_ms_last_sent_) {
|
|
|
|
|
capture_time_ms_last_sent_ = capture_time_ms;
|
|
|
|
|
} else if (capture_time_ms == capture_time_ms_last_sent_ &&
|
|
|
|
|
last_packet) {
|
|
|
|
|
TRACE_EVENT_ASYNC_END0("webrtc_rtp", "PacedSend", capture_time_ms);
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-11-09 20:56:23 +00:00
|
|
|
}
|
2013-06-04 09:36:56 +00:00
|
|
|
if (high_priority_packets_->empty() &&
|
|
|
|
|
normal_priority_packets_->empty() &&
|
|
|
|
|
low_priority_packets_->empty() &&
|
|
|
|
|
padding_budget_->bytes_remaining() > 0 &&
|
|
|
|
|
pad_up_to_bitrate_budget_->bytes_remaining() > 0) {
|
|
|
|
|
int padding_needed = std::min(
|
|
|
|
|
padding_budget_->bytes_remaining(),
|
|
|
|
|
pad_up_to_bitrate_budget_->bytes_remaining());
|
2012-11-09 20:56:23 +00:00
|
|
|
critsect_->Leave();
|
2013-06-04 09:36:56 +00:00
|
|
|
int bytes_sent = callback_->TimeToSendPadding(padding_needed);
|
2012-11-09 20:56:23 +00:00
|
|
|
critsect_->Enter();
|
2013-06-04 09:36:56 +00:00
|
|
|
media_budget_->UseBudget(bytes_sent);
|
|
|
|
|
padding_budget_->UseBudget(bytes_sent);
|
|
|
|
|
pad_up_to_bitrate_budget_->UseBudget(bytes_sent);
|
2012-11-09 20:56:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MUST have critsect_ when calling.
|
|
|
|
|
void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) {
|
2013-06-04 09:36:56 +00:00
|
|
|
media_budget_->IncreaseBudget(delta_time_ms);
|
|
|
|
|
padding_budget_->IncreaseBudget(delta_time_ms);
|
|
|
|
|
pad_up_to_bitrate_budget_->IncreaseBudget(delta_time_ms);
|
2012-11-09 20:56:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MUST have critsect_ when calling.
|
2013-06-20 20:18:31 +00:00
|
|
|
bool PacedSender::ShouldSendNextPacket(paced_sender::PacketList** packet_list) {
|
2013-06-04 09:36:56 +00:00
|
|
|
if (media_budget_->bytes_remaining() <= 0) {
|
2012-11-09 20:56:23 +00:00
|
|
|
// All bytes consumed for this interval.
|
|
|
|
|
// Check if we have not sent in a too long time.
|
2013-03-22 23:39:29 +00:00
|
|
|
if ((TickTime::Now() - time_last_send_).Milliseconds() >
|
|
|
|
|
kMaxQueueTimeWithoutSendingMs) {
|
2013-06-04 09:36:56 +00:00
|
|
|
if (!high_priority_packets_->empty()) {
|
2013-06-20 20:18:31 +00:00
|
|
|
*packet_list = high_priority_packets_.get();
|
2013-03-22 23:39:29 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2013-06-04 09:36:56 +00:00
|
|
|
if (!normal_priority_packets_->empty()) {
|
2013-06-20 20:18:31 +00:00
|
|
|
*packet_list = normal_priority_packets_.get();
|
2012-11-09 20:56:23 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2013-06-04 09:36:56 +00:00
|
|
|
if (!high_priority_packets_->empty()) {
|
2013-06-20 20:18:31 +00:00
|
|
|
*packet_list = high_priority_packets_.get();
|
2013-03-22 23:39:29 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2013-06-04 09:36:56 +00:00
|
|
|
if (!normal_priority_packets_->empty()) {
|
2013-06-20 20:18:31 +00:00
|
|
|
*packet_list = normal_priority_packets_.get();
|
2012-11-09 20:56:23 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2013-06-04 09:36:56 +00:00
|
|
|
if (!low_priority_packets_->empty()) {
|
2013-06-20 20:18:31 +00:00
|
|
|
*packet_list = low_priority_packets_.get();
|
2012-11-09 20:56:23 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-04 09:36:56 +00:00
|
|
|
void PacedSender::GetNextPacketFromList(paced_sender::PacketList* packets,
|
2013-06-20 20:18:31 +00:00
|
|
|
uint32_t* ssrc, uint16_t* sequence_number, int64_t* capture_time_ms) {
|
2013-06-04 09:36:56 +00:00
|
|
|
paced_sender::Packet packet = packets->front();
|
|
|
|
|
UpdateMediaBytesSent(packet.bytes_);
|
2013-03-22 23:39:29 +00:00
|
|
|
*sequence_number = packet.sequence_number_;
|
|
|
|
|
*ssrc = packet.ssrc_;
|
|
|
|
|
*capture_time_ms = packet.capture_time_ms_;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-09 20:56:23 +00:00
|
|
|
// MUST have critsect_ when calling.
|
2013-06-04 09:36:56 +00:00
|
|
|
void PacedSender::UpdateMediaBytesSent(int num_bytes) {
|
2012-11-09 20:56:23 +00:00
|
|
|
time_last_send_ = TickTime::Now();
|
2013-06-04 09:36:56 +00:00
|
|
|
media_budget_->UseBudget(num_bytes);
|
|
|
|
|
pad_up_to_bitrate_budget_->UseBudget(num_bytes);
|
2012-11-09 20:56:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace webrtc
|