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