LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/video - send_statistics_proxy.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 432 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 39 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/send_statistics_proxy.h"
      12             : 
      13             : #include <algorithm>
      14             : #include <cmath>
      15             : #include <map>
      16             : #include <vector>
      17             : 
      18             : #include "webrtc/base/checks.h"
      19             : #include "webrtc/base/logging.h"
      20             : #include "webrtc/modules/video_coding/include/video_codec_interface.h"
      21             : #include "webrtc/system_wrappers/include/metrics.h"
      22             : 
      23             : namespace webrtc {
      24             : namespace {
      25             : const float kEncodeTimeWeigthFactor = 0.5f;
      26             : 
      27             : // Used by histograms. Values of entries should not be changed.
      28             : enum HistogramCodecType {
      29             :   kVideoUnknown = 0,
      30             :   kVideoVp8 = 1,
      31             :   kVideoVp9 = 2,
      32             :   kVideoH264 = 3,
      33             :   kVideoMax = 64,
      34             : };
      35             : 
      36             : const char* kRealtimePrefix = "WebRTC.Video.";
      37             : const char* kScreenPrefix = "WebRTC.Video.Screenshare.";
      38             : 
      39           0 : const char* GetUmaPrefix(VideoEncoderConfig::ContentType content_type) {
      40           0 :   switch (content_type) {
      41             :     case VideoEncoderConfig::ContentType::kRealtimeVideo:
      42           0 :       return kRealtimePrefix;
      43             :     case VideoEncoderConfig::ContentType::kScreen:
      44           0 :       return kScreenPrefix;
      45             :   }
      46           0 :   RTC_NOTREACHED();
      47           0 :   return nullptr;
      48             : }
      49             : 
      50           0 : HistogramCodecType PayloadNameToHistogramCodecType(
      51             :     const std::string& payload_name) {
      52           0 :   if (payload_name == "VP8") {
      53           0 :     return kVideoVp8;
      54           0 :   } else if (payload_name == "VP9") {
      55           0 :     return kVideoVp9;
      56           0 :   } else if (payload_name == "H264") {
      57           0 :     return kVideoH264;
      58             :   } else {
      59           0 :     return kVideoUnknown;
      60             :   }
      61             : }
      62             : 
      63           0 : void UpdateCodecTypeHistogram(const std::string& payload_name) {
      64           0 :   RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.Encoder.CodecType",
      65             :                             PayloadNameToHistogramCodecType(payload_name),
      66             :                             kVideoMax);
      67           0 : }
      68             : }  // namespace
      69             : 
      70             : 
      71             : const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
      72             : 
      73           0 : SendStatisticsProxy::SendStatisticsProxy(
      74             :     Clock* clock,
      75             :     const VideoSendStream::Config& config,
      76           0 :     VideoEncoderConfig::ContentType content_type)
      77             :     : clock_(clock),
      78             :       payload_name_(config.encoder_settings.payload_name),
      79             :       rtp_config_(config.rtp),
      80             :       content_type_(content_type),
      81           0 :       start_ms_(clock->TimeInMilliseconds()),
      82             :       last_sent_frame_timestamp_(0),
      83             :       encode_time_(kEncodeTimeWeigthFactor),
      84             :       uma_container_(
      85           0 :           new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) {
      86           0 : }
      87             : 
      88           0 : SendStatisticsProxy::~SendStatisticsProxy() {
      89           0 :   rtc::CritScope lock(&crit_);
      90           0 :   uma_container_->UpdateHistograms(rtp_config_, stats_);
      91             : 
      92           0 :   int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000;
      93           0 :   RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds",
      94             :                               elapsed_sec);
      95             : 
      96           0 :   if (elapsed_sec >= metrics::kMinRunTimeInSeconds)
      97           0 :     UpdateCodecTypeHistogram(payload_name_);
      98           0 : }
      99             : 
     100           0 : SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
     101             :     const char* prefix,
     102             :     const VideoSendStream::Stats& stats,
     103           0 :     Clock* const clock)
     104             :     : uma_prefix_(prefix),
     105             :       clock_(clock),
     106             :       max_sent_width_per_timestamp_(0),
     107             :       max_sent_height_per_timestamp_(0),
     108             :       input_frame_rate_tracker_(100, 10u),
     109             :       input_fps_counter_(clock, nullptr, true),
     110             :       sent_fps_counter_(clock, nullptr, true),
     111             :       first_rtcp_stats_time_ms_(-1),
     112             :       first_rtp_stats_time_ms_(-1),
     113           0 :       start_stats_(stats) {}
     114             : 
     115           0 : SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
     116             : 
     117           0 : void AccumulateRtxStats(const VideoSendStream::Stats& stats,
     118             :                         const std::vector<uint32_t>& rtx_ssrcs,
     119             :                         StreamDataCounters* total_rtp_stats,
     120             :                         StreamDataCounters* rtx_stats) {
     121           0 :   for (auto it : stats.substreams) {
     122           0 :     if (std::find(rtx_ssrcs.begin(), rtx_ssrcs.end(), it.first) !=
     123           0 :         rtx_ssrcs.end()) {
     124           0 :       rtx_stats->Add(it.second.rtp_stats);
     125             :     } else {
     126           0 :       total_rtp_stats->Add(it.second.rtp_stats);
     127             :     }
     128             :   }
     129           0 : }
     130             : 
     131           0 : void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
     132             :     const VideoSendStream::Config::Rtp& rtp_config,
     133             :     const VideoSendStream::Stats& current_stats) {
     134           0 :   RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
     135           0 :   const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
     136           0 :   const int kMinRequiredPeriodicSamples = 6;
     137           0 :   int in_width = input_width_counter_.Avg(kMinRequiredMetricsSamples);
     138           0 :   int in_height = input_height_counter_.Avg(kMinRequiredMetricsSamples);
     139           0 :   if (in_width != -1) {
     140           0 :     RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputWidthInPixels",
     141             :                                 in_width);
     142           0 :     RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputHeightInPixels",
     143             :                                 in_height);
     144             :   }
     145           0 :   AggregatedStats in_fps = input_fps_counter_.GetStats();
     146           0 :   if (in_fps.num_samples >= kMinRequiredPeriodicSamples) {
     147           0 :     RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond",
     148             :                               in_fps.average);
     149           0 :     LOG(LS_INFO) << uma_prefix_ + "InputFramesPerSecond, " << in_fps.ToString();
     150             :   }
     151             : 
     152           0 :   int sent_width = sent_width_counter_.Avg(kMinRequiredMetricsSamples);
     153           0 :   int sent_height = sent_height_counter_.Avg(kMinRequiredMetricsSamples);
     154           0 :   if (sent_width != -1) {
     155           0 :     RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentWidthInPixels",
     156             :                                 sent_width);
     157           0 :     RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentHeightInPixels",
     158             :                                 sent_height);
     159             :   }
     160           0 :   AggregatedStats sent_fps = sent_fps_counter_.GetStats();
     161           0 :   if (sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
     162           0 :     RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond",
     163             :                               sent_fps.average);
     164           0 :     LOG(LS_INFO) << uma_prefix_ + "SentFramesPerSecond, "
     165           0 :                  << sent_fps.ToString();
     166             :   }
     167             : 
     168           0 :   int encode_ms = encode_time_counter_.Avg(kMinRequiredMetricsSamples);
     169           0 :   if (encode_ms != -1) {
     170           0 :     RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
     171             :                                encode_ms);
     172             :   }
     173             :   int key_frames_permille =
     174           0 :       key_frame_counter_.Permille(kMinRequiredMetricsSamples);
     175           0 :   if (key_frames_permille != -1) {
     176           0 :     RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "KeyFramesSentInPermille",
     177             :                                key_frames_permille);
     178             :   }
     179             :   int quality_limited =
     180           0 :       quality_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
     181           0 :   if (quality_limited != -1) {
     182           0 :     RTC_HISTOGRAMS_PERCENTAGE(kIndex,
     183             :                               uma_prefix_ + "QualityLimitedResolutionInPercent",
     184             :                               quality_limited);
     185             :   }
     186           0 :   int downscales = quality_downscales_counter_.Avg(kMinRequiredMetricsSamples);
     187           0 :   if (downscales != -1) {
     188           0 :     RTC_HISTOGRAMS_ENUMERATION(
     189             :         kIndex, uma_prefix_ + "QualityLimitedResolutionDownscales", downscales,
     190             :         20);
     191             :   }
     192             :   int cpu_limited =
     193           0 :       cpu_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
     194           0 :   if (cpu_limited != -1) {
     195           0 :     RTC_HISTOGRAMS_PERCENTAGE(
     196             :         kIndex, uma_prefix_ + "CpuLimitedResolutionInPercent", cpu_limited);
     197             :   }
     198             :   int bw_limited =
     199           0 :       bw_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
     200           0 :   if (bw_limited != -1) {
     201           0 :     RTC_HISTOGRAMS_PERCENTAGE(
     202             :         kIndex, uma_prefix_ + "BandwidthLimitedResolutionInPercent",
     203             :         bw_limited);
     204             :   }
     205             :   int num_disabled =
     206           0 :       bw_resolutions_disabled_counter_.Avg(kMinRequiredMetricsSamples);
     207           0 :   if (num_disabled != -1) {
     208           0 :     RTC_HISTOGRAMS_ENUMERATION(
     209             :         kIndex, uma_prefix_ + "BandwidthLimitedResolutionsDisabled",
     210             :         num_disabled, 10);
     211             :   }
     212           0 :   int delay_ms = delay_counter_.Avg(kMinRequiredMetricsSamples);
     213           0 :   if (delay_ms != -1)
     214           0 :     RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayInMs",
     215             :                                  delay_ms);
     216             : 
     217           0 :   int max_delay_ms = max_delay_counter_.Avg(kMinRequiredMetricsSamples);
     218           0 :   if (max_delay_ms != -1) {
     219           0 :     RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayMaxInMs",
     220             :                                  max_delay_ms);
     221             :   }
     222             : 
     223           0 :   for (const auto& it : qp_counters_) {
     224           0 :     int qp_vp8 = it.second.vp8.Avg(kMinRequiredMetricsSamples);
     225           0 :     if (qp_vp8 != -1) {
     226           0 :       int spatial_idx = it.first;
     227           0 :       if (spatial_idx == -1) {
     228           0 :         RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8",
     229             :                                   qp_vp8);
     230           0 :       } else if (spatial_idx == 0) {
     231           0 :         RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S0",
     232             :                                   qp_vp8);
     233           0 :       } else if (spatial_idx == 1) {
     234           0 :         RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S1",
     235             :                                   qp_vp8);
     236           0 :       } else if (spatial_idx == 2) {
     237           0 :         RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S2",
     238             :                                   qp_vp8);
     239             :       } else {
     240           0 :         LOG(LS_WARNING) << "QP stats not recorded for VP8 spatial idx "
     241           0 :                         << spatial_idx;
     242             :       }
     243             :     }
     244           0 :     int qp_vp9 = it.second.vp9.Avg(kMinRequiredMetricsSamples);
     245           0 :     if (qp_vp9 != -1) {
     246           0 :       int spatial_idx = it.first;
     247           0 :       if (spatial_idx == -1) {
     248           0 :         RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9",
     249             :                                   qp_vp9);
     250           0 :       } else if (spatial_idx == 0) {
     251           0 :         RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S0",
     252             :                                   qp_vp9);
     253           0 :       } else if (spatial_idx == 1) {
     254           0 :         RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S1",
     255             :                                   qp_vp9);
     256           0 :       } else if (spatial_idx == 2) {
     257           0 :         RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S2",
     258             :                                   qp_vp9);
     259             :       } else {
     260           0 :         LOG(LS_WARNING) << "QP stats not recorded for VP9 spatial layer "
     261           0 :                         << spatial_idx;
     262             :       }
     263             :     }
     264           0 :     int qp_h264 = it.second.h264.Avg(kMinRequiredMetricsSamples);
     265           0 :     if (qp_h264 != -1) {
     266           0 :       int spatial_idx = it.first;
     267           0 :       RTC_DCHECK_EQ(-1, spatial_idx);
     268           0 :       RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "Encoded.Qp.H264",
     269             :                                 qp_h264);
     270             :     }
     271             :   }
     272             : 
     273           0 :   if (first_rtcp_stats_time_ms_ != -1) {
     274             :     int64_t elapsed_sec =
     275           0 :         (clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
     276           0 :     if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
     277           0 :       int fraction_lost = report_block_stats_.FractionLostInPercent();
     278           0 :       if (fraction_lost != -1) {
     279           0 :         RTC_HISTOGRAMS_PERCENTAGE(
     280             :             kIndex, uma_prefix_ + "SentPacketsLostInPercent", fraction_lost);
     281             :       }
     282             : 
     283             :       // The RTCP packet type counters, delivered via the
     284             :       // RtcpPacketTypeCounterObserver interface, are aggregates over the entire
     285             :       // life of the send stream and are not reset when switching content type.
     286             :       // For the purpose of these statistics though, we want new counts when
     287             :       // switching since we switch histogram name. On every reset of the
     288             :       // UmaSamplesContainer, we save the initial state of the counters, so that
     289             :       // we can calculate the delta here and aggregate over all ssrcs.
     290           0 :       RtcpPacketTypeCounter counters;
     291           0 :       for (uint32_t ssrc : rtp_config.ssrcs) {
     292           0 :         auto kv = current_stats.substreams.find(ssrc);
     293           0 :         if (kv == current_stats.substreams.end())
     294           0 :           continue;
     295             : 
     296             :         RtcpPacketTypeCounter stream_counters =
     297           0 :             kv->second.rtcp_packet_type_counts;
     298           0 :         kv = start_stats_.substreams.find(ssrc);
     299           0 :         if (kv != start_stats_.substreams.end())
     300           0 :           stream_counters.Subtract(kv->second.rtcp_packet_type_counts);
     301             : 
     302           0 :         counters.Add(stream_counters);
     303             :       }
     304           0 :       RTC_HISTOGRAMS_COUNTS_10000(kIndex,
     305             :                                   uma_prefix_ + "NackPacketsReceivedPerMinute",
     306             :                                   counters.nack_packets * 60 / elapsed_sec);
     307           0 :       RTC_HISTOGRAMS_COUNTS_10000(kIndex,
     308             :                                   uma_prefix_ + "FirPacketsReceivedPerMinute",
     309             :                                   counters.fir_packets * 60 / elapsed_sec);
     310           0 :       RTC_HISTOGRAMS_COUNTS_10000(kIndex,
     311             :                                   uma_prefix_ + "PliPacketsReceivedPerMinute",
     312             :                                   counters.pli_packets * 60 / elapsed_sec);
     313           0 :       if (counters.nack_requests > 0) {
     314           0 :         RTC_HISTOGRAMS_PERCENTAGE(
     315             :             kIndex, uma_prefix_ + "UniqueNackRequestsReceivedInPercent",
     316             :             counters.UniqueNackRequestsInPercent());
     317             :       }
     318             :     }
     319             :   }
     320             : 
     321           0 :   if (first_rtp_stats_time_ms_ != -1) {
     322             :     int64_t elapsed_sec =
     323           0 :         (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
     324           0 :     if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
     325           0 :       RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "NumberOfPauseEvents",
     326             :                                 target_rate_updates_.pause_resume_events);
     327             : 
     328             :       int paused_time_percent =
     329           0 :           paused_time_counter_.Percent(metrics::kMinRunTimeInSeconds * 1000);
     330           0 :       if (paused_time_percent != -1) {
     331           0 :         RTC_HISTOGRAMS_PERCENTAGE(kIndex, uma_prefix_ + "PausedTimeInPercent",
     332             :                                   paused_time_percent);
     333             :       }
     334             : 
     335           0 :       StreamDataCounters rtp;
     336           0 :       StreamDataCounters rtx;
     337           0 :       AccumulateRtxStats(current_stats, rtp_config.rtx.ssrcs, &rtp, &rtx);
     338           0 :       StreamDataCounters start_rtp;
     339           0 :       StreamDataCounters start_rtx;
     340           0 :       AccumulateRtxStats(start_stats_, rtp_config.rtx.ssrcs, &start_rtp,
     341           0 :                          &start_rtx);
     342           0 :       rtp.Subtract(start_rtp);
     343           0 :       rtx.Subtract(start_rtx);
     344           0 :       StreamDataCounters rtp_rtx = rtp;
     345           0 :       rtp_rtx.Add(rtx);
     346             : 
     347           0 :       RTC_HISTOGRAMS_COUNTS_10000(
     348             :           kIndex, uma_prefix_ + "BitrateSentInKbps",
     349             :           static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
     350             :                            1000));
     351           0 :       RTC_HISTOGRAMS_COUNTS_10000(
     352             :           kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
     353             :           static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000));
     354           0 :       RTC_HISTOGRAMS_COUNTS_10000(
     355             :           kIndex, uma_prefix_ + "PaddingBitrateSentInKbps",
     356             :           static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec /
     357             :                            1000));
     358           0 :       RTC_HISTOGRAMS_COUNTS_10000(
     359             :           kIndex, uma_prefix_ + "RetransmittedBitrateSentInKbps",
     360             :           static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 /
     361             :                            elapsed_sec / 1000));
     362           0 :       if (!rtp_config.rtx.ssrcs.empty()) {
     363           0 :         RTC_HISTOGRAMS_COUNTS_10000(
     364             :             kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
     365             :             static_cast<int>(rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
     366             :                              1000));
     367             :       }
     368           0 :       if (rtp_config.flexfec.payload_type != -1 ||
     369           0 :           rtp_config.ulpfec.red_payload_type != -1) {
     370           0 :         RTC_HISTOGRAMS_COUNTS_10000(kIndex,
     371             :                                     uma_prefix_ + "FecBitrateSentInKbps",
     372             :                                     static_cast<int>(rtp_rtx.fec.TotalBytes() *
     373             :                                                      8 / elapsed_sec / 1000));
     374             :       }
     375             :     }
     376             :   }
     377           0 : }
     378             : 
     379           0 : void SendStatisticsProxy::OnEncoderReconfigured(
     380             :     const VideoEncoderConfig& config,
     381             :     uint32_t preferred_bitrate_bps) {
     382           0 :   rtc::CritScope lock(&crit_);
     383           0 :   stats_.preferred_media_bitrate_bps = preferred_bitrate_bps;
     384             : 
     385           0 :   if (content_type_ != config.content_type) {
     386           0 :     uma_container_->UpdateHistograms(rtp_config_, stats_);
     387           0 :     uma_container_.reset(new UmaSamplesContainer(
     388           0 :         GetUmaPrefix(config.content_type), stats_, clock_));
     389           0 :     content_type_ = config.content_type;
     390             :   }
     391           0 : }
     392             : 
     393           0 : void SendStatisticsProxy::OnEncoderStatsUpdate(uint32_t framerate,
     394             :                                                uint32_t bitrate) {
     395           0 :   rtc::CritScope lock(&crit_);
     396           0 :   stats_.encode_frame_rate = framerate;
     397           0 :   stats_.media_bitrate_bps = bitrate;
     398           0 : }
     399             : 
     400           0 : void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
     401             :     int encode_time_ms,
     402             :     const CpuOveruseMetrics& metrics) {
     403           0 :   rtc::CritScope lock(&crit_);
     404           0 :   uma_container_->encode_time_counter_.Add(encode_time_ms);
     405           0 :   encode_time_.Apply(1.0f, encode_time_ms);
     406           0 :   stats_.avg_encode_time_ms = round(encode_time_.filtered());
     407           0 :   stats_.encode_usage_percent = metrics.encode_usage_percent;
     408           0 : }
     409             : 
     410           0 : void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
     411           0 :   rtc::CritScope lock(&crit_);
     412           0 :   stats_.suspended = is_suspended;
     413             :   // Pause framerate stats.
     414           0 :   if (is_suspended) {
     415           0 :     uma_container_->input_fps_counter_.ProcessAndPause();
     416           0 :     uma_container_->sent_fps_counter_.ProcessAndPause();
     417             :   }
     418           0 : }
     419             : 
     420           0 : VideoSendStream::Stats SendStatisticsProxy::GetStats() {
     421           0 :   rtc::CritScope lock(&crit_);
     422           0 :   PurgeOldStats();
     423           0 :   stats_.input_frame_rate =
     424           0 :       round(uma_container_->input_frame_rate_tracker_.ComputeRate());
     425           0 :   return stats_;
     426             : }
     427             : 
     428           0 : void SendStatisticsProxy::PurgeOldStats() {
     429           0 :   int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
     430           0 :   for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
     431           0 :            stats_.substreams.begin();
     432           0 :        it != stats_.substreams.end(); ++it) {
     433           0 :     uint32_t ssrc = it->first;
     434           0 :     if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
     435           0 :       it->second.width = 0;
     436           0 :       it->second.height = 0;
     437             :     }
     438             :   }
     439           0 : }
     440             : 
     441           0 : VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
     442             :     uint32_t ssrc) {
     443             :   std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
     444           0 :       stats_.substreams.find(ssrc);
     445           0 :   if (it != stats_.substreams.end())
     446           0 :     return &it->second;
     447             : 
     448           0 :   bool is_media = std::find(rtp_config_.ssrcs.begin(), rtp_config_.ssrcs.end(),
     449           0 :                             ssrc) != rtp_config_.ssrcs.end();
     450           0 :   bool is_flexfec = rtp_config_.flexfec.payload_type != -1 &&
     451           0 :                     ssrc == rtp_config_.flexfec.ssrc;
     452             :   bool is_rtx =
     453           0 :       std::find(rtp_config_.rtx.ssrcs.begin(), rtp_config_.rtx.ssrcs.end(),
     454           0 :                 ssrc) != rtp_config_.rtx.ssrcs.end();
     455           0 :   if (!is_media && !is_flexfec && !is_rtx)
     456           0 :     return nullptr;
     457             : 
     458             :   // Insert new entry and return ptr.
     459           0 :   VideoSendStream::StreamStats* entry = &stats_.substreams[ssrc];
     460           0 :   entry->is_rtx = is_rtx;
     461           0 :   entry->is_flexfec = is_flexfec;
     462             : 
     463           0 :   return entry;
     464             : }
     465             : 
     466           0 : void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
     467           0 :   rtc::CritScope lock(&crit_);
     468           0 :   VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
     469           0 :   if (!stats)
     470           0 :     return;
     471             : 
     472           0 :   stats->total_bitrate_bps = 0;
     473           0 :   stats->retransmit_bitrate_bps = 0;
     474           0 :   stats->height = 0;
     475           0 :   stats->width = 0;
     476             : }
     477             : 
     478           0 : void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) {
     479           0 :   rtc::CritScope lock(&crit_);
     480           0 :   if (uma_container_->target_rate_updates_.last_ms == -1 && bitrate_bps == 0)
     481           0 :     return;  // Start on first non-zero bitrate, may initially be zero.
     482             : 
     483           0 :   int64_t now = clock_->TimeInMilliseconds();
     484           0 :   if (uma_container_->target_rate_updates_.last_ms != -1) {
     485           0 :     bool was_paused = stats_.target_media_bitrate_bps == 0;
     486           0 :     int64_t diff_ms = now - uma_container_->target_rate_updates_.last_ms;
     487           0 :     uma_container_->paused_time_counter_.Add(was_paused, diff_ms);
     488             : 
     489             :     // Use last to not include update when stream is stopped and video disabled.
     490           0 :     if (uma_container_->target_rate_updates_.last_paused_or_resumed)
     491           0 :       ++uma_container_->target_rate_updates_.pause_resume_events;
     492             : 
     493             :     // Check if video is paused/resumed.
     494           0 :     uma_container_->target_rate_updates_.last_paused_or_resumed =
     495           0 :         (bitrate_bps == 0) != was_paused;
     496             :   }
     497           0 :   uma_container_->target_rate_updates_.last_ms = now;
     498             : 
     499           0 :   stats_.target_media_bitrate_bps = bitrate_bps;
     500             : }
     501             : 
     502           0 : void SendStatisticsProxy::OnSendEncodedImage(
     503             :     const EncodedImage& encoded_image,
     504             :     const CodecSpecificInfo* codec_info) {
     505           0 :   size_t simulcast_idx = 0;
     506             : 
     507           0 :   rtc::CritScope lock(&crit_);
     508           0 :   ++stats_.frames_encoded;
     509           0 :   if (codec_info) {
     510           0 :     if (codec_info->codecType == kVideoCodecVP8) {
     511           0 :       simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx;
     512           0 :     } else if (codec_info->codecType == kVideoCodecGeneric) {
     513           0 :       simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx;
     514             :     }
     515           0 :     if (codec_info->codec_name) {
     516           0 :       stats_.encoder_implementation_name = codec_info->codec_name;
     517             :     }
     518             :   }
     519             : 
     520           0 :   if (simulcast_idx >= rtp_config_.ssrcs.size()) {
     521           0 :     LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx
     522           0 :                   << " >= " << rtp_config_.ssrcs.size() << ").";
     523           0 :     return;
     524             :   }
     525           0 :   uint32_t ssrc = rtp_config_.ssrcs[simulcast_idx];
     526             : 
     527           0 :   VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
     528           0 :   if (!stats)
     529           0 :     return;
     530             : 
     531           0 :   stats->width = encoded_image._encodedWidth;
     532           0 :   stats->height = encoded_image._encodedHeight;
     533           0 :   update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
     534             : 
     535           0 :   uma_container_->key_frame_counter_.Add(encoded_image._frameType ==
     536           0 :                                          kVideoFrameKey);
     537           0 :   stats_.bw_limited_resolution =
     538           0 :       encoded_image.adapt_reason_.bw_resolutions_disabled > 0 ||
     539           0 :       quality_downscales_ > 0;
     540             : 
     541           0 :   if (quality_downscales_ != -1) {
     542           0 :     uma_container_->quality_limited_frame_counter_.Add(quality_downscales_ > 0);
     543           0 :     if (quality_downscales_ > 0)
     544           0 :       uma_container_->quality_downscales_counter_.Add(quality_downscales_);
     545             :   }
     546           0 :   if (encoded_image.adapt_reason_.bw_resolutions_disabled != -1) {
     547           0 :     bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
     548           0 :     uma_container_->bw_limited_frame_counter_.Add(bw_limited);
     549           0 :     if (bw_limited) {
     550           0 :       uma_container_->bw_resolutions_disabled_counter_.Add(
     551           0 :           encoded_image.adapt_reason_.bw_resolutions_disabled);
     552             :     }
     553             :   }
     554             : 
     555           0 :   if (encoded_image.qp_ != -1) {
     556           0 :     if (!stats_.qp_sum)
     557           0 :       stats_.qp_sum = rtc::Optional<uint64_t>(0);
     558           0 :     *stats_.qp_sum += encoded_image.qp_;
     559             : 
     560           0 :     if (codec_info) {
     561           0 :       if (codec_info->codecType == kVideoCodecVP8) {
     562           0 :         int spatial_idx = (rtp_config_.ssrcs.size() == 1)
     563           0 :                               ? -1
     564           0 :                               : static_cast<int>(simulcast_idx);
     565           0 :         uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
     566           0 :       } else if (codec_info->codecType == kVideoCodecVP9) {
     567             :         int spatial_idx =
     568           0 :             (codec_info->codecSpecific.VP9.num_spatial_layers == 1)
     569           0 :                 ? -1
     570           0 :                 : codec_info->codecSpecific.VP9.spatial_idx;
     571           0 :         uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
     572           0 :       } else if (codec_info->codecType == kVideoCodecH264) {
     573           0 :         int spatial_idx = -1;
     574           0 :         uma_container_->qp_counters_[spatial_idx].h264.Add(encoded_image.qp_);
     575             :       }
     576             :     }
     577             :   }
     578             : 
     579             :   // TODO(asapersson): This is incorrect if simulcast layers are encoded on
     580             :   // different threads and there is no guarantee that one frame of all layers
     581             :   // are encoded before the next start.
     582           0 :   if (last_sent_frame_timestamp_ > 0 &&
     583           0 :       encoded_image._timeStamp != last_sent_frame_timestamp_) {
     584           0 :     uma_container_->sent_fps_counter_.Add(1);
     585           0 :     uma_container_->sent_width_counter_.Add(
     586           0 :         uma_container_->max_sent_width_per_timestamp_);
     587           0 :     uma_container_->sent_height_counter_.Add(
     588           0 :         uma_container_->max_sent_height_per_timestamp_);
     589           0 :     uma_container_->max_sent_width_per_timestamp_ = 0;
     590           0 :     uma_container_->max_sent_height_per_timestamp_ = 0;
     591             :   }
     592           0 :   last_sent_frame_timestamp_ = encoded_image._timeStamp;
     593           0 :   uma_container_->max_sent_width_per_timestamp_ =
     594           0 :       std::max(uma_container_->max_sent_width_per_timestamp_,
     595           0 :                static_cast<int>(encoded_image._encodedWidth));
     596           0 :   uma_container_->max_sent_height_per_timestamp_ =
     597           0 :       std::max(uma_container_->max_sent_height_per_timestamp_,
     598           0 :                static_cast<int>(encoded_image._encodedHeight));
     599             : }
     600             : 
     601           0 : int SendStatisticsProxy::GetSendFrameRate() const {
     602           0 :   rtc::CritScope lock(&crit_);
     603           0 :   return stats_.encode_frame_rate;
     604             : }
     605             : 
     606           0 : void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
     607           0 :   rtc::CritScope lock(&crit_);
     608           0 :   uma_container_->input_frame_rate_tracker_.AddSamples(1);
     609           0 :   uma_container_->input_fps_counter_.Add(1);
     610           0 :   uma_container_->input_width_counter_.Add(width);
     611           0 :   uma_container_->input_height_counter_.Add(height);
     612           0 :   uma_container_->cpu_limited_frame_counter_.Add(stats_.cpu_limited_resolution);
     613           0 : }
     614             : 
     615           0 : void SendStatisticsProxy::SetResolutionRestrictionStats(
     616             :     bool scaling_enabled,
     617             :     bool cpu_restricted,
     618             :     int num_quality_downscales) {
     619           0 :   rtc::CritScope lock(&crit_);
     620           0 :   if (scaling_enabled) {
     621           0 :     quality_downscales_ = num_quality_downscales;
     622           0 :     stats_.bw_limited_resolution = quality_downscales_ > 0;
     623           0 :     stats_.cpu_limited_resolution = cpu_restricted;
     624             :   } else {
     625           0 :     stats_.bw_limited_resolution = false;
     626           0 :     stats_.cpu_limited_resolution = false;
     627           0 :     quality_downscales_ = -1;
     628             :   }
     629           0 : }
     630             : 
     631           0 : void SendStatisticsProxy::OnCpuRestrictedResolutionChanged(
     632             :     bool cpu_restricted_resolution) {
     633           0 :   rtc::CritScope lock(&crit_);
     634           0 :   stats_.cpu_limited_resolution = cpu_restricted_resolution;
     635           0 :   ++stats_.number_of_cpu_adapt_changes;
     636           0 : }
     637             : 
     638           0 : void SendStatisticsProxy::OnQualityRestrictedResolutionChanged(
     639             :     int num_quality_downscales) {
     640           0 :   rtc::CritScope lock(&crit_);
     641           0 :   quality_downscales_ = num_quality_downscales;
     642           0 :   stats_.bw_limited_resolution = quality_downscales_ > 0;
     643           0 : }
     644             : 
     645           0 : void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
     646             :     uint32_t ssrc,
     647             :     const RtcpPacketTypeCounter& packet_counter) {
     648           0 :   rtc::CritScope lock(&crit_);
     649           0 :   VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
     650           0 :   if (!stats)
     651           0 :     return;
     652             : 
     653           0 :   stats->rtcp_packet_type_counts = packet_counter;
     654           0 :   if (uma_container_->first_rtcp_stats_time_ms_ == -1)
     655           0 :     uma_container_->first_rtcp_stats_time_ms_ = clock_->TimeInMilliseconds();
     656             : }
     657             : 
     658           0 : void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
     659             :                                             uint32_t ssrc) {
     660           0 :   rtc::CritScope lock(&crit_);
     661           0 :   VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
     662           0 :   if (!stats)
     663           0 :     return;
     664             : 
     665           0 :   stats->rtcp_stats = statistics;
     666           0 :   uma_container_->report_block_stats_.Store(statistics, 0, ssrc);
     667             : }
     668             : 
     669           0 : void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {}
     670             : 
     671           0 : void SendStatisticsProxy::DataCountersUpdated(
     672             :     const StreamDataCounters& counters,
     673             :     uint32_t ssrc) {
     674           0 :   rtc::CritScope lock(&crit_);
     675           0 :   VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
     676           0 :   RTC_DCHECK(stats) << "DataCountersUpdated reported for unknown ssrc: "
     677           0 :                     << ssrc;
     678             : 
     679           0 :   if (stats->is_flexfec) {
     680             :     // The same counters are reported for both the media ssrc and flexfec ssrc.
     681             :     // Bitrate stats are summed for all SSRCs. Use fec stats from media update.
     682           0 :     return;
     683             :   }
     684             : 
     685           0 :   stats->rtp_stats = counters;
     686           0 :   if (uma_container_->first_rtp_stats_time_ms_ == -1)
     687           0 :     uma_container_->first_rtp_stats_time_ms_ = clock_->TimeInMilliseconds();
     688             : }
     689             : 
     690           0 : void SendStatisticsProxy::Notify(uint32_t total_bitrate_bps,
     691             :                                  uint32_t retransmit_bitrate_bps,
     692             :                                  uint32_t ssrc) {
     693           0 :   rtc::CritScope lock(&crit_);
     694           0 :   VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
     695           0 :   if (!stats)
     696           0 :     return;
     697             : 
     698           0 :   stats->total_bitrate_bps = total_bitrate_bps;
     699           0 :   stats->retransmit_bitrate_bps = retransmit_bitrate_bps;
     700             : }
     701             : 
     702           0 : void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
     703             :                                             uint32_t ssrc) {
     704           0 :   rtc::CritScope lock(&crit_);
     705           0 :   VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
     706           0 :   if (!stats)
     707           0 :     return;
     708             : 
     709           0 :   stats->frame_counts = frame_counts;
     710             : }
     711             : 
     712           0 : void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
     713             :                                                int max_delay_ms,
     714             :                                                uint32_t ssrc) {
     715           0 :   rtc::CritScope lock(&crit_);
     716           0 :   VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
     717           0 :   if (!stats)
     718           0 :     return;
     719           0 :   stats->avg_delay_ms = avg_delay_ms;
     720           0 :   stats->max_delay_ms = max_delay_ms;
     721             : 
     722           0 :   uma_container_->delay_counter_.Add(avg_delay_ms);
     723           0 :   uma_container_->max_delay_counter_.Add(max_delay_ms);
     724             : }
     725             : 
     726           0 : void SendStatisticsProxy::SampleCounter::Add(int sample) {
     727           0 :   sum += sample;
     728           0 :   ++num_samples;
     729           0 : }
     730             : 
     731           0 : int SendStatisticsProxy::SampleCounter::Avg(
     732             :     int64_t min_required_samples) const {
     733           0 :   if (num_samples < min_required_samples || num_samples == 0)
     734           0 :     return -1;
     735           0 :   return static_cast<int>((sum + (num_samples / 2)) / num_samples);
     736             : }
     737             : 
     738           0 : void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
     739           0 :   if (sample)
     740           0 :     ++sum;
     741           0 :   ++num_samples;
     742           0 : }
     743             : 
     744           0 : void SendStatisticsProxy::BoolSampleCounter::Add(bool sample, int64_t count) {
     745           0 :   if (sample)
     746           0 :     sum += count;
     747           0 :   num_samples += count;
     748           0 : }
     749           0 : int SendStatisticsProxy::BoolSampleCounter::Percent(
     750             :     int64_t min_required_samples) const {
     751           0 :   return Fraction(min_required_samples, 100.0f);
     752             : }
     753             : 
     754           0 : int SendStatisticsProxy::BoolSampleCounter::Permille(
     755             :     int64_t min_required_samples) const {
     756           0 :   return Fraction(min_required_samples, 1000.0f);
     757             : }
     758             : 
     759           0 : int SendStatisticsProxy::BoolSampleCounter::Fraction(
     760             :     int64_t min_required_samples,
     761             :     float multiplier) const {
     762           0 :   if (num_samples < min_required_samples || num_samples == 0)
     763           0 :     return -1;
     764           0 :   return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
     765             : }
     766             : }  // namespace webrtc

Generated by: LCOV version 1.13