Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(83)

Side by Side Diff: remoting/host/chromoting_host.cc

Issue 10915206: [Chromoting] Refactoring DesktopEnvironment and moving screen/audio recorders to ClientSession. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebased Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/host/chromoting_host.h ('k') | remoting/host/chromoting_host_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/chromoting_host.h" 5 #include "remoting/host/chromoting_host.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback.h" 8 #include "base/callback.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop_proxy.h" 10 #include "base/message_loop_proxy.h"
11 #include "build/build_config.h" 11 #include "build/build_config.h"
12 #include "remoting/base/constants.h" 12 #include "remoting/base/constants.h"
13 #include "remoting/codec/audio_encoder.h"
14 #include "remoting/codec/audio_encoder_speex.h"
15 #include "remoting/codec/audio_encoder_verbatim.h"
16 #include "remoting/codec/video_encoder.h"
17 #include "remoting/codec/video_encoder_row_based.h"
18 #include "remoting/codec/video_encoder_vp8.h"
19 #include "remoting/host/audio_capturer.h"
20 #include "remoting/host/audio_scheduler.h"
21 #include "remoting/host/chromoting_host_context.h" 13 #include "remoting/host/chromoting_host_context.h"
22 #include "remoting/host/desktop_environment.h" 14 #include "remoting/host/desktop_environment.h"
15 #include "remoting/host/desktop_environment_factory.h"
23 #include "remoting/host/event_executor.h" 16 #include "remoting/host/event_executor.h"
24 #include "remoting/host/host_config.h" 17 #include "remoting/host/host_config.h"
25 #include "remoting/host/screen_recorder.h"
26 #include "remoting/protocol/connection_to_client.h" 18 #include "remoting/protocol/connection_to_client.h"
27 #include "remoting/protocol/client_stub.h" 19 #include "remoting/protocol/client_stub.h"
28 #include "remoting/protocol/host_stub.h" 20 #include "remoting/protocol/host_stub.h"
29 #include "remoting/protocol/input_stub.h" 21 #include "remoting/protocol/input_stub.h"
30 #include "remoting/protocol/session_config.h" 22 #include "remoting/protocol/session_config.h"
31 23
32 using remoting::protocol::ConnectionToClient; 24 using remoting::protocol::ConnectionToClient;
33 using remoting::protocol::InputStub; 25 using remoting::protocol::InputStub;
34 26
35 namespace remoting { 27 namespace remoting {
(...skipping 24 matching lines...) Expand all
60 52
61 // Don't use initial delay unless the last request was an error. 53 // Don't use initial delay unless the last request was an error.
62 false, 54 false,
63 }; 55 };
64 56
65 } // namespace 57 } // namespace
66 58
67 ChromotingHost::ChromotingHost( 59 ChromotingHost::ChromotingHost(
68 ChromotingHostContext* context, 60 ChromotingHostContext* context,
69 SignalStrategy* signal_strategy, 61 SignalStrategy* signal_strategy,
70 DesktopEnvironment* environment, 62 DesktopEnvironmentFactory* desktop_environment_factory,
71 scoped_ptr<protocol::SessionManager> session_manager) 63 scoped_ptr<protocol::SessionManager> session_manager)
72 : context_(context), 64 : context_(context),
73 desktop_environment_(environment), 65 desktop_environment_factory_(desktop_environment_factory),
74 session_manager_(session_manager.Pass()), 66 session_manager_(session_manager.Pass()),
75 signal_strategy_(signal_strategy), 67 signal_strategy_(signal_strategy),
76 stopping_recorders_(0), 68 clients_count_(0),
77 state_(kInitial), 69 state_(kInitial),
78 protocol_config_(protocol::CandidateSessionConfig::CreateDefault()), 70 protocol_config_(protocol::CandidateSessionConfig::CreateDefault()),
79 login_backoff_(&kDefaultBackoffPolicy), 71 login_backoff_(&kDefaultBackoffPolicy),
80 authenticating_client_(false), 72 authenticating_client_(false),
81 reject_authenticating_client_(false) { 73 reject_authenticating_client_(false) {
82 DCHECK(context_); 74 DCHECK(context_);
83 DCHECK(signal_strategy); 75 DCHECK(signal_strategy);
84 DCHECK(desktop_environment_);
85 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 76 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
86 77
87 if (!AudioCapturer::IsSupported()) { 78 if (!desktop_environment_factory_->SupportsAudioCapture()) {
88 // Disable audio by replacing our list of supported audio configurations 79 // Disable audio by replacing our list of supported audio configurations
89 // with the NONE config. 80 // with the NONE config.
90 protocol_config_->mutable_audio_configs()->clear(); 81 protocol_config_->mutable_audio_configs()->clear();
91 protocol_config_->mutable_audio_configs()->push_back( 82 protocol_config_->mutable_audio_configs()->push_back(
92 protocol::ChannelConfig()); 83 protocol::ChannelConfig());
93 } 84 }
94 } 85 }
95 86
96 ChromotingHost::~ChromotingHost() { 87 ChromotingHost::~ChromotingHost() {
97 DCHECK(clients_.empty()); 88 DCHECK(clients_.empty());
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 // We are already stopping. Just save the task. 126 // We are already stopping. Just save the task.
136 if (!shutdown_task.is_null()) 127 if (!shutdown_task.is_null())
137 shutdown_tasks_.push_back(shutdown_task); 128 shutdown_tasks_.push_back(shutdown_task);
138 break; 129 break;
139 130
140 case kStarted: 131 case kStarted:
141 if (!shutdown_task.is_null()) 132 if (!shutdown_task.is_null())
142 shutdown_tasks_.push_back(shutdown_task); 133 shutdown_tasks_.push_back(shutdown_task);
143 state_ = kStopping; 134 state_ = kStopping;
144 135
145 // Disconnect all of the clients, implicitly stopping the ScreenRecorder. 136 // Disconnect all of the clients.
146 while (!clients_.empty()) { 137 while (!clients_.empty()) {
147 clients_.front()->Disconnect(); 138 clients_.front()->Disconnect();
148 } 139 }
149 DCHECK(!recorder_.get());
150 DCHECK(!audio_scheduler_.get());
151 140
152 // Destroy session manager. 141 // Run the remaining shutdown tasks.
153 session_manager_.reset(); 142 if (state_ == kStopping && !clients_count_)
143 ShutdownFinish();
154 144
155 if (!stopping_recorders_)
156 ShutdownFinish();
157 break; 145 break;
158 } 146 }
159 } 147 }
160 148
161 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { 149 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) {
162 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 150 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
163 status_observers_.AddObserver(observer); 151 status_observers_.AddObserver(observer);
164 } 152 }
165 153
166 void ChromotingHost::RemoveStatusObserver(HostStatusObserver* observer) { 154 void ChromotingHost::RemoveStatusObserver(HostStatusObserver* observer) {
(...skipping 23 matching lines...) Expand all
190 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 178 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
191 179
192 login_backoff_.Reset(); 180 login_backoff_.Reset();
193 181
194 // Disconnect all other clients. 182 // Disconnect all other clients.
195 // Iterate over a copy of the list of clients, to avoid mutating the list 183 // Iterate over a copy of the list of clients, to avoid mutating the list
196 // while iterating over it. 184 // while iterating over it.
197 ClientList clients_copy(clients_); 185 ClientList clients_copy(clients_);
198 for (ClientList::const_iterator other_client = clients_copy.begin(); 186 for (ClientList::const_iterator other_client = clients_copy.begin();
199 other_client != clients_copy.end(); ++other_client) { 187 other_client != clients_copy.end(); ++other_client) {
200 if ((*other_client) != client) { 188 if (other_client->get() != client) {
201 (*other_client)->Disconnect(); 189 (*other_client)->Disconnect();
202 } 190 }
203 } 191 }
204 192
205 // Disconnects above must have destroyed all other clients and |recorder_|. 193 // Disconnects above must have destroyed all other clients and |recorder_|.
206 DCHECK_EQ(clients_.size(), 1U); 194 DCHECK_EQ(clients_.size(), 1U);
207 DCHECK(!recorder_.get());
208 DCHECK(!audio_scheduler_.get());
209 195
210 // Notify observers that there is at least one authenticated client. 196 // Notify observers that there is at least one authenticated client.
211 const std::string& jid = client->client_jid(); 197 const std::string& jid = client->client_jid();
212 198
213 reject_authenticating_client_ = false; 199 reject_authenticating_client_ = false;
214 200
215 authenticating_client_ = true; 201 authenticating_client_ = true;
216 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 202 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
217 OnClientAuthenticated(jid)); 203 OnClientAuthenticated(jid));
218 authenticating_client_ = false; 204 authenticating_client_ = false;
219 205
220 if (reject_authenticating_client_) { 206 if (reject_authenticating_client_) {
221 client->Disconnect(); 207 client->Disconnect();
222 } 208 }
223 } 209 }
224 210
225 void ChromotingHost::OnSessionChannelsConnected(ClientSession* client) { 211 void ChromotingHost::OnSessionChannelsConnected(ClientSession* client) {
226 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 212 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
227 213
228 // Then we create a ScreenRecorder passing the message loops that 214 // Notify observers.
229 // it should run on.
230 VideoEncoder* video_encoder =
231 CreateVideoEncoder(client->connection()->session()->config());
232
233 recorder_ = new ScreenRecorder(context_->capture_task_runner(),
234 context_->encode_task_runner(),
235 context_->network_task_runner(),
236 desktop_environment_->capturer(),
237 video_encoder);
238 if (client->connection()->session()->config().is_audio_enabled()) {
239 scoped_ptr<AudioEncoder> audio_encoder =
240 CreateAudioEncoder(client->connection()->session()->config());
241 audio_scheduler_ = new AudioScheduler(
242 context_->audio_task_runner(),
243 context_->network_task_runner(),
244 desktop_environment_->audio_capturer(),
245 audio_encoder.Pass(),
246 client->connection()->audio_stub());
247 }
248
249 // Immediately add the connection and start the session.
250 recorder_->AddConnection(client->connection());
251 recorder_->Start();
252 desktop_environment_->OnSessionStarted(client->CreateClipboardProxy());
253
254 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 215 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
255 OnClientConnected(client->client_jid())); 216 OnClientConnected(client->client_jid()));
256 } 217 }
257 218
258 void ChromotingHost::OnSessionAuthenticationFailed(ClientSession* client) { 219 void ChromotingHost::OnSessionAuthenticationFailed(ClientSession* client) {
259 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 220 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
260 221
261 // Notify observers. 222 // Notify observers.
262 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 223 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
263 OnAccessDenied(client->client_jid())); 224 OnAccessDenied(client->client_jid()));
264 } 225 }
265 226
266 void ChromotingHost::OnSessionClosed(ClientSession* client) { 227 void ChromotingHost::OnSessionClosed(ClientSession* client) {
267 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 228 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
268 229
269 scoped_ptr<ClientSession> client_destroyer(client); 230 ClientList::iterator it = clients_.begin();
270 231 for (; it != clients_.end(); ++it) {
271 ClientList::iterator it = std::find(clients_.begin(), clients_.end(), client); 232 if (it->get() == client) {
233 break;
234 }
235 }
272 CHECK(it != clients_.end()); 236 CHECK(it != clients_.end());
273 clients_.erase(it);
274
275 if (recorder_.get()) {
276 recorder_->RemoveConnection(client->connection());
277 }
278
279 if (audio_scheduler_.get()) {
280 audio_scheduler_->OnClientDisconnected();
281 StopAudioScheduler();
282 }
283 237
284 if (client->is_authenticated()) { 238 if (client->is_authenticated()) {
285 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 239 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
286 OnClientDisconnected(client->client_jid())); 240 OnClientDisconnected(client->client_jid()));
241 }
287 242
288 // TODO(sergeyu): This teardown logic belongs to ClientSession 243 client->Stop(base::Bind(&ChromotingHost::OnClientStopped, this));
289 // class. It should start/stop screen recorder or tell the host 244 clients_.erase(it);
290 // when to do it.
291 if (recorder_.get()) {
292 // Currently we don't allow more than one simultaneous connection,
293 // so we need to shutdown recorder when a client disconnects.
294 StopScreenRecorder();
295 }
296 desktop_environment_->OnSessionFinished();
297 }
298 } 245 }
299 246
300 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session, 247 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session,
301 int64 sequence_number) { 248 int64 sequence_number) {
302 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 249 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
303 if (recorder_.get())
304 recorder_->UpdateSequenceNumber(sequence_number);
305 } 250 }
306 251
307 void ChromotingHost::OnSessionRouteChange( 252 void ChromotingHost::OnSessionRouteChange(
308 ClientSession* session, 253 ClientSession* session,
309 const std::string& channel_name, 254 const std::string& channel_name,
310 const protocol::TransportRoute& route) { 255 const protocol::TransportRoute& route) {
311 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 256 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
312 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 257 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
313 OnClientRouteChange(session->client_jid(), channel_name, 258 OnClientRouteChange(session->client_jid(), channel_name,
314 route)); 259 route));
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 *response = protocol::SessionManager::INCOMPATIBLE; 293 *response = protocol::SessionManager::INCOMPATIBLE;
349 return; 294 return;
350 } 295 }
351 296
352 session->set_config(config); 297 session->set_config(config);
353 298
354 *response = protocol::SessionManager::ACCEPT; 299 *response = protocol::SessionManager::ACCEPT;
355 300
356 LOG(INFO) << "Client connected: " << session->jid(); 301 LOG(INFO) << "Client connected: " << session->jid();
357 302
303 // Create the desktop integration implementation for the client to use.
304 scoped_ptr<DesktopEnvironment> desktop_environment =
305 desktop_environment_factory_->Create(context_);
306
358 // Create a client object. 307 // Create a client object.
359 scoped_ptr<protocol::ConnectionToClient> connection( 308 scoped_ptr<protocol::ConnectionToClient> connection(
360 new protocol::ConnectionToClient(session)); 309 new protocol::ConnectionToClient(session));
361 ClientSession* client = new ClientSession( 310 scoped_refptr<ClientSession> client = new ClientSession(
362 this, 311 this,
312 context_->capture_task_runner(),
313 context_->encode_task_runner(),
314 context_->network_task_runner(),
363 connection.Pass(), 315 connection.Pass(),
364 desktop_environment_->event_executor(), 316 desktop_environment.Pass(),
365 desktop_environment_->event_executor(),
366 desktop_environment_->capturer(),
367 max_session_duration_); 317 max_session_duration_);
368 clients_.push_back(client); 318 clients_.push_back(client);
319 clients_count_++;
369 } 320 }
370 321
371 void ChromotingHost::set_protocol_config( 322 void ChromotingHost::set_protocol_config(
372 protocol::CandidateSessionConfig* config) { 323 protocol::CandidateSessionConfig* config) {
373 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 324 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
374 DCHECK(config); 325 DCHECK(config);
375 DCHECK_EQ(state_, kInitial); 326 DCHECK_EQ(state_, kInitial);
376 protocol_config_.reset(config); 327 protocol_config_.reset(config);
377 } 328 }
378 329
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 } 368 }
418 } 369 }
419 370
420 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { 371 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) {
421 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 372 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
422 DCHECK_EQ(state_, kInitial); 373 DCHECK_EQ(state_, kInitial);
423 374
424 ui_strings_ = ui_strings; 375 ui_strings_ = ui_strings;
425 } 376 }
426 377
427 // TODO(sergeyu): Move this to SessionManager? 378 void ChromotingHost::OnClientStopped() {
428 // static 379 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
429 VideoEncoder* ChromotingHost::CreateVideoEncoder(
430 const protocol::SessionConfig& config) {
431 const protocol::ChannelConfig& video_config = config.video_config();
432 380
433 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) { 381 --clients_count_;
434 return VideoEncoderRowBased::CreateVerbatimEncoder(); 382 if (state_ == kStopping && !clients_count_)
435 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) {
436 return VideoEncoderRowBased::CreateZlibEncoder();
437 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) {
438 return new remoting::VideoEncoderVp8();
439 }
440
441 return NULL;
442 }
443
444 // static
445 scoped_ptr<AudioEncoder> ChromotingHost::CreateAudioEncoder(
446 const protocol::SessionConfig& config) {
447 const protocol::ChannelConfig& audio_config = config.audio_config();
448
449 if (audio_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) {
450 return scoped_ptr<AudioEncoder>(new AudioEncoderVerbatim());
451 } else if (audio_config.codec == protocol::ChannelConfig::CODEC_SPEEX) {
452 return scoped_ptr<AudioEncoder>(new AudioEncoderSpeex());
453 }
454
455 NOTIMPLEMENTED();
456 return scoped_ptr<AudioEncoder>(NULL);
457 }
458
459 void ChromotingHost::StopScreenRecorder() {
460 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
461 DCHECK(recorder_.get());
462
463 ++stopping_recorders_;
464 scoped_refptr<ScreenRecorder> recorder = recorder_;
465 recorder_ = NULL;
466 recorder->Stop(base::Bind(&ChromotingHost::OnRecorderStopped, this));
467 }
468
469 void ChromotingHost::StopAudioScheduler() {
470 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
471 DCHECK(audio_scheduler_.get());
472
473 ++stopping_recorders_;
474 scoped_refptr<AudioScheduler> recorder = audio_scheduler_;
475 audio_scheduler_ = NULL;
476 recorder->Stop(base::Bind(&ChromotingHost::OnRecorderStopped, this));
477 }
478
479 void ChromotingHost::OnRecorderStopped() {
480 if (!context_->network_task_runner()->BelongsToCurrentThread()) {
481 context_->network_task_runner()->PostTask(
482 FROM_HERE, base::Bind(&ChromotingHost::OnRecorderStopped, this));
483 return;
484 }
485
486 --stopping_recorders_;
487 DCHECK_GE(stopping_recorders_, 0);
488
489 if (!stopping_recorders_ && state_ == kStopping)
490 ShutdownFinish(); 383 ShutdownFinish();
491 } 384 }
492 385
493 void ChromotingHost::ShutdownFinish() { 386 void ChromotingHost::ShutdownFinish() {
494 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 387 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
495 DCHECK(!stopping_recorders_); 388 DCHECK_EQ(state_, kStopping);
389
390 // Destroy session manager.
391 session_manager_.reset();
496 392
497 state_ = kStopped; 393 state_ = kStopped;
498 394
499 // Keep reference to |this|, so that we don't get destroyed while 395 // Keep reference to |this|, so that we don't get destroyed while
500 // sending notifications. 396 // sending notifications.
501 scoped_refptr<ChromotingHost> self(this); 397 scoped_refptr<ChromotingHost> self(this);
502 398
503 // Notify observers. 399 // Notify observers.
504 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 400 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
505 OnShutdown()); 401 OnShutdown());
506 402
507 for (std::vector<base::Closure>::iterator it = shutdown_tasks_.begin(); 403 for (std::vector<base::Closure>::iterator it = shutdown_tasks_.begin();
508 it != shutdown_tasks_.end(); ++it) { 404 it != shutdown_tasks_.end(); ++it) {
509 it->Run(); 405 it->Run();
510 } 406 }
511 shutdown_tasks_.clear(); 407 shutdown_tasks_.clear();
512 } 408 }
513 409
514 } // namespace remoting 410 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/chromoting_host.h ('k') | remoting/host/chromoting_host_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698