blob: 0b8f12bcfe75135cf5e97098c45bff9c06f965eb [file] [log] [blame]
sprang@webrtc.org09315702014-02-07 12:06:29 +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/receive_statistics_proxy.h"
12
asaperssonf839dcc2015-10-08 00:41:59 -070013#include <cmath>
14
15#include "webrtc/base/checks.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010016#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010017#include "webrtc/system_wrappers/include/clock.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010018#include "webrtc/system_wrappers/include/metrics.h"
sprang@webrtc.org09315702014-02-07 12:06:29 +000019
20namespace webrtc {
sprang@webrtc.org09315702014-02-07 12:06:29 +000021
sprang0ab8e812016-02-24 01:35:40 -080022ReceiveStatisticsProxy::ReceiveStatisticsProxy(
23 const VideoReceiveStream::Config& config,
24 Clock* clock)
pbos@webrtc.org55707692014-12-19 15:45:03 +000025 : clock_(clock),
sprang0ab8e812016-02-24 01:35:40 -080026 config_(config),
sprang@webrtc.org09315702014-02-07 12:06:29 +000027 // 1000ms window, scale 1000 for ms to s.
28 decode_fps_estimator_(1000, 1000),
Tim Psiaki63046262015-09-14 10:38:08 -070029 renders_fps_estimator_(1000, 1000),
asaperssonf839dcc2015-10-08 00:41:59 -070030 render_fps_tracker_(100u, 10u),
31 render_pixel_tracker_(100u, 10u) {
sprang0ab8e812016-02-24 01:35:40 -080032 stats_.ssrc = config.rtp.remote_ssrc;
33 for (auto it : config.rtp.rtx)
34 rtx_stats_[it.second.ssrc] = StreamDataCounters();
sprang@webrtc.org09315702014-02-07 12:06:29 +000035}
36
Åsa Persson3c391cb2015-04-27 10:09:49 +020037ReceiveStatisticsProxy::~ReceiveStatisticsProxy() {
38 UpdateHistograms();
39}
40
asaperssond89920b2015-07-22 06:52:00 -070041void ReceiveStatisticsProxy::UpdateHistograms() {
42 int fraction_lost = report_block_stats_.FractionLostInPercent();
Åsa Persson3c391cb2015-04-27 10:09:49 +020043 if (fraction_lost != -1) {
asapersson58d992e2016-03-29 02:15:06 -070044 RTC_LOGGED_HISTOGRAM_PERCENTAGE("WebRTC.Video.ReceivedPacketsLostInPercent",
45 fraction_lost);
Åsa Persson3c391cb2015-04-27 10:09:49 +020046 }
asapersson6718e972015-07-24 00:20:58 -070047 const int kMinRequiredSamples = 200;
asaperssonf839dcc2015-10-08 00:41:59 -070048 int samples = static_cast<int>(render_fps_tracker_.TotalSampleCount());
49 if (samples > kMinRequiredSamples) {
asapersson58d992e2016-03-29 02:15:06 -070050 RTC_LOGGED_HISTOGRAM_COUNTS_100(
51 "WebRTC.Video.RenderFramesPerSecond",
52 round(render_fps_tracker_.ComputeTotalRate()));
53 RTC_LOGGED_HISTOGRAM_COUNTS_100000(
asapersson28ba9272016-01-25 05:58:23 -080054 "WebRTC.Video.RenderSqrtPixelsPerSecond",
Tim Psiakiad13d2f2015-11-10 16:34:50 -080055 round(render_pixel_tracker_.ComputeTotalRate()));
asaperssonf839dcc2015-10-08 00:41:59 -070056 }
asaperssond89920b2015-07-22 06:52:00 -070057 int width = render_width_counter_.Avg(kMinRequiredSamples);
58 int height = render_height_counter_.Avg(kMinRequiredSamples);
59 if (width != -1) {
asapersson58d992e2016-03-29 02:15:06 -070060 RTC_LOGGED_HISTOGRAM_COUNTS_10000("WebRTC.Video.ReceivedWidthInPixels",
61 width);
62 RTC_LOGGED_HISTOGRAM_COUNTS_10000("WebRTC.Video.ReceivedHeightInPixels",
63 height);
asaperssond89920b2015-07-22 06:52:00 -070064 }
asaperssonf8cdd182016-03-15 01:00:47 -070065 int sync_offset_ms = sync_offset_counter_.Avg(kMinRequiredSamples);
pbos35fdb2a2016-05-03 03:32:10 -070066 if (sync_offset_ms != -1) {
67 RTC_LOGGED_HISTOGRAM_COUNTS_10000("WebRTC.Video.AVSyncOffsetInMs",
68 sync_offset_ms);
69 }
asaperssonf8cdd182016-03-15 01:00:47 -070070
asapersson86b01602015-10-20 23:55:26 -070071 int qp = qp_counters_.vp8.Avg(kMinRequiredSamples);
72 if (qp != -1)
asapersson58d992e2016-03-29 02:15:06 -070073 RTC_LOGGED_HISTOGRAM_COUNTS_200("WebRTC.Video.Decoded.Vp8.Qp", qp);
asapersson86b01602015-10-20 23:55:26 -070074
asapersson6718e972015-07-24 00:20:58 -070075 // TODO(asapersson): DecoderTiming() is call periodically (each 1000ms) and
76 // not per frame. Change decode time to include every frame.
77 const int kMinRequiredDecodeSamples = 5;
78 int decode_ms = decode_time_counter_.Avg(kMinRequiredDecodeSamples);
79 if (decode_ms != -1)
asapersson58d992e2016-03-29 02:15:06 -070080 RTC_LOGGED_HISTOGRAM_COUNTS_1000("WebRTC.Video.DecodeTimeInMs", decode_ms);
asapersson13c433c2015-10-06 04:08:15 -070081
asapersson8688a4e2016-04-27 23:42:35 -070082 int jb_delay_ms = jitter_buffer_delay_counter_.Avg(kMinRequiredDecodeSamples);
83 if (jb_delay_ms != -1) {
84 RTC_LOGGED_HISTOGRAM_COUNTS_10000("WebRTC.Video.JitterBufferDelayInMs",
85 jb_delay_ms);
86 }
87 int target_delay_ms = target_delay_counter_.Avg(kMinRequiredDecodeSamples);
88 if (target_delay_ms != -1) {
89 RTC_LOGGED_HISTOGRAM_COUNTS_10000("WebRTC.Video.TargetDelayInMs",
90 target_delay_ms);
91 }
92 int current_delay_ms = current_delay_counter_.Avg(kMinRequiredDecodeSamples);
93 if (current_delay_ms != -1) {
94 RTC_LOGGED_HISTOGRAM_COUNTS_10000("WebRTC.Video.CurrentDelayInMs",
95 current_delay_ms);
96 }
97
asapersson13c433c2015-10-06 04:08:15 -070098 int delay_ms = delay_counter_.Avg(kMinRequiredDecodeSamples);
99 if (delay_ms != -1)
asapersson58d992e2016-03-29 02:15:06 -0700100 RTC_LOGGED_HISTOGRAM_COUNTS_10000("WebRTC.Video.OnewayDelayInMs", delay_ms);
sprang0ab8e812016-02-24 01:35:40 -0800101
102 StreamDataCounters rtp = stats_.rtp_stats;
103 StreamDataCounters rtx;
104 for (auto it : rtx_stats_)
105 rtx.Add(it.second);
106 StreamDataCounters rtp_rtx = rtp;
107 rtp_rtx.Add(rtx);
108 int64_t elapsed_sec =
109 rtp_rtx.TimeSinceFirstPacketInMs(clock_->TimeInMilliseconds()) / 1000;
110 if (elapsed_sec > metrics::kMinRunTimeInSeconds) {
asapersson58d992e2016-03-29 02:15:06 -0700111 RTC_LOGGED_HISTOGRAM_COUNTS_10000(
sprang0ab8e812016-02-24 01:35:40 -0800112 "WebRTC.Video.BitrateReceivedInKbps",
113 static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
114 1000));
asapersson58d992e2016-03-29 02:15:06 -0700115 RTC_LOGGED_HISTOGRAM_COUNTS_10000(
sprang0ab8e812016-02-24 01:35:40 -0800116 "WebRTC.Video.MediaBitrateReceivedInKbps",
117 static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000));
asapersson58d992e2016-03-29 02:15:06 -0700118 RTC_LOGGED_HISTOGRAM_COUNTS_10000(
sprang0ab8e812016-02-24 01:35:40 -0800119 "WebRTC.Video.PaddingBitrateReceivedInKbps",
120 static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec /
121 1000));
asapersson58d992e2016-03-29 02:15:06 -0700122 RTC_LOGGED_HISTOGRAM_COUNTS_10000(
sprang0ab8e812016-02-24 01:35:40 -0800123 "WebRTC.Video.RetransmittedBitrateReceivedInKbps",
124 static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 / elapsed_sec /
125 1000));
126 if (!rtx_stats_.empty()) {
asapersson58d992e2016-03-29 02:15:06 -0700127 RTC_LOGGED_HISTOGRAM_COUNTS_10000(
128 "WebRTC.Video.RtxBitrateReceivedInKbps",
129 static_cast<int>(rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
130 1000));
sprang0ab8e812016-02-24 01:35:40 -0800131 }
132 if (config_.rtp.fec.ulpfec_payload_type != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700133 RTC_LOGGED_HISTOGRAM_COUNTS_10000(
sprang0ab8e812016-02-24 01:35:40 -0800134 "WebRTC.Video.FecBitrateReceivedInKbps",
135 static_cast<int>(rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec / 1000));
136 }
sprang07fb9be2016-02-24 07:55:00 -0800137 const RtcpPacketTypeCounter& counters = stats_.rtcp_packet_type_counts;
asapersson58d992e2016-03-29 02:15:06 -0700138 RTC_LOGGED_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsSentPerMinute",
139 counters.nack_packets * 60 / elapsed_sec);
140 RTC_LOGGED_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsSentPerMinute",
141 counters.fir_packets * 60 / elapsed_sec);
142 RTC_LOGGED_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute",
143 counters.pli_packets * 60 / elapsed_sec);
sprang07fb9be2016-02-24 07:55:00 -0800144 if (counters.nack_requests > 0) {
asapersson58d992e2016-03-29 02:15:06 -0700145 RTC_LOGGED_HISTOGRAM_PERCENTAGE(
146 "WebRTC.Video.UniqueNackRequestsSentInPercent",
147 counters.UniqueNackRequestsInPercent());
sprang07fb9be2016-02-24 07:55:00 -0800148 }
sprang0ab8e812016-02-24 01:35:40 -0800149 }
Åsa Persson3c391cb2015-04-27 10:09:49 +0200150}
sprang@webrtc.org09315702014-02-07 12:06:29 +0000151
152VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const {
Peter Boströmf2f82832015-05-01 13:00:41 +0200153 rtc::CritScope lock(&crit_);
pbos@webrtc.org55707692014-12-19 15:45:03 +0000154 return stats_;
sprang@webrtc.org09315702014-02-07 12:06:29 +0000155}
156
pbosf42376c2015-08-28 07:35:32 -0700157void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) {
158 rtc::CritScope lock(&crit_);
159 stats_.current_payload_type = payload_type;
160}
161
Peter Boströmb7d9a972015-12-18 16:01:11 +0100162void ReceiveStatisticsProxy::OnDecoderImplementationName(
163 const char* implementation_name) {
164 rtc::CritScope lock(&crit_);
165 stats_.decoder_implementation_name = implementation_name;
166}
pbosf42376c2015-08-28 07:35:32 -0700167void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate,
168 unsigned int bitrate_bps) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200169 rtc::CritScope lock(&crit_);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000170 stats_.network_frame_rate = framerate;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000171 stats_.total_bitrate_bps = bitrate_bps;
sprang@webrtc.org09315702014-02-07 12:06:29 +0000172}
173
pbosf42376c2015-08-28 07:35:32 -0700174void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms,
175 int max_decode_ms,
176 int current_delay_ms,
177 int target_delay_ms,
178 int jitter_buffer_ms,
179 int min_playout_delay_ms,
asapersson13c433c2015-10-06 04:08:15 -0700180 int render_delay_ms,
181 int64_t rtt_ms) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200182 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000183 stats_.decode_ms = decode_ms;
184 stats_.max_decode_ms = max_decode_ms;
185 stats_.current_delay_ms = current_delay_ms;
186 stats_.target_delay_ms = target_delay_ms;
187 stats_.jitter_buffer_ms = jitter_buffer_ms;
188 stats_.min_playout_delay_ms = min_playout_delay_ms;
189 stats_.render_delay_ms = render_delay_ms;
asapersson6718e972015-07-24 00:20:58 -0700190 decode_time_counter_.Add(decode_ms);
asapersson8688a4e2016-04-27 23:42:35 -0700191 jitter_buffer_delay_counter_.Add(jitter_buffer_ms);
192 target_delay_counter_.Add(target_delay_ms);
193 current_delay_counter_.Add(current_delay_ms);
asaperssona1862882016-04-18 00:41:05 -0700194 // Network delay (rtt/2) + target_delay_ms (jitter delay + decode time +
195 // render delay).
196 delay_counter_.Add(target_delay_ms + rtt_ms / 2);
pbos@webrtc.org98c04b32014-12-18 13:12:52 +0000197}
198
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000199void ReceiveStatisticsProxy::RtcpPacketTypesCounterUpdated(
200 uint32_t ssrc,
201 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200202 rtc::CritScope lock(&crit_);
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000203 if (stats_.ssrc != ssrc)
204 return;
205 stats_.rtcp_packet_type_counts = packet_counter;
206}
207
sprang@webrtc.org09315702014-02-07 12:06:29 +0000208void ReceiveStatisticsProxy::StatisticsUpdated(
209 const webrtc::RtcpStatistics& statistics,
210 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200211 rtc::CritScope lock(&crit_);
henrikg91d6ede2015-09-17 00:24:34 -0700212 // TODO(pbos): Handle both local and remote ssrcs here and RTC_DCHECK that we
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000213 // receive stats from one of them.
214 if (stats_.ssrc != ssrc)
215 return;
sprang@webrtc.org09315702014-02-07 12:06:29 +0000216 stats_.rtcp_stats = statistics;
Åsa Persson3c391cb2015-04-27 10:09:49 +0200217 report_block_stats_.Store(statistics, ssrc, 0);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000218}
219
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000220void ReceiveStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200221 rtc::CritScope lock(&crit_);
henrikg91d6ede2015-09-17 00:24:34 -0700222 // TODO(pbos): Handle both local and remote ssrcs here and RTC_DCHECK that we
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000223 // receive stats from one of them.
224 if (stats_.ssrc != ssrc)
225 return;
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000226 stats_.c_name = cname;
227}
228
sprang@webrtc.org09315702014-02-07 12:06:29 +0000229void ReceiveStatisticsProxy::DataCountersUpdated(
230 const webrtc::StreamDataCounters& counters,
231 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200232 rtc::CritScope lock(&crit_);
sprang0ab8e812016-02-24 01:35:40 -0800233 if (ssrc == stats_.ssrc) {
234 stats_.rtp_stats = counters;
235 } else {
236 auto it = rtx_stats_.find(ssrc);
237 if (it != rtx_stats_.end()) {
238 it->second = counters;
239 } else {
240 RTC_NOTREACHED() << "Unexpected stream ssrc: " << ssrc;
241 }
242 }
sprang@webrtc.org09315702014-02-07 12:06:29 +0000243}
244
245void ReceiveStatisticsProxy::OnDecodedFrame() {
246 uint64_t now = clock_->TimeInMilliseconds();
247
Peter Boströmf2f82832015-05-01 13:00:41 +0200248 rtc::CritScope lock(&crit_);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000249 decode_fps_estimator_.Update(1, now);
250 stats_.decode_frame_rate = decode_fps_estimator_.Rate(now);
251}
252
asaperssona1862882016-04-18 00:41:05 -0700253void ReceiveStatisticsProxy::OnRenderedFrame(int width, int height) {
asaperssonf839dcc2015-10-08 00:41:59 -0700254 RTC_DCHECK_GT(width, 0);
255 RTC_DCHECK_GT(height, 0);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000256 uint64_t now = clock_->TimeInMilliseconds();
257
Peter Boströmf2f82832015-05-01 13:00:41 +0200258 rtc::CritScope lock(&crit_);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000259 renders_fps_estimator_.Update(1, now);
260 stats_.render_frame_rate = renders_fps_estimator_.Rate(now);
asaperssond89920b2015-07-22 06:52:00 -0700261 render_width_counter_.Add(width);
262 render_height_counter_.Add(height);
Tim Psiaki63046262015-09-14 10:38:08 -0700263 render_fps_tracker_.AddSamples(1);
asaperssonf839dcc2015-10-08 00:41:59 -0700264 render_pixel_tracker_.AddSamples(sqrt(width * height));
sprang@webrtc.org09315702014-02-07 12:06:29 +0000265}
266
asaperssonf8cdd182016-03-15 01:00:47 -0700267void ReceiveStatisticsProxy::OnSyncOffsetUpdated(int64_t sync_offset_ms) {
268 rtc::CritScope lock(&crit_);
269 sync_offset_counter_.Add(std::abs(sync_offset_ms));
270 stats_.sync_offset_ms = sync_offset_ms;
271}
272
pbos@webrtc.org55707692014-12-19 15:45:03 +0000273void ReceiveStatisticsProxy::OnReceiveRatesUpdated(uint32_t bitRate,
274 uint32_t frameRate) {
275}
276
277void ReceiveStatisticsProxy::OnFrameCountsUpdated(
278 const FrameCounts& frame_counts) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200279 rtc::CritScope lock(&crit_);
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000280 stats_.frame_counts = frame_counts;
281}
282
pbos@webrtc.org55707692014-12-19 15:45:03 +0000283void ReceiveStatisticsProxy::OnDiscardedPacketsUpdated(int discarded_packets) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200284 rtc::CritScope lock(&crit_);
pbos@webrtc.org55707692014-12-19 15:45:03 +0000285 stats_.discarded_packets = discarded_packets;
286}
287
asapersson86b01602015-10-20 23:55:26 -0700288void ReceiveStatisticsProxy::OnPreDecode(
289 const EncodedImage& encoded_image,
290 const CodecSpecificInfo* codec_specific_info) {
Peter Boström74f6e9e2016-04-04 17:56:10 +0200291 if (!codec_specific_info || encoded_image.qp_ == -1) {
asapersson86b01602015-10-20 23:55:26 -0700292 return;
293 }
294 if (codec_specific_info->codecType == kVideoCodecVP8) {
295 qp_counters_.vp8.Add(encoded_image.qp_);
296 }
297}
298
asaperssond89920b2015-07-22 06:52:00 -0700299void ReceiveStatisticsProxy::SampleCounter::Add(int sample) {
300 sum += sample;
301 ++num_samples;
302}
303
304int ReceiveStatisticsProxy::SampleCounter::Avg(int min_required_samples) const {
305 if (num_samples < min_required_samples || num_samples == 0)
306 return -1;
307 return sum / num_samples;
308}
309
sprang@webrtc.org09315702014-02-07 12:06:29 +0000310} // namespace webrtc