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 <cmath> | 14 #include <cmath> |
| 15 #include <utility> |
14 | 16 |
15 #include "webrtc/base/checks.h" | 17 #include "webrtc/base/checks.h" |
16 #include "webrtc/base/logging.h" | 18 #include "webrtc/base/logging.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/system_wrappers/include/clock.h" | 20 #include "webrtc/system_wrappers/include/clock.h" |
19 #include "webrtc/system_wrappers/include/field_trial.h" | 21 #include "webrtc/system_wrappers/include/field_trial.h" |
20 #include "webrtc/system_wrappers/include/metrics.h" | 22 #include "webrtc/system_wrappers/include/metrics.h" |
21 | 23 |
22 namespace webrtc { | 24 namespace webrtc { |
23 namespace { | 25 namespace { |
24 // Periodic time interval for processing samples for |freq_offset_counter_|. | 26 // Periodic time interval for processing samples for |freq_offset_counter_|. |
25 const int64_t kFreqOffsetProcessIntervalMs = 40000; | 27 const int64_t kFreqOffsetProcessIntervalMs = 40000; |
26 | 28 |
27 // Configuration for bad call detection. | 29 // Configuration for bad call detection. |
28 const int kBadCallMinRequiredSamples = 10; | 30 const int kBadCallMinRequiredSamples = 10; |
29 const int kMinSampleLengthMs = 990; | 31 const int kMinSampleLengthMs = 990; |
30 const int kNumMeasurements = 10; | 32 const int kNumMeasurements = 10; |
31 const int kNumMeasurementsVariance = kNumMeasurements * 1.5; | 33 const int kNumMeasurementsVariance = kNumMeasurements * 1.5; |
32 const float kBadFraction = 0.8f; | 34 const float kBadFraction = 0.8f; |
33 // For fps: | 35 // For fps: |
34 // Low means low enough to be bad, high means high enough to be good | 36 // Low means low enough to be bad, high means high enough to be good |
35 const int kLowFpsThreshold = 12; | 37 const int kLowFpsThreshold = 12; |
36 const int kHighFpsThreshold = 14; | 38 const int kHighFpsThreshold = 14; |
37 // For qp and fps variance: | 39 // For qp and fps variance: |
38 // Low means low enough to be good, high means high enough to be bad | 40 // Low means low enough to be good, high means high enough to be bad |
39 const int kLowQpThresholdVp8 = 60; | 41 const int kLowQpThresholdVp8 = 60; |
40 const int kHighQpThresholdVp8 = 70; | 42 const int kHighQpThresholdVp8 = 70; |
41 const int kLowVarianceThreshold = 1; | 43 const int kLowVarianceThreshold = 1; |
42 const int kHighVarianceThreshold = 2; | 44 const int kHighVarianceThreshold = 2; |
| 45 |
| 46 // How large window we use to calculate the framerate/bitrate. |
| 47 const int kRateStatisticsWindowSizeMs = 1000; |
43 } // namespace | 48 } // namespace |
44 | 49 |
45 ReceiveStatisticsProxy::ReceiveStatisticsProxy( | 50 ReceiveStatisticsProxy::ReceiveStatisticsProxy( |
46 const VideoReceiveStream::Config* config, | 51 const VideoReceiveStream::Config* config, |
47 Clock* clock) | 52 Clock* clock) |
48 : clock_(clock), | 53 : clock_(clock), |
49 config_(*config), | 54 config_(*config), |
50 start_ms_(clock->TimeInMilliseconds()), | 55 start_ms_(clock->TimeInMilliseconds()), |
51 last_sample_time_(clock->TimeInMilliseconds()), | 56 last_sample_time_(clock->TimeInMilliseconds()), |
52 fps_threshold_(kLowFpsThreshold, | 57 fps_threshold_(kLowFpsThreshold, |
53 kHighFpsThreshold, | 58 kHighFpsThreshold, |
54 kBadFraction, | 59 kBadFraction, |
55 kNumMeasurements), | 60 kNumMeasurements), |
56 qp_threshold_(kLowQpThresholdVp8, | 61 qp_threshold_(kLowQpThresholdVp8, |
57 kHighQpThresholdVp8, | 62 kHighQpThresholdVp8, |
58 kBadFraction, | 63 kBadFraction, |
59 kNumMeasurements), | 64 kNumMeasurements), |
60 variance_threshold_(kLowVarianceThreshold, | 65 variance_threshold_(kLowVarianceThreshold, |
61 kHighVarianceThreshold, | 66 kHighVarianceThreshold, |
62 kBadFraction, | 67 kBadFraction, |
63 kNumMeasurementsVariance), | 68 kNumMeasurementsVariance), |
64 num_bad_states_(0), | 69 num_bad_states_(0), |
65 num_certain_states_(0), | 70 num_certain_states_(0), |
66 // 1000ms window, scale 1000 for ms to s. | 71 // 1000ms window, scale 1000 for ms to s. |
67 decode_fps_estimator_(1000, 1000), | 72 decode_fps_estimator_(1000, 1000), |
68 renders_fps_estimator_(1000, 1000), | 73 renders_fps_estimator_(1000, 1000), |
69 render_fps_tracker_(100, 10u), | 74 render_fps_tracker_(100, 10u), |
70 render_pixel_tracker_(100, 10u), | 75 render_pixel_tracker_(100, 10u), |
71 freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs), | 76 freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs), |
72 first_report_block_time_ms_(-1) { | 77 first_report_block_time_ms_(-1), |
| 78 avg_rtt_ms_(0), |
| 79 frame_window_accumulated_bytes_(0) { |
73 stats_.ssrc = config_.rtp.remote_ssrc; | 80 stats_.ssrc = config_.rtp.remote_ssrc; |
74 // TODO(brandtr): Replace |rtx_stats_| with a single instance of | 81 // TODO(brandtr): Replace |rtx_stats_| with a single instance of |
75 // StreamDataCounters. | 82 // StreamDataCounters. |
76 if (config_.rtp.rtx_ssrc) { | 83 if (config_.rtp.rtx_ssrc) { |
77 rtx_stats_[config_.rtp.rtx_ssrc] = StreamDataCounters(); | 84 rtx_stats_[config_.rtp.rtx_ssrc] = StreamDataCounters(); |
78 } | 85 } |
79 } | 86 } |
80 | 87 |
81 ReceiveStatisticsProxy::~ReceiveStatisticsProxy() { | 88 ReceiveStatisticsProxy::~ReceiveStatisticsProxy() { |
82 UpdateHistograms(); | 89 UpdateHistograms(); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.AVSyncOffsetInMs", sync_offset_ms); | 124 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.AVSyncOffsetInMs", sync_offset_ms); |
118 } | 125 } |
119 AggregatedStats freq_offset_stats = freq_offset_counter_.GetStats(); | 126 AggregatedStats freq_offset_stats = freq_offset_counter_.GetStats(); |
120 if (freq_offset_stats.num_samples > 0) { | 127 if (freq_offset_stats.num_samples > 0) { |
121 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtpToNtpFreqOffsetInKhz", | 128 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtpToNtpFreqOffsetInKhz", |
122 freq_offset_stats.average); | 129 freq_offset_stats.average); |
123 LOG(LS_INFO) << "WebRTC.Video.RtpToNtpFreqOffsetInKhz, " | 130 LOG(LS_INFO) << "WebRTC.Video.RtpToNtpFreqOffsetInKhz, " |
124 << freq_offset_stats.ToString(); | 131 << freq_offset_stats.ToString(); |
125 } | 132 } |
126 | 133 |
| 134 if (stats_.frame_counts.key_frames > 0 || |
| 135 stats_.frame_counts.delta_frames > 0) { |
| 136 float num_key_frames = stats_.frame_counts.key_frames; |
| 137 float num_total_frames = |
| 138 stats_.frame_counts.key_frames + stats_.frame_counts.delta_frames; |
| 139 int key_frames_permille = |
| 140 (num_key_frames * 1000.0f / num_total_frames + 0.5f); |
| 141 RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.KeyFramesReceivedInPermille", |
| 142 key_frames_permille); |
| 143 } |
| 144 |
127 int qp = qp_counters_.vp8.Avg(kMinRequiredSamples); | 145 int qp = qp_counters_.vp8.Avg(kMinRequiredSamples); |
128 if (qp != -1) | 146 if (qp != -1) |
129 RTC_HISTOGRAM_COUNTS_200("WebRTC.Video.Decoded.Vp8.Qp", qp); | 147 RTC_HISTOGRAM_COUNTS_200("WebRTC.Video.Decoded.Vp8.Qp", qp); |
130 | 148 |
131 // TODO(asapersson): DecoderTiming() is call periodically (each 1000ms) and | 149 // TODO(asapersson): DecoderTiming() is call periodically (each 1000ms) and |
132 // not per frame. Change decode time to include every frame. | 150 // not per frame. Change decode time to include every frame. |
133 const int kMinRequiredDecodeSamples = 5; | 151 const int kMinRequiredDecodeSamples = 5; |
134 int decode_ms = decode_time_counter_.Avg(kMinRequiredDecodeSamples); | 152 int decode_ms = decode_time_counter_.Avg(kMinRequiredDecodeSamples); |
135 if (decode_ms != -1) | 153 if (decode_ms != -1) |
136 RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.DecodeTimeInMs", decode_ms); | 154 RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.DecodeTimeInMs", decode_ms); |
137 | 155 |
138 if (field_trial::FindFullName("WebRTC-NewVideoJitterBuffer") != | 156 int jb_delay_ms = jitter_buffer_delay_counter_.Avg(kMinRequiredDecodeSamples); |
139 "Enabled") { | 157 if (jb_delay_ms != -1) { |
140 int jb_delay_ms = | 158 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.JitterBufferDelayInMs", |
141 jitter_buffer_delay_counter_.Avg(kMinRequiredDecodeSamples); | 159 jb_delay_ms); |
142 if (jb_delay_ms != -1) { | |
143 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.JitterBufferDelayInMs", | |
144 jb_delay_ms); | |
145 } | |
146 } | 160 } |
| 161 |
147 int target_delay_ms = target_delay_counter_.Avg(kMinRequiredDecodeSamples); | 162 int target_delay_ms = target_delay_counter_.Avg(kMinRequiredDecodeSamples); |
148 if (target_delay_ms != -1) { | 163 if (target_delay_ms != -1) { |
149 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.TargetDelayInMs", target_delay_ms); | 164 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.TargetDelayInMs", target_delay_ms); |
150 } | 165 } |
151 int current_delay_ms = current_delay_counter_.Avg(kMinRequiredDecodeSamples); | 166 int current_delay_ms = current_delay_counter_.Avg(kMinRequiredDecodeSamples); |
152 if (current_delay_ms != -1) { | 167 if (current_delay_ms != -1) { |
153 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.CurrentDelayInMs", | 168 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.CurrentDelayInMs", |
154 current_delay_ms); | 169 current_delay_ms); |
155 } | 170 } |
156 int delay_ms = delay_counter_.Avg(kMinRequiredDecodeSamples); | 171 int delay_ms = delay_counter_.Avg(kMinRequiredDecodeSamples); |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 qp_sample_.Reset(); | 308 qp_sample_.Reset(); |
294 | 309 |
295 if (fps_threshold_.IsHigh() || variance_threshold_.IsHigh() || | 310 if (fps_threshold_.IsHigh() || variance_threshold_.IsHigh() || |
296 qp_threshold_.IsHigh()) { | 311 qp_threshold_.IsHigh()) { |
297 if (any_bad) | 312 if (any_bad) |
298 ++num_bad_states_; | 313 ++num_bad_states_; |
299 ++num_certain_states_; | 314 ++num_certain_states_; |
300 } | 315 } |
301 } | 316 } |
302 | 317 |
| 318 void ReceiveStatisticsProxy::UpdateFrameAndBitrate(int64_t now_ms) const { |
| 319 int64_t old_frames_ms = now_ms - kRateStatisticsWindowSizeMs; |
| 320 while (!frame_window_.empty() && |
| 321 frame_window_.begin()->first < old_frames_ms) { |
| 322 frame_window_accumulated_bytes_ -= frame_window_.begin()->second; |
| 323 frame_window_.erase(frame_window_.begin()); |
| 324 } |
| 325 |
| 326 size_t framerate = |
| 327 (frame_window_.size() * 1000 + 500) / kRateStatisticsWindowSizeMs; |
| 328 size_t bitrate_bps = |
| 329 frame_window_accumulated_bytes_ * 8000 / kRateStatisticsWindowSizeMs; |
| 330 stats_.network_frame_rate = static_cast<int>(framerate); |
| 331 stats_.total_bitrate_bps = static_cast<int>(bitrate_bps); |
| 332 } |
| 333 |
303 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const { | 334 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const { |
304 rtc::CritScope lock(&crit_); | 335 rtc::CritScope lock(&crit_); |
| 336 UpdateFrameAndBitrate(clock_->TimeInMilliseconds()); |
305 return stats_; | 337 return stats_; |
306 } | 338 } |
307 | 339 |
308 void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) { | 340 void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) { |
309 rtc::CritScope lock(&crit_); | 341 rtc::CritScope lock(&crit_); |
310 stats_.current_payload_type = payload_type; | 342 stats_.current_payload_type = payload_type; |
311 } | 343 } |
312 | 344 |
313 void ReceiveStatisticsProxy::OnDecoderImplementationName( | 345 void ReceiveStatisticsProxy::OnDecoderImplementationName( |
314 const char* implementation_name) { | 346 const char* implementation_name) { |
315 rtc::CritScope lock(&crit_); | 347 rtc::CritScope lock(&crit_); |
316 stats_.decoder_implementation_name = implementation_name; | 348 stats_.decoder_implementation_name = implementation_name; |
317 } | 349 } |
318 void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate, | 350 void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate, |
319 unsigned int bitrate_bps) { | 351 unsigned int bitrate_bps) { |
320 rtc::CritScope lock(&crit_); | 352 rtc::CritScope lock(&crit_); |
321 if (stats_.rtp_stats.first_packet_time_ms != -1) | 353 if (stats_.rtp_stats.first_packet_time_ms != -1) |
322 QualitySample(); | 354 QualitySample(); |
323 stats_.network_frame_rate = framerate; | |
324 stats_.total_bitrate_bps = bitrate_bps; | |
325 } | 355 } |
326 | 356 |
327 void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms, | 357 void ReceiveStatisticsProxy::OnFrameBufferTimingsUpdated( |
328 int max_decode_ms, | 358 int decode_ms, |
329 int current_delay_ms, | 359 int max_decode_ms, |
330 int target_delay_ms, | 360 int current_delay_ms, |
331 int jitter_buffer_ms, | 361 int target_delay_ms, |
332 int min_playout_delay_ms, | 362 int jitter_buffer_ms, |
333 int render_delay_ms, | 363 int min_playout_delay_ms, |
334 int64_t rtt_ms) { | 364 int render_delay_ms) { |
335 rtc::CritScope lock(&crit_); | 365 rtc::CritScope lock(&crit_); |
336 stats_.decode_ms = decode_ms; | 366 stats_.decode_ms = decode_ms; |
337 stats_.max_decode_ms = max_decode_ms; | 367 stats_.max_decode_ms = max_decode_ms; |
338 stats_.current_delay_ms = current_delay_ms; | 368 stats_.current_delay_ms = current_delay_ms; |
339 stats_.target_delay_ms = target_delay_ms; | 369 stats_.target_delay_ms = target_delay_ms; |
340 stats_.jitter_buffer_ms = jitter_buffer_ms; | 370 stats_.jitter_buffer_ms = jitter_buffer_ms; |
341 stats_.min_playout_delay_ms = min_playout_delay_ms; | 371 stats_.min_playout_delay_ms = min_playout_delay_ms; |
342 stats_.render_delay_ms = render_delay_ms; | 372 stats_.render_delay_ms = render_delay_ms; |
343 decode_time_counter_.Add(decode_ms); | 373 decode_time_counter_.Add(decode_ms); |
344 jitter_buffer_delay_counter_.Add(jitter_buffer_ms); | 374 jitter_buffer_delay_counter_.Add(jitter_buffer_ms); |
345 target_delay_counter_.Add(target_delay_ms); | 375 target_delay_counter_.Add(target_delay_ms); |
346 current_delay_counter_.Add(current_delay_ms); | 376 current_delay_counter_.Add(current_delay_ms); |
347 // Network delay (rtt/2) + target_delay_ms (jitter delay + decode time + | 377 // Network delay (rtt/2) + target_delay_ms (jitter delay + decode time + |
348 // render delay). | 378 // render delay). |
349 delay_counter_.Add(target_delay_ms + rtt_ms / 2); | 379 delay_counter_.Add(target_delay_ms + avg_rtt_ms_ / 2); |
350 } | 380 } |
351 | 381 |
352 void ReceiveStatisticsProxy::RtcpPacketTypesCounterUpdated( | 382 void ReceiveStatisticsProxy::RtcpPacketTypesCounterUpdated( |
353 uint32_t ssrc, | 383 uint32_t ssrc, |
354 const RtcpPacketTypeCounter& packet_counter) { | 384 const RtcpPacketTypeCounter& packet_counter) { |
355 rtc::CritScope lock(&crit_); | 385 rtc::CritScope lock(&crit_); |
356 if (stats_.ssrc != ssrc) | 386 if (stats_.ssrc != ssrc) |
357 return; | 387 return; |
358 stats_.rtcp_packet_type_counts = packet_counter; | 388 stats_.rtcp_packet_type_counts = packet_counter; |
359 } | 389 } |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 if (estimated_freq_khz < kMaxFreqKhz && estimated_freq_khz > 0.0) | 489 if (estimated_freq_khz < kMaxFreqKhz && estimated_freq_khz > 0.0) |
460 offset_khz = static_cast<int>(std::fabs(estimated_freq_khz - 90.0) + 0.5); | 490 offset_khz = static_cast<int>(std::fabs(estimated_freq_khz - 90.0) + 0.5); |
461 | 491 |
462 freq_offset_counter_.Add(offset_khz); | 492 freq_offset_counter_.Add(offset_khz); |
463 } | 493 } |
464 | 494 |
465 void ReceiveStatisticsProxy::OnReceiveRatesUpdated(uint32_t bitRate, | 495 void ReceiveStatisticsProxy::OnReceiveRatesUpdated(uint32_t bitRate, |
466 uint32_t frameRate) { | 496 uint32_t frameRate) { |
467 } | 497 } |
468 | 498 |
| 499 void ReceiveStatisticsProxy::OnCompleteFrame(bool is_keyframe, |
| 500 size_t size_bytes) { |
| 501 rtc::CritScope lock(&crit_); |
| 502 if (is_keyframe) |
| 503 ++stats_.frame_counts.key_frames; |
| 504 else |
| 505 ++stats_.frame_counts.delta_frames; |
| 506 |
| 507 int64_t now_ms = clock_->TimeInMilliseconds(); |
| 508 frame_window_accumulated_bytes_ += size_bytes; |
| 509 frame_window_.insert(std::make_pair(now_ms, size_bytes)); |
| 510 UpdateFrameAndBitrate(now_ms); |
| 511 } |
| 512 |
469 void ReceiveStatisticsProxy::OnFrameCountsUpdated( | 513 void ReceiveStatisticsProxy::OnFrameCountsUpdated( |
470 const FrameCounts& frame_counts) { | 514 const FrameCounts& frame_counts) { |
471 rtc::CritScope lock(&crit_); | 515 rtc::CritScope lock(&crit_); |
472 stats_.frame_counts = frame_counts; | 516 stats_.frame_counts = frame_counts; |
473 } | 517 } |
474 | 518 |
475 void ReceiveStatisticsProxy::OnDiscardedPacketsUpdated(int discarded_packets) { | 519 void ReceiveStatisticsProxy::OnDiscardedPacketsUpdated(int discarded_packets) { |
476 rtc::CritScope lock(&crit_); | 520 rtc::CritScope lock(&crit_); |
477 stats_.discarded_packets = discarded_packets; | 521 stats_.discarded_packets = discarded_packets; |
478 } | 522 } |
(...skipping 21 matching lines...) Expand all Loading... |
500 if (num_samples < min_required_samples || num_samples == 0) | 544 if (num_samples < min_required_samples || num_samples == 0) |
501 return -1; | 545 return -1; |
502 return static_cast<int>(sum / num_samples); | 546 return static_cast<int>(sum / num_samples); |
503 } | 547 } |
504 | 548 |
505 void ReceiveStatisticsProxy::SampleCounter::Reset() { | 549 void ReceiveStatisticsProxy::SampleCounter::Reset() { |
506 num_samples = 0; | 550 num_samples = 0; |
507 sum = 0; | 551 sum = 0; |
508 } | 552 } |
509 | 553 |
| 554 void ReceiveStatisticsProxy::OnRttUpdate(int64_t avg_rtt_ms, |
| 555 int64_t max_rtt_ms) { |
| 556 rtc::CritScope lock(&crit_); |
| 557 avg_rtt_ms_ = avg_rtt_ms; |
| 558 } |
| 559 |
510 } // namespace webrtc | 560 } // namespace webrtc |
OLD | NEW |