blob: 7b831db4dd37b0102f15849aeda072f9bfc193f9 [file] [log] [blame]
/*
* 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 "webrtc/test/gmock.h"
#include "webrtc/test/gtest.h"
#include "webrtc/modules/pacing/packet_router.h"
#include "webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
#include "webrtc/system_wrappers/include/clock.h"
using ::testing::_;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::Return;
namespace webrtc {
class MockPacketRouter : public PacketRouter {
public:
MOCK_METHOD1(SendFeedback, bool(rtcp::TransportFeedback* packet));
};
class RemoteEstimatorProxyTest : public ::testing::Test {
public:
RemoteEstimatorProxyTest() : clock_(0), proxy_(&clock_, &router_) {}
protected:
void IncomingPacket(uint16_t seq, int64_t time_ms) {
RTPHeader header;
header.extension.hasTransportSequenceNumber = true;
header.extension.transportSequenceNumber = seq;
header.ssrc = kMediaSsrc;
proxy_.IncomingPacket(time_ms, kDefaultPacketSize, header);
}
void Process() {
clock_.AdvanceTimeMilliseconds(
RemoteEstimatorProxy::kDefaultProcessIntervalMs);
proxy_.Process();
}
SimulatedClock clock_;
testing::StrictMock<MockPacketRouter> router_;
RemoteEstimatorProxy proxy_;
const size_t kDefaultPacketSize = 100;
const uint32_t kMediaSsrc = 456;
const uint16_t kBaseSeq = 10;
const int64_t kBaseTimeMs = 123;
const int64_t kMaxSmallDeltaMs =
(rtcp::TransportFeedback::kDeltaScaleFactor * 0xFF) / 1000;
};
TEST_F(RemoteEstimatorProxyTest, SendsSinglePacketFeedback) {
IncomingPacket(kBaseSeq, kBaseTimeMs);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
packet->GetStatusVector();
EXPECT_EQ(1u, status_vec.size());
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[0]);
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
return true;
}));
Process();
}
TEST_F(RemoteEstimatorProxyTest, DuplicatedPackets) {
IncomingPacket(kBaseSeq, kBaseTimeMs);
IncomingPacket(kBaseSeq, kBaseTimeMs + 1000);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
packet->GetStatusVector();
EXPECT_EQ(1u, status_vec.size());
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[0]);
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
return true;
}));
Process();
}
TEST_F(RemoteEstimatorProxyTest, FeedbackWithMissingStart) {
// First feedback.
IncomingPacket(kBaseSeq, kBaseTimeMs);
IncomingPacket(kBaseSeq + 1, kBaseTimeMs + 1000);
EXPECT_CALL(router_, SendFeedback(_)).Times(1).WillOnce(Return(true));
Process();
// Second feedback starts with a missing packet (DROP kBaseSeq + 2).
IncomingPacket(kBaseSeq + 3, kBaseTimeMs + 3000);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq + 2, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
packet->GetStatusVector();
EXPECT_EQ(2u, status_vec.size());
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kNotReceived,
status_vec[0]);
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[1]);
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs + 3000,
(packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
return true;
}));
Process();
}
TEST_F(RemoteEstimatorProxyTest, SendsFeedbackWithVaryingDeltas) {
IncomingPacket(kBaseSeq, kBaseTimeMs);
IncomingPacket(kBaseSeq + 1, kBaseTimeMs + kMaxSmallDeltaMs);
IncomingPacket(kBaseSeq + 2, kBaseTimeMs + (2 * kMaxSmallDeltaMs) + 1);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
packet->GetStatusVector();
EXPECT_EQ(3u, status_vec.size());
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[0]);
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[1]);
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedLargeDelta,
status_vec[2]);
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(3u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_EQ(kMaxSmallDeltaMs, delta_vec[1] / 1000);
EXPECT_EQ(kMaxSmallDeltaMs + 1, delta_vec[2] / 1000);
return true;
}));
Process();
}
TEST_F(RemoteEstimatorProxyTest, SendsFragmentedFeedback) {
const int64_t kTooLargeDelta =
rtcp::TransportFeedback::kDeltaScaleFactor * (1 << 16);
IncomingPacket(kBaseSeq, kBaseTimeMs);
IncomingPacket(kBaseSeq + 1, kBaseTimeMs + kTooLargeDelta);
InSequence s;
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([kTooLargeDelta, this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
packet->GetStatusVector();
EXPECT_EQ(1u, status_vec.size());
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[0]);
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
return true;
}))
.RetiresOnSaturation();
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([kTooLargeDelta, this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq + 1, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
packet->GetStatusVector();
EXPECT_EQ(1u, status_vec.size());
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[0]);
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs + kTooLargeDelta,
(packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
return true;
}))
.RetiresOnSaturation();
Process();
}
TEST_F(RemoteEstimatorProxyTest, GracefullyHandlesReorderingAndWrap) {
const int64_t kDeltaMs = 1000;
const uint16_t kLargeSeq = 62762;
IncomingPacket(kBaseSeq, kBaseTimeMs);
IncomingPacket(kLargeSeq, kBaseTimeMs + kDeltaMs);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
return true;
}));
Process();
}
TEST_F(RemoteEstimatorProxyTest, ResendsTimestampsOnReordering) {
IncomingPacket(kBaseSeq, kBaseTimeMs);
IncomingPacket(kBaseSeq + 2, kBaseTimeMs + 2);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(2u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_EQ(2, delta_vec[1] / 1000);
return true;
}));
Process();
IncomingPacket(kBaseSeq + 1, kBaseTimeMs + 1);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq + 1, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(2u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs + 1,
(packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_EQ(1, delta_vec[1] / 1000);
return true;
}));
Process();
}
TEST_F(RemoteEstimatorProxyTest, RemovesTimestampsOutOfScope) {
const int64_t kTimeoutTimeMs =
kBaseTimeMs + RemoteEstimatorProxy::kBackWindowMs;
IncomingPacket(kBaseSeq + 2, kBaseTimeMs);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([kTimeoutTimeMs, this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq + 2, packet->GetBaseSequence());
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
return true;
}));
Process();
IncomingPacket(kBaseSeq + 3, kTimeoutTimeMs); // kBaseSeq + 2 times out here.
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([kTimeoutTimeMs, this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq + 3, packet->GetBaseSequence());
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kTimeoutTimeMs,
(packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
return true;
}));
Process();
// New group, with sequence starting below the first so that they may be
// retransmitted.
IncomingPacket(kBaseSeq, kBaseTimeMs - 1);
IncomingPacket(kBaseSeq + 1, kTimeoutTimeMs - 1);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([kTimeoutTimeMs, this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
// Four status entries (kBaseSeq + 3 missing).
EXPECT_EQ(4u, packet->GetStatusVector().size());
// Only three actual timestamps.
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(3u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs - 1,
(packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_EQ(kTimeoutTimeMs - kBaseTimeMs, delta_vec[1] / 1000);
EXPECT_EQ(1, delta_vec[2] / 1000);
return true;
}));
Process();
}
} // namespace webrtc