blob: 578e39b1140a9a0f7cafcc598b376799eb579ce4 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/protocol/webrtc_frame_scheduler_constant_rate.h"
#include <algorithm>
#include "base/logging.h"
#include "base/time/time.h"
namespace remoting::protocol {
WebrtcFrameSchedulerConstantRate::WebrtcFrameSchedulerConstantRate() {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
WebrtcFrameSchedulerConstantRate::~WebrtcFrameSchedulerConstantRate() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void WebrtcFrameSchedulerConstantRate::Start(
const base::RepeatingClosure& capture_callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
capture_callback_ = capture_callback;
}
void WebrtcFrameSchedulerConstantRate::Pause(bool pause) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
paused_ = pause;
if (paused_) {
capture_timer_.Stop();
} else {
ScheduleNextFrame();
}
}
void WebrtcFrameSchedulerConstantRate::OnFrameCaptured(
const webrtc::DesktopFrame* frame) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(frame_pending_);
frame_pending_ = false;
ScheduleNextFrame();
}
void WebrtcFrameSchedulerConstantRate::SetMaxFramerateFps(int max_framerate) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
max_framerate_fps_ = max_framerate;
ScheduleNextFrame();
}
void WebrtcFrameSchedulerConstantRate::ScheduleNextFrame() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::TimeTicks now = base::TimeTicks::Now();
if (paused_) {
VLOG(0) << "Not scheduling capture because stream is paused.";
return;
}
if (!capture_callback_) {
VLOG(0) << "Not scheduling capture because callback is not provided.";
return;
}
if (frame_pending_) {
// This might be logged every time the capture takes more time than the
// polling period. To avoid spamming, only log if the capture has been
// pending for an unreasonable length of time.
DCHECK(!last_capture_started_time_.is_null());
if (now - last_capture_started_time_ > base::Seconds(1)) {
// Log this as an error, because a capture should never be pending for
// this length of time.
LOG(ERROR) << "Not scheduling capture because a capture is pending.";
}
return;
}
if (max_framerate_fps_ == 0) {
VLOG(0) << "Not scheduling capture because framerate is set to 0.";
return;
}
// Captures should be scheduled at least 1ms apart, otherwise WebRTC's video
// stream encoder complains about non-increasing frame timestamps, which can
// affect some unittests.
base::TimeDelta capture_interval =
std::max(base::Seconds(1) / max_framerate_fps_, base::Milliseconds(1));
base::TimeDelta delay;
if (!last_capture_started_time_.is_null()) {
base::TimeTicks target_capture_time =
std::max(last_capture_started_time_ + capture_interval, now);
delay = std::max(target_capture_time - now, base::Milliseconds(1));
}
capture_timer_.Start(FROM_HERE, delay, this,
&WebrtcFrameSchedulerConstantRate::CaptureNextFrame);
}
void WebrtcFrameSchedulerConstantRate::CaptureNextFrame() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!frame_pending_);
last_capture_started_time_ = base::TimeTicks::Now();
frame_pending_ = true;
capture_callback_.Run();
}
} // namespace remoting::protocol