2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
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.
16 #include "testing/gtest/include/gtest/gtest.h"
18 #include "webrtc/call.h"
19 #include "webrtc/modules/remote_bitrate_estimator/include/rtp_to_ntp.h"
20 #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"
23 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
24 #include "webrtc/test/direct_transport.h"
25 #include "webrtc/test/fake_audio_device.h"
26 #include "webrtc/test/fake_decoder.h"
27 #include "webrtc/test/fake_encoder.h"
28 #include "webrtc/test/frame_generator.h"
29 #include "webrtc/test/frame_generator_capturer.h"
30 #include "webrtc/test/rtp_rtcp_observer.h"
31 #include "webrtc/test/testsupport/fileutils.h"
32 #include "webrtc/test/testsupport/perf_test.h"
33 #include "webrtc/video/transport_adapter.h"
34 #include "webrtc/voice_engine/include/voe_base.h"
35 #include "webrtc/voice_engine/include/voe_codec.h"
36 #include "webrtc/voice_engine/include/voe_network.h"
37 #include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
38 #include "webrtc/voice_engine/include/voe_video_sync.h"
42 static unsigned int kLongTimeoutMs = 120 * 1000;
43 static const uint32_t kSendSsrc = 0x654321;
44 static const uint32_t kReceiverLocalSsrc = 0x123456;
45 static const uint8_t kSendPayloadType = 125;
47 class CallPerfTest : public ::testing::Test {
50 class SyncRtcpObserver : public test::RtpRtcpObserver {
52 explicit SyncRtcpObserver(const FakeNetworkPipe::Config& config)
53 : test::RtpRtcpObserver(kLongTimeoutMs, config),
54 critical_section_(CriticalSectionWrapper::CreateCriticalSection()) {}
56 virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
57 RTCPUtility::RTCPParserV2 parser(packet, length, true);
58 EXPECT_TRUE(parser.IsValid());
60 for (RTCPUtility::RTCPPacketTypes packet_type = parser.Begin();
61 packet_type != RTCPUtility::kRtcpNotValidCode;
62 packet_type = parser.Iterate()) {
63 if (packet_type == RTCPUtility::kRtcpSrCode) {
64 const RTCPUtility::RTCPPacket& packet = parser.Packet();
65 synchronization::RtcpMeasurement ntp_rtp_pair(
66 packet.SR.NTPMostSignificant,
67 packet.SR.NTPLeastSignificant,
68 packet.SR.RTPTimestamp);
69 StoreNtpRtpPair(ntp_rtp_pair);
75 int64_t RtpTimestampToNtp(uint32_t timestamp) const {
76 CriticalSectionScoped cs(critical_section_.get());
77 int64_t timestamp_in_ms = -1;
78 if (ntp_rtp_pairs_.size() == 2) {
79 // TODO(stefan): We can't EXPECT_TRUE on this call due to a bug in the
80 // RTCP sender where it sends RTCP SR before any RTP packets, which leads
81 // to a bogus NTP/RTP mapping.
82 synchronization::RtpToNtpMs(timestamp, ntp_rtp_pairs_, ×tamp_in_ms);
83 return timestamp_in_ms;
89 void StoreNtpRtpPair(synchronization::RtcpMeasurement ntp_rtp_pair) {
90 CriticalSectionScoped cs(critical_section_.get());
91 for (synchronization::RtcpList::iterator it = ntp_rtp_pairs_.begin();
92 it != ntp_rtp_pairs_.end();
94 if (ntp_rtp_pair.ntp_secs == it->ntp_secs &&
95 ntp_rtp_pair.ntp_frac == it->ntp_frac) {
96 // This RTCP has already been added to the list.
100 // We need two RTCP SR reports to map between RTP and NTP. More than two
101 // will not improve the mapping.
102 if (ntp_rtp_pairs_.size() == 2) {
103 ntp_rtp_pairs_.pop_back();
105 ntp_rtp_pairs_.push_front(ntp_rtp_pair);
108 scoped_ptr<CriticalSectionWrapper> critical_section_;
109 synchronization::RtcpList ntp_rtp_pairs_;
112 class VideoRtcpAndSyncObserver : public SyncRtcpObserver, public VideoRenderer {
113 static const int kInSyncThresholdMs = 50;
114 static const int kStartupTimeMs = 2000;
115 static const int kMinRunTimeMs = 30000;
118 VideoRtcpAndSyncObserver(Clock* clock,
120 VoEVideoSync* voe_sync,
121 SyncRtcpObserver* audio_observer)
122 : SyncRtcpObserver(FakeNetworkPipe::Config()),
124 voe_channel_(voe_channel),
126 audio_observer_(audio_observer),
127 creation_time_ms_(clock_->TimeInMilliseconds()),
128 first_time_in_sync_(-1) {}
130 virtual void RenderFrame(const I420VideoFrame& video_frame,
131 int time_to_render_ms) OVERRIDE {
132 int64_t now_ms = clock_->TimeInMilliseconds();
133 uint32_t playout_timestamp = 0;
134 if (voe_sync_->GetPlayoutTimestamp(voe_channel_, playout_timestamp) != 0)
136 int64_t latest_audio_ntp =
137 audio_observer_->RtpTimestampToNtp(playout_timestamp);
138 int64_t latest_video_ntp = RtpTimestampToNtp(video_frame.timestamp());
139 if (latest_audio_ntp < 0 || latest_video_ntp < 0)
141 int time_until_render_ms =
142 std::max(0, static_cast<int>(video_frame.render_time_ms() - now_ms));
143 latest_video_ntp += time_until_render_ms;
144 int64_t stream_offset = latest_audio_ntp - latest_video_ntp;
145 std::stringstream ss;
147 webrtc::test::PrintResult(
148 "stream_offset", "", "synchronization", ss.str(), "ms", false);
149 int64_t time_since_creation = now_ms - creation_time_ms_;
150 // During the first couple of seconds audio and video can falsely be
151 // estimated as being synchronized. We don't want to trigger on those.
152 if (time_since_creation < kStartupTimeMs)
154 if (abs(latest_audio_ntp - latest_video_ntp) < kInSyncThresholdMs) {
155 if (first_time_in_sync_ == -1) {
156 first_time_in_sync_ = now_ms;
157 webrtc::test::PrintResult("sync_convergence_time",
164 if (time_since_creation > kMinRunTimeMs)
165 observation_complete_->Set();
172 VoEVideoSync* voe_sync_;
173 SyncRtcpObserver* audio_observer_;
174 int64_t creation_time_ms_;
175 int64_t first_time_in_sync_;
178 TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSync) {
179 VoiceEngine* voice_engine = VoiceEngine::Create();
180 VoEBase* voe_base = VoEBase::GetInterface(voice_engine);
181 VoECodec* voe_codec = VoECodec::GetInterface(voice_engine);
182 VoENetwork* voe_network = VoENetwork::GetInterface(voice_engine);
183 VoEVideoSync* voe_sync = VoEVideoSync::GetInterface(voice_engine);
184 const std::string audio_filename =
185 test::ResourcePath("voice_engine/audio_long16", "pcm");
186 ASSERT_STRNE("", audio_filename.c_str());
187 test::FakeAudioDevice fake_audio_device(Clock::GetRealTimeClock(),
189 EXPECT_EQ(0, voe_base->Init(&fake_audio_device, NULL));
190 int channel = voe_base->CreateChannel();
192 FakeNetworkPipe::Config net_config;
193 net_config.queue_delay_ms = 500;
194 SyncRtcpObserver audio_observer(net_config);
195 VideoRtcpAndSyncObserver observer(
196 Clock::GetRealTimeClock(), channel, voe_sync, &audio_observer);
198 Call::Config receiver_config(observer.ReceiveTransport());
199 receiver_config.voice_engine = voice_engine;
200 scoped_ptr<Call> sender_call(
201 Call::Create(Call::Config(observer.SendTransport())));
202 scoped_ptr<Call> receiver_call(Call::Create(receiver_config));
203 CodecInst isac = {103, "ISAC", 16000, 480, 1, 32000};
204 EXPECT_EQ(0, voe_codec->SetSendCodec(channel, isac));
206 class VoicePacketReceiver : public PacketReceiver {
208 VoicePacketReceiver(int channel, VoENetwork* voe_network)
210 voe_network_(voe_network),
211 parser_(RtpHeaderParser::Create()) {}
212 virtual bool DeliverPacket(const uint8_t* packet, size_t length) {
214 if (parser_->IsRtcp(packet, static_cast<int>(length))) {
215 ret = voe_network_->ReceivedRTCPPacket(
216 channel_, packet, static_cast<unsigned int>(length));
218 ret = voe_network_->ReceivedRTPPacket(
219 channel_, packet, static_cast<unsigned int>(length));
226 VoENetwork* voe_network_;
227 scoped_ptr<RtpHeaderParser> parser_;
228 } voe_packet_receiver(channel, voe_network);
230 audio_observer.SetReceivers(&voe_packet_receiver, &voe_packet_receiver);
232 internal::TransportAdapter transport_adapter(audio_observer.SendTransport());
234 voe_network->RegisterExternalTransport(channel, transport_adapter));
236 observer.SetReceivers(receiver_call->Receiver(), sender_call->Receiver());
238 test::FakeEncoder fake_encoder(Clock::GetRealTimeClock());
239 test::FakeDecoder fake_decoder;
241 VideoSendStream::Config send_config = sender_call->GetDefaultSendConfig();
242 send_config.rtp.ssrcs.push_back(kSendSsrc);
243 send_config.encoder = &fake_encoder;
244 send_config.internal_source = false;
245 test::FakeEncoder::SetCodecSettings(&send_config.codec, 1);
246 send_config.codec.plType = kSendPayloadType;
248 VideoReceiveStream::Config receive_config =
249 receiver_call->GetDefaultReceiveConfig();
250 receive_config.codecs.clear();
251 receive_config.codecs.push_back(send_config.codec);
252 ExternalVideoDecoder decoder;
253 decoder.decoder = &fake_decoder;
254 decoder.payload_type = send_config.codec.plType;
255 receive_config.external_decoders.push_back(decoder);
256 receive_config.rtp.remote_ssrc = send_config.rtp.ssrcs[0];
257 receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
258 receive_config.renderer = &observer;
259 receive_config.audio_channel_id = channel;
261 VideoSendStream* send_stream =
262 sender_call->CreateVideoSendStream(send_config);
263 VideoReceiveStream* receive_stream =
264 receiver_call->CreateVideoReceiveStream(receive_config);
265 scoped_ptr<test::FrameGeneratorCapturer> capturer(
266 test::FrameGeneratorCapturer::Create(send_stream->Input(),
267 send_config.codec.width,
268 send_config.codec.height,
270 Clock::GetRealTimeClock()));
271 receive_stream->StartReceiving();
272 send_stream->StartSending();
275 fake_audio_device.Start();
276 EXPECT_EQ(0, voe_base->StartPlayout(channel));
277 EXPECT_EQ(0, voe_base->StartReceive(channel));
278 EXPECT_EQ(0, voe_base->StartSend(channel));
280 EXPECT_EQ(kEventSignaled, observer.Wait())
281 << "Timed out while waiting for audio and video to be synchronized.";
283 EXPECT_EQ(0, voe_base->StopSend(channel));
284 EXPECT_EQ(0, voe_base->StopReceive(channel));
285 EXPECT_EQ(0, voe_base->StopPlayout(channel));
286 fake_audio_device.Stop();
289 send_stream->StopSending();
290 receive_stream->StopReceiving();
291 observer.StopSending();
292 audio_observer.StopSending();
294 voe_base->DeleteChannel(channel);
296 voe_codec->Release();
297 voe_network->Release();
299 sender_call->DestroyVideoSendStream(send_stream);
300 receiver_call->DestroyVideoReceiveStream(receive_stream);
301 VoiceEngine::Delete(voice_engine);
303 } // namespace webrtc