blob: 90cfb72ac92abfcba33b4df69f4c5c312a427ba1 [file] [log] [blame]
/*
* Copyright (c) 2011 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.
*/
/*
* This file includes unit tests for the RTPSender.
*/
#include <gtest/gtest.h>
#include "rtp_header_extension.h"
#include "rtp_rtcp_defines.h"
#include "rtp_sender.h"
#include "rtp_utility.h"
#include "typedefs.h"
namespace webrtc {
namespace {
const int kId = 1;
const int kTypeLength = TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES;
const int kPayload = 100;
const uint32_t kTimestamp = 10;
const uint16_t kSeqNum = 33;
const int kTimeOffset = 22222;
const int kMaxPacketLength = 1500;
} // namespace
class FakeClockTest : public RtpRtcpClock {
public:
FakeClockTest() {
time_in_ms_ = 123456;
}
// Return a timestamp in milliseconds relative to some arbitrary
// source; the source is fixed for this clock.
virtual WebRtc_UWord32 GetTimeInMS() {
return time_in_ms_;
}
// Retrieve an NTP absolute timestamp.
virtual void CurrentNTP(WebRtc_UWord32& secs, WebRtc_UWord32& frac) {
secs = time_in_ms_ / 1000;
frac = (time_in_ms_ % 1000) * 4294967;
}
void IncrementTime(WebRtc_UWord32 time_increment_ms) {
time_in_ms_ += time_increment_ms;
}
private:
WebRtc_UWord32 time_in_ms_;
};
class LoopbackTransportTest : public webrtc::Transport {
public:
LoopbackTransportTest()
: packets_sent_(0),
last_sent_packet_len_(0) {
}
virtual int SendPacket(int channel, const void *data, int len) {
packets_sent_++;
memcpy(last_sent_packet_, data, len);
last_sent_packet_len_ = len;
return len;
}
virtual int SendRTCPPacket(int channel, const void *data, int len) {
return -1;
}
int packets_sent_;
int last_sent_packet_len_;
uint8_t last_sent_packet_[kMaxPacketLength];
};
class RtpSenderTest : public ::testing::Test {
protected:
RtpSenderTest()
: fake_clock_(),
rtp_sender_(new RTPSender(0, false, &fake_clock_)),
transport_(),
kMarkerBit(true),
kType(kRtpExtensionTransmissionTimeOffset),
packet_() {
EXPECT_EQ(0, rtp_sender_->SetSequenceNumber(kSeqNum));
}
~RtpSenderTest() {
delete rtp_sender_;
}
FakeClockTest fake_clock_;
RTPSender* rtp_sender_;
LoopbackTransportTest transport_;
const bool kMarkerBit;
RTPExtensionType kType;
uint8_t packet_[kMaxPacketLength];
void VerifyRTPHeaderCommon(const WebRtcRTPHeader& rtp_header) {
EXPECT_EQ(kMarkerBit, rtp_header.header.markerBit);
EXPECT_EQ(kPayload, rtp_header.header.payloadType);
EXPECT_EQ(kSeqNum, rtp_header.header.sequenceNumber);
EXPECT_EQ(kTimestamp, rtp_header.header.timestamp);
EXPECT_EQ(rtp_sender_->SSRC(), rtp_header.header.ssrc);
EXPECT_EQ(0, rtp_header.header.numCSRCs);
EXPECT_EQ(0, rtp_header.header.paddingLength);
}
};
TEST_F(RtpSenderTest, RegisterRtpHeaderExtension) {
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kType, kId));
EXPECT_EQ(RTP_ONE_BYTE_HEADER_LENGTH_IN_BYTES + kTypeLength,
rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(kType));
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
}
TEST_F(RtpSenderTest, BuildRTPPacket) {
WebRtc_Word32 length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
kMarkerBit,
kTimestamp);
EXPECT_EQ(12, length);
// Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtpParser(packet_, length);
webrtc::WebRtcRTPHeader rtp_header;
RtpHeaderExtensionMap map;
map.Register(kType, kId);
const bool valid_rtp_header = rtpParser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header);
ASSERT_FALSE(rtpParser.RTCP());
VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.header.headerLength);
EXPECT_EQ(0, rtp_header.extension.transmissionTimeOffset);
}
TEST_F(RtpSenderTest, BuildRTPPacketWithExtension) {
EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kTimeOffset));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kType, kId));
WebRtc_Word32 length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
kMarkerBit,
kTimestamp);
EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length);
// Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtpParser(packet_, length);
webrtc::WebRtcRTPHeader rtp_header;
RtpHeaderExtensionMap map;
map.Register(kType, kId);
const bool valid_rtp_header = rtpParser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header);
ASSERT_FALSE(rtpParser.RTCP());
VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.header.headerLength);
EXPECT_EQ(kTimeOffset, rtp_header.extension.transmissionTimeOffset);
// Parse without map extension
webrtc::WebRtcRTPHeader rtp_header2;
const bool valid_rtp_header2 = rtpParser.Parse(rtp_header2, NULL);
ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2);
EXPECT_EQ(length, rtp_header2.header.headerLength);
EXPECT_EQ(0, rtp_header2.extension.transmissionTimeOffset);
}
TEST_F(RtpSenderTest, NoTrafficSmoothing) {
EXPECT_EQ(0, rtp_sender_->RegisterSendTransport(&transport_));
WebRtc_Word32 rtp_length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
kMarkerBit,
kTimestamp);
// Packet should be sent immediately.
EXPECT_EQ(0, rtp_sender_->SendToNetwork(packet_, 0, rtp_length,
kAllowRetransmission));
EXPECT_EQ(1, transport_.packets_sent_);
EXPECT_EQ(rtp_length, transport_.last_sent_packet_len_);
}
TEST_F(RtpSenderTest, TrafficSmoothing) {
rtp_sender_->SetTransmissionSmoothingStatus(true);
EXPECT_EQ(0, rtp_sender_->SetStorePacketsStatus(true, 10));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kType, kId));
EXPECT_EQ(0, rtp_sender_->RegisterSendTransport(&transport_));
WebRtc_Word32 rtp_length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
kMarkerBit,
kTimestamp);
// Packet should be stored in a send bucket.
EXPECT_EQ(0, rtp_sender_->SendToNetwork(packet_, 0, rtp_length,
kAllowRetransmission));
EXPECT_EQ(0, transport_.packets_sent_);
const int kStoredTimeInMs = 100;
fake_clock_.IncrementTime(kStoredTimeInMs);
// Process send bucket. Packet should now be sent.
rtp_sender_->ProcessSendToNetwork();
EXPECT_EQ(1, transport_.packets_sent_);
EXPECT_EQ(rtp_length, transport_.last_sent_packet_len_);
// Parse sent packet.
webrtc::ModuleRTPUtility::RTPHeaderParser rtpParser(
transport_.last_sent_packet_, rtp_length);
webrtc::WebRtcRTPHeader rtp_header;
RtpHeaderExtensionMap map;
map.Register(kType, kId);
const bool valid_rtp_header = rtpParser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header);
// Verify transmission time offset.
EXPECT_EQ(kStoredTimeInMs * 90, rtp_header.extension.transmissionTimeOffset);
}
} // namespace webrtc