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

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