258 lines
6.8 KiB
C++
258 lines
6.8 KiB
C++
#include <math.h>
|
|
|
|
#include "MT_Statistics.h"
|
|
#include "audio/Audio_Interface.h"
|
|
#include "helper/HL_Log.h"
|
|
#define LOG_SUBSYSTEM "Statistics"
|
|
|
|
using namespace MT;
|
|
|
|
void JitterStatistics::process(jrtplib::RTPPacket* packet, int rate)
|
|
{
|
|
// Get current timestamp and receive time
|
|
uint32_t timestamp = packet->GetTimestamp();
|
|
jrtplib::RTPTime receiveTime = packet->GetReceiveTime();
|
|
|
|
if (!mLastJitter.is_initialized())
|
|
{
|
|
// First packet
|
|
mReceiveTime = receiveTime;
|
|
mReceiveTimestamp = timestamp;
|
|
mLastJitter = 0.0;
|
|
}
|
|
else
|
|
{
|
|
// It is in units
|
|
int64_t receiveDelta = int64_t(receiveTime.GetDouble() * rate) - int64_t(mReceiveTime.GetDouble() * rate);
|
|
|
|
// Check if packets are ordered ok
|
|
if (timestamp <= mReceiveTimestamp)
|
|
return;
|
|
|
|
// Find differences in timestamp
|
|
int64_t timestampDelta = timestamp - mReceiveTimestamp;
|
|
|
|
if (!timestampDelta)
|
|
// Skip current packet silently. Most probably it is error in RTP stream like duplicated packet.
|
|
return;
|
|
|
|
// Find delta in units
|
|
int64_t delta = receiveDelta - timestampDelta;
|
|
|
|
// Update max delta in milliseconds
|
|
float delta_in_seconds = float(fabs(double(delta) / rate));
|
|
if (delta_in_seconds > mMaxDelta)
|
|
mMaxDelta = delta_in_seconds;
|
|
|
|
// Update jitter value in units
|
|
mLastJitter = mLastJitter.value() + (fabs(double(delta)) - mLastJitter.value()) / 16.0;
|
|
/*printf("PacketNo: %d, current delta in ms: %f, jitter in ms: %f\n",
|
|
(int)packet->GetSequenceNumber(),
|
|
delta_in_ms,
|
|
float(mLastJitter.value() / (rate / 1000)));*/
|
|
|
|
// Save last values
|
|
mReceiveTime = receiveTime;
|
|
mReceiveTimestamp = timestamp;
|
|
|
|
// And mJitter are in seconds again
|
|
mJitter.process(mLastJitter.value() / float(rate));
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------- Statistics ------------------------------------
|
|
|
|
|
|
Statistics::Statistics()
|
|
:mReceived(0), mSent(0), mReceivedRtp(0), mSentRtp(0),
|
|
mReceivedRtcp(0), mSentRtcp(0), mDuplicatedRtp(0), mOldRtp(0), mIllegalRtp(0),
|
|
mPacketLoss(0), mJitter(0.0), mAudioTime(0), mSsrc(0), mPacketDropped(0)
|
|
{
|
|
mBitrateSwitchCounter = 0;
|
|
memset(mLoss, 0, sizeof mLoss);
|
|
|
|
// It is to keep track of statistics instance via grep | wc -l
|
|
//ICELogDebug(<< "Create statistics instance.");
|
|
}
|
|
|
|
Statistics::~Statistics()
|
|
{
|
|
}
|
|
|
|
void Statistics::reset()
|
|
{
|
|
mReceived = 0;
|
|
mSent = 0;
|
|
mReceivedRtp = 0;
|
|
mSentRtp = 0;
|
|
mReceivedRtcp = 0;
|
|
mSentRtcp = 0;
|
|
mDuplicatedRtp = 0;
|
|
mOldRtp = 0;
|
|
mPacketLoss = 0;
|
|
mIllegalRtp = 0;
|
|
mJitter = 0.0;
|
|
mAudioTime = 0;
|
|
mPacketDropped = 0;
|
|
|
|
memset(mLoss, 0, sizeof mLoss);
|
|
}
|
|
|
|
void Statistics::calculateBurstr(double* burstr, double* lossr) const
|
|
{
|
|
int lost = 0;
|
|
int bursts = 0;
|
|
for (int i = 0; i < 128; i++)
|
|
{
|
|
lost += i * mLoss[i];
|
|
bursts += mLoss[i];
|
|
}
|
|
|
|
if (lost < 5)
|
|
{
|
|
// ignore such small packet loss
|
|
*lossr = *burstr = 0;
|
|
return;
|
|
}
|
|
|
|
if (mReceivedRtp > 0 && bursts > 0)
|
|
{
|
|
*burstr = (double)((double)lost / (double)bursts) / (double)(1.0 / (1.0 - (double)lost / (double)mReceivedRtp));
|
|
if (*burstr < 0)
|
|
*burstr = -*burstr;
|
|
else if (*burstr < 1)
|
|
*burstr = 1;
|
|
}
|
|
else
|
|
*burstr = 0;
|
|
//printf("total loss: %d\n", lost);
|
|
if (mReceivedRtp > 0)
|
|
*lossr = (double)((double)lost / (double)mReceivedRtp);
|
|
else
|
|
*lossr = 0;
|
|
}
|
|
|
|
double Statistics::calculateMos(double maximalMos) const
|
|
{
|
|
// calculate lossrate and burst rate
|
|
double burstr, lossr;
|
|
calculateBurstr(&burstr, &lossr);
|
|
|
|
double r;
|
|
double bpl = 8.47627; //mos = -4.23836 + 0.29873 * r - 0.00416744 * r * r + 0.0000209855 * r * r * r;
|
|
double mos;
|
|
|
|
if (mReceivedRtp < 100)
|
|
return 0.0;
|
|
|
|
if (lossr == 0.0 || burstr == 0.0)
|
|
{
|
|
return maximalMos;
|
|
}
|
|
|
|
if (lossr > 0.5)
|
|
return 1;
|
|
|
|
bpl = 17.2647;
|
|
r = 93.2062077233 - 95.0 * (lossr * 100 / (lossr * 100 / burstr + bpl));
|
|
mos = 2.06405 + 0.031738 * r - 0.000356641 * r * r + 2.93143 * pow(10, -6) * r * r * r;
|
|
if (mos < 1)
|
|
return 1;
|
|
|
|
if (mos > maximalMos)
|
|
return maximalMos;
|
|
|
|
return mos;
|
|
}
|
|
|
|
Statistics& Statistics::operator += (const Statistics& src)
|
|
{
|
|
mReceived += src.mReceived;
|
|
mSent += src.mSent;
|
|
mReceivedRtp += src.mReceivedRtp;
|
|
mSentRtp += src.mSentRtp;
|
|
mReceivedRtcp += src.mReceivedRtcp;
|
|
mSentRtcp += src.mSentRtcp;
|
|
mDuplicatedRtp += src.mDuplicatedRtp;
|
|
mOldRtp += src.mOldRtp;
|
|
mPacketLoss += src.mPacketLoss;
|
|
mPacketDropped += src.mPacketDropped;
|
|
mAudioTime += src.mAudioTime;
|
|
|
|
|
|
for (auto codecStat: src.mCodecCount)
|
|
{
|
|
if (mCodecCount.find(codecStat.first) == mCodecCount.end())
|
|
mCodecCount[codecStat.first] = codecStat.second;
|
|
else
|
|
mCodecCount[codecStat.first] += codecStat.second;
|
|
}
|
|
|
|
mJitter = src.mJitter;
|
|
mRttDelay = src.mRttDelay;
|
|
mDecodingInterval = src.mDecodingInterval;
|
|
mDecodeRequested = src.mDecodeRequested;
|
|
|
|
if (!src.mCodecName.empty())
|
|
mCodecName = src.mCodecName;
|
|
|
|
// Find minimal
|
|
if (mFirstRtpTime.is_initialized())
|
|
{
|
|
if (src.mFirstRtpTime.is_initialized())
|
|
{
|
|
if (mFirstRtpTime.value() > src.mFirstRtpTime.value())
|
|
mFirstRtpTime = src.mFirstRtpTime;
|
|
}
|
|
}
|
|
else
|
|
if (src.mFirstRtpTime.is_initialized())
|
|
mFirstRtpTime = src.mFirstRtpTime;
|
|
|
|
mBitrateSwitchCounter += src.mBitrateSwitchCounter;
|
|
mRemotePeer = src.mRemotePeer;
|
|
mSsrc = src.mSsrc;
|
|
|
|
return *this;
|
|
}
|
|
|
|
Statistics& Statistics::operator -= (const Statistics& src)
|
|
{
|
|
mReceived -= src.mReceived;
|
|
mSent -= src.mSent;
|
|
mReceivedRtp -= src.mReceivedRtp;
|
|
mIllegalRtp -= src.mIllegalRtp;
|
|
mSentRtp -= src.mSentRtp;
|
|
mReceivedRtcp -= src.mReceivedRtcp;
|
|
mSentRtcp -= src.mSentRtcp;
|
|
mDuplicatedRtp -= src.mDuplicatedRtp;
|
|
mOldRtp -= src.mOldRtp;
|
|
mPacketLoss -= src.mPacketLoss;
|
|
mPacketDropped -= src.mPacketDropped;
|
|
|
|
mAudioTime -= src.mAudioTime;
|
|
for (auto codecStat: src.mCodecCount)
|
|
{
|
|
if (mCodecCount.find(codecStat.first) != mCodecCount.end())
|
|
mCodecCount[codecStat.first] -= codecStat.second;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
std::string Statistics::toString() const
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "Received: " << mReceivedRtp
|
|
<< ", lost: " << mPacketLoss
|
|
<< ", dropped: " << mPacketDropped
|
|
<< ", sent: " << mSentRtp
|
|
<< ", decoding interval: " << mDecodingInterval.average()
|
|
<< ", decode requested: " << mDecodeRequested.average()
|
|
<< ", packet interval: " << mPacketInterval.average();
|
|
|
|
return oss.str();
|
|
}
|