1 // Copyright 2019 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 #ifndef CAST_STREAMING_NTP_TIME_H_
6 #define CAST_STREAMING_NTP_TIME_H_
7 
8 #include <stdint.h>
9 
10 #include "platform/api/time.h"
11 
12 namespace openscreen {
13 namespace cast {
14 
15 // NTP timestamps are 64-bit timestamps that consist of two 32-bit parts: 1) The
16 // number of seconds since 1 January 1900; and 2) The fraction of the second,
17 // where 0 maps to 0x00000000 and each unit increment represents another 2^-32
18 // seconds.
19 //
20 // Note that it is part of the design of NTP for the seconds part to roll around
21 // on 7 February 2036.
22 using NtpTimestamp = uint64_t;
23 
24 // NTP fixed-point time math: Declare two std::chrono::duration types with the
25 // bit-width necessary to reliably perform all conversions to/from NTP format.
26 using NtpSeconds = std::chrono::duration<int64_t, std::chrono::seconds::period>;
27 using NtpFraction =
28     std::chrono::duration<int64_t, std::ratio<1, INT64_C(0x100000000)>>;
29 
NtpSecondsPart(NtpTimestamp timestamp)30 constexpr NtpSeconds NtpSecondsPart(NtpTimestamp timestamp) {
31   return NtpSeconds(timestamp >> 32);
32 }
33 
NtpFractionPart(NtpTimestamp timestamp)34 constexpr NtpFraction NtpFractionPart(NtpTimestamp timestamp) {
35   return NtpFraction(timestamp & 0xffffffff);
36 }
37 
AssembleNtpTimestamp(NtpSeconds seconds,NtpFraction fraction)38 constexpr NtpTimestamp AssembleNtpTimestamp(NtpSeconds seconds,
39                                             NtpFraction fraction) {
40   return (static_cast<uint64_t>(seconds.count()) << 32) |
41          static_cast<uint32_t>(fraction.count());
42 }
43 
44 // Converts between Clock::time_points and NtpTimestamps. The class is
45 // instantiated with the current Clock time and the current wall clock time, and
46 // these are used to determine a fixed origin reference point for all
47 // conversions. Thus, to avoid introducing unintended timing-related behaviors,
48 // only one NtpTimeConverter instance should be used for converting all the NTP
49 // timestamps in the same streaming session.
50 class NtpTimeConverter {
51  public:
52   NtpTimeConverter(
53       Clock::time_point now,
54       std::chrono::seconds since_unix_epoch = GetWallTimeSinceUnixEpoch());
55   ~NtpTimeConverter();
56 
57   NtpTimestamp ToNtpTimestamp(Clock::time_point time_point) const;
58   Clock::time_point ToLocalTime(NtpTimestamp timestamp) const;
59 
60  private:
61   // The time point on the platform clock's timeline that corresponds to
62   // approximately the same time point on the NTP timeline. Note that it is
63   // acceptable for the granularity of the NTP seconds value to be whole seconds
64   // here: Both a Cast Streaming Sender and Receiver will assume their clocks
65   // can be off (with respect to each other) by even a large amount; and all
66   // that matters is that time ticks forward at a reasonable pace from some
67   // initial point.
68   const Clock::time_point start_time_;
69   const NtpSeconds since_ntp_epoch_;
70 };
71 
72 }  // namespace cast
73 }  // namespace openscreen
74 
75 #endif  // CAST_STREAMING_NTP_TIME_H_
76