From a15fbfdcdee391bd87bb1c2721f0fbb824f5fbfb Mon Sep 17 00:00:00 2001 From: "stefan@webrtc.org" Date: Tue, 17 Jun 2014 17:32:05 +0000 Subject: [PATCH] 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 --- .../modules/rtp_rtcp/source/rtp_rtcp_impl.cc | 70 +++-- .../modules/rtp_rtcp/source/rtp_rtcp_impl.h | 11 +- .../rtp_rtcp/source/rtp_rtcp_impl_unittest.cc | 250 ++++++++++++++++++ webrtc/modules/rtp_rtcp/source/rtp_sender.cc | 63 ++--- webrtc/modules/rtp_rtcp/source/rtp_sender.h | 8 +- .../rtp_rtcp/source/rtp_sender_unittest.cc | 8 +- 6 files changed, 321 insertions(+), 89 deletions(-) diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index fe33e1b7a..70fe71743 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -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(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::iterator it = child_modules_.begin(); + std::vector::iterator it = child_modules_.begin(); while (it != child_modules_.end()) { RtpRtcp* module = *it; if (module == remove_module) { @@ -252,8 +241,9 @@ void ModuleRtpRtcpImpl::SetRTXSendStatus(int mode) { rtp_sender_.SetRTXStatus(mode); } -void ModuleRtpRtcpImpl::RTXSendStatus(int* mode, uint32_t* ssrc, - int* payload_type) const { +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::iterator it = child_modules_.begin(); + std::vector::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::const_iterator it = child_modules_.begin(); + std::vector::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::iterator it = child_modules_.begin(); + std::vector::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::iterator it = child_modules_.begin(); + std::vector::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::iterator it = child_modules_.begin(); + std::vector::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::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::const_iterator it = - child_modules_.begin(); + std::vector::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::iterator it = child_modules_.begin(); + std::vector::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::iterator it = child_modules_.begin(); + std::vector::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::iterator it = child_modules_.begin(); + std::vector::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::iterator it = child_modules_.begin(); + std::vector::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::iterator it = child_modules_.begin(); + std::vector::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::const_iterator it = - child_modules_.begin(); + std::vector::const_iterator it = child_modules_.begin(); while (it != child_modules_.end()) { RtpRtcp* module = *it; if (module) { diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h index ef00a461f..55826b6fe 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -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 critical_section_module_ptrs_; scoped_ptr critical_section_module_ptrs_feedback_; ModuleRtpRtcpImpl* default_module_; - std::list child_modules_; + std::vector 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. diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc index 4b6fa32fb..eb76cfe7c 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc @@ -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 parser(RtpHeaderParser::Create()); + EXPECT_TRUE( + parser->Parse(static_cast(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::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::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::const_iterator it = bytes_received_.begin(); + it != bytes_received_.end(); + ++it) { + sum += it->second; + } + return sum; + } + + private: + std::map bytes_received_; + std::map packets_received_; +}; + +class RtpSendingTest : public ::testing::Test { + protected: + // Map from SSRC to number of received packets and bytes. + typedef std::map > 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 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 receive_statistics_; + RtcpRttStatsTestImpl rtt_stats_; + std::vector senders_; + RtpSendingTestTransport transport_; + NiceMock 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(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(1, 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(2, 1000); + ExpectPadding(expected_padding); + senders_[0]->TimeToSendPadding(1500); + expected_padding[kSenderRtxSsrc + 3] = std::make_pair(3, 1500); + ExpectPadding(expected_padding); +} } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index 6e59a2d70..7cfcd7222 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -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(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(target_bitrate_kbps) * avg_rtt) >> 3; + (static_cast(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(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 diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h index 17457ff22..17b026cad 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h @@ -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 target_bitrate_critsect_; - uint16_t target_bitrate_kbps_ GUARDED_BY(target_bitrate_critsect_); + uint16_t target_bitrate_ GUARDED_BY(target_bitrate_critsect_); }; } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc index 67a4a57dc..18482890f 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -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};