Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(677)

Side by Side Diff: remoting/host/session_manager.cc

Issue 3305001: Move decoder into separate thread, clean up API layering, and redo update protocl (Closed)
Patch Set: Fix compile error. Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « remoting/host/event_executor_win.cc ('k') | remoting/host/session_manager_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/host/session_manager.h" 5 #include "remoting/host/session_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/scoped_ptr.h" 10 #include "base/scoped_ptr.h"
11 #include "base/stl_util-inl.h" 11 #include "base/stl_util-inl.h"
12 #include "media/base/data_buffer.h" 12 #include "media/base/data_buffer.h"
13 #include "remoting/base/capture_data.h" 13 #include "remoting/base/capture_data.h"
14 #include "remoting/base/protocol_decoder.h" 14 #include "remoting/base/protocol_decoder.h"
15 #include "remoting/base/tracer.h"
15 #include "remoting/host/client_connection.h" 16 #include "remoting/host/client_connection.h"
16 17
17 namespace remoting { 18 namespace remoting {
18 19
19 // By default we capture 20 times a second. This number is obtained by 20 // By default we capture 20 times a second. This number is obtained by
20 // experiment to provide good latency. 21 // experiment to provide good latency.
21 static const double kDefaultCaptureRate = 20.0; 22 static const double kDefaultCaptureRate = 20.0;
22 23
23 // Interval that we perform rate regulation. 24 // Interval that we perform rate regulation.
24 static const base::TimeDelta kRateControlInterval = 25 static const base::TimeDelta kRateControlInterval =
(...skipping 29 matching lines...) Expand all
54 } 55 }
55 56
56 SessionManager::~SessionManager() { 57 SessionManager::~SessionManager() {
57 clients_.clear(); 58 clients_.clear();
58 } 59 }
59 60
60 // Public methods -------------------------------------------------------------- 61 // Public methods --------------------------------------------------------------
61 62
62 void SessionManager::Start() { 63 void SessionManager::Start() {
63 capture_loop_->PostTask( 64 capture_loop_->PostTask(
64 FROM_HERE, NewRunnableMethod(this, &SessionManager::DoStart)); 65 FROM_HERE, NewTracedMethod(this, &SessionManager::DoStart));
65 } 66 }
66 67
67 void SessionManager::Pause() { 68 void SessionManager::Pause() {
68 capture_loop_->PostTask( 69 capture_loop_->PostTask(
69 FROM_HERE, NewRunnableMethod(this, &SessionManager::DoPause)); 70 FROM_HERE, NewTracedMethod(this, &SessionManager::DoPause));
70 } 71 }
71 72
72 void SessionManager::SetMaxRate(double rate) { 73 void SessionManager::SetMaxRate(double rate) {
73 capture_loop_->PostTask( 74 capture_loop_->PostTask(
74 FROM_HERE, NewRunnableMethod(this, &SessionManager::DoSetMaxRate, rate)); 75 FROM_HERE, NewTracedMethod(this, &SessionManager::DoSetMaxRate, rate));
75 } 76 }
76 77
77 void SessionManager::AddClient(scoped_refptr<ClientConnection> client) { 78 void SessionManager::AddClient(scoped_refptr<ClientConnection> client) {
78 // Gets the init information for the client. 79 // Gets the init information for the client.
79 capture_loop_->PostTask( 80 capture_loop_->PostTask(
80 FROM_HERE, 81 FROM_HERE,
81 NewRunnableMethod(this, &SessionManager::DoGetInitInfo, client)); 82 NewTracedMethod(this, &SessionManager::DoGetInitInfo, client));
82 } 83 }
83 84
84 void SessionManager::RemoveClient(scoped_refptr<ClientConnection> client) { 85 void SessionManager::RemoveClient(scoped_refptr<ClientConnection> client) {
85 network_loop_->PostTask( 86 network_loop_->PostTask(
86 FROM_HERE, 87 FROM_HERE,
87 NewRunnableMethod(this, &SessionManager::DoRemoveClient, client)); 88 NewTracedMethod(this, &SessionManager::DoRemoveClient, client));
88 } 89 }
89 90
90 void SessionManager::RemoveAllClients() { 91 void SessionManager::RemoveAllClients() {
91 network_loop_->PostTask( 92 network_loop_->PostTask(
92 FROM_HERE, 93 FROM_HERE,
93 NewRunnableMethod(this, &SessionManager::DoRemoveAllClients)); 94 NewTracedMethod(this, &SessionManager::DoRemoveAllClients));
94 } 95 }
95 96
96 // Private accessors ----------------------------------------------------------- 97 // Private accessors -----------------------------------------------------------
97 98
98 Capturer* SessionManager::capturer() { 99 Capturer* SessionManager::capturer() {
99 DCHECK_EQ(capture_loop_, MessageLoop::current()); 100 DCHECK_EQ(capture_loop_, MessageLoop::current());
100 return capturer_.get(); 101 return capturer_.get();
101 } 102 }
102 103
103 Encoder* SessionManager::encoder() { 104 Encoder* SessionManager::encoder() {
(...skipping 10 matching lines...) Expand all
114 NOTREACHED() << "Record session already started."; 115 NOTREACHED() << "Record session already started.";
115 return; 116 return;
116 } 117 }
117 118
118 started_ = true; 119 started_ = true;
119 DoCapture(); 120 DoCapture();
120 121
121 // Starts the rate regulation. 122 // Starts the rate regulation.
122 network_loop_->PostTask( 123 network_loop_->PostTask(
123 FROM_HERE, 124 FROM_HERE,
124 NewRunnableMethod(this, &SessionManager::DoStartRateControl)); 125 NewTracedMethod(this, &SessionManager::DoStartRateControl));
125 } 126 }
126 127
127 void SessionManager::DoPause() { 128 void SessionManager::DoPause() {
128 DCHECK_EQ(capture_loop_, MessageLoop::current()); 129 DCHECK_EQ(capture_loop_, MessageLoop::current());
129 130
130 if (!started_) { 131 if (!started_) {
131 NOTREACHED() << "Record session not started."; 132 NOTREACHED() << "Record session not started.";
132 return; 133 return;
133 } 134 }
134 135
135 started_ = false; 136 started_ = false;
136 137
137 // Pause the rate regulation. 138 // Pause the rate regulation.
138 network_loop_->PostTask( 139 network_loop_->PostTask(
139 FROM_HERE, 140 FROM_HERE,
140 NewRunnableMethod(this, &SessionManager::DoPauseRateControl)); 141 NewTracedMethod(this, &SessionManager::DoPauseRateControl));
141 } 142 }
142 143
143 void SessionManager::DoSetRate(double rate) { 144 void SessionManager::DoSetRate(double rate) {
144 DCHECK_EQ(capture_loop_, MessageLoop::current()); 145 DCHECK_EQ(capture_loop_, MessageLoop::current());
145 if (rate == rate_) 146 if (rate == rate_)
146 return; 147 return;
147 148
148 // Change the current capture rate. 149 // Change the current capture rate.
149 rate_ = rate; 150 rate_ = rate;
150 151
(...skipping 11 matching lines...) Expand all
162 max_rate_ = max_rate; 163 max_rate_ = max_rate;
163 DoSetRate(max_rate); 164 DoSetRate(max_rate);
164 } else { 165 } else {
165 NOTREACHED() << "Rate is too small."; 166 NOTREACHED() << "Rate is too small.";
166 } 167 }
167 } 168 }
168 169
169 void SessionManager::ScheduleNextCapture() { 170 void SessionManager::ScheduleNextCapture() {
170 DCHECK_EQ(capture_loop_, MessageLoop::current()); 171 DCHECK_EQ(capture_loop_, MessageLoop::current());
171 172
173 ScopedTracer tracer("capture");
174
175 TraceContext::tracer()->PrintString("Capture Scheduled");
176
172 if (rate_ == 0) 177 if (rate_ == 0)
173 return; 178 return;
174 179
175 base::TimeDelta interval = base::TimeDelta::FromMilliseconds( 180 base::TimeDelta interval = base::TimeDelta::FromMilliseconds(
176 static_cast<int>(base::Time::kMillisecondsPerSecond / rate_)); 181 static_cast<int>(base::Time::kMillisecondsPerSecond / rate_));
177 capture_loop_->PostDelayedTask( 182 capture_loop_->PostDelayedTask(
178 FROM_HERE, 183 FROM_HERE,
179 NewRunnableMethod(this, &SessionManager::DoCapture), 184 NewTracedMethod(this, &SessionManager::DoCapture),
180 interval.InMilliseconds()); 185 interval.InMilliseconds());
181 } 186 }
182 187
183 void SessionManager::DoCapture() { 188 void SessionManager::DoCapture() {
184 DCHECK_EQ(capture_loop_, MessageLoop::current()); 189 DCHECK_EQ(capture_loop_, MessageLoop::current());
185 // Make sure we have at most two oustanding recordings. We can simply return 190 // Make sure we have at most two oustanding recordings. We can simply return
186 // if we can't make a capture now, the next capture will be started by the 191 // if we can't make a capture now, the next capture will be started by the
187 // end of an encode operation. 192 // end of an encode operation.
188 if (recordings_ >= 2 || !started_) { 193 if (recordings_ >= 2 || !started_) {
189 return; 194 return;
190 } 195 }
196 TraceContext::tracer()->PrintString("Capture Started");
191 197
192 base::Time now = base::Time::Now(); 198 base::Time now = base::Time::Now();
193 base::TimeDelta interval = base::TimeDelta::FromMilliseconds( 199 base::TimeDelta interval = base::TimeDelta::FromMilliseconds(
194 static_cast<int>(base::Time::kMillisecondsPerSecond / rate_)); 200 static_cast<int>(base::Time::kMillisecondsPerSecond / rate_));
195 base::TimeDelta elapsed = now - last_capture_time_; 201 base::TimeDelta elapsed = now - last_capture_time_;
196 202
197 // If this method is called sooner than the required interval we return 203 // If this method is called sooner than the required interval we return
198 // immediately 204 // immediately
199 if (elapsed < interval) { 205 if (elapsed < interval) {
200 return; 206 return;
201 } 207 }
202 208
203 // At this point we are going to perform one capture so save the current time. 209 // At this point we are going to perform one capture so save the current time.
204 last_capture_time_ = now; 210 last_capture_time_ = now;
205 ++recordings_; 211 ++recordings_;
206 212
207 // Before we actually do a capture, schedule the next one. 213 // Before we actually do a capture, schedule the next one.
208 ScheduleNextCapture(); 214 ScheduleNextCapture();
209 215
210 // And finally perform one capture. 216 // And finally perform one capture.
211 DCHECK(capturer_.get()); 217 DCHECK(capturer());
212 218
213 capturer_->CaptureInvalidRects( 219 capturer()->CaptureInvalidRects(
214 NewCallback(this, &SessionManager::CaptureDoneCallback)); 220 NewCallback(this, &SessionManager::CaptureDoneCallback));
215 } 221 }
216 222
217 void SessionManager::CaptureDoneCallback( 223 void SessionManager::CaptureDoneCallback(
218 scoped_refptr<CaptureData> capture_data) { 224 scoped_refptr<CaptureData> capture_data) {
219 // TODO(hclam): There is a bug if the capturer doesn't produce any dirty 225 // TODO(hclam): There is a bug if the capturer doesn't produce any dirty
220 // rects. 226 // rects.
221 DCHECK_EQ(capture_loop_, MessageLoop::current()); 227 DCHECK_EQ(capture_loop_, MessageLoop::current());
228 TraceContext::tracer()->PrintString("Capture Done");
222 encode_loop_->PostTask( 229 encode_loop_->PostTask(
223 FROM_HERE, 230 FROM_HERE,
224 NewRunnableMethod(this, &SessionManager::DoEncode, capture_data)); 231 NewTracedMethod(this, &SessionManager::DoEncode, capture_data));
225 } 232 }
226 233
227 void SessionManager::DoFinishEncode() { 234 void SessionManager::DoFinishEncode() {
228 DCHECK_EQ(capture_loop_, MessageLoop::current()); 235 DCHECK_EQ(capture_loop_, MessageLoop::current());
229 236
230 // Decrement the number of recording in process since we have completed 237 // Decrement the number of recording in process since we have completed
231 // one cycle. 238 // one cycle.
232 --recordings_; 239 --recordings_;
233 240
234 // Try to do a capture again. Note that the following method may do nothing 241 // Try to do a capture again. Note that the following method may do nothing
235 // if it is too early to perform a capture. 242 // if it is too early to perform a capture.
236 if (rate_ > 0) 243 if (rate_ > 0)
237 DoCapture(); 244 DoCapture();
238 } 245 }
239 246
240 void SessionManager::DoGetInitInfo(scoped_refptr<ClientConnection> client) { 247 void SessionManager::DoGetInitInfo(scoped_refptr<ClientConnection> client) {
241 DCHECK_EQ(capture_loop_, MessageLoop::current()); 248 DCHECK_EQ(capture_loop_, MessageLoop::current());
242 249
250 ScopedTracer tracer("init");
251
243 // Sends the init message to the client. 252 // Sends the init message to the client.
244 network_loop_->PostTask( 253 network_loop_->PostTask(
245 FROM_HERE, 254 FROM_HERE,
246 NewRunnableMethod(this, &SessionManager::DoSendInit, client, 255 NewTracedMethod(this, &SessionManager::DoSendInit, client,
247 capturer()->width(), capturer()->height())); 256 capturer()->width(), capturer()->height()));
248 257
249 // And then add the client to the list so it can receive update stream. 258 // And then add the client to the list so it can receive update stream.
250 // It is important we do so in such order or the client will receive 259 // It is important we do so in such order or the client will receive
251 // update stream before init message. 260 // update stream before init message.
252 network_loop_->PostTask( 261 network_loop_->PostTask(
253 FROM_HERE, 262 FROM_HERE,
254 NewRunnableMethod(this, &SessionManager::DoAddClient, client)); 263 NewTracedMethod(this, &SessionManager::DoAddClient, client));
255 } 264 }
256 265
257 // Network thread -------------------------------------------------------------- 266 // Network thread --------------------------------------------------------------
258 267
259 void SessionManager::DoStartRateControl() { 268 void SessionManager::DoStartRateControl() {
260 DCHECK_EQ(network_loop_, MessageLoop::current()); 269 DCHECK_EQ(network_loop_, MessageLoop::current());
261 270
262 if (rate_control_started_) { 271 if (rate_control_started_) {
263 NOTREACHED() << "Rate regulation already started"; 272 NOTREACHED() << "Rate regulation already started";
264 return; 273 return;
265 } 274 }
266 rate_control_started_ = true; 275 rate_control_started_ = true;
267 ScheduleNextRateControl(); 276 ScheduleNextRateControl();
268 } 277 }
269 278
270 void SessionManager::DoPauseRateControl() { 279 void SessionManager::DoPauseRateControl() {
271 DCHECK_EQ(network_loop_, MessageLoop::current()); 280 DCHECK_EQ(network_loop_, MessageLoop::current());
272 281
273 if (!rate_control_started_) { 282 if (!rate_control_started_) {
274 NOTREACHED() << "Rate regulation not started"; 283 NOTREACHED() << "Rate regulation not started";
275 return; 284 return;
276 } 285 }
277 rate_control_started_ = false; 286 rate_control_started_ = false;
278 } 287 }
279 288
280 void SessionManager::ScheduleNextRateControl() { 289 void SessionManager::ScheduleNextRateControl() {
290 ScopedTracer tracer("Rate Control");
281 network_loop_->PostDelayedTask( 291 network_loop_->PostDelayedTask(
282 FROM_HERE, 292 FROM_HERE,
283 NewRunnableMethod(this, &SessionManager::DoRateControl), 293 NewTracedMethod(this, &SessionManager::DoRateControl),
284 kRateControlInterval.InMilliseconds()); 294 kRateControlInterval.InMilliseconds());
285 } 295 }
286 296
287 void SessionManager::DoRateControl() { 297 void SessionManager::DoRateControl() {
288 DCHECK_EQ(network_loop_, MessageLoop::current()); 298 DCHECK_EQ(network_loop_, MessageLoop::current());
289 299
290 // If we have been paused then shutdown the rate regulation loop. 300 // If we have been paused then shutdown the rate regulation loop.
291 if (!rate_control_started_) 301 if (!rate_control_started_)
292 return; 302 return;
293 303
(...skipping 14 matching lines...) Expand all
308 new_rate = 0; 318 new_rate = 0;
309 } else { 319 } else {
310 // Slow down the capture rate using the divider. 320 // Slow down the capture rate using the divider.
311 new_rate = max_rate_ / kRateDividers[slow_down]; 321 new_rate = max_rate_ / kRateDividers[slow_down];
312 } 322 }
313 DCHECK_NE(new_rate, -1.0); 323 DCHECK_NE(new_rate, -1.0);
314 324
315 // Then set the rate. 325 // Then set the rate.
316 capture_loop_->PostTask( 326 capture_loop_->PostTask(
317 FROM_HERE, 327 FROM_HERE,
318 NewRunnableMethod(this, &SessionManager::DoSetRate, new_rate)); 328 NewTracedMethod(this, &SessionManager::DoSetRate, new_rate));
319 ScheduleNextRateControl(); 329 ScheduleNextRateControl();
320 } 330 }
321 331
322 void SessionManager::DoSendUpdate(ChromotingHostMessage* message, 332 void SessionManager::DoSendUpdate(ChromotingHostMessage* message,
323 Encoder::EncodingState state) { 333 Encoder::EncodingState state) {
324 DCHECK_EQ(network_loop_, MessageLoop::current()); 334 DCHECK_EQ(network_loop_, MessageLoop::current());
325 335
336 // TODO(ajwong): We shouldn't need EncodingState. Just inspect message.
337 bool is_end_of_update = (message->rectangle_update().flags() |
338 RectangleUpdatePacket::LAST_PACKET) != 0;
339
340 TraceContext::tracer()->PrintString("DoSendUpdate");
341
326 // Create a data buffer in wire format from |message|. 342 // Create a data buffer in wire format from |message|.
327 // Note that this takes ownership of |message|. 343 // Note that this takes ownership of |message|.
328 scoped_refptr<media::DataBuffer> data = 344 scoped_refptr<media::DataBuffer> data =
329 ClientConnection::CreateWireFormatDataBuffer(message); 345 ClientConnection::CreateWireFormatDataBuffer(message);
330 346
331 for (ClientConnectionList::const_iterator i = clients_.begin(); 347 for (ClientConnectionList::const_iterator i = clients_.begin();
332 i < clients_.end(); ++i) { 348 i < clients_.end(); ++i) {
333 // TODO(hclam): Merge BeginUpdateStreamMessage into |message|.
334 if (state & Encoder::EncodingStarting) {
335 (*i)->SendBeginUpdateStreamMessage();
336 }
337
338 (*i)->SendUpdateStreamPacketMessage(data); 349 (*i)->SendUpdateStreamPacketMessage(data);
339 350
340 // TODO(hclam): Merge EndUpdateStreamMessage into |message|. 351 if (is_end_of_update)
341 if (state & Encoder::EncodingEnded) 352 (*i)->MarkEndOfUpdate();
342 (*i)->SendEndUpdateStreamMessage();
343 } 353 }
354 TraceContext::tracer()->PrintString("DoSendUpdate done");
344 } 355 }
345 356
346 void SessionManager::DoSendInit(scoped_refptr<ClientConnection> client, 357 void SessionManager::DoSendInit(scoped_refptr<ClientConnection> client,
347 int width, int height) { 358 int width, int height) {
348 DCHECK_EQ(network_loop_, MessageLoop::current()); 359 DCHECK_EQ(network_loop_, MessageLoop::current());
349 360
350 // Sends the client init information. 361 // Sends the client init information.
351 client->SendInitClientMessage(width, height); 362 client->SendInitClientMessage(width, height);
352 } 363 }
353 364
(...skipping 20 matching lines...) Expand all
374 385
375 // Clear the list of clients. 386 // Clear the list of clients.
376 clients_.clear(); 387 clients_.clear();
377 } 388 }
378 389
379 // Encoder thread -------------------------------------------------------------- 390 // Encoder thread --------------------------------------------------------------
380 391
381 void SessionManager::DoEncode( 392 void SessionManager::DoEncode(
382 scoped_refptr<CaptureData> capture_data) { 393 scoped_refptr<CaptureData> capture_data) {
383 DCHECK_EQ(encode_loop_, MessageLoop::current()); 394 DCHECK_EQ(encode_loop_, MessageLoop::current());
395 TraceContext::tracer()->PrintString("DoEncode called");
384 396
397 // Early out if there's nothing to encode.
385 if (!capture_data->dirty_rects().size()) { 398 if (!capture_data->dirty_rects().size()) {
386 capture_loop_->PostTask( 399 capture_loop_->PostTask(
387 FROM_HERE, NewRunnableMethod(this, &SessionManager::DoFinishEncode)); 400 FROM_HERE, NewTracedMethod(this, &SessionManager::DoFinishEncode));
401 return;
388 } 402 }
389 403
390 // TODO(hclam): Enable |force_refresh| if a new client was 404 // TODO(hclam): Enable |force_refresh| if a new client was
391 // added. 405 // added.
406 TraceContext::tracer()->PrintString("Encode start");
392 encoder_->Encode(capture_data, false, 407 encoder_->Encode(capture_data, false,
393 NewCallback(this, &SessionManager::EncodeDataAvailableTask)); 408 NewCallback(this, &SessionManager::EncodeDataAvailableTask));
409 TraceContext::tracer()->PrintString("Encode Done");
394 } 410 }
395 411
396 void SessionManager::EncodeDataAvailableTask( 412 void SessionManager::EncodeDataAvailableTask(
397 ChromotingHostMessage* message, Encoder::EncodingState state) { 413 ChromotingHostMessage* message, Encoder::EncodingState state) {
398 DCHECK_EQ(encode_loop_, MessageLoop::current()); 414 DCHECK_EQ(encode_loop_, MessageLoop::current());
399 415
400 // Before a new encode task starts, notify clients a new update 416 // Before a new encode task starts, notify clients a new update
401 // stream is coming. 417 // stream is coming.
402 // Notify this will keep a reference to the DataBuffer in the 418 // Notify this will keep a reference to the DataBuffer in the
403 // task. The ownership will eventually pass to the ClientConnections. 419 // task. The ownership will eventually pass to the ClientConnections.
404 network_loop_->PostTask( 420 network_loop_->PostTask(
405 FROM_HERE, 421 FROM_HERE,
406 NewRunnableMethod(this, &SessionManager::DoSendUpdate, message, state)); 422 NewTracedMethod(this, &SessionManager::DoSendUpdate, message, state));
407 423
408 if (state & Encoder::EncodingEnded) { 424 if (state & Encoder::EncodingEnded) {
409 capture_loop_->PostTask( 425 capture_loop_->PostTask(
410 FROM_HERE, NewRunnableMethod(this, &SessionManager::DoFinishEncode)); 426 FROM_HERE, NewTracedMethod(this, &SessionManager::DoFinishEncode));
411 } 427 }
412 } 428 }
413 429
414 } // namespace remoting 430 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/event_executor_win.cc ('k') | remoting/host/session_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698