diff options
author | dcaiafa@chromium.org <dcaiafa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-29 15:05:16 +0000 |
---|---|---|
committer | dcaiafa@chromium.org <dcaiafa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-29 15:05:16 +0000 |
commit | 4a32f9821e9df919d482558c148089a2221b19f0 (patch) | |
tree | 3c10aba84b0f70783604fc18a6df1aabd3382ccb | |
parent | d35cd7b26ab76fee5a42eeaec4a9538265a490e3 (diff) | |
download | chromium_src-4a32f9821e9df919d482558c148089a2221b19f0.zip chromium_src-4a32f9821e9df919d482558c148089a2221b19f0.tar.gz chromium_src-4a32f9821e9df919d482558c148089a2221b19f0.tar.bz2 |
Use webrtc::MouseCursorMonitor for cursor shapes
Use webrtc::MouseCursorMonitor for cursor shapes instead of
webrtc::VideoFrameCapturer, in preparation for deprecating cursor shape
functionality in the latter.
BUG=324033
Review URL: https://codereview.chromium.org/92473002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247689 0039d316-1c4b-4281-b951-d872f2087c98
28 files changed, 485 insertions, 78 deletions
diff --git a/remoting/host/basic_desktop_environment.cc b/remoting/host/basic_desktop_environment.cc index 7698ca8..142482d4 100644 --- a/remoting/host/basic_desktop_environment.cc +++ b/remoting/host/basic_desktop_environment.cc @@ -11,6 +11,8 @@ #include "remoting/host/client_session_control.h" #include "remoting/host/input_injector.h" #include "remoting/host/screen_controls.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h" #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" namespace remoting { @@ -37,6 +39,14 @@ scoped_ptr<ScreenControls> BasicDesktopEnvironment::CreateScreenControls() { return scoped_ptr<ScreenControls>(); } +scoped_ptr<webrtc::MouseCursorMonitor> +BasicDesktopEnvironment::CreateMouseCursorMonitor() { + return scoped_ptr<webrtc::MouseCursorMonitor>( + webrtc::MouseCursorMonitor::CreateForScreen( + *desktop_capture_options_, + webrtc::kFullDesktopScreenId)); +} + std::string BasicDesktopEnvironment::GetCapabilities() const { return std::string(); } @@ -50,7 +60,8 @@ BasicDesktopEnvironment::CreateVideoCapturer() { // The basic desktop environment does not use X DAMAGE, since it is // broken on many systems - see http://crbug.com/73423. - return scoped_ptr<webrtc::ScreenCapturer>(webrtc::ScreenCapturer::Create()); + return scoped_ptr<webrtc::ScreenCapturer>( + webrtc::ScreenCapturer::Create(*desktop_capture_options_)); } BasicDesktopEnvironment::BasicDesktopEnvironment( @@ -59,7 +70,10 @@ BasicDesktopEnvironment::BasicDesktopEnvironment( scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) : caller_task_runner_(caller_task_runner), input_task_runner_(input_task_runner), - ui_task_runner_(ui_task_runner) { + ui_task_runner_(ui_task_runner), + desktop_capture_options_( + new webrtc::DesktopCaptureOptions( + webrtc::DesktopCaptureOptions::CreateDefault())) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); } diff --git a/remoting/host/basic_desktop_environment.h b/remoting/host/basic_desktop_environment.h index dbc9822..51ea7af 100644 --- a/remoting/host/basic_desktop_environment.h +++ b/remoting/host/basic_desktop_environment.h @@ -13,6 +13,12 @@ #include "base/memory/scoped_ptr.h" #include "remoting/host/desktop_environment.h" +namespace webrtc { + +class DesktopCaptureOptions; + +} // namespace webrtc + namespace remoting { // Used to create audio/video capturers and event executor that work with @@ -26,6 +32,8 @@ class BasicDesktopEnvironment : public DesktopEnvironment { virtual scoped_ptr<InputInjector> CreateInputInjector() OVERRIDE; virtual scoped_ptr<ScreenControls> CreateScreenControls() OVERRIDE; virtual scoped_ptr<webrtc::ScreenCapturer> CreateVideoCapturer() OVERRIDE; + virtual scoped_ptr<webrtc::MouseCursorMonitor> CreateMouseCursorMonitor() + OVERRIDE; virtual std::string GetCapabilities() const OVERRIDE; virtual void SetCapabilities(const std::string& capabilities) OVERRIDE; @@ -49,6 +57,10 @@ class BasicDesktopEnvironment : public DesktopEnvironment { return ui_task_runner_; } + webrtc::DesktopCaptureOptions* desktop_capture_options() { + return desktop_capture_options_.get(); + } + private: // Task runner on which methods of DesktopEnvironment interface should be // called. @@ -60,6 +72,13 @@ class BasicDesktopEnvironment : public DesktopEnvironment { // Used to run UI code. scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; + // Options shared between |ScreenCapturer| and |MouseCursorMonitor|. It + // might contain expensive resources, thus justifying the sharing. + // Also: it's dynamically allocated to avoid having to bring in + // desktop_capture_options.h which brings in X11 headers which causes hard to + // find build errors. + scoped_ptr<webrtc::DesktopCaptureOptions> desktop_capture_options_; + DISALLOW_COPY_AND_ASSIGN(BasicDesktopEnvironment); }; diff --git a/remoting/host/chromoting_host_unittest.cc b/remoting/host/chromoting_host_unittest.cc index 1410371..7e5f599 100644 --- a/remoting/host/chromoting_host_unittest.cc +++ b/remoting/host/chromoting_host_unittest.cc @@ -245,6 +245,9 @@ class ChromotingHostTest : public testing::Test { EXPECT_CALL(*desktop_environment, CreateVideoCapturerPtr()) .Times(AtMost(1)) .WillOnce(Invoke(this, &ChromotingHostTest::CreateVideoCapturer)); + EXPECT_CALL(*desktop_environment, CreateMouseCursorMonitorPtr()) + .Times(AtMost(1)) + .WillOnce(Invoke(this, &ChromotingHostTest::CreateMouseCursorMonitor)); EXPECT_CALL(*desktop_environment, GetCapabilities()) .Times(AtMost(1)); EXPECT_CALL(*desktop_environment, SetCapabilities(_)) @@ -267,6 +270,12 @@ class ChromotingHostTest : public testing::Test { return new ScreenCapturerFake(); } + // Creates a MockMouseCursorMonitor, to mock + // DesktopEnvironment::CreateMouseCursorMonitor(). + webrtc::MouseCursorMonitor* CreateMouseCursorMonitor() { + return new MockMouseCursorMonitor(); + } + void DisconnectAllClients() { host_->DisconnectAllClients(); } diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h index e56b0f3..46a8be7 100644 --- a/remoting/host/chromoting_messages.h +++ b/remoting/host/chromoting_messages.h @@ -138,12 +138,6 @@ IPC_MESSAGE_CONTROL3(ChromotingDesktopNetworkMsg_CreateSharedBuffer, IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_ReleaseSharedBuffer, int /* id */) -IPC_STRUCT_TRAITS_BEGIN(webrtc::MouseCursorShape) - IPC_STRUCT_TRAITS_MEMBER(size) - IPC_STRUCT_TRAITS_MEMBER(hotspot) - IPC_STRUCT_TRAITS_MEMBER(data) -IPC_STRUCT_TRAITS_END() - // Serialized webrtc::DesktopFrame. IPC_STRUCT_BEGIN(SerializedDesktopFrame) // ID of the shared memory buffer containing the pixels. @@ -173,8 +167,8 @@ IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_CaptureCompleted, SerializedDesktopFrame /* frame */ ) // Carries a cursor share update from the desktop session agent to the client. -IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_CursorShapeChanged, - webrtc::MouseCursorShape /* cursor_shape */ ) +IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_MouseCursor, + webrtc::MouseCursor /* cursor */ ) // Carries a clipboard event from the desktop session agent to the client. // |serialized_event| is a serialized protocol::ClipboardEvent. diff --git a/remoting/host/chromoting_param_traits.cc b/remoting/host/chromoting_param_traits.cc index 8b10a7f..8050dc1 100644 --- a/remoting/host/chromoting_param_traits.cc +++ b/remoting/host/chromoting_param_traits.cc @@ -5,6 +5,7 @@ #include "remoting/host/chromoting_param_traits.h" #include "base/strings/stringprintf.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" namespace IPC { @@ -88,6 +89,72 @@ void ParamTraits<webrtc::DesktopRect>::Log(const webrtc::DesktopRect& p, } // static +void ParamTraits<webrtc::MouseCursor>::Write( + Message* m, + const webrtc::MouseCursor& p) { + ParamTraits<webrtc::DesktopSize>::Write(m, p.image()->size()); + + // Data is serialized in such a way that size is exactly width * height * + // |kBytesPerPixel|. + std::string data; + uint8_t* current_row = p.image()->data(); + for (int y = 0; y < p.image()->size().height(); ++y) { + data.append(current_row, + current_row + p.image()->size().width() * + webrtc::DesktopFrame::kBytesPerPixel); + current_row += p.image()->stride(); + } + m->WriteData(reinterpret_cast<const char*>(p.image()->data()), data.size()); + + ParamTraits<webrtc::DesktopVector>::Write(m, p.hotspot()); +} + +// static +bool ParamTraits<webrtc::MouseCursor>::Read( + const Message* m, + PickleIterator* iter, + webrtc::MouseCursor* r) { + webrtc::DesktopSize size; + if (!ParamTraits<webrtc::DesktopSize>::Read(m, iter, &size) || + size.width() <= 0 || size.width() > (SHRT_MAX / 2) || + size.height() <= 0 || size.height() > (SHRT_MAX / 2)) { + return false; + } + + const int expected_length = + size.width() * size.height() * webrtc::DesktopFrame::kBytesPerPixel; + + const char* data; + int data_length; + if (!m->ReadData(iter, &data, &data_length) || + data_length != expected_length) { + return false; + } + + webrtc::DesktopVector hotspot; + if (!ParamTraits<webrtc::DesktopVector>::Read(m, iter, &hotspot)) + return false; + + webrtc::BasicDesktopFrame* image = new webrtc::BasicDesktopFrame(size); + memcpy(image->data(), data, data_length); + + r->set_image(image); + r->set_hotspot(hotspot); + return true; +} + +// static +void ParamTraits<webrtc::MouseCursor>::Log( + const webrtc::MouseCursor& p, + std::string* l) { + l->append(base::StringPrintf( + "webrtc::DesktopRect{image(%d, %d), hotspot(%d, %d)}", + p.image()->size().width(), p.image()->size().height(), + p.hotspot().x(), p.hotspot().y())); +} + + +// static void ParamTraits<remoting::ScreenResolution>::Write( Message* m, const remoting::ScreenResolution& p) { diff --git a/remoting/host/chromoting_param_traits.h b/remoting/host/chromoting_param_traits.h index 7925918..35ca3bc 100644 --- a/remoting/host/chromoting_param_traits.h +++ b/remoting/host/chromoting_param_traits.h @@ -8,7 +8,9 @@ #include "ipc/ipc_message.h" #include "ipc/ipc_param_traits.h" #include "remoting/host/screen_resolution.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor.h" namespace IPC { @@ -37,6 +39,14 @@ struct ParamTraits<webrtc::DesktopRect> { }; template <> +struct ParamTraits<webrtc::MouseCursor> { + typedef webrtc::MouseCursor param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template <> struct ParamTraits<remoting::ScreenResolution> { typedef remoting::ScreenResolution param_type; static void Write(Message* m, const param_type& p); diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc index 52feba7..68528c5 100644 --- a/remoting/host/client_session.cc +++ b/remoting/host/client_session.cc @@ -273,6 +273,7 @@ void ClientSession::OnConnectionAuthenticated( video_encode_task_runner_, network_task_runner_, desktop_environment_->CreateVideoCapturer(), + desktop_environment_->CreateMouseCursorMonitor(), video_encoder.Pass(), connection_->client_stub(), &mouse_clamping_filter_); diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc index 7cd21ee..d390cd6 100644 --- a/remoting/host/client_session_unittest.cc +++ b/remoting/host/client_session_unittest.cc @@ -83,6 +83,10 @@ class ClientSessionTest : public testing::Test { // DesktopEnvironment::CreateVideoCapturer(). webrtc::ScreenCapturer* CreateVideoCapturer(); + // Creates a MockMouseCursorMonitor, to mock + // DesktopEnvironment::CreateMouseCursorMonitor + webrtc::MouseCursorMonitor* CreateMouseCursorMonitor(); + // Notifies the client session that the client connection has been // authenticated and channels have been connected. This effectively enables // the input pipe line and starts video capturing. @@ -198,6 +202,8 @@ DesktopEnvironment* ClientSessionTest::CreateDesktopEnvironment() { .Times(AtMost(1)); EXPECT_CALL(*desktop_environment, CreateVideoCapturerPtr()) .WillOnce(Invoke(this, &ClientSessionTest::CreateVideoCapturer)); + EXPECT_CALL(*desktop_environment, CreateMouseCursorMonitorPtr()) + .WillOnce(Invoke(this, &ClientSessionTest::CreateMouseCursorMonitor)); EXPECT_CALL(*desktop_environment, GetCapabilities()) .Times(AtMost(1)); EXPECT_CALL(*desktop_environment, SetCapabilities(_)) @@ -215,6 +221,10 @@ webrtc::ScreenCapturer* ClientSessionTest::CreateVideoCapturer() { return new ScreenCapturerFake(); } +webrtc::MouseCursorMonitor* ClientSessionTest::CreateMouseCursorMonitor() { + return new MockMouseCursorMonitor(); +} + void ClientSessionTest::ConnectClientSession() { client_session_->OnConnectionAuthenticated(client_session_->connection()); client_session_->OnConnectionChannelsConnected(client_session_->connection()); diff --git a/remoting/host/desktop_environment.h b/remoting/host/desktop_environment.h index 1fa9ccd..c942cb4 100644 --- a/remoting/host/desktop_environment.h +++ b/remoting/host/desktop_environment.h @@ -19,6 +19,7 @@ class SingleThreadTaskRunner; namespace webrtc { class ScreenCapturer; +class MouseCursorMonitor; } // namespace webrtc namespace remoting { @@ -40,6 +41,7 @@ class DesktopEnvironment { virtual scoped_ptr<InputInjector> CreateInputInjector() = 0; virtual scoped_ptr<ScreenControls> CreateScreenControls() = 0; virtual scoped_ptr<webrtc::ScreenCapturer> CreateVideoCapturer() = 0; + virtual scoped_ptr<webrtc::MouseCursorMonitor> CreateMouseCursorMonitor() = 0; // Returns the set of all capabilities supported by |this|. virtual std::string GetCapabilities() const = 0; diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc index 1597765..3fd1299 100644 --- a/remoting/host/desktop_session_agent.cc +++ b/remoting/host/desktop_session_agent.cc @@ -27,6 +27,7 @@ #include "remoting/protocol/input_event_tracker.h" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor.h" #include "third_party/webrtc/modules/desktop_capture/shared_memory.h" namespace remoting { @@ -292,10 +293,12 @@ void DesktopSessionAgent::OnStartSessionAgent( FROM_HERE, base::Bind(&DesktopSessionAgent::StartAudioCapturer, this)); } - // Start the video capturer. + // Start the video capturer and mouse cursor monitor. video_capturer_ = desktop_environment_->CreateVideoCapturer(); + mouse_cursor_monitor_ = desktop_environment_->CreateMouseCursorMonitor(); video_capture_task_runner_->PostTask( - FROM_HERE, base::Bind(&DesktopSessionAgent::StartVideoCapturer, this)); + FROM_HERE, base::Bind( + &DesktopSessionAgent::StartVideoCapturerAndMouseMonitor, this)); } void DesktopSessionAgent::OnCaptureCompleted(webrtc::DesktopFrame* frame) { @@ -321,14 +324,20 @@ void DesktopSessionAgent::OnCaptureCompleted(webrtc::DesktopFrame* frame) { new ChromotingDesktopNetworkMsg_CaptureCompleted(serialized_frame)); } -void DesktopSessionAgent::OnCursorShapeChanged( - webrtc::MouseCursorShape* cursor_shape) { +void DesktopSessionAgent::OnMouseCursor(webrtc::MouseCursor* cursor) { DCHECK(video_capture_task_runner_->BelongsToCurrentThread()); - scoped_ptr<webrtc::MouseCursorShape> owned_cursor(cursor_shape); + scoped_ptr<webrtc::MouseCursor> owned_cursor(cursor); - SendToNetwork(new ChromotingDesktopNetworkMsg_CursorShapeChanged( - *cursor_shape)); + SendToNetwork( + new ChromotingDesktopNetworkMsg_MouseCursor(*owned_cursor)); +} + +void DesktopSessionAgent::OnMouseCursorPosition( + webrtc::MouseCursorMonitor::CursorState state, + const webrtc::DesktopVector& position) { + // We're not subscribing to mouse position changes. + NOTREACHED(); } void DesktopSessionAgent::InjectClipboardEvent( @@ -404,7 +413,8 @@ void DesktopSessionAgent::Stop() { // Stop the video capturer. video_capture_task_runner_->PostTask( - FROM_HERE, base::Bind(&DesktopSessionAgent::StopVideoCapturer, this)); + FROM_HERE, base::Bind( + &DesktopSessionAgent::StopVideoCapturerAndMouseMonitor, this)); } } @@ -416,6 +426,8 @@ void DesktopSessionAgent::OnCaptureFrame() { return; } + mouse_cursor_monitor_->Capture(); + // webrtc::ScreenCapturer supports a very few (currently 2) outstanding // capture requests. The requests are serialized on // |video_capture_task_runner()| task runner. If the client issues more @@ -512,20 +524,24 @@ void DesktopSessionAgent::StopAudioCapturer() { audio_capturer_.reset(); } -void DesktopSessionAgent::StartVideoCapturer() { +void DesktopSessionAgent::StartVideoCapturerAndMouseMonitor() { DCHECK(video_capture_task_runner_->BelongsToCurrentThread()); if (video_capturer_) { - video_capturer_->SetMouseShapeObserver(this); video_capturer_->Start(this); } + + if (mouse_cursor_monitor_) { + mouse_cursor_monitor_->Init(this, webrtc::MouseCursorMonitor::SHAPE_ONLY); + } } -void DesktopSessionAgent::StopVideoCapturer() { +void DesktopSessionAgent::StopVideoCapturerAndMouseMonitor() { DCHECK(video_capture_task_runner_->BelongsToCurrentThread()); video_capturer_.reset(); last_frame_.reset(); + mouse_cursor_monitor_.reset(); // Video capturer must delete all buffers. DCHECK_EQ(shared_buffers_, 0); diff --git a/remoting/host/desktop_session_agent.h b/remoting/host/desktop_session_agent.h index 0421eeb..e5893d0 100644 --- a/remoting/host/desktop_session_agent.h +++ b/remoting/host/desktop_session_agent.h @@ -18,6 +18,7 @@ #include "remoting/host/client_session_control.h" #include "remoting/protocol/clipboard_stub.h" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h" #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" namespace IPC { @@ -47,7 +48,7 @@ class DesktopSessionAgent : public base::RefCountedThreadSafe<DesktopSessionAgent>, public IPC::Listener, public webrtc::DesktopCapturer::Callback, - public webrtc::ScreenCapturer::MouseShapeObserver, + public webrtc::MouseCursorMonitor::Callback, public ClientSessionControl { public: class Delegate { @@ -78,9 +79,11 @@ class DesktopSessionAgent virtual webrtc::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE; virtual void OnCaptureCompleted(webrtc::DesktopFrame* frame) OVERRIDE; - // webrtc::ScreenCapturer::MouseShapeObserver implementation. - virtual void OnCursorShapeChanged( - webrtc::MouseCursorShape* cursor_shape) OVERRIDE; + // webrtc::MouseCursorMonitor::Callback implementation. + virtual void OnMouseCursor(webrtc::MouseCursor* cursor) OVERRIDE; + virtual void OnMouseCursorPosition( + webrtc::MouseCursorMonitor::CursorState state, + const webrtc::DesktopVector& position) OVERRIDE; // Forwards a local clipboard event though the IPC channel to the network // process. @@ -139,11 +142,13 @@ class DesktopSessionAgent // Posted to |audio_capture_task_runner_| to stop the audio capturer. void StopAudioCapturer(); - // Posted to |video_capture_task_runner_| to start the video capturer. - void StartVideoCapturer(); + // Posted to |video_capture_task_runner_| to start the video capturer and the + // mouse cursor monitor. + void StartVideoCapturerAndMouseMonitor(); - // Posted to |video_capture_task_runner_| to stop the video capturer. - void StopVideoCapturer(); + // Posted to |video_capture_task_runner_| to stop the video capturer and the + // mouse cursor monitor. + void StopVideoCapturerAndMouseMonitor(); private: class SharedBuffer; @@ -217,6 +222,9 @@ class DesktopSessionAgent // Captures the screen. scoped_ptr<webrtc::ScreenCapturer> video_capturer_; + // Captures mouse shapes. + scoped_ptr<webrtc::MouseCursorMonitor> mouse_cursor_monitor_; + // Keep reference to the last frame sent to make sure shared buffer is alive // before it's received. scoped_ptr<webrtc::DesktopFrame> last_frame_; diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc index 058a2f4..982870a 100644 --- a/remoting/host/desktop_session_proxy.cc +++ b/remoting/host/desktop_session_proxy.cc @@ -19,6 +19,7 @@ #include "remoting/host/desktop_session_connector.h" #include "remoting/host/ipc_audio_capturer.h" #include "remoting/host/ipc_input_injector.h" +#include "remoting/host/ipc_mouse_cursor_monitor.h" #include "remoting/host/ipc_screen_controls.h" #include "remoting/host/ipc_video_frame_capturer.h" #include "remoting/proto/audio.pb.h" @@ -26,6 +27,7 @@ #include "remoting/proto/event.pb.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor.h" #include "third_party/webrtc/modules/desktop_capture/shared_memory.h" #if defined(OS_WIN) @@ -144,6 +146,12 @@ scoped_ptr<webrtc::ScreenCapturer> DesktopSessionProxy::CreateVideoCapturer() { return scoped_ptr<webrtc::ScreenCapturer>(new IpcVideoFrameCapturer(this)); } +scoped_ptr<webrtc::MouseCursorMonitor> + DesktopSessionProxy::CreateMouseCursorMonitor() { + return scoped_ptr<webrtc::MouseCursorMonitor>( + new IpcMouseCursorMonitor(this)); +} + std::string DesktopSessionProxy::GetCapabilities() const { std::string result = kRateLimitResizeRequests; // Ask the client to send its resolution unconditionally. @@ -183,8 +191,8 @@ bool DesktopSessionProxy::OnMessageReceived(const IPC::Message& message) { OnAudioPacket) IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_CaptureCompleted, OnCaptureCompleted) - IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_CursorShapeChanged, - OnCursorShapeChanged) + IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_MouseCursor, + OnMouseCursor) IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_CreateSharedBuffer, OnCreateSharedBuffer) IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_ReleaseSharedBuffer, @@ -318,6 +326,13 @@ void DesktopSessionProxy::SetVideoCapturer( video_capturer_ = video_capturer; } +void DesktopSessionProxy::SetMouseCursorMonitor( + const base::WeakPtr<IpcMouseCursorMonitor>& mouse_cursor_monitor) { + DCHECK(video_capture_task_runner_->BelongsToCurrentThread()); + + mouse_cursor_monitor_ = mouse_cursor_monitor; +} + void DesktopSessionProxy::DisconnectSession() { DCHECK(caller_task_runner_->BelongsToCurrentThread()); @@ -491,11 +506,12 @@ void DesktopSessionProxy::OnCaptureCompleted( PostCaptureCompleted(frame.Pass()); } -void DesktopSessionProxy::OnCursorShapeChanged( - const webrtc::MouseCursorShape& cursor_shape) { +void DesktopSessionProxy::OnMouseCursor( + const webrtc::MouseCursor& mouse_cursor) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); - PostCursorShape(scoped_ptr<webrtc::MouseCursorShape>( - new webrtc::MouseCursorShape(cursor_shape))); + scoped_ptr<webrtc::MouseCursor> cursor( + webrtc::MouseCursor::CopyOf(mouse_cursor)); + PostMouseCursor(cursor.Pass()); } void DesktopSessionProxy::OnInjectClipboardEvent( @@ -523,14 +539,14 @@ void DesktopSessionProxy::PostCaptureCompleted( base::Passed(&frame))); } -void DesktopSessionProxy::PostCursorShape( - scoped_ptr<webrtc::MouseCursorShape> cursor_shape) { +void DesktopSessionProxy::PostMouseCursor( + scoped_ptr<webrtc::MouseCursor> mouse_cursor) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); video_capture_task_runner_->PostTask( FROM_HERE, - base::Bind(&IpcVideoFrameCapturer::OnCursorShapeChanged, video_capturer_, - base::Passed(&cursor_shape))); + base::Bind(&IpcMouseCursorMonitor::OnMouseCursor, mouse_cursor_monitor_, + base::Passed(&mouse_cursor))); } void DesktopSessionProxy::SendToDesktop(IPC::Message* message) { diff --git a/remoting/host/desktop_session_proxy.h b/remoting/host/desktop_session_proxy.h index 14f3ff7..2cb5d96 100644 --- a/remoting/host/desktop_session_proxy.h +++ b/remoting/host/desktop_session_proxy.h @@ -31,7 +31,12 @@ class ChannelProxy; class Message; } // namespace IPC +namespace webrtc { +class MouseCursor; +} // namespace webrtc + struct SerializedDesktopFrame; +struct SerializedMouseCursor; namespace remoting { @@ -41,6 +46,7 @@ class ClientSessionControl; class DesktopSessionConnector; struct DesktopSessionProxyTraits; class IpcAudioCapturer; +class IpcMouseCursorMonitor; class IpcVideoFrameCapturer; class ScreenControls; @@ -77,6 +83,7 @@ class DesktopSessionProxy scoped_ptr<InputInjector> CreateInputInjector(); scoped_ptr<ScreenControls> CreateScreenControls(); scoped_ptr<webrtc::ScreenCapturer> CreateVideoCapturer(); + scoped_ptr<webrtc::MouseCursorMonitor> CreateMouseCursorMonitor(); std::string GetCapabilities() const; void SetCapabilities(const std::string& capabilities); @@ -109,6 +116,11 @@ class DesktopSessionProxy void SetVideoCapturer( const base::WeakPtr<IpcVideoFrameCapturer> video_capturer); + // Stores |mouse_cursor_monitor| to be used to post mouse cursor changes. + // Called on the |video_capture_task_runner_| thread. + void SetMouseCursorMonitor( + const base::WeakPtr<IpcMouseCursorMonitor>& mouse_cursor_monitor); + // APIs used to implement the InputInjector interface. void InjectClipboardEvent(const protocol::ClipboardEvent& event); void InjectKeyEvent(const protocol::KeyEvent& event); @@ -145,8 +157,8 @@ class DesktopSessionProxy // Handles CaptureCompleted notification from the desktop session agent. void OnCaptureCompleted(const SerializedDesktopFrame& serialized_frame); - // Handles CursorShapeChanged notification from the desktop session agent. - void OnCursorShapeChanged(const webrtc::MouseCursorShape& cursor_shape); + // Handles MouseCursor notification from the desktop session agent. + void OnMouseCursor(const webrtc::MouseCursor& mouse_cursor); // Handles InjectClipboardEvent request from the desktop integration process. void OnInjectClipboardEvent(const std::string& serialized_event); @@ -155,9 +167,9 @@ class DesktopSessionProxy // passing |frame|. void PostCaptureCompleted(scoped_ptr<webrtc::DesktopFrame> frame); - // Posts OnCursorShapeChanged() to |video_capturer_| on the video thread, - // passing |cursor_shape|. - void PostCursorShape(scoped_ptr<webrtc::MouseCursorShape> cursor_shape); + // Posts OnMouseCursor() to |mouse_cursor_monitor_| on the video thread, + // passing |mouse_cursor|. + void PostMouseCursor(scoped_ptr<webrtc::MouseCursor> mouse_cursor); // Sends a message to the desktop session agent. The message is silently // deleted if the channel is broken. @@ -190,6 +202,9 @@ class DesktopSessionProxy // Points to the video capturer receiving captured video frames. base::WeakPtr<IpcVideoFrameCapturer> video_capturer_; + // Points to the mouse cursor monitor receiving mouse cursor changes. + base::WeakPtr<IpcMouseCursorMonitor> mouse_cursor_monitor_; + // IPC channel to the desktop session agent. scoped_ptr<IPC::ChannelProxy> desktop_channel_; diff --git a/remoting/host/host_mock_objects.cc b/remoting/host/host_mock_objects.cc index 4bdd064..56460ed 100644 --- a/remoting/host/host_mock_objects.cc +++ b/remoting/host/host_mock_objects.cc @@ -39,6 +39,11 @@ MockDesktopEnvironment::CreateVideoCapturer() { return scoped_ptr<webrtc::ScreenCapturer>(CreateVideoCapturerPtr()); } +scoped_ptr<webrtc::MouseCursorMonitor> +MockDesktopEnvironment::CreateMouseCursorMonitor() { + return scoped_ptr<webrtc::MouseCursorMonitor>(CreateMouseCursorMonitorPtr()); +} + MockDesktopEnvironmentFactory::MockDesktopEnvironmentFactory() {} MockDesktopEnvironmentFactory::~MockDesktopEnvironmentFactory() {} @@ -69,4 +74,8 @@ MockHostStatusObserver::MockHostStatusObserver() {} MockHostStatusObserver::~MockHostStatusObserver() {} +MockMouseCursorMonitor::MockMouseCursorMonitor() {} + +MockMouseCursorMonitor::~MockMouseCursorMonitor() {} + } // namespace remoting diff --git a/remoting/host/host_mock_objects.h b/remoting/host/host_mock_objects.h index b5f1db9..bb1bd5a 100644 --- a/remoting/host/host_mock_objects.h +++ b/remoting/host/host_mock_objects.h @@ -16,6 +16,7 @@ #include "remoting/host/screen_resolution.h" #include "remoting/proto/control.pb.h" #include "testing/gmock/include/gmock/gmock.h" +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h" namespace base { class SingleThreadTaskRunner; @@ -32,6 +33,7 @@ class MockDesktopEnvironment : public DesktopEnvironment { MOCK_METHOD0(CreateInputInjectorPtr, InputInjector*()); MOCK_METHOD0(CreateScreenControlsPtr, ScreenControls*()); MOCK_METHOD0(CreateVideoCapturerPtr, webrtc::ScreenCapturer*()); + MOCK_METHOD0(CreateMouseCursorMonitorPtr, webrtc::MouseCursorMonitor*()); MOCK_CONST_METHOD0(GetCapabilities, std::string()); MOCK_METHOD1(SetCapabilities, void(const std::string&)); @@ -40,6 +42,8 @@ class MockDesktopEnvironment : public DesktopEnvironment { virtual scoped_ptr<InputInjector> CreateInputInjector() OVERRIDE; virtual scoped_ptr<ScreenControls> CreateScreenControls() OVERRIDE; virtual scoped_ptr<webrtc::ScreenCapturer> CreateVideoCapturer() OVERRIDE; + virtual scoped_ptr<webrtc::MouseCursorMonitor> CreateMouseCursorMonitor() + OVERRIDE; }; class MockClientSessionControl : public ClientSessionControl { @@ -126,6 +130,18 @@ class MockHostStatusObserver : public HostStatusObserver { MOCK_METHOD0(OnShutdown, void()); }; +class MockMouseCursorMonitor : public webrtc::MouseCursorMonitor { + public: + MockMouseCursorMonitor(); + virtual ~MockMouseCursorMonitor(); + + MOCK_METHOD2(Init, void(Callback* callback, Mode mode)); + MOCK_METHOD0(Capture, void()); + + private: + DISALLOW_COPY_AND_ASSIGN(MockMouseCursorMonitor); +}; + } // namespace remoting #endif // REMOTING_HOST_HOST_MOCK_OBJECTS_H_ diff --git a/remoting/host/ipc_desktop_environment.cc b/remoting/host/ipc_desktop_environment.cc index 6ec6676..f6a116e 100644 --- a/remoting/host/ipc_desktop_environment.cc +++ b/remoting/host/ipc_desktop_environment.cc @@ -18,6 +18,7 @@ #include "remoting/host/desktop_session_proxy.h" #include "remoting/host/input_injector.h" #include "remoting/host/screen_controls.h" +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h" #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" namespace remoting { @@ -56,6 +57,11 @@ scoped_ptr<ScreenControls> IpcDesktopEnvironment::CreateScreenControls() { return desktop_session_proxy_->CreateScreenControls(); } +scoped_ptr<webrtc::MouseCursorMonitor> +IpcDesktopEnvironment::CreateMouseCursorMonitor() { + return desktop_session_proxy_->CreateMouseCursorMonitor(); +} + scoped_ptr<webrtc::ScreenCapturer> IpcDesktopEnvironment::CreateVideoCapturer() { return desktop_session_proxy_->CreateVideoCapturer(); diff --git a/remoting/host/ipc_desktop_environment.h b/remoting/host/ipc_desktop_environment.h index 2dee387..90d8dce 100644 --- a/remoting/host/ipc_desktop_environment.h +++ b/remoting/host/ipc_desktop_environment.h @@ -52,6 +52,8 @@ class IpcDesktopEnvironment : public DesktopEnvironment { virtual scoped_ptr<InputInjector> CreateInputInjector() OVERRIDE; virtual scoped_ptr<ScreenControls> CreateScreenControls() OVERRIDE; virtual scoped_ptr<webrtc::ScreenCapturer> CreateVideoCapturer() OVERRIDE; + virtual scoped_ptr<webrtc::MouseCursorMonitor> CreateMouseCursorMonitor() + OVERRIDE; virtual std::string GetCapabilities() const OVERRIDE; virtual void SetCapabilities(const std::string& capabilities) OVERRIDE; diff --git a/remoting/host/ipc_desktop_environment_unittest.cc b/remoting/host/ipc_desktop_environment_unittest.cc index 5bea812..0ecec3c 100644 --- a/remoting/host/ipc_desktop_environment_unittest.cc +++ b/remoting/host/ipc_desktop_environment_unittest.cc @@ -141,6 +141,10 @@ class IpcDesktopEnvironmentTest : public testing::Test { // DesktopEnvironment::CreateVideoCapturer(). webrtc::ScreenCapturer* CreateVideoCapturer(); + // Creates a MockMouseCursorMonitor, to mock + // DesktopEnvironment::CreateMouseCursorMonitor + webrtc::MouseCursorMonitor* CreateMouseCursorMonitor(); + void DeleteDesktopEnvironment(); // Forwards |event| to |clipboard_stub_|. @@ -324,6 +328,10 @@ DesktopEnvironment* IpcDesktopEnvironmentTest::CreateDesktopEnvironment() { .Times(AtMost(1)) .WillOnce(Invoke( this, &IpcDesktopEnvironmentTest::CreateVideoCapturer)); + EXPECT_CALL(*desktop_environment, CreateMouseCursorMonitorPtr()) + .Times(AtMost(1)) + .WillOnce(Invoke( + this, &IpcDesktopEnvironmentTest::CreateMouseCursorMonitor)); EXPECT_CALL(*desktop_environment, GetCapabilities()) .Times(AtMost(1)); EXPECT_CALL(*desktop_environment, SetCapabilities(_)) @@ -347,6 +355,11 @@ webrtc::ScreenCapturer* IpcDesktopEnvironmentTest::CreateVideoCapturer() { return new ScreenCapturerFake(); } +webrtc::MouseCursorMonitor* +IpcDesktopEnvironmentTest::CreateMouseCursorMonitor() { + return new MockMouseCursorMonitor(); +} + void IpcDesktopEnvironmentTest::DeleteDesktopEnvironment() { input_injector_.reset(); screen_controls_.reset(); diff --git a/remoting/host/ipc_mouse_cursor_monitor.cc b/remoting/host/ipc_mouse_cursor_monitor.cc new file mode 100644 index 0000000..8db099e --- /dev/null +++ b/remoting/host/ipc_mouse_cursor_monitor.cc @@ -0,0 +1,42 @@ +// Copyright 2014 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_mouse_cursor_monitor.h" + +#include "remoting/host/desktop_session_proxy.h" +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor.h" + +namespace remoting { + +IpcMouseCursorMonitor::IpcMouseCursorMonitor( + scoped_refptr<DesktopSessionProxy> desktop_session_proxy) + : callback_(NULL), + desktop_session_proxy_(desktop_session_proxy), + weak_factory_(this) { +} + +IpcMouseCursorMonitor::~IpcMouseCursorMonitor() {} + +void IpcMouseCursorMonitor::Init(Callback* callback, Mode mode) { + DCHECK(!callback_); + DCHECK(callback); + DCHECK_EQ(webrtc::MouseCursorMonitor::SHAPE_ONLY, mode); + callback_ = callback; + desktop_session_proxy_->SetMouseCursorMonitor(weak_factory_.GetWeakPtr()); +} + +void IpcMouseCursorMonitor::Capture() { + // Ignore. DesktopSessionAgent will capture the cursor at the same time it + // captures a screen frame when |IpcVideoFrameCapturer::Capture()| is called. + // This saves an IPC roundtrip. +} + +void IpcMouseCursorMonitor::OnMouseCursor( + scoped_ptr<webrtc::MouseCursor> cursor) { + DCHECK(callback_); + callback_->OnMouseCursor(cursor.release()); +} + +} // namespace remoting + diff --git a/remoting/host/ipc_mouse_cursor_monitor.h b/remoting/host/ipc_mouse_cursor_monitor.h new file mode 100644 index 0000000..e237413 --- /dev/null +++ b/remoting/host/ipc_mouse_cursor_monitor.h @@ -0,0 +1,47 @@ +// Copyright 2014 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_MOUSE_CURSOR_MONITOR_H_ +#define REMOTING_HOST_IPC_MOUSE_CURSOR_MONITOR_H_ + +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h" + +namespace remoting { + +class DesktopSessionProxy; + +// Routes webrtc::MouseCursorMonitor calls through the IPC channel to the +// desktop session agent running in the desktop integration process. +class IpcMouseCursorMonitor : public webrtc::MouseCursorMonitor { + public: + explicit IpcMouseCursorMonitor( + scoped_refptr<DesktopSessionProxy> desktop_session_proxy); + virtual ~IpcMouseCursorMonitor(); + + // webrtc::MouseCursorMonitor interface. + virtual void Init(Callback* callback, Mode mode) OVERRIDE; + virtual void Capture() OVERRIDE; + + // Called when the cursor shape has changed. + void OnMouseCursor(scoped_ptr<webrtc::MouseCursor> cursor); + + private: + // The callback passed to |webrtc::MouseCursorMonitor::Init()|. + webrtc::MouseCursorMonitor::Callback* callback_; + + // Wraps the IPC channel to the desktop session agent. + scoped_refptr<DesktopSessionProxy> desktop_session_proxy_; + + // Used to cancel tasks pending on the capturer when it is stopped. + base::WeakPtrFactory<IpcMouseCursorMonitor> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(IpcMouseCursorMonitor); +}; + +} // namespace remoting + +#endif // REMOTING_HOST_IPC_MOUSE_CURSOR_MONITOR_H_ diff --git a/remoting/host/ipc_video_frame_capturer.h b/remoting/host/ipc_video_frame_capturer.h index 616f0a2..fd2cdff 100644 --- a/remoting/host/ipc_video_frame_capturer.h +++ b/remoting/host/ipc_video_frame_capturer.h @@ -10,10 +10,6 @@ #include "base/memory/scoped_ptr.h" #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" -namespace IPC { -class Message; -} // namespace IPC - namespace media { struct MouseCursorShape; } // namespace media diff --git a/remoting/host/me2me_desktop_environment.cc b/remoting/host/me2me_desktop_environment.cc index f9f9113..638de63 100644 --- a/remoting/host/me2me_desktop_environment.cc +++ b/remoting/host/me2me_desktop_environment.cc @@ -38,16 +38,6 @@ scoped_ptr<ScreenControls> Me2MeDesktopEnvironment::CreateScreenControls() { new ResizingHostObserver(DesktopResizer::Create())); } -scoped_ptr<webrtc::ScreenCapturer> -Me2MeDesktopEnvironment::CreateVideoCapturer() { - DCHECK(caller_task_runner()->BelongsToCurrentThread()); - webrtc::DesktopCaptureOptions options = - webrtc::DesktopCaptureOptions::CreateDefault(); - options.set_use_update_notifications(true); - return scoped_ptr<webrtc::ScreenCapturer>( - webrtc::ScreenCapturer::Create(options)); -} - std::string Me2MeDesktopEnvironment::GetCapabilities() const { return kRateLimitResizeRequests; } @@ -60,6 +50,7 @@ Me2MeDesktopEnvironment::Me2MeDesktopEnvironment( input_task_runner, ui_task_runner) { DCHECK(caller_task_runner->BelongsToCurrentThread()); + desktop_capture_options()->set_use_update_notifications(true); } bool Me2MeDesktopEnvironment::InitializeSecurity( diff --git a/remoting/host/me2me_desktop_environment.h b/remoting/host/me2me_desktop_environment.h index f028664..4d1fec8 100644 --- a/remoting/host/me2me_desktop_environment.h +++ b/remoting/host/me2me_desktop_environment.h @@ -21,7 +21,6 @@ class Me2MeDesktopEnvironment : public BasicDesktopEnvironment { // DesktopEnvironment interface. virtual scoped_ptr<ScreenControls> CreateScreenControls() OVERRIDE; - virtual scoped_ptr<webrtc::ScreenCapturer> CreateVideoCapturer() OVERRIDE; virtual std::string GetCapabilities() const OVERRIDE; protected: diff --git a/remoting/host/video_scheduler.cc b/remoting/host/video_scheduler.cc index 5c95c7a..6edac61 100644 --- a/remoting/host/video_scheduler.cc +++ b/remoting/host/video_scheduler.cc @@ -22,6 +22,7 @@ #include "remoting/protocol/util.h" #include "remoting/protocol/video_stub.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor.h" #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_shape.h" #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" @@ -36,6 +37,7 @@ VideoScheduler::VideoScheduler( scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner, scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, scoped_ptr<webrtc::ScreenCapturer> capturer, + scoped_ptr<webrtc::MouseCursorMonitor> mouse_cursor_monitor, scoped_ptr<VideoEncoder> encoder, protocol::CursorShapeStub* cursor_stub, protocol::VideoStub* video_stub) @@ -43,6 +45,7 @@ VideoScheduler::VideoScheduler( encode_task_runner_(encode_task_runner), network_task_runner_(network_task_runner), capturer_(capturer.Pass()), + mouse_cursor_monitor_(mouse_cursor_monitor.Pass()), encoder_(encoder.Pass()), cursor_stub_(cursor_stub), video_stub_(video_stub), @@ -87,11 +90,10 @@ void VideoScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) { } } -void VideoScheduler::OnCursorShapeChanged( - webrtc::MouseCursorShape* cursor_shape) { +void VideoScheduler::OnMouseCursor(webrtc::MouseCursor* cursor) { DCHECK(capture_task_runner_->BelongsToCurrentThread()); - scoped_ptr<webrtc::MouseCursorShape> owned_cursor(cursor_shape); + scoped_ptr<webrtc::MouseCursor> owned_cursor(cursor); // Do nothing if the scheduler is being stopped. if (!capturer_) @@ -99,17 +101,33 @@ void VideoScheduler::OnCursorShapeChanged( scoped_ptr<protocol::CursorShapeInfo> cursor_proto( new protocol::CursorShapeInfo()); - cursor_proto->set_width(cursor_shape->size.width()); - cursor_proto->set_height(cursor_shape->size.height()); - cursor_proto->set_hotspot_x(cursor_shape->hotspot.x()); - cursor_proto->set_hotspot_y(cursor_shape->hotspot.y()); - cursor_proto->set_data(cursor_shape->data); + cursor_proto->set_width(cursor->image()->size().width()); + cursor_proto->set_height(cursor->image()->size().height()); + cursor_proto->set_hotspot_x(cursor->hotspot().x()); + cursor_proto->set_hotspot_y(cursor->hotspot().y()); + + std::string data; + uint8_t* current_row = cursor->image()->data(); + for (int y = 0; y < cursor->image()->size().height(); ++y) { + cursor_proto->mutable_data()->append( + current_row, + current_row + cursor->image()->size().width() * + webrtc::DesktopFrame::kBytesPerPixel); + current_row += cursor->image()->stride(); + } network_task_runner_->PostTask( FROM_HERE, base::Bind(&VideoScheduler::SendCursorShape, this, base::Passed(&cursor_proto))); } +void VideoScheduler::OnMouseCursorPosition( + webrtc::MouseCursorMonitor::CursorState state, + const webrtc::DesktopVector& position) { + // We're not subscribing to mouse position changes. + NOTREACHED(); +} + void VideoScheduler::Start() { DCHECK(network_task_runner_->BelongsToCurrentThread()); @@ -168,8 +186,10 @@ void VideoScheduler::StartOnCaptureThread() { DCHECK(capture_task_runner_->BelongsToCurrentThread()); DCHECK(!capture_timer_); - // Start the capturer and let it notify us if cursor shape changes. - capturer_->SetMouseShapeObserver(this); + // Start mouse cursor monitor. + mouse_cursor_monitor_->Init(this, webrtc::MouseCursorMonitor::SHAPE_ONLY); + + // Start the capturer. capturer_->Start(this); capture_timer_.reset(new base::OneShotTimer<VideoScheduler>()); @@ -224,6 +244,9 @@ void VideoScheduler::CaptureNextFrame() { capture_pending_ = true; + // Capture the mouse shape. + mouse_cursor_monitor_->Capture(); + // And finally perform one capture. capturer_->Capture(webrtc::DesktopRegion()); } diff --git a/remoting/host/video_scheduler.h b/remoting/host/video_scheduler.h index f2eabd9..635ee66 100644 --- a/remoting/host/video_scheduler.h +++ b/remoting/host/video_scheduler.h @@ -15,6 +15,7 @@ #include "remoting/codec/video_encoder.h" #include "remoting/host/capture_scheduler.h" #include "remoting/proto/video.pb.h" +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h" #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" namespace base { @@ -74,7 +75,7 @@ class VideoStub; class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler>, public webrtc::DesktopCapturer::Callback, - public webrtc::ScreenCapturer::MouseShapeObserver { + public webrtc::MouseCursorMonitor::Callback { public: // Creates a VideoScheduler running capture, encode and network tasks on the // supplied TaskRunners. Video and cursor shape updates will be pumped to @@ -85,6 +86,7 @@ class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler>, scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner, scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, scoped_ptr<webrtc::ScreenCapturer> capturer, + scoped_ptr<webrtc::MouseCursorMonitor> mouse_cursor_monitor, scoped_ptr<VideoEncoder> encoder, protocol::CursorShapeStub* cursor_stub, protocol::VideoStub* video_stub); @@ -93,9 +95,12 @@ class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler>, virtual webrtc::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE; virtual void OnCaptureCompleted(webrtc::DesktopFrame* frame) OVERRIDE; - // webrtc::ScreenCapturer::MouseShapeObserver implementation. - virtual void OnCursorShapeChanged( - webrtc::MouseCursorShape* cursor_shape) OVERRIDE; + // webrtc::MouseCursorMonitor::Callback implementation. + virtual void OnMouseCursor( + webrtc::MouseCursor* mouse_cursor) OVERRIDE; + virtual void OnMouseCursorPosition( + webrtc::MouseCursorMonitor::CursorState state, + const webrtc::DesktopVector& position) OVERRIDE; // Starts scheduling frame captures. void Start(); @@ -162,6 +167,9 @@ class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler>, // Used to capture frames. Always accessed on the capture thread. scoped_ptr<webrtc::ScreenCapturer> capturer_; + // Used to capture mouse cursor shapes. Always accessed on the capture thread. + scoped_ptr<webrtc::MouseCursorMonitor> mouse_cursor_monitor_; + // Used to encode captured frames. Always accessed on the encode thread. scoped_ptr<VideoEncoder> encoder_; diff --git a/remoting/host/video_scheduler_unittest.cc b/remoting/host/video_scheduler_unittest.cc index 25567d2..fd6e53c 100644 --- a/remoting/host/video_scheduler_unittest.cc +++ b/remoting/host/video_scheduler_unittest.cc @@ -9,11 +9,14 @@ #include "base/run_loop.h" #include "remoting/base/auto_thread_task_runner.h" #include "remoting/codec/video_encoder.h" +#include "remoting/host/host_mock_objects.h" +#include "remoting/proto/control.pb.h" #include "remoting/proto/video.pb.h" #include "remoting/protocol/protocol_mock_objects.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor.h" #include "third_party/webrtc/modules/desktop_capture/screen_capturer_mock_objects.h" using ::remoting::protocol::MockClientStub; @@ -48,6 +51,10 @@ ACTION(FinishSend) { static const int kWidth = 640; static const int kHeight = 480; +static const int kCursorWidth = 64; +static const int kCursorHeight = 32; +static const int kHotspotX = 11; +static const int kHotspotY = 12; class MockVideoEncoder : public VideoEncoder { public: @@ -74,12 +81,19 @@ class VideoSchedulerTest : public testing::Test { virtual void SetUp() OVERRIDE; - void StartVideoScheduler(scoped_ptr<webrtc::ScreenCapturer> capturer); + void StartVideoScheduler( + scoped_ptr<webrtc::ScreenCapturer> capturer, + scoped_ptr<webrtc::MouseCursorMonitor> mouse_monitor); void StopVideoScheduler(); // webrtc::ScreenCapturer mocks. void OnCapturerStart(webrtc::ScreenCapturer::Callback* callback); void OnCaptureFrame(const webrtc::DesktopRegion& region); + void OnMouseCursorMonitorInit( + webrtc::MouseCursorMonitor::Callback* callback, + webrtc::MouseCursorMonitor::Mode mode); +void OnCaptureMouse(); +void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape); protected: base::MessageLoop message_loop_; @@ -94,17 +108,22 @@ class VideoSchedulerTest : public testing::Test { MockVideoEncoder* encoder_; scoped_ptr<webrtc::DesktopFrame> frame_; + scoped_ptr<webrtc::MouseCursor> mouse_cursor_; // Points to the callback passed to webrtc::ScreenCapturer::Start(). webrtc::ScreenCapturer::Callback* capturer_callback_; + // Points to the callback passed to webrtc::MouseCursor::Init(). + webrtc::MouseCursorMonitor::Callback* mouse_monitor_callback_; + private: DISALLOW_COPY_AND_ASSIGN(VideoSchedulerTest); }; VideoSchedulerTest::VideoSchedulerTest() : encoder_(NULL), - capturer_callback_(NULL) { + capturer_callback_(NULL), + mouse_monitor_callback_(NULL) { } void VideoSchedulerTest::SetUp() { @@ -115,12 +134,14 @@ void VideoSchedulerTest::SetUp() { } void VideoSchedulerTest::StartVideoScheduler( - scoped_ptr<webrtc::ScreenCapturer> capturer) { + scoped_ptr<webrtc::ScreenCapturer> capturer, + scoped_ptr<webrtc::MouseCursorMonitor> mouse_monitor) { scheduler_ = new VideoScheduler( task_runner_, // Capture task_runner_, // Encode task_runner_, // Network capturer.Pass(), + mouse_monitor.Pass(), scoped_ptr<VideoEncoder>(encoder_), &client_stub_, &video_stub_); @@ -146,6 +167,35 @@ void VideoSchedulerTest::OnCaptureFrame(const webrtc::DesktopRegion& region) { capturer_callback_->OnCaptureCompleted(frame_.release()); } +void VideoSchedulerTest::OnCaptureMouse() { + EXPECT_TRUE(mouse_monitor_callback_); + mouse_monitor_callback_->OnMouseCursor(mouse_cursor_.release()); +} + +void VideoSchedulerTest::OnMouseCursorMonitorInit( + webrtc::MouseCursorMonitor::Callback* callback, + webrtc::MouseCursorMonitor::Mode mode) { + EXPECT_FALSE(mouse_monitor_callback_); + EXPECT_TRUE(callback); + + mouse_monitor_callback_ = callback; +} + +void VideoSchedulerTest::SetCursorShape( + const protocol::CursorShapeInfo& cursor_shape) { + EXPECT_TRUE(cursor_shape.has_width()); + EXPECT_EQ(kCursorWidth, cursor_shape.width()); + EXPECT_TRUE(cursor_shape.has_height()); + EXPECT_EQ(kCursorHeight, cursor_shape.height()); + EXPECT_TRUE(cursor_shape.has_hotspot_x()); + EXPECT_EQ(kHotspotX, cursor_shape.hotspot_x()); + EXPECT_TRUE(cursor_shape.has_hotspot_y()); + EXPECT_EQ(kHotspotY, cursor_shape.hotspot_y()); + EXPECT_TRUE(cursor_shape.has_data()); + EXPECT_EQ(kCursorWidth * kCursorHeight * webrtc::DesktopFrame::kBytesPerPixel, + static_cast<int>(cursor_shape.data().size())); +} + // This test mocks capturer, encoder and network layer to simulate one capture // cycle. When the first encoded packet is submitted to the network // VideoScheduler is instructed to come to a complete stop. We expect the stop @@ -153,6 +203,20 @@ void VideoSchedulerTest::OnCaptureFrame(const webrtc::DesktopRegion& region) { TEST_F(VideoSchedulerTest, StartAndStop) { scoped_ptr<webrtc::MockScreenCapturer> capturer( new webrtc::MockScreenCapturer()); + scoped_ptr<MockMouseCursorMonitor> cursor_monitor( + new MockMouseCursorMonitor()); + + { + InSequence s; + + EXPECT_CALL(*cursor_monitor, Init(_, _)) + .WillOnce( + Invoke(this, &VideoSchedulerTest::OnMouseCursorMonitorInit)); + + EXPECT_CALL(*cursor_monitor, Capture()) + .WillRepeatedly(Invoke(this, &VideoSchedulerTest::OnCaptureMouse)); + } + Expectation capturer_start = EXPECT_CALL(*capturer, Start(_)) .WillOnce(Invoke(this, &VideoSchedulerTest::OnCapturerStart)); @@ -160,6 +224,11 @@ TEST_F(VideoSchedulerTest, StartAndStop) { frame_.reset(new webrtc::BasicDesktopFrame( webrtc::DesktopSize(kWidth, kHeight))); + mouse_cursor_.reset(new webrtc::MouseCursor( + new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kCursorWidth, + kCursorHeight)), + webrtc::DesktopVector(kHotspotX, kHotspotY))); + // First the capturer is called. Expectation capturer_capture = EXPECT_CALL(*capturer, Capture(_)) .After(capturer_start) @@ -173,6 +242,9 @@ TEST_F(VideoSchedulerTest, StartAndStop) { EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) .WillRepeatedly(FinishSend()); + EXPECT_CALL(client_stub_, SetCursorShape(_)) + .WillOnce(Invoke(this, &VideoSchedulerTest::SetCursorShape)); + // For the first time when ProcessVideoPacket is received we stop the // VideoScheduler. EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) @@ -182,7 +254,8 @@ TEST_F(VideoSchedulerTest, StartAndStop) { .RetiresOnSaturation(); // Start video frame capture. - StartVideoScheduler(capturer.PassAs<webrtc::ScreenCapturer>()); + StartVideoScheduler(capturer.PassAs<webrtc::ScreenCapturer>(), + cursor_monitor.PassAs<webrtc::MouseCursorMonitor>()); task_runner_ = NULL; run_loop_.Run(); diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index 30ddfa9..955416b 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -297,6 +297,8 @@ 'host/ipc_host_event_logger.h', 'host/ipc_input_injector.cc', 'host/ipc_input_injector.h', + 'host/ipc_mouse_cursor_monitor.cc', + 'host/ipc_mouse_cursor_monitor.h', 'host/ipc_screen_controls.cc', 'host/ipc_screen_controls.h', 'host/ipc_util.h', diff --git a/remoting/webapp/all_js_load.gtestjs b/remoting/webapp/all_js_load.gtestjs index 89a14a8..7c72946 100644 --- a/remoting/webapp/all_js_load.gtestjs +++ b/remoting/webapp/all_js_load.gtestjs @@ -23,7 +23,6 @@ AllJsLoadTest.prototype = { 'client_session.js', //'clipboard_event_proto.js', // Only used by jscompiler. 'clipboard.js', - 'connection_history.js', 'connection_stats.js', //'cs_oauth2_trampoline.js', // Uses globals in the chrome namespace, which // give a compilation error when declared in |