From d4fdc27b912f7e683da966afc8077f275e6a7177 Mon Sep 17 00:00:00 2001 From: Danil Chapovalov Date: Thu, 9 Nov 2017 11:34:32 +0100 Subject: [PATCH] Introduce MicrosecondsToCompactNtp function webrtc clocks use 10based fraction time to calculate intervals. Rtcp require 16based fraction time to report intervals. Bug: webrtc:8239 Change-Id: I25cab5ad7b7614c86c174813a195e7ba767ee43b Reviewed-on: https://webrtc-review.googlesource.com/21383 Commit-Queue: Danil Chapovalov Reviewed-by: Niels Moller Cr-Commit-Position: refs/heads/master@{#20619} --- modules/rtp_rtcp/source/time_util.cc | 17 ++++++++++++++-- modules/rtp_rtcp/source/time_util.h | 5 +++++ modules/rtp_rtcp/source/time_util_unittest.cc | 20 +++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/modules/rtp_rtcp/source/time_util.cc b/modules/rtp_rtcp/source/time_util.cc index af954687c4..cf1d984248 100644 --- a/modules/rtp_rtcp/source/time_util.cc +++ b/modules/rtp_rtcp/source/time_util.cc @@ -16,12 +16,25 @@ namespace webrtc { namespace { // TODO(danilchap): Make generic, optimize and move to base. inline int64_t DivideRoundToNearest(int64_t x, uint32_t y) { - // Caller ensure x is positive by converting unsigned value into it. - // So this Divide doesn't need to handle negative argument case. + // Callers ensure x is positive and x + y / 2 doesn't overflow. return (x + y / 2) / y; } } // namespace +uint32_t SaturatedUsToCompactNtp(int64_t us) { + constexpr uint32_t kMaxCompactNtp = 0xFFFFFFFF; + constexpr int64_t kMicrosecondsInSecond = 1000000; + constexpr int kCompactNtpInSecond = 0x10000; + if (us <= 0) + return 0; + if (us >= kMaxCompactNtp * kMicrosecondsInSecond / kCompactNtpInSecond) + return kMaxCompactNtp; + // To convert to compact ntp need to divide by 1e6 to get seconds, + // then multiply by 0x10000 to get the final result. + // To avoid float operations, multiplication and division swapped. + return DivideRoundToNearest(us * kCompactNtpInSecond, kMicrosecondsInSecond); +} + int64_t CompactNtpRttToMs(uint32_t compact_ntp_interval) { // Interval to convert expected to be positive, e.g. rtt or delay. // Because interval can be derived from non-monotonic ntp clock, diff --git a/modules/rtp_rtcp/source/time_util.h b/modules/rtp_rtcp/source/time_util.h index d13e0803b8..a87a5b794c 100644 --- a/modules/rtp_rtcp/source/time_util.h +++ b/modules/rtp_rtcp/source/time_util.h @@ -34,6 +34,11 @@ inline uint32_t NtpToRtp(NtpTime ntp, uint32_t freq) { inline uint32_t CompactNtp(NtpTime ntp) { return (ntp.seconds() << 16) | (ntp.fractions() >> 16); } + +// Converts interval in microseconds to compact ntp (1/2^16 seconds) resolution. +// Negative values converted to 0, Overlarge values converted to max uint32_t. +uint32_t SaturatedUsToCompactNtp(int64_t us); + // Converts interval between compact ntp timestamps to milliseconds. // This interval can be up to ~9.1 hours (2^15 seconds). // Values close to 2^16 seconds consider negative and result in minimum rtt = 1. diff --git a/modules/rtp_rtcp/source/time_util_unittest.cc b/modules/rtp_rtcp/source/time_util_unittest.cc index eafe15db9b..6ff55dda55 100644 --- a/modules/rtp_rtcp/source/time_util_unittest.cc +++ b/modules/rtp_rtcp/source/time_util_unittest.cc @@ -70,4 +70,24 @@ TEST(TimeUtilTest, CompactNtpRttToMsNegative) { int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff); EXPECT_EQ(1, ntp_to_ms_diff); } + +TEST(TimeUtilTest, SaturatedUsToCompactNtp) { + // Converts negative to zero. + EXPECT_EQ(SaturatedUsToCompactNtp(-1), 0u); + EXPECT_EQ(SaturatedUsToCompactNtp(0), 0u); + // Converts values just above and just below max uint32_t. + EXPECT_EQ(SaturatedUsToCompactNtp(65536000000), 0xffffffff); + EXPECT_EQ(SaturatedUsToCompactNtp(65535999985), 0xffffffff); + EXPECT_EQ(SaturatedUsToCompactNtp(65535999970), 0xfffffffe); + // Converts half-seconds. + EXPECT_EQ(SaturatedUsToCompactNtp(500000), 0x8000u); + EXPECT_EQ(SaturatedUsToCompactNtp(1000000), 0x10000u); + EXPECT_EQ(SaturatedUsToCompactNtp(1500000), 0x18000u); + // Convert us -> compact_ntp -> ms. Compact ntp precision is ~15us. + EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(1516)), 2); + EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(15000)), 15); + EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(5485)), 5); + EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(5515)), 6); +} + } // namespace webrtc