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
23 namespace remoting {
24
25 using protocol::AuthenticationMethod;
26
ChromotingClient(const ClientConfig & config,ClientContext * client_context,protocol::ConnectionToHost * connection,ClientUserInterface * user_interface,VideoRenderer * video_renderer,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 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
~ChromotingClient()49 ChromotingClient::~ChromotingClient() {
50 }
51
Start(SignalStrategy * signal_strategy,scoped_ptr<protocol::TransportFactory> transport_factory)52 void 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
SetCapabilities(const protocol::Capabilities & capabilities)82 void 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
SetPairingResponse(const protocol::PairingResponse & pairing_response)104 void ChromotingClient::SetPairingResponse(
105 const protocol::PairingResponse& pairing_response) {
106 DCHECK(task_runner_->BelongsToCurrentThread());
107
108 user_interface_->SetPairingResponse(pairing_response);
109 }
110
DeliverHostMessage(const protocol::ExtensionMessage & message)111 void ChromotingClient::DeliverHostMessage(
112 const protocol::ExtensionMessage& message) {
113 DCHECK(task_runner_->BelongsToCurrentThread());
114
115 user_interface_->DeliverHostMessage(message);
116 }
117
InjectClipboardEvent(const protocol::ClipboardEvent & event)118 void ChromotingClient::InjectClipboardEvent(
119 const protocol::ClipboardEvent& event) {
120 DCHECK(task_runner_->BelongsToCurrentThread());
121
122 user_interface_->GetClipboardStub()->InjectClipboardEvent(event);
123 }
124
SetCursorShape(const protocol::CursorShapeInfo & cursor_shape)125 void ChromotingClient::SetCursorShape(
126 const protocol::CursorShapeInfo& cursor_shape) {
127 DCHECK(task_runner_->BelongsToCurrentThread());
128
129 user_interface_->GetCursorShapeStub()->SetCursorShape(cursor_shape);
130 }
131
OnConnectionState(protocol::ConnectionToHost::State state,protocol::ErrorCode error)132 void 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
OnConnectionReady(bool ready)146 void ChromotingClient::OnConnectionReady(bool ready) {
147 VLOG(1) << "ChromotingClient::OnConnectionReady(" << ready << ")";
148 user_interface_->OnConnectionReady(ready);
149 }
150
OnRouteChanged(const std::string & channel_name,const protocol::TransportRoute & route)151 void 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
OnAuthenticated()158 void 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
OnChannelsConnected()176 void 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