Support REMB in combination with send-side BWE.
BUG=webrtc:4173 Review URL: https://codereview.webrtc.org/1581113006 Cr-Commit-Position: refs/heads/master@{#11322}
This commit is contained in:
@ -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()));
|
||||
|
@ -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_);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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_;
|
||||
}
|
||||
|
@ -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_;
|
||||
|
@ -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<unsigned int>& ssrcs,
|
||||
unsigned int bitrate) {
|
||||
rtcp_bandwidth_observer_->OnReceivedEstimatedBitrate(bitrate);
|
||||
bitrate_controller_->UpdateDelayBasedEstimate(bitrate);
|
||||
}
|
||||
|
||||
void TransportFeedbackAdapter::OnRttUpdate(int64_t avg_rtt_ms,
|
||||
|
@ -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<RtcpBandwidthObserver> rtcp_bandwidth_observer_;
|
||||
BitrateController* bitrate_controller_;
|
||||
rtc::scoped_ptr<RemoteBitrateEstimator> bitrate_estimator_;
|
||||
ProcessThread* const process_thread_;
|
||||
Clock* const clock_;
|
||||
|
@ -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<TransportFeedbackAdapter> adapter_;
|
||||
|
||||
uint32_t receiver_estimated_bitrate_;
|
||||
|
@ -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<VideoReceiveStream::Config>* 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<BweObserver*>(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<uint32_t>(&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<uint32_t>(&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<RtpRtcp> 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 {
|
||||
|
Reference in New Issue
Block a user