aboutsummaryrefslogtreecommitdiff
path: root/cast/streaming/ntp_time.h
blob: f76dae4abe94ef7a75f99cf2ff5df6c6f9dc38bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// Copyright 2019 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.

#ifndef CAST_STREAMING_NTP_TIME_H_
#define CAST_STREAMING_NTP_TIME_H_

#include <stdint.h>

#include "platform/api/time.h"

namespace cast {
namespace streaming {

// NTP timestamps are 64-bit timestamps that consist of two 32-bit parts: 1) The
// number of seconds since 1 January 1900; and 2) The fraction of the second,
// where 0 maps to 0x00000000 and each unit increment represents another 2^-32
// seconds.
//
// Note that it is part of the design of NTP for the seconds part to roll around
// on 7 February 2036.
using NtpTimestamp = uint64_t;

// NTP fixed-point time math: Declare two std::chrono::duration types with the
// bit-width necessary to reliably perform all conversions to/from NTP format.
using NtpSeconds = std::chrono::duration<int64_t, std::chrono::seconds::period>;
using NtpFraction =
    std::chrono::duration<int64_t, std::ratio<1, INT64_C(0x100000000)>>;

constexpr NtpSeconds NtpSecondsPart(NtpTimestamp timestamp) {
  return NtpSeconds(timestamp >> 32);
}

constexpr NtpFraction NtpFractionPart(NtpTimestamp timestamp) {
  return NtpFraction(timestamp & 0xffffffff);
}

constexpr NtpTimestamp AssembleNtpTimestamp(NtpSeconds seconds,
                                            NtpFraction fraction) {
  return (static_cast<uint64_t>(seconds.count()) << 32) |
         static_cast<uint32_t>(fraction.count());
}

// Converts between openscreen::platform::Clock::time_points and NtpTimestamps.
// The class is instantiated with the current openscreen::platform::Clock time
// and the current wall clock time, and these are used to determine a fixed
// origin reference point for all conversions. Thus, to avoid introducing
// unintended timing-related behaviors, only one NtpTimeConverter instance
// should be used for converting all the NTP timestamps in the same streaming
// session.
class NtpTimeConverter {
 public:
  NtpTimeConverter(openscreen::platform::Clock::time_point now,
                   std::chrono::seconds since_unix_epoch =
                       openscreen::platform::GetWallTimeSinceUnixEpoch());
  ~NtpTimeConverter();

  NtpTimestamp ToNtpTimestamp(
      openscreen::platform::Clock::time_point time_point) const;
  openscreen::platform::Clock::time_point ToLocalTime(
      NtpTimestamp timestamp) const;

 private:
  // The time point on the platform clock's timeline that corresponds to
  // approximately the same time point on the NTP timeline. Note that it is
  // acceptable for the granularity of the NTP seconds value to be whole seconds
  // here: Both a Cast Streaming Sender and Receiver will assume their clocks
  // can be off (with respect to each other) by even a large amount; and all
  // that matters is that time ticks forward at a reasonable pace from some
  // initial point.
  const openscreen::platform::Clock::time_point start_time_;
  const NtpSeconds since_ntp_epoch_;
};

}  // namespace streaming
}  // namespace cast

#endif  // CAST_STREAMING_NTP_TIME_H_