Index: remoting/host/video_scheduler.cc |
diff --git a/remoting/host/video_scheduler.cc b/remoting/host/video_scheduler.cc |
index 7fc1983128d8d0c36604e502b64e08fbd2a88135..a346d04c254898e7ff482099025d70efec8a5e13 100644 |
--- a/remoting/host/video_scheduler.cc |
+++ b/remoting/host/video_scheduler.cc |
@@ -30,6 +30,10 @@ namespace remoting { |
// TODO(hclam): Move this value to CaptureScheduler. |
static const int kMaxPendingFrames = 2; |
+// Interval between empty keep-alive frames. These frames are sent only |
+// when there are no real video frames being sent. |
+static const int kKeepAlivePacketIntervalMs = 500; |
+ |
VideoScheduler::VideoScheduler( |
scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner, |
scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner, |
@@ -68,16 +72,22 @@ void VideoScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) { |
capture_pending_ = false; |
+ if (!frame) { |
+ LOG(ERROR) << "Capture failed."; |
+ return; |
+ } |
+ |
scoped_ptr<webrtc::DesktopFrame> owned_frame(frame); |
- if (frame) { |
- scheduler_.RecordCaptureTime( |
- base::TimeDelta::FromMilliseconds(frame->capture_time_ms())); |
- } |
+ scheduler_.RecordCaptureTime( |
+ base::TimeDelta::FromMilliseconds(frame->capture_time_ms())); |
- encode_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this, |
- base::Passed(&owned_frame), sequence_number_)); |
+ // Encode and send only non-empty frames. |
+ if (!frame->updated_region().is_empty()) { |
+ encode_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this, |
+ base::Passed(&owned_frame), sequence_number_)); |
+ } |
// If a frame was skipped, try to capture it again. |
if (did_skip_frame_) { |
@@ -123,8 +133,10 @@ void VideoScheduler::Stop() { |
cursor_stub_ = NULL; |
video_stub_ = NULL; |
- capture_task_runner_->PostTask(FROM_HERE, |
- base::Bind(&VideoScheduler::StopOnCaptureThread, this)); |
+ keep_alive_timer_.reset(); |
+ |
+ capture_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&VideoScheduler::StopOnCaptureThread, this)); |
} |
void VideoScheduler::Pause(bool pause) { |
@@ -172,6 +184,9 @@ void VideoScheduler::StartOnCaptureThread() { |
capturer_->Start(this); |
capture_timer_.reset(new base::OneShotTimer<VideoScheduler>()); |
+ keep_alive_timer_.reset(new base::DelayTimer<VideoScheduler>( |
+ FROM_HERE, base::TimeDelta::FromMilliseconds(kKeepAlivePacketIntervalMs), |
+ this, &VideoScheduler::SendKeepAlivePacket)); |
// Capture first frame immedately. |
CaptureNextFrame(); |
@@ -249,19 +264,39 @@ void VideoScheduler::SendVideoPacket(scoped_ptr<VideoPacket> packet) { |
return; |
video_stub_->ProcessVideoPacket( |
- packet.Pass(), base::Bind(&VideoScheduler::VideoFrameSentCallback, this)); |
+ packet.Pass(), base::Bind(&VideoScheduler::OnVideoPacketSent, this)); |
} |
-void VideoScheduler::VideoFrameSentCallback() { |
+void VideoScheduler::OnVideoPacketSent() { |
DCHECK(network_task_runner_->BelongsToCurrentThread()); |
if (!video_stub_) |
return; |
+ keep_alive_timer_->Reset(); |
+ |
capture_task_runner_->PostTask( |
FROM_HERE, base::Bind(&VideoScheduler::FrameCaptureCompleted, this)); |
} |
+void VideoScheduler::SendKeepAlivePacket() { |
+ DCHECK(network_task_runner_->BelongsToCurrentThread()); |
+ |
+ if (!video_stub_) |
+ return; |
+ |
+ video_stub_->ProcessVideoPacket( |
+ scoped_ptr<VideoPacket>(new VideoPacket()), |
+ base::Bind(&VideoScheduler::OnKeepAlivePacketSent, this)); |
+} |
+ |
+void VideoScheduler::OnKeepAlivePacketSent() { |
+ DCHECK(network_task_runner_->BelongsToCurrentThread()); |
+ |
+ if (keep_alive_timer_) |
+ keep_alive_timer_->Reset(); |
+} |
+ |
void VideoScheduler::SendCursorShape( |
scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { |
DCHECK(network_task_runner_->BelongsToCurrentThread()); |
@@ -278,17 +313,7 @@ void VideoScheduler::EncodeFrame( |
scoped_ptr<webrtc::DesktopFrame> frame, |
int64 sequence_number) { |
DCHECK(encode_task_runner_->BelongsToCurrentThread()); |
- |
- // If there is nothing to encode then send an empty keep-alive packet. |
- if (!frame || frame->updated_region().is_empty()) { |
- scoped_ptr<VideoPacket> packet(new VideoPacket()); |
- packet->set_client_sequence_number(sequence_number); |
- network_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this, |
- base::Passed(&packet))); |
- capture_task_runner_->DeleteSoon(FROM_HERE, frame.release()); |
- return; |
- } |
+ DCHECK(!frame->updated_region().is_empty()); |
scoped_ptr<VideoPacket> packet = encoder_->Encode(*frame); |
packet->set_client_sequence_number(sequence_number); |