| // Copyright 2014 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/test/receiver/receiver_stats.h" |
| |
| #include "media/cast/net/rtp/rtp_defines.h" |
| |
| namespace media { |
| namespace cast { |
| |
| namespace { |
| |
| constexpr uint32_t kMaxSequenceNumber = 65536; |
| |
| // TODO(miu): Get rid of all the special 16-bit rounding detection and special |
| // handling throughout this file, and just use good 'ol int64_t. |
| // http://crbug.com/530839 |
| bool IsNewerSequenceNumber(uint16_t sequence_number, |
| uint16_t prev_sequence_number) { |
| return (sequence_number != prev_sequence_number) && |
| static_cast<uint16_t>(sequence_number - prev_sequence_number) < 0x8000; |
| } |
| |
| } // namespace |
| |
| ReceiverStats::ReceiverStats(const 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) {} |
| |
| RtpReceiverStatistics ReceiverStats::GetStatistics() { |
| RtpReceiverStatistics ret; |
| // Compute losses. |
| if (interval_number_packets_ == 0) { |
| ret.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) { |
| ret.fraction_lost = 0; |
| } else { |
| float tmp_ratio = |
| (1 - static_cast<float>(interval_number_packets_) / abs(diff)); |
| ret.fraction_lost = static_cast<uint8_t>(256 * tmp_ratio); |
| } |
| } |
| |
| int expected_packets_num = max_sequence_number_ - min_sequence_number_ + 1; |
| if (total_number_packets_ == 0) { |
| ret.cumulative_lost = 0; |
| } else if (sequence_number_cycles_ == 0) { |
| ret.cumulative_lost = expected_packets_num - total_number_packets_; |
| } else { |
| ret.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). |
| ret.extended_high_sequence_number = |
| (sequence_number_cycles_ << 16) + max_sequence_number_; |
| |
| ret.jitter = |
| static_cast<uint32_t>(std::abs(jitter_.InMillisecondsRoundedUp())); |
| |
| // Reset interval values. |
| interval_min_sequence_number_ = 0; |
| interval_number_packets_ = 0; |
| interval_wrap_count_ = 0; |
| |
| return ret; |
| } |
| |
| void ReceiverStats::UpdateStatistics(const RtpCastHeader& header, |
| int rtp_timebase) { |
| const uint16_t 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. |
| const base::TimeTicks now = clock_->NowTicks(); |
| if (total_number_packets_ > 0) { |
| const base::TimeDelta packet_time_difference = |
| now - last_received_packet_time_; |
| const base::TimeDelta media_time_differerence = |
| (header.rtp_timestamp - last_received_rtp_timestamp_) |
| .ToTimeDelta(rtp_timebase); |
| const base::TimeDelta delta = |
| packet_time_difference - media_time_differerence; |
| // Update jitter. |
| jitter_ += (delta - jitter_) / 16; |
| } |
| last_received_rtp_timestamp_ = header.rtp_timestamp; |
| last_received_packet_time_ = now; |
| |
| // Increment counters. |
| ++total_number_packets_; |
| ++interval_number_packets_; |
| } |
| |
| } // namespace cast |
| } // namespace media |