Move the capture ntp computing code to ntp_calculator so that later it can be shared with voe.

BUG=3111
TEST=try bots
R=stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/13489004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6152 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
wu@webrtc.org 2014-05-14 16:53:51 +00:00
parent 4e545cc244
commit 88abf11cad
7 changed files with 258 additions and 76 deletions

View File

@ -199,6 +199,7 @@
'rtp_rtcp/source/nack_rtx_unittest.cc',
'rtp_rtcp/source/producer_fec_unittest.cc',
'rtp_rtcp/source/receive_statistics_unittest.cc',
'rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc',
'rtp_rtcp/source/rtcp_format_remb_unittest.cc',
'rtp_rtcp/source/rtcp_packet_unittest.cc',
'rtp_rtcp/source/rtcp_receiver_unittest.cc',

View File

@ -0,0 +1,50 @@
/*
* 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.
*/
#ifndef WEBRTC_MODULES_RTP_RTCP_INTERFACE_REMOTE_NTP_TIME_ESTIMATOR_H_
#define WEBRTC_MODULES_RTP_RTCP_INTERFACE_REMOTE_NTP_TIME_ESTIMATOR_H_
#include "webrtc/system_wrappers/interface/rtp_to_ntp.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
namespace webrtc {
class Clock;
class RtpRtcp;
class TimestampExtrapolator;
// RemoteNtpTimeEstimator can be used to estimate a given RTP timestamp's NTP
// time in local timebase.
// Note that it needs to be trained with at least 2 RTCP SR (by calling
// |UpdateRtcpTimestamp|) before it can be used.
class RemoteNtpTimeEstimator {
public:
explicit RemoteNtpTimeEstimator(Clock* clock);
~RemoteNtpTimeEstimator();
// Updates the estimator with the timestamp from newly received RTCP SR for
// |ssrc|. The RTCP SR is read from |rtp_rtcp|.
bool UpdateRtcpTimestamp(uint32_t ssrc, RtpRtcp* rtp_rtcp);
// Estimates the NTP timestamp in local timebase from |rtp_timestamp|.
// Returns the NTP timestamp in ms when success. -1 if failed.
int64_t Estimate(uint32_t rtp_timestamp);
private:
Clock* clock_;
scoped_ptr<TimestampExtrapolator> ts_extrapolator_;
RtcpList rtcp_list_;
DISALLOW_COPY_AND_ASSIGN(RemoteNtpTimeEstimator);
};
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_INTERFACE_REMOTE_NTP_TIME_ESTIMATOR_H_

View File

@ -0,0 +1,85 @@
/*
* 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 "webrtc/modules/rtp_rtcp/interface/remote_ntp_time_estimator.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/timestamp_extrapolator.h"
namespace webrtc {
// TODO(wu): Refactor this class so that it can be shared with
// vie_sync_module.cc.
RemoteNtpTimeEstimator::RemoteNtpTimeEstimator(Clock* clock)
: clock_(clock),
ts_extrapolator_(
new TimestampExtrapolator(clock_->TimeInMilliseconds())) {
}
RemoteNtpTimeEstimator::~RemoteNtpTimeEstimator() {}
bool RemoteNtpTimeEstimator::UpdateRtcpTimestamp(uint32_t ssrc,
RtpRtcp* rtp_rtcp) {
assert(rtp_rtcp);
uint16_t rtt = 0;
rtp_rtcp->RTT(ssrc, &rtt, NULL, NULL, NULL);
if (rtt == 0) {
// Waiting for valid rtt.
return true;
}
// Update RTCP list
uint32_t ntp_secs = 0;
uint32_t ntp_frac = 0;
uint32_t rtp_timestamp = 0;
if (0 != rtp_rtcp->RemoteNTP(&ntp_secs,
&ntp_frac,
NULL,
NULL,
&rtp_timestamp)) {
// Waiting for RTCP.
return true;
}
bool new_rtcp_sr = false;
if (!UpdateRtcpList(
ntp_secs, ntp_frac, rtp_timestamp, &rtcp_list_, &new_rtcp_sr)) {
return false;
}
if (!new_rtcp_sr) {
// No new RTCP SR since last time this function was called.
return true;
}
// Update extrapolator with the new arrival time.
// The extrapolator assumes the TimeInMilliseconds time.
int64_t receiver_arrival_time_ms = clock_->TimeInMilliseconds();
int64_t sender_send_time_ms = Clock::NtpToMs(ntp_secs, ntp_frac);
int64_t sender_arrival_time_90k = (sender_send_time_ms + rtt / 2) * 90;
ts_extrapolator_->Update(receiver_arrival_time_ms, sender_arrival_time_90k);
return true;
}
int64_t RemoteNtpTimeEstimator::Estimate(uint32_t rtp_timestamp) {
if (rtcp_list_.size() < 2) {
// We need two RTCP SR reports to calculate NTP.
return -1;
}
int64_t sender_capture_ntp_ms = 0;
if (!RtpToNtpMs(rtp_timestamp, rtcp_list_, &sender_capture_ntp_ms)) {
return -1;
}
uint32_t timestamp = sender_capture_ntp_ms * 90;
int64_t receiver_capture_ms =
ts_extrapolator_->ExtrapolateLocalTime(timestamp);
int64_t ntp_offset =
clock_->CurrentNtpInMilliseconds() - clock_->TimeInMilliseconds();
return receiver_capture_ms + ntp_offset;
}
} // namespace webrtc

View File

@ -0,0 +1,112 @@
/*
* 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 "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/rtp_rtcp/interface/remote_ntp_time_estimator.h"
#include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
using ::testing::_;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SetArgPointee;
namespace webrtc {
static const int kTestRtt = 10;
static const int64_t kLocalClockInitialTimeMs = 123;
static const int64_t kRemoteClockInitialTimeMs = 345;
static const uint32_t kTimestampOffset = 567;
static const int kTestSsrc = 789;
class RemoteNtpTimeEstimatorTest : public ::testing::Test {
protected:
RemoteNtpTimeEstimatorTest()
: local_clock_(kLocalClockInitialTimeMs * 1000),
remote_clock_(kRemoteClockInitialTimeMs * 1000),
estimator_(&local_clock_) {}
~RemoteNtpTimeEstimatorTest() {}
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;
}
void SendRtcpSr() {
uint32_t rtcp_timestamp = GetRemoteTimestamp();
uint32_t ntp_seconds;
uint32_t ntp_fractions;
remote_clock_.CurrentNtp(ntp_seconds, ntp_fractions);
AdvanceTimeMilliseconds(kTestRtt / 2);
ReceiveRtcpSr(rtcp_timestamp, ntp_seconds, ntp_fractions);
}
void UpdateRtcpTimestamp(MockRtpRtcp* rtp_rtcp, bool expected_result) {
if (rtp_rtcp) {
EXPECT_CALL(*rtp_rtcp, RTT(_, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<1>(kTestRtt),
Return(0)));
}
EXPECT_EQ(expected_result,
estimator_.UpdateRtcpTimestamp(kTestSsrc, rtp_rtcp));
}
void ReceiveRtcpSr(uint32_t rtcp_timestamp,
uint32_t ntp_seconds,
uint32_t ntp_fractions) {
EXPECT_CALL(rtp_rtcp_, RemoteNTP(_, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<0>(ntp_seconds),
SetArgPointee<1>(ntp_fractions),
SetArgPointee<4>(rtcp_timestamp),
Return(0)));
UpdateRtcpTimestamp(&rtp_rtcp_, true);
}
SimulatedClock local_clock_;
SimulatedClock remote_clock_;
MockRtpRtcp rtp_rtcp_;
RemoteNtpTimeEstimator estimator_;
};
TEST_F(RemoteNtpTimeEstimatorTest, Estimate) {
// Failed without any RTCP SR, where RemoteNTP returns without valid NTP.
EXPECT_CALL(rtp_rtcp_, RemoteNTP(_, _, _, _, _)).WillOnce(Return(0));
UpdateRtcpTimestamp(&rtp_rtcp_, 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));
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));
}
} // namespace webrtc

View File

@ -20,6 +20,7 @@
# Common
'../interface/fec_receiver.h',
'../interface/receive_statistics.h',
'../interface/remote_ntp_time_estimator.h',
'../interface/rtp_header_parser.h',
'../interface/rtp_payload_registry.h',
'../interface/rtp_receiver.h',
@ -32,6 +33,7 @@
'fec_receiver_impl.h',
'receive_statistics_impl.cc',
'receive_statistics_impl.h',
'remote_ntp_time_estimator.cc',
'rtp_header_parser.cc',
'rtp_rtcp_config.h',
'rtp_rtcp_impl.cc',

View File

@ -15,6 +15,7 @@
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#include "webrtc/modules/rtp_rtcp/interface/fec_receiver.h"
#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
#include "webrtc/modules/rtp_rtcp/interface/remote_ntp_time_estimator.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
@ -25,6 +26,7 @@
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/tick_util.h"
#include "webrtc/system_wrappers/interface/timestamp_extrapolator.h"
#include "webrtc/system_wrappers/interface/trace.h"
namespace webrtc {
@ -45,9 +47,7 @@ ViEReceiver::ViEReceiver(const int32_t channel_id,
rtp_rtcp_(NULL),
vcm_(module_vcm),
remote_bitrate_estimator_(remote_bitrate_estimator),
clock_(Clock::GetRealTimeClock()),
ts_extrapolator_(
new TimestampExtrapolator(clock_->TimeInMilliseconds())),
ntp_estimator_(new RemoteNtpTimeEstimator(Clock::GetRealTimeClock())),
rtp_dump_(NULL),
receiving_(false),
restored_packet_in_use_(false),
@ -175,7 +175,8 @@ int32_t ViEReceiver::OnReceivedPayloadData(
const uint8_t* payload_data, const uint16_t payload_size,
const WebRtcRTPHeader* rtp_header) {
WebRtcRTPHeader rtp_header_with_ntp = *rtp_header;
CalculateCaptureNtpTime(&rtp_header_with_ntp);
rtp_header_with_ntp.ntp_time_ms =
ntp_estimator_->Estimate(rtp_header->header.timestamp);
if (vcm_->IncomingPacket(payload_data,
payload_size,
rtp_header_with_ntp) != 0) {
@ -185,26 +186,6 @@ int32_t ViEReceiver::OnReceivedPayloadData(
return 0;
}
void ViEReceiver::CalculateCaptureNtpTime(WebRtcRTPHeader* rtp_header) {
if (rtcp_list_.size() < 2) {
// We need two RTCP SR reports to calculate NTP.
return;
}
int64_t sender_capture_ntp_ms = 0;
if (!RtpToNtpMs(rtp_header->header.timestamp,
rtcp_list_,
&sender_capture_ntp_ms)) {
return;
}
uint32_t timestamp = sender_capture_ntp_ms * 90;
int64_t receiver_capture_ms =
ts_extrapolator_->ExtrapolateLocalTime(timestamp);
int64_t ntp_offset =
clock_->CurrentNtpInMilliseconds() - clock_->TimeInMilliseconds();
rtp_header->ntp_time_ms = receiver_capture_ms + ntp_offset;
}
bool ViEReceiver::OnRecoveredPacket(const uint8_t* rtp_packet,
int rtp_packet_length) {
RTPHeader header;
@ -352,56 +333,13 @@ int ViEReceiver::InsertRTCPPacket(const uint8_t* rtcp_packet,
return ret;
}
if (!GetRtcpTimestamp()) {
if (!ntp_estimator_->UpdateRtcpTimestamp(rtp_receiver_->SSRC(), rtp_rtcp_)) {
LOG(LS_WARNING) << "Failed to retrieve timestamp information from RTCP SR.";
}
return 0;
}
bool ViEReceiver::GetRtcpTimestamp() {
uint16_t rtt = 0;
rtp_rtcp_->RTT(rtp_receiver_->SSRC(), &rtt, NULL, NULL, NULL);
if (rtt == 0) {
// Waiting for valid rtt.
return true;
}
// Update RTCP list
uint32_t ntp_secs = 0;
uint32_t ntp_frac = 0;
uint32_t rtp_timestamp = 0;
if (0 != rtp_rtcp_->RemoteNTP(&ntp_secs,
&ntp_frac,
NULL,
NULL,
&rtp_timestamp)) {
return false;
}
bool new_rtcp_sr = false;
if (!UpdateRtcpList(ntp_secs,
ntp_frac,
rtp_timestamp,
&rtcp_list_,
&new_rtcp_sr)) {
return false;
}
if (!new_rtcp_sr) {
// No new RTCP SR since last time this function was called.
return true;
}
// Update extrapolator with the new arrival time.
// The extrapolator assumes the TimeInMilliseconds time.
int64_t receiver_arrival_time = clock_->TimeInMilliseconds();
int64_t sender_send_time_ms = Clock::NtpToMs(ntp_secs, ntp_frac);
int64_t sender_arrival_time_90k = (sender_send_time_ms + rtt / 2) * 90;
ts_extrapolator_->Update(receiver_arrival_time, sender_arrival_time_90k);
return true;
}
void ViEReceiver::StartReceive() {
CriticalSectionScoped cs(receive_cs_.get());
receiving_ = true;

View File

@ -16,7 +16,6 @@
#include "webrtc/engine_configurations.h"
#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
#include "webrtc/system_wrappers/interface/rtp_to_ntp.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/typedefs.h"
#include "webrtc/video_engine/include/vie_network.h"
@ -26,6 +25,7 @@ namespace webrtc {
class CriticalSectionWrapper;
class FecReceiver;
class RemoteNtpTimeEstimator;
class ReceiveStatistics;
class RemoteBitrateEstimator;
class RtpDump;
@ -33,7 +33,6 @@ class RtpHeaderParser;
class RTPPayloadRegistry;
class RtpReceiver;
class RtpRtcp;
class TimestampExtrapolator;
class VideoCodingModule;
struct ReceiveBandwidthEstimatorStats;
@ -105,9 +104,6 @@ class ViEReceiver : public RtpData {
bool IsPacketInOrder(const RTPHeader& header) const;
bool IsPacketRetransmitted(const RTPHeader& header, bool in_order) const;
bool GetRtcpTimestamp();
void CalculateCaptureNtpTime(WebRtcRTPHeader* rtp_header);
scoped_ptr<CriticalSectionWrapper> receive_cs_;
scoped_ptr<RtpHeaderParser> rtp_header_parser_;
scoped_ptr<RTPPayloadRegistry> rtp_payload_registry_;
@ -119,9 +115,7 @@ class ViEReceiver : public RtpData {
VideoCodingModule* vcm_;
RemoteBitrateEstimator* remote_bitrate_estimator_;
Clock* clock_;
scoped_ptr<TimestampExtrapolator> ts_extrapolator_;
RtcpList rtcp_list_;
scoped_ptr<RemoteNtpTimeEstimator> ntp_estimator_;
RtpDump* rtp_dump_;
bool receiving_;