[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "remoting/host/session_manager.h" |
| 6 | |
| 7 | #include <algorithm> |
| 8 | |
| 9 | #include "base/logging.h" |
[email protected] | 7c186b16f | 2010-06-15 16:35:33 | [diff] [blame] | 10 | #include "base/scoped_ptr.h" |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 11 | #include "base/stl_util-inl.h" |
[email protected] | be2da4d | 2010-07-23 00:54:47 | [diff] [blame] | 12 | #include "remoting/base/capture_data.h" |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 13 | #include "remoting/base/tracer.h" |
[email protected] | 35b9c56 | 2010-11-09 02:22:43 | [diff] [blame^] | 14 | #include "remoting/proto/control.pb.h" |
| 15 | #include "remoting/protocol/client_stub.h" |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 16 | #include "remoting/protocol/connection_to_client.h" |
[email protected] | 4d10ede | 2010-10-28 18:43:37 | [diff] [blame] | 17 | #include "remoting/protocol/message_decoder.h" |
[email protected] | 35b9c56 | 2010-11-09 02:22:43 | [diff] [blame^] | 18 | #include "remoting/protocol/util.h" |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 19 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 20 | using remoting::protocol::ConnectionToClient; |
| 21 | |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 22 | namespace remoting { |
| 23 | |
| 24 | // By default we capture 20 times a second. This number is obtained by |
| 25 | // experiment to provide good latency. |
| 26 | static const double kDefaultCaptureRate = 20.0; |
| 27 | |
| 28 | // Interval that we perform rate regulation. |
| 29 | static const base::TimeDelta kRateControlInterval = |
| 30 | base::TimeDelta::FromSeconds(1); |
| 31 | |
| 32 | // We divide the pending update stream number by this value to determine the |
| 33 | // rate divider. |
| 34 | static const int kSlowDownFactor = 10; |
| 35 | |
| 36 | // A list of dividers used to divide the max rate to determine the current |
| 37 | // capture rate. |
| 38 | static const int kRateDividers[] = {1, 2, 4, 8, 16}; |
| 39 | |
| 40 | SessionManager::SessionManager( |
| 41 | MessageLoop* capture_loop, |
| 42 | MessageLoop* encode_loop, |
| 43 | MessageLoop* network_loop, |
| 44 | Capturer* capturer, |
| 45 | Encoder* encoder) |
| 46 | : capture_loop_(capture_loop), |
| 47 | encode_loop_(encode_loop), |
| 48 | network_loop_(network_loop), |
| 49 | capturer_(capturer), |
| 50 | encoder_(encoder), |
| 51 | rate_(kDefaultCaptureRate), |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 52 | started_(false), |
| 53 | recordings_(0), |
[email protected] | 887cec8 | 2010-06-15 22:13:43 | [diff] [blame] | 54 | max_rate_(kDefaultCaptureRate), |
[email protected] | 7c186b16f | 2010-06-15 16:35:33 | [diff] [blame] | 55 | rate_control_started_(false) { |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 56 | DCHECK(capture_loop_); |
| 57 | DCHECK(encode_loop_); |
| 58 | DCHECK(network_loop_); |
| 59 | } |
| 60 | |
| 61 | SessionManager::~SessionManager() { |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 62 | connections_.clear(); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 63 | } |
| 64 | |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 65 | // Public methods -------------------------------------------------------------- |
| 66 | |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 67 | void SessionManager::Start() { |
| 68 | capture_loop_->PostTask( |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 69 | FROM_HERE, NewTracedMethod(this, &SessionManager::DoStart)); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 70 | } |
| 71 | |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 72 | void SessionManager::Pause() { |
| 73 | capture_loop_->PostTask( |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 74 | FROM_HERE, NewTracedMethod(this, &SessionManager::DoPause)); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 75 | } |
| 76 | |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 77 | void SessionManager::SetMaxRate(double rate) { |
| 78 | capture_loop_->PostTask( |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 79 | FROM_HERE, NewTracedMethod(this, &SessionManager::DoSetMaxRate, rate)); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 80 | } |
| 81 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 82 | void SessionManager::AddConnection( |
| 83 | scoped_refptr<ConnectionToClient> connection) { |
| 84 | // Gets the init information for the connection. |
[email protected] | ef0a59a6 | 2010-06-09 21:56:39 | [diff] [blame] | 85 | capture_loop_->PostTask( |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 86 | FROM_HERE, |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 87 | NewTracedMethod(this, &SessionManager::DoGetInitInfo, connection)); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 88 | } |
| 89 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 90 | void SessionManager::RemoveConnection( |
| 91 | scoped_refptr<ConnectionToClient> connection) { |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 92 | network_loop_->PostTask( |
| 93 | FROM_HERE, |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 94 | NewTracedMethod(this, &SessionManager::DoRemoveClient, connection)); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 95 | } |
| 96 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 97 | void SessionManager::RemoveAllConnections() { |
[email protected] | 92698ce | 2010-06-28 21:49:30 | [diff] [blame] | 98 | network_loop_->PostTask( |
| 99 | FROM_HERE, |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 100 | NewTracedMethod(this, &SessionManager::DoRemoveAllClients)); |
[email protected] | 92698ce | 2010-06-28 21:49:30 | [diff] [blame] | 101 | } |
| 102 | |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 103 | // Private accessors ----------------------------------------------------------- |
| 104 | |
| 105 | Capturer* SessionManager::capturer() { |
| 106 | DCHECK_EQ(capture_loop_, MessageLoop::current()); |
| 107 | return capturer_.get(); |
| 108 | } |
| 109 | |
| 110 | Encoder* SessionManager::encoder() { |
| 111 | DCHECK_EQ(encode_loop_, MessageLoop::current()); |
| 112 | return encoder_.get(); |
| 113 | } |
| 114 | |
| 115 | // Capturer thread ------------------------------------------------------------- |
| 116 | |
| 117 | void SessionManager::DoStart() { |
| 118 | DCHECK_EQ(capture_loop_, MessageLoop::current()); |
| 119 | |
| 120 | if (started_) { |
[email protected] | 58b4897 | 2010-09-03 00:45:32 | [diff] [blame] | 121 | NOTREACHED() << "Record session already started."; |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 122 | return; |
| 123 | } |
| 124 | |
| 125 | started_ = true; |
| 126 | DoCapture(); |
| 127 | |
| 128 | // Starts the rate regulation. |
| 129 | network_loop_->PostTask( |
| 130 | FROM_HERE, |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 131 | NewTracedMethod(this, &SessionManager::DoStartRateControl)); |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 132 | } |
| 133 | |
| 134 | void SessionManager::DoPause() { |
| 135 | DCHECK_EQ(capture_loop_, MessageLoop::current()); |
| 136 | |
| 137 | if (!started_) { |
[email protected] | 58b4897 | 2010-09-03 00:45:32 | [diff] [blame] | 138 | NOTREACHED() << "Record session not started."; |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 139 | return; |
| 140 | } |
| 141 | |
| 142 | started_ = false; |
| 143 | |
| 144 | // Pause the rate regulation. |
| 145 | network_loop_->PostTask( |
| 146 | FROM_HERE, |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 147 | NewTracedMethod(this, &SessionManager::DoPauseRateControl)); |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 148 | } |
| 149 | |
| 150 | void SessionManager::DoSetRate(double rate) { |
| 151 | DCHECK_EQ(capture_loop_, MessageLoop::current()); |
| 152 | if (rate == rate_) |
| 153 | return; |
| 154 | |
| 155 | // Change the current capture rate. |
| 156 | rate_ = rate; |
| 157 | |
| 158 | // If we have already started then schedule the next capture with the new |
| 159 | // rate. |
| 160 | if (started_) |
| 161 | ScheduleNextCapture(); |
| 162 | } |
| 163 | |
| 164 | void SessionManager::DoSetMaxRate(double max_rate) { |
| 165 | DCHECK_EQ(capture_loop_, MessageLoop::current()); |
| 166 | |
| 167 | // TODO(hclam): Should also check for small epsilon. |
| 168 | if (max_rate != 0) { |
| 169 | max_rate_ = max_rate; |
| 170 | DoSetRate(max_rate); |
| 171 | } else { |
| 172 | NOTREACHED() << "Rate is too small."; |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | void SessionManager::ScheduleNextCapture() { |
| 177 | DCHECK_EQ(capture_loop_, MessageLoop::current()); |
| 178 | |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 179 | ScopedTracer tracer("capture"); |
| 180 | |
| 181 | TraceContext::tracer()->PrintString("Capture Scheduled"); |
| 182 | |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 183 | if (rate_ == 0) |
| 184 | return; |
| 185 | |
| 186 | base::TimeDelta interval = base::TimeDelta::FromMilliseconds( |
| 187 | static_cast<int>(base::Time::kMillisecondsPerSecond / rate_)); |
| 188 | capture_loop_->PostDelayedTask( |
| 189 | FROM_HERE, |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 190 | NewTracedMethod(this, &SessionManager::DoCapture), |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 191 | interval.InMilliseconds()); |
| 192 | } |
| 193 | |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 194 | void SessionManager::DoCapture() { |
| 195 | DCHECK_EQ(capture_loop_, MessageLoop::current()); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 196 | // Make sure we have at most two oustanding recordings. We can simply return |
| 197 | // if we can't make a capture now, the next capture will be started by the |
| 198 | // end of an encode operation. |
[email protected] | 804c9962 | 2010-07-01 15:02:53 | [diff] [blame] | 199 | if (recordings_ >= 2 || !started_) { |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 200 | return; |
[email protected] | 804c9962 | 2010-07-01 15:02:53 | [diff] [blame] | 201 | } |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 202 | TraceContext::tracer()->PrintString("Capture Started"); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 203 | |
| 204 | base::Time now = base::Time::Now(); |
| 205 | base::TimeDelta interval = base::TimeDelta::FromMilliseconds( |
| 206 | static_cast<int>(base::Time::kMillisecondsPerSecond / rate_)); |
| 207 | base::TimeDelta elapsed = now - last_capture_time_; |
| 208 | |
[email protected] | 804c9962 | 2010-07-01 15:02:53 | [diff] [blame] | 209 | // If this method is called sooner than the required interval we return |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 210 | // immediately |
[email protected] | 804c9962 | 2010-07-01 15:02:53 | [diff] [blame] | 211 | if (elapsed < interval) { |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 212 | return; |
[email protected] | 804c9962 | 2010-07-01 15:02:53 | [diff] [blame] | 213 | } |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 214 | |
| 215 | // At this point we are going to perform one capture so save the current time. |
| 216 | last_capture_time_ = now; |
| 217 | ++recordings_; |
| 218 | |
| 219 | // Before we actually do a capture, schedule the next one. |
| 220 | ScheduleNextCapture(); |
| 221 | |
| 222 | // And finally perform one capture. |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 223 | DCHECK(capturer()); |
[email protected] | 804c9962 | 2010-07-01 15:02:53 | [diff] [blame] | 224 | |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 225 | capturer()->CaptureInvalidRects( |
[email protected] | 804c9962 | 2010-07-01 15:02:53 | [diff] [blame] | 226 | NewCallback(this, &SessionManager::CaptureDoneCallback)); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 227 | } |
| 228 | |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 229 | void SessionManager::CaptureDoneCallback( |
[email protected] | be2da4d | 2010-07-23 00:54:47 | [diff] [blame] | 230 | scoped_refptr<CaptureData> capture_data) { |
[email protected] | 88552a9 | 2010-08-06 22:50:00 | [diff] [blame] | 231 | // TODO(hclam): There is a bug if the capturer doesn't produce any dirty |
| 232 | // rects. |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 233 | DCHECK_EQ(capture_loop_, MessageLoop::current()); |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 234 | TraceContext::tracer()->PrintString("Capture Done"); |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 235 | encode_loop_->PostTask( |
| 236 | FROM_HERE, |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 237 | NewTracedMethod(this, &SessionManager::DoEncode, capture_data)); |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 238 | } |
| 239 | |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 240 | void SessionManager::DoFinishEncode() { |
| 241 | DCHECK_EQ(capture_loop_, MessageLoop::current()); |
| 242 | |
| 243 | // Decrement the number of recording in process since we have completed |
| 244 | // one cycle. |
| 245 | --recordings_; |
| 246 | |
| 247 | // Try to do a capture again. Note that the following method may do nothing |
| 248 | // if it is too early to perform a capture. |
| 249 | if (rate_ > 0) |
| 250 | DoCapture(); |
| 251 | } |
| 252 | |
[email protected] | d87c404 | 2010-11-04 00:46:01 | [diff] [blame] | 253 | void SessionManager::DoGetInitInfo( |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 254 | scoped_refptr<ConnectionToClient> connection) { |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 255 | DCHECK_EQ(capture_loop_, MessageLoop::current()); |
| 256 | |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 257 | ScopedTracer tracer("init"); |
| 258 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 259 | // Sends the init message to the connection. |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 260 | network_loop_->PostTask( |
| 261 | FROM_HERE, |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 262 | NewTracedMethod(this, &SessionManager::DoSendInit, connection, |
[email protected] | 804c9962 | 2010-07-01 15:02:53 | [diff] [blame] | 263 | capturer()->width(), capturer()->height())); |
[email protected] | ef0a59a6 | 2010-06-09 21:56:39 | [diff] [blame] | 264 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 265 | // And then add the connection to the list so it can receive update stream. |
| 266 | // It is important we do so in such order or the connection will receive |
[email protected] | ef0a59a6 | 2010-06-09 21:56:39 | [diff] [blame] | 267 | // update stream before init message. |
| 268 | network_loop_->PostTask( |
| 269 | FROM_HERE, |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 270 | NewTracedMethod(this, &SessionManager::DoAddClient, connection)); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 271 | } |
| 272 | |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 273 | // Network thread -------------------------------------------------------------- |
| 274 | |
| 275 | void SessionManager::DoStartRateControl() { |
| 276 | DCHECK_EQ(network_loop_, MessageLoop::current()); |
| 277 | |
| 278 | if (rate_control_started_) { |
| 279 | NOTREACHED() << "Rate regulation already started"; |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 280 | return; |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 281 | } |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 282 | rate_control_started_ = true; |
| 283 | ScheduleNextRateControl(); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 284 | } |
| 285 | |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 286 | void SessionManager::DoPauseRateControl() { |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 287 | DCHECK_EQ(network_loop_, MessageLoop::current()); |
| 288 | |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 289 | if (!rate_control_started_) { |
| 290 | NOTREACHED() << "Rate regulation not started"; |
| 291 | return; |
[email protected] | 92698ce | 2010-06-28 21:49:30 | [diff] [blame] | 292 | } |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 293 | rate_control_started_ = false; |
[email protected] | 92698ce | 2010-06-28 21:49:30 | [diff] [blame] | 294 | } |
| 295 | |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 296 | void SessionManager::ScheduleNextRateControl() { |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 297 | ScopedTracer tracer("Rate Control"); |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 298 | network_loop_->PostDelayedTask( |
| 299 | FROM_HERE, |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 300 | NewTracedMethod(this, &SessionManager::DoRateControl), |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 301 | kRateControlInterval.InMilliseconds()); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 302 | } |
| 303 | |
| 304 | void SessionManager::DoRateControl() { |
| 305 | DCHECK_EQ(network_loop_, MessageLoop::current()); |
| 306 | |
| 307 | // If we have been paused then shutdown the rate regulation loop. |
| 308 | if (!rate_control_started_) |
| 309 | return; |
| 310 | |
| 311 | int max_pending_update_streams = 0; |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 312 | for (size_t i = 0; i < connections_.size(); ++i) { |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 313 | max_pending_update_streams = |
| 314 | std::max(max_pending_update_streams, |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 315 | connections_[i]->GetPendingUpdateStreamMessages()); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 316 | } |
| 317 | |
| 318 | // If |slow_down| equals zero, we have no slow down. |
[email protected] | 887cec8 | 2010-06-15 22:13:43 | [diff] [blame] | 319 | size_t slow_down = max_pending_update_streams / kSlowDownFactor; |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 320 | // Set new_rate to -1 for checking later. |
| 321 | double new_rate = -1; |
| 322 | // If the slow down is too large. |
| 323 | if (slow_down >= arraysize(kRateDividers)) { |
| 324 | // Then we stop the capture completely. |
| 325 | new_rate = 0; |
| 326 | } else { |
| 327 | // Slow down the capture rate using the divider. |
| 328 | new_rate = max_rate_ / kRateDividers[slow_down]; |
| 329 | } |
| 330 | DCHECK_NE(new_rate, -1.0); |
| 331 | |
| 332 | // Then set the rate. |
| 333 | capture_loop_->PostTask( |
| 334 | FROM_HERE, |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 335 | NewTracedMethod(this, &SessionManager::DoSetRate, new_rate)); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 336 | ScheduleNextRateControl(); |
| 337 | } |
| 338 | |
[email protected] | 04b3614 | 2010-11-02 01:08:19 | [diff] [blame] | 339 | void SessionManager::DoSendVideoPacket(VideoPacket* packet) { |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 340 | DCHECK_EQ(network_loop_, MessageLoop::current()); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 341 | |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 342 | TraceContext::tracer()->PrintString("DoSendUpdate"); |
| 343 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 344 | for (ConnectionToClientList::const_iterator i = connections_.begin(); |
| 345 | i < connections_.end(); ++i) { |
[email protected] | 04b3614 | 2010-11-02 01:08:19 | [diff] [blame] | 346 | (*i)->SendVideoPacket(*packet); |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 347 | } |
[email protected] | 04b3614 | 2010-11-02 01:08:19 | [diff] [blame] | 348 | delete packet; |
[email protected] | c3af26f33 | 2010-10-06 22:46:00 | [diff] [blame] | 349 | |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 350 | TraceContext::tracer()->PrintString("DoSendUpdate done"); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 351 | } |
| 352 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 353 | void SessionManager::DoSendInit(scoped_refptr<ConnectionToClient> connection, |
| 354 | int width, int height) { |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 355 | DCHECK_EQ(network_loop_, MessageLoop::current()); |
| 356 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 357 | // Sends the connection init information. |
[email protected] | 35b9c56 | 2010-11-09 02:22:43 | [diff] [blame^] | 358 | protocol::NotifyResolutionRequest* message = |
| 359 | new protocol::NotifyResolutionRequest(); |
| 360 | message->set_width(width); |
| 361 | message->set_height(height); |
| 362 | connection->client_stub()->NotifyResolution(message, |
| 363 | NewDeleteMessageTask(message)); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 364 | } |
| 365 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 366 | void SessionManager::DoAddClient(scoped_refptr<ConnectionToClient> connection) { |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 367 | DCHECK_EQ(network_loop_, MessageLoop::current()); |
| 368 | |
| 369 | // TODO(hclam): Force a full frame for next encode. |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 370 | connections_.push_back(connection); |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 371 | } |
| 372 | |
[email protected] | d87c404 | 2010-11-04 00:46:01 | [diff] [blame] | 373 | void SessionManager::DoRemoveClient( |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 374 | scoped_refptr<ConnectionToClient> connection) { |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 375 | DCHECK_EQ(network_loop_, MessageLoop::current()); |
| 376 | |
| 377 | // TODO(hclam): Is it correct to do to a scoped_refptr? |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 378 | ConnectionToClientList::iterator it |
| 379 | = std::find(connections_.begin(), connections_.end(), connection); |
| 380 | if (it != connections_.end()) { |
| 381 | connections_.erase(it); |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 382 | } |
| 383 | } |
| 384 | |
| 385 | void SessionManager::DoRemoveAllClients() { |
| 386 | DCHECK_EQ(network_loop_, MessageLoop::current()); |
| 387 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 388 | // Clear the list of connections. |
| 389 | connections_.clear(); |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 390 | } |
| 391 | |
| 392 | // Encoder thread -------------------------------------------------------------- |
| 393 | |
| 394 | void SessionManager::DoEncode( |
[email protected] | be2da4d | 2010-07-23 00:54:47 | [diff] [blame] | 395 | scoped_refptr<CaptureData> capture_data) { |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 396 | DCHECK_EQ(encode_loop_, MessageLoop::current()); |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 397 | TraceContext::tracer()->PrintString("DoEncode called"); |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 398 | |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 399 | // Early out if there's nothing to encode. |
[email protected] | 5a196bd | 2010-08-18 21:37:59 | [diff] [blame] | 400 | if (!capture_data->dirty_rects().size()) { |
| 401 | capture_loop_->PostTask( |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 402 | FROM_HERE, NewTracedMethod(this, &SessionManager::DoFinishEncode)); |
| 403 | return; |
[email protected] | 5a196bd | 2010-08-18 21:37:59 | [diff] [blame] | 404 | } |
| 405 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 406 | // TODO(hclam): Enable |force_refresh| if a new connection was |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 407 | // added. |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 408 | TraceContext::tracer()->PrintString("Encode start"); |
[email protected] | 3b3d3af | 2010-07-02 22:23:17 | [diff] [blame] | 409 | encoder_->Encode(capture_data, false, |
| 410 | NewCallback(this, &SessionManager::EncodeDataAvailableTask)); |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 411 | TraceContext::tracer()->PrintString("Encode Done"); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 412 | } |
| 413 | |
[email protected] | 04b3614 | 2010-11-02 01:08:19 | [diff] [blame] | 414 | void SessionManager::EncodeDataAvailableTask(VideoPacket* packet) { |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 415 | DCHECK_EQ(encode_loop_, MessageLoop::current()); |
| 416 | |
[email protected] | 04b3614 | 2010-11-02 01:08:19 | [diff] [blame] | 417 | bool last = (packet->flags() & VideoPacket::LAST_PACKET) != 0; |
| 418 | |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 419 | // Before a new encode task starts, notify connected clients a new update |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 420 | // stream is coming. |
| 421 | // Notify this will keep a reference to the DataBuffer in the |
[email protected] | cd8d237 | 2010-11-04 01:18:04 | [diff] [blame] | 422 | // task. The ownership will eventually pass to the ConnectionToClients. |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 423 | network_loop_->PostTask( |
| 424 | FROM_HERE, |
[email protected] | 04b3614 | 2010-11-02 01:08:19 | [diff] [blame] | 425 | NewTracedMethod(this, &SessionManager::DoSendVideoPacket, packet)); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 426 | |
[email protected] | 04b3614 | 2010-11-02 01:08:19 | [diff] [blame] | 427 | if (last) { |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 428 | capture_loop_->PostTask( |
[email protected] | 8ea7a167 | 2010-10-04 19:48:42 | [diff] [blame] | 429 | FROM_HERE, NewTracedMethod(this, &SessionManager::DoFinishEncode)); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 430 | } |
| 431 | } |
| 432 | |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 433 | } // namespace remoting |