diff --git a/modules/video_coding/packet_buffer.cc b/modules/video_coding/packet_buffer.cc index cc4b8c1466..0d4c085286 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 @@ PacketBuffer::Packet::Packet(const RtpPacketReceived& rtp_packet, rtp_packet.GetExtension(), 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 @@ PacketBuffer::InsertResult PacketBuffer::InsertPacket( } } - 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 @@ PacketBuffer::InsertResult PacketBuffer::InsertPadding(uint16_t seq_num) { return result; } -absl::optional PacketBuffer::LastReceivedPacketMs() const { - MutexLock lock(&mutex_); - return last_received_packet_ms_; -} - -absl::optional 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 @@ void PacketBuffer::ClearInternal() { 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 35dcf82edc..eb8d8365a8 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 @@ class PacketBuffer { }; // 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) @@ -86,16 +85,9 @@ class PacketBuffer { 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 LastReceivedPacketMs() const - RTC_LOCKS_EXCLUDED(mutex_); - absl::optional 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 @@ class PacketBuffer { // determine continuity between them. std::vector> buffer_ RTC_GUARDED_BY(mutex_); - // Timestamp of the last received packet/keyframe packet. - absl::optional last_received_packet_ms_ RTC_GUARDED_BY(mutex_); - absl::optional last_received_keyframe_packet_ms_ - RTC_GUARDED_BY(mutex_); - absl::optional last_received_keyframe_rtp_timestamp_ - RTC_GUARDED_BY(mutex_); - absl::optional newest_inserted_seq_num_ RTC_GUARDED_BY(mutex_); std::set> 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 a01b480398..97012618f3 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 @@ void PrintTo(const PacketBufferInsertResult& result, std::ostream* os) { 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(); } @@ -133,7 +129,6 @@ class PacketBufferTest : public ::testing::Test { } Random rand_; - SimulatedClock clock_; PacketBuffer packet_buffer_; }; @@ -616,67 +611,6 @@ TEST_F(PacketBufferTest, ContinuousSeqNumDoubleMarkerBit) { EXPECT_THAT(Insert(3, kKeyFrame, kNotFirst, kLast).packets, IsEmpty()); } -TEST_F(PacketBufferTest, PacketTimestamps) { - absl::optional packet_ms; - absl::optional 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(); 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 f1872e3bfd..ea9d4896f1 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 @@ void FuzzOneInput(const uint8_t* data, size_t size) { 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(data, size)); while (helper.BytesLeft()) { diff --git a/video/BUILD.gn b/video/BUILD.gn index e4c1986ffc..35ad044d46 100644 --- a/video/BUILD.gn +++ b/video/BUILD.gn @@ -164,6 +164,7 @@ rtc_source_set("video_legacy") { "../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 be208cee0f..e092fe7374 100644 --- a/video/rtp_video_stream_receiver.cc +++ b/video/rtp_video_stream_receiver.cc @@ -271,7 +271,7 @@ RtpVideoStreamReceiver::RtpVideoStreamReceiver( // 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 @@ absl::optional RtpVideoStreamReceiver::GetSyncInfo() const { } { 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 @@ void RtpVideoStreamReceiver::OnReceivedPayloadData( 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 @@ void RtpVideoStreamReceiver::OnRtpPacket(const RtpPacketReceived& packet) { 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(packet.PayloadType()) - << ", timestamp: " << packet.Timestamp() - << ", sequence number: " << packet.SequenceNumber() - << ", arrival time: " << packet.arrival_time_ms(); - int32_t time_offset; - if (packet.GetExtension(&time_offset)) { - ss << ", toffset: " << time_offset; - } - uint32_t send_time; - if (packet.GetExtension(&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 @@ void RtpVideoStreamReceiver::UpdateRtt(int64_t max_rtt_ms) { } absl::optional RtpVideoStreamReceiver::LastReceivedPacketMs() const { - return packet_buffer_.LastReceivedPacketMs(); + MutexLock lock(&sync_info_lock_); + if (last_received_rtp_system_time_) { + return absl::optional(last_received_rtp_system_time_->ms()); + } + return absl::nullopt; } absl::optional RtpVideoStreamReceiver::LastReceivedKeyframePacketMs() const { - return packet_buffer_.LastReceivedKeyframePacketMs(); + MutexLock lock(&sync_info_lock_); + if (last_received_keyframe_rtp_system_time_) { + return absl::optional( + last_received_keyframe_rtp_system_time_->ms()); + } + return absl::nullopt; } void RtpVideoStreamReceiver::AddSecondarySink(RtpPacketSinkInterface* sink) { @@ -1183,4 +1169,38 @@ void RtpVideoStreamReceiver::InsertSpsPpsIntoTracker(uint8_t payload_type) { 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(packet.PayloadType()) + << ", timestamp: " << packet.Timestamp() + << ", sequence number: " << packet.SequenceNumber() + << ", arrival time: " << packet.arrival_time_ms(); + int32_t time_offset; + if (packet.GetExtension(&time_offset)) { + ss << ", toffset: " << time_offset; + } + uint32_t send_time; + if (packet.GetExtension(&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 cc3499a714..7a845194f4 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 @@ class RtpVideoStreamReceiver : public LossNotificationSender, const RtpPacketReceived& rtp_packet, RTPVideoHeader* video_header) RTC_RUN_ON(worker_task_checker_); void OnAssembledFrame(std::unique_ptr 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 @@ class RtpVideoStreamReceiver : public LossNotificationSender, mutable Mutex sync_info_lock_; absl::optional last_received_rtp_timestamp_ RTC_GUARDED_BY(sync_info_lock_); - absl::optional last_received_rtp_system_time_ms_ + absl::optional last_received_rtp_system_time_ + RTC_GUARDED_BY(sync_info_lock_); + absl::optional 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 6664820800..3c23a3d2cd 100644 --- a/video/rtp_video_stream_receiver2.cc +++ b/video/rtp_video_stream_receiver2.cc @@ -250,7 +250,7 @@ RtpVideoStreamReceiver2::RtpVideoStreamReceiver2( 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 @@ absl::optional RtpVideoStreamReceiver2::GetSyncInfo() const { 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 @@ void RtpVideoStreamReceiver2::OnReceivedPayloadData( 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 @@ void RtpVideoStreamReceiver2::OnRtpPacket(const RtpPacketReceived& packet) { 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(packet.PayloadType()) - << ", timestamp: " << packet.Timestamp() - << ", sequence number: " << packet.SequenceNumber() - << ", arrival time: " << packet.arrival_time_ms(); - int32_t time_offset; - if (packet.GetExtension(&time_offset)) { - ss << ", toffset: " << time_offset; - } - uint32_t send_time; - if (packet.GetExtension(&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 @@ void RtpVideoStreamReceiver2::UpdateRtt(int64_t max_rtt_ms) { absl::optional 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(last_received_rtp_system_time_->ms()); + } + return absl::nullopt; } absl::optional RtpVideoStreamReceiver2::LastReceivedKeyframePacketMs() const { - return packet_buffer_.LastReceivedKeyframePacketMs(); + RTC_DCHECK_RUN_ON(&worker_task_checker_); + if (last_received_keyframe_rtp_system_time_) { + return absl::optional( + last_received_keyframe_rtp_system_time_->ms()); + } + return absl::nullopt; } void RtpVideoStreamReceiver2::ManageFrame( @@ -1137,4 +1123,35 @@ void RtpVideoStreamReceiver2::InsertSpsPpsIntoTracker(uint8_t payload_type) { 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(packet.PayloadType()) + << ", timestamp: " << packet.Timestamp() + << ", sequence number: " << packet.SequenceNumber() + << ", arrival time: " << packet.arrival_time_ms(); + int32_t time_offset; + if (packet.GetExtension(&time_offset)) { + ss << ", toffset: " << time_offset; + } + uint32_t send_time; + if (packet.GetExtension(&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 d1319d911a..207dfe7fb0 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 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender, const RtpPacketReceived& rtp_packet, RTPVideoHeader* video_header) RTC_RUN_ON(worker_task_checker_); void OnAssembledFrame(std::unique_ptr 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 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender, absl::optional last_received_rtp_timestamp_ RTC_GUARDED_BY(worker_task_checker_); - absl::optional last_received_rtp_system_time_ms_ + absl::optional last_received_rtp_system_time_ + RTC_GUARDED_BY(worker_task_checker_); + absl::optional last_received_keyframe_rtp_system_time_ RTC_GUARDED_BY(worker_task_checker_); // Handles incoming encrypted frames and forwards them to the