diff options
Diffstat (limited to 'third_party/libwebrtc/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc')
-rw-r--r-- | third_party/libwebrtc/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc | 670 |
1 files changed, 670 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc b/third_party/libwebrtc/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc new file mode 100644 index 0000000000..47ad457be9 --- /dev/null +++ b/third_party/libwebrtc/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc @@ -0,0 +1,670 @@ +/* + * Copyright (c) 2015 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 "modules/remote_bitrate_estimator/remote_estimator_proxy.h" + +#include <cstdint> +#include <memory> +#include <utility> + +#include "absl/types/optional.h" +#include "api/transport/network_types.h" +#include "api/transport/test/mock_network_control.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "system_wrappers/include/clock.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::_; +using ::testing::ElementsAre; +using ::testing::Invoke; +using ::testing::MockFunction; +using ::testing::Return; +using ::testing::SizeIs; + +constexpr uint32_t kMediaSsrc = 456; +constexpr uint16_t kBaseSeq = 10; +constexpr Timestamp kBaseTime = Timestamp::Millis(123); +constexpr TimeDelta kBaseTimeWrapAround = + rtcp::TransportFeedback::kDeltaTick * (int64_t{1} << 32); +constexpr TimeDelta kMaxSmallDelta = rtcp::TransportFeedback::kDeltaTick * 0xFF; + +constexpr TimeDelta kBackWindow = TimeDelta::Millis(500); +constexpr TimeDelta kMinSendInterval = TimeDelta::Millis(50); +constexpr TimeDelta kMaxSendInterval = TimeDelta::Millis(250); +constexpr TimeDelta kDefaultSendInterval = TimeDelta::Millis(100); + +std::vector<uint16_t> SequenceNumbers( + const rtcp::TransportFeedback& feedback_packet) { + std::vector<uint16_t> sequence_numbers; + for (const auto& rtp_packet_received : feedback_packet.GetReceivedPackets()) { + sequence_numbers.push_back(rtp_packet_received.sequence_number()); + } + return sequence_numbers; +} + +std::vector<Timestamp> Timestamps( + const rtcp::TransportFeedback& feedback_packet) { + std::vector<Timestamp> timestamps; + Timestamp timestamp = feedback_packet.BaseTime(); + // rtcp::TransportFeedback makes no promises about epoch of the base time, + // It may add several kBaseTimeWrapAround periods to make it large enough and + // thus to support negative deltas. Align it close to the kBaseTime to make + // tests expectations simpler. + if (timestamp > kBaseTime) { + timestamp -= (timestamp - kBaseTime).RoundTo(kBaseTimeWrapAround); + } + for (const auto& rtp_packet_received : feedback_packet.GetReceivedPackets()) { + timestamp += rtp_packet_received.delta(); + timestamps.push_back(timestamp); + } + return timestamps; +} + +class RemoteEstimatorProxyTest : public ::testing::Test { + public: + RemoteEstimatorProxyTest() + : clock_(0), + proxy_(feedback_sender_.AsStdFunction(), &network_state_estimator_) {} + + protected: + void IncomingPacket(uint16_t seq, + Timestamp arrival_time, + absl::optional<uint32_t> abs_send_time = absl::nullopt) { + RtpHeaderExtensionMap map; + map.Register<TransportSequenceNumber>(1); + map.Register<AbsoluteSendTime>(2); + RtpPacketReceived packet(&map, arrival_time); + packet.SetSsrc(kMediaSsrc); + packet.SetExtension<TransportSequenceNumber>(seq); + if (abs_send_time) { + packet.SetExtension<AbsoluteSendTime>(*abs_send_time); + } + proxy_.IncomingPacket(packet); + } + + void IncomingPacketV2( + uint16_t seq, + Timestamp arrival_time, + absl::optional<FeedbackRequest> feedback_request = absl::nullopt) { + RtpHeaderExtensionMap map; + map.Register<TransportSequenceNumberV2>(1); + RtpPacketReceived packet(&map, arrival_time); + packet.SetSsrc(kMediaSsrc); + packet.SetExtension<webrtc::TransportSequenceNumberV2>(seq, + feedback_request); + proxy_.IncomingPacket(packet); + } + + void Process() { + clock_.AdvanceTime(kDefaultSendInterval); + proxy_.Process(clock_.CurrentTime()); + } + + SimulatedClock clock_; + MockFunction<void(std::vector<std::unique_ptr<rtcp::RtcpPacket>>)> + feedback_sender_; + ::testing::NiceMock<MockNetworkStateEstimator> network_state_estimator_; + RemoteEstimatorProxy proxy_; +}; + +TEST_F(RemoteEstimatorProxyTest, SendsSinglePacketFeedback) { + IncomingPacket(kBaseSeq, kBaseTime); + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq)); + EXPECT_THAT(Timestamps(*feedback_packet), ElementsAre(kBaseTime)); + })); + + Process(); +} + +TEST_F(RemoteEstimatorProxyTest, DuplicatedPackets) { + IncomingPacket(kBaseSeq, kBaseTime); + IncomingPacket(kBaseSeq, kBaseTime + TimeDelta::Seconds(1)); + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq)); + EXPECT_THAT(Timestamps(*feedback_packet), ElementsAre(kBaseTime)); + return true; + })); + + Process(); +} + +TEST_F(RemoteEstimatorProxyTest, FeedbackWithMissingStart) { + // First feedback. + IncomingPacket(kBaseSeq, kBaseTime); + IncomingPacket(kBaseSeq + 1, kBaseTime + TimeDelta::Seconds(1)); + EXPECT_CALL(feedback_sender_, Call); + Process(); + + // Second feedback starts with a missing packet (DROP kBaseSeq + 2). + IncomingPacket(kBaseSeq + 3, kBaseTime + TimeDelta::Seconds(3)); + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq + 2, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq + 3)); + EXPECT_THAT(Timestamps(*feedback_packet), + ElementsAre(kBaseTime + TimeDelta::Seconds(3))); + })); + + Process(); +} + +TEST_F(RemoteEstimatorProxyTest, SendsFeedbackWithVaryingDeltas) { + IncomingPacket(kBaseSeq, kBaseTime); + IncomingPacket(kBaseSeq + 1, kBaseTime + kMaxSmallDelta); + IncomingPacket(kBaseSeq + 2, + kBaseTime + (2 * kMaxSmallDelta) + TimeDelta::Millis(1)); + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq, kBaseSeq + 1, kBaseSeq + 2)); + EXPECT_THAT(Timestamps(*feedback_packet), + ElementsAre(kBaseTime, kBaseTime + kMaxSmallDelta, + kBaseTime + (2 * kMaxSmallDelta) + + TimeDelta::Millis(1))); + })); + + Process(); +} + +TEST_F(RemoteEstimatorProxyTest, SendsFragmentedFeedback) { + static constexpr TimeDelta kTooLargeDelta = + rtcp::TransportFeedback::kDeltaTick * (1 << 16); + + IncomingPacket(kBaseSeq, kBaseTime); + IncomingPacket(kBaseSeq + 1, kBaseTime + kTooLargeDelta); + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq)); + EXPECT_THAT(Timestamps(*feedback_packet), ElementsAre(kBaseTime)); + })) + .WillOnce(Invoke( + [](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq + 1, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq + 1)); + EXPECT_THAT(Timestamps(*feedback_packet), + ElementsAre(kBaseTime + kTooLargeDelta)); + })); + + Process(); +} + +TEST_F(RemoteEstimatorProxyTest, HandlesReorderingAndWrap) { + const TimeDelta kDelta = TimeDelta::Seconds(1); + const uint16_t kLargeSeq = 62762; + IncomingPacket(kBaseSeq, kBaseTime); + IncomingPacket(kLargeSeq, kBaseTime + kDelta); + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [&](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kLargeSeq, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + + EXPECT_THAT(Timestamps(*feedback_packet), + ElementsAre(kBaseTime + kDelta, kBaseTime)); + })); + + Process(); +} + +TEST_F(RemoteEstimatorProxyTest, HandlesMalformedSequenceNumbers) { + // This test generates incoming packets with large jumps in sequence numbers. + // When unwrapped, the sequeunce numbers of these 30 incoming packets, will + // span a range of roughly 650k packets. Test that we only send feedback for + // the last packets. Test for regression found in chromium:949020. + const TimeDelta kDelta = TimeDelta::Seconds(1); + for (int i = 0; i < 10; ++i) { + IncomingPacket(kBaseSeq + i, kBaseTime + 3 * i * kDelta); + IncomingPacket(kBaseSeq + 20000 + i, kBaseTime + (3 * i + 1) * kDelta); + IncomingPacket(kBaseSeq + 40000 + i, kBaseTime + (3 * i + 2) * kDelta); + } + + // Only expect feedback for the last two packets. + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [&](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq + 20009, kBaseSeq + 40009)); + EXPECT_THAT( + Timestamps(*feedback_packet), + ElementsAre(kBaseTime + 28 * kDelta, kBaseTime + 29 * kDelta)); + })); + + Process(); +} + +TEST_F(RemoteEstimatorProxyTest, HandlesBackwardsWrappingSequenceNumbers) { + // This test is like HandlesMalformedSequenceNumbers but for negative wrap + // arounds. Test that we only send feedback for the packets with highest + // sequence numbers. Test for regression found in chromium:949020. + const TimeDelta kDelta = TimeDelta::Seconds(1); + for (int i = 0; i < 10; ++i) { + IncomingPacket(kBaseSeq + i, kBaseTime + 3 * i * kDelta); + IncomingPacket(kBaseSeq + 40000 + i, kBaseTime + (3 * i + 1) * kDelta); + IncomingPacket(kBaseSeq + 20000 + i, kBaseTime + (3 * i + 2) * kDelta); + } + + // Only expect feedback for the first two packets. + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [&](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq + 40000, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq + 40000, kBaseSeq)); + EXPECT_THAT(Timestamps(*feedback_packet), + ElementsAre(kBaseTime + kDelta, kBaseTime)); + })); + + Process(); +} + +TEST_F(RemoteEstimatorProxyTest, ResendsTimestampsOnReordering) { + IncomingPacket(kBaseSeq, kBaseTime); + IncomingPacket(kBaseSeq + 2, kBaseTime + TimeDelta::Millis(2)); + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq, kBaseSeq + 2)); + EXPECT_THAT( + Timestamps(*feedback_packet), + ElementsAre(kBaseTime, kBaseTime + TimeDelta::Millis(2))); + })); + + Process(); + + IncomingPacket(kBaseSeq + 1, kBaseTime + TimeDelta::Millis(1)); + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq + 1, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq + 1, kBaseSeq + 2)); + EXPECT_THAT(Timestamps(*feedback_packet), + ElementsAre(kBaseTime + TimeDelta::Millis(1), + kBaseTime + TimeDelta::Millis(2))); + })); + + Process(); +} + +TEST_F(RemoteEstimatorProxyTest, RemovesTimestampsOutOfScope) { + const Timestamp kTimeoutTime = kBaseTime + kBackWindow; + + IncomingPacket(kBaseSeq + 2, kBaseTime); + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq + 2, feedback_packet->GetBaseSequence()); + + EXPECT_THAT(Timestamps(*feedback_packet), ElementsAre(kBaseTime)); + })); + + Process(); + + IncomingPacket(kBaseSeq + 3, kTimeoutTime); // kBaseSeq + 2 times out here. + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [&](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq + 3, feedback_packet->GetBaseSequence()); + + EXPECT_THAT(Timestamps(*feedback_packet), + ElementsAre(kTimeoutTime)); + })); + + Process(); + + // New group, with sequence starting below the first so that they may be + // retransmitted. + IncomingPacket(kBaseSeq, kBaseTime - TimeDelta::Millis(1)); + IncomingPacket(kBaseSeq + 1, kTimeoutTime - TimeDelta::Millis(1)); + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [&](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence()); + + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq, kBaseSeq + 1, kBaseSeq + 3)); + EXPECT_THAT( + Timestamps(*feedback_packet), + ElementsAre(kBaseTime - TimeDelta::Millis(1), + kTimeoutTime - TimeDelta::Millis(1), kTimeoutTime)); + })); + + Process(); +} + +TEST_F(RemoteEstimatorProxyTest, TimeUntilNextProcessIsDefaultOnUnkownBitrate) { + EXPECT_EQ(proxy_.Process(clock_.CurrentTime()), kDefaultSendInterval); +} + +TEST_F(RemoteEstimatorProxyTest, TimeUntilNextProcessIsMinIntervalOn300kbps) { + proxy_.OnBitrateChanged(300'000); + EXPECT_EQ(proxy_.Process(clock_.CurrentTime()), kMinSendInterval); +} + +TEST_F(RemoteEstimatorProxyTest, TimeUntilNextProcessIsMaxIntervalOn0kbps) { + // TimeUntilNextProcess should be limited by `kMaxSendIntervalMs` when + // bitrate is small. We choose 0 bps as a special case, which also tests + // erroneous behaviors like division-by-zero. + proxy_.OnBitrateChanged(0); + EXPECT_EQ(proxy_.Process(clock_.CurrentTime()), kMaxSendInterval); +} + +TEST_F(RemoteEstimatorProxyTest, TimeUntilNextProcessIsMaxIntervalOn20kbps) { + proxy_.OnBitrateChanged(20'000); + EXPECT_EQ(proxy_.Process(clock_.CurrentTime()), kMaxSendInterval); +} + +TEST_F(RemoteEstimatorProxyTest, TwccReportsUse5PercentOfAvailableBandwidth) { + proxy_.OnBitrateChanged(80'000); + // 80kbps * 0.05 = TwccReportSize(68B * 8b/B) * 1000ms / SendInterval(136ms) + EXPECT_EQ(proxy_.Process(clock_.CurrentTime()), TimeDelta::Millis(136)); +} + +////////////////////////////////////////////////////////////////////////////// +// Tests for the extended protocol where the feedback is explicitly requested +// by the sender. +////////////////////////////////////////////////////////////////////////////// +typedef RemoteEstimatorProxyTest RemoteEstimatorProxyOnRequestTest; +TEST_F(RemoteEstimatorProxyOnRequestTest, DisablesPeriodicProcess) { + IncomingPacketV2(kBaseSeq, kBaseTime); + EXPECT_EQ(proxy_.Process(clock_.CurrentTime()), TimeDelta::PlusInfinity()); +} + +TEST_F(RemoteEstimatorProxyOnRequestTest, ProcessDoesNotSendFeedback) { + IncomingPacketV2(kBaseSeq, kBaseTime); + EXPECT_CALL(feedback_sender_, Call).Times(0); + Process(); +} + +TEST_F(RemoteEstimatorProxyOnRequestTest, RequestSinglePacketFeedback) { + IncomingPacketV2(kBaseSeq, kBaseTime); + IncomingPacketV2(kBaseSeq + 1, kBaseTime + kMaxSmallDelta); + IncomingPacketV2(kBaseSeq + 2, kBaseTime + 2 * kMaxSmallDelta); + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq + 3, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq + 3)); + EXPECT_THAT(Timestamps(*feedback_packet), + ElementsAre(kBaseTime + 3 * kMaxSmallDelta)); + })); + + constexpr FeedbackRequest kSinglePacketFeedbackRequest = { + /*include_timestamps=*/true, /*sequence_count=*/1}; + IncomingPacketV2(kBaseSeq + 3, kBaseTime + 3 * kMaxSmallDelta, + kSinglePacketFeedbackRequest); +} + +TEST_F(RemoteEstimatorProxyOnRequestTest, RequestLastFivePacketFeedback) { + int i = 0; + for (; i < 10; ++i) { + IncomingPacketV2(kBaseSeq + i, kBaseTime + i * kMaxSmallDelta); + } + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq + 6, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq + 6, kBaseSeq + 7, kBaseSeq + 8, + kBaseSeq + 9, kBaseSeq + 10)); + EXPECT_THAT(Timestamps(*feedback_packet), + ElementsAre(kBaseTime + 6 * kMaxSmallDelta, + kBaseTime + 7 * kMaxSmallDelta, + kBaseTime + 8 * kMaxSmallDelta, + kBaseTime + 9 * kMaxSmallDelta, + kBaseTime + 10 * kMaxSmallDelta)); + })); + + constexpr FeedbackRequest kFivePacketsFeedbackRequest = { + /*include_timestamps=*/true, /*sequence_count=*/5}; + IncomingPacketV2(kBaseSeq + i, kBaseTime + i * kMaxSmallDelta, + kFivePacketsFeedbackRequest); +} + +TEST_F(RemoteEstimatorProxyOnRequestTest, + RequestLastFivePacketFeedbackMissingPackets) { + int i = 0; + for (; i < 10; ++i) { + if (i != 7 && i != 9) + IncomingPacketV2(kBaseSeq + i, kBaseTime + i * kMaxSmallDelta); + } + + EXPECT_CALL(feedback_sender_, Call) + .WillOnce(Invoke( + [](std::vector<std::unique_ptr<rtcp::RtcpPacket>> feedback_packets) { + rtcp::TransportFeedback* feedback_packet = + static_cast<rtcp::TransportFeedback*>( + feedback_packets[0].get()); + EXPECT_EQ(kBaseSeq + 6, feedback_packet->GetBaseSequence()); + EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc()); + + EXPECT_THAT(SequenceNumbers(*feedback_packet), + ElementsAre(kBaseSeq + 6, kBaseSeq + 8, kBaseSeq + 10)); + EXPECT_THAT(Timestamps(*feedback_packet), + ElementsAre(kBaseTime + 6 * kMaxSmallDelta, + kBaseTime + 8 * kMaxSmallDelta, + kBaseTime + 10 * kMaxSmallDelta)); + })); + + constexpr FeedbackRequest kFivePacketsFeedbackRequest = { + /*include_timestamps=*/true, /*sequence_count=*/5}; + IncomingPacketV2(kBaseSeq + i, kBaseTime + i * kMaxSmallDelta, + kFivePacketsFeedbackRequest); +} + +TEST_F(RemoteEstimatorProxyTest, ReportsIncomingPacketToNetworkStateEstimator) { + const DataSize kPacketOverhead = DataSize::Bytes(38); + proxy_.SetTransportOverhead(kPacketOverhead); + + EXPECT_CALL(network_state_estimator_, OnReceivedPacket) + .WillOnce([&](const PacketResult& packet) { + EXPECT_EQ(packet.receive_time, kBaseTime); + EXPECT_GT(packet.sent_packet.size, kPacketOverhead); + // Expect first send time to be equal to the arrival time. + EXPECT_EQ(packet.sent_packet.send_time, kBaseTime); + }); + IncomingPacket(kBaseSeq, kBaseTime, AbsoluteSendTime::To24Bits(kBaseTime)); +} + +TEST_F(RemoteEstimatorProxyTest, IncomingPacketHandlesWrapInAbsSendTime) { + // abs send time use 24bit precision. + const uint32_t kFirstAbsSendTime = + AbsoluteSendTime::To24Bits(Timestamp::Millis((1 << 24) - 30)); + // Second abs send time has wrapped. + const uint32_t kSecondAbsSendTime = + AbsoluteSendTime::To24Bits(Timestamp::Millis(1 << 24)); + const TimeDelta kExpectedAbsSendTimeDelta = TimeDelta::Millis(30); + + Timestamp first_send_timestamp = Timestamp::Zero(); + EXPECT_CALL(network_state_estimator_, OnReceivedPacket) + .WillOnce([&](const PacketResult& packet) { + EXPECT_EQ(packet.receive_time, kBaseTime); + first_send_timestamp = packet.sent_packet.send_time; + }); + IncomingPacket(kBaseSeq, kBaseTime, kFirstAbsSendTime); + + EXPECT_CALL(network_state_estimator_, OnReceivedPacket) + .WillOnce([&](const PacketResult& packet) { + EXPECT_EQ(packet.receive_time, kBaseTime + TimeDelta::Millis(123)); + EXPECT_EQ(packet.sent_packet.send_time.ms(), + (first_send_timestamp + kExpectedAbsSendTimeDelta).ms()); + }); + IncomingPacket(kBaseSeq + 1, kBaseTime + TimeDelta::Millis(123), + kSecondAbsSendTime); +} + +TEST_F(RemoteEstimatorProxyTest, IncomingPacketHandlesReorderedPackets) { + const uint32_t kFirstAbsSendTime = + AbsoluteSendTime::To24Bits(Timestamp::Millis((1 << 12))); + Timestamp first_send_timestamp = Timestamp::Zero(); + EXPECT_CALL(network_state_estimator_, OnReceivedPacket) + .WillOnce([&](const PacketResult& packet) { + EXPECT_EQ(packet.receive_time, kBaseTime); + first_send_timestamp = packet.sent_packet.send_time; + }); + IncomingPacket(kBaseSeq + 1, kBaseTime, kFirstAbsSendTime); + + const TimeDelta kExpectedAbsSendTimeDelta = -TimeDelta::Millis(30); + const uint32_t kSecondAbsSendTime = AbsoluteSendTime::To24Bits( + Timestamp::Millis(1 << 12) + kExpectedAbsSendTimeDelta); + EXPECT_CALL(network_state_estimator_, OnReceivedPacket) + .WillOnce([&](const PacketResult& packet) { + EXPECT_EQ(packet.sent_packet.send_time.ms(), + (first_send_timestamp + kExpectedAbsSendTimeDelta).ms()); + }); + IncomingPacket(kBaseSeq, kBaseTime + TimeDelta::Millis(123), + kSecondAbsSendTime); +} + +TEST_F(RemoteEstimatorProxyTest, + IncomingPacketResetSendTimeToArrivalTimeAfterLargeArrivaltimeDelta) { + const uint32_t kFirstAbsSendTime = + AbsoluteSendTime::To24Bits(Timestamp::Millis((1 << 12))); + EXPECT_CALL(network_state_estimator_, OnReceivedPacket) + .WillOnce([&](const PacketResult& packet) { + EXPECT_EQ(packet.receive_time, kBaseTime); + EXPECT_EQ(packet.sent_packet.send_time, kBaseTime); + }); + IncomingPacket(kBaseSeq + 1, kBaseTime, kFirstAbsSendTime); + + EXPECT_CALL(network_state_estimator_, OnReceivedPacket) + .WillOnce([&](const PacketResult& packet) { + EXPECT_EQ(packet.receive_time, kBaseTime + TimeDelta::Seconds(20)); + EXPECT_EQ(packet.sent_packet.send_time, + kBaseTime + TimeDelta::Seconds(20)); + }); + IncomingPacket(kBaseSeq, kBaseTime + TimeDelta::Seconds(20), + kFirstAbsSendTime + 123); +} + +TEST_F(RemoteEstimatorProxyTest, SendTransportFeedbackAndNetworkStateUpdate) { + IncomingPacket(kBaseSeq, kBaseTime, + AbsoluteSendTime::To24Bits(kBaseTime - TimeDelta::Millis(1))); + + EXPECT_CALL(network_state_estimator_, GetCurrentEstimate()) + .WillOnce(Return(NetworkStateEstimate())); + EXPECT_CALL(feedback_sender_, Call(SizeIs(2))); + Process(); +} + +} // namespace +} // namespace webrtc |