blob: e325bf762c9ce703b5df54a9d3ea24b43a5b4223 [file] [log] [blame]
// Copyright (c) 2010 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.
// TODO(hclam): Remove this header once MessageDispatcher is used.
#include "remoting/base/multiple_array_input_stream.h"
#include "remoting/host/client_connection.h"
#include "google/protobuf/message.h"
#include "net/base/io_buffer.h"
#include "remoting/protocol/util.h"
namespace remoting {
// Determine how many update streams we should count to find the size of
// average update stream.
static const size_t kAverageUpdateStream = 10;
ClientConnection::ClientConnection(MessageLoop* message_loop,
EventHandler* handler)
: loop_(message_loop),
handler_(handler) {
DCHECK(loop_);
DCHECK(handler_);
}
ClientConnection::~ClientConnection() {
// TODO(hclam): When we shut down the viewer we may have to close the
// connection.
}
void ClientConnection::Init(ChromotocolConnection* connection) {
DCHECK_EQ(connection->message_loop(), MessageLoop::current());
connection_ = connection;
connection_->SetStateChangeCallback(
NewCallback(this, &ClientConnection::OnConnectionStateChange));
}
ChromotocolConnection* ClientConnection::connection() {
return connection_;
}
void ClientConnection::SendInitClientMessage(int width, int height) {
DCHECK_EQ(loop_, MessageLoop::current());
// If we are disconnected then return.
if (!connection_)
return;
ChromotingHostMessage msg;
msg.mutable_init_client()->set_width(width);
msg.mutable_init_client()->set_height(height);
DCHECK(msg.IsInitialized());
video_writer_.SendMessage(msg);
}
void ClientConnection::SendVideoPacket(const VideoPacket& packet) {
DCHECK_EQ(loop_, MessageLoop::current());
// If we are disconnected then return.
if (!connection_)
return;
ChromotingHostMessage* message = new ChromotingHostMessage();
// TODO(sergeyu): avoid memcopy here.
*message->mutable_video_packet() = packet;
video_writer_.SendMessage(*message);
delete message;
}
int ClientConnection::GetPendingUpdateStreamMessages() {
DCHECK_EQ(loop_, MessageLoop::current());
return video_writer_.GetPendingMessages();
}
void ClientConnection::Disconnect() {
DCHECK_EQ(loop_, MessageLoop::current());
// If there is a channel then close it and release the reference.
if (connection_) {
connection_->Close(NewRunnableMethod(this, &ClientConnection::OnClosed));
connection_ = NULL;
}
}
ClientConnection::ClientConnection() {}
void ClientConnection::OnConnectionStateChange(
ChromotocolConnection::State state) {
if (state == ChromotocolConnection::CONNECTED) {
event_reader_.Init<ChromotingClientMessage>(
connection_->event_channel(),
NewCallback(this, &ClientConnection::OnMessageReceived));
video_writer_.Init(connection_->video_channel());
}
loop_->PostTask(FROM_HERE,
NewRunnableMethod(this, &ClientConnection::StateChangeTask, state));
}
void ClientConnection::OnMessageReceived(ChromotingClientMessage* message) {
loop_->PostTask(FROM_HERE,
NewRunnableMethod(this, &ClientConnection::MessageReceivedTask,
message));
}
void ClientConnection::StateChangeTask(ChromotocolConnection::State state) {
DCHECK_EQ(loop_, MessageLoop::current());
DCHECK(handler_);
switch(state) {
case ChromotocolConnection::CONNECTING:
break;
// Don't care about this message.
case ChromotocolConnection::CONNECTED:
handler_->OnConnectionOpened(this);
break;
case ChromotocolConnection::CLOSED:
handler_->OnConnectionClosed(this);
break;
case ChromotocolConnection::FAILED:
handler_->OnConnectionFailed(this);
break;
default:
// We shouldn't receive other states.
NOTREACHED();
}
}
void ClientConnection::MessageReceivedTask(ChromotingClientMessage* message) {
DCHECK_EQ(loop_, MessageLoop::current());
DCHECK(handler_);
handler_->HandleMessage(this, message);
}
// OnClosed() is used as a callback for ChromotocolConnection::Close().
void ClientConnection::OnClosed() {
}
} // namespace remoting