/* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/video_engine/report_block_stats.h" namespace webrtc { namespace { int FractionLost(uint32_t num_lost_sequence_numbers, uint32_t num_sequence_numbers) { if (num_sequence_numbers == 0) { return 0; } return ((num_lost_sequence_numbers * 255) + (num_sequence_numbers / 2)) / num_sequence_numbers; } } // namespace // Helper class for rtcp statistics. ReportBlockStats::ReportBlockStats() : num_sequence_numbers_(0), num_lost_sequence_numbers_(0) { } void ReportBlockStats::Store(const RtcpStatistics& rtcp_stats, uint32_t remote_ssrc, uint32_t source_ssrc) { RTCPReportBlock block; block.cumulativeLost = rtcp_stats.cumulative_lost; block.fractionLost = rtcp_stats.fraction_lost; block.extendedHighSeqNum = rtcp_stats.extended_max_sequence_number; block.jitter = rtcp_stats.jitter; block.remoteSSRC = remote_ssrc; block.sourceSSRC = source_ssrc; uint32_t num_sequence_numbers = 0; uint32_t num_lost_sequence_numbers = 0; StoreAndAddPacketIncrement( block, &num_sequence_numbers, &num_lost_sequence_numbers); } RTCPReportBlock ReportBlockStats::AggregateAndStore( const ReportBlockVector& report_blocks) { RTCPReportBlock aggregate; if (report_blocks.empty()) { return aggregate; } uint32_t num_sequence_numbers = 0; uint32_t num_lost_sequence_numbers = 0; ReportBlockVector::const_iterator report_block = report_blocks.begin(); for (; report_block != report_blocks.end(); ++report_block) { aggregate.cumulativeLost += report_block->cumulativeLost; aggregate.jitter += report_block->jitter; StoreAndAddPacketIncrement(*report_block, &num_sequence_numbers, &num_lost_sequence_numbers); } if (report_blocks.size() == 1) { // No aggregation needed. return report_blocks[0]; } // Fraction lost since previous report block. aggregate.fractionLost = FractionLost(num_lost_sequence_numbers, num_sequence_numbers); aggregate.jitter = static_cast( (aggregate.jitter + report_blocks.size() / 2) / report_blocks.size()); return aggregate; } void ReportBlockStats::StoreAndAddPacketIncrement( const RTCPReportBlock& report_block, uint32_t* num_sequence_numbers, uint32_t* num_lost_sequence_numbers) { // Get diff with previous report block. ReportBlockMap::iterator prev_report_block = prev_report_blocks_.find( report_block.sourceSSRC); if (prev_report_block != prev_report_blocks_.end()) { int seq_num_diff = report_block.extendedHighSeqNum - prev_report_block->second.extendedHighSeqNum; int cum_loss_diff = report_block.cumulativeLost - prev_report_block->second.cumulativeLost; if (seq_num_diff >= 0 && cum_loss_diff >= 0) { *num_sequence_numbers += seq_num_diff; *num_lost_sequence_numbers += cum_loss_diff; // Update total number of packets/lost packets. num_sequence_numbers_ += seq_num_diff; num_lost_sequence_numbers_ += cum_loss_diff; } } // Store current report block. prev_report_blocks_[report_block.sourceSSRC] = report_block; } int ReportBlockStats::FractionLostInPercent() const { if (num_sequence_numbers_ == 0) { return -1; } return FractionLost( num_lost_sequence_numbers_, num_sequence_numbers_) * 100 / 255; } } // namespace webrtc