summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlfred E. Heggestad <aeh@db.org>2016-03-21 22:13:04 +0100
committerAlfred E. Heggestad <aeh@db.org>2016-03-21 22:13:04 +0100
commit5860fdb9a9b26e37852520d4598749f65f893bb5 (patch)
tree2fbc7a6ec5ccde2d49c3ea79106880126a1de7ed
parentffe31320d624f61afc536570853538c9df227254 (diff)
mos: add pseudo Mean Opinion Score routine
thanks to Lorenzo Mangani for the original patch
-rw-r--r--include/baresip.h8
-rw-r--r--src/mos.c63
-rw-r--r--src/srcs.mk1
-rw-r--r--test/main.c1
-rw-r--r--test/mos.c53
-rw-r--r--test/srcs.mk1
-rw-r--r--test/test.c7
-rw-r--r--test/test.h12
8 files changed, 146 insertions, 0 deletions
diff --git a/include/baresip.h b/include/baresip.h
index 43c929c..2d7b6c7 100644
--- a/include/baresip.h
+++ b/include/baresip.h
@@ -1031,6 +1031,14 @@ static inline bool h264_is_keyframe(int type)
int module_preload(const char *module);
+/*
+ * MOS (Mean Opinion Score)
+ */
+
+double mos_calculate(double *r_factor, double rtt,
+ double jitter, u_int32_t num_packets_lost);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/src/mos.c b/src/mos.c
new file mode 100644
index 0000000..8f78512
--- /dev/null
+++ b/src/mos.c
@@ -0,0 +1,63 @@
+/**
+ * @file src/mos.c MOS (Mean Opinion Score)
+ *
+ * Copyright (C) 2010 - 2016 Creytiv.com
+ */
+#include <re.h>
+#include <baresip.h>
+#include "core.h"
+
+
+static double rfactor_to_mos(double r)
+{
+ double mos;
+
+ mos = 1 + (0.035) * (r) + (0.000007) * (r) * ((r) - 60) * (100 - (r));
+
+ if (mos > 5)
+ mos = 5;
+
+ return mos;
+}
+
+
+/**
+ * Calculate Pseudo-MOS (Mean Opinion Score)
+ *
+ * @param r_factor Pointer to where R-factor is written (optional)
+ * @param rtt Average roundtrip time
+ * @param jitter Jitter
+ * @param num_packets_lost Number of packets lost
+ *
+ * @return The calculated MOS value from 1 to 5
+ *
+ * Reference: https://metacpan.org/pod/Algorithm::MOS
+ */
+double mos_calculate(double *r_factor, double rtt,
+ double jitter, u_int32_t num_packets_lost)
+{
+ double effective_latency = rtt + (jitter * 2) + 10;
+ double mos_val;
+ double r;
+
+ if (effective_latency < 160) {
+ r = 93.2 - (effective_latency / 40);
+ }
+ else {
+ r = 93.2 - (effective_latency - 120) / 10;
+ }
+
+ r = r - (num_packets_lost * 2.5);
+
+ if (r > 100)
+ r = 100;
+ else if (r < 0)
+ r = 0;
+
+ mos_val = rfactor_to_mos(r);
+
+ if (r_factor)
+ *r_factor = r;
+
+ return mos_val;
+}
diff --git a/src/srcs.mk b/src/srcs.mk
index 3c042ec..1ef6a4e 100644
--- a/src/srcs.mk
+++ b/src/srcs.mk
@@ -21,6 +21,7 @@ SRCS += message.c
SRCS += metric.c
SRCS += mnat.c
SRCS += module.c
+SRCS += mos.c
SRCS += net.c
SRCS += play.c
SRCS += realtime.c
diff --git a/test/main.c b/test/main.c
index 3a2cf37..9ee4825 100644
--- a/test/main.c
+++ b/test/main.c
@@ -26,6 +26,7 @@ static const struct test tests[] = {
TEST(test_call_reject),
TEST(test_cmd),
TEST(test_cplusplus),
+ TEST(test_mos),
TEST(test_ua_alloc),
TEST(test_ua_register),
TEST(test_uag_find_param),
diff --git a/test/mos.c b/test/mos.c
new file mode 100644
index 0000000..20b13c2
--- /dev/null
+++ b/test/mos.c
@@ -0,0 +1,53 @@
+/**
+ * @file test/mos.c Test the MOS (Mean Opinion Score) calculator
+ *
+ * Copyright (C) 2010 - 2016 Creytiv.com
+ */
+#include <re.h>
+#include <baresip.h>
+#include "test.h"
+
+
+#define DEBUG_MODULE "mos"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+int test_mos(void)
+{
+#define PRECISION 0.001
+ static struct {
+ /* input: */
+ double rtt;
+ double jitter;
+ uint32_t packet_loss;
+
+ /* output: */
+ double r_factor;
+ double mos;
+ } testv[] = {
+ { 0.0, 0.0, 0, 92.95, 4.404 },
+ { 500.0, 0.0, 0, 54.20, 2.796 },
+ { 1000.0, 0.0, 0, 4.20, 0.990 },
+ { 0.0, 100.0, 0, 84.20, 4.172 },
+ { 0.0, 200.0, 0, 64.20, 3.315 },
+ { 0.0, 0.0, 1, 90.45, 4.350 },
+ { 0.0, 0.0, 10, 67.95, 3.499 },
+ { 10.0, 10.0, 10, 67.20, 3.463 },
+ };
+ size_t i;
+ int err = 0;
+
+ for (i=0; i<ARRAY_SIZE(testv); i++) {
+ double r_factor, mos;
+
+ mos = mos_calculate(&r_factor, testv[i].rtt, testv[i].jitter,
+ testv[i].packet_loss);
+
+ ASSERT_DOUBLE_EQ(testv[i].r_factor, r_factor, PRECISION);
+ ASSERT_DOUBLE_EQ(testv[i].mos, mos, PRECISION);
+ }
+
+ out:
+ return err;
+}
diff --git a/test/srcs.mk b/test/srcs.mk
index 6195d10..332ba3f 100644
--- a/test/srcs.mk
+++ b/test/srcs.mk
@@ -12,6 +12,7 @@ TEST_SRCS += cmd.c
TEST_SRCS += ua.c
TEST_SRCS += cplusplus.c
TEST_SRCS += call.c
+TEST_SRCS += mos.c
#
diff --git a/test/test.c b/test/test.c
index 59e1cd1..8623180 100644
--- a/test/test.c
+++ b/test/test.c
@@ -1,3 +1,4 @@
+#include <math.h>
#include <re.h>
#include <baresip.h>
#include "test.h"
@@ -35,3 +36,9 @@ int re_main_timeout(uint32_t timeout_ms)
tmr_cancel(&tmr);
return err;
}
+
+
+bool test_cmp_double(double a, double b, double precision)
+{
+ return fabs(a - b) < precision;
+}
diff --git a/test/test.h b/test/test.h
index 4a91d28..20ccdcd 100644
--- a/test/test.h
+++ b/test/test.h
@@ -23,6 +23,16 @@
goto out; \
}
+#define ASSERT_DOUBLE_EQ(expected, actual, prec) \
+ if (!test_cmp_double((expected), (actual), (prec))) { \
+ warning("selftest: ASSERT_DOUBLE_EQ: %s:%u:" \
+ " expected=%f, actual=%f\n", \
+ __FILE__, __LINE__, \
+ (double)(expected), (double)(actual)); \
+ err = EINVAL; \
+ goto out; \
+ }
+
#define ASSERT_STREQ(expected, actual) \
if (0 != str_cmp((expected), (actual))) { \
warning("selftest: ASSERT_STREQ: %s:%u:" \
@@ -47,6 +57,7 @@
/* helpers */
int re_main_timeout(uint32_t timeout_ms);
+bool test_cmp_double(double a, double b, double precision);
#ifdef USE_TLS
@@ -78,6 +89,7 @@ int test_cmd(void);
int test_ua_alloc(void);
int test_uag_find_param(void);
int test_ua_register(void);
+int test_mos(void);
int test_call_answer(void);
int test_call_reject(void);