Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(281)

Side by Side Diff: remoting/host/desktop_session_proxy.cc

Issue 13983010: Use webrtc::DesktopCapturer for screen capturer implementation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/host/desktop_session_proxy.h ('k') | remoting/host/desktop_session_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/host/desktop_session_proxy.h" 5 #include "remoting/host/desktop_session_proxy.h"
6 6
7 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/platform_file.h" 9 #include "base/platform_file.h"
10 #include "base/process_util.h" 10 #include "base/process_util.h"
11 #include "base/memory/shared_memory.h"
11 #include "base/single_thread_task_runner.h" 12 #include "base/single_thread_task_runner.h"
12 #include "ipc/ipc_channel_proxy.h" 13 #include "ipc/ipc_channel_proxy.h"
13 #include "ipc/ipc_message_macros.h" 14 #include "ipc/ipc_message_macros.h"
14 #include "media/video/capture/screen/screen_capture_data.h"
15 #include "remoting/base/capabilities.h" 15 #include "remoting/base/capabilities.h"
16 #include "remoting/host/chromoting_messages.h" 16 #include "remoting/host/chromoting_messages.h"
17 #include "remoting/host/client_session.h" 17 #include "remoting/host/client_session.h"
18 #include "remoting/host/client_session_control.h" 18 #include "remoting/host/client_session_control.h"
19 #include "remoting/host/desktop_session_connector.h" 19 #include "remoting/host/desktop_session_connector.h"
20 #include "remoting/host/ipc_audio_capturer.h" 20 #include "remoting/host/ipc_audio_capturer.h"
21 #include "remoting/host/ipc_input_injector.h" 21 #include "remoting/host/ipc_input_injector.h"
22 #include "remoting/host/ipc_screen_controls.h" 22 #include "remoting/host/ipc_screen_controls.h"
23 #include "remoting/host/ipc_video_frame_capturer.h" 23 #include "remoting/host/ipc_video_frame_capturer.h"
24 #include "remoting/proto/audio.pb.h" 24 #include "remoting/proto/audio.pb.h"
25 #include "remoting/proto/control.pb.h" 25 #include "remoting/proto/control.pb.h"
26 #include "remoting/proto/event.pb.h" 26 #include "remoting/proto/event.pb.h"
27 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
28 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
29 #include "third_party/webrtc/modules/desktop_capture/shared_memory.h"
27 30
28 #if defined(OS_WIN) 31 #if defined(OS_WIN)
29 #include "base/win/scoped_handle.h" 32 #include "base/win/scoped_handle.h"
30 #endif // defined(OS_WIN) 33 #endif // defined(OS_WIN)
31 34
35 const bool kReadOnly = true;
32 const char kSendInitialResolution[] = "sendInitialResolution"; 36 const char kSendInitialResolution[] = "sendInitialResolution";
33 37
34 namespace remoting { 38 namespace remoting {
35 39
40 class DesktopSessionProxy::IpcSharedBufferCore
41 : public base::RefCountedThreadSafe<IpcSharedBufferCore> {
42 public:
43 IpcSharedBufferCore(int id,
44 base::SharedMemoryHandle handle,
45 base::ProcessHandle process,
46 size_t size)
47 : id_(id),
48 #if defined(OS_WIN)
49 shared_memory_(handle, kReadOnly, process),
50 #else // !defined(OS_WIN)
51 shared_memory_(handle, kReadOnly),
52 #endif // !defined(OS_WIN)
53 size_(size) {
54 if (!shared_memory_.Map(size)) {
55 LOG(ERROR) << "Failed to map a shared buffer: id=" << id
56 #if defined(OS_WIN)
57 << ", handle=" << handle
58 #else
59 << ", handle.fd=" << handle.fd
60 #endif
61 << ", size=" << size;
62 }
63 }
64
65 int id() { return id_; }
66 size_t size() { return size_; }
67 void* memory() { return shared_memory_.memory(); }
68 webrtc::SharedMemory::Handle handle() {
69 #if defined(OS_WIN)
70 return shared_memory_.handle();
71 #else
72 return shared_memory_.handle().fd;
73 #endif
74 }
75
76 private:
77 virtual ~IpcSharedBufferCore() {}
78 friend class base::RefCountedThreadSafe<IpcSharedBufferCore>;
79
80 int id_;
81 base::SharedMemory shared_memory_;
82 size_t size_;
83
84 DISALLOW_COPY_AND_ASSIGN(IpcSharedBufferCore);
85 };
86
87 class DesktopSessionProxy::IpcSharedBuffer : public webrtc::SharedMemory {
88 public:
89 IpcSharedBuffer(scoped_refptr<IpcSharedBufferCore> core)
90 : SharedMemory(core->memory(), core->size(),
91 core->handle(), core->id()),
92 core_(core) {
93 }
94
95 private:
96 scoped_refptr<IpcSharedBufferCore> core_;
97
98 DISALLOW_COPY_AND_ASSIGN(IpcSharedBuffer);
99 };
100
36 DesktopSessionProxy::DesktopSessionProxy( 101 DesktopSessionProxy::DesktopSessionProxy(
37 scoped_refptr<base::SingleThreadTaskRunner> audio_capture_task_runner, 102 scoped_refptr<base::SingleThreadTaskRunner> audio_capture_task_runner,
38 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, 103 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
39 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, 104 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
40 scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner, 105 scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner,
41 base::WeakPtr<ClientSessionControl> client_session_control, 106 base::WeakPtr<ClientSessionControl> client_session_control,
42 base::WeakPtr<DesktopSessionConnector> desktop_session_connector, 107 base::WeakPtr<DesktopSessionConnector> desktop_session_connector,
43 bool virtual_terminal) 108 bool virtual_terminal)
44 : audio_capture_task_runner_(audio_capture_task_runner), 109 : audio_capture_task_runner_(audio_capture_task_runner),
45 caller_task_runner_(caller_task_runner), 110 caller_task_runner_(caller_task_runner),
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 if (desktop_process_ != base::kNullProcessHandle) { 273 if (desktop_process_ != base::kNullProcessHandle) {
209 base::CloseProcessHandle(desktop_process_); 274 base::CloseProcessHandle(desktop_process_);
210 desktop_process_ = base::kNullProcessHandle; 275 desktop_process_ = base::kNullProcessHandle;
211 } 276 }
212 277
213 shared_buffers_.clear(); 278 shared_buffers_.clear();
214 279
215 // Generate fake responses to keep the video capturer in sync. 280 // Generate fake responses to keep the video capturer in sync.
216 while (pending_capture_frame_requests_) { 281 while (pending_capture_frame_requests_) {
217 --pending_capture_frame_requests_; 282 --pending_capture_frame_requests_;
218 PostCaptureCompleted(scoped_refptr<media::ScreenCaptureData>()); 283 PostCaptureCompleted(scoped_ptr<webrtc::DesktopFrame>());
219 } 284 }
220 } 285 }
221 286
222 void DesktopSessionProxy::SetAudioCapturer( 287 void DesktopSessionProxy::SetAudioCapturer(
223 const base::WeakPtr<IpcAudioCapturer>& audio_capturer) { 288 const base::WeakPtr<IpcAudioCapturer>& audio_capturer) {
224 DCHECK(audio_capture_task_runner_->BelongsToCurrentThread()); 289 DCHECK(audio_capture_task_runner_->BelongsToCurrentThread());
225 290
226 audio_capturer_ = audio_capturer; 291 audio_capturer_ = audio_capturer;
227 } 292 }
228 293
229 void DesktopSessionProxy::CaptureFrame() { 294 void DesktopSessionProxy::CaptureFrame() {
230 if (!caller_task_runner_->BelongsToCurrentThread()) { 295 if (!caller_task_runner_->BelongsToCurrentThread()) {
231 caller_task_runner_->PostTask( 296 caller_task_runner_->PostTask(
232 FROM_HERE, base::Bind(&DesktopSessionProxy::CaptureFrame, this)); 297 FROM_HERE, base::Bind(&DesktopSessionProxy::CaptureFrame, this));
233 return; 298 return;
234 } 299 }
235 300
236 if (desktop_channel_) { 301 if (desktop_channel_) {
237 ++pending_capture_frame_requests_; 302 ++pending_capture_frame_requests_;
238 SendToDesktop(new ChromotingNetworkDesktopMsg_CaptureFrame()); 303 SendToDesktop(new ChromotingNetworkDesktopMsg_CaptureFrame());
239 } else { 304 } else {
240 PostCaptureCompleted(scoped_refptr<media::ScreenCaptureData>()); 305 PostCaptureCompleted(scoped_ptr<webrtc::DesktopFrame>());
241 } 306 }
242 } 307 }
243 308
244 void DesktopSessionProxy::SetVideoCapturer( 309 void DesktopSessionProxy::SetVideoCapturer(
245 const base::WeakPtr<IpcVideoFrameCapturer> video_capturer) { 310 const base::WeakPtr<IpcVideoFrameCapturer> video_capturer) {
246 DCHECK(video_capture_task_runner_->BelongsToCurrentThread()); 311 DCHECK(video_capture_task_runner_->BelongsToCurrentThread());
247 312
248 video_capturer_ = video_capturer; 313 video_capturer_ = video_capturer;
249 } 314 }
250 315
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 scoped_ptr<protocol::ClipboardStub> client_clipboard) { 365 scoped_ptr<protocol::ClipboardStub> client_clipboard) {
301 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 366 DCHECK(caller_task_runner_->BelongsToCurrentThread());
302 367
303 client_clipboard_ = client_clipboard.Pass(); 368 client_clipboard_ = client_clipboard.Pass();
304 } 369 }
305 370
306 void DesktopSessionProxy::SetScreenResolution( 371 void DesktopSessionProxy::SetScreenResolution(
307 const ScreenResolution& resolution) { 372 const ScreenResolution& resolution) {
308 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 373 DCHECK(caller_task_runner_->BelongsToCurrentThread());
309 374
310 if (!resolution.IsValid()) 375 if (!resolution.IsEmpty())
311 return; 376 return;
312 377
313 screen_resolution_ = resolution; 378 screen_resolution_ = resolution;
314 379
315 // Connect to the desktop session if it is not done yet. 380 // Connect to the desktop session if it is not done yet.
316 if (!is_desktop_session_connected_) { 381 if (!is_desktop_session_connected_) {
317 is_desktop_session_connected_ = true; 382 is_desktop_session_connected_ = true;
318 if (desktop_session_connector_) { 383 if (desktop_session_connector_) {
319 desktop_session_connector_->ConnectTerminal(this, screen_resolution_, 384 desktop_session_connector_->ConnectTerminal(this, screen_resolution_,
320 virtual_terminal_); 385 virtual_terminal_);
(...skipping 16 matching lines...) Expand all
337 402
338 if (desktop_session_connector_ && is_desktop_session_connected_) 403 if (desktop_session_connector_ && is_desktop_session_connected_)
339 desktop_session_connector_->DisconnectTerminal(this); 404 desktop_session_connector_->DisconnectTerminal(this);
340 405
341 if (desktop_process_ != base::kNullProcessHandle) { 406 if (desktop_process_ != base::kNullProcessHandle) {
342 base::CloseProcessHandle(desktop_process_); 407 base::CloseProcessHandle(desktop_process_);
343 desktop_process_ = base::kNullProcessHandle; 408 desktop_process_ = base::kNullProcessHandle;
344 } 409 }
345 } 410 }
346 411
347 scoped_refptr<media::SharedBuffer> DesktopSessionProxy::GetSharedBuffer( 412 scoped_refptr<DesktopSessionProxy::IpcSharedBufferCore>
348 int id) { 413 DesktopSessionProxy::GetSharedBufferCore(int id) {
349 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 414 DCHECK(caller_task_runner_->BelongsToCurrentThread());
350 415
351 SharedBuffers::const_iterator i = shared_buffers_.find(id); 416 SharedBuffers::const_iterator i = shared_buffers_.find(id);
352 if (i != shared_buffers_.end()) { 417 if (i != shared_buffers_.end()) {
353 return i->second; 418 return i->second;
354 } else { 419 } else {
355 LOG(ERROR) << "Failed to find the shared buffer " << id; 420 LOG(ERROR) << "Failed to find the shared buffer " << id;
356 return scoped_refptr<media::SharedBuffer>(); 421 return NULL;
357 } 422 }
358 } 423 }
359 424
360 void DesktopSessionProxy::OnAudioPacket(const std::string& serialized_packet) { 425 void DesktopSessionProxy::OnAudioPacket(const std::string& serialized_packet) {
361 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 426 DCHECK(caller_task_runner_->BelongsToCurrentThread());
362 427
363 // Parse a serialized audio packet. No further validation is done since 428 // Parse a serialized audio packet. No further validation is done since
364 // the message was sent by more privileged process. 429 // the message was sent by more privileged process.
365 scoped_ptr<AudioPacket> packet(new AudioPacket()); 430 scoped_ptr<AudioPacket> packet(new AudioPacket());
366 if (!packet->ParseFromString(serialized_packet)) { 431 if (!packet->ParseFromString(serialized_packet)) {
367 LOG(ERROR) << "Failed to parse AudioPacket."; 432 LOG(ERROR) << "Failed to parse AudioPacket.";
368 return; 433 return;
369 } 434 }
370 435
371 // Pass a captured audio packet to |audio_capturer_|. 436 // Pass a captured audio packet to |audio_capturer_|.
372 audio_capture_task_runner_->PostTask( 437 audio_capture_task_runner_->PostTask(
373 FROM_HERE, base::Bind(&IpcAudioCapturer::OnAudioPacket, audio_capturer_, 438 FROM_HERE, base::Bind(&IpcAudioCapturer::OnAudioPacket, audio_capturer_,
374 base::Passed(&packet))); 439 base::Passed(&packet)));
375 } 440 }
376 441
377 void DesktopSessionProxy::OnCreateSharedBuffer( 442 void DesktopSessionProxy::OnCreateSharedBuffer(
378 int id, 443 int id,
379 IPC::PlatformFileForTransit handle, 444 IPC::PlatformFileForTransit handle,
380 uint32 size) { 445 uint32 size) {
381 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 446 DCHECK(caller_task_runner_->BelongsToCurrentThread());
382 447
383 scoped_refptr<media::SharedBuffer> shared_buffer; 448 scoped_refptr<IpcSharedBufferCore> shared_buffer =
449 new IpcSharedBufferCore(id, handle, desktop_process_, size);
384 450
385 #if defined(OS_WIN) 451 if (shared_buffer->memory() != NULL &&
386 shared_buffer = new media::SharedBuffer(id, handle, desktop_process_, size);
387 #elif defined(OS_POSIX)
388 shared_buffer = new media::SharedBuffer(id, handle, size);
389 #else
390 #error Unsupported platform.
391 #endif
392
393 // Check if the buffer has been successfully mapped.
394 bool mapped = shared_buffer->ptr() != NULL;
395 if (!mapped) {
396 #if defined(OS_WIN)
397 LOG(ERROR) << "Failed to map a shared buffer: id=" << id
398 << ", handle=" << handle
399 << ", size=" << size;
400 #elif defined(OS_POSIX)
401 LOG(ERROR) << "Failed to map a shared buffer: id=" << id
402 << ", handle.fd=" << handle.fd
403 << ", size=" << size;
404 #endif
405 }
406
407 if (mapped &&
408 !shared_buffers_.insert(std::make_pair(id, shared_buffer)).second) { 452 !shared_buffers_.insert(std::make_pair(id, shared_buffer)).second) {
409 LOG(ERROR) << "Duplicate shared buffer id " << id << " encountered"; 453 LOG(ERROR) << "Duplicate shared buffer id " << id << " encountered";
410 } 454 }
411
412 // Notify the desktop process that the buffer has been seen and can now be
413 // safely deleted if needed.
414 SendToDesktop(new ChromotingNetworkDesktopMsg_SharedBufferCreated(id));
415 } 455 }
416 456
417 void DesktopSessionProxy::OnReleaseSharedBuffer(int id) { 457 void DesktopSessionProxy::OnReleaseSharedBuffer(int id) {
418 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 458 DCHECK(caller_task_runner_->BelongsToCurrentThread());
419 459
420 // Drop the cached reference to the buffer. 460 // Drop the cached reference to the buffer.
421 shared_buffers_.erase(id); 461 shared_buffers_.erase(id);
422 } 462 }
423 463
424 void DesktopSessionProxy::OnCaptureCompleted( 464 void DesktopSessionProxy::OnCaptureCompleted(
425 const SerializedCapturedData& serialized_data) { 465 const SerializedDesktopFrame& serialized_frame) {
426 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 466 DCHECK(caller_task_runner_->BelongsToCurrentThread());
427 467
428 // Assume that |serialized_data| is well formed because it was received from 468 // Assume that |serialized_frame| is well-formed because it was received from
429 // a more privileged process. 469 // a more privileged process.
430 scoped_refptr<media::ScreenCaptureData> capture_data; 470 scoped_refptr<IpcSharedBufferCore> shared_buffer_core =
431 scoped_refptr<media::SharedBuffer> shared_buffer = 471 GetSharedBufferCore(serialized_frame.shared_buffer_id);
432 GetSharedBuffer(serialized_data.shared_buffer_id); 472 CHECK(shared_buffer_core);
433 CHECK(shared_buffer);
434 473
435 capture_data = new media::ScreenCaptureData( 474 scoped_ptr<webrtc::DesktopFrame> frame(
436 reinterpret_cast<uint8*>(shared_buffer->ptr()), 475 new webrtc::SharedMemoryDesktopFrame(
437 serialized_data.bytes_per_row, 476 serialized_frame.dimensions, serialized_frame.bytes_per_row,
438 serialized_data.dimensions); 477 new IpcSharedBuffer(shared_buffer_core)));
439 capture_data->set_capture_time_ms(serialized_data.capture_time_ms); 478 frame->set_capture_time_ms(serialized_frame.capture_time_ms);
440 capture_data->set_client_sequence_number( 479 frame->set_dpi(serialized_frame.dpi);
441 serialized_data.client_sequence_number);
442 capture_data->set_dpi(serialized_data.dpi);
443 capture_data->set_shared_buffer(shared_buffer);
444 480
445 if (!serialized_data.dirty_region.empty()) { 481 for (size_t i = 0; i < serialized_frame.dirty_region.size(); ++i) {
446 capture_data->mutable_dirty_region().setRects( 482 frame->mutable_updated_region()->AddRect(serialized_frame.dirty_region[i]);
447 &serialized_data.dirty_region[0],
448 serialized_data.dirty_region.size());
449 } 483 }
450 484
451 --pending_capture_frame_requests_; 485 --pending_capture_frame_requests_;
452 PostCaptureCompleted(capture_data); 486 PostCaptureCompleted(frame.Pass());
453 } 487 }
454 488
455 void DesktopSessionProxy::OnCursorShapeChanged( 489 void DesktopSessionProxy::OnCursorShapeChanged(
456 const media::MouseCursorShape& cursor_shape) { 490 const media::MouseCursorShape& cursor_shape) {
457 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 491 DCHECK(caller_task_runner_->BelongsToCurrentThread());
458 PostCursorShape(scoped_ptr<media::MouseCursorShape>( 492 PostCursorShape(scoped_ptr<media::MouseCursorShape>(
459 new media::MouseCursorShape(cursor_shape))); 493 new media::MouseCursorShape(cursor_shape)));
460 } 494 }
461 495
462 void DesktopSessionProxy::OnInjectClipboardEvent( 496 void DesktopSessionProxy::OnInjectClipboardEvent(
463 const std::string& serialized_event) { 497 const std::string& serialized_event) {
464 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 498 DCHECK(caller_task_runner_->BelongsToCurrentThread());
465 499
466 if (client_clipboard_) { 500 if (client_clipboard_) {
467 protocol::ClipboardEvent event; 501 protocol::ClipboardEvent event;
468 if (!event.ParseFromString(serialized_event)) { 502 if (!event.ParseFromString(serialized_event)) {
469 LOG(ERROR) << "Failed to parse protocol::ClipboardEvent."; 503 LOG(ERROR) << "Failed to parse protocol::ClipboardEvent.";
470 return; 504 return;
471 } 505 }
472 506
473 client_clipboard_->InjectClipboardEvent(event); 507 client_clipboard_->InjectClipboardEvent(event);
474 } 508 }
475 } 509 }
476 510
477 void DesktopSessionProxy::PostCaptureCompleted( 511 void DesktopSessionProxy::PostCaptureCompleted(
478 scoped_refptr<media::ScreenCaptureData> capture_data) { 512 scoped_ptr<webrtc::DesktopFrame> frame) {
479 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 513 DCHECK(caller_task_runner_->BelongsToCurrentThread());
480 514
481 video_capture_task_runner_->PostTask( 515 video_capture_task_runner_->PostTask(
482 FROM_HERE, 516 FROM_HERE,
483 base::Bind(&IpcVideoFrameCapturer::OnCaptureCompleted, video_capturer_, 517 base::Bind(&IpcVideoFrameCapturer::OnCaptureCompleted, video_capturer_,
484 capture_data)); 518 base::Passed(&frame)));
485 } 519 }
486 520
487 void DesktopSessionProxy::PostCursorShape( 521 void DesktopSessionProxy::PostCursorShape(
488 scoped_ptr<media::MouseCursorShape> cursor_shape) { 522 scoped_ptr<media::MouseCursorShape> cursor_shape) {
489 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 523 DCHECK(caller_task_runner_->BelongsToCurrentThread());
490 524
491 video_capture_task_runner_->PostTask( 525 video_capture_task_runner_->PostTask(
492 FROM_HERE, 526 FROM_HERE,
493 base::Bind(&IpcVideoFrameCapturer::OnCursorShapeChanged, video_capturer_, 527 base::Bind(&IpcVideoFrameCapturer::OnCursorShapeChanged, video_capturer_,
494 base::Passed(&cursor_shape))); 528 base::Passed(&cursor_shape)));
(...skipping 10 matching lines...) Expand all
505 } 539 }
506 540
507 // static 541 // static
508 void DesktopSessionProxyTraits::Destruct( 542 void DesktopSessionProxyTraits::Destruct(
509 const DesktopSessionProxy* desktop_session_proxy) { 543 const DesktopSessionProxy* desktop_session_proxy) {
510 desktop_session_proxy->caller_task_runner_->DeleteSoon(FROM_HERE, 544 desktop_session_proxy->caller_task_runner_->DeleteSoon(FROM_HERE,
511 desktop_session_proxy); 545 desktop_session_proxy);
512 } 546 }
513 547
514 } // namespace remoting 548 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/desktop_session_proxy.h ('k') | remoting/host/desktop_session_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698