xref: /aosp_15_r20/external/openscreen/cast/streaming/clock_drift_smoother.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
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 Sanglard ClockDriftSmoother::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 Sanglard Clock::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 Sanglard void 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 Sanglard void 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