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 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 } // namespace | 68 } // namespace |
69 | 69 |
70 | 70 |
71 const int SendStatisticsProxy::kStatsTimeoutMs = 5000; | 71 const int SendStatisticsProxy::kStatsTimeoutMs = 5000; |
72 | 72 |
73 SendStatisticsProxy::SendStatisticsProxy( | 73 SendStatisticsProxy::SendStatisticsProxy( |
74 Clock* clock, | 74 Clock* clock, |
75 const VideoSendStream::Config& config, | 75 const VideoSendStream::Config& config, |
76 VideoEncoderConfig::ContentType content_type) | 76 VideoEncoderConfig::ContentType content_type) |
77 : clock_(clock), | 77 : clock_(clock), |
78 config_(config), | 78 payload_name_(config.encoder_settings.payload_name), |
| 79 rtp_config_(config.rtp), |
79 content_type_(content_type), | 80 content_type_(content_type), |
80 start_ms_(clock->TimeInMilliseconds()), | 81 start_ms_(clock->TimeInMilliseconds()), |
81 last_sent_frame_timestamp_(0), | 82 last_sent_frame_timestamp_(0), |
82 encode_time_(kEncodeTimeWeigthFactor), | 83 encode_time_(kEncodeTimeWeigthFactor), |
83 uma_container_( | 84 uma_container_( |
84 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) { | 85 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) { |
85 } | 86 } |
86 | 87 |
87 SendStatisticsProxy::~SendStatisticsProxy() { | 88 SendStatisticsProxy::~SendStatisticsProxy() { |
88 rtc::CritScope lock(&crit_); | 89 rtc::CritScope lock(&crit_); |
89 uma_container_->UpdateHistograms(config_, stats_); | 90 uma_container_->UpdateHistograms(rtp_config_, stats_); |
90 | 91 |
91 int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000; | 92 int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000; |
92 RTC_LOGGED_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds", | 93 RTC_LOGGED_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds", |
93 elapsed_sec); | 94 elapsed_sec); |
94 | 95 |
95 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) | 96 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) |
96 UpdateCodecTypeHistogram(config_.encoder_settings.payload_name); | 97 UpdateCodecTypeHistogram(payload_name_); |
97 } | 98 } |
98 | 99 |
99 SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer( | 100 SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer( |
100 const char* prefix, | 101 const char* prefix, |
101 const VideoSendStream::Stats& stats, | 102 const VideoSendStream::Stats& stats, |
102 Clock* const clock) | 103 Clock* const clock) |
103 : uma_prefix_(prefix), | 104 : uma_prefix_(prefix), |
104 clock_(clock), | 105 clock_(clock), |
105 max_sent_width_per_timestamp_(0), | 106 max_sent_width_per_timestamp_(0), |
106 max_sent_height_per_timestamp_(0), | 107 max_sent_height_per_timestamp_(0), |
107 input_frame_rate_tracker_(100, 10u), | 108 input_frame_rate_tracker_(100, 10u), |
108 sent_frame_rate_tracker_(100, 10u), | 109 sent_frame_rate_tracker_(100, 10u), |
109 first_rtcp_stats_time_ms_(-1), | 110 first_rtcp_stats_time_ms_(-1), |
110 first_rtp_stats_time_ms_(-1), | 111 first_rtp_stats_time_ms_(-1), |
111 start_stats_(stats) {} | 112 start_stats_(stats) {} |
112 | 113 |
113 SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {} | 114 SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {} |
114 | 115 |
115 void AccumulateRtpStats(const VideoSendStream::Stats& stats, | 116 void AccumulateRtxStats(const VideoSendStream::Stats& stats, |
116 const VideoSendStream::Config& config, | 117 const std::vector<uint32_t>& rtx_ssrcs, |
117 StreamDataCounters* total_rtp_stats, | 118 StreamDataCounters* total_rtp_stats, |
118 StreamDataCounters* rtx_stats) { | 119 StreamDataCounters* rtx_stats) { |
119 for (auto it : stats.substreams) { | 120 for (auto it : stats.substreams) { |
120 const std::vector<uint32_t> rtx_ssrcs = config.rtp.rtx.ssrcs; | |
121 if (std::find(rtx_ssrcs.begin(), rtx_ssrcs.end(), it.first) != | 121 if (std::find(rtx_ssrcs.begin(), rtx_ssrcs.end(), it.first) != |
122 rtx_ssrcs.end()) { | 122 rtx_ssrcs.end()) { |
123 rtx_stats->Add(it.second.rtp_stats); | 123 rtx_stats->Add(it.second.rtp_stats); |
124 } else { | 124 } else { |
125 total_rtp_stats->Add(it.second.rtp_stats); | 125 total_rtp_stats->Add(it.second.rtp_stats); |
126 } | 126 } |
127 } | 127 } |
128 } | 128 } |
129 | 129 |
130 void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms( | 130 void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms( |
131 const VideoSendStream::Config& config, | 131 const VideoSendStream::Config::Rtp& rtp_config, |
132 const VideoSendStream::Stats& current_stats) { | 132 const VideoSendStream::Stats& current_stats) { |
133 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix); | 133 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix); |
134 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0; | 134 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0; |
135 const int kMinRequiredSamples = 200; | 135 const int kMinRequiredSamples = 200; |
136 int in_width = input_width_counter_.Avg(kMinRequiredSamples); | 136 int in_width = input_width_counter_.Avg(kMinRequiredSamples); |
137 int in_height = input_height_counter_.Avg(kMinRequiredSamples); | 137 int in_height = input_height_counter_.Avg(kMinRequiredSamples); |
138 int in_fps = round(input_frame_rate_tracker_.ComputeTotalRate()); | 138 int in_fps = round(input_frame_rate_tracker_.ComputeTotalRate()); |
139 if (in_width != -1) { | 139 if (in_width != -1) { |
140 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 140 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
141 kIndex, uma_prefix_ + "InputWidthInPixels", in_width); | 141 kIndex, uma_prefix_ + "InputWidthInPixels", in_width); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 } | 255 } |
256 | 256 |
257 // The RTCP packet type counters, delivered via the | 257 // The RTCP packet type counters, delivered via the |
258 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire | 258 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire |
259 // life of the send stream and are not reset when switching content type. | 259 // life of the send stream and are not reset when switching content type. |
260 // For the purpose of these statistics though, we want new counts when | 260 // For the purpose of these statistics though, we want new counts when |
261 // switching since we switch histogram name. On every reset of the | 261 // switching since we switch histogram name. On every reset of the |
262 // UmaSamplesContainer, we save the initial state of the counters, so that | 262 // UmaSamplesContainer, we save the initial state of the counters, so that |
263 // we can calculate the delta here and aggregate over all ssrcs. | 263 // we can calculate the delta here and aggregate over all ssrcs. |
264 RtcpPacketTypeCounter counters; | 264 RtcpPacketTypeCounter counters; |
265 for (uint32_t ssrc : config.rtp.ssrcs) { | 265 for (uint32_t ssrc : rtp_config.ssrcs) { |
266 auto kv = current_stats.substreams.find(ssrc); | 266 auto kv = current_stats.substreams.find(ssrc); |
267 if (kv == current_stats.substreams.end()) | 267 if (kv == current_stats.substreams.end()) |
268 continue; | 268 continue; |
269 | 269 |
270 RtcpPacketTypeCounter stream_counters = | 270 RtcpPacketTypeCounter stream_counters = |
271 kv->second.rtcp_packet_type_counts; | 271 kv->second.rtcp_packet_type_counts; |
272 kv = start_stats_.substreams.find(ssrc); | 272 kv = start_stats_.substreams.find(ssrc); |
273 if (kv != start_stats_.substreams.end()) | 273 if (kv != start_stats_.substreams.end()) |
274 stream_counters.Subtract(kv->second.rtcp_packet_type_counts); | 274 stream_counters.Subtract(kv->second.rtcp_packet_type_counts); |
275 | 275 |
(...skipping 15 matching lines...) Expand all Loading... |
291 } | 291 } |
292 } | 292 } |
293 } | 293 } |
294 | 294 |
295 if (first_rtp_stats_time_ms_ != -1) { | 295 if (first_rtp_stats_time_ms_ != -1) { |
296 int64_t elapsed_sec = | 296 int64_t elapsed_sec = |
297 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000; | 297 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000; |
298 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) { | 298 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) { |
299 StreamDataCounters rtp; | 299 StreamDataCounters rtp; |
300 StreamDataCounters rtx; | 300 StreamDataCounters rtx; |
301 AccumulateRtpStats(current_stats, config, &rtp, &rtx); | 301 AccumulateRtxStats(current_stats, rtp_config.rtx.ssrcs, &rtp, &rtx); |
302 StreamDataCounters start_rtp; | 302 StreamDataCounters start_rtp; |
303 StreamDataCounters start_rtx; | 303 StreamDataCounters start_rtx; |
304 AccumulateRtpStats(start_stats_, config, &start_rtp, &start_rtx); | 304 AccumulateRtxStats(start_stats_, rtp_config.rtx.ssrcs, &start_rtp, |
| 305 &start_rtx); |
305 rtp.Subtract(start_rtp); | 306 rtp.Subtract(start_rtp); |
306 rtx.Subtract(start_rtx); | 307 rtx.Subtract(start_rtx); |
307 StreamDataCounters rtp_rtx = rtp; | 308 StreamDataCounters rtp_rtx = rtp; |
308 rtp_rtx.Add(rtx); | 309 rtp_rtx.Add(rtx); |
309 | 310 |
310 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 311 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
311 kIndex, uma_prefix_ + "BitrateSentInKbps", | 312 kIndex, uma_prefix_ + "BitrateSentInKbps", |
312 static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec / | 313 static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec / |
313 1000)); | 314 1000)); |
314 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 315 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
315 kIndex, uma_prefix_ + "MediaBitrateSentInKbps", | 316 kIndex, uma_prefix_ + "MediaBitrateSentInKbps", |
316 static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000)); | 317 static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000)); |
317 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 318 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
318 kIndex, uma_prefix_ + "PaddingBitrateSentInKbps", | 319 kIndex, uma_prefix_ + "PaddingBitrateSentInKbps", |
319 static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec / | 320 static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec / |
320 1000)); | 321 1000)); |
321 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 322 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
322 kIndex, uma_prefix_ + "RetransmittedBitrateSentInKbps", | 323 kIndex, uma_prefix_ + "RetransmittedBitrateSentInKbps", |
323 static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 / | 324 static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 / |
324 elapsed_sec / 1000)); | 325 elapsed_sec / 1000)); |
325 if (!config.rtp.rtx.ssrcs.empty()) { | 326 if (!rtp_config.rtx.ssrcs.empty()) { |
326 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 327 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
327 kIndex, uma_prefix_ + "RtxBitrateSentInKbps", | 328 kIndex, uma_prefix_ + "RtxBitrateSentInKbps", |
328 static_cast<int>(rtx.transmitted.TotalBytes() * 8 / elapsed_sec / | 329 static_cast<int>(rtx.transmitted.TotalBytes() * 8 / elapsed_sec / |
329 1000)); | 330 1000)); |
330 } | 331 } |
331 if (config.rtp.fec.red_payload_type != -1) { | 332 if (rtp_config.fec.red_payload_type != -1) { |
332 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 333 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
333 kIndex, uma_prefix_ + "FecBitrateSentInKbps", | 334 kIndex, uma_prefix_ + "FecBitrateSentInKbps", |
334 static_cast<int>(rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec / | 335 static_cast<int>(rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec / |
335 1000)); | 336 1000)); |
336 } | 337 } |
337 } | 338 } |
338 } | 339 } |
339 } | 340 } |
340 | 341 |
341 void SendStatisticsProxy::SetContentType( | 342 void SendStatisticsProxy::SetContentType( |
342 VideoEncoderConfig::ContentType content_type) { | 343 VideoEncoderConfig::ContentType content_type) { |
343 rtc::CritScope lock(&crit_); | 344 rtc::CritScope lock(&crit_); |
344 if (content_type_ != content_type) { | 345 if (content_type_ != content_type) { |
345 uma_container_->UpdateHistograms(config_, stats_); | 346 uma_container_->UpdateHistograms(rtp_config_, stats_); |
346 uma_container_.reset( | 347 uma_container_.reset( |
347 new UmaSamplesContainer(GetUmaPrefix(content_type), stats_, clock_)); | 348 new UmaSamplesContainer(GetUmaPrefix(content_type), stats_, clock_)); |
348 content_type_ = content_type; | 349 content_type_ = content_type; |
349 } | 350 } |
350 } | 351 } |
351 | 352 |
352 void SendStatisticsProxy::OnEncoderStatsUpdate(uint32_t framerate, | 353 void SendStatisticsProxy::OnEncoderStatsUpdate(uint32_t framerate, |
353 uint32_t bitrate) { | 354 uint32_t bitrate) { |
354 rtc::CritScope lock(&crit_); | 355 rtc::CritScope lock(&crit_); |
355 stats_.encode_frame_rate = framerate; | 356 stats_.encode_frame_rate = framerate; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 } | 394 } |
394 | 395 |
395 VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry( | 396 VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry( |
396 uint32_t ssrc) { | 397 uint32_t ssrc) { |
397 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it = | 398 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it = |
398 stats_.substreams.find(ssrc); | 399 stats_.substreams.find(ssrc); |
399 if (it != stats_.substreams.end()) | 400 if (it != stats_.substreams.end()) |
400 return &it->second; | 401 return &it->second; |
401 | 402 |
402 bool is_rtx = false; | 403 bool is_rtx = false; |
403 if (std::find(config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc) == | 404 if (std::find(rtp_config_.ssrcs.begin(), rtp_config_.ssrcs.end(), ssrc) == |
404 config_.rtp.ssrcs.end()) { | 405 rtp_config_.ssrcs.end()) { |
405 if (std::find(config_.rtp.rtx.ssrcs.begin(), config_.rtp.rtx.ssrcs.end(), | 406 if (std::find(rtp_config_.rtx.ssrcs.begin(), rtp_config_.rtx.ssrcs.end(), |
406 ssrc) == config_.rtp.rtx.ssrcs.end()) { | 407 ssrc) == rtp_config_.rtx.ssrcs.end()) { |
407 return nullptr; | 408 return nullptr; |
408 } | 409 } |
409 is_rtx = true; | 410 is_rtx = true; |
410 } | 411 } |
411 | 412 |
412 // Insert new entry and return ptr. | 413 // Insert new entry and return ptr. |
413 VideoSendStream::StreamStats* entry = &stats_.substreams[ssrc]; | 414 VideoSendStream::StreamStats* entry = &stats_.substreams[ssrc]; |
414 entry->is_rtx = is_rtx; | 415 entry->is_rtx = is_rtx; |
415 | 416 |
416 return entry; | 417 return entry; |
(...skipping 26 matching lines...) Expand all Loading... |
443 if (codec_info->codecType == kVideoCodecVP8) { | 444 if (codec_info->codecType == kVideoCodecVP8) { |
444 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx; | 445 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx; |
445 } else if (codec_info->codecType == kVideoCodecGeneric) { | 446 } else if (codec_info->codecType == kVideoCodecGeneric) { |
446 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx; | 447 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx; |
447 } | 448 } |
448 if (codec_info->codec_name) { | 449 if (codec_info->codec_name) { |
449 stats_.encoder_implementation_name = codec_info->codec_name; | 450 stats_.encoder_implementation_name = codec_info->codec_name; |
450 } | 451 } |
451 } | 452 } |
452 | 453 |
453 if (simulcast_idx >= config_.rtp.ssrcs.size()) { | 454 if (simulcast_idx >= rtp_config_.ssrcs.size()) { |
454 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx | 455 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx |
455 << " >= " << config_.rtp.ssrcs.size() << ")."; | 456 << " >= " << rtp_config_.ssrcs.size() << ")."; |
456 return; | 457 return; |
457 } | 458 } |
458 uint32_t ssrc = config_.rtp.ssrcs[simulcast_idx]; | 459 uint32_t ssrc = rtp_config_.ssrcs[simulcast_idx]; |
459 | 460 |
460 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc); | 461 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc); |
461 if (!stats) | 462 if (!stats) |
462 return; | 463 return; |
463 | 464 |
464 stats->width = encoded_image._encodedWidth; | 465 stats->width = encoded_image._encodedWidth; |
465 stats->height = encoded_image._encodedHeight; | 466 stats->height = encoded_image._encodedHeight; |
466 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds(); | 467 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds(); |
467 | 468 |
468 uma_container_->key_frame_counter_.Add(encoded_image._frameType == | 469 uma_container_->key_frame_counter_.Add(encoded_image._frameType == |
(...skipping 16 matching lines...) Expand all Loading... |
485 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0; | 486 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0; |
486 uma_container_->bw_limited_frame_counter_.Add(bw_limited); | 487 uma_container_->bw_limited_frame_counter_.Add(bw_limited); |
487 if (bw_limited) { | 488 if (bw_limited) { |
488 uma_container_->bw_resolutions_disabled_counter_.Add( | 489 uma_container_->bw_resolutions_disabled_counter_.Add( |
489 encoded_image.adapt_reason_.bw_resolutions_disabled); | 490 encoded_image.adapt_reason_.bw_resolutions_disabled); |
490 } | 491 } |
491 } | 492 } |
492 | 493 |
493 if (encoded_image.qp_ != -1 && codec_info) { | 494 if (encoded_image.qp_ != -1 && codec_info) { |
494 if (codec_info->codecType == kVideoCodecVP8) { | 495 if (codec_info->codecType == kVideoCodecVP8) { |
495 int spatial_idx = (config_.rtp.ssrcs.size() == 1) | 496 int spatial_idx = (rtp_config_.ssrcs.size() == 1) |
496 ? -1 | 497 ? -1 |
497 : static_cast<int>(simulcast_idx); | 498 : static_cast<int>(simulcast_idx); |
498 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_); | 499 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_); |
499 } else if (codec_info->codecType == kVideoCodecVP9) { | 500 } else if (codec_info->codecType == kVideoCodecVP9) { |
500 int spatial_idx = (codec_info->codecSpecific.VP9.num_spatial_layers == 1) | 501 int spatial_idx = (codec_info->codecSpecific.VP9.num_spatial_layers == 1) |
501 ? -1 | 502 ? -1 |
502 : codec_info->codecSpecific.VP9.spatial_idx; | 503 : codec_info->codecSpecific.VP9.spatial_idx; |
503 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_); | 504 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_); |
504 } | 505 } |
505 } | 506 } |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 return Fraction(min_required_samples, 1000.0f); | 641 return Fraction(min_required_samples, 1000.0f); |
641 } | 642 } |
642 | 643 |
643 int SendStatisticsProxy::BoolSampleCounter::Fraction( | 644 int SendStatisticsProxy::BoolSampleCounter::Fraction( |
644 int min_required_samples, float multiplier) const { | 645 int min_required_samples, float multiplier) const { |
645 if (num_samples < min_required_samples || num_samples == 0) | 646 if (num_samples < min_required_samples || num_samples == 0) |
646 return -1; | 647 return -1; |
647 return static_cast<int>((sum * multiplier / num_samples) + 0.5f); | 648 return static_cast<int>((sum * multiplier / num_samples) + 0.5f); |
648 } | 649 } |
649 } // namespace webrtc | 650 } // namespace webrtc |
OLD | NEW |