/* * Copyright (c) 2012 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 #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_Word64 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_Word64 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 rtp_parser(packet_, length); webrtc::WebRtcRTPHeader rtp_header; RtpHeaderExtensionMap map; map.Register(kType, kId); const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map); ASSERT_TRUE(valid_rtp_header); ASSERT_FALSE(rtp_parser.RTCP()); VerifyRTPHeaderCommon(rtp_header); EXPECT_EQ(length, rtp_header.header.headerLength); EXPECT_EQ(0, rtp_header.extension.transmissionTimeOffset); } TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) { 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 rtp_parser(packet_, length); webrtc::WebRtcRTPHeader rtp_header; RtpHeaderExtensionMap map; map.Register(kType, kId); const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map); ASSERT_TRUE(valid_rtp_header); ASSERT_FALSE(rtp_parser.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 = rtp_parser.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, BuildRTPPacketWithNegativeTransmissionOffsetExtension) { const int kNegTimeOffset = -500; EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kNegTimeOffset)); 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 rtp_parser(packet_, length); webrtc::WebRtcRTPHeader rtp_header; RtpHeaderExtensionMap map; map.Register(kType, kId); const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map); ASSERT_TRUE(valid_rtp_header); ASSERT_FALSE(rtp_parser.RTCP()); VerifyRTPHeaderCommon(rtp_header); EXPECT_EQ(length, rtp_header.header.headerLength); EXPECT_EQ(kNegTimeOffset, rtp_header.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, kTimestamp / 90, 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_)); rtp_sender_->SetTargetSendBitrate(300000); 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, fake_clock_.GetTimeInMS(), 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 rtp_parser( transport_.last_sent_packet_, rtp_length); webrtc::WebRtcRTPHeader rtp_header; RtpHeaderExtensionMap map; map.Register(kType, kId); const bool valid_rtp_header = rtp_parser.Parse(rtp_header, &map); ASSERT_TRUE(valid_rtp_header); // Verify transmission time offset. EXPECT_EQ(kStoredTimeInMs * 90, rtp_header.extension.transmissionTimeOffset); } } // namespace webrtc