blob: bc0a1e011b88f117455ae9c6ecd6b0e9a2ec3c14 [file] [log] [blame]
pbos@webrtc.org1d096902013-12-13 12:48:05 +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 <assert.h>
11
12#include <algorithm>
13#include <sstream>
14#include <string>
15
16#include "testing/gtest/include/gtest/gtest.h"
17
18#include "webrtc/call.h"
henrik.lundin@webrtc.orged865b52014-03-06 10:28:07 +000019#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
pbos@webrtc.org1d096902013-12-13 12:48:05 +000020#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
21#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
22#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
wu@webrtc.org66773a02014-05-07 17:09:44 +000023#include "webrtc/system_wrappers/interface/rtp_to_ntp.h"
pbos@webrtc.org1d096902013-12-13 12:48:05 +000024#include "webrtc/system_wrappers/interface/scoped_ptr.h"
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +000025#include "webrtc/system_wrappers/interface/thread_annotations.h"
pbos@webrtc.org1d096902013-12-13 12:48:05 +000026#include "webrtc/test/direct_transport.h"
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +000027#include "webrtc/test/encoder_settings.h"
pbos@webrtc.org1d096902013-12-13 12:48:05 +000028#include "webrtc/test/fake_audio_device.h"
29#include "webrtc/test/fake_decoder.h"
30#include "webrtc/test/fake_encoder.h"
31#include "webrtc/test/frame_generator.h"
32#include "webrtc/test/frame_generator_capturer.h"
33#include "webrtc/test/rtp_rtcp_observer.h"
34#include "webrtc/test/testsupport/fileutils.h"
35#include "webrtc/test/testsupport/perf_test.h"
36#include "webrtc/video/transport_adapter.h"
37#include "webrtc/voice_engine/include/voe_base.h"
38#include "webrtc/voice_engine/include/voe_codec.h"
39#include "webrtc/voice_engine/include/voe_network.h"
40#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
41#include "webrtc/voice_engine/include/voe_video_sync.h"
42
43namespace webrtc {
44
45static unsigned int kLongTimeoutMs = 120 * 1000;
46static const uint32_t kSendSsrc = 0x654321;
47static const uint32_t kReceiverLocalSsrc = 0x123456;
48static const uint8_t kSendPayloadType = 125;
49
50class CallPerfTest : public ::testing::Test {
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000051 public:
52 CallPerfTest()
53 : send_stream_(NULL), fake_encoder_(Clock::GetRealTimeClock()) {}
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000054
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000055 protected:
56 VideoSendStream::Config GetSendTestConfig(Call* call) {
57 VideoSendStream::Config config = call->GetDefaultSendConfig();
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000058 config.rtp.ssrcs.push_back(kSendSsrc);
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +000059 config.encoder_settings = test::CreateEncoderSettings(
60 &fake_encoder_, "FAKE", kSendPayloadType, 1);
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000061 return config;
62 }
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000063
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000064 void RunVideoSendTest(Call* call,
65 const VideoSendStream::Config& config,
66 test::RtpRtcpObserver* observer) {
67 send_stream_ = call->CreateVideoSendStream(config);
68 scoped_ptr<test::FrameGeneratorCapturer> frame_generator_capturer(
69 test::FrameGeneratorCapturer::Create(
70 send_stream_->Input(), 320, 240, 30, Clock::GetRealTimeClock()));
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +000071 send_stream_->Start();
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000072 frame_generator_capturer->Start();
73
74 EXPECT_EQ(kEventSignaled, observer->Wait());
75
76 observer->StopSending();
77 frame_generator_capturer->Stop();
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +000078 send_stream_->Stop();
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000079 call->DestroyVideoSendStream(send_stream_);
80 }
81
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000082 void TestMinTransmitBitrate(bool pad_to_min_bitrate);
83
wu@webrtc.orgcd701192014-04-24 22:10:24 +000084 void TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config,
85 int threshold_ms,
86 int start_time_ms,
87 int run_time_ms);
88
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000089 VideoSendStream* send_stream_;
90 test::FakeEncoder fake_encoder_;
pbos@webrtc.org1d096902013-12-13 12:48:05 +000091};
92
93class SyncRtcpObserver : public test::RtpRtcpObserver {
94 public:
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000095 explicit SyncRtcpObserver(const FakeNetworkPipe::Config& config)
96 : test::RtpRtcpObserver(kLongTimeoutMs, config),
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +000097 crit_(CriticalSectionWrapper::CreateCriticalSection()) {}
pbos@webrtc.org1d096902013-12-13 12:48:05 +000098
99 virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
100 RTCPUtility::RTCPParserV2 parser(packet, length, true);
101 EXPECT_TRUE(parser.IsValid());
102
103 for (RTCPUtility::RTCPPacketTypes packet_type = parser.Begin();
104 packet_type != RTCPUtility::kRtcpNotValidCode;
105 packet_type = parser.Iterate()) {
106 if (packet_type == RTCPUtility::kRtcpSrCode) {
107 const RTCPUtility::RTCPPacket& packet = parser.Packet();
wu@webrtc.org66773a02014-05-07 17:09:44 +0000108 RtcpMeasurement ntp_rtp_pair(
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000109 packet.SR.NTPMostSignificant,
110 packet.SR.NTPLeastSignificant,
111 packet.SR.RTPTimestamp);
112 StoreNtpRtpPair(ntp_rtp_pair);
113 }
114 }
115 return SEND_PACKET;
116 }
117
118 int64_t RtpTimestampToNtp(uint32_t timestamp) const {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000119 CriticalSectionScoped lock(crit_.get());
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000120 int64_t timestamp_in_ms = -1;
121 if (ntp_rtp_pairs_.size() == 2) {
122 // TODO(stefan): We can't EXPECT_TRUE on this call due to a bug in the
123 // RTCP sender where it sends RTCP SR before any RTP packets, which leads
124 // to a bogus NTP/RTP mapping.
wu@webrtc.org66773a02014-05-07 17:09:44 +0000125 RtpToNtpMs(timestamp, ntp_rtp_pairs_, &timestamp_in_ms);
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000126 return timestamp_in_ms;
127 }
128 return -1;
129 }
130
131 private:
wu@webrtc.org66773a02014-05-07 17:09:44 +0000132 void StoreNtpRtpPair(RtcpMeasurement ntp_rtp_pair) {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000133 CriticalSectionScoped lock(crit_.get());
wu@webrtc.org66773a02014-05-07 17:09:44 +0000134 for (RtcpList::iterator it = ntp_rtp_pairs_.begin();
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000135 it != ntp_rtp_pairs_.end();
136 ++it) {
137 if (ntp_rtp_pair.ntp_secs == it->ntp_secs &&
138 ntp_rtp_pair.ntp_frac == it->ntp_frac) {
139 // This RTCP has already been added to the list.
140 return;
141 }
142 }
143 // We need two RTCP SR reports to map between RTP and NTP. More than two
144 // will not improve the mapping.
145 if (ntp_rtp_pairs_.size() == 2) {
146 ntp_rtp_pairs_.pop_back();
147 }
148 ntp_rtp_pairs_.push_front(ntp_rtp_pair);
149 }
150
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000151 const scoped_ptr<CriticalSectionWrapper> crit_;
wu@webrtc.org66773a02014-05-07 17:09:44 +0000152 RtcpList ntp_rtp_pairs_ GUARDED_BY(crit_);
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000153};
154
155class VideoRtcpAndSyncObserver : public SyncRtcpObserver, public VideoRenderer {
156 static const int kInSyncThresholdMs = 50;
157 static const int kStartupTimeMs = 2000;
158 static const int kMinRunTimeMs = 30000;
159
160 public:
161 VideoRtcpAndSyncObserver(Clock* clock,
162 int voe_channel,
163 VoEVideoSync* voe_sync,
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000164 SyncRtcpObserver* audio_observer)
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000165 : SyncRtcpObserver(FakeNetworkPipe::Config()),
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000166 clock_(clock),
167 voe_channel_(voe_channel),
168 voe_sync_(voe_sync),
169 audio_observer_(audio_observer),
170 creation_time_ms_(clock_->TimeInMilliseconds()),
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000171 first_time_in_sync_(-1) {}
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000172
173 virtual void RenderFrame(const I420VideoFrame& video_frame,
174 int time_to_render_ms) OVERRIDE {
175 int64_t now_ms = clock_->TimeInMilliseconds();
176 uint32_t playout_timestamp = 0;
177 if (voe_sync_->GetPlayoutTimestamp(voe_channel_, playout_timestamp) != 0)
178 return;
179 int64_t latest_audio_ntp =
180 audio_observer_->RtpTimestampToNtp(playout_timestamp);
181 int64_t latest_video_ntp = RtpTimestampToNtp(video_frame.timestamp());
182 if (latest_audio_ntp < 0 || latest_video_ntp < 0)
183 return;
184 int time_until_render_ms =
185 std::max(0, static_cast<int>(video_frame.render_time_ms() - now_ms));
186 latest_video_ntp += time_until_render_ms;
187 int64_t stream_offset = latest_audio_ntp - latest_video_ntp;
188 std::stringstream ss;
189 ss << stream_offset;
henrik.lundin@webrtc.orged865b52014-03-06 10:28:07 +0000190 webrtc::test::PrintResult("stream_offset",
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000191 "",
henrik.lundin@webrtc.orged865b52014-03-06 10:28:07 +0000192 "synchronization",
193 ss.str(),
194 "ms",
195 false);
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000196 int64_t time_since_creation = now_ms - creation_time_ms_;
197 // During the first couple of seconds audio and video can falsely be
198 // estimated as being synchronized. We don't want to trigger on those.
199 if (time_since_creation < kStartupTimeMs)
200 return;
pbos@webrtc.orgb5f30292014-03-13 08:53:39 +0000201 if (std::abs(latest_audio_ntp - latest_video_ntp) < kInSyncThresholdMs) {
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000202 if (first_time_in_sync_ == -1) {
203 first_time_in_sync_ = now_ms;
204 webrtc::test::PrintResult("sync_convergence_time",
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000205 "",
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000206 "synchronization",
207 time_since_creation,
208 "ms",
209 false);
210 }
211 if (time_since_creation > kMinRunTimeMs)
212 observation_complete_->Set();
213 }
214 }
215
216 private:
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000217 Clock* const clock_;
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000218 int voe_channel_;
219 VoEVideoSync* voe_sync_;
220 SyncRtcpObserver* audio_observer_;
221 int64_t creation_time_ms_;
222 int64_t first_time_in_sync_;
223};
224
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000225TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSync) {
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000226 VoiceEngine* voice_engine = VoiceEngine::Create();
227 VoEBase* voe_base = VoEBase::GetInterface(voice_engine);
228 VoECodec* voe_codec = VoECodec::GetInterface(voice_engine);
229 VoENetwork* voe_network = VoENetwork::GetInterface(voice_engine);
230 VoEVideoSync* voe_sync = VoEVideoSync::GetInterface(voice_engine);
231 const std::string audio_filename =
232 test::ResourcePath("voice_engine/audio_long16", "pcm");
233 ASSERT_STRNE("", audio_filename.c_str());
234 test::FakeAudioDevice fake_audio_device(Clock::GetRealTimeClock(),
235 audio_filename);
236 EXPECT_EQ(0, voe_base->Init(&fake_audio_device, NULL));
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000237 int channel = voe_base->CreateChannel();
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000238
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000239 FakeNetworkPipe::Config net_config;
240 net_config.queue_delay_ms = 500;
241 SyncRtcpObserver audio_observer(net_config);
henrik.lundin@webrtc.orged865b52014-03-06 10:28:07 +0000242 VideoRtcpAndSyncObserver observer(Clock::GetRealTimeClock(),
243 channel,
244 voe_sync,
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000245 &audio_observer);
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000246
247 Call::Config receiver_config(observer.ReceiveTransport());
248 receiver_config.voice_engine = voice_engine;
249 scoped_ptr<Call> sender_call(
250 Call::Create(Call::Config(observer.SendTransport())));
251 scoped_ptr<Call> receiver_call(Call::Create(receiver_config));
252 CodecInst isac = {103, "ISAC", 16000, 480, 1, 32000};
253 EXPECT_EQ(0, voe_codec->SetSendCodec(channel, isac));
254
255 class VoicePacketReceiver : public PacketReceiver {
256 public:
257 VoicePacketReceiver(int channel, VoENetwork* voe_network)
258 : channel_(channel),
259 voe_network_(voe_network),
260 parser_(RtpHeaderParser::Create()) {}
pbos@webrtc.orgcaba2d22014-05-14 13:57:12 +0000261 virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
262 size_t length) OVERRIDE {
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000263 int ret;
264 if (parser_->IsRtcp(packet, static_cast<int>(length))) {
265 ret = voe_network_->ReceivedRTCPPacket(
266 channel_, packet, static_cast<unsigned int>(length));
267 } else {
268 ret = voe_network_->ReceivedRTPPacket(
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000269 channel_, packet, static_cast<unsigned int>(length), PacketTime());
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000270 }
pbos@webrtc.orgcaba2d22014-05-14 13:57:12 +0000271 return ret == 0 ? DELIVERY_OK : DELIVERY_PACKET_ERROR;
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000272 }
273
274 private:
275 int channel_;
276 VoENetwork* voe_network_;
277 scoped_ptr<RtpHeaderParser> parser_;
278 } voe_packet_receiver(channel, voe_network);
279
280 audio_observer.SetReceivers(&voe_packet_receiver, &voe_packet_receiver);
281
282 internal::TransportAdapter transport_adapter(audio_observer.SendTransport());
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000283 transport_adapter.Enable();
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000284 EXPECT_EQ(0,
285 voe_network->RegisterExternalTransport(channel, transport_adapter));
286
287 observer.SetReceivers(receiver_call->Receiver(), sender_call->Receiver());
288
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000289 test::FakeDecoder fake_decoder;
290
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +0000291 VideoSendStream::Config send_config = GetSendTestConfig(sender_call.get());
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000292
293 VideoReceiveStream::Config receive_config =
294 receiver_call->GetDefaultReceiveConfig();
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +0000295 assert(receive_config.codecs.empty());
296 VideoCodec codec =
297 test::CreateDecoderVideoCodec(send_config.encoder_settings);
298 receive_config.codecs.push_back(codec);
299 assert(receive_config.external_decoders.empty());
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000300 ExternalVideoDecoder decoder;
301 decoder.decoder = &fake_decoder;
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +0000302 decoder.payload_type = send_config.encoder_settings.payload_type;
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000303 receive_config.external_decoders.push_back(decoder);
304 receive_config.rtp.remote_ssrc = send_config.rtp.ssrcs[0];
305 receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
306 receive_config.renderer = &observer;
307 receive_config.audio_channel_id = channel;
308
309 VideoSendStream* send_stream =
310 sender_call->CreateVideoSendStream(send_config);
311 VideoReceiveStream* receive_stream =
312 receiver_call->CreateVideoReceiveStream(receive_config);
313 scoped_ptr<test::FrameGeneratorCapturer> capturer(
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +0000314 test::FrameGeneratorCapturer::Create(
315 send_stream->Input(),
316 send_config.encoder_settings.streams[0].width,
317 send_config.encoder_settings.streams[0].height,
318 30,
319 Clock::GetRealTimeClock()));
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000320 receive_stream->Start();
321 send_stream->Start();
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000322 capturer->Start();
323
324 fake_audio_device.Start();
325 EXPECT_EQ(0, voe_base->StartPlayout(channel));
326 EXPECT_EQ(0, voe_base->StartReceive(channel));
327 EXPECT_EQ(0, voe_base->StartSend(channel));
328
329 EXPECT_EQ(kEventSignaled, observer.Wait())
330 << "Timed out while waiting for audio and video to be synchronized.";
331
332 EXPECT_EQ(0, voe_base->StopSend(channel));
333 EXPECT_EQ(0, voe_base->StopReceive(channel));
334 EXPECT_EQ(0, voe_base->StopPlayout(channel));
335 fake_audio_device.Stop();
336
337 capturer->Stop();
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000338 send_stream->Stop();
339 receive_stream->Stop();
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000340 observer.StopSending();
341 audio_observer.StopSending();
342
343 voe_base->DeleteChannel(channel);
344 voe_base->Release();
345 voe_codec->Release();
346 voe_network->Release();
347 voe_sync->Release();
348 sender_call->DestroyVideoSendStream(send_stream);
349 receiver_call->DestroyVideoReceiveStream(receive_stream);
350 VoiceEngine::Delete(voice_engine);
351}
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +0000352
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000353class CaptureNtpTimeObserver : public test::RtpRtcpObserver,
354 public VideoRenderer {
355 public:
356 CaptureNtpTimeObserver(Clock* clock,
357 const FakeNetworkPipe::Config& config,
358 int threshold_ms,
359 int start_time_ms,
360 int run_time_ms)
361 : RtpRtcpObserver(kLongTimeoutMs, config),
362 clock_(clock),
363 threshold_ms_(threshold_ms),
364 start_time_ms_(start_time_ms),
365 run_time_ms_(run_time_ms),
366 creation_time_ms_(clock_->TimeInMilliseconds()),
367 capturer_(NULL),
368 rtp_start_timestamp_set_(false),
369 rtp_start_timestamp_(0) {}
370
371 virtual void RenderFrame(const I420VideoFrame& video_frame,
372 int time_to_render_ms) OVERRIDE {
373 if (video_frame.ntp_time_ms() <= 0) {
374 // Haven't got enough RTCP SR in order to calculate the capture ntp time.
375 return;
376 }
377
378 int64_t now_ms = clock_->TimeInMilliseconds();
379 int64_t time_since_creation = now_ms - creation_time_ms_;
380 if (time_since_creation < start_time_ms_) {
381 // Wait for |start_time_ms_| before start measuring.
382 return;
383 }
384
385 if (time_since_creation > run_time_ms_) {
386 observation_complete_->Set();
387 }
388
389 FrameCaptureTimeList::iterator iter =
390 capture_time_list_.find(video_frame.timestamp());
391 EXPECT_TRUE(iter != capture_time_list_.end());
392
393 // The real capture time has been wrapped to uint32_t before converted
394 // to rtp timestamp in the sender side. So here we convert the estimated
395 // capture time to a uint32_t 90k timestamp also for comparing.
396 uint32_t estimated_capture_timestamp =
397 90 * static_cast<uint32_t>(video_frame.ntp_time_ms());
398 uint32_t real_capture_timestamp = iter->second;
399 int time_offset_ms = real_capture_timestamp - estimated_capture_timestamp;
400 time_offset_ms = time_offset_ms / 90;
401 std::stringstream ss;
402 ss << time_offset_ms;
403
404 webrtc::test::PrintResult("capture_ntp_time",
405 "",
406 "real - estimated",
407 ss.str(),
408 "ms",
409 true);
410 EXPECT_TRUE(std::abs(time_offset_ms) < threshold_ms_);
411 }
412
413 virtual Action OnSendRtp(const uint8_t* packet, size_t length) {
414 RTPHeader header;
415 EXPECT_TRUE(parser_->Parse(packet, static_cast<int>(length), &header));
416
417 if (!rtp_start_timestamp_set_) {
418 // Calculate the rtp timestamp offset in order to calculate the real
419 // capture time.
420 uint32_t first_capture_timestamp =
421 90 * static_cast<uint32_t>(capturer_->first_frame_capture_time());
422 rtp_start_timestamp_ = header.timestamp - first_capture_timestamp;
423 rtp_start_timestamp_set_ = true;
424 }
425
426 uint32_t capture_timestamp = header.timestamp - rtp_start_timestamp_;
427 capture_time_list_.insert(capture_time_list_.end(),
428 std::make_pair(header.timestamp,
429 capture_timestamp));
430 return SEND_PACKET;
431 }
432
433 void SetCapturer(test::FrameGeneratorCapturer* capturer) {
434 capturer_ = capturer;
435 }
436
437 private:
438 Clock* clock_;
439 int threshold_ms_;
440 int start_time_ms_;
441 int run_time_ms_;
442 int64_t creation_time_ms_;
443 test::FrameGeneratorCapturer* capturer_;
444 bool rtp_start_timestamp_set_;
445 uint32_t rtp_start_timestamp_;
446 typedef std::map<uint32_t, uint32_t> FrameCaptureTimeList;
447 FrameCaptureTimeList capture_time_list_;
448};
449
450void CallPerfTest::TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config,
451 int threshold_ms,
452 int start_time_ms,
453 int run_time_ms) {
454 CaptureNtpTimeObserver observer(Clock::GetRealTimeClock(),
455 net_config,
456 threshold_ms,
457 start_time_ms,
458 run_time_ms);
459
460 // Sender/receiver call.
461 Call::Config receiver_config(observer.ReceiveTransport());
462 scoped_ptr<Call> receiver_call(Call::Create(receiver_config));
463 scoped_ptr<Call> sender_call(
464 Call::Create(Call::Config(observer.SendTransport())));
465 observer.SetReceivers(receiver_call->Receiver(), sender_call->Receiver());
466
467 // Configure send stream.
468 VideoSendStream::Config send_config = GetSendTestConfig(sender_call.get());
469 VideoSendStream* send_stream =
470 sender_call->CreateVideoSendStream(send_config);
471 scoped_ptr<test::FrameGeneratorCapturer> capturer(
472 test::FrameGeneratorCapturer::Create(
473 send_stream->Input(),
474 send_config.encoder_settings.streams[0].width,
475 send_config.encoder_settings.streams[0].height,
476 30,
477 Clock::GetRealTimeClock()));
478 observer.SetCapturer(capturer.get());
479
480 // Configure receive stream.
481 VideoReceiveStream::Config receive_config =
482 receiver_call->GetDefaultReceiveConfig();
483 assert(receive_config.codecs.empty());
484 VideoCodec codec =
485 test::CreateDecoderVideoCodec(send_config.encoder_settings);
486 receive_config.codecs.push_back(codec);
487 assert(receive_config.external_decoders.empty());
488 ExternalVideoDecoder decoder;
489 test::FakeDecoder fake_decoder;
490 decoder.decoder = &fake_decoder;
491 decoder.payload_type = send_config.encoder_settings.payload_type;
492 receive_config.external_decoders.push_back(decoder);
493 receive_config.rtp.remote_ssrc = send_config.rtp.ssrcs[0];
494 receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
495 receive_config.renderer = &observer;
496 // Enable the receiver side rtt calculation.
497 receive_config.rtp.rtcp_xr.receiver_reference_time_report = true;
498 VideoReceiveStream* receive_stream =
499 receiver_call->CreateVideoReceiveStream(receive_config);
500
501 // Start the test
502 receive_stream->Start();
503 send_stream->Start();
504 capturer->Start();
505
506 EXPECT_EQ(kEventSignaled, observer.Wait())
507 << "Timed out while waiting for estimated capture ntp time to be "
508 << "within bounds.";
509
510 capturer->Stop();
511 send_stream->Stop();
512 receive_stream->Stop();
513 observer.StopSending();
514
515 sender_call->DestroyVideoSendStream(send_stream);
516 receiver_call->DestroyVideoReceiveStream(receive_stream);
517}
518
wu@webrtc.org9aa7d8d2014-05-29 05:03:52 +0000519TEST_F(CallPerfTest, CaptureNtpTimeWithNetworkDelay) {
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000520 FakeNetworkPipe::Config net_config;
521 net_config.queue_delay_ms = 100;
522 // TODO(wu): lower the threshold as the calculation/estimatation becomes more
523 // accurate.
wu@webrtc.org9aa7d8d2014-05-29 05:03:52 +0000524 const int kThresholdMs = 100;
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000525 const int kStartTimeMs = 10000;
526 const int kRunTimeMs = 20000;
527 TestCaptureNtpTime(net_config, kThresholdMs, kStartTimeMs, kRunTimeMs);
528}
529
wu@webrtc.org0224c202014-05-05 17:42:43 +0000530TEST_F(CallPerfTest, CaptureNtpTimeWithNetworkJitter) {
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000531 FakeNetworkPipe::Config net_config;
wu@webrtc.org0224c202014-05-05 17:42:43 +0000532 net_config.queue_delay_ms = 100;
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000533 net_config.delay_standard_deviation_ms = 10;
534 // TODO(wu): lower the threshold as the calculation/estimatation becomes more
535 // accurate.
wu@webrtc.org0224c202014-05-05 17:42:43 +0000536 const int kThresholdMs = 100;
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000537 const int kStartTimeMs = 10000;
538 const int kRunTimeMs = 20000;
539 TestCaptureNtpTime(net_config, kThresholdMs, kStartTimeMs, kRunTimeMs);
540}
541
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +0000542TEST_F(CallPerfTest, RegisterCpuOveruseObserver) {
543 // Verifies that either a normal or overuse callback is triggered.
544 class OveruseCallbackObserver : public test::RtpRtcpObserver,
545 public webrtc::OveruseCallback {
546 public:
547 OveruseCallbackObserver() : RtpRtcpObserver(kLongTimeoutMs) {}
548
549 virtual void OnOveruse() OVERRIDE {
550 observation_complete_->Set();
551 }
552 virtual void OnNormalUse() OVERRIDE {
553 observation_complete_->Set();
554 }
555 };
556
557 OveruseCallbackObserver observer;
558 Call::Config call_config(observer.SendTransport());
559 call_config.overuse_callback = &observer;
560 scoped_ptr<Call> call(Call::Create(call_config));
561
562 VideoSendStream::Config send_config = GetSendTestConfig(call.get());
563 RunVideoSendTest(call.get(), send_config, &observer);
564}
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000565
566void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) {
567 static const int kMaxEncodeBitrateKbps = 30;
pbos@webrtc.org709e2972014-03-19 10:59:52 +0000568 static const int kMinTransmitBitrateBps = 150000;
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000569 static const int kMinAcceptableTransmitBitrate = 130;
570 static const int kMaxAcceptableTransmitBitrate = 170;
571 static const int kNumBitrateObservationsInRange = 100;
572 class BitrateObserver : public test::RtpRtcpObserver, public PacketReceiver {
573 public:
574 explicit BitrateObserver(bool using_min_transmit_bitrate)
575 : test::RtpRtcpObserver(kLongTimeoutMs),
576 send_stream_(NULL),
577 send_transport_receiver_(NULL),
578 using_min_transmit_bitrate_(using_min_transmit_bitrate),
579 num_bitrate_observations_in_range_(0) {}
580
581 virtual void SetReceivers(PacketReceiver* send_transport_receiver,
582 PacketReceiver* receive_transport_receiver)
583 OVERRIDE {
584 send_transport_receiver_ = send_transport_receiver;
585 test::RtpRtcpObserver::SetReceivers(this, receive_transport_receiver);
586 }
587
588 void SetSendStream(VideoSendStream* send_stream) {
589 send_stream_ = send_stream;
590 }
591
592 private:
pbos@webrtc.orgcaba2d22014-05-14 13:57:12 +0000593 virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
594 size_t length) OVERRIDE {
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000595 VideoSendStream::Stats stats = send_stream_->GetStats();
596 if (stats.substreams.size() > 0) {
597 assert(stats.substreams.size() == 1);
598 int bitrate_kbps = stats.substreams.begin()->second.bitrate_bps / 1000;
599 if (bitrate_kbps > 0) {
600 test::PrintResult(
601 "bitrate_stats_",
602 (using_min_transmit_bitrate_ ? "min_transmit_bitrate"
603 : "without_min_transmit_bitrate"),
604 "bitrate_kbps",
605 static_cast<size_t>(bitrate_kbps),
606 "kbps",
607 false);
608 if (using_min_transmit_bitrate_) {
609 if (bitrate_kbps > kMinAcceptableTransmitBitrate &&
610 bitrate_kbps < kMaxAcceptableTransmitBitrate) {
611 ++num_bitrate_observations_in_range_;
612 }
613 } else {
614 // Expect bitrate stats to roughly match the max encode bitrate.
615 if (bitrate_kbps > kMaxEncodeBitrateKbps - 5 &&
616 bitrate_kbps < kMaxEncodeBitrateKbps + 5) {
617 ++num_bitrate_observations_in_range_;
618 }
619 }
620 if (num_bitrate_observations_in_range_ ==
621 kNumBitrateObservationsInRange)
622 observation_complete_->Set();
623 }
624 }
625 return send_transport_receiver_->DeliverPacket(packet, length);
626 }
627
628 VideoSendStream* send_stream_;
629 PacketReceiver* send_transport_receiver_;
630 const bool using_min_transmit_bitrate_;
631 int num_bitrate_observations_in_range_;
632 } observer(pad_to_min_bitrate);
633
634 scoped_ptr<Call> sender_call(
635 Call::Create(Call::Config(observer.SendTransport())));
636 scoped_ptr<Call> receiver_call(
637 Call::Create(Call::Config(observer.ReceiveTransport())));
638
639 VideoSendStream::Config send_config = GetSendTestConfig(sender_call.get());
640 fake_encoder_.SetMaxBitrate(kMaxEncodeBitrateKbps);
641
642 observer.SetReceivers(receiver_call->Receiver(), sender_call->Receiver());
643
644 send_config.pacing = true;
645 if (pad_to_min_bitrate) {
pbos@webrtc.org709e2972014-03-19 10:59:52 +0000646 send_config.rtp.min_transmit_bitrate_bps = kMinTransmitBitrateBps;
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000647 } else {
pbos@webrtc.org709e2972014-03-19 10:59:52 +0000648 assert(send_config.rtp.min_transmit_bitrate_bps == 0);
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000649 }
650
651 VideoReceiveStream::Config receive_config =
652 receiver_call->GetDefaultReceiveConfig();
653 receive_config.codecs.clear();
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +0000654 VideoCodec codec =
655 test::CreateDecoderVideoCodec(send_config.encoder_settings);
656 receive_config.codecs.push_back(codec);
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000657 test::FakeDecoder fake_decoder;
658 ExternalVideoDecoder decoder;
659 decoder.decoder = &fake_decoder;
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +0000660 decoder.payload_type = send_config.encoder_settings.payload_type;
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000661 receive_config.external_decoders.push_back(decoder);
662 receive_config.rtp.remote_ssrc = send_config.rtp.ssrcs[0];
663 receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
664
665 VideoSendStream* send_stream =
666 sender_call->CreateVideoSendStream(send_config);
667 VideoReceiveStream* receive_stream =
668 receiver_call->CreateVideoReceiveStream(receive_config);
669 scoped_ptr<test::FrameGeneratorCapturer> capturer(
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +0000670 test::FrameGeneratorCapturer::Create(
671 send_stream->Input(),
672 send_config.encoder_settings.streams[0].width,
673 send_config.encoder_settings.streams[0].height,
674 30,
675 Clock::GetRealTimeClock()));
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000676 observer.SetSendStream(send_stream);
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000677 receive_stream->Start();
678 send_stream->Start();
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000679 capturer->Start();
680
681 EXPECT_EQ(kEventSignaled, observer.Wait())
682 << "Timeout while waiting for send-bitrate stats.";
683
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000684 send_stream->Stop();
685 receive_stream->Stop();
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000686 observer.StopSending();
687 capturer->Stop();
688 sender_call->DestroyVideoSendStream(send_stream);
689 receiver_call->DestroyVideoReceiveStream(receive_stream);
690}
691
692TEST_F(CallPerfTest, PadsToMinTransmitBitrate) { TestMinTransmitBitrate(true); }
693
694TEST_F(CallPerfTest, NoPadWithoutMinTransmitBitrate) {
695 TestMinTransmitBitrate(false);
696}
697
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000698} // namespace webrtc