| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "remoting/protocol/connection_to_client.h" |
| |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "base/message_loop/message_loop_proxy.h" |
| #include "net/base/io_buffer.h" |
| #include "remoting/protocol/clipboard_stub.h" |
| #include "remoting/protocol/host_control_dispatcher.h" |
| #include "remoting/protocol/host_event_dispatcher.h" |
| #include "remoting/protocol/host_stub.h" |
| #include "remoting/protocol/input_stub.h" |
| |
| namespace remoting { |
| namespace protocol { |
| |
| ConnectionToClient::ConnectionToClient(protocol::Session* session) |
| : handler_(NULL), |
| clipboard_stub_(NULL), |
| host_stub_(NULL), |
| input_stub_(NULL), |
| session_(session) { |
| session_->SetEventHandler(this); |
| } |
| |
| ConnectionToClient::~ConnectionToClient() { |
| } |
| |
| void ConnectionToClient::SetEventHandler(EventHandler* event_handler) { |
| DCHECK(CalledOnValidThread()); |
| handler_ = event_handler; |
| } |
| |
| protocol::Session* ConnectionToClient::session() { |
| DCHECK(CalledOnValidThread()); |
| return session_.get(); |
| } |
| |
| void ConnectionToClient::Disconnect() { |
| DCHECK(CalledOnValidThread()); |
| |
| CloseChannels(); |
| |
| // This should trigger OnConnectionClosed() event and this object |
| // may be destroyed as the result. |
| session_->Close(); |
| } |
| |
| void ConnectionToClient::UpdateSequenceNumber(int64 sequence_number) { |
| DCHECK(CalledOnValidThread()); |
| handler_->OnSequenceNumberUpdated(this, sequence_number); |
| } |
| |
| VideoStub* ConnectionToClient::video_stub() { |
| DCHECK(CalledOnValidThread()); |
| return video_writer_.get(); |
| } |
| |
| AudioStub* ConnectionToClient::audio_stub() { |
| DCHECK(CalledOnValidThread()); |
| return audio_writer_.get(); |
| } |
| |
| // Return pointer to ClientStub. |
| ClientStub* ConnectionToClient::client_stub() { |
| DCHECK(CalledOnValidThread()); |
| return control_dispatcher_.get(); |
| } |
| |
| void ConnectionToClient::set_clipboard_stub( |
| protocol::ClipboardStub* clipboard_stub) { |
| DCHECK(CalledOnValidThread()); |
| clipboard_stub_ = clipboard_stub; |
| } |
| |
| ClipboardStub* ConnectionToClient::clipboard_stub() { |
| DCHECK(CalledOnValidThread()); |
| return clipboard_stub_; |
| } |
| |
| void ConnectionToClient::set_host_stub(protocol::HostStub* host_stub) { |
| DCHECK(CalledOnValidThread()); |
| host_stub_ = host_stub; |
| } |
| |
| HostStub* ConnectionToClient::host_stub() { |
| DCHECK(CalledOnValidThread()); |
| return host_stub_; |
| } |
| |
| void ConnectionToClient::set_input_stub(protocol::InputStub* input_stub) { |
| DCHECK(CalledOnValidThread()); |
| input_stub_ = input_stub; |
| } |
| |
| InputStub* ConnectionToClient::input_stub() { |
| DCHECK(CalledOnValidThread()); |
| return input_stub_; |
| } |
| |
| void ConnectionToClient::OnSessionStateChange(Session::State state) { |
| DCHECK(CalledOnValidThread()); |
| |
| DCHECK(handler_); |
| switch(state) { |
| case Session::INITIALIZING: |
| case Session::CONNECTING: |
| case Session::ACCEPTING: |
| case Session::CONNECTED: |
| // Don't care about these events. |
| break; |
| |
| case Session::AUTHENTICATED: |
| // Initialize channels. |
| control_dispatcher_.reset(new HostControlDispatcher()); |
| control_dispatcher_->Init( |
| session_.get(), session_->config().control_config(), |
| base::Bind(&ConnectionToClient::OnChannelInitialized, |
| base::Unretained(this))); |
| control_dispatcher_->set_clipboard_stub(clipboard_stub_); |
| control_dispatcher_->set_host_stub(host_stub_); |
| |
| event_dispatcher_.reset(new HostEventDispatcher()); |
| event_dispatcher_->Init( |
| session_.get(), session_->config().event_config(), |
| base::Bind(&ConnectionToClient::OnChannelInitialized, |
| base::Unretained(this))); |
| event_dispatcher_->set_input_stub(input_stub_); |
| event_dispatcher_->set_sequence_number_callback(base::Bind( |
| &ConnectionToClient::UpdateSequenceNumber, base::Unretained(this))); |
| |
| video_writer_ = VideoWriter::Create(session_->config()); |
| video_writer_->Init(session_.get(), base::Bind( |
| &ConnectionToClient::OnChannelInitialized, base::Unretained(this))); |
| |
| audio_writer_ = AudioWriter::Create(session_->config()); |
| if (audio_writer_.get()) { |
| audio_writer_->Init( |
| session_.get(), session_->config().audio_config(), |
| base::Bind(&ConnectionToClient::OnChannelInitialized, |
| base::Unretained(this))); |
| } |
| |
| // Notify the handler after initializing the channels, so that |
| // ClientSession can get a client clipboard stub. |
| handler_->OnConnectionAuthenticated(this); |
| break; |
| |
| case Session::CLOSED: |
| Close(OK); |
| break; |
| |
| case Session::FAILED: |
| Close(session_->error()); |
| break; |
| } |
| } |
| |
| void ConnectionToClient::OnSessionRouteChange( |
| const std::string& channel_name, |
| const TransportRoute& route) { |
| handler_->OnRouteChange(this, channel_name, route); |
| } |
| |
| void ConnectionToClient::OnChannelInitialized(bool successful) { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!successful) { |
| LOG(ERROR) << "Failed to connect a channel"; |
| Close(CHANNEL_CONNECTION_ERROR); |
| return; |
| } |
| |
| NotifyIfChannelsReady(); |
| } |
| |
| void ConnectionToClient::NotifyIfChannelsReady() { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!control_dispatcher_.get() || !control_dispatcher_->is_connected()) |
| return; |
| if (!event_dispatcher_.get() || !event_dispatcher_->is_connected()) |
| return; |
| if (!video_writer_.get() || !video_writer_->is_connected()) |
| return; |
| if ((!audio_writer_.get() || !audio_writer_->is_connected()) && |
| session_->config().is_audio_enabled()) { |
| return; |
| } |
| handler_->OnConnectionChannelsConnected(this); |
| } |
| |
| void ConnectionToClient::Close(ErrorCode error) { |
| CloseChannels(); |
| handler_->OnConnectionClosed(this, error); |
| } |
| |
| void ConnectionToClient::CloseChannels() { |
| control_dispatcher_.reset(); |
| event_dispatcher_.reset(); |
| video_writer_.reset(); |
| audio_writer_.reset(); |
| } |
| |
| } // namespace protocol |
| } // namespace remoting |