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/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
11 #include "base/rand_util.h" | 11 #include "base/rand_util.h" |
12 #include "base/run_loop.h" | 12 #include "base/run_loop.h" |
13 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" |
14 #include "base/synchronization/waitable_event.h" | 14 #include "base/synchronization/waitable_event.h" |
| 15 #include "base/task_runner_util.h" |
15 #include "base/thread_task_runner_handle.h" | 16 #include "base/thread_task_runner_handle.h" |
16 #include "jingle/glue/thread_wrapper.h" | 17 #include "jingle/glue/thread_wrapper.h" |
17 #include "net/base/test_data_directory.h" | 18 #include "net/base/test_data_directory.h" |
18 #include "net/url_request/url_request_context_getter.h" | 19 #include "net/url_request/url_request_context_getter.h" |
19 #include "remoting/base/rsa_key_pair.h" | 20 #include "remoting/base/rsa_key_pair.h" |
20 #include "remoting/client/audio_player.h" | 21 #include "remoting/client/audio_player.h" |
21 #include "remoting/client/chromoting_client.h" | 22 #include "remoting/client/chromoting_client.h" |
22 #include "remoting/client/client_context.h" | 23 #include "remoting/client/client_context.h" |
23 #include "remoting/client/client_user_interface.h" | 24 #include "remoting/client/client_user_interface.h" |
| 25 #include "remoting/codec/video_decoder_verbatim.h" |
| 26 #include "remoting/codec/video_decoder_vpx.h" |
24 #include "remoting/host/chromoting_host.h" | 27 #include "remoting/host/chromoting_host.h" |
25 #include "remoting/host/chromoting_host_context.h" | 28 #include "remoting/host/chromoting_host_context.h" |
26 #include "remoting/host/fake_desktop_environment.h" | 29 #include "remoting/host/fake_desktop_environment.h" |
| 30 #include "remoting/protocol/frame_consumer.h" |
27 #include "remoting/protocol/jingle_session_manager.h" | 31 #include "remoting/protocol/jingle_session_manager.h" |
28 #include "remoting/protocol/me2me_host_authenticator_factory.h" | 32 #include "remoting/protocol/me2me_host_authenticator_factory.h" |
29 #include "remoting/protocol/negotiating_client_authenticator.h" | 33 #include "remoting/protocol/negotiating_client_authenticator.h" |
30 #include "remoting/protocol/session_config.h" | 34 #include "remoting/protocol/session_config.h" |
31 #include "remoting/protocol/transport_context.h" | 35 #include "remoting/protocol/transport_context.h" |
32 #include "remoting/protocol/video_frame_pump.h" | 36 #include "remoting/protocol/video_frame_pump.h" |
33 #include "remoting/protocol/video_renderer.h" | 37 #include "remoting/protocol/video_renderer.h" |
34 #include "remoting/signaling/fake_signal_strategy.h" | 38 #include "remoting/signaling/fake_signal_strategy.h" |
| 39 #include "remoting/test/cyclic_frame_generator.h" |
35 #include "remoting/test/fake_network_dispatcher.h" | 40 #include "remoting/test/fake_network_dispatcher.h" |
36 #include "remoting/test/fake_port_allocator.h" | 41 #include "remoting/test/fake_port_allocator.h" |
37 #include "remoting/test/fake_socket_factory.h" | 42 #include "remoting/test/fake_socket_factory.h" |
38 #include "testing/gtest/include/gtest/gtest.h" | 43 #include "testing/gtest/include/gtest/gtest.h" |
39 | 44 |
40 namespace remoting { | 45 namespace remoting { |
41 | 46 |
42 using protocol::ChannelConfig; | 47 using protocol::ChannelConfig; |
43 | 48 |
| 49 namespace { |
| 50 |
44 const char kHostJid[] = "host_jid@example.com/host"; | 51 const char kHostJid[] = "host_jid@example.com/host"; |
45 const char kHostOwner[] = "jane.doe@example.com"; | 52 const char kHostOwner[] = "jane.doe@example.com"; |
46 const char kClientJid[] = "jane.doe@example.com/client"; | 53 const char kClientJid[] = "jane.doe@example.com/client"; |
47 | 54 |
48 struct NetworkPerformanceParams { | 55 struct NetworkPerformanceParams { |
49 NetworkPerformanceParams(int bandwidth, | 56 NetworkPerformanceParams(int bandwidth, |
50 int max_buffers, | 57 int max_buffers, |
51 double latency_average_ms, | 58 double latency_average_ms, |
52 double latency_stddev_ms, | 59 double latency_stddev_ms, |
53 double out_of_order_rate) | 60 double out_of_order_rate) |
(...skipping 12 matching lines...) Expand all Loading... |
66 | 73 |
67 class FakeCursorShapeStub : public protocol::CursorShapeStub { | 74 class FakeCursorShapeStub : public protocol::CursorShapeStub { |
68 public: | 75 public: |
69 FakeCursorShapeStub() {} | 76 FakeCursorShapeStub() {} |
70 ~FakeCursorShapeStub() override {} | 77 ~FakeCursorShapeStub() override {} |
71 | 78 |
72 // protocol::CursorShapeStub interface. | 79 // protocol::CursorShapeStub interface. |
73 void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) override{}; | 80 void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) override{}; |
74 }; | 81 }; |
75 | 82 |
| 83 scoped_ptr<webrtc::DesktopFrame> DoDecodeFrame( |
| 84 VideoDecoder* decoder, |
| 85 VideoPacket* packet, |
| 86 scoped_ptr<webrtc::DesktopFrame> frame) { |
| 87 if (!decoder->DecodePacket(*packet, frame.get())) |
| 88 frame.reset(); |
| 89 return frame; |
| 90 } |
| 91 |
| 92 } // namespace |
| 93 |
76 class ProtocolPerfTest | 94 class ProtocolPerfTest |
77 : public testing::Test, | 95 : public testing::Test, |
78 public testing::WithParamInterface<NetworkPerformanceParams>, | 96 public testing::WithParamInterface<NetworkPerformanceParams>, |
79 public ClientUserInterface, | 97 public ClientUserInterface, |
80 public protocol::VideoRenderer, | 98 public protocol::VideoRenderer, |
81 public protocol::VideoStub, | 99 public protocol::VideoStub, |
| 100 public protocol::FrameConsumer, |
82 public HostStatusObserver { | 101 public HostStatusObserver { |
83 public: | 102 public: |
84 ProtocolPerfTest() | 103 ProtocolPerfTest() |
85 : host_thread_("host"), | 104 : host_thread_("host"), |
86 capture_thread_("capture"), | 105 capture_thread_("capture"), |
87 encode_thread_("encode") { | 106 encode_thread_("encode"), |
| 107 decode_thread_("decode") { |
88 protocol::VideoFramePump::EnableTimestampsForTests(); | 108 protocol::VideoFramePump::EnableTimestampsForTests(); |
89 host_thread_.StartWithOptions( | 109 host_thread_.StartWithOptions( |
90 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); | 110 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
91 capture_thread_.Start(); | 111 capture_thread_.Start(); |
92 encode_thread_.Start(); | 112 encode_thread_.Start(); |
| 113 decode_thread_.Start(); |
93 } | 114 } |
94 | 115 |
95 virtual ~ProtocolPerfTest() { | 116 virtual ~ProtocolPerfTest() { |
96 host_thread_.task_runner()->DeleteSoon(FROM_HERE, host_.release()); | 117 host_thread_.task_runner()->DeleteSoon(FROM_HERE, host_.release()); |
97 host_thread_.task_runner()->DeleteSoon(FROM_HERE, | 118 host_thread_.task_runner()->DeleteSoon(FROM_HERE, |
98 host_signaling_.release()); | 119 host_signaling_.release()); |
99 message_loop_.RunUntilIdle(); | 120 message_loop_.RunUntilIdle(); |
100 } | 121 } |
101 | 122 |
102 // ClientUserInterface interface. | 123 // ClientUserInterface interface. |
(...skipping 13 matching lines...) Expand all Loading... |
116 const protocol::PairingResponse& pairing_response) override {} | 137 const protocol::PairingResponse& pairing_response) override {} |
117 void DeliverHostMessage(const protocol::ExtensionMessage& message) override {} | 138 void DeliverHostMessage(const protocol::ExtensionMessage& message) override {} |
118 protocol::ClipboardStub* GetClipboardStub() override { return nullptr; } | 139 protocol::ClipboardStub* GetClipboardStub() override { return nullptr; } |
119 protocol::CursorShapeStub* GetCursorShapeStub() override { | 140 protocol::CursorShapeStub* GetCursorShapeStub() override { |
120 return &cursor_shape_stub_; | 141 return &cursor_shape_stub_; |
121 } | 142 } |
122 | 143 |
123 // VideoRenderer interface. | 144 // VideoRenderer interface. |
124 void OnSessionConfig(const protocol::SessionConfig& config) override {} | 145 void OnSessionConfig(const protocol::SessionConfig& config) override {} |
125 protocol::VideoStub* GetVideoStub() override { return this; } | 146 protocol::VideoStub* GetVideoStub() override { return this; } |
126 protocol::FrameConsumer* GetFrameConsumer() override { | 147 protocol::FrameConsumer* GetFrameConsumer() override { return this; } |
127 NOTREACHED(); | |
128 return nullptr; | |
129 } | |
130 | 148 |
131 // protocol::VideoStub interface. | 149 // protocol::VideoStub interface. |
132 void ProcessVideoPacket(scoped_ptr<VideoPacket> video_packet, | 150 void ProcessVideoPacket(scoped_ptr<VideoPacket> packet, |
133 const base::Closure& done) override { | 151 const base::Closure& done) override { |
134 if (video_packet->data().empty()) { | 152 if (packet->data().empty()) { |
135 // Ignore keep-alive packets | 153 // Ignore keep-alive packets |
136 done.Run(); | 154 done.Run(); |
137 return; | 155 return; |
138 } | 156 } |
139 | 157 |
140 last_video_packet_ = std::move(video_packet); | 158 if (packet->format().has_screen_width() && |
| 159 packet->format().has_screen_height()) { |
| 160 frame_size_.set(packet->format().screen_width(), |
| 161 packet->format().screen_height()); |
| 162 } |
141 | 163 |
| 164 scoped_ptr<webrtc::DesktopFrame> frame( |
| 165 new webrtc::BasicDesktopFrame(frame_size_)); |
| 166 base::PostTaskAndReplyWithResult( |
| 167 decode_thread_.task_runner().get(), FROM_HERE, |
| 168 base::Bind(&DoDecodeFrame, video_decoder_.get(), packet.get(), |
| 169 base::Passed(&frame)), |
| 170 base::Bind(&ProtocolPerfTest::OnFrameDecoded, base::Unretained(this), |
| 171 base::Passed(&packet), done)); |
| 172 } |
| 173 |
| 174 void OnFrameDecoded(scoped_ptr<VideoPacket> packet, |
| 175 const base::Closure& done, |
| 176 scoped_ptr<webrtc::DesktopFrame> frame) { |
| 177 last_video_packet_ = std::move(packet); |
| 178 DrawFrame(std::move(frame), done); |
| 179 } |
| 180 |
| 181 // protocol::FrameConsumer interface. |
| 182 scoped_ptr<webrtc::DesktopFrame> AllocateFrame( |
| 183 const webrtc::DesktopSize& size) override { |
| 184 return make_scoped_ptr(new webrtc::BasicDesktopFrame(size)); |
| 185 } |
| 186 |
| 187 void DrawFrame(scoped_ptr<webrtc::DesktopFrame> frame, |
| 188 const base::Closure& done) override { |
| 189 last_video_frame_ = std::move(frame); |
142 if (!on_frame_task_.is_null()) | 190 if (!on_frame_task_.is_null()) |
143 on_frame_task_.Run(); | 191 on_frame_task_.Run(); |
| 192 if (!done.is_null()) |
| 193 done.Run(); |
| 194 } |
144 | 195 |
145 done.Run(); | 196 protocol::FrameConsumer::PixelFormat GetPixelFormat() override { |
| 197 return FORMAT_BGRA; |
146 } | 198 } |
147 | 199 |
148 // HostStatusObserver interface. | 200 // HostStatusObserver interface. |
149 void OnClientConnected(const std::string& jid) override { | 201 void OnClientConnected(const std::string& jid) override { |
150 message_loop_.PostTask( | 202 message_loop_.PostTask( |
151 FROM_HERE, | 203 FROM_HERE, |
152 base::Bind(&ProtocolPerfTest::OnHostConnectedMainThread, | 204 base::Bind(&ProtocolPerfTest::OnHostConnectedMainThread, |
153 base::Unretained(this))); | 205 base::Unretained(this))); |
154 } | 206 } |
155 | 207 |
156 protected: | 208 protected: |
157 void WaitConnected() { | 209 void WaitConnected() { |
158 client_connected_ = false; | 210 client_connected_ = false; |
159 host_connected_ = false; | 211 host_connected_ = false; |
160 | 212 |
161 connecting_loop_.reset(new base::RunLoop()); | 213 connecting_loop_.reset(new base::RunLoop()); |
162 connecting_loop_->Run(); | 214 connecting_loop_->Run(); |
163 | 215 |
164 ASSERT_TRUE(client_connected_ && host_connected_); | 216 ASSERT_TRUE(client_connected_ && host_connected_); |
165 } | 217 } |
166 | 218 |
167 void OnHostConnectedMainThread() { | 219 void OnHostConnectedMainThread() { |
168 host_connected_ = true; | 220 host_connected_ = true; |
169 if (client_connected_) | 221 if (client_connected_) |
170 connecting_loop_->Quit(); | 222 connecting_loop_->Quit(); |
171 } | 223 } |
172 | 224 |
173 void ReceiveFrame(base::TimeDelta* latency) { | 225 scoped_ptr<webrtc::DesktopFrame> ReceiveFrame() { |
| 226 last_video_frame_.reset(); |
| 227 |
174 waiting_frames_loop_.reset(new base::RunLoop()); | 228 waiting_frames_loop_.reset(new base::RunLoop()); |
175 on_frame_task_ = waiting_frames_loop_->QuitClosure(); | 229 on_frame_task_ = waiting_frames_loop_->QuitClosure(); |
176 waiting_frames_loop_->Run(); | 230 waiting_frames_loop_->Run(); |
177 | 231 |
| 232 EXPECT_TRUE(last_video_frame_); |
| 233 return std::move(last_video_frame_); |
| 234 } |
| 235 |
| 236 void ReceiveFrameAndGetLatency(base::TimeDelta* latency) { |
| 237 last_video_packet_.reset(); |
| 238 |
| 239 ReceiveFrame(); |
| 240 |
178 if (latency) { | 241 if (latency) { |
179 base::TimeTicks timestamp = | 242 base::TimeTicks timestamp = |
180 base::TimeTicks::FromInternalValue(last_video_packet_->timestamp()); | 243 base::TimeTicks::FromInternalValue(last_video_packet_->timestamp()); |
181 *latency = base::TimeTicks::Now() - timestamp; | 244 *latency = base::TimeTicks::Now() - timestamp; |
182 } | 245 } |
183 } | 246 } |
184 | 247 |
185 void ReceiveFrames(int frames, base::TimeDelta* max_latency) { | 248 void ReceiveMultipleFramesAndGetMaxLatency(int frames, |
| 249 base::TimeDelta* max_latency) { |
186 if (max_latency) | 250 if (max_latency) |
187 *max_latency = base::TimeDelta(); | 251 *max_latency = base::TimeDelta(); |
188 | 252 |
189 for (int i = 0; i < frames; ++i) { | 253 for (int i = 0; i < frames; ++i) { |
190 base::TimeDelta latency; | 254 base::TimeDelta latency; |
191 | 255 |
192 ReceiveFrame(&latency); | 256 ReceiveFrameAndGetLatency(&latency); |
193 | 257 |
194 if (max_latency && latency > *max_latency) { | 258 if (max_latency && latency > *max_latency) { |
195 *max_latency = latency; | 259 *max_latency = latency; |
196 } | 260 } |
197 } | 261 } |
198 } | 262 } |
199 | 263 |
200 // Creates test host and client and starts connection between them. Caller | 264 // Creates test host and client and starts connection between them. Caller |
201 // should call WaitConnected() to wait until connection is established. The | 265 // should call WaitConnected() to wait until connection is established. The |
202 // host is started on |host_thread_| while the client works on the main | 266 // host is started on |host_thread_| while the client works on the main |
203 // thread. | 267 // thread. |
204 void StartHostAndClient(protocol::ChannelConfig::Codec video_codec) { | 268 void StartHostAndClient(bool use_webrtc, |
| 269 protocol::ChannelConfig::Codec video_codec) { |
205 fake_network_dispatcher_ = new FakeNetworkDispatcher(); | 270 fake_network_dispatcher_ = new FakeNetworkDispatcher(); |
206 | 271 |
207 client_signaling_.reset(new FakeSignalStrategy(kClientJid)); | 272 client_signaling_.reset(new FakeSignalStrategy(kClientJid)); |
208 | 273 |
209 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); | 274 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); |
210 | 275 |
211 protocol_config_ = protocol::CandidateSessionConfig::CreateDefault(); | 276 protocol_config_ = protocol::CandidateSessionConfig::CreateDefault(); |
212 protocol_config_->DisableAudioChannel(); | 277 protocol_config_->DisableAudioChannel(); |
213 protocol_config_->mutable_video_configs()->clear(); | 278 protocol_config_->mutable_video_configs()->clear(); |
214 protocol_config_->mutable_video_configs()->push_back( | 279 protocol_config_->mutable_video_configs()->push_back( |
215 protocol::ChannelConfig( | 280 protocol::ChannelConfig( |
216 protocol::ChannelConfig::TRANSPORT_STREAM, 2, video_codec)); | 281 protocol::ChannelConfig::TRANSPORT_STREAM, 2, video_codec)); |
| 282 protocol_config_->set_webrtc_supported(use_webrtc); |
| 283 protocol_config_->set_ice_supported(!use_webrtc); |
| 284 |
| 285 switch (video_codec) { |
| 286 case ChannelConfig::CODEC_VERBATIM: |
| 287 video_decoder_.reset(new VideoDecoderVerbatim()); |
| 288 break; |
| 289 case ChannelConfig::CODEC_VP8: |
| 290 video_decoder_ = VideoDecoderVpx::CreateForVP8(); |
| 291 break; |
| 292 default: |
| 293 NOTREACHED(); |
| 294 } |
217 | 295 |
218 host_thread_.task_runner()->PostTask( | 296 host_thread_.task_runner()->PostTask( |
219 FROM_HERE, | 297 FROM_HERE, |
220 base::Bind(&ProtocolPerfTest::StartHost, base::Unretained(this))); | 298 base::Bind(&ProtocolPerfTest::StartHost, base::Unretained(this))); |
221 } | 299 } |
222 | 300 |
223 void StartHost() { | 301 void StartHost() { |
224 DCHECK(host_thread_.task_runner()->BelongsToCurrentThread()); | 302 DCHECK(host_thread_.task_runner()->BelongsToCurrentThread()); |
225 | 303 |
226 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); | 304 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 new FakePortAllocatorFactory(fake_network_dispatcher_)); | 378 new FakePortAllocatorFactory(fake_network_dispatcher_)); |
301 port_allocator_factory->socket_factory()->SetBandwidth( | 379 port_allocator_factory->socket_factory()->SetBandwidth( |
302 GetParam().bandwidth, GetParam().max_buffers); | 380 GetParam().bandwidth, GetParam().max_buffers); |
303 port_allocator_factory->socket_factory()->SetLatency( | 381 port_allocator_factory->socket_factory()->SetLatency( |
304 GetParam().latency_average, GetParam().latency_stddev); | 382 GetParam().latency_average, GetParam().latency_stddev); |
305 port_allocator_factory->socket_factory()->set_out_of_order_rate( | 383 port_allocator_factory->socket_factory()->set_out_of_order_rate( |
306 GetParam().out_of_order_rate); | 384 GetParam().out_of_order_rate); |
307 scoped_refptr<protocol::TransportContext> transport_context( | 385 scoped_refptr<protocol::TransportContext> transport_context( |
308 new protocol::TransportContext( | 386 new protocol::TransportContext( |
309 host_signaling_.get(), std::move(port_allocator_factory), | 387 host_signaling_.get(), std::move(port_allocator_factory), |
310 network_settings, protocol::TransportRole::SERVER)); | 388 network_settings, protocol::TransportRole::CLIENT)); |
311 | 389 |
312 std::vector<protocol::AuthenticationMethod> auth_methods; | 390 std::vector<protocol::AuthenticationMethod> auth_methods; |
313 auth_methods.push_back(protocol::AuthenticationMethod::Spake2( | 391 auth_methods.push_back(protocol::AuthenticationMethod::Spake2( |
314 protocol::AuthenticationMethod::NONE)); | 392 protocol::AuthenticationMethod::NONE)); |
315 scoped_ptr<protocol::Authenticator> client_authenticator( | 393 scoped_ptr<protocol::Authenticator> client_authenticator( |
316 new protocol::NegotiatingClientAuthenticator( | 394 new protocol::NegotiatingClientAuthenticator( |
317 std::string(), // client_pairing_id | 395 std::string(), // client_pairing_id |
318 std::string(), // client_pairing_secret | 396 std::string(), // client_pairing_secret |
319 std::string(), // authentication_tag | 397 std::string(), // authentication_tag |
320 base::Bind(&ProtocolPerfTest::FetchPin, base::Unretained(this)), | 398 base::Bind(&ProtocolPerfTest::FetchPin, base::Unretained(this)), |
321 nullptr, auth_methods)); | 399 nullptr, auth_methods)); |
322 client_.reset( | 400 client_.reset( |
323 new ChromotingClient(client_context_.get(), this, this, nullptr)); | 401 new ChromotingClient(client_context_.get(), this, this, nullptr)); |
324 client_->set_protocol_config(protocol_config_->Clone()); | 402 client_->set_protocol_config(protocol_config_->Clone()); |
325 client_->Start(client_signaling_.get(), std::move(client_authenticator), | 403 client_->Start(client_signaling_.get(), std::move(client_authenticator), |
326 transport_context, kHostJid, std::string()); | 404 transport_context, kHostJid, std::string()); |
327 } | 405 } |
328 | 406 |
329 void FetchPin( | 407 void FetchPin( |
330 bool pairing_supported, | 408 bool pairing_supported, |
331 const protocol::SecretFetchedCallback& secret_fetched_callback) { | 409 const protocol::SecretFetchedCallback& secret_fetched_callback) { |
332 secret_fetched_callback.Run("123456"); | 410 secret_fetched_callback.Run("123456"); |
333 } | 411 } |
334 | 412 |
| 413 void MeasureTotalLatency(bool webrtc) { |
| 414 scoped_refptr<test::CyclicFrameGenerator> frame_generator = |
| 415 test::CyclicFrameGenerator::Create(); |
| 416 frame_generator->set_draw_barcode(true); |
| 417 |
| 418 desktop_environment_factory_.set_frame_generator(base::Bind( |
| 419 &test::CyclicFrameGenerator::GenerateFrame, frame_generator)); |
| 420 |
| 421 StartHostAndClient(webrtc, protocol::ChannelConfig::CODEC_VP8); |
| 422 ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
| 423 |
| 424 base::TimeDelta total_latency_big_frames; |
| 425 int big_frame_count = 0; |
| 426 base::TimeDelta total_latency_small_frames; |
| 427 int small_frame_count = 0; |
| 428 |
| 429 int last_frame_id = -1; |
| 430 for (int i = 0; i < 30; ++i) { |
| 431 scoped_ptr<webrtc::DesktopFrame> frame = ReceiveFrame(); |
| 432 test::CyclicFrameGenerator::FrameInfo frame_info = |
| 433 frame_generator->IdentifyFrame(frame.get()); |
| 434 base::TimeDelta latency = base::TimeTicks::Now() - frame_info.timestamp; |
| 435 |
| 436 if (frame_info.frame_id > last_frame_id) { |
| 437 last_frame_id = frame_info.frame_id; |
| 438 |
| 439 switch (frame_info.type) { |
| 440 case test::CyclicFrameGenerator::FrameType::EMPTY: |
| 441 NOTREACHED(); |
| 442 break; |
| 443 case test::CyclicFrameGenerator::FrameType::FULL: |
| 444 total_latency_big_frames += latency; |
| 445 ++big_frame_count; |
| 446 break; |
| 447 case test::CyclicFrameGenerator::FrameType::CURSOR: |
| 448 total_latency_small_frames += latency; |
| 449 ++small_frame_count; |
| 450 break; |
| 451 } |
| 452 } else { |
| 453 LOG(ERROR) << "Unexpected duplicate frame " << frame_info.frame_id; |
| 454 } |
| 455 } |
| 456 |
| 457 CHECK(big_frame_count); |
| 458 VLOG(0) << "Average latency for big frames: " |
| 459 << (total_latency_big_frames / big_frame_count).InMillisecondsF(); |
| 460 |
| 461 if (small_frame_count) { |
| 462 VLOG(0) |
| 463 << "Average latency for small frames: " |
| 464 << (total_latency_small_frames / small_frame_count).InMillisecondsF(); |
| 465 } |
| 466 } |
| 467 |
335 base::MessageLoopForIO message_loop_; | 468 base::MessageLoopForIO message_loop_; |
336 | 469 |
337 scoped_refptr<FakeNetworkDispatcher> fake_network_dispatcher_; | 470 scoped_refptr<FakeNetworkDispatcher> fake_network_dispatcher_; |
338 | 471 |
339 base::Thread host_thread_; | 472 base::Thread host_thread_; |
340 base::Thread capture_thread_; | 473 base::Thread capture_thread_; |
341 base::Thread encode_thread_; | 474 base::Thread encode_thread_; |
| 475 base::Thread decode_thread_; |
342 FakeDesktopEnvironmentFactory desktop_environment_factory_; | 476 FakeDesktopEnvironmentFactory desktop_environment_factory_; |
343 | 477 |
344 FakeCursorShapeStub cursor_shape_stub_; | 478 FakeCursorShapeStub cursor_shape_stub_; |
345 | 479 |
346 scoped_ptr<protocol::CandidateSessionConfig> protocol_config_; | 480 scoped_ptr<protocol::CandidateSessionConfig> protocol_config_; |
347 | 481 |
348 scoped_ptr<FakeSignalStrategy> host_signaling_; | 482 scoped_ptr<FakeSignalStrategy> host_signaling_; |
349 scoped_ptr<FakeSignalStrategy> client_signaling_; | 483 scoped_ptr<FakeSignalStrategy> client_signaling_; |
350 | 484 |
351 scoped_ptr<ChromotingHost> host_; | 485 scoped_ptr<ChromotingHost> host_; |
352 scoped_ptr<ClientContext> client_context_; | 486 scoped_ptr<ClientContext> client_context_; |
353 scoped_ptr<ChromotingClient> client_; | 487 scoped_ptr<ChromotingClient> client_; |
| 488 webrtc::DesktopSize frame_size_; |
| 489 scoped_ptr<VideoDecoder> video_decoder_; |
354 | 490 |
355 scoped_ptr<base::RunLoop> connecting_loop_; | 491 scoped_ptr<base::RunLoop> connecting_loop_; |
356 scoped_ptr<base::RunLoop> waiting_frames_loop_; | 492 scoped_ptr<base::RunLoop> waiting_frames_loop_; |
357 | 493 |
358 bool client_connected_; | 494 bool client_connected_; |
359 bool host_connected_; | 495 bool host_connected_; |
360 | 496 |
361 base::Closure on_frame_task_; | 497 base::Closure on_frame_task_; |
362 | 498 |
363 scoped_ptr<VideoPacket> last_video_packet_; | 499 scoped_ptr<VideoPacket> last_video_packet_; |
| 500 scoped_ptr<webrtc::DesktopFrame> last_video_frame_; |
364 | 501 |
365 private: | 502 private: |
366 DISALLOW_COPY_AND_ASSIGN(ProtocolPerfTest); | 503 DISALLOW_COPY_AND_ASSIGN(ProtocolPerfTest); |
367 }; | 504 }; |
368 | 505 |
369 INSTANTIATE_TEST_CASE_P( | 506 INSTANTIATE_TEST_CASE_P( |
370 NoDelay, | 507 NoDelay, |
371 ProtocolPerfTest, | 508 ProtocolPerfTest, |
372 ::testing::Values(NetworkPerformanceParams(0, 0, 0, 0, 0.0))); | 509 ::testing::Values(NetworkPerformanceParams(0, 0, 0, 0, 0.0))); |
373 | 510 |
(...skipping 19 matching lines...) Expand all Loading... |
393 // 100 MBps | 530 // 100 MBps |
394 NetworkPerformanceParams(800000000, 800000000, 2, 1, 0.0), | 531 NetworkPerformanceParams(800000000, 800000000, 2, 1, 0.0), |
395 // 8 MBps | 532 // 8 MBps |
396 NetworkPerformanceParams(1000000, 300000, 30, 5, 0.01), | 533 NetworkPerformanceParams(1000000, 300000, 30, 5, 0.01), |
397 NetworkPerformanceParams(1000000, 2000000, 30, 5, 0.01), | 534 NetworkPerformanceParams(1000000, 2000000, 30, 5, 0.01), |
398 // 800 kBps | 535 // 800 kBps |
399 NetworkPerformanceParams(100000, 30000, 130, 5, 0.01), | 536 NetworkPerformanceParams(100000, 30000, 130, 5, 0.01), |
400 NetworkPerformanceParams(100000, 200000, 130, 5, 0.01))); | 537 NetworkPerformanceParams(100000, 200000, 130, 5, 0.01))); |
401 | 538 |
402 TEST_P(ProtocolPerfTest, StreamFrameRate) { | 539 TEST_P(ProtocolPerfTest, StreamFrameRate) { |
403 StartHostAndClient(protocol::ChannelConfig::CODEC_VP8); | 540 StartHostAndClient(false, protocol::ChannelConfig::CODEC_VP8); |
404 ASSERT_NO_FATAL_FAILURE(WaitConnected()); | 541 ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
405 | 542 |
406 base::TimeDelta latency; | 543 base::TimeDelta latency; |
407 | 544 |
408 ReceiveFrame(&latency); | 545 ReceiveFrameAndGetLatency(&latency); |
409 LOG(INFO) << "First frame latency: " << latency.InMillisecondsF() << "ms"; | 546 LOG(INFO) << "First frame latency: " << latency.InMillisecondsF() << "ms"; |
410 ReceiveFrames(20, nullptr); | 547 ReceiveMultipleFramesAndGetMaxLatency(20, nullptr); |
411 | 548 |
412 base::TimeTicks started = base::TimeTicks::Now(); | 549 base::TimeTicks started = base::TimeTicks::Now(); |
413 ReceiveFrames(40, &latency); | 550 ReceiveMultipleFramesAndGetMaxLatency(40, &latency); |
414 base::TimeDelta elapsed = base::TimeTicks::Now() - started; | 551 base::TimeDelta elapsed = base::TimeTicks::Now() - started; |
415 LOG(INFO) << "Frame rate: " << (40.0 / elapsed.InSecondsF()); | 552 LOG(INFO) << "Frame rate: " << (40.0 / elapsed.InSecondsF()); |
416 LOG(INFO) << "Maximum latency: " << latency.InMillisecondsF() << "ms"; | 553 LOG(INFO) << "Maximum latency: " << latency.InMillisecondsF() << "ms"; |
417 } | 554 } |
418 | 555 |
419 const int kIntermittentFrameSize = 100 * 1000; | 556 const int kIntermittentFrameSize = 100 * 1000; |
420 | 557 |
421 // Frame generator that rewrites the whole screen every 60th frame. Should only | 558 // Frame generator that rewrites the whole screen every 60th frame. Should only |
422 // be used with the VERBATIM codec as the allocated frame may contain arbitrary | 559 // be used with the VERBATIM codec as the allocated frame may contain arbitrary |
423 // data. | 560 // data. |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
457 scoped_ptr<webrtc::SharedDesktopFrame> current_frame_; | 594 scoped_ptr<webrtc::SharedDesktopFrame> current_frame_; |
458 | 595 |
459 DISALLOW_COPY_AND_ASSIGN(IntermittentChangeFrameGenerator); | 596 DISALLOW_COPY_AND_ASSIGN(IntermittentChangeFrameGenerator); |
460 }; | 597 }; |
461 | 598 |
462 TEST_P(ProtocolPerfTest, IntermittentChanges) { | 599 TEST_P(ProtocolPerfTest, IntermittentChanges) { |
463 desktop_environment_factory_.set_frame_generator( | 600 desktop_environment_factory_.set_frame_generator( |
464 base::Bind(&IntermittentChangeFrameGenerator::GenerateFrame, | 601 base::Bind(&IntermittentChangeFrameGenerator::GenerateFrame, |
465 new IntermittentChangeFrameGenerator())); | 602 new IntermittentChangeFrameGenerator())); |
466 | 603 |
467 StartHostAndClient(protocol::ChannelConfig::CODEC_VERBATIM); | 604 StartHostAndClient(false, protocol::ChannelConfig::CODEC_VERBATIM); |
468 ASSERT_NO_FATAL_FAILURE(WaitConnected()); | 605 ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
469 | 606 |
470 ReceiveFrame(nullptr); | 607 ReceiveFrameAndGetLatency(nullptr); |
471 | 608 |
472 base::TimeDelta expected = GetParam().latency_average; | 609 base::TimeDelta expected = GetParam().latency_average; |
473 if (GetParam().bandwidth > 0) { | 610 if (GetParam().bandwidth > 0) { |
474 expected += base::TimeDelta::FromSecondsD(kIntermittentFrameSize / | 611 expected += base::TimeDelta::FromSecondsD(kIntermittentFrameSize / |
475 GetParam().bandwidth); | 612 GetParam().bandwidth); |
476 } | 613 } |
477 LOG(INFO) << "Expected: " << expected.InMillisecondsF() << "ms"; | 614 LOG(INFO) << "Expected: " << expected.InMillisecondsF() << "ms"; |
478 | 615 |
479 base::TimeDelta sum; | 616 base::TimeDelta sum; |
480 | 617 |
481 const int kFrames = 5; | 618 const int kFrames = 5; |
482 for (int i = 0; i < kFrames; ++i) { | 619 for (int i = 0; i < kFrames; ++i) { |
483 base::TimeDelta latency; | 620 base::TimeDelta latency; |
484 ReceiveFrame(&latency); | 621 ReceiveFrameAndGetLatency(&latency); |
485 LOG(INFO) << "Latency: " << latency.InMillisecondsF() | 622 LOG(INFO) << "Latency: " << latency.InMillisecondsF() |
486 << "ms Encode: " << last_video_packet_->encode_time_ms() | 623 << "ms Encode: " << last_video_packet_->encode_time_ms() |
487 << "ms Capture: " << last_video_packet_->capture_time_ms() | 624 << "ms Capture: " << last_video_packet_->capture_time_ms() |
488 << "ms"; | 625 << "ms"; |
489 sum += latency; | 626 sum += latency; |
490 } | 627 } |
491 | 628 |
492 LOG(INFO) << "Average: " << (sum / kFrames).InMillisecondsF(); | 629 LOG(INFO) << "Average: " << (sum / kFrames).InMillisecondsF(); |
493 } | 630 } |
494 | 631 |
| 632 TEST_P(ProtocolPerfTest, TotalLatencyIce) { |
| 633 MeasureTotalLatency(false); |
| 634 } |
| 635 |
| 636 TEST_P(ProtocolPerfTest, TotalLatencyWebrtc) { |
| 637 MeasureTotalLatency(true); |
| 638 } |
| 639 |
495 } // namespace remoting | 640 } // namespace remoting |
OLD | NEW |