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/webrtc@4715 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/video_engine/test/send_stream_tests.cc b/video_engine/test/send_stream_tests.cc
index dcf2ec1..8117e75 100644
--- a/video_engine/test/send_stream_tests.cc
+++ b/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 @@
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 @@
scoped_ptr<Call> 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 @@
scoped_ptr<Call> 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<NackObserver*>(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<const uint8_t*>(data), static_cast<size_t>(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<int>(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<ThreadWrapper> 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(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