chromoting_client.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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/rectangle_update_decoder.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    scoped_refptr<FrameConsumerProxy> frame_consumer,
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      host_capabilities_received_(false),
39      weak_factory_(this) {
40  rectangle_decoder_ =
41      new RectangleUpdateDecoder(client_context->main_task_runner(),
42                                 client_context->decode_task_runner(),
43                                 frame_consumer);
44  audio_decode_scheduler_.reset(new AudioDecodeScheduler(
45      client_context->main_task_runner(),
46      client_context->audio_decode_task_runner(),
47      audio_player.Pass()));
48}
49
50ChromotingClient::~ChromotingClient() {
51}
52
53void ChromotingClient::Start(
54    scoped_refptr<XmppProxy> xmpp_proxy,
55    scoped_ptr<protocol::TransportFactory> transport_factory) {
56  DCHECK(task_runner_->BelongsToCurrentThread());
57
58  scoped_ptr<protocol::Authenticator> authenticator(
59      new protocol::NegotiatingClientAuthenticator(
60          config_.client_pairing_id,
61          config_.client_paired_secret,
62          config_.authentication_tag,
63          config_.fetch_secret_callback,
64          user_interface_->GetTokenFetcher(config_.host_public_key),
65          config_.authentication_methods));
66
67  // Create a WeakPtr to ourself for to use for all posted tasks.
68  weak_ptr_ = weak_factory_.GetWeakPtr();
69
70  connection_->Connect(xmpp_proxy,
71                       config_.local_jid,
72                       config_.host_jid,
73                       config_.host_public_key,
74                       transport_factory.Pass(),
75                       authenticator.Pass(),
76                       this,
77                       this,
78                       this,
79                       rectangle_decoder_.get(),
80                       audio_decode_scheduler_.get());
81}
82
83void ChromotingClient::Stop(const base::Closure& shutdown_task) {
84  DCHECK(task_runner_->BelongsToCurrentThread());
85
86  connection_->Disconnect(base::Bind(&ChromotingClient::OnDisconnected,
87                                     weak_ptr_, shutdown_task));
88}
89
90FrameProducer* ChromotingClient::GetFrameProducer() {
91  return rectangle_decoder_.get();
92}
93
94void ChromotingClient::OnDisconnected(const base::Closure& shutdown_task) {
95  shutdown_task.Run();
96}
97
98ChromotingStats* ChromotingClient::GetStats() {
99  DCHECK(task_runner_->BelongsToCurrentThread());
100  return rectangle_decoder_->GetStats();
101}
102
103void ChromotingClient::SetCapabilities(
104    const protocol::Capabilities& capabilities) {
105  DCHECK(task_runner_->BelongsToCurrentThread());
106
107  // Only accept the first |protocol::Capabilities| message.
108  if (host_capabilities_received_) {
109    LOG(WARNING) << "protocol::Capabilities has been received already.";
110    return;
111  }
112
113  host_capabilities_received_ = true;
114  if (capabilities.has_capabilities())
115    host_capabilities_ = capabilities.capabilities();
116
117  VLOG(1) << "Host capabilities: " << host_capabilities_;
118
119  // Calculate the set of capabilities enabled by both client and host and pass
120  // it to the webapp.
121  user_interface_->SetCapabilities(
122      IntersectCapabilities(config_.capabilities, host_capabilities_));
123}
124
125void ChromotingClient::SetPairingResponse(
126    const protocol::PairingResponse& pairing_response) {
127  DCHECK(task_runner_->BelongsToCurrentThread());
128
129  user_interface_->SetPairingResponse(pairing_response);
130}
131
132void ChromotingClient::InjectClipboardEvent(
133    const protocol::ClipboardEvent& event) {
134  DCHECK(task_runner_->BelongsToCurrentThread());
135
136  user_interface_->GetClipboardStub()->InjectClipboardEvent(event);
137}
138
139void ChromotingClient::SetCursorShape(
140    const protocol::CursorShapeInfo& cursor_shape) {
141  DCHECK(task_runner_->BelongsToCurrentThread());
142
143  user_interface_->GetCursorShapeStub()->SetCursorShape(cursor_shape);
144}
145
146void ChromotingClient::OnConnectionState(
147    protocol::ConnectionToHost::State state,
148    protocol::ErrorCode error) {
149  DCHECK(task_runner_->BelongsToCurrentThread());
150  VLOG(1) << "ChromotingClient::OnConnectionState(" << state << ")";
151
152  if (state == protocol::ConnectionToHost::AUTHENTICATED) {
153    OnAuthenticated();
154  } else if (state == protocol::ConnectionToHost::CONNECTED) {
155    OnChannelsConnected();
156  }
157  user_interface_->OnConnectionState(state, error);
158}
159
160void ChromotingClient::OnConnectionReady(bool ready) {
161  VLOG(1) << "ChromotingClient::OnConnectionReady(" << ready << ")";
162  user_interface_->OnConnectionReady(ready);
163}
164
165void ChromotingClient::OnAuthenticated() {
166  DCHECK(task_runner_->BelongsToCurrentThread());
167
168  // Initialize the decoder.
169  rectangle_decoder_->Initialize(connection_->config());
170  if (connection_->config().is_audio_enabled())
171    audio_decode_scheduler_->Initialize(connection_->config());
172
173  // Do not negotiate capabilities with the host if the host does not support
174  // them.
175  if (!connection_->config().SupportsCapabilities()) {
176    VLOG(1) << "The host does not support any capabilities.";
177
178    host_capabilities_received_ = true;
179    user_interface_->SetCapabilities(host_capabilities_);
180  }
181}
182
183void ChromotingClient::OnChannelsConnected() {
184  DCHECK(task_runner_->BelongsToCurrentThread());
185
186  // Negotiate capabilities with the host.
187  if (connection_->config().SupportsCapabilities()) {
188    VLOG(1) << "Client capabilities: " << config_.capabilities;
189
190    protocol::Capabilities capabilities;
191    capabilities.set_capabilities(config_.capabilities);
192    connection_->host_stub()->SetCapabilities(capabilities);
193  }
194}
195
196}  // namespace remoting
197