diff options
-rw-r--r-- | include/baresip.h | 8 | ||||
-rw-r--r-- | src/mos.c | 63 | ||||
-rw-r--r-- | src/srcs.mk | 1 | ||||
-rw-r--r-- | test/main.c | 1 | ||||
-rw-r--r-- | test/mos.c | 53 | ||||
-rw-r--r-- | test/srcs.mk | 1 | ||||
-rw-r--r-- | test/test.c | 7 | ||||
-rw-r--r-- | test/test.h | 12 |
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); |