OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/client/chromoting_client.h" | 5 #include "remoting/client/chromoting_client.h" |
6 | 6 |
7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
| 8 #include "remoting/base/tracer.h" |
8 #include "remoting/client/chromoting_view.h" | 9 #include "remoting/client/chromoting_view.h" |
9 #include "remoting/client/client_context.h" | 10 #include "remoting/client/client_context.h" |
10 #include "remoting/client/host_connection.h" | 11 #include "remoting/client/host_connection.h" |
11 #include "remoting/client/input_handler.h" | 12 #include "remoting/client/input_handler.h" |
| 13 #include "remoting/client/rectangle_update_decoder.h" |
12 | 14 |
13 static const uint32 kCreatedColor = 0xffccccff; | 15 static const uint32 kCreatedColor = 0xffccccff; |
14 static const uint32 kDisconnectedColor = 0xff00ccff; | 16 static const uint32 kDisconnectedColor = 0xff00ccff; |
15 static const uint32 kFailedColor = 0xffcc00ff; | 17 static const uint32 kFailedColor = 0xffcc00ff; |
16 | 18 |
17 namespace remoting { | 19 namespace remoting { |
18 | 20 |
19 ChromotingClient::ChromotingClient(const ClientConfig& config, | 21 ChromotingClient::ChromotingClient(const ClientConfig& config, |
20 ClientContext* context, | 22 ClientContext* context, |
21 HostConnection* connection, | 23 HostConnection* connection, |
22 ChromotingView* view, | 24 ChromotingView* view, |
| 25 RectangleUpdateDecoder* rectangle_decoder, |
23 InputHandler* input_handler, | 26 InputHandler* input_handler, |
24 CancelableTask* client_done) | 27 CancelableTask* client_done) |
25 : config_(config), | 28 : config_(config), |
26 context_(context), | 29 context_(context), |
27 connection_(connection), | 30 connection_(connection), |
28 view_(view), | 31 view_(view), |
| 32 rectangle_decoder_(rectangle_decoder), |
29 input_handler_(input_handler), | 33 input_handler_(input_handler), |
30 client_done_(client_done), | 34 client_done_(client_done), |
31 state_(CREATED) { | 35 state_(CREATED), |
| 36 message_being_processed_(false) { |
32 } | 37 } |
33 | 38 |
34 ChromotingClient::~ChromotingClient() { | 39 ChromotingClient::~ChromotingClient() { |
35 } | 40 } |
36 | 41 |
37 void ChromotingClient::Start() { | 42 void ChromotingClient::Start() { |
38 if (message_loop() != MessageLoop::current()) { | 43 if (message_loop() != MessageLoop::current()) { |
39 message_loop()->PostTask( | 44 message_loop()->PostTask( |
40 FROM_HERE, | 45 FROM_HERE, |
41 NewRunnableMethod(this, &ChromotingClient::Start)); | 46 NewRunnableMethod(this, &ChromotingClient::Start)); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 void ChromotingClient::HandleMessages(HostConnection* conn, | 99 void ChromotingClient::HandleMessages(HostConnection* conn, |
95 HostMessageList* messages) { | 100 HostMessageList* messages) { |
96 if (message_loop() != MessageLoop::current()) { | 101 if (message_loop() != MessageLoop::current()) { |
97 message_loop()->PostTask( | 102 message_loop()->PostTask( |
98 FROM_HERE, | 103 FROM_HERE, |
99 NewRunnableMethod(this, &ChromotingClient::HandleMessages, | 104 NewRunnableMethod(this, &ChromotingClient::HandleMessages, |
100 conn, messages)); | 105 conn, messages)); |
101 return; | 106 return; |
102 } | 107 } |
103 | 108 |
104 for (size_t i = 0; i < messages->size(); ++i) { | 109 // Put all messages in the queue. |
105 ChromotingHostMessage* msg = (*messages)[i]; | 110 received_messages_.splice(received_messages_.end(), *messages); |
106 // TODO(ajwong): Consider creating a macro similar to the IPC message | 111 |
107 // mappings. Also reconsider the lifetime of the message object. | 112 if (!message_being_processed_) { |
108 if (msg->has_init_client()) { | 113 DispatchMessage(); |
109 InitClient(msg); | |
110 } else if (msg->has_begin_update_stream()) { | |
111 BeginUpdate(msg); | |
112 } else if (msg->has_update_stream_packet()) { | |
113 HandleUpdate(msg); | |
114 } else if (msg->has_end_update_stream()) { | |
115 EndUpdate(msg); | |
116 } else { | |
117 NOTREACHED() << "Unknown message received"; | |
118 } | |
119 } | 114 } |
120 // Assume we have processed all the messages. | 115 } |
121 messages->clear(); | 116 |
| 117 void ChromotingClient::DispatchMessage() { |
| 118 DCHECK_EQ(message_loop(), MessageLoop::current()); |
| 119 CHECK(!message_being_processed_); |
| 120 |
| 121 if (received_messages_.empty()) { |
| 122 // Nothing to do! |
| 123 return; |
| 124 } |
| 125 |
| 126 ChromotingHostMessage* msg = received_messages_.front(); |
| 127 received_messages_.pop_front(); |
| 128 message_being_processed_ = true; |
| 129 |
| 130 // TODO(ajwong): Consider creating a macro similar to the IPC message |
| 131 // mappings. Also reconsider the lifetime of the message object. |
| 132 if (msg->has_init_client()) { |
| 133 ScopedTracer tracer("Handle Init Client"); |
| 134 // TODO(ajwong): Change this to use a done callback. |
| 135 InitClient(msg->init_client(), |
| 136 NewTracedMethod(this, &ChromotingClient::OnMessageDone, msg)); |
| 137 } else if (msg->has_rectangle_update()) { |
| 138 ScopedTracer tracer("Handle Rectangle Update"); |
| 139 rectangle_decoder_->DecodePacket( |
| 140 msg->rectangle_update(), |
| 141 NewTracedMethod(this, &ChromotingClient::OnMessageDone, msg)); |
| 142 } else { |
| 143 NOTREACHED() << "Unknown message received"; |
| 144 |
| 145 // We have an unknown message. Drop it, and schedule another dispatch. |
| 146 // Call DispatchMessage as a continuation to avoid growing the stack. |
| 147 delete msg; |
| 148 message_being_processed_ = false; |
| 149 message_loop()->PostTask( |
| 150 FROM_HERE, |
| 151 NewTracedMethod(this, &ChromotingClient::DispatchMessage)); |
| 152 return; |
| 153 } |
122 } | 154 } |
123 | 155 |
124 void ChromotingClient::OnConnectionOpened(HostConnection* conn) { | 156 void ChromotingClient::OnConnectionOpened(HostConnection* conn) { |
125 LOG(INFO) << "ChromotingClient::OnConnectionOpened"; | 157 LOG(INFO) << "ChromotingClient::OnConnectionOpened"; |
126 SetState(CONNECTED); | 158 SetState(CONNECTED); |
127 } | 159 } |
128 | 160 |
129 void ChromotingClient::OnConnectionClosed(HostConnection* conn) { | 161 void ChromotingClient::OnConnectionClosed(HostConnection* conn) { |
130 LOG(INFO) << "ChromotingClient::OnConnectionClosed"; | 162 LOG(INFO) << "ChromotingClient::OnConnectionClosed"; |
131 SetState(DISCONNECTED); | 163 SetState(DISCONNECTED); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 break; | 197 break; |
166 | 198 |
167 case FAILED: | 199 case FAILED: |
168 view_->SetSolidFill(kFailedColor); | 200 view_->SetSolidFill(kFailedColor); |
169 break; | 201 break; |
170 } | 202 } |
171 | 203 |
172 Repaint(); | 204 Repaint(); |
173 } | 205 } |
174 | 206 |
175 void ChromotingClient::InitClient(ChromotingHostMessage* msg) { | 207 void ChromotingClient::OnMessageDone(ChromotingHostMessage* msg) { |
| 208 if (message_loop() != MessageLoop::current()) { |
| 209 message_loop()->PostTask( |
| 210 FROM_HERE, |
| 211 NewTracedMethod(this, &ChromotingClient::OnMessageDone, msg)); |
| 212 return; |
| 213 } |
| 214 |
| 215 TraceContext::tracer()->PrintString("Message done"); |
| 216 |
| 217 message_being_processed_ = false; |
| 218 delete msg; |
| 219 DispatchMessage(); |
| 220 } |
| 221 |
| 222 void ChromotingClient::InitClient(const InitClientMessage& init_client, |
| 223 Task* done) { |
176 DCHECK_EQ(message_loop(), MessageLoop::current()); | 224 DCHECK_EQ(message_loop(), MessageLoop::current()); |
177 DCHECK(msg->has_init_client()); | 225 TraceContext::tracer()->PrintString("Init received"); |
178 scoped_ptr<ChromotingHostMessage> deleter(msg); | |
179 | 226 |
180 // Resize the window. | 227 // Resize the window. |
181 int width = msg->init_client().width(); | 228 int width = init_client.width(); |
182 int height = msg->init_client().height(); | 229 int height = init_client.height(); |
183 LOG(INFO) << "Init client received geometry: " << width << "x" << height; | 230 LOG(INFO) << "Init client received geometry: " << width << "x" << height; |
184 | 231 |
185 view_->SetHostScreenSize(width, height); | 232 // TODO(ajwong): What to do here? Does the decoder actually need to request |
| 233 // the right frame size? This is mainly an optimization right? |
| 234 // rectangle_decoder_->SetOutputFrameSize(width, height); |
186 | 235 |
187 // Schedule the input handler to process the event queue. | 236 // Schedule the input handler to process the event queue. |
188 input_handler_->Initialize(); | 237 input_handler_->Initialize(); |
189 } | |
190 | 238 |
191 void ChromotingClient::BeginUpdate(ChromotingHostMessage* msg) { | 239 done->Run(); |
192 DCHECK_EQ(message_loop(), MessageLoop::current()); | 240 delete done; |
193 DCHECK(msg->has_begin_update_stream()); | |
194 | |
195 view_->HandleBeginUpdateStream(msg); | |
196 } | |
197 | |
198 void ChromotingClient::HandleUpdate(ChromotingHostMessage* msg) { | |
199 DCHECK_EQ(message_loop(), MessageLoop::current()); | |
200 DCHECK(msg->has_update_stream_packet()); | |
201 | |
202 view_->HandleUpdateStreamPacket(msg); | |
203 } | |
204 | |
205 void ChromotingClient::EndUpdate(ChromotingHostMessage* msg) { | |
206 DCHECK_EQ(message_loop(), MessageLoop::current()); | |
207 DCHECK(msg->has_end_update_stream()); | |
208 | |
209 view_->HandleEndUpdateStream(msg); | |
210 } | 241 } |
211 | 242 |
212 } // namespace remoting | 243 } // namespace remoting |
OLD | NEW |