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_proxy.h" | 9 #include "base/message_loop_proxy.h" |
10 #include "remoting/base/encoder.h" | |
11 #include "remoting/base/encoder_row_based.h" | |
12 #include "remoting/base/encoder_vp8.h" | |
13 #include "remoting/codec/audio_encoder.h" | |
14 #include "remoting/codec/audio_encoder_verbatim.h" | |
15 #include "remoting/host/audio_capturer.h" | |
16 #include "remoting/host/audio_scheduler.h" | |
17 #include "remoting/host/desktop_environment.h" | |
18 #include "remoting/host/event_executor.h" | |
19 #include "remoting/host/screen_recorder.h" | |
10 #include "remoting/host/video_frame_capturer.h" | 20 #include "remoting/host/video_frame_capturer.h" |
11 #include "remoting/proto/control.pb.h" | 21 #include "remoting/proto/control.pb.h" |
12 #include "remoting/proto/event.pb.h" | 22 #include "remoting/proto/event.pb.h" |
13 #include "remoting/protocol/client_stub.h" | 23 #include "remoting/protocol/client_stub.h" |
14 #include "remoting/protocol/clipboard_thread_proxy.h" | 24 #include "remoting/protocol/clipboard_thread_proxy.h" |
15 | 25 |
16 namespace remoting { | 26 namespace remoting { |
17 | 27 |
18 ClientSession::ClientSession( | 28 ClientSession::ClientSession( |
19 EventHandler* event_handler, | 29 EventHandler* event_handler, |
30 scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner, | |
31 scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner, | |
32 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, | |
20 scoped_ptr<protocol::ConnectionToClient> connection, | 33 scoped_ptr<protocol::ConnectionToClient> connection, |
21 protocol::ClipboardStub* host_clipboard_stub, | 34 scoped_ptr<DesktopEnvironment> desktop_environment, |
22 protocol::InputStub* host_input_stub, | |
23 VideoFrameCapturer* capturer, | |
24 const base::TimeDelta& max_duration) | 35 const base::TimeDelta& max_duration) |
25 : event_handler_(event_handler), | 36 : event_handler_(event_handler), |
26 connection_(connection.Pass()), | 37 connection_(connection.Pass()), |
38 desktop_environment_(desktop_environment.Pass()), | |
27 client_jid_(connection_->session()->jid()), | 39 client_jid_(connection_->session()->jid()), |
28 is_authenticated_(false), | 40 is_authenticated_(false), |
29 host_clipboard_stub_(host_clipboard_stub), | 41 host_clipboard_stub_(desktop_environment_->event_executor()), |
30 host_input_stub_(host_input_stub), | 42 host_input_stub_(desktop_environment_->event_executor()), |
31 input_tracker_(host_input_stub_), | 43 input_tracker_(host_input_stub_), |
32 remote_input_filter_(&input_tracker_), | 44 remote_input_filter_(&input_tracker_), |
33 mouse_input_filter_(&remote_input_filter_), | 45 mouse_input_filter_(&remote_input_filter_), |
34 client_clipboard_factory_(clipboard_echo_filter_.client_filter()), | 46 client_clipboard_factory_(clipboard_echo_filter_.client_filter()), |
35 capturer_(capturer), | 47 capturer_(desktop_environment_->video_capturer()), |
36 max_duration_(max_duration) { | 48 max_duration_(max_duration), |
49 capture_task_runner_(capture_task_runner), | |
50 encode_task_runner_(encode_task_runner), | |
51 network_task_runner_(network_task_runner), | |
52 active_recorders_(0) { | |
37 connection_->SetEventHandler(this); | 53 connection_->SetEventHandler(this); |
38 | 54 |
39 // TODO(sergeyu): Currently ConnectionToClient expects stubs to be | 55 // TODO(sergeyu): Currently ConnectionToClient expects stubs to be |
40 // set before channels are connected. Make it possible to set stubs | 56 // set before channels are connected. Make it possible to set stubs |
41 // later and set them only when connection is authenticated. | 57 // later and set them only when connection is authenticated. |
42 connection_->set_clipboard_stub(&auth_clipboard_filter_); | 58 connection_->set_clipboard_stub(&auth_clipboard_filter_); |
43 connection_->set_host_stub(this); | 59 connection_->set_host_stub(this); |
44 connection_->set_input_stub(this); | 60 connection_->set_input_stub(this); |
45 clipboard_echo_filter_.set_host_stub(host_clipboard_stub_); | 61 clipboard_echo_filter_.set_host_stub(host_clipboard_stub_); |
46 } | 62 } |
47 | 63 |
48 ClientSession::~ClientSession() { | |
49 } | |
50 | |
51 void ClientSession::InjectKeyEvent(const protocol::KeyEvent& event) { | 64 void ClientSession::InjectKeyEvent(const protocol::KeyEvent& event) { |
52 DCHECK(CalledOnValidThread()); | 65 DCHECK(CalledOnValidThread()); |
53 auth_input_filter_.InjectKeyEvent(event); | 66 auth_input_filter_.InjectKeyEvent(event); |
54 } | 67 } |
55 | 68 |
56 void ClientSession::InjectMouseEvent(const protocol::MouseEvent& event) { | 69 void ClientSession::InjectMouseEvent(const protocol::MouseEvent& event) { |
57 DCHECK(CalledOnValidThread()); | 70 DCHECK(CalledOnValidThread()); |
58 | 71 |
59 // Ensure that the MouseInputFilter is clamping to the current dimensions. | 72 // Ensure that the MouseInputFilter is clamping to the current dimensions. |
60 mouse_input_filter_.set_output_size(capturer_->size_most_recent()); | 73 mouse_input_filter_.set_output_size(capturer_->size_most_recent()); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
100 } | 113 } |
101 | 114 |
102 event_handler_->OnSessionAuthenticated(this); | 115 event_handler_->OnSessionAuthenticated(this); |
103 } | 116 } |
104 | 117 |
105 void ClientSession::OnConnectionChannelsConnected( | 118 void ClientSession::OnConnectionChannelsConnected( |
106 protocol::ConnectionToClient* connection) { | 119 protocol::ConnectionToClient* connection) { |
107 DCHECK(CalledOnValidThread()); | 120 DCHECK(CalledOnValidThread()); |
108 DCHECK_EQ(connection_.get(), connection); | 121 DCHECK_EQ(connection_.get(), connection); |
109 SetDisableInputs(false); | 122 SetDisableInputs(false); |
123 | |
124 // Create a ScreenRecorder passing the message loops that it should run on. | |
Wez
2012/09/06 00:13:23
nit: ...ScreenRecorder passing... -> ScreenRecorde
alexeypa (please no reviews)
2012/09/06 17:12:03
Done.
| |
125 Encoder* encoder = CreateEncoder(connection_->session()->config()); | |
126 video_recorder_ = new ScreenRecorder( | |
127 capture_task_runner_, | |
128 encode_task_runner_, | |
129 network_task_runner_, | |
130 desktop_environment_->video_capturer(), | |
131 encoder); | |
132 ++active_recorders_; | |
133 | |
134 if (connection_->session()->config().is_audio_enabled()) { | |
135 scoped_ptr<AudioEncoder> audio_encoder = | |
136 CreateAudioEncoder(connection_->session()->config()); | |
137 audio_scheduler_ = new AudioScheduler( | |
138 capture_task_runner_, | |
139 network_task_runner_, | |
140 desktop_environment_->audio_capturer(), | |
141 audio_encoder.Pass(), | |
142 connection_->audio_stub()); | |
143 ++active_recorders_; | |
144 } | |
145 | |
146 // Start the session. | |
147 video_recorder_->AddConnection(connection_.get()); | |
148 video_recorder_->Start(); | |
149 desktop_environment_->Start(CreateClipboardProxy()); | |
150 | |
110 event_handler_->OnSessionChannelsConnected(this); | 151 event_handler_->OnSessionChannelsConnected(this); |
111 } | 152 } |
112 | 153 |
113 void ClientSession::OnConnectionClosed( | 154 void ClientSession::OnConnectionClosed( |
114 protocol::ConnectionToClient* connection, | 155 protocol::ConnectionToClient* connection, |
115 protocol::ErrorCode error) { | 156 protocol::ErrorCode error) { |
116 DCHECK(CalledOnValidThread()); | 157 DCHECK(CalledOnValidThread()); |
117 DCHECK_EQ(connection_.get(), connection); | 158 DCHECK_EQ(connection_.get(), connection); |
118 if (!is_authenticated_) | 159 if (!is_authenticated_) |
119 event_handler_->OnSessionAuthenticationFailed(this); | 160 event_handler_->OnSessionAuthenticationFailed(this); |
120 auth_input_filter_.set_input_stub(NULL); | 161 auth_input_filter_.set_input_stub(NULL); |
121 auth_clipboard_filter_.set_clipboard_stub(NULL); | 162 auth_clipboard_filter_.set_clipboard_stub(NULL); |
122 | 163 |
123 // Ensure that any pressed keys or buttons are released. | 164 // Ensure that any pressed keys or buttons are released. |
124 input_tracker_.ReleaseAll(); | 165 input_tracker_.ReleaseAll(); |
125 | 166 |
126 // TODO(sergeyu): Log failure reason? | 167 // TODO(sergeyu): Log failure reason? |
127 event_handler_->OnSessionClosed(this); | 168 event_handler_->OnSessionClosed(this); |
128 } | 169 } |
129 | 170 |
130 void ClientSession::OnSequenceNumberUpdated( | 171 void ClientSession::OnSequenceNumberUpdated( |
131 protocol::ConnectionToClient* connection, int64 sequence_number) { | 172 protocol::ConnectionToClient* connection, int64 sequence_number) { |
132 DCHECK(CalledOnValidThread()); | 173 DCHECK(CalledOnValidThread()); |
133 DCHECK_EQ(connection_.get(), connection); | 174 DCHECK_EQ(connection_.get(), connection); |
175 | |
176 if (video_recorder_.get()) | |
177 video_recorder_->UpdateSequenceNumber(sequence_number); | |
178 | |
134 event_handler_->OnSessionSequenceNumber(this, sequence_number); | 179 event_handler_->OnSessionSequenceNumber(this, sequence_number); |
135 } | 180 } |
136 | 181 |
137 void ClientSession::OnRouteChange( | 182 void ClientSession::OnRouteChange( |
138 protocol::ConnectionToClient* connection, | 183 protocol::ConnectionToClient* connection, |
139 const std::string& channel_name, | 184 const std::string& channel_name, |
140 const protocol::TransportRoute& route) { | 185 const protocol::TransportRoute& route) { |
141 DCHECK(CalledOnValidThread()); | 186 DCHECK(CalledOnValidThread()); |
142 DCHECK_EQ(connection_.get(), connection); | 187 DCHECK_EQ(connection_.get(), connection); |
143 event_handler_->OnSessionRouteChange(this, channel_name, route); | 188 event_handler_->OnSessionRouteChange(this, channel_name, route); |
144 } | 189 } |
145 | 190 |
146 void ClientSession::Disconnect() { | 191 void ClientSession::Disconnect() { |
147 DCHECK(CalledOnValidThread()); | 192 DCHECK(CalledOnValidThread()); |
148 DCHECK(connection_.get()); | 193 DCHECK(connection_.get()); |
149 | 194 |
150 max_duration_timer_.Stop(); | 195 max_duration_timer_.Stop(); |
151 // This triggers OnConnectionClosed(), and the session may be destroyed | 196 // This triggers OnConnectionClosed(), and the session may be destroyed |
152 // as the result, so this call must be the last in this method. | 197 // as the result, so this call must be the last in this method. |
153 connection_->Disconnect(); | 198 connection_->Disconnect(); |
154 } | 199 } |
155 | 200 |
201 void ClientSession::StopAndDelete() { | |
202 DCHECK(CalledOnValidThread()); | |
203 | |
204 if (audio_scheduler_.get()) { | |
205 audio_scheduler_->OnClientDisconnected(); | |
206 audio_scheduler_->Stop(base::Bind(&ClientSession::OnRecorderStopped, | |
207 base::Unretained(this))); | |
208 audio_scheduler_ = NULL; | |
209 } | |
210 | |
211 if (video_recorder_.get()) { | |
212 video_recorder_->RemoveConnection(connection_.get()); | |
213 video_recorder_->Stop(base::Bind(&ClientSession::OnRecorderStopped, | |
214 base::Unretained(this))); | |
215 video_recorder_ = NULL; | |
216 } | |
217 | |
218 if (!active_recorders_) { | |
219 delete this; | |
220 } | |
221 } | |
222 | |
156 void ClientSession::LocalMouseMoved(const SkIPoint& mouse_pos) { | 223 void ClientSession::LocalMouseMoved(const SkIPoint& mouse_pos) { |
157 DCHECK(CalledOnValidThread()); | 224 DCHECK(CalledOnValidThread()); |
158 remote_input_filter_.LocalMouseMoved(mouse_pos); | 225 remote_input_filter_.LocalMouseMoved(mouse_pos); |
159 } | 226 } |
160 | 227 |
161 void ClientSession::SetDisableInputs(bool disable_inputs) { | 228 void ClientSession::SetDisableInputs(bool disable_inputs) { |
162 DCHECK(CalledOnValidThread()); | 229 DCHECK(CalledOnValidThread()); |
163 | 230 |
164 if (disable_inputs) { | 231 if (disable_inputs) { |
165 disable_input_filter_.set_input_stub(NULL); | 232 disable_input_filter_.set_input_stub(NULL); |
166 disable_clipboard_filter_.set_clipboard_stub(NULL); | 233 disable_clipboard_filter_.set_clipboard_stub(NULL); |
167 input_tracker_.ReleaseAll(); | 234 input_tracker_.ReleaseAll(); |
168 } else { | 235 } else { |
169 disable_input_filter_.set_input_stub(&mouse_input_filter_); | 236 disable_input_filter_.set_input_stub(&mouse_input_filter_); |
170 disable_clipboard_filter_.set_clipboard_stub( | 237 disable_clipboard_filter_.set_clipboard_stub( |
171 clipboard_echo_filter_.host_filter()); | 238 clipboard_echo_filter_.host_filter()); |
172 } | 239 } |
173 } | 240 } |
174 | 241 |
242 ClientSession::~ClientSession() { | |
243 DCHECK(audio_scheduler_.get() == NULL); | |
244 DCHECK(video_recorder_.get() == NULL); | |
245 } | |
246 | |
175 scoped_ptr<protocol::ClipboardStub> ClientSession::CreateClipboardProxy() { | 247 scoped_ptr<protocol::ClipboardStub> ClientSession::CreateClipboardProxy() { |
176 DCHECK(CalledOnValidThread()); | 248 DCHECK(CalledOnValidThread()); |
177 | 249 |
178 return scoped_ptr<protocol::ClipboardStub>( | 250 return scoped_ptr<protocol::ClipboardStub>( |
179 new protocol::ClipboardThreadProxy( | 251 new protocol::ClipboardThreadProxy( |
180 client_clipboard_factory_.GetWeakPtr(), | 252 client_clipboard_factory_.GetWeakPtr(), |
181 base::MessageLoopProxy::current())); | 253 base::MessageLoopProxy::current())); |
182 } | 254 } |
183 | 255 |
256 void ClientSession::OnRecorderStopped() { | |
257 if (!network_task_runner_->BelongsToCurrentThread()) { | |
258 network_task_runner_->PostTask( | |
259 FROM_HERE, base::Bind(&ClientSession::OnRecorderStopped, | |
260 base::Unretained(this))); | |
261 return; | |
262 } | |
263 | |
264 --active_recorders_; | |
265 DCHECK_GE(active_recorders_, 0); | |
266 | |
267 StopAndDelete(); | |
268 } | |
269 | |
270 // TODO(sergeyu): Move this to SessionManager? | |
271 // static | |
272 Encoder* ClientSession::CreateEncoder(const protocol::SessionConfig& config) { | |
273 const protocol::ChannelConfig& video_config = config.video_config(); | |
274 | |
275 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { | |
276 return EncoderRowBased::CreateVerbatimEncoder(); | |
277 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) { | |
278 return EncoderRowBased::CreateZlibEncoder(); | |
279 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) { | |
280 return new remoting::EncoderVp8(); | |
281 } | |
282 | |
283 return NULL; | |
284 } | |
285 | |
286 // static | |
287 scoped_ptr<AudioEncoder> ClientSession::CreateAudioEncoder( | |
288 const protocol::SessionConfig& config) { | |
289 const protocol::ChannelConfig& audio_config = config.audio_config(); | |
290 | |
291 if (audio_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { | |
292 return scoped_ptr<AudioEncoder>(new AudioEncoderVerbatim()); | |
293 } | |
294 | |
295 NOTIMPLEMENTED(); | |
296 return scoped_ptr<AudioEncoder>(NULL); | |
297 } | |
298 | |
184 } // namespace remoting | 299 } // namespace remoting |
OLD | NEW |