From 63a30499dbb8d280dbf4d18b393aa68ac3ce8c15 Mon Sep 17 00:00:00 2001 From: Piotr Gregor Date: Sun, 20 Mar 2016 23:58:45 +0000 Subject: [PATCH] FS-8961 Increase robustness of estimation Add optional requirement of consecutive streak of estimations in SMA buffer. Fix definitions. Add options to control debugging/printing. --- src/mod/applications/mod_avmd/desa2.c | 4 +- src/mod/applications/mod_avmd/fast_acosf.c | 2 +- src/mod/applications/mod_avmd/fast_acosf.h | 6 +- src/mod/applications/mod_avmd/mod_avmd.c | 76 ++++++++++++++++------ src/mod/applications/mod_avmd/options.h | 27 +++++++- 5 files changed, 89 insertions(+), 26 deletions(-) diff --git a/src/mod/applications/mod_avmd/desa2.c b/src/mod/applications/mod_avmd/desa2.c index 9550a211ce..bb19ad1f44 100644 --- a/src/mod/applications/mod_avmd/desa2.c +++ b/src/mod/applications/mod_avmd/desa2.c @@ -10,7 +10,7 @@ #include "desa2.h" #include "options.h" -#ifdef FASTMATH +#ifdef AVMD_FAST_MATH #include "fast_acosf.h" #endif @@ -40,7 +40,7 @@ extern double desa2(circ_buffer_t *b, size_t i) n = ((x2sq) - (x0 * x4)) - ((x1 * x1) - (x0 * x2)) - ((x3 * x3) - (x2 * x4)); -#ifdef FASTMATH +#ifdef AVMD_FAST_MATH result = 0.5 * (double)fast_acosf((float)n/d); #else result = 0.5 * acos(n/d); diff --git a/src/mod/applications/mod_avmd/fast_acosf.c b/src/mod/applications/mod_avmd/fast_acosf.c index 48e2baf580..b959d0b640 100644 --- a/src/mod/applications/mod_avmd/fast_acosf.c +++ b/src/mod/applications/mod_avmd/fast_acosf.c @@ -20,7 +20,7 @@ #include "fast_acosf.h" #include "options.h" -#ifdef FASTMATH +#ifdef AVMD_FAST_MATH typedef union { diff --git a/src/mod/applications/mod_avmd/fast_acosf.h b/src/mod/applications/mod_avmd/fast_acosf.h index a5f2f0649e..e70c8f936b 100644 --- a/src/mod/applications/mod_avmd/fast_acosf.h +++ b/src/mod/applications/mod_avmd/fast_acosf.h @@ -7,7 +7,7 @@ /*! \brief Arc cosine table initialization. * * @author Eric des Courtis - * @par Changes: Piotr Gregor, 07 Feb 2016 (FS-8809, FS-8810) + * @par Modifications: Piotr Gregor < piotrek.gregor gmail.com > * @return 0 on success, negative value otherwise: * -1 can't access arc cos table with error != NOENT, * -2 table creation failed (compute_table) @@ -19,7 +19,7 @@ extern int init_fast_acosf(void); /*! \brief Arc cosine table deinitialization. * * @author Eric des Courtis - * @par Changes: Piotr Gregor, 09 Feb 2016 (FS-8809, FS-8810) + * @par Modifications: Piotr Gregor < piotrek.gregor gmail.com > * @return 0 on success, negative value otherwise: * -1 munmap failed, * -2 close failed @@ -35,7 +35,7 @@ extern float fast_acosf(float x); /*! \brief Arc cosine table creation. * * @author Eric des Courtis - * @par Changes: Piotr Gregor, 07 Feb 2016 (FS-8809, FS-8810) + * @par Modifications: Piotr Gregor < piotrek.gregor gmail.com > * @return 0 on success, negative value otherwise: * -1 fwrite failed, * -2 fclose failed diff --git a/src/mod/applications/mod_avmd/mod_avmd.c b/src/mod/applications/mod_avmd/mod_avmd.c index ed1b676756..4acba1ca6d 100644 --- a/src/mod/applications/mod_avmd/mod_avmd.c +++ b/src/mod/applications/mod_avmd/mod_avmd.c @@ -55,6 +55,20 @@ #define ISNAN(x) (isnan(x)) #endif + +#include "amplitude.h" +#include "buffer.h" +#include "desa2.h" +//#include "goertzel.h" +#include "psi.h" +#include "sma_buf.h" +#include "options.h" + +#ifdef AVMD_FAST_MATH +#include "fast_acosf.h" +#endif + + /*! Calculate how many audio samples per ms based on the rate */ #define SAMPLES_PER_MS(r, m) ((r) / (1000/(m))) /*! Minimum beep length */ @@ -93,16 +107,9 @@ /* decrease this value to eliminate false positives */ #define VARIANCE_THRESHOLD (0.001) -#include "amplitude.h" -#include "buffer.h" -#include "desa2.h" -//#include "goertzel.h" -#include "psi.h" -#include "sma_buf.h" -#include "options.h" - -#ifdef FASTMATH -#include "fast_acosf.h" +#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK + /* increase this value to eliminate false positives */ + #define SAMPLES_CONSECUTIVE_STREAK 3 #endif /*! Syntax of the API call. */ @@ -148,6 +155,10 @@ typedef struct { /* freq_table_t ft; */ avmd_state_t state; switch_time_t start_time; +#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK + size_t samples_streak; /* number of DESA samples in single streak without reset + needed to validate SMA estimator, half the size of SMA buffer */ +#endif } avmd_session_t; static void avmd_process(avmd_session_t *session, switch_frame_t *frame); @@ -164,13 +175,19 @@ static void init_avmd_session_data(avmd_session_t *avmd_session, switch_core_se { /*! This is a worst case sample rate estimate */ avmd_session->rate = 48000; - INIT_CIRC_BUFFER(&avmd_session->b, (size_t)BEEP_LEN(avmd_session->rate), (size_t)FRAME_LEN(avmd_session->rate), fs_session); + INIT_CIRC_BUFFER(&avmd_session->b, + (size_t)BEEP_LEN(avmd_session->rate), + (size_t)FRAME_LEN(avmd_session->rate), + fs_session); avmd_session->session = fs_session; avmd_session->pos = 0; avmd_session->f = 0.0; avmd_session->state.last_beep = 0; avmd_session->state.beep_state = BEEP_NOTDETECTED; +#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK + avmd_session->samples_streak = SAMPLES_CONSECUTIVE_STREAK; +#endif INIT_SMA_BUFFER( &avmd_session->sma_b, @@ -239,7 +256,7 @@ static switch_bool_t avmd_callback(switch_media_bug_t * bug, void *user_data, sw */ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load) { -#ifdef FASTMATH +#ifdef AVMD_FAST_MATH char err[150]; int ret; #endif @@ -263,7 +280,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load) "Advanced Voicemail detection enabled\n" ); -#ifdef FASTMATH +#ifdef AVMD_FAST_MATH ret = init_fast_acosf(); if (ret != 0) { strerror_r(errno, err, 150); @@ -414,13 +431,13 @@ SWITCH_STANDARD_APP(avmd_start_function) */ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown) { -#ifdef FASTMATH +#ifdef AVMD_FAST_MATH int res; #endif switch_event_free_subclass(AVMD_EVENT_BEEP); -#ifdef FASTMATH +#ifdef AVMD_FAST_MATH res = destroy_fast_acosf(); if (res != 0) { switch (res) { @@ -639,22 +656,39 @@ static void avmd_process(avmd_session_t *session, switch_frame_t *frame) if (f < MIN_FREQUENCY_R(session->rate) || f > MAX_FREQUENCY_R(session->rate)) { v = 99999.0; +#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK RESET_SMA_BUFFER(&session->sma_b); RESET_SMA_BUFFER(&session->sqa_b); + session->samples_streak = SAMPLES_CONSECUTIVE_STREAK; +#endif } else { APPEND_SMA_VAL(&session->sma_b, f); APPEND_SMA_VAL(&session->sqa_b, f * f); - +#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK + if (session->samples_streak > 0) + --session->samples_streak; +#endif /* calculate variance */ v = session->sqa_b.sma - (session->sma_b.sma * session->sma_b.sma); - +#ifdef AVMD_DEBUG +#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG, - "<<< AVMD v=[%f] f=[%f] [%f]Hz sma=[%f] sqa=[%f] >>>\n", v, f, TO_HZ(session->rate, f), - session->sma_b.sma, session->sqa_b.sma); + "<<< AVMD v[%f] f[%f] [%f]Hz\tsma[%f][%f]Hz\tsqa[%f]\tstreak[%zu] pos[%zu] >>>\n", v, f, TO_HZ(session->rate, f), + session->sma_b.sma, TO_HZ(session->rate, session->sma_b.sma), session->sqa_b.sma, session->samples_streak, session->sma_b.pos); +#else + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG, + "<<< AVMD v[%f] f[%f] [%f]Hz\tsma[%f][%f]Hz\tsqa[%f]\tpos[%zu] >>>\n", v, f, TO_HZ(session->rate, f), + session->sma_b.sma, TO_HZ(session->rate, session->sma_b.sma), session->sqa_b.sma, session->sma_b.pos); +#endif +#endif } /* If variance is less than threshold then we have detection */ +#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK + if (v < VARIANCE_THRESHOLD && (session->sma_b.pos > 1) && (session->samples_streak == 0)) { +#else if (v < VARIANCE_THRESHOLD && (session->sma_b.pos > 1)) { +#endif switch_channel_set_variable_printf(channel, "avmd_total_time", "[%d]", (int)(switch_micro_time_now() - session->start_time) / 1000); switch_channel_execute_on(channel, "execute_on_avmd_beep"); @@ -673,8 +707,10 @@ static void avmd_process(avmd_session_t *session, switch_frame_t *frame) switch_core_session_queue_event(session->session, &event); switch_event_fire(&event_copy); +#ifdef AVMD_REPORT_STATUS switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG, "<<< AVMD - Beep Detected f = [%f] >>>\n", TO_HZ(session->rate, session->sma_b.sma)); +#endif switch_channel_set_variable(channel, "avmd_detect", "TRUE"); RESET_SMA_BUFFER(&session->sma_b); RESET_SMA_BUFFER(&session->sqa_b); @@ -689,6 +725,8 @@ static void avmd_process(avmd_session_t *session, switch_frame_t *frame) } } session->pos = pos; + + return; } /* For Emacs: diff --git a/src/mod/applications/mod_avmd/options.h b/src/mod/applications/mod_avmd/options.h index 9be3263938..39274a52c9 100644 --- a/src/mod/applications/mod_avmd/options.h +++ b/src/mod/applications/mod_avmd/options.h @@ -1,7 +1,32 @@ +/* + * @brief Options controlling avmd module. + * + * @author Eric des Courtis + * @par Modifications: Piotr Gregor < piotrek.gregor gmail.com > + */ + + #ifndef __OPTIONS_H__ #define __OPTIONS_H__ -/* #define FASTMATH */ + +/* #define AVMD_DEBUG 1 */ + +/* define/undef this to enable/disable reporting of beep + * detection status after session ended */ +#define AVMD_REPORT_STATUS 1 + +/* define/undefine this to enable/disable faster computation + * of arcus cosine - table will be created mapping floats + * to integers and returning arc cos values given these integer + * indexes into table */ +/* #define AVMD_FAST_MATH */ + +/* define/undefine this to classify avmd beep detection as valid + * only when there is required number of consecutive elements + * in the SMA buffer without reset */ +#define AVMD_REQUIRE_CONTINUOUS_STREAK 1 + #endif