Disable session invalidations on Android with a flag.
[chromium-blink-merge.git] / remoting / protocol / connection_to_host.cc
blob1e6940a12e7e8ef37f80a3cef3957b05c166d7b6
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"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/location.h"
10 #include "remoting/base/constants.h"
11 #include "remoting/jingle_glue/signal_strategy.h"
12 #include "remoting/protocol/audio_reader.h"
13 #include "remoting/protocol/audio_stub.h"
14 #include "remoting/protocol/auth_util.h"
15 #include "remoting/protocol/authenticator.h"
16 #include "remoting/protocol/client_control_dispatcher.h"
17 #include "remoting/protocol/client_event_dispatcher.h"
18 #include "remoting/protocol/client_stub.h"
19 #include "remoting/protocol/clipboard_stub.h"
20 #include "remoting/protocol/errors.h"
21 #include "remoting/protocol/jingle_session_manager.h"
22 #include "remoting/protocol/transport.h"
23 #include "remoting/protocol/video_reader.h"
24 #include "remoting/protocol/video_stub.h"
26 namespace remoting {
27 namespace protocol {
29 ConnectionToHost::ConnectionToHost()
30 : event_callback_(NULL),
31 client_stub_(NULL),
32 clipboard_stub_(NULL),
33 audio_stub_(NULL),
34 signal_strategy_(NULL),
35 state_(INITIALIZING),
36 error_(OK) {
39 ConnectionToHost::~ConnectionToHost() {
40 CloseChannels();
42 if (session_.get())
43 session_.reset();
45 if (session_manager_.get())
46 session_manager_.reset();
48 if (signal_strategy_)
49 signal_strategy_->RemoveListener(this);
52 void ConnectionToHost::Connect(SignalStrategy* signal_strategy,
53 scoped_ptr<TransportFactory> transport_factory,
54 scoped_ptr<Authenticator> authenticator,
55 const std::string& host_jid,
56 HostEventCallback* event_callback) {
57 DCHECK(client_stub_);
58 DCHECK(clipboard_stub_);
59 DCHECK(monitored_video_stub_);
61 signal_strategy_ = signal_strategy;
62 event_callback_ = event_callback;
63 authenticator_ = authenticator.Pass();
65 // Save jid of the host. The actual connection is created later after
66 // |signal_strategy_| is connected.
67 host_jid_ = host_jid;
69 signal_strategy_->AddListener(this);
70 signal_strategy_->Connect();
72 session_manager_.reset(new JingleSessionManager(transport_factory.Pass()));
73 session_manager_->Init(signal_strategy_, this);
75 SetState(CONNECTING, OK);
78 const SessionConfig& ConnectionToHost::config() {
79 return session_->config();
82 ClipboardStub* ConnectionToHost::clipboard_forwarder() {
83 return &clipboard_forwarder_;
86 HostStub* ConnectionToHost::host_stub() {
87 // TODO(wez): Add a HostFilter class, equivalent to input filter.
88 return control_dispatcher_.get();
91 InputStub* ConnectionToHost::input_stub() {
92 return &event_forwarder_;
95 void ConnectionToHost::set_client_stub(ClientStub* client_stub) {
96 client_stub_ = client_stub;
99 void ConnectionToHost::set_clipboard_stub(ClipboardStub* clipboard_stub) {
100 clipboard_stub_ = clipboard_stub;
103 void ConnectionToHost::set_video_stub(VideoStub* video_stub) {
104 DCHECK(video_stub);
105 monitored_video_stub_.reset(new MonitoredVideoStub(
106 video_stub,
107 base::TimeDelta::FromSeconds(
108 MonitoredVideoStub::kConnectivityCheckDelaySeconds),
109 base::Bind(&ConnectionToHost::OnVideoChannelStatus,
110 base::Unretained(this))));
113 void ConnectionToHost::set_audio_stub(AudioStub* audio_stub) {
114 audio_stub_ = audio_stub;
117 void ConnectionToHost::OnSignalStrategyStateChange(
118 SignalStrategy::State state) {
119 DCHECK(CalledOnValidThread());
120 DCHECK(event_callback_);
122 if (state == SignalStrategy::CONNECTED) {
123 VLOG(1) << "Connected as: " << signal_strategy_->GetLocalJid();
124 } else if (state == SignalStrategy::DISCONNECTED) {
125 VLOG(1) << "Connection closed.";
126 CloseOnError(SIGNALING_ERROR);
130 bool ConnectionToHost::OnSignalStrategyIncomingStanza(
131 const buzz::XmlElement* stanza) {
132 return false;
135 void ConnectionToHost::OnSessionManagerReady() {
136 DCHECK(CalledOnValidThread());
138 // After SessionManager is initialized we can try to connect to the host.
139 scoped_ptr<CandidateSessionConfig> candidate_config =
140 CandidateSessionConfig::CreateDefault();
141 if (!audio_stub_) {
142 candidate_config->DisableAudioChannel();
144 candidate_config->EnableVideoCodec(ChannelConfig::CODEC_VP9);
146 session_ = session_manager_->Connect(
147 host_jid_, authenticator_.Pass(), candidate_config.Pass());
148 session_->SetEventHandler(this);
151 void ConnectionToHost::OnIncomingSession(
152 Session* session,
153 SessionManager::IncomingSessionResponse* response) {
154 DCHECK(CalledOnValidThread());
155 // Client always rejects incoming sessions.
156 *response = SessionManager::DECLINE;
159 void ConnectionToHost::OnSessionStateChange(
160 Session::State state) {
161 DCHECK(CalledOnValidThread());
162 DCHECK(event_callback_);
164 switch (state) {
165 case Session::INITIALIZING:
166 case Session::CONNECTING:
167 case Session::ACCEPTING:
168 case Session::CONNECTED:
169 case Session::AUTHENTICATING:
170 // Don't care about these events.
171 break;
173 case Session::AUTHENTICATED:
174 SetState(AUTHENTICATED, OK);
176 control_dispatcher_.reset(new ClientControlDispatcher());
177 control_dispatcher_->Init(
178 session_.get(), session_->config().control_config(),
179 base::Bind(&ConnectionToHost::OnChannelInitialized,
180 base::Unretained(this)));
181 control_dispatcher_->set_client_stub(client_stub_);
182 control_dispatcher_->set_clipboard_stub(clipboard_stub_);
184 event_dispatcher_.reset(new ClientEventDispatcher());
185 event_dispatcher_->Init(
186 session_.get(), session_->config().event_config(),
187 base::Bind(&ConnectionToHost::OnChannelInitialized,
188 base::Unretained(this)));
190 video_reader_ = VideoReader::Create(session_->config());
191 video_reader_->Init(session_.get(), monitored_video_stub_.get(),
192 base::Bind(&ConnectionToHost::OnChannelInitialized,
193 base::Unretained(this)));
195 audio_reader_ = AudioReader::Create(session_->config());
196 if (audio_reader_.get()) {
197 audio_reader_->Init(session_.get(), session_->config().audio_config(),
198 base::Bind(&ConnectionToHost::OnChannelInitialized,
199 base::Unretained(this)));
200 audio_reader_->set_audio_stub(audio_stub_);
202 break;
204 case Session::CLOSED:
205 CloseChannels();
206 SetState(CLOSED, OK);
207 break;
209 case Session::FAILED:
210 // If we were connected then treat signaling timeout error as if
211 // the connection was closed by the peer.
213 // TODO(sergeyu): This logic belongs to the webapp, but we
214 // currently don't expose this error code to the webapp, and it
215 // would be hard to add it because client plugin and webapp
216 // versions may not be in sync. It should be easy to do after we
217 // are finished moving the client plugin to NaCl.
218 if (state_ == CONNECTED && session_->error() == SIGNALING_TIMEOUT) {
219 CloseChannels();
220 SetState(CLOSED, OK);
221 } else {
222 CloseOnError(session_->error());
224 break;
228 void ConnectionToHost::OnSessionRouteChange(const std::string& channel_name,
229 const TransportRoute& route) {
230 event_callback_->OnRouteChanged(channel_name, route);
233 void ConnectionToHost::OnVideoChannelStatus(bool active) {
234 event_callback_->OnConnectionReady(active);
237 ConnectionToHost::State ConnectionToHost::state() const {
238 return state_;
241 void ConnectionToHost::OnChannelInitialized(bool successful) {
242 if (!successful) {
243 LOG(ERROR) << "Failed to connect video channel";
244 CloseOnError(CHANNEL_CONNECTION_ERROR);
245 return;
248 NotifyIfChannelsReady();
251 void ConnectionToHost::NotifyIfChannelsReady() {
252 if (!control_dispatcher_.get() || !control_dispatcher_->is_connected())
253 return;
254 if (!event_dispatcher_.get() || !event_dispatcher_->is_connected())
255 return;
256 if (!video_reader_.get() || !video_reader_->is_connected())
257 return;
258 if ((!audio_reader_.get() || !audio_reader_->is_connected()) &&
259 session_->config().is_audio_enabled()) {
260 return;
262 if (state_ != AUTHENTICATED)
263 return;
265 // Start forwarding clipboard and input events.
266 clipboard_forwarder_.set_clipboard_stub(control_dispatcher_.get());
267 event_forwarder_.set_input_stub(event_dispatcher_.get());
268 SetState(CONNECTED, OK);
271 void ConnectionToHost::CloseOnError(ErrorCode error) {
272 CloseChannels();
273 SetState(FAILED, error);
276 void ConnectionToHost::CloseChannels() {
277 control_dispatcher_.reset();
278 event_dispatcher_.reset();
279 clipboard_forwarder_.set_clipboard_stub(NULL);
280 event_forwarder_.set_input_stub(NULL);
281 video_reader_.reset();
282 audio_reader_.reset();
285 void ConnectionToHost::SetState(State state, ErrorCode error) {
286 DCHECK(CalledOnValidThread());
287 // |error| should be specified only when |state| is set to FAILED.
288 DCHECK(state == FAILED || error == OK);
290 if (state != state_) {
291 state_ = state;
292 error_ = error;
293 event_callback_->OnConnectionState(state_, error_);
297 } // namespace protocol
298 } // namespace remoting