diff options
author | dcaiafa@chromium.org <dcaiafa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-08 06:33:50 +0000 |
---|---|---|
committer | dcaiafa@chromium.org <dcaiafa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-08 06:33:50 +0000 |
commit | 74337c37d04ec323c6358a8f5990d0e0d10fd3c8 (patch) | |
tree | 29d381c1c4c464e3c230e983f024312b2adb8cd1 /remoting | |
parent | 563d60211d5f541015ebad2123d717c48ef95fc4 (diff) | |
download | chromium_src-74337c37d04ec323c6358a8f5990d0e0d10fd3c8.zip chromium_src-74337c37d04ec323c6358a8f5990d0e0d10fd3c8.tar.gz chromium_src-74337c37d04ec323c6358a8f5990d0e0d10fd3c8.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.
Fix memory corruption in VideoSchedulerTests_StartAndStop, where a lingering
capture task could trigger a expectation action declared on the stack during
tear down. My changes to the test somehow made the race condition more likely.
BUG=324033
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=247689
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=248045
Review URL: https://codereview.chromium.org/92473002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288226 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
32 files changed, 619 insertions, 91 deletions
diff --git a/remoting/host/basic_desktop_environment.cc b/remoting/host/basic_desktop_environment.cc index 011bf5c..a28b118 100644 --- a/remoting/host/basic_desktop_environment.cc +++ b/remoting/host/basic_desktop_environment.cc @@ -12,6 +12,8 @@ #include "remoting/host/gnubby_auth_handler.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 { @@ -38,6 +40,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(); } @@ -56,7 +66,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( @@ -65,7 +76,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 ab38c49..9d97dbc 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 { class GnubbyAuthHandler; @@ -28,6 +34,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; virtual scoped_ptr<GnubbyAuthHandler> CreateGnubbyAuthHandler( @@ -53,6 +61,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. @@ -64,6 +76,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 b71c388..6799195 100644 --- a/remoting/host/chromoting_host_unittest.cc +++ b/remoting/host/chromoting_host_unittest.cc @@ -11,6 +11,7 @@ #include "remoting/host/chromoting_host.h" #include "remoting/host/chromoting_host_context.h" #include "remoting/host/desktop_environment.h" +#include "remoting/host/fake_mouse_cursor_monitor.h" #include "remoting/host/fake_screen_capturer.h" #include "remoting/host/host_mock_objects.h" #include "remoting/proto/video.pb.h" @@ -249,6 +250,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(_)) @@ -271,6 +275,12 @@ class ChromotingHostTest : public testing::Test { return new FakeScreenCapturer(); } + // Creates a MockMouseCursorMonitor, to mock + // DesktopEnvironment::CreateMouseCursorMonitor(). + webrtc::MouseCursorMonitor* CreateMouseCursorMonitor() { + return new FakeMouseCursorMonitor(); + } + void DisconnectAllClients() { host_->DisconnectAllClients(); } diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h index f28feaa..12c9163 100644 --- a/remoting/host/chromoting_messages.h +++ b/remoting/host/chromoting_messages.h @@ -144,12 +144,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. @@ -179,8 +173,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 b5e375e..59c124f 100644 --- a/remoting/host/client_session.cc +++ b/remoting/host/client_session.cc @@ -472,6 +472,7 @@ void ClientSession::ResetVideoPipeline() { video_encode_task_runner_, network_task_runner_, video_capturer.Pass(), + 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 d0e1fc6..112afbf 100644 --- a/remoting/host/client_session_unittest.cc +++ b/remoting/host/client_session_unittest.cc @@ -16,6 +16,7 @@ #include "remoting/host/client_session.h" #include "remoting/host/desktop_environment.h" #include "remoting/host/fake_host_extension.h" +#include "remoting/host/fake_mouse_cursor_monitor.h" #include "remoting/host/fake_screen_capturer.h" #include "remoting/host/host_extension.h" #include "remoting/host/host_extension_session.h" @@ -146,6 +147,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. @@ -279,6 +284,9 @@ DesktopEnvironment* ClientSessionTest::CreateDesktopEnvironment() { .Times(AtMost(1)); EXPECT_CALL(*desktop_environment, CreateVideoCapturerPtr()) .WillRepeatedly(Invoke(this, &ClientSessionTest::CreateVideoCapturer)); + EXPECT_CALL(*desktop_environment, CreateMouseCursorMonitorPtr()) + .WillRepeatedly( + Invoke(this, &ClientSessionTest::CreateMouseCursorMonitor)); EXPECT_CALL(*desktop_environment, GetCapabilities()) .Times(AtMost(1)) .WillOnce(Return(kDefaultTestCapability)); @@ -297,6 +305,10 @@ webrtc::ScreenCapturer* ClientSessionTest::CreateVideoCapturer() { return new FakeScreenCapturer(); } +webrtc::MouseCursorMonitor* ClientSessionTest::CreateMouseCursorMonitor() { + return new FakeMouseCursorMonitor(); +} + 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 c289891..50a163a 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 { @@ -45,6 +46,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 a7ed484a..b36388f 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 { @@ -298,10 +299,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) { @@ -327,14 +330,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( @@ -417,7 +426,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)); } } @@ -429,6 +439,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 @@ -545,20 +557,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 2f98194..b9bd8a4 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. @@ -141,11 +144,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; @@ -216,6 +221,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 7904a2d..5094a77 100644 --- a/remoting/host/desktop_session_proxy.cc +++ b/remoting/host/desktop_session_proxy.cc @@ -18,6 +18,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" @@ -25,6 +26,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) @@ -143,6 +145,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. @@ -182,8 +190,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, @@ -316,6 +324,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()); @@ -502,11 +517,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( @@ -534,14 +550,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 1414c61..e143228 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); @@ -146,8 +158,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); @@ -156,9 +168,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. @@ -191,6 +203,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/fake_desktop_environment.cc b/remoting/host/fake_desktop_environment.cc index 5e02ec8..135844c 100644 --- a/remoting/host/fake_desktop_environment.cc +++ b/remoting/host/fake_desktop_environment.cc @@ -63,6 +63,11 @@ FakeDesktopEnvironment::CreateVideoCapturer() { return result.PassAs<webrtc::ScreenCapturer>(); } +scoped_ptr<webrtc::MouseCursorMonitor> +FakeDesktopEnvironment::CreateMouseCursorMonitor() { + return scoped_ptr<webrtc::MouseCursorMonitor>(new FakeMouseCursorMonitor()); +} + std::string FakeDesktopEnvironment::GetCapabilities() const { return std::string(); } diff --git a/remoting/host/fake_desktop_environment.h b/remoting/host/fake_desktop_environment.h index 412702d..5f6c93a 100644 --- a/remoting/host/fake_desktop_environment.h +++ b/remoting/host/fake_desktop_environment.h @@ -6,6 +6,7 @@ #define REMOTING_HOST_FAKE_DESKTOP_ENVIRONMENT_H_ #include "remoting/host/desktop_environment.h" +#include "remoting/host/fake_mouse_cursor_monitor.h" #include "remoting/host/fake_screen_capturer.h" #include "remoting/host/input_injector.h" #include "remoting/host/screen_controls.h" @@ -51,6 +52,8 @@ class FakeDesktopEnvironment : 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; virtual scoped_ptr<GnubbyAuthHandler> CreateGnubbyAuthHandler( diff --git a/remoting/host/fake_mouse_cursor_monitor.cc b/remoting/host/fake_mouse_cursor_monitor.cc new file mode 100644 index 0000000..5635a48 --- /dev/null +++ b/remoting/host/fake_mouse_cursor_monitor.cc @@ -0,0 +1,49 @@ +// 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/fake_mouse_cursor_monitor.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.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 remoting { + +FakeMouseCursorMonitor::FakeMouseCursorMonitor() : callback_(NULL) {} + +FakeMouseCursorMonitor::~FakeMouseCursorMonitor() {} + +void FakeMouseCursorMonitor::Init( + webrtc::MouseCursorMonitor::Callback* callback, + webrtc::MouseCursorMonitor::Mode mode) { + DCHECK(!callback_); + DCHECK(callback); + + // Only shapes supported right now. + CHECK(mode == SHAPE_ONLY); + + callback_ = callback; +} + +void FakeMouseCursorMonitor::Capture() { + DCHECK(callback_); + + const int kWidth = 32; + const int kHeight = 32; + + scoped_ptr<webrtc::DesktopFrame> desktop_frame( + new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight))); + memset(desktop_frame->data(), 0xFF, + webrtc::DesktopFrame::kBytesPerPixel * kWidth * kHeight); + + scoped_ptr<webrtc::MouseCursor> mouse_cursor( + new webrtc::MouseCursor(desktop_frame.release(), + webrtc::DesktopVector())); + + callback_->OnMouseCursor(mouse_cursor.release()); +} + +} // namespace remoting diff --git a/remoting/host/fake_mouse_cursor_monitor.h b/remoting/host/fake_mouse_cursor_monitor.h new file mode 100644 index 0000000..0b46d72 --- /dev/null +++ b/remoting/host/fake_mouse_cursor_monitor.h @@ -0,0 +1,28 @@ +// 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_FAKE_MOUSE_CURSOR_MONITOR_H_ +#define REMOTING_HOST_FAKE_MOUSE_CURSOR_MONITOR_H_ + +#include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h" + +namespace remoting { + +class FakeMouseCursorMonitor : public webrtc::MouseCursorMonitor { + public: + FakeMouseCursorMonitor(); + virtual ~FakeMouseCursorMonitor(); + + virtual void Init(Callback* callback, Mode mode) OVERRIDE; + virtual void Capture() OVERRIDE; + + private: + Callback* callback_; + + DISALLOW_COPY_AND_ASSIGN(FakeMouseCursorMonitor); +}; + +} // namespace remoting + +#endif // REMOTING_HOST_FAKE_MOUSE_CURSOR_MONITOR_H_ diff --git a/remoting/host/host_mock_objects.cc b/remoting/host/host_mock_objects.cc index dcc2646..aad673d 100644 --- a/remoting/host/host_mock_objects.cc +++ b/remoting/host/host_mock_objects.cc @@ -45,6 +45,11 @@ MockDesktopEnvironment::CreateGnubbyAuthHandler( return scoped_ptr<GnubbyAuthHandler>(CreateGnubbyAuthHandlerPtr(client_stub)); } +scoped_ptr<webrtc::MouseCursorMonitor> +MockDesktopEnvironment::CreateMouseCursorMonitor() { + return scoped_ptr<webrtc::MouseCursorMonitor>(CreateMouseCursorMonitorPtr()); +} + MockDesktopEnvironmentFactory::MockDesktopEnvironmentFactory() {} MockDesktopEnvironmentFactory::~MockDesktopEnvironmentFactory() {} @@ -79,4 +84,8 @@ MockGnubbyAuthHandler::MockGnubbyAuthHandler() {} MockGnubbyAuthHandler::~MockGnubbyAuthHandler() {} +MockMouseCursorMonitor::MockMouseCursorMonitor() {} + +MockMouseCursorMonitor::~MockMouseCursorMonitor() {} + } // namespace remoting diff --git a/remoting/host/host_mock_objects.h b/remoting/host/host_mock_objects.h index 930828b..348c591 100644 --- a/remoting/host/host_mock_objects.h +++ b/remoting/host/host_mock_objects.h @@ -19,6 +19,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; @@ -35,6 +36,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&)); MOCK_METHOD1(CreateGnubbyAuthHandlerPtr, GnubbyAuthHandler*( @@ -47,6 +49,8 @@ class MockDesktopEnvironment : public DesktopEnvironment { virtual scoped_ptr<webrtc::ScreenCapturer> CreateVideoCapturer() OVERRIDE; virtual scoped_ptr<GnubbyAuthHandler> CreateGnubbyAuthHandler( protocol::ClientStub* client_stub) OVERRIDE; + virtual scoped_ptr<webrtc::MouseCursorMonitor> CreateMouseCursorMonitor() + OVERRIDE; }; class MockClientSessionControl : public ClientSessionControl { @@ -147,6 +151,18 @@ class MockGnubbyAuthHandler : public GnubbyAuthHandler { DISALLOW_COPY_AND_ASSIGN(MockGnubbyAuthHandler); }; +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 3332712..d19c342 100644 --- a/remoting/host/ipc_desktop_environment.cc +++ b/remoting/host/ipc_desktop_environment.cc @@ -19,6 +19,7 @@ #include "remoting/host/gnubby_auth_handler.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 { @@ -57,6 +58,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 bb68df1..6cdcc7e 100644 --- a/remoting/host/ipc_desktop_environment.h +++ b/remoting/host/ipc_desktop_environment.h @@ -53,6 +53,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; virtual scoped_ptr<GnubbyAuthHandler> CreateGnubbyAuthHandler( diff --git a/remoting/host/ipc_desktop_environment_unittest.cc b/remoting/host/ipc_desktop_environment_unittest.cc index 38b8cd2..542fec6 100644 --- a/remoting/host/ipc_desktop_environment_unittest.cc +++ b/remoting/host/ipc_desktop_environment_unittest.cc @@ -24,6 +24,7 @@ #include "remoting/host/desktop_session.h" #include "remoting/host/desktop_session_connector.h" #include "remoting/host/desktop_session_proxy.h" +#include "remoting/host/fake_mouse_cursor_monitor.h" #include "remoting/host/fake_screen_capturer.h" #include "remoting/host/host_mock_objects.h" #include "remoting/host/ipc_desktop_environment.h" @@ -141,6 +142,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 +329,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 +356,11 @@ webrtc::ScreenCapturer* IpcDesktopEnvironmentTest::CreateVideoCapturer() { return new FakeScreenCapturer(); } +webrtc::MouseCursorMonitor* +IpcDesktopEnvironmentTest::CreateMouseCursorMonitor() { + return new FakeMouseCursorMonitor(); +} + 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..c9581781 --- /dev/null +++ b/remoting/host/ipc_mouse_cursor_monitor.h @@ -0,0 +1,48 @@ +// 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/scoped_ptr.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 abf9a99..e6f5fdc 100644 --- a/remoting/host/me2me_desktop_environment.cc +++ b/remoting/host/me2me_desktop_environment.cc @@ -40,16 +40,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; } @@ -63,6 +53,7 @@ Me2MeDesktopEnvironment::Me2MeDesktopEnvironment( ui_task_runner), gnubby_auth_enabled_(false) { DCHECK(caller_task_runner->BelongsToCurrentThread()); + desktop_capture_options()->set_use_update_notifications(true); } scoped_ptr<GnubbyAuthHandler> Me2MeDesktopEnvironment::CreateGnubbyAuthHandler( diff --git a/remoting/host/me2me_desktop_environment.h b/remoting/host/me2me_desktop_environment.h index 9ee69a9..f5f31e6 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; virtual scoped_ptr<GnubbyAuthHandler> CreateGnubbyAuthHandler( protocol::ClientStub* client_stub) OVERRIDE; diff --git a/remoting/host/video_scheduler.cc b/remoting/host/video_scheduler.cc index 24181c3..7da9adf 100644 --- a/remoting/host/video_scheduler.cc +++ b/remoting/host/video_scheduler.cc @@ -21,6 +21,7 @@ #include "remoting/protocol/message_decoder.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" @@ -48,6 +49,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) @@ -55,6 +57,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), @@ -65,6 +68,7 @@ VideoScheduler::VideoScheduler( sequence_number_(0) { DCHECK(network_task_runner_->BelongsToCurrentThread()); DCHECK(capturer_); + DCHECK(mouse_cursor_monitor_); DCHECK(encoder_); DCHECK(cursor_stub_); DCHECK(video_stub_); @@ -103,11 +107,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_) @@ -115,17 +118,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()); @@ -204,6 +223,7 @@ void VideoScheduler::SetLosslessColor(bool want_lossless) { VideoScheduler::~VideoScheduler() { // Destroy the capturer and encoder on their respective threads. capture_task_runner_->DeleteSoon(FROM_HERE, capturer_.release()); + capture_task_runner_->DeleteSoon(FROM_HERE, mouse_cursor_monitor_.release()); encode_task_runner_->DeleteSoon(FROM_HERE, encoder_.release()); } @@ -213,8 +233,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>()); @@ -222,7 +244,7 @@ void VideoScheduler::StartOnCaptureThread() { FROM_HERE, base::TimeDelta::FromMilliseconds(kKeepAlivePacketIntervalMs), this, &VideoScheduler::SendKeepAlivePacket)); - // Capture first frame immedately. + // Capture first frame immediately. CaptureNextFrame(); } @@ -272,6 +294,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 3b745ff..21b1007 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: // Enables timestamps for generated frames. Used for testing. static void EnableTimestampsForTests(); @@ -88,6 +89,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); @@ -96,9 +98,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(); @@ -177,6 +182,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 3d7375e..adf1923 100644 --- a/remoting/host/video_scheduler_unittest.cc +++ b/remoting/host/video_scheduler_unittest.cc @@ -10,13 +10,18 @@ #include "base/single_thread_task_runner.h" #include "remoting/base/auto_thread.h" #include "remoting/base/auto_thread_task_runner.h" +#include "remoting/codec/video_encoder.h" #include "remoting/codec/video_encoder_verbatim.h" +#include "remoting/host/fake_mouse_cursor_monitor.h" #include "remoting/host/fake_screen_capturer.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; @@ -51,6 +56,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: @@ -99,6 +108,22 @@ class ThreadCheckScreenCapturer : public FakeScreenCapturer { DISALLOW_COPY_AND_ASSIGN(ThreadCheckScreenCapturer); }; +class ThreadCheckMouseCursorMonitor : public FakeMouseCursorMonitor { + public: + ThreadCheckMouseCursorMonitor( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : task_runner_(task_runner) { + } + virtual ~ThreadCheckMouseCursorMonitor() { + EXPECT_TRUE(task_runner_->BelongsToCurrentThread()); + } + + private: + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + DISALLOW_COPY_AND_ASSIGN(ThreadCheckMouseCursorMonitor); +}; + class VideoSchedulerTest : public testing::Test { public: VideoSchedulerTest(); @@ -108,12 +133,18 @@ class VideoSchedulerTest : public testing::Test { void StartVideoScheduler( scoped_ptr<webrtc::ScreenCapturer> capturer, - scoped_ptr<VideoEncoder> encoder); + scoped_ptr<VideoEncoder> encoder, + 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_; @@ -126,17 +157,19 @@ class VideoSchedulerTest : public testing::Test { MockClientStub client_stub_; MockVideoStub video_stub_; - scoped_ptr<webrtc::DesktopFrame> frame_; - // 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() - : capturer_callback_(NULL) { + : capturer_callback_(NULL), + mouse_monitor_callback_(NULL) { } void VideoSchedulerTest::SetUp() { @@ -158,12 +191,14 @@ void VideoSchedulerTest::TearDown() { void VideoSchedulerTest::StartVideoScheduler( scoped_ptr<webrtc::ScreenCapturer> capturer, - scoped_ptr<VideoEncoder> encoder) { + scoped_ptr<VideoEncoder> encoder, + scoped_ptr<webrtc::MouseCursorMonitor> mouse_monitor) { scheduler_ = new VideoScheduler( capture_task_runner_, encode_task_runner_, main_task_runner_, capturer.Pass(), + mouse_monitor.Pass(), encoder.Pass(), &client_stub_, &video_stub_); @@ -184,9 +219,47 @@ void VideoSchedulerTest::OnCapturerStart( } void VideoSchedulerTest::OnCaptureFrame(const webrtc::DesktopRegion& region) { - frame_->mutable_updated_region()->SetRect( + scoped_ptr<webrtc::DesktopFrame> frame( + new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight))); + frame->mutable_updated_region()->SetRect( webrtc::DesktopRect::MakeXYWH(0, 0, 10, 10)); - capturer_callback_->OnCaptureCompleted(frame_.release()); + capturer_callback_->OnCaptureCompleted(frame.release()); +} + +void VideoSchedulerTest::OnCaptureMouse() { + EXPECT_TRUE(mouse_monitor_callback_); + + scoped_ptr<webrtc::MouseCursor> mouse_cursor( + new webrtc::MouseCursor( + new webrtc::BasicDesktopFrame( + webrtc::DesktopSize(kCursorWidth, kCursorHeight)), + webrtc::DesktopVector(kHotspotX, kHotspotY))); + + 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 @@ -196,13 +269,24 @@ 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)); - frame_.reset(new webrtc::BasicDesktopFrame( - webrtc::DesktopSize(kWidth, kHeight))); - // First the capturer is called. Expectation capturer_capture = EXPECT_CALL(*capturer, Capture(_)) .After(capturer_start) @@ -225,24 +309,39 @@ TEST_F(VideoSchedulerTest, StartAndStop) { InvokeWithoutArgs(this, &VideoSchedulerTest::StopVideoScheduler))) .RetiresOnSaturation(); + EXPECT_CALL(client_stub_, SetCursorShape(_)) + .WillOnce(Invoke(this, &VideoSchedulerTest::SetCursorShape)); + // Start video frame capture. + scoped_ptr<webrtc::MouseCursorMonitor> mouse_cursor_monitor( + new FakeMouseCursorMonitor()); StartVideoScheduler(capturer.PassAs<webrtc::ScreenCapturer>(), - encoder.PassAs<VideoEncoder>()); + encoder.PassAs<VideoEncoder>(), + cursor_monitor.PassAs<webrtc::MouseCursorMonitor>()); + + // Run until there are no more pending tasks from the VideoScheduler. + // Otherwise, a lingering frame capture might attempt to trigger a capturer + // expectation action and crash. + base::RunLoop().RunUntilIdle(); } -// Verify that the capturer and encoder are torn down on the correct threads. +// Verify that the capturer, encoder and mouse monitor are torn down on the +// correct threads. TEST_F(VideoSchedulerTest, DeleteOnThreads) { -capture_task_runner_ = AutoThread::Create("capture", main_task_runner_); -encode_task_runner_ = AutoThread::Create("encode", main_task_runner_); + capture_task_runner_ = AutoThread::Create("capture", main_task_runner_); + encode_task_runner_ = AutoThread::Create("encode", main_task_runner_); scoped_ptr<webrtc::ScreenCapturer> capturer( new ThreadCheckScreenCapturer(capture_task_runner_)); scoped_ptr<VideoEncoder> encoder( new ThreadCheckVideoEncoder(encode_task_runner_)); + scoped_ptr<webrtc::MouseCursorMonitor> mouse_cursor_monitor( + new ThreadCheckMouseCursorMonitor(capture_task_runner_)); - // Start and stop the scheduler, so it will tear down the screen capturer and - // video encoder. - StartVideoScheduler(capturer.Pass(), encoder.Pass()); + // Start and stop the scheduler, so it will tear down the screen capturer, + // video encoder and mouse monitor. + StartVideoScheduler(capturer.Pass(), encoder.Pass(), + mouse_cursor_monitor.Pass()); StopVideoScheduler(); } diff --git a/remoting/remoting_host.gypi b/remoting/remoting_host.gypi index 725286f..3be04ea 100644 --- a/remoting/remoting_host.gypi +++ b/remoting/remoting_host.gypi @@ -170,6 +170,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/remoting_test.gypi b/remoting/remoting_test.gypi index c365d6a..656de77 100644 --- a/remoting/remoting_test.gypi +++ b/remoting/remoting_test.gypi @@ -24,6 +24,8 @@ 'host/fake_host_status_monitor.h', 'host/fake_screen_capturer.cc', 'host/fake_screen_capturer.h', + 'host/fake_mouse_cursor_monitor.cc', + 'host/fake_mouse_cursor_monitor.h', 'host/policy_hack/fake_policy_watcher.cc', 'host/policy_hack/fake_policy_watcher.h', 'host/policy_hack/mock_policy_callback.cc', |