2010-05-25 15:03:14 -04:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
* Copyright ( C ) 2010 , Eric des Courtis < eric . des . courtis @ benbria . com >
*
* Version : MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* Eric des Courtis < eric . des . courtis @ benbria . com >
* Copyright ( C ) Benbria . All Rights Reserved .
*
* Contributor ( s ) :
*
* Eric des Courtis < eric . des . courtis @ benbria . com >
2016-04-23 00:01:11 +01:00
* Piotr Gregor < piotrek . gregor gmail . com > :
2010-05-25 15:03:14 -04:00
*
* mod_avmd . c - - Advanced Voicemail Detection Module
*
2016-04-05 14:53:01 +01:00
* This module detects single frequency tones ( used in voicemail to denote
* the moment caller ' s voice is started to be recorded , aka . beep sounds ,
* beeps ) using modified DESA - 2 algorithm .
2010-05-25 15:03:14 -04:00
*/
# include <switch.h>
2016-03-27 20:39:53 +01:00
# include <g711.h>
2010-05-25 15:03:14 -04:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <math.h>
# ifdef WIN32
# include <float.h>
# define ISNAN(x) (!!(_isnan(x)))
2016-05-12 01:09:12 +01:00
# define ISINF(x) (isinf(x))
2010-05-25 15:03:14 -04:00
# else
2016-05-12 01:09:12 +01:00
int __isnan ( double ) ;
# define ISNAN(x) (__isnan(x))
# define ISINF(x) (__isinf(x))
2010-05-25 15:03:14 -04:00
# endif
2016-03-20 23:58:45 +00:00
2016-03-29 20:53:31 +01:00
# include "avmd_buffer.h"
2016-03-27 20:39:53 +01:00
# include "avmd_desa2_tweaked.h"
2016-03-29 20:53:31 +01:00
# include "avmd_sma_buf.h"
# include "avmd_options.h"
2016-03-20 23:58:45 +00:00
2016-03-29 20:53:31 +01:00
# include "avmd_fast_acosf.h"
2016-03-20 23:58:45 +00:00
2010-05-25 15:03:14 -04:00
/*! Calculate how many audio samples per ms based on the rate */
# define SAMPLES_PER_MS(r, m) ((r) / (1000 / (m)))
/*! Minimum beep length */
2016-03-27 20:39:53 +01:00
# define BEEP_TIME (2)
2016-04-09 19:50:41 +01:00
/*! How often to evaluate the output of DESA-2 in ms */
2016-03-27 20:39:53 +01:00
# define SINE_TIME (2*0.125)
2016-04-09 19:50:41 +01:00
/*! How long in samples does DESA-2 results get evaluated */
2010-05-25 15:03:14 -04:00
# define SINE_LEN(r) SAMPLES_PER_MS((r), SINE_TIME)
/*! How long in samples is the minimum beep length */
# define BEEP_LEN(r) SAMPLES_PER_MS((r), BEEP_TIME)
2016-04-09 19:50:41 +01:00
/*! Number of points in DESA-2 sample */
2010-05-25 15:03:14 -04:00
# define P (5)
/*! Guesstimate frame length in ms */
# define FRAME_TIME (20)
/*! Length in samples of the frame (guesstimate) */
# define FRAME_LEN(r) SAMPLES_PER_MS((r), FRAME_TIME)
/*! Conversion to Hertz */
# define TO_HZ(r, f) (((r) * (f)) / (2.0 * M_PI))
/*! Minimum beep frequency in Hertz */
# define MIN_FREQUENCY (300.0)
2016-02-22 18:26:57 +00:00
/*! Minimum frequency as digital normalized frequency */
2012-04-09 12:31:48 -05:00
# define MIN_FREQUENCY_R(r) ((2.0 * M_PI * MIN_FREQUENCY) / (r))
2016-02-22 18:26:57 +00:00
/*!
* Maximum beep frequency in Hertz
* Note : The maximum frequency the DESA - 2 algorithm can uniquely
* identify is 0.25 of the sampling rate . All the frequencies
* below that level are detected unambiguously . This means 2 kHz
* for 8 kHz audio . All the frequencies above 0.25 sampling rate
2016-04-10 23:00:19 +01:00
* will be aliased to frequencies below that threshold ,
* i . e . OMEGA > PI / 2 will be aliased to PI - OMEGA .
2016-02-22 18:26:57 +00:00
* This is not a problem here as we are interested in detection
2016-04-09 19:50:41 +01:00
* of any constant amplitude and frequency sine wave instead
2016-04-07 15:56:49 +01:00
* of detection of particular frequency .
2016-04-10 23:00:19 +01:00
* In case of DESA - 1 , frequencies up to 0.5 sampling rate are
* identified uniquely .
2016-02-22 18:26:57 +00:00
*/
2012-04-09 12:31:48 -05:00
# define MAX_FREQUENCY (2500.0)
2016-02-22 18:26:57 +00:00
/*! Maximum frequency as digital normalized frequency */
2012-04-09 12:31:48 -05:00
# define MAX_FREQUENCY_R(r) ((2.0 * M_PI * MAX_FREQUENCY) / (r))
/* decrease this value to eliminate false positives */
2016-03-27 20:39:53 +01:00
# define VARIANCE_THRESHOLD (0.00025)
2010-05-25 15:03:14 -04:00
/*! Syntax of the API call. */
2016-05-03 13:30:03 +01:00
# define AVMD_SYNTAX "<uuid> < start | stop | set [inbound|outbound|default] | load [inbound|outbound] | reload | show >"
2010-05-25 15:03:14 -04:00
/*! Number of expected parameters in api call. */
2016-05-05 18:39:58 +01:00
# define AVMD_PARAMS_API_MIN 1u
# define AVMD_PARAMS_API_MAX 2u
# define AVMD_PARAMS_APP_MAX 30u
# define AVMD_PARAMS_APP_START_MIN 0u
# define AVMD_PARAMS_APP_START_MAX 20u
2010-05-25 15:03:14 -04:00
2016-05-03 13:30:03 +01:00
/* don't forget to update avmd_events_str table
* if you modify this */
2016-04-21 00:05:23 +01:00
enum avmd_event
{
AVMD_EVENT_BEEP = 0 ,
AVMD_EVENT_SESSION_START = 1 ,
AVMD_EVENT_SESSION_STOP = 2
} ;
2016-04-23 00:01:11 +01:00
/* This array MUST be NULL terminated! */
2016-04-21 00:05:23 +01:00
const char * avmd_events_str [ ] = { [ AVMD_EVENT_BEEP ] = " avmd::beep " ,
[ AVMD_EVENT_SESSION_START ] = " avmd::start " ,
[ AVMD_EVENT_SESSION_STOP ] = " avmd::stop " ,
2016-04-23 00:01:11 +01:00
NULL /* MUST be last and always here */
2016-04-21 00:05:23 +01:00
} ;
2010-05-25 15:03:14 -04:00
2016-04-23 00:01:11 +01:00
# define AVMD_CHAR_BUF_LEN 20u
# define AVMD_BUF_LINEAR_LEN 160u
2016-03-27 20:39:53 +01:00
2016-05-05 18:39:58 +01:00
enum avmd_app
{
AVMD_APP_START_APP = 0 ,
AVMD_APP_STOP_APP = 1 ,
AVMD_APP_START_FUNCTION = 2 /* deprecated since version 1.6.8 */
} ;
2010-05-25 15:03:14 -04:00
/* Prototypes */
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_avmd_shutdown ) ;
SWITCH_MODULE_LOAD_FUNCTION ( mod_avmd_load ) ;
2016-02-21 15:16:55 +00:00
SWITCH_MODULE_DEFINITION ( mod_avmd , mod_avmd_load , mod_avmd_shutdown , NULL ) ;
2016-04-05 14:53:01 +01:00
SWITCH_STANDARD_API ( avmd_api_main ) ;
2016-04-10 23:00:19 +01:00
SWITCH_STANDARD_APP ( avmd_start_app ) ;
SWITCH_STANDARD_APP ( avmd_stop_app ) ;
2010-05-25 15:03:14 -04:00
SWITCH_STANDARD_APP ( avmd_start_function ) ;
2016-04-23 00:01:11 +01:00
struct avmd_settings {
uint8_t debug ;
uint8_t report_status ;
uint8_t fast_math ;
uint8_t require_continuous_streak ;
2016-05-03 13:30:03 +01:00
uint16_t sample_n_continuous_streak ;
2016-05-30 21:05:22 +01:00
uint16_t sample_n_to_skip ;
2016-04-23 00:01:11 +01:00
uint8_t simplified_estimation ;
uint8_t inbound_channnel ;
uint8_t outbound_channnel ;
} ;
2010-05-25 15:03:14 -04:00
/*! Status of the beep detection */
typedef enum {
2014-01-02 17:51:09 -06:00
BEEP_DETECTED ,
BEEP_NOTDETECTED
2010-05-25 15:03:14 -04:00
} avmd_beep_state_t ;
/*! Data related to the current status of the beep */
typedef struct {
2014-01-02 17:51:09 -06:00
avmd_beep_state_t beep_state ;
size_t last_beep ;
2010-05-25 15:03:14 -04:00
} avmd_state_t ;
/*! Type that holds session information pertinent to the avmd module. */
typedef struct {
2014-01-02 17:51:09 -06:00
/*! Internal FreeSWITCH session. */
2016-04-23 00:01:11 +01:00
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 ;
2014-01-02 17:51:09 -06:00
/* freq_table_t ft; */
avmd_state_t state ;
2014-07-09 08:25:54 -05:00
switch_time_t start_time ;
2016-06-04 21:52:04 +01:00
size_t samples_streak ; /* number of DESA samples in single streak without reset needed to validate SMA estimator */
2016-03-27 20:39:53 +01:00
size_t sample_count ;
2010-05-25 15:03:14 -04:00
} avmd_session_t ;
2016-04-23 00:01:11 +01:00
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 ) ;
2016-04-21 00:05:23 +01:00
2016-06-04 21:52:04 +01:00
static switch_bool_t avmd_callback ( switch_media_bug_t * bug , void * user_data , switch_abc_type_t type ) ;
static switch_status_t avmd_register_all_events ( void ) ;
2016-04-21 00:05:23 +01:00
2016-06-04 21:52:04 +01:00
static void avmd_unregister_all_events ( void ) ;
2016-04-21 00:05:23 +01:00
static void
2016-06-04 21:52:04 +01:00
avmd_fire_event ( enum avmd_event type , switch_core_session_t * fs_s , double freq , double v , avmd_beep_state_t beep_status , uint8_t info ) ;
2010-05-25 15:03:14 -04:00
2016-04-23 00:01:11 +01:00
/* 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 ) ;
2016-05-03 13:30:03 +01:00
/* bind reloadxml callback */
2016-04-23 00:01:11 +01:00
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 ) ;
2016-05-05 18:39:58 +01:00
/*! \brief The avmd session data initialization function.
* @ param avmd_session A reference to a avmd session .
* @ param fs_session A reference to a FreeSWITCH session .
* @ details Avmd globals mutex must be locked .
2010-05-25 15:03:14 -04:00
*/
2016-04-09 19:50:41 +01:00
static switch_status_t
2016-06-04 21:52:04 +01:00
init_avmd_session_data ( avmd_session_t * avmd_session , switch_core_session_t * fs_session , switch_mutex_t * mutex )
2010-05-25 15:03:14 -04:00
{
2016-04-23 00:01:11 +01:00
size_t buf_sz ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
if ( mutex ! = NULL )
{
switch_mutex_lock ( mutex ) ;
}
2016-04-07 00:17:21 +01:00
/*! This is a worst case sample rate estimate */
avmd_session - > rate = 48000 ;
2016-06-04 21:52:04 +01:00
INIT_CIRC_BUFFER ( & avmd_session - > b , ( size_t ) BEEP_LEN ( avmd_session - > rate ) , ( size_t ) FRAME_LEN ( avmd_session - > rate ) , fs_session ) ;
2016-04-06 23:01:34 +01:00
if ( avmd_session - > b . buf = = NULL ) {
2016-04-23 00:01:11 +01:00
status = SWITCH_STATUS_MEMERR ;
goto end ;
2016-04-06 23:01:34 +01:00
}
2014-01-02 17:51:09 -06:00
avmd_session - > session = fs_session ;
avmd_session - > pos = 0 ;
avmd_session - > f = 0.0 ;
avmd_session - > state . last_beep = 0 ;
avmd_session - > state . beep_state = BEEP_NOTDETECTED ;
2016-06-04 21:52:04 +01:00
avmd_session - > samples_streak = 0 ;
2016-05-05 18:39:58 +01:00
memcpy ( & avmd_session - > settings , & avmd_globals . settings , sizeof ( struct avmd_settings ) ) ;
2016-06-04 21:52:04 +01:00
switch_mutex_init ( & avmd_session - > mutex , SWITCH_MUTEX_DEFAULT , switch_core_session_get_pool ( fs_session ) ) ;
2016-03-27 20:39:53 +01:00
avmd_session - > sample_count = 0 ;
2016-04-07 00:17:21 +01:00
2016-04-07 15:56:49 +01:00
buf_sz = BEEP_LEN ( ( uint32_t ) avmd_session - > rate ) / ( uint32_t ) SINE_LEN ( avmd_session - > rate ) ;
2016-04-07 00:17:21 +01:00
if ( buf_sz < 1 ) {
2016-04-23 00:01:11 +01:00
status = SWITCH_STATUS_MORE_DATA ;
goto end ;
2016-04-07 00:17:21 +01:00
}
INIT_SMA_BUFFER ( & avmd_session - > sma_b , buf_sz , fs_session ) ;
if ( avmd_session - > sma_b . data = = NULL ) {
2016-04-23 00:01:11 +01:00
status = SWITCH_STATUS_FALSE ;
goto end ;
2016-04-07 00:17:21 +01:00
}
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 ) {
2016-04-23 00:01:11 +01:00
status = SWITCH_STATUS_FALSE ;
goto end ;
2016-04-07 00:17:21 +01:00
}
memset ( avmd_session - > sqa_b . data , 0 , sizeof ( BUFF_TYPE ) * buf_sz ) ;
2016-04-23 00:01:11 +01:00
end :
if ( mutex ! = NULL )
{
switch_mutex_unlock ( mutex ) ;
}
return status ;
2010-05-25 15:03:14 -04:00
}
2016-02-04 23:14:19 +00:00
/*! \brief The callback function that is called when new audio data becomes available.
2010-05-25 15:03:14 -04:00
* @ param bug A reference to the media bug .
* @ param user_data The session information for this call .
* @ param type The switch callback type .
* @ return The success or failure of the function .
*/
2016-06-04 21:52:04 +01:00
static switch_bool_t
avmd_callback ( switch_media_bug_t * bug , void * user_data , switch_abc_type_t type )
2010-05-25 15:03:14 -04:00
{
2016-04-04 02:31:46 +01:00
avmd_session_t * avmd_session ;
switch_codec_t * read_codec ;
2016-04-06 16:12:39 +01:00
switch_codec_t * write_codec ;
2016-04-04 02:31:46 +01:00
switch_frame_t * frame ;
switch_core_session_t * fs_session ;
2014-01-02 17:51:09 -06:00
avmd_session = ( avmd_session_t * ) user_data ;
if ( avmd_session = = NULL ) {
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " No avmd session assigned! \n " ) ;
2016-04-04 02:31:46 +01:00
return SWITCH_FALSE ;
}
2016-06-04 21:52:04 +01:00
if ( type ! = SWITCH_ABC_TYPE_INIT ) {
switch_mutex_lock ( avmd_session - > mutex ) ;
}
2016-04-04 02:31:46 +01:00
fs_session = avmd_session - > session ;
if ( fs_session = = NULL ) {
2016-06-04 21:52:04 +01:00
if ( type ! = SWITCH_ABC_TYPE_INIT ) {
switch_mutex_lock ( avmd_session - > mutex ) ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " No FreeSWITCH session assigned! \n " ) ;
2014-01-02 17:51:09 -06:00
return SWITCH_FALSE ;
}
switch ( type ) {
case SWITCH_ABC_TYPE_INIT :
2016-06-04 21:52:04 +01:00
if ( avmd_session - > settings . outbound_channnel = = 1 ) {
read_codec = switch_core_session_get_read_codec ( fs_session ) ;
if ( read_codec = = NULL ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) , SWITCH_LOG_WARNING , " No read codec assigned, default session rate to 8000 samples/s \n " ) ;
avmd_session - > rate = 8000 ;
2016-04-04 02:31:46 +01:00
} else {
2016-06-04 21:52:04 +01:00
if ( read_codec - > implementation = = NULL ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) , SWITCH_LOG_WARNING , " No read codec implementation assigned, default session rate to 8000 samples/s \n " ) ;
avmd_session - > rate = 8000 ;
} else {
avmd_session - > rate = read_codec - > implementation - > samples_per_second ;
}
2016-04-04 02:31:46 +01:00
}
}
2016-06-04 21:52:04 +01:00
if ( avmd_session - > settings . inbound_channnel = = 1 ) {
write_codec = switch_core_session_get_write_codec ( fs_session ) ;
if ( write_codec = = NULL ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) , SWITCH_LOG_WARNING , " No write codec assigned, default session rate to 8000 samples/s \n " ) ;
avmd_session - > rate = 8000 ;
2016-04-06 16:12:39 +01:00
} else {
2016-06-04 21:52:04 +01:00
if ( write_codec - > implementation = = NULL ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) , SWITCH_LOG_WARNING , " No write codec implementation assigned, default session rate to 8000 samples/s \n " ) ;
avmd_session - > rate = 8000 ;
} else {
avmd_session - > rate = write_codec - > implementation - > samples_per_second ;
}
2016-04-06 16:12:39 +01:00
}
}
2014-07-09 08:25:54 -05:00
avmd_session - > start_time = switch_micro_time_now ( ) ;
2016-03-27 20:39:53 +01:00
/* avmd_session->vmd_codec.channels =
* read_codec - > implementation - > number_of_channels ; */
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) , SWITCH_LOG_INFO , " Avmd session initialized, [%u] samples/s \n " , avmd_session - > rate ) ;
2014-01-02 17:51:09 -06:00
break ;
case SWITCH_ABC_TYPE_READ_REPLACE :
frame = switch_core_media_bug_get_read_replace_frame ( bug ) ;
avmd_process ( avmd_session , frame ) ;
2016-06-04 21:52:04 +01:00
break ;
2014-01-02 17:51:09 -06:00
case SWITCH_ABC_TYPE_WRITE_REPLACE :
2016-03-28 01:46:02 +01:00
frame = switch_core_media_bug_get_write_replace_frame ( bug ) ;
avmd_process ( avmd_session , frame ) ;
2016-06-04 21:52:04 +01:00
break ;
2015-04-22 16:06:43 -07:00
default :
break ;
2014-01-02 17:51:09 -06:00
}
2016-06-04 21:52:04 +01:00
if ( type ! = SWITCH_ABC_TYPE_INIT ) {
switch_mutex_unlock ( avmd_session - > mutex ) ;
}
2014-01-02 17:51:09 -06:00
return SWITCH_TRUE ;
2010-05-25 15:03:14 -04:00
}
2016-04-21 00:05:23 +01:00
static switch_status_t
avmd_register_all_events ( void )
{
size_t idx = 0 ;
const char * e = avmd_events_str [ 0 ] ;
while ( e ! = NULL )
{
if ( switch_event_reserve_subclass ( e ) ! = SWITCH_STATUS_SUCCESS ) {
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't register subclass [%s]! \n " , e ) ;
2016-04-21 00:05:23 +01:00
return SWITCH_STATUS_TERM ;
}
+ + idx ;
e = avmd_events_str [ idx ] ;
}
return SWITCH_STATUS_SUCCESS ;
}
static void
avmd_unregister_all_events ( void )
{
size_t idx = 0 ;
const char * e = avmd_events_str [ 0 ] ;
while ( e ! = NULL )
{
switch_event_free_subclass ( e ) ;
+ + idx ;
e = avmd_events_str [ idx ] ;
}
return ;
}
static void
2016-06-04 21:52:04 +01:00
avmd_fire_event ( enum avmd_event type , switch_core_session_t * fs_s , double freq , double v , avmd_beep_state_t beep_status , uint8_t info )
2016-04-21 00:05:23 +01:00
{
int res ;
switch_event_t * event ;
switch_status_t status ;
switch_event_t * event_copy ;
char buf [ AVMD_CHAR_BUF_LEN ] ;
2016-06-04 21:52:04 +01:00
status = switch_event_create_subclass ( & event , SWITCH_EVENT_CUSTOM , avmd_events_str [ type ] ) ;
2016-04-23 00:01:11 +01:00
if ( status ! = SWITCH_STATUS_SUCCESS ) {
2016-04-21 00:05:23 +01:00
return ;
2016-04-23 00:01:11 +01:00
}
2016-06-04 21:52:04 +01:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Unique-ID " , switch_core_session_get_uuid ( fs_s ) ) ;
2016-04-21 00:05:23 +01:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " call-command " , " avmd " ) ;
switch ( type )
{
case AVMD_EVENT_BEEP :
2016-06-04 21:52:04 +01:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Beep-Status " , " DETECTED " ) ;
2016-04-21 00:05:23 +01:00
res = snprintf ( buf , AVMD_CHAR_BUF_LEN , " %f " , freq ) ;
if ( res < 0 | | res > AVMD_CHAR_BUF_LEN - 1 ) {
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_s ) , SWITCH_LOG_ERROR , " Frequency truncated [%s], [%d] attempted! \n " , buf , res ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " frequency " , " ERROR (TRUNCATED) " ) ;
2016-04-21 00:05:23 +01:00
}
2016-06-04 21:52:04 +01:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " frequency " , buf ) ;
2016-04-21 00:05:23 +01:00
res = snprintf ( buf , AVMD_CHAR_BUF_LEN , " %f " , v ) ;
if ( res < 0 | | res > AVMD_CHAR_BUF_LEN - 1 ) {
2016-06-04 21:52:04 +01:00
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 , " variance " , " ERROR (TRUNCATED) " ) ;
2016-04-21 00:05:23 +01:00
}
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " variance " , buf ) ;
break ;
case AVMD_EVENT_SESSION_START :
2016-06-04 21:52:04 +01:00
break ;
2016-04-21 00:05:23 +01:00
case AVMD_EVENT_SESSION_STOP :
2016-06-04 21:52:04 +01:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Beep-Status " , beep_status = = BEEP_DETECTED ? " DETECTED " : " NOTDETECTED " ) ;
if ( info = = 0 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_s ) , SWITCH_LOG_ERROR , " Error, avmd session object not found in media bug! \n " ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " stop-status " , " ERROR (AVMD SESSION OBJECT NOT FOUND IN MEDIA BUG) " ) ;
}
2016-04-21 00:05:23 +01:00
break ;
default :
switch_event_destroy ( & event ) ;
return ;
}
2016-04-23 00:01:11 +01:00
if ( ( switch_event_dup ( & event_copy , event ) ) ! = SWITCH_STATUS_SUCCESS ) {
2016-04-21 00:05:23 +01:00
return ;
2016-04-23 00:01:11 +01:00
}
2016-04-21 00:05:23 +01:00
switch_core_session_queue_event ( fs_s , & event ) ;
switch_event_fire ( & event_copy ) ;
return ;
}
2016-04-23 00:01:11 +01:00
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 ;
}
2016-04-29 18:23:33 +01:00
* output = ( uint8_t ) helper ;
2016-04-23 00:01:11 +01:00
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 ;
}
2016-04-29 18:23:33 +01:00
* output = ( uint16_t ) helper ;
2016-04-23 00:01:11 +01:00
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 ;
2016-05-03 13:30:03 +01:00
avmd_globals . settings . sample_n_continuous_streak = 15 ;
2016-05-30 21:05:22 +01:00
avmd_globals . settings . sample_n_to_skip = 6 ;
2016-04-23 00:01:11 +01:00
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 ;
2016-05-03 13:30:03 +01:00
} else if ( ! strcmp ( name , " sample_n_continuous_streak " ) ) {
if ( avmd_parse_u16_user_input ( value ,
& avmd_globals . settings . sample_n_continuous_streak , 0 , UINT16_MAX ) = = - 1 )
{
status = SWITCH_STATUS_TERM ;
goto done ;
}
2016-05-30 21:05:22 +01:00
} else if ( ! strcmp ( name , " sample_n_to_skip " ) ) {
2016-05-03 13:30:03 +01:00
if ( avmd_parse_u16_user_input ( value ,
2016-05-30 21:05:22 +01:00
& avmd_globals . settings . sample_n_to_skip , 0 , UINT16_MAX ) = = - 1 )
2016-04-23 00:01:11 +01:00
{
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 " ) ;
2016-05-30 21:05:22 +01:00
stream - > write_function ( stream , " debug \t %u \n " , avmd_globals . settings . debug ) ;
stream - > write_function ( stream , " report status \t %u \n " , avmd_globals . settings . report_status ) ;
stream - > write_function ( stream , " fast_math \t %u \n " , avmd_globals . settings . fast_math ) ;
stream - > write_function ( stream , " require continuous streak \t %u \n " , avmd_globals . settings . require_continuous_streak ) ;
2016-05-03 13:30:03 +01:00
stream - > write_function ( stream , " sample n continuous streak \t %u \n " , avmd_globals . settings . sample_n_continuous_streak ) ;
2016-05-30 21:05:22 +01:00
stream - > write_function ( stream , " sample n to skip \t %u \n " , avmd_globals . settings . sample_n_to_skip ) ;
stream - > write_function ( stream , " simplified estimation \t %u \n " , avmd_globals . settings . simplified_estimation ) ;
stream - > write_function ( stream , " inbound channel \t %u \n " , avmd_globals . settings . inbound_channnel ) ;
stream - > write_function ( stream , " outbound channel \t %u \n " , avmd_globals . settings . outbound_channnel ) ;
2016-04-23 00:01:11 +01:00
stream - > write_function ( stream , " \n \n " ) ;
if ( mutex ! = NULL ) {
switch_mutex_unlock ( mutex ) ;
}
}
2010-05-25 15:03:14 -04:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_avmd_load )
{
2016-04-29 18:23:33 +01:00
# ifndef WIN32
2016-02-21 15:16:55 +00:00
char err [ 150 ] ;
int ret ;
2016-04-29 18:23:33 +01:00
# endif
2010-05-25 15:03:14 -04:00
2014-01-02 17:51:09 -06:00
switch_application_interface_t * app_interface ;
switch_api_interface_t * api_interface ;
/* connect my internal structure to the blank pointer passed to me */
* module_interface = switch_loadable_module_create_module_interface ( pool , modname ) ;
2010-05-25 15:03:14 -04:00
2016-04-21 00:05:23 +01:00
if ( avmd_register_all_events ( ) ! = SWITCH_STATUS_SUCCESS ) {
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't register avmd events! \n " ) ;
2016-04-20 14:59:39 +01:00
return SWITCH_STATUS_TERM ;
}
2010-05-25 15:03:14 -04:00
2016-04-23 00:01:11 +01:00
memset ( & avmd_globals , 0 , sizeof ( avmd_globals ) ) ;
if ( pool = = NULL ) {
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " No memory pool assigned! \n " ) ;
2016-04-23 00:01:11 +01:00
return SWITCH_STATUS_TERM ;
}
switch_mutex_init ( & avmd_globals . mutex , SWITCH_MUTEX_DEFAULT , pool ) ;
avmd_globals . pool = pool ;
2016-02-21 15:16:55 +00:00
2016-04-23 00:01:11 +01:00
if ( avmd_load_xml_configuration ( NULL ) ! = SWITCH_STATUS_SUCCESS )
{
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't load XML configuration! Loading default settings \n " ) ;
2016-05-05 18:39:58 +01:00
avmd_set_xml_default_configuration ( NULL ) ;
2016-04-23 00:01:11 +01:00
}
2016-06-04 21:52:04 +01:00
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 " ) ;
2016-04-23 00:01:11 +01:00
/* Not so severe to prevent further loading, well - it depends, anyway */
}
2016-04-29 18:23:33 +01:00
# ifndef WIN32
2016-04-23 00:01:11 +01:00
if ( avmd_globals . settings . fast_math = = 1 ) {
ret = init_fast_acosf ( ) ;
if ( ret ! = 0 ) {
strerror_r ( errno , err , 150 ) ;
switch ( ret ) {
case - 1 :
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Can't access file [%s], error [%s] \n " , ACOS_TABLE_FILENAME , err ) ;
2016-04-23 00:01:11 +01:00
break ;
case - 2 :
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error creating file [%s], error [%s] \n " , ACOS_TABLE_FILENAME , err ) ;
2016-04-23 00:01:11 +01:00
break ;
case - 3 :
2016-06-04 21:52:04 +01:00
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 ) ;
2016-04-23 00:01:11 +01:00
break ;
case - 4 :
2016-06-04 21:52:04 +01:00
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 ) ;
2016-04-23 00:01:11 +01:00
break ;
default :
2016-06-04 21:52:04 +01:00
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 ) ;
2016-04-23 00:01:11 +01:00
return SWITCH_STATUS_TERM ;
}
return SWITCH_STATUS_TERM ;
} else
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " Advanced voicemail detection: fast math enabled, arc cosine table is [%s] \n " , ACOS_TABLE_FILENAME ) ;
2016-04-23 00:01:11 +01:00
}
2016-04-29 18:23:33 +01:00
# endif
2010-05-25 15:03:14 -04:00
2016-06-04 21:52:04 +01:00
SWITCH_ADD_APP ( app_interface , " avmd_start " , " Start avmd detection " , " Start avmd detection " , avmd_start_app , " " , SAF_NONE ) ;
SWITCH_ADD_APP ( app_interface , " avmd_stop " , " Stop avmd detection " , " Stop avmd detection " , avmd_stop_app , " " , SAF_NONE ) ;
SWITCH_ADD_APP ( app_interface , " avmd " , " Beep detection " , " Advanced detection of voicemail beeps " , avmd_start_function , AVMD_SYNTAX , SAF_NONE ) ;
2010-05-25 15:03:14 -04:00
2016-06-04 21:52:04 +01:00
SWITCH_ADD_API ( api_interface , " avmd " , " Voicemail beep detection " , avmd_api_main , AVMD_SYNTAX ) ;
2010-05-25 15:03:14 -04:00
2016-04-05 16:10:51 +01:00
switch_console_set_complete ( " add avmd ::console::list_uuid ::[start:stop " ) ;
2016-04-23 00:01:11 +01:00
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 " ) ;
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " Advanced voicemail detection enabled \n " ) ;
2016-04-05 16:10:51 +01:00
2016-06-04 21:52:04 +01:00
return SWITCH_STATUS_SUCCESS ; /* indicate that the module should continue to be loaded */
2010-05-25 15:03:14 -04:00
}
2016-05-05 18:39:58 +01:00
void
avmd_config_dump ( avmd_session_t * s )
{
struct avmd_settings * settings ;
if ( s = = NULL ) return ;
settings = & s - > settings ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_INFO ,
" Avmd dynamic configuration: debug [%u], report_status [%u], fast_math [%u], "
" require_continuous_streak [%u], sample_n_continuous_streak [%u], "
2016-05-30 21:05:22 +01:00
" sample_n_to_skip [%u], simplified_estimation [%u], "
2016-05-05 18:39:58 +01:00
" inbound_channel [%u], outbound_channel [%u] \n " ,
settings - > debug , settings - > report_status , settings - > fast_math ,
settings - > require_continuous_streak , settings - > sample_n_continuous_streak ,
2016-05-30 21:05:22 +01:00
settings - > sample_n_to_skip , settings - > simplified_estimation ,
2016-05-05 18:39:58 +01:00
settings - > inbound_channnel , settings - > outbound_channnel ) ;
return ;
}
static switch_status_t
avmd_parse_cmd_data_one_entry ( char * candidate , struct avmd_settings * settings )
{
char * candidate_parsed [ 3 ] ;
int argc ;
const char * key ;
const char * val ;
if ( settings = = NULL ) return SWITCH_STATUS_TERM ;
if ( candidate = = NULL ) return SWITCH_STATUS_NOOP ;
argc = switch_separate_string ( candidate , ' = ' , candidate_parsed , ( sizeof ( candidate_parsed ) / sizeof ( candidate_parsed [ 0 ] ) ) ) ;
2016-05-30 21:05:22 +01:00
if ( argc > 2 ) { /* currently we accept only option=value syntax */
2016-05-05 18:39:58 +01:00
return SWITCH_STATUS_IGNORE ;
}
/* this may be option parameter if valid */
key = candidate_parsed [ 0 ] ; /* option name */
2016-05-30 21:05:22 +01:00
if ( zstr ( key ) ) { /* empty key */
2016-05-05 18:39:58 +01:00
return SWITCH_STATUS_NOT_INITALIZED ;
}
val = candidate_parsed [ 1 ] ; /* value of the option: whole string starting at 1 past the '=' */
2016-05-30 21:05:22 +01:00
if ( zstr ( val ) ) { /* nothing after "=" found, empty value */
2016-05-05 18:39:58 +01:00
return SWITCH_STATUS_MORE_DATA ;
}
/* candidate string has "=" somewhere in the middle and some value,
* try to find what option it is by comparing at most given number of bytes */
if ( ! strcmp ( key , " debug " ) ) {
2016-06-10 23:13:15 +02:00
settings - > debug = ( uint8_t ) switch_true ( val ) ;
2016-05-05 18:39:58 +01:00
} else if ( ! strcmp ( key , " report_status " ) ) {
2016-06-10 23:13:15 +02:00
settings - > report_status = ( uint8_t ) switch_true ( val ) ;
2016-05-05 18:39:58 +01:00
} else if ( ! strcmp ( key , " fast_math " ) ) {
2016-06-10 23:13:15 +02:00
settings - > fast_math = ( uint8_t ) switch_true ( val ) ;
2016-05-05 18:39:58 +01:00
} else if ( ! strcmp ( key , " require_continuous_streak " ) ) {
2016-06-10 23:13:15 +02:00
settings - > require_continuous_streak = ( uint8_t ) switch_true ( val ) ;
2016-05-05 18:39:58 +01:00
} else if ( ! strcmp ( key , " sample_n_continuous_streak " ) ) {
if ( avmd_parse_u16_user_input ( val , & settings - > sample_n_continuous_streak , 0 , UINT16_MAX ) = = - 1 ) {
return SWITCH_STATUS_FALSE ;
}
2016-05-30 21:05:22 +01:00
} else if ( ! strcmp ( key , " sample_n_to_skip " ) ) {
if ( avmd_parse_u16_user_input ( val , & settings - > sample_n_to_skip , 0 , UINT16_MAX ) = = - 1 ) {
2016-05-05 18:39:58 +01:00
return SWITCH_STATUS_FALSE ;
}
} else if ( ! strcmp ( key , " simplified_estimation " ) ) {
2016-06-10 23:13:15 +02:00
settings - > simplified_estimation = ( uint8_t ) switch_true ( val ) ;
2016-05-05 18:39:58 +01:00
} else if ( ! strcmp ( key , " inbound_channel " ) ) {
2016-06-10 23:13:15 +02:00
settings - > inbound_channnel = ( uint8_t ) switch_true ( val ) ;
2016-05-05 18:39:58 +01:00
} else if ( ! strcmp ( key , " outbound_channel " ) ) {
2016-06-10 23:13:15 +02:00
settings - > outbound_channnel = ( uint8_t ) switch_true ( val ) ;
2016-05-05 18:39:58 +01:00
} else {
return SWITCH_STATUS_NOTFOUND ;
}
return SWITCH_STATUS_SUCCESS ;
}
/* RCU style: reads, copies and then updates only if everything is fine,
* if it returns SWITCH_STATUS_SUCCESS parsing went OK and avmd settings
* are updated accordingly to @ cmd_data , if SWITCH_STATUS_FALSE then
2016-05-30 21:05:22 +01:00
* parsing error occurred and avmd session is left untouched */
2016-05-05 18:39:58 +01:00
static switch_status_t
avmd_parse_cmd_data ( avmd_session_t * s , const char * cmd_data , enum avmd_app app )
{
char * mydata ;
struct avmd_settings settings ;
int argc = 0 , idx ;
char * argv [ AVMD_PARAMS_APP_MAX * 2 ] = { 0 } ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
if ( s = = NULL ) {
return SWITCH_STATUS_NOOP ;
}
if ( zstr ( cmd_data ) ) {
return SWITCH_STATUS_SUCCESS ;
}
/* copy current settings first */
memcpy ( & settings , & s - > settings , sizeof ( struct avmd_settings ) ) ;
switch ( app )
{
case AVMD_APP_START_APP :
/* try to parse settings */
mydata = switch_core_session_strdup ( s - > session , cmd_data ) ;
argc = switch_separate_string ( mydata , ' , ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ;
if ( argc < AVMD_PARAMS_APP_START_MIN | | argc > AVMD_PARAMS_APP_START_MAX ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_ERROR ,
" Syntax Error, avmd_start APP takes [%u] to [%u] parameters \n " ,
AVMD_PARAMS_APP_START_MIN , AVMD_PARAMS_APP_START_MAX ) ;
switch_goto_status ( SWITCH_STATUS_MORE_DATA , fail ) ;
}
/* iterate over params, check if they mean something to us, set */
idx = 0 ;
while ( idx < argc ) {
status = avmd_parse_cmd_data_one_entry ( argv [ idx ] , & settings ) ;
if ( status ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_ERROR ,
" Error parsing option [%d] [%s] \n " , idx + 1 , argv [ idx ] ) ; /* idx + 1 to report option 0 as 1 for users convenience */
switch ( status )
{
case SWITCH_STATUS_TERM :
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_ERROR ,
" NULL settings struct passed to parser \n " ) ;
break ;
case SWITCH_STATUS_NOOP :
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_ERROR ,
" NULL settings string passed to parser \n " ) ;
break ;
case SWITCH_STATUS_IGNORE :
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_ERROR ,
" Syntax error. Currently we accept only option=value syntax \n " ) ;
break ;
case SWITCH_STATUS_NOT_INITALIZED :
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_ERROR ,
" Syntax error. No key specified \n " ) ;
break ;
case SWITCH_STATUS_MORE_DATA :
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_ERROR ,
" Syntax error. No value for the key? Currently we accept only option=value syntax \n " ) ;
break ;
case SWITCH_STATUS_FALSE :
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_ERROR ,
" Bad value for this option \n " ) ;
break ;
case SWITCH_STATUS_NOTFOUND :
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_ERROR ,
" Option not found. Please check option name is correct \n " ) ;
break ;
default :
break ;
}
status = SWITCH_STATUS_FALSE ;
goto fail ;
}
+ + idx ;
}
/* OK */
goto end_copy ;
default :
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_ERROR ,
" There is no app with index [%u] for avmd \n " , app ) ;
switch_goto_status ( SWITCH_STATUS_NOTFOUND , fail ) ;
}
end_copy :
/* commit the change */
memcpy ( & s - > settings , & settings , sizeof ( struct avmd_settings ) ) ;
return SWITCH_STATUS_SUCCESS ;
fail :
return status ;
}
2016-04-10 23:00:19 +01:00
SWITCH_STANDARD_APP ( avmd_start_app )
2010-05-25 15:03:14 -04:00
{
2016-04-09 19:50:41 +01:00
switch_media_bug_t * bug ;
switch_status_t status ;
switch_channel_t * channel ;
avmd_session_t * avmd_session ;
2016-04-10 23:00:19 +01:00
switch_core_media_flag_t flags = 0 ;
2014-01-02 17:51:09 -06:00
2016-04-04 02:31:46 +01:00
if ( session = = NULL ) {
2016-04-10 23:00:19 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR ,
" FreeSWITCH is NULL! Please report to developers \n " ) ;
2014-01-02 17:51:09 -06:00
return ;
2016-04-10 23:00:19 +01:00
}
2014-01-02 17:51:09 -06:00
2016-05-30 21:05:22 +01:00
/* Get current channel of the session to tag the session. This indicates that our module is present
* At this moment this cannot return NULL , it will either succeed or assert failed , but we make ourself secure anyway */
2014-01-02 17:51:09 -06:00
channel = switch_core_session_get_channel ( session ) ;
2016-04-10 23:00:19 +01:00
if ( channel = = NULL ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR ,
" No channel for FreeSWITCH session! Please report this "
" to the developers. \n " ) ;
return ;
}
2014-01-02 17:51:09 -06:00
2016-05-30 21:05:22 +01:00
bug = ( switch_media_bug_t * ) switch_channel_get_private ( channel , " _avmd_ " ) ; /* Is this channel already set? */
if ( bug ! = NULL ) { /* We have already started */
2016-04-10 23:00:19 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) ,
SWITCH_LOG_ERROR , " Avmd already started! \n " ) ;
return ;
2014-01-02 17:51:09 -06:00
}
2016-05-30 21:05:22 +01:00
/* Allocate memory attached to this FreeSWITCH session for use in the callback routine and to store state information */
2016-06-04 21:52:04 +01:00
avmd_session = ( avmd_session_t * ) switch_core_session_alloc ( session , sizeof ( avmd_session_t ) ) ;
2016-04-23 00:01:11 +01:00
if ( avmd_session = = NULL ) {
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Can't allocate memory for avmd session! \n " ) ;
2016-04-23 00:01:11 +01:00
goto end ;
}
2014-01-02 17:51:09 -06:00
2016-05-05 18:39:58 +01:00
status = init_avmd_session_data ( avmd_session , session , NULL ) ;
2016-04-09 19:50:41 +01:00
if ( status ! = SWITCH_STATUS_SUCCESS ) {
switch ( status ) {
case SWITCH_STATUS_MEMERR :
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Failed to init avmd session. Buffer error! \n " ) ;
2016-04-07 02:09:14 +01:00
break ;
2016-04-09 19:50:41 +01:00
case SWITCH_STATUS_MORE_DATA :
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Failed to init avmd session. SMA buffer size is 0! \n " ) ;
2016-04-07 02:09:14 +01:00
break ;
2016-04-09 19:50:41 +01:00
case SWITCH_STATUS_FALSE :
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Failed to init avmd session. SMA buffers error \n " ) ;
2016-04-07 02:09:14 +01:00
break ;
default :
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Failed to init avmd session. Unknown error \n " ) ;
2016-04-07 02:09:14 +01:00
break ;
}
2016-04-23 00:01:11 +01:00
goto end ;
2016-04-07 02:09:14 +01:00
}
2014-01-02 17:51:09 -06:00
2016-05-30 21:05:22 +01:00
switch_mutex_lock ( avmd_session - > mutex ) ;
status = avmd_parse_cmd_data ( avmd_session , data , AVMD_APP_START_APP ) ; /* dynamic configuation */
2016-05-05 18:39:58 +01:00
switch ( status ) {
case SWITCH_STATUS_SUCCESS :
break ;
case SWITCH_STATUS_NOOP :
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Failed to set dynamic parameters for avmd session. Session is NULL! Default settings are loaded \n " ) ;
2016-05-05 18:39:58 +01:00
goto end ;
case SWITCH_STATUS_FALSE :
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Failed to set dynamic parameters for avmd session. Parsing error, please check the parameters passed to this APP. "
2016-05-05 18:39:58 +01:00
" Default settings are loaded \n " ) ;
goto end ;
default :
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Failed to set dynamic parameteres for avmd session. Unknown error. Default settings are loaded \n " ) ;
2016-05-05 18:39:58 +01:00
goto end ;
}
2016-06-04 21:52:04 +01:00
if ( avmd_session - > settings . report_status = = 1 ) { /* report dynamic parameters */
2016-05-05 18:39:58 +01:00
avmd_config_dump ( avmd_session ) ;
}
2016-05-30 21:05:22 +01:00
if ( avmd_session - > settings . outbound_channnel = = 1 ) {
if ( SWITCH_CALL_DIRECTION_OUTBOUND ! = switch_channel_direction ( channel ) ) {
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Channel [%s] is not outbound! \n " , switch_channel_get_name ( channel ) ) ;
2016-05-30 21:05:22 +01:00
goto end ;
} else {
flags | = SMBF_READ_REPLACE ;
}
}
if ( avmd_session - > settings . inbound_channnel = = 1 ) {
if ( SWITCH_CALL_DIRECTION_INBOUND ! = switch_channel_direction ( channel ) ) {
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Channel [%s] is not inbound! \n " , switch_channel_get_name ( channel ) ) ;
2016-05-30 21:05:22 +01:00
goto end ;
} else {
flags | = SMBF_WRITE_REPLACE ;
}
}
if ( flags = = 0 ) {
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Can't set direction for channel [%s] \n " , switch_channel_get_name ( channel ) ) ;
2016-05-30 21:05:22 +01:00
goto end ;
}
if ( avmd_session - > settings . outbound_channnel = = 1 ) {
if ( switch_channel_test_flag ( channel , CF_MEDIA_SET ) = = 0 ) {
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Failed to start session. Channel [%s] has no codec assigned yet. "
2016-05-30 21:05:22 +01:00
" Please try again \n " , switch_channel_get_name ( channel ) ) ;
goto end ;
}
}
2016-05-05 18:39:58 +01:00
2016-06-04 21:52:04 +01:00
status = switch_core_media_bug_add ( session , " avmd " , NULL , avmd_callback , avmd_session , 0 , flags , & bug ) ; /* Add a media bug that allows me to intercept the reading leg of the audio stream */
2016-05-30 21:05:22 +01:00
if ( status ! = SWITCH_STATUS_SUCCESS ) { /* If adding a media bug fails exit */
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Failed to add media bug! \n " ) ;
2016-04-23 00:01:11 +01:00
goto end ;
2014-01-02 17:51:09 -06:00
}
2016-05-30 21:05:22 +01:00
switch_channel_set_private ( channel , " _avmd_ " , bug ) ; /* Set the avmd tag to detect an existing avmd media bug */
2016-06-04 21:52:04 +01:00
avmd_fire_event ( AVMD_EVENT_SESSION_START , session , 0 , 0 , 0 , 0 ) ;
2016-05-30 21:05:22 +01:00
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 ) ) ;
}
2016-04-23 00:01:11 +01:00
end :
2016-05-30 21:05:22 +01:00
switch_mutex_unlock ( avmd_session - > mutex ) ;
2016-04-23 00:01:11 +01:00
return ;
2016-04-10 23:00:19 +01:00
}
SWITCH_STANDARD_APP ( avmd_stop_app )
{
switch_media_bug_t * bug ;
switch_channel_t * channel ;
2016-06-04 21:52:04 +01:00
avmd_session_t * avmd_session ;
uint8_t report_status = 0 , avmd_found = 1 ;
avmd_beep_state_t beep_status = BEEP_NOTDETECTED ;
2016-04-10 23:00:19 +01:00
if ( session = = NULL ) {
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " FreeSWITCH is NULL! Please report to developers \n " ) ;
2016-04-10 23:00:19 +01:00
return ;
}
/* Get current channel of the session to tag the session
* This indicates that our module is present
* At this moment this cannot return NULL , it will either
* succeed or assert failed , but we make ourself secure anyway */
channel = switch_core_session_get_channel ( session ) ;
if ( channel = = NULL ) {
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " No channel for FreeSWITCH session! Please report this "
2016-04-10 23:00:19 +01:00
" to the developers. \n " ) ;
return ;
}
/* Is this channel already set? */
bug = ( switch_media_bug_t * ) switch_channel_get_private ( channel , " _avmd_ " ) ;
/* If yes */
if ( bug = = NULL ) {
/* We have not started avmd on this channel */
2016-06-04 21:52:04 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Stop failed - no avmd session running "
2016-04-10 23:00:19 +01:00
" on this channel [%s]! \n " , switch_channel_get_name ( channel ) ) ;
return ;
}
2016-06-04 21:52:04 +01:00
avmd_session = switch_core_media_bug_get_user_data ( bug ) ;
if ( avmd_session = = NULL ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Stop failed - no avmd session object "
" on this channel [%s]! \n " , switch_channel_get_name ( channel ) ) ;
avmd_found = 0 ;
} else {
switch_mutex_lock ( avmd_session - > mutex ) ;
report_status = avmd_session - > settings . report_status ;
beep_status = avmd_session - > state . beep_state ;
switch_mutex_unlock ( avmd_session - > mutex ) ;
}
2016-04-10 23:00:19 +01:00
switch_channel_set_private ( channel , " _avmd_ " , NULL ) ;
switch_core_media_bug_remove ( session , & bug ) ;
2016-06-04 21:52:04 +01:00
if ( avmd_found = = 1 ) {
avmd_fire_event ( AVMD_EVENT_SESSION_STOP , session , 0 , 0 , beep_status , 1 ) ;
} else {
avmd_fire_event ( AVMD_EVENT_SESSION_STOP , session , 0 , 0 , beep_status , 0 ) ;
}
if ( report_status = = 1 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_INFO , " Avmd on channel [%s] stopped, beep status: [%s] \n " ,
switch_channel_get_name ( channel ) , beep_status = = BEEP_DETECTED ? " DETECTED " : " NOTDETECTED " ) ;
}
2016-04-10 23:00:19 +01:00
return ;
}
/*! \brief FreeSWITCH application handler function.
* This handles calls made from applications such as LUA and the dialplan .
*/
SWITCH_STANDARD_APP ( avmd_start_function )
{
switch_media_bug_t * bug ;
switch_channel_t * channel ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING ,
" YOU ARE USING DEPRECATED APP INTERFACE. "
" Please read documentation about new syntax \n " ) ;
if ( session = = NULL ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR ,
" No FreeSWITCH session assigned! \n " ) ;
return ;
}
channel = switch_core_session_get_channel ( session ) ;
/* Is this channel already using avmd ? */
bug = ( switch_media_bug_t * ) switch_channel_get_private ( channel , " _avmd_ " ) ;
/* If it is using avmd */
if ( bug ! = NULL ) {
/* If we have a stop remove audio bug */
if ( strcasecmp ( data , " stop " ) = = 0 ) {
switch_channel_set_private ( channel , " _avmd_ " , NULL ) ;
switch_core_media_bug_remove ( session , & bug ) ;
return ;
}
/* We have already started */
switch_log_printf (
SWITCH_CHANNEL_SESSION_LOG ( session ) ,
SWITCH_LOG_WARNING , " Cannot run 2 at once on the same channel! \n " ) ;
return ;
}
avmd_start_app ( session , NULL ) ;
2010-05-25 15:03:14 -04:00
}
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_avmd_shutdown )
{
2016-04-29 18:23:33 +01:00
# ifndef WIN32
2016-02-21 15:16:55 +00:00
int res ;
2016-04-29 18:23:33 +01:00
# endif
2010-05-25 15:03:14 -04:00
2016-04-23 00:01:11 +01:00
switch_mutex_lock ( avmd_globals . mutex ) ;
2016-04-21 00:05:23 +01:00
2016-04-23 00:01:11 +01:00
avmd_unregister_all_events ( ) ;
2016-04-29 18:23:33 +01:00
# ifndef WIN32
2016-04-23 00:01:11 +01:00
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 :
2016-02-21 15:16:55 +00:00
break ;
2016-04-23 00:01:11 +01:00
}
2016-02-21 15:16:55 +00:00
}
}
2016-04-29 18:23:33 +01:00
# endif
2016-04-23 00:01:11 +01:00
switch_event_unbind_callback ( avmd_reloadxml_event_handler ) ;
switch_mutex_unlock ( avmd_globals . mutex ) ;
2010-05-25 15:03:14 -04:00
2016-04-05 14:53:01 +01:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE ,
2016-04-05 16:10:51 +01:00
" Advanced voicemail detection disabled \n " ) ;
2010-05-25 15:03:14 -04:00
2014-01-02 17:51:09 -06:00
return SWITCH_STATUS_SUCCESS ;
2010-05-25 15:03:14 -04:00
}
/*! \brief FreeSWITCH API handler function.
2016-04-06 16:12:39 +01:00
* This function handles API calls such as the ones
* from mod_event_socket and in some cases
2010-05-25 15:03:14 -04:00
* scripts such as LUA scripts .
*/
SWITCH_STANDARD_API ( avmd_api_main )
{
2016-04-09 19:50:41 +01:00
switch_media_bug_t * bug ;
avmd_session_t * avmd_session ;
switch_channel_t * channel ;
2016-04-23 00:01:11 +01:00
int argc ;
const char * uuid , * uuid_dup ;
const char * command ;
2016-05-05 18:39:58 +01:00
char * dupped = NULL , * argv [ AVMD_PARAMS_API_MAX + 1 ] = { 0 } ;
2016-04-23 00:01:11 +01:00
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 ) ;
2014-01-02 17:51:09 -06:00
/* No command? Display usage */
if ( zstr ( cmd ) ) {
2016-04-04 02:31:46 +01:00
stream - > write_function ( stream , " -ERR, bad command! \n "
" -USAGE: %s \n \n " , AVMD_SYNTAX ) ;
2016-04-09 19:50:41 +01:00
goto end ;
2014-01-02 17:51:09 -06:00
}
/* Duplicated contents of original string */
2016-04-23 00:01:11 +01:00
dupped = strdup ( cmd ) ;
switch_assert ( dupped ) ;
2014-01-02 17:51:09 -06:00
/* Separate the arguments */
2016-04-23 00:01:11 +01:00
argc = switch_separate_string ( ( char * ) dupped , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ;
2014-01-02 17:51:09 -06:00
/* If we don't have the expected number of parameters
* display usage */
2016-05-05 18:39:58 +01:00
if ( argc < AVMD_PARAMS_API_MIN ) {
2016-04-23 00:01:11 +01:00
stream - > write_function ( stream , " -ERR, avmd takes [%u] min and [%u] max parameters! \n "
2016-05-05 18:39:58 +01:00
" -USAGE: %s \n \n " , AVMD_PARAMS_API_MIN , AVMD_PARAMS_API_MAX , AVMD_SYNTAX ) ;
2014-01-02 17:51:09 -06:00
goto end ;
}
2016-04-23 00:01:11 +01:00
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 ;
}
2014-01-02 17:51:09 -06:00
uuid = argv [ 0 ] ;
command = argv [ 1 ] ;
/* using uuid locate a reference to the FreeSWITCH session */
fs_session = switch_core_session_locate ( uuid ) ;
/* If the session was not found exit */
if ( fs_session = = NULL ) {
2016-04-04 02:31:46 +01:00
stream - > write_function ( stream , " -ERR, no FreeSWITCH session for uuid [%s]! "
" \n -USAGE: %s \n \n " , uuid , AVMD_SYNTAX ) ;
2014-01-02 17:51:09 -06:00
goto end ;
}
/* Get current channel of the session to tag the session
2016-04-06 16:12:39 +01:00
* This indicates that our module is present
* At this moment this cannot return NULL , it will either
* succeed or assert failed , but we make ourself secure anyway */
2014-01-02 17:51:09 -06:00
channel = switch_core_session_get_channel ( fs_session ) ;
2016-04-06 16:12:39 +01:00
if ( channel = = NULL ) {
stream - > write_function ( stream , " -ERR, no channel for FreeSWITCH session [%s]! "
2016-04-09 19:50:41 +01:00
" \n Please report this to the developers \n \n " , uuid ) ;
2016-04-07 02:09:14 +01:00
goto end ;
}
/* Is this channel already set? */
bug = ( switch_media_bug_t * ) switch_channel_get_private ( channel , " _avmd_ " ) ;
/* If yes */
if ( bug ! = NULL ) {
/* If we have a stop remove audio bug */
if ( strcasecmp ( command , " stop " ) = = 0 ) {
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 ) ;
2016-06-04 21:52:04 +01:00
avmd_fire_event ( AVMD_EVENT_SESSION_STOP , fs_session , 0 , 0 , 0 , 0 ) ;
2016-04-23 00:01:11 +01:00
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 ) ) ;
}
2016-04-07 02:09:14 +01:00
goto end ;
}
2016-04-23 00:01:11 +01:00
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 ) ;
}
2016-04-06 16:12:39 +01:00
goto end ;
}
2016-04-07 02:09:14 +01:00
2016-04-10 23:00:19 +01:00
if ( strcasecmp ( command , " stop " ) = = 0 ) {
uuid_dup = switch_core_strdup ( switch_core_session_get_pool ( fs_session ) , uuid ) ;
stream - > write_function ( stream , " +ERR, avmd has not yet been started on \n "
" [%s] [%s] \n \n " , uuid_dup , switch_channel_get_name ( channel ) ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) , SWITCH_LOG_ERROR ,
" Stop failed - avmd has not yet been started on channel [%s]! \n " ,
switch_channel_get_name ( channel ) ) ;
goto end ;
}
2016-04-23 00:01:11 +01:00
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 ) ;
2016-05-30 21:05:22 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) , SWITCH_LOG_ERROR ,
2016-04-23 00:01:11 +01:00
" Channel [%s] is not outbound! \n " , switch_channel_get_name ( channel ) ) ;
2016-05-30 21:05:22 +01:00
goto end ;
2016-04-23 00:01:11 +01:00
} else {
flags | = SMBF_READ_REPLACE ;
}
2016-05-30 21:05:22 +01:00
}
if ( avmd_globals . settings . inbound_channnel = = 1 ) {
2016-04-23 00:01:11 +01:00
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 ) ;
2016-05-30 21:05:22 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) , SWITCH_LOG_ERROR ,
2016-04-23 00:01:11 +01:00
" Channel [%s] is not inbound! \n " , switch_channel_get_name ( channel ) ) ;
2016-05-30 21:05:22 +01:00
goto end ;
2016-04-23 00:01:11 +01:00
} else {
flags | = SMBF_WRITE_REPLACE ;
}
2016-05-30 21:05:22 +01:00
}
if ( flags = = 0 ) {
2016-04-06 16:12:39 +01:00
stream - > write_function ( stream , " -ERR, can't set direction for channel [%s] \n "
2016-04-06 23:01:34 +01:00
" for FreeSWITCH session [%s]. Please check avmd configuration \n \n " ,
2016-04-06 16:12:39 +01:00
switch_channel_get_name ( channel ) , uuid ) ;
2016-04-06 23:01:34 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) , SWITCH_LOG_ERROR ,
2016-04-06 16:12:39 +01:00
" Can't set direction for channel [%s] \n " , switch_channel_get_name ( channel ) ) ;
goto end ;
}
2016-04-23 00:01:11 +01:00
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 ;
}
2016-04-06 16:12:39 +01:00
}
2016-05-30 21:05:22 +01:00
if ( strcasecmp ( command , " start " ) ! = 0 ) { /* If we don't see the expected start exit */
2016-04-04 02:31:46 +01:00
stream - > write_function ( stream , " -ERR, did you mean \n "
2016-04-07 02:09:14 +01:00
" api avmd %s start ? \n -USAGE: %s \n \n " , uuid , AVMD_SYNTAX ) ;
2014-01-02 17:51:09 -06:00
goto end ;
}
2016-05-30 21:05:22 +01:00
avmd_session = ( avmd_session_t * ) switch_core_session_alloc ( fs_session , sizeof ( avmd_session_t ) ) ; /* Allocate memory attached to this FreeSWITCH session for use in the callback routine and to store state information */
2016-04-23 00:01:11 +01:00
status = init_avmd_session_data ( avmd_session , fs_session , NULL ) ;
2016-04-09 19:50:41 +01:00
if ( status ! = SWITCH_STATUS_SUCCESS ) {
2016-04-07 02:09:14 +01:00
stream - > write_function ( stream , " -ERR, failed to initialize avmd session \n "
" for FreeSWITCH session [%s] \n " , uuid ) ;
2016-04-09 19:50:41 +01:00
switch ( status ) {
case SWITCH_STATUS_MEMERR :
2016-04-07 02:09:14 +01:00
stream - > write_function ( stream , " -ERR, buffer error \n \n " ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) ,
SWITCH_LOG_ERROR , " Failed to init avmd session. "
" Buffer error! \n " ) ;
break ;
2016-04-09 19:50:41 +01:00
case SWITCH_STATUS_MORE_DATA :
2016-04-07 02:09:14 +01:00
stream - > write_function ( stream , " -ERR, SMA buffer size is 0 \n \n " ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) ,
SWITCH_LOG_ERROR , " Failed to init avmd session. "
" SMA buffer size is 0! \n " ) ;
break ;
2016-04-09 19:50:41 +01:00
case SWITCH_STATUS_FALSE :
2016-04-07 02:09:14 +01:00
stream - > write_function ( stream , " -ERR, SMA buffer error \n \n " ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) ,
SWITCH_LOG_ERROR , " Failed to init avmd session. "
2016-04-09 19:50:41 +01:00
" SMA buffers error \n " ) ;
2016-04-07 02:09:14 +01:00
break ;
default :
stream - > write_function ( stream , " -ERR, unknown error \n \n " ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) ,
SWITCH_LOG_ERROR , " Failed to init avmd session. "
" Unknown error \n " ) ;
break ;
}
goto end ;
}
2014-01-02 17:51:09 -06:00
2016-05-30 21:05:22 +01:00
status = switch_core_media_bug_add ( fs_session , " avmd " , NULL , avmd_callback , avmd_session , 0 , flags , & bug ) ; /* Add a media bug that allows me to intercept the reading leg of the audio stream */
if ( status ! = SWITCH_STATUS_SUCCESS ) { /* If adding a media bug fails exit */
2016-04-06 23:01:34 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fs_session ) ,
SWITCH_LOG_ERROR , " Failed to add media bug! \n " ) ;
2016-04-04 02:31:46 +01:00
stream - > write_function ( stream ,
" -ERR, [%s] failed to add media bug! \n \n " , uuid ) ;
2014-01-02 17:51:09 -06:00
goto end ;
}
2016-05-30 21:05:22 +01:00
switch_channel_set_private ( channel , " _avmd_ " , bug ) ; /* Set the vmd tag to detect an existing vmd media bug */
2014-01-02 17:51:09 -06:00
2016-06-04 21:52:04 +01:00
avmd_fire_event ( AVMD_EVENT_SESSION_START , fs_session , 0 , 0 , 0 , 0 ) ;
2016-04-23 00:01:11 +01:00
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 ) ;
}
2010-05-25 15:03:14 -04:00
end :
2014-01-02 17:51:09 -06:00
if ( fs_session ) {
switch_core_session_rwunlock ( fs_session ) ;
}
2010-05-25 15:03:14 -04:00
2016-04-23 00:01:11 +01:00
switch_safe_free ( dupped ) ;
switch_mutex_unlock ( avmd_globals . mutex ) ;
2010-05-25 15:03:14 -04:00
2014-01-02 17:51:09 -06:00
return SWITCH_STATUS_SUCCESS ;
2010-05-25 15:03:14 -04:00
}
2016-02-04 23:14:19 +00:00
/*! \brief Process one frame of data with avmd algorithm.
* @ param session An avmd session .
* @ param frame An audio frame .
2010-05-25 15:03:14 -04:00
*/
2016-05-30 21:05:22 +01:00
static void avmd_process ( avmd_session_t * s , switch_frame_t * frame ) {
2016-04-09 19:50:41 +01:00
switch_channel_t * channel ;
circ_buffer_t * b ;
size_t pos ;
2016-05-30 21:05:22 +01:00
double omega ;
double f ;
2016-04-09 19:50:41 +01:00
double v ;
double sma_digital_freq ;
uint32_t sine_len_i ;
2016-06-04 21:52:04 +01:00
int sample_to_skip_n = s - > settings . sample_n_to_skip ;
2016-04-09 19:50:41 +01:00
size_t sample_n = 0 ;
2012-04-09 12:31:48 -05:00
2016-04-21 00:05:23 +01:00
b = & s - > b ;
2010-05-25 15:03:14 -04:00
2016-04-09 19:50:41 +01:00
/* If beep has already been detected skip the CPU heavy stuff */
2016-04-21 00:05:23 +01:00
if ( s - > state . beep_state = = BEEP_DETECTED ) return ;
2010-05-25 15:03:14 -04:00
2016-04-09 19:50:41 +01:00
/* Precompute values used heavily in the inner loop */
2016-04-21 00:05:23 +01:00
sine_len_i = ( uint32_t ) SINE_LEN ( s - > rate ) ;
2016-04-09 19:50:41 +01:00
//sine_len = (double)sine_len_i;
//beep_len_i = BEEP_LEN(session->rate);
2014-01-02 17:51:09 -06:00
2016-04-21 00:05:23 +01:00
channel = switch_core_session_get_channel ( s - > session ) ;
2010-05-25 15:03:14 -04:00
2016-04-09 19:50:41 +01:00
/* Insert frame of 16 bit samples into buffer */
INSERT_INT16_FRAME ( b , ( int16_t * ) ( frame - > data ) , frame - > samples ) ;
2016-04-21 00:05:23 +01:00
s - > sample_count + = frame - > samples ;
2014-01-02 17:51:09 -06:00
2016-03-27 20:39:53 +01:00
/* INNER LOOP -- OPTIMIZATION TARGET */
2016-04-21 00:05:23 +01:00
pos = s - > pos ;
2016-03-27 20:39:53 +01:00
while ( sample_n < ( frame - > samples - P ) ) {
/*for (pos = session->pos; pos < (GET_CURRENT_POS(b) - P); pos++) { */
if ( ( sample_n % sine_len_i ) = = 0 ) {
2016-02-22 18:26:57 +00:00
/* Get a desa2 frequency estimate every sine len */
2016-04-04 02:31:46 +01:00
omega = avmd_desa2_tweaked ( b , pos + sample_n ) ;
2014-01-02 17:51:09 -06:00
2016-03-27 20:39:53 +01:00
if ( omega < - 0.999999 | | omega > 0.999999 ) {
2016-05-30 21:05:22 +01:00
if ( s - > settings . debug = = 1 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_DEBUG , " <<< AVMD RESET >>> \n " ) ;
}
2014-01-02 17:51:09 -06:00
v = 99999.0 ;
2016-05-30 21:05:22 +01:00
if ( s - > settings . require_continuous_streak = = 1 ) {
RESET_SMA_BUFFER ( & s - > sma_b ) ;
RESET_SMA_BUFFER ( & s - > sqa_b ) ;
s - > samples_streak = s - > settings . sample_n_continuous_streak ;
sample_to_skip_n = s - > settings . sample_n_to_skip ;
}
2014-01-02 17:51:09 -06:00
} else {
2016-05-12 01:09:12 +01:00
if ( ISNAN ( omega ) ) {
2016-05-30 21:05:22 +01:00
if ( s - > settings . debug = = 1 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_DEBUG , " <<< AVMD, SKIP NaN >>> \n " ) ;
}
sample_to_skip_n = s - > settings . sample_n_to_skip ;
2016-03-27 20:39:53 +01:00
goto loop_continue ;
}
2016-06-04 21:52:04 +01:00
if ( s - > sma_b . pos > 0 & & ( fabs ( omega - s - > sma_b . data [ s - > sma_b . pos - 1 ] ) < 0.00000001 ) ) {
2016-05-30 21:05:22 +01:00
if ( s - > settings . debug = = 1 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_DEBUG , " <<< AVMD, SKIP >>> \n " ) ;
}
2016-03-27 20:39:53 +01:00
goto loop_continue ;
}
2016-05-30 21:05:22 +01:00
if ( s - > settings . debug = = 1 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_DEBUG , " <<< AVMD omega [%f] >>> \n " , omega ) ;
}
2016-03-27 20:39:53 +01:00
if ( sample_to_skip_n > 0 ) {
sample_to_skip_n - - ;
goto loop_continue ;
}
2016-05-30 21:05:22 +01:00
if ( omega < - 0.9999 ) { /* saturate */
2016-03-27 20:39:53 +01:00
omega = - 0.9999 ;
2016-04-23 00:01:11 +01:00
}
if ( omega > 0.9999 ) {
2016-03-27 20:39:53 +01:00
omega = 0.9999 ;
2016-04-23 00:01:11 +01:00
}
2016-03-27 20:39:53 +01:00
2016-05-30 21:05:22 +01:00
APPEND_SMA_VAL ( & s - > sma_b , omega ) ; /* append */
2016-04-21 00:05:23 +01:00
APPEND_SMA_VAL ( & s - > sqa_b , omega * omega ) ;
2016-05-30 21:05:22 +01:00
if ( s - > settings . require_continuous_streak = = 1 ) {
if ( s - > samples_streak > 0 ) {
- - s - > samples_streak ;
}
}
v = s - > sqa_b . sma - ( s - > sma_b . sma * s - > sma_b . sma ) ; /* calculate variance (biased estimator) */
if ( s - > settings . debug = = 1 ) {
# if !defined(WIN32) && defined(AVMD_FAST_MATH)
f = 0.5 * ( double ) fast_acosf ( ( float ) omega ) ;
sma_digital_freq = 0.5 * ( double ) fast_acosf ( ( float ) s - > sma_b . sma ) ;
# else
f = 0.5 * acos ( omega ) ;
sma_digital_freq = 0.5 * acos ( s - > sma_b . sma ) ;
# endif /* !WIN32 && AVMD_FAST_MATH */
if ( s - > settings . require_continuous_streak = = 1 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_DEBUG , " <<< AVMD v[%.10f] \t omega[%f] \t f[%f] [%f]Hz \t \t sma[%f][%f]Hz \t \t sqa[%f] \t "
" streak[%zu] pos[%zu] sample_n[%zu] lpos[%zu] s[%zu]>>> \n " , v , omega , f , TO_HZ ( s - > rate , f ) , s - > sma_b . sma , TO_HZ ( s - > rate , sma_digital_freq ) , s - > sqa_b . sma , s - > samples_streak ,
s - > sma_b . pos , sample_n , s - > sma_b . lpos , pos ) ;
} else {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_DEBUG , " <<< AVMD v[%.10f] \t omega[%f] \t f[%f] [%f]Hz \t \t sma[%f][%f]Hz \t \t sqa[%f] \t pos[%zu] "
" sample_n[%zu] lpos[%zu] s[%zu]>>> \n " , v , omega , f , TO_HZ ( s - > rate , f ) , s - > sma_b . sma , TO_HZ ( s - > rate , sma_digital_freq ) , s - > sqa_b . sma , s - > sma_b . pos , sample_n , s - > sma_b . lpos , pos ) ;
}
2016-04-23 00:01:11 +01:00
}
2014-01-02 17:51:09 -06:00
}
2016-03-27 20:39:53 +01:00
/* DECISION */
2016-04-09 19:50:41 +01:00
/* If variance is less than threshold
2016-05-03 13:30:03 +01:00
* and we have at least two estimates and more than required by continuous
* streak option then we have detection */
2016-05-30 21:05:22 +01:00
if ( ( s - > settings . require_continuous_streak = = 1 & & v < VARIANCE_THRESHOLD & & ( s - > sma_b . lpos > 1 ) & & ( s - > samples_streak = = 0 ) ) | | ( s - > settings . require_continuous_streak = = 0 & & v < VARIANCE_THRESHOLD & & ( s - > sma_b . lpos > 1 ) ) ) {
# if !defined(WIN32) && defined(AVMD_FAST_MATH)
2016-04-21 00:05:23 +01:00
sma_digital_freq = 0.5 * ( double ) fast_acosf ( ( float ) s - > sma_b . sma ) ;
2016-05-30 21:05:22 +01:00
# else
2016-04-21 00:05:23 +01:00
sma_digital_freq = 0.5 * acos ( s - > sma_b . sma ) ;
2016-05-30 21:05:22 +01:00
# endif /* !WIN32 && AVMD_FAST_MATH */
2016-04-21 00:05:23 +01:00
2016-05-30 21:05:22 +01:00
switch_channel_set_variable_printf ( channel , " avmd_total_time " , " [%d] " , ( int ) ( switch_micro_time_now ( ) - s - > start_time ) / 1000 ) ;
2014-07-09 08:25:54 -05:00
switch_channel_execute_on ( channel , " execute_on_avmd_beep " ) ;
2016-06-04 21:52:04 +01:00
avmd_fire_event ( AVMD_EVENT_BEEP , s - > session , TO_HZ ( s - > rate , sma_digital_freq ) , v , 0 , 0 ) ;
2016-05-30 21:05:22 +01:00
if ( s - > settings . report_status = = 1 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( s - > session ) , SWITCH_LOG_INFO , " <<< AVMD - Beep Detected: f = [%f], variance = [%f] >>> \n " , TO_HZ ( s - > rate , sma_digital_freq ) , v ) ;
}
2014-01-02 17:51:09 -06:00
switch_channel_set_variable ( channel , " avmd_detect " , " TRUE " ) ;
2016-04-21 00:05:23 +01:00
RESET_SMA_BUFFER ( & s - > sma_b ) ;
RESET_SMA_BUFFER ( & s - > sqa_b ) ;
s - > state . beep_state = BEEP_DETECTED ;
2016-03-27 20:39:53 +01:00
goto done ;
2016-02-22 18:26:57 +00:00
}
2014-01-02 17:51:09 -06:00
}
2016-03-27 20:39:53 +01:00
loop_continue :
+ + sample_n ;
2014-01-02 17:51:09 -06:00
}
2016-03-27 20:39:53 +01:00
done :
2016-04-21 00:05:23 +01:00
s - > pos + = sample_n ;
s - > pos & = b - > mask ;
2016-03-20 23:58:45 +00:00
return ;
2010-05-25 15:03:14 -04:00
}
2016-04-23 00:01:11 +01:00
static void
avmd_reloadxml_event_handler ( switch_event_t * event )
{
avmd_load_xml_configuration ( avmd_globals . mutex ) ;
}
2010-05-25 15:03:14 -04:00
/* For Emacs:
* Local Variables :
* mode : c
* indent - tabs - mode : t
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
2013-06-25 11:50:17 -05:00
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 noet :
2010-05-25 15:03:14 -04:00
*/