blob: 57189f3175b338e8168ad9006982026fab3726d7 [file] [log] [blame]
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/video/send_statistics_proxy.h"
12
asaperssond89920b2015-07-22 06:52:00 -070013#include <algorithm>
Tim Psiakiad13d2f2015-11-10 16:34:50 -080014#include <cmath>
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000015#include <map>
16
pbos@webrtc.org49096de2015-02-24 22:37:52 +000017#include "webrtc/base/checks.h"
18
Peter Boström415d2cd2015-10-26 11:35:17 +010019#include "webrtc/base/logging.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010020#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
21#include "webrtc/system_wrappers/include/metrics.h"
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000022
23namespace webrtc {
asapersson2a0a2a42015-10-27 01:32:00 -070024namespace {
25// Used by histograms. Values of entries should not be changed.
26enum HistogramCodecType {
27 kVideoUnknown = 0,
28 kVideoVp8 = 1,
29 kVideoVp9 = 2,
30 kVideoH264 = 3,
31 kVideoMax = 64,
32};
33
34HistogramCodecType PayloadNameToHistogramCodecType(
35 const std::string& payload_name) {
36 if (payload_name == "VP8") {
37 return kVideoVp8;
38 } else if (payload_name == "VP9") {
39 return kVideoVp9;
40 } else if (payload_name == "H264") {
41 return kVideoH264;
42 } else {
43 return kVideoUnknown;
44 }
45}
46
47void UpdateCodecTypeHistogram(const std::string& payload_name) {
48 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.Encoder.CodecType",
49 PayloadNameToHistogramCodecType(payload_name), kVideoMax);
50}
51} // namespace
52
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000053
pbos@webrtc.org273a4142014-12-01 15:23:21 +000054const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
55
56SendStatisticsProxy::SendStatisticsProxy(Clock* clock,
57 const VideoSendStream::Config& config)
asaperssond89920b2015-07-22 06:52:00 -070058 : clock_(clock),
59 config_(config),
Tim Psiaki63046262015-09-14 10:38:08 -070060 input_frame_rate_tracker_(100u, 10u),
61 sent_frame_rate_tracker_(100u, 10u),
asaperssond89920b2015-07-22 06:52:00 -070062 last_sent_frame_timestamp_(0),
63 max_sent_width_per_timestamp_(0),
64 max_sent_height_per_timestamp_(0) {
asapersson2a0a2a42015-10-27 01:32:00 -070065 UpdateCodecTypeHistogram(config_.encoder_settings.payload_name);
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +000066}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000067
Åsa Persson24b4eda2015-06-16 10:17:01 +020068SendStatisticsProxy::~SendStatisticsProxy() {
69 UpdateHistograms();
70}
71
72void SendStatisticsProxy::UpdateHistograms() {
73 int input_fps =
Tim Psiakiad13d2f2015-11-10 16:34:50 -080074 round(input_frame_rate_tracker_.ComputeTotalRate());
Åsa Persson24b4eda2015-06-16 10:17:01 +020075 if (input_fps > 0)
76 RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.InputFramesPerSecond", input_fps);
asaperssond89920b2015-07-22 06:52:00 -070077 int sent_fps =
Tim Psiakiad13d2f2015-11-10 16:34:50 -080078 round(sent_frame_rate_tracker_.ComputeTotalRate());
Åsa Persson24b4eda2015-06-16 10:17:01 +020079 if (sent_fps > 0)
80 RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.SentFramesPerSecond", sent_fps);
asaperssond89920b2015-07-22 06:52:00 -070081
asapersson6718e972015-07-24 00:20:58 -070082 const int kMinRequiredSamples = 200;
asaperssond89920b2015-07-22 06:52:00 -070083 int in_width = input_width_counter_.Avg(kMinRequiredSamples);
84 int in_height = input_height_counter_.Avg(kMinRequiredSamples);
85 if (in_width != -1) {
86 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.InputWidthInPixels", in_width);
87 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.InputHeightInPixels", in_height);
88 }
89 int sent_width = sent_width_counter_.Avg(kMinRequiredSamples);
90 int sent_height = sent_height_counter_.Avg(kMinRequiredSamples);
91 if (sent_width != -1) {
92 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.SentWidthInPixels", sent_width);
93 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.SentHeightInPixels", sent_height);
94 }
asapersson6718e972015-07-24 00:20:58 -070095 int encode_ms = encode_time_counter_.Avg(kMinRequiredSamples);
96 if (encode_ms != -1)
97 RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.EncodeTimeInMs", encode_ms);
asaperssondec5ebf2015-10-05 02:36:17 -070098
99 int key_frames_permille = key_frame_counter_.Permille(kMinRequiredSamples);
100 if (key_frames_permille != -1) {
101 RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.KeyFramesSentInPermille",
102 key_frames_permille);
103 }
asapersson4306fc72015-10-19 00:35:21 -0700104 int quality_limited =
105 quality_limited_frame_counter_.Percent(kMinRequiredSamples);
106 if (quality_limited != -1) {
107 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.QualityLimitedResolutionInPercent",
108 quality_limited);
109 }
110 int downscales = quality_downscales_counter_.Avg(kMinRequiredSamples);
111 if (downscales != -1) {
112 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.QualityLimitedResolutionDownscales",
113 downscales, 20);
114 }
asaperssonda535c42015-10-19 23:32:41 -0700115 int bw_limited = bw_limited_frame_counter_.Percent(kMinRequiredSamples);
116 if (bw_limited != -1) {
117 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.BandwidthLimitedResolutionInPercent",
118 bw_limited);
119 }
120 int num_disabled = bw_resolutions_disabled_counter_.Avg(kMinRequiredSamples);
121 if (num_disabled != -1) {
122 RTC_HISTOGRAM_ENUMERATION(
123 "WebRTC.Video.BandwidthLimitedResolutionsDisabled", num_disabled, 10);
124 }
asaperssonf040b232015-11-04 00:59:03 -0800125 int delay_ms = delay_counter_.Avg(kMinRequiredSamples);
126 if (delay_ms != -1)
127 RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendSideDelayInMs", delay_ms);
128
129 int max_delay_ms = max_delay_counter_.Avg(kMinRequiredSamples);
130 if (max_delay_ms != -1) {
131 RTC_HISTOGRAM_COUNTS_100000(
132 "WebRTC.Video.SendSideDelayMaxInMs", max_delay_ms);
133 }
Åsa Persson24b4eda2015-06-16 10:17:01 +0200134}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000135
Peter Boström7083e112015-09-22 16:28:51 +0200136void SendStatisticsProxy::OnOutgoingRate(uint32_t framerate, uint32_t bitrate) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200137 rtc::CritScope lock(&crit_);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000138 stats_.encode_frame_rate = framerate;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000139 stats_.media_bitrate_bps = bitrate;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000140}
141
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000142void SendStatisticsProxy::CpuOveruseMetricsUpdated(
143 const CpuOveruseMetrics& metrics) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200144 rtc::CritScope lock(&crit_);
asapersson6718e972015-07-24 00:20:58 -0700145 // TODO(asapersson): Change to use OnEncodedFrame() for avg_encode_time_ms.
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000146 stats_.avg_encode_time_ms = metrics.avg_encode_time_ms;
147 stats_.encode_usage_percent = metrics.encode_usage_percent;
148}
149
Peter Boström7083e112015-09-22 16:28:51 +0200150void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200151 rtc::CritScope lock(&crit_);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000152 stats_.suspended = is_suspended;
153}
154
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000155VideoSendStream::Stats SendStatisticsProxy::GetStats() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200156 rtc::CritScope lock(&crit_);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000157 PurgeOldStats();
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000158 stats_.input_frame_rate =
Tim Psiakiad13d2f2015-11-10 16:34:50 -0800159 round(input_frame_rate_tracker_.ComputeRate());
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000160 return stats_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000161}
162
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000163void SendStatisticsProxy::PurgeOldStats() {
Peter Boström20f3f942015-05-15 11:33:39 +0200164 int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000165 for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
166 stats_.substreams.begin();
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000167 it != stats_.substreams.end(); ++it) {
168 uint32_t ssrc = it->first;
Peter Boström20f3f942015-05-15 11:33:39 +0200169 if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
170 it->second.width = 0;
171 it->second.height = 0;
172 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000173 }
174}
175
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000176VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
177 uint32_t ssrc) {
178 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
179 stats_.substreams.find(ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000180 if (it != stats_.substreams.end())
181 return &it->second;
182
183 if (std::find(config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc) ==
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000184 config_.rtp.ssrcs.end() &&
185 std::find(config_.rtp.rtx.ssrcs.begin(),
186 config_.rtp.rtx.ssrcs.end(),
187 ssrc) == config_.rtp.rtx.ssrcs.end()) {
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000188 return nullptr;
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000189 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000190
191 return &stats_.substreams[ssrc]; // Insert new entry and return ptr.
192}
193
Peter Boström20f3f942015-05-15 11:33:39 +0200194void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
195 rtc::CritScope lock(&crit_);
196 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
197 if (stats == nullptr)
198 return;
199
200 stats->total_bitrate_bps = 0;
201 stats->retransmit_bitrate_bps = 0;
202 stats->height = 0;
203 stats->width = 0;
204}
205
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000206void SendStatisticsProxy::OnSetRates(uint32_t bitrate_bps, int framerate) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200207 rtc::CritScope lock(&crit_);
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000208 stats_.target_media_bitrate_bps = bitrate_bps;
209}
210
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000211void SendStatisticsProxy::OnSendEncodedImage(
212 const EncodedImage& encoded_image,
213 const RTPVideoHeader* rtp_video_header) {
214 size_t simulcast_idx =
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000215 rtp_video_header != nullptr ? rtp_video_header->simulcastIdx : 0;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000216 if (simulcast_idx >= config_.rtp.ssrcs.size()) {
217 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx
218 << " >= " << config_.rtp.ssrcs.size() << ").";
219 return;
220 }
221 uint32_t ssrc = config_.rtp.ssrcs[simulcast_idx];
222
Peter Boströmf2f82832015-05-01 13:00:41 +0200223 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000224 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000225 if (stats == nullptr)
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000226 return;
227
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000228 stats->width = encoded_image._encodedWidth;
229 stats->height = encoded_image._encodedHeight;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000230 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
asaperssond89920b2015-07-22 06:52:00 -0700231
Peter Boström49e196a2015-10-23 15:58:18 +0200232 key_frame_counter_.Add(encoded_image._frameType == kVideoFrameKey);
asaperssondec5ebf2015-10-05 02:36:17 -0700233
asapersson4306fc72015-10-19 00:35:21 -0700234 if (encoded_image.adapt_reason_.quality_resolution_downscales != -1) {
235 bool downscaled =
236 encoded_image.adapt_reason_.quality_resolution_downscales > 0;
237 quality_limited_frame_counter_.Add(downscaled);
238 if (downscaled) {
239 quality_downscales_counter_.Add(
240 encoded_image.adapt_reason_.quality_resolution_downscales);
241 }
242 }
asaperssonda535c42015-10-19 23:32:41 -0700243 if (encoded_image.adapt_reason_.bw_resolutions_disabled != -1) {
244 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
245 bw_limited_frame_counter_.Add(bw_limited);
246 if (bw_limited) {
247 bw_resolutions_disabled_counter_.Add(
248 encoded_image.adapt_reason_.bw_resolutions_disabled);
249 }
250 }
asapersson4306fc72015-10-19 00:35:21 -0700251
asaperssond89920b2015-07-22 06:52:00 -0700252 // TODO(asapersson): This is incorrect if simulcast layers are encoded on
253 // different threads and there is no guarantee that one frame of all layers
254 // are encoded before the next start.
255 if (last_sent_frame_timestamp_ > 0 &&
256 encoded_image._timeStamp != last_sent_frame_timestamp_) {
Tim Psiaki63046262015-09-14 10:38:08 -0700257 sent_frame_rate_tracker_.AddSamples(1);
asaperssond89920b2015-07-22 06:52:00 -0700258 sent_width_counter_.Add(max_sent_width_per_timestamp_);
259 sent_height_counter_.Add(max_sent_height_per_timestamp_);
260 max_sent_width_per_timestamp_ = 0;
261 max_sent_height_per_timestamp_ = 0;
Åsa Persson24b4eda2015-06-16 10:17:01 +0200262 }
asaperssond89920b2015-07-22 06:52:00 -0700263 last_sent_frame_timestamp_ = encoded_image._timeStamp;
264 max_sent_width_per_timestamp_ =
265 std::max(max_sent_width_per_timestamp_,
266 static_cast<int>(encoded_image._encodedWidth));
267 max_sent_height_per_timestamp_ =
268 std::max(max_sent_height_per_timestamp_,
269 static_cast<int>(encoded_image._encodedHeight));
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000270}
271
asaperssond89920b2015-07-22 06:52:00 -0700272void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200273 rtc::CritScope lock(&crit_);
Tim Psiaki63046262015-09-14 10:38:08 -0700274 input_frame_rate_tracker_.AddSamples(1);
asaperssond89920b2015-07-22 06:52:00 -0700275 input_width_counter_.Add(width);
276 input_height_counter_.Add(height);
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000277}
278
asapersson6718e972015-07-24 00:20:58 -0700279void SendStatisticsProxy::OnEncodedFrame(int encode_time_ms) {
280 rtc::CritScope lock(&crit_);
281 encode_time_counter_.Add(encode_time_ms);
282}
283
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000284void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
285 uint32_t ssrc,
286 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200287 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000288 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000289 if (stats == nullptr)
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000290 return;
291
292 stats->rtcp_packet_type_counts = packet_counter;
293}
294
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000295void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
296 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200297 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000298 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000299 if (stats == nullptr)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000300 return;
301
302 stats->rtcp_stats = statistics;
303}
304
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000305void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {
306}
307
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000308void SendStatisticsProxy::DataCountersUpdated(
309 const StreamDataCounters& counters,
310 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200311 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000312 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
henrikg91d6ede2015-09-17 00:24:34 -0700313 RTC_DCHECK(stats != nullptr)
314 << "DataCountersUpdated reported for unknown ssrc: " << ssrc;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000315
316 stats->rtp_stats = counters;
317}
318
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000319void SendStatisticsProxy::Notify(const BitrateStatistics& total_stats,
320 const BitrateStatistics& retransmit_stats,
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000321 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200322 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000323 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000324 if (stats == nullptr)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000325 return;
326
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000327 stats->total_bitrate_bps = total_stats.bitrate_bps;
328 stats->retransmit_bitrate_bps = retransmit_stats.bitrate_bps;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000329}
330
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000331void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
332 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200333 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000334 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000335 if (stats == nullptr)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000336 return;
337
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000338 stats->frame_counts = frame_counts;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000339}
340
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000341void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
342 int max_delay_ms,
343 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200344 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000345 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000346 if (stats == nullptr)
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000347 return;
348 stats->avg_delay_ms = avg_delay_ms;
349 stats->max_delay_ms = max_delay_ms;
asaperssonf040b232015-11-04 00:59:03 -0800350
351 delay_counter_.Add(avg_delay_ms);
352 max_delay_counter_.Add(max_delay_ms);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000353}
354
asaperssond89920b2015-07-22 06:52:00 -0700355void SendStatisticsProxy::SampleCounter::Add(int sample) {
356 sum += sample;
357 ++num_samples;
358}
359
360int SendStatisticsProxy::SampleCounter::Avg(int min_required_samples) const {
361 if (num_samples < min_required_samples || num_samples == 0)
362 return -1;
asaperssonda535c42015-10-19 23:32:41 -0700363 return (sum + (num_samples / 2)) / num_samples;
asaperssond89920b2015-07-22 06:52:00 -0700364}
365
asaperssondec5ebf2015-10-05 02:36:17 -0700366void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
367 if (sample)
368 ++sum;
369 ++num_samples;
370}
371
372int SendStatisticsProxy::BoolSampleCounter::Percent(
373 int min_required_samples) const {
374 return Fraction(min_required_samples, 100.0f);
375}
376
377int SendStatisticsProxy::BoolSampleCounter::Permille(
378 int min_required_samples) const {
379 return Fraction(min_required_samples, 1000.0f);
380}
381
382int SendStatisticsProxy::BoolSampleCounter::Fraction(
383 int min_required_samples, float multiplier) const {
384 if (num_samples < min_required_samples || num_samples == 0)
385 return -1;
386 return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
387}
388
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000389} // namespace webrtc