/* * Copyright (c) 2011 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 "Bitrate.h" #include "rtp_utility.h" #include "tick_util.h" #define BITRATE_AVERAGE_WINDOW 2000 namespace webrtc { Bitrate::Bitrate() : _packetRate(0), _bitrate(0), _bitrateNextIdx(0), _timeLastRateUpdate(0), _bytesCount(0), _packetCount(0) { memset(_packetRateArray, 0, sizeof(_packetRateArray)); memset(_bitrateDiffMS, 0, sizeof(_bitrateDiffMS)); memset(_bitrateArray, 0, sizeof(_bitrateArray)); } void Bitrate::Init() { _packetRate = 0; _bitrate = 0; _timeLastRateUpdate = 0; _bytesCount = 0; _packetCount = 0; _bitrateNextIdx = 0; memset(_packetRateArray, 0, sizeof(_packetRateArray)); memset(_bitrateDiffMS, 0, sizeof(_bitrateDiffMS)); memset(_bitrateArray, 0, sizeof(_bitrateArray)); } void Bitrate::Update(const WebRtc_Word32 bytes) { _bytesCount += bytes; _packetCount++; } WebRtc_UWord32 Bitrate::PacketRate() const { return _packetRate; } WebRtc_UWord32 Bitrate::BitrateLast() const { return _bitrate; } WebRtc_UWord32 Bitrate::BitrateNow() const { WebRtc_UWord32 now = ModuleRTPUtility::GetTimeInMS(); WebRtc_UWord32 diffMS = now -_timeLastRateUpdate; if(diffMS > 10000) // 10 sec { // too high diff ignore return _bitrate; // bits/s } WebRtc_UWord64 bitsSinceLastRateUpdate = 8*_bytesCount*1000; // have to consider the time when the measurement was done // ((bits/sec * sec) + (bits)) / sec WebRtc_UWord64 bitrate = (((WebRtc_UWord64)_bitrate * 1000) + bitsSinceLastRateUpdate)/(1000+diffMS); return (WebRtc_UWord32)bitrate; } void Bitrate::Process() { // triggered by timer WebRtc_UWord32 now = ModuleRTPUtility::GetTimeInMS(); WebRtc_UWord32 diffMS = now -_timeLastRateUpdate; if(diffMS > 100) { if(diffMS > 10000) // 10 sec { // too high diff ignore _timeLastRateUpdate = now; _bytesCount = 0; _packetCount = 0; return; } _packetRateArray[_bitrateNextIdx] = (_packetCount*1000)/diffMS; _bitrateArray[_bitrateNextIdx] = 8*((_bytesCount*1000)/diffMS); // will overflow at ~34 Mbit/s _bitrateDiffMS[_bitrateNextIdx] = diffMS; _bitrateNextIdx++; if(_bitrateNextIdx >= 10) { _bitrateNextIdx = 0; } WebRtc_UWord32 sumDiffMS = 0; WebRtc_UWord64 sumBitrateMS = 0; WebRtc_UWord32 sumPacketrateMS = 0; for(int i= 0; i <10; i++) { // sum of time sumDiffMS += _bitrateDiffMS[i]; sumBitrateMS += _bitrateArray[i] * _bitrateDiffMS[i]; sumPacketrateMS += _packetRateArray[i] * _bitrateDiffMS[i]; } _timeLastRateUpdate = now; _bytesCount = 0; _packetCount = 0; _packetRate = sumPacketrateMS/sumDiffMS; _bitrate = WebRtc_UWord32(sumBitrateMS / sumDiffMS); } } BitRateStats::BitRateStats() :_dataSamples(), _accumulatedBytes(0) { } BitRateStats::~BitRateStats() { while (_dataSamples.size() > 0) { delete _dataSamples.front(); _dataSamples.pop_front(); } } void BitRateStats::Init() { _accumulatedBytes = 0; while (_dataSamples.size() > 0) { delete _dataSamples.front(); _dataSamples.pop_front(); } } void BitRateStats::Update(WebRtc_UWord32 packetSizeBytes, WebRtc_Word64 nowMs) { // Find an empty slot for storing the new sample and at the same time // accumulate the history. _dataSamples.push_back(new DataTimeSizeTuple(packetSizeBytes, nowMs)); _accumulatedBytes += packetSizeBytes; EraseOld(nowMs); } void BitRateStats::EraseOld(WebRtc_Word64 nowMs) { while (_dataSamples.size() > 0) { if (nowMs - _dataSamples.front()->_timeCompleteMs > BITRATE_AVERAGE_WINDOW) { // Delete old sample _accumulatedBytes -= _dataSamples.front()->_sizeBytes; delete _dataSamples.front(); _dataSamples.pop_front(); } else { break; } } } WebRtc_UWord32 BitRateStats::BitRate(WebRtc_Word64 nowMs) { // Calculate the average bit rate the past BITRATE_AVERAGE_WINDOW ms. // Removes any old samples from the list. EraseOld(nowMs); WebRtc_Word64 timeOldest = nowMs; if (_dataSamples.size() > 0) { timeOldest = _dataSamples.front()->_timeCompleteMs; } // Update average bit rate float denom = static_cast(nowMs - timeOldest); if (nowMs == timeOldest) { // Calculate with a one second window when we haven't // received more than one packet. denom = 1000.0; } return static_cast(_accumulatedBytes * 8.0f * 1000.0f / denom + 0.5f); } } // namespace webrtc