diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn index 3608bae9f3..3d6c0e79a1 100644 --- a/modules/rtp_rtcp/BUILD.gn +++ b/modules/rtp_rtcp/BUILD.gn @@ -131,6 +131,10 @@ rtc_static_library("rtp_rtcp") { "include/rtp_header_parser.h", "include/rtp_rtcp.h", "include/ulpfec_receiver.h", + "source/absolute_capture_time_receiver.cc", + "source/absolute_capture_time_receiver.h", + "source/absolute_capture_time_sender.cc", + "source/absolute_capture_time_sender.h", "source/dtmf_queue.cc", "source/dtmf_queue.h", "source/fec_private_tables_bursty.cc", @@ -224,6 +228,8 @@ rtc_static_library("rtp_rtcp") { "../../api/rtc_event_log", "../../api/transport:field_trial_based_config", "../../api/transport:webrtc_key_value_config", + "../../api/units:time_delta", + "../../api/units:timestamp", "../../api/video:video_bitrate_allocation", "../../api/video:video_bitrate_allocator", "../../api/video:video_frame", @@ -385,6 +391,8 @@ if (rtc_include_tests) { testonly = true sources = [ + "source/absolute_capture_time_receiver_unittest.cc", + "source/absolute_capture_time_sender_unittest.cc", "source/byte_io_unittest.cc", "source/fec_private_tables_bursty_unittest.cc", "source/flexfec_header_reader_writer_unittest.cc", diff --git a/modules/rtp_rtcp/source/absolute_capture_time_receiver.cc b/modules/rtp_rtcp/source/absolute_capture_time_receiver.cc new file mode 100644 index 0000000000..62f300d0e5 --- /dev/null +++ b/modules/rtp_rtcp/source/absolute_capture_time_receiver.cc @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/rtp_rtcp/source/absolute_capture_time_receiver.h" + +#include + +#include "rtc_base/checks.h" + +namespace webrtc { +namespace { + +constexpr Timestamp kInvalidLastReceiveTime = Timestamp::MinusInfinity(); +} // namespace + +constexpr TimeDelta AbsoluteCaptureTimeReceiver::kInterpolationMaxInterval; + +AbsoluteCaptureTimeReceiver::AbsoluteCaptureTimeReceiver(Clock* clock) + : clock_(clock), + remote_to_local_clock_offset_(absl::nullopt), + last_receive_time_(kInvalidLastReceiveTime) {} + +uint32_t AbsoluteCaptureTimeReceiver::GetSource( + uint32_t ssrc, + rtc::ArrayView csrcs) { + if (csrcs.empty()) { + return ssrc; + } + + return csrcs[0]; +} + +void AbsoluteCaptureTimeReceiver::SetRemoteToLocalClockOffset( + absl::optional value_q32x32) { + rtc::CritScope cs(&crit_); + + remote_to_local_clock_offset_ = value_q32x32; +} + +absl::optional +AbsoluteCaptureTimeReceiver::OnReceivePacket( + uint32_t source, + uint32_t rtp_timestamp, + uint32_t rtp_clock_frequency, + const absl::optional& received_extension) { + const Timestamp receive_time = clock_->CurrentTime(); + + rtc::CritScope cs(&crit_); + + AbsoluteCaptureTime extension; + if (received_extension == absl::nullopt) { + if (!ShouldInterpolateExtension(receive_time, source, rtp_timestamp, + rtp_clock_frequency)) { + last_receive_time_ = kInvalidLastReceiveTime; + return absl::nullopt; + } + + extension.absolute_capture_timestamp = InterpolateAbsoluteCaptureTimestamp( + rtp_timestamp, rtp_clock_frequency, last_rtp_timestamp_, + last_absolute_capture_timestamp_); + extension.estimated_capture_clock_offset = + last_estimated_capture_clock_offset_; + } else { + last_source_ = source; + last_rtp_timestamp_ = rtp_timestamp; + last_rtp_clock_frequency_ = rtp_clock_frequency; + last_absolute_capture_timestamp_ = + received_extension->absolute_capture_timestamp; + last_estimated_capture_clock_offset_ = + received_extension->estimated_capture_clock_offset; + + last_receive_time_ = receive_time; + + extension = *received_extension; + } + + extension.estimated_capture_clock_offset = AdjustEstimatedCaptureClockOffset( + extension.estimated_capture_clock_offset); + + return extension; +} + +uint64_t AbsoluteCaptureTimeReceiver::InterpolateAbsoluteCaptureTimestamp( + uint32_t rtp_timestamp, + uint32_t rtp_clock_frequency, + uint32_t last_rtp_timestamp, + uint64_t last_absolute_capture_timestamp) { + RTC_DCHECK_GT(rtp_clock_frequency, 0); + + return last_absolute_capture_timestamp + + static_cast( + rtc::dchecked_cast(rtp_timestamp - last_rtp_timestamp) + << 32) / + rtp_clock_frequency; +} + +bool AbsoluteCaptureTimeReceiver::ShouldInterpolateExtension( + Timestamp receive_time, + uint32_t source, + uint32_t rtp_timestamp, + uint32_t rtp_clock_frequency) const { + // Shouldn't if we don't have a previously received extension stored. + if (last_receive_time_ == kInvalidLastReceiveTime) { + return false; + } + + // Shouldn't if the last received extension is too old. + if ((receive_time - last_receive_time_) > kInterpolationMaxInterval) { + return false; + } + + // Shouldn't if the source has changed. + if (last_source_ != source) { + return false; + } + + // Shouldn't if the RTP clock frequency has changed. + if (last_rtp_clock_frequency_ != rtp_clock_frequency) { + return false; + } + + // Shouldn't if the RTP clock frequency is invalid. + if (rtp_clock_frequency <= 0) { + return false; + } + + return true; +} + +absl::optional +AbsoluteCaptureTimeReceiver::AdjustEstimatedCaptureClockOffset( + absl::optional received_value) const { + if (received_value == absl::nullopt || + remote_to_local_clock_offset_ == absl::nullopt) { + return absl::nullopt; + } + + // Do calculations as "unsigned" to make overflows deterministic. + return static_cast(*received_value) + + static_cast(*remote_to_local_clock_offset_); +} + +} // namespace webrtc diff --git a/modules/rtp_rtcp/source/absolute_capture_time_receiver.h b/modules/rtp_rtcp/source/absolute_capture_time_receiver.h new file mode 100644 index 0000000000..10f9539b2d --- /dev/null +++ b/modules/rtp_rtcp/source/absolute_capture_time_receiver.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_RECEIVER_H_ +#define MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_RECEIVER_H_ + +#include "api/array_view.h" +#include "api/rtp_headers.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "rtc_base/critical_section.h" +#include "rtc_base/thread_annotations.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +// +// Helper class for receiving the |AbsoluteCaptureTime| header extension. +// +// Supports the "timestamp interpolation" optimization: +// A receiver SHOULD memorize the capture system (i.e. CSRC/SSRC), capture +// timestamp, and RTP timestamp of the most recently received abs-capture-time +// packet on each received stream. It can then use that information, in +// combination with RTP timestamps of packets without abs-capture-time, to +// extrapolate missing capture timestamps. +// +// See: https://webrtc.org/experiments/rtp-hdrext/abs-capture-time/ +// +class AbsoluteCaptureTimeReceiver { + public: + static constexpr TimeDelta kInterpolationMaxInterval = + TimeDelta::Millis<5000>(); + + explicit AbsoluteCaptureTimeReceiver(Clock* clock); + + // Returns the source (i.e. SSRC or CSRC) of the capture system. + static uint32_t GetSource(uint32_t ssrc, + rtc::ArrayView csrcs); + + // Sets the NTP clock offset between the sender system (which may be different + // from the capture system) and the local system. This information is normally + // provided by passing half the value of the Round-Trip Time estimation given + // by RTCP sender reports (see DLSR/DLRR). + // + // Note that the value must be in Q32.32-formatted fixed-point seconds. + void SetRemoteToLocalClockOffset(absl::optional value_q32x32); + + // Returns a received header extension, an interpolated header extension, or + // |absl::nullopt| if it's not possible to interpolate a header extension. + absl::optional OnReceivePacket( + uint32_t source, + uint32_t rtp_timestamp, + uint32_t rtp_clock_frequency, + const absl::optional& received_extension); + + private: + friend class AbsoluteCaptureTimeSender; + + static uint64_t InterpolateAbsoluteCaptureTimestamp( + uint32_t rtp_timestamp, + uint32_t rtp_clock_frequency, + uint32_t last_rtp_timestamp, + uint64_t last_absolute_capture_timestamp); + + bool ShouldInterpolateExtension(Timestamp receive_time, + uint32_t source, + uint32_t rtp_timestamp, + uint32_t rtp_clock_frequency) const + RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_); + + absl::optional AdjustEstimatedCaptureClockOffset( + absl::optional received_value) const + RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_); + + Clock* const clock_; + + rtc::CriticalSection crit_; + + absl::optional remote_to_local_clock_offset_ RTC_GUARDED_BY(crit_); + + Timestamp last_receive_time_ RTC_GUARDED_BY(crit_); + + uint32_t last_source_ RTC_GUARDED_BY(crit_); + uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(crit_); + uint32_t last_rtp_clock_frequency_ RTC_GUARDED_BY(crit_); + uint64_t last_absolute_capture_timestamp_ RTC_GUARDED_BY(crit_); + absl::optional last_estimated_capture_clock_offset_ + RTC_GUARDED_BY(crit_); +}; // AbsoluteCaptureTimeReceiver + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_RECEIVER_H_ diff --git a/modules/rtp_rtcp/source/absolute_capture_time_receiver_unittest.cc b/modules/rtp_rtcp/source/absolute_capture_time_receiver_unittest.cc new file mode 100644 index 0000000000..ecf256734d --- /dev/null +++ b/modules/rtp_rtcp/source/absolute_capture_time_receiver_unittest.cc @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/rtp_rtcp/source/absolute_capture_time_receiver.h" + +#include "system_wrappers/include/ntp_time.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(AbsoluteCaptureTimeReceiverTest, GetSourceWithoutCsrcs) { + constexpr uint32_t kSsrc = 12; + + EXPECT_EQ(AbsoluteCaptureTimeReceiver::GetSource(kSsrc, nullptr), kSsrc); +} + +TEST(AbsoluteCaptureTimeReceiverTest, GetSourceWithCsrcs) { + constexpr uint32_t kSsrc = 12; + constexpr uint32_t kCsrcs[] = {34, 56, 78, 90}; + + EXPECT_EQ(AbsoluteCaptureTimeReceiver::GetSource(kSsrc, kCsrcs), kCsrcs[0]); +} + +TEST(AbsoluteCaptureTimeReceiverTest, ReceiveExtensionReturnsExtension) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9020), absl::nullopt}; + + SimulatedClock clock(0); + AbsoluteCaptureTimeReceiver receiver(&clock); + + receiver.SetRemoteToLocalClockOffset(0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0, + kRtpClockFrequency, kExtension0), + kExtension0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp1, + kRtpClockFrequency, kExtension1), + kExtension1); +} + +TEST(AbsoluteCaptureTimeReceiverTest, ReceiveNoExtensionReturnsNoExtension) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + static const absl::optional kExtension0 = absl::nullopt; + static const absl::optional kExtension1 = absl::nullopt; + + SimulatedClock clock(0); + AbsoluteCaptureTimeReceiver receiver(&clock); + + receiver.SetRemoteToLocalClockOffset(0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0, + kRtpClockFrequency, kExtension0), + absl::nullopt); + + EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp1, + kRtpClockFrequency, kExtension1), + absl::nullopt); +} + +TEST(AbsoluteCaptureTimeReceiverTest, InterpolateLaterPacketArrivingLater) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = absl::nullopt; + static const absl::optional kExtension2 = absl::nullopt; + + SimulatedClock clock(0); + AbsoluteCaptureTimeReceiver receiver(&clock); + + receiver.SetRemoteToLocalClockOffset(0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0, + kRtpClockFrequency, kExtension0), + kExtension0); + + absl::optional extension = receiver.OnReceivePacket( + kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1); + EXPECT_TRUE(extension.has_value()); + EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), + UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 20); + EXPECT_EQ(extension->estimated_capture_clock_offset, + kExtension0->estimated_capture_clock_offset); + + extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2, + kRtpClockFrequency, kExtension2); + EXPECT_TRUE(extension.has_value()); + EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), + UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 40); + EXPECT_EQ(extension->estimated_capture_clock_offset, + kExtension0->estimated_capture_clock_offset); +} + +TEST(AbsoluteCaptureTimeReceiverTest, InterpolateEarlierPacketArrivingLater) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = absl::nullopt; + static const absl::optional kExtension2 = absl::nullopt; + + SimulatedClock clock(0); + AbsoluteCaptureTimeReceiver receiver(&clock); + + receiver.SetRemoteToLocalClockOffset(0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0, + kRtpClockFrequency, kExtension0), + kExtension0); + + absl::optional extension = receiver.OnReceivePacket( + kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1); + EXPECT_TRUE(extension.has_value()); + EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), + UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 20); + EXPECT_EQ(extension->estimated_capture_clock_offset, + kExtension0->estimated_capture_clock_offset); + + extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2, + kRtpClockFrequency, kExtension2); + EXPECT_TRUE(extension.has_value()); + EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), + UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 40); + EXPECT_EQ(extension->estimated_capture_clock_offset, + kExtension0->estimated_capture_clock_offset); +} + +TEST(AbsoluteCaptureTimeReceiverTest, + InterpolateLaterPacketArrivingLaterWithRtpTimestampWrapAround) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = ~uint32_t{0} - 79; + constexpr uint32_t kRtpTimestamp1 = 1280 - 80; + constexpr uint32_t kRtpTimestamp2 = 2560 - 80; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = absl::nullopt; + static const absl::optional kExtension2 = absl::nullopt; + + SimulatedClock clock(0); + AbsoluteCaptureTimeReceiver receiver(&clock); + + receiver.SetRemoteToLocalClockOffset(0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0, + kRtpClockFrequency, kExtension0), + kExtension0); + + absl::optional extension = receiver.OnReceivePacket( + kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1); + EXPECT_TRUE(extension.has_value()); + EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), + UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 20); + EXPECT_EQ(extension->estimated_capture_clock_offset, + kExtension0->estimated_capture_clock_offset); + + extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2, + kRtpClockFrequency, kExtension2); + EXPECT_TRUE(extension.has_value()); + EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), + UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 40); + EXPECT_EQ(extension->estimated_capture_clock_offset, + kExtension0->estimated_capture_clock_offset); +} + +TEST(AbsoluteCaptureTimeReceiverTest, + InterpolateEarlierPacketArrivingLaterWithRtpTimestampWrapAround) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 799; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = absl::nullopt; + static const absl::optional kExtension2 = absl::nullopt; + + SimulatedClock clock(0); + AbsoluteCaptureTimeReceiver receiver(&clock); + + receiver.SetRemoteToLocalClockOffset(0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0, + kRtpClockFrequency, kExtension0), + kExtension0); + + absl::optional extension = receiver.OnReceivePacket( + kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1); + EXPECT_TRUE(extension.has_value()); + EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), + UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 20); + EXPECT_EQ(extension->estimated_capture_clock_offset, + kExtension0->estimated_capture_clock_offset); + + extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2, + kRtpClockFrequency, kExtension2); + EXPECT_TRUE(extension.has_value()); + EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), + UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 40); + EXPECT_EQ(extension->estimated_capture_clock_offset, + kExtension0->estimated_capture_clock_offset); +} + +TEST(AbsoluteCaptureTimeReceiverTest, + SkipEstimatedCaptureClockOffsetIfRemoteToLocalClockOffsetIsUnknown) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = absl::nullopt; + static const absl::optional kExtension2 = absl::nullopt; + static const absl::optional kRemoteToLocalClockOffset2 = + Int64MsToQ32x32(-7000007); + + SimulatedClock clock(0); + AbsoluteCaptureTimeReceiver receiver(&clock); + + receiver.SetRemoteToLocalClockOffset(0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0, + kRtpClockFrequency, kExtension0), + kExtension0); + + receiver.SetRemoteToLocalClockOffset(absl::nullopt); + + absl::optional extension = receiver.OnReceivePacket( + kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1); + EXPECT_TRUE(extension.has_value()); + EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), + UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 20); + EXPECT_EQ(extension->estimated_capture_clock_offset, absl::nullopt); + + receiver.SetRemoteToLocalClockOffset(kRemoteToLocalClockOffset2); + + extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2, + kRtpClockFrequency, kExtension2); + EXPECT_TRUE(extension.has_value()); + EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp), + UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 40); + EXPECT_EQ(extension->estimated_capture_clock_offset, + *kExtension0->estimated_capture_clock_offset + + *kRemoteToLocalClockOffset2); +} + +TEST(AbsoluteCaptureTimeReceiverTest, SkipInterpolateIfTooLate) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp1 + 1280; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = absl::nullopt; + static const absl::optional kExtension2 = absl::nullopt; + + SimulatedClock clock(0); + AbsoluteCaptureTimeReceiver receiver(&clock); + + receiver.SetRemoteToLocalClockOffset(0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0, + kRtpClockFrequency, kExtension0), + kExtension0); + + clock.AdvanceTime(AbsoluteCaptureTimeReceiver::kInterpolationMaxInterval); + + EXPECT_TRUE(receiver + .OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + kExtension1) + .has_value()); + + clock.AdvanceTimeMilliseconds(1); + + EXPECT_FALSE(receiver + .OnReceivePacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + kExtension2) + .has_value()); +} + +TEST(AbsoluteCaptureTimeReceiverTest, SkipInterpolateIfSourceChanged) { + constexpr uint32_t kSource0 = 1337; + constexpr uint32_t kSource1 = 1338; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = absl::nullopt; + + SimulatedClock clock(0); + AbsoluteCaptureTimeReceiver receiver(&clock); + + receiver.SetRemoteToLocalClockOffset(0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource0, kRtpTimestamp0, + kRtpClockFrequency, kExtension0), + kExtension0); + + EXPECT_FALSE(receiver + .OnReceivePacket(kSource1, kRtpTimestamp1, + kRtpClockFrequency, kExtension1) + .has_value()); +} + +TEST(AbsoluteCaptureTimeReceiverTest, + SkipInterpolateIfRtpClockFrequencyChanged) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency0 = 64000; + constexpr uint32_t kRtpClockFrequency1 = 32000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 640; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = absl::nullopt; + + SimulatedClock clock(0); + AbsoluteCaptureTimeReceiver receiver(&clock); + + receiver.SetRemoteToLocalClockOffset(0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0, + kRtpClockFrequency0, kExtension0), + kExtension0); + + EXPECT_FALSE(receiver + .OnReceivePacket(kSource, kRtpTimestamp1, + kRtpClockFrequency1, kExtension1) + .has_value()); +} + +TEST(AbsoluteCaptureTimeReceiverTest, + SkipInterpolateIfRtpClockFrequencyIsInvalid) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 0; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 640; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = absl::nullopt; + + SimulatedClock clock(0); + AbsoluteCaptureTimeReceiver receiver(&clock); + + receiver.SetRemoteToLocalClockOffset(0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0, + kRtpClockFrequency, kExtension0), + kExtension0); + + EXPECT_FALSE(receiver + .OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + kExtension1) + .has_value()); +} + +TEST(AbsoluteCaptureTimeReceiverTest, SkipInterpolateIsSticky) { + constexpr uint32_t kSource0 = 1337; + constexpr uint32_t kSource1 = 1338; + constexpr uint32_t kSource2 = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp1 + 1280; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = absl::nullopt; + static const absl::optional kExtension2 = absl::nullopt; + + SimulatedClock clock(0); + AbsoluteCaptureTimeReceiver receiver(&clock); + + receiver.SetRemoteToLocalClockOffset(0); + + EXPECT_EQ(receiver.OnReceivePacket(kSource0, kRtpTimestamp0, + kRtpClockFrequency, kExtension0), + kExtension0); + + EXPECT_FALSE(receiver + .OnReceivePacket(kSource1, kRtpTimestamp1, + kRtpClockFrequency, kExtension1) + .has_value()); + + EXPECT_FALSE(receiver + .OnReceivePacket(kSource2, kRtpTimestamp2, + kRtpClockFrequency, kExtension2) + .has_value()); +} + +} // namespace webrtc diff --git a/modules/rtp_rtcp/source/absolute_capture_time_sender.cc b/modules/rtp_rtcp/source/absolute_capture_time_sender.cc new file mode 100644 index 0000000000..f614c0c521 --- /dev/null +++ b/modules/rtp_rtcp/source/absolute_capture_time_sender.cc @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/rtp_rtcp/source/absolute_capture_time_sender.h" + +#include + +#include "modules/rtp_rtcp/source/absolute_capture_time_receiver.h" +#include "system_wrappers/include/ntp_time.h" + +namespace webrtc { +namespace { + +constexpr Timestamp kInvalidLastSendTime = Timestamp::MinusInfinity(); + +} // namespace + +constexpr TimeDelta AbsoluteCaptureTimeSender::kInterpolationMaxInterval; +constexpr TimeDelta AbsoluteCaptureTimeSender::kInterpolationMaxError; + +static_assert( + AbsoluteCaptureTimeReceiver::kInterpolationMaxInterval >= + AbsoluteCaptureTimeSender::kInterpolationMaxInterval, + "Receivers should be as willing to interpolate timestamps as senders."); + +AbsoluteCaptureTimeSender::AbsoluteCaptureTimeSender(Clock* clock) + : clock_(clock), last_send_time_(kInvalidLastSendTime) {} + +uint32_t AbsoluteCaptureTimeSender::GetSource( + uint32_t ssrc, + rtc::ArrayView csrcs) { + return AbsoluteCaptureTimeReceiver::GetSource(ssrc, csrcs); +} + +absl::optional AbsoluteCaptureTimeSender::OnSendPacket( + uint32_t source, + uint32_t rtp_timestamp, + uint32_t rtp_clock_frequency, + uint64_t absolute_capture_timestamp, + absl::optional estimated_capture_clock_offset) { + const Timestamp send_time = clock_->CurrentTime(); + + rtc::CritScope cs(&crit_); + + if (!ShouldSendExtension(send_time, source, rtp_timestamp, + rtp_clock_frequency, absolute_capture_timestamp, + estimated_capture_clock_offset)) { + return absl::nullopt; + } + + last_source_ = source; + last_rtp_timestamp_ = rtp_timestamp; + last_rtp_clock_frequency_ = rtp_clock_frequency; + last_absolute_capture_timestamp_ = absolute_capture_timestamp; + last_estimated_capture_clock_offset_ = estimated_capture_clock_offset; + + last_send_time_ = send_time; + + AbsoluteCaptureTime extension; + extension.absolute_capture_timestamp = absolute_capture_timestamp; + extension.estimated_capture_clock_offset = estimated_capture_clock_offset; + return extension; +} + +bool AbsoluteCaptureTimeSender::ShouldSendExtension( + Timestamp send_time, + uint32_t source, + uint32_t rtp_timestamp, + uint32_t rtp_clock_frequency, + uint64_t absolute_capture_timestamp, + absl::optional estimated_capture_clock_offset) const { + // Should if we've never sent anything before. + if (last_send_time_ == kInvalidLastSendTime) { + return true; + } + + // Should if the last sent extension is too old. + if ((send_time - last_send_time_) > kInterpolationMaxInterval) { + return true; + } + + // Should if the source has changed. + if (last_source_ != source) { + return true; + } + + // Should if the RTP clock frequency has changed. + if (last_rtp_clock_frequency_ != rtp_clock_frequency) { + return true; + } + + // Should if the RTP clock frequency is invalid. + if (rtp_clock_frequency <= 0) { + return true; + } + + // Should if the estimated capture clock offset has changed. + if (last_estimated_capture_clock_offset_ != estimated_capture_clock_offset) { + return true; + } + + // Should if interpolation would introduce too much error. + const uint64_t interpolated_absolute_capture_timestamp = + AbsoluteCaptureTimeReceiver::InterpolateAbsoluteCaptureTimestamp( + rtp_timestamp, rtp_clock_frequency, last_rtp_timestamp_, + last_absolute_capture_timestamp_); + const int64_t interpolation_error_ms = UQ32x32ToInt64Ms(std::min( + interpolated_absolute_capture_timestamp - absolute_capture_timestamp, + absolute_capture_timestamp - interpolated_absolute_capture_timestamp)); + if (interpolation_error_ms > kInterpolationMaxError.ms()) { + return true; + } + + return false; +} + +} // namespace webrtc diff --git a/modules/rtp_rtcp/source/absolute_capture_time_sender.h b/modules/rtp_rtcp/source/absolute_capture_time_sender.h new file mode 100644 index 0000000000..86158a875d --- /dev/null +++ b/modules/rtp_rtcp/source/absolute_capture_time_sender.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_SENDER_H_ +#define MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_SENDER_H_ + +#include "api/array_view.h" +#include "api/rtp_headers.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "rtc_base/critical_section.h" +#include "rtc_base/thread_annotations.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +// +// Helper class for sending the |AbsoluteCaptureTime| header extension. +// +// Supports the "timestamp interpolation" optimization: +// A sender SHOULD save bandwidth by not sending abs-capture-time with every +// RTP packet. It SHOULD still send them at regular intervals (e.g. every +// second) to help mitigate the impact of clock drift and packet loss. Mixers +// SHOULD always send abs-capture-time with the first RTP packet after +// changing capture system. +// +// Timestamp interpolation works fine as long as there’s reasonably low +// NTP/RTP clock drift. This is not always true. Senders that detect “jumps” +// between its NTP and RTP clock mappings SHOULD send abs-capture-time with +// the first RTP packet after such a thing happening. +// +// See: https://webrtc.org/experiments/rtp-hdrext/abs-capture-time/ +// +class AbsoluteCaptureTimeSender { + public: + static constexpr TimeDelta kInterpolationMaxInterval = + TimeDelta::Millis<1000>(); + static constexpr TimeDelta kInterpolationMaxError = TimeDelta::Millis<1>(); + + explicit AbsoluteCaptureTimeSender(Clock* clock); + + // Returns the source (i.e. SSRC or CSRC) of the capture system. + static uint32_t GetSource(uint32_t ssrc, + rtc::ArrayView csrcs); + + // Returns a header extension to be sent, or |absl::nullopt| if the header + // extension shouldn't be sent. + absl::optional OnSendPacket( + uint32_t source, + uint32_t rtp_timestamp, + uint32_t rtp_clock_frequency, + uint64_t absolute_capture_timestamp, + absl::optional estimated_capture_clock_offset); + + private: + bool ShouldSendExtension( + Timestamp send_time, + uint32_t source, + uint32_t rtp_timestamp, + uint32_t rtp_clock_frequency, + uint64_t absolute_capture_timestamp, + absl::optional estimated_capture_clock_offset) const + RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_); + + Clock* const clock_; + + rtc::CriticalSection crit_; + + Timestamp last_send_time_ RTC_GUARDED_BY(crit_); + + uint32_t last_source_ RTC_GUARDED_BY(crit_); + uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(crit_); + uint32_t last_rtp_clock_frequency_ RTC_GUARDED_BY(crit_); + uint64_t last_absolute_capture_timestamp_ RTC_GUARDED_BY(crit_); + absl::optional last_estimated_capture_clock_offset_ + RTC_GUARDED_BY(crit_); +}; // AbsoluteCaptureTimeSender + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_SENDER_H_ diff --git a/modules/rtp_rtcp/source/absolute_capture_time_sender_unittest.cc b/modules/rtp_rtcp/source/absolute_capture_time_sender_unittest.cc new file mode 100644 index 0000000000..db3fc75100 --- /dev/null +++ b/modules/rtp_rtcp/source/absolute_capture_time_sender_unittest.cc @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/rtp_rtcp/source/absolute_capture_time_sender.h" + +#include "system_wrappers/include/ntp_time.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(AbsoluteCaptureTimeSenderTest, GetSourceWithoutCsrcs) { + constexpr uint32_t kSsrc = 12; + + EXPECT_EQ(AbsoluteCaptureTimeSender::GetSource(kSsrc, nullptr), kSsrc); +} + +TEST(AbsoluteCaptureTimeSenderTest, GetSourceWithCsrcs) { + constexpr uint32_t kSsrc = 12; + constexpr uint32_t kCsrcs[] = {34, 56, 78, 90}; + + EXPECT_EQ(AbsoluteCaptureTimeSender::GetSource(kSsrc, kCsrcs), kCsrcs[0]); +} + +TEST(AbsoluteCaptureTimeSenderTest, InterpolateLaterPacketSentLater) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension2 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)}; + SimulatedClock clock(0); + AbsoluteCaptureTimeSender sender(&clock); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, + kExtension0->absolute_capture_timestamp, + kExtension0->estimated_capture_clock_offset), + kExtension0); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + kExtension1->absolute_capture_timestamp, + kExtension1->estimated_capture_clock_offset), + absl::nullopt); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + kExtension2->absolute_capture_timestamp, + kExtension2->estimated_capture_clock_offset), + absl::nullopt); +} + +TEST(AbsoluteCaptureTimeSenderTest, InterpolateEarlierPacketSentLater) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 20), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension2 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 40), Int64MsToQ32x32(-350)}; + + SimulatedClock clock(0); + AbsoluteCaptureTimeSender sender(&clock); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, + kExtension0->absolute_capture_timestamp, + kExtension0->estimated_capture_clock_offset), + kExtension0); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + kExtension1->absolute_capture_timestamp, + kExtension1->estimated_capture_clock_offset), + absl::nullopt); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + kExtension2->absolute_capture_timestamp, + kExtension2->estimated_capture_clock_offset), + absl::nullopt); +} + +TEST(AbsoluteCaptureTimeSenderTest, + InterpolateLaterPacketSentLaterWithRtpTimestampWrapAround) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = ~uint32_t{0} - 79; + constexpr uint32_t kRtpTimestamp1 = 1280 - 80; + constexpr uint32_t kRtpTimestamp2 = 2560 - 80; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension2 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)}; + + SimulatedClock clock(0); + AbsoluteCaptureTimeSender sender(&clock); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, + kExtension0->absolute_capture_timestamp, + kExtension0->estimated_capture_clock_offset), + kExtension0); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + kExtension1->absolute_capture_timestamp, + kExtension1->estimated_capture_clock_offset), + absl::nullopt); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + kExtension2->absolute_capture_timestamp, + kExtension2->estimated_capture_clock_offset), + absl::nullopt); +} + +TEST(AbsoluteCaptureTimeSenderTest, + InterpolateEarlierPacketSentLaterWithRtpTimestampWrapAround) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 799; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 20), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension2 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 40), Int64MsToQ32x32(-350)}; + + SimulatedClock clock(0); + AbsoluteCaptureTimeSender sender(&clock); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, + kExtension0->absolute_capture_timestamp, + kExtension0->estimated_capture_clock_offset), + kExtension0); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + kExtension1->absolute_capture_timestamp, + kExtension1->estimated_capture_clock_offset), + absl::nullopt); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + kExtension2->absolute_capture_timestamp, + kExtension2->estimated_capture_clock_offset), + absl::nullopt); +} + +TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfTooLate) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension2 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)}; + + SimulatedClock clock(0); + AbsoluteCaptureTimeSender sender(&clock); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, + kExtension0->absolute_capture_timestamp, + kExtension0->estimated_capture_clock_offset), + kExtension0); + + clock.AdvanceTime(AbsoluteCaptureTimeSender::kInterpolationMaxInterval); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + kExtension1->absolute_capture_timestamp, + kExtension1->estimated_capture_clock_offset), + absl::nullopt); + + clock.AdvanceTimeMicroseconds(1); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + kExtension2->absolute_capture_timestamp, + kExtension2->estimated_capture_clock_offset), + kExtension2); +} + +TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfSourceChanged) { + constexpr uint32_t kSource0 = 1337; + constexpr uint32_t kSource1 = 1338; + constexpr uint32_t kSource2 = 1338; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension2 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)}; + + SimulatedClock clock(0); + AbsoluteCaptureTimeSender sender(&clock); + + EXPECT_EQ(sender.OnSendPacket(kSource0, kRtpTimestamp0, kRtpClockFrequency, + kExtension0->absolute_capture_timestamp, + kExtension0->estimated_capture_clock_offset), + kExtension0); + + EXPECT_EQ(sender.OnSendPacket(kSource1, kRtpTimestamp1, kRtpClockFrequency, + kExtension1->absolute_capture_timestamp, + kExtension1->estimated_capture_clock_offset), + kExtension1); + + EXPECT_EQ(sender.OnSendPacket(kSource2, kRtpTimestamp2, kRtpClockFrequency, + kExtension2->absolute_capture_timestamp, + kExtension2->estimated_capture_clock_offset), + absl::nullopt); +} + +TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfRtpClockFrequencyChanged) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency0 = 64000; + constexpr uint32_t kRtpClockFrequency1 = 32000; + constexpr uint32_t kRtpClockFrequency2 = 32000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 640; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 1280; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension2 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)}; + + SimulatedClock clock(0); + AbsoluteCaptureTimeSender sender(&clock); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency0, + kExtension0->absolute_capture_timestamp, + kExtension0->estimated_capture_clock_offset), + kExtension0); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency1, + kExtension1->absolute_capture_timestamp, + kExtension1->estimated_capture_clock_offset), + kExtension1); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency2, + kExtension2->absolute_capture_timestamp, + kExtension2->estimated_capture_clock_offset), + absl::nullopt); +} + +TEST(AbsoluteCaptureTimeSenderTest, + SkipInterpolateIfRtpClockFrequencyIsInvalid) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency0 = 0; + constexpr uint32_t kRtpClockFrequency1 = 0; + constexpr uint32_t kRtpClockFrequency2 = 0; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension2 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)}; + + SimulatedClock clock(0); + AbsoluteCaptureTimeSender sender(&clock); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency0, + kExtension0->absolute_capture_timestamp, + kExtension0->estimated_capture_clock_offset), + kExtension0); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency1, + kExtension1->absolute_capture_timestamp, + kExtension1->estimated_capture_clock_offset), + kExtension1); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency2, + kExtension2->absolute_capture_timestamp, + kExtension2->estimated_capture_clock_offset), + kExtension2); +} + +TEST(AbsoluteCaptureTimeSenderTest, + SkipInterpolateIfEstimatedCaptureClockOffsetChanged) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(370)}; + static const absl::optional kExtension2 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), absl::nullopt}; + + SimulatedClock clock(0); + AbsoluteCaptureTimeSender sender(&clock); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, + kExtension0->absolute_capture_timestamp, + kExtension0->estimated_capture_clock_offset), + kExtension0); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + kExtension1->absolute_capture_timestamp, + kExtension1->estimated_capture_clock_offset), + kExtension1); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + kExtension2->absolute_capture_timestamp, + kExtension2->estimated_capture_clock_offset), + kExtension2); +} + +TEST(AbsoluteCaptureTimeSenderTest, + SkipInterpolateIfTooMuchInterpolationError) { + constexpr uint32_t kSource = 1337; + constexpr uint32_t kRtpClockFrequency = 64000; + constexpr uint32_t kRtpTimestamp0 = 1020300000; + constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280; + constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560; + static const absl::optional kExtension0 = + AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)}; + static const absl::optional kExtension1 = + AbsoluteCaptureTime{ + Int64MsToUQ32x32( + 9000 + 20 + + AbsoluteCaptureTimeSender::kInterpolationMaxError.ms()), + Int64MsToQ32x32(-350)}; + static const absl::optional kExtension2 = + AbsoluteCaptureTime{ + Int64MsToUQ32x32( + 9000 + 40 + + AbsoluteCaptureTimeSender::kInterpolationMaxError.ms() + 1), + Int64MsToQ32x32(-350)}; + + SimulatedClock clock(0); + AbsoluteCaptureTimeSender sender(&clock); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency, + kExtension0->absolute_capture_timestamp, + kExtension0->estimated_capture_clock_offset), + kExtension0); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency, + kExtension1->absolute_capture_timestamp, + kExtension1->estimated_capture_clock_offset), + absl::nullopt); + + EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency, + kExtension2->absolute_capture_timestamp, + kExtension2->estimated_capture_clock_offset), + kExtension2); +} + +} // namespace webrtc