// Copyright 2014 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. #include "cast/streaming/clock_drift_smoother.h" #include #include "util/osp_logging.h" #include "util/saturate_cast.h" namespace openscreen { namespace cast { namespace { constexpr Clock::time_point kNullTime = Clock::time_point::min(); } ClockDriftSmoother::ClockDriftSmoother(Clock::duration time_constant) : time_constant_(time_constant), last_update_time_(kNullTime), estimated_tick_offset_(0.0) { OSP_DCHECK(time_constant_ > decltype(time_constant_)::zero()); } ClockDriftSmoother::~ClockDriftSmoother() = default; Clock::duration ClockDriftSmoother::Current() const { OSP_DCHECK(last_update_time_ != kNullTime); return Clock::duration( rounded_saturate_cast(estimated_tick_offset_)); } void ClockDriftSmoother::Reset(Clock::time_point now, Clock::duration measured_offset) { OSP_DCHECK(now != kNullTime); last_update_time_ = now; estimated_tick_offset_ = static_cast(measured_offset.count()); } void ClockDriftSmoother::Update(Clock::time_point now, Clock::duration measured_offset) { OSP_DCHECK(now != kNullTime); if (last_update_time_ == kNullTime) { Reset(now, measured_offset); } else if (now < last_update_time_) { // |now| is not monotonically non-decreasing. OSP_NOTREACHED(); } else { const double elapsed_ticks = static_cast((now - last_update_time_).count()); last_update_time_ = now; // Compute a weighted-average between the last estimate and // |measured_offset|. The more time that has elasped since the last call to // Update(), the more-heavily |measured_offset| will be weighed. const double weight = elapsed_ticks / (elapsed_ticks + time_constant_.count()); estimated_tick_offset_ = weight * measured_offset.count() + (1.0 - weight) * estimated_tick_offset_; } } // static constexpr std::chrono::seconds ClockDriftSmoother::kDefaultTimeConstant; } // namespace cast } // namespace openscreen