Convert Chromoting logging to appear in client debug-info div.
[chromium-blink-merge.git] / remoting / client / chromoting_client.cc
bloba46409bd47dd372f15007ea22d93977de9d09cf4
1 // Copyright (c) 2011 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/client/chromoting_client.h"
7 #include "base/message_loop.h"
8 #include "remoting/base/tracer.h"
9 #include "remoting/client/chromoting_view.h"
10 #include "remoting/client/client_context.h"
11 #include "remoting/client/client_logger.h"
12 #include "remoting/client/input_handler.h"
13 #include "remoting/client/rectangle_update_decoder.h"
14 #include "remoting/protocol/connection_to_host.h"
15 #include "remoting/protocol/session_config.h"
17 namespace remoting {
19 ChromotingClient::ChromotingClient(const ClientConfig& config,
20 ClientContext* context,
21 protocol::ConnectionToHost* connection,
22 ChromotingView* view,
23 RectangleUpdateDecoder* rectangle_decoder,
24 InputHandler* input_handler,
25 ClientLogger* logger,
26 Task* client_done)
27 : config_(config),
28 context_(context),
29 connection_(connection),
30 view_(view),
31 rectangle_decoder_(rectangle_decoder),
32 input_handler_(input_handler),
33 logger_(logger),
34 client_done_(client_done),
35 state_(CREATED),
36 packet_being_processed_(false),
37 last_sequence_number_(0) {
40 ChromotingClient::~ChromotingClient() {
43 void ChromotingClient::Start() {
44 if (message_loop() != MessageLoop::current()) {
45 message_loop()->PostTask(
46 FROM_HERE,
47 NewRunnableMethod(this, &ChromotingClient::Start));
48 return;
51 connection_->Connect(config_.username, config_.auth_token, config_.host_jid,
52 config_.nonce, this, this, this);
54 if (!view_->Initialize()) {
55 ClientDone();
59 void ChromotingClient::StartSandboxed(scoped_refptr<XmppProxy> xmpp_proxy,
60 const std::string& your_jid,
61 const std::string& host_jid) {
62 // TODO(ajwong): Merge this with Start(), and just change behavior based on
63 // ClientConfig.
64 if (message_loop() != MessageLoop::current()) {
65 message_loop()->PostTask(
66 FROM_HERE,
67 NewRunnableMethod(this, &ChromotingClient::StartSandboxed, xmpp_proxy,
68 your_jid, host_jid));
69 return;
72 connection_->ConnectSandboxed(xmpp_proxy, your_jid, host_jid, config_.nonce,
73 this, this, this);
75 if (!view_->Initialize()) {
76 ClientDone();
80 void ChromotingClient::Stop() {
81 if (message_loop() != MessageLoop::current()) {
82 message_loop()->PostTask(
83 FROM_HERE,
84 NewRunnableMethod(this, &ChromotingClient::Stop));
85 return;
88 connection_->Disconnect();
90 view_->TearDown();
93 void ChromotingClient::ClientDone() {
94 if (client_done_ != NULL) {
95 message_loop()->PostTask(FROM_HERE, client_done_);
99 ChromotingStats* ChromotingClient::GetStats() {
100 return &stats_;
103 void ChromotingClient::Repaint() {
104 if (message_loop() != MessageLoop::current()) {
105 message_loop()->PostTask(
106 FROM_HERE,
107 NewRunnableMethod(this, &ChromotingClient::Repaint));
108 return;
111 view_->Paint();
114 void ChromotingClient::SetViewport(int x, int y, int width, int height) {
115 if (message_loop() != MessageLoop::current()) {
116 message_loop()->PostTask(
117 FROM_HERE,
118 NewRunnableMethod(this, &ChromotingClient::SetViewport,
119 x, y, width, height));
120 return;
123 view_->SetViewport(x, y, width, height);
126 void ChromotingClient::ProcessVideoPacket(const VideoPacket* packet,
127 Task* done) {
128 if (message_loop() != MessageLoop::current()) {
129 message_loop()->PostTask(
130 FROM_HERE,
131 NewRunnableMethod(this, &ChromotingClient::ProcessVideoPacket,
132 packet, done));
133 return;
136 // Record size of the packet for statistics.
137 stats_.video_bandwidth()->Record(packet->data().size());
139 // Record statistics received from host.
140 if (packet->has_capture_time_ms())
141 stats_.video_capture_ms()->Record(packet->capture_time_ms());
142 if (packet->has_encode_time_ms())
143 stats_.video_encode_ms()->Record(packet->encode_time_ms());
144 if (packet->has_client_sequence_number() &&
145 packet->client_sequence_number() > last_sequence_number_) {
146 last_sequence_number_ = packet->client_sequence_number();
147 base::TimeDelta round_trip_latency =
148 base::Time::Now() -
149 base::Time::FromInternalValue(packet->client_sequence_number());
150 stats_.round_trip_ms()->Record(round_trip_latency.InMilliseconds());
153 received_packets_.push_back(QueuedVideoPacket(packet, done));
154 if (!packet_being_processed_)
155 DispatchPacket();
158 int ChromotingClient::GetPendingPackets() {
159 return received_packets_.size();
162 void ChromotingClient::DispatchPacket() {
163 DCHECK_EQ(message_loop(), MessageLoop::current());
164 CHECK(!packet_being_processed_);
166 if (received_packets_.empty()) {
167 // Nothing to do!
168 return;
171 const VideoPacket* packet = received_packets_.front().packet;
172 packet_being_processed_ = true;
174 ScopedTracer tracer("Handle video packet");
176 // Measure the latency between the last packet being received and presented.
177 bool last_packet = (packet->flags() & VideoPacket::LAST_PACKET) != 0;
178 base::Time decode_start;
179 if (last_packet)
180 decode_start = base::Time::Now();
182 rectangle_decoder_->DecodePacket(
183 packet, NewTracedMethod(this, &ChromotingClient::OnPacketDone,
184 last_packet, decode_start));
187 void ChromotingClient::OnConnectionOpened(protocol::ConnectionToHost* conn) {
188 logger_->VLog(1, "ChromotingClient::OnConnectionOpened");
189 Initialize();
190 SetConnectionState(CONNECTED);
193 void ChromotingClient::OnConnectionClosed(protocol::ConnectionToHost* conn) {
194 logger_->VLog(1, "ChromotingClient::OnConnectionClosed");
195 SetConnectionState(DISCONNECTED);
198 void ChromotingClient::OnConnectionFailed(protocol::ConnectionToHost* conn) {
199 logger_->VLog(1, "ChromotingClient::OnConnectionFailed");
200 SetConnectionState(FAILED);
203 MessageLoop* ChromotingClient::message_loop() {
204 return context_->jingle_thread()->message_loop();
207 void ChromotingClient::SetConnectionState(ConnectionState s) {
208 // TODO(ajwong): We actually may want state to be a shared variable. Think
209 // through later.
210 if (message_loop() != MessageLoop::current()) {
211 message_loop()->PostTask(
212 FROM_HERE,
213 NewRunnableMethod(this, &ChromotingClient::SetConnectionState, s));
214 return;
217 state_ = s;
218 view_->SetConnectionState(s);
220 Repaint();
223 void ChromotingClient::OnPacketDone(bool last_packet,
224 base::Time decode_start) {
225 if (message_loop() != MessageLoop::current()) {
226 message_loop()->PostTask(
227 FROM_HERE,
228 NewTracedMethod(this, &ChromotingClient::OnPacketDone,
229 last_packet, decode_start));
230 return;
233 TraceContext::tracer()->PrintString("Packet done");
235 // Record the latency between the final packet being received and
236 // presented.
237 if (last_packet) {
238 stats_.video_decode_ms()->Record(
239 (base::Time::Now() - decode_start).InMilliseconds());
242 received_packets_.front().done->Run();
243 delete received_packets_.front().done;
244 received_packets_.pop_front();
246 packet_being_processed_ = false;
248 // Process the next video packet.
249 DispatchPacket();
252 void ChromotingClient::Initialize() {
253 if (message_loop() != MessageLoop::current()) {
254 message_loop()->PostTask(
255 FROM_HERE,
256 NewTracedMethod(this, &ChromotingClient::Initialize));
257 return;
260 TraceContext::tracer()->PrintString("Initializing client.");
262 const protocol::SessionConfig* config = connection_->config();
264 // Resize the window.
265 int width = config->initial_resolution().width;
266 int height = config->initial_resolution().height;
267 logger_->VLog(1, "Initial screen geometry: %dx%d", width, height);
269 // TODO(ajwong): What to do here? Does the decoder actually need to request
270 // the right frame size? This is mainly an optimization right?
271 // rectangle_decoder_->SetOutputFrameSize(width, height);
272 view_->SetViewport(0, 0, width, height);
274 // Initialize the decoder.
275 rectangle_decoder_->Initialize(config);
277 // Schedule the input handler to process the event queue.
278 input_handler_->Initialize();
281 ////////////////////////////////////////////////////////////////////////////
282 // ClientStub control channel interface.
283 void ChromotingClient::NotifyResolution(
284 const protocol::NotifyResolutionRequest* msg, Task* done) {
285 logger_->Log(logging::LOG_INFO, "NotifyResolution change");
286 NOTIMPLEMENTED();
287 done->Run();
288 delete done;
291 void ChromotingClient::BeginSessionResponse(
292 const protocol::LocalLoginStatus* msg, Task* done) {
293 if (message_loop() != MessageLoop::current()) {
294 message_loop()->PostTask(
295 FROM_HERE,
296 NewRunnableMethod(this, &ChromotingClient::BeginSessionResponse,
297 msg, done));
298 return;
301 logger_->Log(logging::LOG_INFO, "BeginSessionResponse received");
303 // Inform the connection that the client has been authenticated. This will
304 // enable the communication channels.
305 if (msg->success()) {
306 connection_->OnClientAuthenticated();
309 view_->UpdateLoginStatus(msg->success(), msg->error_info());
310 done->Run();
311 delete done;
314 } // namespace remoting