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