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 "api/test/metrics/metric.h"
16 #include "api/test/track_id_stream_info_map.h"
17 #include "rtc_base/checks.h"
18 #include "rtc_base/logging.h"
19 #include "test/pc/e2e/metric_metadata_keys.h"
20
21 namespace webrtc {
22 namespace webrtc_pc_e2e {
23
24 using ::webrtc::test::ImprovementDirection;
25 using ::webrtc::test::Unit;
26
DefaultAudioQualityAnalyzer(test::MetricsLogger * const metrics_logger)27 DefaultAudioQualityAnalyzer::DefaultAudioQualityAnalyzer(
28 test::MetricsLogger* const metrics_logger)
29 : metrics_logger_(metrics_logger) {
30 RTC_CHECK(metrics_logger_);
31 }
32
Start(std::string test_case_name,TrackIdStreamInfoMap * analyzer_helper)33 void DefaultAudioQualityAnalyzer::Start(std::string test_case_name,
34 TrackIdStreamInfoMap* analyzer_helper) {
35 test_case_name_ = std::move(test_case_name);
36 analyzer_helper_ = analyzer_helper;
37 }
38
OnStatsReports(absl::string_view pc_label,const rtc::scoped_refptr<const RTCStatsReport> & report)39 void DefaultAudioQualityAnalyzer::OnStatsReports(
40 absl::string_view pc_label,
41 const rtc::scoped_refptr<const RTCStatsReport>& report) {
42 auto stats = report->GetStatsOfType<RTCInboundRTPStreamStats>();
43
44 for (auto& stat : stats) {
45 if (!stat->kind.is_defined() ||
46 !(*stat->kind == RTCMediaStreamTrackKind::kAudio)) {
47 continue;
48 }
49
50 StatsSample sample;
51 sample.total_samples_received =
52 stat->total_samples_received.ValueOrDefault(0ul);
53 sample.concealed_samples = stat->concealed_samples.ValueOrDefault(0ul);
54 sample.removed_samples_for_acceleration =
55 stat->removed_samples_for_acceleration.ValueOrDefault(0ul);
56 sample.inserted_samples_for_deceleration =
57 stat->inserted_samples_for_deceleration.ValueOrDefault(0ul);
58 sample.silent_concealed_samples =
59 stat->silent_concealed_samples.ValueOrDefault(0ul);
60 sample.jitter_buffer_delay =
61 TimeDelta::Seconds(stat->jitter_buffer_delay.ValueOrDefault(0.));
62 sample.jitter_buffer_target_delay =
63 TimeDelta::Seconds(stat->jitter_buffer_target_delay.ValueOrDefault(0.));
64 sample.jitter_buffer_emitted_count =
65 stat->jitter_buffer_emitted_count.ValueOrDefault(0ul);
66
67 TrackIdStreamInfoMap::StreamInfo stream_info =
68 analyzer_helper_->GetStreamInfoFromTrackId(*stat->track_identifier);
69
70 MutexLock lock(&lock_);
71 stream_info_.emplace(stream_info.stream_label, stream_info);
72 StatsSample prev_sample = last_stats_sample_[stream_info.stream_label];
73 RTC_CHECK_GE(sample.total_samples_received,
74 prev_sample.total_samples_received);
75 double total_samples_diff = static_cast<double>(
76 sample.total_samples_received - prev_sample.total_samples_received);
77 if (total_samples_diff == 0) {
78 return;
79 }
80
81 AudioStreamStats& audio_stream_stats =
82 streams_stats_[stream_info.stream_label];
83 audio_stream_stats.expand_rate.AddSample(
84 (sample.concealed_samples - prev_sample.concealed_samples) /
85 total_samples_diff);
86 audio_stream_stats.accelerate_rate.AddSample(
87 (sample.removed_samples_for_acceleration -
88 prev_sample.removed_samples_for_acceleration) /
89 total_samples_diff);
90 audio_stream_stats.preemptive_rate.AddSample(
91 (sample.inserted_samples_for_deceleration -
92 prev_sample.inserted_samples_for_deceleration) /
93 total_samples_diff);
94
95 int64_t speech_concealed_samples =
96 sample.concealed_samples - sample.silent_concealed_samples;
97 int64_t prev_speech_concealed_samples =
98 prev_sample.concealed_samples - prev_sample.silent_concealed_samples;
99 audio_stream_stats.speech_expand_rate.AddSample(
100 (speech_concealed_samples - prev_speech_concealed_samples) /
101 total_samples_diff);
102
103 int64_t jitter_buffer_emitted_count_diff =
104 sample.jitter_buffer_emitted_count -
105 prev_sample.jitter_buffer_emitted_count;
106 if (jitter_buffer_emitted_count_diff > 0) {
107 TimeDelta jitter_buffer_delay_diff =
108 sample.jitter_buffer_delay - prev_sample.jitter_buffer_delay;
109 TimeDelta jitter_buffer_target_delay_diff =
110 sample.jitter_buffer_target_delay -
111 prev_sample.jitter_buffer_target_delay;
112 audio_stream_stats.average_jitter_buffer_delay_ms.AddSample(
113 jitter_buffer_delay_diff.ms<double>() /
114 jitter_buffer_emitted_count_diff);
115 audio_stream_stats.preferred_buffer_size_ms.AddSample(
116 jitter_buffer_target_delay_diff.ms<double>() /
117 jitter_buffer_emitted_count_diff);
118 }
119
120 last_stats_sample_[stream_info.stream_label] = sample;
121 }
122 }
123
GetTestCaseName(const std::string & stream_label) const124 std::string DefaultAudioQualityAnalyzer::GetTestCaseName(
125 const std::string& stream_label) const {
126 return test_case_name_ + "/" + stream_label;
127 }
128
Stop()129 void DefaultAudioQualityAnalyzer::Stop() {
130 MutexLock lock(&lock_);
131 for (auto& item : streams_stats_) {
132 const TrackIdStreamInfoMap::StreamInfo& stream_info =
133 stream_info_[item.first];
134 std::map<std::string, std::string> metric_metadata{
135 {MetricMetadataKey::kAudioStreamMetadataKey, item.first},
136 {MetricMetadataKey::kPeerMetadataKey, stream_info.receiver_peer},
137 {MetricMetadataKey::kReceiverMetadataKey, stream_info.receiver_peer}};
138
139 metrics_logger_->LogMetric("expand_rate", GetTestCaseName(item.first),
140 item.second.expand_rate, Unit::kUnitless,
141 ImprovementDirection::kSmallerIsBetter,
142 metric_metadata);
143 metrics_logger_->LogMetric("accelerate_rate", GetTestCaseName(item.first),
144 item.second.accelerate_rate, Unit::kUnitless,
145 ImprovementDirection::kSmallerIsBetter,
146 metric_metadata);
147 metrics_logger_->LogMetric("preemptive_rate", GetTestCaseName(item.first),
148 item.second.preemptive_rate, Unit::kUnitless,
149 ImprovementDirection::kSmallerIsBetter,
150 metric_metadata);
151 metrics_logger_->LogMetric(
152 "speech_expand_rate", GetTestCaseName(item.first),
153 item.second.speech_expand_rate, Unit::kUnitless,
154 ImprovementDirection::kSmallerIsBetter, metric_metadata);
155 metrics_logger_->LogMetric(
156 "average_jitter_buffer_delay_ms", GetTestCaseName(item.first),
157 item.second.average_jitter_buffer_delay_ms, Unit::kMilliseconds,
158 ImprovementDirection::kNeitherIsBetter, metric_metadata);
159 metrics_logger_->LogMetric(
160 "preferred_buffer_size_ms", GetTestCaseName(item.first),
161 item.second.preferred_buffer_size_ms, Unit::kMilliseconds,
162 ImprovementDirection::kNeitherIsBetter, metric_metadata);
163 }
164 }
165
166 std::map<std::string, AudioStreamStats>
GetAudioStreamsStats() const167 DefaultAudioQualityAnalyzer::GetAudioStreamsStats() const {
168 MutexLock lock(&lock_);
169 return streams_stats_;
170 }
171
172 } // namespace webrtc_pc_e2e
173 } // namespace webrtc
174