OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/video/receive_statistics_proxy.h" | 11 #include "webrtc/video/receive_statistics_proxy.h" |
12 | 12 |
13 #include <algorithm> | 13 #include <algorithm> |
14 #include <cmath> | 14 #include <cmath> |
| 15 #include <sstream> |
15 #include <utility> | 16 #include <utility> |
16 | 17 |
| 18 #include "webrtc/modules/pacing/alr_detector.h" |
17 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | 19 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
18 #include "webrtc/rtc_base/checks.h" | 20 #include "webrtc/rtc_base/checks.h" |
19 #include "webrtc/rtc_base/logging.h" | 21 #include "webrtc/rtc_base/logging.h" |
20 #include "webrtc/system_wrappers/include/clock.h" | 22 #include "webrtc/system_wrappers/include/clock.h" |
21 #include "webrtc/system_wrappers/include/field_trial.h" | |
22 #include "webrtc/system_wrappers/include/metrics.h" | 23 #include "webrtc/system_wrappers/include/metrics.h" |
23 | 24 |
24 namespace webrtc { | 25 namespace webrtc { |
25 namespace { | 26 namespace { |
26 // Periodic time interval for processing samples for |freq_offset_counter_|. | 27 // Periodic time interval for processing samples for |freq_offset_counter_|. |
27 const int64_t kFreqOffsetProcessIntervalMs = 40000; | 28 const int64_t kFreqOffsetProcessIntervalMs = 40000; |
28 | 29 |
29 // Configuration for bad call detection. | 30 // Configuration for bad call detection. |
30 const int kBadCallMinRequiredSamples = 10; | 31 const int kBadCallMinRequiredSamples = 10; |
31 const int kMinSampleLengthMs = 990; | 32 const int kMinSampleLengthMs = 990; |
32 const int kNumMeasurements = 10; | 33 const int kNumMeasurements = 10; |
33 const int kNumMeasurementsVariance = kNumMeasurements * 1.5; | 34 const int kNumMeasurementsVariance = kNumMeasurements * 1.5; |
34 const float kBadFraction = 0.8f; | 35 const float kBadFraction = 0.8f; |
35 // For fps: | 36 // For fps: |
36 // Low means low enough to be bad, high means high enough to be good | 37 // Low means low enough to be bad, high means high enough to be good |
37 const int kLowFpsThreshold = 12; | 38 const int kLowFpsThreshold = 12; |
38 const int kHighFpsThreshold = 14; | 39 const int kHighFpsThreshold = 14; |
39 // For qp and fps variance: | 40 // For qp and fps variance: |
40 // Low means low enough to be good, high means high enough to be bad | 41 // Low means low enough to be good, high means high enough to be bad |
41 const int kLowQpThresholdVp8 = 60; | 42 const int kLowQpThresholdVp8 = 60; |
42 const int kHighQpThresholdVp8 = 70; | 43 const int kHighQpThresholdVp8 = 70; |
43 const int kLowVarianceThreshold = 1; | 44 const int kLowVarianceThreshold = 1; |
44 const int kHighVarianceThreshold = 2; | 45 const int kHighVarianceThreshold = 2; |
45 | 46 |
46 // Some metrics are reported as a maximum over this period. | 47 // Some metrics are reported as a maximum over this period. |
47 const int kMovingMaxWindowMs = 10000; | 48 const int kMovingMaxWindowMs = 10000; |
48 | 49 |
49 // How large window we use to calculate the framerate/bitrate. | 50 // How large window we use to calculate the framerate/bitrate. |
50 const int kRateStatisticsWindowSizeMs = 1000; | 51 const int kRateStatisticsWindowSizeMs = 1000; |
| 52 |
| 53 std::string UmaPrefixForContentType(VideoContentType content_type) { |
| 54 std::stringstream ss; |
| 55 ss << "WebRTC.Video"; |
| 56 if (videocontenttypehelpers::IsScreenshare(content_type)) { |
| 57 ss << ".Screenshare"; |
| 58 } |
| 59 return ss.str(); |
| 60 } |
| 61 |
| 62 std::string UmaSuffixForContentType(VideoContentType content_type) { |
| 63 std::stringstream ss; |
| 64 int simulcast_id = videocontenttypehelpers::GetSimulcastId(content_type); |
| 65 if (simulcast_id > 0) { |
| 66 ss << ".S" << simulcast_id - 1; |
| 67 } |
| 68 int experiment_id = videocontenttypehelpers::GetExperimentId(content_type); |
| 69 if (experiment_id > 0) { |
| 70 ss << ".ExperimentGroup" << experiment_id - 1; |
| 71 } |
| 72 return ss.str(); |
| 73 } |
51 } // namespace | 74 } // namespace |
52 | 75 |
53 ReceiveStatisticsProxy::ReceiveStatisticsProxy( | 76 ReceiveStatisticsProxy::ReceiveStatisticsProxy( |
54 const VideoReceiveStream::Config* config, | 77 const VideoReceiveStream::Config* config, |
55 Clock* clock) | 78 Clock* clock) |
56 : clock_(clock), | 79 : clock_(clock), |
57 config_(*config), | 80 config_(*config), |
58 start_ms_(clock->TimeInMilliseconds()), | 81 start_ms_(clock->TimeInMilliseconds()), |
59 last_sample_time_(clock->TimeInMilliseconds()), | 82 last_sample_time_(clock->TimeInMilliseconds()), |
60 fps_threshold_(kLowFpsThreshold, | 83 fps_threshold_(kLowFpsThreshold, |
61 kHighFpsThreshold, | 84 kHighFpsThreshold, |
62 kBadFraction, | 85 kBadFraction, |
63 kNumMeasurements), | 86 kNumMeasurements), |
64 qp_threshold_(kLowQpThresholdVp8, | 87 qp_threshold_(kLowQpThresholdVp8, |
65 kHighQpThresholdVp8, | 88 kHighQpThresholdVp8, |
66 kBadFraction, | 89 kBadFraction, |
67 kNumMeasurements), | 90 kNumMeasurements), |
68 variance_threshold_(kLowVarianceThreshold, | 91 variance_threshold_(kLowVarianceThreshold, |
69 kHighVarianceThreshold, | 92 kHighVarianceThreshold, |
70 kBadFraction, | 93 kBadFraction, |
71 kNumMeasurementsVariance), | 94 kNumMeasurementsVariance), |
72 num_bad_states_(0), | 95 num_bad_states_(0), |
73 num_certain_states_(0), | 96 num_certain_states_(0), |
74 // 1000ms window, scale 1000 for ms to s. | 97 // 1000ms window, scale 1000 for ms to s. |
75 decode_fps_estimator_(1000, 1000), | 98 decode_fps_estimator_(1000, 1000), |
76 renders_fps_estimator_(1000, 1000), | 99 renders_fps_estimator_(1000, 1000), |
77 render_fps_tracker_(100, 10u), | 100 render_fps_tracker_(100, 10u), |
78 render_pixel_tracker_(100, 10u), | 101 render_pixel_tracker_(100, 10u), |
79 total_byte_tracker_(100, 10u), // bucket_interval_ms, bucket_count | 102 total_byte_tracker_(100, 10u), // bucket_interval_ms, bucket_count |
80 e2e_delay_max_ms_video_(-1), | |
81 e2e_delay_max_ms_screenshare_(-1), | |
82 interframe_delay_max_ms_video_(-1), | |
83 interframe_delay_max_ms_screenshare_(-1), | |
84 interframe_delay_max_moving_(kMovingMaxWindowMs), | 103 interframe_delay_max_moving_(kMovingMaxWindowMs), |
85 freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs), | 104 freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs), |
86 first_report_block_time_ms_(-1), | 105 first_report_block_time_ms_(-1), |
87 avg_rtt_ms_(0), | 106 avg_rtt_ms_(0), |
88 last_content_type_(VideoContentType::UNSPECIFIED) { | 107 last_content_type_(VideoContentType::UNSPECIFIED) { |
89 stats_.ssrc = config_.rtp.remote_ssrc; | 108 stats_.ssrc = config_.rtp.remote_ssrc; |
90 // TODO(brandtr): Replace |rtx_stats_| with a single instance of | 109 // TODO(brandtr): Replace |rtx_stats_| with a single instance of |
91 // StreamDataCounters. | 110 // StreamDataCounters. |
92 if (config_.rtp.rtx_ssrc) { | 111 if (config_.rtp.rtx_ssrc) { |
93 rtx_stats_[config_.rtp.rtx_ssrc] = StreamDataCounters(); | 112 rtx_stats_[config_.rtp.rtx_ssrc] = StreamDataCounters(); |
94 } | 113 } |
95 } | 114 } |
96 | 115 |
97 ReceiveStatisticsProxy::~ReceiveStatisticsProxy() { | 116 ReceiveStatisticsProxy::~ReceiveStatisticsProxy() { |
98 UpdateHistograms(); | 117 UpdateHistograms(); |
99 } | 118 } |
100 | 119 |
101 void ReceiveStatisticsProxy::UpdateHistograms() { | 120 void ReceiveStatisticsProxy::UpdateHistograms() { |
102 RTC_HISTOGRAM_COUNTS_100000( | 121 int stream_duration_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000; |
103 "WebRTC.Video.ReceiveStreamLifetimeInSeconds", | 122 if (stats_.frame_counts.key_frames > 0 || |
104 (clock_->TimeInMilliseconds() - start_ms_) / 1000); | 123 stats_.frame_counts.delta_frames > 0) { |
| 124 RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.ReceiveStreamLifetimeInSeconds", |
| 125 stream_duration_sec); |
| 126 LOG(LS_INFO) << "WebRTC.Video.ReceiveStreamLifetimeInSeconds " |
| 127 << stream_duration_sec; |
| 128 } |
105 | 129 |
106 if (first_report_block_time_ms_ != -1 && | 130 if (first_report_block_time_ms_ != -1 && |
107 ((clock_->TimeInMilliseconds() - first_report_block_time_ms_) / 1000) >= | 131 ((clock_->TimeInMilliseconds() - first_report_block_time_ms_) / 1000) >= |
108 metrics::kMinRunTimeInSeconds) { | 132 metrics::kMinRunTimeInSeconds) { |
109 int fraction_lost = report_block_stats_.FractionLostInPercent(); | 133 int fraction_lost = report_block_stats_.FractionLostInPercent(); |
110 if (fraction_lost != -1) { | 134 if (fraction_lost != -1) { |
111 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.ReceivedPacketsLostInPercent", | 135 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.ReceivedPacketsLostInPercent", |
112 fraction_lost); | 136 fraction_lost); |
113 LOG(LS_INFO) << "WebRTC.Video.ReceivedPacketsLostInPercent " | 137 LOG(LS_INFO) << "WebRTC.Video.ReceivedPacketsLostInPercent " |
114 << fraction_lost; | 138 << fraction_lost; |
115 } | 139 } |
116 } | 140 } |
117 | 141 |
118 const int kMinRequiredSamples = 200; | 142 const int kMinRequiredSamples = 200; |
119 int samples = static_cast<int>(render_fps_tracker_.TotalSampleCount()); | 143 int samples = static_cast<int>(render_fps_tracker_.TotalSampleCount()); |
120 if (samples >= kMinRequiredSamples) { | 144 if (samples >= kMinRequiredSamples) { |
121 RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.RenderFramesPerSecond", | 145 RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.RenderFramesPerSecond", |
122 round(render_fps_tracker_.ComputeTotalRate())); | 146 round(render_fps_tracker_.ComputeTotalRate())); |
123 RTC_HISTOGRAM_COUNTS_100000( | 147 RTC_HISTOGRAM_COUNTS_100000( |
124 "WebRTC.Video.RenderSqrtPixelsPerSecond", | 148 "WebRTC.Video.RenderSqrtPixelsPerSecond", |
125 round(render_pixel_tracker_.ComputeTotalRate())); | 149 round(render_pixel_tracker_.ComputeTotalRate())); |
126 } | 150 } |
127 int width = render_width_counter_.Avg(kMinRequiredSamples); | 151 |
128 int height = render_height_counter_.Avg(kMinRequiredSamples); | |
129 if (width != -1) { | |
130 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.ReceivedWidthInPixels", width); | |
131 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.ReceivedHeightInPixels", height); | |
132 LOG(LS_INFO) << "WebRTC.Video.ReceivedWidthInPixels " << width; | |
133 LOG(LS_INFO) << "WebRTC.Video.ReceivedHeightInPixels " << height; | |
134 } | |
135 int sync_offset_ms = sync_offset_counter_.Avg(kMinRequiredSamples); | 152 int sync_offset_ms = sync_offset_counter_.Avg(kMinRequiredSamples); |
136 if (sync_offset_ms != -1) { | 153 if (sync_offset_ms != -1) { |
137 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.AVSyncOffsetInMs", sync_offset_ms); | 154 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.AVSyncOffsetInMs", sync_offset_ms); |
138 LOG(LS_INFO) << "WebRTC.Video.AVSyncOffsetInMs " << sync_offset_ms; | 155 LOG(LS_INFO) << "WebRTC.Video.AVSyncOffsetInMs " << sync_offset_ms; |
139 } | 156 } |
140 AggregatedStats freq_offset_stats = freq_offset_counter_.GetStats(); | 157 AggregatedStats freq_offset_stats = freq_offset_counter_.GetStats(); |
141 if (freq_offset_stats.num_samples > 0) { | 158 if (freq_offset_stats.num_samples > 0) { |
142 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtpToNtpFreqOffsetInKhz", | 159 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtpToNtpFreqOffsetInKhz", |
143 freq_offset_stats.average); | 160 freq_offset_stats.average); |
144 LOG(LS_INFO) << "WebRTC.Video.RtpToNtpFreqOffsetInKhz, " | 161 LOG(LS_INFO) << "WebRTC.Video.RtpToNtpFreqOffsetInKhz, " |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 int current_delay_ms = current_delay_counter_.Avg(kMinRequiredSamples); | 199 int current_delay_ms = current_delay_counter_.Avg(kMinRequiredSamples); |
183 if (current_delay_ms != -1) { | 200 if (current_delay_ms != -1) { |
184 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.CurrentDelayInMs", | 201 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.CurrentDelayInMs", |
185 current_delay_ms); | 202 current_delay_ms); |
186 LOG(LS_INFO) << "WebRTC.Video.CurrentDelayInMs " << current_delay_ms; | 203 LOG(LS_INFO) << "WebRTC.Video.CurrentDelayInMs " << current_delay_ms; |
187 } | 204 } |
188 int delay_ms = delay_counter_.Avg(kMinRequiredSamples); | 205 int delay_ms = delay_counter_.Avg(kMinRequiredSamples); |
189 if (delay_ms != -1) | 206 if (delay_ms != -1) |
190 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.OnewayDelayInMs", delay_ms); | 207 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.OnewayDelayInMs", delay_ms); |
191 | 208 |
192 int e2e_delay_ms_video = e2e_delay_counter_video_.Avg(kMinRequiredSamples); | 209 // Aggregate content_specific_stats_ by removing experiment or simulcast |
193 if (e2e_delay_ms_video != -1) { | 210 // information; |
194 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.EndToEndDelayInMs", | 211 std::map<VideoContentType, ContentSpecificStats> aggregated_stats; |
195 e2e_delay_ms_video); | 212 for (auto it : content_specific_stats_) { |
196 LOG(LS_INFO) << "WebRTC.Video.EndToEndDelayInMs " << e2e_delay_ms_video; | 213 // Calculate simulcast specific metrics (".S0" ... ".S2" suffixes). |
| 214 VideoContentType content_type = it.first; |
| 215 if (videocontenttypehelpers::GetSimulcastId(content_type) > 0) { |
| 216 // Aggregate on experiment id. |
| 217 videocontenttypehelpers::SetExperimentId(&content_type, 0); |
| 218 aggregated_stats[content_type].Add(it.second); |
| 219 } |
| 220 // Calculate experiment specific metrics (".ExperimentGroup[0-7]" suffixes). |
| 221 content_type = it.first; |
| 222 if (videocontenttypehelpers::GetExperimentId(content_type) > 0) { |
| 223 // Aggregate on simulcast id. |
| 224 videocontenttypehelpers::SetSimulcastId(&content_type, 0); |
| 225 aggregated_stats[content_type].Add(it.second); |
| 226 } |
| 227 // Calculate aggregated metrics (no suffixes. Aggregated on everything). |
| 228 content_type = it.first; |
| 229 videocontenttypehelpers::SetSimulcastId(&content_type, 0); |
| 230 videocontenttypehelpers::SetExperimentId(&content_type, 0); |
| 231 aggregated_stats[content_type].Add(it.second); |
197 } | 232 } |
198 | 233 |
199 int e2e_delay_ms_screenshare = | 234 for (auto it : aggregated_stats) { |
200 e2e_delay_counter_screenshare_.Avg(kMinRequiredSamples); | 235 // For the metric Foo we report the following slices: |
201 if (e2e_delay_ms_screenshare != -1) { | 236 // WebRTC.Video.Foo, |
202 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.Screenshare.EndToEndDelayInMs", | 237 // WebRTC.Video.Screenshare.Foo, |
203 e2e_delay_ms_screenshare); | 238 // WebRTC.Video.Foo.S[0-3], |
204 } | 239 // WebRTC.Video.Foo.ExperimentGroup[0-7], |
| 240 // WebRTC.Video.Screenshare.Foo.S[0-3], |
| 241 // WebRTC.Video.Screenshare.Foo.ExperimentGroup[0-7]. |
| 242 auto content_type = it.first; |
| 243 auto stats = it.second; |
| 244 std::string uma_prefix = UmaPrefixForContentType(content_type); |
| 245 std::string uma_suffix = UmaSuffixForContentType(content_type); |
| 246 // Metrics can be sliced on either simulcast id or experiment id but not |
| 247 // both. |
| 248 RTC_DCHECK(videocontenttypehelpers::GetExperimentId(content_type) == 0 || |
| 249 videocontenttypehelpers::GetSimulcastId(content_type) == 0); |
205 | 250 |
206 int e2e_delay_max_ms_video = e2e_delay_max_ms_video_; | 251 int e2e_delay_ms = stats.e2e_delay_counter.Avg(kMinRequiredSamples); |
207 if (e2e_delay_max_ms_video != -1) { | 252 if (e2e_delay_ms != -1) { |
208 RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.EndToEndDelayMaxInMs", | 253 RTC_HISTOGRAM_COUNTS_SPARSE_10000( |
209 e2e_delay_max_ms_video); | 254 uma_prefix + ".EndToEndDelayInMs" + uma_suffix, e2e_delay_ms); |
210 } | 255 LOG(LS_INFO) << uma_prefix << ".EndToEndDelayInMs" << uma_suffix << " " |
| 256 << e2e_delay_ms; |
| 257 } |
| 258 int e2e_delay_max_ms = stats.e2e_delay_counter.Max(); |
| 259 if (e2e_delay_max_ms != -1 && e2e_delay_ms != -1) { |
| 260 RTC_HISTOGRAM_COUNTS_SPARSE_100000( |
| 261 uma_prefix + ".EndToEndDelayMaxInMs" + uma_suffix, e2e_delay_max_ms); |
| 262 LOG(LS_INFO) << uma_prefix << ".EndToEndDelayMaxInMs" << uma_suffix << " " |
| 263 << e2e_delay_max_ms; |
| 264 } |
| 265 int interframe_delay_ms = |
| 266 stats.interframe_delay_counter.Avg(kMinRequiredSamples); |
| 267 if (interframe_delay_ms != -1) { |
| 268 RTC_HISTOGRAM_COUNTS_SPARSE_10000( |
| 269 uma_prefix + ".InterframeDelayInMs" + uma_suffix, |
| 270 interframe_delay_ms); |
| 271 LOG(LS_INFO) << uma_prefix << ".InterframeDelayInMs" << uma_suffix << " " |
| 272 << interframe_delay_ms; |
| 273 } |
| 274 int interframe_delay_max_ms = stats.interframe_delay_counter.Max(); |
| 275 if (interframe_delay_max_ms != -1 && interframe_delay_ms != -1) { |
| 276 RTC_HISTOGRAM_COUNTS_SPARSE_10000( |
| 277 uma_prefix + ".InterframeDelayMaxInMs" + uma_suffix, |
| 278 interframe_delay_max_ms); |
| 279 LOG(LS_INFO) << uma_prefix << ".InterframeDelayMaxInMs" << uma_suffix |
| 280 << " " << interframe_delay_max_ms; |
| 281 } |
211 | 282 |
212 int e2e_delay_max_ms_screenshare = e2e_delay_max_ms_screenshare_; | 283 int width = stats.received_width.Avg(kMinRequiredSamples); |
213 if (e2e_delay_max_ms_screenshare != -1) { | 284 if (width != -1) { |
214 RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.Screenshare.EndToEndDelayMaxInMs", | 285 RTC_HISTOGRAM_COUNTS_SPARSE_10000( |
215 e2e_delay_max_ms_screenshare); | 286 uma_prefix + ".ReceivedWidthInPixels" + uma_suffix, width); |
216 } | 287 LOG(LS_INFO) << uma_prefix << ".ReceivedWidthInPixels" << uma_suffix |
| 288 << " " << width; |
| 289 } |
217 | 290 |
218 int interframe_delay_ms_screenshare = | 291 int height = stats.received_height.Avg(kMinRequiredSamples); |
219 interframe_delay_counter_screenshare_.Avg(kMinRequiredSamples); | 292 if (height != -1) { |
220 if (interframe_delay_ms_screenshare != -1) { | 293 RTC_HISTOGRAM_COUNTS_SPARSE_10000( |
221 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.Screenshare.InterframeDelayInMs", | 294 uma_prefix + ".ReceivedHeightInPixels" + uma_suffix, height); |
222 interframe_delay_ms_screenshare); | 295 LOG(LS_INFO) << uma_prefix << ".ReceivedHeightInPixels" << uma_suffix |
223 RTC_DCHECK_GE(interframe_delay_max_ms_screenshare_, | 296 << " " << height; |
224 interframe_delay_ms_screenshare); | 297 } |
225 RTC_HISTOGRAM_COUNTS_10000( | |
226 "WebRTC.Video.Screenshare.InterframeDelayMaxInMs", | |
227 interframe_delay_max_ms_screenshare_); | |
228 } | |
229 | 298 |
230 int interframe_delay_ms_video = | 299 if (content_type != VideoContentType::UNSPECIFIED) { |
231 interframe_delay_counter_video_.Avg(kMinRequiredSamples); | 300 // Don't report these 3 metrics unsliced, as more precise variants |
232 if (interframe_delay_ms_video != -1) { | 301 // are reported separately in this method. |
233 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.InterframeDelayInMs", | 302 float flow_duration_sec = stats.flow_duration_ms / 1000.0; |
234 interframe_delay_ms_video); | 303 if (flow_duration_sec >= metrics::kMinRunTimeInSeconds) { |
235 RTC_DCHECK_GE(interframe_delay_max_ms_video_, interframe_delay_ms_video); | 304 int media_bitrate_kbps = static_cast<int>(stats.total_media_bytes * 8 / |
236 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.InterframeDelayMaxInMs", | 305 flow_duration_sec / 1000); |
237 interframe_delay_max_ms_video_); | 306 RTC_HISTOGRAM_COUNTS_SPARSE_10000( |
| 307 uma_prefix + ".MediaBitrateReceivedInKbps" + uma_suffix, |
| 308 media_bitrate_kbps); |
| 309 LOG(LS_INFO) << uma_prefix << ".MediaBitrateReceivedInKbps" |
| 310 << uma_suffix << " " << media_bitrate_kbps; |
| 311 } |
| 312 |
| 313 int num_total_frames = |
| 314 stats.frame_counts.key_frames + stats.frame_counts.delta_frames; |
| 315 if (num_total_frames >= kMinRequiredSamples) { |
| 316 int num_key_frames = stats.frame_counts.key_frames; |
| 317 int key_frames_permille = |
| 318 (num_key_frames * 1000 + num_total_frames / 2) / num_total_frames; |
| 319 RTC_HISTOGRAM_COUNTS_SPARSE_1000( |
| 320 uma_prefix + ".KeyFramesReceivedInPermille" + uma_suffix, |
| 321 key_frames_permille); |
| 322 LOG(LS_INFO) << uma_prefix << ".KeyFramesReceivedInPermille" |
| 323 << uma_suffix << " " << key_frames_permille; |
| 324 } |
| 325 |
| 326 int qp = stats.qp_counter.Avg(kMinRequiredSamples); |
| 327 if (qp != -1) { |
| 328 RTC_HISTOGRAM_COUNTS_SPARSE_200( |
| 329 uma_prefix + ".Decoded.Vp8.Qp" + uma_suffix, qp); |
| 330 LOG(LS_INFO) << uma_prefix << ".Decoded.Vp8.Qp" << uma_suffix << " " |
| 331 << qp; |
| 332 } |
| 333 } |
238 } | 334 } |
239 | 335 |
240 StreamDataCounters rtp = stats_.rtp_stats; | 336 StreamDataCounters rtp = stats_.rtp_stats; |
241 StreamDataCounters rtx; | 337 StreamDataCounters rtx; |
242 for (auto it : rtx_stats_) | 338 for (auto it : rtx_stats_) |
243 rtx.Add(it.second); | 339 rtx.Add(it.second); |
244 StreamDataCounters rtp_rtx = rtp; | 340 StreamDataCounters rtp_rtx = rtp; |
245 rtp_rtx.Add(rtx); | 341 rtp_rtx.Add(rtx); |
246 int64_t elapsed_sec = | 342 int64_t elapsed_sec = |
247 rtp_rtx.TimeSinceFirstPacketInMs(clock_->TimeInMilliseconds()) / 1000; | 343 rtp_rtx.TimeSinceFirstPacketInMs(clock_->TimeInMilliseconds()) / 1000; |
248 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) { | 344 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) { |
249 RTC_HISTOGRAM_COUNTS_10000( | 345 RTC_HISTOGRAM_COUNTS_10000( |
250 "WebRTC.Video.BitrateReceivedInKbps", | 346 "WebRTC.Video.BitrateReceivedInKbps", |
251 static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec / | 347 static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec / |
252 1000)); | 348 1000)); |
253 RTC_HISTOGRAM_COUNTS_10000( | 349 int media_bitrate_kbs = |
254 "WebRTC.Video.MediaBitrateReceivedInKbps", | 350 static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000); |
255 static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000)); | 351 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.MediaBitrateReceivedInKbps", |
| 352 media_bitrate_kbs); |
| 353 LOG(LS_INFO) << "WebRTC.Video.MediaBitrateReceivedInKbps " |
| 354 << media_bitrate_kbs; |
256 RTC_HISTOGRAM_COUNTS_10000( | 355 RTC_HISTOGRAM_COUNTS_10000( |
257 "WebRTC.Video.PaddingBitrateReceivedInKbps", | 356 "WebRTC.Video.PaddingBitrateReceivedInKbps", |
258 static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec / | 357 static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec / |
259 1000)); | 358 1000)); |
260 RTC_HISTOGRAM_COUNTS_10000( | 359 RTC_HISTOGRAM_COUNTS_10000( |
261 "WebRTC.Video.RetransmittedBitrateReceivedInKbps", | 360 "WebRTC.Video.RetransmittedBitrateReceivedInKbps", |
262 static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 / elapsed_sec / | 361 static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 / elapsed_sec / |
263 1000)); | 362 1000)); |
264 if (!rtx_stats_.empty()) { | 363 if (!rtx_stats_.empty()) { |
265 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateReceivedInKbps", | 364 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateReceivedInKbps", |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 } | 621 } |
523 if (total_bytes > last_total_bytes) | 622 if (total_bytes > last_total_bytes) |
524 total_byte_tracker_.AddSamples(total_bytes - last_total_bytes); | 623 total_byte_tracker_.AddSamples(total_bytes - last_total_bytes); |
525 } | 624 } |
526 | 625 |
527 void ReceiveStatisticsProxy::OnDecodedFrame(rtc::Optional<uint8_t> qp, | 626 void ReceiveStatisticsProxy::OnDecodedFrame(rtc::Optional<uint8_t> qp, |
528 VideoContentType content_type) { | 627 VideoContentType content_type) { |
529 uint64_t now = clock_->TimeInMilliseconds(); | 628 uint64_t now = clock_->TimeInMilliseconds(); |
530 | 629 |
531 rtc::CritScope lock(&crit_); | 630 rtc::CritScope lock(&crit_); |
| 631 |
| 632 ContentSpecificStats* content_specific_stats = |
| 633 &content_specific_stats_[content_type]; |
532 ++stats_.frames_decoded; | 634 ++stats_.frames_decoded; |
533 if (qp) { | 635 if (qp) { |
534 if (!stats_.qp_sum) { | 636 if (!stats_.qp_sum) { |
535 if (stats_.frames_decoded != 1) { | 637 if (stats_.frames_decoded != 1) { |
536 LOG(LS_WARNING) | 638 LOG(LS_WARNING) |
537 << "Frames decoded was not 1 when first qp value was received."; | 639 << "Frames decoded was not 1 when first qp value was received."; |
538 stats_.frames_decoded = 1; | 640 stats_.frames_decoded = 1; |
539 } | 641 } |
540 stats_.qp_sum = rtc::Optional<uint64_t>(0); | 642 stats_.qp_sum = rtc::Optional<uint64_t>(0); |
541 } | 643 } |
542 *stats_.qp_sum += *qp; | 644 *stats_.qp_sum += *qp; |
| 645 content_specific_stats->qp_counter.Add(*qp); |
543 } else if (stats_.qp_sum) { | 646 } else if (stats_.qp_sum) { |
544 LOG(LS_WARNING) | 647 LOG(LS_WARNING) |
545 << "QP sum was already set and no QP was given for a frame."; | 648 << "QP sum was already set and no QP was given for a frame."; |
546 stats_.qp_sum = rtc::Optional<uint64_t>(); | 649 stats_.qp_sum = rtc::Optional<uint64_t>(); |
547 } | 650 } |
548 last_content_type_ = content_type; | 651 last_content_type_ = content_type; |
549 decode_fps_estimator_.Update(1, now); | 652 decode_fps_estimator_.Update(1, now); |
550 if (last_decoded_frame_time_ms_) { | 653 if (last_decoded_frame_time_ms_) { |
551 int64_t interframe_delay_ms = now - *last_decoded_frame_time_ms_; | 654 int64_t interframe_delay_ms = now - *last_decoded_frame_time_ms_; |
552 RTC_DCHECK_GE(interframe_delay_ms, 0); | 655 RTC_DCHECK_GE(interframe_delay_ms, 0); |
553 interframe_delay_max_moving_.Add(interframe_delay_ms, now); | 656 interframe_delay_max_moving_.Add(interframe_delay_ms, now); |
554 if (last_content_type_ == VideoContentType::SCREENSHARE) { | 657 content_specific_stats->interframe_delay_counter.Add(interframe_delay_ms); |
555 interframe_delay_counter_screenshare_.Add(interframe_delay_ms); | 658 content_specific_stats->flow_duration_ms += interframe_delay_ms; |
556 if (interframe_delay_max_ms_screenshare_ < interframe_delay_ms) { | |
557 interframe_delay_max_ms_screenshare_ = interframe_delay_ms; | |
558 } | |
559 } else { | |
560 interframe_delay_counter_video_.Add(interframe_delay_ms); | |
561 if (interframe_delay_max_ms_video_ < interframe_delay_ms) { | |
562 interframe_delay_max_ms_video_ = interframe_delay_ms; | |
563 } | |
564 } | |
565 } | 659 } |
566 last_decoded_frame_time_ms_.emplace(now); | 660 last_decoded_frame_time_ms_.emplace(now); |
567 } | 661 } |
568 | 662 |
569 void ReceiveStatisticsProxy::OnRenderedFrame(const VideoFrame& frame) { | 663 void ReceiveStatisticsProxy::OnRenderedFrame(const VideoFrame& frame) { |
570 int width = frame.width(); | 664 int width = frame.width(); |
571 int height = frame.height(); | 665 int height = frame.height(); |
572 RTC_DCHECK_GT(width, 0); | 666 RTC_DCHECK_GT(width, 0); |
573 RTC_DCHECK_GT(height, 0); | 667 RTC_DCHECK_GT(height, 0); |
574 uint64_t now = clock_->TimeInMilliseconds(); | 668 uint64_t now = clock_->TimeInMilliseconds(); |
575 | |
576 rtc::CritScope lock(&crit_); | 669 rtc::CritScope lock(&crit_); |
| 670 ContentSpecificStats* content_specific_stats = |
| 671 &content_specific_stats_[last_content_type_]; |
577 renders_fps_estimator_.Update(1, now); | 672 renders_fps_estimator_.Update(1, now); |
578 ++stats_.frames_rendered; | 673 ++stats_.frames_rendered; |
579 stats_.width = width; | 674 stats_.width = width; |
580 stats_.height = height; | 675 stats_.height = height; |
581 render_width_counter_.Add(width); | |
582 render_height_counter_.Add(height); | |
583 render_fps_tracker_.AddSamples(1); | 676 render_fps_tracker_.AddSamples(1); |
584 render_pixel_tracker_.AddSamples(sqrt(width * height)); | 677 render_pixel_tracker_.AddSamples(sqrt(width * height)); |
| 678 content_specific_stats->received_width.Add(width); |
| 679 content_specific_stats->received_height.Add(height); |
585 | 680 |
586 if (frame.ntp_time_ms() > 0) { | 681 if (frame.ntp_time_ms() > 0) { |
587 int64_t delay_ms = clock_->CurrentNtpInMilliseconds() - frame.ntp_time_ms(); | 682 int64_t delay_ms = clock_->CurrentNtpInMilliseconds() - frame.ntp_time_ms(); |
588 if (delay_ms >= 0) { | 683 if (delay_ms >= 0) { |
589 if (last_content_type_ == VideoContentType::SCREENSHARE) { | 684 content_specific_stats->e2e_delay_counter.Add(delay_ms); |
590 e2e_delay_max_ms_screenshare_ = | |
591 std::max(delay_ms, e2e_delay_max_ms_screenshare_); | |
592 e2e_delay_counter_screenshare_.Add(delay_ms); | |
593 } else { | |
594 e2e_delay_max_ms_video_ = std::max(delay_ms, e2e_delay_max_ms_video_); | |
595 e2e_delay_counter_video_.Add(delay_ms); | |
596 } | |
597 } | 685 } |
598 } | 686 } |
599 } | 687 } |
600 | 688 |
601 void ReceiveStatisticsProxy::OnSyncOffsetUpdated(int64_t sync_offset_ms, | 689 void ReceiveStatisticsProxy::OnSyncOffsetUpdated(int64_t sync_offset_ms, |
602 double estimated_freq_khz) { | 690 double estimated_freq_khz) { |
603 rtc::CritScope lock(&crit_); | 691 rtc::CritScope lock(&crit_); |
604 sync_offset_counter_.Add(std::abs(sync_offset_ms)); | 692 sync_offset_counter_.Add(std::abs(sync_offset_ms)); |
605 stats_.sync_offset_ms = sync_offset_ms; | 693 stats_.sync_offset_ms = sync_offset_ms; |
606 | 694 |
607 const double kMaxFreqKhz = 10000.0; | 695 const double kMaxFreqKhz = 10000.0; |
608 int offset_khz = kMaxFreqKhz; | 696 int offset_khz = kMaxFreqKhz; |
609 // Should not be zero or negative. If so, report max. | 697 // Should not be zero or negative. If so, report max. |
610 if (estimated_freq_khz < kMaxFreqKhz && estimated_freq_khz > 0.0) | 698 if (estimated_freq_khz < kMaxFreqKhz && estimated_freq_khz > 0.0) |
611 offset_khz = static_cast<int>(std::fabs(estimated_freq_khz - 90.0) + 0.5); | 699 offset_khz = static_cast<int>(std::fabs(estimated_freq_khz - 90.0) + 0.5); |
612 | 700 |
613 freq_offset_counter_.Add(offset_khz); | 701 freq_offset_counter_.Add(offset_khz); |
614 } | 702 } |
615 | 703 |
616 void ReceiveStatisticsProxy::OnReceiveRatesUpdated(uint32_t bitRate, | 704 void ReceiveStatisticsProxy::OnReceiveRatesUpdated(uint32_t bitRate, |
617 uint32_t frameRate) { | 705 uint32_t frameRate) { |
618 } | 706 } |
619 | 707 |
620 void ReceiveStatisticsProxy::OnCompleteFrame(bool is_keyframe, | 708 void ReceiveStatisticsProxy::OnCompleteFrame(bool is_keyframe, |
621 size_t size_bytes) { | 709 size_t size_bytes, |
| 710 VideoContentType content_type) { |
622 rtc::CritScope lock(&crit_); | 711 rtc::CritScope lock(&crit_); |
623 if (is_keyframe) | 712 if (is_keyframe) { |
624 ++stats_.frame_counts.key_frames; | 713 ++stats_.frame_counts.key_frames; |
625 else | 714 } else { |
626 ++stats_.frame_counts.delta_frames; | 715 ++stats_.frame_counts.delta_frames; |
| 716 } |
| 717 |
| 718 ContentSpecificStats* content_specific_stats = |
| 719 &content_specific_stats_[content_type]; |
| 720 |
| 721 content_specific_stats->total_media_bytes += size_bytes; |
| 722 if (is_keyframe) { |
| 723 ++content_specific_stats->frame_counts.key_frames; |
| 724 } else { |
| 725 ++content_specific_stats->frame_counts.delta_frames; |
| 726 } |
627 | 727 |
628 int64_t now_ms = clock_->TimeInMilliseconds(); | 728 int64_t now_ms = clock_->TimeInMilliseconds(); |
629 frame_window_.insert(std::make_pair(now_ms, size_bytes)); | 729 frame_window_.insert(std::make_pair(now_ms, size_bytes)); |
630 UpdateFramerate(now_ms); | 730 UpdateFramerate(now_ms); |
631 } | 731 } |
632 | 732 |
633 void ReceiveStatisticsProxy::OnFrameCountsUpdated( | 733 void ReceiveStatisticsProxy::OnFrameCountsUpdated( |
634 const FrameCounts& frame_counts) { | 734 const FrameCounts& frame_counts) { |
635 rtc::CritScope lock(&crit_); | 735 rtc::CritScope lock(&crit_); |
636 stats_.frame_counts = frame_counts; | 736 stats_.frame_counts = frame_counts; |
(...skipping 21 matching lines...) Expand all Loading... |
658 // TODO(sprang): Figure out any other state that should be reset. | 758 // TODO(sprang): Figure out any other state that should be reset. |
659 | 759 |
660 rtc::CritScope lock(&crit_); | 760 rtc::CritScope lock(&crit_); |
661 // Don't report inter-frame delay if stream was paused. | 761 // Don't report inter-frame delay if stream was paused. |
662 last_decoded_frame_time_ms_.reset(); | 762 last_decoded_frame_time_ms_.reset(); |
663 } | 763 } |
664 | 764 |
665 void ReceiveStatisticsProxy::SampleCounter::Add(int sample) { | 765 void ReceiveStatisticsProxy::SampleCounter::Add(int sample) { |
666 sum += sample; | 766 sum += sample; |
667 ++num_samples; | 767 ++num_samples; |
| 768 if (!max || sample > *max) { |
| 769 max.emplace(sample); |
| 770 } |
| 771 } |
| 772 |
| 773 void ReceiveStatisticsProxy::SampleCounter::Add(const SampleCounter& other) { |
| 774 sum += other.sum; |
| 775 num_samples += other.num_samples; |
| 776 if (other.max && (!max || *max < *other.max)) |
| 777 max = other.max; |
668 } | 778 } |
669 | 779 |
670 int ReceiveStatisticsProxy::SampleCounter::Avg( | 780 int ReceiveStatisticsProxy::SampleCounter::Avg( |
671 int64_t min_required_samples) const { | 781 int64_t min_required_samples) const { |
672 if (num_samples < min_required_samples || num_samples == 0) | 782 if (num_samples < min_required_samples || num_samples == 0) |
673 return -1; | 783 return -1; |
674 return static_cast<int>(sum / num_samples); | 784 return static_cast<int>(sum / num_samples); |
675 } | 785 } |
676 | 786 |
| 787 int ReceiveStatisticsProxy::SampleCounter::Max() const { |
| 788 return max.value_or(-1); |
| 789 } |
| 790 |
677 void ReceiveStatisticsProxy::SampleCounter::Reset() { | 791 void ReceiveStatisticsProxy::SampleCounter::Reset() { |
678 num_samples = 0; | 792 num_samples = 0; |
679 sum = 0; | 793 sum = 0; |
| 794 max.reset(); |
680 } | 795 } |
681 | 796 |
682 void ReceiveStatisticsProxy::OnRttUpdate(int64_t avg_rtt_ms, | 797 void ReceiveStatisticsProxy::OnRttUpdate(int64_t avg_rtt_ms, |
683 int64_t max_rtt_ms) { | 798 int64_t max_rtt_ms) { |
684 rtc::CritScope lock(&crit_); | 799 rtc::CritScope lock(&crit_); |
685 avg_rtt_ms_ = avg_rtt_ms; | 800 avg_rtt_ms_ = avg_rtt_ms; |
686 } | 801 } |
687 | 802 |
| 803 void ReceiveStatisticsProxy::ContentSpecificStats::Add( |
| 804 const ContentSpecificStats& other) { |
| 805 e2e_delay_counter.Add(other.e2e_delay_counter); |
| 806 interframe_delay_counter.Add(other.interframe_delay_counter); |
| 807 flow_duration_ms += other.flow_duration_ms; |
| 808 total_media_bytes += other.total_media_bytes; |
| 809 received_height.Add(other.received_height); |
| 810 received_width.Add(other.received_width); |
| 811 qp_counter.Add(other.qp_counter); |
| 812 frame_counts.key_frames += other.frame_counts.key_frames; |
| 813 frame_counts.delta_frames += other.frame_counts.delta_frames; |
| 814 } |
| 815 |
688 } // namespace webrtc | 816 } // namespace webrtc |
OLD | NEW |