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/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) {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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};
|
||||
|
Loading…
Reference in New Issue
Block a user