mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-06-10 06:38:00 +00:00
Merge pull request #824 in FS/freeswitch from ~PIOTRGREGOR/freeswitch:feature/FS-9011-avmd-add-configuration-file to master
* commit 'bf140e9b68a68ff1da2546012524350a5e504ae5': FS-9011 [avmd] Add XML config
This commit is contained in:
commit
94d3f62aef
@ -20,8 +20,6 @@
|
|||||||
#include "avmd_fast_acosf.h"
|
#include "avmd_fast_acosf.h"
|
||||||
#include "avmd_options.h"
|
#include "avmd_options.h"
|
||||||
|
|
||||||
#ifdef AVMD_FAST_MATH
|
|
||||||
|
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
@ -315,6 +313,3 @@ dump_table_summary(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif /* FAST_ACOSF_TESTING */
|
#endif /* FAST_ACOSF_TESTING */
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* @brief Fast arithmetic using precomputed arc cosine table.
|
* @brief Fast arithmetic using precomputed arc cosine table.
|
||||||
* @author Eric des Courtis
|
* Contributor(s):
|
||||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
*
|
||||||
|
* Eric des Courtis <eric.des.courtis@benbria.com>
|
||||||
|
* Piotr Gregor <piotrek.gregor gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -14,8 +16,6 @@
|
|||||||
|
|
||||||
/*! \brief Arc cosine table initialization.
|
/*! \brief Arc cosine table initialization.
|
||||||
*
|
*
|
||||||
* @author Eric des Courtis
|
|
||||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
|
||||||
* @return 0 on success, negative value otherwise:
|
* @return 0 on success, negative value otherwise:
|
||||||
* -1 can't access arc cos table with error != NOENT,
|
* -1 can't access arc cos table with error != NOENT,
|
||||||
* -2 table creation failed (compute_table)
|
* -2 table creation failed (compute_table)
|
||||||
@ -26,8 +26,6 @@ extern int init_fast_acosf(void);
|
|||||||
|
|
||||||
/*! \brief Arc cosine table deinitialization.
|
/*! \brief Arc cosine table deinitialization.
|
||||||
*
|
*
|
||||||
* @author Eric des Courtis
|
|
||||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
|
||||||
* @return 0 on success, negative value otherwise:
|
* @return 0 on success, negative value otherwise:
|
||||||
* -1 munmap failed,
|
* -1 munmap failed,
|
||||||
* -2 close failed
|
* -2 close failed
|
||||||
@ -36,14 +34,11 @@ extern int destroy_fast_acosf(void);
|
|||||||
|
|
||||||
/*! \brief Return arc cos for this argument.
|
/*! \brief Return arc cos for this argument.
|
||||||
* @details Uses previously created and mmapped file.
|
* @details Uses previously created and mmapped file.
|
||||||
* @author Eric des Courtis
|
|
||||||
*/
|
*/
|
||||||
extern float fast_acosf(float x);
|
extern float fast_acosf(float x);
|
||||||
|
|
||||||
/*! \brief Arc cosine table creation.
|
/*! \brief Arc cosine table creation.
|
||||||
*
|
*
|
||||||
* @author Eric des Courtis
|
|
||||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
|
||||||
* @return 0 on success, negative value otherwise:
|
* @return 0 on success, negative value otherwise:
|
||||||
* -1 fwrite failed,
|
* -1 fwrite failed,
|
||||||
* -2 fclose failed
|
* -2 fclose failed
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* @brief SMA buffer.
|
* @brief SMA buffer.
|
||||||
*
|
*
|
||||||
* @author Eric des Courtis
|
* Contributor(s):
|
||||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
*
|
||||||
|
* Eric des Courtis <eric.des.courtis@benbria.com>
|
||||||
|
* Piotr Gregor <piotrek.gregor gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
<configuration name="avmd.conf" description="AVMD config">
|
||||||
|
<settings>
|
||||||
|
|
||||||
|
<!-- Edit these settings to change default behaviour
|
||||||
|
of each avmd session. Settings can be overwritten
|
||||||
|
by values passed dynamically per each session -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Global settings -->
|
||||||
|
|
||||||
|
<!-- define/undefine this to enable/disable printing of avmd
|
||||||
|
intermediate computations to log -->
|
||||||
|
<param name="debug" value="0"/>
|
||||||
|
|
||||||
|
<!-- define/undef this to enable/disable reporting of beep
|
||||||
|
detection status after session ended -->
|
||||||
|
<param name="report_status" value="1"/>
|
||||||
|
|
||||||
|
<!-- define/undefine this to enable/disable faster computation
|
||||||
|
of arcus cosine - table will be created mapping floats
|
||||||
|
to integers and returning arc cos values given these integer
|
||||||
|
indices into table -->
|
||||||
|
<param name="fast_math" value="0"/>
|
||||||
|
<!-- Global settings end -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Per call (session) settings. These settings can be overwritten
|
||||||
|
with custom/different values per each avmd session -->
|
||||||
|
|
||||||
|
<!-- define/undefine this to classify avmd beep detection as valid
|
||||||
|
only when there is required number of consecutive elements
|
||||||
|
in the SMA buffer without reset -->
|
||||||
|
<param name="require_continuous_streak" value="1"/>
|
||||||
|
|
||||||
|
<!-- define number of samples to skip starting from the beginning
|
||||||
|
of the frame and after reset -->
|
||||||
|
<param name="sample_n_to_skeep" value="6"/>
|
||||||
|
|
||||||
|
<!-- define/undefine this to enable/disable simplified estimation
|
||||||
|
of frequency based on approximation of sin(x) with (x)
|
||||||
|
in the range x=[0,PI/2] -->
|
||||||
|
<param name="simplified_estimation" value="1"/>
|
||||||
|
|
||||||
|
<!-- define/undefine to enable/disable avmd on internal channel -->
|
||||||
|
<param name="inbound_channel" value="0"/>
|
||||||
|
|
||||||
|
<!-- define/undefine to enable/disable avmd on external channel -->
|
||||||
|
<param name="outbound_channel" value="1"/>
|
||||||
|
<!-- Per call settings end -->
|
||||||
|
</settings>
|
||||||
|
</configuration>
|
||||||
|
|
@ -19,8 +19,8 @@
|
|||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
*
|
*
|
||||||
* Piotr Gregor <piotrek.gregor gmail.com>:
|
|
||||||
* Eric des Courtis <eric.des.courtis@benbria.com>
|
* Eric des Courtis <eric.des.courtis@benbria.com>
|
||||||
|
* Piotr Gregor <piotrek.gregor gmail.com>:
|
||||||
*
|
*
|
||||||
* mod_avmd.c -- Advanced Voicemail Detection Module
|
* mod_avmd.c -- Advanced Voicemail Detection Module
|
||||||
*
|
*
|
||||||
@ -48,9 +48,7 @@
|
|||||||
#include "avmd_sma_buf.h"
|
#include "avmd_sma_buf.h"
|
||||||
#include "avmd_options.h"
|
#include "avmd_options.h"
|
||||||
|
|
||||||
#ifdef AVMD_FAST_MATH
|
|
||||||
#include "avmd_fast_acosf.h"
|
#include "avmd_fast_acosf.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*! Calculate how many audio samples per ms based on the rate */
|
/*! Calculate how many audio samples per ms based on the rate */
|
||||||
@ -101,10 +99,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*! Syntax of the API call. */
|
/*! Syntax of the API call. */
|
||||||
#define AVMD_SYNTAX "<uuid> <start|stop>"
|
#define AVMD_SYNTAX "<uuid> < start | stop | set [inbound|outbound|default] | load [inbound|outbound] | reload | show>"
|
||||||
|
|
||||||
/*! Number of expected parameters in api call. */
|
/*! Number of expected parameters in api call. */
|
||||||
#define AVMD_PARAMS 2
|
#define AVMD_PARAMS_MIN 1u
|
||||||
|
#define AVMD_PARAMS_MAX 2u
|
||||||
|
|
||||||
enum avmd_event
|
enum avmd_event
|
||||||
{
|
{
|
||||||
@ -112,14 +111,15 @@ enum avmd_event
|
|||||||
AVMD_EVENT_SESSION_START = 1,
|
AVMD_EVENT_SESSION_START = 1,
|
||||||
AVMD_EVENT_SESSION_STOP = 2
|
AVMD_EVENT_SESSION_STOP = 2
|
||||||
};
|
};
|
||||||
|
/* This array MUST be NULL terminated! */
|
||||||
const char* avmd_events_str[] = { [AVMD_EVENT_BEEP] = "avmd::beep",
|
const char* avmd_events_str[] = { [AVMD_EVENT_BEEP] = "avmd::beep",
|
||||||
[AVMD_EVENT_SESSION_START] = "avmd::start",
|
[AVMD_EVENT_SESSION_START] = "avmd::start",
|
||||||
[AVMD_EVENT_SESSION_STOP] = "avmd::stop",
|
[AVMD_EVENT_SESSION_STOP] = "avmd::stop",
|
||||||
NULL
|
NULL /* MUST be last and always here */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define AVMD_CHAR_BUF_LEN 20
|
#define AVMD_CHAR_BUF_LEN 20u
|
||||||
#define AVMD_BUF_LINEAR_LEN 160
|
#define AVMD_BUF_LINEAR_LEN 160u
|
||||||
|
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
@ -131,6 +131,17 @@ SWITCH_STANDARD_APP(avmd_start_app);
|
|||||||
SWITCH_STANDARD_APP(avmd_stop_app);
|
SWITCH_STANDARD_APP(avmd_stop_app);
|
||||||
SWITCH_STANDARD_APP(avmd_start_function);
|
SWITCH_STANDARD_APP(avmd_start_function);
|
||||||
|
|
||||||
|
struct avmd_settings {
|
||||||
|
uint8_t debug;
|
||||||
|
uint8_t report_status;
|
||||||
|
uint8_t fast_math;
|
||||||
|
uint8_t require_continuous_streak;
|
||||||
|
uint16_t sample_n_to_skeep;
|
||||||
|
uint8_t simplified_estimation;
|
||||||
|
uint8_t inbound_channnel;
|
||||||
|
uint8_t outbound_channnel;
|
||||||
|
};
|
||||||
|
|
||||||
/*! Status of the beep detection */
|
/*! Status of the beep detection */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BEEP_DETECTED,
|
BEEP_DETECTED,
|
||||||
@ -147,6 +158,8 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
/*! Internal FreeSWITCH session. */
|
/*! Internal FreeSWITCH session. */
|
||||||
switch_core_session_t *session;
|
switch_core_session_t *session;
|
||||||
|
switch_mutex_t *mutex;
|
||||||
|
struct avmd_settings settings;
|
||||||
uint32_t rate;
|
uint32_t rate;
|
||||||
circ_buffer_t b;
|
circ_buffer_t b;
|
||||||
sma_buffer_t sma_b;
|
sma_buffer_t sma_b;
|
||||||
@ -163,7 +176,14 @@ typedef struct {
|
|||||||
size_t sample_count;
|
size_t sample_count;
|
||||||
} avmd_session_t;
|
} avmd_session_t;
|
||||||
|
|
||||||
static void avmd_process(avmd_session_t *s, switch_frame_t *frame);
|
struct avmd_globals
|
||||||
|
{
|
||||||
|
switch_mutex_t *mutex;
|
||||||
|
struct avmd_settings settings;
|
||||||
|
switch_memory_pool_t *pool;
|
||||||
|
} avmd_globals;
|
||||||
|
|
||||||
|
static void avmd_process(avmd_session_t *session, switch_frame_t *frame);
|
||||||
|
|
||||||
static switch_bool_t avmd_callback(switch_media_bug_t * bug,
|
static switch_bool_t avmd_callback(switch_media_bug_t * bug,
|
||||||
void *user_data, switch_abc_type_t type);
|
void *user_data, switch_abc_type_t type);
|
||||||
@ -177,16 +197,43 @@ static void
|
|||||||
avmd_fire_event(enum avmd_event type, switch_core_session_t *fs_s,
|
avmd_fire_event(enum avmd_event type, switch_core_session_t *fs_s,
|
||||||
double freq, double v);
|
double freq, double v);
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
static void avmd_set_xml_inbound_configuration(switch_mutex_t *mutex);
|
||||||
|
/* API [set outbound], set inbound = 0, outbound = 1 */
|
||||||
|
static void avmd_set_xml_outbound_configuration(switch_mutex_t *mutex);
|
||||||
|
|
||||||
|
/* API [reload], reload XML configuration data from RAM */
|
||||||
|
static switch_status_t avmd_load_xml_configuration(switch_mutex_t *mutex);
|
||||||
|
/* API [load inbound], reload + set inbound */
|
||||||
|
static switch_status_t avmd_load_xml_inbound_configuration(switch_mutex_t *mutex);
|
||||||
|
/* API [load outbound], reload + set outbound */
|
||||||
|
static switch_status_t avmd_load_xml_outbound_configuration(switch_mutex_t *mutex);
|
||||||
|
|
||||||
|
/* bind callback */
|
||||||
|
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);
|
||||||
|
|
||||||
/*! \brief The avmd session data initialization function.
|
/*! \brief The avmd session data initialization function.
|
||||||
* @author Eric des Courtis
|
|
||||||
* @param avmd_session A reference to a avmd session.
|
* @param avmd_session A reference to a avmd session.
|
||||||
* @param fs_session A reference to a FreeSWITCH session.
|
* @param fs_session A reference to a FreeSWITCH session.
|
||||||
*/
|
*/
|
||||||
static switch_status_t
|
static switch_status_t
|
||||||
init_avmd_session_data(avmd_session_t *avmd_session,
|
init_avmd_session_data(avmd_session_t *avmd_session,
|
||||||
switch_core_session_t *fs_session)
|
switch_core_session_t *fs_session, switch_mutex_t *mutex)
|
||||||
{
|
{
|
||||||
size_t buf_sz;
|
size_t buf_sz;
|
||||||
|
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if (mutex != NULL)
|
||||||
|
{
|
||||||
|
switch_mutex_lock(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
/*! This is a worst case sample rate estimate */
|
/*! This is a worst case sample rate estimate */
|
||||||
avmd_session->rate = 48000;
|
avmd_session->rate = 48000;
|
||||||
@ -195,7 +242,8 @@ init_avmd_session_data(avmd_session_t *avmd_session,
|
|||||||
(size_t)FRAME_LEN(avmd_session->rate),
|
(size_t)FRAME_LEN(avmd_session->rate),
|
||||||
fs_session);
|
fs_session);
|
||||||
if (avmd_session->b.buf == NULL) {
|
if (avmd_session->b.buf == NULL) {
|
||||||
return SWITCH_STATUS_MEMERR;
|
status = SWITCH_STATUS_MEMERR;
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
avmd_session->session = fs_session;
|
avmd_session->session = fs_session;
|
||||||
avmd_session->pos = 0;
|
avmd_session->pos = 0;
|
||||||
@ -205,31 +253,40 @@ init_avmd_session_data(avmd_session_t *avmd_session,
|
|||||||
#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
|
#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
|
||||||
avmd_session->samples_streak = SAMPLES_CONSECUTIVE_STREAK;
|
avmd_session->samples_streak = SAMPLES_CONSECUTIVE_STREAK;
|
||||||
#endif
|
#endif
|
||||||
|
memset(&avmd_session->settings, 0, sizeof(struct avmd_settings));
|
||||||
|
switch_mutex_init(&avmd_session->mutex, SWITCH_MUTEX_DEFAULT,
|
||||||
|
switch_core_session_get_pool(fs_session));
|
||||||
avmd_session->sample_count = 0;
|
avmd_session->sample_count = 0;
|
||||||
|
|
||||||
buf_sz = BEEP_LEN((uint32_t)avmd_session->rate) / (uint32_t)SINE_LEN(avmd_session->rate);
|
buf_sz = BEEP_LEN((uint32_t)avmd_session->rate) / (uint32_t)SINE_LEN(avmd_session->rate);
|
||||||
if (buf_sz < 1) {
|
if (buf_sz < 1) {
|
||||||
return SWITCH_STATUS_MORE_DATA;
|
status = SWITCH_STATUS_MORE_DATA;
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_SMA_BUFFER(&avmd_session->sma_b, buf_sz, fs_session);
|
INIT_SMA_BUFFER(&avmd_session->sma_b, buf_sz, fs_session);
|
||||||
if (avmd_session->sma_b.data == NULL) {
|
if (avmd_session->sma_b.data == NULL) {
|
||||||
return SWITCH_STATUS_FALSE;
|
status = SWITCH_STATUS_FALSE;
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
memset(avmd_session->sma_b.data, 0, sizeof(BUFF_TYPE) * buf_sz);
|
memset(avmd_session->sma_b.data, 0, sizeof(BUFF_TYPE) * buf_sz);
|
||||||
|
|
||||||
INIT_SMA_BUFFER(&avmd_session->sqa_b, buf_sz, fs_session);
|
INIT_SMA_BUFFER(&avmd_session->sqa_b, buf_sz, fs_session);
|
||||||
if (avmd_session->sqa_b.data == NULL) {
|
if (avmd_session->sqa_b.data == NULL) {
|
||||||
return SWITCH_STATUS_FALSE;
|
status = SWITCH_STATUS_FALSE;
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
memset(avmd_session->sqa_b.data, 0, sizeof(BUFF_TYPE) * buf_sz);
|
memset(avmd_session->sqa_b.data, 0, sizeof(BUFF_TYPE) * buf_sz);
|
||||||
return SWITCH_STATUS_SUCCESS;
|
end:
|
||||||
|
if (mutex != NULL)
|
||||||
|
{
|
||||||
|
switch_mutex_unlock(mutex);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! \brief The callback function that is called when new audio data becomes available.
|
/*! \brief The callback function that is called when new audio data becomes available.
|
||||||
*
|
|
||||||
* @author Eric des Courtis
|
|
||||||
* @param bug A reference to the media bug.
|
* @param bug A reference to the media bug.
|
||||||
* @param user_data The session information for this call.
|
* @param user_data The session information for this call.
|
||||||
* @param type The switch callback type.
|
* @param type The switch callback type.
|
||||||
@ -365,8 +422,9 @@ avmd_fire_event(enum avmd_event type, switch_core_session_t *fs_s, double freq,
|
|||||||
|
|
||||||
status = switch_event_create_subclass(&event,
|
status = switch_event_create_subclass(&event,
|
||||||
SWITCH_EVENT_CUSTOM, avmd_events_str[type]);
|
SWITCH_EVENT_CUSTOM, avmd_events_str[type]);
|
||||||
if (status != SWITCH_STATUS_SUCCESS)
|
if (status != SWITCH_STATUS_SUCCESS) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID",
|
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID",
|
||||||
switch_core_session_get_uuid(fs_s));
|
switch_core_session_get_uuid(fs_s));
|
||||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "avmd");
|
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "avmd");
|
||||||
@ -406,27 +464,233 @@ avmd_fire_event(enum avmd_event type, switch_core_session_t *fs_s, double freq,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((switch_event_dup(&event_copy, event)) != SWITCH_STATUS_SUCCESS)
|
if ((switch_event_dup(&event_copy, event)) != SWITCH_STATUS_SUCCESS) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch_core_session_queue_event(fs_s, &event);
|
switch_core_session_queue_event(fs_s, &event);
|
||||||
switch_event_fire(&event_copy);
|
switch_event_fire(&event_copy);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief FreeSWITCH module loading function.
|
int
|
||||||
*
|
avmd_parse_u8_user_input(const char *input, uint8_t *output,
|
||||||
* @author Eric des Courtis
|
uint8_t min, uint8_t max)
|
||||||
* @par Modifications: Piotr Gregor
|
{
|
||||||
* @return On success SWITCH_STATUS_SUCCES,
|
char *pCh;
|
||||||
* on failure SWITCH_STATUS_TERM.
|
unsigned long helper;
|
||||||
*/
|
helper = strtoul(input, &pCh, 10);
|
||||||
|
if (helper < min || helper > UINT8_MAX || helper > max || (pCh == input) || (*pCh != '\0')) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*output= helper;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
helper = strtoul(input, &pCh, 10);
|
||||||
|
if (helper < min || helper > UINT16_MAX || helper > max || (pCh == input) || (*pCh != '\0')) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*output= helper;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avmd_set_xml_default_configuration(switch_mutex_t *mutex)
|
||||||
|
{
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_lock(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
avmd_globals.settings.debug = 0;
|
||||||
|
avmd_globals.settings.report_status = 1;
|
||||||
|
avmd_globals.settings.fast_math = 0;
|
||||||
|
avmd_globals.settings.require_continuous_streak = 1;
|
||||||
|
avmd_globals.settings.sample_n_to_skeep = 6;
|
||||||
|
avmd_globals.settings.simplified_estimation = 1;
|
||||||
|
avmd_globals.settings.inbound_channnel = 0;
|
||||||
|
avmd_globals.settings.outbound_channnel = 1;
|
||||||
|
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_unlock(avmd_globals.mutex);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
avmd_set_xml_inbound_configuration(switch_mutex_t *mutex)
|
||||||
|
{
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_lock(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
avmd_globals.settings.inbound_channnel = 1;
|
||||||
|
avmd_globals.settings.outbound_channnel = 0;
|
||||||
|
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_unlock(avmd_globals.mutex);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
avmd_set_xml_outbound_configuration(switch_mutex_t *mutex)
|
||||||
|
{
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_lock(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
avmd_globals.settings.inbound_channnel = 0;
|
||||||
|
avmd_globals.settings.outbound_channnel = 1;
|
||||||
|
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_unlock(avmd_globals.mutex);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_lock(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((xml = switch_xml_open_cfg("avmd.conf", &cfg, NULL)) == NULL) {
|
||||||
|
status = SWITCH_STATUS_TERM;
|
||||||
|
} else {
|
||||||
|
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 (zstr(name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (zstr(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_to_skeep")) {
|
||||||
|
if(avmd_parse_u16_user_input(value, &avmd_globals.settings.sample_n_to_skeep, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
switch_xml_free(xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_unlock(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_lock(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
avmd_globals.settings.inbound_channnel = 1;
|
||||||
|
avmd_globals.settings.outbound_channnel = 0;
|
||||||
|
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_unlock(avmd_globals.mutex);
|
||||||
|
}
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
switch_mutex_lock(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
avmd_globals.settings.inbound_channnel = 0;
|
||||||
|
avmd_globals.settings.outbound_channnel = 1;
|
||||||
|
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_unlock(avmd_globals.mutex);
|
||||||
|
}
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
avmd_show(switch_stream_handle_t *stream, switch_mutex_t *mutex)
|
||||||
|
{
|
||||||
|
const char *line = "=================================================================================================";
|
||||||
|
if (stream == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_lock(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 treak\t%u\n", avmd_globals.settings.require_continuous_streak);
|
||||||
|
stream->write_function(stream, "sample n to skeep \t%u\n", avmd_globals.settings.sample_n_to_skeep);
|
||||||
|
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, "\n\n");
|
||||||
|
|
||||||
|
if (mutex != NULL) {
|
||||||
|
switch_mutex_unlock(mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load)
|
SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load)
|
||||||
{
|
{
|
||||||
#ifdef AVMD_FAST_MATH
|
|
||||||
char err[150];
|
char err[150];
|
||||||
int ret;
|
int ret;
|
||||||
#endif
|
|
||||||
|
|
||||||
switch_application_interface_t *app_interface;
|
switch_application_interface_t *app_interface;
|
||||||
switch_api_interface_t *api_interface;
|
switch_api_interface_t *api_interface;
|
||||||
@ -439,10 +703,31 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load)
|
|||||||
return SWITCH_STATUS_TERM;
|
return SWITCH_STATUS_TERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
|
memset(&avmd_globals, 0, sizeof(avmd_globals));
|
||||||
"Advanced voicemail detection enabled\n");
|
if (pool == NULL) {
|
||||||
|
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);
|
||||||
|
avmd_globals.pool = pool;
|
||||||
|
|
||||||
#ifdef AVMD_FAST_MATH
|
if (avmd_load_xml_configuration(NULL) != SWITCH_STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||||
|
"Couldn't load XML configuration\n");
|
||||||
|
return SWITCH_STATUS_TERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (avmd_globals.settings.fast_math == 1) {
|
||||||
ret = init_fast_acosf();
|
ret = init_fast_acosf();
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
strerror_r(errno, err, 150);
|
strerror_r(errno, err, 150);
|
||||||
@ -482,7 +767,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load)
|
|||||||
"Advanced voicemail detection: fast math enabled, arc cosine table "
|
"Advanced voicemail detection: fast math enabled, arc cosine table "
|
||||||
"is [%s]\n", ACOS_TABLE_FILENAME
|
"is [%s]\n", ACOS_TABLE_FILENAME
|
||||||
);
|
);
|
||||||
#endif
|
}
|
||||||
|
|
||||||
SWITCH_ADD_APP(app_interface, "avmd_start","Start avmd detection",
|
SWITCH_ADD_APP(app_interface, "avmd_start","Start avmd detection",
|
||||||
"Start avmd detection", avmd_start_app, "", SAF_NONE);
|
"Start avmd detection", avmd_start_app, "", SAF_NONE);
|
||||||
@ -496,17 +781,22 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load)
|
|||||||
avmd_api_main, AVMD_SYNTAX);
|
avmd_api_main, AVMD_SYNTAX);
|
||||||
|
|
||||||
switch_console_set_complete("add avmd ::console::list_uuid ::[start:stop");
|
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_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
|
||||||
|
"Advanced voicemail detection enabled\n");
|
||||||
|
|
||||||
/* indicate that the module should continue to be loaded */
|
/* indicate that the module should continue to be loaded */
|
||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief FreeSWITCH application handler function.
|
|
||||||
* This handles avmd start request calls made from applications
|
|
||||||
* such as LUA and the dialplan.
|
|
||||||
*
|
|
||||||
* @return Success or failure of the function.
|
|
||||||
*/
|
|
||||||
SWITCH_STANDARD_APP(avmd_start_app)
|
SWITCH_STANDARD_APP(avmd_start_app)
|
||||||
{
|
{
|
||||||
switch_media_bug_t *bug;
|
switch_media_bug_t *bug;
|
||||||
@ -543,44 +833,49 @@ SWITCH_STANDARD_APP(avmd_start_app)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AVMD_OUTBOUND_CHANNEL
|
switch_mutex_lock(avmd_globals.mutex);
|
||||||
|
|
||||||
|
if (avmd_globals.settings.outbound_channnel == 1) {
|
||||||
if (SWITCH_CALL_DIRECTION_OUTBOUND != switch_channel_direction(channel)) {
|
if (SWITCH_CALL_DIRECTION_OUTBOUND != switch_channel_direction(channel)) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
|
||||||
"Channel [%s] is not outbound!\n", switch_channel_get_name(channel));
|
"Channel [%s] is not outbound!\n", switch_channel_get_name(channel));
|
||||||
} else {
|
} else {
|
||||||
flags |= SMBF_READ_REPLACE;
|
flags |= SMBF_READ_REPLACE;
|
||||||
}
|
}
|
||||||
#endif
|
} else if (avmd_globals.settings.inbound_channnel == 1) {
|
||||||
#ifdef AVMD_INBOUND_CHANNEL
|
|
||||||
if (SWITCH_CALL_DIRECTION_INBOUND != switch_channel_direction(channel)) {
|
if (SWITCH_CALL_DIRECTION_INBOUND != switch_channel_direction(channel)) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
|
||||||
"Channel [%s] is not inbound!\n", switch_channel_get_name(channel));
|
"Channel [%s] is not inbound!\n", switch_channel_get_name(channel));
|
||||||
} else {
|
} else {
|
||||||
flags |= SMBF_WRITE_REPLACE;
|
flags |= SMBF_WRITE_REPLACE;
|
||||||
}
|
}
|
||||||
#endif
|
} else {
|
||||||
if(flags == 0) {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR,
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR,
|
||||||
"Can't set direction for channel [%s]\n", switch_channel_get_name(channel));
|
"Can't set direction for channel [%s]\n", switch_channel_get_name(channel));
|
||||||
return;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef AVMD_OUTBOUND_CHANNEL
|
if (avmd_globals.settings.outbound_channnel == 1) {
|
||||||
if (switch_channel_test_flag(channel, CF_MEDIA_SET) == 0) {
|
if (switch_channel_test_flag(channel, CF_MEDIA_SET) == 0) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR,
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR,
|
||||||
"Failed to start session. Channel [%s] has no codec assigned yet."
|
"Failed to start session. Channel [%s] has no codec assigned yet."
|
||||||
" Please try again\n", switch_channel_get_name(channel));
|
" Please try again\n", switch_channel_get_name(channel));
|
||||||
return;
|
goto end;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Allocate memory attached to this FreeSWITCH session for
|
/* Allocate memory attached to this FreeSWITCH session for
|
||||||
* use in the callback routine and to store state information */
|
* use in the callback routine and to store state information */
|
||||||
avmd_session = (avmd_session_t *) switch_core_session_alloc(
|
avmd_session = (avmd_session_t *) switch_core_session_alloc(
|
||||||
session, sizeof(avmd_session_t));
|
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);
|
status = init_avmd_session_data(avmd_session, session, NULL);
|
||||||
if (status != SWITCH_STATUS_SUCCESS) {
|
if (status != SWITCH_STATUS_SUCCESS) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case SWITCH_STATUS_MEMERR:
|
case SWITCH_STATUS_MEMERR:
|
||||||
@ -605,7 +900,7 @@ SWITCH_STANDARD_APP(avmd_start_app)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
return;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a media bug that allows me to intercept the
|
/* Add a media bug that allows me to intercept the
|
||||||
@ -625,7 +920,7 @@ SWITCH_STANDARD_APP(avmd_start_app)
|
|||||||
if (status != SWITCH_STATUS_SUCCESS) {
|
if (status != SWITCH_STATUS_SUCCESS) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
|
||||||
SWITCH_LOG_ERROR, "Failed to add media bug!\n");
|
SWITCH_LOG_ERROR, "Failed to add media bug!\n");
|
||||||
return;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the avmd tag to detect an existing avmd media bug */
|
/* Set the avmd tag to detect an existing avmd media bug */
|
||||||
@ -637,14 +932,12 @@ SWITCH_STANDARD_APP(avmd_start_app)
|
|||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO,
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO,
|
||||||
"Avmd on channel [%s] started!\n", switch_channel_get_name(channel));
|
"Avmd on channel [%s] started!\n", switch_channel_get_name(channel));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
end:
|
||||||
|
switch_mutex_unlock(avmd_globals.mutex);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief FreeSWITCH application handler function.
|
|
||||||
* This handles avmd stop request calls made from applications
|
|
||||||
* such as LUA and the dialplan.
|
|
||||||
*
|
|
||||||
* @return Success or failure of the function.
|
|
||||||
*/
|
|
||||||
SWITCH_STANDARD_APP(avmd_stop_app)
|
SWITCH_STANDARD_APP(avmd_stop_app)
|
||||||
{
|
{
|
||||||
switch_media_bug_t *bug;
|
switch_media_bug_t *bug;
|
||||||
@ -691,9 +984,6 @@ SWITCH_STANDARD_APP(avmd_stop_app)
|
|||||||
|
|
||||||
/*! \brief FreeSWITCH application handler function.
|
/*! \brief FreeSWITCH application handler function.
|
||||||
* This handles calls made from applications such as LUA and the dialplan.
|
* This handles calls made from applications such as LUA and the dialplan.
|
||||||
*
|
|
||||||
* @author Eric des Courtis
|
|
||||||
* @return Success or failure of the function.
|
|
||||||
*/
|
*/
|
||||||
SWITCH_STANDARD_APP(avmd_start_function)
|
SWITCH_STANDARD_APP(avmd_start_function)
|
||||||
{
|
{
|
||||||
@ -730,20 +1020,15 @@ SWITCH_STANDARD_APP(avmd_start_function)
|
|||||||
avmd_start_app(session, NULL);
|
avmd_start_app(session, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Called when the module shuts down.
|
|
||||||
*
|
|
||||||
* @author Eric des Courtis
|
|
||||||
* @return The success or failure of the function.
|
|
||||||
*/
|
|
||||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown)
|
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown)
|
||||||
{
|
{
|
||||||
#ifdef AVMD_FAST_MATH
|
|
||||||
int res;
|
int res;
|
||||||
#endif
|
|
||||||
|
switch_mutex_lock(avmd_globals.mutex);
|
||||||
|
|
||||||
avmd_unregister_all_events();
|
avmd_unregister_all_events();
|
||||||
|
|
||||||
#ifdef AVMD_FAST_MATH
|
if (avmd_globals.settings.fast_math == 1) {
|
||||||
res = destroy_fast_acosf();
|
res = destroy_fast_acosf();
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
switch (res) {
|
switch (res) {
|
||||||
@ -759,7 +1044,11 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
switch_event_unbind_callback(avmd_reloadxml_event_handler);
|
||||||
|
|
||||||
|
switch_mutex_unlock(avmd_globals.mutex);
|
||||||
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
|
||||||
"Advanced voicemail detection disabled\n");
|
"Advanced voicemail detection disabled\n");
|
||||||
@ -771,9 +1060,6 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown)
|
|||||||
* This function handles API calls such as the ones
|
* This function handles API calls such as the ones
|
||||||
* from mod_event_socket and in some cases
|
* from mod_event_socket and in some cases
|
||||||
* scripts such as LUA scripts.
|
* scripts such as LUA scripts.
|
||||||
*
|
|
||||||
* @author Eric des Courtis
|
|
||||||
* @return The success or failure of the function.
|
|
||||||
*/
|
*/
|
||||||
SWITCH_STANDARD_API(avmd_api_main)
|
SWITCH_STANDARD_API(avmd_api_main)
|
||||||
{
|
{
|
||||||
@ -781,14 +1067,15 @@ SWITCH_STANDARD_API(avmd_api_main)
|
|||||||
avmd_session_t *avmd_session;
|
avmd_session_t *avmd_session;
|
||||||
switch_channel_t *channel;
|
switch_channel_t *channel;
|
||||||
int argc;
|
int argc;
|
||||||
char *argv[AVMD_PARAMS];
|
const char *uuid, *uuid_dup;
|
||||||
char *ccmd = NULL;
|
const char *command;
|
||||||
char *uuid, *uuid_dup;
|
char *dupped = NULL, *argv[AVMD_PARAMS_MAX + 1] = { 0 };
|
||||||
char *command;
|
|
||||||
switch_core_media_flag_t flags = 0;
|
switch_core_media_flag_t flags = 0;
|
||||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||||
switch_core_session_t *fs_session = NULL;
|
switch_core_session_t *fs_session = NULL;
|
||||||
|
|
||||||
|
switch_mutex_lock(avmd_globals.mutex);
|
||||||
|
|
||||||
/* No command? Display usage */
|
/* No command? Display usage */
|
||||||
if (zstr(cmd)) {
|
if (zstr(cmd)) {
|
||||||
stream->write_function(stream, "-ERR, bad command!\n"
|
stream->write_function(stream, "-ERR, bad command!\n"
|
||||||
@ -797,15 +1084,119 @@ SWITCH_STANDARD_API(avmd_api_main)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Duplicated contents of original string */
|
/* Duplicated contents of original string */
|
||||||
ccmd = strdup(cmd);
|
dupped = strdup(cmd);
|
||||||
|
switch_assert(dupped);
|
||||||
/* Separate the arguments */
|
/* Separate the arguments */
|
||||||
argc = switch_separate_string(ccmd, ' ', argv, AVMD_PARAMS);
|
argc = switch_separate_string((char*)dupped, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||||
|
|
||||||
/* If we don't have the expected number of parameters
|
/* If we don't have the expected number of parameters
|
||||||
* display usage */
|
* display usage */
|
||||||
if (argc != AVMD_PARAMS) {
|
if (argc < AVMD_PARAMS_MIN) {
|
||||||
stream->write_function(stream, "-ERR, avmd takes [%u] parameters!\n"
|
stream->write_function(stream, "-ERR, avmd takes [%u] min and [%u] max parameters!\n"
|
||||||
"-USAGE: %s\n\n", AVMD_PARAMS, AVMD_SYNTAX);
|
"-USAGE: %s\n\n", AVMD_PARAMS_MIN, AVMD_PARAMS_MAX, AVMD_SYNTAX);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
command = argv[0];
|
||||||
|
if (strcasecmp(command, "reload") == 0) {
|
||||||
|
if (avmd_load_xml_configuration(NULL) != SWITCH_STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
stream->write_function(stream, "-ERR, couldn't reload XML configuration\n");
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||||
|
"Couldn't reload XML configuration\n");
|
||||||
|
}
|
||||||
|
if (avmd_globals.settings.report_status == 1) {
|
||||||
|
stream->write_function(stream, "+OK\n XML reloaded\n\n");
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
|
||||||
|
"XML reloaded\n");
|
||||||
|
}
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (strcasecmp(command, "load") == 0) {
|
||||||
|
if (argc != 2) {
|
||||||
|
stream->write_function(stream, "-ERR, load command takes 1 parameter!\n"
|
||||||
|
"-USAGE: %s\n\n", AVMD_SYNTAX);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
command = argv[1];
|
||||||
|
if (strcasecmp(command, "inbound") == 0) {
|
||||||
|
status = avmd_load_xml_inbound_configuration(NULL);
|
||||||
|
if (avmd_globals.settings.report_status == 1) {
|
||||||
|
if (status != SWITCH_STATUS_SUCCESS) {
|
||||||
|
stream->write_function(stream, "-ERR, couldn't load XML configuration\n");
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||||
|
"Couldn't load XML configuration\n");
|
||||||
|
} else {
|
||||||
|
stream->write_function(stream, "+OK\n inbound "
|
||||||
|
"XML configuration loaded\n\n");
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
|
||||||
|
"Inbound XML configuration loaded\n");
|
||||||
|
}
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(command, "outbound") == 0) {
|
||||||
|
status = avmd_load_xml_outbound_configuration(NULL);
|
||||||
|
if (avmd_globals.settings.report_status == 1) {
|
||||||
|
if (status != SWITCH_STATUS_SUCCESS) {
|
||||||
|
stream->write_function(stream, "-ERR, couldn't load XML configuration\n");
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||||
|
"Couldn't load XML configuration\n");
|
||||||
|
} else {
|
||||||
|
stream->write_function(stream, "+OK\n outbound "
|
||||||
|
"XML configuration loaded\n\n");
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
|
||||||
|
"Outbound XML configuration loaded\n");
|
||||||
|
}
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stream->write_function(stream, "-ERR, load command: bad syntax!\n"
|
||||||
|
"-USAGE: %s\n\n", AVMD_SYNTAX);
|
||||||
|
}
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (strcasecmp(command, "set") == 0) {
|
||||||
|
if (argc != 2) {
|
||||||
|
stream->write_function(stream, "-ERR, set command takes 1 parameter!\n"
|
||||||
|
"-USAGE: %s\n\n", AVMD_SYNTAX);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
command = argv[1];
|
||||||
|
if (strcasecmp(command, "inbound") == 0) {
|
||||||
|
avmd_set_xml_inbound_configuration(NULL);
|
||||||
|
if (avmd_globals.settings.report_status == 1) {
|
||||||
|
stream->write_function(stream, "+OK\n inbound "
|
||||||
|
"XML configuration loaded\n\n");
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
|
||||||
|
"Inbound XML configuration loaded\n");
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(command, "outbound") == 0) {
|
||||||
|
avmd_set_xml_outbound_configuration(NULL);
|
||||||
|
if (avmd_globals.settings.report_status == 1) {
|
||||||
|
stream->write_function(stream, "+OK\n outbound "
|
||||||
|
"XML configuration loaded\n\n");
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
|
||||||
|
"Outbound XML configuration loaded\n");
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(command, "default") == 0) {
|
||||||
|
avmd_set_xml_default_configuration(NULL);
|
||||||
|
if (avmd_globals.settings.report_status == 1) {
|
||||||
|
stream->write_function(stream, "+OK\n reset "
|
||||||
|
"to factory settings\n\n");
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
|
||||||
|
"Reset to factory settings\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stream->write_function(stream, "-ERR, set command: bad syntax!\n"
|
||||||
|
"-USAGE: %s\n\n", AVMD_SYNTAX);
|
||||||
|
}
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (strcasecmp(command, "show") == 0) {
|
||||||
|
avmd_show(stream, NULL);
|
||||||
|
if (avmd_globals.settings.report_status == 1) {
|
||||||
|
stream->write_function(stream, "+OK\n show\n\n");
|
||||||
|
}
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -843,22 +1234,21 @@ SWITCH_STANDARD_API(avmd_api_main)
|
|||||||
switch_channel_set_private(channel, "_avmd_", NULL);
|
switch_channel_set_private(channel, "_avmd_", NULL);
|
||||||
switch_core_media_bug_remove(fs_session, &bug);
|
switch_core_media_bug_remove(fs_session, &bug);
|
||||||
avmd_fire_event(AVMD_EVENT_SESSION_STOP, fs_session, 0, 0);
|
avmd_fire_event(AVMD_EVENT_SESSION_STOP, fs_session, 0, 0);
|
||||||
#ifdef AVMD_REPORT_STATUS
|
if (avmd_globals.settings.report_status == 1) {
|
||||||
stream->write_function(stream, "+OK\n [%s] [%s] stopped\n\n",
|
stream->write_function(stream, "+OK\n [%s] [%s] stopped\n\n",
|
||||||
uuid_dup, switch_channel_get_name(channel));
|
uuid_dup, switch_channel_get_name(channel));
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_INFO,
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_INFO,
|
||||||
"Avmd on channel [%s] stopped!\n", switch_channel_get_name(channel));
|
"Avmd on channel [%s] stopped!\n", switch_channel_get_name(channel));
|
||||||
#endif
|
}
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
if (avmd_globals.settings.report_status == 1) {
|
||||||
#ifdef AVMD_REPORT_STATUS
|
|
||||||
/* We have already started */
|
/* We have already started */
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session),
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session),
|
||||||
SWITCH_LOG_ERROR, "Avmd already started!\n");
|
SWITCH_LOG_ERROR, "Avmd already started!\n");
|
||||||
stream->write_function(stream, "-ERR, avmd for FreeSWITCH session [%s]"
|
stream->write_function(stream, "-ERR, avmd for FreeSWITCH session [%s]"
|
||||||
"\n already started\n\n", uuid);
|
"\n already started\n\n", uuid);
|
||||||
#endif
|
}
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,7 +1262,7 @@ SWITCH_STANDARD_API(avmd_api_main)
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AVMD_OUTBOUND_CHANNEL
|
if (avmd_globals.settings.outbound_channnel == 1) {
|
||||||
if (SWITCH_CALL_DIRECTION_OUTBOUND != switch_channel_direction(channel)) {
|
if (SWITCH_CALL_DIRECTION_OUTBOUND != switch_channel_direction(channel)) {
|
||||||
stream->write_function(stream, "-ERR, channel for FreeSWITCH session [%s]"
|
stream->write_function(stream, "-ERR, channel for FreeSWITCH session [%s]"
|
||||||
"\n is not outbound\n\n", uuid);
|
"\n is not outbound\n\n", uuid);
|
||||||
@ -881,8 +1271,7 @@ SWITCH_STANDARD_API(avmd_api_main)
|
|||||||
} else {
|
} else {
|
||||||
flags |= SMBF_READ_REPLACE;
|
flags |= SMBF_READ_REPLACE;
|
||||||
}
|
}
|
||||||
#endif
|
} else if (avmd_globals.settings.inbound_channnel == 1) {
|
||||||
#ifdef AVMD_INBOUND_CHANNEL
|
|
||||||
if (SWITCH_CALL_DIRECTION_INBOUND != switch_channel_direction(channel)) {
|
if (SWITCH_CALL_DIRECTION_INBOUND != switch_channel_direction(channel)) {
|
||||||
stream->write_function(stream, "-ERR, channel for FreeSWITCH session [%s]"
|
stream->write_function(stream, "-ERR, channel for FreeSWITCH session [%s]"
|
||||||
"\n is not inbound\n\n", uuid);
|
"\n is not inbound\n\n", uuid);
|
||||||
@ -891,8 +1280,7 @@ SWITCH_STANDARD_API(avmd_api_main)
|
|||||||
} else {
|
} else {
|
||||||
flags |= SMBF_WRITE_REPLACE;
|
flags |= SMBF_WRITE_REPLACE;
|
||||||
}
|
}
|
||||||
#endif
|
} else {
|
||||||
if(flags == 0) {
|
|
||||||
stream->write_function(stream, "-ERR, can't set direction for channel [%s]\n"
|
stream->write_function(stream, "-ERR, can't set direction for channel [%s]\n"
|
||||||
" for FreeSWITCH session [%s]. Please check avmd configuration\n\n",
|
" for FreeSWITCH session [%s]. Please check avmd configuration\n\n",
|
||||||
switch_channel_get_name(channel), uuid);
|
switch_channel_get_name(channel), uuid);
|
||||||
@ -902,7 +1290,7 @@ SWITCH_STANDARD_API(avmd_api_main)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef AVMD_OUTBOUND_CHANNEL
|
if (avmd_globals.settings.outbound_channnel == 1) {
|
||||||
if (switch_channel_test_flag(channel, CF_MEDIA_SET) == 0) {
|
if (switch_channel_test_flag(channel, CF_MEDIA_SET) == 0) {
|
||||||
stream->write_function(stream, "-ERR, channel [%s] for FreeSWITCH session [%s]"
|
stream->write_function(stream, "-ERR, channel [%s] for FreeSWITCH session [%s]"
|
||||||
"\n has no read codec assigned yet. Please try again.\n\n",
|
"\n has no read codec assigned yet. Please try again.\n\n",
|
||||||
@ -912,7 +1300,7 @@ SWITCH_STANDARD_API(avmd_api_main)
|
|||||||
" Please try again\n", switch_channel_get_name(channel));
|
" Please try again\n", switch_channel_get_name(channel));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
/* If we don't see the expected start exit */
|
/* If we don't see the expected start exit */
|
||||||
if (strcasecmp(command, "start") != 0) {
|
if (strcasecmp(command, "start") != 0) {
|
||||||
@ -925,7 +1313,7 @@ SWITCH_STANDARD_API(avmd_api_main)
|
|||||||
* use in the callback routine and to store state information */
|
* use in the callback routine and to store state information */
|
||||||
avmd_session = (avmd_session_t *) switch_core_session_alloc(
|
avmd_session = (avmd_session_t *) switch_core_session_alloc(
|
||||||
fs_session, sizeof(avmd_session_t));
|
fs_session, sizeof(avmd_session_t));
|
||||||
status = init_avmd_session_data(avmd_session, fs_session);
|
status = init_avmd_session_data(avmd_session, fs_session, NULL);
|
||||||
if (status != SWITCH_STATUS_SUCCESS) {
|
if (status != SWITCH_STATUS_SUCCESS) {
|
||||||
stream->write_function(stream, "-ERR, failed to initialize avmd session\n"
|
stream->write_function(stream, "-ERR, failed to initialize avmd session\n"
|
||||||
" for FreeSWITCH session [%s]\n", uuid);
|
" for FreeSWITCH session [%s]\n", uuid);
|
||||||
@ -985,27 +1373,27 @@ SWITCH_STANDARD_API(avmd_api_main)
|
|||||||
|
|
||||||
/* OK */
|
/* OK */
|
||||||
avmd_fire_event(AVMD_EVENT_SESSION_START, fs_session, 0, 0);
|
avmd_fire_event(AVMD_EVENT_SESSION_START, fs_session, 0, 0);
|
||||||
#ifdef AVMD_REPORT_STATUS
|
if (avmd_globals.settings.report_status == 1) {
|
||||||
stream->write_function(stream, "+OK\n [%s] [%s] started!\n\n",
|
stream->write_function(stream, "+OK\n [%s] [%s] started!\n\n",
|
||||||
uuid, switch_channel_get_name(channel));
|
uuid, switch_channel_get_name(channel));
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_INFO,
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_INFO,
|
||||||
"Avmd on channel [%s] started!\n", switch_channel_get_name(channel));
|
"Avmd on channel [%s] started!\n", switch_channel_get_name(channel));
|
||||||
switch_assert(status == SWITCH_STATUS_SUCCESS);
|
switch_assert(status == SWITCH_STATUS_SUCCESS);
|
||||||
#endif
|
}
|
||||||
end:
|
end:
|
||||||
|
|
||||||
if (fs_session) {
|
if (fs_session) {
|
||||||
switch_core_session_rwunlock(fs_session);
|
switch_core_session_rwunlock(fs_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch_safe_free(ccmd);
|
switch_safe_free(dupped);
|
||||||
|
|
||||||
|
switch_mutex_unlock(avmd_globals.mutex);
|
||||||
|
|
||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Process one frame of data with avmd algorithm.
|
/*! \brief Process one frame of data with avmd algorithm.
|
||||||
* @author Eric des Courtis
|
|
||||||
* @par Modifications: Piotr Gregor
|
|
||||||
* @param session An avmd session.
|
* @param session An avmd session.
|
||||||
* @param frame An audio frame.
|
* @param frame An audio frame.
|
||||||
*/
|
*/
|
||||||
@ -1088,17 +1476,20 @@ static void avmd_process(avmd_session_t *s, switch_frame_t *frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* saturate */
|
/* saturate */
|
||||||
if (omega < -0.9999)
|
if (omega < -0.9999) {
|
||||||
omega = -0.9999;
|
omega = -0.9999;
|
||||||
if (omega > 0.9999)
|
}
|
||||||
|
if (omega > 0.9999) {
|
||||||
omega = 0.9999;
|
omega = 0.9999;
|
||||||
|
}
|
||||||
|
|
||||||
/* append */
|
/* append */
|
||||||
APPEND_SMA_VAL(&s->sma_b, omega);
|
APPEND_SMA_VAL(&s->sma_b, omega);
|
||||||
APPEND_SMA_VAL(&s->sqa_b, omega * omega);
|
APPEND_SMA_VAL(&s->sqa_b, omega * omega);
|
||||||
#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
|
#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
|
||||||
if (s->samples_streak > 0)
|
if (s->samples_streak > 0) {
|
||||||
--s->samples_streak;
|
--s->samples_streak;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
/* calculate variance (biased estimator) */
|
/* calculate variance (biased estimator) */
|
||||||
v = s->sqa_b.sma - (s->sma_b.sma * s->sma_b.sma);
|
v = s->sqa_b.sma - (s->sma_b.sma * s->sma_b.sma);
|
||||||
@ -1171,6 +1562,13 @@ done:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
avmd_reloadxml_event_handler(switch_event_t *event)
|
||||||
|
{
|
||||||
|
avmd_load_xml_configuration(avmd_globals.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* For Emacs:
|
/* For Emacs:
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* mode:c
|
* mode:c
|
||||||
@ -1181,4 +1579,3 @@ done:
|
|||||||
* For VIM:
|
* For VIM:
|
||||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user