Add round-robin selection of send stream to pad on.

BUG=1812
R=pbos@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/21669004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6472 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2014-06-17 17:32:05 +00:00
parent 9c09e6ee2b
commit a15fbfdcde
6 changed files with 321 additions and 89 deletions

View File

@ -17,11 +17,6 @@
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/trace.h"
#ifdef MATLAB
#include "webrtc/modules/rtp_rtcp/test/BWEStandAlone/MatlabPlot.h"
extern MatlabEngine eng; // Global variable defined elsewhere.
#endif
#ifdef _WIN32
// Disable warning C4355: 'this' : used in base member initializer list.
#pragma warning(disable : 4355)
@ -66,7 +61,9 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
configuration.outgoing_transport,
configuration.audio_messages,
configuration.paced_sender),
rtcp_sender_(configuration.id, configuration.audio, configuration.clock,
rtcp_sender_(configuration.id,
configuration.audio,
configuration.clock,
configuration.receive_statistics),
rtcp_receiver_(configuration.id, configuration.clock, this),
clock_(configuration.clock),
@ -83,15 +80,13 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
CriticalSectionWrapper::CreateCriticalSection()),
default_module_(
static_cast<ModuleRtpRtcpImpl*>(configuration.default_module)),
padding_index_(-1), // Start padding at the first child module.
nack_method_(kNackOff),
nack_last_time_sent_full_(0),
nack_last_seq_number_sent_(0),
simulcast_(false),
key_frame_req_method_(kKeyFrameReqFirRtp),
remote_bitrate_(configuration.remote_bitrate_estimator),
#ifdef MATLAB
, plot1_(NULL),
#endif
rtt_stats_(configuration.rtt_stats),
critical_section_rtt_(CriticalSectionWrapper::CreateCriticalSection()),
rtt_ms_(0) {
@ -121,12 +116,6 @@ ModuleRtpRtcpImpl::~ModuleRtpRtcpImpl() {
if (default_module_) {
default_module_->DeRegisterChildModule(this);
}
#ifdef MATLAB
if (plot1_) {
eng.DeletePlot(plot1_);
plot1_ = NULL;
}
#endif
}
void ModuleRtpRtcpImpl::RegisterChildModule(RtpRtcp* module) {
@ -148,7 +137,7 @@ void ModuleRtpRtcpImpl::DeRegisterChildModule(RtpRtcp* remove_module) {
CriticalSectionScoped double_lock(
critical_section_module_ptrs_feedback_.get());
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
while (it != child_modules_.end()) {
RtpRtcp* module = *it;
if (module == remove_module) {
@ -252,7 +241,8 @@ void ModuleRtpRtcpImpl::SetRTXSendStatus(int mode) {
rtp_sender_.SetRTXStatus(mode);
}
void ModuleRtpRtcpImpl::RTXSendStatus(int* mode, uint32_t* ssrc,
void ModuleRtpRtcpImpl::RTXSendStatus(int* mode,
uint32_t* ssrc,
int* payload_type) const {
rtp_sender_.RTXStatus(mode, ssrc, payload_type);
}
@ -372,7 +362,7 @@ int32_t ModuleRtpRtcpImpl::SetCSRCs(
// For default we need to update all child modules too.
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
while (it != child_modules_.end()) {
RtpRtcp* module = *it;
if (module) {
@ -443,7 +433,7 @@ bool ModuleRtpRtcpImpl::SendingMedia() const {
}
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
std::list<ModuleRtpRtcpImpl*>::const_iterator it = child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::const_iterator it = child_modules_.begin();
while (it != child_modules_.end()) {
RTPSender& rtp_sender = (*it)->rtp_sender_;
if (rtp_sender.SendingMedia()) {
@ -488,7 +478,7 @@ int32_t ModuleRtpRtcpImpl::SendOutgoingData(
return -1;
}
int idx = 0;
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
for (; idx < rtp_video_hdr->simulcastIdx; ++it) {
if (it == child_modules_.end()) {
return -1;
@ -515,7 +505,7 @@ int32_t ModuleRtpRtcpImpl::SendOutgoingData(
fragmentation,
rtp_video_hdr);
} else {
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
// Send to all "child" modules
while (it != child_modules_.end()) {
if ((*it)->SendingMedia()) {
@ -546,7 +536,7 @@ bool ModuleRtpRtcpImpl::TimeToSendPacket(uint32_t ssrc,
}
} else {
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
while (it != child_modules_.end()) {
if ((*it)->SendingMedia() && ssrc == (*it)->rtp_sender_.SSRC()) {
return (*it)->rtp_sender_.TimeToSendPacket(sequence_number,
@ -568,13 +558,15 @@ int ModuleRtpRtcpImpl::TimeToSendPadding(int bytes) {
}
} else {
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
while (it != child_modules_.end()) {
// Decide what media stream to pad on based on a round-robin scheme.
for (size_t i = 0; i < child_modules_.size(); ++i) {
padding_index_ = (padding_index_ + 1) % child_modules_.size();
// Send padding on one of the modules sending media.
if ((*it)->SendingMedia()) {
return (*it)->rtp_sender_.TimeToSendPadding(bytes);
if (child_modules_[padding_index_]->SendingMedia() &&
child_modules_[padding_index_]->rtp_sender_.GetTargetBitrate() > 0) {
return child_modules_[padding_index_]->rtp_sender_.TimeToSendPadding(
bytes);
}
++it;
}
}
return 0;
@ -603,8 +595,7 @@ uint16_t ModuleRtpRtcpImpl::MaxDataPayloadLength() const {
if (IsDefaultModule()) {
// For default we need to update all child modules too.
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
std::list<ModuleRtpRtcpImpl*>::const_iterator it =
child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::const_iterator it = child_modules_.begin();
while (it != child_modules_.end()) {
RtpRtcp* module = *it;
if (module) {
@ -1001,28 +992,28 @@ void ModuleRtpRtcpImpl::SetTargetSendBitrate(
if (IsDefaultModule()) {
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
if (simulcast_) {
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
for (size_t i = 0;
it != child_modules_.end() && i < stream_bitrates.size(); ++it) {
if ((*it)->SendingMedia()) {
RTPSender& rtp_sender = (*it)->rtp_sender_;
rtp_sender.SetTargetSendBitrate(stream_bitrates[i]);
rtp_sender.SetTargetBitrate(stream_bitrates[i]);
++i;
}
}
} else {
if (stream_bitrates.size() > 1)
return;
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
for (; it != child_modules_.end(); ++it) {
RTPSender& rtp_sender = (*it)->rtp_sender_;
rtp_sender.SetTargetSendBitrate(stream_bitrates[0]);
rtp_sender.SetTargetBitrate(stream_bitrates[0]);
}
}
} else {
if (stream_bitrates.size() > 1)
return;
rtp_sender_.SetTargetSendBitrate(stream_bitrates[0]);
rtp_sender_.SetTargetBitrate(stream_bitrates[0]);
}
}
@ -1054,7 +1045,7 @@ int32_t ModuleRtpRtcpImpl::SendRTCPSliceLossIndication(
int32_t ModuleRtpRtcpImpl::SetCameraDelay(const int32_t delay_ms) {
if (IsDefaultModule()) {
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
while (it != child_modules_.end()) {
RtpRtcp* module = *it;
if (module) {
@ -1084,7 +1075,7 @@ int32_t ModuleRtpRtcpImpl::GenericFECStatus(
if (IsDefaultModule()) {
// For default we need to check all child modules too.
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
while (it != child_modules_.end()) {
RtpRtcp* module = *it;
if (module) {
@ -1118,7 +1109,7 @@ int32_t ModuleRtpRtcpImpl::SetFecParameters(
// For default we need to update all child modules too.
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
while (it != child_modules_.end()) {
RtpRtcp* module = *it;
if (module) {
@ -1172,8 +1163,7 @@ void ModuleRtpRtcpImpl::BitrateSent(uint32_t* total_rate,
if (nack_rate != NULL)
*nack_rate = 0;
std::list<ModuleRtpRtcpImpl*>::const_iterator it =
child_modules_.begin();
std::vector<ModuleRtpRtcpImpl*>::const_iterator it = child_modules_.begin();
while (it != child_modules_.end()) {
RtpRtcp* module = *it;
if (module) {

View File

@ -21,10 +21,6 @@
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/test/testsupport/gtest_prod_util.h"
#ifdef MATLAB
class MatlabPlot;
#endif
namespace webrtc {
class ModuleRtpRtcpImpl : public RtpRtcp {
@ -426,7 +422,8 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
scoped_ptr<CriticalSectionWrapper> critical_section_module_ptrs_;
scoped_ptr<CriticalSectionWrapper> critical_section_module_ptrs_feedback_;
ModuleRtpRtcpImpl* default_module_;
std::list<ModuleRtpRtcpImpl*> child_modules_;
std::vector<ModuleRtpRtcpImpl*> child_modules_;
size_t padding_index_;
// Send side
NACKMethod nack_method_;
@ -439,10 +436,6 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
RemoteBitrateEstimator* remote_bitrate_;
#ifdef MATLAB
MatlabPlot* plot1_;
#endif
RtcpRttStats* rtt_stats_;
// The processed RTT from RtcpRttStats.

View File

@ -12,13 +12,22 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/pacing/include/mock/mock_paced_sender.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
#include "webrtc/system_wrappers/interface/scoped_vector.h"
using ::testing::_;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SaveArg;
namespace webrtc {
namespace {
const uint32_t kSenderSsrc = 0x12345;
const uint32_t kReceiverSsrc = 0x23456;
const uint32_t kSenderRtxSsrc = 0x32345;
const uint32_t kOneWayNetworkDelayMs = 100;
class RtcpRttStatsTestImpl : public RtcpRttStats {
@ -215,4 +224,245 @@ TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_FirAndPli) {
EXPECT_EQ(2U, sender_.RtcpReceived().fir_packets);
EXPECT_EQ(1U, sender_.RtcpReceived().pli_packets);
}
class RtpSendingTestTransport : public Transport {
public:
void ResetCounters() { bytes_received_.clear(); }
virtual int SendPacket(int channel, const void* data, int length) {
RTPHeader header;
scoped_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
EXPECT_TRUE(
parser->Parse(static_cast<const uint8_t*>(data), length, &header));
bytes_received_[header.ssrc] += length;
++packets_received_[header.ssrc];
return length;
}
virtual int SendRTCPPacket(int channel, const void* data, int length) {
return length;
}
int GetPacketsReceived(uint32_t ssrc) const {
std::map<uint32_t, int>::const_iterator it = packets_received_.find(ssrc);
if (it == packets_received_.end())
return 0;
return it->second;
}
int GetBytesReceived(uint32_t ssrc) const {
std::map<uint32_t, int>::const_iterator it = bytes_received_.find(ssrc);
if (it == bytes_received_.end())
return 0;
return it->second;
}
int GetTotalBytesReceived() const {
int sum = 0;
for (std::map<uint32_t, int>::const_iterator it = bytes_received_.begin();
it != bytes_received_.end();
++it) {
sum += it->second;
}
return sum;
}
private:
std::map<uint32_t, int> bytes_received_;
std::map<uint32_t, int> packets_received_;
};
class RtpSendingTest : public ::testing::Test {
protected:
// Map from SSRC to number of received packets and bytes.
typedef std::map<uint32_t, std::pair<int, int> > PaddingMap;
RtpSendingTest() {
// Send module.
RtpRtcp::Configuration config;
config.audio = false;
config.clock = Clock::GetRealTimeClock();
config.outgoing_transport = &transport_;
config.receive_statistics = receive_statistics_.get();
config.rtt_stats = &rtt_stats_;
config.paced_sender = &pacer_;
memset(&codec_, 0, sizeof(VideoCodec));
codec_.plType = 100;
strncpy(codec_.plName, "VP8", 3);
codec_.numberOfSimulcastStreams = 3;
codec_.simulcastStream[0].width = 320;
codec_.simulcastStream[0].height = 180;
codec_.simulcastStream[0].maxBitrate = 300;
codec_.simulcastStream[1].width = 640;
codec_.simulcastStream[1].height = 360;
codec_.simulcastStream[1].maxBitrate = 600;
codec_.simulcastStream[2].width = 1280;
codec_.simulcastStream[2].height = 720;
codec_.simulcastStream[2].maxBitrate = 1200;
// We need numberOfSimulcastStreams + 1 RTP modules since we need one
// default module.
for (int i = 0; i < codec_.numberOfSimulcastStreams + 1; ++i) {
RtpRtcp* sender = RtpRtcp::CreateRtpRtcp(config);
EXPECT_EQ(0, sender->RegisterSendPayload(codec_));
EXPECT_EQ(0, sender->SetSendingStatus(true));
EXPECT_EQ(0, sender->SetSendingMediaStatus(true));
sender->SetSSRC(kSenderSsrc + i);
sender->SetRemoteSSRC(kReceiverSsrc + i);
senders_.push_back(sender);
config.default_module = senders_[0];
}
std::vector<uint32_t> bitrates;
bitrates.push_back(codec_.simulcastStream[0].maxBitrate);
bitrates.push_back(codec_.simulcastStream[1].maxBitrate);
bitrates.push_back(codec_.simulcastStream[2].maxBitrate);
senders_[0]->SetTargetSendBitrate(bitrates);
}
~RtpSendingTest() {
for (int i = senders_.size() - 1; i >= 0; --i) {
delete senders_[i];
}
}
void SendFrameOnSender(int sender_index,
const uint8_t* payload,
size_t length) {
RTPVideoHeader rtp_video_header = {
codec_.simulcastStream[sender_index].width,
codec_.simulcastStream[sender_index].height,
true,
0,
kRtpVideoVp8,
{}};
uint32_t seq_num = 0;
uint32_t ssrc = 0;
int64_t capture_time_ms = 0;
bool retransmission = false;
EXPECT_CALL(pacer_, SendPacket(_, _, _, _, _, _))
.WillRepeatedly(DoAll(SaveArg<1>(&ssrc),
SaveArg<2>(&seq_num),
SaveArg<3>(&capture_time_ms),
SaveArg<5>(&retransmission),
Return(true)));
EXPECT_EQ(0,
senders_[sender_index]->SendOutgoingData(kVideoFrameKey,
codec_.plType,
0,
0,
payload,
length,
NULL,
&rtp_video_header));
EXPECT_TRUE(senders_[sender_index]->TimeToSendPacket(
ssrc, seq_num, capture_time_ms, retransmission));
}
void ExpectPadding(const PaddingMap& expected_padding) {
int expected_total_bytes = 0;
for (PaddingMap::const_iterator it = expected_padding.begin();
it != expected_padding.end();
++it) {
int packets_received = transport_.GetBytesReceived(it->first);
if (it->second.first > 0) {
EXPECT_GE(packets_received, it->second.first)
<< "On SSRC: " << it->first;
}
int bytes_received = transport_.GetBytesReceived(it->first);
expected_total_bytes += bytes_received;
if (it->second.second > 0) {
EXPECT_GE(bytes_received, it->second.second)
<< "On SSRC: " << it->first;
} else {
EXPECT_EQ(0, bytes_received) << "On SSRC: " << it->first;
}
}
EXPECT_EQ(expected_total_bytes, transport_.GetTotalBytesReceived());
}
scoped_ptr<ReceiveStatistics> receive_statistics_;
RtcpRttStatsTestImpl rtt_stats_;
std::vector<RtpRtcp*> senders_;
RtpSendingTestTransport transport_;
NiceMock<MockPacedSender> pacer_;
VideoCodec codec_;
};
TEST_F(RtpSendingTest, RoundRobinPadding) {
// We have to send on an SSRC to be allowed to pad, since a marker bit must
// be sent prior to padding packets.
const uint8_t payload[200] = {0};
for (int i = 0; i < codec_.numberOfSimulcastStreams; ++i) {
SendFrameOnSender(i + 1, payload, sizeof(payload));
}
transport_.ResetCounters();
senders_[0]->TimeToSendPadding(500);
PaddingMap expected_padding;
expected_padding[kSenderSsrc + 1] = std::make_pair(2, 500);
expected_padding[kSenderSsrc + 2] = std::make_pair(0, 0);
expected_padding[kSenderSsrc + 3] = std::make_pair(0, 0);
ExpectPadding(expected_padding);
senders_[0]->TimeToSendPadding(1000);
expected_padding[kSenderSsrc + 2] = std::make_pair(4, 1000);
ExpectPadding(expected_padding);
senders_[0]->TimeToSendPadding(1500);
expected_padding[kSenderSsrc + 3] = std::make_pair(6, 1500);
ExpectPadding(expected_padding);
}
TEST_F(RtpSendingTest, RoundRobinPaddingRtx) {
// Enable RTX to allow padding to be sent prior to media.
for (int i = 1; i < codec_.numberOfSimulcastStreams + 1; ++i) {
senders_[i]->SetRtxSendPayloadType(96);
senders_[i]->SetRtxSsrc(kSenderRtxSsrc + i);
senders_[i]->SetRTXSendStatus(kRtxRetransmitted);
}
transport_.ResetCounters();
senders_[0]->TimeToSendPadding(500);
PaddingMap expected_padding;
expected_padding[kSenderSsrc + 1] = std::make_pair(0, 0);
expected_padding[kSenderSsrc + 2] = std::make_pair(0, 0);
expected_padding[kSenderSsrc + 3] = std::make_pair(0, 0);
expected_padding[kSenderRtxSsrc + 1] = std::make_pair(2, 500);
expected_padding[kSenderRtxSsrc + 2] = std::make_pair(0, 0);
expected_padding[kSenderRtxSsrc + 3] = std::make_pair(0, 0);
ExpectPadding(expected_padding);
senders_[0]->TimeToSendPadding(1000);
expected_padding[kSenderRtxSsrc + 2] = std::make_pair(4, 500);
ExpectPadding(expected_padding);
senders_[0]->TimeToSendPadding(1500);
expected_padding[kSenderRtxSsrc + 3] = std::make_pair(6, 500);
ExpectPadding(expected_padding);
}
TEST_F(RtpSendingTest, RoundRobinPaddingRtxRedundantPayloads) {
for (int i = 1; i < codec_.numberOfSimulcastStreams + 1; ++i) {
senders_[i]->SetRtxSendPayloadType(96);
senders_[i]->SetRtxSsrc(kSenderRtxSsrc + i);
senders_[i]->SetRTXSendStatus(kRtxRetransmitted | kRtxRedundantPayloads);
senders_[i]->SetStorePacketsStatus(true, 100);
}
// First send payloads so that we have something to retransmit.
const size_t kPayloadSize = 500;
const uint8_t payload[kPayloadSize] = {0};
for (int i = 0; i < codec_.numberOfSimulcastStreams; ++i) {
SendFrameOnSender(i + 1, payload, sizeof(payload));
}
transport_.ResetCounters();
senders_[0]->TimeToSendPadding(500);
PaddingMap expected_padding;
expected_padding[kSenderSsrc + 1] = std::make_pair<int, int>(0, 0);
expected_padding[kSenderSsrc + 2] = std::make_pair<int, int>(0, 0);
expected_padding[kSenderSsrc + 3] = std::make_pair<int, int>(0, 0);
expected_padding[kSenderRtxSsrc + 1] = std::make_pair<int, int>(1, 500);
expected_padding[kSenderRtxSsrc + 2] = std::make_pair<int, int>(0, 0);
expected_padding[kSenderRtxSsrc + 3] = std::make_pair<int, int>(0, 0);
ExpectPadding(expected_padding);
senders_[0]->TimeToSendPadding(1000);
expected_padding[kSenderRtxSsrc + 2] = std::make_pair<int, int>(2, 1000);
ExpectPadding(expected_padding);
senders_[0]->TimeToSendPadding(1500);
expected_padding[kSenderRtxSsrc + 3] = std::make_pair<int, int>(3, 1500);
ExpectPadding(expected_padding);
}
} // namespace webrtc

View File

@ -89,7 +89,7 @@ RTPSender::RTPSender(const int32_t id,
rtx_(kRtxOff),
payload_type_rtx_(-1),
target_bitrate_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
target_bitrate_kbps_(0) {
target_bitrate_(0) {
memset(nack_byte_count_times_, 0, sizeof(nack_byte_count_times_));
memset(nack_byte_count_, 0, sizeof(nack_byte_count_));
memset(csrcs_, 0, sizeof(csrcs_));
@ -127,8 +127,14 @@ RTPSender::~RTPSender() {
delete video_;
}
void RTPSender::SetTargetSendBitrate(const uint32_t bits) {
SetTargetBitrateKbps(static_cast<uint16_t>(bits / 1000));
void RTPSender::SetTargetBitrate(uint32_t bitrate) {
CriticalSectionScoped cs(target_bitrate_critsect_.get());
target_bitrate_ = bitrate;
}
uint32_t RTPSender::GetTargetBitrate() {
CriticalSectionScoped cs(target_bitrate_critsect_.get());
return target_bitrate_;
}
uint16_t RTPSender::ActualSendBitrateKbit() const {
@ -330,7 +336,6 @@ void RTPSender::RTXStatus(int* mode, uint32_t* ssrc,
*payload_type = payload_type_rtx_;
}
void RTPSender::SetRtxPayloadType(int payload_type) {
CriticalSectionScoped cs(send_critsect_);
payload_type_rtx_ = payload_type;
@ -465,8 +470,8 @@ bool RTPSender::SendPaddingAccordingToBitrate(
// Current bitrate since last estimate(1 second) averaged with the
// estimate since then, to get the most up to date bitrate.
uint32_t current_bitrate = bitrate_sent_.BitrateNow();
uint16_t target_bitrate_kbps = GetTargetBitrateKbps();
int bitrate_diff = target_bitrate_kbps * 1000 - current_bitrate;
uint32_t target_bitrate = GetTargetBitrate();
int bitrate_diff = target_bitrate - current_bitrate;
if (bitrate_diff <= 0) {
return true;
}
@ -477,7 +482,7 @@ bool RTPSender::SendPaddingAccordingToBitrate(
} else {
bytes = (bitrate_diff / 8);
// Cap at 200 ms of target send data.
int bytes_cap = target_bitrate_kbps * 25; // 1000 / 8 / 5.
int bytes_cap = target_bitrate / 1000 * 25; // 1000 / 8 / 5.
if (bytes > bytes_cap) {
bytes = bytes_cap;
}
@ -656,12 +661,12 @@ void RTPSender::OnReceivedNACK(
"num_seqnum", nack_sequence_numbers.size(), "avg_rtt", avg_rtt);
const int64_t now = clock_->TimeInMilliseconds();
uint32_t bytes_re_sent = 0;
uint16_t target_bitrate_kbps = GetTargetBitrateKbps();
uint32_t target_bitrate = GetTargetBitrate();
// Enough bandwidth to send NACK?
if (!ProcessNACKBitRate(now)) {
LOG(LS_INFO) << "NACK bitrate reached. Skip sending NACK response. Target "
<< target_bitrate_kbps;
<< target_bitrate;
return;
}
@ -681,10 +686,10 @@ void RTPSender::OnReceivedNACK(
break;
}
// Delay bandwidth estimate (RTT * BW).
if (target_bitrate_kbps != 0 && avg_rtt) {
if (target_bitrate != 0 && avg_rtt) {
// kbits/s * ms = bits => bits/8 = bytes
uint32_t target_bytes =
(static_cast<uint32_t>(target_bitrate_kbps) * avg_rtt) >> 3;
(static_cast<uint32_t>(target_bitrate / 1000) * avg_rtt) >> 3;
if (bytes_re_sent > target_bytes) {
break; // Ignore the rest of the packets in the list.
}
@ -699,33 +704,34 @@ void RTPSender::OnReceivedNACK(
bool RTPSender::ProcessNACKBitRate(const uint32_t now) {
uint32_t num = 0;
int32_t byte_count = 0;
const uint32_t avg_interval = 1000;
uint16_t target_bitrate_kbps = GetTargetBitrateKbps();
int byte_count = 0;
const int kAvgIntervalMs = 1000;
uint32_t target_bitrate = GetTargetBitrate();
CriticalSectionScoped cs(send_critsect_);
if (target_bitrate_kbps == 0) {
if (target_bitrate == 0) {
return true;
}
for (num = 0; num < NACK_BYTECOUNT_SIZE; ++num) {
if ((now - nack_byte_count_times_[num]) > avg_interval) {
if ((now - nack_byte_count_times_[num]) > kAvgIntervalMs) {
// Don't use data older than 1sec.
break;
} else {
byte_count += nack_byte_count_[num];
}
}
int32_t time_interval = avg_interval;
int time_interval = kAvgIntervalMs;
if (num == NACK_BYTECOUNT_SIZE) {
// More than NACK_BYTECOUNT_SIZE nack messages has been received
// during the last msg_interval.
time_interval = now - nack_byte_count_times_[num - 1];
if (time_interval < 0) {
time_interval = avg_interval;
time_interval = kAvgIntervalMs;
}
}
return (byte_count * 8) < (target_bitrate_kbps * time_interval);
return (byte_count * 8) <
static_cast<int>(target_bitrate / 1000 * time_interval);
}
void RTPSender::UpdateNACKBitRate(const uint32_t bytes,
@ -882,8 +888,13 @@ int RTPSender::TimeToSendPadding(int bytes) {
int bytes_sent = SendRedundantPayloads(payload_type, bytes);
bytes -= bytes_sent;
if (bytes > 0) {
int padding_sent = SendPadData(payload_type, timestamp, capture_time_ms,
bytes, kDontStore, true, true);
int padding_sent = SendPadData(payload_type,
timestamp,
capture_time_ms,
bytes,
kDontStore,
true,
rtx_ == kRtxOff);
bytes_sent += padding_sent;
}
return bytes_sent;
@ -1659,14 +1670,4 @@ void RTPSender::BitrateUpdated(const BitrateStatistics& stats) {
bitrate_callback_->Notify(stats, ssrc_);
}
}
void RTPSender::SetTargetBitrateKbps(uint16_t bitrate_kbps) {
CriticalSectionScoped cs(target_bitrate_critsect_.get());
target_bitrate_kbps_ = bitrate_kbps;
}
uint16_t RTPSender::GetTargetBitrateKbps() {
CriticalSectionScoped cs(target_bitrate_critsect_.get());
return target_bitrate_kbps_;
}
} // namespace webrtc

View File

@ -83,7 +83,8 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
// was sent within the statistics window.
bool GetSendSideDelay(int* avg_send_delay_ms, int* max_send_delay_ms) const;
void SetTargetSendBitrate(const uint32_t bits);
void SetTargetBitrate(uint32_t bitrate);
uint32_t GetTargetBitrate();
virtual uint16_t MaxDataPayloadLength() const
OVERRIDE; // with RTP and FEC headers.
@ -329,9 +330,6 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
bool is_retransmit);
bool IsFecPacket(const uint8_t* buffer, const RTPHeader& header) const;
void SetTargetBitrateKbps(uint16_t bitrate_kbps);
uint16_t GetTargetBitrateKbps();
Clock* clock_;
Bitrate bitrate_sent_;
@ -399,7 +397,7 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
// that by the time the function returns there is no guarantee
// that the target bitrate is still valid.
scoped_ptr<CriticalSectionWrapper> target_bitrate_critsect_;
uint16_t target_bitrate_kbps_ GUARDED_BY(target_bitrate_critsect_);
uint16_t target_bitrate_ GUARDED_BY(target_bitrate_critsect_);
};
} // namespace webrtc

View File

@ -444,7 +444,7 @@ TEST_F(RtpSenderTest, TrafficSmoothingWithExtensions) {
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
rtp_sender_->SetTargetSendBitrate(300000);
rtp_sender_->SetTargetBitrate(300000);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
@ -498,7 +498,7 @@ TEST_F(RtpSenderTest, TrafficSmoothingRetransmits) {
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
rtp_sender_->SetTargetSendBitrate(300000);
rtp_sender_->SetTargetBitrate(300000);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
@ -580,7 +580,7 @@ TEST_F(RtpSenderTest, SendPadding) {
kAbsoluteSendTimeExtensionId);
webrtc::RTPHeader rtp_header;
rtp_sender_->SetTargetSendBitrate(300000);
rtp_sender_->SetTargetBitrate(300000);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
@ -698,7 +698,7 @@ TEST_F(RtpSenderTest, SendRedundantPayloads) {
kTransmissionTimeOffsetExtensionId);
rtp_parser->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
kAbsoluteSendTimeExtensionId);
rtp_sender_->SetTargetSendBitrate(300000);
rtp_sender_->SetTargetBitrate(300000);
const size_t kNumPayloadSizes = 10;
const int kPayloadSizes[kNumPayloadSizes] = {500, 550, 600, 650, 700, 750,
800, 850, 900, 950};