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