blob: 6ae50a1ceac787dfe54dda717863ef04673cff6a [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/audio/output_glitch_counter.h"
#include <memory>
#include <string>
#include <tuple>
#include "base/check_op.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "media/base/audio_latency.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace audio {
namespace {
const std::string kMissedDeadlineIntervals =
"Media.AudioRendererMissedDeadline3.Intervals";
const std::string kMissedDeadlineMixingIntervals =
"Media.AudioRendererMissedDeadline3.Mixing.Intervals";
const std::string kMissedDeadlineShort =
"Media.AudioRendererMissedDeadline3.Short";
const std::string kMissedDeadlineMixingShort =
"Media.AudioRendererMissedDeadline3.Mixing.Short";
const std::string kAudioGlitches2 = "Media.AudioRendererAudioGlitches2";
class OutputGlitchCounterTest : public ::testing::Test {
public:
OutputGlitchCounterTest() = default;
OutputGlitchCounterTest(const OutputGlitchCounterTest&) = delete;
OutputGlitchCounterTest& operator=(const OutputGlitchCounterTest&) = delete;
base::HistogramTester histogram_tester_;
std::unique_ptr<OutputGlitchCounter> output_glitch_counter_ =
std::make_unique<OutputGlitchCounter>(media::AudioLatency::LATENCY_RTC);
};
TEST_F(OutputGlitchCounterTest, IntervalHistograms) {
// Report 500 non-mixing callbacks, 50 of which are missed.
for (int i = 0; i < 500; i++) {
bool is_mixing = false;
bool missed_callback = i % (500 / 50) == 0;
output_glitch_counter_->ReportMissedCallback(missed_callback, is_mixing);
}
// Report 500 mixing callbacks, 100 of which are missed. This makes 1000 total
// callbacks.
for (int i = 0; i < 500; i++) {
bool is_mixing = true;
bool missed_callback = i % (500 / 100) == 0;
output_glitch_counter_->ReportMissedCallback(missed_callback, is_mixing);
}
histogram_tester_.ExpectUniqueSample(kMissedDeadlineIntervals, 150, 1);
histogram_tester_.ExpectTotalCount(kMissedDeadlineMixingIntervals, 0);
// Report 500 mixing callbacks, 25 of which are missed. This makes 1000
// consecutive mixing callbacks.
for (int i = 0; i < 500; i++) {
bool is_mixing = true;
bool missed_callback = i % (500 / 25) == 0;
output_glitch_counter_->ReportMissedCallback(missed_callback, is_mixing);
}
histogram_tester_.ExpectUniqueSample(kMissedDeadlineIntervals, 150, 1);
histogram_tester_.ExpectUniqueSample(kMissedDeadlineMixingIntervals, 125, 1);
// Report 2000 mixing callbacks, none of which are mixed.
for (int i = 0; i < 2000; i++) {
bool is_mixing = true;
bool missed_callback = false;
output_glitch_counter_->ReportMissedCallback(missed_callback, is_mixing);
}
histogram_tester_.ExpectTotalCount(kMissedDeadlineIntervals, 3);
histogram_tester_.ExpectBucketCount(kMissedDeadlineIntervals, 150, 1);
histogram_tester_.ExpectBucketCount(kMissedDeadlineIntervals, 25, 1);
histogram_tester_.ExpectBucketCount(kMissedDeadlineIntervals, 0, 1);
histogram_tester_.ExpectTotalCount(kMissedDeadlineMixingIntervals, 3);
histogram_tester_.ExpectBucketCount(kMissedDeadlineMixingIntervals, 125, 1);
histogram_tester_.ExpectBucketCount(kMissedDeadlineMixingIntervals, 0, 2);
// Since the stream was at least 1000 callbacks, we do not expect any stats
// for short streams.
output_glitch_counter_.reset();
histogram_tester_.ExpectTotalCount(kMissedDeadlineShort, 0);
histogram_tester_.ExpectTotalCount(kMissedDeadlineMixingShort, 0);
}
TEST_F(OutputGlitchCounterTest, MixingThenStopMixing) {
// Report 500 mixing callbacks, 25 of which are missed.
for (int i = 0; i < 500; i++) {
bool is_mixing = true;
bool missed_callback = i % (500 / 25) == 0;
output_glitch_counter_->ReportMissedCallback(missed_callback, is_mixing);
}
// We report a non-mixing callback. Since we are no longer mixing, we should
// upload the mixign data.
output_glitch_counter_->ReportMissedCallback(/*missed_callback = */ false,
/*is_mixing = */ false);
histogram_tester_.ExpectTotalCount(kMissedDeadlineMixingIntervals, 0);
histogram_tester_.ExpectUniqueSample(kMissedDeadlineMixingShort, 25, 1);
// The sample should not be uploaded again on destruction.
output_glitch_counter_.reset();
histogram_tester_.ExpectUniqueSample(kMissedDeadlineMixingShort, 25, 1);
}
TEST_F(OutputGlitchCounterTest, ShortHistograms) {
// Report 100 non-mixing callbacks, 4 of which are missed.
for (int i = 0; i < 100; i++) {
bool is_mixing = false;
bool missed_callback = i % (100 / 4) == 0;
output_glitch_counter_->ReportMissedCallback(missed_callback, is_mixing);
}
// Report 100 mixing callbacks, 10 of which are missed.
for (int i = 0; i < 100; i++) {
bool is_mixing = true;
bool missed_callback = i % (100 / 10) == 0;
output_glitch_counter_->ReportMissedCallback(missed_callback, is_mixing);
}
// Report a bunch of missed mixing callbacks. These should be considered
// trailing and should not be reflected in the histograms.
for (int i = 0; i < 2000; i++) {
bool is_mixing = true;
bool missed_callback = true;
output_glitch_counter_->ReportMissedCallback(missed_callback, is_mixing);
}
// This histograms should be uploaded upon destruction of
// output_glitch_counter_.
histogram_tester_.ExpectTotalCount(kMissedDeadlineShort, 0);
histogram_tester_.ExpectTotalCount(kMissedDeadlineMixingShort, 0);
output_glitch_counter_.reset();
histogram_tester_.ExpectUniqueSample(kMissedDeadlineShort, 14, 1);
histogram_tester_.ExpectUniqueSample(kMissedDeadlineMixingShort, 10, 1);
// Since the stream was shorter than 1000 callbacks, no interval data should
// be uploaded.
histogram_tester_.ExpectTotalCount(kMissedDeadlineIntervals, 0);
histogram_tester_.ExpectTotalCount(kMissedDeadlineMixingIntervals, 0);
}
TEST_F(OutputGlitchCounterTest, BinaryGlitchMetricTrue) {
output_glitch_counter_->ReportMissedCallback(/*missed_callback = */ true,
/*is_mixing = */ false);
output_glitch_counter_->ReportMissedCallback(/*missed_callback = */ false,
/*is_mixing = */ false);
output_glitch_counter_.reset();
histogram_tester_.ExpectUniqueSample(kAudioGlitches2, 1, 1);
}
TEST_F(OutputGlitchCounterTest, BinaryGlitchMetricFalse) {
output_glitch_counter_->ReportMissedCallback(/*missed_callback = */ false,
/*is_mixing = */ false);
// This missed callback will be considered trailing.
output_glitch_counter_->ReportMissedCallback(/*missed_callback = */ true,
/*is_mixing = */ false);
output_glitch_counter_.reset();
histogram_tester_.ExpectUniqueSample(kAudioGlitches2, 0, 1);
}
TEST_F(OutputGlitchCounterTest, GetLogStats) {
// Report 100 callbacks, 25 of which are missed.
for (int i = 0; i < 100; i++) {
bool is_mixing = i % 3 == 0;
bool missed_callback = i % (100 / 25) == 0;
output_glitch_counter_->ReportMissedCallback(missed_callback, is_mixing);
}
output_glitch_counter_->ReportMissedCallback(true, false);
OutputGlitchCounter::LogStats log_stats =
output_glitch_counter_->GetLogStats();
// The 101th call (a miss) is trailing and should not be counted.
CHECK_EQ(log_stats.callback_count_, 100u);
CHECK_EQ(log_stats.miss_count_, 25u);
}
class OutputGlitchCounterNamesTest
: public ::testing::TestWithParam<
std::tuple<media::AudioLatency::LatencyType, std::string>> {
public:
OutputGlitchCounterNamesTest() = default;
~OutputGlitchCounterNamesTest() override = default;
base::HistogramTester histogram_tester_;
std::unique_ptr<OutputGlitchCounter> output_glitch_counter_;
};
TEST_P(OutputGlitchCounterNamesTest, MetricNames) {
media::AudioLatency::LatencyType latency_type = std::get<0>(GetParam());
std::string suffix = std::get<1>(GetParam());
// Test the short statistics.
output_glitch_counter_ = std::make_unique<OutputGlitchCounter>(latency_type);
for (int i = 0; i < 100; i++) {
bool is_mixing = true;
bool missed_callback = i % (100 / 10) == 0;
output_glitch_counter_->ReportMissedCallback(missed_callback, is_mixing);
}
output_glitch_counter_.reset();
histogram_tester_.ExpectUniqueSample(kMissedDeadlineShort + "." + suffix, 10,
1);
histogram_tester_.ExpectUniqueSample(
kMissedDeadlineMixingShort + "." + suffix, 10, 1);
histogram_tester_.ExpectUniqueSample(kAudioGlitches2 + "." + suffix, 1, 1);
// Test the Interval statistics
output_glitch_counter_ = std::make_unique<OutputGlitchCounter>(latency_type);
for (int i = 0; i < 1000; i++) {
bool is_mixing = true;
bool missed_callback = i % (1000 / 10) == 0;
output_glitch_counter_->ReportMissedCallback(missed_callback, is_mixing);
}
histogram_tester_.ExpectUniqueSample(kMissedDeadlineIntervals + "." + suffix,
10, 1);
histogram_tester_.ExpectUniqueSample(
kMissedDeadlineMixingIntervals + "." + suffix, 10, 1);
}
INSTANTIATE_TEST_SUITE_P(
All,
OutputGlitchCounterNamesTest,
::testing::Values(
std::make_tuple(media::AudioLatency::LATENCY_EXACT_MS,
"LatencyExactMs"),
std::make_tuple(media::AudioLatency::LATENCY_INTERACTIVE,
"LatencyInteractive"),
std::make_tuple(media::AudioLatency::LATENCY_RTC, "LatencyRtc"),
std::make_tuple(media::AudioLatency::LATENCY_PLAYBACK,
"LatencyPlayback"),
std::make_tuple(media::AudioLatency::LATENCY_COUNT, "LatencyUnknown")));
} // namespace
} // namespace audio