Skip to content

Instantly share code, notes, and snippets.

@TheBeachMaster
Forked from sergioa/MOS calculation
Created September 6, 2018 14:12
Show Gist options
  • Save TheBeachMaster/b5fbb7e3e3dacc940ce84f25d944dc47 to your computer and use it in GitHub Desktop.
Save TheBeachMaster/b5fbb7e3e3dacc940ce84f25d944dc47 to your computer and use it in GitHub Desktop.
static int internal_get_and_notify_call_statistics(pjsua_call_id call_id, long comm_id)
{
pj_status_t status = PJ_SUCCESS;
pjsua_stream_stat stat;
int LOCAL_DELAY = 30;
float R;
float a = 0.0f; //iLBC a = 10;
float b = 19.8f;
float c = 29.7f;
int rx_pkts = 0;
int tx_pkts = 0;
float rx_loss = 0.0;
float tx_loss = 0.0;
float rx_jit = 0.0;
float tx_jit = 0.0;
float avg_rtt = 0.0;
float avg_latency = 0.0;
float MOS = 0.0;
if (internal_call_has_media(call_id)) {
PJ_LOG(4, (THIS_FILE,"Call have had media. Calculate the statistics."));
} else {
PJ_LOG(4, (THIS_FILE,"Call has never established media, return with no calculations."));
return PJ_EINVAL;
}
status = pjsua_call_get_stream_stat(call_id, 0, &stat);
//Only calculate the MOS if we have sent and received packets (also protects us from potential division by zero).
if (status == PJ_SUCCESS) {
PJ_LOG(4, (THIS_FILE,
"pjsip stats: stat.rtcp.rx.pkt=%d : stat.rtcp.tx.pkt=%d : stat.rtcp.rx.loss=%d : stat.rtcp.rtt.mean=%d : stat.rtcp.rx.dup=%d ",
stat.rtcp.rx.pkt, stat.rtcp.tx.pkt, stat.rtcp.rx.loss, stat.rtcp.rtt.mean, stat.rtcp.rx.dup));
rx_pkts = stat.rtcp.rx.pkt;
tx_pkts = stat.rtcp.tx.pkt;
rx_loss = (stat.rtcp.rx.pkt == 0) ? 1.0f : ((float)stat.rtcp.rx.loss) / (float)((stat.rtcp.rx.pkt + stat.rtcp.rx.loss));
tx_loss = (stat.rtcp.tx.pkt == 0) ? 1.0f : ((float)stat.rtcp.tx.loss) / (float)stat.rtcp.tx.pkt;
rx_jit = (float)stat.rtcp.rx.jitter.mean/1000;
tx_jit = (float)stat.rtcp.tx.jitter.mean/1000;
avg_rtt = stat.rtcp.rtt.mean / 2000.0f;
if (avg_rtt == 0) { //means that there is no rtt information in rtcp packets so we estimate value
PJ_LOG(4, (THIS_FILE, "There is no avg_rtt in rtcp packet. We set avg_rtt to estimated fixed value"));
avg_rtt = TU_AVERAGE_RTT_ESTIMATION;
}
//Johan: For the local delay we also have to take sound card latency and jbuf state into account.
avg_latency = (stat.rtcp.rtt.mean / 2000.0f) + LOCAL_DELAY + pjsua_var.media_cfg.snd_play_latency +
pjsua_var.media_cfg.snd_rec_latency + rx_jit;
//Calculate R
{
float d = avg_latency;
float d2 = d-177.3f;
float Id = 0.024f * d + 0.11f * (d - 177.3f) * (d2 < 0 ? 0 : 1);
float P = rx_loss; //stats.getPacketLoss();
float Ie = a + b * (float)log(1 + c * P);
R = 94.2f - Id - Ie;
PJ_LOG(4, (THIS_FILE, "d=%f : d2=%f : Id=%f : P=%f : Ie=%f : R=%f", d, d2, Id, P, Ie, R));
}
if (R < 0) {
MOS = 1;
} else if (R > 100) {
MOS = 4.5;
} else {
MOS = 1 + 0.035f * R + 7.10f/1000000 * R * (R - 60) * (100 - R);
}
PJ_LOG(4, (THIS_FILE,
"Our stats: rx_pkts=%d tx_pkts=%d rx_loss=%f \naverage rtt=%f average_latency=%f R=%f \nMOS score : %3.1f \n", rx_pkts,
tx_pkts, rx_loss, avg_rtt, avg_latency, R, MOS));
//notifying statistics
tu_var.cfg.callbacks.on_call_media_statistics(get_call_uuid(call_id), comm_id, rx_pkts, tx_pkts, rx_loss, tx_loss,
rx_jit, tx_jit, avg_rtt, avg_latency, MOS);
} else {
PJ_LOG(1, (THIS_FILE, "Failed to call pjsua_call_get_stream_stat, status=%d",status));
}
return status;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment