How to enable payload QoE analysis in existing RTP monitoring system

How to enable payload QoE analysis in existing RTP monitoring system

In many cases requirements for software and traffic processing are so specific that it is quite difficult to record audio for post call analysis. This may be due to legal aspects of call recordings, hard drive capacity and CPU load. Installing a stand along probe for analysis may also be an issue due to corporate polices and existing environment. However, receiving non-intrusively calculated payload MOS and information on impairments that caused degradation can bring a great value for QoE analysis and problem root cause detection.

You might have already heard of Sevana Passive Voice Quality Analyzer (PVQA) and real-time call quality monitoring server that is using PVQA technology for payload waveform analysis and MOS prediction. Now we would like present a PVQA RTP Library that suits those who already have an RTP monitoring system, but would like to get more out of it.

Simple integration of PVQA RTP Library will enable your system to receive, analyze and process such metrics as several types of dead air, SNR, amplitude clipping, VAD clipping, clicking/crackling and echo, so besides network metrics as E-Model MOS/R-factor you will receive payload MOS and information on the reasons that caused call quality degradation.

PVQA RTP Library provides API to analyze RTP streams instead of plain audio streams and without making call recordings that may violate legislation. The library is developers friendly and does not limit them in selection of RTP streams to monitor, or implementation of traffic capturing and monitoring rules. PVQA RTP Library is provided as standard Linux “.a” and “.so” binaries making the integration as simple as possible.

The library API is typical with usual initialize / create stream context / get statistics / close stream context functions. API language is C, which is easy to translate into any other programming language. Here is a cut&paste from the library header file (contact us for further details):

// Result codes for PvqaRtp library

enum PvqaStatus

{

Pvqa_Ok,

Pvqa_Failed,

Pvqa_BadParameter

};

// RTP stream context type

typedef void* PvqaRtp_StreamContext;

// Logging callback – to ease integration with 3rd party log systems

typedef void (*PvqaRtp_LogCallback) (int level, const char* filename, int line, const char* subsystem, const char* msg);

// Settings to configure PVQA RTP library.

struct PvqaRtp_Settings

{

// Dynamic payload types

int mAmrNbPtype; // AMR narrowband

int mAmrWbPtype; // AMR wideband

int mIlbc30Ptype; // Ilbc 30ms

int mIlbc20Ptype; // Ilbc 20 ms

int mIsac32KPtype; // ISAC 32KHz

int mIsac16KPtype; // ISAC 16KHz

// Non zero to avoid decoding. Only network MOS + jitter + packet counters stats.

int mSrtpMode;

// Optional callback to integrate logging. Can be NULL.

PvqaRtp_LogCallback mLogCallback;

// Can be 0 (Error) / 1 (Info) / 2 (Debug) / 3 (Media)

int mLogLevel;

// PVQA license file path. Must be set except the cases when SRTP mode is active.

const char* mPvqaLicensePath;

// PVQA settings file path. Must be set except the cases when SRTP mode is active.

const char* mPvqaSettingsPath;

};

// Get build number of library

extern const char* PvqaRtp_GetVersion(void);

// Initialized library. Options is zero terminated string with command line options (used for standalone server).

extern PvqaStatus PvqaRtp_InitLibrary(PvqaRtp_Settings* settings);

// Releases library.

extern PvqaStatus PvqaRtp_FreeLibrary();

// Creates new stream decoder & analyzer context

extern PvqaStatus PvqaRtp_CreateStreamContext(PvqaRtp_StreamContext* ctx);

// Destroy stream context

extern PvqaStatus PvqaRtp_FreeStreamContext(PvqaRtp_StreamContext ctx);

// Updates stream with RTP packet

extern PvqaStatus PvqaRtp_UpdateStream(PvqaRtp_StreamContext ctx, const void* packetData, size_t packetLength);

// Obtained statistics

struct PvqaRtp_Statistics

{

// Used payload types

char* mPayloadTypes;

// Most used codec name

char* mCodecName;

// Network MOS / Sevana MOS / Jitter stats

double mNetworkMos,

mSevanaMos;

// Jitter and max delta in seconds

double mJitter;

double mMaxDelta;

// Optional interval report

char* mIntervalReport;

// Number of RTP packets in the stream

int mRtpPacketCounter;

// Number of lost packets in the stream

int mLostPacketCounter;

// Number of bad RTP packets (failed to decode) in the stream

int mRtpIllegalPacketCounter;

// UNIX timestamps to record stream start & finish

time_t mStartTime, mEndTime;

// AMR codec mode switches counters.

// Counters are increased every time when codec changes bitrate.

int mAmrNbSwitchCounter;

int mAmrWbSwitchCounter;

};

// Gets current statistics for stream. Resulting statistics must be finalized with freeRtpStreamStats.

extern PvqaStatus PvqaRtp_GetStreamStats(PvqaRtp_StreamContext ctx, PvqaRtp_Statistics* stats);

// Frees memory related to Statistics structure.

// Please do not forget to call it after PvqaRtp_GetStreamStats.

extern PvqaStatus PvqaRtp_FreeStreamStats(PvqaRtp_Statistics* stats);

Example of API usage is here (it is cut from real demo application) :

int parseSinglePcap(const std::string& path)

{

// Initialize library – no options, no log callbacks

PvqaRtp_Settings settings;

memset(&settings, 0, sizeof settings);

settings.mPvqaLicensePath = “pvqa.lic”;

settings.mPvqaSettingsPath = “pvqa.cfg”;

if (Pvqa_Ok != PvqaRtp_InitLibrary(&settings))

{

printf(“Failed to initialize PVQA libraries.”);

return EXIT_FAILURE;

}

PvqaRtp_StreamContext ctx = NULL;

if (Pvqa_Ok != PvqaRtp_CreateStreamContext(&ctx))

{

printf(“Failed to create PVQA RTP stream context.”);

PvqaRtp_FreeLibrary();

return EXIT_FAILURE;

}

// Read file and send to library

char errbuf[PCAP_ERRBUF_SIZE];

pcap_t* handle = pcap_open_offline(path.c_str(), errbuf);

// Throw exception if smth wrong

if (!handle)

{

printf(“Failed to open .pcap file. Error: %s\n”, errbuf);

return EXIT_FAILURE;

}

pcap_pkthdr* packetHeader = NULL;

const u_char* packetData = NULL;

int readCode = 0;

int linkType = pcap_datalink(handle);

NetworkFrame::PacketData p;

while ((readCode = pcap_next_ex(handle, &packetHeader, &packetData)) == 1)

{

// Increate processed packet counter

if (parsePacket(linkType, packetHeader, packetData, p))

PvqaRtp_UpdateStream(ctx, p.mData, p.mLength);

}

pcap_close(handle);

// Get statistics

PvqaRtp_Statistics stats;

if (Pvqa_Ok != PvqaRtp_GetStreamStats(ctx, &stats))

{

printf(“Failed to get stats for RTP stream. See log for details.”);

PvqaRtp_FreeStreamContext(ctx);

PvqaRtp_FreeLibrary();

return EXIT_FAILURE;

}

printf(“Sevana MOS: %f\nNetwork MOS: %f\nDetector report:\n%s\n”, stats.mSevanaMos, stats.mNetworkMos, stats.mIntervalReport);

PvqaRtp_FreeStreamStats(&stats);

PvqaRtp_FreeStreamContext(ctx);

PvqaRtp_FreeLibrary();

return EXIT_SUCCESS;

}

要查看或添加评论,请登录

Valeri Sitnikov的更多文章

社区洞察

其他会员也浏览了