blob: c2e4b302554e8f2a09e055d226684f719874d5b0 [file] [log] [blame]
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +00001/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10#include "testing/gtest/include/gtest/gtest.h"
11#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +000012#include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h"
pbos@webrtc.org013d9942013-08-22 09:42:17 +000013#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +000014#include "webrtc/system_wrappers/interface/event_wrapper.h"
15#include "webrtc/system_wrappers/interface/scoped_ptr.h"
pbos@webrtc.org29023282013-09-11 10:14:56 +000016#include "webrtc/system_wrappers/interface/sleep.h"
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +000017#include "webrtc/system_wrappers/interface/thread_wrapper.h"
pbos@webrtc.org0e63e762013-09-20 11:56:26 +000018#include "webrtc/video_engine/internal/transport_adapter.h"
19#include "webrtc/video_engine/new_include/call.h"
20#include "webrtc/video_engine/new_include/video_send_stream.h"
21#include "webrtc/video_engine/test/common/direct_transport.h"
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +000022#include "webrtc/video_engine/test/common/fake_encoder.h"
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +000023#include "webrtc/video_engine/test/common/frame_generator_capturer.h"
24#include "webrtc/video_engine/test/common/null_transport.h"
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +000025
26namespace webrtc {
27
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +000028class SendTransportObserver : public test::NullTransport {
29 public:
30 explicit SendTransportObserver(unsigned long timeout_ms)
31 : rtp_header_parser_(RtpHeaderParser::Create()),
32 send_test_complete_(EventWrapper::Create()),
33 timeout_ms_(timeout_ms) {}
34
pbos@webrtc.org841c8a42013-09-09 15:04:25 +000035 EventTypeWrapper Wait() { return send_test_complete_->Wait(timeout_ms_); }
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +000036
37 protected:
38 scoped_ptr<RtpHeaderParser> rtp_header_parser_;
39 scoped_ptr<EventWrapper> send_test_complete_;
40
41 private:
42 unsigned long timeout_ms_;
43};
44
pbos@webrtc.org013d9942013-08-22 09:42:17 +000045class VideoSendStreamTest : public ::testing::Test {
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +000046 public:
47 VideoSendStreamTest() : fake_encoder_(Clock::GetRealTimeClock()) {}
pbos@webrtc.org841c8a42013-09-09 15:04:25 +000048
pbos@webrtc.org013d9942013-08-22 09:42:17 +000049 protected:
pbos@webrtc.org841c8a42013-09-09 15:04:25 +000050 void RunSendTest(Call* call,
pbos@webrtc.org74fa4892013-08-23 09:19:30 +000051 const VideoSendStream::Config& config,
pbos@webrtc.org013d9942013-08-22 09:42:17 +000052 SendTransportObserver* observer) {
pbos@webrtc.org74fa4892013-08-23 09:19:30 +000053 VideoSendStream* send_stream = call->CreateSendStream(config);
pbos@webrtc.org013d9942013-08-22 09:42:17 +000054 scoped_ptr<test::FrameGeneratorCapturer> frame_generator_capturer(
55 test::FrameGeneratorCapturer::Create(
andresp@webrtc.orgab654952013-09-19 12:14:03 +000056 send_stream->Input(), 320, 240, 30, Clock::GetRealTimeClock()));
pbos@webrtc.org013d9942013-08-22 09:42:17 +000057 send_stream->StartSend();
58 frame_generator_capturer->Start();
59
60 EXPECT_EQ(kEventSignaled, observer->Wait());
61
62 frame_generator_capturer->Stop();
63 send_stream->StopSend();
64 call->DestroySendStream(send_stream);
65 }
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +000066
pbos@webrtc.org841c8a42013-09-09 15:04:25 +000067 VideoSendStream::Config GetSendTestConfig(Call* call) {
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +000068 VideoSendStream::Config config = call->GetDefaultSendConfig();
69 config.encoder = &fake_encoder_;
70 config.internal_source = false;
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +000071 config.rtp.ssrcs.push_back(kSendSsrc);
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +000072 test::FakeEncoder::SetCodecSettings(&config.codec, 1);
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +000073 return config;
74 }
75
pbos@webrtc.org5860de02013-09-16 13:01:47 +000076 void TestNackRetransmission(uint32_t retransmit_ssrc);
77
pbos@webrtc.org0e63e762013-09-20 11:56:26 +000078 static const uint32_t kSendSsrc;
79 static const uint32_t kSendRtxSsrc;
80
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +000081 test::FakeEncoder fake_encoder_;
pbos@webrtc.org013d9942013-08-22 09:42:17 +000082};
83
84const uint32_t VideoSendStreamTest::kSendSsrc = 0xC0FFEE;
pbos@webrtc.org5860de02013-09-16 13:01:47 +000085const uint32_t VideoSendStreamTest::kSendRtxSsrc = 0xBADCAFE;
pbos@webrtc.org013d9942013-08-22 09:42:17 +000086
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +000087TEST_F(VideoSendStreamTest, SendsSetSsrc) {
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +000088 class SendSsrcObserver : public SendTransportObserver {
89 public:
90 SendSsrcObserver() : SendTransportObserver(30 * 1000) {}
91
92 virtual bool SendRTP(const uint8_t* packet, size_t length) OVERRIDE {
93 RTPHeader header;
94 EXPECT_TRUE(
95 rtp_header_parser_->Parse(packet, static_cast<int>(length), &header));
96
97 if (header.ssrc == kSendSsrc)
98 send_test_complete_->Set();
99
100 return true;
101 }
102 } observer;
103
pbos@webrtc.org841c8a42013-09-09 15:04:25 +0000104 Call::Config call_config(&observer);
105 scoped_ptr<Call> call(Call::Create(call_config));
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +0000106
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +0000107 VideoSendStream::Config send_config = GetSendTestConfig(call.get());
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +0000108
pbos@webrtc.org013d9942013-08-22 09:42:17 +0000109 RunSendTest(call.get(), send_config, &observer);
110}
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +0000111
pbos@webrtc.org013d9942013-08-22 09:42:17 +0000112TEST_F(VideoSendStreamTest, SupportsCName) {
113 static std::string kCName = "PjQatC14dGfbVwGPUOA9IH7RlsFDbWl4AhXEiDsBizo=";
114 class CNameObserver : public SendTransportObserver {
115 public:
116 CNameObserver() : SendTransportObserver(30 * 1000) {}
117
118 virtual bool SendRTCP(const uint8_t* packet, size_t length) OVERRIDE {
119 RTCPUtility::RTCPParserV2 parser(packet, length, true);
120 EXPECT_TRUE(parser.IsValid());
121
122 RTCPUtility::RTCPPacketTypes packet_type = parser.Begin();
123 while (packet_type != RTCPUtility::kRtcpNotValidCode) {
124 if (packet_type == RTCPUtility::kRtcpSdesChunkCode) {
125 EXPECT_EQ(parser.Packet().CName.CName, kCName);
126 send_test_complete_->Set();
127 }
128
129 packet_type = parser.Iterate();
130 }
131
132 return true;
133 }
134 } observer;
135
pbos@webrtc.org841c8a42013-09-09 15:04:25 +0000136 Call::Config call_config(&observer);
137 scoped_ptr<Call> call(Call::Create(call_config));
pbos@webrtc.org013d9942013-08-22 09:42:17 +0000138
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +0000139 VideoSendStream::Config send_config = GetSendTestConfig(call.get());
pbos@webrtc.org013d9942013-08-22 09:42:17 +0000140 send_config.rtp.c_name = kCName;
141
142 RunSendTest(call.get(), send_config, &observer);
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +0000143}
144
pbos@webrtc.org5c678ea2013-09-11 19:00:39 +0000145TEST_F(VideoSendStreamTest, SupportsAbsoluteSendTime) {
146 static const uint8_t kAbsSendTimeExtensionId = 13;
147 class AbsoluteSendTimeObserver : public SendTransportObserver {
148 public:
149 AbsoluteSendTimeObserver() : SendTransportObserver(30 * 1000) {
150 EXPECT_TRUE(rtp_header_parser_->RegisterRtpHeaderExtension(
151 kRtpExtensionAbsoluteSendTime, kAbsSendTimeExtensionId));
152 }
153
154 virtual bool SendRTP(const uint8_t* packet, size_t length) OVERRIDE {
155 RTPHeader header;
156 EXPECT_TRUE(
157 rtp_header_parser_->Parse(packet, static_cast<int>(length), &header));
158
159 if (header.extension.absoluteSendTime > 0)
160 send_test_complete_->Set();
161
162 return true;
163 }
164 } observer;
165
166 Call::Config call_config(&observer);
167 scoped_ptr<Call> call(Call::Create(call_config));
168
169 VideoSendStream::Config send_config = GetSendTestConfig(call.get());
170 send_config.rtp.extensions.push_back(
171 RtpExtension("abs-send-time", kAbsSendTimeExtensionId));
172
173 RunSendTest(call.get(), send_config, &observer);
174}
175
pbos@webrtc.org29023282013-09-11 10:14:56 +0000176TEST_F(VideoSendStreamTest, SupportsTransmissionTimeOffset) {
177 static const uint8_t kTOffsetExtensionId = 13;
178 class DelayedEncoder : public test::FakeEncoder {
179 public:
180 DelayedEncoder(Clock* clock) : test::FakeEncoder(clock) {}
181 virtual int32_t Encode(
182 const I420VideoFrame& input_image,
183 const CodecSpecificInfo* codec_specific_info,
184 const std::vector<VideoFrameType>* frame_types) OVERRIDE {
185 // A delay needs to be introduced to assure that we get a timestamp
186 // offset.
187 SleepMs(5);
188 return FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
189 }
190 } encoder(Clock::GetRealTimeClock());
191
192 class TransmissionTimeOffsetObserver : public SendTransportObserver {
193 public:
194 TransmissionTimeOffsetObserver() : SendTransportObserver(30 * 1000) {
195 EXPECT_TRUE(rtp_header_parser_->RegisterRtpHeaderExtension(
196 kRtpExtensionTransmissionTimeOffset, kTOffsetExtensionId));
197 }
198
199 virtual bool SendRTP(const uint8_t* packet, size_t length) OVERRIDE {
200 RTPHeader header;
201 EXPECT_TRUE(
202 rtp_header_parser_->Parse(packet, static_cast<int>(length), &header));
203
204 EXPECT_GT(header.extension.transmissionTimeOffset, 0);
205 send_test_complete_->Set();
206
207 return true;
208 }
209 } observer;
210
211 Call::Config call_config(&observer);
212 scoped_ptr<Call> call(Call::Create(call_config));
213
214 VideoSendStream::Config send_config = GetSendTestConfig(call.get());
215 send_config.encoder = &encoder;
216 send_config.rtp.extensions.push_back(
217 RtpExtension("toffset", kTOffsetExtensionId));
218
219 RunSendTest(call.get(), send_config, &observer);
220}
221
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000222class LossyReceiveStatistics : public NullReceiveStatistics {
223 public:
224 LossyReceiveStatistics(uint32_t send_ssrc,
225 uint32_t last_sequence_number,
226 uint32_t cumulative_lost,
227 uint8_t fraction_lost)
228 : lossy_stats_(new LossyStatistician(last_sequence_number,
229 cumulative_lost,
230 fraction_lost)) {
231 stats_map_[send_ssrc] = lossy_stats_.get();
232 }
233
234 virtual StatisticianMap GetActiveStatisticians() const OVERRIDE {
235 return stats_map_;
236 }
237
238 virtual StreamStatistician* GetStatistician(uint32_t ssrc) const OVERRIDE {
239 return lossy_stats_.get();
240 }
241
242 private:
243 class LossyStatistician : public StreamStatistician {
244 public:
245 LossyStatistician(uint32_t extended_max_sequence_number,
246 uint32_t cumulative_lost,
247 uint8_t fraction_lost) {
248 stats_.fraction_lost = fraction_lost;
249 stats_.cumulative_lost = cumulative_lost;
250 stats_.extended_max_sequence_number = extended_max_sequence_number;
251 }
252 virtual bool GetStatistics(Statistics* statistics, bool reset) OVERRIDE {
253 *statistics = stats_;
254 return true;
255 }
256 virtual void GetDataCounters(uint32_t* bytes_received,
257 uint32_t* packets_received) const OVERRIDE {
258 *bytes_received = 0;
259 *packets_received = 0;
260 }
261 virtual uint32_t BitrateReceived() const OVERRIDE { return 0; }
262 virtual void ResetStatistics() OVERRIDE {}
263 virtual bool IsRetransmitOfOldPacket(const RTPHeader& header,
264 int min_rtt) const OVERRIDE {
265 return false;
266 }
267
268 virtual bool IsPacketInOrder(uint16_t sequence_number) const OVERRIDE {
269 return true;
270 }
271 Statistics stats_;
272 };
273
274 scoped_ptr<LossyStatistician> lossy_stats_;
275 StatisticianMap stats_map_;
276};
277
278TEST_F(VideoSendStreamTest, SupportsFec) {
279 static const int kRedPayloadType = 118;
280 static const int kUlpfecPayloadType = 119;
281 class FecObserver : public SendTransportObserver {
282 public:
283 FecObserver()
284 : SendTransportObserver(30 * 1000),
285 transport_adapter_(&transport_),
286 send_count_(0),
287 received_media_(false),
288 received_fec_(false) {}
289
290 void SetReceiver(PacketReceiver* receiver) {
291 transport_.SetReceiver(receiver);
292 }
293
294 virtual bool SendRTP(const uint8_t* packet, size_t length) OVERRIDE {
295 RTPHeader header;
296 EXPECT_TRUE(
297 rtp_header_parser_->Parse(packet, static_cast<int>(length), &header));
298
299 // Send lossy receive reports to trigger FEC enabling.
300 if (send_count_++ % 2 != 0) {
301 // Receive statistics reporting having lost 50% of the packets.
302 LossyReceiveStatistics lossy_receive_stats(
303 kSendSsrc, header.sequenceNumber, send_count_ / 2, 127);
304 RTCPSender rtcp_sender(
305 0, false, Clock::GetRealTimeClock(), &lossy_receive_stats);
306 EXPECT_EQ(0, rtcp_sender.RegisterSendTransport(&transport_adapter_));
307
308 rtcp_sender.SetRTCPStatus(kRtcpNonCompound);
309 rtcp_sender.SetRemoteSSRC(kSendSsrc);
310
311 RTCPSender::FeedbackState feedback_state;
312
313 EXPECT_EQ(0, rtcp_sender.SendRTCP(feedback_state, kRtcpRr));
314 }
315
316 EXPECT_EQ(kRedPayloadType, header.payloadType);
317
318 uint8_t encapsulated_payload_type = packet[header.headerLength];
319
320 if (encapsulated_payload_type == kUlpfecPayloadType) {
321 received_fec_ = true;
322 } else {
323 received_media_ = true;
324 }
325
326 if (received_media_ && received_fec_)
327 send_test_complete_->Set();
328
329 return true;
330 }
331
332 private:
333 internal::TransportAdapter transport_adapter_;
334 test::DirectTransport transport_;
335 int send_count_;
336 bool received_media_;
337 bool received_fec_;
338 } observer;
339
340 Call::Config call_config(&observer);
341 scoped_ptr<Call> call(Call::Create(call_config));
342
343 observer.SetReceiver(call->Receiver());
344
345 VideoSendStream::Config send_config = GetSendTestConfig(call.get());
346 send_config.rtp.fec.red_payload_type = kRedPayloadType;
347 send_config.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
348
349 RunSendTest(call.get(), send_config, &observer);
350}
351
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000352void VideoSendStreamTest::TestNackRetransmission(uint32_t retransmit_ssrc) {
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000353 class NackObserver : public SendTransportObserver {
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000354 public:
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000355 NackObserver(uint32_t retransmit_ssrc)
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000356 : SendTransportObserver(30 * 1000),
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000357 transport_adapter_(&transport_),
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000358 send_count_(0),
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000359 retransmit_ssrc_(retransmit_ssrc),
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000360 nacked_sequence_number_(0) {}
361
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000362 void SetReceiver(PacketReceiver* receiver) {
363 transport_.SetReceiver(receiver);
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000364 }
365
366 virtual bool SendRTP(const uint8_t* packet, size_t length) OVERRIDE {
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000367 RTPHeader header;
368 EXPECT_TRUE(
369 rtp_header_parser_->Parse(packet, static_cast<int>(length), &header));
370
371 // Nack second packet after receiving the third one.
372 if (++send_count_ == 3) {
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000373 nacked_sequence_number_ = header.sequenceNumber - 1;
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000374 NullReceiveStatistics null_stats;
375 RTCPSender rtcp_sender(
376 0, false, Clock::GetRealTimeClock(), &null_stats);
377 EXPECT_EQ(0, rtcp_sender.RegisterSendTransport(&transport_adapter_));
378
379 rtcp_sender.SetRTCPStatus(kRtcpNonCompound);
380 rtcp_sender.SetRemoteSSRC(kSendSsrc);
381
382 RTCPSender::FeedbackState feedback_state;
383
384 EXPECT_EQ(0,
385 rtcp_sender.SendRTCP(
386 feedback_state, kRtcpNack, 1, &nacked_sequence_number_));
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000387 }
388
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000389 uint16_t sequence_number = header.sequenceNumber;
390
391 if (header.ssrc == retransmit_ssrc_ && retransmit_ssrc_ != kSendSsrc) {
392 // Not kSendSsrc, assume correct RTX packet. Extract sequence number.
393 const uint8_t* rtx_header = packet + header.headerLength;
394 sequence_number = (rtx_header[0] << 8) + rtx_header[1];
395 }
396
397 if (sequence_number == nacked_sequence_number_) {
398 EXPECT_EQ(retransmit_ssrc_, header.ssrc);
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000399 send_test_complete_->Set();
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000400 }
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000401
402 return true;
403 }
404 private:
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000405 internal::TransportAdapter transport_adapter_;
406 test::DirectTransport transport_;
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000407 int send_count_;
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000408 uint32_t retransmit_ssrc_;
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000409 uint16_t nacked_sequence_number_;
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000410 } observer(retransmit_ssrc);
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000411
412 Call::Config call_config(&observer);
413 scoped_ptr<Call> call(Call::Create(call_config));
414 observer.SetReceiver(call->Receiver());
415
416 VideoSendStream::Config send_config = GetSendTestConfig(call.get());
417 send_config.rtp.nack.rtp_history_ms = 1000;
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000418 if (retransmit_ssrc != kSendSsrc)
419 send_config.rtp.rtx.ssrcs.push_back(retransmit_ssrc);
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000420
421 RunSendTest(call.get(), send_config, &observer);
422}
423
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000424TEST_F(VideoSendStreamTest, RetransmitsNack) {
425 // Normal NACKs should use the send SSRC.
426 TestNackRetransmission(kSendSsrc);
427}
428
429TEST_F(VideoSendStreamTest, RetransmitsNackOverRtx) {
430 // NACKs over RTX should use a separate SSRC.
431 TestNackRetransmission(kSendRtxSsrc);
432}
433
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +0000434} // namespace webrtc