Line data Source code
1 : /*
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/modules/rtp_rtcp/source/receive_statistics_impl.h"
12 :
13 : #include <math.h>
14 :
15 : #include <cstdlib>
16 :
17 : #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
18 : #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
19 : #include "webrtc/modules/rtp_rtcp/source/time_util.h"
20 :
21 : namespace webrtc {
22 :
23 : const int64_t kStatisticsTimeoutMs = 8000;
24 : const int64_t kStatisticsProcessIntervalMs = 1000;
25 :
26 0 : StreamStatistician::~StreamStatistician() {}
27 :
28 0 : StreamStatisticianImpl::StreamStatisticianImpl(
29 : Clock* clock,
30 : RtcpStatisticsCallback* rtcp_callback,
31 0 : StreamDataCountersCallback* rtp_callback)
32 : : clock_(clock),
33 : incoming_bitrate_(kStatisticsProcessIntervalMs,
34 : RateStatistics::kBpsScale),
35 : ssrc_(0),
36 : max_reordering_threshold_(kDefaultMaxReorderingThreshold),
37 : jitter_q4_(0),
38 : cumulative_loss_(0),
39 : jitter_q4_transmission_time_offset_(0),
40 : last_receive_time_ms_(0),
41 : last_received_timestamp_(0),
42 : last_received_transmission_time_offset_(0),
43 : received_seq_first_(0),
44 : received_seq_max_(0),
45 : received_seq_wraps_(0),
46 : received_packet_overhead_(12),
47 : last_report_inorder_packets_(0),
48 : last_report_old_packets_(0),
49 : last_report_seq_max_(0),
50 : rtcp_callback_(rtcp_callback),
51 0 : rtp_callback_(rtp_callback) {}
52 :
53 0 : void StreamStatisticianImpl::IncomingPacket(const RTPHeader& header,
54 : size_t packet_length,
55 : bool retransmitted) {
56 0 : UpdateCounters(header, packet_length, retransmitted);
57 0 : NotifyRtpCallback();
58 0 : }
59 :
60 0 : void StreamStatisticianImpl::UpdateCounters(const RTPHeader& header,
61 : size_t packet_length,
62 : bool retransmitted) {
63 0 : rtc::CritScope cs(&stream_lock_);
64 0 : bool in_order = InOrderPacketInternal(header.sequenceNumber);
65 0 : ssrc_ = header.ssrc;
66 0 : incoming_bitrate_.Update(packet_length, clock_->TimeInMilliseconds());
67 0 : receive_counters_.transmitted.AddPacket(packet_length, header);
68 0 : if (!in_order && retransmitted) {
69 0 : receive_counters_.retransmitted.AddPacket(packet_length, header);
70 : }
71 :
72 0 : if (receive_counters_.transmitted.packets == 1) {
73 0 : received_seq_first_ = header.sequenceNumber;
74 0 : receive_counters_.first_packet_time_ms = clock_->TimeInMilliseconds();
75 : }
76 :
77 : // Count only the new packets received. That is, if packets 1, 2, 3, 5, 4, 6
78 : // are received, 4 will be ignored.
79 0 : if (in_order) {
80 : // Current time in samples.
81 0 : NtpTime receive_time(*clock_);
82 :
83 : // Wrong if we use RetransmitOfOldPacket.
84 0 : if (receive_counters_.transmitted.packets > 1 &&
85 0 : received_seq_max_ > header.sequenceNumber) {
86 : // Wrap around detected.
87 0 : received_seq_wraps_++;
88 : }
89 : // New max.
90 0 : received_seq_max_ = header.sequenceNumber;
91 :
92 : // If new time stamp and more than one in-order packet received, calculate
93 : // new jitter statistics.
94 0 : if (header.timestamp != last_received_timestamp_ &&
95 0 : (receive_counters_.transmitted.packets -
96 0 : receive_counters_.retransmitted.packets) > 1) {
97 0 : UpdateJitter(header, receive_time);
98 : }
99 0 : last_received_timestamp_ = header.timestamp;
100 0 : last_receive_time_ntp_ = receive_time;
101 0 : last_receive_time_ms_ = clock_->TimeInMilliseconds();
102 : }
103 :
104 0 : size_t packet_oh = header.headerLength + header.paddingLength;
105 :
106 : // Our measured overhead. Filter from RFC 5104 4.2.1.2:
107 : // avg_OH (new) = 15/16*avg_OH (old) + 1/16*pckt_OH,
108 0 : received_packet_overhead_ = (15 * received_packet_overhead_ + packet_oh) >> 4;
109 0 : }
110 :
111 0 : void StreamStatisticianImpl::UpdateJitter(const RTPHeader& header,
112 : NtpTime receive_time) {
113 : uint32_t receive_time_rtp =
114 0 : NtpToRtp(receive_time, header.payload_type_frequency);
115 : uint32_t last_receive_time_rtp =
116 0 : NtpToRtp(last_receive_time_ntp_, header.payload_type_frequency);
117 0 : int32_t time_diff_samples = (receive_time_rtp - last_receive_time_rtp) -
118 0 : (header.timestamp - last_received_timestamp_);
119 :
120 0 : time_diff_samples = std::abs(time_diff_samples);
121 :
122 : // lib_jingle sometimes deliver crazy jumps in TS for the same stream.
123 : // If this happens, don't update jitter value. Use 5 secs video frequency
124 : // as the threshold.
125 0 : if (time_diff_samples < 450000) {
126 : // Note we calculate in Q4 to avoid using float.
127 0 : int32_t jitter_diff_q4 = (time_diff_samples << 4) - jitter_q4_;
128 0 : jitter_q4_ += ((jitter_diff_q4 + 8) >> 4);
129 : }
130 :
131 : // Extended jitter report, RFC 5450.
132 : // Actual network jitter, excluding the source-introduced jitter.
133 : int32_t time_diff_samples_ext =
134 0 : (receive_time_rtp - last_receive_time_rtp) -
135 0 : ((header.timestamp +
136 0 : header.extension.transmissionTimeOffset) -
137 0 : (last_received_timestamp_ +
138 0 : last_received_transmission_time_offset_));
139 :
140 0 : time_diff_samples_ext = std::abs(time_diff_samples_ext);
141 :
142 0 : if (time_diff_samples_ext < 450000) {
143 : int32_t jitter_diffQ4TransmissionTimeOffset =
144 0 : (time_diff_samples_ext << 4) - jitter_q4_transmission_time_offset_;
145 0 : jitter_q4_transmission_time_offset_ +=
146 0 : ((jitter_diffQ4TransmissionTimeOffset + 8) >> 4);
147 : }
148 0 : }
149 :
150 0 : void StreamStatisticianImpl::NotifyRtpCallback() {
151 0 : StreamDataCounters data;
152 : uint32_t ssrc;
153 : {
154 0 : rtc::CritScope cs(&stream_lock_);
155 0 : data = receive_counters_;
156 0 : ssrc = ssrc_;
157 : }
158 0 : rtp_callback_->DataCountersUpdated(data, ssrc);
159 0 : }
160 :
161 0 : void StreamStatisticianImpl::NotifyRtcpCallback() {
162 0 : RtcpStatistics data;
163 : uint32_t ssrc;
164 : {
165 0 : rtc::CritScope cs(&stream_lock_);
166 0 : data = last_reported_statistics_;
167 0 : ssrc = ssrc_;
168 : }
169 0 : rtcp_callback_->StatisticsUpdated(data, ssrc);
170 0 : }
171 :
172 0 : void StreamStatisticianImpl::FecPacketReceived(const RTPHeader& header,
173 : size_t packet_length) {
174 : {
175 0 : rtc::CritScope cs(&stream_lock_);
176 0 : receive_counters_.fec.AddPacket(packet_length, header);
177 : }
178 0 : NotifyRtpCallback();
179 0 : }
180 :
181 0 : void StreamStatisticianImpl::SetMaxReorderingThreshold(
182 : int max_reordering_threshold) {
183 0 : rtc::CritScope cs(&stream_lock_);
184 0 : max_reordering_threshold_ = max_reordering_threshold;
185 0 : }
186 :
187 0 : bool StreamStatisticianImpl::GetStatistics(RtcpStatistics* statistics,
188 : bool reset) {
189 : {
190 0 : rtc::CritScope cs(&stream_lock_);
191 0 : if (received_seq_first_ == 0 &&
192 0 : receive_counters_.transmitted.payload_bytes == 0) {
193 : // We have not received anything.
194 0 : return false;
195 : }
196 :
197 0 : if (!reset) {
198 0 : if (last_report_inorder_packets_ == 0) {
199 : // No report.
200 0 : return false;
201 : }
202 : // Just get last report.
203 0 : *statistics = last_reported_statistics_;
204 0 : return true;
205 : }
206 :
207 0 : *statistics = CalculateRtcpStatistics();
208 : }
209 :
210 0 : NotifyRtcpCallback();
211 :
212 0 : return true;
213 : }
214 :
215 0 : RtcpStatistics StreamStatisticianImpl::CalculateRtcpStatistics() {
216 0 : RtcpStatistics stats;
217 :
218 0 : if (last_report_inorder_packets_ == 0) {
219 : // First time we send a report.
220 0 : last_report_seq_max_ = received_seq_first_ - 1;
221 : }
222 :
223 : // Calculate fraction lost.
224 0 : uint16_t exp_since_last = (received_seq_max_ - last_report_seq_max_);
225 :
226 0 : if (last_report_seq_max_ > received_seq_max_) {
227 : // Can we assume that the seq_num can't go decrease over a full RTCP period?
228 0 : exp_since_last = 0;
229 : }
230 :
231 : // Number of received RTP packets since last report, counts all packets but
232 : // not re-transmissions.
233 : uint32_t rec_since_last =
234 0 : (receive_counters_.transmitted.packets -
235 0 : receive_counters_.retransmitted.packets) - last_report_inorder_packets_;
236 :
237 : // With NACK we don't know the expected retransmissions during the last
238 : // second. We know how many "old" packets we have received. We just count
239 : // the number of old received to estimate the loss, but it still does not
240 : // guarantee an exact number since we run this based on time triggered by
241 : // sending of an RTP packet. This should have a minimum effect.
242 :
243 : // With NACK we don't count old packets as received since they are
244 : // re-transmitted. We use RTT to decide if a packet is re-ordered or
245 : // re-transmitted.
246 : uint32_t retransmitted_packets =
247 0 : receive_counters_.retransmitted.packets - last_report_old_packets_;
248 0 : rec_since_last += retransmitted_packets;
249 :
250 0 : int32_t missing = 0;
251 0 : if (exp_since_last > rec_since_last) {
252 0 : missing = (exp_since_last - rec_since_last);
253 : }
254 0 : uint8_t local_fraction_lost = 0;
255 0 : if (exp_since_last) {
256 : // Scale 0 to 255, where 255 is 100% loss.
257 0 : local_fraction_lost =
258 0 : static_cast<uint8_t>(255 * missing / exp_since_last);
259 : }
260 0 : stats.fraction_lost = local_fraction_lost;
261 :
262 : // We need a counter for cumulative loss too.
263 : // TODO(danilchap): Ensure cumulative loss is below maximum value of 2^24.
264 0 : cumulative_loss_ += missing;
265 0 : stats.cumulative_lost = cumulative_loss_;
266 0 : stats.extended_max_sequence_number =
267 0 : (received_seq_wraps_ << 16) + received_seq_max_;
268 : // Note: internal jitter value is in Q4 and needs to be scaled by 1/16.
269 0 : stats.jitter = jitter_q4_ >> 4;
270 :
271 : // Store this report.
272 0 : last_reported_statistics_ = stats;
273 :
274 : // Only for report blocks in RTCP SR and RR.
275 0 : last_report_inorder_packets_ =
276 0 : receive_counters_.transmitted.packets -
277 0 : receive_counters_.retransmitted.packets;
278 0 : last_report_old_packets_ = receive_counters_.retransmitted.packets;
279 0 : last_report_seq_max_ = received_seq_max_;
280 : BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "cumulative_loss_pkts",
281 : clock_->TimeInMilliseconds(),
282 : cumulative_loss_, ssrc_);
283 : BWE_TEST_LOGGING_PLOT_WITH_SSRC(
284 : 1, "received_seq_max_pkts", clock_->TimeInMilliseconds(),
285 : (received_seq_max_ - received_seq_first_), ssrc_);
286 :
287 0 : return stats;
288 : }
289 :
290 0 : void StreamStatisticianImpl::GetDataCounters(
291 : size_t* bytes_received, uint32_t* packets_received) const {
292 0 : rtc::CritScope cs(&stream_lock_);
293 0 : if (bytes_received) {
294 0 : *bytes_received = receive_counters_.transmitted.payload_bytes +
295 0 : receive_counters_.transmitted.header_bytes +
296 0 : receive_counters_.transmitted.padding_bytes;
297 : }
298 0 : if (packets_received) {
299 0 : *packets_received = receive_counters_.transmitted.packets;
300 : }
301 0 : }
302 :
303 0 : void StreamStatisticianImpl::GetReceiveStreamDataCounters(
304 : StreamDataCounters* data_counters) const {
305 0 : rtc::CritScope cs(&stream_lock_);
306 0 : *data_counters = receive_counters_;
307 0 : }
308 :
309 0 : uint32_t StreamStatisticianImpl::BitrateReceived() const {
310 0 : rtc::CritScope cs(&stream_lock_);
311 0 : return incoming_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0);
312 : }
313 :
314 0 : void StreamStatisticianImpl::LastReceiveTimeNtp(uint32_t* secs,
315 : uint32_t* frac) const {
316 0 : rtc::CritScope cs(&stream_lock_);
317 0 : *secs = last_receive_time_ntp_.seconds();
318 0 : *frac = last_receive_time_ntp_.fractions();
319 0 : }
320 :
321 0 : bool StreamStatisticianImpl::IsRetransmitOfOldPacket(
322 : const RTPHeader& header, int64_t min_rtt) const {
323 0 : rtc::CritScope cs(&stream_lock_);
324 0 : if (InOrderPacketInternal(header.sequenceNumber)) {
325 0 : return false;
326 : }
327 0 : uint32_t frequency_khz = header.payload_type_frequency / 1000;
328 0 : assert(frequency_khz > 0);
329 :
330 0 : int64_t time_diff_ms = clock_->TimeInMilliseconds() -
331 0 : last_receive_time_ms_;
332 :
333 : // Diff in time stamp since last received in order.
334 0 : uint32_t timestamp_diff = header.timestamp - last_received_timestamp_;
335 0 : uint32_t rtp_time_stamp_diff_ms = timestamp_diff / frequency_khz;
336 :
337 0 : int64_t max_delay_ms = 0;
338 0 : if (min_rtt == 0) {
339 : // Jitter standard deviation in samples.
340 0 : float jitter_std = sqrt(static_cast<float>(jitter_q4_ >> 4));
341 :
342 : // 2 times the standard deviation => 95% confidence.
343 : // And transform to milliseconds by dividing by the frequency in kHz.
344 0 : max_delay_ms = static_cast<int64_t>((2 * jitter_std) / frequency_khz);
345 :
346 : // Min max_delay_ms is 1.
347 0 : if (max_delay_ms == 0) {
348 0 : max_delay_ms = 1;
349 : }
350 : } else {
351 0 : max_delay_ms = (min_rtt / 3) + 1;
352 : }
353 0 : return time_diff_ms > rtp_time_stamp_diff_ms + max_delay_ms;
354 : }
355 :
356 0 : bool StreamStatisticianImpl::IsPacketInOrder(uint16_t sequence_number) const {
357 0 : rtc::CritScope cs(&stream_lock_);
358 0 : return InOrderPacketInternal(sequence_number);
359 : }
360 :
361 0 : bool StreamStatisticianImpl::InOrderPacketInternal(
362 : uint16_t sequence_number) const {
363 : // First packet is always in order.
364 0 : if (last_receive_time_ms_ == 0)
365 0 : return true;
366 :
367 0 : if (IsNewerSequenceNumber(sequence_number, received_seq_max_)) {
368 0 : return true;
369 : } else {
370 : // If we have a restart of the remote side this packet is still in order.
371 0 : return !IsNewerSequenceNumber(sequence_number, received_seq_max_ -
372 0 : max_reordering_threshold_);
373 : }
374 : }
375 :
376 0 : ReceiveStatistics* ReceiveStatistics::Create(Clock* clock) {
377 0 : return new ReceiveStatisticsImpl(clock);
378 : }
379 :
380 0 : ReceiveStatisticsImpl::ReceiveStatisticsImpl(Clock* clock)
381 : : clock_(clock),
382 : rtcp_stats_callback_(NULL),
383 0 : rtp_stats_callback_(NULL) {}
384 :
385 0 : ReceiveStatisticsImpl::~ReceiveStatisticsImpl() {
386 0 : while (!statisticians_.empty()) {
387 0 : delete statisticians_.begin()->second;
388 0 : statisticians_.erase(statisticians_.begin());
389 : }
390 0 : }
391 :
392 0 : void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header,
393 : size_t packet_length,
394 : bool retransmitted) {
395 : StreamStatisticianImpl* impl;
396 : {
397 0 : rtc::CritScope cs(&receive_statistics_lock_);
398 0 : StatisticianImplMap::iterator it = statisticians_.find(header.ssrc);
399 0 : if (it != statisticians_.end()) {
400 0 : impl = it->second;
401 : } else {
402 0 : impl = new StreamStatisticianImpl(clock_, this, this);
403 0 : statisticians_[header.ssrc] = impl;
404 : }
405 : }
406 : // StreamStatisticianImpl instance is created once and only destroyed when
407 : // this whole ReceiveStatisticsImpl is destroyed. StreamStatisticianImpl has
408 : // it's own locking so don't hold receive_statistics_lock_ (potential
409 : // deadlock).
410 0 : impl->IncomingPacket(header, packet_length, retransmitted);
411 0 : }
412 :
413 0 : void ReceiveStatisticsImpl::FecPacketReceived(const RTPHeader& header,
414 : size_t packet_length) {
415 0 : rtc::CritScope cs(&receive_statistics_lock_);
416 0 : StatisticianImplMap::iterator it = statisticians_.find(header.ssrc);
417 : // Ignore FEC if it is the first packet.
418 0 : if (it != statisticians_.end()) {
419 0 : it->second->FecPacketReceived(header, packet_length);
420 : }
421 0 : }
422 :
423 0 : StatisticianMap ReceiveStatisticsImpl::GetActiveStatisticians() const {
424 0 : rtc::CritScope cs(&receive_statistics_lock_);
425 0 : StatisticianMap active_statisticians;
426 0 : for (StatisticianImplMap::const_iterator it = statisticians_.begin();
427 0 : it != statisticians_.end(); ++it) {
428 : uint32_t secs;
429 : uint32_t frac;
430 0 : it->second->LastReceiveTimeNtp(&secs, &frac);
431 0 : if (clock_->CurrentNtpInMilliseconds() -
432 0 : Clock::NtpToMs(secs, frac) < kStatisticsTimeoutMs) {
433 0 : active_statisticians[it->first] = it->second;
434 : }
435 : }
436 0 : return active_statisticians;
437 : }
438 :
439 0 : StreamStatistician* ReceiveStatisticsImpl::GetStatistician(
440 : uint32_t ssrc) const {
441 0 : rtc::CritScope cs(&receive_statistics_lock_);
442 0 : StatisticianImplMap::const_iterator it = statisticians_.find(ssrc);
443 0 : if (it == statisticians_.end())
444 0 : return NULL;
445 0 : return it->second;
446 : }
447 :
448 0 : void ReceiveStatisticsImpl::SetMaxReorderingThreshold(
449 : int max_reordering_threshold) {
450 0 : rtc::CritScope cs(&receive_statistics_lock_);
451 0 : for (StatisticianImplMap::iterator it = statisticians_.begin();
452 0 : it != statisticians_.end(); ++it) {
453 0 : it->second->SetMaxReorderingThreshold(max_reordering_threshold);
454 : }
455 0 : }
456 :
457 0 : void ReceiveStatisticsImpl::RegisterRtcpStatisticsCallback(
458 : RtcpStatisticsCallback* callback) {
459 0 : rtc::CritScope cs(&receive_statistics_lock_);
460 0 : if (callback != NULL)
461 0 : assert(rtcp_stats_callback_ == NULL);
462 0 : rtcp_stats_callback_ = callback;
463 0 : }
464 :
465 0 : void ReceiveStatisticsImpl::StatisticsUpdated(const RtcpStatistics& statistics,
466 : uint32_t ssrc) {
467 0 : rtc::CritScope cs(&receive_statistics_lock_);
468 0 : if (rtcp_stats_callback_)
469 0 : rtcp_stats_callback_->StatisticsUpdated(statistics, ssrc);
470 0 : }
471 :
472 0 : void ReceiveStatisticsImpl::CNameChanged(const char* cname, uint32_t ssrc) {
473 0 : rtc::CritScope cs(&receive_statistics_lock_);
474 0 : if (rtcp_stats_callback_)
475 0 : rtcp_stats_callback_->CNameChanged(cname, ssrc);
476 0 : }
477 :
478 0 : void ReceiveStatisticsImpl::RegisterRtpStatisticsCallback(
479 : StreamDataCountersCallback* callback) {
480 0 : rtc::CritScope cs(&receive_statistics_lock_);
481 0 : if (callback != NULL)
482 0 : assert(rtp_stats_callback_ == NULL);
483 0 : rtp_stats_callback_ = callback;
484 0 : }
485 :
486 0 : void ReceiveStatisticsImpl::DataCountersUpdated(const StreamDataCounters& stats,
487 : uint32_t ssrc) {
488 0 : rtc::CritScope cs(&receive_statistics_lock_);
489 0 : if (rtp_stats_callback_) {
490 0 : rtp_stats_callback_->DataCountersUpdated(stats, ssrc);
491 : }
492 0 : }
493 :
494 0 : void NullReceiveStatistics::IncomingPacket(const RTPHeader& rtp_header,
495 : size_t packet_length,
496 0 : bool retransmitted) {}
497 :
498 0 : void NullReceiveStatistics::FecPacketReceived(const RTPHeader& header,
499 0 : size_t packet_length) {}
500 :
501 0 : StatisticianMap NullReceiveStatistics::GetActiveStatisticians() const {
502 0 : return StatisticianMap();
503 : }
504 :
505 0 : StreamStatistician* NullReceiveStatistics::GetStatistician(
506 : uint32_t ssrc) const {
507 0 : return NULL;
508 : }
509 :
510 0 : void NullReceiveStatistics::SetMaxReorderingThreshold(
511 0 : int max_reordering_threshold) {}
512 :
513 0 : void NullReceiveStatistics::RegisterRtcpStatisticsCallback(
514 0 : RtcpStatisticsCallback* callback) {}
515 :
516 0 : void NullReceiveStatistics::RegisterRtpStatisticsCallback(
517 0 : StreamDataCountersCallback* callback) {}
518 :
519 : } // namespace webrtc
|