diff --git a/webrtc/modules/pacing/include/paced_sender.h b/webrtc/modules/pacing/include/paced_sender.h index 6b812878c..3bd989671 100644 --- a/webrtc/modules/pacing/include/paced_sender.h +++ b/webrtc/modules/pacing/include/paced_sender.h @@ -70,7 +70,9 @@ class PacedSender : public Module { // pad. We will send padding packets to increase the total bitrate until we // reach |pad_up_to_bitrate_kbps|. If the media bitrate is above // |pad_up_to_bitrate_kbps| no padding will be sent. - void UpdateBitrate(int target_bitrate_kbps, int pad_up_to_bitrate_kbps); + void UpdateBitrate(int target_bitrate_kbps, + int max_padding_bitrate_kbps, + int pad_up_to_bitrate_kbps); // Returns true if we send the packet now, else it will add the packet // information to the queue and call TimeToSendPacket when it's time to send. diff --git a/webrtc/modules/pacing/paced_sender.cc b/webrtc/modules/pacing/paced_sender.cc index a242cc9c9..49e8ef829 100644 --- a/webrtc/modules/pacing/paced_sender.cc +++ b/webrtc/modules/pacing/paced_sender.cc @@ -29,9 +29,6 @@ const int kMaxIntervalTimeMs = 30; // low bitrates (less than 320 kbits/s). const int kMaxQueueTimeWithoutSendingMs = 30; -// Max padding bytes per second. -const int kMaxPaddingKbps = 800; - } // namespace namespace webrtc { @@ -128,7 +125,7 @@ PacedSender::PacedSender(Callback* callback, int target_bitrate_kbps, critsect_(CriticalSectionWrapper::CreateCriticalSection()), media_budget_(new paced_sender::IntervalBudget( pace_multiplier_ * target_bitrate_kbps)), - padding_budget_(new paced_sender::IntervalBudget(kMaxPaddingKbps)), + padding_budget_(new paced_sender::IntervalBudget(0)), // No padding until UpdateBitrate is called. pad_up_to_bitrate_budget_(new paced_sender::IntervalBudget(0)), time_last_update_(TickTime::Now()), @@ -164,9 +161,11 @@ bool PacedSender::Enabled() const { } void PacedSender::UpdateBitrate(int target_bitrate_kbps, + int max_padding_bitrate_kbps, int pad_up_to_bitrate_kbps) { CriticalSectionScoped cs(critsect_.get()); media_budget_->set_target_rate_kbps(pace_multiplier_ * target_bitrate_kbps); + padding_budget_->set_target_rate_kbps(max_padding_bitrate_kbps); pad_up_to_bitrate_budget_->set_target_rate_kbps(pad_up_to_bitrate_kbps); } diff --git a/webrtc/modules/pacing/paced_sender_unittest.cc b/webrtc/modules/pacing/paced_sender_unittest.cc index 3e6127373..286c09747 100644 --- a/webrtc/modules/pacing/paced_sender_unittest.cc +++ b/webrtc/modules/pacing/paced_sender_unittest.cc @@ -211,7 +211,7 @@ TEST_F(PacedSenderTest, Padding) { uint16_t sequence_number = 1234; int64_t capture_time_ms = 56789; - send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate); + send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate, kTargetBitrate); // Due to the multiplicative factor we can send 3 packets not 2 packets. SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, capture_time_ms, 250); @@ -237,7 +237,7 @@ TEST_F(PacedSenderTest, Padding) { TEST_F(PacedSenderTest, NoPaddingWhenDisabled) { send_bucket_->SetStatus(false); - send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate); + send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate, kTargetBitrate); // No padding is expected since the pacer is disabled. EXPECT_CALL(callback_, TimeToSendPadding(_)).Times(0); EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess()); @@ -257,7 +257,7 @@ TEST_F(PacedSenderTest, VerifyPaddingUpToBitrate) { int64_t capture_time_ms = 56789; const int kTimeStep = 5; const int64_t kBitrateWindow = 100; - send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate); + send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate, kTargetBitrate); int64_t start_time = TickTime::MillisecondTimestamp(); while (TickTime::MillisecondTimestamp() - start_time < kBitrateWindow) { SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, @@ -276,7 +276,9 @@ TEST_F(PacedSenderTest, VerifyMaxPaddingBitrate) { const int kTimeStep = 5; const int64_t kBitrateWindow = 100; const int kTargetBitrate = 1500; - send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate); + const int kMaxPaddingBitrate = 800; + send_bucket_->UpdateBitrate(kTargetBitrate, kMaxPaddingBitrate, + kTargetBitrate); int64_t start_time = TickTime::MillisecondTimestamp(); while (TickTime::MillisecondTimestamp() - start_time < kBitrateWindow) { SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, @@ -298,7 +300,7 @@ TEST_F(PacedSenderTest, VerifyAverageBitrateVaryingMediaPayload) { send_bucket_.reset(new PacedSender(&callback, kTargetBitrate, kPaceMultiplier)); send_bucket_->SetStatus(true); - send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate); + send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate, kTargetBitrate); int64_t start_time = TickTime::MillisecondTimestamp(); int media_bytes = 0; while (TickTime::MillisecondTimestamp() - start_time < kBitrateWindow) { diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h index f7992dc05..65d57946b 100644 --- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h +++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h @@ -679,7 +679,8 @@ class RtpRtcp : public Module { /* * Set the target send bitrate */ - virtual void SetTargetSendBitrate(const uint32_t bitrate) = 0; + virtual void SetTargetSendBitrate( + const std::vector& stream_bitrates) = 0; /* * Turn on/off generic FEC diff --git a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h index 2b6bedc3c..608fe351a 100644 --- a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h +++ b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h @@ -218,7 +218,7 @@ class MockRtpRtcp : public RtpRtcp { MOCK_METHOD1(SetCameraDelay, int32_t(const int32_t delayMS)); MOCK_METHOD1(SetTargetSendBitrate, - void(const uint32_t bitrate)); + void(const std::vector& stream_bitrates)); MOCK_METHOD3(SetGenericFECStatus, int32_t(const bool enable, const uint8_t payloadTypeRED, const uint8_t payloadTypeFEC)); MOCK_METHOD3(GenericFECStatus, diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index 0922d2c92..5055d14e3 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -1254,42 +1254,35 @@ RtpVideoCodecTypes ModuleRtpRtcpImpl::SendVideoCodec() const { return rtp_sender_.VideoCodecType(); } -void ModuleRtpRtcpImpl::SetTargetSendBitrate(const uint32_t bitrate) { +void ModuleRtpRtcpImpl::SetTargetSendBitrate( + const std::vector& stream_bitrates) { WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, - "SetTargetSendBitrate: %ubit", bitrate); + "SetTargetSendBitrate: %ld streams", stream_bitrates.size()); const bool have_child_modules(child_modules_.empty() ? false : true); if (have_child_modules) { CriticalSectionScoped lock(critical_section_module_ptrs_.get()); if (simulcast_) { - uint32_t bitrate_remainder = bitrate; std::list::iterator it = child_modules_.begin(); - for (int i = 0; it != child_modules_.end() && - i < send_video_codec_.numberOfSimulcastStreams; ++it) { + for (size_t i = 0; + it != child_modules_.end() && i < stream_bitrates.size(); ++it) { if ((*it)->SendingMedia()) { RTPSender& rtp_sender = (*it)->rtp_sender_; - if (send_video_codec_.simulcastStream[i].maxBitrate * 1000 > - bitrate_remainder) { - rtp_sender.SetTargetSendBitrate(bitrate_remainder); - bitrate_remainder = 0; - } else { - rtp_sender.SetTargetSendBitrate( - send_video_codec_.simulcastStream[i].maxBitrate * 1000); - bitrate_remainder -= - send_video_codec_.simulcastStream[i].maxBitrate * 1000; - } + rtp_sender.SetTargetSendBitrate(stream_bitrates[i]); ++i; } } } else { + assert(stream_bitrates.size() == 1); std::list::iterator it = child_modules_.begin(); for (; it != child_modules_.end(); ++it) { RTPSender& rtp_sender = (*it)->rtp_sender_; - rtp_sender.SetTargetSendBitrate(bitrate); + rtp_sender.SetTargetSendBitrate(stream_bitrates[0]); } } } else { - rtp_sender_.SetTargetSendBitrate(bitrate); + assert(stream_bitrates.size() == 1); + rtp_sender_.SetTargetSendBitrate(stream_bitrates[0]); } } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h index 11340c264..8f339b6d0 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -303,7 +303,8 @@ class ModuleRtpRtcpImpl : public RtpRtcp { virtual int32_t SetCameraDelay(const int32_t delay_ms) OVERRIDE; - virtual void SetTargetSendBitrate(const uint32_t bitrate) OVERRIDE; + virtual void SetTargetSendBitrate( + const std::vector& stream_bitrates) OVERRIDE; virtual int32_t SetGenericFECStatus( const bool enable, diff --git a/webrtc/video_engine/vie_encoder.cc b/webrtc/video_engine/vie_encoder.cc index 7de8ac074..e0d9a4350 100644 --- a/webrtc/video_engine/vie_encoder.cc +++ b/webrtc/video_engine/vie_encoder.cc @@ -55,6 +55,28 @@ static const int kMinPacingDelayMs = 200; // VideoEngine API and remove the kTransmissionMaxBitrateMultiplier. static const int kTransmissionMaxBitrateMultiplier = 2; +std::vector AllocateStreamBitrates( + uint32_t total_bitrate, + const SimulcastStream* stream_configs, + size_t number_of_streams) { + if (number_of_streams == 0) { + std::vector stream_bitrates(1, 0); + stream_bitrates[0] = total_bitrate; + return stream_bitrates; + } + std::vector stream_bitrates(number_of_streams, 0); + uint32_t bitrate_remainder = total_bitrate; + for (size_t i = 0; i < stream_bitrates.size() && bitrate_remainder > 0; ++i) { + if (stream_configs[i].maxBitrate * 1000 > bitrate_remainder) { + stream_bitrates[i] = bitrate_remainder; + } else { + stream_bitrates[i] = stream_configs[i].maxBitrate * 1000; + } + bitrate_remainder -= stream_bitrates[i]; + } + return stream_bitrates; +} + class QMVideoSettingsCallback : public VCMQMSettingsCallback { public: explicit QMVideoSettingsCallback(VideoProcessingModule* vpm); @@ -401,7 +423,11 @@ int32_t ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec) { return -1; } // Convert from kbps to bps. - default_rtp_rtcp_->SetTargetSendBitrate(video_codec.startBitrate * 1000); + std::vector stream_bitrates = AllocateStreamBitrates( + video_codec.startBitrate * 1000, + video_codec.simulcastStream, + video_codec.numberOfSimulcastStreams); + default_rtp_rtcp_->SetTargetSendBitrate(stream_bitrates); uint16_t max_data_payload_length = default_rtp_rtcp_->MaxDataPayloadLength(); @@ -1013,10 +1039,36 @@ void ViEEncoder::OnNetworkChanged(const uint32_t bitrate_bps, if (vcm_.SendCodec(&send_codec) != 0) { return; } - int pad_up_to_bitrate = std::min(bitrate_kbps, - static_cast(send_codec.maxBitrate)); - paced_sender_->UpdateBitrate(bitrate_kbps, pad_up_to_bitrate); - default_rtp_rtcp_->SetTargetSendBitrate(bitrate_bps); + SimulcastStream* stream_configs = send_codec.simulcastStream; + // Allocate the bandwidth between the streams. + std::vector stream_bitrates = AllocateStreamBitrates( + bitrate_bps, + stream_configs, + send_codec.numberOfSimulcastStreams); + // Find the max amount of padding we can allow ourselves to send at this + // point, based on which streams are currently active and what our current + // available bandwidth is. + int max_padding_bitrate_kbps = 0; + int i = send_codec.numberOfSimulcastStreams - 1; + for (std::vector::reverse_iterator it = stream_bitrates.rbegin(); + it != stream_bitrates.rend(); ++it) { + if (*it > 0) { + max_padding_bitrate_kbps = std::min((*it + 500) / 1000, + stream_configs[i].minBitrate); + break; + } + --i; + } + int pad_up_to_bitrate_kbps = + stream_configs[send_codec.numberOfSimulcastStreams - 1].minBitrate; + for (int i = 0; i < send_codec.numberOfSimulcastStreams - 1; ++i) { + pad_up_to_bitrate_kbps += stream_configs[i].targetBitrate; + } + pad_up_to_bitrate_kbps = std::min(bitrate_kbps, pad_up_to_bitrate_kbps); + paced_sender_->UpdateBitrate(bitrate_kbps, + max_padding_bitrate_kbps, + pad_up_to_bitrate_kbps); + default_rtp_rtcp_->SetTargetSendBitrate(stream_bitrates); } PacedSender* ViEEncoder::GetPacedSender() {