tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

statistics_calculator.cc (15738B)


      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 "modules/audio_coding/neteq/statistics_calculator.h"
     12 
     13 #include <algorithm>
     14 #include <cstdint>
     15 #include <cstring>  // memset
     16 
     17 #include "absl/strings/string_view.h"
     18 #include "api/neteq/neteq.h"
     19 #include "api/neteq/tick_timer.h"
     20 #include "rtc_base/checks.h"
     21 #include "rtc_base/numerics/safe_conversions.h"
     22 #include "system_wrappers/include/metrics.h"
     23 
     24 namespace webrtc {
     25 
     26 namespace {
     27 size_t AddIntToSizeTWithLowerCap(int a, size_t b) {
     28  const size_t ret = b + a;
     29  // If a + b is negative, resulting in a negative wrap, cap it to zero instead.
     30  static_assert(sizeof(size_t) >= sizeof(int),
     31                "int must not be wider than size_t for this to work");
     32  return (a < 0 && ret > b) ? 0 : ret;
     33 }
     34 
     35 constexpr int kInterruptionLenMs = 150;
     36 }  // namespace
     37 
     38 // Allocating the static const so that it can be passed by reference to
     39 // RTC_DCHECK.
     40 const size_t StatisticsCalculator::kLenWaitingTimes;
     41 
     42 StatisticsCalculator::PeriodicUmaLogger::PeriodicUmaLogger(
     43    absl::string_view uma_name,
     44    int report_interval_ms,
     45    int max_value)
     46    : uma_name_(uma_name),
     47      report_interval_ms_(report_interval_ms),
     48      max_value_(max_value),
     49      timer_(0) {}
     50 
     51 StatisticsCalculator::PeriodicUmaLogger::~PeriodicUmaLogger() = default;
     52 
     53 void StatisticsCalculator::PeriodicUmaLogger::AdvanceClock(int step_ms) {
     54  timer_ += step_ms;
     55  if (timer_ < report_interval_ms_) {
     56    return;
     57  }
     58  LogToUma(Metric());
     59  Reset();
     60  timer_ -= report_interval_ms_;
     61  RTC_DCHECK_GE(timer_, 0);
     62 }
     63 
     64 void StatisticsCalculator::PeriodicUmaLogger::LogToUma(int value) const {
     65  RTC_HISTOGRAM_COUNTS_SPARSE(uma_name_, value, 1, max_value_, 50);
     66 }
     67 
     68 StatisticsCalculator::PeriodicUmaCount::PeriodicUmaCount(
     69    absl::string_view uma_name,
     70    int report_interval_ms,
     71    int max_value)
     72    : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}
     73 
     74 StatisticsCalculator::PeriodicUmaCount::~PeriodicUmaCount() {
     75  // Log the count for the current (incomplete) interval.
     76  LogToUma(Metric());
     77 }
     78 
     79 void StatisticsCalculator::PeriodicUmaCount::RegisterSample() {
     80  ++counter_;
     81 }
     82 
     83 int StatisticsCalculator::PeriodicUmaCount::Metric() const {
     84  return counter_;
     85 }
     86 
     87 void StatisticsCalculator::PeriodicUmaCount::Reset() {
     88  counter_ = 0;
     89 }
     90 
     91 StatisticsCalculator::PeriodicUmaAverage::PeriodicUmaAverage(
     92    absl::string_view uma_name,
     93    int report_interval_ms,
     94    int max_value)
     95    : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}
     96 
     97 StatisticsCalculator::PeriodicUmaAverage::~PeriodicUmaAverage() {
     98  // Log the average for the current (incomplete) interval.
     99  LogToUma(Metric());
    100 }
    101 
    102 void StatisticsCalculator::PeriodicUmaAverage::RegisterSample(int value) {
    103  sum_ += value;
    104  ++counter_;
    105 }
    106 
    107 int StatisticsCalculator::PeriodicUmaAverage::Metric() const {
    108  return counter_ == 0 ? 0 : static_cast<int>(sum_ / counter_);
    109 }
    110 
    111 void StatisticsCalculator::PeriodicUmaAverage::Reset() {
    112  sum_ = 0.0;
    113  counter_ = 0;
    114 }
    115 
    116 StatisticsCalculator::StatisticsCalculator(TickTimer* tick_timer)
    117    : preemptive_samples_(0),
    118      accelerate_samples_(0),
    119      expanded_speech_samples_(0),
    120      expanded_noise_samples_(0),
    121      timestamps_since_last_report_(0),
    122      secondary_decoded_samples_(0),
    123      discarded_secondary_packets_(0),
    124      delayed_packet_outage_counter_(
    125          "WebRTC.Audio.DelayedPacketOutageEventsPerMinute",
    126          60000,  // 60 seconds report interval.
    127          100),
    128      excess_buffer_delay_("WebRTC.Audio.AverageExcessBufferDelayMs",
    129                           60000,  // 60 seconds report interval.
    130                           1000),
    131      buffer_full_counter_("WebRTC.Audio.JitterBufferFullPerMinute",
    132                           60000,  // 60 seconds report interval.
    133                           100),
    134      expand_uma_logger_("WebRTC.Audio.ExpandRatePercent",
    135                         10,  // Report once every 10 s.
    136                         tick_timer),
    137      speech_expand_uma_logger_("WebRTC.Audio.SpeechExpandRatePercent",
    138                                10,  // Report once every 10 s.
    139                                tick_timer) {}
    140 
    141 StatisticsCalculator::~StatisticsCalculator() = default;
    142 
    143 void StatisticsCalculator::Reset() {
    144  preemptive_samples_ = 0;
    145  accelerate_samples_ = 0;
    146  expanded_speech_samples_ = 0;
    147  expanded_noise_samples_ = 0;
    148  secondary_decoded_samples_ = 0;
    149  discarded_secondary_packets_ = 0;
    150  waiting_times_.clear();
    151 }
    152 
    153 void StatisticsCalculator::ResetMcu() {
    154  timestamps_since_last_report_ = 0;
    155 }
    156 
    157 void StatisticsCalculator::ExpandedVoiceSamples(size_t num_samples,
    158                                                bool is_new_concealment_event) {
    159  if (!decoded_output_played_) {
    160    return;
    161  }
    162  expanded_speech_samples_ += num_samples;
    163  ConcealedSamplesCorrection(dchecked_cast<int>(num_samples), true);
    164  lifetime_stats_.concealment_events += is_new_concealment_event;
    165 }
    166 
    167 void StatisticsCalculator::ExpandedNoiseSamples(size_t num_samples,
    168                                                bool is_new_concealment_event) {
    169  if (!decoded_output_played_) {
    170    return;
    171  }
    172  expanded_noise_samples_ += num_samples;
    173  ConcealedSamplesCorrection(dchecked_cast<int>(num_samples), false);
    174  lifetime_stats_.concealment_events += is_new_concealment_event;
    175 }
    176 
    177 void StatisticsCalculator::ExpandedVoiceSamplesCorrection(int num_samples) {
    178  if (!decoded_output_played_) {
    179    return;
    180  }
    181  expanded_speech_samples_ =
    182      AddIntToSizeTWithLowerCap(num_samples, expanded_speech_samples_);
    183  ConcealedSamplesCorrection(num_samples, true);
    184 }
    185 
    186 void StatisticsCalculator::ExpandedNoiseSamplesCorrection(int num_samples) {
    187  if (!decoded_output_played_) {
    188    return;
    189  }
    190  expanded_noise_samples_ =
    191      AddIntToSizeTWithLowerCap(num_samples, expanded_noise_samples_);
    192  ConcealedSamplesCorrection(num_samples, false);
    193 }
    194 
    195 void StatisticsCalculator::DecodedOutputPlayed() {
    196  decoded_output_played_ = true;
    197 }
    198 
    199 void StatisticsCalculator::EndExpandEvent(int fs_hz) {
    200  if (!decoded_output_played_) {
    201    return;
    202  }
    203  RTC_DCHECK_GE(lifetime_stats_.concealed_samples,
    204                concealed_samples_at_event_end_);
    205  const int event_duration_ms =
    206      1000 *
    207      (lifetime_stats_.concealed_samples - concealed_samples_at_event_end_) /
    208      fs_hz;
    209  if (event_duration_ms >= kInterruptionLenMs && decoded_output_played_) {
    210    lifetime_stats_.interruption_count++;
    211    lifetime_stats_.total_interruption_duration_ms += event_duration_ms;
    212    RTC_HISTOGRAM_COUNTS("WebRTC.Audio.AudioInterruptionMs", event_duration_ms,
    213                         /*min=*/150, /*max=*/5000, /*bucket_count=*/50);
    214  }
    215  concealed_samples_at_event_end_ = lifetime_stats_.concealed_samples;
    216 }
    217 
    218 void StatisticsCalculator::ConcealedSamplesCorrection(int num_samples,
    219                                                      bool is_voice) {
    220  if (!decoded_output_played_) {
    221    return;
    222  }
    223  if (num_samples < 0) {
    224    // Store negative correction to subtract from future positive additions.
    225    // See also the function comment in the header file.
    226    concealed_samples_correction_ -= num_samples;
    227    if (!is_voice) {
    228      silent_concealed_samples_correction_ -= num_samples;
    229    }
    230    return;
    231  }
    232 
    233  const size_t canceled_out =
    234      std::min(static_cast<size_t>(num_samples), concealed_samples_correction_);
    235  concealed_samples_correction_ -= canceled_out;
    236  lifetime_stats_.concealed_samples += num_samples - canceled_out;
    237 
    238  if (!is_voice) {
    239    const size_t silent_canceled_out = std::min(
    240        static_cast<size_t>(num_samples), silent_concealed_samples_correction_);
    241    silent_concealed_samples_correction_ -= silent_canceled_out;
    242    lifetime_stats_.silent_concealed_samples +=
    243        num_samples - silent_canceled_out;
    244  }
    245 }
    246 
    247 void StatisticsCalculator::PreemptiveExpandedSamples(size_t num_samples) {
    248  if (!decoded_output_played_) {
    249    return;
    250  }
    251  preemptive_samples_ += num_samples;
    252  operations_and_state_.preemptive_samples += num_samples;
    253  lifetime_stats_.inserted_samples_for_deceleration += num_samples;
    254 }
    255 
    256 void StatisticsCalculator::AcceleratedSamples(size_t num_samples) {
    257  if (!decoded_output_played_) {
    258    return;
    259  }
    260  accelerate_samples_ += num_samples;
    261  operations_and_state_.accelerate_samples += num_samples;
    262  lifetime_stats_.removed_samples_for_acceleration += num_samples;
    263 }
    264 
    265 void StatisticsCalculator::GeneratedNoiseSamples(size_t num_samples) {
    266  if (!decoded_output_played_) {
    267    return;
    268  }
    269  lifetime_stats_.generated_noise_samples += num_samples;
    270 }
    271 
    272 void StatisticsCalculator::PacketsDiscarded(size_t num_packets) {
    273  lifetime_stats_.packets_discarded += num_packets;
    274 }
    275 
    276 void StatisticsCalculator::SecondaryPacketsDiscarded(size_t num_packets) {
    277  discarded_secondary_packets_ += num_packets;
    278  lifetime_stats_.fec_packets_discarded += num_packets;
    279 }
    280 
    281 void StatisticsCalculator::SecondaryPacketsReceived(size_t num_packets) {
    282  lifetime_stats_.fec_packets_received += num_packets;
    283 }
    284 
    285 void StatisticsCalculator::IncreaseCounter(size_t num_samples, int fs_hz) {
    286  if (!decoded_output_played_) {
    287    return;
    288  }
    289  const int time_step_ms =
    290      CheckedDivExact(static_cast<int>(1000 * num_samples), fs_hz);
    291  delayed_packet_outage_counter_.AdvanceClock(time_step_ms);
    292  excess_buffer_delay_.AdvanceClock(time_step_ms);
    293  buffer_full_counter_.AdvanceClock(time_step_ms);
    294  timestamps_since_last_report_ += static_cast<uint32_t>(num_samples);
    295  if (timestamps_since_last_report_ >
    296      static_cast<uint32_t>(fs_hz * kMaxReportPeriod)) {
    297    timestamps_since_last_report_ = 0;
    298  }
    299  lifetime_stats_.total_samples_received += num_samples;
    300  expand_uma_logger_.UpdateSampleCounter(lifetime_stats_.concealed_samples,
    301                                         fs_hz);
    302  uint64_t speech_concealed_samples = 0;
    303  if (lifetime_stats_.concealed_samples >
    304      lifetime_stats_.silent_concealed_samples) {
    305    speech_concealed_samples = lifetime_stats_.concealed_samples -
    306                               lifetime_stats_.silent_concealed_samples;
    307  }
    308  speech_expand_uma_logger_.UpdateSampleCounter(speech_concealed_samples,
    309                                                fs_hz);
    310 }
    311 
    312 void StatisticsCalculator::JitterBufferDelay(size_t num_samples,
    313                                             uint64_t waiting_time_ms,
    314                                             uint64_t target_delay_ms,
    315                                             uint64_t unlimited_target_delay_ms,
    316                                             uint64_t processing_delay_us) {
    317  lifetime_stats_.jitter_buffer_delay_ms += waiting_time_ms * num_samples;
    318  lifetime_stats_.jitter_buffer_target_delay_ms +=
    319      target_delay_ms * num_samples;
    320  lifetime_stats_.jitter_buffer_minimum_delay_ms +=
    321      unlimited_target_delay_ms * num_samples;
    322  lifetime_stats_.jitter_buffer_emitted_count += num_samples;
    323  lifetime_stats_.total_processing_delay_us +=
    324      num_samples * processing_delay_us;
    325 }
    326 
    327 void StatisticsCalculator::SecondaryDecodedSamples(int num_samples) {
    328  secondary_decoded_samples_ += num_samples;
    329 }
    330 
    331 void StatisticsCalculator::FlushedPacketBuffer() {
    332  operations_and_state_.packet_buffer_flushes++;
    333  buffer_full_counter_.RegisterSample();
    334 }
    335 
    336 void StatisticsCalculator::ReceivedPacket() {
    337  ++lifetime_stats_.jitter_buffer_packets_received;
    338 }
    339 
    340 void StatisticsCalculator::RelativePacketArrivalDelay(size_t delay_ms) {
    341  lifetime_stats_.relative_packet_arrival_delay_ms += delay_ms;
    342 }
    343 
    344 void StatisticsCalculator::LogDelayedPacketOutageEvent(int num_samples,
    345                                                       int fs_hz) {
    346  int outage_duration_ms = num_samples / (fs_hz / 1000);
    347  RTC_HISTOGRAM_COUNTS("WebRTC.Audio.DelayedPacketOutageEventMs",
    348                       outage_duration_ms, 1 /* min */, 2000 /* max */,
    349                       100 /* bucket count */);
    350  delayed_packet_outage_counter_.RegisterSample();
    351  lifetime_stats_.delayed_packet_outage_samples += num_samples;
    352  ++lifetime_stats_.delayed_packet_outage_events;
    353 }
    354 
    355 void StatisticsCalculator::StoreWaitingTime(int waiting_time_ms) {
    356  excess_buffer_delay_.RegisterSample(waiting_time_ms);
    357  RTC_DCHECK_LE(waiting_times_.size(), kLenWaitingTimes);
    358  if (waiting_times_.size() == kLenWaitingTimes) {
    359    // Erase first value.
    360    waiting_times_.pop_front();
    361  }
    362  waiting_times_.push_back(waiting_time_ms);
    363  operations_and_state_.last_waiting_time_ms = waiting_time_ms;
    364 }
    365 
    366 void StatisticsCalculator::GetNetworkStatistics(size_t samples_per_packet,
    367                                                NetEqNetworkStatistics* stats) {
    368  RTC_DCHECK(stats);
    369 
    370  stats->accelerate_rate =
    371      CalculateQ14Ratio(accelerate_samples_, timestamps_since_last_report_);
    372 
    373  stats->preemptive_rate =
    374      CalculateQ14Ratio(preemptive_samples_, timestamps_since_last_report_);
    375 
    376  stats->expand_rate =
    377      CalculateQ14Ratio(expanded_speech_samples_ + expanded_noise_samples_,
    378                        timestamps_since_last_report_);
    379 
    380  stats->speech_expand_rate = CalculateQ14Ratio(expanded_speech_samples_,
    381                                                timestamps_since_last_report_);
    382 
    383  stats->secondary_decoded_rate = CalculateQ14Ratio(
    384      secondary_decoded_samples_, timestamps_since_last_report_);
    385 
    386  const size_t discarded_secondary_samples =
    387      discarded_secondary_packets_ * samples_per_packet;
    388  stats->secondary_discarded_rate =
    389      CalculateQ14Ratio(discarded_secondary_samples,
    390                        static_cast<uint32_t>(discarded_secondary_samples +
    391                                              secondary_decoded_samples_));
    392 
    393  if (waiting_times_.empty()) {
    394    stats->mean_waiting_time_ms = -1;
    395    stats->median_waiting_time_ms = -1;
    396    stats->min_waiting_time_ms = -1;
    397    stats->max_waiting_time_ms = -1;
    398  } else {
    399    std::sort(waiting_times_.begin(), waiting_times_.end());
    400    // Find mid-point elements. If the size is odd, the two values
    401    // `middle_left` and `middle_right` will both be the one middle element; if
    402    // the size is even, they will be the the two neighboring elements at the
    403    // middle of the list.
    404    const int middle_left = waiting_times_[(waiting_times_.size() - 1) / 2];
    405    const int middle_right = waiting_times_[waiting_times_.size() / 2];
    406    // Calculate the average of the two. (Works also for odd sizes.)
    407    stats->median_waiting_time_ms = (middle_left + middle_right) / 2;
    408    stats->min_waiting_time_ms = waiting_times_.front();
    409    stats->max_waiting_time_ms = waiting_times_.back();
    410    double sum = 0;
    411    for (auto time : waiting_times_) {
    412      sum += time;
    413    }
    414    stats->mean_waiting_time_ms = static_cast<int>(sum / waiting_times_.size());
    415  }
    416 
    417  // Reset counters.
    418  ResetMcu();
    419  Reset();
    420 }
    421 
    422 NetEqLifetimeStatistics StatisticsCalculator::GetLifetimeStatistics() const {
    423  return lifetime_stats_;
    424 }
    425 
    426 NetEqOperationsAndState StatisticsCalculator::GetOperationsAndState() const {
    427  return operations_and_state_;
    428 }
    429 
    430 uint16_t StatisticsCalculator::CalculateQ14Ratio(size_t numerator,
    431                                                 uint32_t denominator) {
    432  if (numerator == 0) {
    433    return 0;
    434  } else if (numerator < denominator) {
    435    // Ratio must be smaller than 1 in Q14.
    436    RTC_DCHECK_LT((numerator << 14) / denominator, (1 << 14));
    437    return static_cast<uint16_t>((numerator << 14) / denominator);
    438  } else {
    439    // Will not produce a ratio larger than 1, since this is probably an error.
    440    return 1 << 14;
    441  }
    442 }
    443 
    444 }  // namespace webrtc