Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / remoting / host / desktop_session_agent.cc
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/desktop_session_agent.h"
6
7 #include "base/files/file_util.h"
8 #include "base/logging.h"
9 #include "base/memory/shared_memory.h"
10 #include "ipc/ipc_channel_proxy.h"
11 #include "ipc/ipc_message.h"
12 #include "ipc/ipc_message_macros.h"
13 #include "remoting/base/auto_thread_task_runner.h"
14 #include "remoting/base/constants.h"
15 #include "remoting/host/audio_capturer.h"
16 #include "remoting/host/chromoting_messages.h"
17 #include "remoting/host/desktop_environment.h"
18 #include "remoting/host/input_injector.h"
19 #include "remoting/host/ipc_util.h"
20 #include "remoting/host/remote_input_filter.h"
21 #include "remoting/host/screen_controls.h"
22 #include "remoting/host/screen_resolution.h"
23 #include "remoting/proto/audio.pb.h"
24 #include "remoting/proto/control.pb.h"
25 #include "remoting/proto/event.pb.h"
26 #include "remoting/protocol/clipboard_stub.h"
27 #include "remoting/protocol/input_event_tracker.h"
28 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
29 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
30 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor.h"
31 #include "third_party/webrtc/modules/desktop_capture/shared_memory.h"
32
33 namespace remoting {
34
35 namespace {
36
37 // Routes local clipboard events though the IPC channel to the network process.
38 class DesktopSesssionClipboardStub : public protocol::ClipboardStub {
39  public:
40   explicit DesktopSesssionClipboardStub(
41       scoped_refptr<DesktopSessionAgent> desktop_session_agent);
42   ~DesktopSesssionClipboardStub() override;
43
44   // protocol::ClipboardStub implementation.
45   void InjectClipboardEvent(const protocol::ClipboardEvent& event) override;
46
47  private:
48   scoped_refptr<DesktopSessionAgent> desktop_session_agent_;
49
50   DISALLOW_COPY_AND_ASSIGN(DesktopSesssionClipboardStub);
51 };
52
53 DesktopSesssionClipboardStub::DesktopSesssionClipboardStub(
54     scoped_refptr<DesktopSessionAgent> desktop_session_agent)
55     : desktop_session_agent_(desktop_session_agent) {
56 }
57
58 DesktopSesssionClipboardStub::~DesktopSesssionClipboardStub() {
59 }
60
61 void DesktopSesssionClipboardStub::InjectClipboardEvent(
62     const protocol::ClipboardEvent& event) {
63   desktop_session_agent_->InjectClipboardEvent(event);
64 }
65
66 }  // namespace
67
68 // webrtc::SharedMemory implementation that notifies creating
69 // DesktopSessionAgent when it's deleted.
70 class DesktopSessionAgent::SharedBuffer : public webrtc::SharedMemory {
71  public:
72   static scoped_ptr<SharedBuffer> Create(DesktopSessionAgent* agent,
73                                          size_t size,
74                                          int id) {
75     scoped_ptr<base::SharedMemory> memory(new base::SharedMemory());
76     if (!memory->CreateAndMapAnonymous(size))
77       return nullptr;
78     return make_scoped_ptr(new SharedBuffer(agent, memory.Pass(), size, id));
79   }
80
81   ~SharedBuffer() override { agent_->OnSharedBufferDeleted(id()); }
82
83  private:
84   SharedBuffer(DesktopSessionAgent* agent,
85                scoped_ptr<base::SharedMemory> memory,
86                size_t size,
87                int id)
88       : SharedMemory(memory->memory(), size,
89 #if defined(OS_WIN)
90                      memory->handle(),
91 #else
92                      memory->handle().fd,
93 #endif
94                      id),
95         agent_(agent),
96         shared_memory_(memory.Pass()) {
97   }
98
99   DesktopSessionAgent* agent_;
100   scoped_ptr<base::SharedMemory> shared_memory_;
101
102   DISALLOW_COPY_AND_ASSIGN(SharedBuffer);
103 };
104
105 DesktopSessionAgent::Delegate::~Delegate() {
106 }
107
108 DesktopSessionAgent::DesktopSessionAgent(
109     scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner,
110     scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
111     scoped_refptr<AutoThreadTaskRunner> input_task_runner,
112     scoped_refptr<AutoThreadTaskRunner> io_task_runner,
113     scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner)
114     : audio_capture_task_runner_(audio_capture_task_runner),
115       caller_task_runner_(caller_task_runner),
116       input_task_runner_(input_task_runner),
117       io_task_runner_(io_task_runner),
118       video_capture_task_runner_(video_capture_task_runner),
119       next_shared_buffer_id_(1),
120       shared_buffers_(0),
121       started_(false),
122       weak_factory_(this) {
123   DCHECK(caller_task_runner_->BelongsToCurrentThread());
124 }
125
126 bool DesktopSessionAgent::OnMessageReceived(const IPC::Message& message) {
127   DCHECK(caller_task_runner_->BelongsToCurrentThread());
128
129   bool handled = true;
130   if (started_) {
131     IPC_BEGIN_MESSAGE_MAP(DesktopSessionAgent, message)
132       IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_CaptureFrame,
133                           OnCaptureFrame)
134       IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_InjectClipboardEvent,
135                           OnInjectClipboardEvent)
136       IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_InjectKeyEvent,
137                           OnInjectKeyEvent)
138       IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_InjectTextEvent,
139                           OnInjectTextEvent)
140       IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_InjectMouseEvent,
141                           OnInjectMouseEvent)
142       IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_SetScreenResolution,
143                           SetScreenResolution)
144       IPC_MESSAGE_UNHANDLED(handled = false)
145     IPC_END_MESSAGE_MAP()
146   } else {
147     IPC_BEGIN_MESSAGE_MAP(DesktopSessionAgent, message)
148       IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_StartSessionAgent,
149                           OnStartSessionAgent)
150       IPC_MESSAGE_UNHANDLED(handled = false)
151     IPC_END_MESSAGE_MAP()
152   }
153
154   CHECK(handled) << "Received unexpected IPC type: " << message.type();
155   return handled;
156 }
157
158 void DesktopSessionAgent::OnChannelConnected(int32 peer_pid) {
159   DCHECK(caller_task_runner_->BelongsToCurrentThread());
160
161   VLOG(1) << "IPC: desktop <- network (" << peer_pid << ")";
162
163   desktop_pipe_.Close();
164 }
165
166 void DesktopSessionAgent::OnChannelError() {
167   DCHECK(caller_task_runner_->BelongsToCurrentThread());
168
169   // Make sure the channel is closed.
170   network_channel_.reset();
171   desktop_pipe_.Close();
172
173   // Notify the caller that the channel has been disconnected.
174   if (delegate_.get())
175     delegate_->OnNetworkProcessDisconnected();
176 }
177
178 webrtc::SharedMemory* DesktopSessionAgent::CreateSharedMemory(size_t size) {
179   DCHECK(video_capture_task_runner_->BelongsToCurrentThread());
180
181   scoped_ptr<SharedBuffer> buffer =
182       SharedBuffer::Create(this, size, next_shared_buffer_id_);
183   if (buffer) {
184     shared_buffers_++;
185
186     // |next_shared_buffer_id_| starts from 1 and incrementing it by 2 makes
187     // sure it is always odd and therefore zero is never used as a valid buffer
188     // ID.
189     //
190     // It is very unlikely (though theoretically possible) to allocate the same
191     // ID for two different buffers due to integer overflow. It should take
192     // about a year of allocating 100 new buffers every second. Practically
193     // speaking it never happens.
194     next_shared_buffer_id_ += 2;
195
196     IPC::PlatformFileForTransit handle;
197 #if defined(OS_WIN)
198     handle = buffer->handle();
199 #else
200     handle = base::FileDescriptor(buffer->handle(), false);
201 #endif
202     SendToNetwork(new ChromotingDesktopNetworkMsg_CreateSharedBuffer(
203         buffer->id(), handle, buffer->size()));
204   }
205
206   return buffer.release();
207 }
208
209 DesktopSessionAgent::~DesktopSessionAgent() {
210   DCHECK(!audio_capturer_);
211   DCHECK(!desktop_environment_);
212   DCHECK(!network_channel_);
213   DCHECK(!screen_controls_);
214   DCHECK(!video_capturer_);
215 }
216
217 const std::string& DesktopSessionAgent::client_jid() const {
218   return client_jid_;
219 }
220
221 void DesktopSessionAgent::DisconnectSession() {
222   SendToNetwork(new ChromotingDesktopNetworkMsg_DisconnectSession());
223 }
224
225 void DesktopSessionAgent::OnLocalMouseMoved(
226     const webrtc::DesktopVector& new_pos) {
227   DCHECK(caller_task_runner_->BelongsToCurrentThread());
228
229   remote_input_filter_->LocalMouseMoved(new_pos);
230 }
231
232 void DesktopSessionAgent::SetDisableInputs(bool disable_inputs) {
233   DCHECK(caller_task_runner_->BelongsToCurrentThread());
234
235   // Do not expect this method to be called because it is only used by It2Me.
236   NOTREACHED();
237 }
238
239 void DesktopSessionAgent::ResetVideoPipeline() {
240   DCHECK(caller_task_runner_->BelongsToCurrentThread());
241
242   // This method is only used by HostExtensionSessions in the network process.
243   NOTREACHED();
244 }
245
246 void DesktopSessionAgent::OnStartSessionAgent(
247     const std::string& authenticated_jid,
248     const ScreenResolution& resolution,
249     bool virtual_terminal) {
250   DCHECK(caller_task_runner_->BelongsToCurrentThread());
251   DCHECK(!started_);
252   DCHECK(!audio_capturer_);
253   DCHECK(!desktop_environment_);
254   DCHECK(!input_injector_);
255   DCHECK(!screen_controls_);
256   DCHECK(!video_capturer_);
257
258   started_ = true;
259   client_jid_ = authenticated_jid;
260
261   // Enable the curtain mode.
262   delegate_->desktop_environment_factory().SetEnableCurtaining(
263       virtual_terminal);
264
265   // Create a desktop environment for the new session.
266   desktop_environment_ = delegate_->desktop_environment_factory().Create(
267       weak_factory_.GetWeakPtr());
268
269   // Create the session controller and set the initial screen resolution.
270   screen_controls_ = desktop_environment_->CreateScreenControls();
271   SetScreenResolution(resolution);
272
273   // Create the input injector.
274   input_injector_ = desktop_environment_->CreateInputInjector();
275
276   // Hook up the input filter.
277   input_tracker_.reset(new protocol::InputEventTracker(input_injector_.get()));
278   remote_input_filter_.reset(new RemoteInputFilter(input_tracker_.get()));
279
280 #if defined(OS_WIN)
281   // LocalInputMonitorWin filters out an echo of the injected input before it
282   // reaches |remote_input_filter_|.
283   remote_input_filter_->SetExpectLocalEcho(false);
284 #endif  // defined(OS_WIN)
285
286   // Start the input injector.
287   scoped_ptr<protocol::ClipboardStub> clipboard_stub(
288       new DesktopSesssionClipboardStub(this));
289   input_injector_->Start(clipboard_stub.Pass());
290
291   // Start the audio capturer.
292   if (delegate_->desktop_environment_factory().SupportsAudioCapture()) {
293     audio_capturer_ = desktop_environment_->CreateAudioCapturer();
294     audio_capture_task_runner_->PostTask(
295         FROM_HERE, base::Bind(&DesktopSessionAgent::StartAudioCapturer, this));
296   }
297
298   // Start the video capturer and mouse cursor monitor.
299   video_capturer_ = desktop_environment_->CreateVideoCapturer();
300   mouse_cursor_monitor_ = desktop_environment_->CreateMouseCursorMonitor();
301   video_capture_task_runner_->PostTask(
302       FROM_HERE, base::Bind(
303           &DesktopSessionAgent::StartVideoCapturerAndMouseMonitor, this));
304 }
305
306 void DesktopSessionAgent::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
307   DCHECK(video_capture_task_runner_->BelongsToCurrentThread());
308
309   last_frame_.reset(frame);
310
311   current_size_ = frame->size();
312
313   // Serialize webrtc::DesktopFrame.
314   SerializedDesktopFrame serialized_frame;
315   serialized_frame.shared_buffer_id = frame->shared_memory()->id();
316   serialized_frame.bytes_per_row = frame->stride();
317   serialized_frame.dimensions = frame->size();
318   serialized_frame.capture_time_ms = frame->capture_time_ms();
319   serialized_frame.dpi = frame->dpi();
320   for (webrtc::DesktopRegion::Iterator i(frame->updated_region());
321        !i.IsAtEnd(); i.Advance()) {
322     serialized_frame.dirty_region.push_back(i.rect());
323   }
324
325   SendToNetwork(
326       new ChromotingDesktopNetworkMsg_CaptureCompleted(serialized_frame));
327 }
328
329 void DesktopSessionAgent::OnMouseCursor(webrtc::MouseCursor* cursor) {
330   DCHECK(video_capture_task_runner_->BelongsToCurrentThread());
331
332   scoped_ptr<webrtc::MouseCursor> owned_cursor(cursor);
333
334   SendToNetwork(
335       new ChromotingDesktopNetworkMsg_MouseCursor(*owned_cursor));
336 }
337
338 void DesktopSessionAgent::OnMouseCursorPosition(
339     webrtc::MouseCursorMonitor::CursorState state,
340     const webrtc::DesktopVector& position) {
341   // We're not subscribing to mouse position changes.
342   NOTREACHED();
343 }
344
345 void DesktopSessionAgent::InjectClipboardEvent(
346     const protocol::ClipboardEvent& event) {
347   DCHECK(caller_task_runner_->BelongsToCurrentThread());
348
349   std::string serialized_event;
350   if (!event.SerializeToString(&serialized_event)) {
351     LOG(ERROR) << "Failed to serialize protocol::ClipboardEvent.";
352     return;
353   }
354
355   SendToNetwork(
356       new ChromotingDesktopNetworkMsg_InjectClipboardEvent(serialized_event));
357 }
358
359 void DesktopSessionAgent::ProcessAudioPacket(scoped_ptr<AudioPacket> packet) {
360   DCHECK(audio_capture_task_runner_->BelongsToCurrentThread());
361
362   std::string serialized_packet;
363   if (!packet->SerializeToString(&serialized_packet)) {
364     LOG(ERROR) << "Failed to serialize AudioPacket.";
365     return;
366   }
367
368   SendToNetwork(new ChromotingDesktopNetworkMsg_AudioPacket(serialized_packet));
369 }
370
371 bool DesktopSessionAgent::Start(const base::WeakPtr<Delegate>& delegate,
372                                 IPC::PlatformFileForTransit* desktop_pipe_out) {
373   DCHECK(caller_task_runner_->BelongsToCurrentThread());
374   DCHECK(delegate_.get() == NULL);
375
376   delegate_ = delegate;
377
378   // Create an IPC channel to communicate with the network process.
379   bool result = CreateConnectedIpcChannel(io_task_runner_,
380                                           this,
381                                           &desktop_pipe_,
382                                           &network_channel_);
383   base::PlatformFile raw_desktop_pipe = desktop_pipe_.GetPlatformFile();
384 #if defined(OS_WIN)
385   *desktop_pipe_out = IPC::PlatformFileForTransit(raw_desktop_pipe);
386 #elif defined(OS_POSIX)
387   *desktop_pipe_out = IPC::PlatformFileForTransit(raw_desktop_pipe, false);
388 #else
389 #error Unsupported platform.
390 #endif
391   return result;
392 }
393
394 void DesktopSessionAgent::Stop() {
395   DCHECK(caller_task_runner_->BelongsToCurrentThread());
396
397   delegate_.reset();
398
399   // Make sure the channel is closed.
400   network_channel_.reset();
401
402   if (started_) {
403     started_ = false;
404
405     // Ignore any further callbacks.
406     weak_factory_.InvalidateWeakPtrs();
407     client_jid_.clear();
408
409     remote_input_filter_.reset();
410
411     // Ensure that any pressed keys or buttons are released.
412     input_tracker_->ReleaseAll();
413     input_tracker_.reset();
414
415     desktop_environment_.reset();
416     input_injector_.reset();
417     screen_controls_.reset();
418
419     // Stop the audio capturer.
420     audio_capture_task_runner_->PostTask(
421         FROM_HERE, base::Bind(&DesktopSessionAgent::StopAudioCapturer, this));
422
423     // Stop the video capturer.
424     video_capture_task_runner_->PostTask(
425         FROM_HERE, base::Bind(
426             &DesktopSessionAgent::StopVideoCapturerAndMouseMonitor, this));
427   }
428 }
429
430 void DesktopSessionAgent::OnCaptureFrame() {
431   if (!video_capture_task_runner_->BelongsToCurrentThread()) {
432     video_capture_task_runner_->PostTask(
433         FROM_HERE,
434         base::Bind(&DesktopSessionAgent::OnCaptureFrame, this));
435     return;
436   }
437
438   mouse_cursor_monitor_->Capture();
439
440   // webrtc::DesktopCapturer supports a very few (currently 2) outstanding
441   // capture requests. The requests are serialized on
442   // |video_capture_task_runner()| task runner. If the client issues more
443   // requests, pixel data in captured frames will likely be corrupted but
444   // stability of webrtc::DesktopCapturer will not be affected.
445   video_capturer_->Capture(webrtc::DesktopRegion());
446 }
447
448 void DesktopSessionAgent::OnInjectClipboardEvent(
449     const std::string& serialized_event) {
450   DCHECK(caller_task_runner_->BelongsToCurrentThread());
451
452   protocol::ClipboardEvent event;
453   if (!event.ParseFromString(serialized_event)) {
454     LOG(ERROR) << "Failed to parse protocol::ClipboardEvent.";
455     return;
456   }
457
458   // InputStub implementations must verify events themselves, so we don't need
459   // verification here. This matches HostEventDispatcher.
460   input_injector_->InjectClipboardEvent(event);
461 }
462
463 void DesktopSessionAgent::OnInjectKeyEvent(
464     const std::string& serialized_event) {
465   DCHECK(caller_task_runner_->BelongsToCurrentThread());
466
467   protocol::KeyEvent event;
468   if (!event.ParseFromString(serialized_event)) {
469     LOG(ERROR) << "Failed to parse protocol::KeyEvent.";
470     return;
471   }
472
473   // InputStub implementations must verify events themselves, so we need only
474   // basic verification here. This matches HostEventDispatcher.
475   if (!event.has_usb_keycode() || !event.has_pressed()) {
476     LOG(ERROR) << "Received invalid key event.";
477     return;
478   }
479
480   remote_input_filter_->InjectKeyEvent(event);
481 }
482
483 void DesktopSessionAgent::OnInjectTextEvent(
484     const std::string& serialized_event) {
485   DCHECK(caller_task_runner_->BelongsToCurrentThread());
486
487   protocol::TextEvent event;
488   if (!event.ParseFromString(serialized_event)) {
489     LOG(ERROR) << "Failed to parse protocol::TextEvent.";
490     return;
491   }
492
493   // InputStub implementations must verify events themselves, so we need only
494   // basic verification here. This matches HostEventDispatcher.
495   if (!event.has_text()) {
496     LOG(ERROR) << "Received invalid TextEvent.";
497     return;
498   }
499
500   remote_input_filter_->InjectTextEvent(event);
501 }
502
503 void DesktopSessionAgent::OnInjectMouseEvent(
504     const std::string& serialized_event) {
505   DCHECK(caller_task_runner_->BelongsToCurrentThread());
506
507   protocol::MouseEvent event;
508   if (!event.ParseFromString(serialized_event)) {
509     LOG(ERROR) << "Failed to parse protocol::MouseEvent.";
510     return;
511   }
512
513   // InputStub implementations must verify events themselves, so we don't need
514   // verification here. This matches HostEventDispatcher.
515   remote_input_filter_->InjectMouseEvent(event);
516 }
517
518 void DesktopSessionAgent::SetScreenResolution(
519     const ScreenResolution& resolution) {
520   DCHECK(caller_task_runner_->BelongsToCurrentThread());
521
522   if (screen_controls_ && resolution.IsEmpty())
523     screen_controls_->SetScreenResolution(resolution);
524 }
525
526 void DesktopSessionAgent::SendToNetwork(IPC::Message* message) {
527   if (!caller_task_runner_->BelongsToCurrentThread()) {
528     caller_task_runner_->PostTask(
529         FROM_HERE,
530         base::Bind(&DesktopSessionAgent::SendToNetwork, this, message));
531     return;
532   }
533
534   if (network_channel_) {
535     network_channel_->Send(message);
536   } else {
537     delete message;
538   }
539 }
540
541 void DesktopSessionAgent::StartAudioCapturer() {
542   DCHECK(audio_capture_task_runner_->BelongsToCurrentThread());
543
544   if (audio_capturer_) {
545     audio_capturer_->Start(base::Bind(&DesktopSessionAgent::ProcessAudioPacket,
546                                       this));
547   }
548 }
549
550 void DesktopSessionAgent::StopAudioCapturer() {
551   DCHECK(audio_capture_task_runner_->BelongsToCurrentThread());
552
553   audio_capturer_.reset();
554 }
555
556 void DesktopSessionAgent::StartVideoCapturerAndMouseMonitor() {
557   DCHECK(video_capture_task_runner_->BelongsToCurrentThread());
558
559   if (video_capturer_) {
560     video_capturer_->Start(this);
561   }
562
563   if (mouse_cursor_monitor_) {
564     mouse_cursor_monitor_->Init(this, webrtc::MouseCursorMonitor::SHAPE_ONLY);
565   }
566 }
567
568 void DesktopSessionAgent::StopVideoCapturerAndMouseMonitor() {
569   DCHECK(video_capture_task_runner_->BelongsToCurrentThread());
570
571   video_capturer_.reset();
572   last_frame_.reset();
573   mouse_cursor_monitor_.reset();
574
575   // Video capturer must delete all buffers.
576   DCHECK_EQ(shared_buffers_, 0);
577 }
578
579 void DesktopSessionAgent::OnSharedBufferDeleted(int id) {
580   DCHECK(video_capture_task_runner_->BelongsToCurrentThread());
581   DCHECK(id != 0);
582
583   shared_buffers_--;
584   DCHECK_GE(shared_buffers_, 0);
585   SendToNetwork(new ChromotingDesktopNetworkMsg_ReleaseSharedBuffer(id));
586 }
587
588 }  // namespace remoting