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