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