Index: remoting/host/capture_scheduler.cc |
diff --git a/remoting/host/capture_scheduler.cc b/remoting/host/capture_scheduler.cc |
index ccd141ddcdc85f8c5cb8c1916fe41f12a17a4d06..56a2d28d715f616ca0ef4a88c8bdfc1cfac93bae 100644 |
--- a/remoting/host/capture_scheduler.cc |
+++ b/remoting/host/capture_scheduler.cc |
@@ -10,6 +10,7 @@ |
#include "base/sys_info.h" |
#include "base/time/default_tick_clock.h" |
#include "base/time/time.h" |
+#include "remoting/proto/video.pb.h" |
namespace { |
@@ -25,7 +26,22 @@ const int64 kDefaultMinimumIntervalMs = 33; |
// available while 1 means using 100% of all CPUs available. |
const double kRecordingCpuConsumption = 0.5; |
-// Maximum number of frames that can be processed simultaneously. |
+// Maximum number of captured frames in the encoding queue. Currently capturer |
+// implementations do not allow to keep more than 2 DesktopFrame objects. |
+static const int kMaxFramesInEncodingQueue = 2; |
+ |
+// Maximum number of unacknowledged frames. Ignored if the client doesn't |
+// support ACKs. This value was chosen experimentally, using synthetic |
+// performance tests (see ProtocolPerfTest), to maximize frame rate, while |
+// keeping round-trip latency low. |
+static const int kMaxUnacknowledgedFrames = 4; |
+ |
+// Maximum number of frames that can be processed (captured, encoded or sent) |
+// simultaneously. It's used only in the case when the client doesn't support |
+// ACKs. |
+// |
+// TODO(sergeyu): Remove this once all current versions support ACKs. |
+// crbug.com/460963 . |
static const int kMaxPendingFrames = 2; |
} // namespace |
@@ -35,6 +51,7 @@ namespace remoting { |
// We assume that the number of available cores is constant. |
CaptureScheduler::CaptureScheduler(const base::Closure& capture_closure) |
: capture_closure_(capture_closure), |
+ acks_supported_(false), |
tick_clock_(new base::DefaultTickClock()), |
capture_timer_(new base::Timer(false, false)), |
minimum_interval_( |
@@ -42,9 +59,12 @@ CaptureScheduler::CaptureScheduler(const base::Closure& capture_closure) |
num_of_processors_(base::SysInfo::NumberOfProcessors()), |
capture_time_(kStatisticsWindow), |
encode_time_(kStatisticsWindow), |
- pending_frames_(0), |
+ num_encoding_frames_(0), |
+ num_sending_frames_(0), |
+ num_unacknowledged_frames_(0), |
capture_pending_(false), |
- is_paused_(false) { |
+ is_paused_(false), |
+ next_frame_id_(0) { |
DCHECK(num_of_processors_); |
} |
@@ -52,13 +72,13 @@ CaptureScheduler::~CaptureScheduler() { |
} |
void CaptureScheduler::Start() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
ScheduleNextCapture(); |
} |
void CaptureScheduler::Pause(bool pause) { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
if (is_paused_ != pause) { |
is_paused_ = pause; |
@@ -72,29 +92,54 @@ void CaptureScheduler::Pause(bool pause) { |
} |
void CaptureScheduler::OnCaptureCompleted() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
capture_pending_ = false; |
capture_time_.Record( |
(tick_clock_->NowTicks() - last_capture_started_time_).InMilliseconds()); |
+ ++num_encoding_frames_; |
+ |
+ ScheduleNextCapture(); |
+} |
+ |
+void CaptureScheduler::OnFrameEncoded(VideoPacket* packet) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ // Set packet_id for the outgoing packet. |
+ packet->set_frame_id(next_frame_id_); |
+ ++next_frame_id_; |
+ |
+ // Update internal stats. |
+ encode_time_.Record(packet->encode_time_ms()); |
+ |
+ --num_encoding_frames_; |
+ ++num_sending_frames_; |
+ ++num_unacknowledged_frames_; |
+ |
ScheduleNextCapture(); |
} |
void CaptureScheduler::OnFrameSent() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
- // Decrement the pending capture count. |
- pending_frames_--; |
- DCHECK_GE(pending_frames_, 0); |
+ --num_sending_frames_; |
+ DCHECK_GE(num_sending_frames_, 0); |
ScheduleNextCapture(); |
} |
-void CaptureScheduler::OnFrameEncoded(base::TimeDelta encode_time) { |
- DCHECK(CalledOnValidThread()); |
+void CaptureScheduler::ProcessVideoAck(scoped_ptr<VideoAck> video_ack) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ // Host always sets |frame_id| field to indicated that it expects ACK from the |
+ // client. It's assumed that the client doesn't support ACKs until the first |
+ // ACK message is received. |
+ acks_supported_ = true; |
+ |
+ --num_unacknowledged_frames_; |
+ DCHECK_GE(num_unacknowledged_frames_, 0); |
- encode_time_.Record(encode_time.InMilliseconds()); |
ScheduleNextCapture(); |
} |
@@ -102,18 +147,35 @@ void CaptureScheduler::SetTickClockForTest( |
scoped_ptr<base::TickClock> tick_clock) { |
tick_clock_ = tick_clock.Pass(); |
} |
+ |
void CaptureScheduler::SetTimerForTest(scoped_ptr<base::Timer> timer) { |
capture_timer_ = timer.Pass(); |
} |
+ |
void CaptureScheduler::SetNumOfProcessorsForTest(int num_of_processors) { |
num_of_processors_ = num_of_processors; |
} |
void CaptureScheduler::ScheduleNextCapture() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
- if (is_paused_ || pending_frames_ >= kMaxPendingFrames || capture_pending_) |
+ if (is_paused_ || capture_pending_ || |
+ num_encoding_frames_ >= kMaxFramesInEncodingQueue) { |
return; |
+ } |
+ |
+ if (acks_supported_) { |
+ if (num_encoding_frames_ + num_unacknowledged_frames_ >= |
+ kMaxUnacknowledgedFrames) { |
+ return; |
+ } |
+ } else { |
+ // TODO(sergeyu): Remove this once all current versions support ACKs. |
+ // crbug.com/460963 . |
+ if (num_encoding_frames_ + num_sending_frames_ >= kMaxPendingFrames) { |
+ return; |
+ } |
+ } |
// Delay by an amount chosen such that if capture and encode times |
// continue to follow the averages, then we'll consume the target |
@@ -134,13 +196,10 @@ void CaptureScheduler::ScheduleNextCapture() { |
} |
void CaptureScheduler::CaptureNextFrame() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
DCHECK(!is_paused_); |
DCHECK(!capture_pending_); |
- pending_frames_++; |
- DCHECK_LE(pending_frames_, kMaxPendingFrames); |
- |
capture_pending_ = true; |
last_capture_started_time_ = tick_clock_->NowTicks(); |
capture_closure_.Run(); |