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

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

Issue 10920019: [Chromoting] Refactoring DesktopEnvironment and moving screen/audio recorders to ClientSession. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: - 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
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/base/encoder.h"
14 #include "remoting/base/encoder_row_based.h"
15 #include "remoting/base/encoder_vp8.h"
16 #include "remoting/codec/audio_encoder.h"
17 #include "remoting/codec/audio_encoder_verbatim.h"
18 #include "remoting/host/audio_scheduler.h"
19 #include "remoting/host/chromoting_host_context.h" 13 #include "remoting/host/chromoting_host_context.h"
20 #include "remoting/host/desktop_environment.h" 14 #include "remoting/host/desktop_environment.h"
15 #include "remoting/host/desktop_environment_factory.h"
21 #include "remoting/host/event_executor.h" 16 #include "remoting/host/event_executor.h"
22 #include "remoting/host/host_config.h" 17 #include "remoting/host/host_config.h"
23 #include "remoting/host/screen_recorder.h"
24 #include "remoting/protocol/connection_to_client.h" 18 #include "remoting/protocol/connection_to_client.h"
25 #include "remoting/protocol/client_stub.h" 19 #include "remoting/protocol/client_stub.h"
26 #include "remoting/protocol/host_stub.h" 20 #include "remoting/protocol/host_stub.h"
27 #include "remoting/protocol/input_stub.h" 21 #include "remoting/protocol/input_stub.h"
28 #include "remoting/protocol/session_config.h" 22 #include "remoting/protocol/session_config.h"
29 23
30 using remoting::protocol::ConnectionToClient; 24 using remoting::protocol::ConnectionToClient;
31 using remoting::protocol::InputStub; 25 using remoting::protocol::InputStub;
32 26
33 namespace remoting { 27 namespace remoting {
(...skipping 24 matching lines...) Expand all
58 52
59 // 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.
60 false, 54 false,
61 }; 55 };
62 56
63 } // namespace 57 } // namespace
64 58
65 ChromotingHost::ChromotingHost( 59 ChromotingHost::ChromotingHost(
66 ChromotingHostContext* context, 60 ChromotingHostContext* context,
67 SignalStrategy* signal_strategy, 61 SignalStrategy* signal_strategy,
68 DesktopEnvironment* environment, 62 DesktopEnvironmentFactory* desktop_environment_factory,
69 scoped_ptr<protocol::SessionManager> session_manager) 63 scoped_ptr<protocol::SessionManager> session_manager)
70 : context_(context), 64 : context_(context),
71 desktop_environment_(environment), 65 desktop_environment_factory_(desktop_environment_factory),
72 session_manager_(session_manager.Pass()), 66 session_manager_(session_manager.Pass()),
73 signal_strategy_(signal_strategy), 67 signal_strategy_(signal_strategy),
74 stopping_recorders_(0),
75 state_(kInitial), 68 state_(kInitial),
76 protocol_config_(protocol::CandidateSessionConfig::CreateDefault()), 69 protocol_config_(protocol::CandidateSessionConfig::CreateDefault()),
77 login_backoff_(&kDefaultBackoffPolicy), 70 login_backoff_(&kDefaultBackoffPolicy),
78 authenticating_client_(false), 71 authenticating_client_(false),
79 reject_authenticating_client_(false) { 72 reject_authenticating_client_(false) {
80 DCHECK(context_); 73 DCHECK(context_);
81 DCHECK(signal_strategy); 74 DCHECK(signal_strategy);
82 DCHECK(desktop_environment_);
83 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 75 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
84 76
85 if (!desktop_environment_->audio_capturer()) { 77 #if !defined(OS_WIN)
simonmorris 2012/09/04 18:47:21 Add a HasAudioCapturer() method to DesktopEnvironm
Wez 2012/09/04 20:29:30 Good idea, although I'd suggest SupportsAudioCaptu
alexeypa (please no reviews) 2012/09/05 22:53:29 Done.
alexeypa (please no reviews) 2012/09/05 22:53:29 Done.
86 // Disable audio by replacing our list of supported audio configurations 78 // Disable audio by replacing our list of supported audio configurations
87 // with the NONE config. 79 // with the NONE config.
88 protocol_config_->mutable_audio_configs()->clear(); 80 // AudioCapturer::Create() is currently only implemented for Windows.
89 protocol_config_->mutable_audio_configs()->push_back( 81 protocol_config_->mutable_audio_configs()->clear();
90 protocol::ChannelConfig(protocol::ChannelConfig::TRANSPORT_NONE, 82 protocol_config_->mutable_audio_configs()->push_back(
91 protocol::kDefaultStreamVersion, 83 protocol::ChannelConfig(protocol::ChannelConfig::TRANSPORT_NONE,
92 protocol::ChannelConfig::CODEC_VERBATIM)); 84 protocol::kDefaultStreamVersion,
93 } 85 protocol::ChannelConfig::CODEC_VERBATIM));
86 #endif // !defined(OS_WIN)
94 } 87 }
95 88
96 ChromotingHost::~ChromotingHost() { 89 ChromotingHost::~ChromotingHost() {
97 DCHECK(clients_.empty()); 90 DCHECK(clients_.empty());
98 } 91 }
99 92
100 void ChromotingHost::Start() { 93 void ChromotingHost::Start() {
101 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 94 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
102 95
103 LOG(INFO) << "Starting host"; 96 LOG(INFO) << "Starting host";
(...skipping 28 matching lines...) Expand all
132 // We are already stopping. Just save the task. 125 // We are already stopping. Just save the task.
133 if (!shutdown_task.is_null()) 126 if (!shutdown_task.is_null())
134 shutdown_tasks_.push_back(shutdown_task); 127 shutdown_tasks_.push_back(shutdown_task);
135 break; 128 break;
136 129
137 case kStarted: 130 case kStarted:
138 if (!shutdown_task.is_null()) 131 if (!shutdown_task.is_null())
139 shutdown_tasks_.push_back(shutdown_task); 132 shutdown_tasks_.push_back(shutdown_task);
140 state_ = kStopping; 133 state_ = kStopping;
141 134
142 // Disconnect all of the clients, implicitly stopping the ScreenRecorder. 135 // Disconnect all of the clients.
143 while (!clients_.empty()) { 136 while (!clients_.empty()) {
144 clients_.front()->Disconnect(); 137 clients_.front()->Disconnect();
145 } 138 }
146 DCHECK(!recorder_.get());
147 DCHECK(!audio_scheduler_.get());
148 139
149 // Destroy session manager. 140 // Destroy session manager.
150 session_manager_.reset(); 141 session_manager_.reset();
151 142
152 if (!stopping_recorders_) 143 // Run the remaining shutdown tasks.
153 ShutdownFinish(); 144 ShutdownFinish();
154 break; 145 break;
155 } 146 }
156 } 147 }
157 148
158 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { 149 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) {
159 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 150 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
160 status_observers_.AddObserver(observer); 151 status_observers_.AddObserver(observer);
161 } 152 }
162 153
163 void ChromotingHost::RemoveStatusObserver(HostStatusObserver* observer) { 154 void ChromotingHost::RemoveStatusObserver(HostStatusObserver* observer) {
(...skipping 30 matching lines...) Expand all
194 ClientList clients_copy(clients_); 185 ClientList clients_copy(clients_);
195 for (ClientList::const_iterator other_client = clients_copy.begin(); 186 for (ClientList::const_iterator other_client = clients_copy.begin();
196 other_client != clients_copy.end(); ++other_client) { 187 other_client != clients_copy.end(); ++other_client) {
197 if ((*other_client) != client) { 188 if ((*other_client) != client) {
198 (*other_client)->Disconnect(); 189 (*other_client)->Disconnect();
199 } 190 }
200 } 191 }
201 192
202 // Disconnects above must have destroyed all other clients and |recorder_|. 193 // Disconnects above must have destroyed all other clients and |recorder_|.
203 DCHECK_EQ(clients_.size(), 1U); 194 DCHECK_EQ(clients_.size(), 1U);
204 DCHECK(!recorder_.get());
205 DCHECK(!audio_scheduler_.get());
206 195
207 // Notify observers that there is at least one authenticated client. 196 // Notify observers that there is at least one authenticated client.
208 const std::string& jid = client->client_jid(); 197 const std::string& jid = client->client_jid();
209 198
210 reject_authenticating_client_ = false; 199 reject_authenticating_client_ = false;
211 200
212 authenticating_client_ = true; 201 authenticating_client_ = true;
213 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 202 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
214 OnClientAuthenticated(jid)); 203 OnClientAuthenticated(jid));
215 authenticating_client_ = false; 204 authenticating_client_ = false;
216 205
217 if (reject_authenticating_client_) { 206 if (reject_authenticating_client_) {
218 client->Disconnect(); 207 client->Disconnect();
219 } 208 }
220 } 209 }
221 210
222 void ChromotingHost::OnSessionChannelsConnected(ClientSession* client) { 211 void ChromotingHost::OnSessionChannelsConnected(ClientSession* client) {
223 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 212 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
224 213
225 // Then we create a ScreenRecorder passing the message loops that 214 // Notify observers.
226 // it should run on.
227 Encoder* encoder = CreateEncoder(client->connection()->session()->config());
228
229 recorder_ = new ScreenRecorder(context_->capture_task_runner(),
230 context_->encode_task_runner(),
231 context_->network_task_runner(),
232 desktop_environment_->capturer(),
233 encoder);
234 if (client->connection()->session()->config().is_audio_enabled()) {
235 scoped_ptr<AudioEncoder> audio_encoder =
236 CreateAudioEncoder(client->connection()->session()->config());
237 audio_scheduler_ = new AudioScheduler(
238 context_->capture_task_runner(),
239 context_->network_task_runner(),
240 desktop_environment_->audio_capturer(),
241 audio_encoder.Pass(),
242 client->connection()->audio_stub());
243 }
244
245 // Immediately add the connection and start the session.
246 recorder_->AddConnection(client->connection());
247 recorder_->Start();
248 desktop_environment_->OnSessionStarted(client->CreateClipboardProxy());
249
250 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 215 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
251 OnClientConnected(client->client_jid())); 216 OnClientConnected(client->client_jid()));
252 } 217 }
253 218
254 void ChromotingHost::OnSessionAuthenticationFailed(ClientSession* client) { 219 void ChromotingHost::OnSessionAuthenticationFailed(ClientSession* client) {
255 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 220 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
256 221
257 // Notify observers. 222 // Notify observers.
258 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 223 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
259 OnAccessDenied(client->client_jid())); 224 OnAccessDenied(client->client_jid()));
260 } 225 }
261 226
262 void ChromotingHost::OnSessionClosed(ClientSession* client) { 227 void ChromotingHost::OnSessionClosed(ClientSession* client) {
263 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 228 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
264 229
265 scoped_ptr<ClientSession> client_destroyer(client);
266
267 ClientList::iterator it = std::find(clients_.begin(), clients_.end(), client); 230 ClientList::iterator it = std::find(clients_.begin(), clients_.end(), client);
268 CHECK(it != clients_.end()); 231 CHECK(it != clients_.end());
269 clients_.erase(it); 232 clients_.erase(it);
270 233
271 if (recorder_.get()) {
272 recorder_->RemoveConnection(client->connection());
273 }
274
275 if (audio_scheduler_.get()) {
276 audio_scheduler_->OnClientDisconnected();
277 StopAudioScheduler();
278 }
279
280 if (client->is_authenticated()) { 234 if (client->is_authenticated()) {
281 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 235 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
282 OnClientDisconnected(client->client_jid())); 236 OnClientDisconnected(client->client_jid()));
237 }
283 238
284 // TODO(sergeyu): This teardown logic belongs to ClientSession 239 client->StopAndDelete();
285 // class. It should start/stop screen recorder or tell the host
286 // when to do it.
287 if (recorder_.get()) {
288 // Currently we don't allow more than one simultaneous connection,
289 // so we need to shutdown recorder when a client disconnects.
290 StopScreenRecorder();
291 }
292 desktop_environment_->OnSessionFinished();
293 }
294 } 240 }
295 241
296 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session, 242 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session,
297 int64 sequence_number) { 243 int64 sequence_number) {
298 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 244 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
299 if (recorder_.get())
300 recorder_->UpdateSequenceNumber(sequence_number);
301 } 245 }
302 246
303 void ChromotingHost::OnSessionRouteChange( 247 void ChromotingHost::OnSessionRouteChange(
304 ClientSession* session, 248 ClientSession* session,
305 const std::string& channel_name, 249 const std::string& channel_name,
306 const protocol::TransportRoute& route) { 250 const protocol::TransportRoute& route) {
307 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 251 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
308 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 252 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
309 OnClientRouteChange(session->client_jid(), channel_name, 253 OnClientRouteChange(session->client_jid(), channel_name,
310 route)); 254 route));
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 *response = protocol::SessionManager::INCOMPATIBLE; 288 *response = protocol::SessionManager::INCOMPATIBLE;
345 return; 289 return;
346 } 290 }
347 291
348 session->set_config(config); 292 session->set_config(config);
349 293
350 *response = protocol::SessionManager::ACCEPT; 294 *response = protocol::SessionManager::ACCEPT;
351 295
352 LOG(INFO) << "Client connected: " << session->jid(); 296 LOG(INFO) << "Client connected: " << session->jid();
353 297
298 // Create the desktop integration implementation for the client to use.
299 scoped_ptr<DesktopEnvironment> desktop_environment =
300 desktop_environment_factory_->Create(context_);
301
354 // Create a client object. 302 // Create a client object.
355 scoped_ptr<protocol::ConnectionToClient> connection( 303 scoped_ptr<protocol::ConnectionToClient> connection(
356 new protocol::ConnectionToClient(session)); 304 new protocol::ConnectionToClient(session));
357 ClientSession* client = new ClientSession( 305 ClientSession* client = new ClientSession(
358 this, 306 this,
307 context_->capture_task_runner(),
308 context_->encode_task_runner(),
309 context_->network_task_runner(),
359 connection.Pass(), 310 connection.Pass(),
360 desktop_environment_->event_executor(), 311 desktop_environment.Pass(),
361 desktop_environment_->event_executor(),
362 desktop_environment_->capturer(),
363 max_session_duration_); 312 max_session_duration_);
364 clients_.push_back(client); 313 clients_.push_back(client);
365 } 314 }
366 315
367 void ChromotingHost::set_protocol_config( 316 void ChromotingHost::set_protocol_config(
368 protocol::CandidateSessionConfig* config) { 317 protocol::CandidateSessionConfig* config) {
369 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 318 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
370 DCHECK(config); 319 DCHECK(config);
371 DCHECK_EQ(state_, kInitial); 320 DCHECK_EQ(state_, kInitial);
372 protocol_config_.reset(config); 321 protocol_config_.reset(config);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 } 362 }
414 } 363 }
415 364
416 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) { 365 void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) {
417 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 366 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
418 DCHECK_EQ(state_, kInitial); 367 DCHECK_EQ(state_, kInitial);
419 368
420 ui_strings_ = ui_strings; 369 ui_strings_ = ui_strings;
421 } 370 }
422 371
423 // TODO(sergeyu): Move this to SessionManager?
424 // static
425 Encoder* ChromotingHost::CreateEncoder(const protocol::SessionConfig& config) {
426 const protocol::ChannelConfig& video_config = config.video_config();
427
428 if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) {
429 return EncoderRowBased::CreateVerbatimEncoder();
430 } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) {
431 return EncoderRowBased::CreateZlibEncoder();
432 } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) {
433 return new remoting::EncoderVp8();
434 }
435
436 return NULL;
437 }
438
439 // static
440 scoped_ptr<AudioEncoder> ChromotingHost::CreateAudioEncoder(
441 const protocol::SessionConfig& config) {
442 const protocol::ChannelConfig& audio_config = config.audio_config();
443
444 if (audio_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) {
445 return scoped_ptr<AudioEncoder>(new AudioEncoderVerbatim());
446 }
447
448 NOTIMPLEMENTED();
449 return scoped_ptr<AudioEncoder>(NULL);
450 }
451
452 void ChromotingHost::StopScreenRecorder() {
453 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
454 DCHECK(recorder_.get());
455
456 ++stopping_recorders_;
457 scoped_refptr<ScreenRecorder> recorder = recorder_;
458 recorder_ = NULL;
459 recorder->Stop(base::Bind(&ChromotingHost::OnRecorderStopped, this));
460 }
461
462 void ChromotingHost::StopAudioScheduler() {
463 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
464 DCHECK(audio_scheduler_.get());
465
466 ++stopping_recorders_;
467 scoped_refptr<AudioScheduler> recorder = audio_scheduler_;
468 audio_scheduler_ = NULL;
469 recorder->Stop(base::Bind(&ChromotingHost::OnRecorderStopped, this));
470 }
471
472 void ChromotingHost::OnRecorderStopped() {
473 if (!context_->network_task_runner()->BelongsToCurrentThread()) {
474 context_->network_task_runner()->PostTask(
475 FROM_HERE, base::Bind(&ChromotingHost::OnRecorderStopped, this));
476 return;
477 }
478
479 --stopping_recorders_;
480 DCHECK_GE(stopping_recorders_, 0);
481
482 if (!stopping_recorders_ && state_ == kStopping)
483 ShutdownFinish();
484 }
485
486 void ChromotingHost::ShutdownFinish() { 372 void ChromotingHost::ShutdownFinish() {
487 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 373 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
488 DCHECK(!stopping_recorders_);
489 374
490 state_ = kStopped; 375 state_ = kStopped;
491 376
492 // Keep reference to |this|, so that we don't get destroyed while 377 // Keep reference to |this|, so that we don't get destroyed while
493 // sending notifications. 378 // sending notifications.
494 scoped_refptr<ChromotingHost> self(this); 379 scoped_refptr<ChromotingHost> self(this);
495 380
496 // Notify observers. 381 // Notify observers.
497 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 382 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
498 OnShutdown()); 383 OnShutdown());
499 384
500 for (std::vector<base::Closure>::iterator it = shutdown_tasks_.begin(); 385 for (std::vector<base::Closure>::iterator it = shutdown_tasks_.begin();
501 it != shutdown_tasks_.end(); ++it) { 386 it != shutdown_tasks_.end(); ++it) {
502 it->Run(); 387 it->Run();
503 } 388 }
504 shutdown_tasks_.clear(); 389 shutdown_tasks_.clear();
505 } 390 }
506 391
507 } // namespace remoting 392 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698