diff options
author | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-08 09:52:34 +0000 |
---|---|---|
committer | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-08 09:52:34 +0000 |
commit | 4c35f73337302284aaa503dc2d6b2172623687b5 (patch) | |
tree | 35d32d1c06d8c8fd2b87ffbe0587d1509c5ac6eb | |
parent | dd29cd42928c96b849ab5b832fbe78e1cd1cd9ef (diff) | |
download | chromium_src-4c35f73337302284aaa503dc2d6b2172623687b5.zip chromium_src-4c35f73337302284aaa503dc2d6b2172623687b5.tar.gz chromium_src-4c35f73337302284aaa503dc2d6b2172623687b5.tar.bz2 |
[Chromoting] Refactoring DesktopEnvironment and moving screen/audio recorders to ClientSession.
This CL changes the way screen/audio recorders and event executors are managed. New DesktopEnvironmentFactory class is now used by ChromotingHost's owner to specify the kind of desktop environment (or virtual terminal) to be used by the host. Screen/audio recorders and event executors now owned by the ClientSession instance, so there is a separate set of recorders and stubs exists for each authenticated client session. Clients sessions can now be torn dowsn in parallel with the host shuttting down.
This is the 2nd attempt to land this change. This version includes:
- |ClientSession| objects are torn down asynchronously now.
- |ChromotingHost| now waits until all connections are torn down before deleting the session manager.
BUG=134694
TEST=remoting_unittests
Review URL: https://chromiumcodereview.appspot.com/10911152
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155574 0039d316-1c4b-4281-b951-d872f2087c98
30 files changed, 723 insertions, 463 deletions
diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc index 7dae872..8540217 100644 --- a/remoting/host/chromoting_host.cc +++ b/remoting/host/chromoting_host.cc @@ -19,9 +19,9 @@ #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" @@ -66,13 +66,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), @@ -80,10 +80,9 @@ ChromotingHost::ChromotingHost( reject_authenticating_client_(false) { DCHECK(context_); DCHECK(signal_strategy); - DCHECK(desktop_environment_); DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); - if (!desktop_environment_->audio_capturer()) { + 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(); @@ -141,18 +140,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; } } @@ -203,8 +199,6 @@ void ChromotingHost::OnSessionAuthenticated(ClientSession* client) { // 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(); @@ -224,32 +218,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())); } @@ -265,42 +234,21 @@ 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(); - } - 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->StopAndDelete(base::Bind(&ChromotingHost::OnClientStopped, this)); } void ChromotingHost::OnSessionSequenceNumber(ClientSession* session, int64 sequence_number) { DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); - if (recorder_.get()) - recorder_->UpdateSequenceNumber(sequence_number); } void ChromotingHost::OnSessionRouteChange( @@ -354,17 +302,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( 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( @@ -423,75 +377,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() { - 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() { +void ChromotingHost::OnClientStopped() { 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; diff --git a/remoting/host/chromoting_host.h b/remoting/host/chromoting_host.h index 3cbf2b7..0d53e48 100644 --- a/remoting/host/chromoting_host.h +++ b/remoting/host/chromoting_host.h @@ -12,9 +12,7 @@ #include "base/observer_list.h" #include "base/threading/thread.h" #include "net/base/backoff_entry.h" -#include "remoting/codec/video_encoder.h" #include "remoting/host/client_session.h" -#include "remoting/host/desktop_environment.h" #include "remoting/host/host_key_pair.h" #include "remoting/host/host_status_observer.h" #include "remoting/host/mouse_move_observer.h" @@ -31,13 +29,8 @@ class SessionConfig; class CandidateSessionConfig; } // namespace protocol -class AudioEncoder; -class AudioScheduler; class ChromotingHostContext; -class DesktopEnvironment; -class Encoder; -class ScreenRecorder; -class VideoFrameCapturer; +class DesktopEnvironmentFactory; // A class to implement the functionality of a host process. // @@ -69,10 +62,11 @@ class ChromotingHost : public base::RefCountedThreadSafe<ChromotingHost>, public: // The caller must ensure that |context|, |signal_strategy| and // |environment| out-live the host. - ChromotingHost(ChromotingHostContext* context, - SignalStrategy* signal_strategy, - DesktopEnvironment* environment, - scoped_ptr<protocol::SessionManager> session_manager); + ChromotingHost( + ChromotingHostContext* context, + SignalStrategy* signal_strategy, + DesktopEnvironmentFactory* desktop_environment_factory, + scoped_ptr<protocol::SessionManager> session_manager); // Asynchronously start the host process. // @@ -163,21 +157,12 @@ class ChromotingHost : public base::RefCountedThreadSafe<ChromotingHost>, kStopped, }; - // Creates encoder for the specified configuration. - static VideoEncoder* CreateVideoEncoder( - const protocol::SessionConfig& config); - - // Creates an audio encoder for the specified configuration. - static scoped_ptr<AudioEncoder> CreateAudioEncoder( - const protocol::SessionConfig& config); - virtual ~ChromotingHost(); - void StopScreenRecorder(); - void StopAudioScheduler(); - void OnRecorderStopped(); + // Called when a client session is stopped completely. + void OnClientStopped(); - // Called from Shutdown() or OnScreenRecorderStopped() to finish shutdown. + // Called from Shutdown() to finish shutdown. void ShutdownFinish(); // Unless specified otherwise all members of this class must be @@ -185,7 +170,7 @@ class ChromotingHost : public base::RefCountedThreadSafe<ChromotingHost>, // Parameters specified when the host was created. ChromotingHostContext* context_; - DesktopEnvironment* desktop_environment_; + DesktopEnvironmentFactory* desktop_environment_factory_; scoped_ptr<protocol::SessionManager> session_manager_; // Connection objects. @@ -197,15 +182,10 @@ class ChromotingHost : public base::RefCountedThreadSafe<ChromotingHost>, // The connections to remote clients. ClientList clients_; - // Schedulers for audio and video capture. - // TODO(sergeyu): Do we need to have one set of schedulers per client? - scoped_refptr<ScreenRecorder> recorder_; - scoped_refptr<AudioScheduler> audio_scheduler_; - - // Number of screen recorders and audio schedulers that are currently being - // stopped. Used to delay shutdown if one or more recorders/schedulers are - // asynchronously shutting down. - int stopping_recorders_; + // The number of allocated |ClientSession| objects. |clients_count_| can be + // greater than |clients_.size()| because it also includes the objects that + // are about to be deleted. + int clients_count_; // Tracks the internal state of the host. State state_; diff --git a/remoting/host/chromoting_host_unittest.cc b/remoting/host/chromoting_host_unittest.cc index 3a82f0c..4137bc2 100644 --- a/remoting/host/chromoting_host_unittest.cc +++ b/remoting/host/chromoting_host_unittest.cc @@ -9,6 +9,9 @@ #include "remoting/host/audio_capturer.h" #include "remoting/host/chromoting_host_context.h" #include "remoting/host/chromoting_host.h" +#include "remoting/host/desktop_environment.h" +#include "remoting/host/desktop_environment_factory.h" +#include "remoting/host/event_executor_fake.h" #include "remoting/host/host_mock_objects.h" #include "remoting/host/it2me_host_user_interface.h" #include "remoting/host/video_frame_capturer_fake.h" @@ -62,6 +65,34 @@ void DoNothing() { } // namespace +class MockDesktopEnvironmentFactory : public DesktopEnvironmentFactory { + public: + MockDesktopEnvironmentFactory(); + virtual ~MockDesktopEnvironmentFactory(); + + virtual scoped_ptr<DesktopEnvironment> Create( + ChromotingHostContext* context) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(MockDesktopEnvironmentFactory); +}; + +MockDesktopEnvironmentFactory::MockDesktopEnvironmentFactory() { +} + +MockDesktopEnvironmentFactory::~MockDesktopEnvironmentFactory() { +} + +scoped_ptr<DesktopEnvironment> MockDesktopEnvironmentFactory::Create( + ChromotingHostContext* context) { + scoped_ptr<EventExecutor> event_executor(new EventExecutorFake()); + scoped_ptr<VideoFrameCapturer> video_capturer(new VideoFrameCapturerFake()); + return scoped_ptr<DesktopEnvironment>(new DesktopEnvironment( + scoped_ptr<AudioCapturer>(NULL), + event_executor.Pass(), + video_capturer.Pass())); +} + class ChromotingHostTest : public testing::Test { public: ChromotingHostTest() { @@ -83,18 +114,11 @@ class ChromotingHostTest : public testing::Test { .Times(AnyNumber()) .WillRepeatedly(Return(message_loop_proxy_.get())); - scoped_ptr<VideoFrameCapturer> capturer(new VideoFrameCapturerFake()); - scoped_ptr<AudioCapturer> audio_capturer(NULL); - event_executor_ = new MockEventExecutor(); - desktop_environment_ = DesktopEnvironment::CreateFake( - &context_, - capturer.Pass(), - scoped_ptr<EventExecutor>(event_executor_), - audio_capturer.Pass()); + desktop_environment_factory_.reset(new MockDesktopEnvironmentFactory()); session_manager_ = new protocol::MockSessionManager(); host_ = new ChromotingHost( - &context_, &signal_strategy_, desktop_environment_.get(), + &context_, &signal_strategy_, desktop_environment_factory_.get(), scoped_ptr<protocol::SessionManager>(session_manager_)); host_->AddStatusObserver(&host_status_observer_); @@ -145,11 +169,11 @@ class ChromotingHostTest : public testing::Test { EXPECT_CALL(*session2_, config()) .WillRepeatedly(ReturnRef(session_config2_)); - owned_connection1_.reset(new MockConnectionToClient( - session1_, &host_stub1_, desktop_environment_->event_executor())); + owned_connection1_.reset(new MockConnectionToClient(session1_, + &host_stub1_)); connection1_ = owned_connection1_.get(); - owned_connection2_.reset(new MockConnectionToClient( - session2_, &host_stub2_, desktop_environment_->event_executor())); + owned_connection2_.reset(new MockConnectionToClient(session2_, + &host_stub2_)); connection2_ = owned_connection2_.get(); ON_CALL(video_stub1_, ProcessVideoPacketPtr(_, _)) @@ -194,12 +218,17 @@ class ChromotingHostTest : public testing::Test { ((connection_index == 0) ? owned_connection1_ : owned_connection2_). PassAs<protocol::ConnectionToClient>(); protocol::ConnectionToClient* connection_ptr = connection.get(); + scoped_ptr<DesktopEnvironment> desktop_environment = + host_->desktop_environment_factory_->Create(&context_); + connection_ptr->set_input_stub(desktop_environment->event_executor()); + ClientSession* client = new ClientSession( host_.get(), + 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(), + host_->desktop_environment_factory_->Create(&context_), base::TimeDelta()); connection_ptr->set_host_stub(client); @@ -265,6 +294,7 @@ class ChromotingHostTest : public testing::Test { static void AddClientToHost(scoped_refptr<ChromotingHost> host, ClientSession* session) { host->clients_.push_back(session); + ++host->clients_count_; } void ShutdownHost() { @@ -304,12 +334,9 @@ class ChromotingHostTest : public testing::Test { EXPECT_CALL(host_status_observer_, OnClientAuthenticated(session_jid)); EXPECT_CALL(host_status_observer_, OnClientConnected(session_jid)) .After(client_authenticated); - Expectation session_started = - EXPECT_CALL(*event_executor_, OnSessionStartedPtr(_)) - .After(client_authenticated); Expectation video_packet_sent = EXPECT_CALL(video_stub, ProcessVideoPacketPtr(_, _)) - .After(session_started) + .After(client_authenticated) .WillOnce(DoAll( action, RunDoneTask())) @@ -355,12 +382,10 @@ class ChromotingHostTest : public testing::Test { A action) { const std::string& session_jid = get_session_jid(connection_index); - EXPECT_CALL(*event_executor_, OnSessionFinished()) - .After(after) - .WillOnce(action); if (expect_host_status_change) { EXPECT_CALL(host_status_observer_, OnClientDisconnected(session_jid)) .After(after) + .WillOnce(action) .RetiresOnSaturation(); } } @@ -371,8 +396,7 @@ class ChromotingHostTest : public testing::Test { MockChromotingHostContext context_; MockConnectionToClientEventHandler handler_; MockSignalStrategy signal_strategy_; - MockEventExecutor* event_executor_; - scoped_ptr<DesktopEnvironment> desktop_environment_; + scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_; scoped_ptr<It2MeHostUserInterface> it2me_host_user_interface_; scoped_refptr<ChromotingHost> host_; MockHostStatusObserver host_status_observer_; diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc index 4459000..b3096d1 100644 --- a/remoting/host/client_session.cc +++ b/remoting/host/client_session.cc @@ -7,6 +7,16 @@ #include <algorithm> #include "base/message_loop_proxy.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_scheduler.h" +#include "remoting/host/desktop_environment.h" +#include "remoting/host/event_executor.h" +#include "remoting/host/screen_recorder.h" #include "remoting/host/video_frame_capturer.h" #include "remoting/proto/control.pb.h" #include "remoting/proto/event.pb.h" @@ -17,26 +27,32 @@ namespace remoting { ClientSession::ClientSession( EventHandler* event_handler, + scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, scoped_ptr<protocol::ConnectionToClient> connection, - protocol::ClipboardStub* host_clipboard_stub, - protocol::InputStub* host_input_stub, - VideoFrameCapturer* capturer, + scoped_ptr<DesktopEnvironment> desktop_environment, const base::TimeDelta& max_duration) : event_handler_(event_handler), connection_(connection.Pass()), + desktop_environment_(desktop_environment.Pass()), client_jid_(connection_->session()->jid()), - host_clipboard_stub_(host_clipboard_stub), - host_input_stub_(host_input_stub), + host_clipboard_stub_(desktop_environment_->event_executor()), + host_input_stub_(desktop_environment_->event_executor()), input_tracker_(host_input_stub_), remote_input_filter_(&input_tracker_), - mouse_clamping_filter_(capturer, &remote_input_filter_), + mouse_clamping_filter_(desktop_environment_->video_capturer(), + &remote_input_filter_), disable_input_filter_(&mouse_clamping_filter_), disable_clipboard_filter_(clipboard_echo_filter_.host_filter()), auth_input_filter_(&disable_input_filter_), auth_clipboard_filter_(&disable_clipboard_filter_), client_clipboard_factory_(clipboard_echo_filter_.client_filter()), - capturer_(capturer), - max_duration_(max_duration) { + max_duration_(max_duration), + capture_task_runner_(capture_task_runner), + encode_task_runner_(encode_task_runner), + network_task_runner_(network_task_runner), + active_recorders_(0) { connection_->SetEventHandler(this); // TODO(sergeyu): Currently ConnectionToClient expects stubs to be @@ -52,9 +68,6 @@ ClientSession::ClientSession( auth_clipboard_filter_.set_enabled(false); } -ClientSession::~ClientSession() { -} - void ClientSession::NotifyClientDimensions( const protocol::ClientDimensions& dimensions) { // TODO(wez): Use the dimensions, e.g. to resize the host desktop to match. @@ -98,6 +111,34 @@ void ClientSession::OnConnectionChannelsConnected( DCHECK(CalledOnValidThread()); DCHECK_EQ(connection_.get(), connection); SetDisableInputs(false); + + // Create a ScreenRecorder, passing the message loops that it should run on. + VideoEncoder* video_encoder = + CreateVideoEncoder(connection_->session()->config()); + video_recorder_ = new ScreenRecorder(capture_task_runner_, + encode_task_runner_, + network_task_runner_, + desktop_environment_->video_capturer(), + video_encoder); + ++active_recorders_; + + if (connection_->session()->config().is_audio_enabled()) { + scoped_ptr<AudioEncoder> audio_encoder = + CreateAudioEncoder(connection_->session()->config()); + audio_scheduler_ = new AudioScheduler( + capture_task_runner_, + network_task_runner_, + desktop_environment_->audio_capturer(), + audio_encoder.Pass(), + connection_->audio_stub()); + ++active_recorders_; + } + + // Start the session. + video_recorder_->AddConnection(connection_.get()); + video_recorder_->Start(); + desktop_environment_->Start(CreateClipboardProxy()); + event_handler_->OnSessionChannelsConnected(this); } @@ -127,6 +168,10 @@ void ClientSession::OnSequenceNumberUpdated( protocol::ConnectionToClient* connection, int64 sequence_number) { DCHECK(CalledOnValidThread()); DCHECK_EQ(connection_.get(), connection); + + if (video_recorder_.get()) + video_recorder_->UpdateSequenceNumber(sequence_number); + event_handler_->OnSessionSequenceNumber(this, sequence_number); } @@ -149,6 +194,32 @@ void ClientSession::Disconnect() { connection_->Disconnect(); } +void ClientSession::StopAndDelete(const base::Closure& done_task) { + DCHECK(CalledOnValidThread()); + DCHECK(done_task_.is_null()); + + done_task_ = done_task; + if (audio_scheduler_.get()) { + audio_scheduler_->OnClientDisconnected(); + audio_scheduler_->Stop(base::Bind(&ClientSession::OnRecorderStopped, + base::Unretained(this))); + audio_scheduler_ = NULL; + } + + if (video_recorder_.get()) { + video_recorder_->RemoveConnection(connection_.get()); + video_recorder_->Stop(base::Bind(&ClientSession::OnRecorderStopped, + base::Unretained(this))); + video_recorder_ = NULL; + } + + if (!active_recorders_) { + base::Closure done_task = done_task_; + delete this; + done_task.Run(); + } +} + void ClientSession::LocalMouseMoved(const SkIPoint& mouse_pos) { DCHECK(CalledOnValidThread()); remote_input_filter_.LocalMouseMoved(mouse_pos); @@ -164,6 +235,11 @@ void ClientSession::SetDisableInputs(bool disable_inputs) { disable_clipboard_filter_.set_enabled(!disable_inputs); } +ClientSession::~ClientSession() { + DCHECK(audio_scheduler_.get() == NULL); + DCHECK(video_recorder_.get() == NULL); +} + scoped_ptr<protocol::ClipboardStub> ClientSession::CreateClipboardProxy() { DCHECK(CalledOnValidThread()); @@ -173,4 +249,57 @@ scoped_ptr<protocol::ClipboardStub> ClientSession::CreateClipboardProxy() { base::MessageLoopProxy::current())); } +void ClientSession::OnRecorderStopped() { + if (!network_task_runner_->BelongsToCurrentThread()) { + network_task_runner_->PostTask( + FROM_HERE, base::Bind(&ClientSession::OnRecorderStopped, + base::Unretained(this))); + return; + } + + DCHECK(!done_task_.is_null()); + + --active_recorders_; + DCHECK_GE(active_recorders_, 0); + + if (!active_recorders_) { + base::Closure done_task = done_task_; + delete this; + done_task.Run(); + } +} + +// TODO(sergeyu): Move this to SessionManager? +// static +VideoEncoder* ClientSession::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(); + } + + NOTIMPLEMENTED(); + return NULL; +} + +// static +scoped_ptr<AudioEncoder> ClientSession::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); +} + } // namespace remoting diff --git a/remoting/host/client_session.h b/remoting/host/client_session.h index 109e180..5d63159 100644 --- a/remoting/host/client_session.h +++ b/remoting/host/client_session.h @@ -22,8 +22,17 @@ #include "remoting/protocol/input_stub.h" #include "third_party/skia/include/core/SkPoint.h" +namespace base { +class SingleThreadTaskRunner; +} // namespace base + namespace remoting { +class AudioEncoder; +class AudioScheduler; +class DesktopEnvironment; +class ScreenRecorder; +class VideoEncoder; class VideoFrameCapturer; // A ClientSession keeps a reference to a connection to a client, and maintains @@ -66,12 +75,12 @@ class ClientSession : public protocol::HostStub, }; ClientSession(EventHandler* event_handler, + scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, scoped_ptr<protocol::ConnectionToClient> connection, - protocol::ClipboardStub* host_clipboard_stub, - protocol::InputStub* host_input_stub, - VideoFrameCapturer* capturer, + scoped_ptr<DesktopEnvironment> desktop_environment, const base::TimeDelta& max_duration); - virtual ~ClientSession(); // protocol::HostStub interface. virtual void NotifyClientDimensions( @@ -94,15 +103,23 @@ class ClientSession : public protocol::HostStub, const protocol::TransportRoute& route) OVERRIDE; // Disconnects the session and destroys the transport. Event handler - // is guaranteed not to be called after this method is called. Can - // be called multiple times. The object should not be used after - // this method returns. + // is guaranteed not to be called after this method is called. The object + // should not be used after this method returns. void Disconnect(); + // Stop all the session and deletes |this| once it is completely stopped. + // StopAndDelete() is the only way to destoy a |ClientSession| instance. + // |done_task| is executed when the session is completely stopped. + void StopAndDelete(const base::Closure& done_task); + protocol::ConnectionToClient* connection() const { return connection_.get(); } + DesktopEnvironment* desktop_environment() const { + return desktop_environment_.get(); + } + const std::string& client_jid() { return client_jid_; } bool is_authenticated() { return auth_input_filter_.enabled(); } @@ -116,15 +133,30 @@ class ClientSession : public protocol::HostStub, // keys or mouse buttons pressed then these will be released. void SetDisableInputs(bool disable_inputs); + private: + virtual ~ClientSession(); + // Creates a proxy for sending clipboard events to the client. scoped_ptr<protocol::ClipboardStub> CreateClipboardProxy(); - private: + void OnRecorderStopped(); + + // Creates an audio encoder for the specified configuration. + static scoped_ptr<AudioEncoder> CreateAudioEncoder( + const protocol::SessionConfig& config); + + // Creates a video encoder for the specified configuration. + static VideoEncoder* CreateVideoEncoder( + const protocol::SessionConfig& config); + EventHandler* event_handler_; // The connection to the client. scoped_ptr<protocol::ConnectionToClient> connection_; + // The desktop environment used by this session. + scoped_ptr<DesktopEnvironment> desktop_environment_; + std::string client_jid_; // The host clipboard and input stubs to which this object delegates. @@ -159,12 +191,6 @@ class ClientSession : public protocol::HostStub, // it. base::WeakPtrFactory<protocol::ClipboardStub> client_clipboard_factory_; - // VideoFrameCapturer, used to determine current screen size for ensuring - // injected mouse events fall within the screen area. - // TODO(lambroslambrou): Move floor-control logic, and clamping to screen - // area, out of this class (crbug.com/96508). - VideoFrameCapturer* capturer_; - // The maximum duration of this session. // There is no maximum if this value is <= 0. base::TimeDelta max_duration_; @@ -173,6 +199,22 @@ class ClientSession : public protocol::HostStub, // is reached. base::OneShotTimer<ClientSession> max_duration_timer_; + scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_; + + // Schedulers for audio and video capture. + scoped_refptr<AudioScheduler> audio_scheduler_; + scoped_refptr<ScreenRecorder> video_recorder_; + + // Number of screen recorders and audio schedulers that are currently being + // used or shutdown. Used to delay shutdown if one or more + // recorders/schedulers are asynchronously shutting down. + int active_recorders_; + + // The task to be executed when the session is completely stopped. + base::Closure done_task_; + DISALLOW_COPY_AND_ASSIGN(ClientSession); }; diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc index bf54230..801e5a8 100644 --- a/remoting/host/client_session_unittest.cc +++ b/remoting/host/client_session_unittest.cc @@ -4,7 +4,9 @@ #include "base/message_loop.h" #include "remoting/base/constants.h" +#include "remoting/host/audio_capturer.h" #include "remoting/host/client_session.h" +#include "remoting/host/desktop_environment.h" #include "remoting/host/host_mock_objects.h" #include "remoting/protocol/protocol_mock_objects.h" #include "testing/gtest/include/gtest/gtest.h" @@ -17,8 +19,10 @@ using protocol::MockConnectionToClientEventHandler; using protocol::MockHostStub; using protocol::MockInputStub; using protocol::MockSession; +using protocol::SessionConfig; using testing::_; +using testing::AnyNumber; using testing::DeleteArg; using testing::InSequence; using testing::Return; @@ -29,31 +33,72 @@ class ClientSessionTest : public testing::Test { ClientSessionTest() {} virtual void SetUp() OVERRIDE { + message_loop_proxy_ = base::MessageLoopProxy::current(); + + EXPECT_CALL(context_, ui_task_runner()) + .Times(AnyNumber()) + .WillRepeatedly(Return(message_loop_proxy_.get())); + EXPECT_CALL(context_, capture_task_runner()) + .Times(AnyNumber()) + .WillRepeatedly(Return(message_loop_proxy_.get())); + EXPECT_CALL(context_, encode_task_runner()) + .Times(AnyNumber()) + .WillRepeatedly(Return(message_loop_proxy_.get())); + EXPECT_CALL(context_, network_task_runner()) + .Times(AnyNumber()) + .WillRepeatedly(Return(message_loop_proxy_.get())); + client_jid_ = "user@domain/rest-of-jid"; + event_executor_ = new MockEventExecutor(); + capturer_ = new MockVideoFrameCapturer(); + EXPECT_CALL(*capturer_, Start(_)); + EXPECT_CALL(*capturer_, Stop()); + EXPECT_CALL(*capturer_, InvalidateRegion(_)).Times(AnyNumber()); + EXPECT_CALL(*capturer_, CaptureInvalidRegion(_)).Times(AnyNumber()); + + scoped_ptr<DesktopEnvironment> desktop_environment(new DesktopEnvironment( + scoped_ptr<AudioCapturer>(NULL), + scoped_ptr<EventExecutor>(event_executor_), + scoped_ptr<VideoFrameCapturer>(capturer_))); + // Set up a large default screen size that won't affect most tests. default_screen_size_.set(1000, 1000); - EXPECT_CALL(capturer_, size_most_recent()) + EXPECT_CALL(*capturer_, size_most_recent()) .WillRepeatedly(ReturnRef(default_screen_size_)); + session_config_ = SessionConfig::GetDefault(); + protocol::MockSession* session = new MockSession(); + EXPECT_CALL(*session, config()).WillRepeatedly(ReturnRef(session_config_)); EXPECT_CALL(*session, jid()).WillRepeatedly(ReturnRef(client_jid_)); EXPECT_CALL(*session, SetEventHandler(_)); EXPECT_CALL(*session, Close()); scoped_ptr<protocol::ConnectionToClient> connection( new protocol::ConnectionToClient(session)); connection_ = connection.get(); - client_session_.reset(new ClientSession( - &session_event_handler_, connection.Pass(), - &host_clipboard_stub_, &host_input_stub_, &capturer_, - base::TimeDelta())); + + client_session_ = new ClientSession( + &session_event_handler_, + context_.capture_task_runner(), + context_.encode_task_runner(), + context_.network_task_runner(), + connection.Pass(), + desktop_environment.Pass(), + base::TimeDelta()); } virtual void TearDown() OVERRIDE { - client_session_.reset(); - // Run message loop before destroying because protocol::Session is - // destroyed asynchronously. - message_loop_.RunAllPending(); + // MockClientSessionEventHandler won't trigger StopAndDelete, so fake it. + client_session_->StopAndDelete(base::Bind( + &ClientSessionTest::OnClientStopped, base::Unretained(this))); + + // Run message loop before destroying because the session is destroyed + // asynchronously. + message_loop_.Run(); + + // Verify that the client session has been stopped. + EXPECT_TRUE(client_session_ == NULL); } protected: @@ -64,15 +109,22 @@ class ClientSessionTest : public testing::Test { protocol::OK); } + void OnClientStopped() { + client_session_ = NULL; + message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure()); + } + + MockChromotingHostContext context_; + scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; SkISize default_screen_size_; MessageLoop message_loop_; std::string client_jid_; MockHostStub host_stub_; - MockClipboardStub host_clipboard_stub_; - MockInputStub host_input_stub_; - MockVideoFrameCapturer capturer_; + MockEventExecutor* event_executor_; + MockVideoFrameCapturer* capturer_; MockClientSessionEventHandler session_event_handler_; - scoped_ptr<ClientSession> client_session_; + ClientSession* client_session_; + SessionConfig session_config_; // ClientSession owns |connection_| but tests need it to inject fake events. protocol::ConnectionToClient* connection_; @@ -98,10 +150,12 @@ TEST_F(ClientSessionTest, ClipboardStubFilter) { InSequence s; EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_)); + EXPECT_CALL(*event_executor_, StartPtr(_)); EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_)); - EXPECT_CALL(host_clipboard_stub_, InjectClipboardEvent(EqualsClipboardEvent( + EXPECT_CALL(*event_executor_, InjectClipboardEvent(EqualsClipboardEvent( kMimeTypeTextUtf8, "b"))); EXPECT_CALL(session_event_handler_, OnSessionClosed(_)); + EXPECT_CALL(*event_executor_, StopAndDeleteMock()); // This event should not get through to the clipboard stub, // because the client isn't authenticated yet. @@ -159,11 +213,13 @@ TEST_F(ClientSessionTest, InputStubFilter) { InSequence s; EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_)); + EXPECT_CALL(*event_executor_, StartPtr(_)); EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_)); - EXPECT_CALL(host_input_stub_, InjectKeyEvent(EqualsKeyEvent(2, true))); - EXPECT_CALL(host_input_stub_, InjectKeyEvent(EqualsKeyEvent(2, false))); - EXPECT_CALL(host_input_stub_, InjectMouseEvent(EqualsMouseEvent(200, 201))); + EXPECT_CALL(*event_executor_, InjectKeyEvent(EqualsKeyEvent(2, true))); + EXPECT_CALL(*event_executor_, InjectKeyEvent(EqualsKeyEvent(2, false))); + EXPECT_CALL(*event_executor_, InjectMouseEvent(EqualsMouseEvent(200, 201))); EXPECT_CALL(session_event_handler_, OnSessionClosed(_)); + EXPECT_CALL(*event_executor_, StopAndDeleteMock()); // These events should not get through to the input stub, // because the client isn't authenticated yet. @@ -195,10 +251,12 @@ TEST_F(ClientSessionTest, LocalInputTest) { InSequence s; EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_)); + EXPECT_CALL(*event_executor_, StartPtr(_)); EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_)); - EXPECT_CALL(host_input_stub_, InjectMouseEvent(EqualsMouseEvent(100, 101))); - EXPECT_CALL(host_input_stub_, InjectMouseEvent(EqualsMouseEvent(200, 201))); + EXPECT_CALL(*event_executor_, InjectMouseEvent(EqualsMouseEvent(100, 101))); + EXPECT_CALL(*event_executor_, InjectMouseEvent(EqualsMouseEvent(200, 201))); EXPECT_CALL(session_event_handler_, OnSessionClosed(_)); + EXPECT_CALL(*event_executor_, StopAndDeleteMock()); client_session_->OnConnectionAuthenticated(client_session_->connection()); client_session_->OnConnectionChannelsConnected(client_session_->connection()); @@ -232,16 +290,18 @@ TEST_F(ClientSessionTest, RestoreEventState) { InSequence s; EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_)); + EXPECT_CALL(*event_executor_, StartPtr(_)); EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_)); - EXPECT_CALL(host_input_stub_, InjectKeyEvent(EqualsKeyEvent(1, true))); - EXPECT_CALL(host_input_stub_, InjectKeyEvent(EqualsKeyEvent(2, true))); - EXPECT_CALL(host_input_stub_, InjectMouseEvent(EqualsMouseButtonEvent( + EXPECT_CALL(*event_executor_, InjectKeyEvent(EqualsKeyEvent(1, true))); + EXPECT_CALL(*event_executor_, InjectKeyEvent(EqualsKeyEvent(2, true))); + EXPECT_CALL(*event_executor_, InjectMouseEvent(EqualsMouseButtonEvent( protocol::MouseEvent::BUTTON_LEFT, true))); - EXPECT_CALL(host_input_stub_, InjectKeyEvent(EqualsKeyEvent(1, false))); - EXPECT_CALL(host_input_stub_, InjectKeyEvent(EqualsKeyEvent(2, false))); - EXPECT_CALL(host_input_stub_, InjectMouseEvent(EqualsMouseButtonEvent( + EXPECT_CALL(*event_executor_, InjectKeyEvent(EqualsKeyEvent(1, false))); + EXPECT_CALL(*event_executor_, InjectKeyEvent(EqualsKeyEvent(2, false))); + EXPECT_CALL(*event_executor_, InjectMouseEvent(EqualsMouseButtonEvent( protocol::MouseEvent::BUTTON_LEFT, false))); EXPECT_CALL(session_event_handler_, OnSessionClosed(_)); + EXPECT_CALL(*event_executor_, StopAndDeleteMock()); client_session_->OnConnectionAuthenticated(client_session_->connection()); client_session_->OnConnectionChannelsConnected(client_session_->connection()); @@ -255,12 +315,14 @@ TEST_F(ClientSessionTest, RestoreEventState) { TEST_F(ClientSessionTest, ClampMouseEvents) { SkISize screen(SkISize::Make(200, 100)); - EXPECT_CALL(capturer_, size_most_recent()) + EXPECT_CALL(*capturer_, size_most_recent()) .WillRepeatedly(ReturnRef(screen)); EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_)); + EXPECT_CALL(*event_executor_, StartPtr(_)); EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_)); EXPECT_CALL(session_event_handler_, OnSessionClosed(_)); + EXPECT_CALL(*event_executor_, StopAndDeleteMock()); client_session_->OnConnectionAuthenticated(client_session_->connection()); client_session_->OnConnectionChannelsConnected(client_session_->connection()); @@ -275,7 +337,7 @@ TEST_F(ClientSessionTest, ClampMouseEvents) { for (int i = 0; i < 3; i++) { event.set_x(input_x[i]); event.set_y(input_y[j]); - EXPECT_CALL(host_input_stub_, InjectMouseEvent(EqualsMouseEvent( + EXPECT_CALL(*event_executor_, InjectMouseEvent(EqualsMouseEvent( expected_x[i], expected_y[j]))); connection_->input_stub()->InjectMouseEvent(event); } diff --git a/remoting/host/desktop_environment.cc b/remoting/host/desktop_environment.cc index 12d3655..8807a02 100644 --- a/remoting/host/desktop_environment.cc +++ b/remoting/host/desktop_environment.cc @@ -4,99 +4,31 @@ #include "remoting/host/desktop_environment.h" -#include "base/bind.h" #include "base/compiler_specific.h" #include "remoting/host/audio_capturer.h" -#include "remoting/host/video_frame_capturer.h" #include "remoting/host/chromoting_host_context.h" +#include "remoting/host/desktop_environment.h" #include "remoting/host/event_executor.h" - -#if defined(OS_WIN) -#include "remoting/host/session_event_executor_win.h" -#endif +#include "remoting/host/video_frame_capturer.h" namespace remoting { -// static -scoped_ptr<DesktopEnvironment> DesktopEnvironment::Create( - ChromotingHostContext* context) { - scoped_ptr<VideoFrameCapturer> capturer(VideoFrameCapturer::Create()); - scoped_ptr<EventExecutor> event_executor = EventExecutor::Create( - context->desktop_task_runner(), context->ui_task_runner()); - scoped_ptr<AudioCapturer> audio_capturer = AudioCapturer::Create(); - - if (capturer.get() == NULL || event_executor.get() == NULL) { - LOG(ERROR) << "Unable to create DesktopEnvironment"; - return scoped_ptr<DesktopEnvironment>(); - } - - return scoped_ptr<DesktopEnvironment>( - new DesktopEnvironment(context, - capturer.Pass(), - event_executor.Pass(), - audio_capturer.Pass())); -} - -// static -scoped_ptr<DesktopEnvironment> DesktopEnvironment::CreateForService( - ChromotingHostContext* context) { - scoped_ptr<VideoFrameCapturer> capturer(VideoFrameCapturer::Create()); - scoped_ptr<EventExecutor> event_executor = EventExecutor::Create( - context->desktop_task_runner(), context->ui_task_runner()); - scoped_ptr<AudioCapturer> audio_capturer = AudioCapturer::Create(); - - if (capturer.get() == NULL || event_executor.get() == NULL) { - LOG(ERROR) << "Unable to create DesktopEnvironment"; - return scoped_ptr<DesktopEnvironment>(); - } - -#if defined(OS_WIN) - event_executor.reset(new SessionEventExecutorWin( - context->desktop_task_runner(), - event_executor.Pass())); -#endif - - return scoped_ptr<DesktopEnvironment>( - new DesktopEnvironment(context, - capturer.Pass(), - event_executor.Pass(), - audio_capturer.Pass())); -} - -// static -scoped_ptr<DesktopEnvironment> DesktopEnvironment::CreateFake( - ChromotingHostContext* context, - scoped_ptr<VideoFrameCapturer> capturer, - scoped_ptr<EventExecutor> event_executor, - scoped_ptr<AudioCapturer> audio_capturer) { - return scoped_ptr<DesktopEnvironment>( - new DesktopEnvironment(context, - capturer.Pass(), - event_executor.Pass(), - audio_capturer.Pass())); -} - DesktopEnvironment::DesktopEnvironment( - ChromotingHostContext* context, - scoped_ptr<VideoFrameCapturer> capturer, + scoped_ptr<AudioCapturer> audio_capturer, scoped_ptr<EventExecutor> event_executor, - scoped_ptr<AudioCapturer> audio_capturer) - : context_(context), - capturer_(capturer.Pass()), - audio_capturer_(audio_capturer.Pass()), - event_executor_(event_executor.Pass()) { + scoped_ptr<VideoFrameCapturer> video_capturer) + : audio_capturer_(audio_capturer.Pass()), + event_executor_(event_executor.Pass()), + video_capturer_(video_capturer.Pass()) { } DesktopEnvironment::~DesktopEnvironment() { + event_executor_.release()->StopAndDelete(); } -void DesktopEnvironment::OnSessionStarted( +void DesktopEnvironment::Start( scoped_ptr<protocol::ClipboardStub> client_clipboard) { - event_executor_->OnSessionStarted(client_clipboard.Pass()); -} - -void DesktopEnvironment::OnSessionFinished() { - event_executor_->OnSessionFinished(); + event_executor_->Start(client_clipboard.Pass()); } } // namespace remoting diff --git a/remoting/host/desktop_environment.h b/remoting/host/desktop_environment.h index 8b32a89..a653c78e 100644 --- a/remoting/host/desktop_environment.h +++ b/remoting/host/desktop_environment.h @@ -5,8 +5,6 @@ #ifndef REMOTING_HOST_DESKTOP_ENVIRONMENT_H_ #define REMOTING_HOST_DESKTOP_ENVIRONMENT_H_ -#include <string> - #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" @@ -23,47 +21,28 @@ class ClipboardStub; class DesktopEnvironment { public: - // Creates a DesktopEnvironment used in a host plugin. - static scoped_ptr<DesktopEnvironment> Create( - ChromotingHostContext* context); - - // Creates a DesktopEnvironment used in a service process. - static scoped_ptr<DesktopEnvironment> CreateForService( - ChromotingHostContext* context); - - static scoped_ptr<DesktopEnvironment> CreateFake( - ChromotingHostContext* context, - scoped_ptr<VideoFrameCapturer> capturer, - scoped_ptr<EventExecutor> event_executor, - scoped_ptr<AudioCapturer> audio_capturer); - + DesktopEnvironment(scoped_ptr<AudioCapturer> audio_capturer, + scoped_ptr<EventExecutor> event_executor, + scoped_ptr<VideoFrameCapturer> video_capturer); virtual ~DesktopEnvironment(); - VideoFrameCapturer* capturer() const { return capturer_.get(); } - EventExecutor* event_executor() const { return event_executor_.get(); } AudioCapturer* audio_capturer() const { return audio_capturer_.get(); } - void OnSessionStarted(scoped_ptr<protocol::ClipboardStub> client_clipboard); - void OnSessionFinished(); - - private: - DesktopEnvironment(ChromotingHostContext* context, - scoped_ptr<VideoFrameCapturer> capturer, - scoped_ptr<EventExecutor> event_executor, - scoped_ptr<AudioCapturer> audio_capturer); - - // Host context used to make sure operations are run on the correct thread. - // This is owned by the ChromotingHost. - ChromotingHostContext* context_; + EventExecutor* event_executor() const { return event_executor_.get(); } + VideoFrameCapturer* video_capturer() const { return video_capturer_.get(); } - // Used to capture video to deliver to clients. - scoped_ptr<VideoFrameCapturer> capturer_; + virtual void Start( + scoped_ptr<protocol::ClipboardStub> client_clipboard); + private: // Used to capture audio to deliver to clients. scoped_ptr<AudioCapturer> audio_capturer_; // Executes input and clipboard events received from the client. scoped_ptr<EventExecutor> event_executor_; + // Used to capture video to deliver to clients. + scoped_ptr<VideoFrameCapturer> video_capturer_; + DISALLOW_COPY_AND_ASSIGN(DesktopEnvironment); }; diff --git a/remoting/host/desktop_environment_factory.cc b/remoting/host/desktop_environment_factory.cc new file mode 100644 index 0000000..8edc1205 --- /dev/null +++ b/remoting/host/desktop_environment_factory.cc @@ -0,0 +1,42 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "remoting/host/desktop_environment_factory.h" + +#include "remoting/host/audio_capturer.h" +#include "remoting/host/chromoting_host_context.h" +#include "remoting/host/desktop_environment.h" +#include "remoting/host/event_executor.h" +#include "remoting/host/video_frame_capturer.h" + +namespace remoting { + +DesktopEnvironmentFactory::DesktopEnvironmentFactory() { +} + +DesktopEnvironmentFactory::~DesktopEnvironmentFactory() { +} + +scoped_ptr<DesktopEnvironment> DesktopEnvironmentFactory::Create( + ChromotingHostContext* context) { + scoped_ptr<AudioCapturer> audio_capturer = AudioCapturer::Create(); + scoped_ptr<EventExecutor> event_executor = EventExecutor::Create( + context->desktop_task_runner(), + context->ui_task_runner()); + scoped_ptr<VideoFrameCapturer> video_capturer(VideoFrameCapturer::Create()); + return scoped_ptr<DesktopEnvironment>(new DesktopEnvironment( + audio_capturer.Pass(), + event_executor.Pass(), + video_capturer.Pass())); +} + +bool DesktopEnvironmentFactory::SupportsAudioCapture() const { +#if defined(OS_WIN) + return true; +#else // !defined(OS_WIN) + return false; +#endif // !defined(OS_WIN) +} + +} // namespace remoting diff --git a/remoting/host/desktop_environment_factory.h b/remoting/host/desktop_environment_factory.h new file mode 100644 index 0000000..c77aef6 --- /dev/null +++ b/remoting/host/desktop_environment_factory.h @@ -0,0 +1,34 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REMOTING_HOST_DESKTOP_ENVIRONMENT_FACTORY_H_ +#define REMOTING_HOST_DESKTOP_ENVIRONMENT_FACTORY_H_ + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" + +namespace remoting { + +class ChromotingHostContext; +class DesktopEnvironment; + +class DesktopEnvironmentFactory { + public: + DesktopEnvironmentFactory(); + virtual ~DesktopEnvironmentFactory(); + + virtual scoped_ptr<DesktopEnvironment> Create( + ChromotingHostContext* context); + + // Returns |true| if created |DesktopEnvironment| instances support audio + // capture. + virtual bool SupportsAudioCapture() const; + + protected: + DISALLOW_COPY_AND_ASSIGN(DesktopEnvironmentFactory); +}; + +} // namespace remoting + +#endif // REMOTING_HOST_DESKTOP_ENVIRONMENT_FACTORY_H_ diff --git a/remoting/host/event_executor.h b/remoting/host/event_executor.h index c660eb3..1032367 100644 --- a/remoting/host/event_executor.h +++ b/remoting/host/event_executor.h @@ -28,11 +28,11 @@ class EventExecutor : public protocol::ClipboardStub, scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); // Initialises any objects needed to execute events. - virtual void OnSessionStarted( + virtual void Start( scoped_ptr<protocol::ClipboardStub> client_clipboard) = 0; - // Destroys any objects constructed by Start(). - virtual void OnSessionFinished() = 0; + // Destroys any objects constructed by Start() and deletes |this|. + virtual void StopAndDelete() = 0; }; } // namespace remoting diff --git a/remoting/host/event_executor_fake.cc b/remoting/host/event_executor_fake.cc new file mode 100644 index 0000000..a86ab4b --- /dev/null +++ b/remoting/host/event_executor_fake.cc @@ -0,0 +1,33 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "remoting/host/event_executor_fake.h" + +namespace remoting { + +EventExecutorFake::EventExecutorFake() { +} + +EventExecutorFake::~EventExecutorFake() { +} + +void EventExecutorFake::InjectClipboardEvent( + const protocol::ClipboardEvent& event) { +} + +void EventExecutorFake::InjectKeyEvent(const protocol::KeyEvent& event) { +} + +void EventExecutorFake::InjectMouseEvent(const protocol::MouseEvent& event) { +} + +void EventExecutorFake::Start( + scoped_ptr<protocol::ClipboardStub> client_clipboard) { +} + +void EventExecutorFake::StopAndDelete() { + delete this; +} + +} // namespace remoting diff --git a/remoting/host/event_executor_fake.h b/remoting/host/event_executor_fake.h new file mode 100644 index 0000000..2a7d906 --- /dev/null +++ b/remoting/host/event_executor_fake.h @@ -0,0 +1,36 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REMOTING_HOST_EVENT_EXECUTOR_FAKE_H_ +#define REMOTING_HOST_EVENT_EXECUTOR_FAKE_H_ + +#include "remoting/host/event_executor.h" + +namespace remoting { + +// A dummy implementation of |EventExecutor| that does nothing. +class EventExecutorFake : public EventExecutor { + public: + EventExecutorFake(); + virtual ~EventExecutorFake(); + + // ClipboardStub interface. + virtual void InjectClipboardEvent( + const protocol::ClipboardEvent& event) OVERRIDE; + + // InputStub interface. + virtual void InjectKeyEvent(const protocol::KeyEvent& event) OVERRIDE; + virtual void InjectMouseEvent(const protocol::MouseEvent& event) OVERRIDE; + + virtual void Start( + scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; + virtual void StopAndDelete() OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(EventExecutorFake); +}; + +} // namespace remoting + +#endif // REMOTING_HOST_EVENT_EXECUTOR_FAKE_H_ diff --git a/remoting/host/event_executor_linux.cc b/remoting/host/event_executor_linux.cc index fe64ad2..47c2984 100644 --- a/remoting/host/event_executor_linux.cc +++ b/remoting/host/event_executor_linux.cc @@ -50,9 +50,9 @@ class EventExecutorLinux : public EventExecutor { virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE; // EventExecutor interface. - virtual void OnSessionStarted( + virtual void Start( scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; - virtual void OnSessionFinished() OVERRIDE; + virtual void StopAndDelete() OVERRIDE; private: // |mode| is one of the AutoRepeatModeOn, AutoRepeatModeOff, @@ -439,13 +439,13 @@ void EventExecutorLinux::InjectMouseEvent(const MouseEvent& event) { XFlush(display_); } -void EventExecutorLinux::OnSessionStarted( +void EventExecutorLinux::Start( scoped_ptr<protocol::ClipboardStub> client_clipboard) { return; } -void EventExecutorLinux::OnSessionFinished() { - return; +void EventExecutorLinux::StopAndDelete() { + delete this; } } // namespace diff --git a/remoting/host/event_executor_mac.cc b/remoting/host/event_executor_mac.cc index 47320f9..66b6206 100644 --- a/remoting/host/event_executor_mac.cc +++ b/remoting/host/event_executor_mac.cc @@ -57,9 +57,9 @@ class EventExecutorMac : public EventExecutor { virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE; // EventExecutor interface. - virtual void OnSessionStarted( + virtual void Start( scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; - virtual void OnSessionFinished() OVERRIDE; + virtual void StopAndDelete() OVERRIDE; private: scoped_refptr<base::SingleThreadTaskRunner> task_runner_; @@ -404,12 +404,12 @@ void EventExecutorMac::InjectMouseEvent(const MouseEvent& event) { } } -void EventExecutorMac::OnSessionStarted( +void EventExecutorMac::Start( scoped_ptr<protocol::ClipboardStub> client_clipboard) { if (!task_runner_->BelongsToCurrentThread()) { task_runner_->PostTask( FROM_HERE, - base::Bind(&EventExecutorMac::OnSessionStarted, + base::Bind(&EventExecutorMac::Start, base::Unretained(this), base::Passed(&client_clipboard))); return; @@ -418,16 +418,17 @@ void EventExecutorMac::OnSessionStarted( clipboard_->Start(client_clipboard.Pass()); } -void EventExecutorMac::OnSessionFinished() { +void EventExecutorMac::StopAndDelete() { if (!task_runner_->BelongsToCurrentThread()) { task_runner_->PostTask( FROM_HERE, - base::Bind(&EventExecutorMac::OnSessionFinished, + base::Bind(&EventExecutorMac::StopAndDelete, base::Unretained(this))); return; } clipboard_->Stop(); + delete this; } } // namespace diff --git a/remoting/host/event_executor_win.cc b/remoting/host/event_executor_win.cc index cede6d8..00a7a24 100644 --- a/remoting/host/event_executor_win.cc +++ b/remoting/host/event_executor_win.cc @@ -44,9 +44,9 @@ class EventExecutorWin : public EventExecutor { virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE; // EventExecutor interface. - virtual void OnSessionStarted( + virtual void Start( scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; - virtual void OnSessionFinished() OVERRIDE; + virtual void StopAndDelete() OVERRIDE; private: HKL GetForegroundKeyboardLayout(); @@ -105,12 +105,12 @@ void EventExecutorWin::InjectMouseEvent(const MouseEvent& event) { HandleMouse(event); } -void EventExecutorWin::OnSessionStarted( +void EventExecutorWin::Start( scoped_ptr<protocol::ClipboardStub> client_clipboard) { if (!ui_task_runner_->BelongsToCurrentThread()) { ui_task_runner_->PostTask( FROM_HERE, - base::Bind(&EventExecutorWin::OnSessionStarted, + base::Bind(&EventExecutorWin::Start, base::Unretained(this), base::Passed(&client_clipboard))); return; @@ -119,16 +119,17 @@ void EventExecutorWin::OnSessionStarted( clipboard_->Start(client_clipboard.Pass()); } -void EventExecutorWin::OnSessionFinished() { +void EventExecutorWin::StopAndDelete() { if (!ui_task_runner_->BelongsToCurrentThread()) { ui_task_runner_->PostTask( FROM_HERE, - base::Bind(&EventExecutorWin::OnSessionFinished, + base::Bind(&EventExecutorWin::StopAndDelete, base::Unretained(this))); return; } clipboard_->Stop(); + delete this; } HKL EventExecutorWin::GetForegroundKeyboardLayout() { diff --git a/remoting/host/host_mock_objects.cc b/remoting/host/host_mock_objects.cc index f8867a3..2eb6c91 100644 --- a/remoting/host/host_mock_objects.cc +++ b/remoting/host/host_mock_objects.cc @@ -30,9 +30,14 @@ MockEventExecutor::MockEventExecutor() {} MockEventExecutor::~MockEventExecutor() {} -void MockEventExecutor::OnSessionStarted( +void MockEventExecutor::Start( scoped_ptr<protocol::ClipboardStub> client_clipboard) { - OnSessionStartedPtr(client_clipboard.get()); + StartPtr(client_clipboard.get()); +} + +void MockEventExecutor::StopAndDelete() { + StopAndDeleteMock(); + delete this; } MockDisconnectWindow::MockDisconnectWindow() {} diff --git a/remoting/host/host_mock_objects.h b/remoting/host/host_mock_objects.h index b0264d1..19c05bb 100644 --- a/remoting/host/host_mock_objects.h +++ b/remoting/host/host_mock_objects.h @@ -126,11 +126,12 @@ class MockEventExecutor : public EventExecutor { void(const protocol::ClipboardEvent& event)); MOCK_METHOD1(InjectKeyEvent, void(const protocol::KeyEvent& event)); MOCK_METHOD1(InjectMouseEvent, void(const protocol::MouseEvent& event)); - MOCK_METHOD1(OnSessionStartedPtr, + MOCK_METHOD1(StartPtr, void(protocol::ClipboardStub* client_clipboard)); - MOCK_METHOD0(OnSessionFinished, void()); + MOCK_METHOD0(StopAndDeleteMock, void()); - void OnSessionStarted(scoped_ptr<protocol::ClipboardStub> client_clipboard); + void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard); + void StopAndDelete(); private: DISALLOW_COPY_AND_ASSIGN(MockEventExecutor); diff --git a/remoting/host/plugin/host_script_object.cc b/remoting/host/plugin/host_script_object.cc index 8cffb5e..c900bc6 100644 --- a/remoting/host/plugin/host_script_object.cc +++ b/remoting/host/plugin/host_script_object.cc @@ -19,7 +19,7 @@ #include "remoting/base/auth_token_util.h" #include "remoting/host/chromoting_host.h" #include "remoting/host/chromoting_host_context.h" -#include "remoting/host/desktop_environment.h" +#include "remoting/host/desktop_environment_factory.h" #include "remoting/host/host_config.h" #include "remoting/host/host_event_logger.h" #include "remoting/host/host_key_pair.h" @@ -93,6 +93,7 @@ HostNPScriptObject::HostNPScriptObject( np_thread_id_(base::PlatformThread::CurrentId()), plugin_task_runner_( new PluginThreadTaskRunner(plugin_thread_delegate)), + desktop_environment_factory_(new DesktopEnvironmentFactory()), failed_login_attempts_(0), disconnected_event_(true, false), nat_traversal_enabled_(false), @@ -511,43 +512,22 @@ void HostNPScriptObject::ReadPolicyAndConnect(const std::string& uid, // Only proceed to FinishConnect() if at least one policy update has been // received. if (policy_received_) { - FinishConnectMainThread(uid, auth_token, auth_service); + FinishConnect(uid, auth_token, auth_service); } else { // Otherwise, create the policy watcher, and thunk the connect. pending_connect_ = - base::Bind(&HostNPScriptObject::FinishConnectMainThread, + base::Bind(&HostNPScriptObject::FinishConnect, base::Unretained(this), uid, auth_token, auth_service); } } -void HostNPScriptObject::FinishConnectMainThread( - const std::string& uid, - const std::string& auth_token, - const std::string& auth_service) { - if (!host_context_->capture_task_runner()->BelongsToCurrentThread()) { - host_context_->capture_task_runner()->PostTask(FROM_HERE, base::Bind( - &HostNPScriptObject::FinishConnectMainThread, base::Unretained(this), - uid, auth_token, auth_service)); - return; - } - - // DesktopEnvironment must be initialized on the capture thread. - // - // TODO(sergeyu): Fix DesktopEnvironment so that it can be created - // on either the UI or the network thread so that we can avoid - // jumping to the main thread here. - desktop_environment_ = DesktopEnvironment::Create(host_context_.get()); - - FinishConnectNetworkThread(uid, auth_token, auth_service); -} - -void HostNPScriptObject::FinishConnectNetworkThread( +void HostNPScriptObject::FinishConnect( const std::string& uid, const std::string& auth_token, const std::string& auth_service) { if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { host_context_->network_task_runner()->PostTask(FROM_HERE, base::Bind( - &HostNPScriptObject::FinishConnectNetworkThread, base::Unretained(this), + &HostNPScriptObject::FinishConnect, base::Unretained(this), uid, auth_token, auth_service)); return; } @@ -564,12 +544,6 @@ void HostNPScriptObject::FinishConnectNetworkThread( return; } - // Verify that DesktopEnvironment has been created. - if (desktop_environment_.get() == NULL) { - SetState(kError); - return; - } - // Generate a key pair for the Host to use. // TODO(wez): Move this to the worker thread. host_key_pair_.Generate(); @@ -603,7 +577,8 @@ void HostNPScriptObject::FinishConnectNetworkThread( // Create the Host. host_ = new ChromotingHost( - host_context_.get(), signal_strategy_.get(), desktop_environment_.get(), + host_context_.get(), signal_strategy_.get(), + desktop_environment_factory_.get(), CreateHostSessionManager(network_settings, host_context_->url_request_context_getter())); host_->AddStatusObserver(this); @@ -895,7 +870,6 @@ void HostNPScriptObject::DisconnectInternal() { return; case kStarting: - desktop_environment_.reset(); SetState(kDisconnecting); SetState(kDisconnected); return; @@ -925,8 +899,6 @@ void HostNPScriptObject::DisconnectInternal() { void HostNPScriptObject::OnShutdownFinished() { DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); - - desktop_environment_.reset(); } void HostNPScriptObject::OnPolicyUpdate( diff --git a/remoting/host/plugin/host_script_object.h b/remoting/host/plugin/host_script_object.h index abb6734..a1bb4fe 100644 --- a/remoting/host/plugin/host_script_object.h +++ b/remoting/host/plugin/host_script_object.h @@ -33,7 +33,7 @@ namespace remoting { class ChromotingHost; -class DesktopEnvironment; +class DesktopEnvironmentFactory; class HostEventLogger; class It2MeHostUserInterface; class MutableHostConfig; @@ -198,12 +198,10 @@ class HostNPScriptObject : public HostStatusObserver { void ReadPolicyAndConnect(const std::string& uid, const std::string& auth_token, const std::string& auth_service); - void FinishConnectMainThread(const std::string& uid, - const std::string& auth_token, - const std::string& auth_service); - void FinishConnectNetworkThread(const std::string& uid, - const std::string& auth_token, - const std::string& auth_service); + void FinishConnect(const std::string& uid, + const std::string& auth_token, + const std::string& auth_service); + void DisconnectInternal(); // Callback for ChromotingHost::Shutdown(). @@ -313,7 +311,7 @@ class HostNPScriptObject : public HostStatusObserver { scoped_ptr<SignalStrategy> signal_strategy_; scoped_ptr<RegisterSupportHostRequest> register_request_; scoped_ptr<LogToServer> log_to_server_; - scoped_ptr<DesktopEnvironment> desktop_environment_; + scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_; scoped_ptr<It2MeHostUserInterface> it2me_host_user_interface_; scoped_ptr<HostEventLogger> host_event_logger_; diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc index bc18501..6dcad1b 100644 --- a/remoting/host/remoting_me2me_host.cc +++ b/remoting/host/remoting_me2me_host.cc @@ -39,7 +39,7 @@ #include "remoting/host/config_file_watcher.h" #include "remoting/host/constants.h" #include "remoting/host/config_file_watcher.h" -#include "remoting/host/desktop_environment.h" +#include "remoting/host/desktop_environment_factory.h" #include "remoting/host/dns_blackhole_checker.h" #include "remoting/host/event_executor.h" #include "remoting/host/heartbeat_sender.h" @@ -75,6 +75,7 @@ // N.B. OS_WIN is defined by including src/base headers. #if defined(OS_WIN) #include <commctrl.h> +#include "remoting/host/win/session_desktop_environment_factory.h" #endif // defined(OS_WIN) #if defined(TOOLKIT_GTK) @@ -120,6 +121,11 @@ class HostProcess allow_nat_traversal_(true), restarting_(false), shutting_down_(false), +#if defined(OS_WIN) + desktop_environment_factory_(new SessionDesktopEnvironmentFactory()), +#else // !defined(OS_WIN) + desktop_environment_factory_(new DesktopEnvironmentFactory()), +#endif // !defined(OS_WIN) exit_code_(kSuccessExitCode) #if defined(OS_MACOSX) , curtain_(base::Bind(&HostProcess::OnDisconnectRequested, @@ -537,11 +543,6 @@ class HostProcess signaling_connector_->EnableOAuth(oauth_credentials.Pass()); } - if (!desktop_environment_.get()) { - desktop_environment_ = - DesktopEnvironment::CreateForService(context_.get()); - } - NetworkSettings network_settings( allow_nat_traversal_ ? NetworkSettings::NAT_TRAVERSAL_ENABLED : @@ -552,7 +553,8 @@ class HostProcess } host_ = new ChromotingHost( - context_.get(), signal_strategy_.get(), desktop_environment_.get(), + context_.get(), signal_strategy_.get(), + desktop_environment_factory_.get(), CreateHostSessionManager(network_settings, context_->url_request_context_getter())); @@ -650,7 +652,6 @@ class HostProcess void ResetHost() { DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); - desktop_environment_.reset(); host_event_logger_.reset(); log_to_server_.reset(); heartbeat_sender_.reset(); @@ -685,9 +686,9 @@ class HostProcess bool restarting_; bool shutting_down_; + scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_; scoped_ptr<XmppSignalStrategy> signal_strategy_; scoped_ptr<SignalingConnector> signaling_connector_; - scoped_ptr<DesktopEnvironment> desktop_environment_; scoped_ptr<HeartbeatSender> heartbeat_sender_; scoped_ptr<LogToServer> log_to_server_; scoped_ptr<HostEventLogger> host_event_logger_; diff --git a/remoting/host/screen_recorder_unittest.cc b/remoting/host/screen_recorder_unittest.cc index 74a445e..194db96 100644 --- a/remoting/host/screen_recorder_unittest.cc +++ b/remoting/host/screen_recorder_unittest.cc @@ -100,8 +100,7 @@ class ScreenRecorderTest : public testing::Test { EXPECT_CALL(*session_, SetEventHandler(_)); EXPECT_CALL(*session_, Close()) .Times(AnyNumber()); - connection_.reset(new MockConnectionToClient( - session_, &host_stub_, &event_executor_)); + connection_.reset(new MockConnectionToClient(session_, &host_stub_)); connection_->SetEventHandler(&handler_); record_ = new ScreenRecorder( @@ -122,7 +121,6 @@ class ScreenRecorderTest : public testing::Test { MockConnectionToClientEventHandler handler_; MockHostStub host_stub_; - MockEventExecutor event_executor_; MockSession* session_; // Owned by |connection_|. scoped_ptr<MockConnectionToClient> connection_; diff --git a/remoting/host/simple_host_process.cc b/remoting/host/simple_host_process.cc index 0887eb3..38902f9 100644 --- a/remoting/host/simple_host_process.cc +++ b/remoting/host/simple_host_process.cc @@ -41,6 +41,8 @@ #include "remoting/host/desktop_environment.h" #include "remoting/host/dns_blackhole_checker.h" #include "remoting/host/event_executor.h" +#include "remoting/host/desktop_environment.h" +#include "remoting/host/desktop_environment_factory.h" #include "remoting/host/heartbeat_sender.h" #include "remoting/host/host_key_pair.h" #include "remoting/host/host_secret.h" @@ -94,6 +96,36 @@ const char kVideoSwitchValueVp8[] = "vp8"; namespace remoting { +class FakeDesktopEnvironmentFactory : public DesktopEnvironmentFactory { + public: + FakeDesktopEnvironmentFactory(); + virtual ~FakeDesktopEnvironmentFactory(); + + virtual scoped_ptr<DesktopEnvironment> Create( + ChromotingHostContext* context) OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(FakeDesktopEnvironmentFactory); +}; + +FakeDesktopEnvironmentFactory::FakeDesktopEnvironmentFactory() { +} + +FakeDesktopEnvironmentFactory::~FakeDesktopEnvironmentFactory() { +} + +scoped_ptr<DesktopEnvironment> FakeDesktopEnvironmentFactory::Create( + ChromotingHostContext* context) { + scoped_ptr<VideoFrameCapturer> capturer(new VideoFrameCapturerFake()); + scoped_ptr<EventExecutor> event_executor = EventExecutor::Create( + context->desktop_task_runner(), + context->ui_task_runner()); + scoped_ptr<AudioCapturer> audio_capturer(NULL); + return scoped_ptr<DesktopEnvironment>(new DesktopEnvironment( + audio_capturer.Pass(), + event_executor.Pass(), + capturer.Pass())); +} + class SimpleHost : public HeartbeatSender::Listener { public: SimpleHost() @@ -229,22 +261,13 @@ class SimpleHost : public HeartbeatSender::Listener { base::Bind(&SimpleHost::OnAuthFailed, base::Unretained(this)))); if (fake_) { - scoped_ptr<VideoFrameCapturer> capturer(new VideoFrameCapturerFake()); - scoped_ptr<EventExecutor> event_executor = EventExecutor::Create( - context_.desktop_task_runner(), - context_.ui_task_runner()); - scoped_ptr<AudioCapturer> audio_capturer(NULL); - desktop_environment_ = DesktopEnvironment::CreateFake( - &context_, - capturer.Pass(), - event_executor.Pass(), - audio_capturer.Pass()); + desktop_environment_factory_.reset(new FakeDesktopEnvironmentFactory()); } else { - desktop_environment_ = DesktopEnvironment::Create(&context_); + desktop_environment_factory_.reset(new DesktopEnvironmentFactory()); } host_ = new ChromotingHost( - &context_, signal_strategy_.get(), desktop_environment_.get(), + &context_, signal_strategy_.get(), desktop_environment_factory_.get(), CreateHostSessionManager(network_settings_, context_.url_request_context_getter())); @@ -331,10 +354,10 @@ class SimpleHost : public HeartbeatSender::Listener { std::string xmpp_auth_token_; std::string xmpp_auth_service_; + scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_; scoped_ptr<XmppSignalStrategy> signal_strategy_; scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker_; scoped_ptr<SignalingConnector> signaling_connector_; - scoped_ptr<DesktopEnvironment> desktop_environment_; scoped_ptr<LogToServer> log_to_server_; scoped_ptr<It2MeHostUserInterface> it2me_host_user_interface_; scoped_ptr<RegisterSupportHostRequest> register_request_; diff --git a/remoting/host/win/session_desktop_environment_factory.cc b/remoting/host/win/session_desktop_environment_factory.cc new file mode 100644 index 0000000..b90ef33 --- /dev/null +++ b/remoting/host/win/session_desktop_environment_factory.cc @@ -0,0 +1,38 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "remoting/host/win/session_desktop_environment_factory.h" + +#include "remoting/host/audio_capturer.h" +#include "remoting/host/chromoting_host_context.h" +#include "remoting/host/desktop_environment.h" +#include "remoting/host/event_executor.h" +#include "remoting/host/video_frame_capturer.h" +#include "remoting/host/win/session_event_executor.h" + +namespace remoting { + +SessionDesktopEnvironmentFactory::SessionDesktopEnvironmentFactory() { +} + +SessionDesktopEnvironmentFactory::~SessionDesktopEnvironmentFactory() { +} + +scoped_ptr<DesktopEnvironment> SessionDesktopEnvironmentFactory::Create( + ChromotingHostContext* context) { + scoped_ptr<AudioCapturer> audio_capturer = AudioCapturer::Create(); + scoped_ptr<EventExecutor> event_executor = EventExecutor::Create( + context->desktop_task_runner(), + context->ui_task_runner()); + event_executor.reset(new SessionEventExecutorWin( + context->desktop_task_runner(), + event_executor.Pass())); + scoped_ptr<VideoFrameCapturer> video_capturer(VideoFrameCapturer::Create()); + return scoped_ptr<DesktopEnvironment>(new DesktopEnvironment( + audio_capturer.Pass(), + event_executor.Pass(), + video_capturer.Pass())); +} + +} // namespace remoting diff --git a/remoting/host/win/session_desktop_environment_factory.h b/remoting/host/win/session_desktop_environment_factory.h new file mode 100644 index 0000000..6f71230 --- /dev/null +++ b/remoting/host/win/session_desktop_environment_factory.h @@ -0,0 +1,26 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REMOTING_HOST_WIN_SESSION_DESKTOP_ENVIRONMENT_FACTORY_H_ +#define REMOTING_HOST_WIN_SESSION_DESKTOP_ENVIRONMENT_FACTORY_H_ + +#include "remoting/host/desktop_environment_factory.h" + +namespace remoting { + +class SessionDesktopEnvironmentFactory : public DesktopEnvironmentFactory { + public: + SessionDesktopEnvironmentFactory(); + virtual ~SessionDesktopEnvironmentFactory(); + + virtual scoped_ptr<DesktopEnvironment> Create( + ChromotingHostContext* context) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(SessionDesktopEnvironmentFactory); +}; + +} // namespace remoting + +#endif // REMOTING_HOST_WIN_SESSION_DESKTOP_ENVIRONMENT_FACTORY_H_ diff --git a/remoting/host/session_event_executor_win.cc b/remoting/host/win/session_event_executor.cc index 9fc2834..027aef0 100644 --- a/remoting/host/session_event_executor_win.cc +++ b/remoting/host/win/session_event_executor.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/host/session_event_executor_win.h" +#include "remoting/host/win/session_event_executor.h" #include <string> @@ -56,29 +56,30 @@ SessionEventExecutorWin::SessionEventExecutorWin( SessionEventExecutorWin::~SessionEventExecutorWin() { } -void SessionEventExecutorWin::OnSessionStarted( +void SessionEventExecutorWin::Start( scoped_ptr<protocol::ClipboardStub> client_clipboard) { if (!task_runner_->BelongsToCurrentThread()) { task_runner_->PostTask( FROM_HERE, - base::Bind(&SessionEventExecutorWin::OnSessionStarted, + base::Bind(&SessionEventExecutorWin::Start, weak_ptr_, base::Passed(&client_clipboard))); return; } - nested_executor_->OnSessionStarted(client_clipboard.Pass()); + nested_executor_->Start(client_clipboard.Pass()); } -void SessionEventExecutorWin::OnSessionFinished() { +void SessionEventExecutorWin::StopAndDelete() { if (!task_runner_->BelongsToCurrentThread()) { task_runner_->PostTask( FROM_HERE, - base::Bind(&SessionEventExecutorWin::OnSessionFinished, + base::Bind(&SessionEventExecutorWin::StopAndDelete, weak_ptr_)); return; } - nested_executor_->OnSessionFinished(); + nested_executor_.release()->StopAndDelete(); + delete this; } void SessionEventExecutorWin::InjectClipboardEvent( diff --git a/remoting/host/session_event_executor_win.h b/remoting/host/win/session_event_executor.h index b6d48bf..118238d 100644 --- a/remoting/host/session_event_executor_win.h +++ b/remoting/host/win/session_event_executor.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_HOST_SESSION_EVENT_EXECUTOR_WIN_H_ -#define REMOTING_HOST_SESSION_EVENT_EXECUTOR_WIN_H_ +#ifndef REMOTING_HOST_WIN_SESSION_EVENT_EXECUTOR_H_ +#define REMOTING_HOST_WIN_SESSION_EVENT_EXECUTOR_H_ #include <set> @@ -29,9 +29,9 @@ class SessionEventExecutorWin : public EventExecutor { ~SessionEventExecutorWin(); // EventExecutor implementation. - virtual void OnSessionStarted( + virtual void Start( scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; - virtual void OnSessionFinished() OVERRIDE; + virtual void StopAndDelete() OVERRIDE; // protocol::ClipboardStub implementation. virtual void InjectClipboardEvent( @@ -66,4 +66,4 @@ class SessionEventExecutorWin : public EventExecutor { } // namespace remoting -#endif // REMOTING_HOST_SESSION_EVENT_EXECUTOR_WIN_H_ +#endif // REMOTING_HOST_WIN_SESSION_EVENT_EXECUTOR_H_ diff --git a/remoting/protocol/protocol_mock_objects.cc b/remoting/protocol/protocol_mock_objects.cc index a37b0d7..58f912b 100644 --- a/remoting/protocol/protocol_mock_objects.cc +++ b/remoting/protocol/protocol_mock_objects.cc @@ -13,11 +13,9 @@ namespace protocol { MockConnectionToClient::MockConnectionToClient( Session* session, - HostStub* host_stub, - InputStub* input_stub) + HostStub* host_stub) : ConnectionToClient(session) { set_host_stub(host_stub); - set_input_stub(input_stub); } MockConnectionToClient::~MockConnectionToClient() {} diff --git a/remoting/protocol/protocol_mock_objects.h b/remoting/protocol/protocol_mock_objects.h index 5251287..e65826a 100644 --- a/remoting/protocol/protocol_mock_objects.h +++ b/remoting/protocol/protocol_mock_objects.h @@ -28,8 +28,7 @@ namespace protocol { class MockConnectionToClient : public ConnectionToClient { public: MockConnectionToClient(Session* session, - HostStub* host_stub, - InputStub* input_stub); + HostStub* host_stub); virtual ~MockConnectionToClient(); MOCK_METHOD1(Init, void(Session* session)); diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index b41fd56..3598bdc 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -1222,6 +1222,8 @@ 'host/continue_window_win.cc', 'host/desktop_environment.cc', 'host/desktop_environment.h', + 'host/desktop_environment_factory.cc', + 'host/desktop_environment_factory.h', 'host/differ.cc', 'host/differ.h', 'host/disconnect_window.h', @@ -1289,8 +1291,6 @@ 'host/screen_recorder.h', 'host/server_log_entry.cc', 'host/server_log_entry.h', - 'host/session_event_executor_win.cc', - 'host/session_event_executor_win.h', 'host/session_manager_factory.cc', 'host/session_manager_factory.h', 'host/signaling_connector.cc', @@ -1317,6 +1317,10 @@ 'host/win/desktop.h', 'host/win/scoped_thread_desktop.cc', 'host/win/scoped_thread_desktop.h', + 'host/win/session_desktop_environment_factory.cc', + 'host/win/session_desktop_environment_factory.h', + 'host/win/session_event_executor.cc', + 'host/win/session_event_executor.h', 'host/x_server_pixel_buffer.cc', 'host/x_server_pixel_buffer.h', ], @@ -1760,6 +1764,8 @@ 'host/client_session_unittest.cc', 'host/differ_block_unittest.cc', 'host/differ_unittest.cc', + 'host/event_executor_fake.cc', + 'host/event_executor_fake.h', 'host/heartbeat_sender_unittest.cc', 'host/host_key_pair_unittest.cc', 'host/host_mock_objects.cc', |