mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +01:00

Bug: webrtc:13982 Change-Id: Ib32b374237e19d10b3d36fe981939289c34dd6e8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/288965 Commit-Queue: Evan Shrubsole <eshr@webrtc.org> Auto-Submit: Evan Shrubsole <eshr@webrtc.org> Commit-Queue: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/main@{#39075}
277 lines
11 KiB
C++
277 lines
11 KiB
C++
/*
|
|
* Copyright (c) 2012 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 "system_wrappers/include/rtp_to_ntp_estimator.h"
|
|
|
|
#include <stddef.h>
|
|
|
|
#include "rtc_base/random.h"
|
|
#include "test/gtest.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
constexpr uint64_t kOneMsInNtp = 4294967;
|
|
constexpr uint64_t kOneHourInNtp = uint64_t{60 * 60} << 32;
|
|
constexpr uint32_t kTimestampTicksPerMs = 90;
|
|
} // namespace
|
|
|
|
TEST(WrapAroundTests, OldRtcpWrapped_OldRtpTimestamp) {
|
|
RtpToNtpEstimator estimator;
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(kOneMsInNtp), 0),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
// No wraparound will be detected, since we are not allowed to wrap below 0,
|
|
// but there will be huge rtp timestamp jump, e.g. old_timestamp = 0,
|
|
// new_timestamp = 4294967295, which should be detected.
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(2 * kOneMsInNtp),
|
|
-kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kInvalidMeasurement);
|
|
}
|
|
|
|
TEST(WrapAroundTests, OldRtcpWrapped_OldRtpTimestamp_Wraparound_Detected) {
|
|
RtpToNtpEstimator estimator;
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), 0xFFFFFFFE),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + 2 * kOneMsInNtp),
|
|
0xFFFFFFFE + 2 * kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
// Expected to fail since the older RTCP has a smaller RTP timestamp than the
|
|
// newer (old:10, new:4294967206).
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + 3 * kOneMsInNtp),
|
|
0xFFFFFFFE + kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kInvalidMeasurement);
|
|
}
|
|
|
|
TEST(WrapAroundTests, OldRtcpWrapped_OldRtpTimestamp_NegativeWraparound) {
|
|
RtpToNtpEstimator estimator;
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), 0),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
// Expected to fail since the older RTCP has a smaller RTP timestamp than the
|
|
// newer (old:0, new:-180).
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + 2 * kOneMsInNtp),
|
|
0xFFFFFFFF - 2 * kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kInvalidMeasurement);
|
|
}
|
|
|
|
TEST(WrapAroundTests, NewRtcpWrapped) {
|
|
RtpToNtpEstimator estimator;
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), 0xFFFFFFFF),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + kOneMsInNtp),
|
|
0xFFFFFFFF + kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
// Since this RTP packet has the same timestamp as the RTCP packet constructed
|
|
// at time 0 it should be mapped to 0 as well.
|
|
EXPECT_EQ(estimator.Estimate(0xFFFFFFFF), NtpTime(1));
|
|
}
|
|
|
|
TEST(WrapAroundTests, RtpWrapped) {
|
|
RtpToNtpEstimator estimator;
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1),
|
|
0xFFFFFFFF - 2 * kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + kOneMsInNtp),
|
|
0xFFFFFFFF - kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
|
|
// Since this RTP packet has the same timestamp as the RTCP packet constructed
|
|
// at time 0 it should be mapped to 0 as well.
|
|
EXPECT_EQ(estimator.Estimate(0xFFFFFFFF - 2 * kTimestampTicksPerMs),
|
|
NtpTime(1));
|
|
// Two kTimestampTicksPerMs advanced.
|
|
EXPECT_EQ(estimator.Estimate(0xFFFFFFFF), NtpTime(1 + 2 * kOneMsInNtp));
|
|
// Wrapped rtp.
|
|
EXPECT_EQ(estimator.Estimate(0xFFFFFFFF + kTimestampTicksPerMs),
|
|
NtpTime(1 + 3 * kOneMsInNtp));
|
|
}
|
|
|
|
TEST(WrapAroundTests, OldRtp_RtcpsWrapped) {
|
|
RtpToNtpEstimator estimator;
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), 0xFFFFFFFF),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + kOneMsInNtp),
|
|
0xFFFFFFFF + kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
|
|
EXPECT_FALSE(estimator.Estimate(0xFFFFFFFF - kTimestampTicksPerMs).Valid());
|
|
}
|
|
|
|
TEST(WrapAroundTests, OldRtp_NewRtcpWrapped) {
|
|
RtpToNtpEstimator estimator;
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), 0xFFFFFFFF),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + kOneMsInNtp),
|
|
0xFFFFFFFF + kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
|
|
// Constructed at the same time as the first RTCP and should therefore be
|
|
// mapped to zero.
|
|
EXPECT_EQ(estimator.Estimate(0xFFFFFFFF), NtpTime(1));
|
|
}
|
|
|
|
TEST(WrapAroundTests, GracefullyHandleRtpJump) {
|
|
RtpToNtpEstimator estimator;
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), 0xFFFFFFFF),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1 + kOneMsInNtp),
|
|
0xFFFFFFFF + kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
|
|
// Constructed at the same time as the first RTCP and should therefore be
|
|
// mapped to zero.
|
|
EXPECT_EQ(estimator.Estimate(0xFFFFFFFF), NtpTime(1));
|
|
|
|
uint32_t timestamp = 0xFFFFFFFF - 0xFFFFF;
|
|
uint64_t ntp_raw = 1 + 2 * kOneMsInNtp;
|
|
for (int i = 0; i < RtpToNtpEstimator::kMaxInvalidSamples - 1; ++i) {
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw), timestamp),
|
|
RtpToNtpEstimator::kInvalidMeasurement);
|
|
ntp_raw += kOneMsInNtp;
|
|
timestamp += kTimestampTicksPerMs;
|
|
}
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw), timestamp),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
ntp_raw += kOneMsInNtp;
|
|
timestamp += kTimestampTicksPerMs;
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw), timestamp),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
|
|
EXPECT_EQ(estimator.Estimate(timestamp), NtpTime(ntp_raw));
|
|
}
|
|
|
|
TEST(UpdateRtcpMeasurementTests, FailsForZeroNtp) {
|
|
RtpToNtpEstimator estimator;
|
|
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(0), 0x12345678),
|
|
RtpToNtpEstimator::kInvalidMeasurement);
|
|
}
|
|
|
|
TEST(UpdateRtcpMeasurementTests, FailsForEqualNtp) {
|
|
RtpToNtpEstimator estimator;
|
|
NtpTime ntp(0, 699925050);
|
|
uint32_t timestamp = 0x12345678;
|
|
|
|
EXPECT_EQ(estimator.UpdateMeasurements(ntp, timestamp),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
// Ntp time already added, list not updated.
|
|
EXPECT_EQ(estimator.UpdateMeasurements(ntp, timestamp + 1),
|
|
RtpToNtpEstimator::kSameMeasurement);
|
|
}
|
|
|
|
TEST(UpdateRtcpMeasurementTests, FailsForOldNtp) {
|
|
RtpToNtpEstimator estimator;
|
|
uint64_t ntp_raw = 699925050;
|
|
NtpTime ntp(ntp_raw);
|
|
uint32_t timestamp = 0x12345678;
|
|
EXPECT_EQ(estimator.UpdateMeasurements(ntp, timestamp),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
|
|
// Old ntp time, list not updated.
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw - kOneMsInNtp),
|
|
timestamp + kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kInvalidMeasurement);
|
|
}
|
|
|
|
TEST(UpdateRtcpMeasurementTests, FailsForTooNewNtp) {
|
|
RtpToNtpEstimator estimator;
|
|
|
|
uint64_t ntp_raw = 699925050;
|
|
uint32_t timestamp = 0x12345678;
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw), timestamp),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
|
|
// Ntp time from far future, list not updated.
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw + 2 * kOneHourInNtp),
|
|
timestamp + 10 * kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kInvalidMeasurement);
|
|
}
|
|
|
|
TEST(UpdateRtcpMeasurementTests, FailsForEqualTimestamp) {
|
|
RtpToNtpEstimator estimator;
|
|
|
|
uint32_t timestamp = 0x12345678;
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(2), timestamp),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
// Timestamp already added, list not updated.
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(3), timestamp),
|
|
RtpToNtpEstimator::kSameMeasurement);
|
|
}
|
|
|
|
TEST(UpdateRtcpMeasurementTests, FailsForOldRtpTimestamp) {
|
|
RtpToNtpEstimator estimator;
|
|
uint32_t timestamp = 0x12345678;
|
|
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(2), timestamp),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
// Old timestamp, list not updated.
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(2 + kOneMsInNtp),
|
|
timestamp - kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kInvalidMeasurement);
|
|
}
|
|
|
|
TEST(UpdateRtcpMeasurementTests, VerifyParameters) {
|
|
RtpToNtpEstimator estimator;
|
|
uint32_t timestamp = 0x12345678;
|
|
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(kOneMsInNtp), timestamp),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
|
|
EXPECT_DOUBLE_EQ(estimator.EstimatedFrequencyKhz(), 0.0);
|
|
|
|
// Add second report, parameters should be calculated.
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(2 * kOneMsInNtp),
|
|
timestamp + kTimestampTicksPerMs),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
|
|
EXPECT_NEAR(estimator.EstimatedFrequencyKhz(), kTimestampTicksPerMs, 0.01);
|
|
}
|
|
|
|
TEST(RtpToNtpTests, FailsForNoParameters) {
|
|
RtpToNtpEstimator estimator;
|
|
uint32_t timestamp = 0x12345678;
|
|
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(1), timestamp),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
// Parameters are not calculated, conversion of RTP to NTP time should fail.
|
|
EXPECT_DOUBLE_EQ(estimator.EstimatedFrequencyKhz(), 0.0);
|
|
EXPECT_FALSE(estimator.Estimate(timestamp).Valid());
|
|
}
|
|
|
|
TEST(RtpToNtpTests, AveragesErrorOut) {
|
|
RtpToNtpEstimator estimator;
|
|
uint64_t ntp_raw = 90000000; // More than 1 ms.
|
|
ASSERT_GT(ntp_raw, kOneMsInNtp);
|
|
uint32_t timestamp = 0x12345678;
|
|
constexpr uint64_t kNtpSecStep = uint64_t{1} << 32; // 1 second.
|
|
constexpr int kRtpTicksPerMs = 90;
|
|
constexpr int kRtpStep = kRtpTicksPerMs * 1000;
|
|
|
|
EXPECT_EQ(estimator.UpdateMeasurements(NtpTime(ntp_raw), timestamp),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
|
|
Random rand(1123536L);
|
|
for (size_t i = 0; i < 1000; i++) {
|
|
// Advance both timestamps by exactly 1 second.
|
|
ntp_raw += kNtpSecStep;
|
|
timestamp += kRtpStep;
|
|
// Add upto 1ms of errors to NTP and RTP timestamps passed to estimator.
|
|
EXPECT_EQ(
|
|
estimator.UpdateMeasurements(
|
|
NtpTime(ntp_raw + rand.Rand(-int{kOneMsInNtp}, int{kOneMsInNtp})),
|
|
timestamp + rand.Rand(-kRtpTicksPerMs, kRtpTicksPerMs)),
|
|
RtpToNtpEstimator::kNewMeasurement);
|
|
|
|
NtpTime estimated_ntp = estimator.Estimate(timestamp);
|
|
EXPECT_TRUE(estimated_ntp.Valid());
|
|
// Allow upto 2 ms of error.
|
|
EXPECT_NEAR(ntp_raw, static_cast<uint64_t>(estimated_ntp), 2 * kOneMsInNtp);
|
|
}
|
|
}
|
|
|
|
} // namespace webrtc
|