1*3f982cf4SFabien Sanglard // Copyright 2015 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 #ifndef CAST_STREAMING_RTP_TIME_H_ 6*3f982cf4SFabien Sanglard #define CAST_STREAMING_RTP_TIME_H_ 7*3f982cf4SFabien Sanglard 8*3f982cf4SFabien Sanglard #include <stdint.h> 9*3f982cf4SFabien Sanglard 10*3f982cf4SFabien Sanglard #include <chrono> 11*3f982cf4SFabien Sanglard #include <cmath> 12*3f982cf4SFabien Sanglard #include <limits> 13*3f982cf4SFabien Sanglard #include <sstream> 14*3f982cf4SFabien Sanglard #include <type_traits> 15*3f982cf4SFabien Sanglard 16*3f982cf4SFabien Sanglard #include "cast/streaming/expanded_value_base.h" 17*3f982cf4SFabien Sanglard #include "platform/api/time.h" 18*3f982cf4SFabien Sanglard #include "util/saturate_cast.h" 19*3f982cf4SFabien Sanglard 20*3f982cf4SFabien Sanglard namespace openscreen { 21*3f982cf4SFabien Sanglard namespace cast { 22*3f982cf4SFabien Sanglard 23*3f982cf4SFabien Sanglard // Forward declarations (see below). 24*3f982cf4SFabien Sanglard class RtpTimeDelta; 25*3f982cf4SFabien Sanglard class RtpTimeTicks; 26*3f982cf4SFabien Sanglard 27*3f982cf4SFabien Sanglard // Convenience operator overloads for logging. 28*3f982cf4SFabien Sanglard std::ostream& operator<<(std::ostream& out, const RtpTimeDelta rhs); 29*3f982cf4SFabien Sanglard std::ostream& operator<<(std::ostream& out, const RtpTimeTicks rhs); 30*3f982cf4SFabien Sanglard 31*3f982cf4SFabien Sanglard // The difference between two RtpTimeTicks values. This data type is modeled 32*3f982cf4SFabien Sanglard // off of Chromium's base::TimeDelta, and used for performing compiler-checked 33*3f982cf4SFabien Sanglard // arithmetic with RtpTimeTicks. 34*3f982cf4SFabien Sanglard // 35*3f982cf4SFabien Sanglard // This data type wraps a value, providing only the meaningful set of math 36*3f982cf4SFabien Sanglard // operations that may be performed on the value. RtpTimeDeltas may be 37*3f982cf4SFabien Sanglard // added/subtracted with other RtpTimeDeltas to produce a RtpTimeDelta holding 38*3f982cf4SFabien Sanglard // the sum/difference. RtpTimeDeltas may also be multiplied or divided by 39*3f982cf4SFabien Sanglard // integer amounts. Finally, RtpTimeDeltas may be divided by other 40*3f982cf4SFabien Sanglard // RtpTimeDeltas to compute a number of periods (trunc'ed to an integer), or 41*3f982cf4SFabien Sanglard // modulo each other to determine a time period remainder. 42*3f982cf4SFabien Sanglard // 43*3f982cf4SFabien Sanglard // The base class provides bit truncation/extension features for 44*3f982cf4SFabien Sanglard // wire-formatting, and also the comparison operators. 45*3f982cf4SFabien Sanglard // 46*3f982cf4SFabien Sanglard // Usage example: 47*3f982cf4SFabien Sanglard // 48*3f982cf4SFabien Sanglard // // Time math. 49*3f982cf4SFabien Sanglard // RtpTimeDelta zero; 50*3f982cf4SFabien Sanglard // RtpTimeDelta one_second_later = 51*3f982cf4SFabien Sanglard // zero + RtpTimeDelta::FromTicks(kAudioSamplingRate); 52*3f982cf4SFabien Sanglard // RtpTimeDelta ten_seconds_later = one_second_later * 10; 53*3f982cf4SFabien Sanglard // int64_t ten_periods = ten_seconds_later / one_second_later; 54*3f982cf4SFabien Sanglard // 55*3f982cf4SFabien Sanglard // // Logging convenience. 56*3f982cf4SFabien Sanglard // OSP_DLOG_INFO << "The RTP time offset is " << ten_seconds_later; 57*3f982cf4SFabien Sanglard // 58*3f982cf4SFabien Sanglard // // Convert (approximately!) between RTP timebase and microsecond timebase: 59*3f982cf4SFabien Sanglard // RtpTimeDelta nine_seconds_in_rtp = ten_seconds_later - one_second_later; 60*3f982cf4SFabien Sanglard // using std::chrono::microseconds; 61*3f982cf4SFabien Sanglard // microseconds nine_seconds_duration = 62*3f982cf4SFabien Sanglard // nine_seconds_in_rtp.ToDuration<microseconds>(kAudioSamplingRate); 63*3f982cf4SFabien Sanglard // RtpTimeDelta two_seconds_in_rtp = 64*3f982cf4SFabien Sanglard // RtpTimeDelta::FromDuration(std::chrono::seconds(2), 65*3f982cf4SFabien Sanglard // kAudioSamplingRate); 66*3f982cf4SFabien Sanglard class RtpTimeDelta : public ExpandedValueBase<int64_t, RtpTimeDelta> { 67*3f982cf4SFabien Sanglard public: RtpTimeDelta()68*3f982cf4SFabien Sanglard constexpr RtpTimeDelta() : ExpandedValueBase(0) {} 69*3f982cf4SFabien Sanglard 70*3f982cf4SFabien Sanglard // Arithmetic operators (with other deltas). 71*3f982cf4SFabien Sanglard constexpr RtpTimeDelta operator+(RtpTimeDelta rhs) const { 72*3f982cf4SFabien Sanglard return RtpTimeDelta(value_ + rhs.value_); 73*3f982cf4SFabien Sanglard } 74*3f982cf4SFabien Sanglard constexpr RtpTimeDelta operator-(RtpTimeDelta rhs) const { 75*3f982cf4SFabien Sanglard return RtpTimeDelta(value_ - rhs.value_); 76*3f982cf4SFabien Sanglard } 77*3f982cf4SFabien Sanglard constexpr RtpTimeDelta& operator+=(RtpTimeDelta rhs) { 78*3f982cf4SFabien Sanglard return (*this = (*this + rhs)); 79*3f982cf4SFabien Sanglard } 80*3f982cf4SFabien Sanglard constexpr RtpTimeDelta& operator-=(RtpTimeDelta rhs) { 81*3f982cf4SFabien Sanglard return (*this = (*this - rhs)); 82*3f982cf4SFabien Sanglard } 83*3f982cf4SFabien Sanglard constexpr RtpTimeDelta operator-() const { return RtpTimeDelta(-value_); } 84*3f982cf4SFabien Sanglard 85*3f982cf4SFabien Sanglard // Multiplicative operators (with other deltas). 86*3f982cf4SFabien Sanglard constexpr int64_t operator/(RtpTimeDelta rhs) const { 87*3f982cf4SFabien Sanglard return value_ / rhs.value_; 88*3f982cf4SFabien Sanglard } 89*3f982cf4SFabien Sanglard constexpr RtpTimeDelta operator%(RtpTimeDelta rhs) const { 90*3f982cf4SFabien Sanglard return RtpTimeDelta(value_ % rhs.value_); 91*3f982cf4SFabien Sanglard } 92*3f982cf4SFabien Sanglard constexpr RtpTimeDelta& operator%=(RtpTimeDelta rhs) { 93*3f982cf4SFabien Sanglard return (*this = (*this % rhs)); 94*3f982cf4SFabien Sanglard } 95*3f982cf4SFabien Sanglard 96*3f982cf4SFabien Sanglard // Multiplicative operators (with integer types). 97*3f982cf4SFabien Sanglard template <typename IntType> 98*3f982cf4SFabien Sanglard constexpr RtpTimeDelta operator*(IntType rhs) const { 99*3f982cf4SFabien Sanglard static_assert(std::numeric_limits<IntType>::is_integer, 100*3f982cf4SFabien Sanglard "|rhs| must be a POD integer type"); 101*3f982cf4SFabien Sanglard return RtpTimeDelta(value_ * rhs); 102*3f982cf4SFabien Sanglard } 103*3f982cf4SFabien Sanglard template <typename IntType> 104*3f982cf4SFabien Sanglard constexpr RtpTimeDelta operator/(IntType rhs) const { 105*3f982cf4SFabien Sanglard static_assert(std::numeric_limits<IntType>::is_integer, 106*3f982cf4SFabien Sanglard "|rhs| must be a POD integer type"); 107*3f982cf4SFabien Sanglard return RtpTimeDelta(value_ / rhs); 108*3f982cf4SFabien Sanglard } 109*3f982cf4SFabien Sanglard template <typename IntType> 110*3f982cf4SFabien Sanglard constexpr RtpTimeDelta& operator*=(IntType rhs) { 111*3f982cf4SFabien Sanglard return (*this = (*this * rhs)); 112*3f982cf4SFabien Sanglard } 113*3f982cf4SFabien Sanglard template <typename IntType> 114*3f982cf4SFabien Sanglard constexpr RtpTimeDelta& operator/=(IntType rhs) { 115*3f982cf4SFabien Sanglard return (*this = (*this / rhs)); 116*3f982cf4SFabien Sanglard } 117*3f982cf4SFabien Sanglard 118*3f982cf4SFabien Sanglard // Maps this RtpTimeDelta to an approximate std::chrono::duration using the 119*3f982cf4SFabien Sanglard // given RTP timebase. Assumes a zero-valued Duration corresponds to a 120*3f982cf4SFabien Sanglard // zero-valued RtpTimeDelta. 121*3f982cf4SFabien Sanglard template <typename Duration> ToDuration(int rtp_timebase)122*3f982cf4SFabien Sanglard Duration ToDuration(int rtp_timebase) const { 123*3f982cf4SFabien Sanglard OSP_DCHECK_GT(rtp_timebase, 0); 124*3f982cf4SFabien Sanglard constexpr Duration kOneSecond = 125*3f982cf4SFabien Sanglard std::chrono::duration_cast<Duration>(std::chrono::seconds(1)); 126*3f982cf4SFabien Sanglard return Duration(ToNearestRepresentativeValue<typename Duration::rep>( 127*3f982cf4SFabien Sanglard static_cast<double>(value_) / rtp_timebase * kOneSecond.count())); 128*3f982cf4SFabien Sanglard } 129*3f982cf4SFabien Sanglard 130*3f982cf4SFabien Sanglard // Maps the |duration| to an approximate RtpTimeDelta using the given RTP 131*3f982cf4SFabien Sanglard // timebase. Assumes a zero-valued Duration corresponds to a zero-valued 132*3f982cf4SFabien Sanglard // RtpTimeDelta. 133*3f982cf4SFabien Sanglard template <typename Duration> FromDuration(Duration duration,int rtp_timebase)134*3f982cf4SFabien Sanglard static constexpr RtpTimeDelta FromDuration(Duration duration, 135*3f982cf4SFabien Sanglard int rtp_timebase) { 136*3f982cf4SFabien Sanglard constexpr Duration kOneSecond = 137*3f982cf4SFabien Sanglard std::chrono::duration_cast<Duration>(std::chrono::seconds(1)); 138*3f982cf4SFabien Sanglard static_assert(kOneSecond > Duration::zero(), 139*3f982cf4SFabien Sanglard "Duration is too coarse-grained to represent one second."); 140*3f982cf4SFabien Sanglard return RtpTimeDelta(ToNearestRepresentativeValue<int64_t>( 141*3f982cf4SFabien Sanglard static_cast<double>(duration.count()) / kOneSecond.count() * 142*3f982cf4SFabien Sanglard rtp_timebase)); 143*3f982cf4SFabien Sanglard } 144*3f982cf4SFabien Sanglard 145*3f982cf4SFabien Sanglard // Construct a RtpTimeDelta from an exact number of ticks. FromTicks(int64_t ticks)146*3f982cf4SFabien Sanglard static constexpr RtpTimeDelta FromTicks(int64_t ticks) { 147*3f982cf4SFabien Sanglard return RtpTimeDelta(ticks); 148*3f982cf4SFabien Sanglard } 149*3f982cf4SFabien Sanglard 150*3f982cf4SFabien Sanglard private: 151*3f982cf4SFabien Sanglard friend class ExpandedValueBase<int64_t, RtpTimeDelta>; 152*3f982cf4SFabien Sanglard friend class RtpTimeTicks; 153*3f982cf4SFabien Sanglard friend std::ostream& operator<<(std::ostream& out, const RtpTimeDelta rhs); 154*3f982cf4SFabien Sanglard RtpTimeDelta(int64_t ticks)155*3f982cf4SFabien Sanglard constexpr explicit RtpTimeDelta(int64_t ticks) : ExpandedValueBase(ticks) {} 156*3f982cf4SFabien Sanglard value()157*3f982cf4SFabien Sanglard constexpr int64_t value() const { return value_; } 158*3f982cf4SFabien Sanglard 159*3f982cf4SFabien Sanglard template <typename Rep> 160*3f982cf4SFabien Sanglard static std::enable_if_t<std::is_floating_point<Rep>::value, Rep> ToNearestRepresentativeValue(double ticks)161*3f982cf4SFabien Sanglard ToNearestRepresentativeValue(double ticks) { 162*3f982cf4SFabien Sanglard return Rep(ticks); 163*3f982cf4SFabien Sanglard } 164*3f982cf4SFabien Sanglard 165*3f982cf4SFabien Sanglard template <typename Rep> 166*3f982cf4SFabien Sanglard static std::enable_if_t<std::is_integral<Rep>::value, Rep> ToNearestRepresentativeValue(double ticks)167*3f982cf4SFabien Sanglard ToNearestRepresentativeValue(double ticks) { 168*3f982cf4SFabien Sanglard return rounded_saturate_cast<Rep>(ticks); 169*3f982cf4SFabien Sanglard } 170*3f982cf4SFabien Sanglard }; 171*3f982cf4SFabien Sanglard 172*3f982cf4SFabien Sanglard // A media timestamp whose timebase matches the periodicity of the content 173*3f982cf4SFabien Sanglard // (e.g., for audio, the timebase would be the sampling frequency). This data 174*3f982cf4SFabien Sanglard // type is modeled off of Chromium's base::TimeTicks. 175*3f982cf4SFabien Sanglard // 176*3f982cf4SFabien Sanglard // This data type wraps a value, providing only the meaningful set of math 177*3f982cf4SFabien Sanglard // operations that may be performed on the value. The difference between two 178*3f982cf4SFabien Sanglard // RtpTimeTicks is a RtpTimeDelta. Likewise, adding or subtracting a 179*3f982cf4SFabien Sanglard // RtpTimeTicks with a RtpTimeDelta produces an off-set RtpTimeTicks. 180*3f982cf4SFabien Sanglard // 181*3f982cf4SFabien Sanglard // The base class provides bit truncation/extension features for 182*3f982cf4SFabien Sanglard // wire-formatting, and also the comparison operators. 183*3f982cf4SFabien Sanglard // 184*3f982cf4SFabien Sanglard // Usage example: 185*3f982cf4SFabien Sanglard // 186*3f982cf4SFabien Sanglard // // Time math. 187*3f982cf4SFabien Sanglard // RtpTimeTicks origin; 188*3f982cf4SFabien Sanglard // RtpTimeTicks at_one_second = 189*3f982cf4SFabien Sanglard // origin + RtpTimeDelta::FromTicks(kAudioSamplingRate); 190*3f982cf4SFabien Sanglard // RtpTimeTicks at_two_seconds = 191*3f982cf4SFabien Sanglard // at_one_second + RtpTimeDelta::FromTicks(kAudioSamplingRate); 192*3f982cf4SFabien Sanglard // RtpTimeDelta elasped_in_between = at_two_seconds - at_one_second; 193*3f982cf4SFabien Sanglard // RtpTimeDelta thrice_as_much_elasped = elasped_in_between * 3; 194*3f982cf4SFabien Sanglard // RtpTimeTicks at_four_seconds = at_one_second + thrice_as_much_elasped; 195*3f982cf4SFabien Sanglard // 196*3f982cf4SFabien Sanglard // // Logging convenience. 197*3f982cf4SFabien Sanglard // OSP_DLOG_INFO << "The RTP timestamp is " << at_four_seconds; 198*3f982cf4SFabien Sanglard // 199*3f982cf4SFabien Sanglard // // Convert (approximately!) between RTP timebase and stream time offsets in 200*3f982cf4SFabien Sanglard // // microsecond timebase: 201*3f982cf4SFabien Sanglard // using std::chrono::microseconds; 202*3f982cf4SFabien Sanglard // microseconds four_seconds_since_stream_start = 203*3f982cf4SFabien Sanglard // at_four_seconds.ToTimeSinceOrigin<microseconds>(kAudioSamplingRate); 204*3f982cf4SFabien Sanglard // RtpTimeTicks at_three_seconds = RtpTimeDelta::FromTimeSinceOrigin( 205*3f982cf4SFabien Sanglard // std::chrono::seconds(3), kAudioSamplingRate); 206*3f982cf4SFabien Sanglard class RtpTimeTicks : public ExpandedValueBase<int64_t, RtpTimeTicks> { 207*3f982cf4SFabien Sanglard public: RtpTimeTicks()208*3f982cf4SFabien Sanglard constexpr RtpTimeTicks() : ExpandedValueBase(0) {} 209*3f982cf4SFabien Sanglard 210*3f982cf4SFabien Sanglard // Compute the difference between two RtpTimeTickses. 211*3f982cf4SFabien Sanglard constexpr RtpTimeDelta operator-(RtpTimeTicks rhs) const { 212*3f982cf4SFabien Sanglard return RtpTimeDelta(value_ - rhs.value_); 213*3f982cf4SFabien Sanglard } 214*3f982cf4SFabien Sanglard 215*3f982cf4SFabien Sanglard // Return a new RtpTimeTicks before or after this one. 216*3f982cf4SFabien Sanglard constexpr RtpTimeTicks operator+(RtpTimeDelta rhs) const { 217*3f982cf4SFabien Sanglard return RtpTimeTicks(value_ + rhs.value()); 218*3f982cf4SFabien Sanglard } 219*3f982cf4SFabien Sanglard constexpr RtpTimeTicks operator-(RtpTimeDelta rhs) const { 220*3f982cf4SFabien Sanglard return RtpTimeTicks(value_ - rhs.value()); 221*3f982cf4SFabien Sanglard } 222*3f982cf4SFabien Sanglard constexpr RtpTimeTicks& operator+=(RtpTimeDelta rhs) { 223*3f982cf4SFabien Sanglard return (*this = (*this + rhs)); 224*3f982cf4SFabien Sanglard } 225*3f982cf4SFabien Sanglard constexpr RtpTimeTicks& operator-=(RtpTimeDelta rhs) { 226*3f982cf4SFabien Sanglard return (*this = (*this - rhs)); 227*3f982cf4SFabien Sanglard } 228*3f982cf4SFabien Sanglard 229*3f982cf4SFabien Sanglard // Maps this RtpTimeTicks to an approximate std::chrono::duration representing 230*3f982cf4SFabien Sanglard // the amount of time since the origin point (e.g., the start of a stream) 231*3f982cf4SFabien Sanglard // using the given |rtp_timebase|. Assumes a zero-valued Duration corresponds 232*3f982cf4SFabien Sanglard // to a zero-valued RtpTimeTicks. 233*3f982cf4SFabien Sanglard template <typename Duration> ToTimeSinceOrigin(int rtp_timebase)234*3f982cf4SFabien Sanglard Duration ToTimeSinceOrigin(int rtp_timebase) const { 235*3f982cf4SFabien Sanglard return (*this - RtpTimeTicks()).ToDuration<Duration>(rtp_timebase); 236*3f982cf4SFabien Sanglard } 237*3f982cf4SFabien Sanglard 238*3f982cf4SFabien Sanglard // Maps the |time_since_origin| to an approximate RtpTimeTicks using the given 239*3f982cf4SFabien Sanglard // RTP timebase. Assumes a zero-valued Duration corresponds to a zero-valued 240*3f982cf4SFabien Sanglard // RtpTimeTicks. 241*3f982cf4SFabien Sanglard template <typename Duration> FromTimeSinceOrigin(Duration time_since_origin,int rtp_timebase)242*3f982cf4SFabien Sanglard static constexpr RtpTimeTicks FromTimeSinceOrigin(Duration time_since_origin, 243*3f982cf4SFabien Sanglard int rtp_timebase) { 244*3f982cf4SFabien Sanglard return RtpTimeTicks() + 245*3f982cf4SFabien Sanglard RtpTimeDelta::FromDuration(time_since_origin, rtp_timebase); 246*3f982cf4SFabien Sanglard } 247*3f982cf4SFabien Sanglard 248*3f982cf4SFabien Sanglard private: 249*3f982cf4SFabien Sanglard friend class ExpandedValueBase<int64_t, RtpTimeTicks>; 250*3f982cf4SFabien Sanglard friend std::ostream& operator<<(std::ostream& out, const RtpTimeTicks rhs); 251*3f982cf4SFabien Sanglard RtpTimeTicks(int64_t value)252*3f982cf4SFabien Sanglard constexpr explicit RtpTimeTicks(int64_t value) : ExpandedValueBase(value) {} 253*3f982cf4SFabien Sanglard value()254*3f982cf4SFabien Sanglard constexpr int64_t value() const { return value_; } 255*3f982cf4SFabien Sanglard }; 256*3f982cf4SFabien Sanglard 257*3f982cf4SFabien Sanglard } // namespace cast 258*3f982cf4SFabien Sanglard } // namespace openscreen 259*3f982cf4SFabien Sanglard 260*3f982cf4SFabien Sanglard #endif // CAST_STREAMING_RTP_TIME_H_ 261