<commit_before>/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "modules/audio_coding/neteq/statistics_calculator.h"

#include <assert.h>
#include <string.h>  // memset

#include <algorithm>

#include "modules/audio_coding/neteq/delay_manager.h"
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "system_wrappers/include/metrics.h"

namespace webrtc {

namespace {
size_t AddIntToSizeTWithLowerCap(int a, size_t b) {
  const size_t ret = b + a;
  // If a + b is negative, resulting in a negative wrap, cap it to zero instead.
  static_assert(sizeof(size_t) >= sizeof(int),
                "int must not be wider than size_t for this to work");
  return (a < 0 && ret > b) ? 0 : ret;
}

constexpr int kInterruptionLenMs = 150;
}  // namespace

// Allocating the static const so that it can be passed by reference to
// RTC_DCHECK.
const size_t StatisticsCalculator::kLenWaitingTimes;

StatisticsCalculator::PeriodicUmaLogger::PeriodicUmaLogger(
    const std::string& uma_name,
    int report_interval_ms,
    int max_value)
    : uma_name_(uma_name),
      report_interval_ms_(report_interval_ms),
      max_value_(max_value),
      timer_(0) {}

StatisticsCalculator::PeriodicUmaLogger::~PeriodicUmaLogger() = default;

void StatisticsCalculator::PeriodicUmaLogger::AdvanceClock(int step_ms) {
  timer_ += step_ms;
  if (timer_ < report_interval_ms_) {
    return;
  }
  LogToUma(Metric());
  Reset();
  timer_ -= report_interval_ms_;
  RTC_DCHECK_GE(timer_, 0);
}

void StatisticsCalculator::PeriodicUmaLogger::LogToUma(int value) const {
  RTC_HISTOGRAM_COUNTS_SPARSE(uma_name_, value, 1, max_value_, 50);
}

StatisticsCalculator::PeriodicUmaCount::PeriodicUmaCount(
    const std::string& uma_name,
    int report_interval_ms,
    int max_value)
    : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}

StatisticsCalculator::PeriodicUmaCount::~PeriodicUmaCount() {
  // Log the count for the current (incomplete) interval.
  LogToUma(Metric());
}

void StatisticsCalculator::PeriodicUmaCount::RegisterSample() {
  ++counter_;
}

int StatisticsCalculator::PeriodicUmaCount::Metric() const {
  return counter_;
}

void StatisticsCalculator::PeriodicUmaCount::Reset() {
  counter_ = 0;
}

StatisticsCalculator::PeriodicUmaAverage::PeriodicUmaAverage(
    const std::string& uma_name,
    int report_interval_ms,
    int max_value)
    : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}

StatisticsCalculator::PeriodicUmaAverage::~PeriodicUmaAverage() {
  // Log the average for the current (incomplete) interval.
  LogToUma(Metric());
}

void StatisticsCalculator::PeriodicUmaAverage::RegisterSample(int value) {
  sum_ += value;
  ++counter_;
}

int StatisticsCalculator::PeriodicUmaAverage::Metric() const {
  return counter_ == 0 ? 0 : static_cast<int>(sum_ / counter_);
}

void StatisticsCalculator::PeriodicUmaAverage::Reset() {
  sum_ = 0.0;
  counter_ = 0;
}

StatisticsCalculator::StatisticsCalculator()
    : preemptive_samples_(0),
      accelerate_samples_(0),
      added_zero_samples_(0),
      expanded_speech_samples_(0),
      expanded_noise_samples_(0),
      discarded_packets_(0),
      lost_timestamps_(0),
      timestamps_since_last_report_(0),
      secondary_decoded_samples_(0),
      discarded_secondary_packets_(0),
      delayed_packet_outage_counter_(
          "WebRTC.Audio.DelayedPacketOutageEventsPerMinute",
          60000,  // 60 seconds report interval.
          100),
      excess_buffer_delay_("WebRTC.Audio.AverageExcessBufferDelayMs",
                           60000,  // 60 seconds report interval.
                           1000),
      buffer_full_counter_("WebRTC.Audio.JitterBufferFullPerMinute",
                           60000,  // 60 seconds report interval.
                           100) {}

StatisticsCalculator::~StatisticsCalculator() = default;

void StatisticsCalculator::Reset() {
  preemptive_samples_ = 0;
  accelerate_samples_ = 0;
  added_zero_samples_ = 0;
  expanded_speech_samples_ = 0;
  expanded_noise_samples_ = 0;
  secondary_decoded_samples_ = 0;
  discarded_secondary_packets_ = 0;
  waiting_times_.clear();
}

void StatisticsCalculator::ResetMcu() {
  discarded_packets_ = 0;
  lost_timestamps_ = 0;
  timestamps_since_last_report_ = 0;
}

void StatisticsCalculator::ExpandedVoiceSamples(size_t num_samples,
                                                bool is_new_concealment_event) {
  expanded_speech_samples_ += num_samples;
  ConcealedSamplesCorrection(rtc::dchecked_cast<int>(num_samples), true);
  lifetime_stats_.concealment_events += is_new_concealment_event;
}

void StatisticsCalculator::ExpandedNoiseSamples(size_t num_samples,
                                                bool is_new_concealment_event) {
  expanded_noise_samples_ += num_samples;
  ConcealedSamplesCorrection(rtc::dchecked_cast<int>(num_samples), false);
  lifetime_stats_.concealment_events += is_new_concealment_event;
}

void StatisticsCalculator::ExpandedVoiceSamplesCorrection(int num_samples) {
  expanded_speech_samples_ =
      AddIntToSizeTWithLowerCap(num_samples, expanded_speech_samples_);
  ConcealedSamplesCorrection(num_samples, true);
}

void StatisticsCalculator::ExpandedNoiseSamplesCorrection(int num_samples) {
  expanded_noise_samples_ =
      AddIntToSizeTWithLowerCap(num_samples, expanded_noise_samples_);
  ConcealedSamplesCorrection(num_samples, false);
}

void StatisticsCalculator::DecodedOutputPlayed() {
  decoded_output_played_ = true;
}

void StatisticsCalculator::EndExpandEvent(int fs_hz) {
  RTC_DCHECK_GE(lifetime_stats_.concealed_samples,
                concealed_samples_at_event_end_);
  const int event_duration_ms =
      1000 *
      (lifetime_stats_.concealed_samples - concealed_samples_at_event_end_) /
      fs_hz;
  if (event_duration_ms >= kInterruptionLenMs && decoded_output_played_) {
    lifetime_stats_.interruption_count++;
    lifetime_stats_.total_interruption_duration_ms += event_duration_ms;
  }
  concealed_samples_at_event_end_ = lifetime_stats_.concealed_samples;
}

void StatisticsCalculator::ConcealedSamplesCorrection(int num_samples,
                                                      bool is_voice) {
  if (num_samples < 0) {
    // Store negative correction to subtract from future positive additions.
    // See also the function comment in the header file.
    concealed_samples_correction_ -= num_samples;
    if (!is_voice) {
      silent_concealed_samples_correction_ -= num_samples;<commit_msg>Add UMA counter for audio interruptions<commit_after>/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "modules/audio_coding/neteq/statistics_calculator.h"

#include <assert.h>
#include <string.h>  // memset

#include <algorithm>

#include "modules/audio_coding/neteq/delay_manager.h"
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "system_wrappers/include/metrics.h"

namespace webrtc {

namespace {
size_t AddIntToSizeTWithLowerCap(int a, size_t b) {
  const size_t ret = b + a;
  // If a + b is negative, resulting in a negative wrap, cap it to zero instead.
  static_assert(sizeof(size_t) >= sizeof(int),
                "int must not be wider than size_t for this to work");
  return (a < 0 && ret > b) ? 0 : ret;
}

constexpr int kInterruptionLenMs = 150;
}  // namespace

// Allocating the static const so that it can be passed by reference to
// RTC_DCHECK.
const size_t StatisticsCalculator::kLenWaitingTimes;

StatisticsCalculator::PeriodicUmaLogger::PeriodicUmaLogger(
    const std::string& uma_name,
    int report_interval_ms,
    int max_value)
    : uma_name_(uma_name),
      report_interval_ms_(report_interval_ms),
      max_value_(max_value),
      timer_(0) {}

StatisticsCalculator::PeriodicUmaLogger::~PeriodicUmaLogger() = default;

void StatisticsCalculator::PeriodicUmaLogger::AdvanceClock(int step_ms) {
  timer_ += step_ms;
  if (timer_ < report_interval_ms_) {
    return;
  }
  LogToUma(Metric());
  Reset();
  timer_ -= report_interval_ms_;
  RTC_DCHECK_GE(timer_, 0);
}

void StatisticsCalculator::PeriodicUmaLogger::LogToUma(int value) const {
  RTC_HISTOGRAM_COUNTS_SPARSE(uma_name_, value, 1, max_value_, 50);
}

StatisticsCalculator::PeriodicUmaCount::PeriodicUmaCount(
    const std::string& uma_name,
    int report_interval_ms,
    int max_value)
    : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}

StatisticsCalculator::PeriodicUmaCount::~PeriodicUmaCount() {
  // Log the count for the current (incomplete) interval.
  LogToUma(Metric());
}

void StatisticsCalculator::PeriodicUmaCount::RegisterSample() {
  ++counter_;
}

int StatisticsCalculator::PeriodicUmaCount::Metric() const {
  return counter_;
}

void StatisticsCalculator::PeriodicUmaCount::Reset() {
  counter_ = 0;
}

StatisticsCalculator::PeriodicUmaAverage::PeriodicUmaAverage(
    const std::string& uma_name,
    int report_interval_ms,
    int max_value)
    : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}

StatisticsCalculator::PeriodicUmaAverage::~PeriodicUmaAverage() {
  // Log the average for the current (incomplete) interval.
  LogToUma(Metric());
}

void StatisticsCalculator::PeriodicUmaAverage::RegisterSample(int value) {
  sum_ += value;
  ++counter_;
}

int StatisticsCalculator::PeriodicUmaAverage::Metric() const {
  return counter_ == 0 ? 0 : static_cast<int>(sum_ / counter_);
}

void StatisticsCalculator::PeriodicUmaAverage::Reset() {
  sum_ = 0.0;
  counter_ = 0;
}

StatisticsCalculator::StatisticsCalculator()
    : preemptive_samples_(0),
      accelerate_samples_(0),
      added_zero_samples_(0),
      expanded_speech_samples_(0),
      expanded_noise_samples_(0),
      discarded_packets_(0),
      lost_timestamps_(0),
      timestamps_since_last_report_(0),
      secondary_decoded_samples_(0),
      discarded_secondary_packets_(0),
      delayed_packet_outage_counter_(
          "WebRTC.Audio.DelayedPacketOutageEventsPerMinute",
          60000,  // 60 seconds report interval.
          100),
      excess_buffer_delay_("WebRTC.Audio.AverageExcessBufferDelayMs",
                           60000,  // 60 seconds report interval.
                           1000),
      buffer_full_counter_("WebRTC.Audio.JitterBufferFullPerMinute",
                           60000,  // 60 seconds report interval.
                           100) {}

StatisticsCalculator::~StatisticsCalculator() = default;

void StatisticsCalculator::Reset() {
  preemptive_samples_ = 0;
  accelerate_samples_ = 0;
  added_zero_samples_ = 0;
  expanded_speech_samples_ = 0;
  expanded_noise_samples_ = 0;
  secondary_decoded_samples_ = 0;
  discarded_secondary_packets_ = 0;
  waiting_times_.clear();
}

void StatisticsCalculator::ResetMcu() {
  discarded_packets_ = 0;
  lost_timestamps_ = 0;
  timestamps_since_last_report_ = 0;
}

void StatisticsCalculator::ExpandedVoiceSamples(size_t num_samples,
                                                bool is_new_concealment_event) {
  expanded_speech_samples_ += num_samples;
  ConcealedSamplesCorrection(rtc::dchecked_cast<int>(num_samples), true);
  lifetime_stats_.concealment_events += is_new_concealment_event;
}

void StatisticsCalculator::ExpandedNoiseSamples(size_t num_samples,
                                                bool is_new_concealment_event) {
  expanded_noise_samples_ += num_samples;
  ConcealedSamplesCorrection(rtc::dchecked_cast<int>(num_samples), false);
  lifetime_stats_.concealment_events += is_new_concealment_event;
}

void StatisticsCalculator::ExpandedVoiceSamplesCorrection(int num_samples) {
  expanded_speech_samples_ =
      AddIntToSizeTWithLowerCap(num_samples, expanded_speech_samples_);
  ConcealedSamplesCorrection(num_samples, true);
}

void StatisticsCalculator::ExpandedNoiseSamplesCorrection(int num_samples) {
  expanded_noise_samples_ =
      AddIntToSizeTWithLowerCap(num_samples, expanded_noise_samples_);
  ConcealedSamplesCorrection(num_samples, false);
}

void StatisticsCalculator::DecodedOutputPlayed() {
  decoded_output_played_ = true;
}

void StatisticsCalculator::EndExpandEvent(int fs_hz) {
  RTC_DCHECK_GE(lifetime_stats_.concealed_samples,
                concealed_samples_at_event_end_);
  const int event_duration_ms =
      1000 *
      (lifetime_stats_.concealed_samples - concealed_samples_at_event_end_) /
      fs_hz;
  if (event_duration_ms >= kInterruptionLenMs && decoded_output_played_) {
    lifetime_stats_.interruption_count++;
    lifetime_stats_.total_interruption_duration_ms += event_duration_ms;
    RTC_HISTOGRAM_COUNTS("WebRTC.Audio.AudioInterruptionMs", event_duration_ms,
                         /*min=*/150, /*max=*/5000, /*bucket_count=*/50);
  }
  concealed_samples_at_event_end_ = lifetime_stats_.concealed_samples;
}

void StatisticsCalculator::ConcealedSamplesCorrection(int num_samples,
                                                      bool is_voice) {
  if (num_samples < 0) {
    // Store negative correction to subtract from future positive additions.
    // See also the function comment in the header file.
    concealed_samples_correction_ -= num_samples;
    if (!is_voice) {
      silent_concealed_samples_correction_ -= num_samples;
{'fraction_non_alphanumeric': 0.0896551724137931, 'fraction_numerical': 0.011566091954022988, 'mean_word_length': 4.209955089820359, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2646294', 'n_tokens_mistral': 4569, 'n_tokens_neox': 4336, 'n_words': 855}