- report packet loss timeline

This commit is contained in:
2026-01-06 12:46:13 +03:00
parent 622f458807
commit 11d4bf7495
3 changed files with 64 additions and 52 deletions

View File

@@ -224,11 +224,6 @@ RtpBuffer::FetchResult RtpBuffer::fetch(ResultList& rl)
} }
else else
{ {
// Did we fetch any packet before ?
bool is_fetched_packet = mFetchedPacket.get() != nullptr;
if (is_fetched_packet)
is_fetched_packet &= mFetchedPacket->rtp().get() != nullptr;
if (mLastSeqno.has_value()) if (mLastSeqno.has_value())
{ {
if (mPacketList.empty()) if (mPacketList.empty())
@@ -239,7 +234,8 @@ RtpBuffer::FetchResult RtpBuffer::fetch(ResultList& rl)
else else
{ {
// Current sequence number ? // Current sequence number ?
uint32_t seqno = mPacketList.front()->rtp()->GetExtendedSequenceNumber(); auto& packet = *mPacketList.front();
uint32_t seqno = packet.rtp()->GetExtendedSequenceNumber();
// Gap between new packet and previous on // Gap between new packet and previous on
int gap = (int64_t)seqno - (int64_t)*mLastSeqno - 1; int gap = (int64_t)seqno - (int64_t)*mLastSeqno - 1;
@@ -248,7 +244,8 @@ RtpBuffer::FetchResult RtpBuffer::fetch(ResultList& rl)
{ {
// std::cout << "Increase the packet loss for SSRC " << std::hex << mSsrc << std::endl; // std::cout << "Increase the packet loss for SSRC " << std::hex << mSsrc << std::endl;
mStat.mPacketLoss++; mStat.mPacketLoss++;
//mStat.mLoss[gap]++; auto currentTimestamp = uint64_t(packet.rtp()->GetReceiveTime().GetDouble() * 1000000);
mStat.mPacketLossTimeline.push_back({gap, std::chrono::microseconds(currentTimestamp)});
mLastSeqno = *mLastSeqno + 1; mLastSeqno = *mLastSeqno + 1;
result = FetchResult::Gap; result = FetchResult::Gap;
} }

View File

@@ -18,37 +18,44 @@
#include "../audio/Audio_Resampler.h" #include "../audio/Audio_Resampler.h"
#include <optional> #include <optional>
#include <chrono>
using namespace std::chrono_literals;
namespace MT namespace MT
{ {
using jrtplib::RTPPacket; using jrtplib::RTPPacket;
class RtpBuffer class RtpBuffer
{ {
public: public:
enum class FetchResult enum class FetchResult
{ {
RegularPacket, RegularPacket,
Gap, Gap,
NoPacket NoPacket
}; };
// Owns rtp packet data // Owns rtp packet data
class Packet class Packet
{ {
public: public:
Packet(const std::shared_ptr<RTPPacket>& packet, int timelen, int rate); Packet(const std::shared_ptr<RTPPacket>& packet, int timelen, int rate);
std::shared_ptr<RTPPacket> rtp() const; std::shared_ptr<RTPPacket> rtp() const;
int timelength() const; int timelength() const;
int rate() const; int rate() const;
const std::vector<short>& pcm() const; const std::vector<short>& pcm() const;
std::vector<short>& pcm(); std::vector<short>& pcm();
const std::chrono::microseconds& timestamp() const;
std::chrono::microseconds& timestamp();
protected: protected:
std::shared_ptr<RTPPacket> mRtp; std::shared_ptr<RTPPacket> mRtp;
int mTimelength = 0, mRate = 0; int mTimelength = 0,
std::vector<short> mPcm; mRate = 0;
std::vector<short> mPcm;
std::chrono::microseconds mTimestamp = 0us;
}; };
RtpBuffer(Statistics& stat); RtpBuffer(Statistics& stat);
@@ -80,13 +87,13 @@ namespace MT
FetchResult fetch(ResultList& rl); FetchResult fetch(ResultList& rl);
protected: protected:
unsigned mSsrc = 0; unsigned mSsrc = 0;
int mHigh = RTP_BUFFER_HIGH, int mHigh = RTP_BUFFER_HIGH,
mLow = RTP_BUFFER_LOW, mLow = RTP_BUFFER_LOW,
mPrebuffer = RTP_BUFFER_PREBUFFER; mPrebuffer = RTP_BUFFER_PREBUFFER;
int mReturnedCounter = 0, int mReturnedCounter = 0,
mAddCounter = 0; mAddCounter = 0;
mutable Mutex mGuard; mutable Mutex mGuard;
typedef std::vector<std::shared_ptr<Packet>> PacketList; typedef std::vector<std::shared_ptr<Packet>> PacketList;
@@ -99,21 +106,21 @@ namespace MT
// To calculate average interval between packet add. It is close to jitter but more useful in debugging. // To calculate average interval between packet add. It is close to jitter but more useful in debugging.
float mLastAddTime = 0.0; float mLastAddTime = 0.0;
}; };
class Receiver class Receiver
{ {
public: public:
Receiver(Statistics& stat); Receiver(Statistics& stat);
virtual ~Receiver(); virtual ~Receiver();
protected: protected:
Statistics& mStat; Statistics& mStat;
}; };
class AudioReceiver: public Receiver class AudioReceiver: public Receiver
{ {
public: public:
AudioReceiver(const CodecList::Settings& codecSettings, Statistics& stat); AudioReceiver(const CodecList::Settings& codecSettings, Statistics& stat);
~AudioReceiver(); ~AudioReceiver();
@@ -127,10 +134,10 @@ namespace MT
// Returns false when there is no rtp data from jitter // Returns false when there is no rtp data from jitter
enum DecodeOptions enum DecodeOptions
{ {
DecodeOptions_ResampleToMainRate = 0, DecodeOptions_ResampleToMainRate = 0,
DecodeOptions_DontResample = 1, DecodeOptions_DontResample = 1,
DecodeOptions_FillCngGap = 2, DecodeOptions_FillCngGap = 2,
DecodeOptions_SkipDecode = 4 DecodeOptions_SkipDecode = 4
}; };
enum DecodeResult enum DecodeResult
@@ -155,7 +162,7 @@ namespace MT
// Return samplerate for given packet // Return samplerate for given packet
int samplerateFor(jrtplib::RTPPacket& p); int samplerateFor(jrtplib::RTPPacket& p);
protected: protected:
RtpBuffer mBuffer; RtpBuffer mBuffer;
CodecMap mCodecMap; CodecMap mCodecMap;
PCodec mCodec; PCodec mCodec;
@@ -186,7 +193,7 @@ namespace MT
int mFailedCount = 0; int mFailedCount = 0;
Audio::Resampler mResampler8, mResampler16, Audio::Resampler mResampler8, mResampler16,
mResampler32, mResampler48; mResampler32, mResampler48;
Audio::PWavFileWriter mDecodedDump; Audio::PWavFileWriter mDecodedDump;
@@ -202,16 +209,16 @@ namespace MT
void processDecoded(Audio::DataWindow& output, int options); void processDecoded(Audio::DataWindow& output, int options);
void processStatisticsWithAmrCodec(Codec* c); void processStatisticsWithAmrCodec(Codec* c);
}; };
class DtmfReceiver: public Receiver class DtmfReceiver: public Receiver
{ {
public: public:
DtmfReceiver(Statistics& stat); DtmfReceiver(Statistics& stat);
~DtmfReceiver(); ~DtmfReceiver();
void add(std::shared_ptr<RTPPacket> p); void add(std::shared_ptr<RTPPacket> p);
}; };
} }
#endif #endif

View File

@@ -50,6 +50,12 @@ protected:
float mMaxDelta = 0.0f; float mMaxDelta = 0.0f;
}; };
struct PacketLossEvent
{
int mGap = 0;
std::chrono::microseconds mTimestamp;
};
class Statistics class Statistics
{ {
public: public:
@@ -78,13 +84,15 @@ public:
// AMR codec bitrate switch counter // AMR codec bitrate switch counter
int mBitrateSwitchCounter = 0; int mBitrateSwitchCounter = 0;
std::string mCodecName; std::string mCodecName;
float mJitter = 0.0f; // Jitter float mJitter = 0.0f; // Jitter
TestResult<float> mRttDelay; // RTT delay TestResult<float> mRttDelay; // RTT delay
// Timestamp when first RTP packet has arrived // Timestamp when first RTP packet has arrived
std::optional<timepoint_t> mFirstRtpTime; std::optional<timepoint_t> mFirstRtpTime;
std::map<int, int> mCodecCount; // Stats on used codecs std::map<int, int> mCodecCount; // Stats on used codecs
std::vector<PacketLossEvent> mPacketLossTimeline; // Packet loss timeline
// It is to calculate network MOS // It is to calculate network MOS
void calculateBurstr(double* burstr, double* loss) const; void calculateBurstr(double* burstr, double* loss) const;