Files
platform-external-webrtc/webrtc/modules/audio_coding/neteq/statistics_calculator.cc
Henrik Lundin 1f4ffe02fb NetEq: Implement two UMA stats for delay adaptation.
This CL adds calculation and logging of average excess buffer delay
and number of delayed packet outage events per minute.

The first is the average of time spent in the packet buffer for all
packets. The average is calculated for intervals of one minute, and
the result is logged to the UMA stat
WebRTC.Audio.AverageExcessBufferDelayMs.

The second is a counter of delayed packet outage events that is
restarted every minute, and the result is logged to the UMA stat
WebRTC.Audio.DelayedPacketOutageEventsPerMinute. For a description of
delayed packet outages, see previous CL implementing a duration log
for these events.

BUG=webrtc:4915, chromium:488124
R=minyue@webrtc.org

Review URL: https://codereview.webrtc.org/1287333005 .

Cr-Commit-Position: refs/heads/master@{#9731}
2015-08-19 08:47:00 +00:00

283 lines
8.5 KiB
C++

/*
* 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 "webrtc/modules/audio_coding/neteq/statistics_calculator.h"
#include <assert.h>
#include <string.h> // memset
#include "webrtc/base/checks.h"
#include "webrtc/modules/audio_coding/neteq/decision_logic.h"
#include "webrtc/modules/audio_coding/neteq/delay_manager.h"
#include "webrtc/system_wrappers/interface/metrics.h"
namespace webrtc {
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_;
DCHECK_GE(timer_, 0);
}
void StatisticsCalculator::PeriodicUmaLogger::LogToUma(int value) const {
RTC_HISTOGRAM_COUNTS(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 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),
len_waiting_times_(0),
next_waiting_time_index_(0),
secondary_decoded_samples_(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) {
memset(waiting_times_, 0, kLenWaitingTimes * sizeof(waiting_times_[0]));
}
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;
}
void StatisticsCalculator::ResetMcu() {
discarded_packets_ = 0;
lost_timestamps_ = 0;
timestamps_since_last_report_ = 0;
}
void StatisticsCalculator::ResetWaitingTimeStatistics() {
memset(waiting_times_, 0, kLenWaitingTimes * sizeof(waiting_times_[0]));
len_waiting_times_ = 0;
next_waiting_time_index_ = 0;
}
void StatisticsCalculator::ExpandedVoiceSamples(int num_samples) {
expanded_speech_samples_ += num_samples;
}
void StatisticsCalculator::ExpandedNoiseSamples(int num_samples) {
expanded_noise_samples_ += num_samples;
}
void StatisticsCalculator::PreemptiveExpandedSamples(int num_samples) {
preemptive_samples_ += num_samples;
}
void StatisticsCalculator::AcceleratedSamples(int num_samples) {
accelerate_samples_ += num_samples;
}
void StatisticsCalculator::AddZeros(int num_samples) {
added_zero_samples_ += num_samples;
}
void StatisticsCalculator::PacketsDiscarded(int num_packets) {
discarded_packets_ += num_packets;
}
void StatisticsCalculator::LostSamples(int num_samples) {
lost_timestamps_ += num_samples;
}
void StatisticsCalculator::IncreaseCounter(int num_samples, int fs_hz) {
const int time_step_ms = rtc::CheckedDivExact(1000 * num_samples, fs_hz);
delayed_packet_outage_counter_.AdvanceClock(time_step_ms);
excess_buffer_delay_.AdvanceClock(time_step_ms);
timestamps_since_last_report_ += static_cast<uint32_t>(num_samples);
if (timestamps_since_last_report_ >
static_cast<uint32_t>(fs_hz * kMaxReportPeriod)) {
lost_timestamps_ = 0;
timestamps_since_last_report_ = 0;
discarded_packets_ = 0;
}
}
void StatisticsCalculator::SecondaryDecodedSamples(int num_samples) {
secondary_decoded_samples_ += num_samples;
}
void StatisticsCalculator::LogDelayedPacketOutageEvent(int outage_duration_ms) {
RTC_HISTOGRAM_COUNTS("WebRTC.Audio.DelayedPacketOutageEventMs",
outage_duration_ms, 1 /* min */, 2000 /* max */,
100 /* bucket count */);
delayed_packet_outage_counter_.RegisterSample();
}
void StatisticsCalculator::StoreWaitingTime(int waiting_time_ms) {
excess_buffer_delay_.RegisterSample(waiting_time_ms);
assert(next_waiting_time_index_ < kLenWaitingTimes);
waiting_times_[next_waiting_time_index_] = waiting_time_ms;
next_waiting_time_index_++;
if (next_waiting_time_index_ >= kLenWaitingTimes) {
next_waiting_time_index_ = 0;
}
if (len_waiting_times_ < kLenWaitingTimes) {
len_waiting_times_++;
}
}
void StatisticsCalculator::GetNetworkStatistics(
int fs_hz,
int num_samples_in_buffers,
int samples_per_packet,
const DelayManager& delay_manager,
const DecisionLogic& decision_logic,
NetEqNetworkStatistics *stats) {
if (fs_hz <= 0 || !stats) {
assert(false);
return;
}
stats->added_zero_samples = added_zero_samples_;
stats->current_buffer_size_ms =
static_cast<uint16_t>(num_samples_in_buffers * 1000 / fs_hz);
const int ms_per_packet = decision_logic.packet_length_samples() /
(fs_hz / 1000);
stats->preferred_buffer_size_ms = (delay_manager.TargetLevel() >> 8) *
ms_per_packet;
stats->jitter_peaks_found = delay_manager.PeakFound();
stats->clockdrift_ppm = delay_manager.AverageIAT();
stats->packet_loss_rate =
CalculateQ14Ratio(lost_timestamps_, timestamps_since_last_report_);
const unsigned discarded_samples = discarded_packets_ * samples_per_packet;
stats->packet_discard_rate =
CalculateQ14Ratio(discarded_samples, timestamps_since_last_report_);
stats->accelerate_rate =
CalculateQ14Ratio(accelerate_samples_, timestamps_since_last_report_);
stats->preemptive_rate =
CalculateQ14Ratio(preemptive_samples_, timestamps_since_last_report_);
stats->expand_rate =
CalculateQ14Ratio(expanded_speech_samples_ + expanded_noise_samples_,
timestamps_since_last_report_);
stats->speech_expand_rate =
CalculateQ14Ratio(expanded_speech_samples_,
timestamps_since_last_report_);
stats->secondary_decoded_rate =
CalculateQ14Ratio(secondary_decoded_samples_,
timestamps_since_last_report_);
// Reset counters.
ResetMcu();
Reset();
}
void StatisticsCalculator::WaitingTimes(std::vector<int>* waiting_times) {
if (!waiting_times) {
return;
}
waiting_times->assign(waiting_times_, waiting_times_ + len_waiting_times_);
ResetWaitingTimeStatistics();
}
uint16_t StatisticsCalculator::CalculateQ14Ratio(uint32_t numerator,
uint32_t denominator) {
if (numerator == 0) {
return 0;
} else if (numerator < denominator) {
// Ratio must be smaller than 1 in Q14.
assert((numerator << 14) / denominator < (1 << 14));
return static_cast<uint16_t>((numerator << 14) / denominator);
} else {
// Will not produce a ratio larger than 1, since this is probably an error.
return 1 << 14;
}
}
} // namespace webrtc