From 8d0cd07d0c5e30eacaac4c118f9fd624b11e67ab Mon Sep 17 00:00:00 2001 From: "stefan@webrtc.org" Date: Mon, 3 Dec 2012 14:01:46 +0000 Subject: [PATCH] Add test to verify that padding only frames are passing through the RTP module. Review URL: https://webrtc-codereview.appspot.com/934023 git-svn-id: http://webrtc.googlecode.com/svn/trunk@3224 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/modules/modules.gyp | 1 - webrtc/modules/rtp_rtcp/source/rtcp_sender.cc | 6 + .../rtp_rtcp/source/rtp_rtcp_tests.gypi | 6 + .../modules/rtp_rtcp/test/testAPI/test_api.cc | 2 +- .../rtp_rtcp/test/testAPI/test_api.gypi | 42 ----- .../modules/rtp_rtcp/test/testAPI/test_api.h | 31 +++- .../rtp_rtcp/test/testAPI/test_api_audio.cc | 1 - .../rtp_rtcp/test/testAPI/test_api_rtcp.cc | 13 +- .../rtp_rtcp/test/testAPI/test_api_video.cc | 165 +++++++++++++----- 9 files changed, 166 insertions(+), 101 deletions(-) delete mode 100644 webrtc/modules/rtp_rtcp/test/testAPI/test_api.gypi diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index 324435724..29d03ec44 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -45,7 +45,6 @@ 'audio_processing/audio_processing_tests.gypi', 'rtp_rtcp/source/rtp_rtcp_tests.gypi', 'rtp_rtcp/test/testFec/test_fec.gypi', - 'rtp_rtcp/test/testAPI/test_api.gypi', 'video_coding/main/source/video_coding_test.gypi', 'video_coding/codecs/test/video_codecs_test_framework.gypi', 'video_coding/codecs/tools/video_codecs_tools.gypi', diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc index 789eaf1b5..051fc448c 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc @@ -522,6 +522,12 @@ WebRtc_Word32 RTCPSender::AddReportBlock(const WebRtc_UWord32 SSRC, "%s invalid argument", __FUNCTION__); return -1; } + std::map::iterator it = + _reportBlocks.find(SSRC); + if (it != _reportBlocks.end()) { + delete it->second; + _reportBlocks.erase(it); + } RTCPReportBlock* copyReportBlock = new RTCPReportBlock(); memcpy(copyReportBlock, reportBlock, sizeof(RTCPReportBlock)); _reportBlocks[SSRC] = copyReportBlock; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_tests.gypi b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_tests.gypi index 74f9a2d6e..4ca681986 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_tests.gypi +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_tests.gypi @@ -22,6 +22,12 @@ '../../../', ], 'sources': [ + '../test/testAPI/test_api.cc', + '../test/testAPI/test_api.h', + '../test/testAPI/test_api_audio.cc', + '../test/testAPI/test_api_nack.cc', + '../test/testAPI/test_api_rtcp.cc', + '../test/testAPI/test_api_video.cc', 'fec_test_helper.cc', 'fec_test_helper.h', 'producer_fec_unittest.cc', diff --git a/webrtc/modules/rtp_rtcp/test/testAPI/test_api.cc b/webrtc/modules/rtp_rtcp/test/testAPI/test_api.cc index f2fe14465..3503af223 100644 --- a/webrtc/modules/rtp_rtcp/test/testAPI/test_api.cc +++ b/webrtc/modules/rtp_rtcp/test/testAPI/test_api.cc @@ -24,7 +24,7 @@ class RtpRtcpAPITest : public ::testing::Test { protected: RtpRtcpAPITest() { test_CSRC[0] = 1234; - test_CSRC[2] = 2345; + test_CSRC[1] = 2345; test_id = 123; test_ssrc = 3456; test_timestamp = 4567; diff --git a/webrtc/modules/rtp_rtcp/test/testAPI/test_api.gypi b/webrtc/modules/rtp_rtcp/test/testAPI/test_api.gypi deleted file mode 100644 index eaa3a7202..000000000 --- a/webrtc/modules/rtp_rtcp/test/testAPI/test_api.gypi +++ /dev/null @@ -1,42 +0,0 @@ -# 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. - -{ - 'targets': [ - { - 'target_name': 'test_rtp_rtcp_api', - 'type': 'executable', - 'dependencies': [ - 'rtp_rtcp', - '<(webrtc_root)/test/test.gyp:test_support_main', - '<(DEPTH)/testing/gtest.gyp:gtest', - ], - - 'include_dirs': [ - '../../interface', - '../../source', - '../../../../system_wrappers/interface', - ], - - 'sources': [ - 'test_api.cc', - 'test_api_audio.cc', - 'test_api_nack.cc', - 'test_api_rtcp.cc', - 'test_api_video.cc', - ], - - }, - ], -} - -# Local Variables: -# tab-width:2 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/webrtc/modules/rtp_rtcp/test/testAPI/test_api.h b/webrtc/modules/rtp_rtcp/test/testAPI/test_api.h index 6261d7f13..3e4f2d64f 100644 --- a/webrtc/modules/rtp_rtcp/test/testAPI/test_api.h +++ b/webrtc/modules/rtp_rtcp/test/testAPI/test_api.h @@ -77,12 +77,35 @@ class LoopBackTransport : public webrtc::Transport { class RtpReceiver : public RtpData { public: - virtual WebRtc_Word32 OnReceivedPayloadData( - const WebRtc_UWord8* payloadData, - const WebRtc_UWord16 payloadSize, - const webrtc::WebRtcRTPHeader* rtpHeader) { + enum { kMaxPayloadSize = 1500 }; + + virtual WebRtc_Word32 OnReceivedPayloadData( + const WebRtc_UWord8* payloadData, + const WebRtc_UWord16 payloadSize, + const webrtc::WebRtcRTPHeader* rtpHeader) { + EXPECT_LE(payloadSize, kMaxPayloadSize); + memcpy(_payloadData, payloadData, payloadSize); + memcpy(&_rtpHeader, rtpHeader, sizeof(_rtpHeader)); + _payloadSize = payloadSize; return 0; } + + const WebRtc_UWord8* payload_data() const { + return _payloadData; + } + + WebRtc_UWord16 payload_size() const { + return _payloadSize; + } + + webrtc::WebRtcRTPHeader rtp_header() const { + return _rtpHeader; + } + + private: + WebRtc_UWord8 _payloadData[kMaxPayloadSize]; + WebRtc_UWord16 _payloadSize; + webrtc::WebRtcRTPHeader _rtpHeader; }; } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/test/testAPI/test_api_audio.cc b/webrtc/modules/rtp_rtcp/test/testAPI/test_api_audio.cc index bf88ace97..ce899d7f0 100644 --- a/webrtc/modules/rtp_rtcp/test/testAPI/test_api_audio.cc +++ b/webrtc/modules/rtp_rtcp/test/testAPI/test_api_audio.cc @@ -328,5 +328,4 @@ TEST_F(RtpRtcpAudioTest, DTMF) { fake_clock.IncrementTime(20); module1->Process(); } - delete audioFeedback; } diff --git a/webrtc/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc b/webrtc/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc index 833f8675c..d25d4cb09 100644 --- a/webrtc/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc +++ b/webrtc/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc @@ -10,10 +10,10 @@ #include #include -#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "test_api.h" - #include "common_types.h" #include "rtp_rtcp.h" #include "rtp_rtcp_defines.h" @@ -80,7 +80,7 @@ class RtpRtcpRtcpTest : public ::testing::Test { protected: RtpRtcpRtcpTest() { test_CSRC[0] = 1234; - test_CSRC[2] = 2345; + test_CSRC[1] = 2345; test_id = 123; test_ssrc = 3456; test_timestamp = 4567; @@ -97,11 +97,12 @@ class RtpRtcpRtcpTest : public ::testing::Test { RtpRtcp::Configuration configuration; configuration.id = test_id; - configuration.audio = false; + configuration.audio = true; configuration.clock = &fake_clock; configuration.outgoing_transport = transport1; configuration.rtcp_feedback = myRTCPFeedback1; configuration.intra_frame_callback = myRTCPFeedback1; + configuration.incoming_data = receiver; module1 = RtpRtcp::CreateRtpRtcp(configuration); @@ -150,6 +151,8 @@ class RtpRtcpRtcpTest : public ::testing::Test { virtual void TearDown() { delete module1; delete module2; + delete myRTCPFeedback1; + delete myRTCPFeedback2; delete transport1; delete transport2; delete receiver; @@ -217,6 +220,8 @@ TEST_F(RtpRtcpRtcpTest, RTCP_CNAME) { TEST_F(RtpRtcpRtcpTest, RTCP) { RTCPReportBlock reportBlock; + reportBlock.remoteSSRC = 1; + reportBlock.sourceSSRC = 2; reportBlock.cumulativeLost = 1; reportBlock.delaySinceLastSR = 2; reportBlock.extendedHighSeqNum = 3; diff --git a/webrtc/modules/rtp_rtcp/test/testAPI/test_api_video.cc b/webrtc/modules/rtp_rtcp/test/testAPI/test_api_video.cc index fdd3ed30e..7a9d3dbb0 100644 --- a/webrtc/modules/rtp_rtcp/test/testAPI/test_api_video.cc +++ b/webrtc/modules/rtp_rtcp/test/testAPI/test_api_video.cc @@ -8,88 +8,157 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include + #include #include -#include -#include "test_api.h" +#include "gtest/gtest.h" +#include "webrtc/common_types.h" +#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h" +#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" +#include "webrtc/modules/rtp_rtcp/test/testAPI/test_api.h" -#include "common_types.h" -#include "rtp_rtcp.h" -#include "rtp_rtcp_defines.h" - -using namespace webrtc; +namespace webrtc { class RtpRtcpVideoTest : public ::testing::Test { protected: - RtpRtcpVideoTest() { - test_id = 123; - test_ssrc = 3456; - test_timestamp = 4567; - test_sequence_number = 2345; + RtpRtcpVideoTest() + : test_id_(123), + test_ssrc_(3456), + test_timestamp_(4567), + test_sequence_number_(2345) { } ~RtpRtcpVideoTest() {} virtual void SetUp() { - transport = new LoopBackTransport(); - receiver = new RtpReceiver(); + transport_ = new LoopBackTransport(); + receiver_ = new RtpReceiver(); RtpRtcp::Configuration configuration; - configuration.id = test_id; + configuration.id = test_id_; configuration.audio = false; configuration.clock = &fake_clock; - configuration.incoming_data = receiver; - configuration.outgoing_transport = transport; + configuration.incoming_data = receiver_; + configuration.outgoing_transport = transport_; - video_module = RtpRtcp::CreateRtpRtcp(configuration); + video_module_ = RtpRtcp::CreateRtpRtcp(configuration); - EXPECT_EQ(0, video_module->SetRTCPStatus(kRtcpCompound)); - EXPECT_EQ(0, video_module->SetSSRC(test_ssrc)); - EXPECT_EQ(0, video_module->SetNACKStatus(kNackRtcp)); - EXPECT_EQ(0, video_module->SetStorePacketsStatus(true)); - EXPECT_EQ(0, video_module->SetSendingStatus(true)); + EXPECT_EQ(0, video_module_->SetRTCPStatus(kRtcpCompound)); + EXPECT_EQ(0, video_module_->SetSSRC(test_ssrc_)); + EXPECT_EQ(0, video_module_->SetNACKStatus(kNackRtcp)); + EXPECT_EQ(0, video_module_->SetStorePacketsStatus(true)); + EXPECT_EQ(0, video_module_->SetSendingStatus(true)); - transport->SetSendModule(video_module); + transport_->SetSendModule(video_module_); VideoCodec video_codec; memset(&video_codec, 0, sizeof(video_codec)); video_codec.plType = 123; memcpy(video_codec.plName, "I420", 5); - EXPECT_EQ(0, video_module->RegisterSendPayload(video_codec)); - EXPECT_EQ(0, video_module->RegisterReceivePayload(video_codec)); + EXPECT_EQ(0, video_module_->RegisterSendPayload(video_codec)); + EXPECT_EQ(0, video_module_->RegisterReceivePayload(video_codec)); - payload_data_length = sizeof(payload_data); + payload_data_length_ = sizeof(video_frame_); - for (int n = 0; n < payload_data_length; n++) { - payload_data[n] = n%10; + for (int n = 0; n < payload_data_length_; n++) { + video_frame_[n] = n%10; } } - virtual void TearDown() { - delete video_module; - delete transport; - delete receiver; + WebRtc_Word32 BuildRTPheader(WebRtc_UWord8* dataBuffer, + WebRtc_UWord32 timestamp, + WebRtc_UWord32 sequence_number) { + dataBuffer[0] = static_cast(0x80); // version 2 + dataBuffer[1] = static_cast(kPayloadType); + ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer + 2, + sequence_number); + ModuleRTPUtility::AssignUWord32ToBuffer(dataBuffer + 4, timestamp); + ModuleRTPUtility::AssignUWord32ToBuffer(dataBuffer + 8, + 0x1234); // SSRC. + WebRtc_Word32 rtpHeaderLength = 12; + return rtpHeaderLength; } - int test_id; - RtpRtcp* video_module; - LoopBackTransport* transport; - RtpReceiver* receiver; - WebRtc_UWord32 test_ssrc; - WebRtc_UWord32 test_timestamp; - WebRtc_UWord16 test_sequence_number; - WebRtc_UWord8 payload_data[65000]; - int payload_data_length; + int PaddingPacket(uint8_t* buffer, + WebRtc_UWord32 timestamp, + WebRtc_UWord32 sequence_number, + WebRtc_Word32 bytes) { + // Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP. + int max_length = 224; + + int padding_bytes_in_packet = max_length; + if (bytes < max_length) { + padding_bytes_in_packet = (bytes + 16) & 0xffe0; // Keep our modulus 32. + } + // Correct seq num, timestamp and payload type. + int header_length = BuildRTPheader(buffer, timestamp, + sequence_number); + buffer[0] |= 0x20; // Set padding bit. + WebRtc_Word32* data = + reinterpret_cast(&(buffer[header_length])); + + // Fill data buffer with random data. + for (int j = 0; j < (padding_bytes_in_packet >> 2); j++) { + data[j] = rand(); // NOLINT + } + // Set number of padding bytes in the last byte of the packet. + buffer[header_length + padding_bytes_in_packet - 1] = + padding_bytes_in_packet; + return padding_bytes_in_packet + header_length; + } + + virtual void TearDown() { + delete video_module_; + delete transport_; + delete receiver_; + } + + int test_id_; + RtpRtcp* video_module_; + LoopBackTransport* transport_; + RtpReceiver* receiver_; + WebRtc_UWord32 test_ssrc_; + WebRtc_UWord32 test_timestamp_; + WebRtc_UWord16 test_sequence_number_; + WebRtc_UWord8 video_frame_[65000]; + int payload_data_length_; FakeRtpRtcpClock fake_clock; + enum { kPayloadType = 100 }; }; TEST_F(RtpRtcpVideoTest, BasicVideo) { WebRtc_UWord32 timestamp = 3000; - EXPECT_EQ(0, video_module->SendOutgoingData(webrtc::kVideoFrameDelta, 123, - timestamp, - timestamp / 90, - payload_data, - payload_data_length)); - + EXPECT_EQ(0, video_module_->SendOutgoingData(kVideoFrameDelta, 123, + timestamp, + timestamp / 90, + video_frame_, + payload_data_length_)); } +TEST_F(RtpRtcpVideoTest, PaddingOnlyFrames) { + const int kPadSize = 255; + uint8_t padding_packet[kPadSize]; + uint32_t seq_num = 0; + uint32_t timestamp = 3000; + VideoCodec codec; + codec.codecType = kVideoCodecVP8; + codec.plType = kPayloadType; + strncpy(codec.plName, "VP8", 4); + EXPECT_EQ(0, video_module_->RegisterReceivePayload(codec)); + for (int frame_idx = 0; frame_idx < 10; ++frame_idx) { + for (int packet_idx = 0; packet_idx < 5; ++packet_idx) { + int packet_size = PaddingPacket(padding_packet, timestamp, seq_num, + kPadSize); + ++seq_num; + EXPECT_EQ(0, video_module_->IncomingPacket(padding_packet, packet_size)); + EXPECT_EQ(0, receiver_->payload_size()); + EXPECT_EQ(packet_size - 12, receiver_->rtp_header().header.paddingLength); + } + timestamp += 3000; + fake_clock.IncrementTime(33); + } +} + +} // namespace webrtc