From b44b6e5b20d93e1fdc7330385c56fa5c37c3eaec Mon Sep 17 00:00:00 2001
From: Piotr Gregor <piotrek.gregor@gmail.com>
Date: Tue, 20 Sep 2016 17:49:07 +0100
Subject: [PATCH] FS-9564 [avmd]: add lagged detectors

Addition of detectors which skip first few frames
of audio before they start to process it helps
to properly handle some Verizon voicemails.
The result of avmd test using this commit is
OK. All PASS [100]

Thi scommit also resolves:
FS-9588 Add script for outbound avmdy
FS-9589 Add resolution info to events
---
 conf/vanilla/autoload_configs/avmd.conf.xml   |   4 +-
 .../conf/autoload_configs/avmd.conf.xml       |   4 +-
 .../mod_avmd/conf/avmd_test_dialplan.xml      |  70 +++++-
 src/mod/applications/mod_avmd/mod_avmd.c      | 199 +++++++++++++-----
 .../mod_avmd/scripts/avmd_originate.pl        |   5 +-
 .../scripts/avmd_originate_multiple.pl        |  87 ++++++++
 .../mod_avmd/scripts/avmd_test.pl             |  31 ++-
 7 files changed, 328 insertions(+), 72 deletions(-)
 create mode 100644 src/mod/applications/mod_avmd/scripts/avmd_originate_multiple.pl

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