blob: be0c7dd544a2c563d380b099c99a9b32161e536c [file] [log] [blame]
/*
* 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"
#define BITRATE_AVERAGE_WINDOW 2000
namespace webrtc {
Bitrate::Bitrate(RtpRtcpClock* clock) :
_clock(*clock),
_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 = _clock.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 = _clock.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<float>(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<WebRtc_UWord32>(_accumulatedBytes * 8.0f * 1000.0f /
denom + 0.5f);
}
} // namespace webrtc