1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "media/cast/net/rtp/receiver_stats.h"
6
7#include "base/logging.h"
8#include "media/cast/net/rtp/rtp_receiver_defines.h"
9
10namespace media {
11namespace cast {
12
13static const uint32 kMaxSequenceNumber = 65536;
14
15ReceiverStats::ReceiverStats(base::TickClock* clock)
16    : clock_(clock),
17      min_sequence_number_(0),
18      max_sequence_number_(0),
19      total_number_packets_(0),
20      sequence_number_cycles_(0),
21      interval_min_sequence_number_(0),
22      interval_number_packets_(0),
23      interval_wrap_count_(0) {}
24
25ReceiverStats::~ReceiverStats() {}
26
27void ReceiverStats::GetStatistics(uint8* fraction_lost,
28                                  uint32* cumulative_lost,
29                                  uint32* extended_high_sequence_number,
30                                  uint32* jitter) {
31  // Compute losses.
32  if (interval_number_packets_ == 0) {
33    *fraction_lost = 0;
34  } else {
35    int diff = 0;
36    if (interval_wrap_count_ == 0) {
37      diff = max_sequence_number_ - interval_min_sequence_number_ + 1;
38    } else {
39      diff = kMaxSequenceNumber * (interval_wrap_count_ - 1) +
40             (max_sequence_number_ - interval_min_sequence_number_ +
41              kMaxSequenceNumber + 1);
42    }
43
44    if (diff < 1) {
45      *fraction_lost = 0;
46    } else {
47      float tmp_ratio =
48          (1 - static_cast<float>(interval_number_packets_) / abs(diff));
49      *fraction_lost = static_cast<uint8>(256 * tmp_ratio);
50    }
51  }
52
53  int expected_packets_num = max_sequence_number_ - min_sequence_number_ + 1;
54  if (total_number_packets_ == 0) {
55    *cumulative_lost = 0;
56  } else if (sequence_number_cycles_ == 0) {
57    *cumulative_lost = expected_packets_num - total_number_packets_;
58  } else {
59    *cumulative_lost =
60        kMaxSequenceNumber * (sequence_number_cycles_ - 1) +
61        (expected_packets_num - total_number_packets_ + kMaxSequenceNumber);
62  }
63
64  // Extended high sequence number consists of the highest seq number and the
65  // number of cycles (wrap).
66  *extended_high_sequence_number =
67      (sequence_number_cycles_ << 16) + max_sequence_number_;
68
69  *jitter = static_cast<uint32>(std::abs(jitter_.InMillisecondsRoundedUp()));
70
71  // Reset interval values.
72  interval_min_sequence_number_ = 0;
73  interval_number_packets_ = 0;
74  interval_wrap_count_ = 0;
75}
76
77void ReceiverStats::UpdateStatistics(const RtpCastHeader& header) {
78  const uint16 new_seq_num = header.sequence_number;
79
80  if (interval_number_packets_ == 0) {
81    // First packet in the interval.
82    interval_min_sequence_number_ = new_seq_num;
83  }
84  if (total_number_packets_ == 0) {
85    // First incoming packet.
86    min_sequence_number_ = new_seq_num;
87    max_sequence_number_ = new_seq_num;
88  }
89
90  if (IsNewerSequenceNumber(new_seq_num, max_sequence_number_)) {
91    // Check wrap.
92    if (new_seq_num < max_sequence_number_) {
93      ++sequence_number_cycles_;
94      ++interval_wrap_count_;
95    }
96    max_sequence_number_ = new_seq_num;
97  }
98
99  // Compute Jitter.
100  base::TimeTicks now = clock_->NowTicks();
101  base::TimeDelta delta_new_timestamp =
102      base::TimeDelta::FromMilliseconds(header.rtp_timestamp);
103  if (total_number_packets_ > 0) {
104    // Update jitter.
105    base::TimeDelta delta =
106        (now - last_received_packet_time_) -
107        ((delta_new_timestamp - last_received_timestamp_) / 90);
108    jitter_ += (delta - jitter_) / 16;
109  }
110  last_received_timestamp_ = delta_new_timestamp;
111  last_received_packet_time_ = now;
112
113  // Increment counters.
114  ++total_number_packets_;
115  ++interval_number_packets_;
116}
117
118}  // namespace cast
119}  // namespace media
120