Index: webrtc/call/call_perf_tests.cc |
diff --git a/webrtc/call/call_perf_tests.cc b/webrtc/call/call_perf_tests.cc |
index 43618722096d3a104cf98b1d3b43debaceb7c39f..beb05a047d9f9a11f8268142754399538479771e 100644 |
--- a/webrtc/call/call_perf_tests.cc |
+++ b/webrtc/call/call_perf_tests.cc |
@@ -7,7 +7,9 @@ |
* in the file PATENTS. All contributing project authors may |
* be found in the AUTHORS file in the root of the source tree. |
*/ |
+ |
#include <algorithm> |
+#include <limits> |
#include <memory> |
#include <sstream> |
#include <string> |
@@ -33,6 +35,7 @@ |
#include "webrtc/test/fake_encoder.h" |
#include "webrtc/test/frame_generator.h" |
#include "webrtc/test/frame_generator_capturer.h" |
+#include "webrtc/test/histogram.h" |
#include "webrtc/test/rtp_rtcp_observer.h" |
#include "webrtc/test/testsupport/fileutils.h" |
#include "webrtc/test/testsupport/perf_test.h" |
@@ -71,100 +74,35 @@ class CallPerfTest : public test::CallTest { |
int run_time_ms); |
}; |
-class SyncRtcpObserver : public test::RtpRtcpObserver { |
- public: |
- SyncRtcpObserver() : test::RtpRtcpObserver(CallPerfTest::kLongTimeoutMs) {} |
- |
- Action OnSendRtcp(const uint8_t* packet, size_t length) override { |
- RTCPUtility::RTCPParserV2 parser(packet, length, true); |
- EXPECT_TRUE(parser.IsValid()); |
- |
- for (RTCPUtility::RTCPPacketTypes packet_type = parser.Begin(); |
- packet_type != RTCPUtility::RTCPPacketTypes::kInvalid; |
- packet_type = parser.Iterate()) { |
- if (packet_type == RTCPUtility::RTCPPacketTypes::kSr) { |
- const RTCPUtility::RTCPPacket& packet = parser.Packet(); |
- RtcpMeasurement ntp_rtp_pair( |
- packet.SR.NTPMostSignificant, |
- packet.SR.NTPLeastSignificant, |
- packet.SR.RTPTimestamp); |
- StoreNtpRtpPair(ntp_rtp_pair); |
- } |
- } |
- return SEND_PACKET; |
- } |
- |
- int64_t RtpTimestampToNtp(uint32_t timestamp) const { |
- rtc::CritScope lock(&crit_); |
- int64_t timestamp_in_ms = -1; |
- if (ntp_rtp_pairs_.size() == 2) { |
- // TODO(stefan): We can't EXPECT_TRUE on this call due to a bug in the |
- // RTCP sender where it sends RTCP SR before any RTP packets, which leads |
- // to a bogus NTP/RTP mapping. |
- RtpToNtpMs(timestamp, ntp_rtp_pairs_, ×tamp_in_ms); |
- return timestamp_in_ms; |
- } |
- return -1; |
- } |
- |
- private: |
- void StoreNtpRtpPair(RtcpMeasurement ntp_rtp_pair) { |
- rtc::CritScope lock(&crit_); |
- for (RtcpList::iterator it = ntp_rtp_pairs_.begin(); |
- it != ntp_rtp_pairs_.end(); |
- ++it) { |
- if (ntp_rtp_pair.ntp_secs == it->ntp_secs && |
- ntp_rtp_pair.ntp_frac == it->ntp_frac) { |
- // This RTCP has already been added to the list. |
- return; |
- } |
- } |
- // We need two RTCP SR reports to map between RTP and NTP. More than two |
- // will not improve the mapping. |
- if (ntp_rtp_pairs_.size() == 2) { |
- ntp_rtp_pairs_.pop_back(); |
- } |
- ntp_rtp_pairs_.push_front(ntp_rtp_pair); |
- } |
- |
- rtc::CriticalSection crit_; |
- RtcpList ntp_rtp_pairs_ GUARDED_BY(crit_); |
-}; |
- |
-class VideoRtcpAndSyncObserver : public SyncRtcpObserver, public VideoRenderer { |
+class VideoRtcpAndSyncObserver : public test::RtpRtcpObserver, |
+ public VideoRenderer { |
static const int kInSyncThresholdMs = 50; |
static const int kStartupTimeMs = 2000; |
static const int kMinRunTimeMs = 30000; |
public: |
- VideoRtcpAndSyncObserver(Clock* clock, |
- int voe_channel, |
- VoEVideoSync* voe_sync, |
- SyncRtcpObserver* audio_observer) |
- : clock_(clock), |
- voe_channel_(voe_channel), |
- voe_sync_(voe_sync), |
- audio_observer_(audio_observer), |
+ explicit VideoRtcpAndSyncObserver(Clock* clock) |
+ : test::RtpRtcpObserver(CallPerfTest::kLongTimeoutMs), |
+ clock_(clock), |
creation_time_ms_(clock_->TimeInMilliseconds()), |
- first_time_in_sync_(-1) {} |
+ first_time_in_sync_(-1), |
+ receive_stream_(nullptr) {} |
void RenderFrame(const VideoFrame& video_frame, |
int time_to_render_ms) override { |
- int64_t now_ms = clock_->TimeInMilliseconds(); |
- uint32_t playout_timestamp = 0; |
- if (voe_sync_->GetPlayoutTimestamp(voe_channel_, playout_timestamp) != 0) |
- return; |
- int64_t latest_audio_ntp = |
- audio_observer_->RtpTimestampToNtp(playout_timestamp); |
- int64_t latest_video_ntp = RtpTimestampToNtp(video_frame.timestamp()); |
- if (latest_audio_ntp < 0 || latest_video_ntp < 0) |
+ VideoReceiveStream::Stats stats; |
+ { |
+ rtc::CritScope lock(&crit_); |
+ if (receive_stream_) |
+ stats = receive_stream_->GetStats(); |
+ } |
+ if (stats.sync_offset_ms == std::numeric_limits<int>::max()) |
return; |
- int time_until_render_ms = |
- std::max(0, static_cast<int>(video_frame.render_time_ms() - now_ms)); |
- latest_video_ntp += time_until_render_ms; |
- int64_t stream_offset = latest_audio_ntp - latest_video_ntp; |
+ |
+ int64_t now_ms = clock_->TimeInMilliseconds(); |
+ |
std::stringstream ss; |
- ss << stream_offset; |
+ ss << stats.sync_offset_ms; |
webrtc::test::PrintResult("stream_offset", |
"", |
"synchronization", |
@@ -176,7 +114,7 @@ class VideoRtcpAndSyncObserver : public SyncRtcpObserver, public VideoRenderer { |
// estimated as being synchronized. We don't want to trigger on those. |
if (time_since_creation < kStartupTimeMs) |
return; |
- if (std::abs(latest_audio_ntp - latest_video_ntp) < kInSyncThresholdMs) { |
+ if (std::abs(stats.sync_offset_ms) < kInSyncThresholdMs) { |
if (first_time_in_sync_ == -1) { |
first_time_in_sync_ = now_ms; |
webrtc::test::PrintResult("sync_convergence_time", |
@@ -193,13 +131,17 @@ class VideoRtcpAndSyncObserver : public SyncRtcpObserver, public VideoRenderer { |
bool IsTextureSupported() const override { return false; } |
+ void set_receive_stream(VideoReceiveStream* receive_stream) { |
+ rtc::CritScope lock(&crit_); |
+ receive_stream_ = receive_stream; |
+ } |
+ |
private: |
Clock* const clock_; |
- const int voe_channel_; |
- VoEVideoSync* const voe_sync_; |
- SyncRtcpObserver* const audio_observer_; |
const int64_t creation_time_ms_; |
int64_t first_time_in_sync_; |
+ rtc::CriticalSection crit_; |
+ VideoReceiveStream* receive_stream_ GUARDED_BY(crit_); |
}; |
void CallPerfTest::TestAudioVideoSync(FecMode fec, |
@@ -238,11 +180,11 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, |
std::unique_ptr<RtpHeaderParser> parser_; |
}; |
+ test::ClearHistograms(); |
VoiceEngine* voice_engine = VoiceEngine::Create(); |
VoEBase* voe_base = VoEBase::GetInterface(voice_engine); |
VoECodec* voe_codec = VoECodec::GetInterface(voice_engine); |
VoENetwork* voe_network = VoENetwork::GetInterface(voice_engine); |
- VoEVideoSync* voe_sync = VoEVideoSync::GetInterface(voice_engine); |
const std::string audio_filename = |
test::ResourcePath("voice_engine/audio_long16", "pcm"); |
ASSERT_STRNE("", audio_filename.c_str()); |
@@ -254,8 +196,6 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, |
int send_channel_id = voe_base->CreateChannel(voe_config); |
int recv_channel_id = voe_base->CreateChannel(); |
- SyncRtcpObserver audio_observer; |
- |
AudioState::Config send_audio_state_config; |
send_audio_state_config.voice_engine = voice_engine; |
Call::Config sender_config; |
@@ -267,14 +207,16 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, |
AudioPacketReceiver voe_send_packet_receiver(send_channel_id, voe_network); |
AudioPacketReceiver voe_recv_packet_receiver(recv_channel_id, voe_network); |
+ VideoRtcpAndSyncObserver observer(Clock::GetRealTimeClock()); |
+ |
FakeNetworkPipe::Config net_config; |
net_config.queue_delay_ms = 500; |
net_config.loss_percent = 5; |
test::PacketTransport audio_send_transport( |
- nullptr, &audio_observer, test::PacketTransport::kSender, net_config); |
+ nullptr, &observer, test::PacketTransport::kSender, net_config); |
audio_send_transport.SetReceiver(&voe_recv_packet_receiver); |
test::PacketTransport audio_receive_transport( |
- nullptr, &audio_observer, test::PacketTransport::kReceiver, net_config); |
+ nullptr, &observer, test::PacketTransport::kReceiver, net_config); |
audio_receive_transport.SetReceiver(&voe_send_packet_receiver); |
internal::TransportAdapter send_transport_adapter(&audio_send_transport); |
@@ -287,9 +229,6 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, |
EXPECT_EQ(0, voe_network->RegisterExternalTransport(recv_channel_id, |
recv_transport_adapter)); |
- VideoRtcpAndSyncObserver observer(Clock::GetRealTimeClock(), recv_channel_id, |
- voe_sync, &audio_observer); |
- |
test::PacketTransport sync_send_transport(sender_call_.get(), &observer, |
test::PacketTransport::kSender, |
FakeNetworkPipe::Config()); |
@@ -341,7 +280,8 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, |
audio_receive_stream = |
receiver_call_->CreateAudioReceiveStream(audio_recv_config); |
} |
- |
+ EXPECT_EQ(1u, video_receive_streams_.size()); |
+ observer.set_receive_stream(video_receive_streams_[0]); |
DriftingClock drifting_clock(clock_, video_ntp_speed); |
CreateFrameGeneratorCapturerWithDrift(&drifting_clock, video_rtp_speed); |
@@ -376,11 +316,12 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, |
voe_base->Release(); |
voe_codec->Release(); |
voe_network->Release(); |
- voe_sync->Release(); |
DestroyCalls(); |
VoiceEngine::Delete(voice_engine); |
+ |
+ EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.AVSyncOffsetInMs")); |
} |
TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSyncWithVideoNtpDrift) { |