1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "remoting/host/ipc_desktop_environment.h" 6 7 #include <utility> 8 9 #include "base/compiler_specific.h" 10 #include "base/logging.h" 11 #include "base/process/process_handle.h" 12 #include "base/single_thread_task_runner.h" 13 #include "ipc/ipc_sender.h" 14 #include "remoting/host/audio_capturer.h" 15 #include "remoting/host/chromoting_messages.h" 16 #include "remoting/host/client_session_control.h" 17 #include "remoting/host/desktop_session.h" 18 #include "remoting/host/desktop_session_proxy.h" 19 #include "remoting/host/input_injector.h" 20 #include "remoting/host/screen_controls.h" 21 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" 22 23 namespace remoting { 24 25 IpcDesktopEnvironment::IpcDesktopEnvironment( 26 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner, 27 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, 28 scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner, 29 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, 30 base::WeakPtr<ClientSessionControl> client_session_control, 31 base::WeakPtr<DesktopSessionConnector> desktop_session_connector, 32 bool virtual_terminal) { 33 DCHECK(caller_task_runner->BelongsToCurrentThread()); 34 35 desktop_session_proxy_ = new DesktopSessionProxy(audio_task_runner, 36 caller_task_runner, 37 io_task_runner, 38 capture_task_runner, 39 client_session_control, 40 desktop_session_connector, 41 virtual_terminal); 42 } 43 44 IpcDesktopEnvironment::~IpcDesktopEnvironment() { 45 } 46 47 scoped_ptr<AudioCapturer> IpcDesktopEnvironment::CreateAudioCapturer() { 48 return desktop_session_proxy_->CreateAudioCapturer(); 49 } 50 51 scoped_ptr<InputInjector> IpcDesktopEnvironment::CreateInputInjector() { 52 return desktop_session_proxy_->CreateInputInjector(); 53 } 54 55 scoped_ptr<ScreenControls> IpcDesktopEnvironment::CreateScreenControls() { 56 return desktop_session_proxy_->CreateScreenControls(); 57 } 58 59 scoped_ptr<webrtc::ScreenCapturer> 60 IpcDesktopEnvironment::CreateVideoCapturer() { 61 return desktop_session_proxy_->CreateVideoCapturer(); 62 } 63 64 std::string IpcDesktopEnvironment::GetCapabilities() const { 65 return desktop_session_proxy_->GetCapabilities(); 66 } 67 68 void IpcDesktopEnvironment::SetCapabilities(const std::string& capabilities) { 69 return desktop_session_proxy_->SetCapabilities(capabilities); 70 } 71 72 IpcDesktopEnvironmentFactory::IpcDesktopEnvironmentFactory( 73 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner, 74 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, 75 scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner, 76 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, 77 IPC::Sender* daemon_channel) 78 : audio_task_runner_(audio_task_runner), 79 caller_task_runner_(caller_task_runner), 80 capture_task_runner_(capture_task_runner), 81 io_task_runner_(io_task_runner), 82 curtain_enabled_(false), 83 daemon_channel_(daemon_channel), 84 connector_factory_(this), 85 next_id_(0) { 86 } 87 88 IpcDesktopEnvironmentFactory::~IpcDesktopEnvironmentFactory() { 89 } 90 91 scoped_ptr<DesktopEnvironment> IpcDesktopEnvironmentFactory::Create( 92 base::WeakPtr<ClientSessionControl> client_session_control) { 93 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 94 95 return scoped_ptr<DesktopEnvironment>( 96 new IpcDesktopEnvironment(audio_task_runner_, 97 caller_task_runner_, 98 capture_task_runner_, 99 io_task_runner_, 100 client_session_control, 101 connector_factory_.GetWeakPtr(), 102 curtain_enabled_)); 103 } 104 105 void IpcDesktopEnvironmentFactory::SetEnableCurtaining(bool enable) { 106 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 107 108 curtain_enabled_ = enable; 109 } 110 111 bool IpcDesktopEnvironmentFactory::SupportsAudioCapture() const { 112 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 113 114 return AudioCapturer::IsSupported(); 115 } 116 117 void IpcDesktopEnvironmentFactory::ConnectTerminal( 118 DesktopSessionProxy* desktop_session_proxy, 119 const ScreenResolution& resolution, 120 bool virtual_terminal) { 121 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 122 123 int id = next_id_++; 124 bool inserted = active_connections_.insert( 125 std::make_pair(id, desktop_session_proxy)).second; 126 CHECK(inserted); 127 128 VLOG(1) << "Network: registered desktop environment " << id; 129 130 daemon_channel_->Send(new ChromotingNetworkHostMsg_ConnectTerminal( 131 id, resolution, virtual_terminal)); 132 } 133 134 void IpcDesktopEnvironmentFactory::DisconnectTerminal( 135 DesktopSessionProxy* desktop_session_proxy) { 136 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 137 138 ActiveConnectionsList::iterator i; 139 for (i = active_connections_.begin(); i != active_connections_.end(); ++i) { 140 if (i->second == desktop_session_proxy) 141 break; 142 } 143 144 if (i != active_connections_.end()) { 145 int id = i->first; 146 active_connections_.erase(i); 147 148 VLOG(1) << "Network: unregistered desktop environment " << id; 149 daemon_channel_->Send(new ChromotingNetworkHostMsg_DisconnectTerminal(id)); 150 } 151 } 152 153 void IpcDesktopEnvironmentFactory::SetScreenResolution( 154 DesktopSessionProxy* desktop_session_proxy, 155 const ScreenResolution& resolution) { 156 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 157 158 ActiveConnectionsList::iterator i; 159 for (i = active_connections_.begin(); i != active_connections_.end(); ++i) { 160 if (i->second == desktop_session_proxy) 161 break; 162 } 163 164 if (i != active_connections_.end()) { 165 daemon_channel_->Send(new ChromotingNetworkDaemonMsg_SetScreenResolution( 166 i->first, resolution)); 167 } 168 } 169 170 void IpcDesktopEnvironmentFactory::OnDesktopSessionAgentAttached( 171 int terminal_id, 172 base::ProcessHandle desktop_process, 173 IPC::PlatformFileForTransit desktop_pipe) { 174 if (!caller_task_runner_->BelongsToCurrentThread()) { 175 caller_task_runner_->PostTask(FROM_HERE, base::Bind( 176 &IpcDesktopEnvironmentFactory::OnDesktopSessionAgentAttached, 177 base::Unretained(this), terminal_id, desktop_process, desktop_pipe)); 178 return; 179 } 180 181 ActiveConnectionsList::iterator i = active_connections_.find(terminal_id); 182 if (i != active_connections_.end()) { 183 i->second->DetachFromDesktop(); 184 i->second->AttachToDesktop(desktop_process, desktop_pipe); 185 } else { 186 base::CloseProcessHandle(desktop_process); 187 188 #if defined(OS_POSIX) 189 DCHECK(desktop_pipe.auto_close); 190 191 base::ClosePlatformFile(desktop_pipe.fd); 192 #endif // defined(OS_POSIX) 193 } 194 } 195 196 void IpcDesktopEnvironmentFactory::OnTerminalDisconnected(int terminal_id) { 197 if (!caller_task_runner_->BelongsToCurrentThread()) { 198 caller_task_runner_->PostTask(FROM_HERE, base::Bind( 199 &IpcDesktopEnvironmentFactory::OnTerminalDisconnected, 200 base::Unretained(this), terminal_id)); 201 return; 202 } 203 204 ActiveConnectionsList::iterator i = active_connections_.find(terminal_id); 205 if (i != active_connections_.end()) { 206 DesktopSessionProxy* desktop_session_proxy = i->second; 207 active_connections_.erase(i); 208 209 // Disconnect the client session. 210 desktop_session_proxy->DisconnectSession(); 211 } 212 } 213 214 } // namespace remoting 215