blob: 85f08483ea2ede5bd1f81ef554d073fd04d35836 [file] [log] [blame]
/*
* Copyright (c) 2014 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/include/remote_ntp_time_estimator.h"
#include "absl/types/optional.h"
#include "modules/rtp_rtcp/source/time_util.h"
#include "system_wrappers/include/clock.h"
#include "system_wrappers/include/ntp_time.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
constexpr int64_t kTestRtt = 10;
constexpr int64_t kLocalClockInitialTimeMs = 123;
constexpr int64_t kRemoteClockInitialTimeMs = 345;
constexpr uint32_t kTimestampOffset = 567;
constexpr int64_t kRemoteToLocalClockOffsetMs =
kLocalClockInitialTimeMs - kRemoteClockInitialTimeMs;
class RemoteNtpTimeEstimatorTest : public ::testing::Test {
protected:
RemoteNtpTimeEstimatorTest()
: local_clock_(kLocalClockInitialTimeMs * 1000),
remote_clock_(kRemoteClockInitialTimeMs * 1000),
estimator_(new RemoteNtpTimeEstimator(&local_clock_)) {}
~RemoteNtpTimeEstimatorTest() override = default;
void AdvanceTimeMilliseconds(int64_t ms) {
local_clock_.AdvanceTimeMilliseconds(ms);
remote_clock_.AdvanceTimeMilliseconds(ms);
}
uint32_t GetRemoteTimestamp() {
return static_cast<uint32_t>(remote_clock_.TimeInMilliseconds()) * 90 +
kTimestampOffset;
}
NtpTime GetRemoteNtpTime() {
return TimeMicrosToNtp(remote_clock_.TimeInMicroseconds());
}
void SendRtcpSr() {
uint32_t rtcp_timestamp = GetRemoteTimestamp();
NtpTime ntp = GetRemoteNtpTime();
AdvanceTimeMilliseconds(kTestRtt / 2);
ReceiveRtcpSr(kTestRtt, rtcp_timestamp, ntp.seconds(), ntp.fractions());
}
void SendRtcpSrInaccurately(int64_t ntp_error_ms,
int64_t networking_delay_ms) {
uint32_t rtcp_timestamp = GetRemoteTimestamp();
int64_t ntp_error_fractions =
ntp_error_ms * static_cast<int64_t>(NtpTime::kFractionsPerSecond) /
1000;
NtpTime ntp(static_cast<uint64_t>(GetRemoteNtpTime()) +
ntp_error_fractions);
AdvanceTimeMilliseconds(kTestRtt / 2 + networking_delay_ms);
ReceiveRtcpSr(kTestRtt, rtcp_timestamp, ntp.seconds(), ntp.fractions());
}
void UpdateRtcpTimestamp(int64_t rtt,
uint32_t ntp_secs,
uint32_t ntp_frac,
uint32_t rtp_timestamp,
bool expected_result) {
EXPECT_EQ(expected_result, estimator_->UpdateRtcpTimestamp(
rtt, ntp_secs, ntp_frac, rtp_timestamp));
}
void ReceiveRtcpSr(int64_t rtt,
uint32_t rtcp_timestamp,
uint32_t ntp_seconds,
uint32_t ntp_fractions) {
UpdateRtcpTimestamp(rtt, ntp_seconds, ntp_fractions, rtcp_timestamp, true);
}
SimulatedClock local_clock_;
SimulatedClock remote_clock_;
std::unique_ptr<RemoteNtpTimeEstimator> estimator_;
};
TEST_F(RemoteNtpTimeEstimatorTest, Estimate) {
// Failed without valid NTP.
UpdateRtcpTimestamp(kTestRtt, 0, 0, 0, false);
AdvanceTimeMilliseconds(1000);
// Remote peer sends first RTCP SR.
SendRtcpSr();
// Remote sends a RTP packet.
AdvanceTimeMilliseconds(15);
uint32_t rtp_timestamp = GetRemoteTimestamp();
int64_t capture_ntp_time_ms = local_clock_.CurrentNtpInMilliseconds();
// Local peer needs at least 2 RTCP SR to calculate the capture time.
const int64_t kNotEnoughRtcpSr = -1;
EXPECT_EQ(kNotEnoughRtcpSr, estimator_->Estimate(rtp_timestamp));
EXPECT_EQ(absl::nullopt, estimator_->EstimateRemoteToLocalClockOffsetMs());
AdvanceTimeMilliseconds(800);
// Remote sends second RTCP SR.
SendRtcpSr();
// Local peer gets enough RTCP SR to calculate the capture time.
EXPECT_EQ(capture_ntp_time_ms, estimator_->Estimate(rtp_timestamp));
EXPECT_EQ(kRemoteToLocalClockOffsetMs,
estimator_->EstimateRemoteToLocalClockOffsetMs());
}
TEST_F(RemoteNtpTimeEstimatorTest, AveragesErrorsOut) {
// Remote peer sends first 10 RTCP SR without errors.
for (int i = 0; i < 10; ++i) {
AdvanceTimeMilliseconds(1000);
SendRtcpSr();
}
AdvanceTimeMilliseconds(150);
uint32_t rtp_timestamp = GetRemoteTimestamp();
int64_t capture_ntp_time_ms = local_clock_.CurrentNtpInMilliseconds();
// Local peer gets enough RTCP SR to calculate the capture time.
EXPECT_EQ(capture_ntp_time_ms, estimator_->Estimate(rtp_timestamp));
EXPECT_EQ(kRemoteToLocalClockOffsetMs,
estimator_->EstimateRemoteToLocalClockOffsetMs());
// Remote sends corrupted RTCP SRs
AdvanceTimeMilliseconds(1000);
SendRtcpSrInaccurately(/*ntp_error_ms=*/2, /*networking_delay_ms=*/-1);
AdvanceTimeMilliseconds(1000);
SendRtcpSrInaccurately(/*ntp_error_ms=*/-2, /*networking_delay_ms=*/1);
// New RTP packet to estimate timestamp.
AdvanceTimeMilliseconds(150);
rtp_timestamp = GetRemoteTimestamp();
capture_ntp_time_ms = local_clock_.CurrentNtpInMilliseconds();
// Errors should be averaged out.
EXPECT_EQ(capture_ntp_time_ms, estimator_->Estimate(rtp_timestamp));
EXPECT_EQ(kRemoteToLocalClockOffsetMs,
estimator_->EstimateRemoteToLocalClockOffsetMs());
}
} // namespace webrtc