Track last packet receive times in RtpVideoStreamReceiver instead of the PacketBuffer.

Bug: webrtc:12579
Change-Id: I4adb8c6ada913127b9e65d97ddce0dc71ec6ccee
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/214784
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33713}
diff --git a/modules/video_coding/packet_buffer.cc b/modules/video_coding/packet_buffer.cc
index cc4b8c1..0d4c085 100644
--- a/modules/video_coding/packet_buffer.cc
+++ b/modules/video_coding/packet_buffer.cc
@@ -30,7 +30,6 @@
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/numerics/mod_ops.h"
-#include "system_wrappers/include/clock.h"
 
 namespace webrtc {
 namespace video_coding {
@@ -51,11 +50,8 @@
                   rtp_packet.GetExtension<AbsoluteCaptureTimeExtension>(),
                   receive_time_ms) {}
 
-PacketBuffer::PacketBuffer(Clock* clock,
-                           size_t start_buffer_size,
-                           size_t max_buffer_size)
-    : clock_(clock),
-      max_size_(max_buffer_size),
+PacketBuffer::PacketBuffer(size_t start_buffer_size, size_t max_buffer_size)
+    : max_size_(max_buffer_size),
       first_seq_num_(0),
       first_packet_received_(false),
       is_cleared_to_first_seq_num_(false),
@@ -114,14 +110,6 @@
     }
   }
 
-  int64_t now_ms = clock_->TimeInMilliseconds();
-  last_received_packet_ms_ = now_ms;
-  if (packet->video_header.frame_type == VideoFrameType::kVideoFrameKey ||
-      last_received_keyframe_rtp_timestamp_ == packet->timestamp) {
-    last_received_keyframe_packet_ms_ = now_ms;
-    last_received_keyframe_rtp_timestamp_ = packet->timestamp;
-  }
-
   packet->continuous = false;
   buffer_[index] = std::move(packet);
 
@@ -181,18 +169,10 @@
   return result;
 }
 
-absl::optional<int64_t> PacketBuffer::LastReceivedPacketMs() const {
-  MutexLock lock(&mutex_);
-  return last_received_packet_ms_;
-}
-
-absl::optional<int64_t> PacketBuffer::LastReceivedKeyframePacketMs() const {
-  MutexLock lock(&mutex_);
-  return last_received_keyframe_packet_ms_;
-}
 void PacketBuffer::ForceSpsPpsIdrIsH264Keyframe() {
   sps_pps_idr_is_h264_keyframe_ = true;
 }
+
 void PacketBuffer::ClearInternal() {
   for (auto& entry : buffer_) {
     entry = nullptr;
@@ -200,8 +180,6 @@
 
   first_packet_received_ = false;
   is_cleared_to_first_seq_num_ = false;
-  last_received_packet_ms_.reset();
-  last_received_keyframe_packet_ms_.reset();
   newest_inserted_seq_num_.reset();
   missing_packets_.clear();
 }
diff --git a/modules/video_coding/packet_buffer.h b/modules/video_coding/packet_buffer.h
index 35dcf82..eb8d836 100644
--- a/modules/video_coding/packet_buffer.h
+++ b/modules/video_coding/packet_buffer.h
@@ -25,7 +25,6 @@
 #include "rtc_base/numerics/sequence_number_util.h"
 #include "rtc_base/synchronization/mutex.h"
 #include "rtc_base/thread_annotations.h"
-#include "system_wrappers/include/clock.h"
 
 namespace webrtc {
 namespace video_coding {
@@ -76,7 +75,7 @@
   };
 
   // Both |start_buffer_size| and |max_buffer_size| must be a power of 2.
-  PacketBuffer(Clock* clock, size_t start_buffer_size, size_t max_buffer_size);
+  PacketBuffer(size_t start_buffer_size, size_t max_buffer_size);
   ~PacketBuffer();
 
   ABSL_MUST_USE_RESULT InsertResult InsertPacket(std::unique_ptr<Packet> packet)
@@ -86,16 +85,9 @@
   void ClearTo(uint16_t seq_num) RTC_LOCKS_EXCLUDED(mutex_);
   void Clear() RTC_LOCKS_EXCLUDED(mutex_);
 
-  // Timestamp (not RTP timestamp) of the last received packet/keyframe packet.
-  absl::optional<int64_t> LastReceivedPacketMs() const
-      RTC_LOCKS_EXCLUDED(mutex_);
-  absl::optional<int64_t> LastReceivedKeyframePacketMs() const
-      RTC_LOCKS_EXCLUDED(mutex_);
   void ForceSpsPpsIdrIsH264Keyframe();
 
  private:
-  Clock* const clock_;
-
   // Clears with |mutex_| taken.
   void ClearInternal() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
 
@@ -132,13 +124,6 @@
   // determine continuity between them.
   std::vector<std::unique_ptr<Packet>> buffer_ RTC_GUARDED_BY(mutex_);
 
-  // Timestamp of the last received packet/keyframe packet.
-  absl::optional<int64_t> last_received_packet_ms_ RTC_GUARDED_BY(mutex_);
-  absl::optional<int64_t> last_received_keyframe_packet_ms_
-      RTC_GUARDED_BY(mutex_);
-  absl::optional<uint32_t> last_received_keyframe_rtp_timestamp_
-      RTC_GUARDED_BY(mutex_);
-
   absl::optional<uint16_t> newest_inserted_seq_num_ RTC_GUARDED_BY(mutex_);
   std::set<uint16_t, DescendingSeqNumComp<uint16_t>> missing_packets_
       RTC_GUARDED_BY(mutex_);
diff --git a/modules/video_coding/packet_buffer_unittest.cc b/modules/video_coding/packet_buffer_unittest.cc
index a01b480..97012618 100644
--- a/modules/video_coding/packet_buffer_unittest.cc
+++ b/modules/video_coding/packet_buffer_unittest.cc
@@ -19,7 +19,6 @@
 #include "common_video/h264/h264_common.h"
 #include "modules/video_coding/frame_object.h"
 #include "rtc_base/random.h"
-#include "system_wrappers/include/clock.h"
 #include "test/field_trial.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
@@ -100,10 +99,7 @@
 
 class PacketBufferTest : public ::testing::Test {
  protected:
-  PacketBufferTest()
-      : rand_(0x7732213),
-        clock_(0),
-        packet_buffer_(&clock_, kStartSize, kMaxSize) {}
+  PacketBufferTest() : rand_(0x7732213), packet_buffer_(kStartSize, kMaxSize) {}
 
   uint16_t Rand() { return rand_.Rand<uint16_t>(); }
 
@@ -133,7 +129,6 @@
   }
 
   Random rand_;
-  SimulatedClock clock_;
   PacketBuffer packet_buffer_;
 };
 
@@ -616,67 +611,6 @@
   EXPECT_THAT(Insert(3, kKeyFrame, kNotFirst, kLast).packets, IsEmpty());
 }
 
-TEST_F(PacketBufferTest, PacketTimestamps) {
-  absl::optional<int64_t> packet_ms;
-  absl::optional<int64_t> packet_keyframe_ms;
-
-  packet_ms = packet_buffer_.LastReceivedPacketMs();
-  packet_keyframe_ms = packet_buffer_.LastReceivedKeyframePacketMs();
-  EXPECT_FALSE(packet_ms);
-  EXPECT_FALSE(packet_keyframe_ms);
-
-  int64_t keyframe_ms = clock_.TimeInMilliseconds();
-  Insert(100, kKeyFrame, kFirst, kLast, {}, /*timestamp=*/1000);
-  packet_ms = packet_buffer_.LastReceivedPacketMs();
-  packet_keyframe_ms = packet_buffer_.LastReceivedKeyframePacketMs();
-  EXPECT_TRUE(packet_ms);
-  EXPECT_TRUE(packet_keyframe_ms);
-  EXPECT_EQ(keyframe_ms, *packet_ms);
-  EXPECT_EQ(keyframe_ms, *packet_keyframe_ms);
-
-  clock_.AdvanceTimeMilliseconds(100);
-  int64_t delta_ms = clock_.TimeInMilliseconds();
-  Insert(101, kDeltaFrame, kFirst, kLast, {}, /*timestamp=*/2000);
-  packet_ms = packet_buffer_.LastReceivedPacketMs();
-  packet_keyframe_ms = packet_buffer_.LastReceivedKeyframePacketMs();
-  EXPECT_TRUE(packet_ms);
-  EXPECT_TRUE(packet_keyframe_ms);
-  EXPECT_EQ(delta_ms, *packet_ms);
-  EXPECT_EQ(keyframe_ms, *packet_keyframe_ms);
-
-  packet_buffer_.Clear();
-  packet_ms = packet_buffer_.LastReceivedPacketMs();
-  packet_keyframe_ms = packet_buffer_.LastReceivedKeyframePacketMs();
-  EXPECT_FALSE(packet_ms);
-  EXPECT_FALSE(packet_keyframe_ms);
-}
-
-TEST_F(PacketBufferTest,
-       LastReceivedKeyFrameReturnsReceiveTimeOfALastReceivedPacketOfAKeyFrame) {
-  clock_.AdvanceTimeMilliseconds(100);
-  Insert(/*seq_num=*/100, kKeyFrame, kFirst, kNotLast, {}, /*timestamp=*/1000);
-  EXPECT_EQ(packet_buffer_.LastReceivedKeyframePacketMs(),
-            clock_.TimeInMilliseconds());
-
-  clock_.AdvanceTimeMilliseconds(100);
-  Insert(/*seq_num=*/102, kDeltaFrame, kNotFirst, kLast, {},
-         /*timestamp=*/1000);
-  EXPECT_EQ(packet_buffer_.LastReceivedKeyframePacketMs(),
-            clock_.TimeInMilliseconds());
-
-  clock_.AdvanceTimeMilliseconds(100);
-  Insert(/*seq_num=*/101, kDeltaFrame, kNotFirst, kNotLast, {},
-         /*timestamp=*/1000);
-  EXPECT_EQ(packet_buffer_.LastReceivedKeyframePacketMs(),
-            clock_.TimeInMilliseconds());
-
-  clock_.AdvanceTimeMilliseconds(100);
-  Insert(/*seq_num=*/103, kDeltaFrame, kFirst, kNotLast, {},
-         /*timestamp=*/2000);
-  EXPECT_EQ(packet_buffer_.LastReceivedKeyframePacketMs(),
-            clock_.TimeInMilliseconds() - 100);
-}
-
 TEST_F(PacketBufferTest, IncomingCodecChange) {
   auto packet = std::make_unique<PacketBuffer::Packet>();
   packet->video_header.is_first_packet_in_frame = true;
diff --git a/test/fuzzers/packet_buffer_fuzzer.cc b/test/fuzzers/packet_buffer_fuzzer.cc
index f1872e3..ea9d489 100644
--- a/test/fuzzers/packet_buffer_fuzzer.cc
+++ b/test/fuzzers/packet_buffer_fuzzer.cc
@@ -13,7 +13,6 @@
 
 #include "modules/video_coding/frame_object.h"
 #include "modules/video_coding/packet_buffer.h"
-#include "system_wrappers/include/clock.h"
 #include "test/fuzzers/fuzz_data_helper.h"
 
 namespace webrtc {
@@ -24,8 +23,7 @@
   if (size > 200000) {
     return;
   }
-  SimulatedClock clock(0);
-  video_coding::PacketBuffer packet_buffer(&clock, 8, 1024);
+  video_coding::PacketBuffer packet_buffer(8, 1024);
   test::FuzzDataHelper helper(rtc::ArrayView<const uint8_t>(data, size));
 
   while (helper.BytesLeft()) {
diff --git a/video/BUILD.gn b/video/BUILD.gn
index e4c1986..35ad044 100644
--- a/video/BUILD.gn
+++ b/video/BUILD.gn
@@ -164,6 +164,7 @@
     "../api:sequence_checker",
     "../api/crypto:frame_decryptor_interface",
     "../api/task_queue",
+    "../api/units:timestamp",
     "../api/video:encoded_image",
     "../api/video:recordable_encoded_frame",
     "../api/video:video_frame",
diff --git a/video/rtp_video_stream_receiver.cc b/video/rtp_video_stream_receiver.cc
index be208ce..e092fe7 100644
--- a/video/rtp_video_stream_receiver.cc
+++ b/video/rtp_video_stream_receiver.cc
@@ -271,7 +271,7 @@
       // TODO(bugs.webrtc.org/10336): Let |rtcp_feedback_buffer_| communicate
       // directly with |rtp_rtcp_|.
       rtcp_feedback_buffer_(this, nack_sender, this),
-      packet_buffer_(clock_, kPacketBufferStartSize, PacketBufferMaxSize()),
+      packet_buffer_(kPacketBufferStartSize, PacketBufferMaxSize()),
       has_received_frame_(false),
       frames_decryptable_(false),
       absolute_capture_time_receiver_(clock) {
@@ -384,11 +384,11 @@
   }
   {
     MutexLock lock(&sync_info_lock_);
-    if (!last_received_rtp_timestamp_ || !last_received_rtp_system_time_ms_) {
+    if (!last_received_rtp_timestamp_ || !last_received_rtp_system_time_) {
       return absl::nullopt;
     }
     info.latest_received_capture_timestamp = *last_received_rtp_timestamp_;
-    info.latest_receive_time_ms = *last_received_rtp_system_time_ms_;
+    info.latest_receive_time_ms = last_received_rtp_system_time_->ms();
   }
 
   // Leaves info.current_delay_ms uninitialized.
@@ -543,6 +543,12 @@
 
   ParseGenericDependenciesResult generic_descriptor_state =
       ParseGenericDependenciesExtension(rtp_packet, &video_header);
+
+  if (!rtp_packet.recovered()) {
+    UpdatePacketReceiveTimestamps(
+        rtp_packet, video_header.frame_type == VideoFrameType::kVideoFrameKey);
+  }
+
   if (generic_descriptor_state == kDropPacket)
     return;
 
@@ -671,35 +677,6 @@
     return;
   }
 
-  if (!packet.recovered()) {
-    // TODO(nisse): Exclude out-of-order packets?
-    int64_t now_ms = clock_->TimeInMilliseconds();
-    {
-      MutexLock lock(&sync_info_lock_);
-      last_received_rtp_timestamp_ = packet.Timestamp();
-      last_received_rtp_system_time_ms_ = now_ms;
-    }
-    // Periodically log the RTP header of incoming packets.
-    if (now_ms - last_packet_log_ms_ > kPacketLogIntervalMs) {
-      rtc::StringBuilder ss;
-      ss << "Packet received on SSRC: " << packet.Ssrc()
-         << " with payload type: " << static_cast<int>(packet.PayloadType())
-         << ", timestamp: " << packet.Timestamp()
-         << ", sequence number: " << packet.SequenceNumber()
-         << ", arrival time: " << packet.arrival_time_ms();
-      int32_t time_offset;
-      if (packet.GetExtension<TransmissionOffset>(&time_offset)) {
-        ss << ", toffset: " << time_offset;
-      }
-      uint32_t send_time;
-      if (packet.GetExtension<AbsoluteSendTime>(&send_time)) {
-        ss << ", abs send time: " << send_time;
-      }
-      RTC_LOG(LS_INFO) << ss.str();
-      last_packet_log_ms_ = now_ms;
-    }
-  }
-
   ReceivePacket(packet);
 
   // Update receive statistics after ReceivePacket.
@@ -942,12 +919,21 @@
 }
 
 absl::optional<int64_t> RtpVideoStreamReceiver::LastReceivedPacketMs() const {
-  return packet_buffer_.LastReceivedPacketMs();
+  MutexLock lock(&sync_info_lock_);
+  if (last_received_rtp_system_time_) {
+    return absl::optional<int64_t>(last_received_rtp_system_time_->ms());
+  }
+  return absl::nullopt;
 }
 
 absl::optional<int64_t> RtpVideoStreamReceiver::LastReceivedKeyframePacketMs()
     const {
-  return packet_buffer_.LastReceivedKeyframePacketMs();
+  MutexLock lock(&sync_info_lock_);
+  if (last_received_keyframe_rtp_system_time_) {
+    return absl::optional<int64_t>(
+        last_received_keyframe_rtp_system_time_->ms());
+  }
+  return absl::nullopt;
 }
 
 void RtpVideoStreamReceiver::AddSecondarySink(RtpPacketSinkInterface* sink) {
@@ -1183,4 +1169,38 @@
                              sprop_decoder.pps_nalu());
 }
 
+void RtpVideoStreamReceiver::UpdatePacketReceiveTimestamps(
+    const RtpPacketReceived& packet,
+    bool is_keyframe) {
+  Timestamp now = clock_->CurrentTime();
+  {
+    MutexLock lock(&sync_info_lock_);
+    if (is_keyframe) {
+      last_received_keyframe_rtp_system_time_ = now;
+    }
+    last_received_rtp_system_time_ = now;
+    last_received_rtp_timestamp_ = packet.Timestamp();
+  }
+
+  // Periodically log the RTP header of incoming packets.
+  if (now.ms() - last_packet_log_ms_ > kPacketLogIntervalMs) {
+    rtc::StringBuilder ss;
+    ss << "Packet received on SSRC: " << packet.Ssrc()
+       << " with payload type: " << static_cast<int>(packet.PayloadType())
+       << ", timestamp: " << packet.Timestamp()
+       << ", sequence number: " << packet.SequenceNumber()
+       << ", arrival time: " << packet.arrival_time_ms();
+    int32_t time_offset;
+    if (packet.GetExtension<TransmissionOffset>(&time_offset)) {
+      ss << ", toffset: " << time_offset;
+    }
+    uint32_t send_time;
+    if (packet.GetExtension<AbsoluteSendTime>(&send_time)) {
+      ss << ", abs send time: " << send_time;
+    }
+    RTC_LOG(LS_INFO) << ss.str();
+    last_packet_log_ms_ = now.ms();
+  }
+}
+
 }  // namespace webrtc
diff --git a/video/rtp_video_stream_receiver.h b/video/rtp_video_stream_receiver.h
index cc3499a..7a84519 100644
--- a/video/rtp_video_stream_receiver.h
+++ b/video/rtp_video_stream_receiver.h
@@ -22,6 +22,7 @@
 #include "api/array_view.h"
 #include "api/crypto/frame_decryptor_interface.h"
 #include "api/sequence_checker.h"
+#include "api/units/timestamp.h"
 #include "api/video/color_space.h"
 #include "api/video_codecs/video_codec.h"
 #include "call/rtp_packet_sink_interface.h"
@@ -303,6 +304,9 @@
       const RtpPacketReceived& rtp_packet,
       RTPVideoHeader* video_header) RTC_RUN_ON(worker_task_checker_);
   void OnAssembledFrame(std::unique_ptr<RtpFrameObject> frame);
+  void UpdatePacketReceiveTimestamps(const RtpPacketReceived& packet,
+                                     bool is_keyframe)
+      RTC_RUN_ON(worker_task_checker_);
 
   Clock* const clock_;
   // Ownership of this object lies with VideoReceiveStream, which owns |this|.
@@ -378,7 +382,9 @@
   mutable Mutex sync_info_lock_;
   absl::optional<uint32_t> last_received_rtp_timestamp_
       RTC_GUARDED_BY(sync_info_lock_);
-  absl::optional<int64_t> last_received_rtp_system_time_ms_
+  absl::optional<Timestamp> last_received_rtp_system_time_
+      RTC_GUARDED_BY(sync_info_lock_);
+  absl::optional<Timestamp> last_received_keyframe_rtp_system_time_
       RTC_GUARDED_BY(sync_info_lock_);
 
   // Used to validate the buffered frame decryptor is always run on the correct
diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc
index 6664820..3c23a3d 100644
--- a/video/rtp_video_stream_receiver2.cc
+++ b/video/rtp_video_stream_receiver2.cc
@@ -250,7 +250,7 @@
                                             clock_,
                                             &rtcp_feedback_buffer_,
                                             &rtcp_feedback_buffer_)),
-      packet_buffer_(clock_, kPacketBufferStartSize, PacketBufferMaxSize()),
+      packet_buffer_(kPacketBufferStartSize, PacketBufferMaxSize()),
       has_received_frame_(false),
       frames_decryptable_(false),
       absolute_capture_time_receiver_(clock) {
@@ -353,11 +353,11 @@
     return absl::nullopt;
   }
 
-  if (!last_received_rtp_timestamp_ || !last_received_rtp_system_time_ms_) {
+  if (!last_received_rtp_timestamp_ || !last_received_rtp_system_time_) {
     return absl::nullopt;
   }
   info.latest_received_capture_timestamp = *last_received_rtp_timestamp_;
-  info.latest_receive_time_ms = *last_received_rtp_system_time_ms_;
+  info.latest_receive_time_ms = last_received_rtp_system_time_->ms();
 
   // Leaves info.current_delay_ms uninitialized.
   return info;
@@ -511,6 +511,12 @@
 
   ParseGenericDependenciesResult generic_descriptor_state =
       ParseGenericDependenciesExtension(rtp_packet, &video_header);
+
+  if (!rtp_packet.recovered()) {
+    UpdatePacketReceiveTimestamps(
+        rtp_packet, video_header.frame_type == VideoFrameType::kVideoFrameKey);
+  }
+
   if (generic_descriptor_state == kDropPacket)
     return;
 
@@ -639,34 +645,6 @@
     return;
   }
 
-  if (!packet.recovered()) {
-    // TODO(nisse): Exclude out-of-order packets?
-    int64_t now_ms = clock_->TimeInMilliseconds();
-
-    last_received_rtp_timestamp_ = packet.Timestamp();
-    last_received_rtp_system_time_ms_ = now_ms;
-
-    // Periodically log the RTP header of incoming packets.
-    if (now_ms - last_packet_log_ms_ > kPacketLogIntervalMs) {
-      rtc::StringBuilder ss;
-      ss << "Packet received on SSRC: " << packet.Ssrc()
-         << " with payload type: " << static_cast<int>(packet.PayloadType())
-         << ", timestamp: " << packet.Timestamp()
-         << ", sequence number: " << packet.SequenceNumber()
-         << ", arrival time: " << packet.arrival_time_ms();
-      int32_t time_offset;
-      if (packet.GetExtension<TransmissionOffset>(&time_offset)) {
-        ss << ", toffset: " << time_offset;
-      }
-      uint32_t send_time;
-      if (packet.GetExtension<AbsoluteSendTime>(&send_time)) {
-        ss << ", abs send time: " << send_time;
-      }
-      RTC_LOG(LS_INFO) << ss.str();
-      last_packet_log_ms_ = now_ms;
-    }
-  }
-
   ReceivePacket(packet);
 
   // Update receive statistics after ReceivePacket.
@@ -915,12 +893,20 @@
 
 absl::optional<int64_t> RtpVideoStreamReceiver2::LastReceivedPacketMs() const {
   RTC_DCHECK_RUN_ON(&worker_task_checker_);
-  return last_received_rtp_system_time_ms_;
+  if (last_received_rtp_system_time_) {
+    return absl::optional<int64_t>(last_received_rtp_system_time_->ms());
+  }
+  return absl::nullopt;
 }
 
 absl::optional<int64_t> RtpVideoStreamReceiver2::LastReceivedKeyframePacketMs()
     const {
-  return packet_buffer_.LastReceivedKeyframePacketMs();
+  RTC_DCHECK_RUN_ON(&worker_task_checker_);
+  if (last_received_keyframe_rtp_system_time_) {
+    return absl::optional<int64_t>(
+        last_received_keyframe_rtp_system_time_->ms());
+  }
+  return absl::nullopt;
 }
 
 void RtpVideoStreamReceiver2::ManageFrame(
@@ -1137,4 +1123,35 @@
                              sprop_decoder.pps_nalu());
 }
 
+void RtpVideoStreamReceiver2::UpdatePacketReceiveTimestamps(
+    const RtpPacketReceived& packet,
+    bool is_keyframe) {
+  Timestamp now = clock_->CurrentTime();
+  if (is_keyframe) {
+    last_received_keyframe_rtp_system_time_ = now;
+  }
+  last_received_rtp_system_time_ = now;
+  last_received_rtp_timestamp_ = packet.Timestamp();
+
+  // Periodically log the RTP header of incoming packets.
+  if (now.ms() - last_packet_log_ms_ > kPacketLogIntervalMs) {
+    rtc::StringBuilder ss;
+    ss << "Packet received on SSRC: " << packet.Ssrc()
+       << " with payload type: " << static_cast<int>(packet.PayloadType())
+       << ", timestamp: " << packet.Timestamp()
+       << ", sequence number: " << packet.SequenceNumber()
+       << ", arrival time: " << packet.arrival_time_ms();
+    int32_t time_offset;
+    if (packet.GetExtension<TransmissionOffset>(&time_offset)) {
+      ss << ", toffset: " << time_offset;
+    }
+    uint32_t send_time;
+    if (packet.GetExtension<AbsoluteSendTime>(&send_time)) {
+      ss << ", abs send time: " << send_time;
+    }
+    RTC_LOG(LS_INFO) << ss.str();
+    last_packet_log_ms_ = now.ms();
+  }
+}
+
 }  // namespace webrtc
diff --git a/video/rtp_video_stream_receiver2.h b/video/rtp_video_stream_receiver2.h
index d1319d9..207dfe7 100644
--- a/video/rtp_video_stream_receiver2.h
+++ b/video/rtp_video_stream_receiver2.h
@@ -19,6 +19,7 @@
 #include "absl/types/optional.h"
 #include "api/crypto/frame_decryptor_interface.h"
 #include "api/sequence_checker.h"
+#include "api/units/timestamp.h"
 #include "api/video/color_space.h"
 #include "api/video_codecs/video_codec.h"
 #include "call/rtp_packet_sink_interface.h"
@@ -260,6 +261,9 @@
       const RtpPacketReceived& rtp_packet,
       RTPVideoHeader* video_header) RTC_RUN_ON(worker_task_checker_);
   void OnAssembledFrame(std::unique_ptr<RtpFrameObject> frame);
+  void UpdatePacketReceiveTimestamps(const RtpPacketReceived& packet,
+                                     bool is_keyframe)
+      RTC_RUN_ON(worker_task_checker_);
 
   Clock* const clock_;
   // Ownership of this object lies with VideoReceiveStream, which owns |this|.
@@ -331,7 +335,9 @@
 
   absl::optional<uint32_t> last_received_rtp_timestamp_
       RTC_GUARDED_BY(worker_task_checker_);
-  absl::optional<int64_t> last_received_rtp_system_time_ms_
+  absl::optional<Timestamp> last_received_rtp_system_time_
+      RTC_GUARDED_BY(worker_task_checker_);
+  absl::optional<Timestamp> last_received_keyframe_rtp_system_time_
       RTC_GUARDED_BY(worker_task_checker_);
 
   // Handles incoming encrypted frames and forwards them to the