xref: /aosp_15_r20/external/openscreen/cast/streaming/rtp_time.h (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
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