danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 1 | /* |
Karl Wiberg | 79eb1d9 | 2017-11-08 12:26:07 +0100 | [diff] [blame] | 2 | * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 10 | #ifndef SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_ |
| 11 | #define SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_ |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 12 | |
Chen Xing | 6094953 | 2019-08-16 16:00:30 +0200 | [diff] [blame] | 13 | #include <cmath> |
| 14 | #include <cstdint> |
| 15 | #include <limits> |
pbos | c7c26a0 | 2017-01-02 08:42:32 -0800 | [diff] [blame] | 16 | |
Patrik Höglund | 3e11343 | 2017-12-15 14:40:10 +0100 | [diff] [blame] | 17 | #include "rtc_base/numerics/safe_conversions.h" |
| 18 | |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 19 | namespace webrtc { |
| 20 | |
| 21 | class NtpTime { |
| 22 | public: |
danilchap | 27260ce | 2017-02-15 01:18:15 -0800 | [diff] [blame] | 23 | static constexpr uint64_t kFractionsPerSecond = 0x100000000; |
| 24 | NtpTime() : value_(0) {} |
| 25 | explicit NtpTime(uint64_t value) : value_(value) {} |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 26 | NtpTime(uint32_t seconds, uint32_t fractions) |
danilchap | 27260ce | 2017-02-15 01:18:15 -0800 | [diff] [blame] | 27 | : value_(seconds * kFractionsPerSecond + fractions) {} |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 28 | |
| 29 | NtpTime(const NtpTime&) = default; |
| 30 | NtpTime& operator=(const NtpTime&) = default; |
danilchap | 27260ce | 2017-02-15 01:18:15 -0800 | [diff] [blame] | 31 | explicit operator uint64_t() const { return value_; } |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 32 | |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 33 | void Set(uint32_t seconds, uint32_t fractions) { |
danilchap | 27260ce | 2017-02-15 01:18:15 -0800 | [diff] [blame] | 34 | value_ = seconds * kFractionsPerSecond + fractions; |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 35 | } |
danilchap | 27260ce | 2017-02-15 01:18:15 -0800 | [diff] [blame] | 36 | void Reset() { value_ = 0; } |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 37 | |
danilchap | 3795376 | 2017-02-09 11:15:25 -0800 | [diff] [blame] | 38 | int64_t ToMs() const { |
| 39 | static constexpr double kNtpFracPerMs = 4.294967296E6; // 2^32 / 1000. |
danilchap | 27260ce | 2017-02-15 01:18:15 -0800 | [diff] [blame] | 40 | const double frac_ms = static_cast<double>(fractions()) / kNtpFracPerMs; |
| 41 | return 1000 * static_cast<int64_t>(seconds()) + |
danilchap | 3795376 | 2017-02-09 11:15:25 -0800 | [diff] [blame] | 42 | static_cast<int64_t>(frac_ms + 0.5); |
| 43 | } |
danilchap | 27260ce | 2017-02-15 01:18:15 -0800 | [diff] [blame] | 44 | // NTP standard (RFC1305, section 3.1) explicitly state value 0 is invalid. |
| 45 | bool Valid() const { return value_ != 0; } |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 46 | |
Patrik Höglund | 3e11343 | 2017-12-15 14:40:10 +0100 | [diff] [blame] | 47 | uint32_t seconds() const { |
| 48 | return rtc::dchecked_cast<uint32_t>(value_ / kFractionsPerSecond); |
| 49 | } |
| 50 | uint32_t fractions() const { |
| 51 | return rtc::dchecked_cast<uint32_t>(value_ % kFractionsPerSecond); |
| 52 | } |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 53 | |
| 54 | private: |
danilchap | 27260ce | 2017-02-15 01:18:15 -0800 | [diff] [blame] | 55 | uint64_t value_; |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 56 | }; |
| 57 | |
| 58 | inline bool operator==(const NtpTime& n1, const NtpTime& n2) { |
danilchap | 27260ce | 2017-02-15 01:18:15 -0800 | [diff] [blame] | 59 | return static_cast<uint64_t>(n1) == static_cast<uint64_t>(n2); |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 60 | } |
| 61 | inline bool operator!=(const NtpTime& n1, const NtpTime& n2) { |
| 62 | return !(n1 == n2); |
| 63 | } |
| 64 | |
Chen Xing | 6094953 | 2019-08-16 16:00:30 +0200 | [diff] [blame] | 65 | // Converts |int64_t| milliseconds to Q32.32-formatted fixed-point seconds. |
| 66 | // Performs clamping if the result overflows or underflows. |
| 67 | inline int64_t Int64MsToQ32x32(int64_t milliseconds) { |
| 68 | // TODO(bugs.webrtc.org/10893): Change to use |rtc::saturated_cast| once the |
| 69 | // bug has been fixed. |
| 70 | double result = |
| 71 | std::round(milliseconds * (NtpTime::kFractionsPerSecond / 1000.0)); |
| 72 | |
| 73 | if (result <= std::numeric_limits<int64_t>::min()) { |
| 74 | return std::numeric_limits<int64_t>::min(); |
| 75 | } |
| 76 | |
| 77 | if (result >= std::numeric_limits<int64_t>::max()) { |
| 78 | return std::numeric_limits<int64_t>::max(); |
| 79 | } |
| 80 | |
| 81 | return rtc::dchecked_cast<int64_t>(result); |
| 82 | } |
| 83 | |
| 84 | // Converts |int64_t| milliseconds to UQ32.32-formatted fixed-point seconds. |
| 85 | // Performs clamping if the result overflows or underflows. |
| 86 | inline uint64_t Int64MsToUQ32x32(int64_t milliseconds) { |
| 87 | // TODO(bugs.webrtc.org/10893): Change to use |rtc::saturated_cast| once the |
| 88 | // bug has been fixed. |
| 89 | double result = |
| 90 | std::round(milliseconds * (NtpTime::kFractionsPerSecond / 1000.0)); |
| 91 | |
| 92 | if (result <= std::numeric_limits<uint64_t>::min()) { |
| 93 | return std::numeric_limits<uint64_t>::min(); |
| 94 | } |
| 95 | |
| 96 | if (result >= std::numeric_limits<uint64_t>::max()) { |
| 97 | return std::numeric_limits<uint64_t>::max(); |
| 98 | } |
| 99 | |
| 100 | return rtc::dchecked_cast<uint64_t>(result); |
| 101 | } |
| 102 | |
| 103 | // Converts Q32.32-formatted fixed-point seconds to |int64_t| milliseconds. |
| 104 | inline int64_t Q32x32ToInt64Ms(int64_t q32x32) { |
| 105 | return rtc::dchecked_cast<int64_t>( |
| 106 | std::round(q32x32 * (1000.0 / NtpTime::kFractionsPerSecond))); |
| 107 | } |
| 108 | |
| 109 | // Converts UQ32.32-formatted fixed-point seconds to |int64_t| milliseconds. |
| 110 | inline int64_t UQ32x32ToInt64Ms(uint64_t q32x32) { |
| 111 | return rtc::dchecked_cast<int64_t>( |
| 112 | std::round(q32x32 * (1000.0 / NtpTime::kFractionsPerSecond))); |
| 113 | } |
| 114 | |
danilchap | b1ac203 | 2015-11-26 09:01:10 -0800 | [diff] [blame] | 115 | } // namespace webrtc |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 116 | #endif // SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_ |