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/client/chromoting_client.h"
6
7#include "base/bind.h"
8#include "remoting/base/capabilities.h"
9#include "remoting/client/audio_decode_scheduler.h"
10#include "remoting/client/audio_player.h"
11#include "remoting/client/client_context.h"
12#include "remoting/client/client_user_interface.h"
13#include "remoting/client/video_renderer.h"
14#include "remoting/proto/audio.pb.h"
15#include "remoting/proto/video.pb.h"
16#include "remoting/protocol/authentication_method.h"
17#include "remoting/protocol/connection_to_host.h"
18#include "remoting/protocol/host_stub.h"
19#include "remoting/protocol/negotiating_client_authenticator.h"
20#include "remoting/protocol/session_config.h"
21#include "remoting/protocol/transport.h"
22
23namespace remoting {
24
25using protocol::AuthenticationMethod;
26
27ChromotingClient::ChromotingClient(
28    const ClientConfig& config,
29    ClientContext* client_context,
30    protocol::ConnectionToHost* connection,
31    ClientUserInterface* user_interface,
32    VideoRenderer* video_renderer,
33    scoped_ptr<AudioPlayer> audio_player)
34    : config_(config),
35      task_runner_(client_context->main_task_runner()),
36      connection_(connection),
37      user_interface_(user_interface),
38      video_renderer_(video_renderer),
39      host_capabilities_received_(false),
40      weak_factory_(this) {
41  if (audio_player) {
42    audio_decode_scheduler_.reset(new AudioDecodeScheduler(
43        client_context->main_task_runner(),
44        client_context->audio_decode_task_runner(),
45        audio_player.Pass()));
46  }
47}
48
49ChromotingClient::~ChromotingClient() {
50}
51
52void ChromotingClient::Start(
53    SignalStrategy* signal_strategy,
54    scoped_ptr<protocol::TransportFactory> transport_factory) {
55  DCHECK(task_runner_->BelongsToCurrentThread());
56
57  scoped_ptr<protocol::Authenticator> authenticator(
58      new protocol::NegotiatingClientAuthenticator(
59          config_.client_pairing_id,
60          config_.client_paired_secret,
61          config_.authentication_tag,
62          config_.fetch_secret_callback,
63          user_interface_->GetTokenFetcher(config_.host_public_key),
64          config_.authentication_methods));
65
66  // Create a WeakPtr to ourself for to use for all posted tasks.
67  weak_ptr_ = weak_factory_.GetWeakPtr();
68
69  connection_->set_client_stub(this);
70  connection_->set_clipboard_stub(this);
71  connection_->set_video_stub(video_renderer_);
72  connection_->set_audio_stub(audio_decode_scheduler_.get());
73
74  connection_->Connect(signal_strategy,
75                       transport_factory.Pass(),
76                       authenticator.Pass(),
77                       config_.host_jid,
78                       config_.host_public_key,
79                       this);
80}
81
82void ChromotingClient::SetCapabilities(
83    const protocol::Capabilities& capabilities) {
84  DCHECK(task_runner_->BelongsToCurrentThread());
85
86  // Only accept the first |protocol::Capabilities| message.
87  if (host_capabilities_received_) {
88    LOG(WARNING) << "protocol::Capabilities has been received already.";
89    return;
90  }
91
92  host_capabilities_received_ = true;
93  if (capabilities.has_capabilities())
94    host_capabilities_ = capabilities.capabilities();
95
96  VLOG(1) << "Host capabilities: " << host_capabilities_;
97
98  // Calculate the set of capabilities enabled by both client and host and pass
99  // it to the webapp.
100  user_interface_->SetCapabilities(
101      IntersectCapabilities(config_.capabilities, host_capabilities_));
102}
103
104void ChromotingClient::SetPairingResponse(
105    const protocol::PairingResponse& pairing_response) {
106  DCHECK(task_runner_->BelongsToCurrentThread());
107
108  user_interface_->SetPairingResponse(pairing_response);
109}
110
111void ChromotingClient::DeliverHostMessage(
112    const protocol::ExtensionMessage& message) {
113  DCHECK(task_runner_->BelongsToCurrentThread());
114
115  user_interface_->DeliverHostMessage(message);
116}
117
118void ChromotingClient::InjectClipboardEvent(
119    const protocol::ClipboardEvent& event) {
120  DCHECK(task_runner_->BelongsToCurrentThread());
121
122  user_interface_->GetClipboardStub()->InjectClipboardEvent(event);
123}
124
125void ChromotingClient::SetCursorShape(
126    const protocol::CursorShapeInfo& cursor_shape) {
127  DCHECK(task_runner_->BelongsToCurrentThread());
128
129  user_interface_->GetCursorShapeStub()->SetCursorShape(cursor_shape);
130}
131
132void ChromotingClient::OnConnectionState(
133    protocol::ConnectionToHost::State state,
134    protocol::ErrorCode error) {
135  DCHECK(task_runner_->BelongsToCurrentThread());
136  VLOG(1) << "ChromotingClient::OnConnectionState(" << state << ")";
137
138  if (state == protocol::ConnectionToHost::AUTHENTICATED) {
139    OnAuthenticated();
140  } else if (state == protocol::ConnectionToHost::CONNECTED) {
141    OnChannelsConnected();
142  }
143  user_interface_->OnConnectionState(state, error);
144}
145
146void ChromotingClient::OnConnectionReady(bool ready) {
147  VLOG(1) << "ChromotingClient::OnConnectionReady(" << ready << ")";
148  user_interface_->OnConnectionReady(ready);
149}
150
151void ChromotingClient::OnRouteChanged(const std::string& channel_name,
152                                      const protocol::TransportRoute& route) {
153  VLOG(0) << "Using " << protocol::TransportRoute::GetTypeString(route.type)
154          << " connection for " << channel_name << " channel";
155  user_interface_->OnRouteChanged(channel_name, route);
156}
157
158void ChromotingClient::OnAuthenticated() {
159  DCHECK(task_runner_->BelongsToCurrentThread());
160
161  // Initialize the decoder.
162  video_renderer_->Initialize(connection_->config());
163  if (connection_->config().is_audio_enabled())
164    audio_decode_scheduler_->Initialize(connection_->config());
165
166  // Do not negotiate capabilities with the host if the host does not support
167  // them.
168  if (!connection_->config().SupportsCapabilities()) {
169    VLOG(1) << "The host does not support any capabilities.";
170
171    host_capabilities_received_ = true;
172    user_interface_->SetCapabilities(host_capabilities_);
173  }
174}
175
176void ChromotingClient::OnChannelsConnected() {
177  DCHECK(task_runner_->BelongsToCurrentThread());
178
179  // Negotiate capabilities with the host.
180  if (connection_->config().SupportsCapabilities()) {
181    VLOG(1) << "Client capabilities: " << config_.capabilities;
182
183    protocol::Capabilities capabilities;
184    capabilities.set_capabilities(config_.capabilities);
185    connection_->host_stub()->SetCapabilities(capabilities);
186  }
187}
188
189}  // namespace remoting
190