diff --git a/webrtc/call/congestion_controller.cc b/webrtc/call/congestion_controller.cc index 4030f8e75b..0267d79fca 100644 --- a/webrtc/call/congestion_controller.cc +++ b/webrtc/call/congestion_controller.cc @@ -237,8 +237,7 @@ TransportFeedbackObserver* CongestionController::GetTransportFeedbackObserver() { if (transport_feedback_adapter_.get() == nullptr) { transport_feedback_adapter_.reset(new TransportFeedbackAdapter( - bitrate_controller_->CreateRtcpBandwidthObserver(), - Clock::GetRealTimeClock(), process_thread_)); + bitrate_controller_.get(), Clock::GetRealTimeClock(), process_thread_)); transport_feedback_adapter_->SetBitrateEstimator( new RemoteBitrateEstimatorAbsSendTime( transport_feedback_adapter_.get(), Clock::GetRealTimeClock())); diff --git a/webrtc/modules/bitrate_controller/bitrate_controller_impl.cc b/webrtc/modules/bitrate_controller/bitrate_controller_impl.cc index f8fd2bb987..da51c6ff53 100644 --- a/webrtc/modules/bitrate_controller/bitrate_controller_impl.cc +++ b/webrtc/modules/bitrate_controller/bitrate_controller_impl.cc @@ -143,6 +143,15 @@ void BitrateControllerImpl::OnReceivedEstimatedBitrate(uint32_t bitrate) { MaybeTriggerOnNetworkChanged(); } +void BitrateControllerImpl::UpdateDelayBasedEstimate(uint32_t bitrate_bps) { + { + rtc::CritScope cs(&critsect_); + bandwidth_estimation_.UpdateDelayBasedEstimate(clock_->TimeInMilliseconds(), + bitrate_bps); + } + MaybeTriggerOnNetworkChanged(); +} + int64_t BitrateControllerImpl::TimeUntilNextProcess() { const int64_t kBitrateControllerUpdateIntervalMs = 25; rtc::CritScope cs(&critsect_); diff --git a/webrtc/modules/bitrate_controller/bitrate_controller_impl.h b/webrtc/modules/bitrate_controller/bitrate_controller_impl.h index b601899631..d7888ccde3 100644 --- a/webrtc/modules/bitrate_controller/bitrate_controller_impl.h +++ b/webrtc/modules/bitrate_controller/bitrate_controller_impl.h @@ -36,8 +36,9 @@ class BitrateControllerImpl : public BitrateController { RtcpBandwidthObserver* CreateRtcpBandwidthObserver() override; void SetStartBitrate(int start_bitrate_bps) override; - void SetMinMaxBitrate(int min_bitrate_bps, - int max_bitrate_bps) override; + void SetMinMaxBitrate(int min_bitrate_bps, int max_bitrate_bps) override; + + void UpdateDelayBasedEstimate(uint32_t bitrate_bps) override; void SetReservedBitrate(uint32_t reserved_bitrate_bps) override; diff --git a/webrtc/modules/bitrate_controller/bitrate_controller_unittest.cc b/webrtc/modules/bitrate_controller/bitrate_controller_unittest.cc index 2b9e589fbd..fd9636a88d 100644 --- a/webrtc/modules/bitrate_controller/bitrate_controller_unittest.cc +++ b/webrtc/modules/bitrate_controller/bitrate_controller_unittest.cc @@ -162,14 +162,18 @@ TEST_F(BitrateControllerTest, OneBitrateObserverOneRtcpObserver) { bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(300000, bitrate_observer_.last_bitrate_); - // Test that a low REMB trigger immediately. + // Test that a low delay-based estimate limits the combined estimate. + controller_->UpdateDelayBasedEstimate(280000); + EXPECT_EQ(280000, bitrate_observer_.last_bitrate_); + + // Test that a low REMB limits the combined estimate. bandwidth_observer_->OnReceivedEstimatedBitrate(250000); EXPECT_EQ(250000, bitrate_observer_.last_bitrate_); EXPECT_EQ(0, bitrate_observer_.last_fraction_loss_); EXPECT_EQ(50, bitrate_observer_.last_rtt_); bandwidth_observer_->OnReceivedEstimatedBitrate(1000); - EXPECT_EQ(100000, bitrate_observer_.last_bitrate_); // Min cap. + EXPECT_EQ(100000, bitrate_observer_.last_bitrate_); } TEST_F(BitrateControllerTest, OneBitrateObserverTwoRtcpObservers) { diff --git a/webrtc/modules/bitrate_controller/include/bitrate_controller.h b/webrtc/modules/bitrate_controller/include/bitrate_controller.h index d1eca8e0fe..a9c247acf1 100644 --- a/webrtc/modules/bitrate_controller/include/bitrate_controller.h +++ b/webrtc/modules/bitrate_controller/include/bitrate_controller.h @@ -57,6 +57,8 @@ class BitrateController : public Module { virtual void SetStartBitrate(int start_bitrate_bps) = 0; virtual void SetMinMaxBitrate(int min_bitrate_bps, int max_bitrate_bps) = 0; + virtual void UpdateDelayBasedEstimate(uint32_t bitrate_bps) = 0; + virtual void SetEventLog(RtcEventLog* event_log) = 0; // Gets the available payload bandwidth in bits per second. Note that diff --git a/webrtc/modules/bitrate_controller/include/mock/mock_bitrate_controller.h b/webrtc/modules/bitrate_controller/include/mock/mock_bitrate_controller.h index 7a7d2e406b..8748696d45 100644 --- a/webrtc/modules/bitrate_controller/include/mock/mock_bitrate_controller.h +++ b/webrtc/modules/bitrate_controller/include/mock/mock_bitrate_controller.h @@ -24,6 +24,21 @@ class MockBitrateObserver : public BitrateObserver { uint8_t fraction_loss, int64_t rtt_ms)); }; + +class MockBitrateController : public BitrateController { + public: + MOCK_METHOD0(CreateRtcpBandwidthObserver, RtcpBandwidthObserver*()); + MOCK_METHOD1(SetStartBitrate, void(int start_bitrate_bps)); + MOCK_METHOD2(SetMinMaxBitrate, + void(int min_bitrate_bps, int max_bitrate_bps)); + MOCK_METHOD1(UpdateDelayBasedEstimate, void(uint32_t bitrate_bps)); + MOCK_METHOD1(SetEventLog, void(RtcEventLog* event_log)); + MOCK_CONST_METHOD1(AvailableBandwidth, bool(uint32_t* bandwidth)); + MOCK_METHOD1(SetReservedBitrate, void(uint32_t reserved_bitrate_bps)); + + MOCK_METHOD0(Process, int()); + MOCK_METHOD0(TimeUntilNextProcess, int64_t()); +}; } // namespace test } // namespace webrtc diff --git a/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc b/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc index 258c4d94de..68912907e6 100644 --- a/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc +++ b/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc @@ -55,6 +55,7 @@ SendSideBandwidthEstimation::SendSideBandwidthEstimation() last_fraction_loss_(0), last_round_trip_time_ms_(0), bwe_incoming_(0), + delay_based_bitrate_bps_(0), time_last_decrease_ms_(0), first_report_time_ms_(-1), initially_lost_packets_(0), @@ -104,6 +105,13 @@ void SendSideBandwidthEstimation::UpdateReceiverEstimate( bitrate_ = CapBitrateToThresholds(now_ms, bitrate_); } +void SendSideBandwidthEstimation::UpdateDelayBasedEstimate( + int64_t now_ms, + uint32_t bitrate_bps) { + delay_based_bitrate_bps_ = bitrate_bps; + bitrate_ = CapBitrateToThresholds(now_ms, bitrate_); +} + void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss, int64_t rtt, int number_of_packets, @@ -268,6 +276,9 @@ uint32_t SendSideBandwidthEstimation::CapBitrateToThresholds( if (bwe_incoming_ > 0 && bitrate > bwe_incoming_) { bitrate = bwe_incoming_; } + if (delay_based_bitrate_bps_ > 0 && bitrate > delay_based_bitrate_bps_) { + bitrate = delay_based_bitrate_bps_; + } if (bitrate > max_bitrate_configured_) { bitrate = max_bitrate_configured_; } diff --git a/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h b/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h index 7ffb42cb54..608a5e738d 100644 --- a/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h +++ b/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h @@ -35,6 +35,9 @@ class SendSideBandwidthEstimation { // Call when we receive a RTCP message with TMMBR or REMB. void UpdateReceiverEstimate(int64_t now_ms, uint32_t bandwidth); + // Call when a new delay-based estimate is available. + void UpdateDelayBasedEstimate(int64_t now_ms, uint32_t bitrate_bps); + // Call when we receive a RTCP message with a ReceiveBlock. void UpdateReceiverBlock(uint8_t fraction_loss, int64_t rtt, @@ -80,6 +83,7 @@ class SendSideBandwidthEstimation { int64_t last_round_trip_time_ms_; uint32_t bwe_incoming_; + uint32_t delay_based_bitrate_bps_; int64_t time_last_decrease_ms_; int64_t first_report_time_ms_; int initially_lost_packets_; diff --git a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.cc b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.cc index 5904594ac8..7e45136fef 100644 --- a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.cc +++ b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.cc @@ -27,11 +27,11 @@ const int64_t kBaseTimestampScaleFactor = const int64_t kBaseTimestampRangeSizeUs = kBaseTimestampScaleFactor * (1 << 24); TransportFeedbackAdapter::TransportFeedbackAdapter( - RtcpBandwidthObserver* bandwidth_observer, + BitrateController* bitrate_controller, Clock* clock, ProcessThread* process_thread) : send_time_history_(clock, kSendTimeHistoryWindowMs), - rtcp_bandwidth_observer_(bandwidth_observer), + bitrate_controller_(bitrate_controller), process_thread_(process_thread), clock_(clock), current_offset_ms_(kNoTimestamp), @@ -124,7 +124,7 @@ void TransportFeedbackAdapter::OnTransportFeedback( void TransportFeedbackAdapter::OnReceiveBitrateChanged( const std::vector& ssrcs, unsigned int bitrate) { - rtcp_bandwidth_observer_->OnReceivedEstimatedBitrate(bitrate); + bitrate_controller_->UpdateDelayBasedEstimate(bitrate); } void TransportFeedbackAdapter::OnRttUpdate(int64_t avg_rtt_ms, diff --git a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h index 93f30e6cee..c142eeabcf 100644 --- a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h +++ b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h @@ -15,7 +15,7 @@ #include "webrtc/base/criticalsection.h" #include "webrtc/base/thread_annotations.h" -#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" #include "webrtc/modules/include/module_common_types.h" #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "webrtc/modules/remote_bitrate_estimator/include/send_time_history.h" @@ -28,7 +28,7 @@ class TransportFeedbackAdapter : public TransportFeedbackObserver, public CallStatsObserver, public RemoteBitrateObserver { public: - TransportFeedbackAdapter(RtcpBandwidthObserver* bandwidth_observer, + TransportFeedbackAdapter(BitrateController* bitrate_controller, Clock* clock, ProcessThread* process_thread); virtual ~TransportFeedbackAdapter(); @@ -54,7 +54,7 @@ class TransportFeedbackAdapter : public TransportFeedbackObserver, rtc::CriticalSection lock_; SendTimeHistory send_time_history_ GUARDED_BY(&lock_); - rtc::scoped_ptr rtcp_bandwidth_observer_; + BitrateController* bitrate_controller_; rtc::scoped_ptr bitrate_estimator_; ProcessThread* const process_thread_; Clock* const clock_; diff --git a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter_unittest.cc b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter_unittest.cc index 64d0e55397..f2ef5d9587 100644 --- a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter_unittest.cc +++ b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter_unittest.cc @@ -16,6 +16,7 @@ #include "webrtc/base/checks.h" #include "webrtc/base/scoped_ptr.h" +#include "webrtc/modules/bitrate_controller/include/mock/mock_bitrate_controller.h" #include "webrtc/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_estimator.h" #include "webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h" #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" @@ -34,13 +35,14 @@ class TransportFeedbackAdapterTest : public ::testing::Test { TransportFeedbackAdapterTest() : clock_(0), bitrate_estimator_(nullptr), + bitrate_controller_(this), receiver_estimated_bitrate_(0) {} virtual ~TransportFeedbackAdapterTest() {} virtual void SetUp() { - adapter_.reset(new TransportFeedbackAdapter( - new RtcpBandwidthObserverAdapter(this), &clock_, &process_thread_)); + adapter_.reset(new TransportFeedbackAdapter(&bitrate_controller_, &clock_, + &process_thread_)); bitrate_estimator_ = new MockRemoteBitrateEstimator(); EXPECT_CALL(process_thread_, RegisterModule(bitrate_estimator_)).Times(1); @@ -55,19 +57,15 @@ class TransportFeedbackAdapterTest : public ::testing::Test { protected: // Proxy class used since TransportFeedbackAdapter will own the instance // passed at construction. - class RtcpBandwidthObserverAdapter : public RtcpBandwidthObserver { + class MockBitrateControllerAdapter : public MockBitrateController { public: - explicit RtcpBandwidthObserverAdapter(TransportFeedbackAdapterTest* owner) - : owner_(owner) {} + explicit MockBitrateControllerAdapter(TransportFeedbackAdapterTest* owner) + : MockBitrateController(), owner_(owner) {} - void OnReceivedEstimatedBitrate(uint32_t bitrate) override { - owner_->receiver_estimated_bitrate_ = bitrate; - } + ~MockBitrateControllerAdapter() override {} - void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks, - int64_t rtt, - int64_t now_ms) override { - RTC_NOTREACHED(); + void UpdateDelayBasedEstimate(uint32_t bitrate_bps) override { + owner_->receiver_estimated_bitrate_ = bitrate_bps; } TransportFeedbackAdapterTest* const owner_; @@ -113,6 +111,7 @@ class TransportFeedbackAdapterTest : public ::testing::Test { SimulatedClock clock_; MockProcessThread process_thread_; MockRemoteBitrateEstimator* bitrate_estimator_; + MockBitrateControllerAdapter bitrate_controller_; rtc::scoped_ptr adapter_; uint32_t receiver_estimated_bitrate_; diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc index 48dc3e8bbd..0bf7570d1d 100644 --- a/webrtc/video/end_to_end_tests.cc +++ b/webrtc/video/end_to_end_tests.cc @@ -20,6 +20,7 @@ #include "webrtc/call.h" #include "webrtc/call/transport_adapter.h" #include "webrtc/frame_callback.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h" #include "webrtc/modules/rtp_rtcp/source/byte_io.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h" #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" @@ -1807,6 +1808,143 @@ TEST_F(EndToEndTest, VerifyBandwidthStats) { RunBaseTest(&test); } + +// Verifies that it's possible to limit the send BWE by sending a REMB. +// This is verified by allowing the send BWE to ramp-up to >1000 kbps, +// then have the test generate a REMB of 500 kbps and verify that the send BWE +// is reduced to exactly 500 kbps. Then a REMB of 1000 kbps is generated and the +// test verifies that the send BWE ramps back up to exactly 1000 kbps. +TEST_F(EndToEndTest, RembWithSendSideBwe) { + class BweObserver : public test::EndToEndTest { + public: + BweObserver() + : EndToEndTest(kDefaultTimeoutMs), + sender_call_(nullptr), + clock_(Clock::GetRealTimeClock()), + sender_ssrc_(0), + remb_bitrate_bps_(1000000), + receive_transport_(nullptr), + event_(false, false), + poller_thread_(&BitrateStatsPollingThread, + this, + "BitrateStatsPollingThread"), + state_(kWaitForFirstRampUp) {} + + ~BweObserver() {} + + test::PacketTransport* CreateReceiveTransport() { + receive_transport_ = new test::PacketTransport( + nullptr, this, test::PacketTransport::kReceiver, + FakeNetworkPipe::Config()); + return receive_transport_; + } + + Call::Config GetSenderCallConfig() override { + Call::Config config; + // Set a high start bitrate to reduce the test completion time. + config.bitrate_config.start_bitrate_bps = remb_bitrate_bps_; + return config; + } + + void ModifyVideoConfigs( + VideoSendStream::Config* send_config, + std::vector* receive_configs, + VideoEncoderConfig* encoder_config) override { + ASSERT_EQ(1u, send_config->rtp.ssrcs.size()); + send_config->rtp.extensions.clear(); + send_config->rtp.extensions.push_back( + RtpExtension(RtpExtension::kTransportSequenceNumber, + test::kTransportSequenceNumberExtensionId)); + sender_ssrc_ = send_config->rtp.ssrcs[0]; + + encoder_config->streams[0].max_bitrate_bps = + encoder_config->streams[0].target_bitrate_bps = 2000000; + + ASSERT_EQ(1u, receive_configs->size()); + (*receive_configs)[0].rtp.remb = false; + (*receive_configs)[0].rtp.transport_cc = true; + (*receive_configs)[0].rtp.extensions = send_config->rtp.extensions; + RtpRtcp::Configuration config; + config.receiver_only = true; + config.clock = clock_; + config.outgoing_transport = receive_transport_; + rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config)); + rtp_rtcp_->SetRemoteSSRC((*receive_configs)[0].rtp.remote_ssrc); + rtp_rtcp_->SetSSRC((*receive_configs)[0].rtp.local_ssrc); + rtp_rtcp_->SetREMBStatus(true); + rtp_rtcp_->SetSendingStatus(true); + rtp_rtcp_->SetRTCPStatus(RtcpMode::kReducedSize); + } + + void OnCallsCreated(Call* sender_call, Call* receiver_call) override { + sender_call_ = sender_call; + } + + static bool BitrateStatsPollingThread(void* obj) { + return static_cast(obj)->PollStats(); + } + + bool PollStats() { + if (sender_call_) { + Call::Stats stats = sender_call_->GetStats(); + switch (state_) { + case kWaitForFirstRampUp: + if (stats.send_bandwidth_bps >= remb_bitrate_bps_) { + state_ = kWaitForRemb; + remb_bitrate_bps_ /= 2; + rtp_rtcp_->SetREMBData( + remb_bitrate_bps_, + std::vector(&sender_ssrc_, &sender_ssrc_ + 1)); + rtp_rtcp_->SendRTCP(kRtcpRr); + } + break; + + case kWaitForRemb: + if (stats.send_bandwidth_bps == remb_bitrate_bps_) { + state_ = kWaitForSecondRampUp; + remb_bitrate_bps_ *= 2; + rtp_rtcp_->SetREMBData( + remb_bitrate_bps_, + std::vector(&sender_ssrc_, &sender_ssrc_ + 1)); + rtp_rtcp_->SendRTCP(kRtcpRr); + } + break; + + case kWaitForSecondRampUp: + if (stats.send_bandwidth_bps == remb_bitrate_bps_) { + observation_complete_.Set(); + } + break; + } + } + + return !event_.Wait(1000); + } + + void PerformTest() override { + poller_thread_.Start(); + EXPECT_TRUE(Wait()) + << "Timed out while waiting for bitrate to change according to REMB."; + poller_thread_.Stop(); + } + + private: + enum TestState { kWaitForFirstRampUp, kWaitForRemb, kWaitForSecondRampUp }; + + Call* sender_call_; + Clock* const clock_; + uint32_t sender_ssrc_; + int remb_bitrate_bps_; + rtc::scoped_ptr rtp_rtcp_; + test::PacketTransport* receive_transport_; + rtc::Event event_; + rtc::PlatformThread poller_thread_; + TestState state_; + } test; + + RunBaseTest(&test); +} + TEST_F(EndToEndTest, VerifyNackStats) { static const int kPacketNumberToDrop = 200; class NackObserver : public test::EndToEndTest {