// Copyright 2013 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 "media/cast/rtp_receiver/receiver_stats.h" #include "base/logging.h" #include "media/cast/rtp_receiver/rtp_receiver_defines.h" namespace media { namespace cast { static const uint32 kMaxSequenceNumber = 65536; ReceiverStats::ReceiverStats(base::TickClock* clock) : clock_(clock), min_sequence_number_(0), max_sequence_number_(0), total_number_packets_(0), sequence_number_cycles_(0), interval_min_sequence_number_(0), interval_number_packets_(0), interval_wrap_count_(0) {} ReceiverStats::~ReceiverStats() {} void ReceiverStats::GetStatistics(uint8* fraction_lost, uint32* cumulative_lost, uint32* extended_high_sequence_number, uint32* jitter) { // Compute losses. if (interval_number_packets_ == 0) { *fraction_lost = 0; } else { int diff = 0; if (interval_wrap_count_ == 0) { diff = max_sequence_number_ - interval_min_sequence_number_ + 1; } else { diff = kMaxSequenceNumber * (interval_wrap_count_ - 1) + (max_sequence_number_ - interval_min_sequence_number_ + kMaxSequenceNumber + 1); } if (diff < 1) { *fraction_lost = 0; } else { float tmp_ratio = (1 - static_cast<float>(interval_number_packets_) / abs(diff)); *fraction_lost = static_cast<uint8>(256 * tmp_ratio); } } int expected_packets_num = max_sequence_number_ - min_sequence_number_ + 1; if (total_number_packets_ == 0) { *cumulative_lost = 0; } else if (sequence_number_cycles_ == 0) { *cumulative_lost = expected_packets_num - total_number_packets_; } else { *cumulative_lost = kMaxSequenceNumber * (sequence_number_cycles_ - 1) + (expected_packets_num - total_number_packets_ + kMaxSequenceNumber); } // Extended high sequence number consists of the highest seq number and the // number of cycles (wrap). *extended_high_sequence_number = (sequence_number_cycles_ << 16) + max_sequence_number_; *jitter = static_cast<uint32>(std::abs(jitter_.InMillisecondsRoundedUp())); // Reset interval values. interval_min_sequence_number_ = 0; interval_number_packets_ = 0; interval_wrap_count_ = 0; } void ReceiverStats::UpdateStatistics(const RtpCastHeader& header) { const uint16 new_seq_num = header.sequence_number; if (interval_number_packets_ == 0) { // First packet in the interval. interval_min_sequence_number_ = new_seq_num; } if (total_number_packets_ == 0) { // First incoming packet. min_sequence_number_ = new_seq_num; max_sequence_number_ = new_seq_num; } if (IsNewerSequenceNumber(new_seq_num, max_sequence_number_)) { // Check wrap. if (new_seq_num < max_sequence_number_) { ++sequence_number_cycles_; ++interval_wrap_count_; } max_sequence_number_ = new_seq_num; } // Compute Jitter. base::TimeTicks now = clock_->NowTicks(); base::TimeDelta delta_new_timestamp = base::TimeDelta::FromMilliseconds(header.rtp_timestamp); if (total_number_packets_ > 0) { // Update jitter. base::TimeDelta delta = (now - last_received_packet_time_) - ((delta_new_timestamp - last_received_timestamp_) / 90); jitter_ += (delta - jitter_) / 16; } last_received_timestamp_ = delta_new_timestamp; last_received_packet_time_ = now; // Increment counters. ++total_number_packets_; ++interval_number_packets_; } } // namespace cast } // namespace media