| 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 <cmath> | 13 #include <cmath> |
| 14 | 14 |
| 15 #include "webrtc/base/checks.h" | 15 #include "webrtc/base/checks.h" |
| 16 #include "webrtc/base/logging.h" | 16 #include "webrtc/base/logging.h" |
| 17 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | 17 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
| 18 #include "webrtc/system_wrappers/include/clock.h" | 18 #include "webrtc/system_wrappers/include/clock.h" |
| 19 #include "webrtc/system_wrappers/include/field_trial.h" | 19 #include "webrtc/system_wrappers/include/field_trial.h" |
| 20 #include "webrtc/system_wrappers/include/metrics.h" | 20 #include "webrtc/system_wrappers/include/metrics.h" |
| 21 | 21 |
| 22 namespace webrtc { | 22 namespace webrtc { |
| 23 namespace { | 23 namespace { |
| 24 // Periodic time interval for processing samples for |freq_offset_counter_|. | 24 // Periodic time interval for processing samples for |freq_offset_counter_|. |
| 25 const int64_t kFreqOffsetProcessIntervalMs = 40000; | 25 const int64_t kFreqOffsetProcessIntervalMs = 40000; |
| 26 | 26 |
| 27 // Configuration for bad call detection. | 27 // Configuration for bad call detection. |
| 28 const int kBadCallMinRequiredSamples = 10; |
| 28 const int kMinSampleLengthMs = 990; | 29 const int kMinSampleLengthMs = 990; |
| 29 const int kNumMeasurements = 10; | 30 const int kNumMeasurements = 10; |
| 30 const int kNumMeasurementsVariance = kNumMeasurements * 1.5; | 31 const int kNumMeasurementsVariance = kNumMeasurements * 1.5; |
| 31 const float kBadFraction = 0.8f; | 32 const float kBadFraction = 0.8f; |
| 32 // For fps: | 33 // For fps: |
| 33 // 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 |
| 34 const int kLowFpsThreshold = 12; | 35 const int kLowFpsThreshold = 12; |
| 35 const int kHighFpsThreshold = 14; | 36 const int kHighFpsThreshold = 14; |
| 36 // For qp and fps variance: | 37 // For qp and fps variance: |
| 37 // 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 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 53 kBadFraction, | 54 kBadFraction, |
| 54 kNumMeasurements), | 55 kNumMeasurements), |
| 55 qp_threshold_(kLowQpThresholdVp8, | 56 qp_threshold_(kLowQpThresholdVp8, |
| 56 kHighQpThresholdVp8, | 57 kHighQpThresholdVp8, |
| 57 kBadFraction, | 58 kBadFraction, |
| 58 kNumMeasurements), | 59 kNumMeasurements), |
| 59 variance_threshold_(kLowVarianceThreshold, | 60 variance_threshold_(kLowVarianceThreshold, |
| 60 kHighVarianceThreshold, | 61 kHighVarianceThreshold, |
| 61 kBadFraction, | 62 kBadFraction, |
| 62 kNumMeasurementsVariance), | 63 kNumMeasurementsVariance), |
| 64 num_bad_states_(0), |
| 65 num_certain_states_(0), |
| 63 // 1000ms window, scale 1000 for ms to s. | 66 // 1000ms window, scale 1000 for ms to s. |
| 64 decode_fps_estimator_(1000, 1000), | 67 decode_fps_estimator_(1000, 1000), |
| 65 renders_fps_estimator_(1000, 1000), | 68 renders_fps_estimator_(1000, 1000), |
| 66 render_fps_tracker_(100, 10u), | 69 render_fps_tracker_(100, 10u), |
| 67 render_pixel_tracker_(100, 10u), | 70 render_pixel_tracker_(100, 10u), |
| 68 freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs), | 71 freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs), |
| 69 first_report_block_time_ms_(-1) { | 72 first_report_block_time_ms_(-1) { |
| 70 stats_.ssrc = config_.rtp.remote_ssrc; | 73 stats_.ssrc = config_.rtp.remote_ssrc; |
| 71 for (auto it : config_.rtp.rtx) | 74 for (auto it : config_.rtp.rtx) |
| 72 rtx_stats_[it.second.ssrc] = StreamDataCounters(); | 75 rtx_stats_[it.second.ssrc] = StreamDataCounters(); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 counters.nack_packets * 60 / elapsed_sec); | 197 counters.nack_packets * 60 / elapsed_sec); |
| 195 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsSentPerMinute", | 198 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsSentPerMinute", |
| 196 counters.fir_packets * 60 / elapsed_sec); | 199 counters.fir_packets * 60 / elapsed_sec); |
| 197 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute", | 200 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute", |
| 198 counters.pli_packets * 60 / elapsed_sec); | 201 counters.pli_packets * 60 / elapsed_sec); |
| 199 if (counters.nack_requests > 0) { | 202 if (counters.nack_requests > 0) { |
| 200 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent", | 203 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent", |
| 201 counters.UniqueNackRequestsInPercent()); | 204 counters.UniqueNackRequestsInPercent()); |
| 202 } | 205 } |
| 203 } | 206 } |
| 207 |
| 208 if (num_certain_states_ >= kBadCallMinRequiredSamples) { |
| 209 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BadCall.Any", |
| 210 100 * num_bad_states_ / num_certain_states_); |
| 211 } |
| 212 rtc::Optional<double> fps_fraction = |
| 213 fps_threshold_.FractionHigh(kBadCallMinRequiredSamples); |
| 214 if (fps_fraction) { |
| 215 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BadCall.FrameRate", |
| 216 static_cast<int>(100 * (1 - *fps_fraction))); |
| 217 } |
| 218 rtc::Optional<double> variance_fraction = |
| 219 variance_threshold_.FractionHigh(kBadCallMinRequiredSamples); |
| 220 if (variance_fraction) { |
| 221 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BadCall.FrameRateVariance", |
| 222 static_cast<int>(100 * *variance_fraction)); |
| 223 } |
| 224 rtc::Optional<double> qp_fraction = |
| 225 qp_threshold_.FractionHigh(kBadCallMinRequiredSamples); |
| 226 if (qp_fraction) { |
| 227 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BadCall.Qp", |
| 228 static_cast<int>(100 * *qp_fraction)); |
| 229 } |
| 204 } | 230 } |
| 205 | 231 |
| 206 void ReceiveStatisticsProxy::QualitySample() { | 232 void ReceiveStatisticsProxy::QualitySample() { |
| 207 int64_t now = clock_->TimeInMilliseconds(); | 233 int64_t now = clock_->TimeInMilliseconds(); |
| 208 if (last_sample_time_ + kMinSampleLengthMs > now) | 234 if (last_sample_time_ + kMinSampleLengthMs > now) |
| 209 return; | 235 return; |
| 210 | 236 |
| 211 double fps = | 237 double fps = |
| 212 render_fps_tracker_.ComputeRateForInterval(now - last_sample_time_); | 238 render_fps_tracker_.ComputeRateForInterval(now - last_sample_time_); |
| 213 int qp = qp_sample_.Avg(1); | 239 int qp = qp_sample_.Avg(1); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 LOG(LS_WARNING) << "Bad call (variance) end: " << now; | 281 LOG(LS_WARNING) << "Bad call (variance) end: " << now; |
| 256 } | 282 } |
| 257 | 283 |
| 258 LOG(LS_INFO) << "SAMPLE: sample_length: " << (now - last_sample_time_) | 284 LOG(LS_INFO) << "SAMPLE: sample_length: " << (now - last_sample_time_) |
| 259 << " fps: " << fps << " fps_bad: " << fps_bad << " qp: " << qp | 285 << " fps: " << fps << " fps_bad: " << fps_bad << " qp: " << qp |
| 260 << " qp_bad: " << qp_bad << " variance_bad: " << variance_bad | 286 << " qp_bad: " << qp_bad << " variance_bad: " << variance_bad |
| 261 << " fps_variance: " << fps_variance; | 287 << " fps_variance: " << fps_variance; |
| 262 | 288 |
| 263 last_sample_time_ = now; | 289 last_sample_time_ = now; |
| 264 qp_sample_.Reset(); | 290 qp_sample_.Reset(); |
| 291 |
| 292 if (fps_threshold_.IsHigh() || variance_threshold_.IsHigh() || |
| 293 qp_threshold_.IsHigh()) { |
| 294 if (any_bad) |
| 295 ++num_bad_states_; |
| 296 ++num_certain_states_; |
| 297 } |
| 265 } | 298 } |
| 266 | 299 |
| 267 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const { | 300 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const { |
| 268 rtc::CritScope lock(&crit_); | 301 rtc::CritScope lock(&crit_); |
| 269 return stats_; | 302 return stats_; |
| 270 } | 303 } |
| 271 | 304 |
| 272 void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) { | 305 void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) { |
| 273 rtc::CritScope lock(&crit_); | 306 rtc::CritScope lock(&crit_); |
| 274 stats_.current_payload_type = payload_type; | 307 stats_.current_payload_type = payload_type; |
| 275 } | 308 } |
| 276 | 309 |
| 277 void ReceiveStatisticsProxy::OnDecoderImplementationName( | 310 void ReceiveStatisticsProxy::OnDecoderImplementationName( |
| 278 const char* implementation_name) { | 311 const char* implementation_name) { |
| 279 rtc::CritScope lock(&crit_); | 312 rtc::CritScope lock(&crit_); |
| 280 stats_.decoder_implementation_name = implementation_name; | 313 stats_.decoder_implementation_name = implementation_name; |
| 281 } | 314 } |
| 282 void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate, | 315 void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate, |
| 283 unsigned int bitrate_bps) { | 316 unsigned int bitrate_bps) { |
| 284 rtc::CritScope lock(&crit_); | 317 rtc::CritScope lock(&crit_); |
| 285 QualitySample(); | 318 if (stats_.rtp_stats.first_packet_time_ms != -1) |
| 319 QualitySample(); |
| 286 stats_.network_frame_rate = framerate; | 320 stats_.network_frame_rate = framerate; |
| 287 stats_.total_bitrate_bps = bitrate_bps; | 321 stats_.total_bitrate_bps = bitrate_bps; |
| 288 } | 322 } |
| 289 | 323 |
| 290 void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms, | 324 void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms, |
| 291 int max_decode_ms, | 325 int max_decode_ms, |
| 292 int current_delay_ms, | 326 int current_delay_ms, |
| 293 int target_delay_ms, | 327 int target_delay_ms, |
| 294 int jitter_buffer_ms, | 328 int jitter_buffer_ms, |
| 295 int min_playout_delay_ms, | 329 int min_playout_delay_ms, |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 return -1; | 481 return -1; |
| 448 return sum / num_samples; | 482 return sum / num_samples; |
| 449 } | 483 } |
| 450 | 484 |
| 451 void ReceiveStatisticsProxy::SampleCounter::Reset() { | 485 void ReceiveStatisticsProxy::SampleCounter::Reset() { |
| 452 num_samples = 0; | 486 num_samples = 0; |
| 453 sum = 0; | 487 sum = 0; |
| 454 } | 488 } |
| 455 | 489 |
| 456 } // namespace webrtc | 490 } // namespace webrtc |
| OLD | NEW |