| Index: media/cast/net/rtcp/receiver_rtcp_session.cc
|
| diff --git a/media/cast/net/rtcp/receiver_rtcp_session.cc b/media/cast/net/rtcp/receiver_rtcp_session.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ba917da6155be5ef2728e7f403a4dad78aba6759
|
| --- /dev/null
|
| +++ b/media/cast/net/rtcp/receiver_rtcp_session.cc
|
| @@ -0,0 +1,172 @@
|
| +// 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/pacing/paced_sender.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 {
|
| +
|
| +namespace {
|
| +
|
| +// Create a NTP diff from seconds and fractions of seconds; delay_fraction is
|
| +// fractions of a second where 0x80000000 is half a second.
|
| +uint32_t ConvertToNtpDiff(uint32_t delay_seconds, uint32_t delay_fraction) {
|
| + return ((delay_seconds & 0x0000FFFF) << 16) +
|
| + ((delay_fraction & 0xFFFF0000) >> 16);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +ReceiverRtcpSession::ReceiverRtcpSession(base::TickClock* clock,
|
| + PacedPacketSender* packet_sender,
|
| + uint32_t local_ssrc,
|
| + uint32_t remote_ssrc)
|
| + : clock_(clock),
|
| + packet_sender_(packet_sender),
|
| + 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() {}
|
| +
|
| +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::SendRtcpReport(
|
| + RtcpTimeData time_data,
|
| + const RtcpCastMessage* cast_message,
|
| + base::TimeDelta target_delay,
|
| + const ReceiverRtcpEventSubscriber::RtcpEvents* rtcp_events,
|
| + const RtpReceiverStatistics* rtp_receiver_statistics) const {
|
| + RtcpReportBlock report_block;
|
| + RtcpReceiverReferenceTimeReport rrtr;
|
| + rrtr.ntp_seconds = time_data.ntp_seconds;
|
| + rrtr.ntp_fraction = time_data.ntp_fraction;
|
| +
|
| + if (rtp_receiver_statistics) {
|
| + report_block.remote_ssrc = 0; // Not needed to set send side.
|
| + report_block.media_ssrc = remote_ssrc_; // SSRC of the RTP packet sender.
|
| + report_block.fraction_lost = rtp_receiver_statistics->fraction_lost;
|
| + report_block.cumulative_lost = rtp_receiver_statistics->cumulative_lost;
|
| + report_block.extended_high_sequence_number =
|
| + rtp_receiver_statistics->extended_high_sequence_number;
|
| + report_block.jitter = rtp_receiver_statistics->jitter;
|
| + report_block.last_sr = last_report_truncated_ntp_;
|
| + if (!time_last_report_received_.is_null()) {
|
| + uint32_t delay_seconds = 0;
|
| + uint32_t delay_fraction = 0;
|
| + base::TimeDelta delta = time_data.timestamp - time_last_report_received_;
|
| + ConvertTimeToFractions(delta.InMicroseconds(), &delay_seconds,
|
| + &delay_fraction);
|
| + report_block.delay_since_last_sr =
|
| + ConvertToNtpDiff(delay_seconds, delay_fraction);
|
| + } else {
|
| + report_block.delay_since_last_sr = 0;
|
| + }
|
| + }
|
| + RtcpBuilder rtcp_builder(local_ssrc_);
|
| + packet_sender_->SendRtcpPacket(
|
| + local_ssrc_, rtcp_builder.BuildRtcpFromReceiver(
|
| + rtp_receiver_statistics ? &report_block : NULL, &rrtr,
|
| + cast_message, rtcp_events, target_delay));
|
| +}
|
| +
|
| +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
|
|
|