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