Make class of static functions in rtp_to_ntp.h:

- UpdateRtcpList
- RtpToNtp

class RtpToNtpEstimator
- UpdateMeasurements
- Estimate

List with rtcp measurements is now private.

BUG=none

Review-Url: https://codereview.webrtc.org/2574133003
Cr-Commit-Position: refs/heads/master@{#15762}
This commit is contained in:
asapersson
2016-12-22 07:53:51 -08:00
committed by Commit bot
parent bf5f5297c5
commit fe50b4d750
12 changed files with 253 additions and 290 deletions

View File

@ -24,7 +24,6 @@
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
#include "webrtc/system_wrappers/include/metrics_default.h"
#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
#include "webrtc/test/call_test.h"
#include "webrtc/test/direct_transport.h"
#include "webrtc/test/drifting_clock.h"

View File

@ -14,7 +14,7 @@
#include <memory>
#include "webrtc/base/constructormagic.h"
#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
#include "webrtc/system_wrappers/include/rtp_to_ntp_estimator.h"
namespace webrtc {
@ -43,7 +43,7 @@ class RemoteNtpTimeEstimator {
private:
Clock* clock_;
std::unique_ptr<TimestampExtrapolator> ts_extrapolator_;
RtcpMeasurements rtcp_list_;
RtpToNtpEstimator rtp_to_ntp_;
int64_t last_timing_log_ms_;
RTC_DISALLOW_COPY_AND_ASSIGN(RemoteNtpTimeEstimator);
};

View File

@ -33,8 +33,8 @@ bool RemoteNtpTimeEstimator::UpdateRtcpTimestamp(int64_t rtt,
uint32_t ntp_frac,
uint32_t rtcp_timestamp) {
bool new_rtcp_sr = false;
if (!UpdateRtcpList(
ntp_secs, ntp_frac, rtcp_timestamp, &rtcp_list_, &new_rtcp_sr)) {
if (!rtp_to_ntp_.UpdateMeasurements(ntp_secs, ntp_frac, rtcp_timestamp,
&new_rtcp_sr)) {
return false;
}
if (!new_rtcp_sr) {
@ -52,7 +52,7 @@ bool RemoteNtpTimeEstimator::UpdateRtcpTimestamp(int64_t rtt,
int64_t RemoteNtpTimeEstimator::Estimate(uint32_t rtp_timestamp) {
int64_t sender_capture_ntp_ms = 0;
if (!RtpToNtpMs(rtp_timestamp, rtcp_list_, &sender_capture_ntp_ms)) {
if (!rtp_to_ntp_.Estimate(rtp_timestamp, &sender_capture_ntp_ms)) {
return -1;
}
uint32_t timestamp = sender_capture_ntp_ms * 90;

View File

@ -28,7 +28,7 @@ rtc_static_library("system_wrappers") {
"include/logging.h",
"include/metrics.h",
"include/ntp_time.h",
"include/rtp_to_ntp.h",
"include/rtp_to_ntp_estimator.h",
"include/rw_lock_wrapper.h",
"include/sleep.h",
"include/static_instance.h",
@ -50,7 +50,7 @@ rtc_static_library("system_wrappers") {
"source/event_timer_win.h",
"source/file_impl.cc",
"source/logging.cc",
"source/rtp_to_ntp.cc",
"source/rtp_to_ntp_estimator.cc",
"source/rw_lock.cc",
"source/rw_lock_posix.cc",
"source/rw_lock_posix.h",
@ -179,7 +179,7 @@ if (rtc_include_tests) {
"source/metrics_default_unittest.cc",
"source/metrics_unittest.cc",
"source/ntp_time_unittest.cc",
"source/rtp_to_ntp_unittest.cc",
"source/rtp_to_ntp_estimator_unittest.cc",
"source/stringize_macros_unittest.cc",
]
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]

View File

@ -1,71 +0,0 @@
/*
* 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.
*/
#ifndef SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_H_
#define SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_H_
#include <list>
#include "webrtc/system_wrappers/include/ntp_time.h"
#include "webrtc/typedefs.h"
namespace webrtc {
struct RtcpMeasurement {
RtcpMeasurement();
RtcpMeasurement(uint32_t ntp_secs, uint32_t ntp_frac, uint32_t timestamp);
bool IsEqual(const RtcpMeasurement& other) const;
NtpTime ntp_time;
uint32_t rtp_timestamp;
};
struct RtcpMeasurements {
RtcpMeasurements();
~RtcpMeasurements();
bool Contains(const RtcpMeasurement& other) const;
bool IsValid(const RtcpMeasurement& other) const;
void UpdateParameters();
// Estimated parameters from RTP and NTP timestamp pairs in |list|.
struct RtpToNtpParameters {
double frequency_khz = 0.0;
double offset_ms = 0.0;
bool calculated = false;
};
std::list<RtcpMeasurement> list;
RtpToNtpParameters params;
};
// Updates |list| in |rtcp_measurements| with timestamps from the RTCP SR.
// |new_rtcp_sr| will be set to true if these are the timestamps which have
// never be added to |list|.
// |rtcp_measurements.params| are estimated from the RTP and NTP timestamp pairs
// in the |list| when a new RTCP SR is inserted.
bool UpdateRtcpList(uint32_t ntp_secs,
uint32_t ntp_frac,
uint32_t rtp_timestamp,
RtcpMeasurements* rtcp_measurements,
bool* new_rtcp_sr);
// Converts an RTP timestamp to the NTP domain in milliseconds using the
// estimated |rtcp_measurements.params|.
bool RtpToNtpMs(int64_t rtp_timestamp,
const RtcpMeasurements& rtcp_measurements,
int64_t* rtp_timestamp_in_ms);
// Returns 1 there has been a forward wrap around, 0 if there has been no wrap
// around and -1 if there has been a backwards wrap around (i.e. reordering).
int CheckForWrapArounds(uint32_t rtp_timestamp, uint32_t rtcp_rtp_timestamp);
} // namespace webrtc
#endif // SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_H_

View File

@ -0,0 +1,72 @@
/*
* 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.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_ESTIMATOR_H_
#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_ESTIMATOR_H_
#include <list>
#include "webrtc/system_wrappers/include/ntp_time.h"
#include "webrtc/typedefs.h"
namespace webrtc {
// Class for converting an RTP timestamp to the NTP domain in milliseconds.
// The class needs to be trained with (at least 2) RTP/NTP timestamp pairs from
// RTCP sender reports before the convertion can be done.
class RtpToNtpEstimator {
public:
RtpToNtpEstimator();
~RtpToNtpEstimator();
// RTP and NTP timestamp pair from a RTCP SR report.
struct RtcpMeasurement {
RtcpMeasurement(uint32_t ntp_secs, uint32_t ntp_frac, uint32_t timestamp);
bool IsEqual(const RtcpMeasurement& other) const;
NtpTime ntp_time;
uint32_t rtp_timestamp;
};
// Estimated parameters from RTP and NTP timestamp pairs in |measurements_|.
struct Parameters {
double frequency_khz = 0.0;
double offset_ms = 0.0;
bool calculated = false;
};
// Updates measurements with RTP/NTP timestamp pair from a RTCP sender report.
// |new_rtcp_sr| is set to true if a new report is added.
bool UpdateMeasurements(uint32_t ntp_secs,
uint32_t ntp_frac,
uint32_t rtp_timestamp,
bool* new_rtcp_sr);
// Converts an RTP timestamp to the NTP domain in milliseconds.
// Returns true on success, false otherwise.
bool Estimate(int64_t rtp_timestamp, int64_t* rtp_timestamp_ms) const;
const Parameters& params() const { return params_; }
private:
void UpdateParameters();
std::list<RtcpMeasurement> measurements_;
Parameters params_;
};
// Returns:
// 1: forward wrap around.
// 0: no wrap around.
// -1: backwards wrap around (i.e. reordering).
int CheckForWrapArounds(uint32_t new_timestamp, uint32_t old_timestamp);
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_ESTIMATOR_H_

View File

@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
#include "webrtc/system_wrappers/include/rtp_to_ntp_estimator.h"
#include "webrtc/base/logging.h"
#include "webrtc/system_wrappers/include/clock.h"
@ -19,16 +19,16 @@ namespace {
const size_t kNumRtcpReportsToUse = 2;
// Calculates the RTP timestamp frequency from two pairs of NTP/RTP timestamps.
bool CalculateFrequency(int64_t rtcp_ntp_ms1,
bool CalculateFrequency(int64_t ntp_ms1,
uint32_t rtp_timestamp1,
int64_t rtcp_ntp_ms2,
int64_t ntp_ms2,
uint32_t rtp_timestamp2,
double* frequency_khz) {
if (rtcp_ntp_ms1 <= rtcp_ntp_ms2) {
if (ntp_ms1 <= ntp_ms2)
return false;
}
*frequency_khz = static_cast<double>(rtp_timestamp1 - rtp_timestamp2) /
static_cast<double>(rtcp_ntp_ms1 - rtcp_ntp_ms2);
static_cast<double>(ntp_ms1 - ntp_ms2);
return true;
}
@ -45,133 +45,126 @@ bool CompensateForWrapAround(uint32_t new_timestamp,
*compensated_timestamp = new_timestamp + (wraps << 32);
return true;
}
} // namespace
// Class holding RTP and NTP timestamp from a RTCP SR report.
RtcpMeasurement::RtcpMeasurement() : ntp_time(0, 0), rtp_timestamp(0) {}
RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs,
uint32_t ntp_frac,
uint32_t timestamp)
: ntp_time(ntp_secs, ntp_frac), rtp_timestamp(timestamp) {}
bool RtcpMeasurement::IsEqual(const RtcpMeasurement& other) const {
// Use || since two equal timestamps will result in zero frequency and in
// RtpToNtpMs, |rtp_timestamp_ms| is estimated by dividing by the frequency.
return (ntp_time == other.ntp_time) || (rtp_timestamp == other.rtp_timestamp);
}
// Class holding list of RTP and NTP timestamp pairs.
RtcpMeasurements::RtcpMeasurements() {}
RtcpMeasurements::~RtcpMeasurements() {}
bool RtcpMeasurements::Contains(const RtcpMeasurement& other) const {
for (const auto& it : list) {
if (it.IsEqual(other))
bool Contains(const std::list<RtpToNtpEstimator::RtcpMeasurement>& measurements,
const RtpToNtpEstimator::RtcpMeasurement& other) {
for (const auto& measurement : measurements) {
if (measurement.IsEqual(other))
return true;
}
return false;
}
bool RtcpMeasurements::IsValid(const RtcpMeasurement& other) const {
bool IsValid(const std::list<RtpToNtpEstimator::RtcpMeasurement>& measurements,
const RtpToNtpEstimator::RtcpMeasurement& other) {
if (!other.ntp_time.Valid())
return false;
int64_t ntp_ms_new = other.ntp_time.ToMs();
for (const auto& it : list) {
if (ntp_ms_new <= it.ntp_time.ToMs()) {
for (const auto& measurement : measurements) {
if (ntp_ms_new <= measurement.ntp_time.ToMs()) {
// Old report.
return false;
}
int64_t timestamp_new = other.rtp_timestamp;
if (!CompensateForWrapAround(timestamp_new, it.rtp_timestamp,
if (!CompensateForWrapAround(timestamp_new, measurement.rtp_timestamp,
&timestamp_new)) {
return false;
}
if (timestamp_new <= it.rtp_timestamp) {
if (timestamp_new <= measurement.rtp_timestamp) {
LOG(LS_WARNING) << "Newer RTCP SR report with older RTP timestamp.";
return false;
}
}
return true;
}
} // namespace
void RtcpMeasurements::UpdateParameters() {
if (list.size() != kNumRtcpReportsToUse)
RtpToNtpEstimator::RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs,
uint32_t ntp_frac,
uint32_t timestamp)
: ntp_time(ntp_secs, ntp_frac), rtp_timestamp(timestamp) {}
bool RtpToNtpEstimator::RtcpMeasurement::IsEqual(
const RtcpMeasurement& other) const {
// Use || since two equal timestamps will result in zero frequency and in
// RtpToNtpMs, |rtp_timestamp_ms| is estimated by dividing by the frequency.
return (ntp_time == other.ntp_time) || (rtp_timestamp == other.rtp_timestamp);
}
// Class for converting an RTP timestamp to the NTP domain.
RtpToNtpEstimator::RtpToNtpEstimator() {}
RtpToNtpEstimator::~RtpToNtpEstimator() {}
void RtpToNtpEstimator::UpdateParameters() {
if (measurements_.size() != kNumRtcpReportsToUse)
return;
int64_t timestamp_new = list.front().rtp_timestamp;
int64_t timestamp_old = list.back().rtp_timestamp;
int64_t timestamp_new = measurements_.front().rtp_timestamp;
int64_t timestamp_old = measurements_.back().rtp_timestamp;
if (!CompensateForWrapAround(timestamp_new, timestamp_old, &timestamp_new))
return;
int64_t ntp_ms_new = list.front().ntp_time.ToMs();
int64_t ntp_ms_old = list.back().ntp_time.ToMs();
int64_t ntp_ms_new = measurements_.front().ntp_time.ToMs();
int64_t ntp_ms_old = measurements_.back().ntp_time.ToMs();
if (!CalculateFrequency(ntp_ms_new, timestamp_new, ntp_ms_old, timestamp_old,
&params.frequency_khz)) {
&params_.frequency_khz)) {
return;
}
params.offset_ms = timestamp_new - params.frequency_khz * ntp_ms_new;
params.calculated = true;
params_.offset_ms = timestamp_new - params_.frequency_khz * ntp_ms_new;
params_.calculated = true;
}
// Updates list holding NTP and RTP timestamp pairs.
bool UpdateRtcpList(uint32_t ntp_secs,
uint32_t ntp_frac,
uint32_t rtp_timestamp,
RtcpMeasurements* rtcp_measurements,
bool* new_rtcp_sr) {
bool RtpToNtpEstimator::UpdateMeasurements(uint32_t ntp_secs,
uint32_t ntp_frac,
uint32_t rtp_timestamp,
bool* new_rtcp_sr) {
*new_rtcp_sr = false;
RtcpMeasurement measurement(ntp_secs, ntp_frac, rtp_timestamp);
if (rtcp_measurements->Contains(measurement)) {
if (Contains(measurements_, measurement)) {
// RTCP SR report already added.
return true;
}
if (!rtcp_measurements->IsValid(measurement)) {
if (!IsValid(measurements_, measurement)) {
// Old report or invalid parameters.
return false;
}
// Insert new RTCP SR report.
if (rtcp_measurements->list.size() == kNumRtcpReportsToUse)
rtcp_measurements->list.pop_back();
if (measurements_.size() == kNumRtcpReportsToUse)
measurements_.pop_back();
rtcp_measurements->list.push_front(measurement);
measurements_.push_front(measurement);
*new_rtcp_sr = true;
// List updated, calculate new parameters.
rtcp_measurements->UpdateParameters();
UpdateParameters();
return true;
}
// Converts |rtp_timestamp| to the NTP time base using the NTP and RTP timestamp
// pairs in |rtcp|. The converted timestamp is returned in
// |rtp_timestamp_in_ms|. This function compensates for wrap arounds in RTP
// timestamps and returns false if it can't do the conversion due to reordering.
bool RtpToNtpMs(int64_t rtp_timestamp,
const RtcpMeasurements& rtcp,
int64_t* rtp_timestamp_in_ms) {
if (!rtcp.params.calculated || rtcp.list.empty())
bool RtpToNtpEstimator::Estimate(int64_t rtp_timestamp,
int64_t* rtp_timestamp_ms) const {
if (!params_.calculated || measurements_.empty())
return false;
uint32_t rtcp_timestamp_old = rtcp.list.back().rtp_timestamp;
uint32_t rtp_timestamp_old = measurements_.back().rtp_timestamp;
int64_t rtp_timestamp_unwrapped;
if (!CompensateForWrapAround(rtp_timestamp, rtcp_timestamp_old,
if (!CompensateForWrapAround(rtp_timestamp, rtp_timestamp_old,
&rtp_timestamp_unwrapped)) {
return false;
}
double rtp_timestamp_ms =
(static_cast<double>(rtp_timestamp_unwrapped) - rtcp.params.offset_ms) /
rtcp.params.frequency_khz +
double rtp_ms =
(static_cast<double>(rtp_timestamp_unwrapped) - params_.offset_ms) /
params_.frequency_khz +
0.5f;
if (rtp_timestamp_ms < 0) {
if (rtp_ms < 0)
return false;
}
*rtp_timestamp_in_ms = rtp_timestamp_ms;
*rtp_timestamp_ms = rtp_ms;
return true;
}

View File

@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
#include "webrtc/system_wrappers/include/rtp_to_ntp_estimator.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
@ -38,236 +38,215 @@ TEST(WrapAroundTests, BackwardWrap) {
}
TEST(WrapAroundTests, OldRtcpWrapped_OldRtpTimestamp) {
RtcpMeasurements rtcp;
RtpToNtpEstimator estimator;
bool new_sr;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 1;
uint32_t timestamp = 0;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
ntp_frac += kOneMsInNtpFrac;
timestamp -= kTimestampTicksPerMs;
// Expected to fail since the older RTCP has a smaller RTP timestamp than the
// newer (old:0, new:4294967206).
EXPECT_FALSE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_FALSE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
}
TEST(WrapAroundTests, NewRtcpWrapped) {
RtcpMeasurements rtcp;
RtpToNtpEstimator estimator;
bool new_sr;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 1;
uint32_t timestamp = 0xFFFFFFFF;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
ntp_frac += kOneMsInNtpFrac;
timestamp += kTimestampTicksPerMs;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
int64_t timestamp_ms = -1;
EXPECT_TRUE(RtpToNtpMs(rtcp.list.back().rtp_timestamp, rtcp, &timestamp_ms));
EXPECT_TRUE(estimator.Estimate(0xFFFFFFFF, &timestamp_ms));
// 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(0, timestamp_ms);
}
TEST(WrapAroundTests, RtpWrapped) {
RtcpMeasurements rtcp;
RtpToNtpEstimator estimator;
bool new_sr;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 1;
uint32_t timestamp = 0xFFFFFFFF - 2 * kTimestampTicksPerMs;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
ntp_frac += kOneMsInNtpFrac;
timestamp += kTimestampTicksPerMs;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
int64_t timestamp_ms = -1;
EXPECT_TRUE(RtpToNtpMs(rtcp.list.back().rtp_timestamp, rtcp, &timestamp_ms));
EXPECT_TRUE(estimator.Estimate(0xFFFFFFFF - 2 * kTimestampTicksPerMs,
&timestamp_ms));
// 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(0, timestamp_ms);
// Two kTimestampTicksPerMs advanced.
timestamp += kTimestampTicksPerMs;
EXPECT_TRUE(RtpToNtpMs(timestamp, rtcp, &timestamp_ms));
EXPECT_TRUE(estimator.Estimate(timestamp, &timestamp_ms));
EXPECT_EQ(2, timestamp_ms);
// Wrapped rtp.
timestamp += kTimestampTicksPerMs;
EXPECT_TRUE(RtpToNtpMs(timestamp, rtcp, &timestamp_ms));
EXPECT_TRUE(estimator.Estimate(timestamp, &timestamp_ms));
EXPECT_EQ(3, timestamp_ms);
}
TEST(WrapAroundTests, OldRtp_RtcpsWrapped) {
RtcpMeasurements rtcp;
RtpToNtpEstimator estimator;
bool new_sr;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 1;
uint32_t timestamp = 0;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
ntp_frac += kOneMsInNtpFrac;
timestamp += kTimestampTicksPerMs;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
timestamp -= 2*kTimestampTicksPerMs;
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
timestamp -= 2 * kTimestampTicksPerMs;
int64_t timestamp_ms = -1;
EXPECT_FALSE(RtpToNtpMs(timestamp, rtcp, &timestamp_ms));
EXPECT_FALSE(estimator.Estimate(timestamp, &timestamp_ms));
}
TEST(WrapAroundTests, OldRtp_NewRtcpWrapped) {
RtcpMeasurements rtcp;
RtpToNtpEstimator estimator;
bool new_sr;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 1;
uint32_t timestamp = 0xFFFFFFFF;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
ntp_frac += kOneMsInNtpFrac;
timestamp += kTimestampTicksPerMs;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
timestamp -= kTimestampTicksPerMs;
int64_t timestamp_ms = -1;
EXPECT_TRUE(RtpToNtpMs(timestamp, rtcp, &timestamp_ms));
EXPECT_TRUE(estimator.Estimate(timestamp, &timestamp_ms));
// Constructed at the same time as the first RTCP and should therefore be
// mapped to zero.
EXPECT_EQ(0, timestamp_ms);
}
TEST(UpdateRtcpListTests, InjectRtcpSr) {
const uint32_t kNtpSec = 10;
const uint32_t kNtpFrac = 12345;
const uint32_t kTs = 0x12345678;
bool new_sr;
RtcpMeasurements rtcp;
EXPECT_TRUE(UpdateRtcpList(kNtpSec, kNtpFrac, kTs, &rtcp, &new_sr));
EXPECT_TRUE(new_sr);
EXPECT_EQ(1u, rtcp.list.size());
EXPECT_EQ(kNtpSec, rtcp.list.front().ntp_time.seconds());
EXPECT_EQ(kNtpFrac, rtcp.list.front().ntp_time.fractions());
EXPECT_EQ(kTs, rtcp.list.front().rtp_timestamp);
// Add second report.
EXPECT_TRUE(UpdateRtcpList(kNtpSec, kNtpFrac + kOneMsInNtpFrac, kTs + 1,
&rtcp, &new_sr));
EXPECT_EQ(2u, rtcp.list.size());
EXPECT_EQ(kTs + 1, rtcp.list.front().rtp_timestamp);
EXPECT_EQ(kTs + 0, rtcp.list.back().rtp_timestamp);
// List should contain last two reports.
EXPECT_TRUE(UpdateRtcpList(kNtpSec, kNtpFrac + 2 * kOneMsInNtpFrac, kTs + 2,
&rtcp, &new_sr));
EXPECT_EQ(2u, rtcp.list.size());
EXPECT_EQ(kTs + 2, rtcp.list.front().rtp_timestamp);
EXPECT_EQ(kTs + 1, rtcp.list.back().rtp_timestamp);
}
TEST(UpdateRtcpListTests, FailsForZeroNtp) {
RtcpMeasurements rtcp;
TEST(UpdateRtcpMeasurementTests, FailsForZeroNtp) {
RtpToNtpEstimator estimator;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 0;
uint32_t timestamp = 0x12345678;
bool new_sr;
EXPECT_FALSE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_FALSE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
EXPECT_FALSE(new_sr);
EXPECT_EQ(0u, rtcp.list.size());
}
TEST(UpdateRtcpListTests, FailsForEqualNtp) {
RtcpMeasurements rtcp;
TEST(UpdateRtcpMeasurementTests, FailsForEqualNtp) {
RtpToNtpEstimator estimator;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 699925050;
uint32_t timestamp = 0x12345678;
bool new_sr;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
EXPECT_TRUE(new_sr);
EXPECT_EQ(1u, rtcp.list.size());
// Ntp time already added, list not updated.
++timestamp;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
EXPECT_FALSE(new_sr);
EXPECT_EQ(1u, rtcp.list.size());
}
TEST(UpdateRtcpListTests, FailsForOldNtp) {
RtcpMeasurements rtcp;
TEST(UpdateRtcpMeasurementTests, FailsForOldNtp) {
RtpToNtpEstimator estimator;
uint32_t ntp_sec = 1;
uint32_t ntp_frac = 699925050;
uint32_t timestamp = 0x12345678;
bool new_sr;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
EXPECT_TRUE(new_sr);
EXPECT_EQ(1u, rtcp.list.size());
// Old ntp time, list not updated.
ntp_frac -= kOneMsInNtpFrac;
timestamp += kTimestampTicksPerMs;
EXPECT_FALSE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_EQ(1u, rtcp.list.size());
EXPECT_FALSE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
}
TEST(UpdateRtcpListTests, FailsForEqualTimestamp) {
RtcpMeasurements rtcp;
TEST(UpdateRtcpMeasurementTests, FailsForEqualTimestamp) {
RtpToNtpEstimator estimator;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 2;
uint32_t timestamp = 0x12345678;
bool new_sr;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
EXPECT_TRUE(new_sr);
EXPECT_EQ(1u, rtcp.list.size());
// Timestamp already added, list not updated.
++ntp_frac;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
EXPECT_FALSE(new_sr);
EXPECT_EQ(1u, rtcp.list.size());
}
TEST(UpdateRtcpListTests, FailsForOldRtpTimestamp) {
RtcpMeasurements rtcp;
TEST(UpdateRtcpMeasurementTests, FailsForOldRtpTimestamp) {
RtpToNtpEstimator estimator;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 2;
uint32_t timestamp = 0x12345678;
bool new_sr;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
EXPECT_TRUE(new_sr);
EXPECT_EQ(1u, rtcp.list.size());
// Old timestamp, list not updated.
ntp_frac += kOneMsInNtpFrac;
timestamp -= kTimestampTicksPerMs;
EXPECT_FALSE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_FALSE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
EXPECT_FALSE(new_sr);
EXPECT_EQ(1u, rtcp.list.size());
}
TEST(UpdateRtcpListTests, VerifyParameters) {
RtcpMeasurements rtcp;
TEST(UpdateRtcpMeasurementTests, VerifyParameters) {
RtpToNtpEstimator estimator;
uint32_t ntp_sec = 1;
uint32_t ntp_frac = 2;
uint32_t timestamp = 0x12345678;
bool new_sr;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
EXPECT_TRUE(new_sr);
EXPECT_FALSE(rtcp.params.calculated);
EXPECT_FALSE(estimator.params().calculated);
// Add second report, parameters should be calculated.
ntp_frac += kOneMsInNtpFrac;
timestamp += kTimestampTicksPerMs;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_TRUE(rtcp.params.calculated);
EXPECT_DOUBLE_EQ(90.0, rtcp.params.frequency_khz);
EXPECT_NE(0.0, rtcp.params.offset_ms);
}
TEST(RtpToNtpTests, FailsForEmptyList) {
RtcpMeasurements rtcp;
rtcp.params.calculated = true;
// List is empty, conversion of RTP to NTP time should fail.
EXPECT_EQ(0u, rtcp.list.size());
int64_t timestamp_ms = -1;
EXPECT_FALSE(RtpToNtpMs(0, rtcp, &timestamp_ms));
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
EXPECT_TRUE(estimator.params().calculated);
EXPECT_DOUBLE_EQ(90.0, estimator.params().frequency_khz);
EXPECT_NE(0.0, estimator.params().offset_ms);
}
TEST(RtpToNtpTests, FailsForNoParameters) {
RtcpMeasurements rtcp;
RtpToNtpEstimator estimator;
uint32_t ntp_sec = 1;
uint32_t ntp_frac = 2;
uint32_t timestamp = 0x12345678;
bool new_sr;
EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
EXPECT_EQ(1u, rtcp.list.size());
EXPECT_TRUE(
estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
EXPECT_TRUE(new_sr);
// Parameters are not calculated, conversion of RTP to NTP time should fail.
EXPECT_FALSE(rtcp.params.calculated);
EXPECT_FALSE(estimator.params().calculated);
int64_t timestamp_ms = -1;
EXPECT_FALSE(RtpToNtpMs(timestamp, rtcp, &timestamp_ms));
EXPECT_FALSE(estimator.Estimate(timestamp, &timestamp_ms));
}
}; // namespace webrtc

View File

@ -41,8 +41,8 @@ bool UpdateMeasurements(StreamSynchronization::Measurements* stream,
}
bool new_rtcp_sr = false;
if (!UpdateRtcpList(ntp_secs, ntp_frac, rtp_timestamp, &stream->rtcp,
&new_rtcp_sr)) {
if (!stream->rtp_to_ntp.UpdateMeasurements(ntp_secs, ntp_frac, rtp_timestamp,
&new_rtcp_sr)) {
return false;
}
@ -183,14 +183,14 @@ bool RtpStreamsSynchronizer::GetStreamSyncOffsetInMs(
}
int64_t latest_audio_ntp;
if (!RtpToNtpMs(playout_timestamp, audio_measurement_.rtcp,
&latest_audio_ntp)) {
if (!audio_measurement_.rtp_to_ntp.Estimate(playout_timestamp,
&latest_audio_ntp)) {
return false;
}
int64_t latest_video_ntp;
if (!RtpToNtpMs(frame.timestamp(), video_measurement_.rtcp,
&latest_video_ntp)) {
if (!video_measurement_.rtp_to_ntp.Estimate(frame.timestamp(),
&latest_video_ntp)) {
return false;
}
@ -200,7 +200,7 @@ bool RtpStreamsSynchronizer::GetStreamSyncOffsetInMs(
latest_video_ntp += time_to_render_ms;
*stream_offset_ms = latest_audio_ntp - latest_video_ntp;
*estimated_freq_khz = video_measurement_.rtcp.params.frequency_khz;
*estimated_freq_khz = video_measurement_.rtp_to_ntp.params().frequency_khz;
return true;
}

View File

@ -40,15 +40,13 @@ bool StreamSynchronization::ComputeRelativeDelay(
int* relative_delay_ms) {
assert(relative_delay_ms);
int64_t audio_last_capture_time_ms;
if (!RtpToNtpMs(audio_measurement.latest_timestamp,
audio_measurement.rtcp,
&audio_last_capture_time_ms)) {
if (!audio_measurement.rtp_to_ntp.Estimate(audio_measurement.latest_timestamp,
&audio_last_capture_time_ms)) {
return false;
}
int64_t video_last_capture_time_ms;
if (!RtpToNtpMs(video_measurement.latest_timestamp,
video_measurement.rtcp,
&video_last_capture_time_ms)) {
if (!video_measurement.rtp_to_ntp.Estimate(video_measurement.latest_timestamp,
&video_last_capture_time_ms)) {
return false;
}
if (video_last_capture_time_ms < 0) {

View File

@ -13,7 +13,7 @@
#include <list>
#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
#include "webrtc/system_wrappers/include/rtp_to_ntp_estimator.h"
#include "webrtc/typedefs.h"
namespace webrtc {
@ -21,8 +21,8 @@ namespace webrtc {
class StreamSynchronization {
public:
struct Measurements {
Measurements() : rtcp(), latest_receive_time_ms(0), latest_timestamp(0) {}
RtcpMeasurements rtcp;
Measurements() : latest_receive_time_ms(0), latest_timestamp(0) {}
RtpToNtpEstimator rtp_to_ntp;
int64_t latest_receive_time_ms;
uint32_t latest_timestamp;
};

View File

@ -34,13 +34,6 @@ class Time {
: kNtpJan1970(2208988800UL),
time_now_ms_(offset) {}
RtcpMeasurement GenerateRtcp(int frequency, uint32_t offset) const {
RtcpMeasurement rtcp;
rtcp.ntp_time = GetNowNtp();
rtcp.rtp_timestamp = GetNowRtp(frequency, offset);
return rtcp;
}
NtpTime GetNowNtp() const {
uint32_t ntp_secs = time_now_ms_ / 1000 + kNtpJan1970;
int64_t remainder_ms = time_now_ms_ % 1000;
@ -104,29 +97,29 @@ class StreamSynchronizationTest : public ::testing::Test {
StreamSynchronization::Measurements audio;
StreamSynchronization::Measurements video;
// Generate NTP/RTP timestamp pair for both streams corresponding to RTCP.
RtcpMeasurement rtcp =
send_time_->GenerateRtcp(audio_frequency, audio_offset);
EXPECT_TRUE(UpdateRtcpList(rtcp.ntp_time.seconds(),
rtcp.ntp_time.fractions(), rtcp.rtp_timestamp,
&audio.rtcp, &new_sr));
NtpTime ntp_time = send_time_->GetNowNtp();
uint32_t rtp_timestamp =
send_time_->GetNowRtp(audio_frequency, audio_offset);
EXPECT_TRUE(audio.rtp_to_ntp.UpdateMeasurements(
ntp_time.seconds(), ntp_time.fractions(), rtp_timestamp, &new_sr));
send_time_->IncreaseTimeMs(100);
receive_time_->IncreaseTimeMs(100);
rtcp = send_time_->GenerateRtcp(video_frequency, video_offset);
EXPECT_TRUE(UpdateRtcpList(rtcp.ntp_time.seconds(),
rtcp.ntp_time.fractions(), rtcp.rtp_timestamp,
&video.rtcp, &new_sr));
ntp_time = send_time_->GetNowNtp();
rtp_timestamp = send_time_->GetNowRtp(video_frequency, video_offset);
EXPECT_TRUE(video.rtp_to_ntp.UpdateMeasurements(
ntp_time.seconds(), ntp_time.fractions(), rtp_timestamp, &new_sr));
send_time_->IncreaseTimeMs(900);
receive_time_->IncreaseTimeMs(900);
rtcp = send_time_->GenerateRtcp(audio_frequency, audio_offset);
EXPECT_TRUE(UpdateRtcpList(rtcp.ntp_time.seconds(),
rtcp.ntp_time.fractions(), rtcp.rtp_timestamp,
&audio.rtcp, &new_sr));
ntp_time = send_time_->GetNowNtp();
rtp_timestamp = send_time_->GetNowRtp(audio_frequency, audio_offset);
EXPECT_TRUE(audio.rtp_to_ntp.UpdateMeasurements(
ntp_time.seconds(), ntp_time.fractions(), rtp_timestamp, &new_sr));
send_time_->IncreaseTimeMs(100);
receive_time_->IncreaseTimeMs(100);
rtcp = send_time_->GenerateRtcp(video_frequency, video_offset);
EXPECT_TRUE(UpdateRtcpList(rtcp.ntp_time.seconds(),
rtcp.ntp_time.fractions(), rtcp.rtp_timestamp,
&video.rtcp, &new_sr));
ntp_time = send_time_->GetNowNtp();
rtp_timestamp = send_time_->GetNowRtp(video_frequency, video_offset);
EXPECT_TRUE(video.rtp_to_ntp.UpdateMeasurements(
ntp_time.seconds(), ntp_time.fractions(), rtp_timestamp, &new_sr));
send_time_->IncreaseTimeMs(900);
receive_time_->IncreaseTimeMs(900);