OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include <numeric> |
5 #include <utility> | 6 #include <utility> |
6 | 7 |
7 #include "base/base64.h" | 8 #include "base/base64.h" |
8 #include "base/files/file_util.h" | 9 #include "base/files/file_util.h" |
9 #include "base/macros.h" | 10 #include "base/macros.h" |
10 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
11 #include "base/message_loop/message_loop.h" | 12 #include "base/message_loop/message_loop.h" |
12 #include "base/rand_util.h" | 13 #include "base/rand_util.h" |
13 #include "base/run_loop.h" | 14 #include "base/run_loop.h" |
14 #include "base/single_thread_task_runner.h" | 15 #include "base/single_thread_task_runner.h" |
15 #include "base/synchronization/waitable_event.h" | 16 #include "base/synchronization/waitable_event.h" |
16 #include "base/task_runner_util.h" | 17 #include "base/task_runner_util.h" |
17 #include "base/threading/thread_task_runner_handle.h" | 18 #include "base/threading/thread_task_runner_handle.h" |
18 #include "jingle/glue/thread_wrapper.h" | 19 #include "jingle/glue/thread_wrapper.h" |
19 #include "net/test/test_data_directory.h" | 20 #include "net/test/test_data_directory.h" |
20 #include "net/url_request/url_request_context_getter.h" | 21 #include "net/url_request/url_request_context_getter.h" |
21 #include "remoting/base/rsa_key_pair.h" | 22 #include "remoting/base/rsa_key_pair.h" |
22 #include "remoting/base/url_request.h" | 23 #include "remoting/base/url_request.h" |
23 #include "remoting/client/audio_player.h" | 24 #include "remoting/client/audio_player.h" |
24 #include "remoting/client/chromoting_client.h" | 25 #include "remoting/client/chromoting_client.h" |
25 #include "remoting/client/client_context.h" | 26 #include "remoting/client/client_context.h" |
26 #include "remoting/client/client_user_interface.h" | 27 #include "remoting/client/client_user_interface.h" |
27 #include "remoting/codec/video_decoder_verbatim.h" | 28 #include "remoting/client/software_video_renderer.h" |
28 #include "remoting/codec/video_decoder_vpx.h" | |
29 #include "remoting/host/chromoting_host.h" | 29 #include "remoting/host/chromoting_host.h" |
30 #include "remoting/host/chromoting_host_context.h" | 30 #include "remoting/host/chromoting_host_context.h" |
31 #include "remoting/host/fake_desktop_environment.h" | 31 #include "remoting/host/fake_desktop_environment.h" |
32 #include "remoting/protocol/auth_util.h" | 32 #include "remoting/protocol/auth_util.h" |
33 #include "remoting/protocol/client_authentication_config.h" | 33 #include "remoting/protocol/client_authentication_config.h" |
34 #include "remoting/protocol/frame_consumer.h" | 34 #include "remoting/protocol/frame_consumer.h" |
| 35 #include "remoting/protocol/frame_stats.h" |
35 #include "remoting/protocol/jingle_session_manager.h" | 36 #include "remoting/protocol/jingle_session_manager.h" |
36 #include "remoting/protocol/me2me_host_authenticator_factory.h" | 37 #include "remoting/protocol/me2me_host_authenticator_factory.h" |
37 #include "remoting/protocol/session_config.h" | 38 #include "remoting/protocol/session_config.h" |
38 #include "remoting/protocol/transport_context.h" | 39 #include "remoting/protocol/transport_context.h" |
39 #include "remoting/protocol/video_frame_pump.h" | 40 #include "remoting/protocol/video_frame_pump.h" |
40 #include "remoting/protocol/video_renderer.h" | 41 #include "remoting/protocol/video_renderer.h" |
41 #include "remoting/signaling/fake_signal_strategy.h" | 42 #include "remoting/signaling/fake_signal_strategy.h" |
42 #include "remoting/test/cyclic_frame_generator.h" | 43 #include "remoting/test/cyclic_frame_generator.h" |
43 #include "remoting/test/fake_network_dispatcher.h" | 44 #include "remoting/test/fake_network_dispatcher.h" |
44 #include "remoting/test/fake_port_allocator.h" | 45 #include "remoting/test/fake_port_allocator.h" |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 | 80 |
80 class FakeCursorShapeStub : public protocol::CursorShapeStub { | 81 class FakeCursorShapeStub : public protocol::CursorShapeStub { |
81 public: | 82 public: |
82 FakeCursorShapeStub() {} | 83 FakeCursorShapeStub() {} |
83 ~FakeCursorShapeStub() override {} | 84 ~FakeCursorShapeStub() override {} |
84 | 85 |
85 // protocol::CursorShapeStub interface. | 86 // protocol::CursorShapeStub interface. |
86 void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) override{}; | 87 void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) override{}; |
87 }; | 88 }; |
88 | 89 |
89 std::unique_ptr<webrtc::DesktopFrame> DoDecodeFrame( | |
90 VideoDecoder* decoder, | |
91 VideoPacket* packet, | |
92 std::unique_ptr<webrtc::DesktopFrame> frame) { | |
93 if (!decoder->DecodePacket(*packet, frame.get())) | |
94 frame.reset(); | |
95 return frame; | |
96 } | |
97 | |
98 } // namespace | 90 } // namespace |
99 | 91 |
100 class ProtocolPerfTest | 92 class ProtocolPerfTest |
101 : public testing::Test, | 93 : public testing::Test, |
102 public testing::WithParamInterface<NetworkPerformanceParams>, | 94 public testing::WithParamInterface<NetworkPerformanceParams>, |
103 public ClientUserInterface, | 95 public ClientUserInterface, |
104 public protocol::VideoRenderer, | |
105 public protocol::VideoStub, | |
106 public protocol::FrameConsumer, | 96 public protocol::FrameConsumer, |
| 97 public protocol::FrameStatsConsumer, |
107 public HostStatusObserver { | 98 public HostStatusObserver { |
108 public: | 99 public: |
109 ProtocolPerfTest() | 100 ProtocolPerfTest() |
110 : host_thread_("host"), | 101 : host_thread_("host"), |
111 capture_thread_("capture"), | 102 capture_thread_("capture"), |
112 encode_thread_("encode"), | 103 encode_thread_("encode"), |
113 decode_thread_("decode") { | 104 decode_thread_("decode") { |
114 protocol::VideoFramePump::EnableTimestampsForTests(); | 105 protocol::VideoFramePump::EnableTimestampsForTests(); |
115 host_thread_.StartWithOptions( | 106 host_thread_.StartWithOptions( |
116 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); | 107 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
(...skipping 25 matching lines...) Expand all Loading... |
142 void SetPairingResponse( | 133 void SetPairingResponse( |
143 const protocol::PairingResponse& pairing_response) override {} | 134 const protocol::PairingResponse& pairing_response) override {} |
144 void DeliverHostMessage(const protocol::ExtensionMessage& message) override {} | 135 void DeliverHostMessage(const protocol::ExtensionMessage& message) override {} |
145 void SetDesktopSize(const webrtc::DesktopSize& size, | 136 void SetDesktopSize(const webrtc::DesktopSize& size, |
146 const webrtc::DesktopVector& dpi) override {} | 137 const webrtc::DesktopVector& dpi) override {} |
147 protocol::ClipboardStub* GetClipboardStub() override { return nullptr; } | 138 protocol::ClipboardStub* GetClipboardStub() override { return nullptr; } |
148 protocol::CursorShapeStub* GetCursorShapeStub() override { | 139 protocol::CursorShapeStub* GetCursorShapeStub() override { |
149 return &cursor_shape_stub_; | 140 return &cursor_shape_stub_; |
150 } | 141 } |
151 | 142 |
152 // VideoRenderer interface. | |
153 bool Initialize(const ClientContext& client_context, | |
154 protocol::FrameStatsConsumer* stats_consumer) override { | |
155 return true; | |
156 } | |
157 void OnSessionConfig(const protocol::SessionConfig& config) override {} | |
158 protocol::VideoStub* GetVideoStub() override { return this; } | |
159 protocol::FrameConsumer* GetFrameConsumer() override { return this; } | |
160 protocol::FrameStatsConsumer* GetFrameStatsConsumer() override { | |
161 return nullptr; | |
162 } | |
163 | |
164 // protocol::VideoStub interface. | |
165 void ProcessVideoPacket(std::unique_ptr<VideoPacket> packet, | |
166 const base::Closure& done) override { | |
167 if (packet->data().empty()) { | |
168 // Ignore keep-alive packets | |
169 done.Run(); | |
170 return; | |
171 } | |
172 | |
173 if (packet->format().has_screen_width() && | |
174 packet->format().has_screen_height()) { | |
175 frame_size_.set(packet->format().screen_width(), | |
176 packet->format().screen_height()); | |
177 } | |
178 | |
179 std::unique_ptr<webrtc::DesktopFrame> frame( | |
180 new webrtc::BasicDesktopFrame(frame_size_)); | |
181 base::PostTaskAndReplyWithResult( | |
182 decode_thread_.task_runner().get(), FROM_HERE, | |
183 base::Bind(&DoDecodeFrame, video_decoder_.get(), packet.get(), | |
184 base::Passed(&frame)), | |
185 base::Bind(&ProtocolPerfTest::OnFrameDecoded, base::Unretained(this), | |
186 base::Passed(&packet), done)); | |
187 } | |
188 | |
189 void OnFrameDecoded(std::unique_ptr<VideoPacket> packet, | |
190 const base::Closure& done, | |
191 std::unique_ptr<webrtc::DesktopFrame> frame) { | |
192 last_video_packet_ = std::move(packet); | |
193 DrawFrame(std::move(frame), done); | |
194 } | |
195 | |
196 // protocol::FrameConsumer interface. | 143 // protocol::FrameConsumer interface. |
197 std::unique_ptr<webrtc::DesktopFrame> AllocateFrame( | 144 std::unique_ptr<webrtc::DesktopFrame> AllocateFrame( |
198 const webrtc::DesktopSize& size) override { | 145 const webrtc::DesktopSize& size) override { |
199 return base::MakeUnique<webrtc::BasicDesktopFrame>(size); | 146 return base::MakeUnique<webrtc::BasicDesktopFrame>(size); |
200 } | 147 } |
201 | 148 |
202 void DrawFrame(std::unique_ptr<webrtc::DesktopFrame> frame, | 149 void DrawFrame(std::unique_ptr<webrtc::DesktopFrame> frame, |
203 const base::Closure& done) override { | 150 const base::Closure& done) override { |
204 last_video_frame_ = std::move(frame); | 151 last_video_frame_ = std::move(frame); |
205 if (!on_frame_task_.is_null()) | 152 if (!on_frame_task_.is_null()) |
206 on_frame_task_.Run(); | 153 on_frame_task_.Run(); |
207 if (!done.is_null()) | 154 if (!done.is_null()) |
208 done.Run(); | 155 done.Run(); |
209 } | 156 } |
210 | 157 |
211 protocol::FrameConsumer::PixelFormat GetPixelFormat() override { | 158 protocol::FrameConsumer::PixelFormat GetPixelFormat() override { |
212 return FORMAT_BGRA; | 159 return FORMAT_BGRA; |
213 } | 160 } |
214 | 161 |
| 162 // FrameStatsConsumer interface. |
| 163 void OnVideoFrameStats(const protocol::FrameStats& frame_stats) override { |
| 164 frame_stats_.push_back(frame_stats); |
| 165 |
| 166 if (waiting_frame_stats_loop_ && |
| 167 frame_stats_.size() >= num_expected_frame_stats_) { |
| 168 waiting_frame_stats_loop_->Quit(); |
| 169 } |
| 170 } |
| 171 |
215 // HostStatusObserver interface. | 172 // HostStatusObserver interface. |
216 void OnClientConnected(const std::string& jid) override { | 173 void OnClientConnected(const std::string& jid) override { |
217 message_loop_.task_runner()->PostTask( | 174 message_loop_.task_runner()->PostTask( |
218 FROM_HERE, base::Bind(&ProtocolPerfTest::OnHostConnectedMainThread, | 175 FROM_HERE, base::Bind(&ProtocolPerfTest::OnHostConnectedMainThread, |
219 base::Unretained(this))); | 176 base::Unretained(this))); |
220 } | 177 } |
221 | 178 |
222 protected: | 179 protected: |
223 void WaitConnected() { | 180 void WaitConnected() { |
224 client_connected_ = false; | 181 client_connected_ = false; |
(...skipping 10 matching lines...) Expand all Loading... |
235 if (client_connected_) | 192 if (client_connected_) |
236 connecting_loop_->Quit(); | 193 connecting_loop_->Quit(); |
237 } | 194 } |
238 | 195 |
239 std::unique_ptr<webrtc::DesktopFrame> ReceiveFrame() { | 196 std::unique_ptr<webrtc::DesktopFrame> ReceiveFrame() { |
240 last_video_frame_.reset(); | 197 last_video_frame_.reset(); |
241 | 198 |
242 waiting_frames_loop_.reset(new base::RunLoop()); | 199 waiting_frames_loop_.reset(new base::RunLoop()); |
243 on_frame_task_ = waiting_frames_loop_->QuitClosure(); | 200 on_frame_task_ = waiting_frames_loop_->QuitClosure(); |
244 waiting_frames_loop_->Run(); | 201 waiting_frames_loop_->Run(); |
| 202 waiting_frames_loop_.reset(); |
245 | 203 |
246 EXPECT_TRUE(last_video_frame_); | 204 EXPECT_TRUE(last_video_frame_); |
247 return std::move(last_video_frame_); | 205 return std::move(last_video_frame_); |
248 } | 206 } |
249 | 207 |
250 void ReceiveFrameAndGetLatency(base::TimeDelta* latency) { | 208 void WaitFrameStats(int num_frames) { |
251 last_video_packet_.reset(); | 209 num_expected_frame_stats_ = num_frames; |
252 | 210 |
253 ReceiveFrame(); | 211 waiting_frame_stats_loop_.reset(new base::RunLoop()); |
| 212 waiting_frame_stats_loop_->Run(); |
| 213 waiting_frame_stats_loop_.reset(); |
254 | 214 |
255 if (latency) { | 215 EXPECT_GE(frame_stats_.size(), num_expected_frame_stats_); |
256 base::TimeTicks timestamp = | |
257 base::TimeTicks::FromInternalValue(last_video_packet_->timestamp()); | |
258 *latency = base::TimeTicks::Now() - timestamp; | |
259 } | |
260 } | |
261 | |
262 void ReceiveMultipleFramesAndGetMaxLatency(int frames, | |
263 base::TimeDelta* max_latency) { | |
264 if (max_latency) | |
265 *max_latency = base::TimeDelta(); | |
266 | |
267 for (int i = 0; i < frames; ++i) { | |
268 base::TimeDelta latency; | |
269 | |
270 ReceiveFrameAndGetLatency(&latency); | |
271 | |
272 if (max_latency && latency > *max_latency) { | |
273 *max_latency = latency; | |
274 } | |
275 } | |
276 } | 216 } |
277 | 217 |
278 // Creates test host and client and starts connection between them. Caller | 218 // Creates test host and client and starts connection between them. Caller |
279 // should call WaitConnected() to wait until connection is established. The | 219 // should call WaitConnected() to wait until connection is established. The |
280 // host is started on |host_thread_| while the client works on the main | 220 // host is started on |host_thread_| while the client works on the main |
281 // thread. | 221 // thread. |
282 void StartHostAndClient(bool use_webrtc, | 222 void StartHostAndClient(bool use_webrtc) { |
283 protocol::ChannelConfig::Codec video_codec) { | |
284 fake_network_dispatcher_ = new FakeNetworkDispatcher(); | 223 fake_network_dispatcher_ = new FakeNetworkDispatcher(); |
285 | 224 |
286 client_signaling_.reset(new FakeSignalStrategy(kClientJid)); | 225 client_signaling_.reset(new FakeSignalStrategy(kClientJid)); |
287 | 226 |
288 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); | 227 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); |
289 | 228 |
290 protocol_config_ = protocol::CandidateSessionConfig::CreateDefault(); | 229 protocol_config_ = protocol::CandidateSessionConfig::CreateDefault(); |
291 protocol_config_->DisableAudioChannel(); | 230 protocol_config_->DisableAudioChannel(); |
292 protocol_config_->mutable_video_configs()->clear(); | |
293 protocol_config_->mutable_video_configs()->push_back( | |
294 protocol::ChannelConfig( | |
295 protocol::ChannelConfig::TRANSPORT_STREAM, 2, video_codec)); | |
296 protocol_config_->set_webrtc_supported(use_webrtc); | 231 protocol_config_->set_webrtc_supported(use_webrtc); |
297 protocol_config_->set_ice_supported(!use_webrtc); | 232 protocol_config_->set_ice_supported(!use_webrtc); |
298 | 233 |
299 switch (video_codec) { | |
300 case ChannelConfig::CODEC_VERBATIM: | |
301 video_decoder_.reset(new VideoDecoderVerbatim()); | |
302 break; | |
303 case ChannelConfig::CODEC_VP8: | |
304 video_decoder_ = VideoDecoderVpx::CreateForVP8(); | |
305 break; | |
306 default: | |
307 NOTREACHED(); | |
308 } | |
309 | |
310 host_thread_.task_runner()->PostTask( | 234 host_thread_.task_runner()->PostTask( |
311 FROM_HERE, | 235 FROM_HERE, |
312 base::Bind(&ProtocolPerfTest::StartHost, base::Unretained(this))); | 236 base::Bind(&ProtocolPerfTest::StartHost, base::Unretained(this))); |
313 } | 237 } |
314 | 238 |
315 void StartHost() { | 239 void StartHost() { |
316 DCHECK(host_thread_.task_runner()->BelongsToCurrentThread()); | 240 DCHECK(host_thread_.task_runner()->BelongsToCurrentThread()); |
317 | 241 |
318 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); | 242 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); |
319 | 243 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 | 301 |
378 void StartClientAfterHost() { | 302 void StartClientAfterHost() { |
379 client_signaling_->ConnectTo(host_signaling_.get()); | 303 client_signaling_->ConnectTo(host_signaling_.get()); |
380 | 304 |
381 protocol::NetworkSettings network_settings( | 305 protocol::NetworkSettings network_settings( |
382 protocol::NetworkSettings::NAT_TRAVERSAL_OUTGOING); | 306 protocol::NetworkSettings::NAT_TRAVERSAL_OUTGOING); |
383 | 307 |
384 // Initialize client. | 308 // Initialize client. |
385 client_context_.reset( | 309 client_context_.reset( |
386 new ClientContext(base::ThreadTaskRunnerHandle::Get())); | 310 new ClientContext(base::ThreadTaskRunnerHandle::Get())); |
| 311 client_context_->Start(); |
387 | 312 |
388 std::unique_ptr<FakePortAllocatorFactory> port_allocator_factory( | 313 std::unique_ptr<FakePortAllocatorFactory> port_allocator_factory( |
389 new FakePortAllocatorFactory(fake_network_dispatcher_)); | 314 new FakePortAllocatorFactory(fake_network_dispatcher_)); |
390 port_allocator_factory->socket_factory()->SetBandwidth( | 315 port_allocator_factory->socket_factory()->SetBandwidth( |
391 GetParam().bandwidth, GetParam().max_buffers); | 316 GetParam().bandwidth, GetParam().max_buffers); |
392 port_allocator_factory->socket_factory()->SetLatency( | 317 port_allocator_factory->socket_factory()->SetLatency( |
393 GetParam().latency_average, GetParam().latency_stddev); | 318 GetParam().latency_average, GetParam().latency_stddev); |
394 port_allocator_factory->socket_factory()->set_out_of_order_rate( | 319 port_allocator_factory->socket_factory()->set_out_of_order_rate( |
395 GetParam().out_of_order_rate); | 320 GetParam().out_of_order_rate); |
396 scoped_refptr<protocol::TransportContext> transport_context( | 321 scoped_refptr<protocol::TransportContext> transport_context( |
397 new protocol::TransportContext( | 322 new protocol::TransportContext( |
398 host_signaling_.get(), std::move(port_allocator_factory), nullptr, | 323 host_signaling_.get(), std::move(port_allocator_factory), nullptr, |
399 network_settings, protocol::TransportRole::CLIENT)); | 324 network_settings, protocol::TransportRole::CLIENT)); |
400 | 325 |
401 protocol::ClientAuthenticationConfig client_auth_config; | 326 protocol::ClientAuthenticationConfig client_auth_config; |
402 client_auth_config.host_id = kHostId; | 327 client_auth_config.host_id = kHostId; |
403 client_auth_config.fetch_secret_callback = | 328 client_auth_config.fetch_secret_callback = |
404 base::Bind(&ProtocolPerfTest::FetchPin, base::Unretained(this)); | 329 base::Bind(&ProtocolPerfTest::FetchPin, base::Unretained(this)); |
405 | 330 |
406 client_.reset( | 331 video_renderer_.reset(new SoftwareVideoRenderer(this)); |
407 new ChromotingClient(client_context_.get(), this, this, nullptr)); | 332 video_renderer_->Initialize(*client_context_, this); |
| 333 |
| 334 client_.reset(new ChromotingClient(client_context_.get(), this, |
| 335 video_renderer_.get(), nullptr)); |
408 client_->set_protocol_config(protocol_config_->Clone()); | 336 client_->set_protocol_config(protocol_config_->Clone()); |
409 client_->Start(client_signaling_.get(), client_auth_config, | 337 client_->Start(client_signaling_.get(), client_auth_config, |
410 transport_context, kHostJid, std::string()); | 338 transport_context, kHostJid, std::string()); |
411 } | 339 } |
412 | 340 |
413 void FetchPin( | 341 void FetchPin( |
414 bool pairing_supported, | 342 bool pairing_supported, |
415 const protocol::SecretFetchedCallback& secret_fetched_callback) { | 343 const protocol::SecretFetchedCallback& secret_fetched_callback) { |
416 secret_fetched_callback.Run(kHostPin); | 344 secret_fetched_callback.Run(kHostPin); |
417 } | 345 } |
(...skipping 13 matching lines...) Expand all Loading... |
431 | 359 |
432 FakeCursorShapeStub cursor_shape_stub_; | 360 FakeCursorShapeStub cursor_shape_stub_; |
433 | 361 |
434 std::unique_ptr<protocol::CandidateSessionConfig> protocol_config_; | 362 std::unique_ptr<protocol::CandidateSessionConfig> protocol_config_; |
435 | 363 |
436 std::unique_ptr<FakeSignalStrategy> host_signaling_; | 364 std::unique_ptr<FakeSignalStrategy> host_signaling_; |
437 std::unique_ptr<FakeSignalStrategy> client_signaling_; | 365 std::unique_ptr<FakeSignalStrategy> client_signaling_; |
438 | 366 |
439 std::unique_ptr<ChromotingHost> host_; | 367 std::unique_ptr<ChromotingHost> host_; |
440 std::unique_ptr<ClientContext> client_context_; | 368 std::unique_ptr<ClientContext> client_context_; |
| 369 std::unique_ptr<SoftwareVideoRenderer> video_renderer_; |
441 std::unique_ptr<ChromotingClient> client_; | 370 std::unique_ptr<ChromotingClient> client_; |
442 webrtc::DesktopSize frame_size_; | |
443 std::unique_ptr<VideoDecoder> video_decoder_; | |
444 | 371 |
445 std::unique_ptr<base::RunLoop> connecting_loop_; | 372 std::unique_ptr<base::RunLoop> connecting_loop_; |
446 std::unique_ptr<base::RunLoop> waiting_frames_loop_; | 373 std::unique_ptr<base::RunLoop> waiting_frames_loop_; |
447 | 374 |
| 375 std::unique_ptr<base::RunLoop> waiting_frame_stats_loop_; |
| 376 size_t num_expected_frame_stats_; |
| 377 |
448 bool client_connected_; | 378 bool client_connected_; |
449 bool host_connected_; | 379 bool host_connected_; |
450 | 380 |
451 base::Closure on_frame_task_; | 381 base::Closure on_frame_task_; |
452 | 382 |
453 std::unique_ptr<VideoPacket> last_video_packet_; | 383 std::unique_ptr<VideoPacket> last_video_packet_; |
454 std::unique_ptr<webrtc::DesktopFrame> last_video_frame_; | 384 std::unique_ptr<webrtc::DesktopFrame> last_video_frame_; |
| 385 std::vector<protocol::FrameStats> frame_stats_; |
455 | 386 |
456 private: | 387 private: |
457 DISALLOW_COPY_AND_ASSIGN(ProtocolPerfTest); | 388 DISALLOW_COPY_AND_ASSIGN(ProtocolPerfTest); |
458 }; | 389 }; |
459 | 390 |
460 INSTANTIATE_TEST_CASE_P( | 391 INSTANTIATE_TEST_CASE_P( |
461 NoDelay, | 392 NoDelay, |
462 ProtocolPerfTest, | 393 ProtocolPerfTest, |
463 ::testing::Values(NetworkPerformanceParams(0, 0, 0, 0, 0.0))); | 394 ::testing::Values(NetworkPerformanceParams(0, 0, 0, 0, 0.0))); |
464 | 395 |
(...skipping 18 matching lines...) Expand all Loading... |
483 ::testing::Values( | 414 ::testing::Values( |
484 // 100 Mbps | 415 // 100 Mbps |
485 NetworkPerformanceParams(12500000, 12500000, 2, 1, 0.0), | 416 NetworkPerformanceParams(12500000, 12500000, 2, 1, 0.0), |
486 // 8 Mbps | 417 // 8 Mbps |
487 NetworkPerformanceParams(1000000, 300000, 30, 5, 0.01), | 418 NetworkPerformanceParams(1000000, 300000, 30, 5, 0.01), |
488 NetworkPerformanceParams(1000000, 2000000, 30, 5, 0.01), | 419 NetworkPerformanceParams(1000000, 2000000, 30, 5, 0.01), |
489 // 800 kBps | 420 // 800 kBps |
490 NetworkPerformanceParams(100000, 30000, 130, 5, 0.01), | 421 NetworkPerformanceParams(100000, 30000, 130, 5, 0.01), |
491 NetworkPerformanceParams(100000, 200000, 130, 5, 0.01))); | 422 NetworkPerformanceParams(100000, 200000, 130, 5, 0.01))); |
492 | 423 |
493 TEST_P(ProtocolPerfTest, StreamFrameRate) { | |
494 StartHostAndClient(false, protocol::ChannelConfig::CODEC_VP8); | |
495 ASSERT_NO_FATAL_FAILURE(WaitConnected()); | |
496 | |
497 base::TimeDelta latency; | |
498 | |
499 ReceiveFrameAndGetLatency(&latency); | |
500 LOG(INFO) << "First frame latency: " << latency.InMillisecondsF() << "ms"; | |
501 ReceiveMultipleFramesAndGetMaxLatency(20, nullptr); | |
502 | |
503 base::TimeTicks started = base::TimeTicks::Now(); | |
504 ReceiveMultipleFramesAndGetMaxLatency(40, &latency); | |
505 base::TimeDelta elapsed = base::TimeTicks::Now() - started; | |
506 LOG(INFO) << "Frame rate: " << (40.0 / elapsed.InSecondsF()); | |
507 LOG(INFO) << "Maximum latency: " << latency.InMillisecondsF() << "ms"; | |
508 } | |
509 | |
510 const int kIntermittentFrameSize = 100 * 1000; | 424 const int kIntermittentFrameSize = 100 * 1000; |
511 | 425 |
512 // Frame generator that rewrites the whole screen every 60th frame. Should only | 426 // Frame generator that rewrites the whole screen every 60th frame. Should only |
513 // be used with the VERBATIM codec as the allocated frame may contain arbitrary | 427 // be used with the VERBATIM codec as the allocated frame may contain arbitrary |
514 // data. | 428 // data. |
515 class IntermittentChangeFrameGenerator | 429 class IntermittentChangeFrameGenerator |
516 : public base::RefCountedThreadSafe<IntermittentChangeFrameGenerator> { | 430 : public base::RefCountedThreadSafe<IntermittentChangeFrameGenerator> { |
517 public: | 431 public: |
518 IntermittentChangeFrameGenerator() | 432 IntermittentChangeFrameGenerator() |
519 : frame_index_(0) {} | 433 : frame_index_(0) {} |
(...skipping 23 matching lines...) Expand all Loading... |
543 private: | 457 private: |
544 ~IntermittentChangeFrameGenerator() {} | 458 ~IntermittentChangeFrameGenerator() {} |
545 friend class base::RefCountedThreadSafe<IntermittentChangeFrameGenerator>; | 459 friend class base::RefCountedThreadSafe<IntermittentChangeFrameGenerator>; |
546 | 460 |
547 int frame_index_; | 461 int frame_index_; |
548 std::unique_ptr<webrtc::SharedDesktopFrame> current_frame_; | 462 std::unique_ptr<webrtc::SharedDesktopFrame> current_frame_; |
549 | 463 |
550 DISALLOW_COPY_AND_ASSIGN(IntermittentChangeFrameGenerator); | 464 DISALLOW_COPY_AND_ASSIGN(IntermittentChangeFrameGenerator); |
551 }; | 465 }; |
552 | 466 |
553 TEST_P(ProtocolPerfTest, IntermittentChanges) { | |
554 desktop_environment_factory_.set_frame_generator( | |
555 base::Bind(&IntermittentChangeFrameGenerator::GenerateFrame, | |
556 new IntermittentChangeFrameGenerator())); | |
557 | |
558 StartHostAndClient(false, protocol::ChannelConfig::CODEC_VERBATIM); | |
559 ASSERT_NO_FATAL_FAILURE(WaitConnected()); | |
560 | |
561 ReceiveFrameAndGetLatency(nullptr); | |
562 | |
563 base::TimeDelta expected = GetParam().latency_average; | |
564 if (GetParam().bandwidth > 0) { | |
565 expected += base::TimeDelta::FromSecondsD(kIntermittentFrameSize / | |
566 GetParam().bandwidth); | |
567 } | |
568 LOG(INFO) << "Expected: " << expected.InMillisecondsF() << "ms"; | |
569 | |
570 base::TimeDelta sum; | |
571 | |
572 const int kFrames = 5; | |
573 for (int i = 0; i < kFrames; ++i) { | |
574 base::TimeDelta latency; | |
575 ReceiveFrameAndGetLatency(&latency); | |
576 LOG(INFO) << "Latency: " << latency.InMillisecondsF() | |
577 << "ms Encode: " << last_video_packet_->encode_time_ms() | |
578 << "ms Capture: " << last_video_packet_->capture_time_ms() | |
579 << "ms"; | |
580 sum += latency; | |
581 } | |
582 | |
583 LOG(INFO) << "Average: " << (sum / kFrames).InMillisecondsF(); | |
584 } | |
585 | |
586 // TotalLatency[Ice|Webrtc] tests measure video latency in the case when the | 467 // TotalLatency[Ice|Webrtc] tests measure video latency in the case when the |
587 // whole screen is updated occasionally. It's intended to simulate the case when | 468 // whole screen is updated occasionally. It's intended to simulate the case when |
588 // user actions (e.g. Alt-Tab, click on the task bar) cause whole screen to be | 469 // user actions (e.g. Alt-Tab, click on the task bar) cause whole screen to be |
589 // updated. | 470 // updated. |
590 void ProtocolPerfTest::MeasureTotalLatency(bool use_webrtc) { | 471 void ProtocolPerfTest::MeasureTotalLatency(bool use_webrtc) { |
591 scoped_refptr<test::CyclicFrameGenerator> frame_generator = | 472 scoped_refptr<test::CyclicFrameGenerator> frame_generator = |
592 test::CyclicFrameGenerator::Create(); | 473 test::CyclicFrameGenerator::Create(); |
593 frame_generator->set_draw_barcode(true); | 474 frame_generator->set_draw_barcode(true); |
594 | 475 |
595 desktop_environment_factory_.set_frame_generator( | 476 desktop_environment_factory_.set_frame_generator( |
596 base::Bind(&test::CyclicFrameGenerator::GenerateFrame, frame_generator)); | 477 base::Bind(&test::CyclicFrameGenerator::GenerateFrame, frame_generator)); |
597 | 478 |
598 StartHostAndClient(use_webrtc, protocol::ChannelConfig::CODEC_VP8); | 479 StartHostAndClient(use_webrtc); |
599 ASSERT_NO_FATAL_FAILURE(WaitConnected()); | 480 ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
600 | 481 |
601 int skipped_frames = 0; | 482 int skipped_frames = 0; |
602 while (skipped_frames < 10) { | 483 while (skipped_frames < 10) { |
603 std::unique_ptr<webrtc::DesktopFrame> frame = ReceiveFrame(); | 484 std::unique_ptr<webrtc::DesktopFrame> frame = ReceiveFrame(); |
604 test::CyclicFrameGenerator::ChangeInfoList changes = | 485 test::CyclicFrameGenerator::ChangeInfoList changes = |
605 frame_generator->GetChangeList(frame.get()); | 486 frame_generator->GetChangeList(frame.get()); |
606 skipped_frames += changes.size(); | 487 skipped_frames += changes.size(); |
607 } | 488 } |
608 | 489 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
655 | 536 |
656 // ScrollPerformance[Ice|Webrtc] tests simulate whole screen being scrolled | 537 // ScrollPerformance[Ice|Webrtc] tests simulate whole screen being scrolled |
657 // continuously. They measure FPS and video latency. | 538 // continuously. They measure FPS and video latency. |
658 void ProtocolPerfTest::MeasureScrollPerformance(bool use_webrtc) { | 539 void ProtocolPerfTest::MeasureScrollPerformance(bool use_webrtc) { |
659 scoped_refptr<test::ScrollFrameGenerator> frame_generator = | 540 scoped_refptr<test::ScrollFrameGenerator> frame_generator = |
660 new test::ScrollFrameGenerator(); | 541 new test::ScrollFrameGenerator(); |
661 | 542 |
662 desktop_environment_factory_.set_frame_generator( | 543 desktop_environment_factory_.set_frame_generator( |
663 base::Bind(&test::ScrollFrameGenerator::GenerateFrame, frame_generator)); | 544 base::Bind(&test::ScrollFrameGenerator::GenerateFrame, frame_generator)); |
664 | 545 |
665 StartHostAndClient(use_webrtc, protocol::ChannelConfig::CODEC_VP8); | 546 StartHostAndClient(use_webrtc); |
666 ASSERT_NO_FATAL_FAILURE(WaitConnected()); | 547 ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
667 | 548 |
| 549 int warm_up_frames = 0; |
| 550 |
668 base::TimeTicks start_time = base::TimeTicks::Now(); | 551 base::TimeTicks start_time = base::TimeTicks::Now(); |
669 const base::TimeDelta kWarmUpTime = base::TimeDelta::FromSeconds(2); | 552 const base::TimeDelta kWarmUpTime = base::TimeDelta::FromSeconds(2); |
670 while ((base::TimeTicks::Now() - start_time) < kWarmUpTime) { | 553 while ((base::TimeTicks::Now() - start_time) < kWarmUpTime) { |
671 ReceiveFrame(); | 554 ReceiveFrame(); |
| 555 ++warm_up_frames; |
672 } | 556 } |
673 | 557 |
674 // Run the test for 2 seconds. | 558 // Run the test for 2 seconds. |
675 const base::TimeDelta kTestTime = base::TimeDelta::FromSeconds(2); | 559 const base::TimeDelta kTestTime = base::TimeDelta::FromSeconds(2); |
676 | 560 |
677 int num_frames = 0; | 561 int num_frames = 0; |
678 base::TimeDelta total_latency; | 562 base::TimeDelta latency_sum; |
679 start_time = base::TimeTicks::Now(); | 563 start_time = base::TimeTicks::Now(); |
680 while ((base::TimeTicks::Now() - start_time) < kTestTime) { | 564 while ((base::TimeTicks::Now() - start_time) < kTestTime) { |
681 std::unique_ptr<webrtc::DesktopFrame> frame = ReceiveFrame(); | 565 std::unique_ptr<webrtc::DesktopFrame> frame = ReceiveFrame(); |
682 ++num_frames; | 566 ++num_frames; |
683 total_latency += frame_generator->GetFrameLatency(*frame); | 567 latency_sum += frame_generator->GetFrameLatency(*frame); |
684 } | 568 } |
685 | 569 |
686 VLOG(0) << "FPS: " | 570 base::TimeDelta total_time = (base::TimeTicks::Now() - start_time); |
687 << num_frames / (base::TimeTicks::Now() - start_time).InSecondsF(); | |
688 | 571 |
689 VLOG(0) << "Average latency: " | 572 WaitFrameStats(warm_up_frames + num_frames); |
690 << (total_latency).InMillisecondsF() / num_frames; | 573 |
| 574 int total_size = |
| 575 std::accumulate(frame_stats_.begin() + warm_up_frames, |
| 576 frame_stats_.begin() + warm_up_frames + num_frames, 0, |
| 577 [](int sum, const protocol::FrameStats& stats) { |
| 578 return sum + stats.host_stats.frame_size; |
| 579 }); |
| 580 |
| 581 VLOG(0) << "FPS: " << num_frames / total_time.InSecondsF(); |
| 582 VLOG(0) << "Average latency: " << latency_sum.InMillisecondsF() / num_frames |
| 583 << " ms"; |
| 584 VLOG(0) << "Total size: " << total_size << " bytes"; |
| 585 VLOG(0) << "Bandwidth utilization: " |
| 586 << 100 * total_size / (total_time.InSecondsF() * GetParam().bandwidth) |
| 587 << "%"; |
691 } | 588 } |
692 | 589 |
693 TEST_P(ProtocolPerfTest, ScrollPerformanceIce) { | 590 TEST_P(ProtocolPerfTest, ScrollPerformanceIce) { |
694 MeasureScrollPerformance(false); | 591 MeasureScrollPerformance(false); |
695 } | 592 } |
696 | 593 |
697 TEST_P(ProtocolPerfTest, ScrollPerformanceWebrtc) { | 594 TEST_P(ProtocolPerfTest, ScrollPerformanceWebrtc) { |
698 MeasureScrollPerformance(true); | 595 MeasureScrollPerformance(true); |
699 } | 596 } |
700 | 597 |
701 } // namespace remoting | 598 } // namespace remoting |
OLD | NEW |