Add conversions to and from double for units.

Bug: webrtc:8415
Change-Id: I6b1f7afb163daa327e45c51f1a3fb7cafbb1444e
Reviewed-on: https://webrtc-review.googlesource.com/78183
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23451}
diff --git a/api/units/data_rate.h b/api/units/data_rate.h
index 067b200..c7164e3 100644
--- a/api/units/data_rate.h
+++ b/api/units/data_rate.h
@@ -16,6 +16,7 @@
 #include <string>
 
 #include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
 
 #include "api/units/data_size.h"
 #include "api/units/time_delta.h"
@@ -43,28 +44,78 @@
   static DataRate Infinity() {
     return DataRate(data_rate_impl::kPlusInfinityVal);
   }
-  static DataRate bits_per_second(int64_t bits_per_sec) {
-    RTC_DCHECK_GE(bits_per_sec, 0);
-    return DataRate(bits_per_sec);
+
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static DataRate bps(T bits_per_second) {
+    RTC_DCHECK_GE(bits_per_second, 0);
+    RTC_DCHECK_LT(bits_per_second, data_rate_impl::kPlusInfinityVal);
+    return DataRate(rtc::dchecked_cast<int64_t>(bits_per_second));
   }
-  static DataRate bps(int64_t bits_per_sec) {
-    return DataRate::bits_per_second(bits_per_sec);
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static DataRate kbps(T kilobits_per_sec) {
+    RTC_DCHECK_GE(kilobits_per_sec, 0);
+    RTC_DCHECK_LT(kilobits_per_sec, data_rate_impl::kPlusInfinityVal / 1000);
+    return DataRate::bps(rtc::dchecked_cast<int64_t>(kilobits_per_sec) * 1000);
   }
-  static DataRate kbps(int64_t kilobits_per_sec) {
-    return DataRate::bits_per_second(kilobits_per_sec * 1000);
+
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static DataRate bps(T bits_per_second) {
+    if (bits_per_second == std::numeric_limits<T>::infinity()) {
+      return Infinity();
+    } else {
+      RTC_DCHECK(!std::isnan(bits_per_second));
+      RTC_DCHECK_GE(bits_per_second, 0);
+      RTC_DCHECK_LT(bits_per_second, data_rate_impl::kPlusInfinityVal);
+      return DataRate(rtc::dchecked_cast<int64_t>(bits_per_second));
+    }
   }
-  int64_t bits_per_second() const {
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static DataRate kbps(T kilobits_per_sec) {
+    return DataRate::bps(kilobits_per_sec * 1e3);
+  }
+
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type bps() const {
     RTC_DCHECK(IsFinite());
-    return bits_per_sec_;
+    return rtc::dchecked_cast<T>(bits_per_sec_);
   }
-  int64_t bps() const { return bits_per_second(); }
-  int64_t kbps() const { return (bps() + 500) / 1000; }
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type kbps() const {
+    return rtc::dchecked_cast<T>((bps() + 500) / 1000);
+  }
+
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type bps()
+      const {
+    if (IsInfinite()) {
+      return std::numeric_limits<T>::infinity();
+    } else {
+      return bits_per_sec_;
+    }
+  }
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type kbps()
+      const {
+    return bps<T>() * 1e-3;
+  }
+
   bool IsZero() const { return bits_per_sec_ == 0; }
   bool IsInfinite() const {
     return bits_per_sec_ == data_rate_impl::kPlusInfinityVal;
   }
   bool IsFinite() const { return !IsInfinite(); }
 
+  double operator/(const DataRate& other) const {
+    return bps<double>() / other.bps<double>();
+  }
   bool operator==(const DataRate& other) const {
     return bits_per_sec_ == other.bits_per_sec_;
   }
@@ -92,34 +143,32 @@
 };
 
 inline DataRate operator*(const DataRate& rate, const double& scalar) {
-  return DataRate::bits_per_second(std::round(rate.bits_per_second() * scalar));
+  return DataRate::bps(std::round(rate.bps() * scalar));
 }
 inline DataRate operator*(const double& scalar, const DataRate& rate) {
   return rate * scalar;
 }
 inline DataRate operator*(const DataRate& rate, const int64_t& scalar) {
-  return DataRate::bits_per_second(rate.bits_per_second() * scalar);
+  return DataRate::bps(rate.bps() * scalar);
 }
 inline DataRate operator*(const int64_t& scalar, const DataRate& rate) {
   return rate * scalar;
 }
 inline DataRate operator*(const DataRate& rate, const int32_t& scalar) {
-  return DataRate::bits_per_second(rate.bits_per_second() * scalar);
+  return DataRate::bps(rate.bps() * scalar);
 }
 inline DataRate operator*(const int32_t& scalar, const DataRate& rate) {
   return rate * scalar;
 }
 
 inline DataRate operator/(const DataSize& size, const TimeDelta& duration) {
-  return DataRate::bits_per_second(data_rate_impl::Microbits(size) /
-                                   duration.us());
+  return DataRate::bps(data_rate_impl::Microbits(size) / duration.us());
 }
 inline TimeDelta operator/(const DataSize& size, const DataRate& rate) {
-  return TimeDelta::us(data_rate_impl::Microbits(size) /
-                       rate.bits_per_second());
+  return TimeDelta::us(data_rate_impl::Microbits(size) / rate.bps());
 }
 inline DataSize operator*(const DataRate& rate, const TimeDelta& duration) {
-  int64_t microbits = rate.bits_per_second() * duration.us();
+  int64_t microbits = rate.bps() * duration.us();
   return DataSize::bytes((microbits + 4000000) / 8000000);
 }
 inline DataSize operator*(const TimeDelta& duration, const DataRate& rate) {
diff --git a/api/units/data_rate_unittest.cc b/api/units/data_rate_unittest.cc
index d4dd192..9a58b47 100644
--- a/api/units/data_rate_unittest.cc
+++ b/api/units/data_rate_unittest.cc
@@ -15,7 +15,6 @@
 namespace test {
 TEST(DataRateTest, GetBackSameValues) {
   const int64_t kValue = 123 * 8;
-  EXPECT_EQ(DataRate::bits_per_second(kValue).bits_per_second(), kValue);
   EXPECT_EQ(DataRate::bps(kValue).bps(), kValue);
   EXPECT_EQ(DataRate::kbps(kValue).kbps(), kValue);
 }
@@ -28,22 +27,22 @@
 TEST(DataRateTest, IdentityChecks) {
   const int64_t kValue = 3000;
   EXPECT_TRUE(DataRate::Zero().IsZero());
-  EXPECT_FALSE(DataRate::bits_per_second(kValue).IsZero());
+  EXPECT_FALSE(DataRate::bps(kValue).IsZero());
 
   EXPECT_TRUE(DataRate::Infinity().IsInfinite());
   EXPECT_FALSE(DataRate::Zero().IsInfinite());
-  EXPECT_FALSE(DataRate::bits_per_second(kValue).IsInfinite());
+  EXPECT_FALSE(DataRate::bps(kValue).IsInfinite());
 
   EXPECT_FALSE(DataRate::Infinity().IsFinite());
-  EXPECT_TRUE(DataRate::bits_per_second(kValue).IsFinite());
+  EXPECT_TRUE(DataRate::bps(kValue).IsFinite());
   EXPECT_TRUE(DataRate::Zero().IsFinite());
 }
 
 TEST(DataRateTest, ComparisonOperators) {
   const int64_t kSmall = 450;
   const int64_t kLarge = 451;
-  const DataRate small = DataRate::bits_per_second(kSmall);
-  const DataRate large = DataRate::bits_per_second(kLarge);
+  const DataRate small = DataRate::bps(kSmall);
+  const DataRate large = DataRate::bps(kLarge);
 
   EXPECT_EQ(DataRate::Zero(), DataRate::bps(0));
   EXPECT_EQ(DataRate::Infinity(), DataRate::Infinity());
@@ -59,15 +58,36 @@
   EXPECT_GT(DataRate::Infinity(), large);
 }
 
+TEST(DataRateTest, ConvertsToAndFromDouble) {
+  const int64_t kValue = 128;
+  const double kDoubleValue = static_cast<double>(kValue);
+  const double kDoubleKbps = kValue * 1e-3;
+  const double kFloatKbps = static_cast<float>(kDoubleKbps);
+
+  EXPECT_EQ(DataRate::bps(kValue).bps<double>(), kDoubleValue);
+  EXPECT_EQ(DataRate::bps(kValue).kbps<double>(), kDoubleKbps);
+  EXPECT_EQ(DataRate::bps(kValue).kbps<float>(), kFloatKbps);
+  EXPECT_EQ(DataRate::bps(kDoubleValue).bps(), kValue);
+  EXPECT_EQ(DataRate::kbps(kDoubleKbps).bps(), kValue);
+
+  const double kInfinity = std::numeric_limits<double>::infinity();
+  EXPECT_EQ(DataRate::Infinity().bps<double>(), kInfinity);
+  EXPECT_TRUE(DataRate::bps(kInfinity).IsInfinite());
+  EXPECT_TRUE(DataRate::kbps(kInfinity).IsInfinite());
+}
+
 TEST(DataRateTest, MathOperations) {
   const int64_t kValueA = 450;
   const int64_t kValueB = 267;
-  const DataRate size_a = DataRate::bits_per_second(kValueA);
+  const DataRate rate_a = DataRate::bps(kValueA);
+  const DataRate rate_b = DataRate::bps(kValueB);
   const int32_t kInt32Value = 123;
   const double kFloatValue = 123.0;
-  EXPECT_EQ((size_a * kValueB).bits_per_second(), kValueA * kValueB);
-  EXPECT_EQ((size_a * kInt32Value).bits_per_second(), kValueA * kInt32Value);
-  EXPECT_EQ((size_a * kFloatValue).bits_per_second(), kValueA * kFloatValue);
+  EXPECT_EQ((rate_a * kValueB).bps(), kValueA * kValueB);
+  EXPECT_EQ((rate_a * kInt32Value).bps(), kValueA * kInt32Value);
+  EXPECT_EQ((rate_a * kFloatValue).bps(), kValueA * kFloatValue);
+
+  EXPECT_EQ(rate_a / rate_b, static_cast<double>(kValueA) / kValueB);
 }
 
 TEST(UnitConversionTest, DataRateAndDataSizeAndTimeDelta) {
@@ -75,11 +95,11 @@
   const int64_t kBitsPerSecond = 440;
   const int64_t kBytes = 44000;
   const TimeDelta delta_a = TimeDelta::seconds(kSeconds);
-  const DataRate rate_b = DataRate::bits_per_second(kBitsPerSecond);
+  const DataRate rate_b = DataRate::bps(kBitsPerSecond);
   const DataSize size_c = DataSize::bytes(kBytes);
   EXPECT_EQ((delta_a * rate_b).bytes(), kSeconds * kBitsPerSecond / 8);
   EXPECT_EQ((rate_b * delta_a).bytes(), kSeconds * kBitsPerSecond / 8);
-  EXPECT_EQ((size_c / delta_a).bits_per_second(), kBytes * 8 / kSeconds);
+  EXPECT_EQ((size_c / delta_a).bps(), kBytes * 8 / kSeconds);
   EXPECT_EQ((size_c / rate_b).seconds(), kBytes * 8 / kBitsPerSecond);
 }
 
diff --git a/api/units/data_size.h b/api/units/data_size.h
index 74ab19e..8c35766 100644
--- a/api/units/data_size.h
+++ b/api/units/data_size.h
@@ -15,8 +15,10 @@
 #include <cmath>
 #include <limits>
 #include <string>
+#include <type_traits>
 
 #include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
 
 namespace webrtc {
 namespace data_size_impl {
@@ -31,15 +33,46 @@
   static DataSize Infinity() {
     return DataSize(data_size_impl::kPlusInfinityVal);
   }
-  static DataSize bytes(int64_t bytes) {
+
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static DataSize bytes(T bytes) {
     RTC_DCHECK_GE(bytes, 0);
-    return DataSize(bytes);
+    RTC_DCHECK_LT(bytes, data_size_impl::kPlusInfinityVal);
+    return DataSize(rtc::dchecked_cast<int64_t>(bytes));
   }
-  int64_t bytes() const {
+
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static DataSize bytes(T bytes) {
+    if (bytes == std::numeric_limits<T>::infinity()) {
+      return Infinity();
+    } else {
+      RTC_DCHECK(!std::isnan(bytes));
+      RTC_DCHECK_GE(bytes, 0);
+      RTC_DCHECK_LT(bytes, data_size_impl::kPlusInfinityVal);
+      return DataSize(rtc::dchecked_cast<int64_t>(bytes));
+    }
+  }
+
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type bytes() const {
     RTC_DCHECK(IsFinite());
-    return bytes_;
+    return rtc::dchecked_cast<T>(bytes_);
   }
-  int64_t kilobytes() const { return (bytes() + 500) / 1000; }
+
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type bytes()
+      const {
+    if (IsInfinite()) {
+      return std::numeric_limits<T>::infinity();
+    } else {
+      return bytes_;
+    }
+  }
+
   bool IsZero() const { return bytes_ == 0; }
   bool IsInfinite() const { return bytes_ == data_size_impl::kPlusInfinityVal; }
   bool IsFinite() const { return !IsInfinite(); }
@@ -57,6 +90,9 @@
     bytes_ += other.bytes();
     return *this;
   }
+  double operator/(const DataSize& other) const {
+    return bytes<double>() / other.bytes<double>();
+  }
   bool operator==(const DataSize& other) const {
     return bytes_ == other.bytes_;
   }
@@ -76,6 +112,7 @@
   explicit DataSize(int64_t bytes) : bytes_(bytes) {}
   int64_t bytes_;
 };
+
 inline DataSize operator*(const DataSize& size, const double& scalar) {
   return DataSize::bytes(std::round(size.bytes() * scalar));
 }
diff --git a/api/units/data_size_unittest.cc b/api/units/data_size_unittest.cc
index 35cff01..7747258 100644
--- a/api/units/data_size_unittest.cc
+++ b/api/units/data_size_unittest.cc
@@ -19,11 +19,6 @@
   EXPECT_EQ(DataSize::bytes(kValue).bytes(), kValue);
 }
 
-TEST(DataSizeTest, GetDifferentPrefix) {
-  const int64_t kValue = 123 * 8000;
-  EXPECT_EQ(DataSize::bytes(kValue).kilobytes(), kValue / 1000);
-}
-
 TEST(DataSizeTest, IdentityChecks) {
   const int64_t kValue = 3000;
   EXPECT_TRUE(DataSize::Zero().IsZero());
@@ -58,6 +53,18 @@
   EXPECT_GT(DataSize::Infinity(), large);
 }
 
+TEST(DataSizeTest, ConvertsToAndFromDouble) {
+  const int64_t kValue = 128;
+  const double kDoubleValue = static_cast<double>(kValue);
+
+  EXPECT_EQ(DataSize::bytes(kValue).bytes<double>(), kDoubleValue);
+  EXPECT_EQ(DataSize::bytes(kDoubleValue).bytes(), kValue);
+
+  const double kInfinity = std::numeric_limits<double>::infinity();
+  EXPECT_EQ(DataSize::Infinity().bytes<double>(), kInfinity);
+  EXPECT_TRUE(DataSize::bytes(kInfinity).IsInfinite());
+}
+
 TEST(DataSizeTest, MathOperations) {
   const int64_t kValueA = 450;
   const int64_t kValueB = 267;
@@ -73,6 +80,7 @@
   EXPECT_EQ((size_a * kFloatValue).bytes(), kValueA * kFloatValue);
 
   EXPECT_EQ((size_a / 10).bytes(), kValueA / 10);
+  EXPECT_EQ(size_a / size_b, static_cast<double>(kValueA) / kValueB);
 
   DataSize mutable_size = DataSize::bytes(kValueA);
   mutable_size += size_b;
diff --git a/api/units/time_delta.h b/api/units/time_delta.h
index 2491920..0f99e80 100644
--- a/api/units/time_delta.h
+++ b/api/units/time_delta.h
@@ -17,6 +17,7 @@
 #include <string>
 
 #include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
 
 namespace webrtc {
 namespace timedelta_impl {
@@ -41,33 +42,107 @@
   static TimeDelta MinusInfinity() {
     return TimeDelta(timedelta_impl::kMinusInfinityVal);
   }
-  static TimeDelta seconds(int64_t seconds) {
-    return TimeDelta::us(seconds * 1000000);
+
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static TimeDelta seconds(T seconds) {
+    RTC_DCHECK_GT(seconds, timedelta_impl::kMinusInfinityVal / 1000000);
+    RTC_DCHECK_LT(seconds, timedelta_impl::kPlusInfinityVal / 1000000);
+    return TimeDelta(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
   }
-  static TimeDelta ms(int64_t milliseconds) {
-    return TimeDelta::us(milliseconds * 1000);
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static TimeDelta ms(T milliseconds) {
+    RTC_DCHECK_GT(milliseconds, timedelta_impl::kMinusInfinityVal / 1000);
+    RTC_DCHECK_LT(milliseconds, timedelta_impl::kPlusInfinityVal / 1000);
+    return TimeDelta(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
   }
-  static TimeDelta us(int64_t microseconds) {
-    // Infinities only allowed via use of explicit constants.
-    RTC_DCHECK(microseconds > std::numeric_limits<int64_t>::min());
-    RTC_DCHECK(microseconds < std::numeric_limits<int64_t>::max());
-    return TimeDelta(microseconds);
-  }
-  int64_t seconds() const {
-    return (us() + (us() >= 0 ? 500000 : -500000)) / 1000000;
-  }
-  int64_t ms() const { return (us() + (us() >= 0 ? 500 : -500)) / 1000; }
-  int64_t us() const {
-    RTC_DCHECK(IsFinite());
-    return microseconds_;
-  }
-  int64_t ns() const {
-    RTC_DCHECK(us() > std::numeric_limits<int64_t>::min() / 1000);
-    RTC_DCHECK(us() < std::numeric_limits<int64_t>::max() / 1000);
-    return us() * 1000;
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static TimeDelta us(T microseconds) {
+    RTC_DCHECK_GT(microseconds, timedelta_impl::kMinusInfinityVal);
+    RTC_DCHECK_LT(microseconds, timedelta_impl::kPlusInfinityVal);
+    return TimeDelta(rtc::dchecked_cast<int64_t>(microseconds));
   }
 
-  double SecondsAsDouble() const;
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static TimeDelta seconds(T seconds) {
+    return TimeDelta::us(seconds * 1e6);
+  }
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static TimeDelta ms(T milliseconds) {
+    return TimeDelta::us(milliseconds * 1e3);
+  }
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static TimeDelta us(T microseconds) {
+    if (microseconds == std::numeric_limits<T>::infinity()) {
+      return PlusInfinity();
+    } else if (microseconds == -std::numeric_limits<T>::infinity()) {
+      return MinusInfinity();
+    } else {
+      RTC_DCHECK(!std::isnan(microseconds));
+      RTC_DCHECK_GT(microseconds, timedelta_impl::kMinusInfinityVal);
+      RTC_DCHECK_LT(microseconds, timedelta_impl::kPlusInfinityVal);
+      return TimeDelta(rtc::dchecked_cast<int64_t>(microseconds));
+    }
+  }
+
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
+    return rtc::dchecked_cast<T>((us() + (us() >= 0 ? 500000 : -500000)) /
+                                 1000000);
+  }
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type ms() const {
+    return rtc::dchecked_cast<T>((us() + (us() >= 0 ? 500 : -500)) / 1000);
+  }
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
+    RTC_DCHECK(IsFinite());
+    return rtc::dchecked_cast<T>(microseconds_);
+  }
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type ns() const {
+    RTC_DCHECK_GE(us(), std::numeric_limits<T>::min() / 1000);
+    RTC_DCHECK_LE(us(), std::numeric_limits<T>::max() / 1000);
+    return rtc::dchecked_cast<T>(us() * 1000);
+  }
+
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type seconds()
+      const {
+    return us<T>() * 1e-6;
+  }
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type ms()
+      const {
+    return us<T>() * 1e-3;
+  }
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type us()
+      const {
+    if (IsPlusInfinity()) {
+      return std::numeric_limits<T>::infinity();
+    } else if (IsMinusInfinity()) {
+      return -std::numeric_limits<T>::infinity();
+    } else {
+      return microseconds_;
+    }
+  }
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type ns()
+      const {
+    return us<T>() * 1e3;
+  }
 
   TimeDelta Abs() const { return TimeDelta::us(std::abs(us())); }
   bool IsZero() const { return microseconds_ == 0; }
@@ -96,7 +171,9 @@
     microseconds_ += other.us();
     return *this;
   }
-
+  double operator/(const TimeDelta& other) const {
+    return us<double>() / other.us<double>();
+  }
   bool operator==(const TimeDelta& other) const {
     return microseconds_ == other.microseconds_;
   }
diff --git a/api/units/time_delta_unittest.cc b/api/units/time_delta_unittest.cc
index 493c6bf..94a27f2 100644
--- a/api/units/time_delta_unittest.cc
+++ b/api/units/time_delta_unittest.cc
@@ -80,6 +80,51 @@
   EXPECT_LT(TimeDelta::MinusInfinity(), TimeDelta::Zero());
 }
 
+TEST(TimeDeltaTest, CanBeInititializedFromLargeInt) {
+  const int kMaxInt = std::numeric_limits<int>::max();
+  EXPECT_EQ(TimeDelta::seconds(kMaxInt).us(),
+            static_cast<int64_t>(kMaxInt) * 1000000);
+  EXPECT_EQ(TimeDelta::ms(kMaxInt).us(), static_cast<int64_t>(kMaxInt) * 1000);
+}
+
+TEST(TimeDeltaTest, ConvertsToAndFromDouble) {
+  const int64_t kMicros = 17017;
+  const double kNanosDouble = kMicros * 1e3;
+  const double kMicrosDouble = kMicros;
+  const double kMillisDouble = kMicros * 1e-3;
+  const double kSecondsDouble = kMillisDouble * 1e-3;
+
+  EXPECT_EQ(TimeDelta::us(kMicros).seconds<double>(), kSecondsDouble);
+  EXPECT_EQ(TimeDelta::seconds(kSecondsDouble).us(), kMicros);
+
+  EXPECT_EQ(TimeDelta::us(kMicros).ms<double>(), kMillisDouble);
+  EXPECT_EQ(TimeDelta::ms(kMillisDouble).us(), kMicros);
+
+  EXPECT_EQ(TimeDelta::us(kMicros).us<double>(), kMicrosDouble);
+  EXPECT_EQ(TimeDelta::us(kMicrosDouble).us(), kMicros);
+
+  EXPECT_NEAR(TimeDelta::us(kMicros).ns<double>(), kNanosDouble, 1);
+
+  const double kPlusInfinity = std::numeric_limits<double>::infinity();
+  const double kMinusInfinity = -kPlusInfinity;
+
+  EXPECT_EQ(TimeDelta::PlusInfinity().seconds<double>(), kPlusInfinity);
+  EXPECT_EQ(TimeDelta::MinusInfinity().seconds<double>(), kMinusInfinity);
+  EXPECT_EQ(TimeDelta::PlusInfinity().ms<double>(), kPlusInfinity);
+  EXPECT_EQ(TimeDelta::MinusInfinity().ms<double>(), kMinusInfinity);
+  EXPECT_EQ(TimeDelta::PlusInfinity().us<double>(), kPlusInfinity);
+  EXPECT_EQ(TimeDelta::MinusInfinity().us<double>(), kMinusInfinity);
+  EXPECT_EQ(TimeDelta::PlusInfinity().ns<double>(), kPlusInfinity);
+  EXPECT_EQ(TimeDelta::MinusInfinity().ns<double>(), kMinusInfinity);
+
+  EXPECT_TRUE(TimeDelta::seconds(kPlusInfinity).IsPlusInfinity());
+  EXPECT_TRUE(TimeDelta::seconds(kMinusInfinity).IsMinusInfinity());
+  EXPECT_TRUE(TimeDelta::ms(kPlusInfinity).IsPlusInfinity());
+  EXPECT_TRUE(TimeDelta::ms(kMinusInfinity).IsMinusInfinity());
+  EXPECT_TRUE(TimeDelta::us(kPlusInfinity).IsPlusInfinity());
+  EXPECT_TRUE(TimeDelta::us(kMinusInfinity).IsMinusInfinity());
+}
+
 TEST(TimeDeltaTest, MathOperations) {
   const int64_t kValueA = 267;
   const int64_t kValueB = 450;
@@ -94,6 +139,9 @@
   EXPECT_EQ((TimeDelta::us(kValueA) * kInt32Value).us(), kValueA * kInt32Value);
   EXPECT_EQ((TimeDelta::us(kValueA) * kFloatValue).us(), kValueA * kFloatValue);
 
+  EXPECT_EQ((delta_b / 10).ms(), kValueB / 10);
+  EXPECT_EQ(delta_b / delta_a, static_cast<double>(kValueB) / kValueA);
+
   EXPECT_EQ(TimeDelta::us(-kValueA).Abs().us(), kValueA);
   EXPECT_EQ(TimeDelta::us(kValueA).Abs().us(), kValueA);
 }
diff --git a/api/units/timestamp.cc b/api/units/timestamp.cc
index 7ae084c..4b2c44b 100644
--- a/api/units/timestamp.cc
+++ b/api/units/timestamp.cc
@@ -13,14 +13,6 @@
 #include "rtc_base/strings/string_builder.h"
 
 namespace webrtc {
-double Timestamp::SecondsAsDouble() const {
-  if (IsInfinite()) {
-    return std::numeric_limits<double>::infinity();
-  } else {
-    return us() * 1e-6;
-  }
-}
-
 std::string ToString(const Timestamp& value) {
   char buf[64];
   rtc::SimpleStringBuilder sb(buf);
diff --git a/api/units/timestamp.h b/api/units/timestamp.h
index 40f3e92..a66e061 100644
--- a/api/units/timestamp.h
+++ b/api/units/timestamp.h
@@ -17,6 +17,7 @@
 
 #include "api/units/time_delta.h"
 #include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
 
 namespace webrtc {
 namespace timestamp_impl {
@@ -34,22 +35,94 @@
   static Timestamp Infinity() {
     return Timestamp(timestamp_impl::kPlusInfinityVal);
   }
-  static Timestamp seconds(int64_t seconds) {
-    return Timestamp::us(seconds * 1000000);
-  }
-  static Timestamp ms(int64_t millis) { return Timestamp::us(millis * 1000); }
-  static Timestamp us(int64_t micros) {
-    RTC_DCHECK_GE(micros, 0);
-    return Timestamp(micros);
-  }
-  int64_t seconds() const { return (us() + 500000) / 1000000; }
-  int64_t ms() const { return (us() + 500) / 1000; }
-  int64_t us() const {
-    RTC_DCHECK(IsFinite());
-    return microseconds_;
+
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static Timestamp seconds(T seconds) {
+    RTC_DCHECK_GE(seconds, 0);
+    RTC_DCHECK_LT(seconds, timestamp_impl::kPlusInfinityVal / 1000000);
+    return Timestamp(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
   }
 
-  double SecondsAsDouble() const;
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static Timestamp ms(T milliseconds) {
+    RTC_DCHECK_GE(milliseconds, 0);
+    RTC_DCHECK_LT(milliseconds, timestamp_impl::kPlusInfinityVal / 1000);
+    return Timestamp(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
+  }
+
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static Timestamp us(T microseconds) {
+    RTC_DCHECK_GE(microseconds, 0);
+    RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
+    return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
+  }
+
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static Timestamp seconds(T seconds) {
+    return Timestamp::us(seconds * 1e6);
+  }
+
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static Timestamp ms(T milliseconds) {
+    return Timestamp::us(milliseconds * 1e3);
+  }
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static Timestamp us(T microseconds) {
+    if (microseconds == std::numeric_limits<double>::infinity()) {
+      return Infinity();
+    } else {
+      RTC_DCHECK(!std::isnan(microseconds));
+      RTC_DCHECK_GE(microseconds, 0);
+      RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
+      return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
+    }
+  }
+
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
+    return rtc::dchecked_cast<T>((us() + 500000) / 1000000);
+  }
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type ms() const {
+    return rtc::dchecked_cast<T>((us() + 500) / 1000);
+  }
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
+    RTC_DCHECK(IsFinite());
+    return rtc::dchecked_cast<T>(microseconds_);
+  }
+
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type seconds()
+      const {
+    return us<T>() * 1e-6;
+  }
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type ms()
+      const {
+    return us<T>() * 1e-3;
+  }
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type us()
+      const {
+    if (IsInfinite()) {
+      return std::numeric_limits<T>::infinity();
+    } else {
+      return microseconds_;
+    }
+  }
 
   bool IsInfinite() const {
     return microseconds_ == timestamp_impl::kPlusInfinityVal;
diff --git a/api/units/timestamp_unittest.cc b/api/units/timestamp_unittest.cc
index 3b2770c..eecfe02 100644
--- a/api/units/timestamp_unittest.cc
+++ b/api/units/timestamp_unittest.cc
@@ -58,6 +58,39 @@
   EXPECT_GT(Timestamp::ms(kLarge), Timestamp::ms(kSmall));
 }
 
+TEST(TimestampTest, CanBeInititializedFromLargeInt) {
+  const int kMaxInt = std::numeric_limits<int>::max();
+  EXPECT_EQ(Timestamp::seconds(kMaxInt).us(),
+            static_cast<int64_t>(kMaxInt) * 1000000);
+  EXPECT_EQ(Timestamp::ms(kMaxInt).us(), static_cast<int64_t>(kMaxInt) * 1000);
+}
+
+TEST(TimestampTest, ConvertsToAndFromDouble) {
+  const int64_t kMicros = 17017;
+  const double kMicrosDouble = kMicros;
+  const double kMillisDouble = kMicros * 1e-3;
+  const double kSecondsDouble = kMillisDouble * 1e-3;
+
+  EXPECT_EQ(Timestamp::us(kMicros).seconds<double>(), kSecondsDouble);
+  EXPECT_EQ(Timestamp::seconds(kSecondsDouble).us(), kMicros);
+
+  EXPECT_EQ(Timestamp::us(kMicros).ms<double>(), kMillisDouble);
+  EXPECT_EQ(Timestamp::ms(kMillisDouble).us(), kMicros);
+
+  EXPECT_EQ(Timestamp::us(kMicros).us<double>(), kMicrosDouble);
+  EXPECT_EQ(Timestamp::us(kMicrosDouble).us(), kMicros);
+
+  const double kPlusInfinity = std::numeric_limits<double>::infinity();
+
+  EXPECT_EQ(Timestamp::Infinity().seconds<double>(), kPlusInfinity);
+  EXPECT_EQ(Timestamp::Infinity().ms<double>(), kPlusInfinity);
+  EXPECT_EQ(Timestamp::Infinity().us<double>(), kPlusInfinity);
+
+  EXPECT_TRUE(Timestamp::seconds(kPlusInfinity).IsInfinite());
+  EXPECT_TRUE(Timestamp::ms(kPlusInfinity).IsInfinite());
+  EXPECT_TRUE(Timestamp::us(kPlusInfinity).IsInfinite());
+}
+
 TEST(UnitConversionTest, TimestampAndTimeDeltaMath) {
   const int64_t kValueA = 267;
   const int64_t kValueB = 450;