[email protected] | 91e4b7f6 | 2012-01-25 23:23:02 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | 44f6076 | 2011-03-23 12:13:35 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "remoting/host/client_session.h" |
| 6 | |
[email protected] | 4fe827a | 2011-08-10 03:30:19 | [diff] [blame] | 7 | #include <algorithm> |
| 8 | |
[email protected] | 7ccb707 | 2013-06-10 20:56:28 | [diff] [blame] | 9 | #include "base/message_loop/message_loop_proxy.h" |
[email protected] | a5d181f | 2013-04-19 14:55:37 | [diff] [blame] | 10 | #include "remoting/base/capabilities.h" |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 11 | #include "remoting/codec/audio_encoder.h" |
[email protected] | a6ccb772 | 2012-10-23 21:10:43 | [diff] [blame] | 12 | #include "remoting/codec/audio_encoder_opus.h" |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 13 | #include "remoting/codec/audio_encoder_speex.h" |
| 14 | #include "remoting/codec/audio_encoder_verbatim.h" |
| 15 | #include "remoting/codec/video_encoder.h" |
[email protected] | 2149bef | 2012-10-18 03:26:53 | [diff] [blame] | 16 | #include "remoting/codec/video_encoder_verbatim.h" |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 17 | #include "remoting/codec/video_encoder_vp8.h" |
[email protected] | ce404ca | 2013-01-16 17:23:53 | [diff] [blame] | 18 | #include "remoting/host/audio_capturer.h" |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 19 | #include "remoting/host/audio_scheduler.h" |
| 20 | #include "remoting/host/desktop_environment.h" |
[email protected] | b0b72f11 | 2013-03-24 03:42:42 | [diff] [blame] | 21 | #include "remoting/host/input_injector.h" |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 22 | #include "remoting/host/screen_controls.h" |
[email protected] | 739e280 | 2013-03-18 01:03:48 | [diff] [blame] | 23 | #include "remoting/host/screen_resolution.h" |
[email protected] | 2ce8025 | 2012-10-26 07:23:12 | [diff] [blame] | 24 | #include "remoting/host/video_scheduler.h" |
[email protected] | 50d71c7 | 2012-05-03 01:28:55 | [diff] [blame] | 25 | #include "remoting/proto/control.pb.h" |
[email protected] | c78669c9 | 2011-06-13 22:42:38 | [diff] [blame] | 26 | #include "remoting/proto/event.pb.h" |
[email protected] | ff3761a1 | 2012-05-22 22:29:24 | [diff] [blame] | 27 | #include "remoting/protocol/client_stub.h" |
[email protected] | 7f44ba4 | 2012-05-31 20:26:29 | [diff] [blame] | 28 | #include "remoting/protocol/clipboard_thread_proxy.h" |
[email protected] | 8835692 | 2013-06-04 06:26:01 | [diff] [blame] | 29 | #include "remoting/protocol/pairing_registry.h" |
[email protected] | 3aef722 | 2013-06-07 22:39:50 | [diff] [blame] | 30 | #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" |
[email protected] | c78669c9 | 2011-06-13 22:42:38 | [diff] [blame] | 31 | |
[email protected] | 48a8ca3 | 2013-02-13 04:31:01 | [diff] [blame] | 32 | // Default DPI to assume for old clients that use notifyClientDimensions. |
| 33 | const int kDefaultDPI = 96; |
[email protected] | 739e280 | 2013-03-18 01:03:48 | [diff] [blame] | 34 | |
| 35 | namespace remoting { |
[email protected] | 48a8ca3 | 2013-02-13 04:31:01 | [diff] [blame] | 36 | |
[email protected] | 44f6076 | 2011-03-23 12:13:35 | [diff] [blame] | 37 | ClientSession::ClientSession( |
| 38 | EventHandler* event_handler, |
[email protected] | 032d9dd | 2012-11-01 17:55:04 | [diff] [blame] | 39 | scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner, |
[email protected] | ce404ca | 2013-01-16 17:23:53 | [diff] [blame] | 40 | scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, |
[email protected] | 16dbfb0e | 2012-11-14 04:11:19 | [diff] [blame] | 41 | scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner, |
| 42 | scoped_refptr<base::SingleThreadTaskRunner> video_encode_task_runner, |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 43 | scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, |
[email protected] | ce404ca | 2013-01-16 17:23:53 | [diff] [blame] | 44 | scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
[email protected] | 3361e1f | 2012-03-20 20:31:44 | [diff] [blame] | 45 | scoped_ptr<protocol::ConnectionToClient> connection, |
[email protected] | 8190479 | 2012-10-18 04:16:28 | [diff] [blame] | 46 | DesktopEnvironmentFactory* desktop_environment_factory, |
[email protected] | 8835692 | 2013-06-04 06:26:01 | [diff] [blame] | 47 | const base::TimeDelta& max_duration, |
| 48 | scoped_refptr<protocol::PairingRegistry> pairing_registry) |
[email protected] | 44f6076 | 2011-03-23 12:13:35 | [diff] [blame] | 49 | : event_handler_(event_handler), |
[email protected] | 3361e1f | 2012-03-20 20:31:44 | [diff] [blame] | 50 | connection_(connection.Pass()), |
| 51 | client_jid_(connection_->session()->jid()), |
[email protected] | aa46ba5 | 2013-04-27 00:00:44 | [diff] [blame] | 52 | control_factory_(this), |
[email protected] | 233bb94 | 2013-03-15 07:18:17 | [diff] [blame] | 53 | desktop_environment_factory_(desktop_environment_factory), |
[email protected] | eccc2d4 | 2013-01-10 19:35:14 | [diff] [blame] | 54 | input_tracker_(&host_input_filter_), |
[email protected] | 86cbe6b | 2012-04-03 00:56:18 | [diff] [blame] | 55 | remote_input_filter_(&input_tracker_), |
[email protected] | 58f1ad4 | 2013-01-10 23:49:51 | [diff] [blame] | 56 | mouse_clamping_filter_(&remote_input_filter_), |
[email protected] | eccc2d4 | 2013-01-10 19:35:14 | [diff] [blame] | 57 | disable_input_filter_(mouse_clamping_filter_.input_filter()), |
[email protected] | 750ae6b | 2012-08-20 22:52:40 | [diff] [blame] | 58 | disable_clipboard_filter_(clipboard_echo_filter_.host_filter()), |
| 59 | auth_input_filter_(&disable_input_filter_), |
| 60 | auth_clipboard_filter_(&disable_clipboard_filter_), |
[email protected] | 7f44ba4 | 2012-05-31 20:26:29 | [diff] [blame] | 61 | client_clipboard_factory_(clipboard_echo_filter_.client_filter()), |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 62 | max_duration_(max_duration), |
[email protected] | 032d9dd | 2012-11-01 17:55:04 | [diff] [blame] | 63 | audio_task_runner_(audio_task_runner), |
[email protected] | ce404ca | 2013-01-16 17:23:53 | [diff] [blame] | 64 | input_task_runner_(input_task_runner), |
[email protected] | 16dbfb0e | 2012-11-14 04:11:19 | [diff] [blame] | 65 | video_capture_task_runner_(video_capture_task_runner), |
| 66 | video_encode_task_runner_(video_encode_task_runner), |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 67 | network_task_runner_(network_task_runner), |
[email protected] | 8835692 | 2013-06-04 06:26:01 | [diff] [blame] | 68 | ui_task_runner_(ui_task_runner), |
| 69 | pairing_registry_(pairing_registry) { |
[email protected] | ee910fd | 2011-11-10 18:23:31 | [diff] [blame] | 70 | connection_->SetEventHandler(this); |
| 71 | |
| 72 | // TODO(sergeyu): Currently ConnectionToClient expects stubs to be |
| 73 | // set before channels are connected. Make it possible to set stubs |
| 74 | // later and set them only when connection is authenticated. |
[email protected] | 34df2ab | 2012-08-19 06:54:23 | [diff] [blame] | 75 | connection_->set_clipboard_stub(&auth_clipboard_filter_); |
[email protected] | ee910fd | 2011-11-10 18:23:31 | [diff] [blame] | 76 | connection_->set_host_stub(this); |
[email protected] | 880c6cd | 2012-08-21 04:35:07 | [diff] [blame] | 77 | connection_->set_input_stub(&auth_input_filter_); |
[email protected] | 750ae6b | 2012-08-20 22:52:40 | [diff] [blame] | 78 | |
| 79 | // |auth_*_filter_|'s states reflect whether the session is authenticated. |
| 80 | auth_input_filter_.set_enabled(false); |
| 81 | auth_clipboard_filter_.set_enabled(false); |
[email protected] | 2f408489 | 2013-02-25 20:30:20 | [diff] [blame] | 82 | |
| 83 | #if defined(OS_WIN) |
| 84 | // LocalInputMonitorWin filters out an echo of the injected input before it |
| 85 | // reaches |remote_input_filter_|. |
| 86 | remote_input_filter_.SetExpectLocalEcho(false); |
| 87 | #endif // defined(OS_WIN) |
[email protected] | 44f6076 | 2011-03-23 12:13:35 | [diff] [blame] | 88 | } |
| 89 | |
[email protected] | f19f09ca | 2013-03-13 11:10:29 | [diff] [blame] | 90 | ClientSession::~ClientSession() { |
| 91 | DCHECK(CalledOnValidThread()); |
[email protected] | f9d8a77 | 2013-06-01 04:33:17 | [diff] [blame] | 92 | DCHECK(!audio_scheduler_.get()); |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 93 | DCHECK(!desktop_environment_); |
[email protected] | b0b72f11 | 2013-03-24 03:42:42 | [diff] [blame] | 94 | DCHECK(!input_injector_); |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 95 | DCHECK(!screen_controls_); |
[email protected] | f9d8a77 | 2013-06-01 04:33:17 | [diff] [blame] | 96 | DCHECK(!video_scheduler_.get()); |
[email protected] | f19f09ca | 2013-03-13 11:10:29 | [diff] [blame] | 97 | |
| 98 | connection_.reset(); |
| 99 | } |
| 100 | |
[email protected] | 48a8ca3 | 2013-02-13 04:31:01 | [diff] [blame] | 101 | void ClientSession::NotifyClientResolution( |
| 102 | const protocol::ClientResolution& resolution) { |
[email protected] | a5d181f | 2013-04-19 14:55:37 | [diff] [blame] | 103 | DCHECK(CalledOnValidThread()); |
| 104 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 105 | // TODO(sergeyu): Move these checks to protocol layer. |
| 106 | if (!resolution.has_dips_width() || !resolution.has_dips_height() || |
| 107 | resolution.dips_width() < 0 || resolution.dips_height() < 0 || |
| 108 | resolution.width() <= 0 || resolution.height() <= 0) { |
| 109 | LOG(ERROR) << "Received invalid ClientResolution message."; |
[email protected] | 739e280 | 2013-03-18 01:03:48 | [diff] [blame] | 110 | return; |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 111 | } |
[email protected] | 739e280 | 2013-03-18 01:03:48 | [diff] [blame] | 112 | |
| 113 | VLOG(1) << "Received ClientResolution (dips_width=" |
| 114 | << resolution.dips_width() << ", dips_height=" |
| 115 | << resolution.dips_height() << ")"; |
| 116 | |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 117 | if (!screen_controls_) |
[email protected] | 739e280 | 2013-03-18 01:03:48 | [diff] [blame] | 118 | return; |
| 119 | |
| 120 | ScreenResolution client_resolution( |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 121 | webrtc::DesktopSize(resolution.dips_width(), resolution.dips_height()), |
| 122 | webrtc::DesktopVector(kDefaultDPI, kDefaultDPI)); |
[email protected] | 739e280 | 2013-03-18 01:03:48 | [diff] [blame] | 123 | |
| 124 | // Try to match the client's resolution. |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 125 | screen_controls_->SetScreenResolution(client_resolution); |
[email protected] | 50d71c7 | 2012-05-03 01:28:55 | [diff] [blame] | 126 | } |
| 127 | |
| 128 | void ClientSession::ControlVideo(const protocol::VideoControl& video_control) { |
[email protected] | a5d181f | 2013-04-19 14:55:37 | [diff] [blame] | 129 | DCHECK(CalledOnValidThread()); |
| 130 | |
[email protected] | 50d71c7 | 2012-05-03 01:28:55 | [diff] [blame] | 131 | if (video_control.has_enable()) { |
| 132 | VLOG(1) << "Received VideoControl (enable=" |
| 133 | << video_control.enable() << ")"; |
[email protected] | 324b196 | 2013-05-01 19:30:22 | [diff] [blame] | 134 | video_scheduler_->Pause(!video_control.enable()); |
[email protected] | 50d71c7 | 2012-05-03 01:28:55 | [diff] [blame] | 135 | } |
[email protected] | f2b9cf3 | 2012-04-27 00:13:43 | [diff] [blame] | 136 | } |
| 137 | |
[email protected] | f458bed | 2012-10-18 03:27:59 | [diff] [blame] | 138 | void ClientSession::ControlAudio(const protocol::AudioControl& audio_control) { |
[email protected] | a5d181f | 2013-04-19 14:55:37 | [diff] [blame] | 139 | DCHECK(CalledOnValidThread()); |
| 140 | |
[email protected] | f458bed | 2012-10-18 03:27:59 | [diff] [blame] | 141 | if (audio_control.has_enable()) { |
| 142 | VLOG(1) << "Received AudioControl (enable=" |
| 143 | << audio_control.enable() << ")"; |
[email protected] | f9d8a77 | 2013-06-01 04:33:17 | [diff] [blame] | 144 | if (audio_scheduler_.get()) |
[email protected] | ce404ca | 2013-01-16 17:23:53 | [diff] [blame] | 145 | audio_scheduler_->Pause(!audio_control.enable()); |
[email protected] | f458bed | 2012-10-18 03:27:59 | [diff] [blame] | 146 | } |
| 147 | } |
| 148 | |
[email protected] | a5d181f | 2013-04-19 14:55:37 | [diff] [blame] | 149 | void ClientSession::SetCapabilities( |
| 150 | const protocol::Capabilities& capabilities) { |
| 151 | DCHECK(CalledOnValidThread()); |
| 152 | |
| 153 | // The client should not send protocol::Capabilities if it is not supported by |
| 154 | // the config channel. |
| 155 | if (!connection_->session()->config().SupportsCapabilities()) { |
| 156 | LOG(ERROR) << "Unexpected protocol::Capabilities has been received."; |
| 157 | return; |
| 158 | } |
| 159 | |
| 160 | // Ignore all the messages but the 1st one. |
| 161 | if (client_capabilities_) { |
| 162 | LOG(WARNING) << "protocol::Capabilities has been received already."; |
| 163 | return; |
| 164 | } |
| 165 | |
| 166 | client_capabilities_ = make_scoped_ptr(new std::string()); |
| 167 | if (capabilities.has_capabilities()) |
| 168 | *client_capabilities_ = capabilities.capabilities(); |
| 169 | |
| 170 | VLOG(1) << "Client capabilities: " << *client_capabilities_; |
| 171 | |
| 172 | // Calculate the set of capabilities enabled by both client and host and |
| 173 | // pass it to the desktop environment if it is available. |
[email protected] | 324b196 | 2013-05-01 19:30:22 | [diff] [blame] | 174 | desktop_environment_->SetCapabilities( |
| 175 | IntersectCapabilities(*client_capabilities_, host_capabilities_)); |
[email protected] | a5d181f | 2013-04-19 14:55:37 | [diff] [blame] | 176 | } |
| 177 | |
[email protected] | 8835692 | 2013-06-04 06:26:01 | [diff] [blame] | 178 | void ClientSession::RequestPairing( |
| 179 | const protocol::PairingRequest& pairing_request) { |
| 180 | if (pairing_request.has_client_name()) { |
| 181 | protocol::PairingRegistry::Pairing pairing = |
| 182 | pairing_registry_->CreatePairing(pairing_request.client_name()); |
| 183 | protocol::PairingResponse pairing_response; |
[email protected] | df5189f | 2013-06-18 12:12:05 | [diff] [blame] | 184 | pairing_response.set_client_id(pairing.client_id()); |
| 185 | pairing_response.set_shared_secret(pairing.shared_secret()); |
[email protected] | 8835692 | 2013-06-04 06:26:01 | [diff] [blame] | 186 | connection_->client_stub()->SetPairingResponse(pairing_response); |
| 187 | } |
| 188 | } |
| 189 | |
[email protected] | 09eabd65c | 2013-08-13 00:13:48 | [diff] [blame^] | 190 | void ClientSession::DeliverClientMessage( |
| 191 | const protocol::ExtensionMessage& message) { |
| 192 | // No messages are currently supported. |
| 193 | LOG(INFO) << "Unexpected message received: " |
| 194 | << message.type() << ": " << message.data(); |
| 195 | } |
| 196 | |
[email protected] | cba6f81 | 2012-03-27 01:01:50 | [diff] [blame] | 197 | void ClientSession::OnConnectionAuthenticated( |
[email protected] | ee910fd | 2011-11-10 18:23:31 | [diff] [blame] | 198 | protocol::ConnectionToClient* connection) { |
[email protected] | 86cbe6b | 2012-04-03 00:56:18 | [diff] [blame] | 199 | DCHECK(CalledOnValidThread()); |
| 200 | DCHECK_EQ(connection_.get(), connection); |
[email protected] | f9d8a77 | 2013-06-01 04:33:17 | [diff] [blame] | 201 | DCHECK(!audio_scheduler_.get()); |
[email protected] | a5d181f | 2013-04-19 14:55:37 | [diff] [blame] | 202 | DCHECK(!desktop_environment_); |
[email protected] | 324b196 | 2013-05-01 19:30:22 | [diff] [blame] | 203 | DCHECK(!input_injector_); |
| 204 | DCHECK(!screen_controls_); |
[email protected] | f9d8a77 | 2013-06-01 04:33:17 | [diff] [blame] | 205 | DCHECK(!video_scheduler_.get()); |
[email protected] | 34df2ab | 2012-08-19 06:54:23 | [diff] [blame] | 206 | |
[email protected] | 750ae6b | 2012-08-20 22:52:40 | [diff] [blame] | 207 | auth_input_filter_.set_enabled(true); |
| 208 | auth_clipboard_filter_.set_enabled(true); |
[email protected] | 34df2ab | 2012-08-19 06:54:23 | [diff] [blame] | 209 | |
[email protected] | ff3761a1 | 2012-05-22 22:29:24 | [diff] [blame] | 210 | clipboard_echo_filter_.set_client_stub(connection_->client_stub()); |
[email protected] | 58f1ad4 | 2013-01-10 23:49:51 | [diff] [blame] | 211 | mouse_clamping_filter_.set_video_stub(connection_->video_stub()); |
[email protected] | 34df2ab | 2012-08-19 06:54:23 | [diff] [blame] | 212 | |
[email protected] | 5dc5b12a | 2012-06-23 01:05:14 | [diff] [blame] | 213 | if (max_duration_ > base::TimeDelta()) { |
| 214 | // TODO(simonmorris): Let Disconnect() tell the client that the |
| 215 | // disconnection was caused by the session exceeding its maximum duration. |
| 216 | max_duration_timer_.Start(FROM_HERE, max_duration_, |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 217 | this, &ClientSession::DisconnectSession); |
[email protected] | 5dc5b12a | 2012-06-23 01:05:14 | [diff] [blame] | 218 | } |
[email protected] | 34df2ab | 2012-08-19 06:54:23 | [diff] [blame] | 219 | |
[email protected] | 324b196 | 2013-05-01 19:30:22 | [diff] [blame] | 220 | // Disconnect the session if the connection was rejected by the host. |
| 221 | if (!event_handler_->OnSessionAuthenticated(this)) { |
| 222 | DisconnectSession(); |
| 223 | return; |
| 224 | } |
[email protected] | ce404ca | 2013-01-16 17:23:53 | [diff] [blame] | 225 | |
[email protected] | 96361d0 | 2013-05-08 18:26:18 | [diff] [blame] | 226 | // Create the desktop environment. Drop the connection if it could not be |
| 227 | // created for any reason (for instance the curtain could not initialize). |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 228 | desktop_environment_ = |
| 229 | desktop_environment_factory_->Create(control_factory_.GetWeakPtr()); |
[email protected] | 96361d0 | 2013-05-08 18:26:18 | [diff] [blame] | 230 | if (!desktop_environment_) { |
| 231 | DisconnectSession(); |
| 232 | return; |
| 233 | } |
| 234 | |
[email protected] | a5d181f | 2013-04-19 14:55:37 | [diff] [blame] | 235 | host_capabilities_ = desktop_environment_->GetCapabilities(); |
| 236 | |
[email protected] | 324b196 | 2013-05-01 19:30:22 | [diff] [blame] | 237 | // Ignore protocol::Capabilities messages from the client if it does not |
| 238 | // support any capabilities. |
| 239 | if (!connection_->session()->config().SupportsCapabilities()) { |
[email protected] | a5d181f | 2013-04-19 14:55:37 | [diff] [blame] | 240 | VLOG(1) << "The client does not support any capabilities."; |
| 241 | |
| 242 | client_capabilities_ = make_scoped_ptr(new std::string()); |
| 243 | desktop_environment_->SetCapabilities(*client_capabilities_); |
| 244 | } |
[email protected] | 233bb94 | 2013-03-15 07:18:17 | [diff] [blame] | 245 | |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 246 | // Create the object that controls the screen resolution. |
| 247 | screen_controls_ = desktop_environment_->CreateScreenControls(); |
[email protected] | 61cfdc5 | 2013-03-09 03:04:56 | [diff] [blame] | 248 | |
[email protected] | 324b196 | 2013-05-01 19:30:22 | [diff] [blame] | 249 | // Create the event executor. |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 250 | input_injector_ = desktop_environment_->CreateInputInjector(); |
[email protected] | eccc2d4 | 2013-01-10 19:35:14 | [diff] [blame] | 251 | |
| 252 | // Connect the host clipboard and input stubs. |
[email protected] | b0b72f11 | 2013-03-24 03:42:42 | [diff] [blame] | 253 | host_input_filter_.set_input_stub(input_injector_.get()); |
| 254 | clipboard_echo_filter_.set_host_stub(input_injector_.get()); |
[email protected] | eccc2d4 | 2013-01-10 19:35:14 | [diff] [blame] | 255 | |
[email protected] | 2ce8025 | 2012-10-26 07:23:12 | [diff] [blame] | 256 | // Create a VideoEncoder based on the session's video channel configuration. |
| 257 | scoped_ptr<VideoEncoder> video_encoder = |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 258 | CreateVideoEncoder(connection_->session()->config()); |
[email protected] | 2ce8025 | 2012-10-26 07:23:12 | [diff] [blame] | 259 | |
[email protected] | cdd1c9e | 2012-10-26 21:14:04 | [diff] [blame] | 260 | // Create a VideoScheduler to pump frames from the capturer to the client. |
[email protected] | 324b196 | 2013-05-01 19:30:22 | [diff] [blame] | 261 | video_scheduler_ = new VideoScheduler( |
[email protected] | c18ad89 | 2012-12-08 03:39:24 | [diff] [blame] | 262 | video_capture_task_runner_, |
| 263 | video_encode_task_runner_, |
| 264 | network_task_runner_, |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 265 | desktop_environment_->CreateVideoCapturer(), |
[email protected] | c18ad89 | 2012-12-08 03:39:24 | [diff] [blame] | 266 | video_encoder.Pass(), |
| 267 | connection_->client_stub(), |
[email protected] | eccc2d4 | 2013-01-10 19:35:14 | [diff] [blame] | 268 | &mouse_clamping_filter_); |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 269 | |
[email protected] | cdd1c9e | 2012-10-26 21:14:04 | [diff] [blame] | 270 | // Create an AudioScheduler if audio is enabled, to pump audio samples. |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 271 | if (connection_->session()->config().is_audio_enabled()) { |
| 272 | scoped_ptr<AudioEncoder> audio_encoder = |
| 273 | CreateAudioEncoder(connection_->session()->config()); |
[email protected] | 324b196 | 2013-05-01 19:30:22 | [diff] [blame] | 274 | audio_scheduler_ = new AudioScheduler( |
[email protected] | 032d9dd | 2012-11-01 17:55:04 | [diff] [blame] | 275 | audio_task_runner_, |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 276 | network_task_runner_, |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 277 | desktop_environment_->CreateAudioCapturer(), |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 278 | audio_encoder.Pass(), |
| 279 | connection_->audio_stub()); |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 280 | } |
[email protected] | 324b196 | 2013-05-01 19:30:22 | [diff] [blame] | 281 | } |
| 282 | |
| 283 | void ClientSession::OnConnectionChannelsConnected( |
| 284 | protocol::ConnectionToClient* connection) { |
| 285 | DCHECK(CalledOnValidThread()); |
| 286 | DCHECK_EQ(connection_.get(), connection); |
| 287 | |
| 288 | // Negotiate capabilities with the client. |
| 289 | if (connection_->session()->config().SupportsCapabilities()) { |
| 290 | VLOG(1) << "Host capabilities: " << host_capabilities_; |
| 291 | |
| 292 | protocol::Capabilities capabilities; |
| 293 | capabilities.set_capabilities(host_capabilities_); |
| 294 | connection_->client_stub()->SetCapabilities(capabilities); |
| 295 | } |
| 296 | |
| 297 | // Start the event executor. |
| 298 | input_injector_->Start(CreateClipboardProxy()); |
| 299 | SetDisableInputs(false); |
| 300 | |
| 301 | // Start capturing the screen. |
| 302 | video_scheduler_->Start(); |
| 303 | |
| 304 | // Start recording audio. |
| 305 | if (connection_->session()->config().is_audio_enabled()) |
| 306 | audio_scheduler_->Start(); |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 307 | |
[email protected] | cdd1c9e | 2012-10-26 21:14:04 | [diff] [blame] | 308 | // Notify the event handler that all our channels are now connected. |
[email protected] | cba6f81 | 2012-03-27 01:01:50 | [diff] [blame] | 309 | event_handler_->OnSessionChannelsConnected(this); |
[email protected] | ee910fd | 2011-11-10 18:23:31 | [diff] [blame] | 310 | } |
| 311 | |
[email protected] | cba6f81 | 2012-03-27 01:01:50 | [diff] [blame] | 312 | void ClientSession::OnConnectionClosed( |
[email protected] | 1f249e2 | 2011-11-29 20:19:59 | [diff] [blame] | 313 | protocol::ConnectionToClient* connection, |
[email protected] | 204a9e3 | 2012-03-02 05:42:58 | [diff] [blame] | 314 | protocol::ErrorCode error) { |
[email protected] | ec641187 | 2011-11-11 03:28:55 | [diff] [blame] | 315 | DCHECK(CalledOnValidThread()); |
[email protected] | ee910fd | 2011-11-10 18:23:31 | [diff] [blame] | 316 | DCHECK_EQ(connection_.get(), connection); |
[email protected] | 750ae6b | 2012-08-20 22:52:40 | [diff] [blame] | 317 | |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 318 | // Ignore any further callbacks. |
| 319 | control_factory_.InvalidateWeakPtrs(); |
[email protected] | a031c97 | 2012-12-27 20:10:40 | [diff] [blame] | 320 | |
[email protected] | 24a2a9d2 | 2012-12-07 09:06:47 | [diff] [blame] | 321 | // If the client never authenticated then the session failed. |
[email protected] | 750ae6b | 2012-08-20 22:52:40 | [diff] [blame] | 322 | if (!auth_input_filter_.enabled()) |
[email protected] | 1f249e2 | 2011-11-29 20:19:59 | [diff] [blame] | 323 | event_handler_->OnSessionAuthenticationFailed(this); |
[email protected] | 750ae6b | 2012-08-20 22:52:40 | [diff] [blame] | 324 | |
| 325 | // Block any further input events from the client. |
| 326 | // TODO(wez): Fix ChromotingHost::OnSessionClosed not to check our |
| 327 | // is_authenticated(), so that we can disable |auth_*_filter_| here. |
| 328 | disable_input_filter_.set_enabled(false); |
| 329 | disable_clipboard_filter_.set_enabled(false); |
[email protected] | 86cbe6b | 2012-04-03 00:56:18 | [diff] [blame] | 330 | |
| 331 | // Ensure that any pressed keys or buttons are released. |
| 332 | input_tracker_.ReleaseAll(); |
| 333 | |
[email protected] | 24a2a9d2 | 2012-12-07 09:06:47 | [diff] [blame] | 334 | // Stop components access the client, audio or video stubs, which are no |
| 335 | // longer valid once ConnectionToClient calls OnConnectionClosed(). |
[email protected] | f9d8a77 | 2013-06-01 04:33:17 | [diff] [blame] | 336 | if (audio_scheduler_.get()) { |
[email protected] | ce404ca | 2013-01-16 17:23:53 | [diff] [blame] | 337 | audio_scheduler_->Stop(); |
[email protected] | 24a2a9d2 | 2012-12-07 09:06:47 | [diff] [blame] | 338 | audio_scheduler_ = NULL; |
| 339 | } |
[email protected] | f9d8a77 | 2013-06-01 04:33:17 | [diff] [blame] | 340 | if (video_scheduler_.get()) { |
[email protected] | ce404ca | 2013-01-16 17:23:53 | [diff] [blame] | 341 | video_scheduler_->Stop(); |
[email protected] | 24a2a9d2 | 2012-12-07 09:06:47 | [diff] [blame] | 342 | video_scheduler_ = NULL; |
| 343 | } |
[email protected] | ce404ca | 2013-01-16 17:23:53 | [diff] [blame] | 344 | |
[email protected] | 24a2a9d2 | 2012-12-07 09:06:47 | [diff] [blame] | 345 | client_clipboard_factory_.InvalidateWeakPtrs(); |
[email protected] | b0b72f11 | 2013-03-24 03:42:42 | [diff] [blame] | 346 | input_injector_.reset(); |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 347 | screen_controls_.reset(); |
| 348 | desktop_environment_.reset(); |
[email protected] | 24a2a9d2 | 2012-12-07 09:06:47 | [diff] [blame] | 349 | |
| 350 | // Notify the ChromotingHost that this client is disconnected. |
[email protected] | ee910fd | 2011-11-10 18:23:31 | [diff] [blame] | 351 | // TODO(sergeyu): Log failure reason? |
[email protected] | ee910fd | 2011-11-10 18:23:31 | [diff] [blame] | 352 | event_handler_->OnSessionClosed(this); |
[email protected] | ee910fd | 2011-11-10 18:23:31 | [diff] [blame] | 353 | } |
| 354 | |
| 355 | void ClientSession::OnSequenceNumberUpdated( |
| 356 | protocol::ConnectionToClient* connection, int64 sequence_number) { |
[email protected] | ec641187 | 2011-11-11 03:28:55 | [diff] [blame] | 357 | DCHECK(CalledOnValidThread()); |
[email protected] | ee910fd | 2011-11-10 18:23:31 | [diff] [blame] | 358 | DCHECK_EQ(connection_.get(), connection); |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 359 | |
[email protected] | f9d8a77 | 2013-06-01 04:33:17 | [diff] [blame] | 360 | if (video_scheduler_.get()) |
[email protected] | 2ce8025 | 2012-10-26 07:23:12 | [diff] [blame] | 361 | video_scheduler_->UpdateSequenceNumber(sequence_number); |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 362 | |
[email protected] | ee910fd | 2011-11-10 18:23:31 | [diff] [blame] | 363 | event_handler_->OnSessionSequenceNumber(this, sequence_number); |
| 364 | } |
| 365 | |
[email protected] | 17af2ab | 2012-02-02 04:07:52 | [diff] [blame] | 366 | void ClientSession::OnRouteChange( |
| 367 | protocol::ConnectionToClient* connection, |
| 368 | const std::string& channel_name, |
[email protected] | be451c8 | 2012-03-20 22:24:47 | [diff] [blame] | 369 | const protocol::TransportRoute& route) { |
[email protected] | 91e4b7f6 | 2012-01-25 23:23:02 | [diff] [blame] | 370 | DCHECK(CalledOnValidThread()); |
| 371 | DCHECK_EQ(connection_.get(), connection); |
[email protected] | be451c8 | 2012-03-20 22:24:47 | [diff] [blame] | 372 | event_handler_->OnSessionRouteChange(this, channel_name, route); |
[email protected] | 91e4b7f6 | 2012-01-25 23:23:02 | [diff] [blame] | 373 | } |
| 374 | |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 375 | const std::string& ClientSession::client_jid() const { |
| 376 | return client_jid_; |
| 377 | } |
| 378 | |
| 379 | void ClientSession::DisconnectSession() { |
[email protected] | ec641187 | 2011-11-11 03:28:55 | [diff] [blame] | 380 | DCHECK(CalledOnValidThread()); |
| 381 | DCHECK(connection_.get()); |
[email protected] | a46bcef | 2011-11-11 01:27:23 | [diff] [blame] | 382 | |
[email protected] | 5dc5b12a | 2012-06-23 01:05:14 | [diff] [blame] | 383 | max_duration_timer_.Stop(); |
[email protected] | 24a2a9d2 | 2012-12-07 09:06:47 | [diff] [blame] | 384 | |
[email protected] | 86cbe6b | 2012-04-03 00:56:18 | [diff] [blame] | 385 | // This triggers OnConnectionClosed(), and the session may be destroyed |
[email protected] | a46bcef | 2011-11-11 01:27:23 | [diff] [blame] | 386 | // as the result, so this call must be the last in this method. |
| 387 | connection_->Disconnect(); |
[email protected] | 44f6076 | 2011-03-23 12:13:35 | [diff] [blame] | 388 | } |
| 389 | |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 390 | void ClientSession::OnLocalMouseMoved(const SkIPoint& position) { |
[email protected] | ec641187 | 2011-11-11 03:28:55 | [diff] [blame] | 391 | DCHECK(CalledOnValidThread()); |
[email protected] | 231316a | 2013-03-25 06:01:12 | [diff] [blame] | 392 | remote_input_filter_.LocalMouseMoved(position); |
[email protected] | 86cbe6b | 2012-04-03 00:56:18 | [diff] [blame] | 393 | } |
[email protected] | ec641187 | 2011-11-11 03:28:55 | [diff] [blame] | 394 | |
[email protected] | 86cbe6b | 2012-04-03 00:56:18 | [diff] [blame] | 395 | void ClientSession::SetDisableInputs(bool disable_inputs) { |
| 396 | DCHECK(CalledOnValidThread()); |
| 397 | |
[email protected] | 750ae6b | 2012-08-20 22:52:40 | [diff] [blame] | 398 | if (disable_inputs) |
[email protected] | 86cbe6b | 2012-04-03 00:56:18 | [diff] [blame] | 399 | input_tracker_.ReleaseAll(); |
[email protected] | 750ae6b | 2012-08-20 22:52:40 | [diff] [blame] | 400 | |
| 401 | disable_input_filter_.set_enabled(!disable_inputs); |
| 402 | disable_clipboard_filter_.set_enabled(!disable_inputs); |
[email protected] | c78669c9 | 2011-06-13 22:42:38 | [diff] [blame] | 403 | } |
| 404 | |
[email protected] | 7f44ba4 | 2012-05-31 20:26:29 | [diff] [blame] | 405 | scoped_ptr<protocol::ClipboardStub> ClientSession::CreateClipboardProxy() { |
| 406 | DCHECK(CalledOnValidThread()); |
| 407 | |
| 408 | return scoped_ptr<protocol::ClipboardStub>( |
| 409 | new protocol::ClipboardThreadProxy( |
| 410 | client_clipboard_factory_.GetWeakPtr(), |
| 411 | base::MessageLoopProxy::current())); |
| 412 | } |
| 413 | |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 414 | // TODO(sergeyu): Move this to SessionManager? |
| 415 | // static |
[email protected] | 2ce8025 | 2012-10-26 07:23:12 | [diff] [blame] | 416 | scoped_ptr<VideoEncoder> ClientSession::CreateVideoEncoder( |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 417 | const protocol::SessionConfig& config) { |
| 418 | const protocol::ChannelConfig& video_config = config.video_config(); |
| 419 | |
| 420 | if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { |
[email protected] | 2ce8025 | 2012-10-26 07:23:12 | [diff] [blame] | 421 | return scoped_ptr<VideoEncoder>(new remoting::VideoEncoderVerbatim()); |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 422 | } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) { |
[email protected] | 2ce8025 | 2012-10-26 07:23:12 | [diff] [blame] | 423 | return scoped_ptr<VideoEncoder>(new remoting::VideoEncoderVp8()); |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 424 | } |
| 425 | |
| 426 | NOTIMPLEMENTED(); |
[email protected] | 3c2dc95 | 2013-06-14 00:35:13 | [diff] [blame] | 427 | return scoped_ptr<VideoEncoder>(); |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 428 | } |
| 429 | |
| 430 | // static |
| 431 | scoped_ptr<AudioEncoder> ClientSession::CreateAudioEncoder( |
| 432 | const protocol::SessionConfig& config) { |
| 433 | const protocol::ChannelConfig& audio_config = config.audio_config(); |
| 434 | |
| 435 | if (audio_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { |
| 436 | return scoped_ptr<AudioEncoder>(new AudioEncoderVerbatim()); |
| 437 | } else if (audio_config.codec == protocol::ChannelConfig::CODEC_SPEEX) { |
| 438 | return scoped_ptr<AudioEncoder>(new AudioEncoderSpeex()); |
[email protected] | a6ccb772 | 2012-10-23 21:10:43 | [diff] [blame] | 439 | } else if (audio_config.codec == protocol::ChannelConfig::CODEC_OPUS) { |
| 440 | return scoped_ptr<AudioEncoder>(new AudioEncoderOpus()); |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 441 | } |
| 442 | |
| 443 | NOTIMPLEMENTED(); |
[email protected] | 3c2dc95 | 2013-06-14 00:35:13 | [diff] [blame] | 444 | return scoped_ptr<AudioEncoder>(); |
[email protected] | 170cba4 | 2012-09-12 22:28:39 | [diff] [blame] | 445 | } |
| 446 | |
[email protected] | 44f6076 | 2011-03-23 12:13:35 | [diff] [blame] | 447 | } // namespace remoting |