diff options
author | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-27 20:23:11 +0000 |
---|---|---|
committer | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-27 20:23:11 +0000 |
commit | 0d1559665198c3281def9139b1cc3f4e3643a572 (patch) | |
tree | d8a71107fc2d7f878ef135d9e5dd76af17ddbbd7 /remoting | |
parent | ee93d9728aa8effce2a6ebf1f42e13e0793b21c7 (diff) | |
download | chromium_src-0d1559665198c3281def9139b1cc3f4e3643a572.zip chromium_src-0d1559665198c3281def9139b1cc3f4e3643a572.tar.gz chromium_src-0d1559665198c3281def9139b1cc3f4e3643a572.tar.bz2 |
The video capturer now runs in a separate process.
Changes in this CL:
1. Introduces DesktopSessionProxy class wrapping the network end of the network-to-desktop IPC channel. The class provides a callable interface integrating the remote video capturer with the desktop enviroment object maintained by the networking code.
2. DesktopSessionProxy supports multiple "DesktopAttached" requests gacefully switching between desktop process instances.
3. DesktopSessionProxy uses shared buffers to pass video frames between processes.
BUG=134694
Review URL: https://chromiumcodereview.appspot.com/11417015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@169719 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/host/chromoting_messages.h | 5 | ||||
-rw-r--r-- | remoting/host/desktop_process.cc | 2 | ||||
-rw-r--r-- | remoting/host/desktop_session_agent.cc | 3 | ||||
-rw-r--r-- | remoting/host/desktop_session_agent.h | 11 | ||||
-rw-r--r-- | remoting/host/desktop_session_proxy.cc | 283 | ||||
-rw-r--r-- | remoting/host/desktop_session_proxy.h | 129 | ||||
-rw-r--r-- | remoting/host/ipc_desktop_environment.cc | 76 | ||||
-rw-r--r-- | remoting/host/ipc_desktop_environment.h | 19 | ||||
-rw-r--r-- | remoting/host/ipc_desktop_environment_factory.cc | 12 | ||||
-rw-r--r-- | remoting/host/ipc_desktop_environment_factory.h | 6 | ||||
-rw-r--r-- | remoting/host/ipc_video_frame_capturer.cc | 57 | ||||
-rw-r--r-- | remoting/host/ipc_video_frame_capturer.h | 54 | ||||
-rw-r--r-- | remoting/host/remoting_me2me_host.cc | 3 | ||||
-rw-r--r-- | remoting/host/video_frame_capturer.h | 2 | ||||
-rw-r--r-- | remoting/remoting.gyp | 4 |
15 files changed, 578 insertions, 88 deletions
diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h index c9a37f7..a39743e 100644 --- a/remoting/host/chromoting_messages.h +++ b/remoting/host/chromoting_messages.h @@ -94,7 +94,7 @@ IPC_MESSAGE_CONTROL1(ChromotingDesktopDaemonMsg_DesktopAttached, //----------------------------------------------------------------------------- // Chromoting messages sent from the desktop to the network process. -// Notifies the network process that a shared buffer has been created. Receiving +// Notifies the network process that a shared buffer has been created. Receipt // of this message must be confirmed by replying with // ChromotingNetworkDesktopMsg_SharedBufferCreated message. IPC_MESSAGE_CONTROL3(ChromotingDesktopNetworkMsg_CreateSharedBuffer, @@ -128,6 +128,9 @@ IPC_STRUCT_BEGIN(SerializedCapturedData) // ID of the shared memory buffer containing the pixels. IPC_STRUCT_MEMBER(int, shared_buffer_id) + // Width of a single row of pixels in bytes. + IPC_STRUCT_MEMBER(int, bytes_per_row) + // Captured region. IPC_STRUCT_MEMBER(std::vector<SkIRect>, dirty_region) diff --git a/remoting/host/desktop_process.cc b/remoting/host/desktop_process.cc index 6fcb4ff..ddab4da 100644 --- a/remoting/host/desktop_process.cc +++ b/remoting/host/desktop_process.cc @@ -49,8 +49,6 @@ void DesktopProcess::OnChannelConnected(int32 peer_pid) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); VLOG(1) << "IPC: desktop <- daemon (" << peer_pid << ")"; - - NOTIMPLEMENTED(); } void DesktopProcess::OnChannelError() { diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc index 56d7127..cb4b051 100644 --- a/remoting/host/desktop_session_agent.cc +++ b/remoting/host/desktop_session_agent.cc @@ -93,6 +93,7 @@ void DesktopSessionAgent::OnCaptureCompleted( // Serialize CaptureData SerializedCapturedData serialized_data; serialized_data.shared_buffer_id = capture_data->shared_buffer()->id(); + serialized_data.bytes_per_row = capture_data->data_planes().strides[0]; serialized_data.dimensions = capture_data->size(); serialized_data.pixel_format = capture_data->pixel_format(); serialized_data.capture_time_ms = capture_data->capture_time_ms(); @@ -118,6 +119,8 @@ bool DesktopSessionAgent::Start(const base::Closure& disconnected_task, DCHECK(caller_task_runner()->BelongsToCurrentThread()); disconnected_task_ = disconnected_task; + + // Create an IPC channel to communicate with the network process. if (!CreateChannelForNetworkProcess(desktop_pipe_out, &network_channel_)) return false; diff --git a/remoting/host/desktop_session_agent.h b/remoting/host/desktop_session_agent.h index 85ea314..a8d9303 100644 --- a/remoting/host/desktop_session_agent.h +++ b/remoting/host/desktop_session_agent.h @@ -95,12 +95,10 @@ class DesktopSessionAgent // Sends a message to the network process. void SendToNetwork(IPC::Message* message); - // Posted to |video_capture_task_runner_| task runner to start the video - // capturer. + // Posted to |video_capture_task_runner_| to start the video capturer. void StartVideoCapturer(); - // Posted to |video_capture_task_runner_| task runner to stop the video - // capturer. + // Posted to |video_capture_task_runner_| to stop the video capturer. void StopVideoCapturer(); // Getters providing access to the task runners for platform-specific derived @@ -121,10 +119,10 @@ class DesktopSessionAgent // Task runner on which public methods of this class should be called. scoped_refptr<AutoThreadTaskRunner> caller_task_runner_; - // Message loop used by the IPC channel. + // Task runner used by the IPC channel. scoped_refptr<AutoThreadTaskRunner> io_task_runner_; - // Task runner dedicated to running themethods of the video capturer. + // Task runner dedicated to running methods of |video_capturer_|. scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner_; // Runs on |caller_task_runner_| to notify the caller that the network-to- @@ -141,6 +139,7 @@ class DesktopSessionAgent typedef std::list<scoped_refptr<SharedBuffer> > SharedBuffers; SharedBuffers shared_buffers_; + // Captures the screen. scoped_ptr<VideoFrameCapturer> video_capturer_; DISALLOW_COPY_AND_ASSIGN(DesktopSessionAgent); diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc new file mode 100644 index 0000000..ef59c4d --- /dev/null +++ b/remoting/host/desktop_session_proxy.cc @@ -0,0 +1,283 @@ +// 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_session_proxy.h" + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/platform_file.h" +#include "base/single_thread_task_runner.h" +#include "ipc/ipc_channel_proxy.h" +#include "ipc/ipc_message_macros.h" +#include "remoting/base/capture_data.h" +#include "remoting/host/audio_capturer.h" +#include "remoting/host/chromoting_messages.h" +#include "remoting/host/ipc_video_frame_capturer.h" + +#if defined(OS_WIN) +#include "base/win/scoped_handle.h" +#endif // defined(OS_WIN) + +namespace remoting { + +DesktopSessionProxy::DesktopSessionProxy( + scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner) + : caller_task_runner_(caller_task_runner), + video_capture_task_runner_(video_capture_task_runner), + pending_capture_frame_requests_(0), + video_capturer_(NULL) { +} + +bool DesktopSessionProxy::OnMessageReceived(const IPC::Message& message) { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(DesktopSessionProxy, message) + IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_CaptureCompleted, + OnCaptureCompleted) + IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_CreateSharedBuffer, + OnCreateSharedBuffer) + IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_ReleaseSharedBuffer, + OnReleaseSharedBuffer) + IPC_END_MESSAGE_MAP() + + return handled; +} + +void DesktopSessionProxy::OnChannelConnected(int32 peer_pid) { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + + VLOG(1) << "IPC: network <- desktop (" << peer_pid << ")"; +} + +void DesktopSessionProxy::OnChannelError() { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + + Disconnect(); +} + +bool DesktopSessionProxy::Connect(IPC::PlatformFileForTransit desktop_process, + IPC::PlatformFileForTransit desktop_pipe) { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + DCHECK(!desktop_channel_); + +#if defined(OS_WIN) + // On Windows: |desktop_process| is a valid handle, but |desktop_pipe| needs + // to be duplicated from the desktop process. + desktop_process_.Set(desktop_process); + + base::win::ScopedHandle pipe; + if (!DuplicateHandle(desktop_process_, desktop_pipe, GetCurrentProcess(), + pipe.Receive(), 0, FALSE, DUPLICATE_SAME_ACCESS)) { + LOG_GETLASTERROR(ERROR) << "Failed to duplicate the desktop-to-network" + " pipe handle"; + return false; + } + + // Connect to the desktop process. + desktop_channel_.reset(new IPC::ChannelProxy(IPC::ChannelHandle(pipe), + IPC::Channel::MODE_CLIENT, + this, + caller_task_runner_)); +#elif defined(OS_POSIX) + // On posix: both |desktop_process| and |desktop_pipe| are valid file + // descriptors. + DCHECK(desktop_process.auto_close); + DCHECK(desktop_pipe.auto_close); + + base::ClosePlatformFile(desktop_process.fd); + + // Connect to the desktop process. + desktop_channel_.reset(new IPC::ChannelProxy( + IPC::ChannelHandle("", desktop_pipe), + IPC::Channel::MODE_CLIENT, + this, + caller_task_runner_)); +#else +#error Unsupported platform. +#endif + + return true; +} + +void DesktopSessionProxy::Disconnect() { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + + desktop_channel_.reset(); + +#if defined(OS_WIN) + desktop_process_.Close(); +#endif // defined(OS_WIN) + + shared_buffers_.clear(); + + // Generate fake responses to keep the video capturer in sync. + while (pending_capture_frame_requests_) { + --pending_capture_frame_requests_; + OnCaptureFrameCompleted(scoped_refptr<CaptureData>()); + } +} + +void DesktopSessionProxy::InvalidateRegion(const SkRegion& invalid_region) { + if (!caller_task_runner_->BelongsToCurrentThread()) { + caller_task_runner_->PostTask( + FROM_HERE, base::Bind(&DesktopSessionProxy::InvalidateRegion, this, + invalid_region)); + return; + } + + std::vector<SkIRect> invalid_rects; + for (SkRegion::Iterator i(invalid_region); !i.done(); i.next()) + invalid_rects.push_back(i.rect()); + + SendToDesktop( + new ChromotingNetworkDesktopMsg_InvalidateRegion(invalid_rects)); +} + +void DesktopSessionProxy::CaptureFrame() { + if (!caller_task_runner_->BelongsToCurrentThread()) { + caller_task_runner_->PostTask( + FROM_HERE, base::Bind(&DesktopSessionProxy::CaptureFrame, this)); + return; + } + + ++pending_capture_frame_requests_; + SendToDesktop(new ChromotingNetworkDesktopMsg_CaptureFrame()); +} + +void DesktopSessionProxy::StartVideoCapturer( + IpcVideoFrameCapturer* video_capturer) { + DCHECK(video_capture_task_runner_->BelongsToCurrentThread()); + DCHECK(video_capturer_ == NULL); + + video_capturer_ = video_capturer; +} + +void DesktopSessionProxy::StopVideoCapturer() { + DCHECK(video_capture_task_runner_->BelongsToCurrentThread()); + + video_capturer_ = NULL; +} + +DesktopSessionProxy::~DesktopSessionProxy() { +} + +scoped_refptr<SharedBuffer> DesktopSessionProxy::GetSharedBuffer(int id) { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + + SharedBuffers::const_iterator i = shared_buffers_.find(id); + if (i != shared_buffers_.end()) { + return i->second; + } else { + LOG(ERROR) << "Failed to find the shared buffer " << id; + return scoped_refptr<SharedBuffer>(); + } +} + +void DesktopSessionProxy::OnCreateSharedBuffer( + int id, + IPC::PlatformFileForTransit handle, + uint32 size) { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + + scoped_refptr<SharedBuffer> shared_buffer; + +#if defined(OS_WIN) + shared_buffer = new SharedBuffer(id, handle, desktop_process_, size); +#elif defined(OS_POSIX) + shared_buffer = new SharedBuffer(id, handle, size); +#else +#error Unsupported platform. +#endif + + // Check if the buffer has been successfully mapped. + bool mapped = shared_buffer->ptr() != NULL; + if (!mapped) { +#if defined(OS_WIN) + LOG(ERROR) << "Failed to map a shared buffer: id=" << id + << ", handle=" << handle + << ", size=" << size; +#elif defined(OS_POSIX) + LOG(ERROR) << "Failed to map a shared buffer: id=" << id + << ", handle.fd=" << handle.fd + << ", size=" << size; +#endif + } + + if (mapped && + !shared_buffers_.insert(std::make_pair(id, shared_buffer)).second) { + LOG(ERROR) << "Duplicate shared buffer id " << id << " encountered"; + } + + // Notify the desktop process that the buffer has been seen and can now be + // safely deleted if needed. + SendToDesktop(new ChromotingNetworkDesktopMsg_SharedBufferCreated(id)); +} + +void DesktopSessionProxy::OnReleaseSharedBuffer(int id) { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + + // Drop the cached reference to the buffer. + shared_buffers_.erase(id); +} + +void DesktopSessionProxy::OnCaptureCompleted( + const SerializedCapturedData& serialized_data) { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + + // Assume that |serialized_data| is well formed because it was received from + // a more privileged process. + scoped_refptr<CaptureData> capture_data; + scoped_refptr<SharedBuffer> shared_buffer = + GetSharedBuffer(serialized_data.shared_buffer_id); + CHECK(shared_buffer); + + DataPlanes planes; + planes.data[0] = reinterpret_cast<uint8*>(shared_buffer->ptr()); + planes.strides[0] = serialized_data.bytes_per_row; + + capture_data = new CaptureData( + planes, serialized_data.dimensions, + static_cast<media::VideoFrame::Format>(serialized_data.pixel_format)); + capture_data->set_capture_time_ms(serialized_data.capture_time_ms); + capture_data->set_client_sequence_number( + serialized_data.client_sequence_number); + capture_data->set_dpi(serialized_data.dpi); + capture_data->set_shared_buffer(shared_buffer); + + if (!serialized_data.dirty_region.empty()) { + capture_data->mutable_dirty_region().setRects( + &serialized_data.dirty_region[0], + serialized_data.dirty_region.size()); + } + + --pending_capture_frame_requests_; + OnCaptureFrameCompleted(capture_data); +} + +void DesktopSessionProxy::OnCaptureFrameCompleted( + scoped_refptr<CaptureData> capture_data) { + if (!video_capture_task_runner_->BelongsToCurrentThread()) { + video_capture_task_runner_->PostTask( + FROM_HERE, base::Bind(&DesktopSessionProxy::OnCaptureFrameCompleted, + this, capture_data)); + return; + } + + if (video_capturer_) + video_capturer_->OnCaptureCompleted(capture_data); +} + +void DesktopSessionProxy::SendToDesktop(IPC::Message* message) { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + + if (desktop_channel_) { + desktop_channel_->Send(message); + } else { + delete message; + } +} + +} // namespace remoting diff --git a/remoting/host/desktop_session_proxy.h b/remoting/host/desktop_session_proxy.h new file mode 100644 index 0000000..14b5b30 --- /dev/null +++ b/remoting/host/desktop_session_proxy.h @@ -0,0 +1,129 @@ +// 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_SESSION_PROXY_H_ +#define REMOTING_HOST_DESKTOP_SESSION_PROXY_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "ipc/ipc_listener.h" +#include "ipc/ipc_platform_file.h" +#include "remoting/base/shared_buffer.h" +#include "remoting/host/video_frame_capturer.h" +#include "third_party/skia/include/core/SkRegion.h" + +#if defined(OS_WIN) +#include "base/win/scoped_handle.h" +#endif + +namespace base { +class SingleThreadTaskRunner; +} // namespace base + +namespace IPC { +class ChannelProxy; +class Message; +} // namespace IPC + +struct SerializedCapturedData; + +namespace remoting { + +class IpcVideoFrameCapturer; + +// This class routes calls to the DesktopEnvironment's stubs though the IPC +// channel to the DesktopSessionAgent instance running in the desktop +// integration process. +class DesktopSessionProxy + : public base::RefCountedThreadSafe<DesktopSessionProxy>, + public IPC::Listener { + public: + DesktopSessionProxy( + scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner); + + // IPC::Listener implementation. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; + virtual void OnChannelError() OVERRIDE; + + // Connects to the desktop process. + bool Connect(IPC::PlatformFileForTransit desktop_process, + IPC::PlatformFileForTransit desktop_pipe); + + // Closes the connection to the desktop session agent and cleans up + // the associated resources. + void Disconnect(); + + // APIs used to implement the VideoFrameCapturer interface. These must be + // called on |video_capture_task_runner_|. + void InvalidateRegion(const SkRegion& invalid_region); + void CaptureFrame(); + + // Stores |video_capturer| to be used to post captured video frames. + // |video_capturer| must be valid until StopVideoCapturer() is called. + void StartVideoCapturer(IpcVideoFrameCapturer* video_capturer); + + // Clears the cached pointer to the video capturer. Any frames captured after + // StopVideoCapturer() has been called will be silently dropped. + void StopVideoCapturer(); + + private: + friend class base::RefCountedThreadSafe<DesktopSessionProxy>; + virtual ~DesktopSessionProxy(); + + // Returns a shared buffer from the list of known buffers. + scoped_refptr<SharedBuffer> GetSharedBuffer(int id); + + // Registers a new shared buffer created by the desktop process. + void OnCreateSharedBuffer(int id, + IPC::PlatformFileForTransit handle, + uint32 size); + + // Drops a cached reference to the shared buffer. + void OnReleaseSharedBuffer(int id); + + // Handles CaptureCompleted notification from the desktop session agent. + void OnCaptureCompleted(const SerializedCapturedData& serialized_data); + + // Posted to |video_capture_task_runner_| to pass a captured video frame back + // to |video_capturer_|. + void OnCaptureFrameCompleted(scoped_refptr<CaptureData> capture_data); + + // Sends a message to the desktop session agent. The message is silently + // deleted if the channel is broken. + void SendToDesktop(IPC::Message* message); + + // Task runner on which public methods of this class should be called (unless + // it is documented otherwise). + scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; + + // Task runner on which |video_capturer_delegate_| will be invoked. + scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner_; + + // IPC channel to the desktop session agent. + scoped_ptr<IPC::ChannelProxy> desktop_channel_; + +#if defined(OS_WIN) + // Handle of the desktop process. + base::win::ScopedHandle desktop_process_; +#endif // defined(OS_WIN) + + int pending_capture_frame_requests_; + + typedef std::map<int, scoped_refptr<SharedBuffer> > SharedBuffers; + SharedBuffers shared_buffers_; + + // Points to the video capturer receiving captured video frames. + IpcVideoFrameCapturer* video_capturer_; + + DISALLOW_COPY_AND_ASSIGN(DesktopSessionProxy); +}; + +} // namespace remoting + +#endif // REMOTING_HOST_DESKTOP_SESSION_PROXY_H_ diff --git a/remoting/host/ipc_desktop_environment.cc b/remoting/host/ipc_desktop_environment.cc index 9d52be7..57fc3f2 100644 --- a/remoting/host/ipc_desktop_environment.cc +++ b/remoting/host/ipc_desktop_environment.cc @@ -9,10 +9,15 @@ #include "base/platform_file.h" #include "base/single_thread_task_runner.h" #include "ipc/ipc_channel_proxy.h" +#include "ipc/ipc_message_macros.h" +#include "remoting/base/capture_data.h" #include "remoting/host/audio_capturer.h" +#include "remoting/host/chromoting_messages.h" #include "remoting/host/client_session.h" #include "remoting/host/desktop_session_connector.h" +#include "remoting/host/desktop_session_proxy.h" #include "remoting/host/event_executor.h" +#include "remoting/host/ipc_video_frame_capturer.h" #include "remoting/host/video_frame_capturer.h" #if defined(OS_WIN) @@ -26,34 +31,25 @@ IpcDesktopEnvironment::IpcDesktopEnvironment( scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, DesktopSessionConnector* desktop_session_connector, + scoped_refptr<DesktopSessionProxy> desktop_session_proxy, ClientSession* client) : DesktopEnvironment( AudioCapturer::Create(), EventExecutor::Create(input_task_runner, ui_task_runner), - VideoFrameCapturer::Create()), + scoped_ptr<VideoFrameCapturer>( + new IpcVideoFrameCapturer(desktop_session_proxy))), network_task_runner_(network_task_runner), desktop_session_connector_(desktop_session_connector), client_(client), + desktop_session_proxy_(desktop_session_proxy), connected_(false) { } -bool IpcDesktopEnvironment::OnMessageReceived(const IPC::Message& message) { - DCHECK(network_task_runner_->BelongsToCurrentThread()); - - NOTIMPLEMENTED(); - return false; -} - -void IpcDesktopEnvironment::OnChannelConnected(int32 peer_pid) { - DCHECK(network_task_runner_->BelongsToCurrentThread()); - - VLOG(1) << "IPC: network <- desktop (" << peer_pid << ")"; -} - -void IpcDesktopEnvironment::OnChannelError() { - DCHECK(network_task_runner_->BelongsToCurrentThread()); - - desktop_channel_.reset(); +IpcDesktopEnvironment::~IpcDesktopEnvironment() { + if (connected_) { + connected_ = false; + desktop_session_connector_->DisconnectTerminal(this); + } } void IpcDesktopEnvironment::Start( @@ -78,48 +74,8 @@ void IpcDesktopEnvironment::OnDesktopSessionAgentAttached( IPC::PlatformFileForTransit desktop_pipe) { DCHECK(network_task_runner_->BelongsToCurrentThread()); -#if defined(OS_WIN) - // On Windows: |desktop_process| is a valid handle, but |desktop_pipe| needs - // to be duplicated from the desktop process. - base::win::ScopedHandle pipe; - if (!DuplicateHandle(desktop_process, desktop_pipe, GetCurrentProcess(), - pipe.Receive(), 0, FALSE, DUPLICATE_SAME_ACCESS)) { - LOG_GETLASTERROR(ERROR) << "Failed to duplicate the desktop-to-network" - " pipe handle"; - return; - } - - base::ClosePlatformFile(desktop_process); - - // Connect to the desktop process. - desktop_channel_.reset(new IPC::ChannelProxy(IPC::ChannelHandle(pipe), - IPC::Channel::MODE_CLIENT, - this, - network_task_runner_)); -#elif defined(OS_POSIX) - // On posix: both |desktop_process| and |desktop_pipe| are valid file - // descriptors. - DCHECK(desktop_process.auto_close); - DCHECK(desktop_pipe.auto_close); - - base::ClosePlatformFile(desktop_process.fd); - - // Connect to the desktop process. - desktop_channel_.reset(new IPC::ChannelProxy( - IPC::ChannelHandle("", desktop_pipe), - IPC::Channel::MODE_CLIENT, - this, - network_task_runner_)); -#else -#error Unsupported platform. -#endif -} - -IpcDesktopEnvironment::~IpcDesktopEnvironment() { - if (connected_) { - connected_ = false; - desktop_session_connector_->DisconnectTerminal(this); - } + desktop_session_proxy_->Disconnect(); + desktop_session_proxy_->Connect(desktop_process, desktop_pipe); } } // namespace remoting diff --git a/remoting/host/ipc_desktop_environment.h b/remoting/host/ipc_desktop_environment.h index d65495fb..8ec721b 100644 --- a/remoting/host/ipc_desktop_environment.h +++ b/remoting/host/ipc_desktop_environment.h @@ -8,7 +8,6 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "ipc/ipc_listener.h" #include "ipc/ipc_platform_file.h" #include "remoting/host/desktop_environment.h" @@ -16,18 +15,15 @@ namespace base { class SingleThreadTaskRunner; } // base -namespace IPC { -class ChannelProxy; -} // base - namespace remoting { class ClientSession; class DesktopSessionConnector; +class DesktopSessionProxy; // A variant of desktop environment integrating with the desktop by means of // a helper process and talking to that process via IPC. -class IpcDesktopEnvironment : public DesktopEnvironment, public IPC::Listener { +class IpcDesktopEnvironment : public DesktopEnvironment { public: // |desktop_session_connector| is used to bind the IpcDesktopEnvironment to // a desktop session, to be notified with a new IPC channel every time @@ -38,14 +34,10 @@ class IpcDesktopEnvironment : public DesktopEnvironment, public IPC::Listener { scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, DesktopSessionConnector* desktop_session_connector, + scoped_refptr<DesktopSessionProxy> desktop_session_proxy, ClientSession* client); virtual ~IpcDesktopEnvironment(); - // IPC::Listener implementation. - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; - virtual void OnChannelError() OVERRIDE; - virtual void Start( scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; @@ -68,12 +60,11 @@ class IpcDesktopEnvironment : public DesktopEnvironment, public IPC::Listener { // Specifies the client session that owns |this|. ClientSession* client_; + scoped_refptr<DesktopSessionProxy> desktop_session_proxy_; + // True if |this| has been connected to a desktop session. bool connected_; - // Connects |this| with the desktop process. - scoped_ptr<IPC::ChannelProxy> desktop_channel_; - DISALLOW_COPY_AND_ASSIGN(IpcDesktopEnvironment); }; diff --git a/remoting/host/ipc_desktop_environment_factory.cc b/remoting/host/ipc_desktop_environment_factory.cc index 6adef35..927c168 100644 --- a/remoting/host/ipc_desktop_environment_factory.cc +++ b/remoting/host/ipc_desktop_environment_factory.cc @@ -13,6 +13,7 @@ #include "remoting/host/chromoting_host_context.h" #include "remoting/host/chromoting_messages.h" #include "remoting/host/desktop_session_connector.h" +#include "remoting/host/desktop_session_proxy.h" #include "remoting/host/event_executor.h" #include "remoting/host/ipc_desktop_environment.h" #include "remoting/host/video_frame_capturer.h" @@ -23,10 +24,12 @@ IpcDesktopEnvironmentFactory::IpcDesktopEnvironmentFactory( IPC::ChannelProxy* daemon_channel, scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner) : DesktopEnvironmentFactory(input_task_runner, ui_task_runner), daemon_channel_(daemon_channel), network_task_runner_(network_task_runner), + video_capture_task_runner_(video_capture_task_runner), next_id_(0) { } @@ -37,8 +40,13 @@ scoped_ptr<DesktopEnvironment> IpcDesktopEnvironmentFactory::Create( ClientSession* client) { DCHECK(network_task_runner_->BelongsToCurrentThread()); + scoped_refptr<DesktopSessionProxy> desktop_session_proxy( + new DesktopSessionProxy(network_task_runner_, + video_capture_task_runner_)); + return scoped_ptr<DesktopEnvironment>(new IpcDesktopEnvironment( - input_task_runner_, network_task_runner_, ui_task_runner_, this, client)); + input_task_runner_, network_task_runner_, ui_task_runner_, + this, desktop_session_proxy, client)); } void IpcDesktopEnvironmentFactory::ConnectTerminal( diff --git a/remoting/host/ipc_desktop_environment_factory.h b/remoting/host/ipc_desktop_environment_factory.h index e0c7fd8..2b0ebfe 100644 --- a/remoting/host/ipc_desktop_environment_factory.h +++ b/remoting/host/ipc_desktop_environment_factory.h @@ -32,7 +32,8 @@ class IpcDesktopEnvironmentFactory IPC::ChannelProxy* daemon_channel, scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner); virtual ~IpcDesktopEnvironmentFactory(); virtual scoped_ptr<DesktopEnvironment> Create(ClientSession* client) OVERRIDE; @@ -55,6 +56,9 @@ class IpcDesktopEnvironmentFactory // Task runner used to service calls to the DesktopSessionConnector APIs. scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_; + // Task runner used to run the video capturer. + scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner_; + // List of DesktopEnvironment instances we've told the daemon process about. typedef std::map<int, IpcDesktopEnvironment*> ActiveConnectionsList; ActiveConnectionsList active_connections_; diff --git a/remoting/host/ipc_video_frame_capturer.cc b/remoting/host/ipc_video_frame_capturer.cc new file mode 100644 index 0000000..801787d --- /dev/null +++ b/remoting/host/ipc_video_frame_capturer.cc @@ -0,0 +1,57 @@ +// 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/ipc_video_frame_capturer.h" + +#include "remoting/base/capture_data.h" +#include "remoting/host/desktop_session_proxy.h" + +namespace remoting { + +IpcVideoFrameCapturer::IpcVideoFrameCapturer( + scoped_refptr<DesktopSessionProxy> desktop_session_proxy) + : delegate_(NULL), + desktop_session_proxy_(desktop_session_proxy), + size_most_recent_(SkISize::Make(0, 0)) { +} + +IpcVideoFrameCapturer::~IpcVideoFrameCapturer() { +} + +void IpcVideoFrameCapturer::Start(Delegate* delegate) { + delegate_ = delegate; + desktop_session_proxy_->StartVideoCapturer(this); +} + +void IpcVideoFrameCapturer::Stop() { + desktop_session_proxy_->StopVideoCapturer(); + delegate_ = NULL; +} + +media::VideoFrame::Format IpcVideoFrameCapturer::pixel_format() const { + return media::VideoFrame::RGB32; +} + +void IpcVideoFrameCapturer::InvalidateRegion(const SkRegion& invalid_region) { + desktop_session_proxy_->InvalidateRegion(invalid_region); +} + +void IpcVideoFrameCapturer::CaptureInvalidRegion() { + desktop_session_proxy_->CaptureFrame(); +} + +const SkISize& IpcVideoFrameCapturer::size_most_recent() const { + return size_most_recent_; +} + +void IpcVideoFrameCapturer::OnCaptureCompleted( + scoped_refptr<CaptureData> capture_data) { + if (capture_data) + size_most_recent_ = capture_data->size(); + + if (delegate_) + delegate_->OnCaptureCompleted(capture_data); +} + +} // namespace remoting diff --git a/remoting/host/ipc_video_frame_capturer.h b/remoting/host/ipc_video_frame_capturer.h new file mode 100644 index 0000000..75ac5ee --- /dev/null +++ b/remoting/host/ipc_video_frame_capturer.h @@ -0,0 +1,54 @@ +// 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_IPC_VIDEO_FRAME_CAPTURER_H_ +#define REMOTING_HOST_IPC_VIDEO_FRAME_CAPTURER_H_ + +#include "base/memory/ref_counted.h" +#include "remoting/host/video_frame_capturer.h" + +namespace IPC { +class Message; +} // IPC + +namespace remoting { + +class DesktopSessionProxy; + +// Routes VideoFrameCapturer calls though the IPC channel to the desktop session +// agent running in the desktop integration process. +class IpcVideoFrameCapturer : public VideoFrameCapturer { + public: + explicit IpcVideoFrameCapturer( + scoped_refptr<DesktopSessionProxy> desktop_session_proxy); + virtual ~IpcVideoFrameCapturer(); + + // VideoFrameCapturer interface. + virtual void Start(Delegate* delegate) OVERRIDE; + virtual void Stop() OVERRIDE; + virtual media::VideoFrame::Format pixel_format() const OVERRIDE; + virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; + virtual void CaptureInvalidRegion() OVERRIDE; + virtual const SkISize& size_most_recent() const OVERRIDE; + + // Called when a video frame has been captured. |capture_data| describes + // a captured frame. + void OnCaptureCompleted(scoped_refptr<CaptureData> capture_data); + + private: + // Points to the delegate passed to VideoFrameCapturer::Start(). + VideoFrameCapturer::Delegate* delegate_; + + // Wraps the IPC channel to the desktop session agent. + scoped_refptr<DesktopSessionProxy> desktop_session_proxy_; + + // Size of the most recent captured frame. + SkISize size_most_recent_; + + DISALLOW_COPY_AND_ASSIGN(IpcVideoFrameCapturer); +}; + +} // namespace remoting + +#endif // REMOTING_HOST_IPC_VIDEO_FRAME_CAPTURER_H_ diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc index 1ae5d45..8cfdc5f 100644 --- a/remoting/host/remoting_me2me_host.cc +++ b/remoting/host/remoting_me2me_host.cc @@ -562,7 +562,8 @@ void HostProcess::StartOnUiThread() { daemon_channel_.get(), context_->input_task_runner(), context_->network_task_runner(), - context_->ui_task_runner()); + context_->ui_task_runner(), + context_->video_capture_task_runner()); desktop_session_connector_ = desktop_environment_factory; #else // !defined(REMOTING_MULTI_PROCESS) DesktopEnvironmentFactory* desktop_environment_factory = diff --git a/remoting/host/video_frame_capturer.h b/remoting/host/video_frame_capturer.h index acf8152..018abf3 100644 --- a/remoting/host/video_frame_capturer.h +++ b/remoting/host/video_frame_capturer.h @@ -58,7 +58,7 @@ class VideoFrameCapturer { public: virtual ~Delegate() {} - // Called when the capturer has completed. |capture_data| describes + // Called when a video frame has been captured. |capture_data| describes // a captured frame. virtual void OnCaptureCompleted( scoped_refptr<CaptureData> capture_data) = 0; diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index 200d96e..5b47447 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -1548,6 +1548,8 @@ 'host/desktop_resizer_win.cc', 'host/desktop_resizer_mac.cc', 'host/desktop_session_connector.h', + 'host/desktop_session_proxy.cc', + 'host/desktop_session_proxy.h', 'host/differ.cc', 'host/differ.h', 'host/disconnect_window.h', @@ -1587,6 +1589,8 @@ 'host/ipc_desktop_environment_factory.h', 'host/ipc_desktop_environment.cc', 'host/ipc_desktop_environment.h', + 'host/ipc_video_frame_capturer.cc', + 'host/ipc_video_frame_capturer.h', 'host/it2me_host_user_interface.cc', 'host/it2me_host_user_interface.h', 'host/json_host_config.cc', |