Index: webrtc/modules/congestion_controller/congestion_controller_unittest.cc |
diff --git a/webrtc/modules/congestion_controller/congestion_controller_unittest.cc b/webrtc/modules/congestion_controller/congestion_controller_unittest.cc |
index ca0d28fcd5c8cfbd819cdbcd9c98ac3bc62f7738..6df6381790acdd97eb96f8e89677d27acbf5ccab 100644 |
--- a/webrtc/modules/congestion_controller/congestion_controller_unittest.cc |
+++ b/webrtc/modules/congestion_controller/congestion_controller_unittest.cc |
@@ -9,12 +9,13 @@ |
*/ |
#include "webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h" |
-#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" |
+#include "webrtc/modules/bitrate_controller/include/mock/mock_bitrate_controller.h" |
#include "webrtc/modules/congestion_controller/include/congestion_controller.h" |
#include "webrtc/modules/congestion_controller/include/mock/mock_congestion_controller.h" |
#include "webrtc/modules/pacing/mock/mock_paced_sender.h" |
#include "webrtc/modules/remote_bitrate_estimator/include/bwe_defines.h" |
#include "webrtc/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h" |
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" |
#include "webrtc/system_wrappers/include/clock.h" |
#include "webrtc/test/gmock.h" |
#include "webrtc/test/gtest.h" |
@@ -27,6 +28,8 @@ using testing::SaveArg; |
using testing::StrictMock; |
namespace { |
+const webrtc::PacedPacketInfo kPacingInfo0(0, 5, 2000); |
+const webrtc::PacedPacketInfo kPacingInfo1(1, 8, 4000); |
// Helper to convert some time format to resolution used in absolute send time |
// header extension, rounded upwards. |t| is the time to convert, in some |
@@ -36,6 +39,34 @@ uint32_t AbsSendTime(int64_t t, int64_t denom) { |
return (((t << 18) + (denom >> 1)) / denom) & 0x00fffffful; |
} |
+// TODO(elad.alon): This is not meant to be landed like this. Ask reviewers |
elad.alon_webrtc.org
2017/03/02 11:51:47
Soliciting feedback. :-)
|
+// where would be a good place to put ComparePacketVectors(), so that it would |
+// be visible to both unit-test suites. |
+void ComparePacketVectors(const std::vector<webrtc::PacketFeedback>& truth, |
+ const std::vector<webrtc::PacketFeedback>& input) { |
+ ASSERT_EQ(truth.size(), input.size()); |
+ size_t len = truth.size(); |
+ // truth contains the input data for the test, and input is what will be |
+ // sent to the bandwidth estimator. truth.arrival_tims_ms is used to |
+ // populate the transport feedback messages. As these times may be changed |
+ // (because of resolution limits in the packets, and because of the time |
+ // base adjustment performed by the TransportFeedbackAdapter at the first |
+ // packet, the truth[x].arrival_time and input[x].arrival_time may not be |
+ // equal. However, the difference must be the same for all x. |
+ int64_t arrival_time_delta = |
+ truth[0].arrival_time_ms - input[0].arrival_time_ms; |
+ for (size_t i = 0; i < len; ++i) { |
+ RTC_CHECK(truth[i].arrival_time_ms != webrtc::PacketFeedback::kNotReceived); |
+ if (input[i].arrival_time_ms != webrtc::PacketFeedback::kNotReceived) { |
+ EXPECT_EQ(truth[i].arrival_time_ms, |
+ input[i].arrival_time_ms + arrival_time_delta); |
+ } |
+ EXPECT_EQ(truth[i].send_time_ms, input[i].send_time_ms); |
+ EXPECT_EQ(truth[i].sequence_number, input[i].sequence_number); |
+ EXPECT_EQ(truth[i].payload_size, input[i].payload_size); |
+ EXPECT_EQ(truth[i].pacing_info, input[i].pacing_info); |
+ } |
+} |
} // namespace |
namespace webrtc { |
@@ -51,7 +82,9 @@ class CongestionControllerTest : public ::testing::Test { |
std::unique_ptr<PacedSender> pacer(pacer_); // Passes ownership. |
controller_.reset(new CongestionController( |
&clock_, &observer_, &remote_bitrate_observer_, &event_log_, |
- &packet_router_, std::move(pacer))); |
+ &packet_router_, std::move(pacer), |
+ std::unique_ptr<BitrateController>( |
+ BitrateController::CreateBitrateController(&clock_, &event_log_)))); |
bandwidth_observer_.reset( |
controller_->GetBitrateController()->CreateRtcpBandwidthObserver()); |
@@ -62,6 +95,29 @@ class CongestionControllerTest : public ::testing::Test { |
controller_->SetBweBitrates(0, kInitialBitrateBps, 5 * kInitialBitrateBps); |
} |
+ void OnSentPacket(const PacketFeedback& packet_feedback) { |
+ controller_->AddPacket(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)); |
+ } |
+ |
+ class MockBitrateControllerAdapter : public MockBitrateController { |
stefan-webrtc
2017/03/02 15:58:07
I would prefer not to have this mock, and to not e
|
+ public: |
+ explicit MockBitrateControllerAdapter(CongestionControllerTest* owner) |
+ : MockBitrateController(), owner_(owner) {} |
+ |
+ ~MockBitrateControllerAdapter() override {} |
+ |
+ void OnDelayBasedBweResult(const DelayBasedBwe::Result& result) override { |
+ owner_->target_bitrate_bps_ = |
+ rtc::Optional<uint32_t>(result.target_bitrate_bps); |
+ } |
+ |
+ CongestionControllerTest* const owner_; |
+ }; |
+ |
SimulatedClock clock_; |
StrictMock<MockCongestionObserver> observer_; |
NiceMock<MockPacedSender>* pacer_; |
@@ -71,6 +127,7 @@ class CongestionControllerTest : public ::testing::Test { |
PacketRouter packet_router_; |
std::unique_ptr<CongestionController> controller_; |
const uint32_t kInitialBitrateBps = 60000; |
+ rtc::Optional<uint32_t> target_bitrate_bps_; |
}; |
TEST_F(CongestionControllerTest, OnNetworkChanged) { |
@@ -217,9 +274,11 @@ TEST_F(CongestionControllerTest, OnReceivedPacketWithAbsSendTime) { |
NiceMock<MockCongestionObserver> observer; |
StrictMock<MockRemoteBitrateObserver> remote_bitrate_observer; |
std::unique_ptr<PacedSender> pacer(new NiceMock<MockPacedSender>()); |
- controller_.reset( |
- new CongestionController(&clock_, &observer, &remote_bitrate_observer, |
- &event_log_, &packet_router_, std::move(pacer))); |
+ controller_.reset(new CongestionController( |
+ &clock_, &observer, &remote_bitrate_observer, &event_log_, |
+ &packet_router_, std::move(pacer), |
+ std::unique_ptr<BitrateController>( |
+ BitrateController::CreateBitrateController(&clock_, &event_log_)))); |
size_t payload_size = 1000; |
RTPHeader header; |
@@ -240,5 +299,141 @@ TEST_F(CongestionControllerTest, OnReceivedPacketWithAbsSendTime) { |
ASSERT_EQ(1u, ssrcs.size()); |
EXPECT_EQ(header.ssrc, ssrcs[0]); |
} |
+ |
+TEST_F(CongestionControllerTest, UpdatesDelayBasedEstimate) { |
+ NiceMock<MockCongestionObserver> observer; |
+ StrictMock<MockRemoteBitrateObserver> remote_bitrate_observer; |
+ std::unique_ptr<PacedSender> pacer(new NiceMock<MockPacedSender>()); |
+ controller_.reset( |
+ new CongestionController(&clock_, &observer, &remote_bitrate_observer, |
+ &event_log_, &packet_router_, std::move(pacer), |
+ std::unique_ptr<BitrateController>( |
+ new MockBitrateControllerAdapter(this)))); |
+ |
+ uint16_t seq_num = 0; |
+ size_t kPayloadSize = 1000; |
+ // The test must run and insert packets/feedback long enough that the |
+ // BWE computes a valid estimate. |
+ const int64_t kRunTimeMs = 6000; |
+ int64_t start_time_ms = clock_.TimeInMilliseconds(); |
+ while (clock_.TimeInMilliseconds() - start_time_ms < kRunTimeMs) { |
+ PacketFeedback packet(clock_.TimeInMilliseconds(), |
+ clock_.TimeInMilliseconds(), seq_num, kPayloadSize, |
+ PacedPacketInfo()); |
+ 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); |
+ ++seq_num; |
+ } |
stefan-webrtc
2017/03/02 15:58:07
Keep this loop, and also add a similar after:
whi
|
+ |
+ EXPECT_TRUE(target_bitrate_bps_); |
+} |
+ |
+TEST_F(CongestionControllerTest, LongFeedbackDelays) { |
+ // Custom setup |
+ std::unique_ptr<PacedSender> pacer(new NiceMock<MockPacedSender>()); |
+ auto mock_bitrate_controller = std::unique_ptr<MockBitrateControllerAdapter>( |
+ new MockBitrateControllerAdapter(this)); |
+ EXPECT_CALL(*mock_bitrate_controller, SetBitrates(_, _, _)); |
+ EXPECT_CALL(*mock_bitrate_controller, GetNetworkParameters(_, _, _)); |
+ EXPECT_CALL(observer_, OnNetworkChanged(_, _, _, _)); |
+ controller_.reset(new CongestionController( |
+ &clock_, &observer_, &remote_bitrate_observer_, &event_log_, |
+ &packet_router_, std::move(pacer), |
+ std::unique_ptr<BitrateController>(std::move(mock_bitrate_controller)))); |
+ controller_->SetBweBitrates(0, kInitialBitrateBps, 5 * kInitialBitrateBps); |
+ |
+ 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(); |
+ } |
+ ComparePacketVectors(packets, controller_->GetTransportFeedbackVector()); |
+ } |
+ |
+ // Target bitrate should have halved due to feedback delays. |
+ 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); |
+ ComparePacketVectors(packets, controller_->GetTransportFeedbackVector()); |
+ } |
+} |
} // namespace test |
} // namespace webrtc |