| /* |
| * 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 "testing/gtest/include/gtest/gtest.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_format_video_generic.h" |
| #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h" |
| #include "webrtc/modules/rtp_rtcp/source/rtp_sender.h" |
| #include "webrtc/system_wrappers/interface/scoped_ptr.h" |
| #include "webrtc/typedefs.h" |
| |
| namespace webrtc { |
| |
| namespace { |
| const int kTransmissionTimeOffsetExtensionId = 1; |
| const int kAbsoluteSendTimeExtensionId = 14; |
| const int kPayload = 100; |
| const uint32_t kTimestamp = 10; |
| const uint16_t kSeqNum = 33; |
| const int kTimeOffset = 22222; |
| const int kMaxPacketLength = 1500; |
| const uint32_t kAbsoluteSendTime = 0x00aabbcc; |
| const uint8_t kAudioLevel = 0x5a; |
| const uint8_t kAudioLevelExtensionId = 9; |
| const int kAudioPayload = 103; |
| } // namespace |
| |
| using testing::_; |
| |
| const uint8_t* GetPayloadData(const RTPHeader& rtp_header, |
| const uint8_t* packet) { |
| return packet + rtp_header.headerLength; |
| } |
| |
| uint16_t GetPayloadDataLength(const RTPHeader& rtp_header, |
| const uint16_t packet_length) { |
| uint16_t length = packet_length - rtp_header.headerLength - |
| rtp_header.paddingLength; |
| return static_cast<uint16_t>(length); |
| } |
| |
| uint64_t ConvertMsToAbsSendTime(int64_t time_ms) { |
| return 0x00fffffful & ((time_ms << 18) / 1000); |
| } |
| |
| 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_(123456789), |
| mock_paced_sender_(), |
| rtp_sender_(), |
| payload_(kPayload), |
| transport_(), |
| kMarkerBit(true) { |
| EXPECT_CALL(mock_paced_sender_, |
| SendPacket(_, _, _, _, _, _)).WillRepeatedly(testing::Return(true)); |
| } |
| |
| virtual void SetUp() { |
| rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_, NULL, |
| &mock_paced_sender_)); |
| rtp_sender_->SetSequenceNumber(kSeqNum); |
| } |
| |
| SimulatedClock fake_clock_; |
| MockPacedSender mock_paced_sender_; |
| scoped_ptr<RTPSender> rtp_sender_; |
| int payload_; |
| LoopbackTransportTest transport_; |
| const bool kMarkerBit; |
| uint8_t packet_[kMaxPacketLength]; |
| |
| void VerifyRTPHeaderCommon(const RTPHeader& rtp_header) { |
| EXPECT_EQ(kMarkerBit, rtp_header.markerBit); |
| EXPECT_EQ(payload_, rtp_header.payloadType); |
| EXPECT_EQ(kSeqNum, rtp_header.sequenceNumber); |
| EXPECT_EQ(kTimestamp, rtp_header.timestamp); |
| EXPECT_EQ(rtp_sender_->SSRC(), rtp_header.ssrc); |
| EXPECT_EQ(0, rtp_header.numCSRCs); |
| EXPECT_EQ(0, rtp_header.paddingLength); |
| } |
| }; |
| |
| TEST_F(RtpSenderTest, RegisterRtpTransmissionTimeOffsetHeaderExtension) { |
| EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); |
| EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength, |
| rtp_sender_->RtpHeaderExtensionTotalLength()); |
| EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( |
| kRtpExtensionTransmissionTimeOffset)); |
| EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| } |
| |
| TEST_F(RtpSenderTest, RegisterRtpAbsoluteSendTimeHeaderExtension) { |
| EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); |
| EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength, |
| rtp_sender_->RtpHeaderExtensionTotalLength()); |
| EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( |
| kRtpExtensionAbsoluteSendTime)); |
| EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| } |
| |
| TEST_F(RtpSenderTest, RegisterRtpAudioLevelHeaderExtension) { |
| EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionAudioLevel, kAudioLevelExtensionId)); |
| // Accounted size for audio level is zero because it is currently specially |
| // treated by RTPSenderAudio. |
| EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| // EXPECT_EQ(kRtpOneByteHeaderLength + kAudioLevelLength, |
| // rtp_sender_->RtpHeaderExtensionTotalLength()); |
| EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( |
| kRtpExtensionAudioLevel)); |
| EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| } |
| |
| TEST_F(RtpSenderTest, RegisterRtpHeaderExtensions) { |
| EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); |
| EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength, |
| rtp_sender_->RtpHeaderExtensionTotalLength()); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); |
| EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength + |
| kAbsoluteSendTimeLength, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionAudioLevel, kAudioLevelExtensionId)); |
| EXPECT_EQ(kRtpOneByteHeaderLength + kTransmissionTimeOffsetLength + |
| kAbsoluteSendTimeLength, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( |
| kRtpExtensionTransmissionTimeOffset)); |
| EXPECT_EQ(kRtpOneByteHeaderLength + kAbsoluteSendTimeLength, |
| rtp_sender_->RtpHeaderExtensionTotalLength()); |
| EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( |
| kRtpExtensionAbsoluteSendTime)); |
| EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension( |
| kRtpExtensionAudioLevel)); |
| EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| } |
| |
| TEST_F(RtpSenderTest, BuildRTPPacket) { |
| int32_t length = rtp_sender_->BuildRTPheader(packet_, |
| kPayload, |
| kMarkerBit, |
| kTimestamp, |
| 0); |
| EXPECT_EQ(12, length); |
| |
| // Verify |
| webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length); |
| webrtc::RTPHeader rtp_header; |
| |
| RtpHeaderExtensionMap map; |
| map.Register(kRtpExtensionTransmissionTimeOffset, |
| kTransmissionTimeOffsetExtensionId); |
| 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.headerLength); |
| EXPECT_EQ(0, rtp_header.extension.transmissionTimeOffset); |
| EXPECT_EQ(0u, rtp_header.extension.absoluteSendTime); |
| } |
| |
| TEST_F(RtpSenderTest, BuildRTPPacketWithTransmissionOffsetExtension) { |
| EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kTimeOffset)); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); |
| |
| int32_t length = rtp_sender_->BuildRTPheader(packet_, |
| kPayload, |
| kMarkerBit, |
| kTimestamp, |
| 0); |
| EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length); |
| |
| // Verify |
| webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length); |
| webrtc::RTPHeader rtp_header; |
| |
| RtpHeaderExtensionMap map; |
| map.Register(kRtpExtensionTransmissionTimeOffset, |
| kTransmissionTimeOffsetExtensionId); |
| 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.headerLength); |
| EXPECT_EQ(kTimeOffset, rtp_header.extension.transmissionTimeOffset); |
| |
| // Parse without map extension |
| webrtc::RTPHeader 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.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( |
| kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); |
| |
| int32_t length = rtp_sender_->BuildRTPheader(packet_, |
| kPayload, |
| kMarkerBit, |
| kTimestamp, |
| 0); |
| EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length); |
| |
| // Verify |
| webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length); |
| webrtc::RTPHeader rtp_header; |
| |
| RtpHeaderExtensionMap map; |
| map.Register(kRtpExtensionTransmissionTimeOffset, |
| kTransmissionTimeOffsetExtensionId); |
| 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.headerLength); |
| EXPECT_EQ(kNegTimeOffset, rtp_header.extension.transmissionTimeOffset); |
| } |
| |
| TEST_F(RtpSenderTest, BuildRTPPacketWithAbsoluteSendTimeExtension) { |
| EXPECT_EQ(0, rtp_sender_->SetAbsoluteSendTime(kAbsoluteSendTime)); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); |
| |
| int32_t length = rtp_sender_->BuildRTPheader(packet_, |
| kPayload, |
| kMarkerBit, |
| kTimestamp, |
| 0); |
| EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length); |
| |
| // Verify |
| webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length); |
| webrtc::RTPHeader rtp_header; |
| |
| RtpHeaderExtensionMap map; |
| map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId); |
| 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.headerLength); |
| EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime); |
| |
| // Parse without map extension |
| webrtc::RTPHeader 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.headerLength); |
| EXPECT_EQ(0u, rtp_header2.extension.absoluteSendTime); |
| } |
| |
| TEST_F(RtpSenderTest, BuildRTPPacketWithHeaderExtensions) { |
| EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kTimeOffset)); |
| EXPECT_EQ(0, rtp_sender_->SetAbsoluteSendTime(kAbsoluteSendTime)); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); |
| |
| int32_t length = rtp_sender_->BuildRTPheader(packet_, |
| kPayload, |
| kMarkerBit, |
| kTimestamp, |
| 0); |
| EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length); |
| |
| // Verify |
| webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length); |
| webrtc::RTPHeader rtp_header; |
| |
| RtpHeaderExtensionMap map; |
| map.Register(kRtpExtensionTransmissionTimeOffset, |
| kTransmissionTimeOffsetExtensionId); |
| map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId); |
| 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.headerLength); |
| EXPECT_EQ(kTimeOffset, rtp_header.extension.transmissionTimeOffset); |
| EXPECT_EQ(kAbsoluteSendTime, rtp_header.extension.absoluteSendTime); |
| |
| // Parse without map extension |
| webrtc::RTPHeader 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.headerLength); |
| EXPECT_EQ(0, rtp_header2.extension.transmissionTimeOffset); |
| EXPECT_EQ(0u, rtp_header2.extension.absoluteSendTime); |
| } |
| |
| TEST_F(RtpSenderTest, TrafficSmoothingWithExtensions) { |
| EXPECT_CALL(mock_paced_sender_, |
| SendPacket(PacedSender::kNormalPriority, _, kSeqNum, _, _, _)). |
| WillOnce(testing::Return(false)); |
| |
| rtp_sender_->SetStorePacketsStatus(true, 10); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); |
| rtp_sender_->SetTargetSendBitrate(300000); |
| int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); |
| int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_, |
| kPayload, |
| kMarkerBit, |
| kTimestamp, |
| capture_time_ms); |
| |
| // Packet should be stored in a send bucket. |
| EXPECT_EQ(0, rtp_sender_->SendToNetwork(packet_, |
| 0, |
| rtp_length, |
| capture_time_ms, |
| kAllowRetransmission, |
| PacedSender::kNormalPriority)); |
| |
| EXPECT_EQ(0, transport_.packets_sent_); |
| |
| const int kStoredTimeInMs = 100; |
| fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); |
| |
| rtp_sender_->TimeToSendPacket(kSeqNum, capture_time_ms, false); |
| |
| // Process send bucket. Packet should now be sent. |
| 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::RTPHeader rtp_header; |
| RtpHeaderExtensionMap map; |
| map.Register(kRtpExtensionTransmissionTimeOffset, |
| kTransmissionTimeOffsetExtensionId); |
| map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId); |
| 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); |
| uint64_t expected_send_time = |
| ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds()); |
| EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime); |
| } |
| |
| TEST_F(RtpSenderTest, TrafficSmoothingRetransmits) { |
| EXPECT_CALL(mock_paced_sender_, |
| SendPacket(PacedSender::kNormalPriority, _, kSeqNum, _, _, _)). |
| WillOnce(testing::Return(false)); |
| |
| rtp_sender_->SetStorePacketsStatus(true, 10); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); |
| rtp_sender_->SetTargetSendBitrate(300000); |
| int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); |
| int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_, |
| kPayload, |
| kMarkerBit, |
| kTimestamp, |
| capture_time_ms); |
| |
| // Packet should be stored in a send bucket. |
| EXPECT_EQ(0, rtp_sender_->SendToNetwork(packet_, |
| 0, |
| rtp_length, |
| capture_time_ms, |
| kAllowRetransmission, |
| PacedSender::kNormalPriority)); |
| |
| EXPECT_EQ(0, transport_.packets_sent_); |
| |
| EXPECT_CALL(mock_paced_sender_, |
| SendPacket(PacedSender::kHighPriority, _, kSeqNum, _, _, _)). |
| WillOnce(testing::Return(false)); |
| |
| const int kStoredTimeInMs = 100; |
| fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); |
| |
| EXPECT_EQ(rtp_length, rtp_sender_->ReSendPacket(kSeqNum)); |
| EXPECT_EQ(0, transport_.packets_sent_); |
| |
| rtp_sender_->TimeToSendPacket(kSeqNum, capture_time_ms, false); |
| |
| // Process send bucket. Packet should now be sent. |
| 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::RTPHeader rtp_header; |
| RtpHeaderExtensionMap map; |
| map.Register(kRtpExtensionTransmissionTimeOffset, |
| kTransmissionTimeOffsetExtensionId); |
| map.Register(kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId); |
| 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); |
| uint64_t expected_send_time = |
| ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds()); |
| EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime); |
| } |
| |
| // This test sends 1 regular video packet, then 4 padding packets, and then |
| // 1 more regular packet. |
| TEST_F(RtpSenderTest, SendPadding) { |
| // Make all (non-padding) packets go to send queue. |
| EXPECT_CALL(mock_paced_sender_, |
| SendPacket(PacedSender::kNormalPriority, _, _, _, _, _)). |
| WillRepeatedly(testing::Return(false)); |
| |
| uint16_t seq_num = kSeqNum; |
| uint32_t timestamp = kTimestamp; |
| rtp_sender_->SetStorePacketsStatus(true, 10); |
| int rtp_header_len = 12; |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); |
| rtp_header_len += 4; // 4 bytes extension. |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); |
| rtp_header_len += 4; // 4 bytes extension. |
| rtp_header_len += 4; // 4 extra bytes common to all extension headers. |
| |
| // Create and set up parser. |
| scoped_ptr<webrtc::RtpHeaderParser> rtp_parser( |
| webrtc::RtpHeaderParser::Create()); |
| ASSERT_TRUE(rtp_parser.get() != NULL); |
| rtp_parser->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset, |
| kTransmissionTimeOffsetExtensionId); |
| rtp_parser->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime, |
| kAbsoluteSendTimeExtensionId); |
| webrtc::RTPHeader rtp_header; |
| |
| rtp_sender_->SetTargetSendBitrate(300000); |
| int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); |
| int32_t rtp_length = rtp_sender_->BuildRTPheader(packet_, |
| kPayload, |
| kMarkerBit, |
| timestamp, |
| capture_time_ms); |
| |
| // Packet should be stored in a send bucket. |
| EXPECT_EQ(0, rtp_sender_->SendToNetwork(packet_, |
| 0, |
| rtp_length, |
| capture_time_ms, |
| kAllowRetransmission, |
| PacedSender::kNormalPriority)); |
| |
| int total_packets_sent = 0; |
| EXPECT_EQ(total_packets_sent, transport_.packets_sent_); |
| |
| const int kStoredTimeInMs = 100; |
| fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); |
| rtp_sender_->TimeToSendPacket(seq_num++, capture_time_ms, false); |
| // Packet should now be sent. This test doesn't verify the regular video |
| // packet, since it is tested in another test. |
| EXPECT_EQ(++total_packets_sent, transport_.packets_sent_); |
| timestamp += 90 * kStoredTimeInMs; |
| |
| // Send padding 4 times, waiting 50 ms between each. |
| for (int i = 0; i < 4; ++i) { |
| const int kPaddingPeriodMs = 50; |
| const int kPaddingBytes = 100; |
| const int kMaxPaddingLength = 224; // Value taken from rtp_sender.cc. |
| // Padding will be forced to full packets. |
| EXPECT_EQ(kMaxPaddingLength, rtp_sender_->TimeToSendPadding(kPaddingBytes)); |
| |
| // Process send bucket. Padding should now be sent. |
| EXPECT_EQ(++total_packets_sent, transport_.packets_sent_); |
| EXPECT_EQ(kMaxPaddingLength + rtp_header_len, |
| transport_.last_sent_packet_len_); |
| // Parse sent packet. |
| ASSERT_TRUE(rtp_parser->Parse(transport_.last_sent_packet_, kPaddingBytes, |
| &rtp_header)); |
| |
| // Verify sequence number and timestamp. |
| EXPECT_EQ(seq_num++, rtp_header.sequenceNumber); |
| EXPECT_EQ(timestamp, rtp_header.timestamp); |
| // Verify transmission time offset. |
| EXPECT_EQ(0, rtp_header.extension.transmissionTimeOffset); |
| uint64_t expected_send_time = |
| ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds()); |
| EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime); |
| fake_clock_.AdvanceTimeMilliseconds(kPaddingPeriodMs); |
| timestamp += 90 * kPaddingPeriodMs; |
| } |
| |
| // Send a regular video packet again. |
| capture_time_ms = fake_clock_.TimeInMilliseconds(); |
| rtp_length = rtp_sender_->BuildRTPheader(packet_, |
| kPayload, |
| kMarkerBit, |
| timestamp, |
| capture_time_ms); |
| |
| // Packet should be stored in a send bucket. |
| EXPECT_EQ(0, rtp_sender_->SendToNetwork(packet_, |
| 0, |
| rtp_length, |
| capture_time_ms, |
| kAllowRetransmission, |
| PacedSender::kNormalPriority)); |
| |
| rtp_sender_->TimeToSendPacket(seq_num, capture_time_ms, false); |
| // Process send bucket. |
| EXPECT_EQ(++total_packets_sent, transport_.packets_sent_); |
| EXPECT_EQ(rtp_length, transport_.last_sent_packet_len_); |
| // Parse sent packet. |
| ASSERT_TRUE(rtp_parser->Parse(transport_.last_sent_packet_, rtp_length, |
| &rtp_header)); |
| |
| // Verify sequence number and timestamp. |
| EXPECT_EQ(seq_num, rtp_header.sequenceNumber); |
| EXPECT_EQ(timestamp, rtp_header.timestamp); |
| // Verify transmission time offset. This packet is sent without delay. |
| EXPECT_EQ(0, rtp_header.extension.transmissionTimeOffset); |
| uint64_t expected_send_time = |
| ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds()); |
| EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime); |
| } |
| |
| TEST_F(RtpSenderTest, SendGenericVideo) { |
| char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC"; |
| const uint8_t payload_type = 127; |
| ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000, |
| 0, 1500)); |
| uint8_t payload[] = {47, 11, 32, 93, 89}; |
| |
| // Send keyframe |
| ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kVideoFrameKey, payload_type, 1234, |
| 4321, payload, sizeof(payload), |
| NULL)); |
| |
| ModuleRTPUtility::RTPHeaderParser rtp_parser(transport_.last_sent_packet_, |
| transport_.last_sent_packet_len_); |
| webrtc::RTPHeader rtp_header; |
| ASSERT_TRUE(rtp_parser.Parse(rtp_header)); |
| |
| const uint8_t* payload_data = GetPayloadData(rtp_header, |
| transport_.last_sent_packet_); |
| uint8_t generic_header = *payload_data++; |
| |
| ASSERT_EQ(sizeof(payload) + sizeof(generic_header), |
| GetPayloadDataLength(rtp_header, transport_.last_sent_packet_len_)); |
| |
| EXPECT_TRUE(generic_header & RtpFormatVideoGeneric::kKeyFrameBit); |
| EXPECT_TRUE(generic_header & RtpFormatVideoGeneric::kFirstPacketBit); |
| |
| EXPECT_EQ(0, memcmp(payload, payload_data, sizeof(payload))); |
| |
| // Send delta frame |
| payload[0] = 13; |
| payload[1] = 42; |
| payload[4] = 13; |
| |
| ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kVideoFrameDelta, payload_type, |
| 1234, 4321, payload, |
| sizeof(payload), NULL)); |
| |
| ModuleRTPUtility::RTPHeaderParser rtp_parser2(transport_.last_sent_packet_, |
| transport_.last_sent_packet_len_); |
| ASSERT_TRUE(rtp_parser.Parse(rtp_header)); |
| |
| payload_data = GetPayloadData(rtp_header, transport_.last_sent_packet_); |
| generic_header = *payload_data++; |
| |
| EXPECT_FALSE(generic_header & RtpFormatVideoGeneric::kKeyFrameBit); |
| EXPECT_TRUE(generic_header & RtpFormatVideoGeneric::kFirstPacketBit); |
| |
| ASSERT_EQ(sizeof(payload) + sizeof(generic_header), |
| GetPayloadDataLength(rtp_header, transport_.last_sent_packet_len_)); |
| |
| EXPECT_EQ(0, memcmp(payload, payload_data, sizeof(payload))); |
| } |
| |
| class RtpSenderAudioTest : public RtpSenderTest { |
| protected: |
| RtpSenderAudioTest() {} |
| |
| virtual void SetUp() { |
| payload_ = kAudioPayload; |
| rtp_sender_.reset(new RTPSender(0, true, &fake_clock_, &transport_, NULL, |
| &mock_paced_sender_)); |
| rtp_sender_->SetSequenceNumber(kSeqNum); |
| } |
| }; |
| |
| TEST_F(RtpSenderAudioTest, BuildRTPPacketWithAudioLevelExtension) { |
| EXPECT_EQ(0, rtp_sender_->SetAudioLevelIndicationStatus(true, |
| kAudioLevelExtensionId)); |
| EXPECT_EQ(0, rtp_sender_->SetAudioLevel(kAudioLevel)); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionAudioLevel, kAudioLevelExtensionId)); |
| |
| int32_t length = rtp_sender_->BuildRTPheader(packet_, |
| kAudioPayload, |
| kMarkerBit, |
| kTimestamp, |
| 0); |
| EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length); |
| |
| // Currently, no space is added by for header extension by BuildRTPHeader(). |
| EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength()); |
| |
| // Verify |
| webrtc::ModuleRTPUtility::RTPHeaderParser rtp_parser(packet_, length); |
| webrtc::RTPHeader rtp_header; |
| |
| RtpHeaderExtensionMap map; |
| map.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId); |
| 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.headerLength); |
| // TODO(solenberg): Should verify that we got audio level in header extension. |
| |
| // Parse without map extension |
| webrtc::RTPHeader 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.headerLength); |
| // TODO(solenberg): Should verify that we didn't get audio level. |
| EXPECT_EQ(0, rtp_sender_->SetAudioLevelIndicationStatus(false, 0)); |
| } |
| |
| TEST_F(RtpSenderAudioTest, SendAudio) { |
| char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME"; |
| const uint8_t payload_type = 127; |
| ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 48000, |
| 0, 1500)); |
| uint8_t payload[] = {47, 11, 32, 93, 89}; |
| |
| ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kAudioFrameCN, payload_type, 1234, |
| 4321, payload, sizeof(payload), |
| NULL)); |
| |
| ModuleRTPUtility::RTPHeaderParser rtp_parser(transport_.last_sent_packet_, |
| transport_.last_sent_packet_len_); |
| webrtc::RTPHeader rtp_header; |
| ASSERT_TRUE(rtp_parser.Parse(rtp_header)); |
| |
| const uint8_t* payload_data = GetPayloadData(rtp_header, |
| transport_.last_sent_packet_); |
| |
| ASSERT_EQ(sizeof(payload), GetPayloadDataLength(rtp_header, |
| transport_.last_sent_packet_len_)); |
| |
| EXPECT_EQ(0, memcmp(payload, payload_data, sizeof(payload))); |
| } |
| |
| TEST_F(RtpSenderAudioTest, SendAudioWithAudioLevelExtension) { |
| EXPECT_EQ(0, rtp_sender_->SetAudioLevelIndicationStatus(true, |
| kAudioLevelExtensionId)); |
| EXPECT_EQ(0, rtp_sender_->SetAudioLevel(kAudioLevel)); |
| EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( |
| kRtpExtensionAudioLevel, kAudioLevelExtensionId)); |
| |
| char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME"; |
| const uint8_t payload_type = 127; |
| ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 48000, |
| 0, 1500)); |
| uint8_t payload[] = {47, 11, 32, 93, 89}; |
| |
| ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kAudioFrameCN, payload_type, 1234, |
| 4321, payload, sizeof(payload), |
| NULL)); |
| |
| ModuleRTPUtility::RTPHeaderParser rtp_parser(transport_.last_sent_packet_, |
| transport_.last_sent_packet_len_); |
| webrtc::RTPHeader rtp_header; |
| ASSERT_TRUE(rtp_parser.Parse(rtp_header)); |
| |
| const uint8_t* payload_data = GetPayloadData(rtp_header, |
| transport_.last_sent_packet_); |
| |
| ASSERT_EQ(sizeof(payload), GetPayloadDataLength( |
| rtp_header, transport_.last_sent_packet_len_)); |
| |
| EXPECT_EQ(0, memcmp(payload, payload_data, sizeof(payload))); |
| |
| uint8_t extension[] = { 0xbe, 0xde, 0x00, 0x01, |
| (kAudioLevelExtensionId << 4) + 0, // ID + length. |
| kAudioLevel, // Data. |
| 0x00, 0x00 // Padding. |
| }; |
| |
| EXPECT_EQ(0, memcmp(extension, payload_data - sizeof(extension), |
| sizeof(extension))); |
| EXPECT_EQ(0, rtp_sender_->SetAudioLevelIndicationStatus(false, 0)); |
| } |
| |
| } // namespace webrtc |