15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/client_session.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "remoting/base/capabilities.h"
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "remoting/base/logging.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/codec/audio_encoder.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/codec/audio_encoder_opus.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/codec/audio_encoder_verbatim.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/codec/video_encoder.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/codec/video_encoder_verbatim.h"
178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "remoting/codec/video_encoder_vpx.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/audio_capturer.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/audio_scheduler.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/desktop_environment.h"
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/host/host_extension_session.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/input_injector.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/screen_controls.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/screen_resolution.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/video_scheduler.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/proto/control.pb.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/proto/event.pb.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/protocol/client_stub.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/protocol/clipboard_thread_proxy.h"
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "remoting/protocol/pairing_registry.h"
316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Default DPI to assume for old clients that use notifyClientDimensions.
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kDefaultDPI = 96;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ClientSession::ClientSession(
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EventHandler* event_handler,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner,
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> video_encode_task_runner,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<protocol::ConnectionToClient> connection,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DesktopEnvironmentFactory* desktop_environment_factory,
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const base::TimeDelta& max_duration,
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_refptr<protocol::PairingRegistry> pairing_registry,
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::vector<HostExtension*>& extensions)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : event_handler_(event_handler),
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      connection_(connection.Pass()),
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_jid_(connection_->session()->jid()),
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      desktop_environment_factory_(desktop_environment_factory),
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      input_tracker_(&host_input_filter_),
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      remote_input_filter_(&input_tracker_),
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      mouse_clamping_filter_(&remote_input_filter_),
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      disable_input_filter_(mouse_clamping_filter_.input_filter()),
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      disable_clipboard_filter_(clipboard_echo_filter_.host_filter()),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auth_input_filter_(&disable_input_filter_),
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auth_clipboard_filter_(&disable_clipboard_filter_),
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_clipboard_factory_(clipboard_echo_filter_.client_filter()),
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_duration_(max_duration),
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      audio_task_runner_(audio_task_runner),
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      input_task_runner_(input_task_runner),
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      video_capture_task_runner_(video_capture_task_runner),
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      video_encode_task_runner_(video_encode_task_runner),
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      network_task_runner_(network_task_runner),
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      ui_task_runner_(ui_task_runner),
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      pairing_registry_(pairing_registry),
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      pause_video_(false),
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      lossless_video_encode_(false),
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      lossless_video_color_(false),
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_factory_(this) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connection_->SetEventHandler(this);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sergeyu): Currently ConnectionToClient expects stubs to be
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // set before channels are connected. Make it possible to set stubs
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // later and set them only when connection is authenticated.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connection_->set_clipboard_stub(&auth_clipboard_filter_);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connection_->set_host_stub(this);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connection_->set_input_stub(&auth_input_filter_);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |auth_*_filter_|'s states reflect whether the session is authenticated.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_input_filter_.set_enabled(false);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_clipboard_filter_.set_enabled(false);
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Create a manager for the configured extensions, if any.
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  extension_manager_.reset(new HostExtensionSessionManager(extensions, this));
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // LocalInputMonitorWin filters out an echo of the injected input before it
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // reaches |remote_input_filter_|.
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remote_input_filter_.SetExpectLocalEcho(false);
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif  // defined(OS_WIN)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ClientSession::~ClientSession() {
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(CalledOnValidThread());
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!audio_scheduler_.get());
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!desktop_environment_);
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!input_injector_);
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!screen_controls_);
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!video_scheduler_.get());
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connection_.reset();
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ClientSession::NotifyClientResolution(
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const protocol::ClientResolution& resolution) {
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(CalledOnValidThread());
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // TODO(sergeyu): Move these checks to protocol layer.
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!resolution.has_dips_width() || !resolution.has_dips_height() ||
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      resolution.dips_width() < 0 || resolution.dips_height() < 0 ||
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      resolution.width() <= 0 || resolution.height() <= 0) {
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(ERROR) << "Received invalid ClientResolution message.";
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VLOG(1) << "Received ClientResolution (dips_width="
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          << resolution.dips_width() << ", dips_height="
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          << resolution.dips_height() << ")";
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!screen_controls_)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScreenResolution client_resolution(
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      webrtc::DesktopSize(resolution.dips_width(), resolution.dips_height()),
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      webrtc::DesktopVector(kDefaultDPI, kDefaultDPI));
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Try to match the client's resolution.
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  screen_controls_->SetScreenResolution(client_resolution);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSession::ControlVideo(const protocol::VideoControl& video_control) {
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(CalledOnValidThread());
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Note that |video_scheduler_| may be NULL, depending upon whether extensions
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // choose to wrap or "steal" the video capturer or encoder.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (video_control.has_enable()) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Received VideoControl (enable="
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << video_control.enable() << ")";
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    pause_video_ = !video_control.enable();
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (video_scheduler_.get())
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      video_scheduler_->Pause(pause_video_);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (video_control.has_lossless_encode()) {
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    VLOG(1) << "Received VideoControl (lossless_encode="
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            << video_control.lossless_encode() << ")";
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    lossless_video_encode_ = video_control.lossless_encode();
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (video_scheduler_.get())
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      video_scheduler_->SetLosslessEncode(lossless_video_encode_);
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (video_control.has_lossless_color()) {
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    VLOG(1) << "Received VideoControl (lossless_color="
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            << video_control.lossless_color() << ")";
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    lossless_video_color_ = video_control.lossless_color();
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (video_scheduler_.get())
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      video_scheduler_->SetLosslessColor(lossless_video_color_);
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSession::ControlAudio(const protocol::AudioControl& audio_control) {
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(CalledOnValidThread());
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (audio_control.has_enable()) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Received AudioControl (enable="
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << audio_control.enable() << ")";
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (audio_scheduler_.get())
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      audio_scheduler_->Pause(!audio_control.enable());
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ClientSession::SetCapabilities(
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const protocol::Capabilities& capabilities) {
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(CalledOnValidThread());
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Ignore all the messages but the 1st one.
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (client_capabilities_) {
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(WARNING) << "protocol::Capabilities has been received already.";
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Compute the set of capabilities supported by both client and host.
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  client_capabilities_ = make_scoped_ptr(new std::string());
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (capabilities.has_capabilities())
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *client_capabilities_ = capabilities.capabilities();
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  capabilities_ = IntersectCapabilities(*client_capabilities_,
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                        host_capabilities_);
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  extension_manager_->OnNegotiatedCapabilities(
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      connection_->client_stub(), capabilities_);
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << "Client capabilities: " << *client_capabilities_;
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Calculate the set of capabilities enabled by both client and host and
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // pass it to the desktop environment if it is available.
1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  desktop_environment_->SetCapabilities(capabilities_);
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ClientSession::RequestPairing(
202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const protocol::PairingRequest& pairing_request) {
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (pairing_registry_.get() && pairing_request.has_client_name()) {
204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    protocol::PairingRegistry::Pairing pairing =
205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        pairing_registry_->CreatePairing(pairing_request.client_name());
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    protocol::PairingResponse pairing_response;
2077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    pairing_response.set_client_id(pairing.client_id());
2087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    pairing_response.set_shared_secret(pairing.shared_secret());
209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    connection_->client_stub()->SetPairingResponse(pairing_response);
210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
213c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid ClientSession::DeliverClientMessage(
214c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    const protocol::ExtensionMessage& message) {
21558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (message.has_type()) {
21658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (message.type() == "test-echo") {
21758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      protocol::ExtensionMessage reply;
21858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      reply.set_type("test-echo-reply");
21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (message.has_data())
22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        reply.set_data(message.data().substr(0, 16));
22158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      connection_->client_stub()->DeliverHostMessage(reply);
22258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return;
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else if (message.type() == "gnubby-auth") {
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (gnubby_auth_handler_) {
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        gnubby_auth_handler_->DeliverClientMessage(message.data());
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      } else {
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        HOST_LOG << "gnubby auth is not enabled";
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return;
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else {
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (!extension_manager_->OnExtensionMessage(message))
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return;
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      DLOG(INFO) << "Unexpected message received: "
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 << message.type() << ": " << message.data();
23658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
23758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
238c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
239c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
240c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid ClientSession::OnConnectionAuthenticating(
241c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    protocol::ConnectionToClient* connection) {
242c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  event_handler_->OnSessionAuthenticating(this);
243c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
244c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSession::OnConnectionAuthenticated(
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protocol::ConnectionToClient* connection) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(connection_.get(), connection);
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!audio_scheduler_.get());
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!desktop_environment_);
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!input_injector_);
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!screen_controls_);
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!video_scheduler_.get());
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_input_filter_.set_enabled(true);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_clipboard_filter_.set_enabled(true);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  clipboard_echo_filter_.set_client_stub(connection_->client_stub());
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  mouse_clamping_filter_.set_video_stub(connection_->video_stub());
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (max_duration_ > base::TimeDelta()) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(simonmorris): Let Disconnect() tell the client that the
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // disconnection was caused by the session exceeding its maximum duration.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    max_duration_timer_.Start(FROM_HERE, max_duration_,
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              this, &ClientSession::DisconnectSession);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Disconnect the session if the connection was rejected by the host.
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!event_handler_->OnSessionAuthenticated(this)) {
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DisconnectSession();
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
274b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Create the desktop environment. Drop the connection if it could not be
275b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // created for any reason (for instance the curtain could not initialize).
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  desktop_environment_ =
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      desktop_environment_factory_->Create(weak_factory_.GetWeakPtr());
278b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!desktop_environment_) {
279b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    DisconnectSession();
280b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
281b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
282b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Collate the set of capabilities to offer the client, if it supports them.
2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  host_capabilities_ = desktop_environment_->GetCapabilities();
2851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!host_capabilities_.empty())
2861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    host_capabilities_.append(" ");
2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  host_capabilities_.append(extension_manager_->GetCapabilities());
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the object that controls the screen resolution.
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  screen_controls_ = desktop_environment_->CreateScreenControls();
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Create the event executor.
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  input_injector_ = desktop_environment_->CreateInputInjector();
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Connect the host clipboard and input stubs.
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  host_input_filter_.set_input_stub(input_injector_.get());
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  clipboard_echo_filter_.set_host_stub(input_injector_.get());
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an AudioScheduler if audio is enabled, to pump audio samples.
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (connection_->session()->config().is_audio_enabled()) {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<AudioEncoder> audio_encoder =
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CreateAudioEncoder(connection_->session()->config());
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    audio_scheduler_ = new AudioScheduler(
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        audio_task_runner_,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        network_task_runner_,
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        desktop_environment_->CreateAudioCapturer(),
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        audio_encoder.Pass(),
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        connection_->audio_stub());
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Create a GnubbyAuthHandler to proxy gnubbyd messages.
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  gnubby_auth_handler_ = desktop_environment_->CreateGnubbyAuthHandler(
313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      connection_->client_stub());
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ClientSession::OnConnectionChannelsConnected(
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    protocol::ConnectionToClient* connection) {
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(CalledOnValidThread());
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(connection_.get(), connection);
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Negotiate capabilities with the client.
3221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  VLOG(1) << "Host capabilities: " << host_capabilities_;
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  protocol::Capabilities capabilities;
3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  capabilities.set_capabilities(host_capabilities_);
3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  connection_->client_stub()->SetCapabilities(capabilities);
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Start the event executor.
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  input_injector_->Start(CreateClipboardProxy());
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetDisableInputs(false);
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Start recording video.
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ResetVideoPipeline();
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Start recording audio.
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (connection_->session()->config().is_audio_enabled())
337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    audio_scheduler_->Start();
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notify the event handler that all our channels are now connected.
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event_handler_->OnSessionChannelsConnected(this);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSession::OnConnectionClosed(
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protocol::ConnectionToClient* connection,
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protocol::ErrorCode error) {
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(connection_.get(), connection);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Ignore any further callbacks.
3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  weak_factory_.InvalidateWeakPtrs();
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the client never authenticated then the session failed.
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!auth_input_filter_.enabled())
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event_handler_->OnSessionAuthenticationFailed(this);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Block any further input events from the client.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(wez): Fix ChromotingHost::OnSessionClosed not to check our
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is_authenticated(), so that we can disable |auth_*_filter_| here.
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  disable_input_filter_.set_enabled(false);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  disable_clipboard_filter_.set_enabled(false);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensure that any pressed keys or buttons are released.
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  input_tracker_.ReleaseAll();
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Stop components access the client, audio or video stubs, which are no
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // longer valid once ConnectionToClient calls OnConnectionClosed().
367868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (audio_scheduler_.get()) {
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_scheduler_->Stop();
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_scheduler_ = NULL;
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
371868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (video_scheduler_.get()) {
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    video_scheduler_->Stop();
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    video_scheduler_ = NULL;
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client_clipboard_factory_.InvalidateWeakPtrs();
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  input_injector_.reset();
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  screen_controls_.reset();
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  desktop_environment_.reset();
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Notify the ChromotingHost that this client is disconnected.
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sergeyu): Log failure reason?
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event_handler_->OnSessionClosed(this);
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSession::OnSequenceNumberUpdated(
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protocol::ConnectionToClient* connection, int64 sequence_number) {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(connection_.get(), connection);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
391868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (video_scheduler_.get())
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    video_scheduler_->UpdateSequenceNumber(sequence_number);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSession::OnRouteChange(
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protocol::ConnectionToClient* connection,
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& channel_name,
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const protocol::TransportRoute& route) {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(connection_.get(), connection);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event_handler_->OnSessionRouteChange(this, channel_name, route);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string& ClientSession::client_jid() const {
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return client_jid_;
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ClientSession::DisconnectSession() {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(connection_.get());
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  max_duration_timer_.Stop();
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This triggers OnConnectionClosed(), and the session may be destroyed
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // as the result, so this call must be the last in this method.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connection_->Disconnect();
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ClientSession::OnLocalMouseMoved(const webrtc::DesktopVector& position) {
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remote_input_filter_.LocalMouseMoved(position);
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSession::SetDisableInputs(bool disable_inputs) {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (disable_inputs)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    input_tracker_.ReleaseAll();
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  disable_input_filter_.set_enabled(!disable_inputs);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  disable_clipboard_filter_.set_enabled(!disable_inputs);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ClientSession::ResetVideoPipeline() {
4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(CalledOnValidThread());
4365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (video_scheduler_.get()) {
4385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    video_scheduler_->Stop();
4395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    video_scheduler_ = NULL;
4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Create VideoEncoder and DesktopCapturer to match the session's video
4436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // channel configuration.
4446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scoped_ptr<webrtc::DesktopCapturer> video_capturer =
4451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      desktop_environment_->CreateVideoCapturer();
4461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extension_manager_->OnCreateVideoCapturer(&video_capturer);
4475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<VideoEncoder> video_encoder =
4481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      CreateVideoEncoder(connection_->session()->config());
4491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extension_manager_->OnCreateVideoEncoder(&video_encoder);
4505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Don't start the VideoScheduler if either capturer or encoder are missing.
4525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!video_capturer || !video_encoder)
4535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
4545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Create a VideoScheduler to pump frames from the capturer to the client.
4565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  video_scheduler_ = new VideoScheduler(
4575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      video_capture_task_runner_,
4585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      video_encode_task_runner_,
4595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      network_task_runner_,
4605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      video_capturer.Pass(),
4616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      desktop_environment_->CreateMouseCursorMonitor(),
4625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      video_encoder.Pass(),
4635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      connection_->client_stub(),
4645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      &mouse_clamping_filter_);
4655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Apply video-control parameters to the new scheduler.
4675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  video_scheduler_->Pause(pause_video_);
4685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  video_scheduler_->SetLosslessEncode(lossless_video_encode_);
4695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  video_scheduler_->SetLosslessColor(lossless_video_color_);
4705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Start capturing the screen.
4725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  video_scheduler_->Start();
4735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
475a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ClientSession::SetGnubbyAuthHandlerForTesting(
476a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    GnubbyAuthHandler* gnubby_auth_handler) {
4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(CalledOnValidThread());
478a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  gnubby_auth_handler_.reset(gnubby_auth_handler);
479a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
480a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<protocol::ClipboardStub> ClientSession::CreateClipboardProxy() {
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return scoped_ptr<protocol::ClipboardStub>(
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new protocol::ClipboardThreadProxy(
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          client_clipboard_factory_.GetWeakPtr(),
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::MessageLoopProxy::current()));
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(sergeyu): Move this to SessionManager?
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<VideoEncoder> ClientSession::CreateVideoEncoder(
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const protocol::SessionConfig& config) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const protocol::ChannelConfig& video_config = config.video_config();
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
496d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) {
4978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return remoting::VideoEncoderVpx::CreateForVP8().PassAs<VideoEncoder>();
498e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP9) {
499e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    return remoting::VideoEncoderVpx::CreateForVP9().PassAs<VideoEncoder>();
5005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else if (video_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) {
5015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return scoped_ptr<VideoEncoder>(new remoting::VideoEncoderVerbatim());
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
504d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  NOTREACHED();
5057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return scoped_ptr<VideoEncoder>();
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<AudioEncoder> ClientSession::CreateAudioEncoder(
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const protocol::SessionConfig& config) {
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const protocol::ChannelConfig& audio_config = config.audio_config();
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (audio_config.codec == protocol::ChannelConfig::CODEC_VERBATIM) {
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return scoped_ptr<AudioEncoder>(new AudioEncoderVerbatim());
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (audio_config.codec == protocol::ChannelConfig::CODEC_OPUS) {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return scoped_ptr<AudioEncoder>(new AudioEncoderOpus());
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
519d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  NOTREACHED();
5207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return scoped_ptr<AudioEncoder>();
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
524