| 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 "base/base64.h" | 5 #include "base/base64.h" |
| 6 #include "base/file_util.h" | 6 #include "base/file_util.h" |
| 7 #include "base/message_loop/message_loop.h" | 7 #include "base/message_loop/message_loop.h" |
| 8 #include "base/rand_util.h" |
| 8 #include "base/run_loop.h" | 9 #include "base/run_loop.h" |
| 9 #include "base/single_thread_task_runner.h" | 10 #include "base/single_thread_task_runner.h" |
| 10 #include "base/synchronization/waitable_event.h" | 11 #include "base/synchronization/waitable_event.h" |
| 11 #include "base/thread_task_runner_handle.h" | 12 #include "base/thread_task_runner_handle.h" |
| 12 #include "jingle/glue/thread_wrapper.h" | 13 #include "jingle/glue/thread_wrapper.h" |
| 13 #include "net/base/test_data_directory.h" | 14 #include "net/base/test_data_directory.h" |
| 14 #include "net/url_request/url_request_context_getter.h" | 15 #include "net/url_request/url_request_context_getter.h" |
| 15 #include "remoting/base/rsa_key_pair.h" | 16 #include "remoting/base/rsa_key_pair.h" |
| 16 #include "remoting/client/audio_player.h" | 17 #include "remoting/client/audio_player.h" |
| 17 #include "remoting/client/chromoting_client.h" | 18 #include "remoting/client/chromoting_client.h" |
| 18 #include "remoting/client/client_context.h" | 19 #include "remoting/client/client_context.h" |
| 19 #include "remoting/client/client_user_interface.h" | 20 #include "remoting/client/client_user_interface.h" |
| 20 #include "remoting/client/video_renderer.h" | 21 #include "remoting/client/video_renderer.h" |
| 21 #include "remoting/host/chromoting_host.h" | 22 #include "remoting/host/chromoting_host.h" |
| 22 #include "remoting/host/chromoting_host_context.h" | 23 #include "remoting/host/chromoting_host_context.h" |
| 23 #include "remoting/host/fake_desktop_environment.h" | 24 #include "remoting/host/fake_desktop_environment.h" |
| 24 #include "remoting/host/video_scheduler.h" | 25 #include "remoting/host/video_scheduler.h" |
| 25 #include "remoting/protocol/chromium_port_allocator.h" | |
| 26 #include "remoting/protocol/jingle_session_manager.h" | 26 #include "remoting/protocol/jingle_session_manager.h" |
| 27 #include "remoting/protocol/libjingle_transport_factory.h" | 27 #include "remoting/protocol/libjingle_transport_factory.h" |
| 28 #include "remoting/protocol/me2me_host_authenticator_factory.h" | 28 #include "remoting/protocol/me2me_host_authenticator_factory.h" |
| 29 #include "remoting/protocol/negotiating_client_authenticator.h" | 29 #include "remoting/protocol/negotiating_client_authenticator.h" |
| 30 #include "remoting/protocol/session_config.h" | 30 #include "remoting/protocol/session_config.h" |
| 31 #include "remoting/signaling/fake_signal_strategy.h" | 31 #include "remoting/signaling/fake_signal_strategy.h" |
| 32 #include "remoting/test/fake_network_dispatcher.h" |
| 33 #include "remoting/test/fake_port_allocator.h" |
| 34 #include "remoting/test/fake_socket_factory.h" |
| 32 #include "testing/gtest/include/gtest/gtest.h" | 35 #include "testing/gtest/include/gtest/gtest.h" |
| 33 | 36 |
| 34 namespace remoting { | 37 namespace remoting { |
| 35 | 38 |
| 36 using protocol::ChannelConfig; | 39 using protocol::ChannelConfig; |
| 37 | 40 |
| 38 const char kHostJid[] = "host_jid@example.com/host"; | 41 const char kHostJid[] = "host_jid@example.com/host"; |
| 39 const char kHostOwner[] = "jane.doe@example.com"; | 42 const char kHostOwner[] = "jane.doe@example.com"; |
| 40 const char kClientJid[] = "jane.doe@example.com/client"; | 43 const char kClientJid[] = "jane.doe@example.com/client"; |
| 41 | 44 |
| 42 class ProtocolPerfTest : public testing::Test, | 45 struct NetworkPerformanceParams { |
| 43 public ClientUserInterface, | 46 NetworkPerformanceParams(int bandwidth, |
| 44 public VideoRenderer, | 47 int max_buffers, |
| 45 public HostStatusObserver { | 48 double latency_average_ms, |
| 49 double latency_stddev_ms, |
| 50 double out_of_order_rate) |
| 51 : bandwidth(bandwidth), |
| 52 max_buffers(max_buffers), |
| 53 latency_average(base::TimeDelta::FromMillisecondsD(latency_average_ms)), |
| 54 latency_stddev(base::TimeDelta::FromMillisecondsD(latency_stddev_ms)), |
| 55 out_of_order_rate(out_of_order_rate) {} |
| 56 |
| 57 int bandwidth; |
| 58 int max_buffers; |
| 59 base::TimeDelta latency_average; |
| 60 base::TimeDelta latency_stddev; |
| 61 double out_of_order_rate; |
| 62 }; |
| 63 |
| 64 class ProtocolPerfTest |
| 65 : public testing::Test, |
| 66 public testing::WithParamInterface<NetworkPerformanceParams>, |
| 67 public ClientUserInterface, |
| 68 public VideoRenderer, |
| 69 public HostStatusObserver { |
| 46 public: | 70 public: |
| 47 ProtocolPerfTest() | 71 ProtocolPerfTest() |
| 48 : host_thread_("host"), | 72 : host_thread_("host"), |
| 49 capture_thread_("capture"), | 73 capture_thread_("capture"), |
| 50 encode_thread_("encode") { | 74 encode_thread_("encode") { |
| 51 VideoScheduler::EnableTimestampsForTests(); | 75 VideoScheduler::EnableTimestampsForTests(); |
| 52 host_thread_.StartWithOptions( | 76 host_thread_.StartWithOptions( |
| 53 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); | 77 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
| 54 capture_thread_.Start(); | 78 capture_thread_.Start(); |
| 55 encode_thread_.Start(); | 79 encode_thread_.Start(); |
| 56 } | 80 } |
| 81 |
| 57 virtual ~ProtocolPerfTest() { | 82 virtual ~ProtocolPerfTest() { |
| 58 host_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, host_.release()); | 83 host_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, host_.release()); |
| 59 host_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, | 84 host_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, |
| 60 host_signaling_.release()); | 85 host_signaling_.release()); |
| 61 message_loop_.RunUntilIdle(); | 86 message_loop_.RunUntilIdle(); |
| 62 } | 87 } |
| 63 | 88 |
| 64 // ClientUserInterface interface. | 89 // ClientUserInterface interface. |
| 65 virtual void OnConnectionState(protocol::ConnectionToHost::State state, | 90 virtual void OnConnectionState(protocol::ConnectionToHost::State state, |
| 66 protocol::ErrorCode error) OVERRIDE { | 91 protocol::ErrorCode error) OVERRIDE { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 *max_latency = latency; | 180 *max_latency = latency; |
| 156 } | 181 } |
| 157 } | 182 } |
| 158 } | 183 } |
| 159 | 184 |
| 160 // Creates test host and client and starts connection between them. Caller | 185 // Creates test host and client and starts connection between them. Caller |
| 161 // should call WaitConnected() to wait until connection is established. The | 186 // should call WaitConnected() to wait until connection is established. The |
| 162 // host is started on |host_thread_| while the client works on the main | 187 // host is started on |host_thread_| while the client works on the main |
| 163 // thread. | 188 // thread. |
| 164 void StartHostAndClient(protocol::ChannelConfig::Codec video_codec) { | 189 void StartHostAndClient(protocol::ChannelConfig::Codec video_codec) { |
| 190 fake_network_dispatcher_ = new FakeNetworkDispatcher(); |
| 191 |
| 165 client_signaling_.reset(new FakeSignalStrategy(kClientJid)); | 192 client_signaling_.reset(new FakeSignalStrategy(kClientJid)); |
| 166 | 193 |
| 167 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); | 194 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); |
| 168 | 195 |
| 169 protocol_config_ = protocol::CandidateSessionConfig::CreateDefault(); | 196 protocol_config_ = protocol::CandidateSessionConfig::CreateDefault(); |
| 170 protocol_config_->DisableAudioChannel(); | 197 protocol_config_->DisableAudioChannel(); |
| 171 protocol_config_->mutable_video_configs()->clear(); | 198 protocol_config_->mutable_video_configs()->clear(); |
| 172 protocol_config_->mutable_video_configs()->push_back( | 199 protocol_config_->mutable_video_configs()->push_back( |
| 173 protocol::ChannelConfig( | 200 protocol::ChannelConfig( |
| 174 protocol::ChannelConfig::TRANSPORT_STREAM, 2, video_codec)); | 201 protocol::ChannelConfig::TRANSPORT_STREAM, 2, video_codec)); |
| 175 | 202 |
| 176 host_thread_.message_loop_proxy()->PostTask( | 203 host_thread_.message_loop_proxy()->PostTask( |
| 177 FROM_HERE, | 204 FROM_HERE, |
| 178 base::Bind(&ProtocolPerfTest::StartHost, base::Unretained(this))); | 205 base::Bind(&ProtocolPerfTest::StartHost, base::Unretained(this))); |
| 179 } | 206 } |
| 180 | 207 |
| 181 void StartHost() { | 208 void StartHost() { |
| 182 DCHECK(host_thread_.message_loop_proxy()->BelongsToCurrentThread()); | 209 DCHECK(host_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 183 | 210 |
| 184 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); | 211 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); |
| 185 | 212 |
| 186 host_signaling_.reset(new FakeSignalStrategy(kHostJid)); | 213 host_signaling_.reset(new FakeSignalStrategy(kHostJid)); |
| 187 host_signaling_->ConnectTo(client_signaling_.get()); | 214 host_signaling_->ConnectTo(client_signaling_.get()); |
| 188 | 215 |
| 189 protocol::NetworkSettings network_settings( | 216 protocol::NetworkSettings network_settings( |
| 190 protocol::NetworkSettings::NAT_TRAVERSAL_OUTGOING); | 217 protocol::NetworkSettings::NAT_TRAVERSAL_OUTGOING); |
| 191 | 218 |
| 192 // TODO(sergeyu): Replace with a fake port allocator. | 219 scoped_ptr<FakePortAllocator> port_allocator( |
| 193 scoped_ptr<cricket::HttpPortAllocatorBase> host_port_allocator = | 220 FakePortAllocator::Create(fake_network_dispatcher_)); |
| 194 protocol::ChromiumPortAllocator::Create(NULL, network_settings) | 221 port_allocator->socket_factory()->SetBandwidth(GetParam().bandwidth, |
| 195 .PassAs<cricket::HttpPortAllocatorBase>(); | 222 GetParam().max_buffers); |
| 196 | 223 port_allocator->socket_factory()->SetLatency(GetParam().latency_average, |
| 224 GetParam().latency_stddev); |
| 225 port_allocator->socket_factory()->set_out_of_order_rate( |
| 226 GetParam().out_of_order_rate); |
| 197 scoped_ptr<protocol::TransportFactory> host_transport_factory( | 227 scoped_ptr<protocol::TransportFactory> host_transport_factory( |
| 198 new protocol::LibjingleTransportFactory( | 228 new protocol::LibjingleTransportFactory( |
| 199 host_signaling_.get(), | 229 host_signaling_.get(), |
| 200 host_port_allocator.Pass(), | 230 port_allocator.PassAs<cricket::HttpPortAllocatorBase>(), |
| 201 network_settings)); | 231 network_settings)); |
| 202 | 232 |
| 203 scoped_ptr<protocol::SessionManager> session_manager( | 233 scoped_ptr<protocol::SessionManager> session_manager( |
| 204 new protocol::JingleSessionManager(host_transport_factory.Pass())); | 234 new protocol::JingleSessionManager(host_transport_factory.Pass())); |
| 205 | 235 |
| 206 // Encoder runs on a separate thread, main thread is used for everything | 236 // Encoder runs on a separate thread, main thread is used for everything |
| 207 // else. | 237 // else. |
| 208 host_.reset(new ChromotingHost(host_signaling_.get(), | 238 host_.reset(new ChromotingHost(host_signaling_.get(), |
| 209 &desktop_environment_factory_, | 239 &desktop_environment_factory_, |
| 210 session_manager.Pass(), | 240 session_manager.Pass(), |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 void StartClientAfterHost() { | 280 void StartClientAfterHost() { |
| 251 client_signaling_->ConnectTo(host_signaling_.get()); | 281 client_signaling_->ConnectTo(host_signaling_.get()); |
| 252 | 282 |
| 253 protocol::NetworkSettings network_settings( | 283 protocol::NetworkSettings network_settings( |
| 254 protocol::NetworkSettings::NAT_TRAVERSAL_OUTGOING); | 284 protocol::NetworkSettings::NAT_TRAVERSAL_OUTGOING); |
| 255 | 285 |
| 256 // Initialize client. | 286 // Initialize client. |
| 257 client_context_.reset( | 287 client_context_.reset( |
| 258 new ClientContext(base::ThreadTaskRunnerHandle::Get())); | 288 new ClientContext(base::ThreadTaskRunnerHandle::Get())); |
| 259 | 289 |
| 260 // TODO(sergeyu): Replace with a fake port allocator | 290 scoped_ptr<FakePortAllocator> port_allocator( |
| 261 scoped_ptr<cricket::HttpPortAllocatorBase> client_port_allocator = | 291 FakePortAllocator::Create(fake_network_dispatcher_)); |
| 262 protocol::ChromiumPortAllocator::Create(NULL, network_settings) | 292 port_allocator->socket_factory()->SetBandwidth(GetParam().bandwidth, |
| 263 .PassAs<cricket::HttpPortAllocatorBase>(); | 293 GetParam().max_buffers); |
| 264 | 294 port_allocator->socket_factory()->SetLatency(GetParam().latency_average, |
| 295 GetParam().latency_stddev); |
| 296 port_allocator->socket_factory()->set_out_of_order_rate( |
| 297 GetParam().out_of_order_rate); |
| 265 scoped_ptr<protocol::TransportFactory> client_transport_factory( | 298 scoped_ptr<protocol::TransportFactory> client_transport_factory( |
| 266 new protocol::LibjingleTransportFactory(client_signaling_.get(), | 299 new protocol::LibjingleTransportFactory( |
| 267 client_port_allocator.Pass(), | 300 client_signaling_.get(), |
| 268 network_settings)); | 301 port_allocator.PassAs<cricket::HttpPortAllocatorBase>(), |
| 302 network_settings)); |
| 269 | 303 |
| 270 std::vector<protocol::AuthenticationMethod> auth_methods; | 304 std::vector<protocol::AuthenticationMethod> auth_methods; |
| 271 auth_methods.push_back(protocol::AuthenticationMethod::Spake2( | 305 auth_methods.push_back(protocol::AuthenticationMethod::Spake2( |
| 272 protocol::AuthenticationMethod::NONE)); | 306 protocol::AuthenticationMethod::NONE)); |
| 273 scoped_ptr<protocol::Authenticator> client_authenticator( | 307 scoped_ptr<protocol::Authenticator> client_authenticator( |
| 274 new protocol::NegotiatingClientAuthenticator( | 308 new protocol::NegotiatingClientAuthenticator( |
| 275 std::string(), // client_pairing_id | 309 std::string(), // client_pairing_id |
| 276 std::string(), // client_pairing_secret | 310 std::string(), // client_pairing_secret |
| 277 std::string(), // authentication_tag | 311 std::string(), // authentication_tag |
| 278 base::Bind(&ProtocolPerfTest::FetchPin, base::Unretained(this)), | 312 base::Bind(&ProtocolPerfTest::FetchPin, base::Unretained(this)), |
| 279 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>(), | 313 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>(), |
| 280 auth_methods)); | 314 auth_methods)); |
| 281 client_.reset(new ChromotingClient( | 315 client_.reset(new ChromotingClient( |
| 282 client_context_.get(), this, this, scoped_ptr<AudioPlayer>())); | 316 client_context_.get(), this, this, scoped_ptr<AudioPlayer>())); |
| 283 client_->SetProtocolConfigForTests(protocol_config_->Clone()); | 317 client_->SetProtocolConfigForTests(protocol_config_->Clone()); |
| 284 client_->Start( | 318 client_->Start( |
| 285 client_signaling_.get(), client_authenticator.Pass(), | 319 client_signaling_.get(), client_authenticator.Pass(), |
| 286 client_transport_factory.Pass(), kHostJid, std::string()); | 320 client_transport_factory.Pass(), kHostJid, std::string()); |
| 287 } | 321 } |
| 288 | 322 |
| 289 void FetchPin( | 323 void FetchPin( |
| 290 bool pairing_supported, | 324 bool pairing_supported, |
| 291 const protocol::SecretFetchedCallback& secret_fetched_callback) { | 325 const protocol::SecretFetchedCallback& secret_fetched_callback) { |
| 292 secret_fetched_callback.Run("123456"); | 326 secret_fetched_callback.Run("123456"); |
| 293 } | 327 } |
| 294 | 328 |
| 295 base::MessageLoopForIO message_loop_; | 329 base::MessageLoopForIO message_loop_; |
| 296 | 330 |
| 331 scoped_refptr<FakeNetworkDispatcher> fake_network_dispatcher_; |
| 332 |
| 297 base::Thread host_thread_; | 333 base::Thread host_thread_; |
| 298 base::Thread capture_thread_; | 334 base::Thread capture_thread_; |
| 299 base::Thread encode_thread_; | 335 base::Thread encode_thread_; |
| 300 FakeDesktopEnvironmentFactory desktop_environment_factory_; | 336 FakeDesktopEnvironmentFactory desktop_environment_factory_; |
| 301 | 337 |
| 302 scoped_ptr<protocol::CandidateSessionConfig> protocol_config_; | 338 scoped_ptr<protocol::CandidateSessionConfig> protocol_config_; |
| 303 | 339 |
| 304 scoped_ptr<FakeSignalStrategy> host_signaling_; | 340 scoped_ptr<FakeSignalStrategy> host_signaling_; |
| 305 scoped_ptr<FakeSignalStrategy> client_signaling_; | 341 scoped_ptr<FakeSignalStrategy> client_signaling_; |
| 306 | 342 |
| 307 scoped_ptr<ChromotingHost> host_; | 343 scoped_ptr<ChromotingHost> host_; |
| 308 scoped_ptr<ClientContext> client_context_; | 344 scoped_ptr<ClientContext> client_context_; |
| 309 scoped_ptr<ChromotingClient> client_; | 345 scoped_ptr<ChromotingClient> client_; |
| 310 | 346 |
| 311 scoped_ptr<base::RunLoop> connecting_loop_; | 347 scoped_ptr<base::RunLoop> connecting_loop_; |
| 312 scoped_ptr<base::RunLoop> waiting_frames_loop_; | 348 scoped_ptr<base::RunLoop> waiting_frames_loop_; |
| 313 | 349 |
| 314 bool client_connected_; | 350 bool client_connected_; |
| 315 bool host_connected_; | 351 bool host_connected_; |
| 316 | 352 |
| 317 base::Closure on_frame_task_; | 353 base::Closure on_frame_task_; |
| 318 | 354 |
| 319 scoped_ptr<VideoPacket> last_video_packet_; | 355 scoped_ptr<VideoPacket> last_video_packet_; |
| 320 | 356 |
| 321 DISALLOW_COPY_AND_ASSIGN(ProtocolPerfTest); | 357 DISALLOW_COPY_AND_ASSIGN(ProtocolPerfTest); |
| 322 }; | 358 }; |
| 323 | 359 |
| 324 TEST_F(ProtocolPerfTest, StreamFrameRate) { | 360 INSTANTIATE_TEST_CASE_P( |
| 361 NoDelay, |
| 362 ProtocolPerfTest, |
| 363 ::testing::Values(NetworkPerformanceParams(0, 0, 0, 0, 0.0))); |
| 364 |
| 365 INSTANTIATE_TEST_CASE_P( |
| 366 HighLatency, |
| 367 ProtocolPerfTest, |
| 368 ::testing::Values(NetworkPerformanceParams(0, 0, 300, 30, 0.0), |
| 369 NetworkPerformanceParams(0, 0, 30, 10, 0.0))); |
| 370 |
| 371 INSTANTIATE_TEST_CASE_P( |
| 372 OutOfOrder, |
| 373 ProtocolPerfTest, |
| 374 ::testing::Values(NetworkPerformanceParams(0, 0, 2, 0, 0.01), |
| 375 NetworkPerformanceParams(0, 0, 30, 1, 0.01), |
| 376 NetworkPerformanceParams(0, 0, 30, 1, 0.1), |
| 377 NetworkPerformanceParams(0, 0, 300, 20, 0.01), |
| 378 NetworkPerformanceParams(0, 0, 300, 20, 0.1))); |
| 379 |
| 380 INSTANTIATE_TEST_CASE_P( |
| 381 LimitedBandwidth, |
| 382 ProtocolPerfTest, |
| 383 ::testing::Values( |
| 384 // 100 MBps |
| 385 NetworkPerformanceParams(800000000, 800000000, 2, 1, 0.0), |
| 386 // 8 MBps |
| 387 NetworkPerformanceParams(1000000, 300000, 30, 5, 0.01), |
| 388 NetworkPerformanceParams(1000000, 2000000, 30, 5, 0.01), |
| 389 // 800 kBps |
| 390 NetworkPerformanceParams(100000, 30000, 130, 5, 0.01), |
| 391 NetworkPerformanceParams(100000, 200000, 130, 5, 0.01))); |
| 392 |
| 393 TEST_P(ProtocolPerfTest, StreamFrameRate) { |
| 325 StartHostAndClient(protocol::ChannelConfig::CODEC_VP8); | 394 StartHostAndClient(protocol::ChannelConfig::CODEC_VP8); |
| 326 ASSERT_NO_FATAL_FAILURE(WaitConnected()); | 395 ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
| 327 | 396 |
| 328 base::TimeDelta latency; | 397 base::TimeDelta latency; |
| 329 | 398 |
| 330 ReceiveFrame(&latency); | 399 ReceiveFrame(&latency); |
| 331 LOG(INFO) << "First frame latency: " << latency.InMillisecondsF() << "ms"; | 400 LOG(INFO) << "First frame latency: " << latency.InMillisecondsF() << "ms"; |
| 332 ReceiveFrames(20, NULL); | 401 ReceiveFrames(20, NULL); |
| 333 | 402 |
| 334 base::TimeTicks started = base::TimeTicks::Now(); | 403 base::TimeTicks started = base::TimeTicks::Now(); |
| 335 ReceiveFrames(40, &latency); | 404 ReceiveFrames(40, &latency); |
| 336 base::TimeDelta elapsed = base::TimeTicks::Now() - started; | 405 base::TimeDelta elapsed = base::TimeTicks::Now() - started; |
| 337 LOG(INFO) << "Frame rate: " << (40.0 / elapsed.InSecondsF()); | 406 LOG(INFO) << "Frame rate: " << (40.0 / elapsed.InSecondsF()); |
| 338 LOG(INFO) << "Maximum latency: " << latency.InMillisecondsF() << "ms"; | 407 LOG(INFO) << "Maximum latency: " << latency.InMillisecondsF() << "ms"; |
| 339 } | 408 } |
| 340 | 409 |
| 410 const int kIntermittentFrameSize = 100 * 1000; |
| 411 |
| 341 // Frame generator that rewrites the whole screen every 60th frame. Should only | 412 // Frame generator that rewrites the whole screen every 60th frame. Should only |
| 342 // be used with the VERBATIM codec as the allocated frame may contain arbitrary | 413 // be used with the VERBATIM codec as the allocated frame may contain arbitrary |
| 343 // data. | 414 // data. |
| 344 class IntermittentChangeFrameGenerator | 415 class IntermittentChangeFrameGenerator |
| 345 : public base::RefCountedThreadSafe<IntermittentChangeFrameGenerator> { | 416 : public base::RefCountedThreadSafe<IntermittentChangeFrameGenerator> { |
| 346 public: | 417 public: |
| 347 IntermittentChangeFrameGenerator() | 418 IntermittentChangeFrameGenerator() |
| 348 : frame_index_(0) {} | 419 : frame_index_(0) {} |
| 349 | 420 |
| 350 scoped_ptr<webrtc::DesktopFrame> GenerateFrame( | 421 scoped_ptr<webrtc::DesktopFrame> GenerateFrame( |
| 351 webrtc::DesktopCapturer::Callback* callback) { | 422 webrtc::DesktopCapturer::Callback* callback) { |
| 352 const int kWidth = 800; | 423 const int kWidth = 1000; |
| 353 const int kHeight = 600; | 424 const int kHeight = kIntermittentFrameSize / kWidth / 4; |
| 354 | 425 |
| 355 bool fresh_frame = false; | 426 bool fresh_frame = false; |
| 356 if (frame_index_ % 60 == 0 || !current_frame_) { | 427 if (frame_index_ % 60 == 0 || !current_frame_) { |
| 357 current_frame_.reset(webrtc::SharedDesktopFrame::Wrap( | 428 current_frame_.reset(webrtc::SharedDesktopFrame::Wrap( |
| 358 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight)))); | 429 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight)))); |
| 359 fresh_frame = true; | 430 fresh_frame = true; |
| 360 } | 431 } |
| 361 ++frame_index_; | 432 ++frame_index_; |
| 362 | 433 |
| 363 scoped_ptr<webrtc::DesktopFrame> result(current_frame_->Share()); | 434 scoped_ptr<webrtc::DesktopFrame> result(current_frame_->Share()); |
| 364 result->mutable_updated_region()->Clear(); | 435 result->mutable_updated_region()->Clear(); |
| 365 if (fresh_frame) { | 436 if (fresh_frame) { |
| 366 result->mutable_updated_region()->AddRect( | 437 result->mutable_updated_region()->AddRect( |
| 367 webrtc::DesktopRect::MakeXYWH(0, 0, kWidth, kHeight)); | 438 webrtc::DesktopRect::MakeXYWH(0, 0, kWidth, kHeight)); |
| 368 } | 439 } |
| 369 return result.Pass(); | 440 return result.Pass(); |
| 370 } | 441 } |
| 371 | 442 |
| 372 private: | 443 private: |
| 373 ~IntermittentChangeFrameGenerator() {} | 444 ~IntermittentChangeFrameGenerator() {} |
| 374 friend class base::RefCountedThreadSafe<IntermittentChangeFrameGenerator>; | 445 friend class base::RefCountedThreadSafe<IntermittentChangeFrameGenerator>; |
| 375 | 446 |
| 376 int frame_index_; | 447 int frame_index_; |
| 377 scoped_ptr<webrtc::SharedDesktopFrame> current_frame_; | 448 scoped_ptr<webrtc::SharedDesktopFrame> current_frame_; |
| 378 | 449 |
| 379 DISALLOW_COPY_AND_ASSIGN(IntermittentChangeFrameGenerator); | 450 DISALLOW_COPY_AND_ASSIGN(IntermittentChangeFrameGenerator); |
| 380 }; | 451 }; |
| 381 | 452 |
| 382 TEST_F(ProtocolPerfTest, IntermittentChanges) { | 453 TEST_P(ProtocolPerfTest, IntermittentChanges) { |
| 383 desktop_environment_factory_.set_frame_generator( | 454 desktop_environment_factory_.set_frame_generator( |
| 384 base::Bind(&IntermittentChangeFrameGenerator::GenerateFrame, | 455 base::Bind(&IntermittentChangeFrameGenerator::GenerateFrame, |
| 385 new IntermittentChangeFrameGenerator())); | 456 new IntermittentChangeFrameGenerator())); |
| 386 | 457 |
| 387 StartHostAndClient(protocol::ChannelConfig::CODEC_VERBATIM); | 458 StartHostAndClient(protocol::ChannelConfig::CODEC_VERBATIM); |
| 388 ASSERT_NO_FATAL_FAILURE(WaitConnected()); | 459 ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
| 389 | 460 |
| 390 ReceiveFrame(NULL); | 461 ReceiveFrame(NULL); |
| 391 | 462 |
| 392 for (int i = 0; i < 5; ++i) { | 463 base::TimeDelta expected = GetParam().latency_average; |
| 464 if (GetParam().bandwidth > 0) { |
| 465 expected += base::TimeDelta::FromSecondsD(kIntermittentFrameSize / |
| 466 GetParam().bandwidth); |
| 467 } |
| 468 LOG(INFO) << "Expected: " << expected.InMillisecondsF() << "ms"; |
| 469 |
| 470 base::TimeDelta sum; |
| 471 |
| 472 const int kFrames = 5; |
| 473 for (int i = 0; i < kFrames; ++i) { |
| 393 base::TimeDelta latency; | 474 base::TimeDelta latency; |
| 394 ReceiveFrame(&latency); | 475 ReceiveFrame(&latency); |
| 395 LOG(INFO) << "Latency: " << latency.InMillisecondsF() | 476 LOG(INFO) << "Latency: " << latency.InMillisecondsF() |
| 396 << "ms Encode: " << last_video_packet_->encode_time_ms() | 477 << "ms Encode: " << last_video_packet_->encode_time_ms() |
| 397 << "ms Capture: " << last_video_packet_->capture_time_ms() | 478 << "ms Capture: " << last_video_packet_->capture_time_ms() |
| 398 << "ms"; | 479 << "ms"; |
| 480 sum += latency; |
| 399 } | 481 } |
| 482 |
| 483 LOG(INFO) << "Average: " << (sum / kFrames).InMillisecondsF(); |
| 400 } | 484 } |
| 401 | 485 |
| 402 } // namespace remoting | 486 } // namespace remoting |
| OLD | NEW |