1*3f982cf4SFabien Sanglard // Copyright 2014 The Chromium Authors. All rights reserved. 2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be 3*3f982cf4SFabien Sanglard // found in the LICENSE file. 4*3f982cf4SFabien Sanglard 5*3f982cf4SFabien Sanglard #ifndef CAST_STREAMING_CLOCK_DRIFT_SMOOTHER_H_ 6*3f982cf4SFabien Sanglard #define CAST_STREAMING_CLOCK_DRIFT_SMOOTHER_H_ 7*3f982cf4SFabien Sanglard 8*3f982cf4SFabien Sanglard #include <chrono> 9*3f982cf4SFabien Sanglard 10*3f982cf4SFabien Sanglard #include "platform/api/time.h" 11*3f982cf4SFabien Sanglard 12*3f982cf4SFabien Sanglard namespace openscreen { 13*3f982cf4SFabien Sanglard namespace cast { 14*3f982cf4SFabien Sanglard 15*3f982cf4SFabien Sanglard // Tracks the jitter and drift between clocks, providing a smoothed offset. 16*3f982cf4SFabien Sanglard // Internally, a Simple IIR filter is used to maintain a running average that 17*3f982cf4SFabien Sanglard // moves at a rate based on the passage of time. 18*3f982cf4SFabien Sanglard class ClockDriftSmoother { 19*3f982cf4SFabien Sanglard public: 20*3f982cf4SFabien Sanglard // |time_constant| is the amount of time an impulse signal takes to decay by 21*3f982cf4SFabien Sanglard // ~62.6%. Interpretation: If the value passed to several Update() calls is 22*3f982cf4SFabien Sanglard // held constant for T seconds, then the running average will have moved 23*3f982cf4SFabien Sanglard // towards the value by ~62.6% from where it started. 24*3f982cf4SFabien Sanglard explicit ClockDriftSmoother(Clock::duration time_constant); 25*3f982cf4SFabien Sanglard ~ClockDriftSmoother(); 26*3f982cf4SFabien Sanglard 27*3f982cf4SFabien Sanglard // Returns the current offset. 28*3f982cf4SFabien Sanglard Clock::duration Current() const; 29*3f982cf4SFabien Sanglard 30*3f982cf4SFabien Sanglard // Discard all history and reset to exactly |offset|, measured |now|. 31*3f982cf4SFabien Sanglard void Reset(Clock::time_point now, Clock::duration offset); 32*3f982cf4SFabien Sanglard 33*3f982cf4SFabien Sanglard // Update the current offset, which was measured |now|. The weighting that 34*3f982cf4SFabien Sanglard // |measured_offset| will have on the running average is influenced by how 35*3f982cf4SFabien Sanglard // much time has passed since the last call to this method (or Reset()). 36*3f982cf4SFabien Sanglard // |now| should be monotonically non-decreasing over successive calls of this 37*3f982cf4SFabien Sanglard // method. 38*3f982cf4SFabien Sanglard void Update(Clock::time_point now, Clock::duration measured_offset); 39*3f982cf4SFabien Sanglard 40*3f982cf4SFabien Sanglard // A time constant suitable for most use cases, where the clocks are expected 41*3f982cf4SFabien Sanglard // to drift very little with respect to each other, and the jitter caused by 42*3f982cf4SFabien Sanglard // clock imprecision is effectively canceled out. 43*3f982cf4SFabien Sanglard static constexpr std::chrono::seconds kDefaultTimeConstant{30}; 44*3f982cf4SFabien Sanglard 45*3f982cf4SFabien Sanglard private: 46*3f982cf4SFabien Sanglard const std::chrono::duration<double, Clock::duration::period> time_constant_; 47*3f982cf4SFabien Sanglard 48*3f982cf4SFabien Sanglard // The time at which |estimated_tick_offset_| was last updated. 49*3f982cf4SFabien Sanglard Clock::time_point last_update_time_; 50*3f982cf4SFabien Sanglard 51*3f982cf4SFabien Sanglard // The current estimated offset, as number of Clock::duration ticks. 52*3f982cf4SFabien Sanglard double estimated_tick_offset_; 53*3f982cf4SFabien Sanglard }; 54*3f982cf4SFabien Sanglard 55*3f982cf4SFabien Sanglard } // namespace cast 56*3f982cf4SFabien Sanglard } // namespace openscreen 57*3f982cf4SFabien Sanglard 58*3f982cf4SFabien Sanglard #endif // CAST_STREAMING_CLOCK_DRIFT_SMOOTHER_H_ 59