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 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 49 ChromotingClient::~ChromotingClient() { 50 } 51 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 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 104 void ChromotingClient::SetPairingResponse( 105 const protocol::PairingResponse& pairing_response) { 106 DCHECK(task_runner_->BelongsToCurrentThread()); 107 108 user_interface_->SetPairingResponse(pairing_response); 109 } 110 111 void ChromotingClient::DeliverHostMessage( 112 const protocol::ExtensionMessage& message) { 113 DCHECK(task_runner_->BelongsToCurrentThread()); 114 115 user_interface_->DeliverHostMessage(message); 116 } 117 118 void ChromotingClient::InjectClipboardEvent( 119 const protocol::ClipboardEvent& event) { 120 DCHECK(task_runner_->BelongsToCurrentThread()); 121 122 user_interface_->GetClipboardStub()->InjectClipboardEvent(event); 123 } 124 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 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 146 void ChromotingClient::OnConnectionReady(bool ready) { 147 VLOG(1) << "ChromotingClient::OnConnectionReady(" << ready << ")"; 148 user_interface_->OnConnectionReady(ready); 149 } 150 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 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 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