diff --git a/conf/vanilla/autoload_configs/avmd.conf.xml b/conf/vanilla/autoload_configs/avmd.conf.xml index 1afd67d14f..f40c0a0cda 100644 --- a/conf/vanilla/autoload_configs/avmd.conf.xml +++ b/conf/vanilla/autoload_configs/avmd.conf.xml @@ -37,7 +37,7 @@ - + - + - + @@ -332,7 +332,7 @@ - + @@ -340,7 +340,7 @@ - + @@ -493,7 +493,7 @@ - + @@ -501,7 +501,7 @@ - + @@ -509,7 +509,7 @@ - + @@ -780,3 +780,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/applications/mod_avmd/mod_avmd.c b/src/mod/applications/mod_avmd/mod_avmd.c index 5bc48120a2..3fbab37730 100644 --- a/src/mod/applications/mod_avmd/mod_avmd.c +++ b/src/mod/applications/mod_avmd/mod_avmd.c @@ -62,7 +62,7 @@ int __isnan(double); /*! Calculate how many audio samples per ms based on the rate */ #define AVMD_SAMPLES_PER_MS(r, m) ((r) / (1000/(m))) /*! Minimum beep length */ -#define AVMD_BEEP_TIME (4) +#define AVMD_BEEP_TIME (2) /*! How often to evaluate the output of DESA-2 in ms */ #define AVMD_SINE_TIME (1*0.125) /*! How long in samples does DESA-2 results get evaluated */ @@ -78,9 +78,9 @@ int __isnan(double); /*! Conversion to Hertz */ #define AVMD_TO_HZ(r, f) (((r) * (f)) / (2.0 * M_PI)) /*! Minimum absolute pressure/amplitude */ -#define AVMD_MIN_AMP (5.0) +#define AVMD_MIN_AMP (17.0) /*! Minimum beep frequency in Hertz */ -#define AVMD_MIN_FREQUENCY (400.0) +#define AVMD_MIN_FREQUENCY (440.0) /*! Minimum frequency as digital normalized frequency */ #define AVMD_MIN_FREQUENCY_R(r) ((2.0 * M_PI * AVMD_MIN_FREQUENCY) / (r)) /*! @@ -101,8 +101,9 @@ int __isnan(double); /*! Maximum frequency as digital normalized frequency */ #define AVMD_MAX_FREQUENCY_R(r) ((2.0 * M_PI * AVMD_MAX_FREQUENCY) / (r)) #define AVMD_VARIANCE_RSD_THRESHOLD (0.000025) -#define AVMD_AMPLITUDE_RSD_THRESHOLD (0.015) +#define AVMD_AMPLITUDE_RSD_THRESHOLD (0.0148) #define AVMD_DETECTORS_N 45 +#define AVMD_DETECTORS_LAGGED_N 3 /*! Syntax of the API call. */ @@ -115,8 +116,7 @@ int __isnan(double); #define AVMD_PARAMS_APP_START_MIN 0u #define AVMD_PARAMS_APP_START_MAX 20u -/* don't forget to update avmd_events_str table - * if you modify this */ +/* don't forget to update avmd_events_str table if you modify this */ enum avmd_event { AVMD_EVENT_BEEP = 0, @@ -215,6 +215,7 @@ struct avmd_detector { avmd_session_t *s; size_t samples; uint8_t idx; + uint8_t lagged, lag; }; /*! Type that holds session information pertinent to the avmd module. */ @@ -228,12 +229,12 @@ struct avmd_session { double f; avmd_state_t state; switch_time_t start_time, stop_time, detection_start_time, detection_stop_time; - size_t sample_count; + size_t frame_n; uint8_t frame_n_to_skip; switch_mutex_t *mutex_detectors_done; switch_thread_cond_t *cond_detectors_done; - struct avmd_detector detectors[AVMD_DETECTORS_N]; + struct avmd_detector detectors[AVMD_DETECTORS_N + AVMD_DETECTORS_LAGGED_N]; }; struct avmd_globals @@ -241,6 +242,7 @@ struct avmd_globals switch_mutex_t *mutex; struct avmd_settings settings; switch_memory_pool_t *pool; + size_t session_n; } avmd_globals; static void avmd_process(avmd_session_t *session, switch_frame_t *frame); @@ -251,7 +253,7 @@ static switch_status_t avmd_register_all_events(void); static void avmd_unregister_all_events(void); static void avmd_fire_event(enum avmd_event type, switch_core_session_t *fs_s, double freq, double v_freq, double amp, double v_amp, avmd_beep_state_t beep_status, uint8_t info, - switch_time_t detection_start_time, switch_time_t detection_stop_time, switch_time_t start_time, switch_time_t stop_time); + switch_time_t detection_start_time, switch_time_t detection_stop_time, switch_time_t start_time, switch_time_t stop_time, uint8_t resolution, uint8_t offset, uint8_t idx); static enum avmd_detection_mode avmd_process_sample(avmd_session_t *s, circ_buffer_t *b, size_t sample_n, size_t pos, struct avmd_detector *d); @@ -282,17 +284,36 @@ static uint8_t avmd_detection_in_progress(avmd_session_t *s); static switch_status_t avmd_launch_threads(avmd_session_t *s) { - uint8_t idx; - switch_threadattr_t *thd_attr = NULL; + uint8_t idx; + struct avmd_detector *d; + switch_threadattr_t *thd_attr = NULL; idx = 0; while (idx < AVMD_DETECTORS_N) { - s->detectors[idx].flag_processing_done = 1; - s->detectors[idx].flag_should_exit = 0; - s->detectors[idx].result = AVMD_DETECT_NONE; + d = &s->detectors[idx]; + d->flag_processing_done = 1; + d->flag_should_exit = 0; + d->result = AVMD_DETECT_NONE; + d->lagged = 0; + d->lag = 0; switch_threadattr_create(&thd_attr, avmd_globals.pool); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); - if (switch_thread_create(&s->detectors[idx].thread, thd_attr, avmd_detector_func, (void *)&s->detectors[idx], switch_core_session_get_pool(s->session)) != SWITCH_STATUS_SUCCESS) { + if (switch_thread_create(&d->thread, thd_attr, avmd_detector_func, (void *)d, switch_core_session_get_pool(s->session)) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + ++idx; + } + idx = 0; + while (idx < AVMD_DETECTORS_LAGGED_N) { + d = &s->detectors[AVMD_DETECTORS_N + idx]; + d->flag_processing_done = 1; + d->flag_should_exit = 0; + d->result = AVMD_DETECT_NONE; + d->lagged = 1; + d->lag = idx + 1; + switch_threadattr_create(&thd_attr, avmd_globals.pool); + switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); + if (switch_thread_create(&d->thread, thd_attr, avmd_detector_func, (void *)d, switch_core_session_get_pool(s->session)) != SWITCH_STATUS_SUCCESS) { return SWITCH_STATUS_FALSE; } ++idx; @@ -377,7 +398,7 @@ static switch_status_t init_avmd_session_data(avmd_session_t *avmd_session, swit avmd_session->state.beep_state = BEEP_NOTDETECTED; memcpy(&avmd_session->settings, &avmd_globals.settings, sizeof(struct avmd_settings)); switch_mutex_init(&avmd_session->mutex, SWITCH_MUTEX_DEFAULT, switch_core_session_get_pool(fs_session)); - avmd_session->sample_count = 0; + avmd_session->frame_n = 0; avmd_session->detection_start_time = 0; avmd_session->detection_stop_time = 0; avmd_session->frame_n_to_skip = 0; @@ -408,8 +429,26 @@ static switch_status_t init_avmd_session_data(avmd_session_t *avmd_session, swit ++idx; } } + idx = 0; + resolution = 1; + offset = 0; + while (idx < AVMD_DETECTORS_LAGGED_N) { + d = &avmd_session->detectors[AVMD_DETECTORS_N + idx]; + if (avmd_init_buffer(&d->buffer, buf_sz, resolution, offset, fs_session) != SWITCH_STATUS_SUCCESS) { + status = SWITCH_STATUS_FALSE; + goto end; + } + d->s = avmd_session; + d->flag_processing_done = 1; + d->flag_should_exit = 1; + d->idx = AVMD_DETECTORS_N + idx; + switch_mutex_init(&d->mutex, SWITCH_MUTEX_DEFAULT, switch_core_session_get_pool(fs_session)); + switch_thread_cond_create(&d->cond_start_processing, switch_core_session_get_pool(fs_session)); + ++idx; + } switch_mutex_init(&avmd_session->mutex_detectors_done, SWITCH_MUTEX_DEFAULT, switch_core_session_get_pool(fs_session)); switch_thread_cond_create(&avmd_session->cond_detectors_done, switch_core_session_get_pool(fs_session)); + end: if (mutex != NULL) { @@ -431,7 +470,7 @@ static void avmd_session_close(avmd_session_t *s) { switch_mutex_unlock(s->mutex_detectors_done); idx = 0; - while (idx < AVMD_DETECTORS_N) { + while (idx < AVMD_DETECTORS_N + AVMD_DETECTORS_LAGGED_N) { d = &s->detectors[idx]; switch_mutex_lock(d->mutex); d = &s->detectors[idx]; @@ -529,6 +568,11 @@ static switch_bool_t avmd_callback(switch_media_bug_t * bug, void *user_data, sw case SWITCH_ABC_TYPE_CLOSE: avmd_session_close(avmd_session); + switch_mutex_lock(avmd_globals.mutex); + if (avmd_globals.session_n > 0) { + --avmd_globals.session_n; + } + switch_mutex_unlock(avmd_globals.mutex); break; default: @@ -569,7 +613,7 @@ static void avmd_unregister_all_events(void) { } static void avmd_fire_event(enum avmd_event type, switch_core_session_t *fs_s, double freq, double v_freq, double amp, double v_amp, avmd_beep_state_t beep_status, uint8_t info, - switch_time_t detection_start_time, switch_time_t detection_stop_time, switch_time_t start_time, switch_time_t stop_time) { + switch_time_t detection_start_time, switch_time_t detection_stop_time, switch_time_t start_time, switch_time_t stop_time, uint8_t resolution, uint8_t offset, uint8_t idx) { int res; switch_event_t *event; switch_time_t detection_time, total_time; @@ -622,6 +666,27 @@ static void avmd_fire_event(enum avmd_event type, switch_core_session_t *fs_s, d switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detection-time", "ERROR (TRUNCATED)"); } switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detection-time", buf); + + res = snprintf(buf, AVMD_CHAR_BUF_LEN, "%u", resolution); + if (res < 0 || res > AVMD_CHAR_BUF_LEN - 1) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_s), SWITCH_LOG_ERROR, "Error, truncated [%s], [%d] attempeted!\n", buf, res); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detector-resolution", "ERROR (TRUNCATED)"); + } + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detector-resolution", buf); + + res = snprintf(buf, AVMD_CHAR_BUF_LEN, "%u", offset); + if (res < 0 || res > AVMD_CHAR_BUF_LEN - 1) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_s), SWITCH_LOG_ERROR, "Error, truncated [%s], [%d] attempeted!\n", buf, res); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detector-offset", "ERROR (TRUNCATED)"); + } + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detector-offset", buf); + + res = snprintf(buf, AVMD_CHAR_BUF_LEN, "%u", idx); + if (res < 0 || res > AVMD_CHAR_BUF_LEN - 1) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_s), SWITCH_LOG_ERROR, "Error, truncated [%s], [%d] attempeted!\n", buf, res); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detector-index", "ERROR (TRUNCATED)"); + } + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Detector-index", buf); break; case AVMD_EVENT_SESSION_START: @@ -1255,7 +1320,7 @@ SWITCH_STANDARD_APP(avmd_start_app) { goto end; } switch_channel_set_private(channel, "_avmd_", bug); /* Set the avmd tag to detect an existing avmd media bug */ - avmd_fire_event(AVMD_EVENT_SESSION_START, session, 0, 0, 0, 0, 0, 0, 0, 0, avmd_session->start_time, 0); + avmd_fire_event(AVMD_EVENT_SESSION_START, session, 0, 0, 0, 0, 0, 0, 0, 0, avmd_session->start_time, 0, 0, 0, 0); if (avmd_session->settings.report_status == 1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Avmd on channel [%s] started!\n", switch_channel_get_name(channel)); } @@ -1265,6 +1330,10 @@ SWITCH_STANDARD_APP(avmd_start_app) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to start detection threads!\n"); goto end; } + + switch_mutex_lock(avmd_globals.mutex); + ++avmd_globals.session_n; + switch_mutex_unlock(avmd_globals.mutex); end: switch_mutex_unlock(avmd_session->mutex); @@ -1310,13 +1379,14 @@ SWITCH_STANDARD_APP(avmd_stop_app) { stop_time = avmd_session->stop_time; total_time = stop_time - start_time; switch_mutex_unlock(avmd_session->mutex); - avmd_fire_event(AVMD_EVENT_SESSION_STOP, session, 0, 0, 0, 0, beep_status, 1, 0, 0, start_time, stop_time); + avmd_fire_event(AVMD_EVENT_SESSION_STOP, session, 0, 0, 0, 0, beep_status, 1, 0, 0, start_time, stop_time, 0, 0, 0); if (report_status == 1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Avmd on channel [%s] stopped, beep status: [%s], total running time [%" PRId64 "] [us]\n", switch_channel_get_name(channel), beep_status == BEEP_DETECTED ? "DETECTED" : "NOTDETECTED", total_time); } } switch_channel_set_private(channel, "_avmd_", NULL); switch_core_media_bug_remove(session, &bug); + return; } @@ -1349,12 +1419,19 @@ SWITCH_STANDARD_APP(avmd_start_function) { } SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown) { + size_t session_n; #ifndef WIN32 int res; #endif switch_mutex_lock(avmd_globals.mutex); + session_n = avmd_globals.session_n; + if (session_n > 0) { + switch_mutex_unlock(avmd_globals.mutex); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PLEASE DO NOT RELOAD MODULE WHILE SESSIONS ARE RUNNING\n"); + } + avmd_unregister_all_events(); #ifndef WIN32 @@ -1382,9 +1459,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown) { return SWITCH_STATUS_SUCCESS; } -/*! \brief FreeSWITCH API handler function. - * This function handles API calls from mod_event_socket and LUA scripts. - */ +/*! \brief FreeSWITCH API handler function. */ SWITCH_STANDARD_API(avmd_api_main) { switch_media_bug_t *bug; avmd_session_t *avmd_session; @@ -1527,7 +1602,7 @@ SWITCH_STANDARD_API(avmd_api_main) { uuid_dup = switch_core_strdup(switch_core_session_get_pool(fs_session), uuid); switch_channel_set_private(channel, "_avmd_", NULL); switch_core_media_bug_remove(fs_session, &bug); - avmd_fire_event(AVMD_EVENT_SESSION_STOP, fs_session, 0, 0, 0, 0, 0, 0, 0, 0, avmd_session->start_time, avmd_session->stop_time); + avmd_fire_event(AVMD_EVENT_SESSION_STOP, fs_session, 0, 0, 0, 0, 0, 0, 0, 0, avmd_session->start_time, avmd_session->stop_time, 0, 0, 0); if (avmd_globals.settings.report_status == 1) { stream->write_function(stream, "+OK\n [%s] [%s] stopped\n\n", uuid_dup, switch_channel_get_name(channel)); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_INFO, "Avmd on channel [%s] stopped!\n", switch_channel_get_name(channel)); @@ -1617,7 +1692,7 @@ SWITCH_STANDARD_API(avmd_api_main) { switch_channel_set_private(channel, "_avmd_", bug); /* Set the vmd tag to detect an existing vmd media bug */ - avmd_fire_event(AVMD_EVENT_SESSION_START, fs_session, 0, 0, 0, 0, 0, 0, 0, 0, avmd_session->start_time, 0); + avmd_fire_event(AVMD_EVENT_SESSION_START, fs_session, 0, 0, 0, 0, 0, 0, 0, 0, avmd_session->start_time, 0, 0, 0, 0); if (avmd_globals.settings.report_status == 1) { stream->write_function(stream, "+OK\n [%s] [%s] started!\n\n", uuid, switch_channel_get_name(channel)); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_INFO, "Avmd on channel [%s] started!\n", switch_channel_get_name(channel)); @@ -1638,11 +1713,17 @@ end: static int avmd_decision_amplitude(const avmd_session_t *s, const struct avmd_buffer *b, double v, double rsd_threshold) { - double rsd; + double a, rsd; + size_t lpos; - if ((s->settings.require_continuous_streak_amp == 1 && (b->sma_amp_b.lpos > s->settings.sample_n_continuous_streak_amp) && (b->samples_streak_amp == 0)) - || (s->settings.require_continuous_streak_amp == 0 && (b->sma_amp_b.lpos > 1))) { - rsd = sqrt(v) / fabs(b->sma_amp_b.sma); + lpos = b->sma_b.lpos; + if ((lpos >= AVMD_BEEP_LEN(s->rate) / b->resolution) && ((s->settings.require_continuous_streak_amp == 1 && (b->sma_amp_b.lpos > s->settings.sample_n_continuous_streak_amp) && (b->samples_streak_amp == 0)) + || (s->settings.require_continuous_streak_amp == 0 && (b->sma_amp_b.lpos > 1)))) { + a = fabs(b->sma_amp_b.sma); + if (a < AVMD_MIN_AMP) { + return 0; + } + rsd = sqrt(v) / a; if (rsd < rsd_threshold) { return 1; } @@ -1668,19 +1749,20 @@ avmd_decision_freq(const avmd_session_t *s, const struct avmd_buffer *b, double if ((rsd < 0.6 * rsd_threshold) && (b->sma_amp_b.sma >= 0.01 * b->amplitude_max)) { return 1; } - if ((rsd < rsd_threshold) && (b->sma_amp_b.sma >= 0.02 * b->amplitude_max)) { + if ((rsd < rsd_threshold) && (b->sma_amp_b.sma >= 0.015 * b->amplitude_max)) { return 1; } } return 0; } -static void avmd_report_detection(avmd_session_t *s, enum avmd_detection_mode mode, const struct avmd_buffer *b) { +static void avmd_report_detection(avmd_session_t *s, enum avmd_detection_mode mode, const struct avmd_detector *d) { switch_channel_t *channel; switch_time_t detection_time; double f_sma = 0.0; double v_amp = 9999.9, v_fir = 9999.9; + const struct avmd_buffer *b = &d->buffer; const sma_buffer_t *sma_b_fir = &b->sma_b_fir; const sma_buffer_t *sqa_b_fir = &b->sqa_b_fir; @@ -1698,20 +1780,20 @@ static void avmd_report_detection(avmd_session_t *s, enum avmd_detection_mode mo case AVMD_DETECT_AMP: v_amp = sqa_amp_b->sma - (sma_amp_b->sma * sma_amp_b->sma); /* calculate variance of amplitude (biased estimator) */ - avmd_fire_event(AVMD_EVENT_BEEP, s->session, 0, 0, sma_amp_b->sma, v_amp, 0, 0, s->detection_start_time, s->detection_stop_time, 0, 0); + avmd_fire_event(AVMD_EVENT_BEEP, s->session, 0, 0, sma_amp_b->sma, v_amp, 0, 0, s->detection_start_time, s->detection_stop_time, 0, 0, b->resolution, b->offset, d->idx); if (s->settings.report_status == 1) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_INFO, "<<< AVMD - Beep Detected [%u][%u][%u]: amplitude = [%f] variance = [%f], detection time [%" PRId64 "] [us] >>>\n", - mode, b->resolution, b->offset, sma_amp_b->sma, v_amp, detection_time); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_INFO, "<<< AVMD - Beep Detected [%u][%u][%u][%u]: amplitude = [%f](max [%f]) variance = [%f], detection time [%" PRId64 "] [us] >>>\n", + mode, b->resolution, b->offset, d->idx, sma_amp_b->sma, b->amplitude_max, v_amp, detection_time); } break; case AVMD_DETECT_FREQ: f_sma = sma_b_fir->sma; v_fir = sqa_b_fir->sma - (sma_b_fir->sma * sma_b_fir->sma); /* calculate variance of filtered samples */ - avmd_fire_event(AVMD_EVENT_BEEP, s->session, AVMD_TO_HZ(s->rate, f_sma), v_fir, 0, 0, 0, 0, s->detection_start_time, s->detection_stop_time, 0, 0); + avmd_fire_event(AVMD_EVENT_BEEP, s->session, AVMD_TO_HZ(s->rate, f_sma), v_fir, 0, 0, 0, 0, s->detection_start_time, s->detection_stop_time, 0, 0, b->resolution, b->offset, d->idx); if (s->settings.report_status == 1) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_INFO, "<<< AVMD - Beep Detected [%u][%u][%u]: f = [%f] variance = [%f], detection time [%" PRId64 "] [us] >>>\n", - mode, b->resolution, b->offset, AVMD_TO_HZ(s->rate, f_sma), v_fir, detection_time); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_INFO, "<<< AVMD - Beep Detected [%u][%u][%u][%u]: f = [%f] variance = [%f], detection time [%" PRId64 "] [us] >>>\n", + mode, b->resolution, b->offset, d->idx, AVMD_TO_HZ(s->rate, f_sma), v_fir, detection_time); } break; @@ -1719,10 +1801,10 @@ static void avmd_report_detection(avmd_session_t *s, enum avmd_detection_mode mo v_amp = sqa_amp_b->sma - (sma_amp_b->sma * sma_amp_b->sma); /* calculate variance of amplitude (biased estimator) */ f_sma = sma_b_fir->sma; v_fir = sqa_b_fir->sma - (sma_b_fir->sma * sma_b_fir->sma); /* calculate variance of filtered samples */ - avmd_fire_event(AVMD_EVENT_BEEP, s->session, AVMD_TO_HZ(s->rate, f_sma), v_fir, sma_amp_b->sma, v_amp, 0, 0, s->detection_start_time, s->detection_stop_time, 0, 0); + avmd_fire_event(AVMD_EVENT_BEEP, s->session, AVMD_TO_HZ(s->rate, f_sma), v_fir, sma_amp_b->sma, v_amp, 0, 0, s->detection_start_time, s->detection_stop_time, 0, 0, b->resolution, b->offset, d->idx); if (s->settings.report_status == 1) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_INFO, "<<< AVMD - Beep Detected [%u][%u][%u]: f = [%f] variance = [%f], amplitude = [%f] variance = [%f], detection time [%" PRId64 "] [us] >>>\n", - mode, b->resolution, b->offset, AVMD_TO_HZ(s->rate, f_sma), v_fir, sma_amp_b->sma, v_amp, detection_time); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_INFO, "<<< AVMD - Beep Detected [%u][%u][%u][%u]: f = [%f] variance = [%f], amplitude = [%f](max [%f]) variance = [%f], detection time [%" PRId64 "] [us] >>>\n", + mode, b->resolution, b->offset, d->idx, AVMD_TO_HZ(s->rate, f_sma), v_fir, sma_amp_b->sma, b->amplitude_max, v_amp, detection_time); } break; @@ -1735,7 +1817,7 @@ static void avmd_report_detection(avmd_session_t *s, enum avmd_detection_mode mo static uint8_t avmd_detection_in_progress(avmd_session_t *s) { uint8_t idx = 0; - while (idx < AVMD_DETECTORS_N) { + while (idx < AVMD_DETECTORS_N +AVMD_DETECTORS_LAGGED_N) { switch_mutex_lock(s->detectors[idx].mutex); if (s->detectors[idx].flag_processing_done == 0) { switch_mutex_unlock(s->detectors[idx].mutex); @@ -1751,10 +1833,10 @@ static enum avmd_detection_mode avmd_detection_result(avmd_session_t *s) { enum avmd_detection_mode res; uint8_t idx = 0; - while (idx < AVMD_DETECTORS_N) { + while (idx < AVMD_DETECTORS_N + AVMD_DETECTORS_LAGGED_N) { res = s->detectors[idx].result; if (res != AVMD_DETECT_NONE) { - avmd_report_detection(s, res, &s->detectors[idx].buffer); + avmd_report_detection(s, res, &s->detectors[idx]); return res; } ++idx; @@ -1792,17 +1874,16 @@ static void avmd_process(avmd_session_t *s, switch_frame_t *frame) { } INSERT_INT16_FRAME(b, (int16_t *)(frame->data), frame->samples); /* Insert frame of 16 bit samples into buffer */ - s->sample_count += frame->samples; idx = 0; - while (idx < AVMD_DETECTORS_N) { + while (idx < AVMD_DETECTORS_N + AVMD_DETECTORS_LAGGED_N) { d = &s->detectors[idx]; switch_mutex_lock(d->mutex); d = &s->detectors[idx]; if (d->result == AVMD_DETECT_NONE) { d->flag_processing_done = 0; d->flag_should_exit = 0; - d->samples = frame->samples; + d->samples = (s->frame_n == 0 ? frame->samples - AVMD_P : frame->samples); switch_thread_cond_signal(d->cond_start_processing); } switch_mutex_unlock(d->mutex); @@ -1816,7 +1897,12 @@ static void avmd_process(avmd_session_t *s, switch_frame_t *frame) { avmd_detection_result(s); switch_mutex_unlock(s->mutex_detectors_done); - s->pos += frame->samples - AVMD_P; + ++s->frame_n; + if (s->frame_n == 1) { + s->pos += frame->samples - AVMD_P; + } else { + s->pos += frame->samples; + } s->pos &= b->mask; return; @@ -1854,7 +1940,7 @@ static enum avmd_detection_mode avmd_process_sample(avmd_session_t *s, circ_buff omega = avmd_desa2_tweaked(b, pos + sample_n, &litude); if (mode == AVMD_DETECT_AMP || mode == AVMD_DETECT_BOTH) { - if (ISNAN(amplitude)) { + if (ISNAN(amplitude) || ISINF(amplitude)) { valid_amplitude = 0; if (s->settings.require_continuous_streak_amp == 1) { RESET_SMA_BUFFER(sma_amp_b); @@ -1940,7 +2026,7 @@ static enum avmd_detection_mode avmd_process_sample(avmd_session_t *s, circ_buff return AVMD_DETECT_FREQ; } if (mode == AVMD_DETECT_BOTH) { - if ((sma_amp_b->sma > AVMD_MIN_AMP) && (avmd_decision_amplitude(s, buffer, v_amp, AVMD_AMPLITUDE_RSD_THRESHOLD) == 1) && (avmd_decision_freq(s, buffer, v_fir, AVMD_VARIANCE_RSD_THRESHOLD) == 1) && (valid_omega == 1)) { + if ((avmd_decision_amplitude(s, buffer, v_amp, AVMD_AMPLITUDE_RSD_THRESHOLD) == 1) && (avmd_decision_freq(s, buffer, v_fir, AVMD_VARIANCE_RSD_THRESHOLD) == 1) && (valid_omega == 1)) { return AVMD_DETECT_BOTH; } } @@ -1974,10 +2060,18 @@ avmd_detector_func(switch_thread_t *thread, void *arg) { resolution = d->buffer.resolution; offset = d->buffer.offset; samples = d->samples; - switch_mutex_unlock(d->mutex); - sample_n = 0; - while (sample_n < (samples - AVMD_P)) { + if (d->lagged == 1) { + if (d->lag > 0) { + --d->lag; + goto done; + } + pos += AVMD_P; + } + + switch_mutex_unlock(d->mutex); + sample_n = 1; + while (sample_n <= samples) { if (((sample_n + offset) % resolution) == 0) { res = avmd_process_sample(d->s, &s->b, sample_n, pos, d); if (res != AVMD_DETECT_NONE) { @@ -1987,6 +2081,7 @@ avmd_detector_func(switch_thread_t *thread, void *arg) { ++sample_n; } switch_mutex_lock(d->mutex); +done: d->flag_processing_done = 1; d->result = res; switch_mutex_unlock(d->mutex); diff --git a/src/mod/applications/mod_avmd/scripts/avmd_originate.pl b/src/mod/applications/mod_avmd/scripts/avmd_originate.pl index e4e4f7f55b..28d0cc97df 100644 --- a/src/mod/applications/mod_avmd/scripts/avmd_originate.pl +++ b/src/mod/applications/mod_avmd/scripts/avmd_originate.pl @@ -1,8 +1,7 @@ #!/usr/bin/perl -w -#brief Call single voicemail available in default dialplan -# and print detection result to the console. +#brief Call single voicemail and print detection result to the console. #author Piotr Gregor #date 15 Sept 2016 02:44 PM @@ -74,7 +73,7 @@ sub test_once { my $uuid = $con->api('create_uuid')->getBody(); my ($time_epoch, $time_hires) = Time::HiRes::gettimeofday(); - printf("Calling with uuid [%s] [%s]...\n", $uuid, POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime($time_epoch)), $time_hires); + printf("Calling with uuid [%s] [%s]...\n", $uuid, POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime($time_epoch))); $con->bgapi(sprintf($originate_string, $uuid)); diff --git a/src/mod/applications/mod_avmd/scripts/avmd_originate_multiple.pl b/src/mod/applications/mod_avmd/scripts/avmd_originate_multiple.pl new file mode 100644 index 0000000000..ace73e0570 --- /dev/null +++ b/src/mod/applications/mod_avmd/scripts/avmd_originate_multiple.pl @@ -0,0 +1,87 @@ +#!/usr/bin/perl -w + + +#brief Call (possibly) multiple voicemails +# and print detection result to the console. +#author Piotr Gregor +#date 15 Sept 2016 02:44 PM + + +use strict; +use warnings; +require ESL; +use POSIX; +use Time::HiRes; + +my $host = "127.0.0.1"; +my $port = "8021"; +my $pass = "ClueCon"; +my $extension_base = "sofia/internal/1000\@192.168.1.60"; + +my $playback = 'local_stream://moh'; +my $context = 'default'; +#Example: +#my $endpoint = "originate {originator_codec=PCMA,origination_uuid=%s}sofia/gateway/box_b/840534002 \&park()"; +my $endpoint = "originate {originator_codec=PCMA,origination_uuid=%s}sofia/gateway/%s/%s \&park()"; +my $gateway; +my $dest; +my $callerid; +my $thread_n; +my $idx = 0; + + +if ($#ARGV + 1 eq 4) { + $gateway = $ARGV[0]; + $dest = $ARGV[1]; + $callerid = $ARGV[2]; + $thread_n = $ARGV[3]; + print "Dialing [" .$thread_n ."] calls simultaneously to [" .$gateway ."][" .$dest ."] as [" .$callerid ."]\n"; +} else { + die "Please specify gateway, destination number, caller id and number of calls to make\n"; +} + +my $con = new ESL::ESLconnection($host, $port, $pass); +if (!$con) { + die "Unable to establish connection to $host:$port\n"; +} +if ($con->connected()) { + print "OK, Connected.\n"; +} else { + die "Connection failure.\n"; +} + +while($con->connected() && ($idx < $thread_n)) { + call_once($dest, $callerid, $idx); + $idx++; + Time::HiRes::sleep(0.15); # avoid switch_core_session.c:2265 Throttle Error! 33, switch_time.c:1227 Over Session Rate of 30! +} + +print "Disconnected.\n\n"; + +sub call_once { + my ($dest, $callerid, $idx) = @_; + my $uuid = + my $originate_string = + 'originate ' . + '{ignore_early_media=true,' . + 'originator_codec=PCMA,' . + 'origination_uuid=%s,' . + 'originate_timeout=60,' . + 'origination_caller_id_number=' . $callerid . ',' . + 'origination_caller_id_name=' . $callerid . '}'; + + if(defined($endpoint)) { + $originate_string = ''; + $originate_string .= $endpoint; + } else { + $originate_string .= 'loopback/' . $dest . '/' . $context; + $originate_string .= ' ' . '&playback(' . $playback . ')'; + } + + my $uuid = $con->api('create_uuid')->getBody(); + my ($time_epoch, $time_hires) = Time::HiRes::gettimeofday(); + printf("[%s]\tCalling with uuid [%s] [%s]... [%s]\n", $idx + 1, $uuid, POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime($time_epoch)), $originate_string); + + $con->bgapi(sprintf($originate_string, $uuid, $gateway, $dest)); + $con->api('uuid_setvar ' . $uuid .' execute_on_answer avmd_start'); +} diff --git a/src/mod/applications/mod_avmd/scripts/avmd_test.pl b/src/mod/applications/mod_avmd/scripts/avmd_test.pl index 3550b85469..06b91f4be1 100644 --- a/src/mod/applications/mod_avmd/scripts/avmd_test.pl +++ b/src/mod/applications/mod_avmd/scripts/avmd_test.pl @@ -1,13 +1,13 @@ #!/usr/bin/perl -w -#brief Test module avmd by calling all voicemails available -# in avmd test suite and print detection results to the console. +#brief Test module avmd by calling voicemails from avmd test suite +# and print detection results to the console. #author Piotr Gregor #details If you are testing serving voicemails from dialplan then avmd # must be set to inbound mode, either globally (by avmd set inbound # in fs_cli) or in dialplan settings ( "DETECTED", 840531213 => "DETECTED", 840531214 => "DETECTED", + 840531400 => "DETECTED", # obscure voicemails ATT pack + 840531401 => "DETECTED", + 840531402 => "DETECTED", + 840531403 => "DETECTED", + 840531404 => "DETECTED", + 840531405 => "DETECTED", + 840531051 => "NOTDETECTED", # fragment of "Save tonight" by Eagle-Eye Cherry covered by D-Lete-Funk-K ); my $host = "127.0.0.1"; @@ -122,7 +129,7 @@ my $pass = "ClueCon"; my $extension_base = "sofia/internal/1000\@192.168.1.60"; my $playback = 'local_stream://moh'; -my $context = 'default'; +my $context = 'default'; my $endpoint; my $dest; my $expectation; @@ -162,7 +169,7 @@ $con->events("plain", "CHANNEL_HANGUP"); print "OK.\n\n"; printf("\nRunning [" .keys(%numbers) ."] tests.\n\n"); -printf("outbound uuid | destination number | timestamp | expectation | test result\n\n"); +printf("outbound uuid | destination number | timestamp | expectation | test result | freq | f-variance | amplitude | a-variance\n\n"); foreach $dest (sort keys %numbers) { if (!$con->connected()) { last; @@ -182,7 +189,7 @@ sub test_once { my $originate_string = 'originate ' . '{ignore_early_media=true,' . - 'origination_uuid=%s,' . + 'origination_uuid=%s,' . 'originate_timeout=60,' . 'origination_caller_id_number=' . $callerid . ',' . 'origination_caller_id_name=' . $callerid . '}'; @@ -192,6 +199,11 @@ sub test_once { my $uuid_in = ""; my $freq = "N/A"; my $freq_var = "N/A"; + my $amp = "N/A"; + my $amp_var = "N/A"; + my $resolution = "N/A"; + my $offset = "N/A"; + my $idx = "N/A"; if(defined($endpoint)) { $originate_string .= $endpoint; @@ -220,6 +232,11 @@ sub test_once { if ($avmd_event_type eq 'avmd::beep') { $freq = $e->getHeader("Frequency"); $freq_var = $e->getHeader("Frequency-variance"); + $amp = $e->getHeader("Amplitude"); + $amp_var = $e->getHeader("Amplitude-variance"); + $resolution = $e->getHeader("Detector-resolution"); + $offset = $e->getHeader("Detector-offset"); + $idx = $e->getHeader("Detector-index"); } $outcome = $e->getHeader("Beep-Status"); if ($outcome eq $expectation) { @@ -243,6 +260,6 @@ sub test_once { } } } - printf("\t[%s]\t[%s]\t\t[%s]\t[%s]HZ\t[%s]\n", POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime($time_epoch)), $expectation, $result, $freq, $freq_var); + printf("\t[%s]\t[%s]\t\t[%s]\t[%s]HZ\t[%s]\t[%s]\t[%s]\t[%s][%s][%s]\n", POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime($time_epoch)), $expectation, $result, $freq, $freq_var, $amp, $amp_var, $resolution, $offset, $idx); Time::HiRes::sleep(0.5); # avoid switch_core_session.c:2265 Throttle Error! 33, switch_time.c:1227 Over Session Rate of 30! }