From df531a2eeeaf27e51c5467fd079098f20eed0612 Mon Sep 17 00:00:00 2001 From: "pbos@webrtc.org" Date: Tue, 10 Sep 2013 14:56:33 +0000 Subject: [PATCH] Test that VideoSendStream responds to NACK. BUG=2228 R=stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/2194006 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4715 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/video_engine/test/send_stream_tests.cc | 96 ++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/webrtc/video_engine/test/send_stream_tests.cc b/webrtc/video_engine/test/send_stream_tests.cc index dcf2ec168..8117e75c5 100644 --- a/webrtc/video_engine/test/send_stream_tests.cc +++ b/webrtc/video_engine/test/send_stream_tests.cc @@ -9,9 +9,11 @@ */ #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" +#include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h" #include "webrtc/system_wrappers/interface/event_wrapper.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/system_wrappers/interface/thread_wrapper.h" #include "webrtc/video_engine/test/common/fake_encoder.h" #include "webrtc/video_engine/test/common/frame_generator.h" #include "webrtc/video_engine/test/common/frame_generator_capturer.h" @@ -67,6 +69,7 @@ class VideoSendStreamTest : public ::testing::Test { VideoSendStream::Config config = call->GetDefaultSendConfig(); config.encoder = &fake_encoder_; config.internal_source = false; + config.rtp.ssrcs.push_back(kSendSsrc); test::FakeEncoder::SetCodecSettings(&config.codec, 1); return config; } @@ -97,7 +100,6 @@ TEST_F(VideoSendStreamTest, SendsSetSsrc) { scoped_ptr call(Call::Create(call_config)); VideoSendStream::Config send_config = GetSendTestConfig(call.get()); - send_config.rtp.ssrcs.push_back(kSendSsrc); RunSendTest(call.get(), send_config, &observer); } @@ -130,10 +132,100 @@ TEST_F(VideoSendStreamTest, SupportsCName) { scoped_ptr call(Call::Create(call_config)); VideoSendStream::Config send_config = GetSendTestConfig(call.get()); - send_config.rtp.ssrcs.push_back(kSendSsrc); send_config.rtp.c_name = kCName; RunSendTest(call.get(), send_config, &observer); } +TEST_F(VideoSendStreamTest, RespondsToNack) { + class NackObserver : public SendTransportObserver, webrtc::Transport { + public: + NackObserver() + : SendTransportObserver(30 * 1000), + thread_(ThreadWrapper::CreateThread(NackProcess, this)), + send_call_receiver_(NULL), + send_count_(0), + ssrc_(0), + nacked_sequence_number_(0) {} + + ~NackObserver() { + EXPECT_TRUE(thread_->Stop()); + } + + void SetReceiver(PacketReceiver* send_call_receiver) { + send_call_receiver_ = send_call_receiver; + } + + // Sending NACKs must be done from a different "network" thread to prevent + // violating locking orders. With this no locks are held prior to inserting + // packets back into the sender. + static bool NackProcess(void* observer) { + return static_cast(observer)->SendNack(); + } + + bool SendNack() { + NullReceiveStatistics null_stats; + RTCPSender rtcp_sender(0, false, Clock::GetRealTimeClock(), &null_stats); + EXPECT_EQ(0, rtcp_sender.RegisterSendTransport(this)); + + rtcp_sender.SetRTCPStatus(kRtcpNonCompound); + rtcp_sender.SetRemoteSSRC(ssrc_); + + RTCPSender::FeedbackState feedback_state; + EXPECT_EQ(0, rtcp_sender.SendRTCP( + feedback_state, kRtcpNack, 1, &nacked_sequence_number_)); + return false; + } + + virtual int SendPacket(int channel, const void* data, int len) OVERRIDE { + ADD_FAILURE() + << "This should never be reached. Only a NACK should be sent."; + return -1; + } + + virtual int SendRTCPPacket(int channel, + const void* data, + int len) OVERRIDE { + EXPECT_TRUE(send_call_receiver_->DeliverPacket( + static_cast(data), static_cast(len))); + return len; + } + + virtual bool SendRTP(const uint8_t* packet, size_t length) OVERRIDE { + EXPECT_TRUE(send_call_receiver_ != NULL); + RTPHeader header; + EXPECT_TRUE( + rtp_header_parser_->Parse(packet, static_cast(length), &header)); + + // Nack second packet after receiving the third one. + if (++send_count_ == 3) { + ssrc_ = header.ssrc; + nacked_sequence_number_ = header.sequenceNumber - 1; + unsigned int id; + EXPECT_TRUE(thread_->Start(id)); + } + + if (header.sequenceNumber == nacked_sequence_number_) + send_test_complete_->Set(); + + return true; + } + private: + scoped_ptr thread_; + PacketReceiver* send_call_receiver_; + int send_count_; + uint32_t ssrc_; + uint16_t nacked_sequence_number_; + } observer; + + Call::Config call_config(&observer); + scoped_ptr call(Call::Create(call_config)); + observer.SetReceiver(call->Receiver()); + + VideoSendStream::Config send_config = GetSendTestConfig(call.get()); + send_config.rtp.nack.rtp_history_ms = 1000; + + RunSendTest(call.get(), send_config, &observer); +} + } // namespace webrtc