Using unit classes in AimdRateControl.

Bug: webrtc:9718
Change-Id: I1efed4e55c9d1ccec3c32ed012cb3cd82d7f4ee8
Reviewed-on: https://webrtc-review.googlesource.com/c/110788
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25705}
diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe.cc b/modules/congestion_controller/goog_cc/delay_based_bwe.cc
index 60f52a1..7a1ee11 100644
--- a/modules/congestion_controller/goog_cc/delay_based_bwe.cc
+++ b/modules/congestion_controller/goog_cc/delay_based_bwe.cc
@@ -175,12 +175,11 @@
   // Call constructor. An alternative would be to return an empty Result here,
   // or to estimate the throughput based on the feedback we received.
   RTC_DCHECK(rate_control_.ValidEstimate());
-  rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2,
-                            arrival_time.ms());
+  rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2, arrival_time);
   Result result;
   result.updated = true;
   result.probe = false;
-  result.target_bitrate = DataRate::bps(rate_control_.LatestEstimate());
+  result.target_bitrate = rate_control_.LatestEstimate();
   RTC_LOG(LS_WARNING) << "Long feedback delay detected, reducing BWE to "
                       << ToString(result.target_bitrate);
   return result;
@@ -239,27 +238,26 @@
   // Currently overusing the bandwidth.
   if (delay_detector_->State() == BandwidthUsage::kBwOverusing) {
     if (acked_bitrate &&
-        rate_control_.TimeToReduceFurther(at_time.ms(), acked_bitrate->bps())) {
+        rate_control_.TimeToReduceFurther(at_time, *acked_bitrate)) {
       result.updated =
           UpdateEstimate(at_time, acked_bitrate, &result.target_bitrate);
     } else if (!acked_bitrate && rate_control_.ValidEstimate() &&
-               rate_control_.InitialTimeToReduceFurther(at_time.ms())) {
+               rate_control_.InitialTimeToReduceFurther(at_time)) {
       // Overusing before we have a measured acknowledged bitrate. Reduce send
       // rate by 50% every 200 ms.
       // TODO(tschumim): Improve this and/or the acknowledged bitrate estimator
       // so that we (almost) always have a bitrate estimate.
-      rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2,
-                                at_time.ms());
+      rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2, at_time);
       result.updated = true;
       result.probe = false;
-      result.target_bitrate = DataRate::bps(rate_control_.LatestEstimate());
+      result.target_bitrate = rate_control_.LatestEstimate();
     }
   } else {
     if (probe_bitrate) {
       result.probe = true;
       result.updated = true;
       result.target_bitrate = *probe_bitrate;
-      rate_control_.SetEstimate(probe_bitrate->bps(), at_time.ms());
+      rate_control_.SetEstimate(*probe_bitrate, at_time);
     } else {
       result.updated =
           UpdateEstimate(at_time, acked_bitrate, &result.target_bitrate);
@@ -287,16 +285,13 @@
 bool DelayBasedBwe::UpdateEstimate(Timestamp at_time,
                                    absl::optional<DataRate> acked_bitrate,
                                    DataRate* target_rate) {
-  absl::optional<int> acked_bitrate_bps;
-  if (acked_bitrate)
-    acked_bitrate_bps = acked_bitrate->bps<int>();
-  const RateControlInput input(delay_detector_->State(), acked_bitrate_bps);
-  *target_rate = DataRate::bps(rate_control_.Update(&input, at_time.ms()));
+  const RateControlInput input(delay_detector_->State(), acked_bitrate);
+  *target_rate = rate_control_.Update(&input, at_time);
   return rate_control_.ValidEstimate();
 }
 
 void DelayBasedBwe::OnRttUpdate(TimeDelta avg_rtt) {
-  rate_control_.SetRtt(avg_rtt.ms());
+  rate_control_.SetRtt(avg_rtt);
 }
 
 bool DelayBasedBwe::LatestEstimate(std::vector<uint32_t>* ssrcs,
@@ -311,23 +306,23 @@
     return false;
 
   *ssrcs = {kFixedSsrc};
-  *bitrate = DataRate::bps(rate_control_.LatestEstimate());
+  *bitrate = rate_control_.LatestEstimate();
   return true;
 }
 
 void DelayBasedBwe::SetStartBitrate(DataRate start_bitrate) {
   RTC_LOG(LS_INFO) << "BWE Setting start bitrate to: "
                    << ToString(start_bitrate);
-  rate_control_.SetStartBitrate(start_bitrate.bps());
+  rate_control_.SetStartBitrate(start_bitrate);
 }
 
 void DelayBasedBwe::SetMinBitrate(DataRate min_bitrate) {
   // Called from both the configuration thread and the network thread. Shouldn't
   // be called from the network thread in the future.
-  rate_control_.SetMinBitrate(min_bitrate.bps());
+  rate_control_.SetMinBitrate(min_bitrate);
 }
 
 TimeDelta DelayBasedBwe::GetExpectedBwePeriod() const {
-  return TimeDelta::ms(rate_control_.GetExpectedBandwidthPeriodMs());
+  return rate_control_.GetExpectedBandwidthPeriod();
 }
 }  // namespace webrtc
diff --git a/modules/remote_bitrate_estimator/BUILD.gn b/modules/remote_bitrate_estimator/BUILD.gn
index f21c6d8..f6991ea 100644
--- a/modules/remote_bitrate_estimator/BUILD.gn
+++ b/modules/remote_bitrate_estimator/BUILD.gn
@@ -42,6 +42,7 @@
   deps = [
     "../..:webrtc_common",
     "../../api/units:data_rate",
+    "../../api/units:timestamp",
     "../../modules:module_api",
     "../../modules:module_api_public",
     "../../modules/rtp_rtcp:rtp_rtcp_format",
diff --git a/modules/remote_bitrate_estimator/aimd_rate_control.cc b/modules/remote_bitrate_estimator/aimd_rate_control.cc
index a992e7f..4c91776 100644
--- a/modules/remote_bitrate_estimator/aimd_rate_control.cc
+++ b/modules/remote_bitrate_estimator/aimd_rate_control.cc
@@ -26,10 +26,9 @@
 
 namespace webrtc {
 
-static const int64_t kDefaultRttMs = 200;
-static const int64_t kMaxFeedbackIntervalMs = 1000;
-static const float kDefaultBackoffFactor = 0.85f;
-static const int64_t kDefaultInitialBackOffIntervalMs = 200;
+constexpr TimeDelta kDefaultRtt = TimeDelta::Millis<200>();
+constexpr float kDefaultBackoffFactor = 0.85f;
+constexpr TimeDelta kDefaultInitialBackOffInterval = TimeDelta::Millis<200>();
 
 const char kBweBackOffFactorExperiment[] = "WebRTC-BweBackOffFactor";
 const char kBweInitialBackOffIntervalExperiment[] =
@@ -55,7 +54,7 @@
   return kDefaultBackoffFactor;
 }
 
-int64_t ReadInitialBackoffIntervalMs() {
+TimeDelta ReadInitialBackoffInterval() {
   std::string experiment_string =
       webrtc::field_trial::FindFullName(kBweInitialBackOffIntervalExperiment);
   int64_t backoff_interval;
@@ -63,7 +62,7 @@
       sscanf(experiment_string.c_str(), "Enabled-%" SCNd64, &backoff_interval);
   if (parsed_values == 1) {
     if (10 <= backoff_interval && backoff_interval <= 200) {
-      return backoff_interval;
+      return TimeDelta::ms(backoff_interval);
     }
     RTC_LOG(WARNING)
         << "Initial back-off interval must be between 10 and 200 ms.";
@@ -71,188 +70,193 @@
   RTC_LOG(LS_WARNING) << "Failed to parse parameters for "
                       << kBweInitialBackOffIntervalExperiment
                       << " experiment. Using default.";
-  return kDefaultInitialBackOffIntervalMs;
+  return kDefaultInitialBackOffInterval;
 }
 
 AimdRateControl::AimdRateControl()
-    : min_configured_bitrate_bps_(congestion_controller::GetMinBitrateBps()),
-      max_configured_bitrate_bps_(30000000),
-      current_bitrate_bps_(max_configured_bitrate_bps_),
-      latest_estimated_throughput_bps_(current_bitrate_bps_),
+    : min_configured_bitrate_(congestion_controller::GetMinBitrate()),
+      max_configured_bitrate_(DataRate::kbps(30000)),
+      current_bitrate_(max_configured_bitrate_),
+      latest_estimated_throughput_(current_bitrate_),
       avg_max_bitrate_kbps_(-1.0f),
       var_max_bitrate_kbps_(0.4f),
       rate_control_state_(kRcHold),
       rate_control_region_(kRcMaxUnknown),
-      time_last_bitrate_change_(-1),
-      time_last_bitrate_decrease_(-1),
-      time_first_throughput_estimate_(-1),
+      time_last_bitrate_change_(Timestamp::MinusInfinity()),
+      time_last_bitrate_decrease_(Timestamp::MinusInfinity()),
+      time_first_throughput_estimate_(Timestamp::MinusInfinity()),
       bitrate_is_initialized_(false),
       beta_(webrtc::field_trial::IsEnabled(kBweBackOffFactorExperiment)
                 ? ReadBackoffFactor()
                 : kDefaultBackoffFactor),
-      rtt_(kDefaultRttMs),
+      rtt_(kDefaultRtt),
       in_experiment_(!AdaptiveThresholdExperimentIsDisabled()),
       smoothing_experiment_(
           webrtc::field_trial::IsEnabled("WebRTC-Audio-BandwidthSmoothing")),
       in_initial_backoff_interval_experiment_(
           webrtc::field_trial::IsEnabled(kBweInitialBackOffIntervalExperiment)),
-      initial_backoff_interval_ms_(kDefaultInitialBackOffIntervalMs) {
+      initial_backoff_interval_(kDefaultInitialBackOffInterval) {
   if (in_initial_backoff_interval_experiment_) {
-    initial_backoff_interval_ms_ = ReadInitialBackoffIntervalMs();
+    initial_backoff_interval_ = ReadInitialBackoffInterval();
     RTC_LOG(LS_INFO) << "Using aimd rate control with initial back-off interval"
-                     << " " << initial_backoff_interval_ms_ << " ms.";
+                     << " " << ToString(initial_backoff_interval_) << ".";
   }
   RTC_LOG(LS_INFO) << "Using aimd rate control with back off factor " << beta_;
 }
 
 AimdRateControl::~AimdRateControl() {}
 
-void AimdRateControl::SetStartBitrate(int start_bitrate_bps) {
-  current_bitrate_bps_ = start_bitrate_bps;
-  latest_estimated_throughput_bps_ = current_bitrate_bps_;
+void AimdRateControl::SetStartBitrate(DataRate start_bitrate) {
+  current_bitrate_ = start_bitrate;
+  latest_estimated_throughput_ = current_bitrate_;
   bitrate_is_initialized_ = true;
 }
 
-void AimdRateControl::SetMinBitrate(int min_bitrate_bps) {
-  min_configured_bitrate_bps_ = min_bitrate_bps;
-  current_bitrate_bps_ = std::max<int>(min_bitrate_bps, current_bitrate_bps_);
+void AimdRateControl::SetMinBitrate(DataRate min_bitrate) {
+  min_configured_bitrate_ = min_bitrate;
+  current_bitrate_ = std::max(min_bitrate, current_bitrate_);
 }
 
 bool AimdRateControl::ValidEstimate() const {
   return bitrate_is_initialized_;
 }
 
-int64_t AimdRateControl::GetFeedbackInterval() const {
+TimeDelta AimdRateControl::GetFeedbackInterval() const {
   // Estimate how often we can send RTCP if we allocate up to 5% of bandwidth
   // to feedback.
-  static const int kRtcpSize = 80;
-  const int64_t interval = static_cast<int64_t>(
-      kRtcpSize * 8.0 * 1000.0 / (0.05 * current_bitrate_bps_) + 0.5);
-  const int64_t kMinFeedbackIntervalMs = 200;
-  return rtc::SafeClamp(interval, kMinFeedbackIntervalMs,
-                        kMaxFeedbackIntervalMs);
+  const DataSize kRtcpSize = DataSize::bytes(80);
+  const DataRate rtcp_bitrate = current_bitrate_ * 0.05;
+  const TimeDelta interval = kRtcpSize / rtcp_bitrate;
+  const TimeDelta kMinFeedbackInterval = TimeDelta::ms(200);
+  const TimeDelta kMaxFeedbackInterval = TimeDelta::ms(1000);
+  return interval.Clamped(kMinFeedbackInterval, kMaxFeedbackInterval);
 }
 
-bool AimdRateControl::TimeToReduceFurther(
-    int64_t now_ms,
-    uint32_t estimated_throughput_bps) const {
-  const int64_t bitrate_reduction_interval =
-      std::max<int64_t>(std::min<int64_t>(rtt_, 200), 10);
-  if (now_ms - time_last_bitrate_change_ >= bitrate_reduction_interval) {
+bool AimdRateControl::TimeToReduceFurther(Timestamp at_time,
+                                          DataRate estimated_throughput) const {
+  const TimeDelta bitrate_reduction_interval =
+      rtt_.Clamped(TimeDelta::ms(10), TimeDelta::ms(200));
+  if (at_time - time_last_bitrate_change_ >= bitrate_reduction_interval) {
     return true;
   }
   if (ValidEstimate()) {
     // TODO(terelius/holmer): Investigate consequences of increasing
     // the threshold to 0.95 * LatestEstimate().
-    const uint32_t threshold = static_cast<uint32_t>(0.5 * LatestEstimate());
-    return estimated_throughput_bps < threshold;
+    const DataRate threshold = 0.5 * LatestEstimate();
+    return estimated_throughput < threshold;
   }
   return false;
 }
 
-bool AimdRateControl::InitialTimeToReduceFurther(int64_t now_ms) const {
+bool AimdRateControl::InitialTimeToReduceFurther(Timestamp at_time) const {
   if (!in_initial_backoff_interval_experiment_) {
     return ValidEstimate() &&
-           TimeToReduceFurther(now_ms, LatestEstimate() / 2 - 1);
+           TimeToReduceFurther(at_time,
+                               LatestEstimate() / 2 - DataRate::bps(1));
   }
   // TODO(terelius): We could use the RTT (clamped to suitable limits) instead
   // of a fixed bitrate_reduction_interval.
-  if (time_last_bitrate_decrease_ == -1 ||
-      now_ms - time_last_bitrate_decrease_ >= initial_backoff_interval_ms_) {
+  if (time_last_bitrate_decrease_.IsInfinite() ||
+      at_time - time_last_bitrate_decrease_ >= initial_backoff_interval_) {
     return true;
   }
   return false;
 }
 
-uint32_t AimdRateControl::LatestEstimate() const {
-  return current_bitrate_bps_;
+DataRate AimdRateControl::LatestEstimate() const {
+  return current_bitrate_;
 }
 
-void AimdRateControl::SetRtt(int64_t rtt) {
+void AimdRateControl::SetRtt(TimeDelta rtt) {
   rtt_ = rtt;
 }
 
-uint32_t AimdRateControl::Update(const RateControlInput* input,
-                                 int64_t now_ms) {
+DataRate AimdRateControl::Update(const RateControlInput* input,
+                                 Timestamp at_time) {
   RTC_CHECK(input);
 
   // Set the initial bit rate value to what we're receiving the first half
   // second.
   // TODO(bugs.webrtc.org/9379): The comment above doesn't match to the code.
   if (!bitrate_is_initialized_) {
-    const int64_t kInitializationTimeMs = 5000;
-    RTC_DCHECK_LE(kBitrateWindowMs, kInitializationTimeMs);
-    if (time_first_throughput_estimate_ < 0) {
-      if (input->estimated_throughput_bps)
-        time_first_throughput_estimate_ = now_ms;
-    } else if (now_ms - time_first_throughput_estimate_ >
-                   kInitializationTimeMs &&
-               input->estimated_throughput_bps) {
-      current_bitrate_bps_ = *input->estimated_throughput_bps;
+    const TimeDelta kInitializationTime = TimeDelta::seconds(5);
+    RTC_DCHECK_LE(kBitrateWindowMs, kInitializationTime.ms());
+    if (time_first_throughput_estimate_.IsInfinite()) {
+      if (input->estimated_throughput)
+        time_first_throughput_estimate_ = at_time;
+    } else if (at_time - time_first_throughput_estimate_ >
+                   kInitializationTime &&
+               input->estimated_throughput) {
+      current_bitrate_ = *input->estimated_throughput;
       bitrate_is_initialized_ = true;
     }
   }
 
-  current_bitrate_bps_ = ChangeBitrate(current_bitrate_bps_, *input, now_ms);
-  return current_bitrate_bps_;
+  current_bitrate_ = ChangeBitrate(current_bitrate_, *input, at_time);
+  return current_bitrate_;
 }
 
-void AimdRateControl::SetEstimate(int bitrate_bps, int64_t now_ms) {
+void AimdRateControl::SetEstimate(DataRate bitrate, Timestamp at_time) {
   bitrate_is_initialized_ = true;
-  uint32_t prev_bitrate_bps = current_bitrate_bps_;
-  current_bitrate_bps_ = ClampBitrate(bitrate_bps, bitrate_bps);
-  time_last_bitrate_change_ = now_ms;
-  if (current_bitrate_bps_ < prev_bitrate_bps) {
-    time_last_bitrate_decrease_ = now_ms;
+  DataRate prev_bitrate = current_bitrate_;
+  current_bitrate_ = ClampBitrate(bitrate, bitrate);
+  time_last_bitrate_change_ = at_time;
+  if (current_bitrate_ < prev_bitrate) {
+    time_last_bitrate_decrease_ = at_time;
   }
 }
 
-int AimdRateControl::GetNearMaxIncreaseRateBps() const {
-  RTC_DCHECK_GT(current_bitrate_bps_, 0);
-  double bits_per_frame = static_cast<double>(current_bitrate_bps_) / 30.0;
-  double packets_per_frame = std::ceil(bits_per_frame / (8.0 * 1200.0));
-  double avg_packet_size_bits = bits_per_frame / packets_per_frame;
+double AimdRateControl::GetNearMaxIncreaseRateBpsPerSecond() const {
+  RTC_DCHECK(!current_bitrate_.IsZero());
+  const TimeDelta kFrameInterval = TimeDelta::seconds(1) / 30;
+  DataSize frame_size = current_bitrate_ * kFrameInterval;
+  const DataSize kPacketSize = DataSize::bytes(1200);
+  double packets_per_frame = std::ceil(frame_size / kPacketSize);
+  DataSize avg_packet_size = frame_size / packets_per_frame;
 
   // Approximate the over-use estimator delay to 100 ms.
-  const int64_t response_time = in_experiment_ ? (rtt_ + 100) * 2 : rtt_ + 100;
-  constexpr double kMinIncreaseRateBps = 4000;
-  return static_cast<int>(std::max(
-      kMinIncreaseRateBps, (avg_packet_size_bits * 1000) / response_time));
+  TimeDelta response_time = rtt_ + TimeDelta::ms(100);
+  if (in_experiment_)
+    response_time = response_time * 2;
+  double increase_rate_bps_per_second =
+      (avg_packet_size / response_time).bps<double>();
+  double kMinIncreaseRateBpsPerSecond = 4000;
+  return std::max(kMinIncreaseRateBpsPerSecond, increase_rate_bps_per_second);
 }
 
-int AimdRateControl::GetExpectedBandwidthPeriodMs() const {
-  const int kMinPeriodMs = smoothing_experiment_ ? 500 : 2000;
-  constexpr int kDefaultPeriodMs = 3000;
-  constexpr int kMaxPeriodMs = 50000;
+TimeDelta AimdRateControl::GetExpectedBandwidthPeriod() const {
+  const TimeDelta kMinPeriod =
+      smoothing_experiment_ ? TimeDelta::ms(500) : TimeDelta::seconds(2);
+  const TimeDelta kDefaultPeriod = TimeDelta::seconds(3);
+  const TimeDelta kMaxPeriod = TimeDelta::seconds(50);
 
-  int increase_rate = GetNearMaxIncreaseRateBps();
+  double increase_rate_bps_per_second = GetNearMaxIncreaseRateBpsPerSecond();
   if (!last_decrease_)
-    return smoothing_experiment_ ? kMinPeriodMs : kDefaultPeriodMs;
-
-  return std::min(kMaxPeriodMs,
-                  std::max<int>(1000 * static_cast<int64_t>(*last_decrease_) /
-                                    increase_rate,
-                                kMinPeriodMs));
+    return smoothing_experiment_ ? kMinPeriod : kDefaultPeriod;
+  double time_to_recover_decrease_seconds =
+      last_decrease_->bps() / increase_rate_bps_per_second;
+  TimeDelta period = TimeDelta::seconds(time_to_recover_decrease_seconds);
+  return period.Clamped(kMinPeriod, kMaxPeriod);
 }
 
-uint32_t AimdRateControl::ChangeBitrate(uint32_t new_bitrate_bps,
+DataRate AimdRateControl::ChangeBitrate(DataRate new_bitrate,
                                         const RateControlInput& input,
-                                        int64_t now_ms) {
-  uint32_t estimated_throughput_bps =
-      input.estimated_throughput_bps.value_or(latest_estimated_throughput_bps_);
-  if (input.estimated_throughput_bps)
-    latest_estimated_throughput_bps_ = *input.estimated_throughput_bps;
+                                        Timestamp at_time) {
+  DataRate estimated_throughput =
+      input.estimated_throughput.value_or(latest_estimated_throughput_);
+  if (input.estimated_throughput)
+    latest_estimated_throughput_ = *input.estimated_throughput;
 
   // An over-use should always trigger us to reduce the bitrate, even though
   // we have not yet established our first estimate. By acting on the over-use,
   // we will end up with a valid estimate.
   if (!bitrate_is_initialized_ &&
       input.bw_state != BandwidthUsage::kBwOverusing)
-    return current_bitrate_bps_;
+    return current_bitrate_;
 
-  ChangeState(input, now_ms);
+  ChangeState(input, at_time);
   // Calculated here because it's used in multiple places.
-  const float estimated_throughput_kbps = estimated_throughput_bps / 1000.0f;
+  const float estimated_throughput_kbps = estimated_throughput.kbps<double>();
   // Calculate the max bit rate std dev given the normalized
   // variance and the current throughput bitrate.
   const float std_max_bit_rate =
@@ -270,45 +274,41 @@
         avg_max_bitrate_kbps_ = -1.0;
       }
       if (rate_control_region_ == kRcNearMax) {
-        uint32_t additive_increase_bps =
-            AdditiveRateIncrease(now_ms, time_last_bitrate_change_);
-        new_bitrate_bps += additive_increase_bps;
+        DataRate additive_increase =
+            AdditiveRateIncrease(at_time, time_last_bitrate_change_);
+        new_bitrate += additive_increase;
       } else {
-        uint32_t multiplicative_increase_bps = MultiplicativeRateIncrease(
-            now_ms, time_last_bitrate_change_, new_bitrate_bps);
-        new_bitrate_bps += multiplicative_increase_bps;
+        DataRate multiplicative_increase = MultiplicativeRateIncrease(
+            at_time, time_last_bitrate_change_, new_bitrate);
+        new_bitrate += multiplicative_increase;
       }
 
-      time_last_bitrate_change_ = now_ms;
+      time_last_bitrate_change_ = at_time;
       break;
 
     case kRcDecrease:
       // Set bit rate to something slightly lower than max
       // to get rid of any self-induced delay.
-      new_bitrate_bps =
-          static_cast<uint32_t>(beta_ * estimated_throughput_bps + 0.5);
-      if (new_bitrate_bps > current_bitrate_bps_) {
+      new_bitrate = estimated_throughput * beta_;
+      if (new_bitrate > current_bitrate_) {
         // Avoid increasing the rate when over-using.
         if (rate_control_region_ != kRcMaxUnknown) {
-          new_bitrate_bps = static_cast<uint32_t>(
-              beta_ * avg_max_bitrate_kbps_ * 1000 + 0.5f);
+          new_bitrate = DataRate::kbps(beta_ * avg_max_bitrate_kbps_);
         }
-        new_bitrate_bps = std::min(new_bitrate_bps, current_bitrate_bps_);
+        new_bitrate = std::min(new_bitrate, current_bitrate_);
       }
       rate_control_region_ = kRcNearMax;
 
-      if (bitrate_is_initialized_ &&
-          estimated_throughput_bps < current_bitrate_bps_) {
+      if (bitrate_is_initialized_ && estimated_throughput < current_bitrate_) {
         constexpr float kDegradationFactor = 0.9f;
         if (smoothing_experiment_ &&
-            new_bitrate_bps <
-                kDegradationFactor * beta_ * current_bitrate_bps_) {
+            new_bitrate < kDegradationFactor * beta_ * current_bitrate_) {
           // If bitrate decreases more than a normal back off after overuse, it
           // indicates a real network degradation. We do not let such a decrease
           // to determine the bandwidth estimation period.
           last_decrease_ = absl::nullopt;
         } else {
-          last_decrease_ = current_bitrate_bps_ - new_bitrate_bps;
+          last_decrease_ = current_bitrate_ - new_bitrate;
         }
       }
       if (estimated_throughput_kbps <
@@ -320,51 +320,49 @@
       UpdateMaxThroughputEstimate(estimated_throughput_kbps);
       // Stay on hold until the pipes are cleared.
       rate_control_state_ = kRcHold;
-      time_last_bitrate_change_ = now_ms;
-      time_last_bitrate_decrease_ = now_ms;
+      time_last_bitrate_change_ = at_time;
+      time_last_bitrate_decrease_ = at_time;
       break;
 
     default:
       assert(false);
   }
-  return ClampBitrate(new_bitrate_bps, estimated_throughput_bps);
+  return ClampBitrate(new_bitrate, estimated_throughput);
 }
 
-uint32_t AimdRateControl::ClampBitrate(
-    uint32_t new_bitrate_bps,
-    uint32_t estimated_throughput_bps) const {
+DataRate AimdRateControl::ClampBitrate(DataRate new_bitrate,
+                                       DataRate estimated_throughput) const {
   // Don't change the bit rate if the send side is too far off.
   // We allow a bit more lag at very low rates to not too easily get stuck if
   // the encoder produces uneven outputs.
-  const uint32_t max_bitrate_bps =
-      static_cast<uint32_t>(1.5f * estimated_throughput_bps) + 10000;
-  if (new_bitrate_bps > current_bitrate_bps_ &&
-      new_bitrate_bps > max_bitrate_bps) {
-    new_bitrate_bps = std::max(current_bitrate_bps_, max_bitrate_bps);
+  const DataRate max_bitrate = 1.5 * estimated_throughput + DataRate::kbps(10);
+  if (new_bitrate > current_bitrate_ && new_bitrate > max_bitrate) {
+    new_bitrate = std::max(current_bitrate_, max_bitrate);
   }
-  new_bitrate_bps = std::max(new_bitrate_bps, min_configured_bitrate_bps_);
-  return new_bitrate_bps;
+  new_bitrate = std::max(new_bitrate, min_configured_bitrate_);
+  return new_bitrate;
 }
 
-uint32_t AimdRateControl::MultiplicativeRateIncrease(
-    int64_t now_ms,
-    int64_t last_ms,
-    uint32_t current_bitrate_bps) const {
+DataRate AimdRateControl::MultiplicativeRateIncrease(
+    Timestamp at_time,
+    Timestamp last_time,
+    DataRate current_bitrate) const {
   double alpha = 1.08;
-  if (last_ms > -1) {
-    auto time_since_last_update_ms =
-        rtc::SafeMin<int64_t>(now_ms - last_ms, 1000);
-    alpha = pow(alpha, time_since_last_update_ms / 1000.0);
+  if (last_time.IsFinite()) {
+    auto time_since_last_update = at_time - last_time;
+    alpha = pow(alpha, std::min(time_since_last_update.seconds<double>(), 1.0));
   }
-  uint32_t multiplicative_increase_bps =
-      std::max(current_bitrate_bps * (alpha - 1.0), 1000.0);
-  return multiplicative_increase_bps;
+  DataRate multiplicative_increase =
+      std::max(current_bitrate * (alpha - 1.0), DataRate::bps(1000));
+  return multiplicative_increase;
 }
 
-uint32_t AimdRateControl::AdditiveRateIncrease(int64_t now_ms,
-                                               int64_t last_ms) const {
-  return static_cast<uint32_t>((now_ms - last_ms) *
-                               GetNearMaxIncreaseRateBps() / 1000);
+DataRate AimdRateControl::AdditiveRateIncrease(Timestamp at_time,
+                                               Timestamp last_time) const {
+  double time_period_seconds = (at_time - last_time).seconds<double>();
+  double data_rate_increase_bps =
+      GetNearMaxIncreaseRateBpsPerSecond() * time_period_seconds;
+  return DataRate::bps(data_rate_increase_bps);
 }
 
 void AimdRateControl::UpdateMaxThroughputEstimate(
@@ -394,11 +392,11 @@
 }
 
 void AimdRateControl::ChangeState(const RateControlInput& input,
-                                  int64_t now_ms) {
+                                  Timestamp at_time) {
   switch (input.bw_state) {
     case BandwidthUsage::kBwNormal:
       if (rate_control_state_ == kRcHold) {
-        time_last_bitrate_change_ = now_ms;
+        time_last_bitrate_change_ = at_time;
         rate_control_state_ = kRcIncrease;
       }
       break;
diff --git a/modules/remote_bitrate_estimator/aimd_rate_control.h b/modules/remote_bitrate_estimator/aimd_rate_control.h
index 24b8535..47afce6 100644
--- a/modules/remote_bitrate_estimator/aimd_rate_control.h
+++ b/modules/remote_bitrate_estimator/aimd_rate_control.h
@@ -16,6 +16,9 @@
 #include "absl/types/optional.h"
 #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
 
+#include "api/units/data_rate.h"
+#include "api/units/timestamp.h"
+
 namespace webrtc {
 
 // A rate control implementation based on additive increases of
@@ -32,28 +35,28 @@
   // either if it has been explicitly set via SetStartBitrate/SetEstimate, or if
   // we have measured a throughput.
   bool ValidEstimate() const;
-  void SetStartBitrate(int start_bitrate_bps);
-  void SetMinBitrate(int min_bitrate_bps);
-  int64_t GetFeedbackInterval() const;
+  void SetStartBitrate(DataRate start_bitrate);
+  void SetMinBitrate(DataRate min_bitrate);
+  TimeDelta GetFeedbackInterval() const;
 
   // Returns true if the bitrate estimate hasn't been changed for more than
   // an RTT, or if the estimated_throughput is less than half of the current
   // estimate. Should be used to decide if we should reduce the rate further
   // when over-using.
-  bool TimeToReduceFurther(int64_t now_ms,
-                           uint32_t estimated_throughput_bps) const;
+  bool TimeToReduceFurther(Timestamp at_time,
+                           DataRate estimated_throughput) const;
   // As above. To be used if overusing before we have measured a throughput.
-  bool InitialTimeToReduceFurther(int64_t now_ms) const;
+  bool InitialTimeToReduceFurther(Timestamp at_time) const;
 
-  uint32_t LatestEstimate() const;
-  void SetRtt(int64_t rtt);
-  uint32_t Update(const RateControlInput* input, int64_t now_ms);
-  void SetEstimate(int bitrate_bps, int64_t now_ms);
+  DataRate LatestEstimate() const;
+  void SetRtt(TimeDelta rtt);
+  DataRate Update(const RateControlInput* input, Timestamp at_time);
+  void SetEstimate(DataRate bitrate, Timestamp at_time);
 
   // Returns the increase rate when used bandwidth is near the link capacity.
-  int GetNearMaxIncreaseRateBps() const;
+  double GetNearMaxIncreaseRateBpsPerSecond() const;
   // Returns the expected time between overuse signals (assuming steady state).
-  int GetExpectedBandwidthPeriodMs() const;
+  TimeDelta GetExpectedBandwidthPeriod() const;
 
  private:
   friend class GoogCcStatePrinter;
@@ -64,41 +67,41 @@
   // in the "decrease" state the bitrate will be decreased to slightly below the
   // current throughput. When in the "hold" state the bitrate will be kept
   // constant to allow built up queues to drain.
-  uint32_t ChangeBitrate(uint32_t current_bitrate,
+  DataRate ChangeBitrate(DataRate current_bitrate,
                          const RateControlInput& input,
-                         int64_t now_ms);
-  // Clamps new_bitrate_bps to within the configured min bitrate and a linear
+                         Timestamp at_time);
+  // Clamps new_bitrate to within the configured min bitrate and a linear
   // function of the throughput, so that the new bitrate can't grow too
   // large compared to the bitrate actually being received by the other end.
-  uint32_t ClampBitrate(uint32_t new_bitrate_bps,
-                        uint32_t estimated_throughput_bps) const;
-  uint32_t MultiplicativeRateIncrease(int64_t now_ms,
-                                      int64_t last_ms,
-                                      uint32_t current_bitrate_bps) const;
-  uint32_t AdditiveRateIncrease(int64_t now_ms, int64_t last_ms) const;
-  void UpdateChangePeriod(int64_t now_ms);
+  DataRate ClampBitrate(DataRate new_bitrate,
+                        DataRate estimated_throughput) const;
+  DataRate MultiplicativeRateIncrease(Timestamp at_time,
+                                      Timestamp last_ms,
+                                      DataRate current_bitrate) const;
+  DataRate AdditiveRateIncrease(Timestamp at_time, Timestamp last_time) const;
+  void UpdateChangePeriod(Timestamp at_time);
   void UpdateMaxThroughputEstimate(float estimated_throughput_kbps);
-  void ChangeState(const RateControlInput& input, int64_t now_ms);
+  void ChangeState(const RateControlInput& input, Timestamp at_time);
 
-  uint32_t min_configured_bitrate_bps_;
-  uint32_t max_configured_bitrate_bps_;
-  uint32_t current_bitrate_bps_;
-  uint32_t latest_estimated_throughput_bps_;
+  DataRate min_configured_bitrate_;
+  DataRate max_configured_bitrate_;
+  DataRate current_bitrate_;
+  DataRate latest_estimated_throughput_;
   float avg_max_bitrate_kbps_;
   float var_max_bitrate_kbps_;
   RateControlState rate_control_state_;
   RateControlRegion rate_control_region_;
-  int64_t time_last_bitrate_change_;
-  int64_t time_last_bitrate_decrease_;
-  int64_t time_first_throughput_estimate_;
+  Timestamp time_last_bitrate_change_;
+  Timestamp time_last_bitrate_decrease_;
+  Timestamp time_first_throughput_estimate_;
   bool bitrate_is_initialized_;
   float beta_;
-  int64_t rtt_;
+  TimeDelta rtt_;
   const bool in_experiment_;
   const bool smoothing_experiment_;
   const bool in_initial_backoff_interval_experiment_;
-  int64_t initial_backoff_interval_ms_;
-  absl::optional<int> last_decrease_;
+  TimeDelta initial_backoff_interval_;
+  absl::optional<DataRate> last_decrease_;
 };
 }  // namespace webrtc
 
diff --git a/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc b/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc
index 5cde7ce..4bec9e8 100644
--- a/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc
+++ b/modules/remote_bitrate_estimator/aimd_rate_control_unittest.cc
@@ -40,13 +40,26 @@
   states.simulated_clock.reset(new SimulatedClock(kClockInitialTime));
   return states;
 }
-
+absl::optional<DataRate> OptionalRateFromOptionalBps(
+    absl::optional<int> bitrate_bps) {
+  if (bitrate_bps) {
+    return DataRate::bps(*bitrate_bps);
+  } else {
+    return absl::nullopt;
+  }
+}
 void UpdateRateControl(const AimdRateControlStates& states,
                        const BandwidthUsage& bandwidth_usage,
                        absl::optional<uint32_t> throughput_estimate,
                        int64_t now_ms) {
-  RateControlInput input(bandwidth_usage, throughput_estimate);
-  states.aimd_rate_control->Update(&input, now_ms);
+  RateControlInput input(bandwidth_usage,
+                         OptionalRateFromOptionalBps(throughput_estimate));
+  states.aimd_rate_control->Update(&input, Timestamp::ms(now_ms));
+}
+void SetEstimate(const AimdRateControlStates& states, int bitrate_bps) {
+  states.aimd_rate_control->SetEstimate(
+      DataRate::bps(bitrate_bps),
+      Timestamp::ms(states.simulated_clock->TimeInMilliseconds()));
 }
 
 }  // namespace
@@ -54,40 +67,40 @@
 TEST(AimdRateControlTest, MinNearMaxIncreaseRateOnLowBandwith) {
   auto states = CreateAimdRateControlStates();
   constexpr int kBitrate = 30000;
-  states.aimd_rate_control->SetEstimate(
-      kBitrate, states.simulated_clock->TimeInMilliseconds());
-  EXPECT_EQ(4000, states.aimd_rate_control->GetNearMaxIncreaseRateBps());
+  SetEstimate(states, kBitrate);
+  EXPECT_EQ(4000,
+            states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond());
 }
 
 TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn90kbpsAnd200msRtt) {
   auto states = CreateAimdRateControlStates();
   constexpr int kBitrate = 90000;
-  states.aimd_rate_control->SetEstimate(
-      kBitrate, states.simulated_clock->TimeInMilliseconds());
-  EXPECT_EQ(5000, states.aimd_rate_control->GetNearMaxIncreaseRateBps());
+  SetEstimate(states, kBitrate);
+  EXPECT_EQ(5000,
+            states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond());
 }
 
 TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn60kbpsAnd100msRtt) {
   auto states = CreateAimdRateControlStates();
   constexpr int kBitrate = 60000;
-  states.aimd_rate_control->SetEstimate(
-      kBitrate, states.simulated_clock->TimeInMilliseconds());
-  states.aimd_rate_control->SetRtt(100);
-  EXPECT_EQ(5000, states.aimd_rate_control->GetNearMaxIncreaseRateBps());
+  SetEstimate(states, kBitrate);
+  states.aimd_rate_control->SetRtt(TimeDelta::ms(100));
+  EXPECT_EQ(5000,
+            states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond());
 }
 
 TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriod) {
   // Smoothing experiment disabled
   auto states = CreateAimdRateControlStates();
   constexpr int kBitrate = 300000;
-  states.aimd_rate_control->SetEstimate(
-      kBitrate, states.simulated_clock->TimeInMilliseconds());
+  SetEstimate(states, kBitrate);
   UpdateRateControl(states, BandwidthUsage::kBwOverusing, kBitrate,
                     states.simulated_clock->TimeInMilliseconds());
-  EXPECT_NEAR(14000, states.aimd_rate_control->GetNearMaxIncreaseRateBps(),
+  EXPECT_NEAR(14000,
+              states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond(),
               1000);
   EXPECT_EQ(kDefaultPeriodMsNoSmoothingExp,
-            states.aimd_rate_control->GetExpectedBandwidthPeriodMs());
+            states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
 }
 
 TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriodSmoothingExp) {
@@ -95,21 +108,20 @@
   test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial);
   auto states = CreateAimdRateControlStates();
   constexpr int kBitrate = 300000;
-  states.aimd_rate_control->SetEstimate(
-      kBitrate, states.simulated_clock->TimeInMilliseconds());
+  SetEstimate(states, kBitrate);
   UpdateRateControl(states, BandwidthUsage::kBwOverusing, kBitrate,
                     states.simulated_clock->TimeInMilliseconds());
-  EXPECT_NEAR(14000, states.aimd_rate_control->GetNearMaxIncreaseRateBps(),
+  EXPECT_NEAR(14000,
+              states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond(),
               1000);
   EXPECT_EQ(kMinBwePeriodMsSmoothingExp,
-            states.aimd_rate_control->GetExpectedBandwidthPeriodMs());
+            states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
 }
 
 TEST(AimdRateControlTest, BweLimitedByAckedBitrate) {
   auto states = CreateAimdRateControlStates();
   constexpr int kAckedBitrate = 10000;
-  states.aimd_rate_control->SetEstimate(
-      kAckedBitrate, states.simulated_clock->TimeInMilliseconds());
+  SetEstimate(states, kAckedBitrate);
   while (states.simulated_clock->TimeInMilliseconds() - kClockInitialTime <
          20000) {
     UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate,
@@ -118,14 +130,13 @@
   }
   ASSERT_TRUE(states.aimd_rate_control->ValidEstimate());
   EXPECT_EQ(static_cast<uint32_t>(1.5 * kAckedBitrate + 10000),
-            states.aimd_rate_control->LatestEstimate());
+            states.aimd_rate_control->LatestEstimate().bps());
 }
 
 TEST(AimdRateControlTest, BweNotLimitedByDecreasingAckedBitrate) {
   auto states = CreateAimdRateControlStates();
   constexpr int kAckedBitrate = 100000;
-  states.aimd_rate_control->SetEstimate(
-      kAckedBitrate, states.simulated_clock->TimeInMilliseconds());
+  SetEstimate(states, kAckedBitrate);
   while (states.simulated_clock->TimeInMilliseconds() - kClockInitialTime <
          20000) {
     UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate,
@@ -135,10 +146,10 @@
   ASSERT_TRUE(states.aimd_rate_control->ValidEstimate());
   // If the acked bitrate decreases the BWE shouldn't be reduced to 1.5x
   // what's being acked, but also shouldn't get to increase more.
-  uint32_t prev_estimate = states.aimd_rate_control->LatestEstimate();
+  uint32_t prev_estimate = states.aimd_rate_control->LatestEstimate().bps();
   UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate / 2,
                     states.simulated_clock->TimeInMilliseconds());
-  uint32_t new_estimate = states.aimd_rate_control->LatestEstimate();
+  uint32_t new_estimate = states.aimd_rate_control->LatestEstimate().bps();
   EXPECT_NEAR(new_estimate, static_cast<uint32_t>(1.5 * kAckedBitrate + 10000),
               2000);
   EXPECT_EQ(new_estimate, prev_estimate);
@@ -147,35 +158,34 @@
 TEST(AimdRateControlTest, DefaultPeriodUntilFirstOveruse) {
   // Smoothing experiment disabled
   auto states = CreateAimdRateControlStates();
-  states.aimd_rate_control->SetStartBitrate(300000);
+  states.aimd_rate_control->SetStartBitrate(DataRate::kbps(300));
   EXPECT_EQ(kDefaultPeriodMsNoSmoothingExp,
-            states.aimd_rate_control->GetExpectedBandwidthPeriodMs());
+            states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
   states.simulated_clock->AdvanceTimeMilliseconds(100);
   UpdateRateControl(states, BandwidthUsage::kBwOverusing, 280000,
                     states.simulated_clock->TimeInMilliseconds());
   EXPECT_NE(kDefaultPeriodMsNoSmoothingExp,
-            states.aimd_rate_control->GetExpectedBandwidthPeriodMs());
+            states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
 }
 
 TEST(AimdRateControlTest, MinPeriodUntilFirstOveruseSmoothingExp) {
   // Smoothing experiment enabled
   test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial);
   auto states = CreateAimdRateControlStates();
-  states.aimd_rate_control->SetStartBitrate(300000);
+  states.aimd_rate_control->SetStartBitrate(DataRate::kbps(300));
   EXPECT_EQ(kMinBwePeriodMsSmoothingExp,
-            states.aimd_rate_control->GetExpectedBandwidthPeriodMs());
+            states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
   states.simulated_clock->AdvanceTimeMilliseconds(100);
   UpdateRateControl(states, BandwidthUsage::kBwOverusing, 280000,
                     states.simulated_clock->TimeInMilliseconds());
   EXPECT_NE(kMinBwePeriodMsSmoothingExp,
-            states.aimd_rate_control->GetExpectedBandwidthPeriodMs());
+            states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
 }
 
 TEST(AimdRateControlTest, ExpectedPeriodAfter20kbpsDropAnd5kbpsIncrease) {
   auto states = CreateAimdRateControlStates();
   constexpr int kInitialBitrate = 110000;
-  states.aimd_rate_control->SetEstimate(
-      kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
+  SetEstimate(states, kInitialBitrate);
   states.simulated_clock->AdvanceTimeMilliseconds(100);
   // Make the bitrate drop by 20 kbps to get to 90 kbps.
   // The rate increase at 90 kbps should be 5 kbps, so the period should be 4 s.
@@ -183,8 +193,9 @@
       (kInitialBitrate - 20000) / kFractionAfterOveruse;
   UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate,
                     states.simulated_clock->TimeInMilliseconds());
-  EXPECT_EQ(5000, states.aimd_rate_control->GetNearMaxIncreaseRateBps());
-  EXPECT_EQ(4000, states.aimd_rate_control->GetExpectedBandwidthPeriodMs());
+  EXPECT_EQ(5000,
+            states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond());
+  EXPECT_EQ(4000, states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
 }
 
 TEST(AimdRateControlTest, MinPeriodAfterLargeBitrateDecreaseSmoothingExp) {
@@ -192,8 +203,7 @@
   test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial);
   auto states = CreateAimdRateControlStates();
   constexpr int kInitialBitrate = 110000;
-  states.aimd_rate_control->SetEstimate(
-      kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
+  SetEstimate(states, kInitialBitrate);
   states.simulated_clock->AdvanceTimeMilliseconds(100);
   // Make such a large drop in bitrate that should be treated as network
   // degradation.
@@ -201,20 +211,19 @@
   UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate,
                     states.simulated_clock->TimeInMilliseconds());
   EXPECT_EQ(kMinBwePeriodMsSmoothingExp,
-            states.aimd_rate_control->GetExpectedBandwidthPeriodMs());
+            states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
 }
 
 TEST(AimdRateControlTest, BandwidthPeriodIsNotBelowMin) {
   auto states = CreateAimdRateControlStates();
   constexpr int kInitialBitrate = 10000;
-  states.aimd_rate_control->SetEstimate(
-      kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
+  SetEstimate(states, kInitialBitrate);
   states.simulated_clock->AdvanceTimeMilliseconds(100);
   // Make a small (1.5 kbps) bitrate drop to 8.5 kbps.
   UpdateRateControl(states, BandwidthUsage::kBwOverusing, kInitialBitrate - 1,
                     states.simulated_clock->TimeInMilliseconds());
   EXPECT_EQ(kMinBwePeriodMsNoSmoothingExp,
-            states.aimd_rate_control->GetExpectedBandwidthPeriodMs());
+            states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
 }
 
 TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMaxSmoothingExp) {
@@ -222,29 +231,27 @@
   test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial);
   auto states = CreateAimdRateControlStates();
   constexpr int kInitialBitrate = 50000000;
-  states.aimd_rate_control->SetEstimate(
-      kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
+  SetEstimate(states, kInitialBitrate);
   states.simulated_clock->AdvanceTimeMilliseconds(100);
   // Make a large (10 Mbps) bitrate drop to 10 kbps.
   constexpr int kAckedBitrate = 40000000 / kFractionAfterOveruse;
   UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate,
                     states.simulated_clock->TimeInMilliseconds());
   EXPECT_EQ(kMaxBwePeriodMs,
-            states.aimd_rate_control->GetExpectedBandwidthPeriodMs());
+            states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
 }
 
 TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMaxNoSmoothingExp) {
   auto states = CreateAimdRateControlStates();
   constexpr int kInitialBitrate = 10010000;
-  states.aimd_rate_control->SetEstimate(
-      kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
+  SetEstimate(states, kInitialBitrate);
   states.simulated_clock->AdvanceTimeMilliseconds(100);
   // Make a large (10 Mbps) bitrate drop to 10 kbps.
   constexpr int kAckedBitrate = 10000 / kFractionAfterOveruse;
   UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate,
                     states.simulated_clock->TimeInMilliseconds());
   EXPECT_EQ(kMaxBwePeriodMs,
-            states.aimd_rate_control->GetExpectedBandwidthPeriodMs());
+            states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
 }
 
 TEST(AimdRateControlTest, SendingRateBoundedWhenThroughputNotEstimated) {
@@ -265,7 +272,7 @@
                       states.simulated_clock->TimeInMilliseconds());
     states.simulated_clock->AdvanceTimeMilliseconds(100);
   }
-  EXPECT_LE(states.aimd_rate_control->LatestEstimate(),
+  EXPECT_LE(states.aimd_rate_control->LatestEstimate().bps(),
             kInitialBitrateBps * 1.5 + 10000);
 }
 
diff --git a/modules/remote_bitrate_estimator/bwe_defines.cc b/modules/remote_bitrate_estimator/bwe_defines.cc
index 6cbe468..91f3cd4 100644
--- a/modules/remote_bitrate_estimator/bwe_defines.cc
+++ b/modules/remote_bitrate_estimator/bwe_defines.cc
@@ -34,8 +34,8 @@
 
 RateControlInput::RateControlInput(
     BandwidthUsage bw_state,
-    const absl::optional<uint32_t>& estimated_throughput_bps)
-    : bw_state(bw_state), estimated_throughput_bps(estimated_throughput_bps) {}
+    const absl::optional<DataRate>& estimated_throughput)
+    : bw_state(bw_state), estimated_throughput(estimated_throughput) {}
 
 RateControlInput::~RateControlInput() = default;
 
diff --git a/modules/remote_bitrate_estimator/include/bwe_defines.h b/modules/remote_bitrate_estimator/include/bwe_defines.h
index 2098507..f6ba06c 100644
--- a/modules/remote_bitrate_estimator/include/bwe_defines.h
+++ b/modules/remote_bitrate_estimator/include/bwe_defines.h
@@ -51,11 +51,11 @@
 
 struct RateControlInput {
   RateControlInput(BandwidthUsage bw_state,
-                   const absl::optional<uint32_t>& estimated_throughput_bps);
+                   const absl::optional<DataRate>& estimated_throughput);
   ~RateControlInput();
 
   BandwidthUsage bw_state;
-  absl::optional<uint32_t> estimated_throughput_bps;
+  absl::optional<DataRate> estimated_throughput;
 };
 }  // namespace webrtc
 
diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc b/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc
index a7cfe4c..1ad35c7 100644
--- a/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc
+++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc
@@ -22,6 +22,16 @@
 #include "system_wrappers/include/metrics.h"
 
 namespace webrtc {
+namespace {
+absl::optional<DataRate> OptionalRateFromOptionalBps(
+    absl::optional<int> bitrate_bps) {
+  if (bitrate_bps) {
+    return DataRate::bps(*bitrate_bps);
+  } else {
+    return absl::nullopt;
+  }
+}
+}  // namespace
 
 enum {
   kTimestampGroupLengthMs = 5,
@@ -188,7 +198,8 @@
                        << " bps. Mean send delta: " << best_it->send_mean_ms
                        << " ms, mean recv delta: " << best_it->recv_mean_ms
                        << " ms, num probes: " << best_it->count;
-      remote_rate_.SetEstimate(probe_bitrate_bps, now_ms);
+      remote_rate_.SetEstimate(DataRate::bps(probe_bitrate_bps),
+                               Timestamp::ms(now_ms));
       return ProbeResult::kBitrateUpdated;
     }
   }
@@ -205,7 +216,7 @@
   bool initial_probe = !remote_rate_.ValidEstimate() && new_bitrate_bps > 0;
   bool bitrate_above_estimate =
       remote_rate_.ValidEstimate() &&
-      new_bitrate_bps > static_cast<int>(remote_rate_.LatestEstimate());
+      new_bitrate_bps > remote_rate_.LatestEstimate().bps<int>();
   return initial_probe || bitrate_above_estimate;
 }
 
@@ -316,13 +327,14 @@
       // Check if it's time for a periodic update or if we should update because
       // of an over-use.
       if (last_update_ms_ == -1 ||
-          now_ms - last_update_ms_ > remote_rate_.GetFeedbackInterval()) {
+          now_ms - last_update_ms_ > remote_rate_.GetFeedbackInterval().ms()) {
         update_estimate = true;
       } else if (detector_.State() == BandwidthUsage::kBwOverusing) {
         absl::optional<uint32_t> incoming_rate =
             incoming_bitrate_.Rate(arrival_time_ms);
         if (incoming_rate &&
-            remote_rate_.TimeToReduceFurther(now_ms, *incoming_rate)) {
+            remote_rate_.TimeToReduceFurther(Timestamp::ms(now_ms),
+                                             DataRate::bps(*incoming_rate))) {
           update_estimate = true;
         }
       }
@@ -332,9 +344,11 @@
       // The first overuse should immediately trigger a new estimate.
       // We also have to update the estimate immediately if we are overusing
       // and the target bitrate is too high compared to what we are receiving.
-      const RateControlInput input(detector_.State(),
-                                   incoming_bitrate_.Rate(arrival_time_ms));
-      target_bitrate_bps = remote_rate_.Update(&input, now_ms);
+      const RateControlInput input(
+          detector_.State(),
+          OptionalRateFromOptionalBps(incoming_bitrate_.Rate(arrival_time_ms)));
+      target_bitrate_bps =
+          remote_rate_.Update(&input, Timestamp::ms(now_ms)).bps<uint32_t>();
       update_estimate = remote_rate_.ValidEstimate();
       ssrcs = Keys(ssrcs_);
     }
@@ -374,7 +388,7 @@
 void RemoteBitrateEstimatorAbsSendTime::OnRttUpdate(int64_t avg_rtt_ms,
                                                     int64_t max_rtt_ms) {
   rtc::CritScope lock(&crit_);
-  remote_rate_.SetRtt(avg_rtt_ms);
+  remote_rate_.SetRtt(TimeDelta::ms(avg_rtt_ms));
 }
 
 void RemoteBitrateEstimatorAbsSendTime::RemoveStream(uint32_t ssrc) {
@@ -399,7 +413,7 @@
   if (ssrcs_.empty()) {
     *bitrate_bps = 0;
   } else {
-    *bitrate_bps = remote_rate_.LatestEstimate();
+    *bitrate_bps = remote_rate_.LatestEstimate().bps<uint32_t>();
   }
   return true;
 }
@@ -408,6 +422,6 @@
   // Called from both the configuration thread and the network thread. Shouldn't
   // be called from the network thread in the future.
   rtc::CritScope lock(&crit_);
-  remote_rate_.SetMinBitrate(min_bitrate_bps);
+  remote_rate_.SetMinBitrate(DataRate::bps(min_bitrate_bps));
 }
 }  // namespace webrtc
diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc b/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc
index 1f0de47..a267051 100644
--- a/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc
+++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc
@@ -27,6 +27,16 @@
 #include "system_wrappers/include/metrics.h"
 
 namespace webrtc {
+namespace {
+absl::optional<DataRate> OptionalRateFromOptionalBps(
+    absl::optional<int> bitrate_bps) {
+  if (bitrate_bps) {
+    return DataRate::bps(*bitrate_bps);
+  } else {
+    return absl::nullopt;
+  }
+}
+}  // namespace
 
 enum { kTimestampGroupLengthMs = 5 };
 static const double kTimestampToMs = 1.0 / 90.0;
@@ -133,7 +143,8 @@
         incoming_bitrate_.Rate(now_ms);
     if (incoming_bitrate_bps &&
         (prior_state != BandwidthUsage::kBwOverusing ||
-         GetRemoteRate()->TimeToReduceFurther(now_ms, *incoming_bitrate_bps))) {
+         GetRemoteRate()->TimeToReduceFurther(
+             Timestamp::ms(now_ms), DataRate::bps(*incoming_bitrate_bps)))) {
       // The first overuse should immediately trigger a new estimate.
       // We also have to update the estimate immediately if we are overusing
       // and the target bitrate is too high compared to what we are receiving.
@@ -187,10 +198,12 @@
   }
   AimdRateControl* remote_rate = GetRemoteRate();
 
-  const RateControlInput input(bw_state, incoming_bitrate_.Rate(now_ms));
-  uint32_t target_bitrate = remote_rate->Update(&input, now_ms);
+  const RateControlInput input(
+      bw_state, OptionalRateFromOptionalBps(incoming_bitrate_.Rate(now_ms)));
+  uint32_t target_bitrate =
+      remote_rate->Update(&input, Timestamp::ms(now_ms)).bps<uint32_t>();
   if (remote_rate->ValidEstimate()) {
-    process_interval_ms_ = remote_rate->GetFeedbackInterval();
+    process_interval_ms_ = remote_rate->GetFeedbackInterval().ms();
     RTC_DCHECK_GT(process_interval_ms_, 0);
     std::vector<uint32_t> ssrcs;
     GetSsrcs(&ssrcs);
@@ -202,7 +215,7 @@
 void RemoteBitrateEstimatorSingleStream::OnRttUpdate(int64_t avg_rtt_ms,
                                                      int64_t max_rtt_ms) {
   rtc::CritScope cs(&crit_sect_);
-  GetRemoteRate()->SetRtt(avg_rtt_ms);
+  GetRemoteRate()->SetRtt(TimeDelta::ms(avg_rtt_ms));
 }
 
 void RemoteBitrateEstimatorSingleStream::RemoveStream(unsigned int ssrc) {
@@ -226,7 +239,7 @@
   if (ssrcs->empty())
     *bitrate_bps = 0;
   else
-    *bitrate_bps = remote_rate_->LatestEstimate();
+    *bitrate_bps = remote_rate_->LatestEstimate().bps<uint32_t>();
   return true;
 }
 
@@ -249,7 +262,7 @@
 
 void RemoteBitrateEstimatorSingleStream::SetMinBitrate(int min_bitrate_bps) {
   rtc::CritScope cs(&crit_sect_);
-  remote_rate_->SetMinBitrate(min_bitrate_bps);
+  remote_rate_->SetMinBitrate(DataRate::bps(min_bitrate_bps));
 }
 
 }  // namespace webrtc
diff --git a/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc b/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc
index 120db13..2a4ef06 100644
--- a/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc
+++ b/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc
@@ -55,7 +55,7 @@
 }
 
 TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirteenStreamsWrap) {
-  CapacityDropTestHelper(13, true, 733, 0);
+  CapacityDropTestHelper(13, true, 567, 0);
 }
 
 TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropNineteenStreamsWrap) {