1822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org/*
2822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org *
4822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org *  Use of this source code is governed by a BSD-style license
5822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org *  that can be found in the LICENSE file in the root of the source
6822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org *  tree. An additional intellectual property rights grant can be found
7822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org *  in the file PATENTS.  All contributing project authors may
8822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org */
10822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
11822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org#include "webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h"
12822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
137bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org#include <math.h>
147bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
1500b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org#include "webrtc/base/scoped_ptr.h"
16822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org#include "webrtc/modules/rtp_rtcp/source/bitrate.h"
171227e8b3451b1a2f2a765bf6101cb0862f625568danilchap#include "webrtc/modules/rtp_rtcp/source/time_util.h"
1898f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
19822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
20822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.orgnamespace webrtc {
21822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
22286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgconst int64_t kStatisticsTimeoutMs = 8000;
230b1534c52eab79372557a6d81aaf4dd9407f55d3pkasting@chromium.orgconst int64_t kStatisticsProcessIntervalMs = 1000;
24822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
25286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgStreamStatistician::~StreamStatistician() {}
26822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
2754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.orgStreamStatisticianImpl::StreamStatisticianImpl(
2854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    Clock* clock,
290e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    RtcpStatisticsCallback* rtcp_callback,
300e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    StreamDataCountersCallback* rtp_callback)
31286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    : clock_(clock),
327dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org      stream_lock_(CriticalSectionWrapper::CreateCriticalSection()),
336811b6e308d16f160ba4c32650f195d5d3d9a2b1sprang@webrtc.org      incoming_bitrate_(clock, NULL),
34822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      ssrc_(0),
357bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      max_reordering_threshold_(kDefaultMaxReorderingThreshold),
36822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      jitter_q4_(0),
37822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      cumulative_loss_(0),
38822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      jitter_q4_transmission_time_offset_(0),
397bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      last_receive_time_ms_(0),
40822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      last_received_timestamp_(0),
41822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      last_received_transmission_time_offset_(0),
42822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      received_seq_first_(0),
43822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      received_seq_max_(0),
44822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      received_seq_wraps_(0),
45822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      received_packet_overhead_(12),
46822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      last_report_inorder_packets_(0),
47822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      last_report_old_packets_(0),
48822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      last_report_seq_max_(0),
490e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org      rtcp_callback_(rtcp_callback),
500e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org      rtp_callback_(rtp_callback) {}
51822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
52286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgvoid StreamStatisticianImpl::IncomingPacket(const RTPHeader& header,
5397d0489058ae7a983f7306f32cfd49a2356c6488asapersson@webrtc.org                                            size_t packet_length,
547bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                                            bool retransmitted) {
5597d0489058ae7a983f7306f32cfd49a2356c6488asapersson@webrtc.org  UpdateCounters(header, packet_length, retransmitted);
56a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  NotifyRtpCallback();
57a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org}
58a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org
59a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.orgvoid StreamStatisticianImpl::UpdateCounters(const RTPHeader& header,
6097d0489058ae7a983f7306f32cfd49a2356c6488asapersson@webrtc.org                                            size_t packet_length,
61a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org                                            bool retransmitted) {
627dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(stream_lock_.get());
637bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  bool in_order = InOrderPacketInternal(header.sequenceNumber);
64822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  ssrc_ = header.ssrc;
6597d0489058ae7a983f7306f32cfd49a2356c6488asapersson@webrtc.org  incoming_bitrate_.Update(packet_length);
664414939954fd908b6490ce1bb88271e161219aa3asapersson@webrtc.org  receive_counters_.transmitted.AddPacket(packet_length, header);
670e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  if (!in_order && retransmitted) {
684414939954fd908b6490ce1bb88271e161219aa3asapersson@webrtc.org    receive_counters_.retransmitted.AddPacket(packet_length, header);
690e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  }
70822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
71cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org  if (receive_counters_.transmitted.packets == 1) {
72822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    received_seq_first_ = header.sequenceNumber;
73d08d389ce836238030ec31e45c5f9a5535e0855fasapersson@webrtc.org    receive_counters_.first_packet_time_ms = clock_->TimeInMilliseconds();
74822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
75822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
76822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // Count only the new packets received. That is, if packets 1, 2, 3, 5, 4, 6
77822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // are received, 4 will be ignored.
78822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  if (in_order) {
79822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    // Current time in samples.
801227e8b3451b1a2f2a765bf6101cb0862f625568danilchap    NtpTime receive_time(*clock_);
81822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
82822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    // Wrong if we use RetransmitOfOldPacket.
83cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org    if (receive_counters_.transmitted.packets > 1 &&
840e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org        received_seq_max_ > header.sequenceNumber) {
85822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      // Wrap around detected.
86822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      received_seq_wraps_++;
87822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    }
88822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    // New max.
89822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    received_seq_max_ = header.sequenceNumber;
90822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
910e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    // If new time stamp and more than one in-order packet received, calculate
920e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    // new jitter statistics.
93822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    if (header.timestamp != last_received_timestamp_ &&
94cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org        (receive_counters_.transmitted.packets -
95cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org         receive_counters_.retransmitted.packets) > 1) {
961227e8b3451b1a2f2a765bf6101cb0862f625568danilchap      UpdateJitter(header, receive_time);
97822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    }
98822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    last_received_timestamp_ = header.timestamp;
991227e8b3451b1a2f2a765bf6101cb0862f625568danilchap    last_receive_time_ntp_ = receive_time;
1007bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    last_receive_time_ms_ = clock_->TimeInMilliseconds();
101822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
102822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
1034591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org  size_t packet_oh = header.headerLength + header.paddingLength;
104822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
105822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // Our measured overhead. Filter from RFC 5104 4.2.1.2:
106822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // avg_OH (new) = 15/16*avg_OH (old) + 1/16*pckt_OH,
107822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  received_packet_overhead_ = (15 * received_packet_overhead_ + packet_oh) >> 4;
1080e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org}
1090e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
1100e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.orgvoid StreamStatisticianImpl::UpdateJitter(const RTPHeader& header,
1111227e8b3451b1a2f2a765bf6101cb0862f625568danilchap                                          NtpTime receive_time) {
1121227e8b3451b1a2f2a765bf6101cb0862f625568danilchap  uint32_t receive_time_rtp =
1131227e8b3451b1a2f2a765bf6101cb0862f625568danilchap      NtpToRtp(receive_time, header.payload_type_frequency);
11462bafae6618fe3aefbd18657062abc98a40c3375pbos@webrtc.org  uint32_t last_receive_time_rtp =
1151227e8b3451b1a2f2a765bf6101cb0862f625568danilchap      NtpToRtp(last_receive_time_ntp_, header.payload_type_frequency);
1160e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  int32_t time_diff_samples = (receive_time_rtp - last_receive_time_rtp) -
1170e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org      (header.timestamp - last_received_timestamp_);
1180e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
1190e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  time_diff_samples = abs(time_diff_samples);
1200e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
1210e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  // lib_jingle sometimes deliver crazy jumps in TS for the same stream.
1220e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  // If this happens, don't update jitter value. Use 5 secs video frequency
1230e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  // as the threshold.
1240e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  if (time_diff_samples < 450000) {
1250e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    // Note we calculate in Q4 to avoid using float.
1260e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    int32_t jitter_diff_q4 = (time_diff_samples << 4) - jitter_q4_;
1270e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    jitter_q4_ += ((jitter_diff_q4 + 8) >> 4);
1280e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  }
1290e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
1300e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  // Extended jitter report, RFC 5450.
1310e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  // Actual network jitter, excluding the source-introduced jitter.
1320e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  int32_t time_diff_samples_ext =
1330e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    (receive_time_rtp - last_receive_time_rtp) -
1340e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    ((header.timestamp +
1350e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org      header.extension.transmissionTimeOffset) -
1360e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org     (last_received_timestamp_ +
1370e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org      last_received_transmission_time_offset_));
1380e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
1390e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  time_diff_samples_ext = abs(time_diff_samples_ext);
1400e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
1410e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  if (time_diff_samples_ext < 450000) {
1420e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    int32_t jitter_diffQ4TransmissionTimeOffset =
1430e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org      (time_diff_samples_ext << 4) - jitter_q4_transmission_time_offset_;
1440e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    jitter_q4_transmission_time_offset_ +=
1450e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org      ((jitter_diffQ4TransmissionTimeOffset + 8) >> 4);
1460e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  }
1470e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org}
1480e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
149a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.orgvoid StreamStatisticianImpl::NotifyRtpCallback() {
150a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  StreamDataCounters data;
151a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  uint32_t ssrc;
152a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  {
153a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org    CriticalSectionScoped cs(stream_lock_.get());
154a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org    data = receive_counters_;
155a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org    ssrc = ssrc_;
156a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  }
157a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  rtp_callback_->DataCountersUpdated(data, ssrc);
158a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org}
159a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org
160a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.orgvoid StreamStatisticianImpl::NotifyRtcpCallback() {
161a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  RtcpStatistics data;
162a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  uint32_t ssrc;
163a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  {
164a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org    CriticalSectionScoped cs(stream_lock_.get());
165a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org    data = last_reported_statistics_;
166a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org    ssrc = ssrc_;
167a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  }
168a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  rtcp_callback_->StatisticsUpdated(data, ssrc);
169a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org}
170a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org
171273fbbb921e61273c3d83eb494d0a68db7834d3dasapersson@webrtc.orgvoid StreamStatisticianImpl::FecPacketReceived(const RTPHeader& header,
172273fbbb921e61273c3d83eb494d0a68db7834d3dasapersson@webrtc.org                                               size_t packet_length) {
173a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  {
174a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org    CriticalSectionScoped cs(stream_lock_.get());
1754414939954fd908b6490ce1bb88271e161219aa3asapersson@webrtc.org    receive_counters_.fec.AddPacket(packet_length, header);
176a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  }
177a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  NotifyRtpCallback();
178822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org}
179822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
1807bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.orgvoid StreamStatisticianImpl::SetMaxReorderingThreshold(
1817bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    int max_reordering_threshold) {
1827dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(stream_lock_.get());
1837bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  max_reordering_threshold_ = max_reordering_threshold;
1847bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
1857bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
18654ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.orgbool StreamStatisticianImpl::GetStatistics(RtcpStatistics* statistics,
18754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org                                           bool reset) {
1887dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  {
1897dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org    CriticalSectionScoped cs(stream_lock_.get());
190cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org    if (received_seq_first_ == 0 &&
191cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org        receive_counters_.transmitted.payload_bytes == 0) {
1927dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org      // We have not received anything.
193822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org      return false;
194822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    }
1957dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org
1967dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org    if (!reset) {
1977dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org      if (last_report_inorder_packets_ == 0) {
1987dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org        // No report.
1997dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org        return false;
2007dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org      }
2017dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org      // Just get last report.
2027dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org      *statistics = last_reported_statistics_;
2037dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org      return true;
2047dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org    }
2057dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org
206c00adbed7388c7c3a2e6214e6ab06242997e1825sprang@webrtc.org    *statistics = CalculateRtcpStatistics();
207822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
208822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
209a45cac0fb79782fd4bfe9c6ef1e1a74074a33aeesprang@webrtc.org  NotifyRtcpCallback();
2100e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
2117dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  return true;
2127dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org}
2137dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org
214c00adbed7388c7c3a2e6214e6ab06242997e1825sprang@webrtc.orgRtcpStatistics StreamStatisticianImpl::CalculateRtcpStatistics() {
2157dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  RtcpStatistics stats;
2167dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org
217822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  if (last_report_inorder_packets_ == 0) {
218822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    // First time we send a report.
219822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    last_report_seq_max_ = received_seq_first_ - 1;
220822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
221822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
222822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // Calculate fraction lost.
223822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  uint16_t exp_since_last = (received_seq_max_ - last_report_seq_max_);
224822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
225822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  if (last_report_seq_max_ > received_seq_max_) {
226822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    // Can we assume that the seq_num can't go decrease over a full RTCP period?
227822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    exp_since_last = 0;
228822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
229822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
230822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // Number of received RTP packets since last report, counts all packets but
231822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // not re-transmissions.
232822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  uint32_t rec_since_last =
233cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org      (receive_counters_.transmitted.packets -
234cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org       receive_counters_.retransmitted.packets) - last_report_inorder_packets_;
235822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
236822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // With NACK we don't know the expected retransmissions during the last
237822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // second. We know how many "old" packets we have received. We just count
238822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // the number of old received to estimate the loss, but it still does not
239822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // guarantee an exact number since we run this based on time triggered by
240822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // sending of an RTP packet. This should have a minimum effect.
241822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
242822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // With NACK we don't count old packets as received since they are
243822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // re-transmitted. We use RTT to decide if a packet is re-ordered or
244822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // re-transmitted.
245822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  uint32_t retransmitted_packets =
246cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org      receive_counters_.retransmitted.packets - last_report_old_packets_;
247822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  rec_since_last += retransmitted_packets;
248822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
249286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  int32_t missing = 0;
250822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  if (exp_since_last > rec_since_last) {
251286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    missing = (exp_since_last - rec_since_last);
252822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
253822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  uint8_t local_fraction_lost = 0;
254822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  if (exp_since_last) {
255822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    // Scale 0 to 255, where 255 is 100% loss.
256822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org    local_fraction_lost =
257286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org        static_cast<uint8_t>(255 * missing / exp_since_last);
258822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
2597dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  stats.fraction_lost = local_fraction_lost;
260822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
261822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // We need a counter for cumulative loss too.
262a72e7349d52366655076e609e9e32d456da7f5a2danilchap  // TODO(danilchap): Ensure cumulative loss is below maximum value of 2^24.
263286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  cumulative_loss_ += missing;
2647dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  stats.cumulative_lost = cumulative_loss_;
2657dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  stats.extended_max_sequence_number =
2667dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org      (received_seq_wraps_ << 16) + received_seq_max_;
267822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  // Note: internal jitter value is in Q4 and needs to be scaled by 1/16.
2687dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  stats.jitter = jitter_q4_ >> 4;
26954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
2707dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  // Store this report.
2717dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  last_reported_statistics_ = stats;
2727dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org
2737dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  // Only for report blocks in RTCP SR and RR.
2740e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  last_report_inorder_packets_ =
275cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org      receive_counters_.transmitted.packets -
276cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org      receive_counters_.retransmitted.packets;
277cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org  last_report_old_packets_ = receive_counters_.retransmitted.packets;
2787dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  last_report_seq_max_ = received_seq_max_;
2797dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org
2807dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  return stats;
281822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org}
282822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
283286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgvoid StreamStatisticianImpl::GetDataCounters(
2844591fbd09f9cb6e83433c49a12dd8524c2806502pkasting@chromium.org    size_t* bytes_received, uint32_t* packets_received) const {
2857dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(stream_lock_.get());
286822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  if (bytes_received) {
287cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org    *bytes_received = receive_counters_.transmitted.payload_bytes +
288cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org                      receive_counters_.transmitted.header_bytes +
289cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org                      receive_counters_.transmitted.padding_bytes;
290822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
291822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  if (packets_received) {
292cfd82dfc1156f6610388bec0ebbdeacaf47e9719asapersson@webrtc.org    *packets_received = receive_counters_.transmitted.packets;
293822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  }
294822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org}
295822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
296d952c40c7e31c1603988c1f09ebfba9f17c6a866asapersson@webrtc.orgvoid StreamStatisticianImpl::GetReceiveStreamDataCounters(
297d952c40c7e31c1603988c1f09ebfba9f17c6a866asapersson@webrtc.org    StreamDataCounters* data_counters) const {
298d952c40c7e31c1603988c1f09ebfba9f17c6a866asapersson@webrtc.org  CriticalSectionScoped cs(stream_lock_.get());
299d952c40c7e31c1603988c1f09ebfba9f17c6a866asapersson@webrtc.org  *data_counters = receive_counters_;
300d952c40c7e31c1603988c1f09ebfba9f17c6a866asapersson@webrtc.org}
301d952c40c7e31c1603988c1f09ebfba9f17c6a866asapersson@webrtc.org
302286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orguint32_t StreamStatisticianImpl::BitrateReceived() const {
3037dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(stream_lock_.get());
304822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org  return incoming_bitrate_.BitrateNow();
305822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org}
306822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org
307286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgvoid StreamStatisticianImpl::ProcessBitrate() {
3087dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(stream_lock_.get());
309286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  incoming_bitrate_.Process();
310286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org}
311286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
312286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgvoid StreamStatisticianImpl::LastReceiveTimeNtp(uint32_t* secs,
313286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org                                                uint32_t* frac) const {
3147dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(stream_lock_.get());
3151227e8b3451b1a2f2a765bf6101cb0862f625568danilchap  *secs = last_receive_time_ntp_.seconds();
3161227e8b3451b1a2f2a765bf6101cb0862f625568danilchap  *frac = last_receive_time_ntp_.fractions();
317286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org}
318286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
3197bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.orgbool StreamStatisticianImpl::IsRetransmitOfOldPacket(
32016825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org    const RTPHeader& header, int64_t min_rtt) const {
3217dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(stream_lock_.get());
3227bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (InOrderPacketInternal(header.sequenceNumber)) {
3237bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return false;
3247bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  }
3257bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  uint32_t frequency_khz = header.payload_type_frequency / 1000;
3267bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  assert(frequency_khz > 0);
3277bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
3287bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  int64_t time_diff_ms = clock_->TimeInMilliseconds() -
3297bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      last_receive_time_ms_;
3307bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
3317bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  // Diff in time stamp since last received in order.
3327bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  uint32_t timestamp_diff = header.timestamp - last_received_timestamp_;
33316825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org  uint32_t rtp_time_stamp_diff_ms = timestamp_diff / frequency_khz;
3347bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
33516825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org  int64_t max_delay_ms = 0;
3367bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (min_rtt == 0) {
3377bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    // Jitter standard deviation in samples.
3387bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    float jitter_std = sqrt(static_cast<float>(jitter_q4_ >> 4));
3397bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
3407bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    // 2 times the standard deviation => 95% confidence.
3417bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    // And transform to milliseconds by dividing by the frequency in kHz.
34216825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.org    max_delay_ms = static_cast<int64_t>((2 * jitter_std) / frequency_khz);
3437bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
3447bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    // Min max_delay_ms is 1.
3457bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    if (max_delay_ms == 0) {
3467bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org      max_delay_ms = 1;
3477bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    }
3487bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  } else {
3497bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    max_delay_ms = (min_rtt / 3) + 1;
3507bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  }
3517bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  return time_diff_ms > rtp_time_stamp_diff_ms + max_delay_ms;
3527bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
3537bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
3547bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.orgbool StreamStatisticianImpl::IsPacketInOrder(uint16_t sequence_number) const {
3557dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(stream_lock_.get());
3567bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  return InOrderPacketInternal(sequence_number);
3577bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
3587bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
3597bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.orgbool StreamStatisticianImpl::InOrderPacketInternal(
3607bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    uint16_t sequence_number) const {
3617bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  // First packet is always in order.
3627bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (last_receive_time_ms_ == 0)
3637bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return true;
3647bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
3657bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  if (IsNewerSequenceNumber(sequence_number, received_seq_max_)) {
3667bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return true;
3677bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  } else {
3687bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    // If we have a restart of the remote side this packet is still in order.
3697bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    return !IsNewerSequenceNumber(sequence_number, received_seq_max_ -
3707bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                                  max_reordering_threshold_);
3717bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  }
3727bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
3737bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
374286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgReceiveStatistics* ReceiveStatistics::Create(Clock* clock) {
375286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  return new ReceiveStatisticsImpl(clock);
376286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org}
377286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
378286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgReceiveStatisticsImpl::ReceiveStatisticsImpl(Clock* clock)
379286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    : clock_(clock),
3807dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org      receive_statistics_lock_(CriticalSectionWrapper::CreateCriticalSection()),
38154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org      last_rate_update_ms_(0),
3820e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org      rtcp_stats_callback_(NULL),
3830e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org      rtp_stats_callback_(NULL) {}
384286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
385286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgReceiveStatisticsImpl::~ReceiveStatisticsImpl() {
386286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  while (!statisticians_.empty()) {
387286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    delete statisticians_.begin()->second;
388286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    statisticians_.erase(statisticians_.begin());
389286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  }
390286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org}
391286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
392286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgvoid ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header,
39397d0489058ae7a983f7306f32cfd49a2356c6488asapersson@webrtc.org                                           size_t packet_length,
3940e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org                                           bool retransmitted) {
395c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org  StreamStatisticianImpl* impl;
3967dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  {
3977dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org    CriticalSectionScoped cs(receive_statistics_lock_.get());
398c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org    StatisticianImplMap::iterator it = statisticians_.find(header.ssrc);
399c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org    if (it != statisticians_.end()) {
400c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org      impl = it->second;
401c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org    } else {
402c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org      impl = new StreamStatisticianImpl(clock_, this, this);
403c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org      statisticians_[header.ssrc] = impl;
4047dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org    }
405286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  }
406c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org  // StreamStatisticianImpl instance is created once and only destroyed when
407c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org  // this whole ReceiveStatisticsImpl is destroyed. StreamStatisticianImpl has
408c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org  // it's own locking so don't hold receive_statistics_lock_ (potential
409c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org  // deadlock).
41097d0489058ae7a983f7306f32cfd49a2356c6488asapersson@webrtc.org  impl->IncomingPacket(header, packet_length, retransmitted);
4110e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org}
4120e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
413273fbbb921e61273c3d83eb494d0a68db7834d3dasapersson@webrtc.orgvoid ReceiveStatisticsImpl::FecPacketReceived(const RTPHeader& header,
414273fbbb921e61273c3d83eb494d0a68db7834d3dasapersson@webrtc.org                                              size_t packet_length) {
4150e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  CriticalSectionScoped cs(receive_statistics_lock_.get());
416273fbbb921e61273c3d83eb494d0a68db7834d3dasapersson@webrtc.org  StatisticianImplMap::iterator it = statisticians_.find(header.ssrc);
417c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org  // Ignore FEC if it is the first packet.
418c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org  if (it != statisticians_.end()) {
419273fbbb921e61273c3d83eb494d0a68db7834d3dasapersson@webrtc.org    it->second->FecPacketReceived(header, packet_length);
420c30e9e230065ddde4cc439d9ba430273413e70d7sprang@webrtc.org  }
421286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org}
422286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
423286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgStatisticianMap ReceiveStatisticsImpl::GetActiveStatisticians() const {
4247dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(receive_statistics_lock_.get());
425286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  StatisticianMap active_statisticians;
426286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  for (StatisticianImplMap::const_iterator it = statisticians_.begin();
427286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org       it != statisticians_.end(); ++it) {
428286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    uint32_t secs;
429286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    uint32_t frac;
430286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    it->second->LastReceiveTimeNtp(&secs, &frac);
431286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    if (clock_->CurrentNtpInMilliseconds() -
432286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org        Clock::NtpToMs(secs, frac) < kStatisticsTimeoutMs) {
433286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org      active_statisticians[it->first] = it->second;
434286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    }
435286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  }
436286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  return active_statisticians;
437286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org}
438286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
439286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgStreamStatistician* ReceiveStatisticsImpl::GetStatistician(
440286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    uint32_t ssrc) const {
4417dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(receive_statistics_lock_.get());
442286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  StatisticianImplMap::const_iterator it = statisticians_.find(ssrc);
443286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  if (it == statisticians_.end())
444286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    return NULL;
445286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  return it->second;
4461a65d6c36b6a25f9f734176c697c684c3b43ac4bstefan@webrtc.org}
4471a65d6c36b6a25f9f734176c697c684c3b43ac4bstefan@webrtc.org
4487bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.orgvoid ReceiveStatisticsImpl::SetMaxReorderingThreshold(
4497bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    int max_reordering_threshold) {
4507dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(receive_statistics_lock_.get());
4517bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  for (StatisticianImplMap::iterator it = statisticians_.begin();
4527bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org       it != statisticians_.end(); ++it) {
4537bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    it->second->SetMaxReorderingThreshold(max_reordering_threshold);
4547bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org  }
4557bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org}
4567bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
457a0218a84d17a727111e2e24cf5af915b1b91c06ehenrike@webrtc.orgint32_t ReceiveStatisticsImpl::Process() {
4587dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(receive_statistics_lock_.get());
459286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  for (StatisticianImplMap::iterator it = statisticians_.begin();
460286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org       it != statisticians_.end(); ++it) {
461286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    it->second->ProcessBitrate();
462286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  }
463286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  last_rate_update_ms_ = clock_->TimeInMilliseconds();
464a0218a84d17a727111e2e24cf5af915b1b91c06ehenrike@webrtc.org  return 0;
4651a65d6c36b6a25f9f734176c697c684c3b43ac4bstefan@webrtc.org}
4661a65d6c36b6a25f9f734176c697c684c3b43ac4bstefan@webrtc.org
4670b1534c52eab79372557a6d81aaf4dd9407f55d3pkasting@chromium.orgint64_t ReceiveStatisticsImpl::TimeUntilNextProcess() {
4687dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(receive_statistics_lock_.get());
4690b1534c52eab79372557a6d81aaf4dd9407f55d3pkasting@chromium.org  int64_t time_since_last_update = clock_->TimeInMilliseconds() -
470286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org      last_rate_update_ms_;
4710b1534c52eab79372557a6d81aaf4dd9407f55d3pkasting@chromium.org  return std::max<int64_t>(
4720b1534c52eab79372557a6d81aaf4dd9407f55d3pkasting@chromium.org      kStatisticsProcessIntervalMs - time_since_last_update, 0);
473286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org}
474286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
47554ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.orgvoid ReceiveStatisticsImpl::RegisterRtcpStatisticsCallback(
47654ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    RtcpStatisticsCallback* callback) {
4777dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(receive_statistics_lock_.get());
47854ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  if (callback != NULL)
47954ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    assert(rtcp_stats_callback_ == NULL);
48054ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org  rtcp_stats_callback_ = callback;
48154ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org}
48254ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
48354ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.orgvoid ReceiveStatisticsImpl::StatisticsUpdated(const RtcpStatistics& statistics,
48454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org                                              uint32_t ssrc) {
4857dba27c740048c92692d4e1cf6fee1fee7827901sprang@webrtc.org  CriticalSectionScoped cs(receive_statistics_lock_.get());
486ce4e9a356200170abcdd44ff2af95f87a6781b8epbos@webrtc.org  if (rtcp_stats_callback_)
48754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    rtcp_stats_callback_->StatisticsUpdated(statistics, ssrc);
488ce4e9a356200170abcdd44ff2af95f87a6781b8epbos@webrtc.org}
489ce4e9a356200170abcdd44ff2af95f87a6781b8epbos@webrtc.org
490ce4e9a356200170abcdd44ff2af95f87a6781b8epbos@webrtc.orgvoid ReceiveStatisticsImpl::CNameChanged(const char* cname, uint32_t ssrc) {
491ce4e9a356200170abcdd44ff2af95f87a6781b8epbos@webrtc.org  CriticalSectionScoped cs(receive_statistics_lock_.get());
492ce4e9a356200170abcdd44ff2af95f87a6781b8epbos@webrtc.org  if (rtcp_stats_callback_)
493ce4e9a356200170abcdd44ff2af95f87a6781b8epbos@webrtc.org    rtcp_stats_callback_->CNameChanged(cname, ssrc);
49454ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org}
495286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
4960e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.orgvoid ReceiveStatisticsImpl::RegisterRtpStatisticsCallback(
4970e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    StreamDataCountersCallback* callback) {
4980e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  CriticalSectionScoped cs(receive_statistics_lock_.get());
4990e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  if (callback != NULL)
5000e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    assert(rtp_stats_callback_ == NULL);
5010e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  rtp_stats_callback_ = callback;
5020e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org}
5030e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
5040e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.orgvoid ReceiveStatisticsImpl::DataCountersUpdated(const StreamDataCounters& stats,
5050e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org                                                uint32_t ssrc) {
5060e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  CriticalSectionScoped cs(receive_statistics_lock_.get());
5070e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  if (rtp_stats_callback_) {
5080e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    rtp_stats_callback_->DataCountersUpdated(stats, ssrc);
5090e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org  }
5100e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org}
5110e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
512286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgvoid NullReceiveStatistics::IncomingPacket(const RTPHeader& rtp_header,
51397d0489058ae7a983f7306f32cfd49a2356c6488asapersson@webrtc.org                                           size_t packet_length,
5147bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org                                           bool retransmitted) {}
515286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
516273fbbb921e61273c3d83eb494d0a68db7834d3dasapersson@webrtc.orgvoid NullReceiveStatistics::FecPacketReceived(const RTPHeader& header,
517273fbbb921e61273c3d83eb494d0a68db7834d3dasapersson@webrtc.org                                              size_t packet_length) {}
5180e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
519286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgStatisticianMap NullReceiveStatistics::GetActiveStatisticians() const {
520286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  return StatisticianMap();
521286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org}
522286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
523286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgStreamStatistician* NullReceiveStatistics::GetStatistician(
524286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org    uint32_t ssrc) const {
525286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org  return NULL;
526286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org}
527286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
5287bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.orgvoid NullReceiveStatistics::SetMaxReorderingThreshold(
5297bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org    int max_reordering_threshold) {}
5307bb8f02274ecbfa1f7ef134d708369a369a78c83stefan@webrtc.org
5310b1534c52eab79372557a6d81aaf4dd9407f55d3pkasting@chromium.orgint64_t NullReceiveStatistics::TimeUntilNextProcess() { return 0; }
532286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
533286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.orgint32_t NullReceiveStatistics::Process() { return 0; }
534286fe0b04d97205ac84688bbe613d5749192b2d1stefan@webrtc.org
53554ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.orgvoid NullReceiveStatistics::RegisterRtcpStatisticsCallback(
53654ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org    RtcpStatisticsCallback* callback) {}
53754ae4ffb9e235a9742e2b11298327e02d870571csprang@webrtc.org
5380e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.orgvoid NullReceiveStatistics::RegisterRtpStatisticsCallback(
5390e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org    StreamDataCountersCallback* callback) {}
5400e93257cee79c0d19ddaef1f14ba750bf469a084sprang@webrtc.org
541822fbd8b68ffdb481b9557e2950ae8d6657c8ce6wu@webrtc.org}  // namespace webrtc
542