blob: aec48b7841c690590a343e91aade00de10a9ed46 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/big_endian.h"
#include "base/time/tick_clock.h"
#include "media/cast/net/rtcp/receiver_rtcp_session.h"
#include "media/cast/net/rtcp/rtcp_builder.h"
#include "media/cast/net/rtcp/rtcp_defines.h"
#include "media/cast/net/rtcp/rtcp_utility.h"
namespace media {
namespace cast {
ReceiverRtcpSession::ReceiverRtcpSession(const base::TickClock* clock,
uint32_t local_ssrc,
uint32_t remote_ssrc)
: clock_(clock),
local_ssrc_(local_ssrc),
remote_ssrc_(remote_ssrc),
last_report_truncated_ntp_(0),
local_clock_ahead_by_(ClockDriftSmoother::GetDefaultTimeConstant()),
lip_sync_ntp_timestamp_(0),
parser_(local_ssrc, remote_ssrc) {}
ReceiverRtcpSession::~ReceiverRtcpSession() = default;
bool ReceiverRtcpSession::IncomingRtcpPacket(const uint8_t* data,
size_t length) {
// Check if this is a valid RTCP packet.
if (!IsRtcpPacket(data, length)) {
VLOG(1) << "Rtcp@" << this << "::IncomingRtcpPacket() -- "
<< "Received an invalid (non-RTCP?) packet.";
return false;
}
// Check if this packet is to us.
uint32_t ssrc_of_sender = GetSsrcOfSender(data, length);
if (ssrc_of_sender != remote_ssrc_) {
return false;
}
// Parse this packet.
base::BigEndianReader reader(reinterpret_cast<const char*>(data), length);
if (parser_.Parse(&reader)) {
if (parser_.has_sender_report()) {
OnReceivedNtp(parser_.sender_report().ntp_seconds,
parser_.sender_report().ntp_fraction);
OnReceivedLipSyncInfo(parser_.sender_report().rtp_timestamp,
parser_.sender_report().ntp_seconds,
parser_.sender_report().ntp_fraction);
}
}
return true;
}
void ReceiverRtcpSession::OnReceivedNtp(uint32_t ntp_seconds,
uint32_t ntp_fraction) {
last_report_truncated_ntp_ = ConvertToNtpDiff(ntp_seconds, ntp_fraction);
const base::TimeTicks now = clock_->NowTicks();
time_last_report_received_ = now;
// TODO(miu): This clock offset calculation does not account for packet
// transit time over the network. End2EndTest.EvilNetwork confirms that this
// contributes a very significant source of error here. Determine whether
// RTT should be factored-in, and how that changes the rest of the
// calculation.
const base::TimeDelta measured_offset =
now - ConvertNtpToTimeTicks(ntp_seconds, ntp_fraction);
local_clock_ahead_by_.Update(now, measured_offset);
if (measured_offset < local_clock_ahead_by_.Current()) {
// Logically, the minimum offset between the clocks has to be the correct
// one. For example, the time it took to transmit the current report may
// have been lower than usual, and so some of the error introduced by the
// transmission time can be eliminated.
local_clock_ahead_by_.Reset(now, measured_offset);
}
VLOG(1) << "Local clock is ahead of the remote clock by: "
<< "measured=" << measured_offset.InMicroseconds() << " usec, "
<< "filtered=" << local_clock_ahead_by_.Current().InMicroseconds()
<< " usec.";
}
void ReceiverRtcpSession::OnReceivedLipSyncInfo(RtpTimeTicks rtp_timestamp,
uint32_t ntp_seconds,
uint32_t ntp_fraction) {
if (ntp_seconds == 0) {
NOTREACHED();
return;
}
lip_sync_rtp_timestamp_ = rtp_timestamp;
lip_sync_ntp_timestamp_ =
(static_cast<uint64_t>(ntp_seconds) << 32) | ntp_fraction;
}
bool ReceiverRtcpSession::GetLatestLipSyncTimes(
RtpTimeTicks* rtp_timestamp,
base::TimeTicks* reference_time) const {
if (!lip_sync_ntp_timestamp_)
return false;
const base::TimeTicks local_reference_time =
ConvertNtpToTimeTicks(
static_cast<uint32_t>(lip_sync_ntp_timestamp_ >> 32),
static_cast<uint32_t>(lip_sync_ntp_timestamp_)) +
local_clock_ahead_by_.Current();
// Sanity-check: Getting regular lip sync updates?
DCHECK((clock_->NowTicks() - local_reference_time) <
base::TimeDelta::FromMinutes(1));
*rtp_timestamp = lip_sync_rtp_timestamp_;
*reference_time = local_reference_time;
return true;
}
} // namespace cast
} // namespace media