OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "remoting/host/client_session.h" | 5 #include "remoting/host/client_session.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/message_loop/message_loop_proxy.h" | 9 #include "base/message_loop/message_loop_proxy.h" |
10 #include "remoting/base/capabilities.h" | 10 #include "remoting/base/capabilities.h" |
11 #include "remoting/base/logging.h" | 11 #include "remoting/base/logging.h" |
12 #include "remoting/codec/audio_encoder.h" | 12 #include "remoting/codec/audio_encoder.h" |
13 #include "remoting/codec/audio_encoder_opus.h" | 13 #include "remoting/codec/audio_encoder_opus.h" |
14 #include "remoting/codec/audio_encoder_verbatim.h" | 14 #include "remoting/codec/audio_encoder_verbatim.h" |
15 #include "remoting/codec/video_encoder.h" | 15 #include "remoting/codec/video_encoder.h" |
16 #include "remoting/codec/video_encoder_verbatim.h" | 16 #include "remoting/codec/video_encoder_verbatim.h" |
17 #include "remoting/codec/video_encoder_vpx.h" | 17 #include "remoting/codec/video_encoder_vpx.h" |
18 #include "remoting/host/audio_capturer.h" | 18 #include "remoting/host/audio_capturer.h" |
19 #include "remoting/host/audio_scheduler.h" | 19 #include "remoting/host/audio_pump.h" |
20 #include "remoting/host/desktop_capturer_proxy.h" | 20 #include "remoting/host/desktop_capturer_proxy.h" |
21 #include "remoting/host/desktop_environment.h" | 21 #include "remoting/host/desktop_environment.h" |
22 #include "remoting/host/host_extension_session.h" | 22 #include "remoting/host/host_extension_session.h" |
23 #include "remoting/host/input_injector.h" | 23 #include "remoting/host/input_injector.h" |
24 #include "remoting/host/mouse_shape_pump.h" | 24 #include "remoting/host/mouse_shape_pump.h" |
25 #include "remoting/host/screen_controls.h" | 25 #include "remoting/host/screen_controls.h" |
26 #include "remoting/host/screen_resolution.h" | 26 #include "remoting/host/screen_resolution.h" |
27 #include "remoting/host/video_frame_pump.h" | 27 #include "remoting/host/video_frame_pump.h" |
28 #include "remoting/proto/control.pb.h" | 28 #include "remoting/proto/control.pb.h" |
29 #include "remoting/proto/event.pb.h" | 29 #include "remoting/proto/event.pb.h" |
30 #include "remoting/protocol/client_stub.h" | 30 #include "remoting/protocol/client_stub.h" |
31 #include "remoting/protocol/clipboard_thread_proxy.h" | 31 #include "remoting/protocol/clipboard_thread_proxy.h" |
32 #include "remoting/protocol/pairing_registry.h" | 32 #include "remoting/protocol/pairing_registry.h" |
33 #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" | 33 #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" |
34 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h" | 34 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h" |
35 | 35 |
36 // Default DPI to assume for old clients that use notifyClientDimensions. | 36 // Default DPI to assume for old clients that use notifyClientDimensions. |
37 const int kDefaultDPI = 96; | 37 const int kDefaultDPI = 96; |
38 | 38 |
39 namespace remoting { | 39 namespace remoting { |
40 | 40 |
| 41 namespace { |
| 42 |
| 43 scoped_ptr<VideoEncoder> CreateVideoEncoder( |
| 44 const protocol::SessionConfig& config) { |
| 45 const protocol::ChannelConfig& video_config = config.video_config(); |
| 46 |
| 47 if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) { |
| 48 return VideoEncoderVpx::CreateForVP8().Pass(); |
| 49 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP9) { |
| 50 return VideoEncoderVpx::CreateForVP9().Pass(); |
| 51 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { |
| 52 return make_scoped_ptr(new VideoEncoderVerbatim()); |
| 53 } |
| 54 |
| 55 NOTREACHED(); |
| 56 return nullptr; |
| 57 } |
| 58 |
| 59 scoped_ptr<AudioEncoder> CreateAudioEncoder( |
| 60 const protocol::SessionConfig& config) { |
| 61 const protocol::ChannelConfig& audio_config = config.audio_config(); |
| 62 |
| 63 if (audio_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { |
| 64 return make_scoped_ptr(new AudioEncoderVerbatim()); |
| 65 } else if (audio_config.codec == protocol::ChannelConfig::CODEC_OPUS) { |
| 66 return make_scoped_ptr(new AudioEncoderOpus()); |
| 67 } |
| 68 |
| 69 NOTREACHED(); |
| 70 return nullptr; |
| 71 } |
| 72 |
| 73 } // namespace |
| 74 |
41 ClientSession::ClientSession( | 75 ClientSession::ClientSession( |
42 EventHandler* event_handler, | 76 EventHandler* event_handler, |
43 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner, | 77 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner, |
44 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, | 78 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, |
45 scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner, | 79 scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner, |
46 scoped_refptr<base::SingleThreadTaskRunner> video_encode_task_runner, | 80 scoped_refptr<base::SingleThreadTaskRunner> video_encode_task_runner, |
47 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, | 81 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, |
48 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, | 82 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
49 scoped_ptr<protocol::ConnectionToClient> connection, | 83 scoped_ptr<protocol::ConnectionToClient> connection, |
50 DesktopEnvironmentFactory* desktop_environment_factory, | 84 DesktopEnvironmentFactory* desktop_environment_factory, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 | 127 |
94 #if defined(OS_WIN) | 128 #if defined(OS_WIN) |
95 // LocalInputMonitorWin filters out an echo of the injected input before it | 129 // LocalInputMonitorWin filters out an echo of the injected input before it |
96 // reaches |remote_input_filter_|. | 130 // reaches |remote_input_filter_|. |
97 remote_input_filter_.SetExpectLocalEcho(false); | 131 remote_input_filter_.SetExpectLocalEcho(false); |
98 #endif // defined(OS_WIN) | 132 #endif // defined(OS_WIN) |
99 } | 133 } |
100 | 134 |
101 ClientSession::~ClientSession() { | 135 ClientSession::~ClientSession() { |
102 DCHECK(CalledOnValidThread()); | 136 DCHECK(CalledOnValidThread()); |
103 DCHECK(!audio_scheduler_.get()); | 137 DCHECK(!audio_pump_); |
104 DCHECK(!desktop_environment_); | 138 DCHECK(!desktop_environment_); |
105 DCHECK(!input_injector_); | 139 DCHECK(!input_injector_); |
106 DCHECK(!screen_controls_); | 140 DCHECK(!screen_controls_); |
107 DCHECK(!video_frame_pump_.get()); | 141 DCHECK(!video_frame_pump_); |
108 | 142 |
109 connection_.reset(); | 143 connection_.reset(); |
110 } | 144 } |
111 | 145 |
112 void ClientSession::NotifyClientResolution( | 146 void ClientSession::NotifyClientResolution( |
113 const protocol::ClientResolution& resolution) { | 147 const protocol::ClientResolution& resolution) { |
114 DCHECK(CalledOnValidThread()); | 148 DCHECK(CalledOnValidThread()); |
115 | 149 |
116 // TODO(sergeyu): Move these checks to protocol layer. | 150 // TODO(sergeyu): Move these checks to protocol layer. |
117 if (!resolution.has_dips_width() || !resolution.has_dips_height() || | 151 if (!resolution.has_dips_width() || !resolution.has_dips_height() || |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 video_frame_pump_->SetLosslessColor(lossless_video_color_); | 197 video_frame_pump_->SetLosslessColor(lossless_video_color_); |
164 } | 198 } |
165 } | 199 } |
166 | 200 |
167 void ClientSession::ControlAudio(const protocol::AudioControl& audio_control) { | 201 void ClientSession::ControlAudio(const protocol::AudioControl& audio_control) { |
168 DCHECK(CalledOnValidThread()); | 202 DCHECK(CalledOnValidThread()); |
169 | 203 |
170 if (audio_control.has_enable()) { | 204 if (audio_control.has_enable()) { |
171 VLOG(1) << "Received AudioControl (enable=" | 205 VLOG(1) << "Received AudioControl (enable=" |
172 << audio_control.enable() << ")"; | 206 << audio_control.enable() << ")"; |
173 if (audio_scheduler_.get()) | 207 if (audio_pump_) |
174 audio_scheduler_->Pause(!audio_control.enable()); | 208 audio_pump_->Pause(!audio_control.enable()); |
175 } | 209 } |
176 } | 210 } |
177 | 211 |
178 void ClientSession::SetCapabilities( | 212 void ClientSession::SetCapabilities( |
179 const protocol::Capabilities& capabilities) { | 213 const protocol::Capabilities& capabilities) { |
180 DCHECK(CalledOnValidThread()); | 214 DCHECK(CalledOnValidThread()); |
181 | 215 |
182 // Ignore all the messages but the 1st one. | 216 // Ignore all the messages but the 1st one. |
183 if (client_capabilities_) { | 217 if (client_capabilities_) { |
184 LOG(WARNING) << "protocol::Capabilities has been received already."; | 218 LOG(WARNING) << "protocol::Capabilities has been received already."; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 | 276 |
243 void ClientSession::OnConnectionAuthenticating( | 277 void ClientSession::OnConnectionAuthenticating( |
244 protocol::ConnectionToClient* connection) { | 278 protocol::ConnectionToClient* connection) { |
245 event_handler_->OnSessionAuthenticating(this); | 279 event_handler_->OnSessionAuthenticating(this); |
246 } | 280 } |
247 | 281 |
248 void ClientSession::OnConnectionAuthenticated( | 282 void ClientSession::OnConnectionAuthenticated( |
249 protocol::ConnectionToClient* connection) { | 283 protocol::ConnectionToClient* connection) { |
250 DCHECK(CalledOnValidThread()); | 284 DCHECK(CalledOnValidThread()); |
251 DCHECK_EQ(connection_.get(), connection); | 285 DCHECK_EQ(connection_.get(), connection); |
252 DCHECK(!audio_scheduler_.get()); | 286 DCHECK(!audio_pump_); |
253 DCHECK(!desktop_environment_); | 287 DCHECK(!desktop_environment_); |
254 DCHECK(!input_injector_); | 288 DCHECK(!input_injector_); |
255 DCHECK(!screen_controls_); | 289 DCHECK(!screen_controls_); |
256 DCHECK(!video_frame_pump_.get()); | 290 DCHECK(!video_frame_pump_); |
257 | 291 |
258 auth_input_filter_.set_enabled(true); | 292 auth_input_filter_.set_enabled(true); |
259 auth_clipboard_filter_.set_enabled(true); | 293 auth_clipboard_filter_.set_enabled(true); |
260 | 294 |
261 clipboard_echo_filter_.set_client_stub(connection_->client_stub()); | 295 clipboard_echo_filter_.set_client_stub(connection_->client_stub()); |
262 mouse_clamping_filter_.set_video_stub(connection_->video_stub()); | 296 mouse_clamping_filter_.set_video_stub(connection_->video_stub()); |
263 | 297 |
264 if (max_duration_ > base::TimeDelta()) { | 298 if (max_duration_ > base::TimeDelta()) { |
265 // TODO(simonmorris): Let Disconnect() tell the client that the | 299 // TODO(simonmorris): Let Disconnect() tell the client that the |
266 // disconnection was caused by the session exceeding its maximum duration. | 300 // disconnection was caused by the session exceeding its maximum duration. |
(...skipping 25 matching lines...) Expand all Loading... |
292 // Create the object that controls the screen resolution. | 326 // Create the object that controls the screen resolution. |
293 screen_controls_ = desktop_environment_->CreateScreenControls(); | 327 screen_controls_ = desktop_environment_->CreateScreenControls(); |
294 | 328 |
295 // Create the event executor. | 329 // Create the event executor. |
296 input_injector_ = desktop_environment_->CreateInputInjector(); | 330 input_injector_ = desktop_environment_->CreateInputInjector(); |
297 | 331 |
298 // Connect the host clipboard and input stubs. | 332 // Connect the host clipboard and input stubs. |
299 host_input_filter_.set_input_stub(input_injector_.get()); | 333 host_input_filter_.set_input_stub(input_injector_.get()); |
300 clipboard_echo_filter_.set_host_stub(input_injector_.get()); | 334 clipboard_echo_filter_.set_host_stub(input_injector_.get()); |
301 | 335 |
302 // Create an AudioScheduler if audio is enabled, to pump audio samples. | |
303 if (connection_->session()->config().is_audio_enabled()) { | |
304 scoped_ptr<AudioEncoder> audio_encoder = | |
305 CreateAudioEncoder(connection_->session()->config()); | |
306 audio_scheduler_ = new AudioScheduler( | |
307 audio_task_runner_, | |
308 network_task_runner_, | |
309 desktop_environment_->CreateAudioCapturer(), | |
310 audio_encoder.Pass(), | |
311 connection_->audio_stub()); | |
312 } | |
313 | |
314 // Create a GnubbyAuthHandler to proxy gnubbyd messages. | 336 // Create a GnubbyAuthHandler to proxy gnubbyd messages. |
315 gnubby_auth_handler_ = desktop_environment_->CreateGnubbyAuthHandler( | 337 gnubby_auth_handler_ = desktop_environment_->CreateGnubbyAuthHandler( |
316 connection_->client_stub()); | 338 connection_->client_stub()); |
317 } | 339 } |
318 | 340 |
319 void ClientSession::OnConnectionChannelsConnected( | 341 void ClientSession::OnConnectionChannelsConnected( |
320 protocol::ConnectionToClient* connection) { | 342 protocol::ConnectionToClient* connection) { |
321 DCHECK(CalledOnValidThread()); | 343 DCHECK(CalledOnValidThread()); |
322 DCHECK_EQ(connection_.get(), connection); | 344 DCHECK_EQ(connection_.get(), connection); |
323 | 345 |
324 // Negotiate capabilities with the client. | 346 // Negotiate capabilities with the client. |
325 VLOG(1) << "Host capabilities: " << host_capabilities_; | 347 VLOG(1) << "Host capabilities: " << host_capabilities_; |
326 | 348 |
327 protocol::Capabilities capabilities; | 349 protocol::Capabilities capabilities; |
328 capabilities.set_capabilities(host_capabilities_); | 350 capabilities.set_capabilities(host_capabilities_); |
329 connection_->client_stub()->SetCapabilities(capabilities); | 351 connection_->client_stub()->SetCapabilities(capabilities); |
330 | 352 |
331 // Start the event executor. | 353 // Start the event executor. |
332 input_injector_->Start(CreateClipboardProxy()); | 354 input_injector_->Start(CreateClipboardProxy()); |
333 SetDisableInputs(false); | 355 SetDisableInputs(false); |
334 | 356 |
335 // Start recording video. | 357 // Start recording video. |
336 ResetVideoPipeline(); | 358 ResetVideoPipeline(); |
337 | 359 |
338 // Start recording audio. | 360 // Create an AudioPump if audio is enabled, to pump audio samples. |
339 if (connection_->session()->config().is_audio_enabled()) | 361 if (connection_->session()->config().is_audio_enabled()) { |
340 audio_scheduler_->Start(); | 362 scoped_ptr<AudioEncoder> audio_encoder = |
| 363 CreateAudioEncoder(connection_->session()->config()); |
| 364 audio_pump_.reset(new AudioPump( |
| 365 audio_task_runner_, desktop_environment_->CreateAudioCapturer(), |
| 366 audio_encoder.Pass(), connection_->audio_stub())); |
| 367 } |
341 | 368 |
342 // Notify the event handler that all our channels are now connected. | 369 // Notify the event handler that all our channels are now connected. |
343 event_handler_->OnSessionChannelsConnected(this); | 370 event_handler_->OnSessionChannelsConnected(this); |
344 } | 371 } |
345 | 372 |
346 void ClientSession::OnConnectionClosed( | 373 void ClientSession::OnConnectionClosed( |
347 protocol::ConnectionToClient* connection, | 374 protocol::ConnectionToClient* connection, |
348 protocol::ErrorCode error) { | 375 protocol::ErrorCode error) { |
349 DCHECK(CalledOnValidThread()); | 376 DCHECK(CalledOnValidThread()); |
350 DCHECK_EQ(connection_.get(), connection); | 377 DCHECK_EQ(connection_.get(), connection); |
351 | 378 |
352 // Ignore any further callbacks. | 379 // Ignore any further callbacks. |
353 weak_factory_.InvalidateWeakPtrs(); | 380 weak_factory_.InvalidateWeakPtrs(); |
354 | 381 |
355 // If the client never authenticated then the session failed. | 382 // If the client never authenticated then the session failed. |
356 if (!auth_input_filter_.enabled()) | 383 if (!auth_input_filter_.enabled()) |
357 event_handler_->OnSessionAuthenticationFailed(this); | 384 event_handler_->OnSessionAuthenticationFailed(this); |
358 | 385 |
359 // Block any further input events from the client. | 386 // Block any further input events from the client. |
360 // TODO(wez): Fix ChromotingHost::OnSessionClosed not to check our | 387 // TODO(wez): Fix ChromotingHost::OnSessionClosed not to check our |
361 // is_authenticated(), so that we can disable |auth_*_filter_| here. | 388 // is_authenticated(), so that we can disable |auth_*_filter_| here. |
362 disable_input_filter_.set_enabled(false); | 389 disable_input_filter_.set_enabled(false); |
363 disable_clipboard_filter_.set_enabled(false); | 390 disable_clipboard_filter_.set_enabled(false); |
364 | 391 |
365 // Ensure that any pressed keys or buttons are released. | 392 // Ensure that any pressed keys or buttons are released. |
366 input_tracker_.ReleaseAll(); | 393 input_tracker_.ReleaseAll(); |
367 | 394 |
368 // Stop components access the client, audio or video stubs, which are no | 395 // Stop components access the client, audio or video stubs, which are no |
369 // longer valid once ConnectionToClient calls OnConnectionClosed(). | 396 // longer valid once ConnectionToClient calls OnConnectionClosed(). |
370 if (audio_scheduler_.get()) { | 397 audio_pump_.reset(); |
371 audio_scheduler_->Stop(); | |
372 audio_scheduler_ = nullptr; | |
373 } | |
374 | |
375 video_frame_pump_.reset(); | 398 video_frame_pump_.reset(); |
376 mouse_shape_pump_.reset(); | 399 mouse_shape_pump_.reset(); |
377 | |
378 client_clipboard_factory_.InvalidateWeakPtrs(); | 400 client_clipboard_factory_.InvalidateWeakPtrs(); |
379 input_injector_.reset(); | 401 input_injector_.reset(); |
380 screen_controls_.reset(); | 402 screen_controls_.reset(); |
381 desktop_environment_.reset(); | 403 desktop_environment_.reset(); |
382 | 404 |
383 // Notify the ChromotingHost that this client is disconnected. | 405 // Notify the ChromotingHost that this client is disconnected. |
384 // TODO(sergeyu): Log failure reason? | 406 // TODO(sergeyu): Log failure reason? |
385 event_handler_->OnSessionClosed(this); | 407 event_handler_->OnSessionClosed(this); |
386 } | 408 } |
387 | 409 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 } | 505 } |
484 | 506 |
485 scoped_ptr<protocol::ClipboardStub> ClientSession::CreateClipboardProxy() { | 507 scoped_ptr<protocol::ClipboardStub> ClientSession::CreateClipboardProxy() { |
486 DCHECK(CalledOnValidThread()); | 508 DCHECK(CalledOnValidThread()); |
487 | 509 |
488 return make_scoped_ptr( | 510 return make_scoped_ptr( |
489 new protocol::ClipboardThreadProxy(client_clipboard_factory_.GetWeakPtr(), | 511 new protocol::ClipboardThreadProxy(client_clipboard_factory_.GetWeakPtr(), |
490 base::MessageLoopProxy::current())); | 512 base::MessageLoopProxy::current())); |
491 } | 513 } |
492 | 514 |
493 // TODO(sergeyu): Move this to SessionManager? | |
494 // static | |
495 scoped_ptr<VideoEncoder> ClientSession::CreateVideoEncoder( | |
496 const protocol::SessionConfig& config) { | |
497 const protocol::ChannelConfig& video_config = config.video_config(); | |
498 | |
499 if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) { | |
500 return remoting::VideoEncoderVpx::CreateForVP8().Pass(); | |
501 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP9) { | |
502 return remoting::VideoEncoderVpx::CreateForVP9().Pass(); | |
503 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { | |
504 return make_scoped_ptr(new remoting::VideoEncoderVerbatim()); | |
505 } | |
506 | |
507 NOTREACHED(); | |
508 return nullptr; | |
509 } | |
510 | |
511 // static | |
512 scoped_ptr<AudioEncoder> ClientSession::CreateAudioEncoder( | |
513 const protocol::SessionConfig& config) { | |
514 const protocol::ChannelConfig& audio_config = config.audio_config(); | |
515 | |
516 if (audio_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { | |
517 return make_scoped_ptr(new AudioEncoderVerbatim()); | |
518 } else if (audio_config.codec == protocol::ChannelConfig::CODEC_OPUS) { | |
519 return make_scoped_ptr(new AudioEncoderOpus()); | |
520 } | |
521 | |
522 NOTREACHED(); | |
523 return nullptr; | |
524 } | |
525 | |
526 } // namespace remoting | 515 } // namespace remoting |
OLD | NEW |