blob: eba4e010b59419cb7b3b61d52b084f3beca8a85b [file] [log] [blame]
/*
* Copyright (c) 2013 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 "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/pacing/include/mock/mock_paced_sender.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
#include "webrtc/system_wrappers/interface/scoped_vector.h"
using ::testing::_;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SaveArg;
namespace webrtc {
namespace {
const uint32_t kSenderSsrc = 0x12345;
const uint32_t kReceiverSsrc = 0x23456;
const uint32_t kSenderRtxSsrc = 0x32345;
const uint32_t kOneWayNetworkDelayMs = 100;
class RtcpRttStatsTestImpl : public RtcpRttStats {
public:
RtcpRttStatsTestImpl() : rtt_ms_(0) {}
virtual ~RtcpRttStatsTestImpl() {}
virtual void OnRttUpdate(uint32_t rtt_ms) {
rtt_ms_ = rtt_ms;
}
virtual uint32_t LastProcessedRtt() const {
return rtt_ms_;
}
uint32_t rtt_ms_;
};
class SendTransport : public Transport,
public NullRtpData {
public:
SendTransport() : receiver_(NULL), clock_(NULL), delay_ms_(0) {}
void SetRtpRtcpModule(ModuleRtpRtcpImpl* receiver) {
receiver_ = receiver;
}
void SimulateNetworkDelay(uint32_t delay_ms, SimulatedClock* clock) {
clock_ = clock;
delay_ms_ = delay_ms;
}
virtual int SendPacket(int /*ch*/, const void* /*data*/, int /*len*/) {
return -1;
}
virtual int SendRTCPPacket(int /*ch*/, const void *data, int len) {
if (clock_) {
clock_->AdvanceTimeMilliseconds(delay_ms_);
}
EXPECT_TRUE(receiver_ != NULL);
EXPECT_EQ(0, receiver_->IncomingRtcpPacket(
static_cast<const uint8_t*>(data), len));
return len;
}
ModuleRtpRtcpImpl* receiver_;
SimulatedClock* clock_;
uint32_t delay_ms_;
};
class RtpRtcpModule {
public:
RtpRtcpModule(SimulatedClock* clock)
: receive_statistics_(ReceiveStatistics::Create(clock)) {
RtpRtcp::Configuration config;
config.audio = false;
config.clock = clock;
config.outgoing_transport = &transport_;
config.receive_statistics = receive_statistics_.get();
config.rtt_stats = &rtt_stats_;
impl_.reset(new ModuleRtpRtcpImpl(config));
EXPECT_EQ(0, impl_->SetRTCPStatus(kRtcpCompound));
transport_.SimulateNetworkDelay(kOneWayNetworkDelayMs, clock);
}
RtcpPacketTypeCounter packets_sent_;
RtcpPacketTypeCounter packets_received_;
scoped_ptr<ReceiveStatistics> receive_statistics_;
SendTransport transport_;
RtcpRttStatsTestImpl rtt_stats_;
scoped_ptr<ModuleRtpRtcpImpl> impl_;
RtcpPacketTypeCounter RtcpSent() {
impl_->GetRtcpPacketTypeCounters(&packets_sent_, &packets_received_);
return packets_sent_;
}
RtcpPacketTypeCounter RtcpReceived() {
impl_->GetRtcpPacketTypeCounters(&packets_sent_, &packets_received_);
return packets_received_;
}
};
} // namespace
class RtpRtcpImplTest : public ::testing::Test {
protected:
RtpRtcpImplTest()
: clock_(1335900000),
sender_(&clock_),
receiver_(&clock_) {
// Send module.
EXPECT_EQ(0, sender_.impl_->SetSendingStatus(true));
sender_.impl_->SetSSRC(kSenderSsrc);
sender_.impl_->SetRemoteSSRC(kReceiverSsrc);
// Receive module.
EXPECT_EQ(0, receiver_.impl_->SetSendingStatus(false));
receiver_.impl_->SetSSRC(kReceiverSsrc);
receiver_.impl_->SetRemoteSSRC(kSenderSsrc);
// Transport settings.
sender_.transport_.SetRtpRtcpModule(receiver_.impl_.get());
receiver_.transport_.SetRtpRtcpModule(sender_.impl_.get());
}
SimulatedClock clock_;
RtpRtcpModule sender_;
RtpRtcpModule receiver_;
};
TEST_F(RtpRtcpImplTest, Rtt) {
RTPHeader header;
header.timestamp = 1;
header.sequenceNumber = 123;
header.ssrc = kSenderSsrc;
header.headerLength = 12;
receiver_.receive_statistics_->IncomingPacket(header, 100, false);
// Sender module should send a SR.
EXPECT_EQ(0, sender_.impl_->SendRTCP(kRtcpReport));
// Receiver module should send a RR with a response to the last received SR.
clock_.AdvanceTimeMilliseconds(1000);
EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpReport));
// Verify RTT.
uint16_t rtt;
uint16_t avg_rtt;
uint16_t min_rtt;
uint16_t max_rtt;
EXPECT_EQ(0,
sender_.impl_->RTT(kReceiverSsrc, &rtt, &avg_rtt, &min_rtt, &max_rtt));
EXPECT_EQ(2 * kOneWayNetworkDelayMs, rtt);
EXPECT_EQ(2 * kOneWayNetworkDelayMs, avg_rtt);
EXPECT_EQ(2 * kOneWayNetworkDelayMs, min_rtt);
EXPECT_EQ(2 * kOneWayNetworkDelayMs, max_rtt);
// No RTT from other ssrc.
EXPECT_EQ(-1,
sender_.impl_->RTT(kReceiverSsrc+1, &rtt, &avg_rtt, &min_rtt, &max_rtt));
// Verify RTT from rtt_stats config.
EXPECT_EQ(0U, sender_.rtt_stats_.LastProcessedRtt());
EXPECT_EQ(0U, sender_.impl_->rtt_ms());
sender_.impl_->Process();
EXPECT_EQ(2 * kOneWayNetworkDelayMs, sender_.rtt_stats_.LastProcessedRtt());
EXPECT_EQ(2 * kOneWayNetworkDelayMs, sender_.impl_->rtt_ms());
}
TEST_F(RtpRtcpImplTest, SetRtcpXrRrtrStatus) {
EXPECT_FALSE(receiver_.impl_->RtcpXrRrtrStatus());
receiver_.impl_->SetRtcpXrRrtrStatus(true);
EXPECT_TRUE(receiver_.impl_->RtcpXrRrtrStatus());
}
TEST_F(RtpRtcpImplTest, RttForReceiverOnly) {
receiver_.impl_->SetRtcpXrRrtrStatus(true);
// Receiver module should send a Receiver time reference report (RTRR).
EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpReport));
// Sender module should send a response to the last received RTRR (DLRR).
clock_.AdvanceTimeMilliseconds(1000);
EXPECT_EQ(0, sender_.impl_->SendRTCP(kRtcpReport));
// Verify RTT.
EXPECT_EQ(0U, receiver_.rtt_stats_.LastProcessedRtt());
EXPECT_EQ(0U, receiver_.impl_->rtt_ms());
receiver_.impl_->Process();
EXPECT_EQ(2 * kOneWayNetworkDelayMs, receiver_.rtt_stats_.LastProcessedRtt());
EXPECT_EQ(2 * kOneWayNetworkDelayMs, receiver_.impl_->rtt_ms());
}
TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_Nack) {
EXPECT_EQ(0U, sender_.RtcpReceived().nack_packets);
EXPECT_EQ(0U, receiver_.RtcpSent().nack_packets);
// Receive module sends a NACK.
const uint16_t kNackLength = 1;
uint16_t nack_list[kNackLength] = {123};
EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list, kNackLength));
EXPECT_EQ(1U, receiver_.RtcpSent().nack_packets);
// Send module receives the NACK.
EXPECT_EQ(1U, sender_.RtcpReceived().nack_packets);
}
TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_FirAndPli) {
EXPECT_EQ(0U, sender_.RtcpReceived().fir_packets);
EXPECT_EQ(0U, receiver_.RtcpSent().fir_packets);
// Receive module sends a FIR.
EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpFir));
EXPECT_EQ(1U, receiver_.RtcpSent().fir_packets);
// Send module receives the FIR.
EXPECT_EQ(1U, sender_.RtcpReceived().fir_packets);
// Receive module sends a FIR and PLI.
EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpFir | kRtcpPli));
EXPECT_EQ(2U, receiver_.RtcpSent().fir_packets);
EXPECT_EQ(1U, receiver_.RtcpSent().pli_packets);
// Send module receives the FIR and PLI.
EXPECT_EQ(2U, sender_.RtcpReceived().fir_packets);
EXPECT_EQ(1U, sender_.RtcpReceived().pli_packets);
}
class RtpSendingTestTransport : public Transport {
public:
void ResetCounters() { bytes_received_.clear(); }
virtual int SendPacket(int channel, const void* data, int length) {
RTPHeader header;
scoped_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
EXPECT_TRUE(
parser->Parse(static_cast<const uint8_t*>(data), length, &header));
bytes_received_[header.ssrc] += length;
++packets_received_[header.ssrc];
return length;
}
virtual int SendRTCPPacket(int channel, const void* data, int length) {
return length;
}
int GetPacketsReceived(uint32_t ssrc) const {
std::map<uint32_t, int>::const_iterator it = packets_received_.find(ssrc);
if (it == packets_received_.end())
return 0;
return it->second;
}
int GetBytesReceived(uint32_t ssrc) const {
std::map<uint32_t, int>::const_iterator it = bytes_received_.find(ssrc);
if (it == bytes_received_.end())
return 0;
return it->second;
}
int GetTotalBytesReceived() const {
int sum = 0;
for (std::map<uint32_t, int>::const_iterator it = bytes_received_.begin();
it != bytes_received_.end();
++it) {
sum += it->second;
}
return sum;
}
private:
std::map<uint32_t, int> bytes_received_;
std::map<uint32_t, int> packets_received_;
};
class RtpSendingTest : public ::testing::Test {
protected:
// Map from SSRC to number of received packets and bytes.
typedef std::map<uint32_t, std::pair<int, int> > PaddingMap;
RtpSendingTest() {
// Send module.
RtpRtcp::Configuration config;
config.audio = false;
config.clock = Clock::GetRealTimeClock();
config.outgoing_transport = &transport_;
config.receive_statistics = receive_statistics_.get();
config.rtt_stats = &rtt_stats_;
config.paced_sender = &pacer_;
memset(&codec_, 0, sizeof(VideoCodec));
codec_.plType = 100;
strncpy(codec_.plName, "VP8", 3);
codec_.numberOfSimulcastStreams = 3;
codec_.simulcastStream[0].width = 320;
codec_.simulcastStream[0].height = 180;
codec_.simulcastStream[0].maxBitrate = 300;
codec_.simulcastStream[1].width = 640;
codec_.simulcastStream[1].height = 360;
codec_.simulcastStream[1].maxBitrate = 600;
codec_.simulcastStream[2].width = 1280;
codec_.simulcastStream[2].height = 720;
codec_.simulcastStream[2].maxBitrate = 1200;
// We need numberOfSimulcastStreams + 1 RTP modules since we need one
// default module.
for (int i = 0; i < codec_.numberOfSimulcastStreams + 1; ++i) {
RtpRtcp* sender = RtpRtcp::CreateRtpRtcp(config);
EXPECT_EQ(0, sender->RegisterSendPayload(codec_));
EXPECT_EQ(0, sender->SetSendingStatus(true));
EXPECT_EQ(0, sender->SetSendingMediaStatus(true));
sender->SetSSRC(kSenderSsrc + i);
sender->SetRemoteSSRC(kReceiverSsrc + i);
senders_.push_back(sender);
config.default_module = senders_[0];
}
std::vector<uint32_t> bitrates;
bitrates.push_back(codec_.simulcastStream[0].maxBitrate);
bitrates.push_back(codec_.simulcastStream[1].maxBitrate);
bitrates.push_back(codec_.simulcastStream[2].maxBitrate);
senders_[0]->SetTargetSendBitrate(bitrates);
}
~RtpSendingTest() {
for (int i = senders_.size() - 1; i >= 0; --i) {
delete senders_[i];
}
}
void SendFrameOnSender(int sender_index,
const uint8_t* payload,
size_t length) {
RTPVideoHeader rtp_video_header = {
codec_.simulcastStream[sender_index].width,
codec_.simulcastStream[sender_index].height,
true,
0,
kRtpVideoVp8,
{}};
uint32_t seq_num = 0;
uint32_t ssrc = 0;
int64_t capture_time_ms = 0;
bool retransmission = false;
EXPECT_CALL(pacer_, SendPacket(_, _, _, _, _, _))
.WillRepeatedly(DoAll(SaveArg<1>(&ssrc),
SaveArg<2>(&seq_num),
SaveArg<3>(&capture_time_ms),
SaveArg<5>(&retransmission),
Return(true)));
EXPECT_EQ(0,
senders_[sender_index]->SendOutgoingData(kVideoFrameKey,
codec_.plType,
0,
0,
payload,
length,
NULL,
&rtp_video_header));
EXPECT_TRUE(senders_[sender_index]->TimeToSendPacket(
ssrc, seq_num, capture_time_ms, retransmission));
}
void ExpectPadding(const PaddingMap& expected_padding) {
int expected_total_bytes = 0;
for (PaddingMap::const_iterator it = expected_padding.begin();
it != expected_padding.end();
++it) {
int packets_received = transport_.GetBytesReceived(it->first);
if (it->second.first > 0) {
EXPECT_GE(packets_received, it->second.first)
<< "On SSRC: " << it->first;
}
int bytes_received = transport_.GetBytesReceived(it->first);
expected_total_bytes += bytes_received;
if (it->second.second > 0) {
EXPECT_GE(bytes_received, it->second.second)
<< "On SSRC: " << it->first;
} else {
EXPECT_EQ(0, bytes_received) << "On SSRC: " << it->first;
}
}
EXPECT_EQ(expected_total_bytes, transport_.GetTotalBytesReceived());
}
scoped_ptr<ReceiveStatistics> receive_statistics_;
RtcpRttStatsTestImpl rtt_stats_;
std::vector<RtpRtcp*> senders_;
RtpSendingTestTransport transport_;
NiceMock<MockPacedSender> pacer_;
VideoCodec codec_;
};
TEST_F(RtpSendingTest, DISABLED_RoundRobinPadding) {
// We have to send on an SSRC to be allowed to pad, since a marker bit must
// be sent prior to padding packets.
const uint8_t payload[200] = {0};
for (int i = 0; i < codec_.numberOfSimulcastStreams; ++i) {
SendFrameOnSender(i + 1, payload, sizeof(payload));
}
transport_.ResetCounters();
senders_[0]->TimeToSendPadding(500);
PaddingMap expected_padding;
expected_padding[kSenderSsrc + 1] = std::make_pair(2, 500);
expected_padding[kSenderSsrc + 2] = std::make_pair(0, 0);
expected_padding[kSenderSsrc + 3] = std::make_pair(0, 0);
ExpectPadding(expected_padding);
senders_[0]->TimeToSendPadding(1000);
expected_padding[kSenderSsrc + 2] = std::make_pair(4, 1000);
ExpectPadding(expected_padding);
senders_[0]->TimeToSendPadding(1500);
expected_padding[kSenderSsrc + 3] = std::make_pair(6, 1500);
ExpectPadding(expected_padding);
}
TEST_F(RtpSendingTest, DISABLED_RoundRobinPaddingRtx) {
// Enable RTX to allow padding to be sent prior to media.
for (int i = 1; i < codec_.numberOfSimulcastStreams + 1; ++i) {
senders_[i]->SetRtxSendPayloadType(96);
senders_[i]->SetRtxSsrc(kSenderRtxSsrc + i);
senders_[i]->SetRTXSendStatus(kRtxRetransmitted);
}
transport_.ResetCounters();
senders_[0]->TimeToSendPadding(500);
PaddingMap expected_padding;
expected_padding[kSenderSsrc + 1] = std::make_pair(0, 0);
expected_padding[kSenderSsrc + 2] = std::make_pair(0, 0);
expected_padding[kSenderSsrc + 3] = std::make_pair(0, 0);
expected_padding[kSenderRtxSsrc + 1] = std::make_pair(2, 500);
expected_padding[kSenderRtxSsrc + 2] = std::make_pair(0, 0);
expected_padding[kSenderRtxSsrc + 3] = std::make_pair(0, 0);
ExpectPadding(expected_padding);
senders_[0]->TimeToSendPadding(1000);
expected_padding[kSenderRtxSsrc + 2] = std::make_pair(4, 500);
ExpectPadding(expected_padding);
senders_[0]->TimeToSendPadding(1500);
expected_padding[kSenderRtxSsrc + 3] = std::make_pair(6, 500);
ExpectPadding(expected_padding);
}
TEST_F(RtpSendingTest, DISABLED_RoundRobinPaddingRtxRedundantPayloads) {
for (int i = 1; i < codec_.numberOfSimulcastStreams + 1; ++i) {
senders_[i]->SetRtxSendPayloadType(96);
senders_[i]->SetRtxSsrc(kSenderRtxSsrc + i);
senders_[i]->SetRTXSendStatus(kRtxRetransmitted | kRtxRedundantPayloads);
senders_[i]->SetStorePacketsStatus(true, 100);
}
// First send payloads so that we have something to retransmit.
const size_t kPayloadSize = 500;
const uint8_t payload[kPayloadSize] = {0};
for (int i = 0; i < codec_.numberOfSimulcastStreams; ++i) {
SendFrameOnSender(i + 1, payload, sizeof(payload));
}
transport_.ResetCounters();
senders_[0]->TimeToSendPadding(500);
PaddingMap expected_padding;
expected_padding[kSenderSsrc + 1] = std::make_pair<int, int>(0, 0);
expected_padding[kSenderSsrc + 2] = std::make_pair<int, int>(0, 0);
expected_padding[kSenderSsrc + 3] = std::make_pair<int, int>(0, 0);
expected_padding[kSenderRtxSsrc + 1] = std::make_pair<int, int>(1, 500);
expected_padding[kSenderRtxSsrc + 2] = std::make_pair<int, int>(0, 0);
expected_padding[kSenderRtxSsrc + 3] = std::make_pair<int, int>(0, 0);
ExpectPadding(expected_padding);
senders_[0]->TimeToSendPadding(1000);
expected_padding[kSenderRtxSsrc + 2] = std::make_pair<int, int>(2, 1000);
ExpectPadding(expected_padding);
senders_[0]->TimeToSendPadding(1500);
expected_padding[kSenderRtxSsrc + 3] = std::make_pair<int, int>(3, 1500);
ExpectPadding(expected_padding);
}
} // namespace webrtc