LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/video - receive_statistics_proxy.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 272 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 25 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include "webrtc/video/receive_statistics_proxy.h"
      12             : 
      13             : #include <cmath>
      14             : 
      15             : #include "webrtc/base/checks.h"
      16             : #include "webrtc/base/logging.h"
      17             : #include "webrtc/modules/video_coding/include/video_codec_interface.h"
      18             : #include "webrtc/system_wrappers/include/clock.h"
      19             : #include "webrtc/system_wrappers/include/field_trial.h"
      20             : #include "webrtc/system_wrappers/include/metrics.h"
      21             : 
      22             : namespace webrtc {
      23             : namespace {
      24             : // Periodic time interval for processing samples for |freq_offset_counter_|.
      25             : const int64_t kFreqOffsetProcessIntervalMs = 40000;
      26             : 
      27             : // Configuration for bad call detection.
      28             : const int kBadCallMinRequiredSamples = 10;
      29             : const int kMinSampleLengthMs = 990;
      30             : const int kNumMeasurements = 10;
      31             : const int kNumMeasurementsVariance = kNumMeasurements * 1.5;
      32             : const float kBadFraction = 0.8f;
      33             : // For fps:
      34             : // Low means low enough to be bad, high means high enough to be good
      35             : const int kLowFpsThreshold = 12;
      36             : const int kHighFpsThreshold = 14;
      37             : // For qp and fps variance:
      38             : // Low means low enough to be good, high means high enough to be bad
      39             : const int kLowQpThresholdVp8 = 60;
      40             : const int kHighQpThresholdVp8 = 70;
      41             : const int kLowVarianceThreshold = 1;
      42             : const int kHighVarianceThreshold = 2;
      43             : }  // namespace
      44             : 
      45           0 : ReceiveStatisticsProxy::ReceiveStatisticsProxy(
      46             :     const VideoReceiveStream::Config* config,
      47           0 :     Clock* clock)
      48             :     : clock_(clock),
      49             :       config_(*config),
      50           0 :       start_ms_(clock->TimeInMilliseconds()),
      51           0 :       last_sample_time_(clock->TimeInMilliseconds()),
      52             :       fps_threshold_(kLowFpsThreshold,
      53             :                      kHighFpsThreshold,
      54             :                      kBadFraction,
      55             :                      kNumMeasurements),
      56             :       qp_threshold_(kLowQpThresholdVp8,
      57             :                     kHighQpThresholdVp8,
      58             :                     kBadFraction,
      59             :                     kNumMeasurements),
      60             :       variance_threshold_(kLowVarianceThreshold,
      61             :                           kHighVarianceThreshold,
      62             :                           kBadFraction,
      63             :                           kNumMeasurementsVariance),
      64             :       num_bad_states_(0),
      65             :       num_certain_states_(0),
      66             :       // 1000ms window, scale 1000 for ms to s.
      67             :       decode_fps_estimator_(1000, 1000),
      68             :       renders_fps_estimator_(1000, 1000),
      69             :       render_fps_tracker_(100, 10u),
      70             :       render_pixel_tracker_(100u, 10u),
      71             :       freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs),
      72             :       first_report_block_time_ms_(-1),
      73           0 :       receive_state_(kReceiveStateInitial) {
      74           0 :   stats_.ssrc = config_.rtp.remote_ssrc;
      75           0 :   for (auto it : config_.rtp.rtx)
      76           0 :     rtx_stats_[it.second.ssrc] = StreamDataCounters();
      77           0 : }
      78             : 
      79           0 : ReceiveStatisticsProxy::~ReceiveStatisticsProxy() {
      80           0 :   UpdateHistograms();
      81           0 : }
      82             : 
      83           0 : void ReceiveStatisticsProxy::UpdateHistograms() {
      84           0 :   RTC_HISTOGRAM_COUNTS_100000(
      85             :       "WebRTC.Video.ReceiveStreamLifetimeInSeconds",
      86             :       (clock_->TimeInMilliseconds() - start_ms_) / 1000);
      87             : 
      88           0 :   if (first_report_block_time_ms_ != -1 &&
      89           0 :       ((clock_->TimeInMilliseconds() - first_report_block_time_ms_) / 1000) >=
      90             :           metrics::kMinRunTimeInSeconds) {
      91           0 :     int fraction_lost = report_block_stats_.FractionLostInPercent();
      92           0 :     if (fraction_lost != -1) {
      93           0 :       RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.ReceivedPacketsLostInPercent",
      94             :                                fraction_lost);
      95             :     }
      96             :   }
      97             : 
      98           0 :   const int kMinRequiredSamples = 200;
      99           0 :   int samples = static_cast<int>(render_fps_tracker_.TotalSampleCount());
     100           0 :   if (samples > kMinRequiredSamples) {
     101           0 :     RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.RenderFramesPerSecond",
     102             :                              round(render_fps_tracker_.ComputeTotalRate()));
     103           0 :     RTC_HISTOGRAM_COUNTS_100000(
     104             :         "WebRTC.Video.RenderSqrtPixelsPerSecond",
     105             :         round(render_pixel_tracker_.ComputeTotalRate()));
     106             :   }
     107           0 :   int width = render_width_counter_.Avg(kMinRequiredSamples);
     108           0 :   int height = render_height_counter_.Avg(kMinRequiredSamples);
     109           0 :   if (width != -1) {
     110           0 :     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.ReceivedWidthInPixels", width);
     111           0 :     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.ReceivedHeightInPixels", height);
     112             :   }
     113           0 :   int sync_offset_ms = sync_offset_counter_.Avg(kMinRequiredSamples);
     114           0 :   if (sync_offset_ms != -1) {
     115           0 :     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.AVSyncOffsetInMs", sync_offset_ms);
     116             :   }
     117           0 :   AggregatedStats freq_offset_stats = freq_offset_counter_.GetStats();
     118           0 :   if (freq_offset_stats.num_samples > 0) {
     119           0 :     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtpToNtpFreqOffsetInKhz",
     120             :                                freq_offset_stats.average);
     121           0 :     LOG(LS_INFO) << "WebRTC.Video.RtpToNtpFreqOffsetInKhz, "
     122           0 :                  << freq_offset_stats.ToString();
     123             :   }
     124             : 
     125           0 :   int qp = qp_counters_.vp8.Avg(kMinRequiredSamples);
     126           0 :   if (qp != -1)
     127           0 :     RTC_HISTOGRAM_COUNTS_200("WebRTC.Video.Decoded.Vp8.Qp", qp);
     128             : 
     129             :   // TODO(asapersson): DecoderTiming() is call periodically (each 1000ms) and
     130             :   // not per frame. Change decode time to include every frame.
     131           0 :   const int kMinRequiredDecodeSamples = 5;
     132           0 :   int decode_ms = decode_time_counter_.Avg(kMinRequiredDecodeSamples);
     133           0 :   if (decode_ms != -1)
     134           0 :     RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.DecodeTimeInMs", decode_ms);
     135             : 
     136           0 :   if (field_trial::FindFullName("WebRTC-NewVideoJitterBuffer") !=
     137             :         "Enabled") {
     138             :     int jb_delay_ms =
     139           0 :         jitter_buffer_delay_counter_.Avg(kMinRequiredDecodeSamples);
     140           0 :     if (jb_delay_ms != -1) {
     141           0 :       RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.JitterBufferDelayInMs",
     142             :                                  jb_delay_ms);
     143             :     }
     144             :   }
     145           0 :   int target_delay_ms = target_delay_counter_.Avg(kMinRequiredDecodeSamples);
     146           0 :   if (target_delay_ms != -1) {
     147           0 :     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.TargetDelayInMs", target_delay_ms);
     148             :   }
     149           0 :   int current_delay_ms = current_delay_counter_.Avg(kMinRequiredDecodeSamples);
     150           0 :   if (current_delay_ms != -1) {
     151           0 :     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.CurrentDelayInMs",
     152             :                                current_delay_ms);
     153             :   }
     154           0 :   int delay_ms = delay_counter_.Avg(kMinRequiredDecodeSamples);
     155           0 :   if (delay_ms != -1)
     156           0 :     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.OnewayDelayInMs", delay_ms);
     157             : 
     158           0 :   int e2e_delay_ms = e2e_delay_counter_.Avg(kMinRequiredSamples);
     159           0 :   if (e2e_delay_ms != -1)
     160           0 :     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.EndToEndDelayInMs", e2e_delay_ms);
     161             : 
     162           0 :   StreamDataCounters rtp = stats_.rtp_stats;
     163           0 :   StreamDataCounters rtx;
     164           0 :   for (auto it : rtx_stats_)
     165           0 :     rtx.Add(it.second);
     166           0 :   StreamDataCounters rtp_rtx = rtp;
     167           0 :   rtp_rtx.Add(rtx);
     168             :   int64_t elapsed_sec =
     169           0 :       rtp_rtx.TimeSinceFirstPacketInMs(clock_->TimeInMilliseconds()) / 1000;
     170           0 :   if (elapsed_sec > metrics::kMinRunTimeInSeconds) {
     171           0 :     RTC_HISTOGRAM_COUNTS_10000(
     172             :         "WebRTC.Video.BitrateReceivedInKbps",
     173             :         static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
     174             :                          1000));
     175           0 :     RTC_HISTOGRAM_COUNTS_10000(
     176             :         "WebRTC.Video.MediaBitrateReceivedInKbps",
     177             :         static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000));
     178           0 :     RTC_HISTOGRAM_COUNTS_10000(
     179             :         "WebRTC.Video.PaddingBitrateReceivedInKbps",
     180             :         static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec /
     181             :                          1000));
     182           0 :     RTC_HISTOGRAM_COUNTS_10000(
     183             :         "WebRTC.Video.RetransmittedBitrateReceivedInKbps",
     184             :         static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 / elapsed_sec /
     185             :                          1000));
     186           0 :     if (!rtx_stats_.empty()) {
     187           0 :       RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateReceivedInKbps",
     188             :                                  static_cast<int>(rtx.transmitted.TotalBytes() *
     189             :                                                   8 / elapsed_sec / 1000));
     190             :     }
     191           0 :     if (config_.rtp.ulpfec.ulpfec_payload_type != -1) {
     192           0 :       RTC_HISTOGRAM_COUNTS_10000(
     193             :           "WebRTC.Video.FecBitrateReceivedInKbps",
     194             :           static_cast<int>(rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec / 1000));
     195             :     }
     196           0 :     const RtcpPacketTypeCounter& counters = stats_.rtcp_packet_type_counts;
     197           0 :     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsSentPerMinute",
     198             :                                counters.nack_packets * 60 / elapsed_sec);
     199           0 :     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsSentPerMinute",
     200             :                                counters.fir_packets * 60 / elapsed_sec);
     201           0 :     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute",
     202             :                                counters.pli_packets * 60 / elapsed_sec);
     203           0 :     if (counters.nack_requests > 0) {
     204           0 :       RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent",
     205             :                                counters.UniqueNackRequestsInPercent());
     206             :     }
     207             :   }
     208             : 
     209           0 :   if (num_certain_states_ >= kBadCallMinRequiredSamples) {
     210           0 :     RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BadCall.Any",
     211             :                              100 * num_bad_states_ / num_certain_states_);
     212             :   }
     213             :   rtc::Optional<double> fps_fraction =
     214           0 :       fps_threshold_.FractionHigh(kBadCallMinRequiredSamples);
     215           0 :   if (fps_fraction) {
     216           0 :     RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BadCall.FrameRate",
     217             :                              static_cast<int>(100 * (1 - *fps_fraction)));
     218             :   }
     219             :   rtc::Optional<double> variance_fraction =
     220           0 :       variance_threshold_.FractionHigh(kBadCallMinRequiredSamples);
     221           0 :   if (variance_fraction) {
     222           0 :     RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BadCall.FrameRateVariance",
     223             :                              static_cast<int>(100 * *variance_fraction));
     224             :   }
     225             :   rtc::Optional<double> qp_fraction =
     226           0 :       qp_threshold_.FractionHigh(kBadCallMinRequiredSamples);
     227           0 :   if (qp_fraction) {
     228           0 :     RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BadCall.Qp",
     229             :                              static_cast<int>(100 * *qp_fraction));
     230             :   }
     231           0 : }
     232             : 
     233           0 : void ReceiveStatisticsProxy::QualitySample() {
     234           0 :   int64_t now = clock_->TimeInMilliseconds();
     235           0 :   if (last_sample_time_ + kMinSampleLengthMs > now)
     236           0 :     return;
     237             : 
     238             :   double fps =
     239           0 :       render_fps_tracker_.ComputeRateForInterval(now - last_sample_time_);
     240           0 :   int qp = qp_sample_.Avg(1);
     241             : 
     242           0 :   bool prev_fps_bad = !fps_threshold_.IsHigh().value_or(true);
     243           0 :   bool prev_qp_bad = qp_threshold_.IsHigh().value_or(false);
     244           0 :   bool prev_variance_bad = variance_threshold_.IsHigh().value_or(false);
     245           0 :   bool prev_any_bad = prev_fps_bad || prev_qp_bad || prev_variance_bad;
     246             : 
     247           0 :   fps_threshold_.AddMeasurement(static_cast<int>(fps));
     248           0 :   if (qp != -1)
     249           0 :     qp_threshold_.AddMeasurement(qp);
     250           0 :   rtc::Optional<double> fps_variance_opt = fps_threshold_.CalculateVariance();
     251           0 :   double fps_variance = fps_variance_opt.value_or(0);
     252           0 :   if (fps_variance_opt) {
     253           0 :     variance_threshold_.AddMeasurement(static_cast<int>(fps_variance));
     254             :   }
     255             : 
     256           0 :   bool fps_bad = !fps_threshold_.IsHigh().value_or(true);
     257           0 :   bool qp_bad = qp_threshold_.IsHigh().value_or(false);
     258           0 :   bool variance_bad = variance_threshold_.IsHigh().value_or(false);
     259           0 :   bool any_bad = fps_bad || qp_bad || variance_bad;
     260             : 
     261           0 :   if (!prev_any_bad && any_bad) {
     262           0 :     LOG(LS_INFO) << "Bad call (any) start: " << now;
     263           0 :   } else if (prev_any_bad && !any_bad) {
     264           0 :     LOG(LS_INFO) << "Bad call (any) end: " << now;
     265             :   }
     266             : 
     267           0 :   if (!prev_fps_bad && fps_bad) {
     268           0 :     LOG(LS_INFO) << "Bad call (fps) start: " << now;
     269           0 :   } else if (prev_fps_bad && !fps_bad) {
     270           0 :     LOG(LS_INFO) << "Bad call (fps) end: " << now;
     271             :   }
     272             : 
     273           0 :   if (!prev_qp_bad && qp_bad) {
     274           0 :     LOG(LS_INFO) << "Bad call (qp) start: " << now;
     275           0 :   } else if (prev_qp_bad && !qp_bad) {
     276           0 :     LOG(LS_INFO) << "Bad call (qp) end: " << now;
     277             :   }
     278             : 
     279           0 :   if (!prev_variance_bad && variance_bad) {
     280           0 :     LOG(LS_INFO) << "Bad call (variance) start: " << now;
     281           0 :   } else if (prev_variance_bad && !variance_bad) {
     282           0 :     LOG(LS_INFO) << "Bad call (variance) end: " << now;
     283             :   }
     284             : 
     285           0 :   LOG(LS_VERBOSE) << "SAMPLE: sample_length: " << (now - last_sample_time_)
     286           0 :                   << " fps: " << fps << " fps_bad: " << fps_bad << " qp: " << qp
     287           0 :                   << " qp_bad: " << qp_bad << " variance_bad: " << variance_bad
     288           0 :                   << " fps_variance: " << fps_variance;
     289             : 
     290           0 :   last_sample_time_ = now;
     291           0 :   qp_sample_.Reset();
     292             : 
     293           0 :   if (fps_threshold_.IsHigh() || variance_threshold_.IsHigh() ||
     294           0 :       qp_threshold_.IsHigh()) {
     295           0 :     if (any_bad)
     296           0 :       ++num_bad_states_;
     297           0 :     ++num_certain_states_;
     298             :   }
     299             : }
     300             : 
     301           0 : VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const {
     302           0 :   rtc::CritScope lock(&crit_);
     303           0 :   return stats_;
     304             : }
     305             : 
     306           0 : void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) {
     307           0 :   rtc::CritScope lock(&crit_);
     308           0 :   stats_.current_payload_type = payload_type;
     309           0 : }
     310             : 
     311           0 : void ReceiveStatisticsProxy::OnDecoderImplementationName(
     312             :     const char* implementation_name) {
     313           0 :   rtc::CritScope lock(&crit_);
     314           0 :   stats_.decoder_implementation_name = implementation_name;
     315           0 : }
     316           0 : void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate,
     317             :                                             unsigned int bitrate_bps) {
     318           0 :   rtc::CritScope lock(&crit_);
     319           0 :   if (stats_.rtp_stats.first_packet_time_ms != -1)
     320           0 :     QualitySample();
     321           0 :   stats_.network_frame_rate = framerate;
     322           0 :   stats_.total_bitrate_bps = bitrate_bps;
     323           0 : }
     324             : 
     325           0 : void ReceiveStatisticsProxy::ReceiveStateChange(VideoReceiveState state) {
     326           0 :   rtc::CritScope lock(&crit_);
     327           0 :   receive_state_ = state;
     328           0 : }
     329             : 
     330           0 : void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms,
     331             :                                              int max_decode_ms,
     332             :                                              int current_delay_ms,
     333             :                                              int target_delay_ms,
     334             :                                              int jitter_buffer_ms,
     335             :                                              int min_playout_delay_ms,
     336             :                                              int render_delay_ms,
     337             :                                              int64_t rtt_ms) {
     338           0 :   rtc::CritScope lock(&crit_);
     339           0 :   stats_.decode_ms = decode_ms;
     340           0 :   stats_.max_decode_ms = max_decode_ms;
     341           0 :   stats_.current_delay_ms = current_delay_ms;
     342           0 :   stats_.target_delay_ms = target_delay_ms;
     343           0 :   stats_.jitter_buffer_ms = jitter_buffer_ms;
     344           0 :   stats_.min_playout_delay_ms = min_playout_delay_ms;
     345           0 :   stats_.render_delay_ms = render_delay_ms;
     346           0 :   decode_time_counter_.Add(decode_ms);
     347           0 :   jitter_buffer_delay_counter_.Add(jitter_buffer_ms);
     348           0 :   target_delay_counter_.Add(target_delay_ms);
     349           0 :   current_delay_counter_.Add(current_delay_ms);
     350             :   // Network delay (rtt/2) + target_delay_ms (jitter delay + decode time +
     351             :   // render delay).
     352           0 :   delay_counter_.Add(target_delay_ms + rtt_ms / 2);
     353           0 : }
     354             : 
     355           0 : void ReceiveStatisticsProxy::RtcpPacketTypesCounterUpdated(
     356             :     uint32_t ssrc,
     357             :     const RtcpPacketTypeCounter& packet_counter) {
     358           0 :   rtc::CritScope lock(&crit_);
     359           0 :   if (stats_.ssrc != ssrc)
     360           0 :     return;
     361           0 :   stats_.rtcp_packet_type_counts = packet_counter;
     362             : }
     363             : 
     364           0 : void ReceiveStatisticsProxy::StatisticsUpdated(
     365             :     const webrtc::RtcpStatistics& statistics,
     366             :     uint32_t ssrc) {
     367           0 :   rtc::CritScope lock(&crit_);
     368             :   // TODO(pbos): Handle both local and remote ssrcs here and RTC_DCHECK that we
     369             :   // receive stats from one of them.
     370           0 :   if (stats_.ssrc != ssrc)
     371           0 :     return;
     372           0 :   stats_.rtcp_stats = statistics;
     373           0 :   report_block_stats_.Store(statistics, ssrc, 0);
     374             : 
     375           0 :   if (first_report_block_time_ms_ == -1)
     376           0 :     first_report_block_time_ms_ = clock_->TimeInMilliseconds();
     377             : }
     378             : 
     379           0 : void ReceiveStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {
     380           0 :   rtc::CritScope lock(&crit_);
     381             :   // TODO(pbos): Handle both local and remote ssrcs here and RTC_DCHECK that we
     382             :   // receive stats from one of them.
     383           0 :   if (stats_.ssrc != ssrc)
     384           0 :     return;
     385           0 :   stats_.c_name = cname;
     386             : }
     387             : 
     388           0 : void ReceiveStatisticsProxy::DataCountersUpdated(
     389             :     const webrtc::StreamDataCounters& counters,
     390             :     uint32_t ssrc) {
     391           0 :   rtc::CritScope lock(&crit_);
     392           0 :   if (ssrc == stats_.ssrc) {
     393           0 :     stats_.rtp_stats = counters;
     394             :   } else {
     395           0 :     auto it = rtx_stats_.find(ssrc);
     396           0 :     if (it != rtx_stats_.end()) {
     397           0 :       it->second = counters;
     398             :     } else {
     399           0 :       RTC_NOTREACHED() << "Unexpected stream ssrc: " << ssrc;
     400             :     }
     401             :   }
     402           0 : }
     403             : 
     404           0 : void ReceiveStatisticsProxy::OnDecodedFrame() {
     405           0 :   uint64_t now = clock_->TimeInMilliseconds();
     406             : 
     407           0 :   rtc::CritScope lock(&crit_);
     408           0 :   ++stats_.frames_decoded;
     409           0 :   decode_fps_estimator_.Update(1, now);
     410           0 :   stats_.decode_frame_rate = decode_fps_estimator_.Rate(now).value_or(0);
     411           0 : }
     412             : 
     413           0 : void ReceiveStatisticsProxy::OnRenderedFrame(const VideoFrame& frame) {
     414           0 :   int width = frame.width();
     415           0 :   int height = frame.height();
     416           0 :   RTC_DCHECK_GT(width, 0);
     417           0 :   RTC_DCHECK_GT(height, 0);
     418           0 :   uint64_t now = clock_->TimeInMilliseconds();
     419             : 
     420           0 :   rtc::CritScope lock(&crit_);
     421           0 :   renders_fps_estimator_.Update(1, now);
     422           0 :   stats_.render_frame_rate = renders_fps_estimator_.Rate(now).value_or(0);
     423           0 :   stats_.width = width;
     424           0 :   stats_.height = height;
     425           0 :   render_width_counter_.Add(width);
     426           0 :   render_height_counter_.Add(height);
     427           0 :   render_fps_tracker_.AddSamples(1);
     428           0 :   render_pixel_tracker_.AddSamples(sqrt(width * height));
     429             : 
     430           0 :   if (frame.ntp_time_ms() > 0) {
     431           0 :     int64_t delay_ms = clock_->CurrentNtpInMilliseconds() - frame.ntp_time_ms();
     432           0 :     if (delay_ms >= 0)
     433           0 :       e2e_delay_counter_.Add(delay_ms);
     434             :   }
     435           0 : }
     436             : 
     437           0 : void ReceiveStatisticsProxy::OnSyncOffsetUpdated(int64_t sync_offset_ms,
     438             :                                                  double estimated_freq_khz) {
     439           0 :   rtc::CritScope lock(&crit_);
     440           0 :   sync_offset_counter_.Add(std::abs(sync_offset_ms));
     441           0 :   stats_.sync_offset_ms = sync_offset_ms;
     442             : 
     443           0 :   const double kMaxFreqKhz = 10000.0;
     444           0 :   int offset_khz = kMaxFreqKhz;
     445             :   // Should not be zero or negative. If so, report max.
     446           0 :   if (estimated_freq_khz < kMaxFreqKhz && estimated_freq_khz > 0.0)
     447           0 :     offset_khz = static_cast<int>(std::fabs(estimated_freq_khz - 90.0) + 0.5);
     448             : 
     449           0 :   freq_offset_counter_.Add(offset_khz);
     450           0 : }
     451             : 
     452           0 : void ReceiveStatisticsProxy::OnReceiveRatesUpdated(uint32_t bitRate,
     453             :                                                    uint32_t frameRate) {
     454           0 : }
     455             : 
     456           0 : void ReceiveStatisticsProxy::OnFrameCountsUpdated(
     457             :     const FrameCounts& frame_counts) {
     458           0 :   rtc::CritScope lock(&crit_);
     459           0 :   stats_.frame_counts = frame_counts;
     460           0 : }
     461             : 
     462           0 : void ReceiveStatisticsProxy::OnDiscardedPacketsUpdated(int discarded_packets) {
     463           0 :   rtc::CritScope lock(&crit_);
     464           0 :   stats_.discarded_packets = discarded_packets;
     465           0 : }
     466             : 
     467           0 : void ReceiveStatisticsProxy::OnPreDecode(
     468             :     const EncodedImage& encoded_image,
     469             :     const CodecSpecificInfo* codec_specific_info) {
     470           0 :   if (!codec_specific_info || encoded_image.qp_ == -1) {
     471           0 :     return;
     472             :   }
     473           0 :   if (codec_specific_info->codecType == kVideoCodecVP8) {
     474           0 :     qp_counters_.vp8.Add(encoded_image.qp_);
     475           0 :     rtc::CritScope lock(&crit_);
     476           0 :     qp_sample_.Add(encoded_image.qp_);
     477             :   }
     478             : }
     479             : 
     480           0 : void ReceiveStatisticsProxy::SampleCounter::Add(int sample) {
     481           0 :   sum += sample;
     482           0 :   ++num_samples;
     483           0 : }
     484             : 
     485           0 : int ReceiveStatisticsProxy::SampleCounter::Avg(
     486             :     int64_t min_required_samples) const {
     487           0 :   if (num_samples < min_required_samples || num_samples == 0)
     488           0 :     return -1;
     489           0 :   return static_cast<int>(sum / num_samples);
     490             : }
     491             : 
     492           0 : void ReceiveStatisticsProxy::SampleCounter::Reset() {
     493           0 :   num_samples = 0;
     494           0 :   sum = 0;
     495           0 : }
     496             : 
     497             : }  // namespace webrtc

Generated by: LCOV version 1.13