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