| Index: remoting/host/chromoting_host.cc
 | 
| diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc
 | 
| index 8b71a1f753e70a61189f473865be6aa71303b89e..4c1503d8749a63750e741c59ce8ab8ba8e87ba34 100644
 | 
| --- a/remoting/host/chromoting_host.cc
 | 
| +++ b/remoting/host/chromoting_host.cc
 | 
| @@ -10,19 +10,11 @@
 | 
|  #include "base/message_loop_proxy.h"
 | 
|  #include "build/build_config.h"
 | 
|  #include "remoting/base/constants.h"
 | 
| -#include "remoting/codec/audio_encoder.h"
 | 
| -#include "remoting/codec/audio_encoder_speex.h"
 | 
| -#include "remoting/codec/audio_encoder_verbatim.h"
 | 
| -#include "remoting/codec/video_encoder.h"
 | 
| -#include "remoting/codec/video_encoder_row_based.h"
 | 
| -#include "remoting/codec/video_encoder_vp8.h"
 | 
| -#include "remoting/host/audio_capturer.h"
 | 
| -#include "remoting/host/audio_scheduler.h"
 | 
|  #include "remoting/host/chromoting_host_context.h"
 | 
|  #include "remoting/host/desktop_environment.h"
 | 
| +#include "remoting/host/desktop_environment_factory.h"
 | 
|  #include "remoting/host/event_executor.h"
 | 
|  #include "remoting/host/host_config.h"
 | 
| -#include "remoting/host/screen_recorder.h"
 | 
|  #include "remoting/protocol/connection_to_client.h"
 | 
|  #include "remoting/protocol/client_stub.h"
 | 
|  #include "remoting/protocol/host_stub.h"
 | 
| @@ -67,13 +59,13 @@ const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
 | 
|  ChromotingHost::ChromotingHost(
 | 
|      ChromotingHostContext* context,
 | 
|      SignalStrategy* signal_strategy,
 | 
| -    DesktopEnvironment* environment,
 | 
| +    DesktopEnvironmentFactory* desktop_environment_factory,
 | 
|      scoped_ptr<protocol::SessionManager> session_manager)
 | 
|      : context_(context),
 | 
| -      desktop_environment_(environment),
 | 
| +      desktop_environment_factory_(desktop_environment_factory),
 | 
|        session_manager_(session_manager.Pass()),
 | 
|        signal_strategy_(signal_strategy),
 | 
| -      stopping_recorders_(0),
 | 
| +      clients_count_(0),
 | 
|        state_(kInitial),
 | 
|        protocol_config_(protocol::CandidateSessionConfig::CreateDefault()),
 | 
|        login_backoff_(&kDefaultBackoffPolicy),
 | 
| @@ -81,10 +73,9 @@ ChromotingHost::ChromotingHost(
 | 
|        reject_authenticating_client_(false) {
 | 
|    DCHECK(context_);
 | 
|    DCHECK(signal_strategy);
 | 
| -  DCHECK(desktop_environment_);
 | 
|    DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
 | 
|  
 | 
| -  if (!AudioCapturer::IsSupported()) {
 | 
| +  if (!desktop_environment_factory_->SupportsAudioCapture()) {
 | 
|      // Disable audio by replacing our list of supported audio configurations
 | 
|      // with the NONE config.
 | 
|      protocol_config_->mutable_audio_configs()->clear();
 | 
| @@ -142,18 +133,15 @@ void ChromotingHost::Shutdown(const base::Closure& shutdown_task) {
 | 
|          shutdown_tasks_.push_back(shutdown_task);
 | 
|        state_ = kStopping;
 | 
|  
 | 
| -      // Disconnect all of the clients, implicitly stopping the ScreenRecorder.
 | 
| +      // Disconnect all of the clients.
 | 
|        while (!clients_.empty()) {
 | 
|          clients_.front()->Disconnect();
 | 
|        }
 | 
| -      DCHECK(!recorder_.get());
 | 
| -      DCHECK(!audio_scheduler_.get());
 | 
|  
 | 
| -      // Destroy session manager.
 | 
| -      session_manager_.reset();
 | 
| -
 | 
| -      if (!stopping_recorders_)
 | 
| +      // Run the remaining shutdown tasks.
 | 
| +      if (state_ == kStopping && !clients_count_)
 | 
|          ShutdownFinish();
 | 
| +
 | 
|        break;
 | 
|    }
 | 
|  }
 | 
| @@ -197,15 +185,13 @@ void ChromotingHost::OnSessionAuthenticated(ClientSession* client) {
 | 
|    ClientList clients_copy(clients_);
 | 
|    for (ClientList::const_iterator other_client = clients_copy.begin();
 | 
|         other_client != clients_copy.end(); ++other_client) {
 | 
| -    if ((*other_client) != client) {
 | 
| +    if (other_client->get() != client) {
 | 
|        (*other_client)->Disconnect();
 | 
|      }
 | 
|    }
 | 
|  
 | 
|    // Disconnects above must have destroyed all other clients and |recorder_|.
 | 
|    DCHECK_EQ(clients_.size(), 1U);
 | 
| -  DCHECK(!recorder_.get());
 | 
| -  DCHECK(!audio_scheduler_.get());
 | 
|  
 | 
|    // Notify observers that there is at least one authenticated client.
 | 
|    const std::string& jid = client->client_jid();
 | 
| @@ -225,32 +211,7 @@ void ChromotingHost::OnSessionAuthenticated(ClientSession* client) {
 | 
|  void ChromotingHost::OnSessionChannelsConnected(ClientSession* client) {
 | 
|    DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
 | 
|  
 | 
| -  // Then we create a ScreenRecorder passing the message loops that
 | 
| -  // it should run on.
 | 
| -  VideoEncoder* video_encoder =
 | 
| -      CreateVideoEncoder(client->connection()->session()->config());
 | 
| -
 | 
| -  recorder_ = new ScreenRecorder(context_->capture_task_runner(),
 | 
| -                                 context_->encode_task_runner(),
 | 
| -                                 context_->network_task_runner(),
 | 
| -                                 desktop_environment_->capturer(),
 | 
| -                                 video_encoder);
 | 
| -  if (client->connection()->session()->config().is_audio_enabled()) {
 | 
| -    scoped_ptr<AudioEncoder> audio_encoder =
 | 
| -        CreateAudioEncoder(client->connection()->session()->config());
 | 
| -    audio_scheduler_ = new AudioScheduler(
 | 
| -        context_->audio_task_runner(),
 | 
| -        context_->network_task_runner(),
 | 
| -        desktop_environment_->audio_capturer(),
 | 
| -        audio_encoder.Pass(),
 | 
| -        client->connection()->audio_stub());
 | 
| -  }
 | 
| -
 | 
| -  // Immediately add the connection and start the session.
 | 
| -  recorder_->AddConnection(client->connection());
 | 
| -  recorder_->Start();
 | 
| -  desktop_environment_->OnSessionStarted(client->CreateClipboardProxy());
 | 
| -
 | 
| +  // Notify observers.
 | 
|    FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
 | 
|                      OnClientConnected(client->client_jid()));
 | 
|  }
 | 
| @@ -266,42 +227,26 @@ void ChromotingHost::OnSessionAuthenticationFailed(ClientSession* client) {
 | 
|  void ChromotingHost::OnSessionClosed(ClientSession* client) {
 | 
|    DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
 | 
|  
 | 
| -  scoped_ptr<ClientSession> client_destroyer(client);
 | 
| -
 | 
| -  ClientList::iterator it = std::find(clients_.begin(), clients_.end(), client);
 | 
| -  CHECK(it != clients_.end());
 | 
| -  clients_.erase(it);
 | 
| -
 | 
| -  if (recorder_.get()) {
 | 
| -    recorder_->RemoveConnection(client->connection());
 | 
| -  }
 | 
| -
 | 
| -  if (audio_scheduler_.get()) {
 | 
| -    audio_scheduler_->OnClientDisconnected();
 | 
| -    StopAudioScheduler();
 | 
| +  ClientList::iterator it = clients_.begin();
 | 
| +  for (; it != clients_.end(); ++it) {
 | 
| +    if (it->get() == client) {
 | 
| +      break;
 | 
| +    }
 | 
|    }
 | 
| +  CHECK(it != clients_.end());
 | 
|  
 | 
|    if (client->is_authenticated()) {
 | 
|      FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
 | 
|                        OnClientDisconnected(client->client_jid()));
 | 
| -
 | 
| -    // TODO(sergeyu): This teardown logic belongs to ClientSession
 | 
| -    // class. It should start/stop screen recorder or tell the host
 | 
| -    // when to do it.
 | 
| -    if (recorder_.get()) {
 | 
| -      // Currently we don't allow more than one simultaneous connection,
 | 
| -      // so we need to shutdown recorder when a client disconnects.
 | 
| -      StopScreenRecorder();
 | 
| -    }
 | 
| -    desktop_environment_->OnSessionFinished();
 | 
|    }
 | 
| +
 | 
| +  client->Stop(base::Bind(&ChromotingHost::OnClientStopped, this));
 | 
| +  clients_.erase(it);
 | 
|  }
 | 
|  
 | 
|  void ChromotingHost::OnSessionSequenceNumber(ClientSession* session,
 | 
|                                               int64 sequence_number) {
 | 
|    DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
 | 
| -  if (recorder_.get())
 | 
| -    recorder_->UpdateSequenceNumber(sequence_number);
 | 
|  }
 | 
|  
 | 
|  void ChromotingHost::OnSessionRouteChange(
 | 
| @@ -355,17 +300,23 @@ void ChromotingHost::OnIncomingSession(
 | 
|  
 | 
|    LOG(INFO) << "Client connected: " << session->jid();
 | 
|  
 | 
| +  // Create the desktop integration implementation for the client to use.
 | 
| +  scoped_ptr<DesktopEnvironment> desktop_environment =
 | 
| +      desktop_environment_factory_->Create(context_);
 | 
| +
 | 
|    // Create a client object.
 | 
|    scoped_ptr<protocol::ConnectionToClient> connection(
 | 
|        new protocol::ConnectionToClient(session));
 | 
| -  ClientSession* client = new ClientSession(
 | 
| +  scoped_refptr<ClientSession> client = new ClientSession(
 | 
|        this,
 | 
| +      context_->capture_task_runner(),
 | 
| +      context_->encode_task_runner(),
 | 
| +      context_->network_task_runner(),
 | 
|        connection.Pass(),
 | 
| -      desktop_environment_->event_executor(),
 | 
| -      desktop_environment_->event_executor(),
 | 
| -      desktop_environment_->capturer(),
 | 
| +      desktop_environment.Pass(),
 | 
|        max_session_duration_);
 | 
|    clients_.push_back(client);
 | 
| +  clients_count_++;
 | 
|  }
 | 
|  
 | 
|  void ChromotingHost::set_protocol_config(
 | 
| @@ -424,75 +375,20 @@ void ChromotingHost::SetUiStrings(const UiStrings& ui_strings) {
 | 
|    ui_strings_ = ui_strings;
 | 
|  }
 | 
|  
 | 
| -// TODO(sergeyu): Move this to SessionManager?
 | 
| -// static
 | 
| -VideoEncoder* ChromotingHost::CreateVideoEncoder(
 | 
| -    const protocol::SessionConfig& config) {
 | 
| -  const protocol::ChannelConfig& video_config = config.video_config();
 | 
| -
 | 
| -  if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) {
 | 
| -    return VideoEncoderRowBased::CreateVerbatimEncoder();
 | 
| -  } else if (video_config.codec == protocol::ChannelConfig::CODEC_ZIP) {
 | 
| -    return VideoEncoderRowBased::CreateZlibEncoder();
 | 
| -  } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) {
 | 
| -    return new remoting::VideoEncoderVp8();
 | 
| -  }
 | 
| -
 | 
| -  return NULL;
 | 
| -}
 | 
| -
 | 
| -// static
 | 
| -scoped_ptr<AudioEncoder> ChromotingHost::CreateAudioEncoder(
 | 
| -    const protocol::SessionConfig& config) {
 | 
| -  const protocol::ChannelConfig& audio_config = config.audio_config();
 | 
| -
 | 
| -  if (audio_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) {
 | 
| -    return scoped_ptr<AudioEncoder>(new AudioEncoderVerbatim());
 | 
| -  } else if (audio_config.codec == protocol::ChannelConfig::CODEC_SPEEX) {
 | 
| -    return scoped_ptr<AudioEncoder>(new AudioEncoderSpeex());
 | 
| -  }
 | 
| -
 | 
| -  NOTIMPLEMENTED();
 | 
| -  return scoped_ptr<AudioEncoder>(NULL);
 | 
| -}
 | 
| -
 | 
| -void ChromotingHost::StopScreenRecorder() {
 | 
| +void ChromotingHost::OnClientStopped() {
 | 
|    DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
 | 
| -  DCHECK(recorder_.get());
 | 
|  
 | 
| -  ++stopping_recorders_;
 | 
| -  scoped_refptr<ScreenRecorder> recorder = recorder_;
 | 
| -  recorder_ = NULL;
 | 
| -  recorder->Stop(base::Bind(&ChromotingHost::OnRecorderStopped, this));
 | 
| -}
 | 
| -
 | 
| -void ChromotingHost::StopAudioScheduler() {
 | 
| -  DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
 | 
| -  DCHECK(audio_scheduler_.get());
 | 
| -
 | 
| -  ++stopping_recorders_;
 | 
| -  scoped_refptr<AudioScheduler> recorder = audio_scheduler_;
 | 
| -  audio_scheduler_ = NULL;
 | 
| -  recorder->Stop(base::Bind(&ChromotingHost::OnRecorderStopped, this));
 | 
| -}
 | 
| -
 | 
| -void ChromotingHost::OnRecorderStopped() {
 | 
| -  if (!context_->network_task_runner()->BelongsToCurrentThread()) {
 | 
| -    context_->network_task_runner()->PostTask(
 | 
| -        FROM_HERE, base::Bind(&ChromotingHost::OnRecorderStopped, this));
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  --stopping_recorders_;
 | 
| -  DCHECK_GE(stopping_recorders_, 0);
 | 
| -
 | 
| -  if (!stopping_recorders_ && state_ == kStopping)
 | 
| +  --clients_count_;
 | 
| +  if (state_ == kStopping && !clients_count_)
 | 
|      ShutdownFinish();
 | 
|  }
 | 
|  
 | 
|  void ChromotingHost::ShutdownFinish() {
 | 
|    DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
 | 
| -  DCHECK(!stopping_recorders_);
 | 
| +  DCHECK_EQ(state_, kStopping);
 | 
| +
 | 
| +  // Destroy session manager.
 | 
| +  session_manager_.reset();
 | 
|  
 | 
|    state_ = kStopped;
 | 
|  
 | 
| 
 |