blob: 07c0e39fc0d3916234aaab839b02a5a80569bfa0 [file] [log] [blame]
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/congestion_controller/include/send_side_congestion_controller.h"
#include "webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h"
#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
#include "webrtc/modules/congestion_controller/congestion_controller_unittests_helper.h"
#include "webrtc/modules/congestion_controller/include/mock/mock_congestion_observer.h"
#include "webrtc/modules/pacing/mock/mock_paced_sender.h"
#include "webrtc/modules/remote_bitrate_estimator/include/bwe_defines.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
#include "webrtc/rtc_base/socket.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/test/gmock.h"
#include "webrtc/test/gtest.h"
using testing::_;
using testing::AtLeast;
using testing::NiceMock;
using testing::Return;
using testing::SaveArg;
using testing::StrictMock;
namespace webrtc {
namespace {
const webrtc::PacedPacketInfo kPacingInfo0(0, 5, 2000);
const webrtc::PacedPacketInfo kPacingInfo1(1, 8, 4000);
class MockPacketRouter : public PacketRouter {
public:
MOCK_METHOD2(OnReceiveBitrateChanged,
void(const std::vector<uint32_t>& ssrcs, uint32_t bitrate));
};
const uint32_t kInitialBitrateBps = 60000;
} // namespace
namespace test {
class SendSideCongestionControllerTest : public ::testing::Test {
protected:
SendSideCongestionControllerTest()
: clock_(123456), target_bitrate_observer_(this) {}
~SendSideCongestionControllerTest() override {}
void SetUp() override {
pacer_.reset(new NiceMock<MockPacedSender>());
controller_.reset(new SendSideCongestionController(
&clock_, &observer_, &event_log_, pacer_.get()));
bandwidth_observer_.reset(
controller_->GetBitrateController()->CreateRtcpBandwidthObserver());
// Set the initial bitrate estimate and expect the |observer| and |pacer_|
// to be updated.
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _));
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps));
EXPECT_CALL(*pacer_, CreateProbeCluster(kInitialBitrateBps * 3));
EXPECT_CALL(*pacer_, CreateProbeCluster(kInitialBitrateBps * 5));
controller_->SetBweBitrates(0, kInitialBitrateBps, 5 * kInitialBitrateBps);
}
// Custom setup - use an observer that tracks the target bitrate, without
// prescribing on which iterations it must change (like a mock would).
void TargetBitrateTrackingSetup() {
pacer_.reset(new NiceMock<MockPacedSender>());
controller_.reset(new SendSideCongestionController(
&clock_, &target_bitrate_observer_, &event_log_, pacer_.get()));
controller_->SetBweBitrates(0, kInitialBitrateBps, 5 * kInitialBitrateBps);
}
void OnSentPacket(const PacketFeedback& packet_feedback) {
constexpr uint32_t ssrc = 0;
controller_->AddPacket(ssrc, packet_feedback.sequence_number,
packet_feedback.payload_size,
packet_feedback.pacing_info);
controller_->OnSentPacket(rtc::SentPacket(packet_feedback.sequence_number,
packet_feedback.send_time_ms));
}
// Allows us to track the target bitrate, without prescribing the exact
// iterations when this would hapen, like a mock would.
class TargetBitrateObserver : public SendSideCongestionController::Observer {
public:
explicit TargetBitrateObserver(SendSideCongestionControllerTest* owner)
: owner_(owner) {}
~TargetBitrateObserver() override = default;
void OnNetworkChanged(uint32_t bitrate_bps,
uint8_t fraction_loss, // 0 - 255.
int64_t rtt_ms,
int64_t probing_interval_ms) override {
owner_->target_bitrate_bps_ = rtc::Optional<uint32_t>(bitrate_bps);
}
private:
SendSideCongestionControllerTest* owner_;
};
void PacketTransmissionAndFeedbackBlock(uint16_t* seq_num,
int64_t runtime_ms,
int64_t delay) {
int64_t delay_buildup = 0;
int64_t start_time_ms = clock_.TimeInMilliseconds();
while (clock_.TimeInMilliseconds() - start_time_ms < runtime_ms) {
constexpr size_t kPayloadSize = 1000;
PacketFeedback packet(clock_.TimeInMilliseconds() + delay_buildup,
clock_.TimeInMilliseconds(), *seq_num, kPayloadSize,
PacedPacketInfo());
delay_buildup += delay; // Delay has to increase, or it's just RTT.
OnSentPacket(packet);
// Create expected feedback and send into adapter.
std::unique_ptr<rtcp::TransportFeedback> feedback(
new rtcp::TransportFeedback());
feedback->SetBase(packet.sequence_number, packet.arrival_time_ms * 1000);
EXPECT_TRUE(feedback->AddReceivedPacket(packet.sequence_number,
packet.arrival_time_ms * 1000));
rtc::Buffer raw_packet = feedback->Build();
feedback = rtcp::TransportFeedback::ParseFrom(raw_packet.data(),
raw_packet.size());
EXPECT_TRUE(feedback.get() != nullptr);
controller_->OnTransportFeedback(*feedback.get());
clock_.AdvanceTimeMilliseconds(50);
controller_->Process();
++(*seq_num);
}
}
SimulatedClock clock_;
StrictMock<MockCongestionObserver> observer_;
TargetBitrateObserver target_bitrate_observer_;
NiceMock<MockRtcEventLog> event_log_;
std::unique_ptr<RtcpBandwidthObserver> bandwidth_observer_;
PacketRouter packet_router_;
std::unique_ptr<NiceMock<MockPacedSender>> pacer_;
std::unique_ptr<SendSideCongestionController> controller_;
rtc::Optional<uint32_t> target_bitrate_bps_;
};
TEST_F(SendSideCongestionControllerTest, OnNetworkChanged) {
// Test no change.
clock_.AdvanceTimeMilliseconds(25);
controller_->Process();
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps * 2));
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
clock_.AdvanceTimeMilliseconds(25);
controller_->Process();
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _));
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps));
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps);
clock_.AdvanceTimeMilliseconds(25);
controller_->Process();
}
TEST_F(SendSideCongestionControllerTest, OnSendQueueFull) {
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillOnce(Return(PacedSender::kMaxQueueLengthMs + 1));
EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _));
controller_->Process();
// Let the pacer not be full next time the controller checks.
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillOnce(Return(PacedSender::kMaxQueueLengthMs - 1));
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _));
controller_->Process();
}
TEST_F(SendSideCongestionControllerTest, OnSendQueueFullAndEstimateChange) {
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillOnce(Return(PacedSender::kMaxQueueLengthMs + 1));
EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _));
controller_->Process();
// Receive new estimate but let the queue still be full.
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillOnce(Return(PacedSender::kMaxQueueLengthMs + 1));
// The send pacer should get the new estimate though.
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps * 2));
clock_.AdvanceTimeMilliseconds(25);
controller_->Process();
// Let the pacer not be full next time the controller checks.
// |OnNetworkChanged| should be called with the new estimate.
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillOnce(Return(PacedSender::kMaxQueueLengthMs - 1));
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
clock_.AdvanceTimeMilliseconds(25);
controller_->Process();
}
TEST_F(SendSideCongestionControllerTest, SignalNetworkState) {
EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _));
controller_->SignalNetworkState(kNetworkDown);
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _));
controller_->SignalNetworkState(kNetworkUp);
EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _));
controller_->SignalNetworkState(kNetworkDown);
}
TEST_F(SendSideCongestionControllerTest, OnNetworkRouteChanged) {
int new_bitrate = 200000;
testing::Mock::VerifyAndClearExpectations(pacer_.get());
EXPECT_CALL(observer_, OnNetworkChanged(new_bitrate, _, _, _));
EXPECT_CALL(*pacer_, SetEstimatedBitrate(new_bitrate));
rtc::NetworkRoute route;
route.local_network_id = 1;
controller_->OnNetworkRouteChanged(route, new_bitrate, -1, -1);
// If the bitrate is reset to -1, the new starting bitrate will be
// the minimum default bitrate kMinBitrateBps.
EXPECT_CALL(
observer_,
OnNetworkChanged(congestion_controller::GetMinBitrateBps(), _, _, _));
EXPECT_CALL(*pacer_,
SetEstimatedBitrate(congestion_controller::GetMinBitrateBps()));
route.local_network_id = 2;
controller_->OnNetworkRouteChanged(route, -1, -1, -1);
}
TEST_F(SendSideCongestionControllerTest, OldFeedback) {
int new_bitrate = 200000;
testing::Mock::VerifyAndClearExpectations(pacer_.get());
EXPECT_CALL(observer_, OnNetworkChanged(new_bitrate, _, _, _));
EXPECT_CALL(*pacer_, SetEstimatedBitrate(new_bitrate));
// Send a few packets on the first network route.
std::vector<PacketFeedback> packets;
packets.push_back(PacketFeedback(0, 0, 0, 1500, kPacingInfo0));
packets.push_back(PacketFeedback(10, 10, 1, 1500, kPacingInfo0));
packets.push_back(PacketFeedback(20, 20, 2, 1500, kPacingInfo0));
packets.push_back(PacketFeedback(30, 30, 3, 1500, kPacingInfo1));
packets.push_back(PacketFeedback(40, 40, 4, 1500, kPacingInfo1));
for (const PacketFeedback& packet : packets)
OnSentPacket(packet);
// Change route and then insert a number of feedback packets.
rtc::NetworkRoute route;
route.local_network_id = 1;
controller_->OnNetworkRouteChanged(route, new_bitrate, -1, -1);
for (const PacketFeedback& packet : packets) {
rtcp::TransportFeedback feedback;
feedback.SetBase(packet.sequence_number, packet.arrival_time_ms * 1000);
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sequence_number,
packet.arrival_time_ms * 1000));
feedback.Build();
controller_->OnTransportFeedback(feedback);
}
// If the bitrate is reset to -1, the new starting bitrate will be
// the minimum default bitrate kMinBitrateBps.
EXPECT_CALL(
observer_,
OnNetworkChanged(congestion_controller::GetMinBitrateBps(), _, _, _));
EXPECT_CALL(*pacer_,
SetEstimatedBitrate(congestion_controller::GetMinBitrateBps()));
route.local_network_id = 2;
controller_->OnNetworkRouteChanged(route, -1, -1, -1);
}
TEST_F(SendSideCongestionControllerTest,
SignalNetworkStateAndQueueIsFullAndEstimateChange) {
// Send queue is full
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1));
EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _));
controller_->Process();
// Queue is full and network is down. Expect no bitrate change.
controller_->SignalNetworkState(kNetworkDown);
controller_->Process();
// Queue is full but network is up. Expect no bitrate change.
controller_->SignalNetworkState(kNetworkUp);
controller_->Process();
// Receive new estimate but let the queue still be full.
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps * 2));
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
clock_.AdvanceTimeMilliseconds(25);
controller_->Process();
// Let the pacer not be full next time the controller checks.
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillOnce(Return(PacedSender::kMaxQueueLengthMs - 1));
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
controller_->Process();
}
TEST_F(SendSideCongestionControllerTest, GetPacerQueuingDelayMs) {
EXPECT_CALL(observer_, OnNetworkChanged(_, _, _, _)).Times(AtLeast(1));
const int64_t kQueueTimeMs = 123;
EXPECT_CALL(*pacer_, QueueInMs()).WillRepeatedly(Return(kQueueTimeMs));
EXPECT_EQ(kQueueTimeMs, controller_->GetPacerQueuingDelayMs());
// Expect zero pacer delay when network is down.
controller_->SignalNetworkState(kNetworkDown);
EXPECT_EQ(0, controller_->GetPacerQueuingDelayMs());
// Network is up, pacer delay should be reported.
controller_->SignalNetworkState(kNetworkUp);
EXPECT_EQ(kQueueTimeMs, controller_->GetPacerQueuingDelayMs());
}
TEST_F(SendSideCongestionControllerTest, GetProbingInterval) {
clock_.AdvanceTimeMilliseconds(25);
controller_->Process();
EXPECT_CALL(observer_, OnNetworkChanged(_, _, _, testing::Ne(0)));
EXPECT_CALL(*pacer_, SetEstimatedBitrate(_));
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
clock_.AdvanceTimeMilliseconds(25);
controller_->Process();
}
TEST_F(SendSideCongestionControllerTest, ProbeOnRouteChange) {
testing::Mock::VerifyAndClearExpectations(pacer_.get());
EXPECT_CALL(*pacer_, CreateProbeCluster(kInitialBitrateBps * 6));
EXPECT_CALL(*pacer_, CreateProbeCluster(kInitialBitrateBps * 12));
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
rtc::NetworkRoute route;
route.local_network_id = 1;
controller_->OnNetworkRouteChanged(route, 2 * kInitialBitrateBps, 0,
20 * kInitialBitrateBps);
}
// Estimated bitrate reduced when the feedbacks arrive with such a long delay,
// that the send-time-history no longer holds the feedbacked packets.
TEST_F(SendSideCongestionControllerTest, LongFeedbackDelays) {
TargetBitrateTrackingSetup();
const int64_t kFeedbackTimeoutMs = 60001;
const int kMaxConsecutiveFailedLookups = 5;
for (int i = 0; i < kMaxConsecutiveFailedLookups; ++i) {
std::vector<PacketFeedback> packets;
packets.push_back(
PacketFeedback(i * 100, 2 * i * 100, 0, 1500, kPacingInfo0));
packets.push_back(
PacketFeedback(i * 100 + 10, 2 * i * 100 + 10, 1, 1500, kPacingInfo0));
packets.push_back(
PacketFeedback(i * 100 + 20, 2 * i * 100 + 20, 2, 1500, kPacingInfo0));
packets.push_back(
PacketFeedback(i * 100 + 30, 2 * i * 100 + 30, 3, 1500, kPacingInfo1));
packets.push_back(
PacketFeedback(i * 100 + 40, 2 * i * 100 + 40, 4, 1500, kPacingInfo1));
for (const PacketFeedback& packet : packets)
OnSentPacket(packet);
rtcp::TransportFeedback feedback;
feedback.SetBase(packets[0].sequence_number,
packets[0].arrival_time_ms * 1000);
for (const PacketFeedback& packet : packets) {
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sequence_number,
packet.arrival_time_ms * 1000));
}
feedback.Build();
clock_.AdvanceTimeMilliseconds(kFeedbackTimeoutMs);
PacketFeedback later_packet(kFeedbackTimeoutMs + i * 100 + 40,
kFeedbackTimeoutMs + i * 200 + 40, 5, 1500,
kPacingInfo1);
OnSentPacket(later_packet);
controller_->OnTransportFeedback(feedback);
// Check that packets have timed out.
for (PacketFeedback& packet : packets) {
packet.send_time_ms = -1;
packet.payload_size = 0;
packet.pacing_info = PacedPacketInfo();
}
ComparePacketFeedbackVectors(packets,
controller_->GetTransportFeedbackVector());
}
controller_->Process();
EXPECT_EQ(kInitialBitrateBps / 2, target_bitrate_bps_);
// Test with feedback that isn't late enough to time out.
{
std::vector<PacketFeedback> packets;
packets.push_back(PacketFeedback(100, 200, 0, 1500, kPacingInfo0));
packets.push_back(PacketFeedback(110, 210, 1, 1500, kPacingInfo0));
packets.push_back(PacketFeedback(120, 220, 2, 1500, kPacingInfo0));
packets.push_back(PacketFeedback(130, 230, 3, 1500, kPacingInfo1));
packets.push_back(PacketFeedback(140, 240, 4, 1500, kPacingInfo1));
for (const PacketFeedback& packet : packets)
OnSentPacket(packet);
rtcp::TransportFeedback feedback;
feedback.SetBase(packets[0].sequence_number,
packets[0].arrival_time_ms * 1000);
for (const PacketFeedback& packet : packets) {
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sequence_number,
packet.arrival_time_ms * 1000));
}
feedback.Build();
clock_.AdvanceTimeMilliseconds(kFeedbackTimeoutMs - 1);
PacketFeedback later_packet(kFeedbackTimeoutMs + 140,
kFeedbackTimeoutMs + 240, 5, 1500,
kPacingInfo1);
OnSentPacket(later_packet);
controller_->OnTransportFeedback(feedback);
ComparePacketFeedbackVectors(packets,
controller_->GetTransportFeedbackVector());
}
}
// Bandwidth estimation is updated when feedbacks are received.
// Feedbacks which show an increasing delay cause the estimation to be reduced.
TEST_F(SendSideCongestionControllerTest, UpdatesDelayBasedEstimate) {
TargetBitrateTrackingSetup();
const int64_t kRunTimeMs = 6000;
uint16_t seq_num = 0;
// The test must run and insert packets/feedback long enough that the
// BWE computes a valid estimate. This is first done in an environment which
// simulates no bandwidth limitation, and therefore not built-up delay.
PacketTransmissionAndFeedbackBlock(&seq_num, kRunTimeMs, 0);
ASSERT_TRUE(target_bitrate_bps_);
// Repeat, but this time with a building delay, and make sure that the
// estimation is adjusted downwards.
uint32_t bitrate_before_delay = *target_bitrate_bps_;
PacketTransmissionAndFeedbackBlock(&seq_num, kRunTimeMs, 50);
EXPECT_LT(*target_bitrate_bps_, bitrate_before_delay);
}
} // namespace test
} // namespace webrtc