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