diff --git a/conf/vanilla/autoload_configs/avmd.conf.xml b/conf/vanilla/autoload_configs/avmd.conf.xml
index 2366195621..1afd67d14f 100644
--- a/conf/vanilla/autoload_configs/avmd.conf.xml
+++ b/conf/vanilla/autoload_configs/avmd.conf.xml
@@ -37,13 +37,16 @@
-
+
-
+
+
+
+
+
+
+
+
diff --git a/src/mod/applications/mod_avmd/avmd_buffer.h b/src/mod/applications/mod_avmd/avmd_buffer.h
index b7a6cbb233..3910fa1876 100644
--- a/src/mod/applications/mod_avmd/avmd_buffer.h
+++ b/src/mod/applications/mod_avmd/avmd_buffer.h
@@ -39,7 +39,7 @@ extern size_t next_power_of_2(size_t v);
{ \
(b)->pos++; \
(b)->pos &= (b)->mask; \
- (b)->lpos++; \
+ (b)->lpos + 1 < 2 * (b)->buf_len ? (b)->lpos++ : (b)->lpos = (b)->buf_len; \
if ((b)->backlog < (b)->buf_len) (b)->backlog++; \
}
diff --git a/src/mod/applications/mod_avmd/avmd_desa2_tweaked.c b/src/mod/applications/mod_avmd/avmd_desa2_tweaked.c
index 6bf0b41348..2aa8785491 100644
--- a/src/mod/applications/mod_avmd/avmd_desa2_tweaked.c
+++ b/src/mod/applications/mod_avmd/avmd_desa2_tweaked.c
@@ -63,14 +63,14 @@ avmd_desa2_tweaked(circ_buffer_t *b, size_t i, double *amplitude) {
we do simplified, modified for speed version : */
result = n/d;
- if (ISINF(result)) {
+/* if (ISINF(result)) {
*amplitude = 0.0;
if (n < 0.0) {
return -10.0;
} else {
return 10.0;
}
- }
+ }*/
*amplitude = 2.0 * PSI_Xn / sqrt(PSI_Yn);
return result;
}
diff --git a/src/mod/applications/mod_avmd/avmd_fir.h b/src/mod/applications/mod_avmd/avmd_fir.h
index 23860f5887..25a2c23bb3 100644
--- a/src/mod/applications/mod_avmd/avmd_fir.h
+++ b/src/mod/applications/mod_avmd/avmd_fir.h
@@ -13,9 +13,9 @@
#define __AVMD_FIR_H__
-#define DESA_MAX(a, b) (a) > (b) ? (a) : (b)
-#define MEDIAN_FILTER(a, b, c) (a) > (b) ? ((a) > (c) ? \
- DESA_MAX((b), (c)) : a) : ((b) > (c) ? DESA_MAX((a), (c)) : (b))
+#define AVMD_MAX(a, b) (a) > (b) ? (a) : (b)
+#define AVMD_MEDIAN_FILTER(a, b, c) (a) > (b) ? ((a) > (c) ? \
+ AVMD_MAX((b), (c)) : a) : ((b) > (c) ? AVMD_MAX((a), (c)) : (b))
#endif
diff --git a/src/mod/applications/mod_avmd/avmd_sma_buf.h b/src/mod/applications/mod_avmd/avmd_sma_buf.h
index 5c5c6a108a..e3051c9731 100644
--- a/src/mod/applications/mod_avmd/avmd_sma_buf.h
+++ b/src/mod/applications/mod_avmd/avmd_sma_buf.h
@@ -46,7 +46,7 @@ typedef struct {
#define INC_SMA_POS(b) \
{ \
- (b)->lpos++; \
+ ((b)->lpos + 1 < 2 * (b)->len) ? ((b)->lpos++) : ((b)->lpos = (b)->len); \
(b)->pos = (b)->lpos % (b)->len; \
}
diff --git a/src/mod/applications/mod_avmd/conf/autoload_configs/avmd.conf.xml b/src/mod/applications/mod_avmd/conf/autoload_configs/avmd.conf.xml
index 2366195621..1afd67d14f 100644
--- a/src/mod/applications/mod_avmd/conf/autoload_configs/avmd.conf.xml
+++ b/src/mod/applications/mod_avmd/conf/autoload_configs/avmd.conf.xml
@@ -37,13 +37,16 @@
-
+
-
+
+
+
+
+
+
+
+
diff --git a/src/mod/applications/mod_avmd/conf/avmd_test_dialplan.xml b/src/mod/applications/mod_avmd/conf/avmd_test_dialplan.xml
new file mode 100644
index 0000000000..59099777ba
--- /dev/null
+++ b/src/mod/applications/mod_avmd/conf/avmd_test_dialplan.xml
@@ -0,0 +1,782 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/applications/mod_avmd/mod_avmd.c b/src/mod/applications/mod_avmd/mod_avmd.c
index a058f9e061..5bc48120a2 100644
--- a/src/mod/applications/mod_avmd/mod_avmd.c
+++ b/src/mod/applications/mod_avmd/mod_avmd.c
@@ -29,12 +29,14 @@
* beeps) using modified DESA-2 algorithm.
*/
+
#include
#include
#include
#include
#include
#include
+#include
#ifdef WIN32
#include
@@ -52,32 +54,35 @@ int __isnan(double);
#include "avmd_desa2_tweaked.h"
#include "avmd_sma_buf.h"
#include "avmd_options.h"
+#include "avmd_fir.h"
#include "avmd_fast_acosf.h"
/*! Calculate how many audio samples per ms based on the rate */
-#define SAMPLES_PER_MS(r, m) ((r) / (1000/(m)))
+#define AVMD_SAMPLES_PER_MS(r, m) ((r) / (1000/(m)))
/*! Minimum beep length */
-#define BEEP_TIME (2)
+#define AVMD_BEEP_TIME (4)
/*! How often to evaluate the output of DESA-2 in ms */
-#define SINE_TIME (2*0.125)
+#define AVMD_SINE_TIME (1*0.125)
/*! How long in samples does DESA-2 results get evaluated */
-#define SINE_LEN(r) SAMPLES_PER_MS((r), SINE_TIME)
+#define AVMD_SINE_LEN(r) AVMD_SAMPLES_PER_MS((r), AVMD_SINE_TIME)
/*! How long in samples is the minimum beep length */
-#define BEEP_LEN(r) SAMPLES_PER_MS((r), BEEP_TIME)
+#define AVMD_BEEP_LEN(r) AVMD_SAMPLES_PER_MS((r), AVMD_BEEP_TIME)
/*! Number of points in DESA-2 sample */
-#define P (5)
+#define AVMD_P (5)
/*! Guesstimate frame length in ms */
-#define FRAME_TIME (20)
+#define AVMD_FRAME_TIME (20)
/*! Length in samples of the frame (guesstimate) */
-#define FRAME_LEN(r) SAMPLES_PER_MS((r), FRAME_TIME)
+#define AVMD_FRAME_LEN(r) AVMD_SAMPLES_PER_MS((r), AVMD_FRAME_TIME)
/*! Conversion to Hertz */
-#define TO_HZ(r, f) (((r) * (f)) / (2.0 * M_PI))
+#define AVMD_TO_HZ(r, f) (((r) * (f)) / (2.0 * M_PI))
+/*! Minimum absolute pressure/amplitude */
+#define AVMD_MIN_AMP (5.0)
/*! Minimum beep frequency in Hertz */
-#define MIN_FREQUENCY (300.0)
+#define AVMD_MIN_FREQUENCY (400.0)
/*! Minimum frequency as digital normalized frequency */
-#define MIN_FREQUENCY_R(r) ((2.0 * M_PI * MIN_FREQUENCY) / (r))
+#define AVMD_MIN_FREQUENCY_R(r) ((2.0 * M_PI * AVMD_MIN_FREQUENCY) / (r))
/*!
* Maximum beep frequency in Hertz
* Note: The maximum frequency the DESA-2 algorithm can uniquely
@@ -92,11 +97,12 @@ int __isnan(double);
* In case of DESA-1, frequencies up to 0.5 sampling rate are
* identified uniquely.
*/
-#define MAX_FREQUENCY (2500.0)
+#define AVMD_MAX_FREQUENCY (2000.0)
/*! Maximum frequency as digital normalized frequency */
-#define MAX_FREQUENCY_R(r) ((2.0 * M_PI * MAX_FREQUENCY) / (r))
-/* decrease this value to eliminate false positives */
-#define VARIANCE_THRESHOLD (0.00025)
+#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_DETECTORS_N 45
/*! Syntax of the API call. */
@@ -118,10 +124,11 @@ enum avmd_event
AVMD_EVENT_SESSION_STOP = 2
};
/* This array MUST be NULL terminated! */
-const char* avmd_events_str[] = { [AVMD_EVENT_BEEP] = "avmd::beep",
- [AVMD_EVENT_SESSION_START] = "avmd::start",
- [AVMD_EVENT_SESSION_STOP] = "avmd::stop",
- NULL /* MUST be last and always here */
+const char* avmd_events_str[] = {
+ [AVMD_EVENT_BEEP] = "avmd::beep",
+ [AVMD_EVENT_SESSION_START] = "avmd::start",
+ [AVMD_EVENT_SESSION_STOP] = "avmd::stop",
+ NULL /* MUST be last and always here */
};
#define AVMD_CHAR_BUF_LEN 20u
@@ -134,6 +141,14 @@ enum avmd_app
AVMD_APP_START_FUNCTION = 2 /* deprecated since version 1.6.8 */
};
+enum avmd_detection_mode
+{
+ AVMD_DETECT_AMP = 0,
+ AVMD_DETECT_FREQ = 1,
+ AVMD_DETECT_BOTH = 2,
+ AVMD_DETECT_NONE = 3
+};
+
/* Prototypes */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown);
SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load);
@@ -150,43 +165,76 @@ struct avmd_settings {
uint8_t require_continuous_streak;
uint16_t sample_n_continuous_streak;
uint16_t sample_n_to_skip;
+ uint8_t require_continuous_streak_amp;
+ uint16_t sample_n_continuous_streak_amp;
uint8_t simplified_estimation;
uint8_t inbound_channnel;
uint8_t outbound_channnel;
+ enum avmd_detection_mode mode;
};
/*! Status of the beep detection */
typedef enum {
- BEEP_DETECTED,
- BEEP_NOTDETECTED
+ BEEP_DETECTED,
+ BEEP_NOTDETECTED
} avmd_beep_state_t;
/*! Data related to the current status of the beep */
typedef struct {
- avmd_beep_state_t beep_state;
- size_t last_beep;
+ avmd_beep_state_t beep_state;
+ size_t last_beep;
} avmd_state_t;
+struct avmd_session;
+typedef struct avmd_session avmd_session_t;
+
+struct avmd_buffer {
+ sma_buffer_t sma_b;
+ sma_buffer_t sqa_b;
+
+ sma_buffer_t sma_b_fir;
+ sma_buffer_t sqa_b_fir;
+
+ sma_buffer_t sma_amp_b;
+ sma_buffer_t sqa_amp_b;
+
+ uint8_t resolution;
+ uint8_t offset;
+ double amplitude_max;
+ size_t samples_streak, samples_streak_amp; /* number of DESA samples in single streak without reset needed to validate SMA estimator */
+};
+
+struct avmd_detector {
+ switch_thread_t *thread;
+ switch_mutex_t *mutex;
+ uint8_t flag_processing_done;
+ uint8_t flag_should_exit;
+ enum avmd_detection_mode result;
+ switch_thread_cond_t *cond_start_processing;
+ struct avmd_buffer buffer;
+ avmd_session_t *s;
+ size_t samples;
+ uint8_t idx;
+};
+
/*! Type that holds session information pertinent to the avmd module. */
-typedef struct {
- /*! Internal FreeSWITCH session. */
- switch_core_session_t *session;
+struct avmd_session {
+ switch_core_session_t *session;
switch_mutex_t *mutex;
struct avmd_settings settings;
- uint32_t rate;
- circ_buffer_t b;
- sma_buffer_t sma_b;
- sma_buffer_t sqa_b;
- sma_buffer_t sma_amp_b;
- sma_buffer_t sqa_amp_b;
- size_t pos;
- double f;
- /* freq_table_t ft; */
- avmd_state_t state;
- switch_time_t start_time, stop_time, detection_start_time, detection_stop_time;
- size_t samples_streak; /* number of DESA samples in single streak without reset needed to validate SMA estimator */
- size_t sample_count;
-} avmd_session_t;
+ uint32_t rate;
+ circ_buffer_t b;
+ size_t pos;
+ double f;
+ avmd_state_t state;
+ switch_time_t start_time, stop_time, detection_start_time, detection_stop_time;
+ size_t sample_count;
+ 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_globals
{
@@ -202,10 +250,11 @@ 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,
+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);
+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);
+
/* API [set default], reset to factory settings */
static void avmd_set_xml_default_configuration(switch_mutex_t *mutex);
/* API [set inbound], set inbound = 1, outbound = 0 */
@@ -226,16 +275,87 @@ static void avmd_reloadxml_event_handler(switch_event_t *event);
/* API command */
static void avmd_show(switch_stream_handle_t *stream, switch_mutex_t *mutex);
+static void*
+avmd_detector_func(switch_thread_t *thread, void *arg);
+
+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;
+
+ 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;
+ 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) {
+ return SWITCH_STATUS_FALSE;
+ }
+ ++idx;
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t avmd_init_buffer(struct avmd_buffer *b, size_t buf_sz, uint8_t resolution, uint8_t offset, switch_core_session_t *fs_session) {
+ INIT_SMA_BUFFER(&b->sma_b, buf_sz, fs_session);
+ if (b->sma_b.data == NULL) {
+ return SWITCH_STATUS_FALSE;
+ }
+ memset(b->sma_b.data, 0, sizeof(BUFF_TYPE) * buf_sz);
+
+ INIT_SMA_BUFFER(&b->sqa_b, buf_sz, fs_session);
+ if (b->sqa_b.data == NULL) {
+ return SWITCH_STATUS_FALSE;
+ }
+ memset(b->sqa_b.data, 0, sizeof(BUFF_TYPE) * buf_sz);
+
+ INIT_SMA_BUFFER(&b->sma_b_fir, buf_sz, fs_session);
+ if (b->sma_b_fir.data == NULL) {
+ return SWITCH_STATUS_FALSE;
+ }
+ memset(b->sma_b_fir.data, 0, sizeof(BUFF_TYPE) * buf_sz);
+
+ INIT_SMA_BUFFER(&b->sqa_b_fir, buf_sz, fs_session);
+ if (b->sqa_b_fir.data == NULL) {
+ return SWITCH_STATUS_FALSE;
+ }
+ memset(b->sqa_b_fir.data, 0, sizeof(BUFF_TYPE) * buf_sz);
+
+ INIT_SMA_BUFFER(&b->sma_amp_b, buf_sz, fs_session);
+ if (b->sma_amp_b.data == NULL) {
+ return SWITCH_STATUS_FALSE;
+ }
+ memset(b->sma_amp_b.data, 0, sizeof(BUFF_TYPE) * buf_sz);
+
+ INIT_SMA_BUFFER(&b->sqa_amp_b, buf_sz, fs_session);
+ if (b->sqa_amp_b.data == NULL) {
+ return SWITCH_STATUS_FALSE;
+ }
+ memset(b->sqa_amp_b.data, 0, sizeof(BUFF_TYPE) * buf_sz);
+
+ b->amplitude_max = 0.0;
+ b->samples_streak = 0;
+ b->samples_streak_amp = 0;
+ b->resolution = resolution;
+ b->offset = offset;
+
+ return SWITCH_STATUS_SUCCESS;
+}
/*! \brief The avmd session data initialization function.
* @param avmd_session A reference to a avmd session.
* @param fs_session A reference to a FreeSWITCH session.
* @details Avmd globals mutex must be locked.
*/
-static switch_status_t
-init_avmd_session_data(avmd_session_t *avmd_session, switch_core_session_t *fs_session, switch_mutex_t *mutex)
+static switch_status_t init_avmd_session_data(avmd_session_t *avmd_session, switch_core_session_t *fs_session, switch_mutex_t *mutex)
{
+ uint8_t idx, resolution, offset;
size_t buf_sz;
+ struct avmd_detector *d;
switch_status_t status = SWITCH_STATUS_SUCCESS;
if (mutex != NULL)
@@ -243,58 +363,53 @@ init_avmd_session_data(avmd_session_t *avmd_session, switch_core_session_t *fs_s
switch_mutex_lock(mutex);
}
- /*! 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);
+ /*! This is a worst case sample rate estimate */
+ avmd_session->rate = 48000;
+ INIT_CIRC_BUFFER(&avmd_session->b, (size_t) AVMD_BEEP_LEN(avmd_session->rate), (size_t) AVMD_FRAME_LEN(avmd_session->rate), fs_session);
if (avmd_session->b.buf == NULL) {
- status = SWITCH_STATUS_MEMERR;
- goto end;
+ status = SWITCH_STATUS_MEMERR;
+ goto end;
}
- 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;
- avmd_session->samples_streak = 0;
+ 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;
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));
+ switch_mutex_init(&avmd_session->mutex, SWITCH_MUTEX_DEFAULT, switch_core_session_get_pool(fs_session));
avmd_session->sample_count = 0;
avmd_session->detection_start_time = 0;
avmd_session->detection_stop_time = 0;
+ avmd_session->frame_n_to_skip = 0;
- buf_sz = BEEP_LEN((uint32_t)avmd_session->rate) / (uint32_t)SINE_LEN(avmd_session->rate);
+ buf_sz = AVMD_BEEP_LEN((uint32_t)avmd_session->rate) / (uint32_t) AVMD_SINE_LEN(avmd_session->rate);
if (buf_sz < 1) {
- status = SWITCH_STATUS_MORE_DATA;
- goto end;
+ status = SWITCH_STATUS_MORE_DATA;
+ goto end;
}
-
- INIT_SMA_BUFFER(&avmd_session->sma_b, buf_sz, fs_session);
- if (avmd_session->sma_b.data == NULL) {
- status = SWITCH_STATUS_FALSE;
- goto end;
+ idx = 0;
+ resolution = 0;
+ while (idx < AVMD_DETECTORS_N) {
+ ++resolution;
+ offset = 0;
+ while ((offset < resolution) && (idx < AVMD_DETECTORS_N)) {
+ d = &avmd_session->detectors[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 = 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));
+ ++offset;
+ ++idx;
+ }
}
- memset(avmd_session->sma_b.data, 0, sizeof(BUFF_TYPE) * buf_sz);
-
- INIT_SMA_BUFFER(&avmd_session->sqa_b, buf_sz, fs_session);
- if (avmd_session->sqa_b.data == NULL) {
- status = SWITCH_STATUS_FALSE;
- goto end;
- }
- memset(avmd_session->sqa_b.data, 0, sizeof(BUFF_TYPE) * buf_sz);
-
- INIT_SMA_BUFFER(&avmd_session->sma_amp_b, buf_sz, fs_session);
- if (avmd_session->sma_amp_b.data == NULL) {
- status = SWITCH_STATUS_FALSE;
- goto end;
- }
- memset(avmd_session->sma_amp_b.data, 0, sizeof(BUFF_TYPE) * buf_sz);
-
- INIT_SMA_BUFFER(&avmd_session->sqa_amp_b, buf_sz, fs_session);
- if (avmd_session->sqa_amp_b.data == NULL) {
- status = SWITCH_STATUS_FALSE;
- goto end;
- }
- memset(avmd_session->sqa_amp_b.data, 0, sizeof(BUFF_TYPE) * buf_sz);
+ 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)
{
@@ -303,6 +418,37 @@ end:
return status;
}
+static void avmd_session_close(avmd_session_t *s) {
+ uint8_t idx;
+ struct avmd_detector *d;
+
+ switch_mutex_lock(s->mutex);
+
+ switch_mutex_lock(s->mutex_detectors_done);
+ while (avmd_detection_in_progress(s) == 1) {
+ switch_thread_cond_wait(s->cond_detectors_done, s->mutex_detectors_done);
+ }
+ switch_mutex_unlock(s->mutex_detectors_done);
+
+ idx = 0;
+ while (idx < AVMD_DETECTORS_N) {
+ d = &s->detectors[idx];
+ switch_mutex_lock(d->mutex);
+ d = &s->detectors[idx];
+ d->flag_processing_done = 0;
+ d->flag_should_exit = 1;
+ d->samples = 0;
+ switch_thread_cond_signal(d->cond_start_processing);
+ switch_mutex_unlock(d->mutex);
+ switch_mutex_destroy(d->mutex);
+ switch_thread_cond_destroy(d->cond_start_processing);
+ ++idx;
+ }
+ switch_mutex_unlock(s->mutex);
+ switch_mutex_destroy(s->mutex_detectors_done);
+ switch_thread_cond_destroy(s->cond_detectors_done);
+ switch_mutex_destroy(s->mutex);
+}
/*! \brief The callback function that is called when new audio data becomes available.
* @param bug A reference to the media bug.
@@ -310,99 +456,99 @@ end:
* @param type The switch callback type.
* @return The success or failure of the function.
*/
-static switch_bool_t
-avmd_callback(switch_media_bug_t * bug, void *user_data, switch_abc_type_t type)
-{
- avmd_session_t *avmd_session;
- switch_codec_t *read_codec;
+static switch_bool_t avmd_callback(switch_media_bug_t * bug, void *user_data, switch_abc_type_t type) {
+ avmd_session_t *avmd_session;
+ switch_codec_t *read_codec;
switch_codec_t *write_codec;
- switch_frame_t *frame;
+ switch_frame_t *frame;
switch_core_session_t *fs_session;
- avmd_session = (avmd_session_t *) user_data;
- if (avmd_session == NULL) {
+ avmd_session = (avmd_session_t *) user_data;
+ if (avmd_session == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No avmd session assigned!\n");
- return SWITCH_FALSE;
- }
- if (type != SWITCH_ABC_TYPE_INIT) {
+ return SWITCH_FALSE;
+ }
+ if ((type != SWITCH_ABC_TYPE_INIT) && (type != SWITCH_ABC_TYPE_CLOSE)) {
switch_mutex_lock(avmd_session->mutex);
}
- fs_session = avmd_session->session;
- if (fs_session == NULL) {
+ fs_session = avmd_session->session;
+ if (fs_session == NULL) {
if (type != SWITCH_ABC_TYPE_INIT) {
- switch_mutex_lock(avmd_session->mutex);
+ switch_mutex_unlock(avmd_session->mutex);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No FreeSWITCH session assigned!\n");
- return SWITCH_FALSE;
- }
+ return SWITCH_FALSE;
+ }
- switch (type) {
+ switch (type) {
- case SWITCH_ABC_TYPE_INIT:
- if (avmd_session->settings.outbound_channnel == 1) {
- read_codec = switch_core_session_get_read_codec(fs_session);
- if (read_codec == NULL) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_WARNING, "No read codec assigned, default session rate to 8000 samples/s\n");
- avmd_session->rate = 8000;
- } else {
- if (read_codec->implementation == NULL) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_WARNING, "No read codec implementation assigned, default session rate to 8000 samples/s\n");
+ case SWITCH_ABC_TYPE_INIT:
+ if (avmd_session->settings.outbound_channnel == 1) {
+ read_codec = switch_core_session_get_read_codec(fs_session);
+ if (read_codec == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_WARNING, "No read codec assigned, default session rate to 8000 samples/s\n");
avmd_session->rate = 8000;
} else {
- avmd_session->rate = read_codec->implementation->samples_per_second;
+ if (read_codec->implementation == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_WARNING, "No read codec implementation assigned, default session rate to 8000 samples/s\n");
+ avmd_session->rate = 8000;
+ } else {
+ avmd_session->rate = read_codec->implementation->samples_per_second;
+ }
}
}
- }
- if (avmd_session->settings.inbound_channnel == 1) {
- write_codec = switch_core_session_get_write_codec(fs_session);
- if (write_codec == NULL) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_WARNING, "No write codec assigned, default session rate to 8000 samples/s\n");
- avmd_session->rate = 8000;
- } else {
- if (write_codec->implementation == NULL) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_WARNING, "No write codec implementation assigned, default session rate to 8000 samples/s\n");
+ if (avmd_session->settings.inbound_channnel == 1) {
+ write_codec = switch_core_session_get_write_codec(fs_session);
+ if (write_codec == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_WARNING, "No write codec assigned, default session rate to 8000 samples/s\n");
avmd_session->rate = 8000;
} else {
- avmd_session->rate = write_codec->implementation->samples_per_second;
+ if (write_codec->implementation == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_WARNING, "No write codec implementation assigned, default session rate to 8000 samples/s\n");
+ avmd_session->rate = 8000;
+ } else {
+ avmd_session->rate = write_codec->implementation->samples_per_second;
+ }
}
}
- }
- avmd_session->start_time = switch_micro_time_now();
- /* avmd_session->vmd_codec.channels = read_codec->implementation->number_of_channels; */
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session),SWITCH_LOG_INFO, "Avmd session initialized, [%u] samples/s\n", avmd_session->rate);
- break;
+ avmd_session->start_time = switch_micro_time_now();
+ /* avmd_session->vmd_codec.channels = read_codec->implementation->number_of_channels; */
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session),SWITCH_LOG_INFO, "Avmd session initialized, [%u] samples/s\n", avmd_session->rate);
+ break;
- case SWITCH_ABC_TYPE_READ_REPLACE:
- frame = switch_core_media_bug_get_read_replace_frame(bug);
- avmd_process(avmd_session, frame);
- break;
+ case SWITCH_ABC_TYPE_READ_REPLACE:
+ frame = switch_core_media_bug_get_read_replace_frame(bug);
+ avmd_process(avmd_session, frame);
+ break;
- case SWITCH_ABC_TYPE_WRITE_REPLACE:
- frame = switch_core_media_bug_get_write_replace_frame(bug);
- avmd_process(avmd_session, frame);
- break;
+ case SWITCH_ABC_TYPE_WRITE_REPLACE:
+ frame = switch_core_media_bug_get_write_replace_frame(bug);
+ avmd_process(avmd_session, frame);
+ break;
- default:
- break;
- }
+ case SWITCH_ABC_TYPE_CLOSE:
+ avmd_session_close(avmd_session);
+ break;
- if (type != SWITCH_ABC_TYPE_INIT) {
+ default:
+ break;
+ }
+
+ if ((type != SWITCH_ABC_TYPE_INIT) && (type != SWITCH_ABC_TYPE_CLOSE)) {
switch_mutex_unlock(avmd_session->mutex);
}
- return SWITCH_TRUE;
+ return SWITCH_TRUE;
}
-static switch_status_t
-avmd_register_all_events(void)
-{
+static switch_status_t avmd_register_all_events(void) {
size_t idx = 0;
const char *e = avmd_events_str[0];
while (e != NULL)
{
if (switch_event_reserve_subclass(e) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass [%s]!\n", e);
- return SWITCH_STATUS_TERM;
+ return SWITCH_STATUS_TERM;
}
++idx;
e = avmd_events_str[idx];
@@ -410,9 +556,7 @@ avmd_register_all_events(void)
return SWITCH_STATUS_SUCCESS;
}
-static void
-avmd_unregister_all_events(void)
-{
+static void avmd_unregister_all_events(void) {
size_t idx = 0;
const char *e = avmd_events_str[0];
while (e != NULL)
@@ -424,8 +568,7 @@ avmd_unregister_all_events(void)
return;
}
-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,
+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) {
int res;
switch_event_t *event;
@@ -519,11 +662,8 @@ avmd_fire_event(enum avmd_event type, switch_core_session_t *fs_s, double freq,
return;
}
-int
-avmd_parse_u8_user_input(const char *input, uint8_t *output,
- uint8_t min, uint8_t max)
-{
- char *pCh;
+int avmd_parse_u8_user_input(const char *input, uint8_t *output, uint8_t min, uint8_t max) {
+ char *pCh;
unsigned long helper;
helper = strtoul(input, &pCh, 10);
if (helper < min || helper > UINT8_MAX || helper > max || (pCh == input) || (*pCh != '\0')) {
@@ -533,11 +673,8 @@ avmd_parse_u8_user_input(const char *input, uint8_t *output,
return 0;
}
-int
-avmd_parse_u16_user_input(const char *input, uint16_t *output,
- uint16_t min, uint16_t max)
-{
- char *pCh;
+int avmd_parse_u16_user_input(const char *input, uint16_t *output, uint16_t min, uint16_t max) {
+ char *pCh;
unsigned long helper;
if (min > max) {
return -1;
@@ -550,8 +687,7 @@ avmd_parse_u16_user_input(const char *input, uint16_t *output,
return 0;
}
-static void avmd_set_xml_default_configuration(switch_mutex_t *mutex)
-{
+static void avmd_set_xml_default_configuration(switch_mutex_t *mutex) {
if (mutex != NULL) {
switch_mutex_lock(mutex);
}
@@ -560,20 +696,22 @@ static void avmd_set_xml_default_configuration(switch_mutex_t *mutex)
avmd_globals.settings.report_status = 1;
avmd_globals.settings.fast_math = 0;
avmd_globals.settings.require_continuous_streak = 1;
- avmd_globals.settings.sample_n_continuous_streak = 15;
- avmd_globals.settings.sample_n_to_skip = 15;
+ avmd_globals.settings.sample_n_continuous_streak = 5;
+ avmd_globals.settings.sample_n_to_skip = 0;
+ avmd_globals.settings.require_continuous_streak_amp = 1;
+ avmd_globals.settings.sample_n_continuous_streak_amp = 5;
avmd_globals.settings.simplified_estimation = 1;
avmd_globals.settings.inbound_channnel = 0;
avmd_globals.settings.outbound_channnel = 1;
+ avmd_globals.settings.mode = AVMD_DETECT_BOTH;
if (mutex != NULL) {
switch_mutex_unlock(avmd_globals.mutex);
}
- return;
+ return;
}
-static void
-avmd_set_xml_inbound_configuration(switch_mutex_t *mutex)
+static void avmd_set_xml_inbound_configuration(switch_mutex_t *mutex)
{
if (mutex != NULL) {
switch_mutex_lock(mutex);
@@ -585,12 +723,10 @@ avmd_set_xml_inbound_configuration(switch_mutex_t *mutex)
if (mutex != NULL) {
switch_mutex_unlock(avmd_globals.mutex);
}
- return;
+ return;
}
-static void
-avmd_set_xml_outbound_configuration(switch_mutex_t *mutex)
-{
+static void avmd_set_xml_outbound_configuration(switch_mutex_t *mutex) {
if (mutex != NULL) {
switch_mutex_lock(mutex);
}
@@ -601,77 +737,87 @@ avmd_set_xml_outbound_configuration(switch_mutex_t *mutex)
if (mutex != NULL) {
switch_mutex_unlock(avmd_globals.mutex);
}
- return;
+ return;
}
-static switch_status_t
-avmd_load_xml_configuration(switch_mutex_t *mutex)
-{
- switch_xml_t xml = NULL, x_lists = NULL, x_list = NULL, cfg = NULL;
- switch_status_t status = SWITCH_STATUS_FALSE;
+static switch_status_t avmd_load_xml_configuration(switch_mutex_t *mutex) {
+ switch_xml_t xml = NULL, x_lists = NULL, x_list = NULL, cfg = NULL;
+ switch_status_t status = SWITCH_STATUS_FALSE;
- if (mutex != NULL) {
+ if (mutex != NULL) {
switch_mutex_lock(mutex);
}
- if ((xml = switch_xml_open_cfg("avmd.conf", &cfg, NULL)) == NULL) {
+ if ((xml = switch_xml_open_cfg("avmd.conf", &cfg, NULL)) == NULL) {
status = SWITCH_STATUS_TERM;
} else {
- status = SWITCH_STATUS_SUCCESS;
+ status = SWITCH_STATUS_SUCCESS;
- if ((x_lists = switch_xml_child(cfg, "settings"))) {
- for (x_list = switch_xml_child(x_lists, "param"); x_list; x_list = x_list->next) {
- const char *name = switch_xml_attr(x_list, "name");
- const char *value = switch_xml_attr(x_list, "value");
+ if ((x_lists = switch_xml_child(cfg, "settings"))) {
+ for (x_list = switch_xml_child(x_lists, "param"); x_list; x_list = x_list->next) {
+ const char *name = switch_xml_attr(x_list, "name");
+ const char *value = switch_xml_attr(x_list, "value");
- if (zstr(name)) {
- continue;
- }
- if (zstr(value)) {
- continue;
- }
+ if (zstr(name)) {
+ continue;
+ }
+ if (zstr(value)) {
+ continue;
+ }
- if (!strcmp(name, "debug")) {
- avmd_globals.settings.debug = switch_true(value) ? 1 : 0;
+ if (!strcmp(name, "debug")) {
+ avmd_globals.settings.debug = switch_true(value) ? 1 : 0;
} else if (!strcmp(name, "report_status")) {
- avmd_globals.settings.report_status = switch_true(value) ? 1 : 0;
- } else if (!strcmp(name, "fast_math")) {
- avmd_globals.settings.fast_math = switch_true(value) ? 1 : 0;
- } else if (!strcmp(name, "require_continuous_streak")) {
- avmd_globals.settings.require_continuous_streak = switch_true(value) ? 1 : 0;
- } else if (!strcmp(name, "sample_n_continuous_streak")) {
+ avmd_globals.settings.report_status = switch_true(value) ? 1 : 0;
+ } else if (!strcmp(name, "fast_math")) {
+ avmd_globals.settings.fast_math = switch_true(value) ? 1 : 0;
+ } else if (!strcmp(name, "require_continuous_streak")) {
+ avmd_globals.settings.require_continuous_streak = switch_true(value) ? 1 : 0;
+ } else if (!strcmp(name, "sample_n_continuous_streak")) {
if(avmd_parse_u16_user_input(value, &avmd_globals.settings.sample_n_continuous_streak, 0, UINT16_MAX) == -1) {
status = SWITCH_STATUS_TERM;
goto done;
}
- } else if (!strcmp(name, "sample_n_to_skip")) {
+ } else if (!strcmp(name, "sample_n_to_skip")) {
if(avmd_parse_u16_user_input(value, &avmd_globals.settings.sample_n_to_skip, 0, UINT16_MAX) == -1) {
status = SWITCH_STATUS_TERM;
goto done;
}
- } else if (!strcmp(name, "simplified_estimation")) {
- avmd_globals.settings.simplified_estimation = switch_true(value) ? 1 : 0;
- } else if (!strcmp(name, "inbound_channel")) {
- avmd_globals.settings.inbound_channnel = switch_true(value) ? 1 : 0;
- } else if (!strcmp(name, "outbound_channel")) {
- avmd_globals.settings.outbound_channnel = switch_true(value) ? 1 : 0;
- }
- }
- }
+ } else if (!strcmp(name, "require_continuous_streak_amp")) {
+ avmd_globals.settings.require_continuous_streak_amp = switch_true(value) ? 1 : 0;
+ } else if (!strcmp(name, "sample_n_continuous_streak_amp")) {
+ if(avmd_parse_u16_user_input(value, &avmd_globals.settings.sample_n_continuous_streak_amp, 0, UINT16_MAX) == -1) {
+ status = SWITCH_STATUS_TERM;
+ goto done;
+ }
+ } else if (!strcmp(name, "simplified_estimation")) {
+ avmd_globals.settings.simplified_estimation = switch_true(value) ? 1 : 0;
+ } else if (!strcmp(name, "inbound_channel")) {
+ avmd_globals.settings.inbound_channnel = switch_true(value) ? 1 : 0;
+ } else if (!strcmp(name, "outbound_channel")) {
+ avmd_globals.settings.outbound_channnel = switch_true(value) ? 1 : 0;
+ } else if (!strcmp(name, "detection_mode")) {
+ if(avmd_parse_u8_user_input(value, (uint8_t*)&avmd_globals.settings.mode, 0, 2) == -1) {
+ status = SWITCH_STATUS_TERM;
+ goto done;
+ }
+ }
+ }
+ }
- done:
+done:
- switch_xml_free(xml);
- }
+ switch_xml_free(xml);
+ }
if (mutex != NULL) {
switch_mutex_unlock(mutex);
}
- return status;
+ return status;
}
-static switch_status_t avmd_load_xml_inbound_configuration(switch_mutex_t *mutex)
-{
+
+static switch_status_t avmd_load_xml_inbound_configuration(switch_mutex_t *mutex) {
if (avmd_load_xml_configuration(mutex) != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_TERM;
}
@@ -686,31 +832,28 @@ static switch_status_t avmd_load_xml_inbound_configuration(switch_mutex_t *mutex
if (mutex != NULL) {
switch_mutex_unlock(avmd_globals.mutex);
}
- return SWITCH_STATUS_SUCCESS;
+ return SWITCH_STATUS_SUCCESS;
}
-static switch_status_t avmd_load_xml_outbound_configuration(switch_mutex_t *mutex)
-{
+static switch_status_t avmd_load_xml_outbound_configuration(switch_mutex_t *mutex) {
if (avmd_load_xml_configuration(mutex) != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_TERM;
}
- if (mutex != NULL) {
+ if (mutex != NULL) {
switch_mutex_lock(mutex);
}
avmd_globals.settings.inbound_channnel = 0;
avmd_globals.settings.outbound_channnel = 1;
- if (mutex != NULL) {
+ if (mutex != NULL) {
switch_mutex_unlock(avmd_globals.mutex);
}
- return SWITCH_STATUS_SUCCESS;
+ return SWITCH_STATUS_SUCCESS;
}
-static void
-avmd_show(switch_stream_handle_t *stream, switch_mutex_t *mutex)
-{
+static void avmd_show(switch_stream_handle_t *stream, switch_mutex_t *mutex) {
const char *line = "=================================================================================================";
if (stream == NULL) {
return;
@@ -723,15 +866,18 @@ avmd_show(switch_stream_handle_t *stream, switch_mutex_t *mutex)
stream->write_function(stream, "\n\n");
stream->write_function(stream, "%s\n\n", line);
stream->write_function(stream, "%s\n", "Avmd global settings\n\n");
- stream->write_function(stream, "debug \t%u\n", avmd_globals.settings.debug);
- stream->write_function(stream, "report status \t%u\n", avmd_globals.settings.report_status);
- stream->write_function(stream, "fast_math \t%u\n", avmd_globals.settings.fast_math);
- stream->write_function(stream, "require continuous streak \t%u\n", avmd_globals.settings.require_continuous_streak);
- stream->write_function(stream, "sample n continuous streak\t%u\n", avmd_globals.settings.sample_n_continuous_streak);
- stream->write_function(stream, "sample n to skip \t%u\n", avmd_globals.settings.sample_n_to_skip);
- stream->write_function(stream, "simplified estimation \t%u\n", avmd_globals.settings.simplified_estimation);
- stream->write_function(stream, "inbound channel \t%u\n", avmd_globals.settings.inbound_channnel);
- stream->write_function(stream, "outbound channel \t%u\n", avmd_globals.settings.outbound_channnel);
+ stream->write_function(stream, "debug \t%u\n", avmd_globals.settings.debug);
+ stream->write_function(stream, "report status \t%u\n", avmd_globals.settings.report_status);
+ stream->write_function(stream, "fast_math \t%u\n", avmd_globals.settings.fast_math);
+ stream->write_function(stream, "require continuous streak \t%u\n", avmd_globals.settings.require_continuous_streak);
+ stream->write_function(stream, "sample n continuous streak \t%u\n", avmd_globals.settings.sample_n_continuous_streak);
+ stream->write_function(stream, "sample n to skip \t%u\n", avmd_globals.settings.sample_n_to_skip);
+ stream->write_function(stream, "require continuous streak amp \t%u\n", avmd_globals.settings.require_continuous_streak_amp);
+ stream->write_function(stream, "sample n continuous streak amp \t%u\n", avmd_globals.settings.sample_n_continuous_streak_amp);
+ stream->write_function(stream, "simplified estimation \t%u\n", avmd_globals.settings.simplified_estimation);
+ stream->write_function(stream, "inbound channel \t%u\n", avmd_globals.settings.inbound_channnel);
+ stream->write_function(stream, "outbound channel \t%u\n", avmd_globals.settings.outbound_channnel);
+ stream->write_function(stream, "detection mode \t%u\n", avmd_globals.settings.mode);
stream->write_function(stream, "\n\n");
if (mutex != NULL) {
@@ -739,41 +885,39 @@ avmd_show(switch_stream_handle_t *stream, switch_mutex_t *mutex)
}
}
-SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load)
-{
+SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load) {
#ifndef WIN32
char err[150];
int ret;
#endif
- switch_application_interface_t *app_interface;
- switch_api_interface_t *api_interface;
- /* connect my internal structure to the blank pointer passed to me */
- *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+ switch_application_interface_t *app_interface;
+ switch_api_interface_t *api_interface;
+ /* connect my internal structure to the blank pointer passed to me */
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
- if (avmd_register_all_events() != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register avmd events!\n");
- return SWITCH_STATUS_TERM;
- }
+ if (avmd_register_all_events() != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register avmd events!\n");
+ return SWITCH_STATUS_TERM;
+ }
memset(&avmd_globals, 0, sizeof(avmd_globals));
if (pool == NULL) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No memory pool assigned!\n");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No memory pool assigned!\n");
return SWITCH_STATUS_TERM;
}
- switch_mutex_init(&avmd_globals.mutex, SWITCH_MUTEX_DEFAULT, pool);
+ switch_mutex_init(&avmd_globals.mutex, SWITCH_MUTEX_DEFAULT, pool);
avmd_globals.pool = pool;
- if (avmd_load_xml_configuration(NULL) != SWITCH_STATUS_SUCCESS)
- {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't load XML configuration! Loading default settings\n");
+ if (avmd_load_xml_configuration(NULL) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't load XML configuration! Loading default settings\n");
avmd_set_xml_default_configuration(NULL);
}
- if ((switch_event_bind(modname, SWITCH_EVENT_RELOADXML, NULL, avmd_reloadxml_event_handler, NULL) != SWITCH_STATUS_SUCCESS)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our reloadxml handler! Module will not react to changes made in XML configuration\n");
- /* Not so severe to prevent further loading, well - it depends, anyway */
- }
+ if ((switch_event_bind(modname, SWITCH_EVENT_RELOADXML, NULL, avmd_reloadxml_event_handler, NULL) != SWITCH_STATUS_SUCCESS)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our reloadxml handler! Module will not react to changes made in XML configuration\n");
+ /* Not so severe to prevent further loading, well - it depends, anyway */
+ }
#ifndef WIN32
if (avmd_globals.settings.fast_math == 1) {
@@ -783,77 +927,76 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load)
switch (ret) {
case -1:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't access file [%s], error [%s]\n", ACOS_TABLE_FILENAME, err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't access file [%s], error [%s]\n", ACOS_TABLE_FILENAME, err);
break;
case -2:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating file [%s], error [%s]\n", ACOS_TABLE_FILENAME, err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating file [%s], error [%s]\n", ACOS_TABLE_FILENAME, err);
break;
case -3:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Access rights are OK but can't open file [%s], error [%s]\n", ACOS_TABLE_FILENAME, err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Access rights are OK but can't open file [%s], error [%s]\n", ACOS_TABLE_FILENAME, err);
break;
case -4:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Access rights are OK but can't mmap file [%s], error [%s]\n",ACOS_TABLE_FILENAME, err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Access rights are OK but can't mmap file [%s], error [%s]\n",ACOS_TABLE_FILENAME, err);
break;
default:
- switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_ERROR, "Unknown error [%d] while initializing fast cos table [%s], errno [%s]\n", ret, ACOS_TABLE_FILENAME, err);
+ switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_ERROR, "Unknown error [%d] while initializing fast cos table [%s], errno [%s]\n", ret, ACOS_TABLE_FILENAME, err);
return SWITCH_STATUS_TERM;
}
return SWITCH_STATUS_TERM;
} else
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Advanced voicemail detection: fast math enabled, arc cosine table is [%s]\n", ACOS_TABLE_FILENAME);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Advanced voicemail detection: fast math enabled, arc cosine table is [%s]\n", ACOS_TABLE_FILENAME);
}
#endif
- SWITCH_ADD_APP(app_interface, "avmd_start","Start avmd detection", "Start avmd detection", avmd_start_app, "", SAF_NONE);
- SWITCH_ADD_APP(app_interface, "avmd_stop","Stop avmd detection", "Stop avmd detection", avmd_stop_app, "", SAF_NONE);
- SWITCH_ADD_APP(app_interface, "avmd","Beep detection", "Advanced detection of voicemail beeps", avmd_start_function, AVMD_SYNTAX, SAF_NONE);
+ SWITCH_ADD_APP(app_interface, "avmd_start","Start avmd detection", "Start avmd detection", avmd_start_app, "", SAF_NONE);
+ SWITCH_ADD_APP(app_interface, "avmd_stop","Stop avmd detection", "Stop avmd detection", avmd_stop_app, "", SAF_NONE);
+ SWITCH_ADD_APP(app_interface, "avmd","Beep detection", "Advanced detection of voicemail beeps", avmd_start_function, AVMD_SYNTAX, SAF_NONE);
- SWITCH_ADD_API(api_interface, "avmd", "Voicemail beep detection", avmd_api_main, AVMD_SYNTAX);
+ SWITCH_ADD_API(api_interface, "avmd", "Voicemail beep detection", avmd_api_main, AVMD_SYNTAX);
- switch_console_set_complete("add avmd ::console::list_uuid ::[start:stop");
- switch_console_set_complete("add avmd set inbound"); /* set inbound = 1, outbound = 0 */
- switch_console_set_complete("add avmd set outbound"); /* set inbound = 0, outbound = 1 */
- switch_console_set_complete("add avmd set default"); /* restore to factory settings */
- switch_console_set_complete("add avmd load inbound"); /* reload + set inbound */
- switch_console_set_complete("add avmd load outbound"); /* reload + set outbound */
- switch_console_set_complete("add avmd reload"); /* reload XML (it loads from FS installation
+ switch_console_set_complete("add avmd ::console::list_uuid ::[start:stop");
+ switch_console_set_complete("add avmd set inbound"); /* set inbound = 1, outbound = 0 */
+ switch_console_set_complete("add avmd set outbound"); /* set inbound = 0, outbound = 1 */
+ switch_console_set_complete("add avmd set default"); /* restore to factory settings */
+ switch_console_set_complete("add avmd load inbound"); /* reload + set inbound */
+ switch_console_set_complete("add avmd load outbound"); /* reload + set outbound */
+ switch_console_set_complete("add avmd reload"); /* reload XML (it loads from FS installation
* folder, not module's conf/autoload_configs */
- switch_console_set_complete("add avmd show");
+ switch_console_set_complete("add avmd show");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Advanced voicemail detection enabled\n");
- return SWITCH_STATUS_SUCCESS; /* indicate that the module should continue to be loaded */
+ return SWITCH_STATUS_SUCCESS; /* indicate that the module should continue to be loaded */
}
-void
-avmd_config_dump(avmd_session_t *s)
-{
+void avmd_config_dump(avmd_session_t *s) {
struct avmd_settings *settings;
- if (s == NULL) return;
+ if (s == NULL) {
+ return;
+ }
settings = &s->settings;
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_INFO,
- "Avmd dynamic configuration: debug [%u], report_status [%u], fast_math [%u],"
- " require_continuous_streak [%u], sample_n_continuous_streak [%u], "
- "sample_n_to_skip [%u], simplified_estimation [%u], "
- "inbound_channel [%u], outbound_channel [%u]\n",
- settings->debug, settings->report_status, settings->fast_math,
- settings->require_continuous_streak, settings->sample_n_continuous_streak,
- settings->sample_n_to_skip, settings->simplified_estimation,
- settings->inbound_channnel, settings->outbound_channnel);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_INFO, "Avmd dynamic configuration: debug [%u], report_status [%u], fast_math [%u],"
+ " require_continuous_streak [%u], sample_n_continuous_streak [%u], sample_n_to_skip [%u], require_continuous_streak_amp [%u], sample_n_continuous_streak_amp [%u],"
+ " simplified_estimation [%u], inbound_channel [%u], outbound_channel [%u], detection_mode [%u]\n",
+ settings->debug, settings->report_status, settings->fast_math, settings->require_continuous_streak, settings->sample_n_continuous_streak,
+ settings->sample_n_to_skip, settings->require_continuous_streak_amp, settings->sample_n_continuous_streak_amp,
+ settings->simplified_estimation, settings->inbound_channnel, settings->outbound_channnel, settings->mode);
return;
}
-static switch_status_t
-avmd_parse_cmd_data_one_entry(char *candidate, struct avmd_settings *settings)
-{
+static switch_status_t avmd_parse_cmd_data_one_entry(char *candidate, struct avmd_settings *settings) {
char *candidate_parsed[3];
int argc;
const char *key;
const char *val;
- if (settings == NULL) return SWITCH_STATUS_TERM;
- if (candidate == NULL) return SWITCH_STATUS_NOOP;
+ if (settings == NULL) {
+ return SWITCH_STATUS_TERM;
+ }
+ if (candidate == NULL) {
+ return SWITCH_STATUS_NOOP;
+ }
argc = switch_separate_string(candidate, '=', candidate_parsed, (sizeof(candidate_parsed) / sizeof(candidate_parsed[0])));
if (argc > 2) { /* currently we accept only option=value syntax */
@@ -887,12 +1030,22 @@ avmd_parse_cmd_data_one_entry(char *candidate, struct avmd_settings *settings)
if(avmd_parse_u16_user_input(val, &settings->sample_n_to_skip, 0, UINT16_MAX) == -1) {
return SWITCH_STATUS_FALSE;
}
+ } else if (!strcmp(key, "require_continuous_streak_amp")) {
+ settings->require_continuous_streak_amp = (uint8_t) switch_true(val);
+ } else if (!strcmp(key, "sample_n_continuous_streak_amp")) {
+ if(avmd_parse_u16_user_input(val, &settings->sample_n_continuous_streak_amp, 0, UINT16_MAX) == -1) {
+ return SWITCH_STATUS_FALSE;
+ }
} else if (!strcmp(key, "simplified_estimation")) {
settings->simplified_estimation = (uint8_t) switch_true(val);
} else if (!strcmp(key, "inbound_channel")) {
settings->inbound_channnel = (uint8_t) switch_true(val);
} else if (!strcmp(key, "outbound_channel")) {
settings->outbound_channnel = (uint8_t) switch_true(val);
+ } else if (!strcmp(key, "detection_mode")) {
+ if(avmd_parse_u8_user_input(val, (uint8_t*)&settings->mode, 0, 2) == -1) {
+ return SWITCH_STATUS_FALSE;
+ }
} else {
return SWITCH_STATUS_NOTFOUND;
}
@@ -903,21 +1056,19 @@ avmd_parse_cmd_data_one_entry(char *candidate, struct avmd_settings *settings)
* if it returns SWITCH_STATUS_SUCCESS parsing went OK and avmd settings
* are updated accordingly to @cmd_data, if SWITCH_STATUS_FALSE then
* parsing error occurred and avmd session is left untouched */
-static switch_status_t
-avmd_parse_cmd_data(avmd_session_t *s, const char *cmd_data, enum avmd_app app)
-{
- char *mydata;
+static switch_status_t avmd_parse_cmd_data(avmd_session_t *s, const char *cmd_data, enum avmd_app app) {
+ char *mydata;
struct avmd_settings settings;
- int argc = 0, idx;
- char *argv[AVMD_PARAMS_APP_MAX * 2] = { 0 };
+ int argc = 0, idx;
+ char *argv[AVMD_PARAMS_APP_MAX * 2] = { 0 };
switch_status_t status = SWITCH_STATUS_SUCCESS;
if (s == NULL) {
return SWITCH_STATUS_NOOP;
}
- if (zstr(cmd_data)) {
- return SWITCH_STATUS_SUCCESS;
- }
+ if (zstr(cmd_data)) {
+ return SWITCH_STATUS_SUCCESS;
+ }
/* copy current settings first */
memcpy(&settings, &s->settings, sizeof (struct avmd_settings));
@@ -929,8 +1080,8 @@ avmd_parse_cmd_data(avmd_session_t *s, const char *cmd_data, enum avmd_app app)
argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < AVMD_PARAMS_APP_START_MIN || argc > AVMD_PARAMS_APP_START_MAX) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_ERROR,
- "Syntax Error, avmd_start APP takes [%u] to [%u] parameters\n",
- AVMD_PARAMS_APP_START_MIN, AVMD_PARAMS_APP_START_MAX);
+ "Syntax Error, avmd_start APP takes [%u] to [%u] parameters\n",
+ AVMD_PARAMS_APP_START_MIN, AVMD_PARAMS_APP_START_MAX);
switch_goto_status(SWITCH_STATUS_MORE_DATA, fail);
}
/* iterate over params, check if they mean something to us, set */
@@ -982,7 +1133,7 @@ avmd_parse_cmd_data(avmd_session_t *s, const char *cmd_data, enum avmd_app app)
goto end_copy;
default:
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_ERROR,
- "There is no app with index [%u] for avmd\n", app);
+ "There is no app with index [%u] for avmd\n", app);
switch_goto_status(SWITCH_STATUS_NOTFOUND, fail);
}
@@ -994,50 +1145,49 @@ fail:
return status;
}
-SWITCH_STANDARD_APP(avmd_start_app)
-{
- switch_media_bug_t *bug;
- switch_status_t status;
- switch_channel_t *channel;
- avmd_session_t *avmd_session;
+SWITCH_STANDARD_APP(avmd_start_app) {
+ switch_media_bug_t *bug;
+ switch_status_t status;
+ switch_channel_t *channel;
+ avmd_session_t *avmd_session;
switch_core_media_flag_t flags = 0;
- if (session == NULL) {
+ if (session == NULL) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR,
- "FreeSWITCH is NULL! Please report to developers\n");
- return;
- }
+ "FreeSWITCH is NULL! Please report to developers\n");
+ return;
+ }
- /* Get current channel of the session to tag the session. This indicates that our module is present
- * At this moment this cannot return NULL, it will either succeed or assert failed, but we make ourself secure anyway */
- channel = switch_core_session_get_channel(session);
- if (channel == NULL) {
+ /* Get current channel of the session to tag the session. This indicates that our module is present
+ * At this moment this cannot return NULL, it will either succeed or assert failed, but we make ourself secure anyway */
+ channel = switch_core_session_get_channel(session);
+ if (channel == NULL) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR,
"No channel for FreeSWITCH session! Please report this "
"to the developers.\n");
return;
- }
-
- bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_avmd_"); /* Is this channel already set? */
- if (bug != NULL) { /* We have already started */
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
- SWITCH_LOG_ERROR, "Avmd already started!\n");
- return;
- }
-
- /* Allocate memory attached to this FreeSWITCH session for use in the callback routine and to store state information */
- avmd_session = (avmd_session_t *) switch_core_session_alloc(session, sizeof(avmd_session_t));
- if (avmd_session == NULL) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't allocate memory for avmd session!\n");
- goto end;
}
- status = init_avmd_session_data(avmd_session, session, NULL);
+ bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_avmd_"); /* Is this channel already set? */
+ if (bug != NULL) { /* We have already started */
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
+ SWITCH_LOG_ERROR, "Avmd already started!\n");
+ return;
+ }
+
+ /* Allocate memory attached to this FreeSWITCH session for use in the callback routine and to store state information */
+ avmd_session = (avmd_session_t *) switch_core_session_alloc(session, sizeof(avmd_session_t));
+ if (avmd_session == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't allocate memory for avmd session!\n");
+ goto end;
+ }
+
+ status = init_avmd_session_data(avmd_session, session, avmd_globals.mutex);
if (status != SWITCH_STATUS_SUCCESS) {
switch (status) {
case SWITCH_STATUS_MEMERR:
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to init avmd session. Buffer error!\n");
- break;
+ break;
case SWITCH_STATUS_MORE_DATA:
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to init avmd session. SMA buffer size is 0!\n");
break;
@@ -1073,7 +1223,7 @@ SWITCH_STANDARD_APP(avmd_start_app)
}
if (avmd_session->settings.outbound_channnel == 1) {
if (SWITCH_CALL_DIRECTION_OUTBOUND != switch_channel_direction(channel)) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Channel [%s] is not outbound!\n", switch_channel_get_name(channel));
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Channel [%s] is not outbound!\n", switch_channel_get_name(channel));
goto end;
} else {
flags |= SMBF_READ_REPLACE;
@@ -1081,79 +1231,76 @@ SWITCH_STANDARD_APP(avmd_start_app)
}
if (avmd_session->settings.inbound_channnel == 1) {
if (SWITCH_CALL_DIRECTION_INBOUND != switch_channel_direction(channel)) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Channel [%s] is not inbound!\n", switch_channel_get_name(channel));
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Channel [%s] is not inbound!\n", switch_channel_get_name(channel));
goto end;
} else {
flags |= SMBF_WRITE_REPLACE;
}
}
if (flags == 0) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't set direction for channel [%s]\n", switch_channel_get_name(channel));
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't set direction for channel [%s]\n", switch_channel_get_name(channel));
goto end;
}
if (avmd_session->settings.outbound_channnel == 1) {
if (switch_channel_test_flag(channel, CF_MEDIA_SET) == 0) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to start session. Channel [%s] has no codec assigned yet."
- " Please try again\n", switch_channel_get_name(channel));
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to start session. Channel [%s] has no codec assigned yet."
+ " Please try again\n", switch_channel_get_name(channel));
goto end;
}
}
- status = switch_core_media_bug_add(session, "avmd", NULL, avmd_callback, avmd_session, 0, flags, &bug); /* Add a media bug that allows me to intercept the reading leg of the audio stream */
- if (status != SWITCH_STATUS_SUCCESS) { /* If adding a media bug fails exit */
+ status = switch_core_media_bug_add(session, "avmd", NULL, avmd_callback, avmd_session, 0, flags, &bug); /* Add a media bug that allows me to intercept the reading leg of the audio stream */
+ if (status != SWITCH_STATUS_SUCCESS) { /* If adding a media bug fails exit */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to add media bug!\n");
goto end;
- }
- switch_channel_set_private(channel, "_avmd_", bug); /* Set the avmd tag to detect an existing avmd media bug */
+ }
+ 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);
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));
}
+ status = avmd_launch_threads(avmd_session);
+ if (status != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to start detection threads!\n");
+ goto end;
+ }
+
end:
switch_mutex_unlock(avmd_session->mutex);
return;
}
-SWITCH_STANDARD_APP(avmd_stop_app)
-{
- switch_media_bug_t *bug;
- switch_channel_t *channel;
+SWITCH_STANDARD_APP(avmd_stop_app) {
+ switch_media_bug_t *bug;
+ switch_channel_t *channel;
avmd_session_t *avmd_session;
switch_time_t start_time, stop_time, total_time;
uint8_t report_status = 0;
avmd_beep_state_t beep_status = BEEP_NOTDETECTED;
- if (session == NULL) {
+ if (session == NULL) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "FreeSWITCH is NULL! Please report to developers\n");
- return;
- }
-
- /* Get current channel of the session to tag the session
- * This indicates that our module is present
- * At this moment this cannot return NULL, it will either
- * succeed or assert failed, but we make ourself secure anyway */
- channel = switch_core_session_get_channel(session);
- if (channel == NULL) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No channel for FreeSWITCH session! Please report this "
- "to the developers.\n");
return;
- }
+ }
- /* Is this channel already set? */
- bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_avmd_");
- /* If yes */
- if (bug == NULL) {
- /* We have not started avmd on this channel */
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Stop failed - no avmd session running"
- " on this channel [%s]!\n", switch_channel_get_name(channel));
+ /* Get current channel of the session to tag the session. This indicates that our module is present
+ * At this moment this cannot return NULL, it will either succeed or assert failed, but we make ourself secure anyway */
+ channel = switch_core_session_get_channel(session);
+ if (channel == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No channel for FreeSWITCH session! Please report this to the developers.\n");
return;
- }
+ }
+
+ bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_avmd_");
+ if (bug == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Stop failed - no avmd session running on this channel [%s]!\n", switch_channel_get_name(channel));
+ return;
+ }
avmd_session = switch_core_media_bug_get_user_data(bug);
if (avmd_session == NULL) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Stop failed - no avmd session object, stop event not fired"
- " on this channel [%s]!\n", switch_channel_get_name(channel));
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Stop failed - no avmd session object, stop event not fired on this channel [%s]!\n", switch_channel_get_name(channel));
} else {
switch_mutex_lock(avmd_session->mutex);
report_status = avmd_session->settings.report_status;
@@ -1163,11 +1310,10 @@ 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);
- 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);
- }
+ avmd_fire_event(AVMD_EVENT_SESSION_STOP, session, 0, 0, 0, 0, beep_status, 1, 0, 0, start_time, stop_time);
+ 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);
@@ -1177,45 +1323,34 @@ SWITCH_STANDARD_APP(avmd_stop_app)
/*! \brief FreeSWITCH application handler function.
* This handles calls made from applications such as LUA and the dialplan.
*/
-SWITCH_STANDARD_APP(avmd_start_function)
-{
- switch_media_bug_t *bug;
- switch_channel_t *channel;
+SWITCH_STANDARD_APP(avmd_start_function) {
+ switch_media_bug_t *bug;
+ switch_channel_t *channel;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
- "YOU ARE USING DEPRECATED APP INTERFACE."
- " Please read documentation about new syntax\n");
- if (session == NULL) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
- "No FreeSWITCH session assigned!\n");
- return;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "YOU ARE USING DEPRECATED APP INTERFACE. Please read documentation about new syntax\n");
+ if (session == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No FreeSWITCH session assigned!\n");
+ return;
}
- channel = switch_core_session_get_channel(session);
+ channel = switch_core_session_get_channel(session);
- /* Is this channel already using avmd ? */
- bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_avmd_");
- /* If it is using avmd */
- if (bug != NULL) {
- /* If we have a stop remove audio bug */
- if (strcasecmp(data, "stop") == 0) {
- switch_channel_set_private(channel, "_avmd_", NULL);
- switch_core_media_bug_remove(session, &bug);
- return;
- }
- /* We have already started */
- switch_log_printf(
- SWITCH_CHANNEL_SESSION_LOG(session),
- SWITCH_LOG_WARNING, "Cannot run 2 at once on the same channel!\n");
- return;
- }
+ bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_avmd_");
+ if (bug != NULL) {
+ if (strcasecmp(data, "stop") == 0) {
+ switch_channel_set_private(channel, "_avmd_", NULL);
+ switch_core_media_bug_remove(session, &bug);
+ return;
+ }
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot run 2 at once on the same channel!\n");
+ return;
+ }
avmd_start_app(session, NULL);
}
-SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown)
-{
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown) {
#ifndef WIN32
- int res;
+ int res;
#endif
switch_mutex_lock(avmd_globals.mutex);
@@ -1224,42 +1359,36 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown)
#ifndef WIN32
if (avmd_globals.settings.fast_math == 1) {
- res = destroy_fast_acosf();
+ res = destroy_fast_acosf();
if (res != 0) {
switch (res) {
case -1:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
- "Failed unmap arc cosine table\n");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed unmap arc cosine table\n");
break;
case -2:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
- "Failed closing arc cosine table\n");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed closing arc cosine table\n");
break;
default:
- break;
+ break;
}
}
}
#endif
- switch_event_unbind_callback(avmd_reloadxml_event_handler);
-
+ switch_event_unbind_callback(avmd_reloadxml_event_handler);
switch_mutex_unlock(avmd_globals.mutex);
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
- "Advanced voicemail detection disabled\n");
-
- return SWITCH_STATUS_SUCCESS;
+ switch_mutex_destroy(avmd_globals.mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Advanced voicemail detection disabled\n");
+ return SWITCH_STATUS_SUCCESS;
}
/*! \brief FreeSWITCH API handler function.
* This function handles API calls from mod_event_socket and LUA scripts.
*/
-SWITCH_STANDARD_API(avmd_api_main)
-{
- switch_media_bug_t *bug;
- avmd_session_t *avmd_session;
- switch_channel_t *channel;
+SWITCH_STANDARD_API(avmd_api_main) {
+ switch_media_bug_t *bug;
+ avmd_session_t *avmd_session;
+ switch_channel_t *channel;
int argc;
const char *uuid, *uuid_dup;
const char *command;
@@ -1270,25 +1399,19 @@ SWITCH_STANDARD_API(avmd_api_main)
switch_mutex_lock(avmd_globals.mutex);
- /* No command? Display usage */
- if (zstr(cmd)) {
- stream->write_function(stream, "-ERR, bad command!\n-USAGE: %s\n\n", AVMD_SYNTAX);
- goto end;
- }
+ if (zstr(cmd)) {
+ stream->write_function(stream, "-ERR, bad command!\n-USAGE: %s\n\n", AVMD_SYNTAX);
+ goto end;
+ }
- /* Duplicated contents of original string */
- dupped = strdup(cmd);
- switch_assert(dupped);
- /* Separate the arguments */
- argc = switch_separate_string((char*)dupped, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ dupped = strdup(cmd);
+ switch_assert(dupped);
+ argc = switch_separate_string((char*)dupped, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
- /* If we don't have the expected number of parameters
- * display usage */
- if (argc < AVMD_PARAMS_API_MIN) {
- stream->write_function(stream, "-ERR, avmd takes [%u] min and [%u] max parameters!\n"
- "-USAGE: %s\n\n", AVMD_PARAMS_API_MIN, AVMD_PARAMS_API_MAX, AVMD_SYNTAX);
- goto end;
- }
+ if (argc < AVMD_PARAMS_API_MIN) {
+ stream->write_function(stream, "-ERR, avmd takes [%u] min and [%u] max parameters!\n-USAGE: %s\n\n", AVMD_PARAMS_API_MIN, AVMD_PARAMS_API_MAX, AVMD_SYNTAX);
+ goto end;
+ }
command = argv[0];
if (strcasecmp(command, "reload") == 0) {
@@ -1376,72 +1499,58 @@ SWITCH_STANDARD_API(avmd_api_main)
goto end;
}
- uuid = argv[0];
- command = argv[1];
+ uuid = argv[0];
+ command = argv[1];
- /* using uuid locate a reference to the FreeSWITCH session */
- fs_session = switch_core_session_locate(uuid);
+ fs_session = switch_core_session_locate(uuid); /* using uuid locate a reference to the FreeSWITCH session */
+ if (fs_session == NULL) {
+ stream->write_function(stream, "-ERR, no FreeSWITCH session for uuid [%s]!\n-USAGE: %s\n\n", uuid, AVMD_SYNTAX);
+ goto end;
+ }
- /* If the session was not found exit */
- if (fs_session == NULL) {
- stream->write_function(stream, "-ERR, no FreeSWITCH session for uuid [%s]!\n-USAGE: %s\n\n", uuid, AVMD_SYNTAX);
- goto end;
- }
+ /* Get current channel of the session to tag the session. This indicates that our module is present
+ * At this moment this cannot return NULL, it will either succeed or assert failed, but we make ourself secure anyway */
+ channel = switch_core_session_get_channel(fs_session);
+ if (channel == NULL) {
+ stream->write_function(stream, "-ERR, no channel for FreeSWITCH session [%s]!\n Please report this to the developers\n\n", uuid);
+ goto end;
+ }
- /* Get current channel of the session to tag the session
- * This indicates that our module is present
- * At this moment this cannot return NULL, it will either
- * succeed or assert failed, but we make ourself secure anyway */
- channel = switch_core_session_get_channel(fs_session);
- if (channel == NULL) {
- stream->write_function(stream, "-ERR, no channel for FreeSWITCH session [%s]!"
- "\n Please report this to the developers\n\n", uuid);
- goto end;
- }
-
- /* Is this channel already set? */
- bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_avmd_");
- /* If yes */
- if (bug != NULL) {
- /* If we have a stop remove audio bug */
- if (strcasecmp(command, "stop") == 0) {
+ bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_avmd_");
+ if (bug != NULL) {
+ if (strcasecmp(command, "stop") == 0) {
avmd_session = (avmd_session_t*) switch_core_media_bug_get_user_data(bug);
if (avmd_session == NULL) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Stop failed - no avmd session object"
- " on this channel [%s]!\n", switch_channel_get_name(channel));
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Stop failed - no avmd session object on this channel [%s]!\n", switch_channel_get_name(channel));
goto end;
}
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);
+ 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);
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));
+ 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));
}
- goto end;
- }
- if (avmd_globals.settings.report_status == 1) {
- /* We have already started */
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Avmd already started!\n");
- stream->write_function(stream, "-ERR, avmd for FreeSWITCH session [%s]\n already started\n\n", uuid);
+ goto end;
}
- goto end;
- }
+ if (avmd_globals.settings.report_status == 1) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Avmd already started!\n");
+ stream->write_function(stream, "-ERR, avmd for FreeSWITCH session [%s]\n already started\n\n", uuid);
+ }
+ goto end;
+ }
- if (strcasecmp(command, "stop") == 0) {
+ if (strcasecmp(command, "stop") == 0) {
uuid_dup = switch_core_strdup(switch_core_session_get_pool(fs_session), uuid);
- stream->write_function(stream, "+ERR, avmd has not yet been started on\n"
- " [%s] [%s]\n\n", uuid_dup, switch_channel_get_name(channel));
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR,
- "Stop failed - avmd has not yet been started on channel [%s]!\n", switch_channel_get_name(channel));
+ stream->write_function(stream, "+ERR, avmd has not yet been started on\n [%s] [%s]\n\n", uuid_dup, switch_channel_get_name(channel));
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Stop failed - avmd has not yet been started on channel [%s]!\n", switch_channel_get_name(channel));
goto end;
}
if (avmd_globals.settings.outbound_channnel == 1) {
if (SWITCH_CALL_DIRECTION_OUTBOUND != switch_channel_direction(channel)) {
- stream->write_function(stream, "-ERR, channel for FreeSWITCH session [%s]"
- "\n is not outbound\n\n", uuid);
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Channel [%s] is not outbound!\n", switch_channel_get_name(channel));
+ stream->write_function(stream, "-ERR, channel for FreeSWITCH session [%s]\n is not outbound\n\n", uuid);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Channel [%s] is not outbound!\n", switch_channel_get_name(channel));
goto end;
} else {
flags |= SMBF_READ_REPLACE;
@@ -1449,89 +1558,208 @@ SWITCH_STANDARD_API(avmd_api_main)
}
if (avmd_globals.settings.inbound_channnel == 1) {
if (SWITCH_CALL_DIRECTION_INBOUND != switch_channel_direction(channel)) {
- stream->write_function(stream, "-ERR, channel for FreeSWITCH session [%s]"
- "\n is not inbound\n\n", uuid);
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Channel [%s] is not inbound!\n", switch_channel_get_name(channel));
+ stream->write_function(stream, "-ERR, channel for FreeSWITCH session [%s]\n is not inbound\n\n", uuid);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Channel [%s] is not inbound!\n", switch_channel_get_name(channel));
goto end;
} else {
flags |= SMBF_WRITE_REPLACE;
}
}
if (flags == 0) {
- stream->write_function(stream, "-ERR, can't set direction for channel [%s]\n"
- " for FreeSWITCH session [%s]. Please check avmd configuration\n\n",
- switch_channel_get_name(channel), uuid);
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR,
- "Can't set direction for channel [%s]\n", switch_channel_get_name(channel));
+ stream->write_function(stream, "-ERR, can't set direction for channel [%s]\n for FreeSWITCH session [%s]. Please check avmd configuration\n\n", switch_channel_get_name(channel), uuid);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Can't set direction for channel [%s]\n", switch_channel_get_name(channel));
goto end;
}
if (avmd_globals.settings.outbound_channnel == 1) {
if (switch_channel_test_flag(channel, CF_MEDIA_SET) == 0) {
- stream->write_function(stream, "-ERR, channel [%s] for FreeSWITCH session [%s]"
- "\n has no read codec assigned yet. Please try again.\n\n", switch_channel_get_name(channel), uuid);
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR,
- "Failed to start session. Channel [%s] has no codec assigned yet. Please try again\n", switch_channel_get_name(channel));
+ stream->write_function(stream, "-ERR, channel [%s] for FreeSWITCH session [%s]\n has no read codec assigned yet. Please try again.\n\n", switch_channel_get_name(channel), uuid);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Failed to start session. Channel [%s] has no codec assigned yet. Please try again\n", switch_channel_get_name(channel));
goto end;
}
}
- if (strcasecmp(command, "start") != 0) { /* If we don't see the expected start exit */
- stream->write_function(stream, "-ERR, did you mean\n"
- " api avmd %s start ?\n-USAGE: %s\n\n", uuid, AVMD_SYNTAX);
- goto end;
- }
+ if (strcasecmp(command, "start") != 0) { /* If we don't see the expected start exit */
+ stream->write_function(stream, "-ERR, did you mean\n api avmd %s start ?\n-USAGE: %s\n\n", uuid, AVMD_SYNTAX);
+ goto end;
+ }
avmd_session = (avmd_session_t *) switch_core_session_alloc(fs_session, sizeof(avmd_session_t)); /* Allocate memory attached to this FreeSWITCH session for use in the callback routine and to store state information */
status = init_avmd_session_data(avmd_session, fs_session, NULL);
if (status != SWITCH_STATUS_SUCCESS) {
- stream->write_function(stream, "-ERR, failed to initialize avmd session\n for FreeSWITCH session [%s]\n", uuid);
+ stream->write_function(stream, "-ERR, failed to initialize avmd session\n for FreeSWITCH session [%s]\n", uuid);
switch (status) {
case SWITCH_STATUS_MEMERR:
- stream->write_function(stream, "-ERR, buffer error\n\n");
+ stream->write_function(stream, "-ERR, buffer error\n\n");
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Failed to init avmd session. Buffer error!\n");
- break;
+ break;
case SWITCH_STATUS_MORE_DATA:
- stream->write_function(stream, "-ERR, SMA buffer size is 0\n\n");
+ stream->write_function(stream, "-ERR, SMA buffer size is 0\n\n");
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Failed to init avmd session. SMA buffer size is 0!\n");
break;
case SWITCH_STATUS_FALSE:
- stream->write_function(stream, "-ERR, SMA buffer error\n\n");
+ stream->write_function(stream, "-ERR, SMA buffer error\n\n");
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Failed to init avmd session. SMA buffers error\n");
break;
default:
- stream->write_function(stream, "-ERR, unknown error\n\n");
+ stream->write_function(stream, "-ERR, unknown error\n\n");
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Failed to init avmd session. Unknown error\n");
break;
}
- goto end;
+ goto end;
}
- status = switch_core_media_bug_add(fs_session, "avmd", NULL, avmd_callback, avmd_session, 0, flags, &bug); /* Add a media bug that allows me to intercept the reading leg of the audio stream */
+ status = switch_core_media_bug_add(fs_session, "avmd", NULL, avmd_callback, avmd_session, 0, flags, &bug); /* Add a media bug that allows me to intercept the reading leg of the audio stream */
- if (status != SWITCH_STATUS_SUCCESS) { /* If adding a media bug fails exit */
+ if (status != SWITCH_STATUS_SUCCESS) { /* If adding a media bug fails exit */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_ERROR, "Failed to add media bug!\n");
- stream->write_function(stream, "-ERR, [%s] failed to add media bug!\n\n", uuid);
- goto end;
- }
+ stream->write_function(stream, "-ERR, [%s] failed to add media bug!\n\n", uuid);
+ goto end;
+ }
- switch_channel_set_private(channel, "_avmd_", bug); /* Set the vmd tag to detect an existing vmd media bug */
+ 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);
if (avmd_globals.settings.report_status == 1) {
- stream->write_function(stream, "+OK\n [%s] [%s] started!\n\n", uuid, switch_channel_get_name(channel));
+ 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));
switch_assert(status == SWITCH_STATUS_SUCCESS);
}
end:
- if (fs_session) {
- switch_core_session_rwunlock(fs_session);
- }
+ if (fs_session) {
+ switch_core_session_rwunlock(fs_session);
+ }
- switch_safe_free(dupped);
+ switch_safe_free(dupped);
switch_mutex_unlock(avmd_globals.mutex);
- return SWITCH_STATUS_SUCCESS;
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static int
+avmd_decision_amplitude(const avmd_session_t *s, const struct avmd_buffer *b, double v, double rsd_threshold) {
+ double rsd;
+
+ 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);
+ if (rsd < rsd_threshold) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+avmd_decision_freq(const avmd_session_t *s, const struct avmd_buffer *b, double v, double rsd_threshold) {
+ double f, rsd;
+ size_t lpos;
+ f = AVMD_TO_HZ(s->rate, fabs(b->sma_b_fir.sma));
+ if ((f < AVMD_MIN_FREQUENCY) || (f > AVMD_MAX_FREQUENCY)) {
+ return 0;
+ }
+ lpos = b->sma_b.lpos;
+ if ((lpos >= AVMD_BEEP_LEN(s->rate) / b->resolution) && ((s->settings.require_continuous_streak == 1 && (b->sma_b.lpos > s->settings.sample_n_continuous_streak) && (b->samples_streak == 0))
+ || (s->settings.require_continuous_streak == 0 && (b->sma_b.lpos > 1)))) {
+ rsd = sqrt(v) / f;
+ if ((rsd < 0.3 * rsd_threshold) && (b->sma_amp_b.sma >= 0.005 * b->amplitude_max)) {
+ return 1;
+ }
+ 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)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void avmd_report_detection(avmd_session_t *s, enum avmd_detection_mode mode, const struct avmd_buffer *b) {
+ switch_channel_t *channel;
+ switch_time_t detection_time;
+ double f_sma = 0.0;
+ double v_amp = 9999.9, v_fir = 9999.9;
+
+ const sma_buffer_t *sma_b_fir = &b->sma_b_fir;
+ const sma_buffer_t *sqa_b_fir = &b->sqa_b_fir;
+
+ const sma_buffer_t *sma_amp_b = &b->sma_amp_b;
+ const sma_buffer_t *sqa_amp_b = &b->sqa_amp_b;
+
+ channel = switch_core_session_get_channel(s->session);
+
+ s->detection_stop_time = switch_micro_time_now(); /* stop detection timer */
+ detection_time = s->detection_stop_time - s->detection_start_time; /* detection time length */
+ switch_channel_set_variable_printf(channel, "avmd_total_time", "[%" PRId64 "]", detection_time / 1000);
+ switch_channel_execute_on(channel, "execute_on_avmd_beep");
+ switch_channel_set_variable(channel, "avmd_detect", "TRUE");
+ switch (mode) {
+
+ 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);
+ 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);
+ }
+ 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);
+ 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);
+ }
+ break;
+
+ case AVMD_DETECT_BOTH:
+ 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);
+ 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);
+ }
+ break;
+
+ default:
+ break;
+ }
+ s->state.beep_state = BEEP_DETECTED;
+}
+
+static uint8_t
+avmd_detection_in_progress(avmd_session_t *s) {
+ uint8_t idx = 0;
+ while (idx < AVMD_DETECTORS_N) {
+ switch_mutex_lock(s->detectors[idx].mutex);
+ if (s->detectors[idx].flag_processing_done == 0) {
+ switch_mutex_unlock(s->detectors[idx].mutex);
+ return 1;
+ }
+ switch_mutex_unlock(s->detectors[idx].mutex);
+ ++idx;
+ }
+ return 0;
+}
+
+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) {
+ res = s->detectors[idx].result;
+ if (res != AVMD_DETECT_NONE) {
+ avmd_report_detection(s, res, &s->detectors[idx].buffer);
+ return res;
+ }
+ ++idx;
+ }
+ return AVMD_DETECT_NONE;
}
/*! \brief Process one frame of data with avmd algorithm.
@@ -1539,156 +1767,56 @@ end:
* @param frame An audio frame.
*/
static void avmd_process(avmd_session_t *s, switch_frame_t *frame) {
- switch_channel_t *channel;
- switch_time_t detection_time;
- circ_buffer_t *b;
- size_t pos;
- double omega, amplitude;
- double f;
- double v, v_amp = 0.0;
- double sma_digital_freq;
- uint32_t sine_len_i;
- int sample_to_skip_n = s->settings.sample_n_to_skip;
- size_t sample_n = 0;
+ circ_buffer_t *b;
+ uint8_t idx;
+ struct avmd_detector *d;
b = &s->b;
- /* If beep has already been detected skip the CPU heavy stuff */
- if (s->state.beep_state == BEEP_DETECTED) return;
- if (s->detection_start_time == 0) {
- s->detection_start_time = switch_micro_time_now(); /* start detection timer */
+ switch_mutex_lock(s->mutex_detectors_done);
+ while (avmd_detection_in_progress(s) == 1) {
+ switch_thread_cond_wait(s->cond_detectors_done, s->mutex_detectors_done);
+ }
+ switch_mutex_unlock(s->mutex_detectors_done);
+
+ if (s->state.beep_state == BEEP_DETECTED) { /* If beep has already been detected skip the CPU heavy stuff */
+ return;
}
- /* Precompute values used heavily in the inner loop */
- sine_len_i = (uint32_t) SINE_LEN(s->rate);
- //sine_len = (double)sine_len_i;
- //beep_len_i = BEEP_LEN(session->rate);
+ if (s->frame_n_to_skip > 0) {
+ s->frame_n_to_skip--;
+ return;
+ }
+ if (s->detection_start_time == 0) {
+ s->detection_start_time = switch_micro_time_now(); /* start detection timer */
+ }
- channel = switch_core_session_get_channel(s->session);
-
- /* Insert frame of 16 bit samples into buffer */
- INSERT_INT16_FRAME(b, (int16_t *)(frame->data), frame->samples);
+ INSERT_INT16_FRAME(b, (int16_t *)(frame->data), frame->samples); /* Insert frame of 16 bit samples into buffer */
s->sample_count += frame->samples;
- /* INNER LOOP -- OPTIMIZATION TARGET */
- pos = s->pos;
- while (sample_n < (frame->samples - P)) {
- /*for (pos = session->pos; pos < (GET_CURRENT_POS(b) - P); pos++) { */
- if ((sample_n % sine_len_i) == 0) {
- /* Get a desa2 frequency estimate every sine len */
- omega = avmd_desa2_tweaked(b, pos + sample_n, &litude);
+ idx = 0;
+ while (idx < AVMD_DETECTORS_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;
+ switch_thread_cond_signal(d->cond_start_processing);
+ }
+ switch_mutex_unlock(d->mutex);
+ ++idx;
+ }
- if (omega < -0.999999 || omega > 0.999999) {
- if (s->settings.debug == 1) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_DEBUG, "<<< AVMD RESET >>>\n");
- }
- v = 99999.0;
- if (s->settings.require_continuous_streak == 1) {
- RESET_SMA_BUFFER(&s->sma_b);
- RESET_SMA_BUFFER(&s->sqa_b);
- RESET_SMA_BUFFER(&s->sma_amp_b);
- RESET_SMA_BUFFER(&s->sqa_amp_b);
- s->samples_streak = s->settings.sample_n_continuous_streak;
- sample_to_skip_n = s->settings.sample_n_to_skip;
- }
- } else {
- if (ISNAN(omega)) {
- if (s->settings.debug == 1) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_DEBUG, "<<< AVMD, SKIP NaN >>>\n");
- }
- sample_to_skip_n = s->settings.sample_n_to_skip;
- goto loop_continue;
- }
- if (s->sma_b.pos > 0 && (fabs(omega - s->sma_b.data[s->sma_b.pos - 1]) < 0.00000001)) {
- if (s->settings.debug == 1) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_DEBUG, "<<< AVMD, SKIP >>>\n");
- }
- goto loop_continue;
- }
- if (s->settings.debug == 1) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_DEBUG, "<<< AVMD omega [%f] >>>\n", omega);
- }
- if (sample_to_skip_n > 0) {
- sample_to_skip_n--;
- goto loop_continue;
- }
+ switch_mutex_lock(s->mutex_detectors_done);
+ while (avmd_detection_in_progress(s) == 1) {
+ switch_thread_cond_wait(s->cond_detectors_done, s->mutex_detectors_done);
+ }
+ avmd_detection_result(s);
+ switch_mutex_unlock(s->mutex_detectors_done);
- if (omega < -0.9999) { /* saturate */
- omega = -0.9999;
- }
- if (omega > 0.9999) {
- omega = 0.9999;
- }
-
- APPEND_SMA_VAL(&s->sma_b, omega); /* append */
- APPEND_SMA_VAL(&s->sqa_b, omega * omega);
- APPEND_SMA_VAL(&s->sma_amp_b, amplitude); /* append */
- APPEND_SMA_VAL(&s->sqa_amp_b, amplitude * amplitude);
- if (s->settings.require_continuous_streak == 1) {
- if (s->samples_streak > 0) {
- --s->samples_streak;
- }
- }
- v = s->sqa_b.sma - (s->sma_b.sma * s->sma_b.sma); /* calculate variance of omega(biased estimator) */
- v_amp = s->sqa_amp_b.sma - (s->sma_amp_b.sma * s->sma_amp_b.sma); /* calculate variance of amplitude (biased estimator) */
- if (s->settings.debug == 1) {
-#if !defined(WIN32) && defined(AVMD_FAST_MATH)
- f = 0.5 * (double) fast_acosf((float)omega);
- sma_digital_freq = 0.5 * (double) fast_acosf((float)s->sma_b.sma);
-#else
- f = 0.5 * acos(omega);
- sma_digital_freq = 0.5 * acos(s->sma_b.sma);
-#endif /* !WIN32 && AVMD_FAST_MATH */
- if (s->settings.require_continuous_streak == 1) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_DEBUG, "<<< AVMD v[%.10f]\tomega[%f]\tf[%f] [%f]Hz\t\tsma[%f][%f]Hz\t\tsqa[%f]\t"
- "amplitude[%f]\tv_amp[%f]\t"
- "streak[%zu] pos[%zu] sample_n[%zu] lpos[%zu] s[%zu]>>>\n", v, omega, f, TO_HZ(s->rate, f), s->sma_b.sma, TO_HZ(s->rate, sma_digital_freq), s->sqa_b.sma,
- amplitude, v_amp,
- s->samples_streak, s->sma_b.pos, sample_n, s->sma_b.lpos, pos);
- } else {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_DEBUG, "<<< AVMD v[%.10f]\tomega[%f]\tf[%f] [%f]Hz\t\tsma[%f][%f]Hz\t\tsqa[%f]\t"
- "amplitude[%f]\tv_amp[%f]\t"
- "pos[%zu] sample_n[%zu] lpos[%zu] s[%zu]>>>\n", v, omega, f, TO_HZ(s->rate, f), s->sma_b.sma, TO_HZ(s->rate, sma_digital_freq), s->sqa_b.sma,
- amplitude, v_amp,
- s->sma_b.pos, sample_n, s->sma_b.lpos, pos);
- }
- }
- }
-
- /* DECISION */
- /* If variance is less than threshold
- * and we have at least two estimates and more than required by continuous
- * streak option then we have detection */
- if ((s->settings.require_continuous_streak == 1 && v < VARIANCE_THRESHOLD && (s->sma_b.lpos > 1) && (s->samples_streak == 0)) || (s->settings.require_continuous_streak == 0 && v < VARIANCE_THRESHOLD && (s->sma_b.lpos > 1))) {
-#if !defined(WIN32) && defined(AVMD_FAST_MATH)
- sma_digital_freq = 0.5 * (double) fast_acosf((float)s->sma_b.sma);
-#else
- sma_digital_freq = 0.5 * acos(s->sma_b.sma);
-#endif /* !WIN32 && AVMD_FAST_MATH */
-
- s->detection_stop_time = switch_micro_time_now(); /* stop detection timer */
- detection_time = s->detection_stop_time - s->detection_start_time; /* detection time length */
- switch_channel_set_variable_printf(channel, "avmd_total_time", "[%" PRId64 "]", detection_time / 1000);
- switch_channel_execute_on(channel, "execute_on_avmd_beep");
- switch_channel_set_variable(channel, "avmd_detect", "TRUE");
- avmd_fire_event(AVMD_EVENT_BEEP, s->session, TO_HZ(s->rate, sma_digital_freq), v, s->sma_amp_b.sma, v_amp, 0, 0, s->detection_start_time, s->detection_stop_time, 0, 0);
- if (s->settings.report_status == 1) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_INFO, "<<< AVMD - Beep Detected: f = [%f] variance = [%f], amplitude = [%f] variance = [%f], detection time [%" PRId64 "] [us] >>>\n", TO_HZ(s->rate, sma_digital_freq), v, s->sma_amp_b.sma, v_amp, detection_time);
- }
- RESET_SMA_BUFFER(&s->sma_b);
- RESET_SMA_BUFFER(&s->sqa_b);
- RESET_SMA_BUFFER(&s->sma_amp_b);
- RESET_SMA_BUFFER(&s->sqa_amp_b);
- s->state.beep_state = BEEP_DETECTED;
- goto done;
- }
- }
-loop_continue:
- ++sample_n;
- }
-
-done:
- s->pos += sample_n;
+ s->pos += frame->samples - AVMD_P;
s->pos &= b->mask;
return;
@@ -1698,6 +1826,182 @@ static void avmd_reloadxml_event_handler(switch_event_t *event) {
avmd_load_xml_configuration(avmd_globals.mutex);
}
+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) {
+ struct avmd_buffer *buffer = &d->buffer;
+ uint16_t sample_to_skip_n = s->settings.sample_n_to_skip;
+ enum avmd_detection_mode mode = s->settings.mode;
+ uint8_t valid_amplitude = 1, valid_omega = 1;
+ double omega = 0.0, amplitude = 0.0;
+ double f = 0.0, f_fir = 0.0;
+ double v_amp = 9999.9, v_fir = 9999.9;
+
+ sma_buffer_t *sma_b = &buffer->sma_b;
+ sma_buffer_t *sqa_b = &buffer->sqa_b;
+
+ sma_buffer_t *sma_b_fir = &buffer->sma_b_fir;
+ sma_buffer_t *sqa_b_fir = &buffer->sqa_b_fir;
+
+ sma_buffer_t *sma_amp_b = &buffer->sma_amp_b;
+ sma_buffer_t *sqa_amp_b = &buffer->sqa_amp_b;
+
+ if (sample_to_skip_n > 0) {
+ sample_to_skip_n--;
+ valid_amplitude = 0;
+ valid_omega = 0;
+ return AVMD_DETECT_NONE;
+ }
+
+ omega = avmd_desa2_tweaked(b, pos + sample_n, &litude);
+
+ if (mode == AVMD_DETECT_AMP || mode == AVMD_DETECT_BOTH) {
+ if (ISNAN(amplitude)) {
+ valid_amplitude = 0;
+ if (s->settings.require_continuous_streak_amp == 1) {
+ RESET_SMA_BUFFER(sma_amp_b);
+ RESET_SMA_BUFFER(sqa_amp_b);
+ buffer->samples_streak_amp = s->settings.sample_n_continuous_streak_amp;
+ sample_to_skip_n = s->settings.sample_n_to_skip;
+ }
+ } else {
+ if (ISINF(amplitude)) {
+ amplitude = buffer->amplitude_max;
+ }
+ if (valid_amplitude == 1) {
+ APPEND_SMA_VAL(sma_amp_b, amplitude); /* append amplitude */
+ APPEND_SMA_VAL(sqa_amp_b, amplitude * amplitude);
+ if (s->settings.require_continuous_streak_amp == 1) {
+ if (buffer->samples_streak_amp > 0) {
+ --buffer->samples_streak_amp;
+ valid_amplitude = 0;
+ }
+ }
+ }
+ if (sma_amp_b->sma > buffer->amplitude_max) {
+ buffer->amplitude_max = sma_amp_b->sma;
+ }
+ }
+ }
+
+ if (mode == AVMD_DETECT_FREQ || mode == AVMD_DETECT_BOTH) {
+ if (ISNAN(omega)) {
+ valid_omega = 0;
+ if (s->settings.require_continuous_streak == 1) {
+ RESET_SMA_BUFFER(sma_b);
+ RESET_SMA_BUFFER(sqa_b);
+ RESET_SMA_BUFFER(sma_b_fir);
+ RESET_SMA_BUFFER(sqa_b_fir);
+ buffer->samples_streak = s->settings.sample_n_continuous_streak;
+ sample_to_skip_n = s->settings.sample_n_to_skip;
+ }
+ sample_to_skip_n = s->settings.sample_n_to_skip;
+ } else if (omega < -0.99999 || omega > 0.99999) {
+ valid_omega = 0;
+ if (s->settings.require_continuous_streak == 1) {
+ RESET_SMA_BUFFER(sma_b);
+ RESET_SMA_BUFFER(sqa_b);
+ RESET_SMA_BUFFER(sma_b_fir);
+ RESET_SMA_BUFFER(sqa_b_fir);
+ buffer->samples_streak = s->settings.sample_n_continuous_streak;
+ sample_to_skip_n = s->settings.sample_n_to_skip;
+ }
+ } else {
+ if (valid_omega) {
+
+#if !defined(WIN32) && defined(AVMD_FAST_MATH)
+ f = 0.5 * (double) fast_acosf((float)omega);
+#else
+ f = 0.5 * acos(omega);
+#endif /* !WIN32 && AVMD_FAST_MATH */
+ f_fir = sma_b->pos > 1 ? (AVMD_MEDIAN_FILTER(sma_b->data[sma_b->pos - 2], sma_b->data[sma_b->pos - 1], f)) : f;
+
+ APPEND_SMA_VAL(sma_b, f); /* append frequency */
+ APPEND_SMA_VAL(sqa_b, f * f);
+ APPEND_SMA_VAL(sma_b_fir, f_fir); /* append filtered frequency */
+ APPEND_SMA_VAL(sqa_b_fir, f_fir * f_fir);
+ if (s->settings.require_continuous_streak == 1) {
+ if (buffer->samples_streak > 0) {
+ --buffer->samples_streak;
+ valid_omega = 0;
+ }
+ }
+ }
+ }
+ }
+
+ if (((mode == AVMD_DETECT_AMP) || (mode == AVMD_DETECT_BOTH)) && (valid_amplitude == 1)) {
+ v_amp = sqa_amp_b->sma - (sma_amp_b->sma * sma_amp_b->sma); /* calculate variance of amplitude (biased estimator) */
+ if ((mode == AVMD_DETECT_AMP) && (avmd_decision_amplitude(s, buffer, v_amp, AVMD_AMPLITUDE_RSD_THRESHOLD) == 1)) {
+ return AVMD_DETECT_AMP;
+ }
+ }
+ if (((mode == AVMD_DETECT_FREQ) || (mode == AVMD_DETECT_BOTH)) && (valid_omega == 1)) {
+ v_fir = sqa_b_fir->sma - (sma_b_fir->sma * sma_b_fir->sma); /* calculate variance of filtered samples */
+ if ((mode == AVMD_DETECT_FREQ) && (avmd_decision_freq(s, buffer, v_fir, AVMD_VARIANCE_RSD_THRESHOLD) == 1)) {
+ 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)) {
+ return AVMD_DETECT_BOTH;
+ }
+ }
+ }
+ return AVMD_DETECT_NONE;
+}
+
+static void*
+avmd_detector_func(switch_thread_t *thread, void *arg) {
+ size_t sample_n = 0, samples = AVMD_P;
+ size_t pos;
+ uint8_t resolution, offset;
+ avmd_session_t *s;
+ enum avmd_detection_mode res = AVMD_DETECT_NONE;
+ struct avmd_detector *d;
+
+
+ d = (struct avmd_detector*) arg;
+ s = d->s;
+ pos = s->pos;
+ while (1) {
+ switch_mutex_lock(d->mutex);
+ while ((d->flag_processing_done == 1) && (d->flag_should_exit == 0)) {
+ switch_thread_cond_wait(d->cond_start_processing, d->mutex);
+ }
+ /* master set processing_done flag to 0 */
+ if (d->flag_should_exit == 1) {
+ d->flag_processing_done = 1;
+ goto end;
+ }
+ 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 (((sample_n + offset) % resolution) == 0) {
+ res = avmd_process_sample(d->s, &s->b, sample_n, pos, d);
+ if (res != AVMD_DETECT_NONE) {
+ break;
+ }
+ }
+ ++sample_n;
+ }
+ switch_mutex_lock(d->mutex);
+ d->flag_processing_done = 1;
+ d->result = res;
+ switch_mutex_unlock(d->mutex);
+
+ switch_mutex_lock(s->mutex_detectors_done);
+ switch_thread_cond_signal(s->cond_detectors_done);
+ switch_mutex_unlock(s->mutex_detectors_done);
+ }
+ return NULL;
+
+end:
+ switch_mutex_unlock(d->mutex);
+ return NULL;
+}
+
/* For Emacs:
* Local Variables:
diff --git a/src/mod/applications/mod_avmd/scripts/avmd_get_events.pl b/src/mod/applications/mod_avmd/scripts/avmd_get_events.pl
index 1934cf44a2..024ee32aa2 100644
--- a/src/mod/applications/mod_avmd/scripts/avmd_get_events.pl
+++ b/src/mod/applications/mod_avmd/scripts/avmd_get_events.pl
@@ -1,13 +1,17 @@
+#!/usr/bin/perl -w
+
+
#brief Subscribe to avmd events and print them to the console.
#author Piotr Gregor
#date 13 Sept 2016 09:44 PM
-#!/usr/bin/perl
+$|++; # turn on autoflush
use strict;
use warnings;
require ESL;
+
my $host = "127.0.0.1";
my $port = "8021";
my $pass = "ClueCon";
diff --git a/src/mod/applications/mod_avmd/scripts/avmd_originate.pl b/src/mod/applications/mod_avmd/scripts/avmd_originate.pl
new file mode 100644
index 0000000000..e4e4f7f55b
--- /dev/null
+++ b/src/mod/applications/mod_avmd/scripts/avmd_originate.pl
@@ -0,0 +1,90 @@
+#!/usr/bin/perl -w
+
+
+#brief Call single voicemail available in default dialplan
+# 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';
+my $endpoint;
+my $dest;
+my $callerid;
+
+
+if ($#ARGV + 1 eq 2) {
+ $dest = $ARGV[0];
+ $callerid = $ARGV[1];
+ print "Dialing [" .$dest ."] as " .$callerid ."]\n";
+} else {
+ die "Please specify destination number and caller id\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";
+}
+
+print "Subscribing to avmd events...\n";
+$con->events("plain", "CUSTOM avmd::start");
+$con->events("plain", "CUSTOM avmd::stop");
+$con->events("plain", "CUSTOM avmd::beep");
+
+while($con->connected()) {
+ test_once($dest, $callerid);
+ return 0;
+}
+
+print "Disconnected.\n\n";
+
+sub test_once {
+ my ($dest, $callerid) = @_;
+ my $originate_string =
+ 'originate ' .
+ '{ignore_early_media=true,' .
+ 'origination_uuid=%s,' .
+ 'originate_timeout=60,' .
+ 'origination_caller_id_number=' . $callerid . ',' .
+ 'origination_caller_id_name=' . $callerid . '}';
+
+ if(defined($endpoint)) {
+ $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("Calling with uuid [%s] [%s]...\n", $uuid, POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime($time_epoch)), $time_hires);
+
+ $con->bgapi(sprintf($originate_string, $uuid));
+
+ print "Waiting for the events...\n\n";
+ while($con->connected()) {
+ my $e = $con->recvEvent();
+ if ($e) {
+ my $body = $e->serialize('plain');
+ print $body;
+ print "\n\n";
+ }
+ }
+}
diff --git a/src/mod/applications/mod_avmd/scripts/avmd_test.pl b/src/mod/applications/mod_avmd/scripts/avmd_test.pl
index 1f1af2929a..3550b85469 100644
--- a/src/mod/applications/mod_avmd/scripts/avmd_test.pl
+++ b/src/mod/applications/mod_avmd/scripts/avmd_test.pl
@@ -4,8 +4,10 @@
#brief Test module avmd by calling all voicemails available
# in avmd test suite and print detection results to the console.
#author Piotr Gregor
-#details If you are testing locally - remember to set avmd to inbound mode,
-# "avmd set inbound" in fs_cli.
+#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 ( pairs
my %numbers = (
- 400 => "DETECTED",
- 401 => "DETECTED",
- 402 => "DETECTED",
- 403 => "DETECTED",
- 404 => "DETECTED",
- 405 => "DETECTED",
- 406 => "DETECTED",
- 407 => "DETECTED",
- 408 => "DETECTED",
- 409 => "DETECTED",
- 410 => "DETECTED",
- 411 => "DETECTED",
- 412 => "DETECTED",
- 413 => "DETECTED",
- 414 => "DETECTED",
- 500 => "NOTDETECTED",
- 501 => "NOTDETECTED"
+ 503 => "NOTDETECTED", # dual frequency (similar to single freq with varying amplitude), mode [0] AVMD_DETECT_AMP
+ 504 => "NOTDETECTED",
+ 505 => "NOTDETECTED",
+ 506 => "NOTDETECTED",
+ 507 => "NOTDETECTED",
+ 508 => "NOTDETECTED",
+ 509 => "NOTDETECTED",
+ 510 => "NOTDETECTED",
+ 511 => "NOTDETECTED",
+ 512 => "NOTDETECTED",
+ 513 => "NOTDETECTED",
+ 514 => "NOTDETECTED",
+ 515 => "NOTDETECTED",
+ 516 => "NOTDETECTED",
+ 517 => "NOTDETECTED",
+ 518 => "NOTDETECTED",
+ 519 => "NOTDETECTED",
+ 520 => "NOTDETECTED",
+ 521 => "NOTDETECTED",
+ 522 => "NOTDETECTED",
+ 523 => "NOTDETECTED",
+ 603 => "DETECTED", # dual frequency (similar to single freq with varying amplitude), mode [1] AVMD_DETECT_FREQ
+ 604 => "DETECTED",
+ 605 => "DETECTED",
+ 606 => "DETECTED",
+ 607 => "DETECTED",
+ 608 => "DETECTED",
+ 609 => "DETECTED",
+ 610 => "DETECTED",
+ 611 => "DETECTED",
+ 612 => "DETECTED",
+ 613 => "DETECTED",
+ 614 => "DETECTED",
+ 615 => "DETECTED",
+ 616 => "DETECTED",
+ 617 => "DETECTED",
+ 618 => "DETECTED",
+ 619 => "DETECTED",
+ 620 => "DETECTED",
+ 621 => "DETECTED",
+ 622 => "DETECTED",
+ 623 => "DETECTED",
+ 703 => "NOTDETECTED", # dual frequency (similar to single freq with varying amplitude), mode [2] AVMD_DETECT_BOTH
+ 704 => "NOTDETECTED",
+ 705 => "NOTDETECTED",
+ 706 => "NOTDETECTED",
+ 707 => "NOTDETECTED",
+ 708 => "NOTDETECTED",
+ 709 => "NOTDETECTED",
+ 710 => "NOTDETECTED",
+ 711 => "NOTDETECTED",
+ 712 => "NOTDETECTED",
+ 713 => "NOTDETECTED",
+ 714 => "NOTDETECTED",
+ 715 => "NOTDETECTED",
+ 716 => "NOTDETECTED",
+ 717 => "NOTDETECTED",
+ 718 => "NOTDETECTED",
+ 719 => "NOTDETECTED",
+ 720 => "NOTDETECTED",
+ 721 => "NOTDETECTED",
+ 722 => "NOTDETECTED",
+ 723 => "NOTDETECTED",
+ 840531000 => "DETECTED", # obscure voicemails, mode AVMD_DETECT_BOTH
+ 840531001 => "DETECTED",
+ 840531002 => "DETECTED",
+ 840531003 => "DETECTED",
+ 840531004 => "DETECTED",
+ 840531005 => "DETECTED",
+ 840531006 => "DETECTED",
+ 840531007 => "DETECTED",
+ 840531008 => "DETECTED",
+ 840531009 => "DETECTED",
+ 840531010 => "DETECTED",
+ 840531011 => "DETECTED",
+ 840531012 => "DETECTED",
+ 840531013 => "DETECTED",
+ 840531014 => "DETECTED",
+ 840531200 => "DETECTED", # obscure voicemails, mode AVMD_DETECT_FREQ
+ 840531201 => "DETECTED",
+ 840531202 => "DETECTED",
+ 840531203 => "DETECTED",
+ 840531204 => "DETECTED",
+ 840531205 => "DETECTED",
+ 840531206 => "DETECTED",
+ 840531207 => "DETECTED",
+ 840531208 => "DETECTED",
+ 840531209 => "DETECTED",
+ 840531210 => "DETECTED",
+ 840531211 => "DETECTED",
+ 840531212 => "DETECTED",
+ 840531213 => "DETECTED",
+ 840531214 => "DETECTED",
);
my $host = "127.0.0.1";
@@ -72,7 +150,7 @@ if (!$con) {
if ($con->connected()) {
print "OK.\n";
} else {
- die "Conenction failure.\n";
+ die "Connection failure.\n";
}
print "Subscribing to avmd events...\t";
@@ -108,10 +186,12 @@ sub test_once {
'originate_timeout=60,' .
'origination_caller_id_number=' . $callerid . ',' .
'origination_caller_id_name=' . $callerid . '}';
- my $outcome;
- my $result;
- my $event_uuid;
+ my $outcome = "";
+ my $result = "";
+ my $event_uuid = "N/A";
my $uuid_in = "";
+ my $freq = "N/A";
+ my $freq_var = "N/A";
if(defined($endpoint)) {
$originate_string .= $endpoint;
@@ -137,6 +217,10 @@ sub test_once {
} elsif (!($uuid_in eq "") && (($avmd_event_type eq 'avmd::beep') || ($avmd_event_type eq 'avmd::stop'))) {
$event_uuid = $e->getHeader("Unique-ID");
if ($event_uuid eq $uuid_in) {
+ if ($avmd_event_type eq 'avmd::beep') {
+ $freq = $e->getHeader("Frequency");
+ $freq_var = $e->getHeader("Frequency-variance");
+ }
$outcome = $e->getHeader("Beep-Status");
if ($outcome eq $expectation) {
$result = "PASS";
@@ -150,7 +234,7 @@ sub test_once {
}
} elsif ($event_name eq 'CHANNEL_HANGUP') {
$event_uuid = $e->getHeader("variable_origination_uuid");
- if ($event_uuid eq $uuid_out) {
+ if ((defined $event_uuid) && ($event_uuid eq $uuid_out)) {
$outcome = "HANGUP";
$result = "HANGUP";
$hanguped++;
@@ -159,5 +243,6 @@ sub test_once {
}
}
}
- printf("\t[%s]\t[%s]\t\t[%s]\n", POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime($time_epoch)), $expectation, $result);
+ 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);
+ Time::HiRes::sleep(0.5); # avoid switch_core_session.c:2265 Throttle Error! 33, switch_time.c:1227 Over Session Rate of 30!
}