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:
parent
4e545cc244
commit
88abf11cad
@ -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',
|
||||
|
@ -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_
|
85
webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc
Normal file
85
webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc
Normal 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
|
@ -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
|
@ -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',
|
||||
|
@ -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;
|
||||
|
@ -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_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user