dcsctp: Use TimeDelta in TX path

This commit replaces the internal use of DurationMs, with millisecond
precision, to webrtc::TimeDelta, which uses microsecond precision.

This is just a refactoring. The only change to the public API is
convenience methods to convert between DurationMs and webrtc::TimeDelta.

Bug: webrtc:15593
Change-Id: Ida861bf585c716be5f898d0e7ef98da2c15268b7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/325402
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41062}
diff --git a/net/dcsctp/public/BUILD.gn b/net/dcsctp/public/BUILD.gn
index 6cb289b..032ffe5 100644
--- a/net/dcsctp/public/BUILD.gn
+++ b/net/dcsctp/public/BUILD.gn
@@ -11,6 +11,7 @@
 rtc_source_set("types") {
   deps = [
     "../../../api:array_view",
+    "../../../api/units:time_delta",
     "../../../rtc_base:strong_alias",
   ]
   sources = [
diff --git a/net/dcsctp/public/types.h b/net/dcsctp/public/types.h
index 7d69875..02e2ce1 100644
--- a/net/dcsctp/public/types.h
+++ b/net/dcsctp/public/types.h
@@ -14,6 +14,7 @@
 #include <cstdint>
 #include <limits>
 
+#include "api/units/time_delta.h"
 #include "rtc_base/strong_alias.h"
 
 namespace dcsctp {
@@ -41,6 +42,10 @@
   constexpr explicit DurationMs(const UnderlyingType& v)
       : webrtc::StrongAlias<class DurationMsTag, int32_t>(v) {}
 
+  constexpr explicit DurationMs(webrtc::TimeDelta v)
+      : webrtc::StrongAlias<class DurationMsTag, int32_t>(
+            v.IsInfinite() ? InfiniteDuration() : DurationMs(v.ms())) {}
+
   static constexpr DurationMs InfiniteDuration() {
     return DurationMs(std::numeric_limits<int32_t>::max());
   }
@@ -58,6 +63,11 @@
     value_ *= factor;
     return *this;
   }
+  constexpr webrtc::TimeDelta ToTimeDelta() const {
+    return *this == DurationMs::InfiniteDuration()
+               ? webrtc::TimeDelta::PlusInfinity()
+               : webrtc::TimeDelta::Millis(value_);
+  }
 };
 
 constexpr inline DurationMs operator+(DurationMs lhs, DurationMs rhs) {
diff --git a/net/dcsctp/socket/context.h b/net/dcsctp/socket/context.h
index eca5b9e..8823308 100644
--- a/net/dcsctp/socket/context.h
+++ b/net/dcsctp/socket/context.h
@@ -39,8 +39,8 @@
   // Returns the socket callbacks.
   virtual DcSctpSocketCallbacks& callbacks() const = 0;
 
-  // Observes a measured RTT value, in milliseconds.
-  virtual void ObserveRTT(DurationMs rtt_ms) = 0;
+  // Observes a measured RTT value.
+  virtual void ObserveRTT(webrtc::TimeDelta rtt_ms) = 0;
 
   // Returns the current Retransmission Timeout (rto) value, in milliseconds.
   virtual DurationMs current_rto() const = 0;
diff --git a/net/dcsctp/socket/heartbeat_handler.cc b/net/dcsctp/socket/heartbeat_handler.cc
index 8d1d04a..3e0437b 100644
--- a/net/dcsctp/socket/heartbeat_handler.cc
+++ b/net/dcsctp/socket/heartbeat_handler.cc
@@ -155,7 +155,7 @@
 
   TimeMs now = ctx_->callbacks().TimeMillis();
   if (info->created_at() > TimeMs(0) && info->created_at() <= now) {
-    ctx_->ObserveRTT(now - info->created_at());
+    ctx_->ObserveRTT((now - info->created_at()).ToTimeDelta());
   }
 
   // https://tools.ietf.org/html/rfc4960#section-8.1
diff --git a/net/dcsctp/socket/heartbeat_handler_test.cc b/net/dcsctp/socket/heartbeat_handler_test.cc
index d573192..fc7cd52 100644
--- a/net/dcsctp/socket/heartbeat_handler_test.cc
+++ b/net/dcsctp/socket/heartbeat_handler_test.cc
@@ -30,6 +30,7 @@
 using ::testing::NiceMock;
 using ::testing::Return;
 using ::testing::SizeIs;
+using ::webrtc::TimeDelta;
 
 constexpr DurationMs kHeartbeatInterval = DurationMs(30'000);
 
@@ -136,7 +137,7 @@
   // Respond a while later. This RTT will be measured by the handler
   constexpr DurationMs rtt(313);
 
-  EXPECT_CALL(context_, ObserveRTT(rtt)).Times(1);
+  EXPECT_CALL(context_, ObserveRTT(rtt.ToTimeDelta())).Times(1);
 
   callbacks_.AdvanceTime(rtt);
   handler_.HandleHeartbeatAck(std::move(ack));
diff --git a/net/dcsctp/socket/mock_context.h b/net/dcsctp/socket/mock_context.h
index 88e71d1..7c5cd4e 100644
--- a/net/dcsctp/socket/mock_context.h
+++ b/net/dcsctp/socket/mock_context.h
@@ -51,7 +51,7 @@
   MOCK_METHOD(TSN, peer_initial_tsn, (), (const, override));
   MOCK_METHOD(DcSctpSocketCallbacks&, callbacks, (), (const, override));
 
-  MOCK_METHOD(void, ObserveRTT, (DurationMs rtt_ms), (override));
+  MOCK_METHOD(void, ObserveRTT, (webrtc::TimeDelta rtt), (override));
   MOCK_METHOD(DurationMs, current_rto, (), (const, override));
   MOCK_METHOD(bool,
               IncrementTxErrorCounter,
diff --git a/net/dcsctp/socket/stream_reset_handler_test.cc b/net/dcsctp/socket/stream_reset_handler_test.cc
index 4b12970..d459450 100644
--- a/net/dcsctp/socket/stream_reset_handler_test.cc
+++ b/net/dcsctp/socket/stream_reset_handler_test.cc
@@ -48,6 +48,7 @@
 using ::testing::Return;
 using ::testing::SizeIs;
 using ::testing::UnorderedElementsAre;
+using ::webrtc::TimeDelta;
 using ResponseResult = ReconfigurationResponseParameter::Result;
 using SkippedStream = AnyForwardTsnChunk::SkippedStream;
 
@@ -115,7 +116,7 @@
             kMyInitialTsn,
             kArwnd,
             producer_,
-            [](DurationMs rtt_ms) {},
+            [](TimeDelta rtt) {},
             []() {},
             *t3_rtx_timer_,
             DcSctpOptions())),
@@ -205,7 +206,7 @@
     reasm_->RestoreFromState(state);
     retransmission_queue_ = std::make_unique<RetransmissionQueue>(
         "", &callbacks_, kMyInitialTsn, kArwnd, producer_,
-        [](DurationMs rtt_ms) {}, []() {}, *t3_rtx_timer_, DcSctpOptions(),
+        [](TimeDelta rtt) {}, []() {}, *t3_rtx_timer_, DcSctpOptions(),
         /*supports_partial_reliability=*/true,
         /*use_message_interleaving=*/false);
     retransmission_queue_->RestoreFromState(state);
diff --git a/net/dcsctp/socket/transmission_control_block.cc b/net/dcsctp/socket/transmission_control_block.cc
index c403b06..c1d3533 100644
--- a/net/dcsctp/socket/transmission_control_block.cc
+++ b/net/dcsctp/socket/transmission_control_block.cc
@@ -37,6 +37,7 @@
 #include "rtc_base/strings/string_builder.h"
 
 namespace dcsctp {
+using ::webrtc::TimeDelta;
 
 TransmissionControlBlock::TransmissionControlBlock(
     TimerManager& timer_manager,
@@ -112,10 +113,10 @@
   send_queue.EnableMessageInterleaving(capabilities.message_interleaving);
 }
 
-void TransmissionControlBlock::ObserveRTT(DurationMs rtt) {
+void TransmissionControlBlock::ObserveRTT(TimeDelta rtt) {
   DurationMs prev_rto = rto_.rto();
-  rto_.ObserveRTT(rtt);
-  RTC_DLOG(LS_VERBOSE) << log_prefix_ << "new rtt=" << *rtt
+  rto_.ObserveRTT(DurationMs(rtt));
+  RTC_DLOG(LS_VERBOSE) << log_prefix_ << "new rtt=" << webrtc::ToString(rtt)
                        << ", srtt=" << *rto_.srtt() << ", rto=" << *rto_.rto()
                        << " (" << *prev_rto << ")";
   t3_rtx_->set_duration(rto_.rto());
diff --git a/net/dcsctp/socket/transmission_control_block.h b/net/dcsctp/socket/transmission_control_block.h
index 240454a..8fda890 100644
--- a/net/dcsctp/socket/transmission_control_block.h
+++ b/net/dcsctp/socket/transmission_control_block.h
@@ -67,7 +67,7 @@
   TSN my_initial_tsn() const override { return my_initial_tsn_; }
   TSN peer_initial_tsn() const override { return peer_initial_tsn_; }
   DcSctpSocketCallbacks& callbacks() const override { return callbacks_; }
-  void ObserveRTT(DurationMs rtt) override;
+  void ObserveRTT(webrtc::TimeDelta rtt) override;
   DurationMs current_rto() const override { return rto_.rto(); }
   bool IncrementTxErrorCounter(absl::string_view reason) override {
     return tx_error_counter_.Increment(reason);
diff --git a/net/dcsctp/tx/BUILD.gn b/net/dcsctp/tx/BUILD.gn
index 5547ffa..cd42768 100644
--- a/net/dcsctp/tx/BUILD.gn
+++ b/net/dcsctp/tx/BUILD.gn
@@ -103,6 +103,7 @@
     ":retransmission_timeout",
     ":send_queue",
     "../../../api:array_view",
+    "../../../api/units:time_delta",
     "../../../rtc_base:checks",
     "../../../rtc_base:logging",
     "../../../rtc_base/containers:flat_set",
diff --git a/net/dcsctp/tx/outstanding_data.cc b/net/dcsctp/tx/outstanding_data.cc
index c2706bd..2a92f14 100644
--- a/net/dcsctp/tx/outstanding_data.cc
+++ b/net/dcsctp/tx/outstanding_data.cc
@@ -14,6 +14,7 @@
 #include <utility>
 #include <vector>
 
+#include "api/units/time_delta.h"
 #include "net/dcsctp/common/math.h"
 #include "net/dcsctp/common/sequence_numbers.h"
 #include "net/dcsctp/public/types.h"
@@ -441,8 +442,8 @@
   RTC_DCHECK(IsConsistent());
 }
 
-absl::optional<DurationMs> OutstandingData::MeasureRTT(TimeMs now,
-                                                       UnwrappedTSN tsn) const {
+webrtc::TimeDelta OutstandingData::MeasureRTT(TimeMs now,
+                                              UnwrappedTSN tsn) const {
   auto it = outstanding_data_.find(tsn);
   if (it != outstanding_data_.end() && !it->second.has_been_retransmitted()) {
     // https://tools.ietf.org/html/rfc4960#section-6.3.1
@@ -450,9 +451,9 @@
     // packets that were retransmitted (and thus for which it is ambiguous
     // whether the reply was for the first instance of the chunk or for a
     // later instance)"
-    return now - it->second.time_sent();
+    return (now - it->second.time_sent()).ToTimeDelta();
   }
-  return absl::nullopt;
+  return webrtc::TimeDelta::PlusInfinity();
 }
 
 std::vector<std::pair<TSN, OutstandingData::State>>
diff --git a/net/dcsctp/tx/outstanding_data.h b/net/dcsctp/tx/outstanding_data.h
index f8e9396..323f2de 100644
--- a/net/dcsctp/tx/outstanding_data.h
+++ b/net/dcsctp/tx/outstanding_data.h
@@ -147,8 +147,8 @@
 
   // Given the current time and a TSN, it returns the measured RTT between when
   // the chunk was sent and now. It takes into acccount Karn's algorithm, so if
-  // the chunk has ever been retransmitted, it will return absl::nullopt.
-  absl::optional<DurationMs> MeasureRTT(TimeMs now, UnwrappedTSN tsn) const;
+  // the chunk has ever been retransmitted, it will return `PlusInfinity()`.
+  webrtc::TimeDelta MeasureRTT(TimeMs now, UnwrappedTSN tsn) const;
 
   // Returns the internal state of all queued chunks. This is only used in
   // unit-tests.
diff --git a/net/dcsctp/tx/outstanding_data_test.cc b/net/dcsctp/tx/outstanding_data_test.cc
index b8c2e59..e119a56 100644
--- a/net/dcsctp/tx/outstanding_data_test.cc
+++ b/net/dcsctp/tx/outstanding_data_test.cc
@@ -37,6 +37,7 @@
 using ::testing::Return;
 using ::testing::StrictMock;
 using ::testing::UnorderedElementsAre;
+using ::webrtc::TimeDelta;
 
 constexpr TimeMs kNow(42);
 constexpr OutgoingMessageId kMessageId = OutgoingMessageId(17);
@@ -365,12 +366,11 @@
   buf_.Insert(kMessageId, gen_.Ordered({1}, "BE"), kNow + DurationMs(1));
   buf_.Insert(kMessageId, gen_.Ordered({1}, "BE"), kNow + DurationMs(2));
 
-  static constexpr DurationMs kDuration(123);
-  ASSERT_HAS_VALUE_AND_ASSIGN(
-      DurationMs duration,
-      buf_.MeasureRTT(kNow + kDuration, unwrapper_.Unwrap(TSN(11))));
+  static constexpr TimeDelta kDuration = TimeDelta::Millis(123);
+  TimeDelta duration =
+      buf_.MeasureRTT(kNow + DurationMs(kDuration), unwrapper_.Unwrap(TSN(11)));
 
-  EXPECT_EQ(duration, kDuration - DurationMs(1));
+  EXPECT_EQ(duration, kDuration - TimeDelta::Millis(1));
 }
 
 TEST_F(OutstandingDataTest, MustRetransmitBeforeGettingNackedAgain) {
diff --git a/net/dcsctp/tx/retransmission_queue.cc b/net/dcsctp/tx/retransmission_queue.cc
index 2b9843f..2b166f1 100644
--- a/net/dcsctp/tx/retransmission_queue.cc
+++ b/net/dcsctp/tx/retransmission_queue.cc
@@ -44,6 +44,7 @@
 
 namespace dcsctp {
 namespace {
+using ::webrtc::TimeDelta;
 
 // Allow sending only slightly less than an MTU, to account for headers.
 constexpr float kMinBytesRequiredToSendFactor = 0.9;
@@ -55,7 +56,7 @@
     TSN my_initial_tsn,
     size_t a_rwnd,
     SendQueue& send_queue,
-    std::function<void(DurationMs rtt)> on_new_rtt,
+    std::function<void(TimeDelta rtt)> on_new_rtt,
     std::function<void()> on_clear_retransmission_counter,
     Timer& t3_rtx,
     const DcSctpOptions& options,
@@ -345,11 +346,10 @@
   // TODO(boivie): Consider occasionally sending DATA chunks with I-bit set and
   // use only those packets for measurement.
 
-  absl::optional<DurationMs> rtt =
-      outstanding_data_.MeasureRTT(now, cumulative_tsn_ack);
+  TimeDelta rtt = outstanding_data_.MeasureRTT(now, cumulative_tsn_ack);
 
-  if (rtt.has_value()) {
-    on_new_rtt_(*rtt);
+  if (rtt.IsFinite()) {
+    on_new_rtt_(rtt);
   }
 }
 
diff --git a/net/dcsctp/tx/retransmission_queue.h b/net/dcsctp/tx/retransmission_queue.h
index b44db2a..d4c6edf 100644
--- a/net/dcsctp/tx/retransmission_queue.h
+++ b/net/dcsctp/tx/retransmission_queue.h
@@ -60,7 +60,7 @@
                       TSN my_initial_tsn,
                       size_t a_rwnd,
                       SendQueue& send_queue,
-                      std::function<void(DurationMs rtt)> on_new_rtt,
+                      std::function<void(webrtc::TimeDelta rtt)> on_new_rtt,
                       std::function<void()> on_clear_retransmission_counter,
                       Timer& t3_rtx,
                       const DcSctpOptions& options,
@@ -230,7 +230,7 @@
   // The size of the data chunk (DATA/I-DATA) header that is used.
   const size_t data_chunk_header_size_;
   // Called when a new RTT measurement has been done
-  const std::function<void(DurationMs rtt)> on_new_rtt_;
+  const std::function<void(webrtc::TimeDelta rtt)> on_new_rtt_;
   // Called when a SACK has been seen that cleared the retransmission counter.
   const std::function<void()> on_clear_retransmission_counter_;
   // The retransmission counter.
diff --git a/net/dcsctp/tx/retransmission_queue_test.cc b/net/dcsctp/tx/retransmission_queue_test.cc
index 096bb12..d7b39e50 100644
--- a/net/dcsctp/tx/retransmission_queue_test.cc
+++ b/net/dcsctp/tx/retransmission_queue_test.cc
@@ -52,6 +52,7 @@
 using ::testing::Return;
 using ::testing::SizeIs;
 using ::testing::UnorderedElementsAre;
+using ::webrtc::TimeDelta;
 
 constexpr uint32_t kArwnd = 100000;
 constexpr uint32_t kMaxMtu = 1191;
@@ -130,7 +131,7 @@
   TimeMs now_ = TimeMs(0);
   FakeTimeoutManager timeout_manager_;
   TimerManager timer_manager_;
-  NiceMock<MockFunction<void(DurationMs rtt_ms)>> on_rtt_;
+  NiceMock<MockFunction<void(TimeDelta rtt_ms)>> on_rtt_;
   NiceMock<MockFunction<void()>> on_clear_retransmission_counter_;
   NiceMock<MockSendQueue> producer_;
   std::unique_ptr<Timer> timer_;
@@ -864,7 +865,7 @@
 
   now_ = now_ + DurationMs(123);
 
-  EXPECT_CALL(on_rtt_, Call(DurationMs(123))).Times(1);
+  EXPECT_CALL(on_rtt_, Call(TimeDelta::Millis(123))).Times(1);
   queue.HandleSack(now_, SackChunk(TSN(10), kArwnd, {}, {}));
 }