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 #include "cast/streaming/clock_drift_smoother.h" 6*3f982cf4SFabien Sanglard 7*3f982cf4SFabien Sanglard #include <cmath> 8*3f982cf4SFabien Sanglard 9*3f982cf4SFabien Sanglard #include "util/osp_logging.h" 10*3f982cf4SFabien Sanglard #include "util/saturate_cast.h" 11*3f982cf4SFabien Sanglard 12*3f982cf4SFabien Sanglard namespace openscreen { 13*3f982cf4SFabien Sanglard namespace cast { 14*3f982cf4SFabien Sanglard 15*3f982cf4SFabien Sanglard namespace { 16*3f982cf4SFabien Sanglard constexpr Clock::time_point kNullTime = Clock::time_point::min(); 17*3f982cf4SFabien Sanglard } 18*3f982cf4SFabien Sanglard ClockDriftSmoother(Clock::duration time_constant)19*3f982cf4SFabien SanglardClockDriftSmoother::ClockDriftSmoother(Clock::duration time_constant) 20*3f982cf4SFabien Sanglard : time_constant_(time_constant), 21*3f982cf4SFabien Sanglard last_update_time_(kNullTime), 22*3f982cf4SFabien Sanglard estimated_tick_offset_(0.0) { 23*3f982cf4SFabien Sanglard OSP_DCHECK(time_constant_ > decltype(time_constant_)::zero()); 24*3f982cf4SFabien Sanglard } 25*3f982cf4SFabien Sanglard 26*3f982cf4SFabien Sanglard ClockDriftSmoother::~ClockDriftSmoother() = default; 27*3f982cf4SFabien Sanglard Current() const28*3f982cf4SFabien SanglardClock::duration ClockDriftSmoother::Current() const { 29*3f982cf4SFabien Sanglard OSP_DCHECK(last_update_time_ != kNullTime); 30*3f982cf4SFabien Sanglard return Clock::duration( 31*3f982cf4SFabien Sanglard rounded_saturate_cast<Clock::duration::rep>(estimated_tick_offset_)); 32*3f982cf4SFabien Sanglard } 33*3f982cf4SFabien Sanglard Reset(Clock::time_point now,Clock::duration measured_offset)34*3f982cf4SFabien Sanglardvoid ClockDriftSmoother::Reset(Clock::time_point now, 35*3f982cf4SFabien Sanglard Clock::duration measured_offset) { 36*3f982cf4SFabien Sanglard OSP_DCHECK(now != kNullTime); 37*3f982cf4SFabien Sanglard last_update_time_ = now; 38*3f982cf4SFabien Sanglard estimated_tick_offset_ = static_cast<double>(measured_offset.count()); 39*3f982cf4SFabien Sanglard } 40*3f982cf4SFabien Sanglard Update(Clock::time_point now,Clock::duration measured_offset)41*3f982cf4SFabien Sanglardvoid ClockDriftSmoother::Update(Clock::time_point now, 42*3f982cf4SFabien Sanglard Clock::duration measured_offset) { 43*3f982cf4SFabien Sanglard OSP_DCHECK(now != kNullTime); 44*3f982cf4SFabien Sanglard if (last_update_time_ == kNullTime) { 45*3f982cf4SFabien Sanglard Reset(now, measured_offset); 46*3f982cf4SFabien Sanglard } else if (now < last_update_time_) { 47*3f982cf4SFabien Sanglard // |now| is not monotonically non-decreasing. 48*3f982cf4SFabien Sanglard OSP_NOTREACHED(); 49*3f982cf4SFabien Sanglard } else { 50*3f982cf4SFabien Sanglard const double elapsed_ticks = 51*3f982cf4SFabien Sanglard static_cast<double>((now - last_update_time_).count()); 52*3f982cf4SFabien Sanglard last_update_time_ = now; 53*3f982cf4SFabien Sanglard // Compute a weighted-average between the last estimate and 54*3f982cf4SFabien Sanglard // |measured_offset|. The more time that has elasped since the last call to 55*3f982cf4SFabien Sanglard // Update(), the more-heavily |measured_offset| will be weighed. 56*3f982cf4SFabien Sanglard const double weight = 57*3f982cf4SFabien Sanglard elapsed_ticks / (elapsed_ticks + time_constant_.count()); 58*3f982cf4SFabien Sanglard estimated_tick_offset_ = weight * measured_offset.count() + 59*3f982cf4SFabien Sanglard (1.0 - weight) * estimated_tick_offset_; 60*3f982cf4SFabien Sanglard } 61*3f982cf4SFabien Sanglard } 62*3f982cf4SFabien Sanglard 63*3f982cf4SFabien Sanglard // static 64*3f982cf4SFabien Sanglard constexpr std::chrono::seconds ClockDriftSmoother::kDefaultTimeConstant; 65*3f982cf4SFabien Sanglard 66*3f982cf4SFabien Sanglard } // namespace cast 67*3f982cf4SFabien Sanglard } // namespace openscreen 68