// Copyright 2021 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef THIRD_PARTY_BLINK_WEBRTC_OVERRIDES_LOW_PRECISION_TIMER_H_ #define THIRD_PARTY_BLINK_WEBRTC_OVERRIDES_LOW_PRECISION_TIMER_H_ #include "base/callback.h" #include "base/feature_list.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" #include "base/synchronization/lock.h" #include "base/task/sequenced_task_runner.h" #include "base/thread_annotations.h" #include "base/time/time.h" #include "third_party/webrtc/rtc_base/system/rtc_export.h" #include "third_party/webrtc_overrides/metronome_source.h" namespace blink { // Implements a low precision timer, expect it to fire up to ~16 ms late (plus // any OS or workload related delays). // // This timer only fires on metronome ticks as specified by // MetronomeSource::TimeSnappedToNextTick(). This allows running numerous timers // without increasing the Idle Wake Ups frequency beyond the metronome tick // frequency, i.e. when each tick is already scheduled adding a // LowPrecisionTimer should not add any Idle Wake Ups. // // TODO(https://crbug.com/1267874): Can this timer be moved to base/ or replaced // by a low precision base/ timer without causing excessive Idle Wake Up // frequencies (e.g. WebRTC use case with 50 incoming videos)? class RTC_EXPORT LowPrecisionTimer final { public: LowPrecisionTimer(scoped_refptr task_runner, base::RepeatingCallback callback); ~LowPrecisionTimer(); // Must be called prior to destruction. Unregisters from the metronome // provider. void Shutdown(); // Schedules to invoke the callback |delay| time from now. void StartOneShot(base::TimeDelta delay); // Scheduldes to repeat unconditionally until the timer is stopped. This has // the same behavior as calling StartOneShot(delay) inside each callback. void StartRepeating(base::TimeDelta delay); // True if there is currently activity scheduled. bool IsActive(); // Cancels any scheduled callbacks. void Stop(); // Change which task runner to fire callbacks on. Seamlessy re-schedules // pending callbacks. Must not be called from inside the callback. void MoveToNewTaskRunner( scoped_refptr task_runner); private: // Handles the scheduling and cancellation of a repeating callback. // The callback can be re-scheduled after it has fired, but all other settings // are "const". To change settings the SchedulableCallback has to be // inactivated and replaced by a new SchedulableCallback instance. class SchedulableCallback : public base::RefCountedThreadSafe { public: SchedulableCallback(scoped_refptr task_runner, base::RepeatingCallback callback, base::TimeDelta repeated_delay); ~SchedulableCallback(); // The task can be re-scheduled after each run. void Schedule(base::TimeTicks scheduled_time); bool IsScheduled(); // Inactivate the callback. Returns the cancelled scheduled time, or // base::TimeTicks::Max() if nothing was scheduled when cancelled. base::TimeTicks Inactivate(); private: void MaybeRun(); void RemoveMetronomeListener(); const scoped_refptr task_runner_; const base::RepeatingCallback callback_; // Only accessed on |task_runner_|. bool is_currently_running_ = false; base::Lock active_lock_; // Guarded by |active_lock_|, but to avoid deadlock we do not acquire the // lock when Inactivate() is being called from inside the callback. In this // case the lock is already being held by MaybeRun(). bool is_active_ = true; base::TimeDelta repeated_delay_; base::Lock scheduled_time_lock_; base::TimeTicks scheduled_time_ GUARDED_BY(scheduled_time_lock_) = base::TimeTicks::Max(); // Max represents forever, i.e. not scheduled. }; // Lazy-constructs |schedulable_callback_| and schedules the callback on the // specified time. void ScheduleCallback(base::TimeTicks scheduled_time) EXCLUSIVE_LOCKS_REQUIRED(lock_); // Inactivates in-flight callbacks and re-schedulels the callback using the // latest settings. Used e.g. when we start or stop using the metronome. void RescheduleCallback() EXCLUSIVE_LOCKS_REQUIRED(lock_); const base::RepeatingCallback callback_; base::Lock lock_; bool is_shutdown_ GUARDED_BY(lock_) = false; scoped_refptr task_runner_ GUARDED_BY(lock_); scoped_refptr schedulable_callback_ GUARDED_BY(lock_); // If not repeating this is zero. base::TimeDelta repeated_delay_ GUARDED_BY(lock_); }; } // namespace blink #endif // THIRD_PARTY_BLINK_WEBRTC_OVERRIDES_LOW_PRECISION_TIMER_H_