[Chromoting] Add host support for SelectSource message from client.

This message is piped through to WebRtc's SelectSource to select
which display to show.

Bug: 915411
Change-Id: I30f10c8f94b15ebcff1c0fc0981385cbb8b7bc74
Reviewed-on: https://chromium-review.googlesource.com/c/1410229
Commit-Queue: Gary Kacmarcik <garykac@chromium.org>
Reviewed-by: Dominick Ng <dominickn@chromium.org>
Reviewed-by: Joe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#623544}
diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h
index 21b79729..3747a37 100644
--- a/remoting/host/chromoting_messages.h
+++ b/remoting/host/chromoting_messages.h
@@ -228,6 +228,9 @@
 
 IPC_MESSAGE_CONTROL(ChromotingNetworkDesktopMsg_CaptureFrame)
 
+IPC_MESSAGE_CONTROL(ChromotingNetworkDesktopMsg_SelectSource,
+                    int /* desktop_display_id */)
+
 // Carries a clipboard event from the client to the desktop session agent.
 // |serialized_event| is a serialized protocol::ClipboardEvent.
 IPC_MESSAGE_CONTROL(ChromotingNetworkDesktopMsg_InjectClipboardEvent,
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc
index f53c161..4e921d36 100644
--- a/remoting/host/client_session.cc
+++ b/remoting/host/client_session.cc
@@ -10,6 +10,7 @@
 #include "base/command_line.h"
 #include "base/optional.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "remoting/base/capabilities.h"
@@ -237,6 +238,18 @@
   }
 }
 
+void ClientSession::SelectDesktopDisplay(
+    const protocol::SelectDesktopDisplayRequest& select_display) {
+  int id = webrtc::kFullDesktopScreenId;
+  if (select_display.id() != "all") {
+    if (!base::StringToInt(select_display.id().c_str(), &id)) {
+      // Default to fullscreen if unable to parse id.
+      id = webrtc::kFullDesktopScreenId;
+    }
+  }
+  video_stream_->SelectSource(id);
+}
+
 void ClientSession::OnConnectionAuthenticating() {
   event_handler_->OnSessionAuthenticating(this);
 }
diff --git a/remoting/host/client_session.h b/remoting/host/client_session.h
index 7e42bdd..283bb463 100644
--- a/remoting/host/client_session.h
+++ b/remoting/host/client_session.h
@@ -113,6 +113,8 @@
   void RequestPairing(
       const remoting::protocol::PairingRequest& pairing_request) override;
   void DeliverClientMessage(const protocol::ExtensionMessage& message) override;
+  void SelectDesktopDisplay(
+      const protocol::SelectDesktopDisplayRequest& select_display) override;
 
   // protocol::ConnectionToClient::EventHandler interface.
   void OnConnectionAuthenticating() override;
diff --git a/remoting/host/desktop_capturer_proxy.cc b/remoting/host/desktop_capturer_proxy.cc
index 5600b29e..af68571a 100644
--- a/remoting/host/desktop_capturer_proxy.cc
+++ b/remoting/host/desktop_capturer_proxy.cc
@@ -42,6 +42,7 @@
   void Start();
   void SetSharedMemoryFactory(
       std::unique_ptr<webrtc::SharedMemoryFactory> shared_memory_factory);
+  void SelectSource(SourceId id);
   void CaptureFrame();
 
  private:
@@ -96,6 +97,13 @@
   }
 }
 
+void DesktopCapturerProxy::Core::SelectSource(SourceId id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (capturer_) {
+    capturer_->SelectSource(id);
+  }
+}
+
 void DesktopCapturerProxy::Core::CaptureFrame() {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (capturer_) {
@@ -175,7 +183,10 @@
 }
 
 bool DesktopCapturerProxy::SelectSource(SourceId id) {
-  NOTIMPLEMENTED();
+  DCHECK(thread_checker_.CalledOnValidThread());
+  capture_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&Core::SelectSource, base::Unretained(core_.get()), id));
   return false;
 }
 
diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc
index a9dd0b98a..9ea3c1ef 100644
--- a/remoting/host/desktop_session_agent.cc
+++ b/remoting/host/desktop_session_agent.cc
@@ -181,6 +181,8 @@
     IPC_BEGIN_MESSAGE_MAP(DesktopSessionAgent, message)
       IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_CaptureFrame,
                           OnCaptureFrame)
+      IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_SelectSource,
+                          OnSelectSource)
       IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_InjectClipboardEvent,
                           OnInjectClipboardEvent)
       IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_InjectKeyEvent,
@@ -518,6 +520,11 @@
   video_capturer_->CaptureFrame();
 }
 
+void DesktopSessionAgent::OnSelectSource(int id) {
+  DCHECK(caller_task_runner_->BelongsToCurrentThread());
+  video_capturer_->SelectSource(id);
+}
+
 void DesktopSessionAgent::OnInjectClipboardEvent(
     const std::string& serialized_event) {
   DCHECK(caller_task_runner_->BelongsToCurrentThread());
diff --git a/remoting/host/desktop_session_agent.h b/remoting/host/desktop_session_agent.h
index bbee154..81aac89 100644
--- a/remoting/host/desktop_session_agent.h
+++ b/remoting/host/desktop_session_agent.h
@@ -140,6 +140,9 @@
   // Handles CaptureFrame requests from the client.
   void OnCaptureFrame();
 
+  // Handles desktop display selection requests from the client.
+  void OnSelectSource(int id);
+
   // Handles event executor requests from the client.
   void OnInjectClipboardEvent(const std::string& serialized_event);
   void OnInjectKeyEvent(const std::string& serialized_event);
diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc
index 8eace611..3fd812e 100644
--- a/remoting/host/desktop_session_proxy.cc
+++ b/remoting/host/desktop_session_proxy.cc
@@ -293,6 +293,12 @@
   }
 }
 
+bool DesktopSessionProxy::SelectSource(webrtc::DesktopCapturer::SourceId id) {
+  DCHECK(caller_task_runner_->BelongsToCurrentThread());
+  SendToDesktop(new ChromotingNetworkDesktopMsg_SelectSource(id));
+  return true;
+}
+
 void DesktopSessionProxy::SetVideoCapturer(
     const base::WeakPtr<IpcVideoFrameCapturer> video_capturer) {
   DCHECK(caller_task_runner_->BelongsToCurrentThread());
diff --git a/remoting/host/desktop_session_proxy.h b/remoting/host/desktop_session_proxy.h
index 2eeafb2f..ccaa367 100644
--- a/remoting/host/desktop_session_proxy.h
+++ b/remoting/host/desktop_session_proxy.h
@@ -115,6 +115,7 @@
   // APIs used to implement the webrtc::DesktopCapturer interface. These must be
   // called on the |video_capture_task_runner_| thread.
   void CaptureFrame();
+  bool SelectSource(webrtc::DesktopCapturer::SourceId id);
 
   // Stores |video_capturer| to be used to post captured video frames. Called on
   // the |video_capture_task_runner_| thread.
diff --git a/remoting/host/ipc_video_frame_capturer.cc b/remoting/host/ipc_video_frame_capturer.cc
index c3f9435..a6044f6b 100644
--- a/remoting/host/ipc_video_frame_capturer.cc
+++ b/remoting/host/ipc_video_frame_capturer.cc
@@ -47,8 +47,8 @@
 }
 
 bool IpcVideoFrameCapturer::SelectSource(SourceId id) {
-  NOTIMPLEMENTED();
-  return false;
+  desktop_session_proxy_->SelectSource(id);
+  return true;
 }
 
 }  // namespace remoting
diff --git a/remoting/proto/control.proto b/remoting/proto/control.proto
index 4b50cfa..1829b30 100644
--- a/remoting/proto/control.proto
+++ b/remoting/proto/control.proto
@@ -106,3 +106,9 @@
   // Layout for each video track.
   repeated VideoTrackLayout video_track = 1;
 }
+
+message SelectDesktopDisplayRequest {
+  // Identifier for display to select. Valid strings are "0", "1", ...
+  // The "all" string is used to select the entire desktop.
+  optional string id = 1;
+}
diff --git a/remoting/proto/internal.proto b/remoting/proto/internal.proto
index a02f551..e6f9c81 100644
--- a/remoting/proto/internal.proto
+++ b/remoting/proto/internal.proto
@@ -26,6 +26,7 @@
   optional PairingResponse pairing_response = 8;
   optional ExtensionMessage extension_message = 9;
   optional VideoLayout video_layout = 10;
+  optional SelectDesktopDisplayRequest select_display = 11;
 }
 
 // Defines an event message on the event channel.
diff --git a/remoting/protocol/client_control_dispatcher.cc b/remoting/protocol/client_control_dispatcher.cc
index c7837ec..ffc6beb 100644
--- a/remoting/protocol/client_control_dispatcher.cc
+++ b/remoting/protocol/client_control_dispatcher.cc
@@ -111,6 +111,13 @@
   message_pipe()->Send(&control_message, base::Closure());
 }
 
+void ClientControlDispatcher::SelectDesktopDisplay(
+    const SelectDesktopDisplayRequest& select_display) {
+  ControlMessage message;
+  message.mutable_select_display()->CopyFrom(select_display);
+  message_pipe()->Send(&message, base::Closure());
+}
+
 void ClientControlDispatcher::OnIncomingMessage(
     std::unique_ptr<CompoundBuffer> buffer) {
   DCHECK(client_stub_);
diff --git a/remoting/protocol/client_control_dispatcher.h b/remoting/protocol/client_control_dispatcher.h
index 2fd8456..c915ad9 100644
--- a/remoting/protocol/client_control_dispatcher.h
+++ b/remoting/protocol/client_control_dispatcher.h
@@ -37,6 +37,8 @@
   void SetCapabilities(const Capabilities& capabilities) override;
   void RequestPairing(const PairingRequest& pairing_request) override;
   void DeliverClientMessage(const ExtensionMessage& message) override;
+  void SelectDesktopDisplay(
+      const SelectDesktopDisplayRequest& select_display) override;
 
   // Sets the ClientStub that will be called for each incoming control
   // message. |client_stub| must outlive this object.
diff --git a/remoting/protocol/fake_connection_to_client.cc b/remoting/protocol/fake_connection_to_client.cc
index 910c18a..69edc4fd 100644
--- a/remoting/protocol/fake_connection_to_client.cc
+++ b/remoting/protocol/fake_connection_to_client.cc
@@ -32,6 +32,8 @@
   observer_ = observer;
 }
 
+void FakeVideoStream::SelectSource(int id) {};
+
 base::WeakPtr<FakeVideoStream> FakeVideoStream::GetWeakPtr() {
   return weak_factory_.GetWeakPtr();
 }
diff --git a/remoting/protocol/fake_connection_to_client.h b/remoting/protocol/fake_connection_to_client.h
index 39440af..5078cb14 100644
--- a/remoting/protocol/fake_connection_to_client.h
+++ b/remoting/protocol/fake_connection_to_client.h
@@ -32,6 +32,7 @@
   void SetLosslessEncode(bool want_lossless) override;
   void SetLosslessColor(bool want_lossless) override;
   void SetObserver(Observer* observer) override;
+  void SelectSource(int id) override;
 
   Observer* observer() { return observer_; }
 
diff --git a/remoting/protocol/host_control_dispatcher.cc b/remoting/protocol/host_control_dispatcher.cc
index a4142c6..2b86a9f 100644
--- a/remoting/protocol/host_control_dispatcher.cc
+++ b/remoting/protocol/host_control_dispatcher.cc
@@ -93,6 +93,8 @@
     host_stub_->RequestPairing(message->pairing_request());
   } else if (message->has_extension_message()) {
     host_stub_->DeliverClientMessage(message->extension_message());
+  } else if (message->has_select_display()) {
+    host_stub_->SelectDesktopDisplay(message->select_display());
   } else {
     LOG(WARNING) << "Unknown control message received.";
   }
diff --git a/remoting/protocol/host_stub.h b/remoting/protocol/host_stub.h
index f312ab5..cf75777 100644
--- a/remoting/protocol/host_stub.h
+++ b/remoting/protocol/host_stub.h
@@ -19,6 +19,7 @@
 class ClientResolution;
 class ExtensionMessage;
 class PairingRequest;
+class SelectDesktopDisplayRequest;
 class VideoControl;
 
 class HostStub {
@@ -46,6 +47,10 @@
   // Deliver an extension message from the client to the host.
   virtual void DeliverClientMessage(const ExtensionMessage& message) = 0;
 
+  // Select the specified host display.
+  virtual void SelectDesktopDisplay(
+      const SelectDesktopDisplayRequest& select_display) = 0;
+
  protected:
   virtual ~HostStub() {}
 
diff --git a/remoting/protocol/protocol_mock_objects.h b/remoting/protocol/protocol_mock_objects.h
index ffea02d..a9c0f16 100644
--- a/remoting/protocol/protocol_mock_objects.h
+++ b/remoting/protocol/protocol_mock_objects.h
@@ -133,6 +133,8 @@
   MOCK_METHOD1(SetCapabilities, void(const Capabilities& capabilities));
   MOCK_METHOD1(RequestPairing, void(const PairingRequest& pairing_request));
   MOCK_METHOD1(DeliverClientMessage, void(const ExtensionMessage& message));
+  MOCK_METHOD1(SelectDesktopDisplay,
+               void(const SelectDesktopDisplayRequest& message));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockHostStub);
diff --git a/remoting/protocol/video_frame_pump.cc b/remoting/protocol/video_frame_pump.cc
index 6ff904a8..91a812c8 100644
--- a/remoting/protocol/video_frame_pump.cc
+++ b/remoting/protocol/video_frame_pump.cc
@@ -102,6 +102,8 @@
   observer_ = observer;
 }
 
+void VideoFramePump::SelectSource(int id) {}
+
 void VideoFramePump::OnCaptureResult(
     webrtc::DesktopCapturer::Result result,
     std::unique_ptr<webrtc::DesktopFrame> frame) {
diff --git a/remoting/protocol/video_frame_pump.h b/remoting/protocol/video_frame_pump.h
index 01c644e7b..91a1906 100644
--- a/remoting/protocol/video_frame_pump.h
+++ b/remoting/protocol/video_frame_pump.h
@@ -86,6 +86,7 @@
   void SetLosslessEncode(bool want_lossless) override;
   void SetLosslessColor(bool want_lossless) override;
   void SetObserver(Observer* observer) override;
+  void SelectSource(int id) override;
 
   protocol::VideoFeedbackStub* video_feedback_stub() {
     return &capture_scheduler_;
diff --git a/remoting/protocol/video_stream.h b/remoting/protocol/video_stream.h
index e97bf2364..263c0fa 100644
--- a/remoting/protocol/video_stream.h
+++ b/remoting/protocol/video_stream.h
@@ -49,6 +49,9 @@
 
   // Sets stream observer.
   virtual void SetObserver(Observer* observer) = 0;
+
+  // Selects the current desktop display (if multiple displays).
+  virtual void SelectSource(int id) = 0;
 };
 
 }  // namespace protocol
diff --git a/remoting/protocol/webrtc_video_stream.cc b/remoting/protocol/webrtc_video_stream.cc
index 51ef9d7e..b26fdb24 100644
--- a/remoting/protocol/webrtc_video_stream.cc
+++ b/remoting/protocol/webrtc_video_stream.cc
@@ -160,6 +160,10 @@
                                this);
 }
 
+void WebrtcVideoStream::SelectSource(int id) {
+  capturer_->SelectSource(id);
+}
+
 void WebrtcVideoStream::SetEventTimestampsSource(
     scoped_refptr<InputEventTimestampsSource> event_timestamps_source) {
   event_timestamps_source_ = event_timestamps_source;
diff --git a/remoting/protocol/webrtc_video_stream.h b/remoting/protocol/webrtc_video_stream.h
index 796a9d9..736b645 100644
--- a/remoting/protocol/webrtc_video_stream.h
+++ b/remoting/protocol/webrtc_video_stream.h
@@ -54,6 +54,7 @@
   void SetLosslessEncode(bool want_lossless) override;
   void SetLosslessColor(bool want_lossless) override;
   void SetObserver(Observer* observer) override;
+  void SelectSource(int id) override;
 
  private:
   struct FrameStats;
diff --git a/remoting/test/fake_connection_event_logger.cc b/remoting/test/fake_connection_event_logger.cc
index f77a1a0..7ee1b37 100644
--- a/remoting/test/fake_connection_event_logger.cc
+++ b/remoting/test/fake_connection_event_logger.cc
@@ -229,6 +229,8 @@
   void RequestPairing(
       const protocol::PairingRequest& pairing_request) override {}
   void SetCapabilities(const protocol::Capabilities& capabilities) override {}
+  void SelectDesktopDisplay(
+      const protocol::SelectDesktopDisplayRequest& select_display) override{};
 };
 
 FakeConnectionEventLogger::CounterHostStub::CounterHostStub()