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.
5 #include "remoting/protocol/connection_to_host.h"
8 #include "base/callback.h"
9 #include "base/location.h"
10 #include "remoting/base/constants.h"
11 #include "remoting/protocol/audio_reader.h"
12 #include "remoting/protocol/audio_stub.h"
13 #include "remoting/protocol/auth_util.h"
14 #include "remoting/protocol/authenticator.h"
15 #include "remoting/protocol/client_control_dispatcher.h"
16 #include "remoting/protocol/client_event_dispatcher.h"
17 #include "remoting/protocol/client_stub.h"
18 #include "remoting/protocol/clipboard_stub.h"
19 #include "remoting/protocol/errors.h"
20 #include "remoting/protocol/jingle_session_manager.h"
21 #include "remoting/protocol/transport.h"
22 #include "remoting/protocol/video_reader.h"
23 #include "remoting/protocol/video_stub.h"
28 ConnectionToHost::ConnectionToHost()
29 : event_callback_(NULL
),
31 clipboard_stub_(NULL
),
33 signal_strategy_(NULL
),
38 ConnectionToHost::~ConnectionToHost() {
44 if (session_manager_
.get())
45 session_manager_
.reset();
48 signal_strategy_
->RemoveListener(this);
51 void ConnectionToHost::Connect(SignalStrategy
* signal_strategy
,
52 scoped_ptr
<TransportFactory
> transport_factory
,
53 scoped_ptr
<Authenticator
> authenticator
,
54 const std::string
& host_jid
,
55 HostEventCallback
* event_callback
) {
57 DCHECK(clipboard_stub_
);
58 DCHECK(monitored_video_stub_
);
60 // Initialize default |candidate_config_| if set_candidate_config() wasn't
62 if (!candidate_config_
) {
63 candidate_config_
= CandidateSessionConfig::CreateDefault();
65 candidate_config_
->DisableAudioChannel();
67 candidate_config_
->EnableVideoCodec(ChannelConfig::CODEC_VP9
);
70 signal_strategy_
= signal_strategy
;
71 event_callback_
= event_callback
;
72 authenticator_
= authenticator
.Pass();
74 // Save jid of the host. The actual connection is created later after
75 // |signal_strategy_| is connected.
78 signal_strategy_
->AddListener(this);
79 signal_strategy_
->Connect();
81 session_manager_
.reset(new JingleSessionManager(transport_factory
.Pass()));
82 session_manager_
->Init(signal_strategy_
, this);
84 SetState(CONNECTING
, OK
);
87 void ConnectionToHost::set_candidate_config(
88 scoped_ptr
<CandidateSessionConfig
> config
) {
89 DCHECK_EQ(state_
, INITIALIZING
);
91 candidate_config_
= config
.Pass();
95 const SessionConfig
& ConnectionToHost::config() {
96 return session_
->config();
99 ClipboardStub
* ConnectionToHost::clipboard_forwarder() {
100 return &clipboard_forwarder_
;
103 HostStub
* ConnectionToHost::host_stub() {
104 // TODO(wez): Add a HostFilter class, equivalent to input filter.
105 return control_dispatcher_
.get();
108 InputStub
* ConnectionToHost::input_stub() {
109 return &event_forwarder_
;
112 void ConnectionToHost::set_client_stub(ClientStub
* client_stub
) {
113 client_stub_
= client_stub
;
116 void ConnectionToHost::set_clipboard_stub(ClipboardStub
* clipboard_stub
) {
117 clipboard_stub_
= clipboard_stub
;
120 void ConnectionToHost::set_video_stub(VideoStub
* video_stub
) {
122 monitored_video_stub_
.reset(new MonitoredVideoStub(
124 base::TimeDelta::FromSeconds(
125 MonitoredVideoStub::kConnectivityCheckDelaySeconds
),
126 base::Bind(&ConnectionToHost::OnVideoChannelStatus
,
127 base::Unretained(this))));
130 void ConnectionToHost::set_audio_stub(AudioStub
* audio_stub
) {
131 audio_stub_
= audio_stub
;
134 void ConnectionToHost::OnSignalStrategyStateChange(
135 SignalStrategy::State state
) {
136 DCHECK(CalledOnValidThread());
137 DCHECK(event_callback_
);
139 if (state
== SignalStrategy::CONNECTED
) {
140 VLOG(1) << "Connected as: " << signal_strategy_
->GetLocalJid();
141 } else if (state
== SignalStrategy::DISCONNECTED
) {
142 VLOG(1) << "Connection closed.";
143 CloseOnError(SIGNALING_ERROR
);
147 bool ConnectionToHost::OnSignalStrategyIncomingStanza(
148 const buzz::XmlElement
* stanza
) {
152 void ConnectionToHost::OnSessionManagerReady() {
153 DCHECK(CalledOnValidThread());
155 // After SessionManager is initialized we can try to connect to the host.
156 session_
= session_manager_
->Connect(
157 host_jid_
, authenticator_
.Pass(), candidate_config_
.Pass());
158 session_
->SetEventHandler(this);
161 void ConnectionToHost::OnIncomingSession(
163 SessionManager::IncomingSessionResponse
* response
) {
164 DCHECK(CalledOnValidThread());
165 // Client always rejects incoming sessions.
166 *response
= SessionManager::DECLINE
;
169 void ConnectionToHost::OnSessionStateChange(
170 Session::State state
) {
171 DCHECK(CalledOnValidThread());
172 DCHECK(event_callback_
);
175 case Session::INITIALIZING
:
176 case Session::CONNECTING
:
177 case Session::ACCEPTING
:
178 case Session::CONNECTED
:
179 case Session::AUTHENTICATING
:
180 // Don't care about these events.
183 case Session::AUTHENTICATED
:
184 SetState(AUTHENTICATED
, OK
);
186 control_dispatcher_
.reset(new ClientControlDispatcher());
187 control_dispatcher_
->Init(
188 session_
.get(), session_
->config().control_config(),
189 base::Bind(&ConnectionToHost::OnChannelInitialized
,
190 base::Unretained(this)));
191 control_dispatcher_
->set_client_stub(client_stub_
);
192 control_dispatcher_
->set_clipboard_stub(clipboard_stub_
);
194 event_dispatcher_
.reset(new ClientEventDispatcher());
195 event_dispatcher_
->Init(
196 session_
.get(), session_
->config().event_config(),
197 base::Bind(&ConnectionToHost::OnChannelInitialized
,
198 base::Unretained(this)));
200 video_reader_
= VideoReader::Create(session_
->config());
201 video_reader_
->Init(session_
.get(), monitored_video_stub_
.get(),
202 base::Bind(&ConnectionToHost::OnChannelInitialized
,
203 base::Unretained(this)));
205 audio_reader_
= AudioReader::Create(session_
->config());
206 if (audio_reader_
.get()) {
207 audio_reader_
->Init(session_
.get(), session_
->config().audio_config(),
208 base::Bind(&ConnectionToHost::OnChannelInitialized
,
209 base::Unretained(this)));
210 audio_reader_
->set_audio_stub(audio_stub_
);
214 case Session::CLOSED
:
216 SetState(CLOSED
, OK
);
219 case Session::FAILED
:
220 // If we were connected then treat signaling timeout error as if
221 // the connection was closed by the peer.
223 // TODO(sergeyu): This logic belongs to the webapp, but we
224 // currently don't expose this error code to the webapp, and it
225 // would be hard to add it because client plugin and webapp
226 // versions may not be in sync. It should be easy to do after we
227 // are finished moving the client plugin to NaCl.
228 if (state_
== CONNECTED
&& session_
->error() == SIGNALING_TIMEOUT
) {
230 SetState(CLOSED
, OK
);
232 CloseOnError(session_
->error());
238 void ConnectionToHost::OnSessionRouteChange(const std::string
& channel_name
,
239 const TransportRoute
& route
) {
240 event_callback_
->OnRouteChanged(channel_name
, route
);
243 void ConnectionToHost::OnVideoChannelStatus(bool active
) {
244 event_callback_
->OnConnectionReady(active
);
247 ConnectionToHost::State
ConnectionToHost::state() const {
251 void ConnectionToHost::OnChannelInitialized(bool successful
) {
253 LOG(ERROR
) << "Failed to connect video channel";
254 CloseOnError(CHANNEL_CONNECTION_ERROR
);
258 NotifyIfChannelsReady();
261 void ConnectionToHost::NotifyIfChannelsReady() {
262 if (!control_dispatcher_
.get() || !control_dispatcher_
->is_connected())
264 if (!event_dispatcher_
.get() || !event_dispatcher_
->is_connected())
266 if (!video_reader_
.get() || !video_reader_
->is_connected())
268 if ((!audio_reader_
.get() || !audio_reader_
->is_connected()) &&
269 session_
->config().is_audio_enabled()) {
272 if (state_
!= AUTHENTICATED
)
275 // Start forwarding clipboard and input events.
276 clipboard_forwarder_
.set_clipboard_stub(control_dispatcher_
.get());
277 event_forwarder_
.set_input_stub(event_dispatcher_
.get());
278 SetState(CONNECTED
, OK
);
281 void ConnectionToHost::CloseOnError(ErrorCode error
) {
283 SetState(FAILED
, error
);
286 void ConnectionToHost::CloseChannels() {
287 control_dispatcher_
.reset();
288 event_dispatcher_
.reset();
289 clipboard_forwarder_
.set_clipboard_stub(NULL
);
290 event_forwarder_
.set_input_stub(NULL
);
291 video_reader_
.reset();
292 audio_reader_
.reset();
295 void ConnectionToHost::SetState(State state
, ErrorCode error
) {
296 DCHECK(CalledOnValidThread());
297 // |error| should be specified only when |state| is set to FAILED.
298 DCHECK(state
== FAILED
|| error
== OK
);
300 if (state
!= state_
) {
303 event_callback_
->OnConnectionState(state_
, error_
);
307 } // namespace protocol
308 } // namespace remoting