blob: f9e44aed187a35bc3c1c8dcaa71c526524ad6e36 [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:
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +000056 void CreateTestConfig(Call* call) {
57 send_config_ = call->GetDefaultSendConfig();
58 send_config_.rtp.ssrcs.push_back(kSendSsrc);
59 send_config_.encoder_settings.encoder = &fake_encoder_;
60 send_config_.encoder_settings.payload_type = kSendPayloadType;
61 send_config_.encoder_settings.payload_name = "FAKE";
62 video_streams_ = test::CreateVideoStreams(1);
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000063 }
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000064
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000065 void RunVideoSendTest(Call* call,
66 const VideoSendStream::Config& config,
67 test::RtpRtcpObserver* observer) {
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +000068 send_stream_ = call->CreateVideoSendStream(config, video_streams_, NULL);
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000069 scoped_ptr<test::FrameGeneratorCapturer> frame_generator_capturer(
70 test::FrameGeneratorCapturer::Create(
71 send_stream_->Input(), 320, 240, 30, Clock::GetRealTimeClock()));
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +000072 send_stream_->Start();
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000073 frame_generator_capturer->Start();
74
75 EXPECT_EQ(kEventSignaled, observer->Wait());
76
77 observer->StopSending();
78 frame_generator_capturer->Stop();
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +000079 send_stream_->Stop();
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000080 call->DestroyVideoSendStream(send_stream_);
81 }
82
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000083 void TestMinTransmitBitrate(bool pad_to_min_bitrate);
84
wu@webrtc.orgcd701192014-04-24 22:10:24 +000085 void TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config,
86 int threshold_ms,
87 int start_time_ms,
88 int run_time_ms);
89
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +000090 VideoSendStream::Config send_config_;
91 std::vector<VideoStream> video_streams_;
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +000092 VideoSendStream* send_stream_;
93 test::FakeEncoder fake_encoder_;
pbos@webrtc.org1d096902013-12-13 12:48:05 +000094};
95
96class SyncRtcpObserver : public test::RtpRtcpObserver {
97 public:
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +000098 explicit SyncRtcpObserver(const FakeNetworkPipe::Config& config)
99 : test::RtpRtcpObserver(kLongTimeoutMs, config),
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000100 crit_(CriticalSectionWrapper::CreateCriticalSection()) {}
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000101
102 virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
103 RTCPUtility::RTCPParserV2 parser(packet, length, true);
104 EXPECT_TRUE(parser.IsValid());
105
106 for (RTCPUtility::RTCPPacketTypes packet_type = parser.Begin();
107 packet_type != RTCPUtility::kRtcpNotValidCode;
108 packet_type = parser.Iterate()) {
109 if (packet_type == RTCPUtility::kRtcpSrCode) {
110 const RTCPUtility::RTCPPacket& packet = parser.Packet();
wu@webrtc.org66773a02014-05-07 17:09:44 +0000111 RtcpMeasurement ntp_rtp_pair(
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000112 packet.SR.NTPMostSignificant,
113 packet.SR.NTPLeastSignificant,
114 packet.SR.RTPTimestamp);
115 StoreNtpRtpPair(ntp_rtp_pair);
116 }
117 }
118 return SEND_PACKET;
119 }
120
121 int64_t RtpTimestampToNtp(uint32_t timestamp) const {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000122 CriticalSectionScoped lock(crit_.get());
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000123 int64_t timestamp_in_ms = -1;
124 if (ntp_rtp_pairs_.size() == 2) {
125 // TODO(stefan): We can't EXPECT_TRUE on this call due to a bug in the
126 // RTCP sender where it sends RTCP SR before any RTP packets, which leads
127 // to a bogus NTP/RTP mapping.
wu@webrtc.org66773a02014-05-07 17:09:44 +0000128 RtpToNtpMs(timestamp, ntp_rtp_pairs_, &timestamp_in_ms);
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000129 return timestamp_in_ms;
130 }
131 return -1;
132 }
133
134 private:
wu@webrtc.org66773a02014-05-07 17:09:44 +0000135 void StoreNtpRtpPair(RtcpMeasurement ntp_rtp_pair) {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000136 CriticalSectionScoped lock(crit_.get());
wu@webrtc.org66773a02014-05-07 17:09:44 +0000137 for (RtcpList::iterator it = ntp_rtp_pairs_.begin();
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000138 it != ntp_rtp_pairs_.end();
139 ++it) {
140 if (ntp_rtp_pair.ntp_secs == it->ntp_secs &&
141 ntp_rtp_pair.ntp_frac == it->ntp_frac) {
142 // This RTCP has already been added to the list.
143 return;
144 }
145 }
146 // We need two RTCP SR reports to map between RTP and NTP. More than two
147 // will not improve the mapping.
148 if (ntp_rtp_pairs_.size() == 2) {
149 ntp_rtp_pairs_.pop_back();
150 }
151 ntp_rtp_pairs_.push_front(ntp_rtp_pair);
152 }
153
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000154 const scoped_ptr<CriticalSectionWrapper> crit_;
wu@webrtc.org66773a02014-05-07 17:09:44 +0000155 RtcpList ntp_rtp_pairs_ GUARDED_BY(crit_);
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000156};
157
158class VideoRtcpAndSyncObserver : public SyncRtcpObserver, public VideoRenderer {
159 static const int kInSyncThresholdMs = 50;
160 static const int kStartupTimeMs = 2000;
161 static const int kMinRunTimeMs = 30000;
162
163 public:
164 VideoRtcpAndSyncObserver(Clock* clock,
165 int voe_channel,
166 VoEVideoSync* voe_sync,
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000167 SyncRtcpObserver* audio_observer)
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000168 : SyncRtcpObserver(FakeNetworkPipe::Config()),
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000169 clock_(clock),
170 voe_channel_(voe_channel),
171 voe_sync_(voe_sync),
172 audio_observer_(audio_observer),
173 creation_time_ms_(clock_->TimeInMilliseconds()),
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000174 first_time_in_sync_(-1) {}
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000175
176 virtual void RenderFrame(const I420VideoFrame& video_frame,
177 int time_to_render_ms) OVERRIDE {
178 int64_t now_ms = clock_->TimeInMilliseconds();
179 uint32_t playout_timestamp = 0;
180 if (voe_sync_->GetPlayoutTimestamp(voe_channel_, playout_timestamp) != 0)
181 return;
182 int64_t latest_audio_ntp =
183 audio_observer_->RtpTimestampToNtp(playout_timestamp);
184 int64_t latest_video_ntp = RtpTimestampToNtp(video_frame.timestamp());
185 if (latest_audio_ntp < 0 || latest_video_ntp < 0)
186 return;
187 int time_until_render_ms =
188 std::max(0, static_cast<int>(video_frame.render_time_ms() - now_ms));
189 latest_video_ntp += time_until_render_ms;
190 int64_t stream_offset = latest_audio_ntp - latest_video_ntp;
191 std::stringstream ss;
192 ss << stream_offset;
henrik.lundin@webrtc.orged865b52014-03-06 10:28:07 +0000193 webrtc::test::PrintResult("stream_offset",
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000194 "",
henrik.lundin@webrtc.orged865b52014-03-06 10:28:07 +0000195 "synchronization",
196 ss.str(),
197 "ms",
198 false);
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000199 int64_t time_since_creation = now_ms - creation_time_ms_;
200 // During the first couple of seconds audio and video can falsely be
201 // estimated as being synchronized. We don't want to trigger on those.
202 if (time_since_creation < kStartupTimeMs)
203 return;
pbos@webrtc.orgb5f30292014-03-13 08:53:39 +0000204 if (std::abs(latest_audio_ntp - latest_video_ntp) < kInSyncThresholdMs) {
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000205 if (first_time_in_sync_ == -1) {
206 first_time_in_sync_ = now_ms;
207 webrtc::test::PrintResult("sync_convergence_time",
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000208 "",
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000209 "synchronization",
210 time_since_creation,
211 "ms",
212 false);
213 }
214 if (time_since_creation > kMinRunTimeMs)
215 observation_complete_->Set();
216 }
217 }
218
219 private:
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000220 Clock* const clock_;
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000221 int voe_channel_;
222 VoEVideoSync* voe_sync_;
223 SyncRtcpObserver* audio_observer_;
224 int64_t creation_time_ms_;
225 int64_t first_time_in_sync_;
226};
227
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000228TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSync) {
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000229 VoiceEngine* voice_engine = VoiceEngine::Create();
230 VoEBase* voe_base = VoEBase::GetInterface(voice_engine);
231 VoECodec* voe_codec = VoECodec::GetInterface(voice_engine);
232 VoENetwork* voe_network = VoENetwork::GetInterface(voice_engine);
233 VoEVideoSync* voe_sync = VoEVideoSync::GetInterface(voice_engine);
234 const std::string audio_filename =
235 test::ResourcePath("voice_engine/audio_long16", "pcm");
236 ASSERT_STRNE("", audio_filename.c_str());
237 test::FakeAudioDevice fake_audio_device(Clock::GetRealTimeClock(),
238 audio_filename);
239 EXPECT_EQ(0, voe_base->Init(&fake_audio_device, NULL));
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000240 int channel = voe_base->CreateChannel();
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000241
stefan@webrtc.orgfaada6e2013-12-18 20:28:25 +0000242 FakeNetworkPipe::Config net_config;
243 net_config.queue_delay_ms = 500;
244 SyncRtcpObserver audio_observer(net_config);
henrik.lundin@webrtc.orged865b52014-03-06 10:28:07 +0000245 VideoRtcpAndSyncObserver observer(Clock::GetRealTimeClock(),
246 channel,
247 voe_sync,
henrik.lundin@webrtc.orgd144bb62014-04-22 08:36:33 +0000248 &audio_observer);
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000249
250 Call::Config receiver_config(observer.ReceiveTransport());
251 receiver_config.voice_engine = voice_engine;
252 scoped_ptr<Call> sender_call(
253 Call::Create(Call::Config(observer.SendTransport())));
254 scoped_ptr<Call> receiver_call(Call::Create(receiver_config));
255 CodecInst isac = {103, "ISAC", 16000, 480, 1, 32000};
256 EXPECT_EQ(0, voe_codec->SetSendCodec(channel, isac));
257
258 class VoicePacketReceiver : public PacketReceiver {
259 public:
260 VoicePacketReceiver(int channel, VoENetwork* voe_network)
261 : channel_(channel),
262 voe_network_(voe_network),
263 parser_(RtpHeaderParser::Create()) {}
pbos@webrtc.orgcaba2d22014-05-14 13:57:12 +0000264 virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
265 size_t length) OVERRIDE {
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000266 int ret;
267 if (parser_->IsRtcp(packet, static_cast<int>(length))) {
268 ret = voe_network_->ReceivedRTCPPacket(
269 channel_, packet, static_cast<unsigned int>(length));
270 } else {
271 ret = voe_network_->ReceivedRTPPacket(
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000272 channel_, packet, static_cast<unsigned int>(length), PacketTime());
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000273 }
pbos@webrtc.orgcaba2d22014-05-14 13:57:12 +0000274 return ret == 0 ? DELIVERY_OK : DELIVERY_PACKET_ERROR;
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000275 }
276
277 private:
278 int channel_;
279 VoENetwork* voe_network_;
280 scoped_ptr<RtpHeaderParser> parser_;
281 } voe_packet_receiver(channel, voe_network);
282
283 audio_observer.SetReceivers(&voe_packet_receiver, &voe_packet_receiver);
284
285 internal::TransportAdapter transport_adapter(audio_observer.SendTransport());
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000286 transport_adapter.Enable();
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000287 EXPECT_EQ(0,
288 voe_network->RegisterExternalTransport(channel, transport_adapter));
289
290 observer.SetReceivers(receiver_call->Receiver(), sender_call->Receiver());
291
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000292 test::FakeDecoder fake_decoder;
293
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000294 CreateTestConfig(sender_call.get());
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000295
296 VideoReceiveStream::Config receive_config =
297 receiver_call->GetDefaultReceiveConfig();
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +0000298 assert(receive_config.codecs.empty());
299 VideoCodec codec =
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000300 test::CreateDecoderVideoCodec(send_config_.encoder_settings);
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +0000301 receive_config.codecs.push_back(codec);
302 assert(receive_config.external_decoders.empty());
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000303 ExternalVideoDecoder decoder;
304 decoder.decoder = &fake_decoder;
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000305 decoder.payload_type = send_config_.encoder_settings.payload_type;
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000306 receive_config.external_decoders.push_back(decoder);
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000307 receive_config.rtp.remote_ssrc = send_config_.rtp.ssrcs[0];
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000308 receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
309 receive_config.renderer = &observer;
310 receive_config.audio_channel_id = channel;
311
312 VideoSendStream* send_stream =
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000313 sender_call->CreateVideoSendStream(send_config_, video_streams_, NULL);
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000314 VideoReceiveStream* receive_stream =
315 receiver_call->CreateVideoReceiveStream(receive_config);
316 scoped_ptr<test::FrameGeneratorCapturer> capturer(
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000317 test::FrameGeneratorCapturer::Create(send_stream->Input(),
318 video_streams_[0].width,
319 video_streams_[0].height,
320 30,
321 Clock::GetRealTimeClock()));
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000322 receive_stream->Start();
323 send_stream->Start();
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000324 capturer->Start();
325
326 fake_audio_device.Start();
327 EXPECT_EQ(0, voe_base->StartPlayout(channel));
328 EXPECT_EQ(0, voe_base->StartReceive(channel));
329 EXPECT_EQ(0, voe_base->StartSend(channel));
330
331 EXPECT_EQ(kEventSignaled, observer.Wait())
332 << "Timed out while waiting for audio and video to be synchronized.";
333
334 EXPECT_EQ(0, voe_base->StopSend(channel));
335 EXPECT_EQ(0, voe_base->StopReceive(channel));
336 EXPECT_EQ(0, voe_base->StopPlayout(channel));
337 fake_audio_device.Stop();
338
339 capturer->Stop();
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000340 send_stream->Stop();
341 receive_stream->Stop();
pbos@webrtc.org1d096902013-12-13 12:48:05 +0000342 observer.StopSending();
343 audio_observer.StopSending();
344
345 voe_base->DeleteChannel(channel);
346 voe_base->Release();
347 voe_codec->Release();
348 voe_network->Release();
349 voe_sync->Release();
350 sender_call->DestroyVideoSendStream(send_stream);
351 receiver_call->DestroyVideoReceiveStream(receive_stream);
352 VoiceEngine::Delete(voice_engine);
353}
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +0000354
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000355class CaptureNtpTimeObserver : public test::RtpRtcpObserver,
356 public VideoRenderer {
357 public:
358 CaptureNtpTimeObserver(Clock* clock,
359 const FakeNetworkPipe::Config& config,
360 int threshold_ms,
361 int start_time_ms,
362 int run_time_ms)
363 : RtpRtcpObserver(kLongTimeoutMs, config),
364 clock_(clock),
365 threshold_ms_(threshold_ms),
366 start_time_ms_(start_time_ms),
367 run_time_ms_(run_time_ms),
368 creation_time_ms_(clock_->TimeInMilliseconds()),
369 capturer_(NULL),
370 rtp_start_timestamp_set_(false),
371 rtp_start_timestamp_(0) {}
372
373 virtual void RenderFrame(const I420VideoFrame& video_frame,
374 int time_to_render_ms) OVERRIDE {
375 if (video_frame.ntp_time_ms() <= 0) {
376 // Haven't got enough RTCP SR in order to calculate the capture ntp time.
377 return;
378 }
379
380 int64_t now_ms = clock_->TimeInMilliseconds();
381 int64_t time_since_creation = now_ms - creation_time_ms_;
382 if (time_since_creation < start_time_ms_) {
383 // Wait for |start_time_ms_| before start measuring.
384 return;
385 }
386
387 if (time_since_creation > run_time_ms_) {
388 observation_complete_->Set();
389 }
390
391 FrameCaptureTimeList::iterator iter =
392 capture_time_list_.find(video_frame.timestamp());
393 EXPECT_TRUE(iter != capture_time_list_.end());
394
395 // The real capture time has been wrapped to uint32_t before converted
396 // to rtp timestamp in the sender side. So here we convert the estimated
397 // capture time to a uint32_t 90k timestamp also for comparing.
398 uint32_t estimated_capture_timestamp =
399 90 * static_cast<uint32_t>(video_frame.ntp_time_ms());
400 uint32_t real_capture_timestamp = iter->second;
401 int time_offset_ms = real_capture_timestamp - estimated_capture_timestamp;
402 time_offset_ms = time_offset_ms / 90;
403 std::stringstream ss;
404 ss << time_offset_ms;
405
406 webrtc::test::PrintResult("capture_ntp_time",
407 "",
408 "real - estimated",
409 ss.str(),
410 "ms",
411 true);
412 EXPECT_TRUE(std::abs(time_offset_ms) < threshold_ms_);
413 }
414
415 virtual Action OnSendRtp(const uint8_t* packet, size_t length) {
416 RTPHeader header;
417 EXPECT_TRUE(parser_->Parse(packet, static_cast<int>(length), &header));
418
419 if (!rtp_start_timestamp_set_) {
420 // Calculate the rtp timestamp offset in order to calculate the real
421 // capture time.
422 uint32_t first_capture_timestamp =
423 90 * static_cast<uint32_t>(capturer_->first_frame_capture_time());
424 rtp_start_timestamp_ = header.timestamp - first_capture_timestamp;
425 rtp_start_timestamp_set_ = true;
426 }
427
428 uint32_t capture_timestamp = header.timestamp - rtp_start_timestamp_;
429 capture_time_list_.insert(capture_time_list_.end(),
430 std::make_pair(header.timestamp,
431 capture_timestamp));
432 return SEND_PACKET;
433 }
434
435 void SetCapturer(test::FrameGeneratorCapturer* capturer) {
436 capturer_ = capturer;
437 }
438
439 private:
440 Clock* clock_;
441 int threshold_ms_;
442 int start_time_ms_;
443 int run_time_ms_;
444 int64_t creation_time_ms_;
445 test::FrameGeneratorCapturer* capturer_;
446 bool rtp_start_timestamp_set_;
447 uint32_t rtp_start_timestamp_;
448 typedef std::map<uint32_t, uint32_t> FrameCaptureTimeList;
449 FrameCaptureTimeList capture_time_list_;
450};
451
452void CallPerfTest::TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config,
453 int threshold_ms,
454 int start_time_ms,
455 int run_time_ms) {
456 CaptureNtpTimeObserver observer(Clock::GetRealTimeClock(),
457 net_config,
458 threshold_ms,
459 start_time_ms,
460 run_time_ms);
461
462 // Sender/receiver call.
463 Call::Config receiver_config(observer.ReceiveTransport());
464 scoped_ptr<Call> receiver_call(Call::Create(receiver_config));
465 scoped_ptr<Call> sender_call(
466 Call::Create(Call::Config(observer.SendTransport())));
467 observer.SetReceivers(receiver_call->Receiver(), sender_call->Receiver());
468
469 // Configure send stream.
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000470 CreateTestConfig(sender_call.get());
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000471 VideoSendStream* send_stream =
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000472 sender_call->CreateVideoSendStream(send_config_, video_streams_, NULL);
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000473 scoped_ptr<test::FrameGeneratorCapturer> capturer(
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000474 test::FrameGeneratorCapturer::Create(send_stream->Input(),
475 video_streams_[0].width,
476 video_streams_[0].height,
477 30,
478 Clock::GetRealTimeClock()));
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000479 observer.SetCapturer(capturer.get());
480
481 // Configure receive stream.
482 VideoReceiveStream::Config receive_config =
483 receiver_call->GetDefaultReceiveConfig();
484 assert(receive_config.codecs.empty());
485 VideoCodec codec =
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000486 test::CreateDecoderVideoCodec(send_config_.encoder_settings);
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000487 receive_config.codecs.push_back(codec);
488 assert(receive_config.external_decoders.empty());
489 ExternalVideoDecoder decoder;
490 test::FakeDecoder fake_decoder;
491 decoder.decoder = &fake_decoder;
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000492 decoder.payload_type = send_config_.encoder_settings.payload_type;
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000493 receive_config.external_decoders.push_back(decoder);
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000494 receive_config.rtp.remote_ssrc = send_config_.rtp.ssrcs[0];
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000495 receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
496 receive_config.renderer = &observer;
497 // Enable the receiver side rtt calculation.
498 receive_config.rtp.rtcp_xr.receiver_reference_time_report = true;
499 VideoReceiveStream* receive_stream =
500 receiver_call->CreateVideoReceiveStream(receive_config);
501
502 // Start the test
503 receive_stream->Start();
504 send_stream->Start();
505 capturer->Start();
506
507 EXPECT_EQ(kEventSignaled, observer.Wait())
508 << "Timed out while waiting for estimated capture ntp time to be "
509 << "within bounds.";
510
511 capturer->Stop();
512 send_stream->Stop();
513 receive_stream->Stop();
514 observer.StopSending();
515
516 sender_call->DestroyVideoSendStream(send_stream);
517 receiver_call->DestroyVideoReceiveStream(receive_stream);
518}
519
wu@webrtc.org9aa7d8d2014-05-29 05:03:52 +0000520TEST_F(CallPerfTest, CaptureNtpTimeWithNetworkDelay) {
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000521 FakeNetworkPipe::Config net_config;
522 net_config.queue_delay_ms = 100;
523 // TODO(wu): lower the threshold as the calculation/estimatation becomes more
524 // accurate.
wu@webrtc.org9aa7d8d2014-05-29 05:03:52 +0000525 const int kThresholdMs = 100;
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000526 const int kStartTimeMs = 10000;
527 const int kRunTimeMs = 20000;
528 TestCaptureNtpTime(net_config, kThresholdMs, kStartTimeMs, kRunTimeMs);
529}
530
wu@webrtc.org0224c202014-05-05 17:42:43 +0000531TEST_F(CallPerfTest, CaptureNtpTimeWithNetworkJitter) {
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000532 FakeNetworkPipe::Config net_config;
wu@webrtc.org0224c202014-05-05 17:42:43 +0000533 net_config.queue_delay_ms = 100;
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000534 net_config.delay_standard_deviation_ms = 10;
535 // TODO(wu): lower the threshold as the calculation/estimatation becomes more
536 // accurate.
wu@webrtc.org0224c202014-05-05 17:42:43 +0000537 const int kThresholdMs = 100;
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000538 const int kStartTimeMs = 10000;
539 const int kRunTimeMs = 20000;
540 TestCaptureNtpTime(net_config, kThresholdMs, kStartTimeMs, kRunTimeMs);
541}
542
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +0000543TEST_F(CallPerfTest, RegisterCpuOveruseObserver) {
544 // Verifies that either a normal or overuse callback is triggered.
545 class OveruseCallbackObserver : public test::RtpRtcpObserver,
546 public webrtc::OveruseCallback {
547 public:
548 OveruseCallbackObserver() : RtpRtcpObserver(kLongTimeoutMs) {}
549
550 virtual void OnOveruse() OVERRIDE {
551 observation_complete_->Set();
552 }
553 virtual void OnNormalUse() OVERRIDE {
554 observation_complete_->Set();
555 }
556 };
557
558 OveruseCallbackObserver observer;
559 Call::Config call_config(observer.SendTransport());
560 call_config.overuse_callback = &observer;
561 scoped_ptr<Call> call(Call::Create(call_config));
562
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000563 CreateTestConfig(call.get());
564 RunVideoSendTest(call.get(), send_config_, &observer);
asapersson@webrtc.orgbdc5ed22014-01-31 10:05:07 +0000565}
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000566
567void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) {
568 static const int kMaxEncodeBitrateKbps = 30;
pbos@webrtc.org709e2972014-03-19 10:59:52 +0000569 static const int kMinTransmitBitrateBps = 150000;
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000570 static const int kMinAcceptableTransmitBitrate = 130;
571 static const int kMaxAcceptableTransmitBitrate = 170;
572 static const int kNumBitrateObservationsInRange = 100;
573 class BitrateObserver : public test::RtpRtcpObserver, public PacketReceiver {
574 public:
575 explicit BitrateObserver(bool using_min_transmit_bitrate)
576 : test::RtpRtcpObserver(kLongTimeoutMs),
577 send_stream_(NULL),
578 send_transport_receiver_(NULL),
579 using_min_transmit_bitrate_(using_min_transmit_bitrate),
580 num_bitrate_observations_in_range_(0) {}
581
582 virtual void SetReceivers(PacketReceiver* send_transport_receiver,
583 PacketReceiver* receive_transport_receiver)
584 OVERRIDE {
585 send_transport_receiver_ = send_transport_receiver;
586 test::RtpRtcpObserver::SetReceivers(this, receive_transport_receiver);
587 }
588
589 void SetSendStream(VideoSendStream* send_stream) {
590 send_stream_ = send_stream;
591 }
592
593 private:
pbos@webrtc.orgcaba2d22014-05-14 13:57:12 +0000594 virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
595 size_t length) OVERRIDE {
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000596 VideoSendStream::Stats stats = send_stream_->GetStats();
597 if (stats.substreams.size() > 0) {
598 assert(stats.substreams.size() == 1);
599 int bitrate_kbps = stats.substreams.begin()->second.bitrate_bps / 1000;
600 if (bitrate_kbps > 0) {
601 test::PrintResult(
602 "bitrate_stats_",
603 (using_min_transmit_bitrate_ ? "min_transmit_bitrate"
604 : "without_min_transmit_bitrate"),
605 "bitrate_kbps",
606 static_cast<size_t>(bitrate_kbps),
607 "kbps",
608 false);
609 if (using_min_transmit_bitrate_) {
610 if (bitrate_kbps > kMinAcceptableTransmitBitrate &&
611 bitrate_kbps < kMaxAcceptableTransmitBitrate) {
612 ++num_bitrate_observations_in_range_;
613 }
614 } else {
615 // Expect bitrate stats to roughly match the max encode bitrate.
616 if (bitrate_kbps > kMaxEncodeBitrateKbps - 5 &&
617 bitrate_kbps < kMaxEncodeBitrateKbps + 5) {
618 ++num_bitrate_observations_in_range_;
619 }
620 }
621 if (num_bitrate_observations_in_range_ ==
622 kNumBitrateObservationsInRange)
623 observation_complete_->Set();
624 }
625 }
626 return send_transport_receiver_->DeliverPacket(packet, length);
627 }
628
629 VideoSendStream* send_stream_;
630 PacketReceiver* send_transport_receiver_;
631 const bool using_min_transmit_bitrate_;
632 int num_bitrate_observations_in_range_;
633 } observer(pad_to_min_bitrate);
634
635 scoped_ptr<Call> sender_call(
636 Call::Create(Call::Config(observer.SendTransport())));
637 scoped_ptr<Call> receiver_call(
638 Call::Create(Call::Config(observer.ReceiveTransport())));
639
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000640 CreateTestConfig(sender_call.get());
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000641 fake_encoder_.SetMaxBitrate(kMaxEncodeBitrateKbps);
642
643 observer.SetReceivers(receiver_call->Receiver(), sender_call->Receiver());
644
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000645 send_config_.pacing = true;
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000646 if (pad_to_min_bitrate) {
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000647 send_config_.rtp.min_transmit_bitrate_bps = kMinTransmitBitrateBps;
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000648 } else {
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000649 assert(send_config_.rtp.min_transmit_bitrate_bps == 0);
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000650 }
651
652 VideoReceiveStream::Config receive_config =
653 receiver_call->GetDefaultReceiveConfig();
654 receive_config.codecs.clear();
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +0000655 VideoCodec codec =
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000656 test::CreateDecoderVideoCodec(send_config_.encoder_settings);
pbos@webrtc.orgf577ae92014-03-19 08:43:57 +0000657 receive_config.codecs.push_back(codec);
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000658 test::FakeDecoder fake_decoder;
659 ExternalVideoDecoder decoder;
660 decoder.decoder = &fake_decoder;
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000661 decoder.payload_type = send_config_.encoder_settings.payload_type;
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000662 receive_config.external_decoders.push_back(decoder);
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000663 receive_config.rtp.remote_ssrc = send_config_.rtp.ssrcs[0];
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000664 receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
665
666 VideoSendStream* send_stream =
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000667 sender_call->CreateVideoSendStream(send_config_, video_streams_, NULL);
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000668 VideoReceiveStream* receive_stream =
669 receiver_call->CreateVideoReceiveStream(receive_config);
670 scoped_ptr<test::FrameGeneratorCapturer> capturer(
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000671 test::FrameGeneratorCapturer::Create(send_stream->Input(),
672 video_streams_[0].width,
673 video_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