OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
42 #include "webrtc/test/testsupport/perf_test.h" | 42 #include "webrtc/test/testsupport/perf_test.h" |
43 #include "webrtc/voice_engine/include/voe_base.h" | 43 #include "webrtc/voice_engine/include/voe_base.h" |
44 #include "webrtc/voice_engine/include/voe_codec.h" | 44 #include "webrtc/voice_engine/include/voe_codec.h" |
45 #include "webrtc/voice_engine/include/voe_rtp_rtcp.h" | 45 #include "webrtc/voice_engine/include/voe_rtp_rtcp.h" |
46 #include "webrtc/voice_engine/include/voe_video_sync.h" | 46 #include "webrtc/voice_engine/include/voe_video_sync.h" |
47 | 47 |
48 using webrtc::test::DriftingClock; | 48 using webrtc::test::DriftingClock; |
49 using webrtc::test::FakeAudioDevice; | 49 using webrtc::test::FakeAudioDevice; |
50 | 50 |
51 namespace webrtc { | 51 namespace webrtc { |
52 namespace { | |
53 | |
54 // Converts list of values into comma-separated string for PrintResultList. | |
pbos-webrtc
2016/06/03 15:10:03
Pref that you move this to webrtc/test/testsupport
danilchap
2016/06/03 15:32:13
Moved to perf_test.h since it is a template functi
| |
55 template <typename Container> | |
56 std::string ValuesToString(const Container& container) { | |
57 if (container.empty()) | |
58 return ""; | |
59 | |
60 std::stringstream ss; | |
61 auto it = container.begin(); | |
62 while (true) { | |
63 ss << *it; | |
64 if (++it == container.end()) | |
65 return ss.str(); | |
pbos-webrtc
2016/06/03 15:10:03
preferring break here, I think some compilers migh
danilchap
2016/06/03 15:32:13
Done.
| |
66 ss << ','; | |
67 } | |
68 } | |
69 | |
70 } // namespace | |
52 | 71 |
53 class CallPerfTest : public test::CallTest { | 72 class CallPerfTest : public test::CallTest { |
54 protected: | 73 protected: |
55 enum class FecMode { | 74 enum class FecMode { |
56 kOn, kOff | 75 kOn, kOff |
57 }; | 76 }; |
58 enum class CreateOrder { | 77 enum class CreateOrder { |
59 kAudioFirst, kVideoFirst | 78 kAudioFirst, kVideoFirst |
60 }; | 79 }; |
61 void TestAudioVideoSync(FecMode fec, | 80 void TestAudioVideoSync(FecMode fec, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
93 { | 112 { |
94 rtc::CritScope lock(&crit_); | 113 rtc::CritScope lock(&crit_); |
95 if (receive_stream_) | 114 if (receive_stream_) |
96 stats = receive_stream_->GetStats(); | 115 stats = receive_stream_->GetStats(); |
97 } | 116 } |
98 if (stats.sync_offset_ms == std::numeric_limits<int>::max()) | 117 if (stats.sync_offset_ms == std::numeric_limits<int>::max()) |
99 return; | 118 return; |
100 | 119 |
101 int64_t now_ms = clock_->TimeInMilliseconds(); | 120 int64_t now_ms = clock_->TimeInMilliseconds(); |
102 | 121 |
103 std::stringstream ss; | 122 sync_offset_ms_list_.push_back(stats.sync_offset_ms); |
104 ss << stats.sync_offset_ms; | |
105 webrtc::test::PrintResult("stream_offset", | |
106 "", | |
107 "synchronization", | |
108 ss.str(), | |
109 "ms", | |
110 false); | |
111 int64_t time_since_creation = now_ms - creation_time_ms_; | 123 int64_t time_since_creation = now_ms - creation_time_ms_; |
112 // During the first couple of seconds audio and video can falsely be | 124 // During the first couple of seconds audio and video can falsely be |
113 // estimated as being synchronized. We don't want to trigger on those. | 125 // estimated as being synchronized. We don't want to trigger on those. |
114 if (time_since_creation < kStartupTimeMs) | 126 if (time_since_creation < kStartupTimeMs) |
115 return; | 127 return; |
116 if (std::abs(stats.sync_offset_ms) < kInSyncThresholdMs) { | 128 if (std::abs(stats.sync_offset_ms) < kInSyncThresholdMs) { |
117 if (first_time_in_sync_ == -1) { | 129 if (first_time_in_sync_ == -1) { |
118 first_time_in_sync_ = now_ms; | 130 first_time_in_sync_ = now_ms; |
119 webrtc::test::PrintResult("sync_convergence_time", | 131 webrtc::test::PrintResult("sync_convergence_time", |
120 "", | 132 "", |
121 "synchronization", | 133 "synchronization", |
122 time_since_creation, | 134 time_since_creation, |
123 "ms", | 135 "ms", |
124 false); | 136 false); |
125 } | 137 } |
126 if (time_since_creation > kMinRunTimeMs) | 138 if (time_since_creation > kMinRunTimeMs) |
127 observation_complete_.Set(); | 139 observation_complete_.Set(); |
128 } | 140 } |
129 } | 141 } |
130 | 142 |
131 void set_receive_stream(VideoReceiveStream* receive_stream) { | 143 void set_receive_stream(VideoReceiveStream* receive_stream) { |
132 rtc::CritScope lock(&crit_); | 144 rtc::CritScope lock(&crit_); |
133 receive_stream_ = receive_stream; | 145 receive_stream_ = receive_stream; |
134 } | 146 } |
135 | 147 |
148 void PrintResults() { | |
149 test::PrintResultList("stream_offset", "", "synchronization", | |
150 ValuesToString(sync_offset_ms_list_), "ms", false); | |
151 } | |
152 | |
136 private: | 153 private: |
137 Clock* const clock_; | 154 Clock* const clock_; |
138 const int64_t creation_time_ms_; | 155 const int64_t creation_time_ms_; |
139 int64_t first_time_in_sync_; | 156 int64_t first_time_in_sync_; |
140 rtc::CriticalSection crit_; | 157 rtc::CriticalSection crit_; |
141 VideoReceiveStream* receive_stream_ GUARDED_BY(crit_); | 158 VideoReceiveStream* receive_stream_ GUARDED_BY(crit_); |
159 std::vector<int> sync_offset_ms_list_; | |
142 }; | 160 }; |
143 | 161 |
144 void CallPerfTest::TestAudioVideoSync(FecMode fec, | 162 void CallPerfTest::TestAudioVideoSync(FecMode fec, |
145 CreateOrder create_first, | 163 CreateOrder create_first, |
146 float video_ntp_speed, | 164 float video_ntp_speed, |
147 float video_rtp_speed, | 165 float video_rtp_speed, |
148 float audio_rtp_speed) { | 166 float audio_rtp_speed) { |
149 const char* kSyncGroup = "av_sync"; | 167 const char* kSyncGroup = "av_sync"; |
150 const uint32_t kAudioSendSsrc = 1234; | 168 const uint32_t kAudioSendSsrc = 1234; |
151 const uint32_t kAudioRecvSsrc = 5678; | 169 const uint32_t kAudioRecvSsrc = 5678; |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
293 | 311 |
294 voe_base->DeleteChannel(send_channel_id); | 312 voe_base->DeleteChannel(send_channel_id); |
295 voe_base->DeleteChannel(recv_channel_id); | 313 voe_base->DeleteChannel(recv_channel_id); |
296 voe_base->Release(); | 314 voe_base->Release(); |
297 voe_codec->Release(); | 315 voe_codec->Release(); |
298 | 316 |
299 DestroyCalls(); | 317 DestroyCalls(); |
300 | 318 |
301 VoiceEngine::Delete(voice_engine); | 319 VoiceEngine::Delete(voice_engine); |
302 | 320 |
321 observer.PrintResults(); | |
303 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AVSyncOffsetInMs")); | 322 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AVSyncOffsetInMs")); |
304 } | 323 } |
305 | 324 |
306 TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSyncWithVideoNtpDrift) { | 325 TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSyncWithVideoNtpDrift) { |
307 TestAudioVideoSync(FecMode::kOff, CreateOrder::kAudioFirst, | 326 TestAudioVideoSync(FecMode::kOff, CreateOrder::kAudioFirst, |
308 DriftingClock::PercentsFaster(10.0f), | 327 DriftingClock::PercentsFaster(10.0f), |
309 DriftingClock::kNoDrift, DriftingClock::kNoDrift); | 328 DriftingClock::kNoDrift, DriftingClock::kNoDrift); |
310 } | 329 } |
311 | 330 |
312 TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSyncWithAudioFasterThanVideoDrift) { | 331 TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSyncWithAudioFasterThanVideoDrift) { |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
380 EXPECT_TRUE(iter != capture_time_list_.end()); | 399 EXPECT_TRUE(iter != capture_time_list_.end()); |
381 | 400 |
382 // The real capture time has been wrapped to uint32_t before converted | 401 // The real capture time has been wrapped to uint32_t before converted |
383 // to rtp timestamp in the sender side. So here we convert the estimated | 402 // to rtp timestamp in the sender side. So here we convert the estimated |
384 // capture time to a uint32_t 90k timestamp also for comparing. | 403 // capture time to a uint32_t 90k timestamp also for comparing. |
385 uint32_t estimated_capture_timestamp = | 404 uint32_t estimated_capture_timestamp = |
386 90 * static_cast<uint32_t>(video_frame.ntp_time_ms()); | 405 90 * static_cast<uint32_t>(video_frame.ntp_time_ms()); |
387 uint32_t real_capture_timestamp = iter->second; | 406 uint32_t real_capture_timestamp = iter->second; |
388 int time_offset_ms = real_capture_timestamp - estimated_capture_timestamp; | 407 int time_offset_ms = real_capture_timestamp - estimated_capture_timestamp; |
389 time_offset_ms = time_offset_ms / 90; | 408 time_offset_ms = time_offset_ms / 90; |
390 std::stringstream ss; | 409 time_offset_list_.push_back(time_offset_ms); |
391 ss << time_offset_ms; | |
392 | 410 |
393 webrtc::test::PrintResult( | |
394 "capture_ntp_time", "", "real - estimated", ss.str(), "ms", true); | |
395 EXPECT_TRUE(std::abs(time_offset_ms) < threshold_ms_); | 411 EXPECT_TRUE(std::abs(time_offset_ms) < threshold_ms_); |
396 } | 412 } |
397 | 413 |
398 Action OnSendRtp(const uint8_t* packet, size_t length) override { | 414 Action OnSendRtp(const uint8_t* packet, size_t length) override { |
399 rtc::CritScope lock(&crit_); | 415 rtc::CritScope lock(&crit_); |
400 RTPHeader header; | 416 RTPHeader header; |
401 EXPECT_TRUE(parser_->Parse(packet, length, &header)); | 417 EXPECT_TRUE(parser_->Parse(packet, length, &header)); |
402 | 418 |
403 if (!rtp_start_timestamp_set_) { | 419 if (!rtp_start_timestamp_set_) { |
404 // Calculate the rtp timestamp offset in order to calculate the real | 420 // Calculate the rtp timestamp offset in order to calculate the real |
(...skipping 22 matching lines...) Expand all Loading... | |
427 VideoEncoderConfig* encoder_config) override { | 443 VideoEncoderConfig* encoder_config) override { |
428 (*receive_configs)[0].renderer = this; | 444 (*receive_configs)[0].renderer = this; |
429 // Enable the receiver side rtt calculation. | 445 // Enable the receiver side rtt calculation. |
430 (*receive_configs)[0].rtp.rtcp_xr.receiver_reference_time_report = true; | 446 (*receive_configs)[0].rtp.rtcp_xr.receiver_reference_time_report = true; |
431 } | 447 } |
432 | 448 |
433 void PerformTest() override { | 449 void PerformTest() override { |
434 EXPECT_TRUE(Wait()) << "Timed out while waiting for " | 450 EXPECT_TRUE(Wait()) << "Timed out while waiting for " |
435 "estimated capture NTP time to be " | 451 "estimated capture NTP time to be " |
436 "within bounds."; | 452 "within bounds."; |
453 test::PrintResultList("capture_ntp_time", "", "real - estimated", | |
454 ValuesToString(time_offset_list_), "ms", true); | |
437 } | 455 } |
438 | 456 |
439 rtc::CriticalSection crit_; | 457 rtc::CriticalSection crit_; |
440 const FakeNetworkPipe::Config net_config_; | 458 const FakeNetworkPipe::Config net_config_; |
441 Clock* const clock_; | 459 Clock* const clock_; |
442 int threshold_ms_; | 460 int threshold_ms_; |
443 int start_time_ms_; | 461 int start_time_ms_; |
444 int run_time_ms_; | 462 int run_time_ms_; |
445 int64_t creation_time_ms_; | 463 int64_t creation_time_ms_; |
446 test::FrameGeneratorCapturer* capturer_; | 464 test::FrameGeneratorCapturer* capturer_; |
447 bool rtp_start_timestamp_set_; | 465 bool rtp_start_timestamp_set_; |
448 uint32_t rtp_start_timestamp_; | 466 uint32_t rtp_start_timestamp_; |
449 typedef std::map<uint32_t, uint32_t> FrameCaptureTimeList; | 467 typedef std::map<uint32_t, uint32_t> FrameCaptureTimeList; |
450 FrameCaptureTimeList capture_time_list_ GUARDED_BY(&crit_); | 468 FrameCaptureTimeList capture_time_list_ GUARDED_BY(&crit_); |
469 std::vector<int> time_offset_list_; | |
451 } test(net_config, threshold_ms, start_time_ms, run_time_ms); | 470 } test(net_config, threshold_ms, start_time_ms, run_time_ms); |
452 | 471 |
453 RunBaseTest(&test); | 472 RunBaseTest(&test); |
454 } | 473 } |
455 | 474 |
456 TEST_F(CallPerfTest, CaptureNtpTimeWithNetworkDelay) { | 475 TEST_F(CallPerfTest, CaptureNtpTimeWithNetworkDelay) { |
457 FakeNetworkPipe::Config net_config; | 476 FakeNetworkPipe::Config net_config; |
458 net_config.queue_delay_ms = 100; | 477 net_config.queue_delay_ms = 100; |
459 // TODO(wu): lower the threshold as the calculation/estimatation becomes more | 478 // TODO(wu): lower the threshold as the calculation/estimatation becomes more |
460 // accurate. | 479 // accurate. |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
536 | 555 |
537 private: | 556 private: |
538 // TODO(holmer): Run this with a timer instead of once per packet. | 557 // TODO(holmer): Run this with a timer instead of once per packet. |
539 Action OnSendRtp(const uint8_t* packet, size_t length) override { | 558 Action OnSendRtp(const uint8_t* packet, size_t length) override { |
540 VideoSendStream::Stats stats = send_stream_->GetStats(); | 559 VideoSendStream::Stats stats = send_stream_->GetStats(); |
541 if (stats.substreams.size() > 0) { | 560 if (stats.substreams.size() > 0) { |
542 RTC_DCHECK_EQ(1u, stats.substreams.size()); | 561 RTC_DCHECK_EQ(1u, stats.substreams.size()); |
543 int bitrate_kbps = | 562 int bitrate_kbps = |
544 stats.substreams.begin()->second.total_bitrate_bps / 1000; | 563 stats.substreams.begin()->second.total_bitrate_bps / 1000; |
545 if (bitrate_kbps > 0) { | 564 if (bitrate_kbps > 0) { |
546 test::PrintResult( | 565 bitrate_kbps_list.push_back(bitrate_kbps); |
547 "bitrate_stats_", | |
548 (pad_to_min_bitrate_ ? "min_transmit_bitrate" | |
549 : "without_min_transmit_bitrate"), | |
550 "bitrate_kbps", | |
551 static_cast<size_t>(bitrate_kbps), | |
552 "kbps", | |
553 false); | |
554 if (pad_to_min_bitrate_) { | 566 if (pad_to_min_bitrate_) { |
555 if (bitrate_kbps > kMinAcceptableTransmitBitrate && | 567 if (bitrate_kbps > kMinAcceptableTransmitBitrate && |
556 bitrate_kbps < kMaxAcceptableTransmitBitrate) { | 568 bitrate_kbps < kMaxAcceptableTransmitBitrate) { |
557 ++num_bitrate_observations_in_range_; | 569 ++num_bitrate_observations_in_range_; |
558 } | 570 } |
559 } else { | 571 } else { |
560 // Expect bitrate stats to roughly match the max encode bitrate. | 572 // Expect bitrate stats to roughly match the max encode bitrate. |
561 if (bitrate_kbps > (kMaxEncodeBitrateKbps - | 573 if (bitrate_kbps > (kMaxEncodeBitrateKbps - |
562 kAcceptableBitrateErrorMargin / 2) && | 574 kAcceptableBitrateErrorMargin / 2) && |
563 bitrate_kbps < (kMaxEncodeBitrateKbps + | 575 bitrate_kbps < (kMaxEncodeBitrateKbps + |
(...skipping 21 matching lines...) Expand all Loading... | |
585 VideoEncoderConfig* encoder_config) override { | 597 VideoEncoderConfig* encoder_config) override { |
586 if (pad_to_min_bitrate_) { | 598 if (pad_to_min_bitrate_) { |
587 encoder_config->min_transmit_bitrate_bps = kMinTransmitBitrateBps; | 599 encoder_config->min_transmit_bitrate_bps = kMinTransmitBitrateBps; |
588 } else { | 600 } else { |
589 RTC_DCHECK_EQ(0, encoder_config->min_transmit_bitrate_bps); | 601 RTC_DCHECK_EQ(0, encoder_config->min_transmit_bitrate_bps); |
590 } | 602 } |
591 } | 603 } |
592 | 604 |
593 void PerformTest() override { | 605 void PerformTest() override { |
594 EXPECT_TRUE(Wait()) << "Timeout while waiting for send-bitrate stats."; | 606 EXPECT_TRUE(Wait()) << "Timeout while waiting for send-bitrate stats."; |
607 test::PrintResultList( | |
608 "bitrate_stats_", | |
609 (pad_to_min_bitrate_ ? "min_transmit_bitrate" | |
610 : "without_min_transmit_bitrate"), | |
611 "bitrate_kbps", ValuesToString(bitrate_kbps_list), "kbps", false); | |
595 } | 612 } |
596 | 613 |
597 VideoSendStream* send_stream_; | 614 VideoSendStream* send_stream_; |
598 const bool pad_to_min_bitrate_; | 615 const bool pad_to_min_bitrate_; |
599 int num_bitrate_observations_in_range_; | 616 int num_bitrate_observations_in_range_; |
617 std::vector<size_t> bitrate_kbps_list; | |
600 } test(pad_to_min_bitrate); | 618 } test(pad_to_min_bitrate); |
601 | 619 |
602 fake_encoder_.SetMaxBitrate(kMaxEncodeBitrateKbps); | 620 fake_encoder_.SetMaxBitrate(kMaxEncodeBitrateKbps); |
603 RunBaseTest(&test); | 621 RunBaseTest(&test); |
604 } | 622 } |
605 | 623 |
606 TEST_F(CallPerfTest, PadsToMinTransmitBitrate) { TestMinTransmitBitrate(true); } | 624 TEST_F(CallPerfTest, PadsToMinTransmitBitrate) { TestMinTransmitBitrate(true); } |
607 | 625 |
608 TEST_F(CallPerfTest, NoPadWithoutMinTransmitBitrate) { | 626 TEST_F(CallPerfTest, NoPadWithoutMinTransmitBitrate) { |
609 TestMinTransmitBitrate(false); | 627 TestMinTransmitBitrate(false); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
693 int encoder_inits_; | 711 int encoder_inits_; |
694 uint32_t last_set_bitrate_; | 712 uint32_t last_set_bitrate_; |
695 VideoSendStream* send_stream_; | 713 VideoSendStream* send_stream_; |
696 VideoEncoderConfig encoder_config_; | 714 VideoEncoderConfig encoder_config_; |
697 } test; | 715 } test; |
698 | 716 |
699 RunBaseTest(&test); | 717 RunBaseTest(&test); |
700 } | 718 } |
701 | 719 |
702 } // namespace webrtc | 720 } // namespace webrtc |
OLD | NEW |