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:
parent
9c09e6ee2b
commit
a15fbfdcde
@ -17,11 +17,6 @@
|
|||||||
#include "webrtc/system_wrappers/interface/logging.h"
|
#include "webrtc/system_wrappers/interface/logging.h"
|
||||||
#include "webrtc/system_wrappers/interface/trace.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
|
#ifdef _WIN32
|
||||||
// Disable warning C4355: 'this' : used in base member initializer list.
|
// Disable warning C4355: 'this' : used in base member initializer list.
|
||||||
#pragma warning(disable : 4355)
|
#pragma warning(disable : 4355)
|
||||||
@ -66,7 +61,9 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
|
|||||||
configuration.outgoing_transport,
|
configuration.outgoing_transport,
|
||||||
configuration.audio_messages,
|
configuration.audio_messages,
|
||||||
configuration.paced_sender),
|
configuration.paced_sender),
|
||||||
rtcp_sender_(configuration.id, configuration.audio, configuration.clock,
|
rtcp_sender_(configuration.id,
|
||||||
|
configuration.audio,
|
||||||
|
configuration.clock,
|
||||||
configuration.receive_statistics),
|
configuration.receive_statistics),
|
||||||
rtcp_receiver_(configuration.id, configuration.clock, this),
|
rtcp_receiver_(configuration.id, configuration.clock, this),
|
||||||
clock_(configuration.clock),
|
clock_(configuration.clock),
|
||||||
@ -83,15 +80,13 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
|
|||||||
CriticalSectionWrapper::CreateCriticalSection()),
|
CriticalSectionWrapper::CreateCriticalSection()),
|
||||||
default_module_(
|
default_module_(
|
||||||
static_cast<ModuleRtpRtcpImpl*>(configuration.default_module)),
|
static_cast<ModuleRtpRtcpImpl*>(configuration.default_module)),
|
||||||
|
padding_index_(-1), // Start padding at the first child module.
|
||||||
nack_method_(kNackOff),
|
nack_method_(kNackOff),
|
||||||
nack_last_time_sent_full_(0),
|
nack_last_time_sent_full_(0),
|
||||||
nack_last_seq_number_sent_(0),
|
nack_last_seq_number_sent_(0),
|
||||||
simulcast_(false),
|
simulcast_(false),
|
||||||
key_frame_req_method_(kKeyFrameReqFirRtp),
|
key_frame_req_method_(kKeyFrameReqFirRtp),
|
||||||
remote_bitrate_(configuration.remote_bitrate_estimator),
|
remote_bitrate_(configuration.remote_bitrate_estimator),
|
||||||
#ifdef MATLAB
|
|
||||||
, plot1_(NULL),
|
|
||||||
#endif
|
|
||||||
rtt_stats_(configuration.rtt_stats),
|
rtt_stats_(configuration.rtt_stats),
|
||||||
critical_section_rtt_(CriticalSectionWrapper::CreateCriticalSection()),
|
critical_section_rtt_(CriticalSectionWrapper::CreateCriticalSection()),
|
||||||
rtt_ms_(0) {
|
rtt_ms_(0) {
|
||||||
@ -121,12 +116,6 @@ ModuleRtpRtcpImpl::~ModuleRtpRtcpImpl() {
|
|||||||
if (default_module_) {
|
if (default_module_) {
|
||||||
default_module_->DeRegisterChildModule(this);
|
default_module_->DeRegisterChildModule(this);
|
||||||
}
|
}
|
||||||
#ifdef MATLAB
|
|
||||||
if (plot1_) {
|
|
||||||
eng.DeletePlot(plot1_);
|
|
||||||
plot1_ = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleRtpRtcpImpl::RegisterChildModule(RtpRtcp* module) {
|
void ModuleRtpRtcpImpl::RegisterChildModule(RtpRtcp* module) {
|
||||||
@ -148,7 +137,7 @@ void ModuleRtpRtcpImpl::DeRegisterChildModule(RtpRtcp* remove_module) {
|
|||||||
CriticalSectionScoped double_lock(
|
CriticalSectionScoped double_lock(
|
||||||
critical_section_module_ptrs_feedback_.get());
|
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()) {
|
while (it != child_modules_.end()) {
|
||||||
RtpRtcp* module = *it;
|
RtpRtcp* module = *it;
|
||||||
if (module == remove_module) {
|
if (module == remove_module) {
|
||||||
@ -252,8 +241,9 @@ void ModuleRtpRtcpImpl::SetRTXSendStatus(int mode) {
|
|||||||
rtp_sender_.SetRTXStatus(mode);
|
rtp_sender_.SetRTXStatus(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleRtpRtcpImpl::RTXSendStatus(int* mode, uint32_t* ssrc,
|
void ModuleRtpRtcpImpl::RTXSendStatus(int* mode,
|
||||||
int* payload_type) const {
|
uint32_t* ssrc,
|
||||||
|
int* payload_type) const {
|
||||||
rtp_sender_.RTXStatus(mode, ssrc, payload_type);
|
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.
|
// For default we need to update all child modules too.
|
||||||
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
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()) {
|
while (it != child_modules_.end()) {
|
||||||
RtpRtcp* module = *it;
|
RtpRtcp* module = *it;
|
||||||
if (module) {
|
if (module) {
|
||||||
@ -443,7 +433,7 @@ bool ModuleRtpRtcpImpl::SendingMedia() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
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()) {
|
while (it != child_modules_.end()) {
|
||||||
RTPSender& rtp_sender = (*it)->rtp_sender_;
|
RTPSender& rtp_sender = (*it)->rtp_sender_;
|
||||||
if (rtp_sender.SendingMedia()) {
|
if (rtp_sender.SendingMedia()) {
|
||||||
@ -488,7 +478,7 @@ int32_t ModuleRtpRtcpImpl::SendOutgoingData(
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int idx = 0;
|
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) {
|
for (; idx < rtp_video_hdr->simulcastIdx; ++it) {
|
||||||
if (it == child_modules_.end()) {
|
if (it == child_modules_.end()) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -515,7 +505,7 @@ int32_t ModuleRtpRtcpImpl::SendOutgoingData(
|
|||||||
fragmentation,
|
fragmentation,
|
||||||
rtp_video_hdr);
|
rtp_video_hdr);
|
||||||
} else {
|
} else {
|
||||||
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
||||||
// Send to all "child" modules
|
// Send to all "child" modules
|
||||||
while (it != child_modules_.end()) {
|
while (it != child_modules_.end()) {
|
||||||
if ((*it)->SendingMedia()) {
|
if ((*it)->SendingMedia()) {
|
||||||
@ -546,7 +536,7 @@ bool ModuleRtpRtcpImpl::TimeToSendPacket(uint32_t ssrc,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
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()) {
|
while (it != child_modules_.end()) {
|
||||||
if ((*it)->SendingMedia() && ssrc == (*it)->rtp_sender_.SSRC()) {
|
if ((*it)->SendingMedia() && ssrc == (*it)->rtp_sender_.SSRC()) {
|
||||||
return (*it)->rtp_sender_.TimeToSendPacket(sequence_number,
|
return (*it)->rtp_sender_.TimeToSendPacket(sequence_number,
|
||||||
@ -568,13 +558,15 @@ int ModuleRtpRtcpImpl::TimeToSendPadding(int bytes) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
||||||
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
// Decide what media stream to pad on based on a round-robin scheme.
|
||||||
while (it != child_modules_.end()) {
|
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.
|
// Send padding on one of the modules sending media.
|
||||||
if ((*it)->SendingMedia()) {
|
if (child_modules_[padding_index_]->SendingMedia() &&
|
||||||
return (*it)->rtp_sender_.TimeToSendPadding(bytes);
|
child_modules_[padding_index_]->rtp_sender_.GetTargetBitrate() > 0) {
|
||||||
|
return child_modules_[padding_index_]->rtp_sender_.TimeToSendPadding(
|
||||||
|
bytes);
|
||||||
}
|
}
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -603,8 +595,7 @@ uint16_t ModuleRtpRtcpImpl::MaxDataPayloadLength() const {
|
|||||||
if (IsDefaultModule()) {
|
if (IsDefaultModule()) {
|
||||||
// For default we need to update all child modules too.
|
// For default we need to update all child modules too.
|
||||||
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
||||||
std::list<ModuleRtpRtcpImpl*>::const_iterator it =
|
std::vector<ModuleRtpRtcpImpl*>::const_iterator it = child_modules_.begin();
|
||||||
child_modules_.begin();
|
|
||||||
while (it != child_modules_.end()) {
|
while (it != child_modules_.end()) {
|
||||||
RtpRtcp* module = *it;
|
RtpRtcp* module = *it;
|
||||||
if (module) {
|
if (module) {
|
||||||
@ -1001,28 +992,28 @@ void ModuleRtpRtcpImpl::SetTargetSendBitrate(
|
|||||||
if (IsDefaultModule()) {
|
if (IsDefaultModule()) {
|
||||||
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
||||||
if (simulcast_) {
|
if (simulcast_) {
|
||||||
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
||||||
for (size_t i = 0;
|
for (size_t i = 0;
|
||||||
it != child_modules_.end() && i < stream_bitrates.size(); ++it) {
|
it != child_modules_.end() && i < stream_bitrates.size(); ++it) {
|
||||||
if ((*it)->SendingMedia()) {
|
if ((*it)->SendingMedia()) {
|
||||||
RTPSender& rtp_sender = (*it)->rtp_sender_;
|
RTPSender& rtp_sender = (*it)->rtp_sender_;
|
||||||
rtp_sender.SetTargetSendBitrate(stream_bitrates[i]);
|
rtp_sender.SetTargetBitrate(stream_bitrates[i]);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (stream_bitrates.size() > 1)
|
if (stream_bitrates.size() > 1)
|
||||||
return;
|
return;
|
||||||
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
||||||
for (; it != child_modules_.end(); ++it) {
|
for (; it != child_modules_.end(); ++it) {
|
||||||
RTPSender& rtp_sender = (*it)->rtp_sender_;
|
RTPSender& rtp_sender = (*it)->rtp_sender_;
|
||||||
rtp_sender.SetTargetSendBitrate(stream_bitrates[0]);
|
rtp_sender.SetTargetBitrate(stream_bitrates[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (stream_bitrates.size() > 1)
|
if (stream_bitrates.size() > 1)
|
||||||
return;
|
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) {
|
int32_t ModuleRtpRtcpImpl::SetCameraDelay(const int32_t delay_ms) {
|
||||||
if (IsDefaultModule()) {
|
if (IsDefaultModule()) {
|
||||||
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
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()) {
|
while (it != child_modules_.end()) {
|
||||||
RtpRtcp* module = *it;
|
RtpRtcp* module = *it;
|
||||||
if (module) {
|
if (module) {
|
||||||
@ -1084,7 +1075,7 @@ int32_t ModuleRtpRtcpImpl::GenericFECStatus(
|
|||||||
if (IsDefaultModule()) {
|
if (IsDefaultModule()) {
|
||||||
// For default we need to check all child modules too.
|
// For default we need to check all child modules too.
|
||||||
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
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()) {
|
while (it != child_modules_.end()) {
|
||||||
RtpRtcp* module = *it;
|
RtpRtcp* module = *it;
|
||||||
if (module) {
|
if (module) {
|
||||||
@ -1118,7 +1109,7 @@ int32_t ModuleRtpRtcpImpl::SetFecParameters(
|
|||||||
// For default we need to update all child modules too.
|
// For default we need to update all child modules too.
|
||||||
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
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()) {
|
while (it != child_modules_.end()) {
|
||||||
RtpRtcp* module = *it;
|
RtpRtcp* module = *it;
|
||||||
if (module) {
|
if (module) {
|
||||||
@ -1172,8 +1163,7 @@ void ModuleRtpRtcpImpl::BitrateSent(uint32_t* total_rate,
|
|||||||
if (nack_rate != NULL)
|
if (nack_rate != NULL)
|
||||||
*nack_rate = 0;
|
*nack_rate = 0;
|
||||||
|
|
||||||
std::list<ModuleRtpRtcpImpl*>::const_iterator it =
|
std::vector<ModuleRtpRtcpImpl*>::const_iterator it = child_modules_.begin();
|
||||||
child_modules_.begin();
|
|
||||||
while (it != child_modules_.end()) {
|
while (it != child_modules_.end()) {
|
||||||
RtpRtcp* module = *it;
|
RtpRtcp* module = *it;
|
||||||
if (module) {
|
if (module) {
|
||||||
|
@ -21,10 +21,6 @@
|
|||||||
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||||
#include "webrtc/test/testsupport/gtest_prod_util.h"
|
#include "webrtc/test/testsupport/gtest_prod_util.h"
|
||||||
|
|
||||||
#ifdef MATLAB
|
|
||||||
class MatlabPlot;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
class ModuleRtpRtcpImpl : public RtpRtcp {
|
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_;
|
||||||
scoped_ptr<CriticalSectionWrapper> critical_section_module_ptrs_feedback_;
|
scoped_ptr<CriticalSectionWrapper> critical_section_module_ptrs_feedback_;
|
||||||
ModuleRtpRtcpImpl* default_module_;
|
ModuleRtpRtcpImpl* default_module_;
|
||||||
std::list<ModuleRtpRtcpImpl*> child_modules_;
|
std::vector<ModuleRtpRtcpImpl*> child_modules_;
|
||||||
|
size_t padding_index_;
|
||||||
|
|
||||||
// Send side
|
// Send side
|
||||||
NACKMethod nack_method_;
|
NACKMethod nack_method_;
|
||||||
@ -439,10 +436,6 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
|
|||||||
|
|
||||||
RemoteBitrateEstimator* remote_bitrate_;
|
RemoteBitrateEstimator* remote_bitrate_;
|
||||||
|
|
||||||
#ifdef MATLAB
|
|
||||||
MatlabPlot* plot1_;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RtcpRttStats* rtt_stats_;
|
RtcpRttStats* rtt_stats_;
|
||||||
|
|
||||||
// The processed RTT from RtcpRttStats.
|
// The processed RTT from RtcpRttStats.
|
||||||
|
@ -12,13 +12,22 @@
|
|||||||
#include "testing/gtest/include/gtest/gtest.h"
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
|
|
||||||
#include "webrtc/common_types.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/interface/rtp_rtcp_defines.h"
|
||||||
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.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 webrtc {
|
||||||
namespace {
|
namespace {
|
||||||
const uint32_t kSenderSsrc = 0x12345;
|
const uint32_t kSenderSsrc = 0x12345;
|
||||||
const uint32_t kReceiverSsrc = 0x23456;
|
const uint32_t kReceiverSsrc = 0x23456;
|
||||||
|
const uint32_t kSenderRtxSsrc = 0x32345;
|
||||||
const uint32_t kOneWayNetworkDelayMs = 100;
|
const uint32_t kOneWayNetworkDelayMs = 100;
|
||||||
|
|
||||||
class RtcpRttStatsTestImpl : public RtcpRttStats {
|
class RtcpRttStatsTestImpl : public RtcpRttStats {
|
||||||
@ -215,4 +224,245 @@ TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_FirAndPli) {
|
|||||||
EXPECT_EQ(2U, sender_.RtcpReceived().fir_packets);
|
EXPECT_EQ(2U, sender_.RtcpReceived().fir_packets);
|
||||||
EXPECT_EQ(1U, sender_.RtcpReceived().pli_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
|
} // namespace webrtc
|
||||||
|
@ -89,7 +89,7 @@ RTPSender::RTPSender(const int32_t id,
|
|||||||
rtx_(kRtxOff),
|
rtx_(kRtxOff),
|
||||||
payload_type_rtx_(-1),
|
payload_type_rtx_(-1),
|
||||||
target_bitrate_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
|
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_times_, 0, sizeof(nack_byte_count_times_));
|
||||||
memset(nack_byte_count_, 0, sizeof(nack_byte_count_));
|
memset(nack_byte_count_, 0, sizeof(nack_byte_count_));
|
||||||
memset(csrcs_, 0, sizeof(csrcs_));
|
memset(csrcs_, 0, sizeof(csrcs_));
|
||||||
@ -127,8 +127,14 @@ RTPSender::~RTPSender() {
|
|||||||
delete video_;
|
delete video_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTPSender::SetTargetSendBitrate(const uint32_t bits) {
|
void RTPSender::SetTargetBitrate(uint32_t bitrate) {
|
||||||
SetTargetBitrateKbps(static_cast<uint16_t>(bits / 1000));
|
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 {
|
uint16_t RTPSender::ActualSendBitrateKbit() const {
|
||||||
@ -330,7 +336,6 @@ void RTPSender::RTXStatus(int* mode, uint32_t* ssrc,
|
|||||||
*payload_type = payload_type_rtx_;
|
*payload_type = payload_type_rtx_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RTPSender::SetRtxPayloadType(int payload_type) {
|
void RTPSender::SetRtxPayloadType(int payload_type) {
|
||||||
CriticalSectionScoped cs(send_critsect_);
|
CriticalSectionScoped cs(send_critsect_);
|
||||||
payload_type_rtx_ = payload_type;
|
payload_type_rtx_ = payload_type;
|
||||||
@ -465,8 +470,8 @@ bool RTPSender::SendPaddingAccordingToBitrate(
|
|||||||
// Current bitrate since last estimate(1 second) averaged with the
|
// Current bitrate since last estimate(1 second) averaged with the
|
||||||
// estimate since then, to get the most up to date bitrate.
|
// estimate since then, to get the most up to date bitrate.
|
||||||
uint32_t current_bitrate = bitrate_sent_.BitrateNow();
|
uint32_t current_bitrate = bitrate_sent_.BitrateNow();
|
||||||
uint16_t target_bitrate_kbps = GetTargetBitrateKbps();
|
uint32_t target_bitrate = GetTargetBitrate();
|
||||||
int bitrate_diff = target_bitrate_kbps * 1000 - current_bitrate;
|
int bitrate_diff = target_bitrate - current_bitrate;
|
||||||
if (bitrate_diff <= 0) {
|
if (bitrate_diff <= 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -477,7 +482,7 @@ bool RTPSender::SendPaddingAccordingToBitrate(
|
|||||||
} else {
|
} else {
|
||||||
bytes = (bitrate_diff / 8);
|
bytes = (bitrate_diff / 8);
|
||||||
// Cap at 200 ms of target send data.
|
// 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) {
|
if (bytes > bytes_cap) {
|
||||||
bytes = bytes_cap;
|
bytes = bytes_cap;
|
||||||
}
|
}
|
||||||
@ -656,12 +661,12 @@ void RTPSender::OnReceivedNACK(
|
|||||||
"num_seqnum", nack_sequence_numbers.size(), "avg_rtt", avg_rtt);
|
"num_seqnum", nack_sequence_numbers.size(), "avg_rtt", avg_rtt);
|
||||||
const int64_t now = clock_->TimeInMilliseconds();
|
const int64_t now = clock_->TimeInMilliseconds();
|
||||||
uint32_t bytes_re_sent = 0;
|
uint32_t bytes_re_sent = 0;
|
||||||
uint16_t target_bitrate_kbps = GetTargetBitrateKbps();
|
uint32_t target_bitrate = GetTargetBitrate();
|
||||||
|
|
||||||
// Enough bandwidth to send NACK?
|
// Enough bandwidth to send NACK?
|
||||||
if (!ProcessNACKBitRate(now)) {
|
if (!ProcessNACKBitRate(now)) {
|
||||||
LOG(LS_INFO) << "NACK bitrate reached. Skip sending NACK response. Target "
|
LOG(LS_INFO) << "NACK bitrate reached. Skip sending NACK response. Target "
|
||||||
<< target_bitrate_kbps;
|
<< target_bitrate;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -681,10 +686,10 @@ void RTPSender::OnReceivedNACK(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Delay bandwidth estimate (RTT * BW).
|
// 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
|
// kbits/s * ms = bits => bits/8 = bytes
|
||||||
uint32_t target_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) {
|
if (bytes_re_sent > target_bytes) {
|
||||||
break; // Ignore the rest of the packets in the list.
|
break; // Ignore the rest of the packets in the list.
|
||||||
}
|
}
|
||||||
@ -699,33 +704,34 @@ void RTPSender::OnReceivedNACK(
|
|||||||
|
|
||||||
bool RTPSender::ProcessNACKBitRate(const uint32_t now) {
|
bool RTPSender::ProcessNACKBitRate(const uint32_t now) {
|
||||||
uint32_t num = 0;
|
uint32_t num = 0;
|
||||||
int32_t byte_count = 0;
|
int byte_count = 0;
|
||||||
const uint32_t avg_interval = 1000;
|
const int kAvgIntervalMs = 1000;
|
||||||
uint16_t target_bitrate_kbps = GetTargetBitrateKbps();
|
uint32_t target_bitrate = GetTargetBitrate();
|
||||||
|
|
||||||
CriticalSectionScoped cs(send_critsect_);
|
CriticalSectionScoped cs(send_critsect_);
|
||||||
|
|
||||||
if (target_bitrate_kbps == 0) {
|
if (target_bitrate == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (num = 0; num < NACK_BYTECOUNT_SIZE; ++num) {
|
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.
|
// Don't use data older than 1sec.
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
byte_count += nack_byte_count_[num];
|
byte_count += nack_byte_count_[num];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int32_t time_interval = avg_interval;
|
int time_interval = kAvgIntervalMs;
|
||||||
if (num == NACK_BYTECOUNT_SIZE) {
|
if (num == NACK_BYTECOUNT_SIZE) {
|
||||||
// More than NACK_BYTECOUNT_SIZE nack messages has been received
|
// More than NACK_BYTECOUNT_SIZE nack messages has been received
|
||||||
// during the last msg_interval.
|
// during the last msg_interval.
|
||||||
time_interval = now - nack_byte_count_times_[num - 1];
|
time_interval = now - nack_byte_count_times_[num - 1];
|
||||||
if (time_interval < 0) {
|
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,
|
void RTPSender::UpdateNACKBitRate(const uint32_t bytes,
|
||||||
@ -882,8 +888,13 @@ int RTPSender::TimeToSendPadding(int bytes) {
|
|||||||
int bytes_sent = SendRedundantPayloads(payload_type, bytes);
|
int bytes_sent = SendRedundantPayloads(payload_type, bytes);
|
||||||
bytes -= bytes_sent;
|
bytes -= bytes_sent;
|
||||||
if (bytes > 0) {
|
if (bytes > 0) {
|
||||||
int padding_sent = SendPadData(payload_type, timestamp, capture_time_ms,
|
int padding_sent = SendPadData(payload_type,
|
||||||
bytes, kDontStore, true, true);
|
timestamp,
|
||||||
|
capture_time_ms,
|
||||||
|
bytes,
|
||||||
|
kDontStore,
|
||||||
|
true,
|
||||||
|
rtx_ == kRtxOff);
|
||||||
bytes_sent += padding_sent;
|
bytes_sent += padding_sent;
|
||||||
}
|
}
|
||||||
return bytes_sent;
|
return bytes_sent;
|
||||||
@ -1659,14 +1670,4 @@ void RTPSender::BitrateUpdated(const BitrateStatistics& stats) {
|
|||||||
bitrate_callback_->Notify(stats, ssrc_);
|
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
|
} // namespace webrtc
|
||||||
|
@ -83,7 +83,8 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
|
|||||||
// was sent within the statistics window.
|
// was sent within the statistics window.
|
||||||
bool GetSendSideDelay(int* avg_send_delay_ms, int* max_send_delay_ms) const;
|
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
|
virtual uint16_t MaxDataPayloadLength() const
|
||||||
OVERRIDE; // with RTP and FEC headers.
|
OVERRIDE; // with RTP and FEC headers.
|
||||||
@ -329,9 +330,6 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
|
|||||||
bool is_retransmit);
|
bool is_retransmit);
|
||||||
bool IsFecPacket(const uint8_t* buffer, const RTPHeader& header) const;
|
bool IsFecPacket(const uint8_t* buffer, const RTPHeader& header) const;
|
||||||
|
|
||||||
void SetTargetBitrateKbps(uint16_t bitrate_kbps);
|
|
||||||
uint16_t GetTargetBitrateKbps();
|
|
||||||
|
|
||||||
Clock* clock_;
|
Clock* clock_;
|
||||||
Bitrate bitrate_sent_;
|
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 by the time the function returns there is no guarantee
|
||||||
// that the target bitrate is still valid.
|
// that the target bitrate is still valid.
|
||||||
scoped_ptr<CriticalSectionWrapper> target_bitrate_critsect_;
|
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
|
} // namespace webrtc
|
||||||
|
@ -444,7 +444,7 @@ TEST_F(RtpSenderTest, TrafficSmoothingWithExtensions) {
|
|||||||
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
|
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
|
||||||
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
|
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
|
||||||
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
|
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
|
||||||
rtp_sender_->SetTargetSendBitrate(300000);
|
rtp_sender_->SetTargetBitrate(300000);
|
||||||
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
|
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
|
||||||
int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_,
|
int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_,
|
||||||
kPayload,
|
kPayload,
|
||||||
@ -498,7 +498,7 @@ TEST_F(RtpSenderTest, TrafficSmoothingRetransmits) {
|
|||||||
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
|
kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId));
|
||||||
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
|
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
|
||||||
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
|
kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId));
|
||||||
rtp_sender_->SetTargetSendBitrate(300000);
|
rtp_sender_->SetTargetBitrate(300000);
|
||||||
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
|
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
|
||||||
int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_,
|
int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_,
|
||||||
kPayload,
|
kPayload,
|
||||||
@ -580,7 +580,7 @@ TEST_F(RtpSenderTest, SendPadding) {
|
|||||||
kAbsoluteSendTimeExtensionId);
|
kAbsoluteSendTimeExtensionId);
|
||||||
webrtc::RTPHeader rtp_header;
|
webrtc::RTPHeader rtp_header;
|
||||||
|
|
||||||
rtp_sender_->SetTargetSendBitrate(300000);
|
rtp_sender_->SetTargetBitrate(300000);
|
||||||
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
|
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
|
||||||
int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_,
|
int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_,
|
||||||
kPayload,
|
kPayload,
|
||||||
@ -698,7 +698,7 @@ TEST_F(RtpSenderTest, SendRedundantPayloads) {
|
|||||||
kTransmissionTimeOffsetExtensionId);
|
kTransmissionTimeOffsetExtensionId);
|
||||||
rtp_parser->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
|
rtp_parser->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
|
||||||
kAbsoluteSendTimeExtensionId);
|
kAbsoluteSendTimeExtensionId);
|
||||||
rtp_sender_->SetTargetSendBitrate(300000);
|
rtp_sender_->SetTargetBitrate(300000);
|
||||||
const size_t kNumPayloadSizes = 10;
|
const size_t kNumPayloadSizes = 10;
|
||||||
const int kPayloadSizes[kNumPayloadSizes] = {500, 550, 600, 650, 700, 750,
|
const int kPayloadSizes[kNumPayloadSizes] = {500, 550, 600, 650, 700, 750,
|
||||||
800, 850, 900, 950};
|
800, 850, 900, 950};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user