1 /*
2 * Copyright (c) 2019 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 "test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.h"
12
13 #include "api/stats/rtc_stats.h"
14 #include "api/stats/rtcstats_objects.h"
15 #include "rtc_base/logging.h"
16
17 namespace webrtc {
18 namespace webrtc_pc_e2e {
19
Start(std::string test_case_name,TrackIdStreamInfoMap * analyzer_helper)20 void DefaultAudioQualityAnalyzer::Start(std::string test_case_name,
21 TrackIdStreamInfoMap* analyzer_helper) {
22 test_case_name_ = std::move(test_case_name);
23 analyzer_helper_ = analyzer_helper;
24 }
25
OnStatsReports(absl::string_view pc_label,const rtc::scoped_refptr<const RTCStatsReport> & report)26 void DefaultAudioQualityAnalyzer::OnStatsReports(
27 absl::string_view pc_label,
28 const rtc::scoped_refptr<const RTCStatsReport>& report) {
29 // TODO(https://crbug.com/webrtc/11683): use "inbound-rtp" instead of "track"
30 // stats when required audio metrics moved there
31 auto stats = report->GetStatsOfType<RTCMediaStreamTrackStats>();
32
33 for (auto& stat : stats) {
34 if (!stat->kind.is_defined() ||
35 !(*stat->kind == RTCMediaStreamTrackKind::kAudio) ||
36 !*stat->remote_source) {
37 continue;
38 }
39
40 StatsSample sample;
41 sample.total_samples_received =
42 stat->total_samples_received.ValueOrDefault(0ul);
43 sample.concealed_samples = stat->concealed_samples.ValueOrDefault(0ul);
44 sample.removed_samples_for_acceleration =
45 stat->removed_samples_for_acceleration.ValueOrDefault(0ul);
46 sample.inserted_samples_for_deceleration =
47 stat->inserted_samples_for_deceleration.ValueOrDefault(0ul);
48 sample.silent_concealed_samples =
49 stat->silent_concealed_samples.ValueOrDefault(0ul);
50 sample.jitter_buffer_delay =
51 TimeDelta::Seconds(stat->jitter_buffer_delay.ValueOrDefault(0.));
52 sample.jitter_buffer_target_delay =
53 TimeDelta::Seconds(stat->jitter_buffer_target_delay.ValueOrDefault(0.));
54 sample.jitter_buffer_emitted_count =
55 stat->jitter_buffer_emitted_count.ValueOrDefault(0ul);
56
57 const std::string stream_label = std::string(
58 analyzer_helper_->GetStreamLabelFromTrackId(*stat->track_identifier));
59
60 MutexLock lock(&lock_);
61 StatsSample prev_sample = last_stats_sample_[stream_label];
62 RTC_CHECK_GE(sample.total_samples_received,
63 prev_sample.total_samples_received);
64 double total_samples_diff = static_cast<double>(
65 sample.total_samples_received - prev_sample.total_samples_received);
66 if (total_samples_diff == 0) {
67 return;
68 }
69
70 AudioStreamStats& audio_stream_stats = streams_stats_[stream_label];
71 audio_stream_stats.expand_rate.AddSample(
72 (sample.concealed_samples - prev_sample.concealed_samples) /
73 total_samples_diff);
74 audio_stream_stats.accelerate_rate.AddSample(
75 (sample.removed_samples_for_acceleration -
76 prev_sample.removed_samples_for_acceleration) /
77 total_samples_diff);
78 audio_stream_stats.preemptive_rate.AddSample(
79 (sample.inserted_samples_for_deceleration -
80 prev_sample.inserted_samples_for_deceleration) /
81 total_samples_diff);
82
83 int64_t speech_concealed_samples =
84 sample.concealed_samples - sample.silent_concealed_samples;
85 int64_t prev_speech_concealed_samples =
86 prev_sample.concealed_samples - prev_sample.silent_concealed_samples;
87 audio_stream_stats.speech_expand_rate.AddSample(
88 (speech_concealed_samples - prev_speech_concealed_samples) /
89 total_samples_diff);
90
91 int64_t jitter_buffer_emitted_count_diff =
92 sample.jitter_buffer_emitted_count -
93 prev_sample.jitter_buffer_emitted_count;
94 if (jitter_buffer_emitted_count_diff > 0) {
95 TimeDelta jitter_buffer_delay_diff =
96 sample.jitter_buffer_delay - prev_sample.jitter_buffer_delay;
97 TimeDelta jitter_buffer_target_delay_diff =
98 sample.jitter_buffer_target_delay -
99 prev_sample.jitter_buffer_target_delay;
100 audio_stream_stats.average_jitter_buffer_delay_ms.AddSample(
101 jitter_buffer_delay_diff.ms<double>() /
102 jitter_buffer_emitted_count_diff);
103 audio_stream_stats.preferred_buffer_size_ms.AddSample(
104 jitter_buffer_target_delay_diff.ms<double>() /
105 jitter_buffer_emitted_count_diff);
106 }
107
108 last_stats_sample_[stream_label] = sample;
109 }
110 }
111
GetTestCaseName(const std::string & stream_label) const112 std::string DefaultAudioQualityAnalyzer::GetTestCaseName(
113 const std::string& stream_label) const {
114 return test_case_name_ + "/" + stream_label;
115 }
116
Stop()117 void DefaultAudioQualityAnalyzer::Stop() {
118 using ::webrtc::test::ImproveDirection;
119 MutexLock lock(&lock_);
120 for (auto& item : streams_stats_) {
121 ReportResult("expand_rate", item.first, item.second.expand_rate, "unitless",
122 ImproveDirection::kSmallerIsBetter);
123 ReportResult("accelerate_rate", item.first, item.second.accelerate_rate,
124 "unitless", ImproveDirection::kSmallerIsBetter);
125 ReportResult("preemptive_rate", item.first, item.second.preemptive_rate,
126 "unitless", ImproveDirection::kSmallerIsBetter);
127 ReportResult("speech_expand_rate", item.first,
128 item.second.speech_expand_rate, "unitless",
129 ImproveDirection::kSmallerIsBetter);
130 ReportResult("average_jitter_buffer_delay_ms", item.first,
131 item.second.average_jitter_buffer_delay_ms, "ms",
132 ImproveDirection::kNone);
133 ReportResult("preferred_buffer_size_ms", item.first,
134 item.second.preferred_buffer_size_ms, "ms",
135 ImproveDirection::kNone);
136 }
137 }
138
139 std::map<std::string, AudioStreamStats>
GetAudioStreamsStats() const140 DefaultAudioQualityAnalyzer::GetAudioStreamsStats() const {
141 MutexLock lock(&lock_);
142 return streams_stats_;
143 }
144
ReportResult(const std::string & metric_name,const std::string & stream_label,const SamplesStatsCounter & counter,const std::string & unit,webrtc::test::ImproveDirection improve_direction) const145 void DefaultAudioQualityAnalyzer::ReportResult(
146 const std::string& metric_name,
147 const std::string& stream_label,
148 const SamplesStatsCounter& counter,
149 const std::string& unit,
150 webrtc::test::ImproveDirection improve_direction) const {
151 test::PrintResultMeanAndError(
152 metric_name, /*modifier=*/"", GetTestCaseName(stream_label),
153 counter.IsEmpty() ? 0 : counter.GetAverage(),
154 counter.IsEmpty() ? 0 : counter.GetStandardDeviation(), unit,
155 /*important=*/false, improve_direction);
156 }
157
158 } // namespace webrtc_pc_e2e
159 } // namespace webrtc
160