]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-9011 [avmd] Add XML config
authorPiotr Gregor <piotrek.gregor@gmail.com>
Fri, 22 Apr 2016 23:01:11 +0000 (00:01 +0100)
committerPiotr Gregor <piotrek.gregor@gmail.com>
Thu, 28 Apr 2016 13:22:51 +0000 (14:22 +0100)
Add XML configuration file.
Bind reloadxml callback.
Add safe parsers of user's input.
Add show/set/load/reload API commands.

src/mod/applications/mod_avmd/avmd_fast_acosf.c
src/mod/applications/mod_avmd/avmd_fast_acosf.h
src/mod/applications/mod_avmd/avmd_sma_buf.h
src/mod/applications/mod_avmd/conf/autoload_configs/avmd.conf.xml [new file with mode: 0644]
src/mod/applications/mod_avmd/mod_avmd.c

index 985e95b6f709e2b0fd12e0e0186cec114b99d18a..1974c9852f1f83221ce6f6c4cba82c0b7649f3c2 100644 (file)
@@ -20,8 +20,6 @@
 #include "avmd_fast_acosf.h"
 #include "avmd_options.h"
 
-#ifdef AVMD_FAST_MATH
-
 
 typedef union {
     uint32_t i;
@@ -315,6 +313,3 @@ dump_table_summary(void)
 }
 
 #endif /* FAST_ACOSF_TESTING */
-
-
-#endif
index 3c404039feef6292694a9edb12323077ec5f93a2..1c3b68ca1a125b9755a8ce61df9d32c5a45132f5 100644 (file)
@@ -1,7 +1,9 @@
 /*
  * @brief   Fast arithmetic using precomputed arc cosine table.
- * @author  Eric des Courtis
- * @par     Modifications: Piotr Gregor < piotrek.gregor gmail.com >
+ * Contributor(s):
+ *
+ * Eric des Courtis <eric.des.courtis@benbria.com>
+ * Piotr Gregor <piotrek.gregor gmail.com>
  */
 
 
@@ -14,8 +16,6 @@
 
 /*! \brief Arc cosine table initialization.
  *
- * @author Eric des Courtis
- * @par    Modifications: Piotr Gregor < piotrek.gregor gmail.com >
  * @return 0 on success, negative value otherwise:
  *          -1 can't access arc cos table with error != NOENT,
  *          -2 table creation failed (compute_table)
@@ -26,8 +26,6 @@ extern int init_fast_acosf(void);
 
 /*! \brief Arc cosine table deinitialization.
  *
- * @author Eric des Courtis
- * @par    Modifications: Piotr Gregor < piotrek.gregor gmail.com >
  * @return 0 on success, negative value otherwise:
  *          -1 munmap failed,
  *          -2 close failed
@@ -36,14 +34,11 @@ extern int destroy_fast_acosf(void);
 
 /*! \brief  Return arc cos for this argument.
  * @details Uses previously created and mmapped file.
- * @author  Eric des Courtis
  */
 extern float fast_acosf(float x);
 
 /*! \brief Arc cosine table creation.
  *
- * @author Eric des Courtis
- * @par    Modifications: Piotr Gregor < piotrek.gregor gmail.com >
  * @return 0 on success, negative value otherwise:
  *          -1 fwrite failed,
  *          -2 fclose failed
index 2871cc9b7dc5e8f90a54c9553120d4bc643c75a2..b514b95bea5c8e5a3b8ae551f0d47f3d278e32b6 100644 (file)
@@ -1,8 +1,10 @@
 /*
  * @brief   SMA buffer.
  *
- * @author Eric des Courtis
- * @par    Modifications: Piotr Gregor < piotrek.gregor gmail.com >
+ * Contributor(s):
+ *
+ * Eric des Courtis <eric.des.courtis@benbria.com>
+ * Piotr Gregor <piotrek.gregor gmail.com>
  */
 
 
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
new file mode 100644 (file)
index 0000000..9f10c3e
--- /dev/null
@@ -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>
+
index 059f7ed52ec22ce73cf5249a66c82b616f9b1a96..5e8e2a7ecc3e1566e9a4b3ba5c466d042bddc7cf 100644 (file)
@@ -19,8 +19,8 @@
  *
  * Contributor(s):
  *
- * Piotr Gregor <piotrek.gregor gmail.com>:
  * Eric des Courtis <eric.des.courtis@benbria.com>
+ * Piotr Gregor <piotrek.gregor gmail.com>:
  *
  * mod_avmd.c -- Advanced Voicemail Detection Module
  *
@@ -48,9 +48,7 @@
 #include "avmd_sma_buf.h"
 #include "avmd_options.h"
 
-#ifdef AVMD_FAST_MATH
 #include "avmd_fast_acosf.h"
-#endif
 
 
 /*! Calculate how many audio samples per ms based on the rate */
 #endif
 
 /*! 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. */
-#define AVMD_PARAMS 2
+#define AVMD_PARAMS_MIN 1u
+#define AVMD_PARAMS_MAX 2u
 
 enum avmd_event
 {
@@ -112,14 +111,15 @@ enum avmd_event
     AVMD_EVENT_SESSION_START = 1,
     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
+                                    NULL                                            /* MUST be last and always here */
 };
 
-#define AVMD_CHAR_BUF_LEN 20
-#define AVMD_BUF_LINEAR_LEN 160
+#define AVMD_CHAR_BUF_LEN 20u
+#define AVMD_BUF_LINEAR_LEN 160u
 
 
 /* Prototypes */
@@ -131,6 +131,17 @@ SWITCH_STANDARD_APP(avmd_start_app);
 SWITCH_STANDARD_APP(avmd_stop_app);
 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 */
 typedef enum {
        BEEP_DETECTED,
@@ -146,13 +157,15 @@ typedef struct {
 /*! Type that holds session information pertinent to the avmd module. */
 typedef struct {
        /*! Internal FreeSWITCH session. */
-       switch_core_session_t *session;
-       uint32_t rate;
-       circ_buffer_t b;
-       sma_buffer_t sma_b;
-       sma_buffer_t sqa_b;
-       size_t pos;
-       double f;
+       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;
+       size_t          pos;
+       double          f;
        /* freq_table_t ft; */
        avmd_state_t state;
        switch_time_t start_time;
@@ -163,7 +176,14 @@ typedef struct {
     size_t sample_count;
 } 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,
                                     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,
                     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.
- * @author Eric des Courtis
  * @param avmd_session A reference to a avmd session.
  * @param fs_session A reference to a FreeSWITCH session.
  */
 static switch_status_t
 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 */
        avmd_session->rate = 48000;
@@ -195,7 +242,8 @@ init_avmd_session_data(avmd_session_t *avmd_session,
             (size_t)FRAME_LEN(avmd_session->rate),
             fs_session);
     if (avmd_session->b.buf == NULL) {
-            return SWITCH_STATUS_MEMERR;
+            status =  SWITCH_STATUS_MEMERR;
+            goto end;
     }
        avmd_session->session = fs_session;
        avmd_session->pos = 0;
@@ -205,31 +253,40 @@ init_avmd_session_data(avmd_session_t *avmd_session,
 #ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
     avmd_session->samples_streak = SAMPLES_CONSECUTIVE_STREAK;
 #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;
 
     buf_sz = BEEP_LEN((uint32_t)avmd_session->rate) / (uint32_t)SINE_LEN(avmd_session->rate);
     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);
     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);
 
     INIT_SMA_BUFFER(&avmd_session->sqa_b, buf_sz, fs_session);
     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);
-    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.
- *
- * @author Eric des Courtis
  * @param bug A reference to the media bug.
  * @param user_data The session information for this call.
  * @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,
             SWITCH_EVENT_CUSTOM, avmd_events_str[type]);
-    if (status != SWITCH_STATUS_SUCCESS)
+    if (status != SWITCH_STATUS_SUCCESS) {
         return;
+    }
     switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID",
                     switch_core_session_get_uuid(fs_s));
     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;
     }
 
-    if ((switch_event_dup(&event_copy, event)) != SWITCH_STATUS_SUCCESS)
+    if ((switch_event_dup(&event_copy, event)) != SWITCH_STATUS_SUCCESS) {
         return;
+    }
 
     switch_core_session_queue_event(fs_s, &event);
     switch_event_fire(&event_copy);
     return;
 }
 
-/*! \brief FreeSWITCH module loading function.
- *
- * @author Eric des Courtis
- * @par    Modifications: Piotr Gregor
- * @return On success SWITCH_STATUS_SUCCES,
- *         on failure SWITCH_STATUS_TERM.
- */
+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')) {
+        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)
 {
-#ifdef AVMD_FAST_MATH
     char    err[150];
     int     ret;
-#endif
 
        switch_application_interface_t *app_interface;
        switch_api_interface_t *api_interface;
@@ -438,51 +702,72 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load)
                 "Couldn't register avmd events!\n");
                return SWITCH_STATUS_TERM;
        }
-       
-       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
-               "Advanced voicemail detection enabled\n");
 
-#ifdef AVMD_FAST_MATH
-    ret = init_fast_acosf();
-    if (ret != 0) {
-        strerror_r(errno, err, 150);
-        switch (ret) {
+    memset(&avmd_globals, 0, sizeof(avmd_globals));
+    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;
 
-            case -1:
-                   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);
-                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);
-                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);
-                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);
-                return SWITCH_STATUS_TERM;
-        }
+    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;
-    } 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
-               );
-#endif
+    }
+
+       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();
+        if (ret != 0) {
+            strerror_r(errno, err, 150);
+            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);
+                    break;
+                case -2:
+                       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);
+                    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);
+                    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);
+                    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_ADD_APP(app_interface, "avmd_start","Start avmd detection",
             "Start avmd detection", avmd_start_app, "", SAF_NONE);
@@ -496,17 +781,22 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load)
             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
+                                                             * 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 */
        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_media_bug_t  *bug;
@@ -543,44 +833,49 @@ SWITCH_STANDARD_APP(avmd_start_app)
         return;
        }
 
-#ifdef AVMD_OUTBOUND_CHANNEL
-    if (SWITCH_CALL_DIRECTION_OUTBOUND != switch_channel_direction(channel)) {
-               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
-                       "Channel [%s] is not outbound!\n", switch_channel_get_name(channel));
-    } else {
-        flags |= SMBF_READ_REPLACE;
-    }
-#endif
-#ifdef AVMD_INBOUND_CHANNEL
-    if (SWITCH_CALL_DIRECTION_INBOUND != switch_channel_direction(channel)) {
-               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
-                       "Channel [%s] is not inbound!\n", switch_channel_get_name(channel));
+    switch_mutex_lock(avmd_globals.mutex);
+
+    if (avmd_globals.settings.outbound_channnel == 1) {
+        if (SWITCH_CALL_DIRECTION_OUTBOUND != switch_channel_direction(channel)) {
+                   switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
+                           "Channel [%s] is not outbound!\n", switch_channel_get_name(channel));
+        } else {
+            flags |= SMBF_READ_REPLACE;
+        }
+    } else if (avmd_globals.settings.inbound_channnel == 1) {
+        if (SWITCH_CALL_DIRECTION_INBOUND != switch_channel_direction(channel)) {
+                   switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
+                           "Channel [%s] is not inbound!\n", switch_channel_get_name(channel));
+        } else {
+            flags |= SMBF_WRITE_REPLACE;
+        }
     } else {
-        flags |= SMBF_WRITE_REPLACE;
-    }
-#endif
-    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));
-        return;
+        goto end;
     }
 
 
-#ifdef AVMD_OUTBOUND_CHANNEL
-    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));
-        return;
+    if (avmd_globals.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));
+            goto end;
+        }
     }
-#endif
 
        /* 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);
+       status = init_avmd_session_data(avmd_session, session, NULL);
     if (status != SWITCH_STATUS_SUCCESS) {
         switch (status) {
             case SWITCH_STATUS_MEMERR:
@@ -605,7 +900,7 @@ SWITCH_STANDARD_APP(avmd_start_app)
                 break;
 
         }
-               return;
+        goto end;
     }
 
        /* 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) {
         switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
                        SWITCH_LOG_ERROR, "Failed to add media bug!\n");
-               return;
+        goto end;
        }
 
        /* 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,
             "Avmd on channel [%s] started!\n", switch_channel_get_name(channel));
 #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_media_bug_t  *bug;
@@ -691,9 +984,6 @@ SWITCH_STANDARD_APP(avmd_stop_app)
 
 /*! \brief FreeSWITCH application handler function.
  *  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)
 {
@@ -730,36 +1020,35 @@ SWITCH_STANDARD_APP(avmd_start_function)
     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)
 {
-#ifdef AVMD_FAST_MATH
        int res;
-#endif
 
-    avmd_unregister_all_events();
+    switch_mutex_lock(avmd_globals.mutex);
 
-#ifdef AVMD_FAST_MATH
-       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");
-                break;
-            case -2:
-                   switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
-                           "Failed closing arc cosine table\n");
+    avmd_unregister_all_events();
+       
+    if (avmd_globals.settings.fast_math == 1) {
+           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");
+                    break;
+                case -2:
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+                               "Failed closing arc cosine table\n");
+                    break;
+                default:
                 break;
-            default:
-            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,
                "Advanced voicemail detection disabled\n");
@@ -771,23 +1060,21 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown)
  *  This function handles API calls such as the ones
  *  from mod_event_socket and in some cases
  *  scripts such as LUA scripts.
- *
- *  @author Eric des Courtis
- *  @return The success or failure of the function.
  */
 SWITCH_STANDARD_API(avmd_api_main)
 {
        switch_media_bug_t  *bug;
        avmd_session_t      *avmd_session;
        switch_channel_t    *channel;
-       int     argc;
-       char    *argv[AVMD_PARAMS];
-       char    *ccmd = NULL;
-       char    *uuid, *uuid_dup;
-       char    *command;
-    switch_core_media_flag_t flags = 0;
-       switch_status_t status = SWITCH_STATUS_SUCCESS;
-       switch_core_session_t   *fs_session = NULL;
+    int         argc;
+    const char  *uuid, *uuid_dup;
+    const char  *command;
+    char        *dupped = NULL, *argv[AVMD_PARAMS_MAX + 1] = { 0 };
+    switch_core_media_flag_t    flags = 0;
+    switch_status_t             status = SWITCH_STATUS_SUCCESS;
+    switch_core_session_t       *fs_session = NULL;
+
+    switch_mutex_lock(avmd_globals.mutex);
 
        /* No command? Display usage */
        if (zstr(cmd)) {
@@ -797,18 +1084,122 @@ SWITCH_STANDARD_API(avmd_api_main)
        }
 
        /* Duplicated contents of original string */
-       ccmd = strdup(cmd);
+       dupped = strdup(cmd);
+       switch_assert(dupped);
        /* 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
        * display usage */
-       if (argc != AVMD_PARAMS) {
-               stream->write_function(stream, "-ERR, avmd takes [%u] parameters!\n"
-                "-USAGE: %s\n\n", AVMD_PARAMS, AVMD_SYNTAX);
+       if (argc < AVMD_PARAMS_MIN) {
+               stream->write_function(stream, "-ERR, avmd takes [%u] min and [%u] max parameters!\n"
+                "-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;
+    }
+
        uuid = argv[0];
        command = argv[1];
 
@@ -843,22 +1234,21 @@ SWITCH_STANDARD_API(avmd_api_main)
                        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);
-#ifdef AVMD_REPORT_STATUS
-                       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));
-#endif
+            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));
+            }
                        goto end;
                }
-
-#ifdef AVMD_REPORT_STATUS
-               /* 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);
-#endif
+        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;
        }
 
@@ -872,27 +1262,25 @@ SWITCH_STANDARD_API(avmd_api_main)
         goto end;
     }
 
-#ifdef AVMD_OUTBOUND_CHANNEL
-    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_WARNING,
-                       "Channel [%s] is not outbound!\n", switch_channel_get_name(channel));
-    } else {
-        flags |= SMBF_READ_REPLACE;
-    }
-#endif
-#ifdef AVMD_INBOUND_CHANNEL
-    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_WARNING,
-                       "Channel [%s] is not inbound!\n", switch_channel_get_name(channel));
+    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_WARNING,
+                           "Channel [%s] is not outbound!\n", switch_channel_get_name(channel));
+        } else {
+            flags |= SMBF_READ_REPLACE;
+        }
+    } else 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_WARNING,
+                           "Channel [%s] is not inbound!\n", switch_channel_get_name(channel));
+        } else {
+            flags |= SMBF_WRITE_REPLACE;
+        }
     } else {
-        flags |= SMBF_WRITE_REPLACE;
-    }
-#endif
-    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);
@@ -902,17 +1290,17 @@ SWITCH_STANDARD_API(avmd_api_main)
     }
 
 
-#ifdef AVMD_OUTBOUND_CHANNEL
-    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));
-        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));
+            goto end;
+        }
     }
-#endif
 
        /* If we don't see the expected start exit */
        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 */
     avmd_session = (avmd_session_t *) switch_core_session_alloc(
                                             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) {
                stream->write_function(stream, "-ERR, failed to initialize avmd session\n"
                 " for FreeSWITCH session [%s]\n", uuid);
@@ -985,27 +1373,27 @@ SWITCH_STANDARD_API(avmd_api_main)
 
        /* OK */
     avmd_fire_event(AVMD_EVENT_SESSION_START, fs_session, 0, 0);
-#ifdef AVMD_REPORT_STATUS
-       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);
-#endif
+    if (avmd_globals.settings.report_status == 1) {
+           stream->write_function(stream, "+OK\n [%s] [%s] started!\n\n",
+                uuid, switch_channel_get_name(channel));
+        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fs_session), SWITCH_LOG_INFO,
+                "Avmd on channel [%s] started!\n", switch_channel_get_name(channel));
+        switch_assert(status == SWITCH_STATUS_SUCCESS);
+    }
 end:
 
        if (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;
 }
 
 /*! \brief Process one frame of data with avmd algorithm.
- * @author Eric des Courtis
- * @par Modifications: Piotr Gregor
  * @param session An avmd session.
  * @param frame An audio frame.
  */
@@ -1088,17 +1476,20 @@ static void avmd_process(avmd_session_t *s, switch_frame_t *frame)
                 }
 
                 /* saturate */
-                if (omega < -0.9999)
+                if (omega < -0.9999) {
                     omega = -0.9999;
-                if (omega > 0.9999)
+                }
+                if (omega > 0.9999) {
                     omega = 0.9999;
+                }
 
                 /* append */
                                APPEND_SMA_VAL(&s->sma_b, omega);
                                APPEND_SMA_VAL(&s->sqa_b, omega * omega);
 #ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
-                if (s->samples_streak > 0)
+                if (s->samples_streak > 0) {
                     --s->samples_streak;
+                }
 #endif
                                /* calculate variance (biased estimator) */
                                v = s->sqa_b.sma - (s->sma_b.sma * s->sma_b.sma);
@@ -1171,6 +1562,13 @@ done:
     return;
 }
 
+static void
+avmd_reloadxml_event_handler(switch_event_t *event)
+{
+    avmd_load_xml_configuration(avmd_globals.mutex);
+}
+
+
 /* For Emacs:
  * Local Variables:
  * mode:c
@@ -1181,4 +1579,3 @@ done:
  * For VIM:
  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
  */
-