2010-01-15 19:22:49 +00:00
/*
2014-02-05 15:02:28 -06:00
* Copyright ( c ) 2007 - 2014 , Anthony Minessale II
2010-01-15 19:22:49 +00:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
*
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
*
* * Neither the name of the original author ; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL ,
* EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO ,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR
* PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
* Contributors :
*
* Moises Silva < moy @ sangoma . com >
* David Yat Sin < dyatsin @ sangoma . com >
*
*/
# define _GNU_SOURCE
2010-04-19 11:39:03 -04:00
# include "private/ftdm_core.h"
2010-01-15 19:22:49 +00:00
# include <stdarg.h>
2012-06-19 22:35:37 -04:00
# include <ctype.h>
2010-01-15 19:22:49 +00:00
# ifdef WIN32
# include <io.h>
# endif
# ifdef FTDM_PIKA_SUPPORT
# include "ftdm_pika.h"
# endif
2010-04-05 17:49:43 -04:00
# include "ftdm_cpu_monitor.h"
2010-01-15 19:22:49 +00:00
2010-12-06 17:11:56 -02:00
# ifndef localtime_r
struct tm * localtime_r ( const time_t * clock , struct tm * result ) ;
# endif
2011-12-18 23:02:59 -05:00
# define FORCE_HANGUP_TIMER 30000
2010-05-28 15:06:51 -04:00
# define FTDM_READ_TRACE_INDEX 0
# define FTDM_WRITE_TRACE_INDEX 1
2010-12-10 19:14:08 -05:00
# define MAX_CALLIDS 6000
2011-05-26 11:38:24 -04:00
# define FTDM_HALF_DTMF_PAUSE 500
# define FTDM_FULL_DTMF_PAUSE 1000
2010-03-12 18:27:24 +00:00
2014-07-13 02:15:38 -04:00
# define FTDM_CHANNEL_SW_DTMF_ALLOWED(ftdmchan) (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_DTMF_DETECTION))
2010-11-15 14:13:01 -05:00
ftdm_time_t time_last_throttle_log = 0 ;
ftdm_time_t time_current_throttle_log = 0 ;
2012-06-20 16:28:00 -04:00
typedef struct val_str {
const char * str ;
unsigned long long val ;
} val_str_t ;
static val_str_t channel_flag_strs [ ] = {
{ " configured " , FTDM_CHANNEL_CONFIGURED } ,
{ " ready " , FTDM_CHANNEL_READY } ,
{ " open " , FTDM_CHANNEL_OPEN } ,
{ " dtmf-detect " , FTDM_CHANNEL_DTMF_DETECT } ,
{ " suppress-dtmf " , FTDM_CHANNEL_SUPRESS_DTMF } ,
{ " transcode " , FTDM_CHANNEL_TRANSCODE } ,
{ " buffer " , FTDM_CHANNEL_BUFFER } ,
{ " in-thread " , FTDM_CHANNEL_INTHREAD } ,
{ " wink " , FTDM_CHANNEL_WINK } ,
{ " flash " , FTDM_CHANNEL_FLASH } ,
{ " state-change " , FTDM_CHANNEL_STATE_CHANGE } ,
{ " hold " , FTDM_CHANNEL_HOLD } ,
{ " in-use " , FTDM_CHANNEL_INUSE } ,
{ " off-hook " , FTDM_CHANNEL_OFFHOOK } ,
{ " ringing " , FTDM_CHANNEL_RINGING } ,
{ " progress-detect " , FTDM_CHANNEL_PROGRESS_DETECT } ,
{ " callerid-detect " , FTDM_CHANNEL_CALLERID_DETECT } ,
{ " outbound " , FTDM_CHANNEL_OUTBOUND } ,
{ " suspended " , FTDM_CHANNEL_SUSPENDED } ,
{ " 3-way " , FTDM_CHANNEL_3WAY } ,
{ " progress " , FTDM_CHANNEL_PROGRESS } ,
{ " media " , FTDM_CHANNEL_MEDIA } ,
{ " answered " , FTDM_CHANNEL_ANSWERED } ,
{ " mute " , FTDM_CHANNEL_MUTE } ,
{ " use-rx-gain " , FTDM_CHANNEL_USE_RX_GAIN } ,
{ " use-tx-gain " , FTDM_CHANNEL_USE_TX_GAIN } ,
{ " in-alarm " , FTDM_CHANNEL_IN_ALARM } ,
{ " sig-up " , FTDM_CHANNEL_SIG_UP } ,
{ " user-hangup " , FTDM_CHANNEL_USER_HANGUP } ,
{ " rx-disabled " , FTDM_CHANNEL_RX_DISABLED } ,
{ " tx-disabled " , FTDM_CHANNEL_TX_DISABLED } ,
{ " call-started " , FTDM_CHANNEL_CALL_STARTED } ,
{ " non-block " , FTDM_CHANNEL_NONBLOCK } ,
{ " ind-ack-pending " , FTDM_CHANNEL_IND_ACK_PENDING } ,
{ " blocking " , FTDM_CHANNEL_BLOCKING } ,
{ " media " , FTDM_CHANNEL_DIGITAL_MEDIA } ,
{ " native-sigbridge " , FTDM_CHANNEL_NATIVE_SIGBRIDGE } ,
2014-07-13 02:15:38 -04:00
{ " sig-dtmf-detection " , FTDM_CHANNEL_SIG_DTMF_DETECTION } ,
2012-06-20 16:28:00 -04:00
{ " invalid " , FTDM_CHANNEL_MAX_FLAG } ,
} ;
static val_str_t span_flag_strs [ ] = {
{ " configured " , FTDM_SPAN_CONFIGURED } ,
{ " started " , FTDM_SPAN_STARTED } ,
{ " state-change " , FTDM_SPAN_STATE_CHANGE } ,
{ " suspended " , FTDM_SPAN_SUSPENDED } ,
{ " in-thread " , FTDM_SPAN_IN_THREAD } ,
{ " stop-thread " , FTDM_SPAN_STOP_THREAD } ,
{ " use-chan-queue " , FTDM_SPAN_USE_CHAN_QUEUE } ,
{ " suggest-chan-id " , FTDM_SPAN_SUGGEST_CHAN_ID } ,
{ " use-av-rate " , FTDM_SPAN_USE_AV_RATE } ,
{ " power-saving " , FTDM_SPAN_PWR_SAVING } ,
{ " signals-queue " , FTDM_SPAN_USE_SIGNALS_QUEUE } ,
{ " proceed-state " , FTDM_SPAN_USE_PROCEED_STATE } ,
{ " skip-state " , FTDM_SPAN_USE_SKIP_STATES } ,
{ " non-stoppable " , FTDM_SPAN_NON_STOPPABLE } ,
{ " use-transfer " , FTDM_SPAN_USE_TRANSFER } ,
} ;
2010-12-21 19:04:41 -05:00
static ftdm_status_t ftdm_call_set_call_id ( ftdm_channel_t * fchan , ftdm_caller_data_t * caller_data ) ;
2010-12-10 19:14:08 -05:00
static ftdm_status_t ftdm_call_clear_call_id ( ftdm_caller_data_t * caller_data ) ;
2010-12-14 11:23:47 -05:00
static ftdm_status_t ftdm_channel_done ( ftdm_channel_t * ftdmchan ) ;
2011-02-25 09:58:15 -05:00
static ftdm_status_t ftdm_channel_sig_indicate ( ftdm_channel_t * ftdmchan , ftdm_channel_indication_t indication , ftdm_usrmsg_t * usrmsg ) ;
2012-06-20 16:28:00 -04:00
static const char * ftdm_val2str ( unsigned long long val , val_str_t * val_str_table , ftdm_size_t array_size , const char * default_str ) ;
static unsigned long long ftdm_str2val ( const char * str , val_str_t * val_str_table , ftdm_size_t array_size , unsigned long long default_val ) ;
2010-12-09 13:20:05 -05:00
2010-01-15 19:22:49 +00:00
static int time_is_init = 0 ;
static void time_init ( void )
{
# ifdef WIN32
timeBeginPeriod ( 1 ) ;
# endif
time_is_init = 1 ;
}
static void time_end ( void )
{
# ifdef WIN32
timeEndPeriod ( 1 ) ;
# endif
time_is_init = 0 ;
}
FT_DECLARE ( ftdm_time_t ) ftdm_current_time_in_ms ( void )
{
# ifdef WIN32
return timeGetTime ( ) ;
# else
struct timeval tv ;
gettimeofday ( & tv , NULL ) ;
return ( ( tv . tv_sec * 1000 ) + ( tv . tv_usec / 1000 ) ) ;
# endif
}
2010-12-06 17:11:56 -02:00
static void write_chan_io_dump ( ftdm_io_dump_t * dump , char * dataptr , int dlen )
2010-12-02 18:35:48 -05:00
{
int windex = dump - > windex ;
2010-12-06 17:11:56 -02:00
int avail = ( int ) dump - > size - windex ;
2010-12-02 18:35:48 -05:00
2010-12-03 16:50:03 -05:00
if ( ! dump - > buffer ) {
return ;
}
2010-12-02 18:35:48 -05:00
if ( dlen > avail ) {
int diff = dlen - avail ;
2010-12-07 20:33:23 -02:00
ftdm_assert ( diff < ( int ) dump - > size , " Very small buffer or very big IO chunk! \n " ) ;
2010-12-02 18:35:48 -05:00
/* write only what we can and the rest at the beginning of the buffer */
memcpy ( & dump - > buffer [ windex ] , dataptr , avail ) ;
memcpy ( & dump - > buffer [ 0 ] , & dataptr [ avail ] , diff ) ;
windex = diff ;
2010-12-03 16:50:03 -05:00
/*ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "wrapping around dump buffer %p up to index %d\n\n", dump, windex);*/
2010-12-02 18:35:48 -05:00
dump - > wrapped = 1 ;
} else {
memcpy ( & dump - > buffer [ windex ] , dataptr , dlen ) ;
windex + = dlen ;
}
2010-12-07 20:33:23 -02:00
if ( windex = = ( int ) dump - > size ) {
2010-12-03 16:50:03 -05:00
/*ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "wrapping around dump buffer %p\n", dump);*/
2010-12-02 18:35:48 -05:00
windex = 0 ;
dump - > wrapped = 1 ;
}
dump - > windex = windex ;
}
static void dump_chan_io_to_file ( ftdm_channel_t * fchan , ftdm_io_dump_t * dump , FILE * file )
{
/* write the saved audio buffer */
2010-12-09 07:19:31 -05:00
ftdm_size_t rc = 0 ;
ftdm_size_t towrite = 0 ;
if ( ! dump - > buffer ) {
return ;
}
towrite = dump - > size - dump - > windex ;
2010-12-02 18:35:48 -05:00
if ( dump - > wrapped ) {
rc = fwrite ( & dump - > buffer [ dump - > windex ] , 1 , towrite , file ) ;
if ( rc ! = towrite ) {
2012-02-10 13:29:49 +01:00
ftdm_log_chan ( fchan , FTDM_LOG_ERROR , " only wrote % " FTDM_SIZE_FMT " out of % " FTDM_SIZE_FMT " bytes in io dump buffer: %s \n " ,
2010-12-08 14:30:47 -05:00
rc , towrite , strerror ( errno ) ) ;
2010-12-02 18:35:48 -05:00
}
}
if ( dump - > windex ) {
towrite = dump - > windex ;
rc = fwrite ( & dump - > buffer [ 0 ] , 1 , towrite , file ) ;
if ( rc ! = towrite ) {
2012-02-10 13:29:49 +01:00
ftdm_log_chan ( fchan , FTDM_LOG_ERROR , " only wrote % " FTDM_SIZE_FMT " out of % " FTDM_SIZE_FMT " bytes in io dump buffer: %s \n " ,
2010-12-08 14:30:47 -05:00
rc , towrite , strerror ( errno ) ) ;
2010-12-02 18:35:48 -05:00
}
}
dump - > windex = 0 ;
dump - > wrapped = 0 ;
}
static void stop_chan_io_dump ( ftdm_io_dump_t * dump )
{
if ( ! dump - > buffer ) {
return ;
}
ftdm_safe_free ( dump - > buffer ) ;
2012-06-20 12:30:37 -04:00
memset ( dump , 0 , sizeof ( * dump ) ) ;
2010-12-02 18:35:48 -05:00
}
2010-12-06 07:26:04 -05:00
static ftdm_status_t start_chan_io_dump ( ftdm_channel_t * chan , ftdm_io_dump_t * dump , ftdm_size_t size )
2010-12-02 18:35:48 -05:00
{
if ( dump - > buffer ) {
ftdm_log_chan_msg ( chan , FTDM_LOG_ERROR , " IO dump is already started \n " ) ;
2010-12-06 07:26:04 -05:00
return FTDM_FAIL ;
2010-12-02 18:35:48 -05:00
}
memset ( dump , 0 , sizeof ( * dump ) ) ;
dump - > buffer = ftdm_malloc ( size ) ;
if ( ! dump - > buffer ) {
2010-12-06 07:26:04 -05:00
return FTDM_FAIL ;
2010-12-02 18:35:48 -05:00
}
dump - > size = size ;
2010-12-06 07:26:04 -05:00
return FTDM_SUCCESS ;
2010-12-02 18:35:48 -05:00
}
static void close_dtmf_debug_file ( ftdm_channel_t * ftdmchan )
{
if ( ftdmchan - > dtmfdbg . file ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " closing debug dtmf file \n " ) ;
fclose ( ftdmchan - > dtmfdbg . file ) ;
ftdmchan - > dtmfdbg . file = NULL ;
}
}
2010-12-06 07:26:04 -05:00
static ftdm_status_t disable_dtmf_debug ( ftdm_channel_t * ftdmchan )
2010-12-02 18:35:48 -05:00
{
if ( ! ftdmchan - > dtmfdbg . enabled ) {
2010-12-06 07:26:04 -05:00
return FTDM_SUCCESS ;
2010-12-02 18:35:48 -05:00
}
if ( ! ftdmchan - > rxdump . buffer ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " DTMF debug enabled but no rx dump? \n " ) ;
2010-12-06 07:26:04 -05:00
return FTDM_FAIL ;
2010-12-02 18:35:48 -05:00
}
close_dtmf_debug_file ( ftdmchan ) ;
stop_chan_io_dump ( & ftdmchan - > rxdump ) ;
ftdmchan - > dtmfdbg . enabled = 0 ;
2010-12-06 07:26:04 -05:00
return FTDM_SUCCESS ;
2010-12-02 18:35:48 -05:00
}
2010-04-05 17:49:43 -04:00
typedef struct {
2010-09-23 13:58:20 -04:00
uint8_t enabled ;
2010-04-05 17:49:43 -04:00
uint8_t running ;
uint8_t alarm ;
uint32_t interval ;
uint8_t alarm_action_flags ;
uint8_t set_alarm_threshold ;
2011-12-01 12:13:12 -05:00
uint8_t clear_alarm_threshold ;
2010-04-05 17:49:43 -04:00
ftdm_interrupt_t * interrupt ;
} cpu_monitor_t ;
2010-01-15 19:22:49 +00:00
static struct {
ftdm_hash_t * interface_hash ;
ftdm_hash_t * module_hash ;
ftdm_hash_t * span_hash ;
ftdm_hash_t * group_hash ;
ftdm_mutex_t * mutex ;
ftdm_mutex_t * span_mutex ;
ftdm_mutex_t * group_mutex ;
2010-09-21 07:19:56 -04:00
ftdm_sched_t * timingsched ;
2010-01-15 19:22:49 +00:00
uint32_t span_index ;
uint32_t group_index ;
uint32_t running ;
ftdm_span_t * spans ;
ftdm_group_t * groups ;
2010-04-05 17:49:43 -04:00
cpu_monitor_t cpu_monitor ;
2010-12-10 19:14:08 -05:00
ftdm_caller_data_t * call_ids [ MAX_CALLIDS + 1 ] ;
ftdm_mutex_t * call_id_mutex ;
uint32_t last_call_id ;
2011-03-18 14:47:49 -04:00
char dtmfdebug_directory [ 1024 ] ;
2010-01-15 19:22:49 +00:00
} globals ;
2010-04-05 17:49:43 -04:00
enum ftdm_enum_cpu_alarm_action_flags
{
FTDM_CPU_ALARM_ACTION_WARN = ( 1 < < 0 ) ,
FTDM_CPU_ALARM_ACTION_REJECT = ( 1 < < 1 )
} ;
2010-01-15 19:22:49 +00:00
/* enum lookup funcs */
FTDM_ENUM_NAMES ( TONEMAP_NAMES , TONEMAP_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_tonemap , ftdm_tonemap2str , ftdm_tonemap_t , TONEMAP_NAMES , FTDM_TONEMAP_INVALID )
FTDM_ENUM_NAMES ( OOB_NAMES , OOB_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_oob_event , ftdm_oob_event2str , ftdm_oob_event_t , OOB_NAMES , FTDM_OOB_INVALID )
2012-07-11 19:15:35 +02:00
FTDM_ENUM_NAMES ( TRUNK_TYPE_NAMES , TRUNK_TYPE_STRINGS )
2010-01-15 19:22:49 +00:00
FTDM_STR2ENUM ( ftdm_str2ftdm_trunk_type , ftdm_trunk_type2str , ftdm_trunk_type_t , TRUNK_TYPE_NAMES , FTDM_TRUNK_NONE )
2012-07-11 19:15:35 +02:00
FTDM_ENUM_NAMES ( TRUNK_MODE_NAMES , TRUNK_MODE_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_trunk_mode , ftdm_trunk_mode2str , ftdm_trunk_mode_t , TRUNK_MODE_NAMES , FTDM_TRUNK_MODE_INVALID )
2010-01-15 19:22:49 +00:00
FTDM_ENUM_NAMES ( START_TYPE_NAMES , START_TYPE_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_analog_start_type , ftdm_analog_start_type2str , ftdm_analog_start_type_t , START_TYPE_NAMES , FTDM_ANALOG_START_NA )
FTDM_ENUM_NAMES ( SIGNAL_NAMES , SIGNAL_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_signal_event , ftdm_signal_event2str , ftdm_signal_event_t , SIGNAL_NAMES , FTDM_SIGEVENT_INVALID )
FTDM_ENUM_NAMES ( MDMF_TYPE_NAMES , MDMF_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_mdmf_type , ftdm_mdmf_type2str , ftdm_mdmf_type_t , MDMF_TYPE_NAMES , MDMF_INVALID )
FTDM_ENUM_NAMES ( CHAN_TYPE_NAMES , CHAN_TYPE_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_chan_type , ftdm_chan_type2str , ftdm_chan_type_t , CHAN_TYPE_NAMES , FTDM_CHAN_TYPE_COUNT )
FTDM_ENUM_NAMES ( SIGNALING_STATUS_NAMES , SIGSTATUS_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_signaling_status , ftdm_signaling_status2str , ftdm_signaling_status_t , SIGNALING_STATUS_NAMES , FTDM_SIG_STATE_INVALID )
2010-12-15 16:29:03 -05:00
FTDM_ENUM_NAMES ( TRACE_DIR_NAMES , TRACE_DIR_STRINGS )
2010-12-16 15:57:46 -05:00
FTDM_STR2ENUM ( ftdm_str2ftdm_trace_dir , ftdm_trace_dir2str , ftdm_trace_dir_t , TRACE_DIR_NAMES , FTDM_TRACE_DIR_INVALID )
FTDM_ENUM_NAMES ( TRACE_TYPE_NAMES , TRACE_TYPE_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_trace_type , ftdm_trace_type2str , ftdm_trace_type_t , TRACE_TYPE_NAMES , FTDM_TRACE_TYPE_INVALID )
2010-12-15 16:29:03 -05:00
2010-11-30 13:17:48 -05:00
FTDM_ENUM_NAMES ( TON_NAMES , TON_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_ton , ftdm_ton2str , ftdm_ton_t , TON_NAMES , FTDM_TON_INVALID )
FTDM_ENUM_NAMES ( NPI_NAMES , NPI_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_npi , ftdm_npi2str , ftdm_npi_t , NPI_NAMES , FTDM_NPI_INVALID )
FTDM_ENUM_NAMES ( PRESENTATION_NAMES , PRESENTATION_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_presentation , ftdm_presentation2str , ftdm_presentation_t , PRESENTATION_NAMES , FTDM_PRES_INVALID )
FTDM_ENUM_NAMES ( SCREENING_NAMES , SCREENING_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_screening , ftdm_screening2str , ftdm_screening_t , SCREENING_NAMES , FTDM_SCREENING_INVALID )
FTDM_ENUM_NAMES ( BEARER_CAP_NAMES , BEARER_CAP_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_bearer_cap , ftdm_bearer_cap2str , ftdm_bearer_cap_t , BEARER_CAP_NAMES , FTDM_BEARER_CAP_INVALID )
FTDM_ENUM_NAMES ( USER_LAYER1_PROT_NAMES , USER_LAYER1_PROT_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_usr_layer1_prot , ftdm_user_layer1_prot2str , ftdm_user_layer1_prot_t , USER_LAYER1_PROT_NAMES , FTDM_USER_LAYER1_PROT_INVALID )
2010-12-17 19:26:43 -05:00
FTDM_ENUM_NAMES ( CALLING_PARTY_CATEGORY_NAMES , CALLING_PARTY_CATEGORY_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_calling_party_category , ftdm_calling_party_category2str , ftdm_calling_party_category_t , CALLING_PARTY_CATEGORY_NAMES , FTDM_CPC_INVALID )
2010-12-23 15:39:20 -05:00
FTDM_ENUM_NAMES ( INDICATION_NAMES , INDICATION_STRINGS )
2011-05-26 11:38:24 -04:00
FTDM_STR2ENUM ( ftdm_str2ftdm_channel_indication , ftdm_channel_indication2str , ftdm_channel_indication_t , INDICATION_NAMES , FTDM_CHANNEL_INDICATE_INVALID )
FTDM_ENUM_NAMES ( TRANSFER_RESPONSE_NAMES , TRANSFER_RESPONSE_STRINGS )
FTDM_STR2ENUM ( ftdm_str2ftdm_transfer_response , ftdm_transfer_response2str , ftdm_transfer_response_t , TRANSFER_RESPONSE_NAMES , FTDM_TRANSFER_RESPONSE_INVALID )
2010-12-23 15:39:20 -05:00
2010-04-27 14:32:36 -04:00
static ftdm_status_t ftdm_group_add_channels ( ftdm_span_t * span , int currindex , const char * name ) ;
2010-01-15 19:22:49 +00:00
static void null_logger ( const char * file , const char * func , int line , int level , const char * fmt , . . . )
{
2013-05-10 14:05:07 +02:00
ftdm_unused_arg ( file ) ;
ftdm_unused_arg ( func ) ;
ftdm_unused_arg ( line ) ;
ftdm_unused_arg ( level ) ;
ftdm_unused_arg ( fmt ) ;
2010-01-15 19:22:49 +00:00
}
2010-05-25 19:33:24 -04:00
const char * FTDM_LEVEL_NAMES [ 9 ] = {
2010-01-15 19:22:49 +00:00
" EMERG " ,
" ALERT " ,
" CRIT " ,
" ERROR " ,
" WARNING " ,
" NOTICE " ,
" INFO " ,
" DEBUG " ,
NULL
} ;
2010-05-25 19:33:24 -04:00
static int ftdm_log_level = FTDM_LOG_LEVEL_DEBUG ;
2010-01-15 19:22:49 +00:00
static void default_logger ( const char * file , const char * func , int line , int level , const char * fmt , . . . )
{
char data [ 1024 ] ;
va_list ap ;
if ( level < 0 | | level > 7 ) {
level = 7 ;
}
if ( level > ftdm_log_level ) {
return ;
}
va_start ( ap , fmt ) ;
vsnprintf ( data , sizeof ( data ) , fmt , ap ) ;
2010-05-25 19:33:24 -04:00
fprintf ( stderr , " [%s] %s:%d %s() %s " , FTDM_LEVEL_NAMES [ level ] , file , line , func , data ) ;
2010-01-15 19:22:49 +00:00
va_end ( ap ) ;
}
static __inline__ void * ftdm_std_malloc ( void * pool , ftdm_size_t size )
{
void * ptr = malloc ( size ) ;
2013-05-10 14:05:07 +02:00
ftdm_unused_arg ( pool ) ;
2010-12-08 10:45:45 -05:00
ftdm_assert_return ( ptr ! = NULL , NULL , " Out of memory \n " ) ;
2010-01-15 19:22:49 +00:00
return ptr ;
}
static __inline__ void * ftdm_std_calloc ( void * pool , ftdm_size_t elements , ftdm_size_t size )
{
void * ptr = calloc ( elements , size ) ;
2013-05-10 14:05:07 +02:00
ftdm_unused_arg ( pool ) ;
2010-12-08 10:45:45 -05:00
ftdm_assert_return ( ptr ! = NULL , NULL , " Out of memory \n " ) ;
2010-01-15 19:22:49 +00:00
return ptr ;
}
2010-04-13 15:17:32 -04:00
static __inline__ void * ftdm_std_realloc ( void * pool , void * buff , ftdm_size_t size )
{
buff = realloc ( buff , size ) ;
2013-05-10 14:05:07 +02:00
ftdm_unused_arg ( pool ) ;
2010-12-08 10:45:45 -05:00
ftdm_assert_return ( buff ! = NULL , NULL , " Out of memory \n " ) ;
2010-04-13 15:17:32 -04:00
return buff ;
}
2010-01-15 19:22:49 +00:00
static __inline__ void ftdm_std_free ( void * pool , void * ptr )
{
2013-05-10 14:05:07 +02:00
ftdm_unused_arg ( pool ) ;
2010-01-15 19:22:49 +00:00
ftdm_assert_return ( ptr ! = NULL , , " Attempted to free null pointer " ) ;
free ( ptr ) ;
}
2011-01-18 11:28:37 -05:00
FT_DECLARE ( void ) ftdm_set_echocancel_call_begin ( ftdm_channel_t * chan )
2010-09-28 13:55:46 -04:00
{
ftdm_caller_data_t * caller_data = ftdm_channel_get_caller_data ( chan ) ;
if ( ftdm_channel_test_feature ( chan , FTDM_CHANNEL_FEATURE_HWEC ) ) {
if ( ftdm_channel_test_feature ( chan , FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE ) ) {
2011-01-18 11:28:37 -05:00
/* If the ec is disabled on idle, we need to enable it unless is a digital call */
2011-05-17 17:13:38 -04:00
if ( caller_data - > bearer_capability ! = FTDM_BEARER_CAP_UNRESTRICTED ) {
2011-01-18 11:28:37 -05:00
ftdm_log_chan ( chan , FTDM_LOG_DEBUG , " Enabling ec for call in channel state %s \n " , ftdm_channel_state2str ( chan - > state ) ) ;
2010-09-28 13:55:46 -04:00
ftdm_channel_command ( chan , FTDM_COMMAND_ENABLE_ECHOCANCEL , NULL ) ;
}
} else {
2011-01-18 11:28:37 -05:00
/* If the ec is enabled on idle, we do nothing unless is a digital call that needs it disabled */
2011-05-17 17:13:38 -04:00
if ( caller_data - > bearer_capability = = FTDM_BEARER_CAP_UNRESTRICTED ) {
2011-01-18 11:28:37 -05:00
ftdm_log_chan ( chan , FTDM_LOG_DEBUG , " Disabling ec for digital call in channel state %s \n " , ftdm_channel_state2str ( chan - > state ) ) ;
2010-09-28 13:55:46 -04:00
ftdm_channel_command ( chan , FTDM_COMMAND_DISABLE_ECHOCANCEL , NULL ) ;
}
}
}
}
2011-01-18 11:28:37 -05:00
FT_DECLARE ( void ) ftdm_set_echocancel_call_end ( ftdm_channel_t * chan )
2010-09-28 13:55:46 -04:00
{
if ( ftdm_channel_test_feature ( chan , FTDM_CHANNEL_FEATURE_HWEC ) ) {
if ( ftdm_channel_test_feature ( chan , FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE ) ) {
2011-01-18 11:28:37 -05:00
ftdm_log_chan ( chan , FTDM_LOG_DEBUG , " Disabling ec on call end in channel state %s \n " , ftdm_channel_state2str ( chan - > state ) ) ;
ftdm_channel_command ( chan , FTDM_COMMAND_DISABLE_ECHOCANCEL , NULL ) ;
2010-09-28 13:55:46 -04:00
} else {
2011-01-18 11:28:37 -05:00
ftdm_log_chan ( chan , FTDM_LOG_DEBUG , " Enabling ec back on call end in channel state %s \n " , ftdm_channel_state2str ( chan - > state ) ) ;
ftdm_channel_command ( chan , FTDM_COMMAND_ENABLE_ECHOCANCEL , NULL ) ;
2010-09-28 13:55:46 -04:00
}
}
}
2010-01-15 19:22:49 +00:00
FT_DECLARE_DATA ftdm_memory_handler_t g_ftdm_mem_handler =
{
/*.pool =*/ NULL ,
/*.malloc =*/ ftdm_std_malloc ,
/*.calloc =*/ ftdm_std_calloc ,
2010-04-13 15:17:32 -04:00
/*.realloc =*/ ftdm_std_realloc ,
2010-01-15 19:22:49 +00:00
/*.free =*/ ftdm_std_free
} ;
FT_DECLARE_DATA ftdm_crash_policy_t g_ftdm_crash_policy = FTDM_CRASH_NEVER ;
2010-03-10 20:06:31 +00:00
static ftdm_status_t ftdm_set_caller_data ( ftdm_span_t * span , ftdm_caller_data_t * caller_data )
{
if ( ! caller_data ) {
ftdm_log ( FTDM_LOG_CRIT , " Error: trying to set caller data, but no caller_data! \n " ) ;
return FTDM_FAIL ;
}
2010-12-02 14:25:23 -05:00
if ( caller_data - > dnis . plan > = FTDM_NPI_INVALID ) {
2010-08-31 14:03:12 -04:00
caller_data - > dnis . plan = span - > default_caller_data . dnis . plan ;
}
2010-12-02 14:25:23 -05:00
if ( caller_data - > dnis . type > = FTDM_TON_INVALID ) {
2010-08-31 14:03:12 -04:00
caller_data - > dnis . type = span - > default_caller_data . dnis . type ;
}
2010-12-02 14:25:23 -05:00
if ( caller_data - > cid_num . plan > = FTDM_NPI_INVALID ) {
2010-03-10 20:06:31 +00:00
caller_data - > cid_num . plan = span - > default_caller_data . cid_num . plan ;
}
2010-12-02 14:25:23 -05:00
if ( caller_data - > cid_num . type > = FTDM_TON_INVALID ) {
2010-03-10 20:06:31 +00:00
caller_data - > cid_num . type = span - > default_caller_data . cid_num . type ;
}
2010-12-02 14:25:23 -05:00
if ( caller_data - > ani . plan > = FTDM_NPI_INVALID ) {
2010-03-10 20:06:31 +00:00
caller_data - > ani . plan = span - > default_caller_data . ani . plan ;
}
2010-12-02 14:25:23 -05:00
if ( caller_data - > ani . type > = FTDM_TON_INVALID ) {
2010-03-10 20:06:31 +00:00
caller_data - > ani . type = span - > default_caller_data . ani . type ;
}
2010-12-02 14:25:23 -05:00
if ( caller_data - > rdnis . plan > = FTDM_NPI_INVALID ) {
2010-03-10 20:06:31 +00:00
caller_data - > rdnis . plan = span - > default_caller_data . rdnis . plan ;
}
2010-12-02 14:25:23 -05:00
if ( caller_data - > rdnis . type > = FTDM_NPI_INVALID ) {
2010-03-10 20:06:31 +00:00
caller_data - > rdnis . type = span - > default_caller_data . rdnis . type ;
}
2010-08-31 14:03:12 -04:00
2014-05-01 14:32:23 -04:00
if ( caller_data - > bearer_capability > = FTDM_BEARER_CAP_INVALID ) {
2010-09-01 15:04:09 -04:00
caller_data - > bearer_capability = span - > default_caller_data . bearer_capability ;
}
2014-05-01 14:32:23 -04:00
if ( caller_data - > bearer_layer1 > = FTDM_USER_LAYER1_PROT_INVALID ) {
2010-09-01 15:04:09 -04:00
caller_data - > bearer_layer1 = span - > default_caller_data . bearer_layer1 ;
}
2010-08-31 14:03:12 -04:00
if ( FTDM_FAIL = = ftdm_is_number ( caller_data - > cid_num . digits ) ) {
ftdm_log ( FTDM_LOG_DEBUG , " dropping caller id number %s since we only accept digits \n " , caller_data - > cid_num . digits ) ;
caller_data - > cid_num . digits [ 0 ] = ' \0 ' ;
}
2010-03-10 20:06:31 +00:00
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_set_caller_data ( ftdm_channel_t * ftdmchan , ftdm_caller_data_t * caller_data )
{
ftdm_status_t err = FTDM_SUCCESS ;
if ( ! ftdmchan ) {
2011-05-10 23:35:20 -04:00
ftdm_log ( FTDM_LOG_CRIT , " trying to set caller data, but no ftdmchan! \n " ) ;
2010-03-10 20:06:31 +00:00
return FTDM_FAIL ;
}
if ( ( err = ftdm_set_caller_data ( ftdmchan - > span , caller_data ) ) ! = FTDM_SUCCESS ) {
return err ;
}
ftdmchan - > caller_data = * caller_data ;
2011-05-17 20:02:18 -04:00
if ( ftdmchan - > caller_data . bearer_capability = = FTDM_BEARER_CAP_UNRESTRICTED ) {
2011-05-10 23:35:20 -04:00
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_DIGITAL_MEDIA ) ;
}
2010-03-10 20:06:31 +00:00
return FTDM_SUCCESS ;
}
2010-01-15 19:22:49 +00:00
FT_DECLARE_DATA ftdm_logger_t ftdm_log = null_logger ;
FT_DECLARE ( void ) ftdm_global_set_crash_policy ( ftdm_crash_policy_t policy )
{
g_ftdm_crash_policy | = policy ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_global_set_memory_handler ( ftdm_memory_handler_t * handler )
{
if ( ! handler ) {
return FTDM_FAIL ;
}
if ( ! handler - > malloc ) {
return FTDM_FAIL ;
}
if ( ! handler - > calloc ) {
return FTDM_FAIL ;
}
if ( ! handler - > free ) {
return FTDM_FAIL ;
}
memcpy ( & g_ftdm_mem_handler , handler , sizeof ( * handler ) ) ;
return FTDM_SUCCESS ;
}
FT_DECLARE ( void ) ftdm_global_set_logger ( ftdm_logger_t logger )
{
if ( logger ) {
ftdm_log = logger ;
} else {
ftdm_log = null_logger ;
}
}
FT_DECLARE ( void ) ftdm_global_set_default_logger ( int level )
{
if ( level < 0 | | level > 7 ) {
level = 7 ;
}
ftdm_log = default_logger ;
ftdm_log_level = level ;
}
FT_DECLARE_NONSTD ( int ) ftdm_hash_equalkeys ( void * k1 , void * k2 )
{
return strcmp ( ( char * ) k1 , ( char * ) k2 ) ? 0 : 1 ;
}
FT_DECLARE_NONSTD ( uint32_t ) ftdm_hash_hashfromstring ( void * ky )
{
unsigned char * str = ( unsigned char * ) ky ;
uint32_t hash = 0 ;
int c ;
while ( ( c = * str + + ) ) {
hash = c + ( hash < < 6 ) + ( hash < < 16 ) - hash ;
}
return hash ;
}
static ftdm_status_t ftdm_channel_destroy ( ftdm_channel_t * ftdmchan )
{
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_CONFIGURED ) ) {
while ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_INTHREAD ) ) {
ftdm_log ( FTDM_LOG_INFO , " Waiting for thread to exit on channel %u:%u \n " , ftdmchan - > span_id , ftdmchan - > chan_id ) ;
ftdm_sleep ( 500 ) ;
}
ftdm_mutex_lock ( ftdmchan - > pre_buffer_mutex ) ;
ftdm_buffer_destroy ( & ftdmchan - > pre_buffer ) ;
ftdm_mutex_unlock ( ftdmchan - > pre_buffer_mutex ) ;
ftdm_buffer_destroy ( & ftdmchan - > digit_buffer ) ;
ftdm_buffer_destroy ( & ftdmchan - > gen_dtmf_buffer ) ;
ftdm_buffer_destroy ( & ftdmchan - > dtmf_buffer ) ;
ftdm_buffer_destroy ( & ftdmchan - > fsk_buffer ) ;
ftdmchan - > pre_buffer_size = 0 ;
ftdm_safe_free ( ftdmchan - > dtmf_hangup_buf ) ;
if ( ftdmchan - > tone_session . buffer ) {
teletone_destroy_session ( & ftdmchan - > tone_session ) ;
memset ( & ftdmchan - > tone_session , 0 , sizeof ( ftdmchan - > tone_session ) ) ;
}
2010-01-15 20:35:11 +00:00
if ( ftdmchan - > span - > fio - > channel_destroy ) {
2010-01-15 19:22:49 +00:00
ftdm_log ( FTDM_LOG_INFO , " Closing channel %s:%u:%u fd:%d \n " , ftdmchan - > span - > type , ftdmchan - > span_id , ftdmchan - > chan_id , ftdmchan - > sockfd ) ;
2010-01-15 20:35:11 +00:00
if ( ftdmchan - > span - > fio - > channel_destroy ( ftdmchan ) = = FTDM_SUCCESS ) {
2010-01-15 19:22:49 +00:00
ftdm_clear_flag_locked ( ftdmchan , FTDM_CHANNEL_CONFIGURED ) ;
} else {
ftdm_log ( FTDM_LOG_ERROR , " Error Closing channel %u:%u fd:%d \n " , ftdmchan - > span_id , ftdmchan - > chan_id , ftdmchan - > sockfd ) ;
}
}
ftdm_mutex_destroy ( & ftdmchan - > mutex ) ;
ftdm_mutex_destroy ( & ftdmchan - > pre_buffer_mutex ) ;
2010-12-31 13:44:20 -05:00
if ( ftdmchan - > state_completed_interrupt ) {
ftdm_interrupt_destroy ( & ftdmchan - > state_completed_interrupt ) ;
}
2010-01-15 19:22:49 +00:00
}
return FTDM_SUCCESS ;
}
static ftdm_status_t ftdm_span_destroy ( ftdm_span_t * span )
{
ftdm_status_t status = FTDM_SUCCESS ;
unsigned j ;
2014-07-13 00:34:04 -04:00
/* The signaling must be already stopped (this is just a sanity check, should never happen) */
ftdm_assert_return ( ! ftdm_test_flag ( span , FTDM_SPAN_STARTED ) , FTDM_FAIL , " Signaling for span %s has not been stopped, refusing to destroy span \n " ) ;
2011-01-10 17:46:18 -05:00
2014-07-13 00:34:04 -04:00
ftdm_mutex_lock ( span - > mutex ) ;
2010-01-15 19:22:49 +00:00
/* destroy the channels */
ftdm_clear_flag ( span , FTDM_SPAN_CONFIGURED ) ;
for ( j = 1 ; j < = span - > chan_count & & span - > channels [ j ] ; j + + ) {
ftdm_channel_t * cur_chan = span - > channels [ j ] ;
if ( cur_chan ) {
if ( ftdm_test_flag ( cur_chan , FTDM_CHANNEL_CONFIGURED ) ) {
ftdm_channel_destroy ( cur_chan ) ;
}
ftdm_safe_free ( cur_chan ) ;
cur_chan = NULL ;
}
}
/* destroy the I/O for the span */
2010-01-15 20:35:11 +00:00
if ( span - > fio & & span - > fio - > span_destroy ) {
2010-01-15 19:22:49 +00:00
ftdm_log ( FTDM_LOG_INFO , " Destroying span %u type (%s) \n " , span - > span_id , span - > type ) ;
2010-01-15 20:35:11 +00:00
if ( span - > fio - > span_destroy ( span ) ! = FTDM_SUCCESS ) {
2010-01-15 19:22:49 +00:00
status = FTDM_FAIL ;
}
}
/* destroy final basic resources of the span data structure */
2010-04-05 16:01:08 -04:00
if ( span - > pendingchans ) {
ftdm_queue_destroy ( & span - > pendingchans ) ;
}
2010-08-31 18:13:56 -04:00
if ( span - > pendingsignals ) {
2015-07-05 22:44:24 -04:00
ftdm_sigmsg_t * sigmsg = NULL ;
while ( ( sigmsg = ftdm_queue_dequeue ( span - > pendingsignals ) ) ) {
ftdm_sigmsg_free ( & sigmsg ) ;
}
2010-08-31 18:13:56 -04:00
ftdm_queue_destroy ( & span - > pendingsignals ) ;
}
2010-01-15 19:22:49 +00:00
ftdm_mutex_unlock ( span - > mutex ) ;
ftdm_mutex_destroy ( & span - > mutex ) ;
2014-07-22 20:53:28 -04:00
/* Give the span a chance to destroy its own signaling data */
if ( span - > destroy ) {
span - > destroy ( span ) ;
} else if ( span - > signal_data ) {
/* We take care of their dirty business ... */
ftdm_free ( span - > signal_data ) ;
}
2010-01-15 19:22:49 +00:00
return status ;
}
2010-04-21 11:20:05 -04:00
FT_DECLARE ( ftdm_status_t ) ftdm_channel_get_alarms ( ftdm_channel_t * ftdmchan , ftdm_alarm_flag_t * alarmbits )
2010-01-15 19:22:49 +00:00
{
ftdm_status_t status = FTDM_FAIL ;
2011-01-14 18:43:42 -05:00
ftdm_assert_return ( alarmbits ! = NULL , FTDM_EINVAL , " null alarmbits argument \n " ) ;
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_EINVAL , " null channel argument \n " ) ;
ftdm_assert_return ( ftdmchan - > span ! = NULL , FTDM_EINVAL , " null span \n " ) ;
ftdm_assert_return ( ftdmchan - > span - > fio ! = NULL , FTDM_EINVAL , " null io \n " ) ;
2010-04-21 11:20:05 -04:00
2010-04-21 14:25:11 -04:00
* alarmbits = FTDM_ALARM_NONE ;
2010-04-21 11:20:05 -04:00
2011-01-14 18:43:42 -05:00
if ( ! ftdmchan - > span - > fio - > get_alarms ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " No get_alarms interface for this channel \n " ) ;
return FTDM_ENOSYS ;
}
if ( ! ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_CONFIGURED ) ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " Cannot get alarms from an unconfigured channel \n " ) ;
return FTDM_EINVAL ;
}
2010-04-21 11:20:05 -04:00
ftdm_channel_lock ( ftdmchan ) ;
2011-01-14 18:43:42 -05:00
if ( ( status = ftdmchan - > span - > fio - > get_alarms ( ftdmchan ) ) ! = FTDM_SUCCESS ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " Failed to get alarms from channel \n " ) ;
goto done ;
}
2010-01-15 19:22:49 +00:00
2011-01-14 18:43:42 -05:00
* ftdmchan - > last_error = ' \0 ' ;
* alarmbits = ftdmchan - > alarm_flags ;
if ( ftdm_test_alarm_flag ( ftdmchan , FTDM_ALARM_RED ) ) {
snprintf ( ftdmchan - > last_error + strlen ( ftdmchan - > last_error ) , sizeof ( ftdmchan - > last_error ) - strlen ( ftdmchan - > last_error ) , " RED/ " ) ;
}
if ( ftdm_test_alarm_flag ( ftdmchan , FTDM_ALARM_YELLOW ) ) {
snprintf ( ftdmchan - > last_error + strlen ( ftdmchan - > last_error ) , sizeof ( ftdmchan - > last_error ) - strlen ( ftdmchan - > last_error ) , " YELLOW/ " ) ;
}
if ( ftdm_test_alarm_flag ( ftdmchan , FTDM_ALARM_RAI ) ) {
snprintf ( ftdmchan - > last_error + strlen ( ftdmchan - > last_error ) , sizeof ( ftdmchan - > last_error ) - strlen ( ftdmchan - > last_error ) , " RAI/ " ) ;
}
if ( ftdm_test_alarm_flag ( ftdmchan , FTDM_ALARM_BLUE ) ) {
snprintf ( ftdmchan - > last_error + strlen ( ftdmchan - > last_error ) , sizeof ( ftdmchan - > last_error ) - strlen ( ftdmchan - > last_error ) , " BLUE/ " ) ;
2010-01-15 19:22:49 +00:00
}
2011-01-14 18:43:42 -05:00
if ( ftdm_test_alarm_flag ( ftdmchan , FTDM_ALARM_AIS ) ) {
snprintf ( ftdmchan - > last_error + strlen ( ftdmchan - > last_error ) , sizeof ( ftdmchan - > last_error ) - strlen ( ftdmchan - > last_error ) , " AIS/ " ) ;
}
if ( ftdm_test_alarm_flag ( ftdmchan , FTDM_ALARM_GENERAL ) ) {
snprintf ( ftdmchan - > last_error + strlen ( ftdmchan - > last_error ) , sizeof ( ftdmchan - > last_error ) - strlen ( ftdmchan - > last_error ) , " GENERAL " ) ;
}
* ( ftdmchan - > last_error + strlen ( ftdmchan - > last_error ) - 1 ) = ' \0 ' ;
done :
2010-04-21 11:20:05 -04:00
ftdm_channel_unlock ( ftdmchan ) ;
2010-01-15 19:22:49 +00:00
return status ;
}
static void ftdm_span_add ( ftdm_span_t * span )
{
ftdm_span_t * sp ;
ftdm_mutex_lock ( globals . span_mutex ) ;
for ( sp = globals . spans ; sp & & sp - > next ; sp = sp - > next ) ;
if ( sp ) {
sp - > next = span ;
} else {
globals . spans = span ;
}
2010-09-08 19:41:34 -04:00
hashtable_insert ( globals . span_hash , ( void * ) span - > name , span , HASHTABLE_FLAG_FREE_VALUE ) ;
2010-01-15 19:22:49 +00:00
ftdm_mutex_unlock ( globals . span_mutex ) ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_span_stop ( ftdm_span_t * span )
{
2011-01-04 14:23:25 -05:00
ftdm_status_t status = FTDM_SUCCESS ;
ftdm_mutex_lock ( span - > mutex ) ;
2011-01-10 17:46:18 -05:00
if ( ftdm_test_flag ( span , FTDM_SPAN_NON_STOPPABLE ) ) {
status = FTDM_NOTIMPL ;
goto done ;
}
2011-01-04 14:23:25 -05:00
if ( ! ftdm_test_flag ( span , FTDM_SPAN_STARTED ) ) {
status = FTDM_EINVAL ;
goto done ;
}
if ( ! span - > stop ) {
status = FTDM_ENOSYS ;
goto done ;
2010-01-15 19:22:49 +00:00
}
2011-01-04 14:23:25 -05:00
2012-08-15 13:19:38 +02:00
/* Stop SIG */
2011-01-04 14:23:25 -05:00
status = span - > stop ( span ) ;
2012-08-15 13:19:38 +02:00
if ( status = = FTDM_SUCCESS ) {
2011-01-04 14:23:25 -05:00
ftdm_clear_flag ( span , FTDM_SPAN_STARTED ) ;
2010-01-15 19:22:49 +00:00
}
2011-01-04 14:23:25 -05:00
2012-08-15 13:19:38 +02:00
/* Stop I/O */
if ( span - > fio & & span - > fio - > span_stop ) {
status = span - > fio - > span_stop ( span ) ;
}
2011-01-04 14:23:25 -05:00
done :
ftdm_mutex_unlock ( span - > mutex ) ;
2010-05-25 16:06:42 -04:00
return status ;
2010-01-15 19:22:49 +00:00
}
2010-05-11 15:09:22 -04:00
FT_DECLARE ( ftdm_status_t ) ftdm_span_create ( const char * iotype , const char * name , ftdm_span_t * * span )
2010-01-15 19:22:49 +00:00
{
ftdm_span_t * new_span = NULL ;
2010-05-11 15:09:22 -04:00
ftdm_io_interface_t * fio = NULL ;
2010-01-15 19:22:49 +00:00
ftdm_status_t status = FTDM_FAIL ;
2010-05-11 15:09:22 -04:00
char buf [ 128 ] = " " ;
2010-01-15 19:22:49 +00:00
2010-05-11 15:09:22 -04:00
ftdm_assert_return ( iotype ! = NULL , FTDM_FAIL , " No IO type provided \n " ) ;
ftdm_assert_return ( name ! = NULL , FTDM_FAIL , " No span name provided \n " ) ;
* span = NULL ;
2010-01-15 19:22:49 +00:00
2013-06-02 02:56:44 +02:00
fio = ftdm_global_get_io_interface ( iotype , FTDM_TRUE ) ;
2010-05-11 15:09:22 -04:00
if ( ! fio ) {
ftdm_log ( FTDM_LOG_CRIT , " failure creating span, no such I/O type '%s' \n " , iotype ) ;
return FTDM_FAIL ;
}
if ( ! fio - > configure_span ) {
ftdm_log ( FTDM_LOG_CRIT , " failure creating span, no configure_span method for I/O type '%s' \n " , iotype ) ;
return FTDM_FAIL ;
}
ftdm_mutex_lock ( globals . mutex ) ;
2010-01-15 19:22:49 +00:00
if ( globals . span_index < FTDM_MAX_SPANS_INTERFACE ) {
2010-03-12 18:27:24 +00:00
new_span = ftdm_calloc ( sizeof ( * new_span ) , 1 ) ;
2010-05-11 15:09:22 -04:00
2010-03-12 18:27:24 +00:00
ftdm_assert ( new_span , " allocating span failed \n " ) ;
2010-01-15 19:22:49 +00:00
status = ftdm_mutex_create ( & new_span - > mutex ) ;
2010-03-12 18:27:24 +00:00
ftdm_assert ( status = = FTDM_SUCCESS , " mutex creation failed \n " ) ;
2010-01-15 19:22:49 +00:00
ftdm_set_flag ( new_span , FTDM_SPAN_CONFIGURED ) ;
new_span - > span_id = + + globals . span_index ;
2010-01-15 20:35:11 +00:00
new_span - > fio = fio ;
2010-01-15 19:22:49 +00:00
ftdm_copy_string ( new_span - > tone_map [ FTDM_TONEMAP_DIAL ] , " %(1000,0,350,440) " , FTDM_TONEMAP_LEN ) ;
ftdm_copy_string ( new_span - > tone_map [ FTDM_TONEMAP_RING ] , " %(2000,4000,440,480) " , FTDM_TONEMAP_LEN ) ;
ftdm_copy_string ( new_span - > tone_map [ FTDM_TONEMAP_BUSY ] , " %(500,500,480,620) " , FTDM_TONEMAP_LEN ) ;
ftdm_copy_string ( new_span - > tone_map [ FTDM_TONEMAP_ATTN ] , " %(100,100,1400,2060,2450,2600) " , FTDM_TONEMAP_LEN ) ;
new_span - > trunk_type = FTDM_TRUNK_NONE ;
2012-07-11 19:15:35 +02:00
new_span - > trunk_mode = FTDM_TRUNK_MODE_CPE ;
2010-01-15 19:22:49 +00:00
new_span - > data_type = FTDM_TYPE_SPAN ;
ftdm_mutex_lock ( globals . span_mutex ) ;
if ( ! ftdm_strlen_zero ( name ) & & hashtable_search ( globals . span_hash , ( void * ) name ) ) {
ftdm_log ( FTDM_LOG_WARNING , " name %s is already used, substituting 'span%d' as the name \n " , name , new_span - > span_id ) ;
name = NULL ;
}
ftdm_mutex_unlock ( globals . span_mutex ) ;
if ( ! name ) {
snprintf ( buf , sizeof ( buf ) , " span%d " , new_span - > span_id ) ;
name = buf ;
}
new_span - > name = ftdm_strdup ( name ) ;
2010-05-11 15:09:22 -04:00
new_span - > type = ftdm_strdup ( iotype ) ;
2010-01-15 19:22:49 +00:00
ftdm_span_add ( new_span ) ;
* span = new_span ;
status = FTDM_SUCCESS ;
}
ftdm_mutex_unlock ( globals . mutex ) ;
return status ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_span_close_all ( void )
{
ftdm_span_t * span ;
uint32_t i = 0 , j ;
ftdm_mutex_lock ( globals . span_mutex ) ;
for ( span = globals . spans ; span ; span = span - > next ) {
if ( ftdm_test_flag ( span , FTDM_SPAN_CONFIGURED ) ) {
for ( j = 1 ; j < = span - > chan_count & & span - > channels [ j ] ; j + + ) {
ftdm_channel_t * toclose = span - > channels [ j ] ;
if ( ftdm_test_flag ( toclose , FTDM_CHANNEL_INUSE ) ) {
ftdm_channel_close ( & toclose ) ;
}
i + + ;
}
}
}
ftdm_mutex_unlock ( globals . span_mutex ) ;
return i ? FTDM_SUCCESS : FTDM_FAIL ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_span_load_tones ( ftdm_span_t * span , const char * mapname )
{
ftdm_config_t cfg ;
char * var , * val ;
int x = 0 ;
if ( ! ftdm_config_open_file ( & cfg , " tones.conf " ) ) {
snprintf ( span - > last_error , sizeof ( span - > last_error ) , " error loading tones. " ) ;
return FTDM_FAIL ;
}
while ( ftdm_config_next_pair ( & cfg , & var , & val ) ) {
int detect = 0 ;
if ( ! strcasecmp ( cfg . category , mapname ) & & var & & val ) {
uint32_t index ;
char * name = NULL ;
if ( ! strncasecmp ( var , " detect- " , 7 ) ) {
name = var + 7 ;
detect = 1 ;
} else if ( ! strncasecmp ( var , " generate- " , 9 ) ) {
name = var + 9 ;
} else {
ftdm_log ( FTDM_LOG_WARNING , " Unknown tone name %s \n " , var ) ;
continue ;
}
index = ftdm_str2ftdm_tonemap ( name ) ;
if ( index > = FTDM_TONEMAP_INVALID | | index = = FTDM_TONEMAP_NONE ) {
ftdm_log ( FTDM_LOG_WARNING , " Unknown tone name %s \n " , name ) ;
} else {
if ( detect ) {
char * p = val , * next ;
int i = 0 ;
do {
teletone_process_t this ;
next = strchr ( p , ' , ' ) ;
this = ( teletone_process_t ) atof ( p ) ;
span - > tone_detect_map [ index ] . freqs [ i + + ] = this ;
if ( next ) {
p = next + 1 ;
}
} while ( next ) ;
ftdm_log ( FTDM_LOG_DEBUG , " added tone detect [%s] = [%s] \n " , name , val ) ;
} else {
ftdm_log ( FTDM_LOG_DEBUG , " added tone generation [%s] = [%s] \n " , name , val ) ;
ftdm_copy_string ( span - > tone_map [ index ] , val , sizeof ( span - > tone_map [ index ] ) ) ;
}
x + + ;
}
}
}
ftdm_config_close_file ( & cfg ) ;
if ( ! x ) {
snprintf ( span - > last_error , sizeof ( span - > last_error ) , " error loading tones. " ) ;
return FTDM_FAIL ;
}
return FTDM_SUCCESS ;
}
# define FTDM_SLINEAR_MAX_VALUE 32767
# define FTDM_SLINEAR_MIN_VALUE -32767
2010-04-06 12:04:46 -04:00
static void reset_gain_table ( uint8_t * gain_table , float new_gain , ftdm_codec_t codec_gain )
2010-01-15 19:22:49 +00:00
{
/* sample value */
2010-04-06 12:04:46 -04:00
uint8_t sv = 0 ;
2010-01-15 19:22:49 +00:00
/* linear gain factor */
float lingain = 0 ;
/* linear value for each table sample */
float linvalue = 0 ;
/* amplified (or attenuated in case of negative amplification) sample value */
int ampvalue = 0 ;
/* gain tables are only for alaw and ulaw */
if ( codec_gain ! = FTDM_CODEC_ALAW & & codec_gain ! = FTDM_CODEC_ULAW ) {
2014-05-10 02:56:06 -04:00
ftdm_log ( FTDM_LOG_DEBUG , " Not resetting gain table because codec is not ALAW or ULAW but %d \n " , codec_gain ) ;
2010-01-15 19:22:49 +00:00
return ;
}
if ( ! new_gain ) {
/* for a 0.0db gain table, each alaw/ulaw sample value is left untouched (0 ==0, 1 == 1, 2 == 2 etc)*/
2010-01-15 21:58:36 +00:00
sv = 0 ;
while ( 1 ) {
2010-01-15 19:22:49 +00:00
gain_table [ sv ] = sv ;
2010-01-15 21:58:36 +00:00
if ( sv = = ( FTDM_GAINS_TABLE_SIZE - 1 ) ) {
break ;
}
sv + + ;
2010-01-15 19:22:49 +00:00
}
return ;
}
/* use the 20log rule to increase the gain: http://en.wikipedia.org/wiki/Gain, http:/en.wipedia.org/wiki/20_log_rule#Definitions */
2010-01-15 21:43:41 +00:00
lingain = ( float ) pow ( 10.0 , new_gain / 20.0 ) ;
2010-01-15 21:58:36 +00:00
sv = 0 ;
while ( 1 ) {
2010-01-15 19:22:49 +00:00
/* get the linear value for this alaw/ulaw sample value */
2010-01-15 21:43:41 +00:00
linvalue = codec_gain = = FTDM_CODEC_ALAW ? ( float ) alaw_to_linear ( sv ) : ( float ) ulaw_to_linear ( sv ) ;
2010-01-15 19:22:49 +00:00
/* multiply the linear value and the previously calculated linear gain */
ampvalue = ( int ) ( linvalue * lingain ) ;
/* chop it if goes beyond the limits */
if ( ampvalue > FTDM_SLINEAR_MAX_VALUE ) {
ampvalue = FTDM_SLINEAR_MAX_VALUE ;
}
if ( ampvalue < FTDM_SLINEAR_MIN_VALUE ) {
ampvalue = FTDM_SLINEAR_MIN_VALUE ;
}
gain_table [ sv ] = codec_gain = = FTDM_CODEC_ALAW ? linear_to_alaw ( ampvalue ) : linear_to_ulaw ( ampvalue ) ;
2010-01-15 21:58:36 +00:00
if ( sv = = ( FTDM_GAINS_TABLE_SIZE - 1 ) ) {
break ;
}
sv + + ;
2010-01-15 19:22:49 +00:00
}
}
FT_DECLARE ( ftdm_status_t ) ftdm_span_add_channel ( ftdm_span_t * span , ftdm_socket_t sockfd , ftdm_chan_type_t type , ftdm_channel_t * * chan )
{
2010-01-15 21:43:41 +00:00
unsigned char i = 0 ;
2010-01-15 19:22:49 +00:00
if ( span - > chan_count < FTDM_MAX_CHANNELS_SPAN ) {
ftdm_channel_t * new_chan = span - > channels [ + + span - > chan_count ] ;
if ( ! new_chan ) {
2010-08-23 15:44:55 -04:00
# ifdef FTDM_DEBUG_CHAN_MEMORY
void * chanmem = NULL ;
int pages = 1 ;
int pagesize = sysconf ( _SC_PAGE_SIZE ) ;
if ( sizeof ( * new_chan ) > pagesize ) {
pages = sizeof ( * new_chan ) / pagesize ;
pages + + ;
}
ftdm_log ( FTDM_LOG_DEBUG , " Allocating %d pages of %d bytes for channel of size %d \n " , pages , pagesize , sizeof ( * new_chan ) ) ;
if ( posix_memalign ( & chanmem , pagesize , pagesize * pages ) ) {
return FTDM_FAIL ;
}
ftdm_log ( FTDM_LOG_DEBUG , " Channel pages allocated start at mem %p \n " , chanmem ) ;
memset ( chanmem , 0 , sizeof ( * new_chan ) ) ;
new_chan = chanmem ;
# else
2010-01-15 19:22:49 +00:00
if ( ! ( new_chan = ftdm_calloc ( 1 , sizeof ( * new_chan ) ) ) ) {
return FTDM_FAIL ;
}
2010-08-23 15:44:55 -04:00
# endif
2010-01-15 19:22:49 +00:00
span - > channels [ span - > chan_count ] = new_chan ;
}
new_chan - > type = type ;
new_chan - > sockfd = sockfd ;
2010-01-15 20:35:11 +00:00
new_chan - > fio = span - > fio ;
2010-01-15 19:22:49 +00:00
new_chan - > span_id = span - > span_id ;
new_chan - > chan_id = span - > chan_count ;
new_chan - > span = span ;
2010-05-28 15:06:51 -04:00
new_chan - > fds [ FTDM_READ_TRACE_INDEX ] = - 1 ;
new_chan - > fds [ FTDM_WRITE_TRACE_INDEX ] = - 1 ;
2010-01-15 19:22:49 +00:00
new_chan - > data_type = FTDM_TYPE_CHANNEL ;
if ( ! new_chan - > dtmf_on ) {
new_chan - > dtmf_on = FTDM_DEFAULT_DTMF_ON ;
}
if ( ! new_chan - > dtmf_off ) {
new_chan - > dtmf_off = FTDM_DEFAULT_DTMF_OFF ;
}
ftdm_mutex_create ( & new_chan - > mutex ) ;
ftdm_mutex_create ( & new_chan - > pre_buffer_mutex ) ;
ftdm_buffer_create ( & new_chan - > digit_buffer , 128 , 128 , 0 ) ;
ftdm_buffer_create ( & new_chan - > gen_dtmf_buffer , 128 , 128 , 0 ) ;
new_chan - > dtmf_hangup_buf = ftdm_calloc ( span - > dtmf_hangup_len + 1 , sizeof ( char ) ) ;
/* set 0.0db gain table */
2010-01-15 21:58:36 +00:00
i = 0 ;
while ( 1 ) {
2010-01-15 19:22:49 +00:00
new_chan - > txgain_table [ i ] = i ;
new_chan - > rxgain_table [ i ] = i ;
2010-01-15 21:58:36 +00:00
if ( i = = ( sizeof ( new_chan - > txgain_table ) - 1 ) ) {
break ;
}
i + + ;
2010-01-15 19:22:49 +00:00
}
2012-06-20 16:28:00 -04:00
ftdm_set_flag ( new_chan , FTDM_CHANNEL_CONFIGURED | FTDM_CHANNEL_READY ) ;
2010-12-29 13:38:43 -05:00
new_chan - > state = FTDM_CHANNEL_STATE_DOWN ;
new_chan - > state_status = FTDM_STATE_STATUS_COMPLETED ;
2010-01-15 19:22:49 +00:00
* chan = new_chan ;
return FTDM_SUCCESS ;
}
return FTDM_FAIL ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_span_find_by_name ( const char * name , ftdm_span_t * * span )
{
ftdm_status_t status = FTDM_FAIL ;
ftdm_mutex_lock ( globals . span_mutex ) ;
if ( ! ftdm_strlen_zero ( name ) ) {
if ( ( * span = hashtable_search ( globals . span_hash , ( void * ) name ) ) ) {
status = FTDM_SUCCESS ;
} else {
int span_id = atoi ( name ) ;
ftdm_span_find ( span_id , span ) ;
if ( * span ) {
status = FTDM_SUCCESS ;
}
}
}
ftdm_mutex_unlock ( globals . span_mutex ) ;
return status ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_span_find ( uint32_t id , ftdm_span_t * * span )
{
ftdm_span_t * fspan = NULL , * sp ;
if ( id > FTDM_MAX_SPANS_INTERFACE ) {
return FTDM_FAIL ;
}
ftdm_mutex_lock ( globals . span_mutex ) ;
for ( sp = globals . spans ; sp ; sp = sp - > next ) {
if ( sp - > span_id = = id ) {
fspan = sp ;
break ;
}
}
ftdm_mutex_unlock ( globals . span_mutex ) ;
if ( ! fspan | | ! ftdm_test_flag ( fspan , FTDM_SPAN_CONFIGURED ) ) {
return FTDM_FAIL ;
}
* span = fspan ;
return FTDM_SUCCESS ;
}
2010-09-23 17:51:45 -03:00
FT_DECLARE ( ftdm_status_t ) ftdm_span_poll_event ( ftdm_span_t * span , uint32_t ms , short * poll_events )
2010-01-15 19:22:49 +00:00
{
2010-01-15 20:35:11 +00:00
assert ( span - > fio ! = NULL ) ;
2010-01-15 19:22:49 +00:00
2010-01-15 20:35:11 +00:00
if ( span - > fio - > poll_event ) {
2010-09-23 17:51:45 -03:00
return span - > fio - > poll_event ( span , ms , poll_events ) ;
2010-01-15 19:22:49 +00:00
} else {
2010-01-15 20:35:11 +00:00
ftdm_log ( FTDM_LOG_ERROR , " poll_event method not implemented in module %s! " , span - > fio - > name ) ;
2010-01-15 19:22:49 +00:00
}
return FTDM_NOTIMPL ;
}
2010-12-22 17:35:55 -02:00
/* handle oob events and send the proper SIGEVENT signal to user, when applicable */
static __inline__ ftdm_status_t ftdm_event_handle_oob ( ftdm_event_t * event )
2010-01-15 19:22:49 +00:00
{
2010-03-10 21:47:28 +00:00
ftdm_sigmsg_t sigmsg ;
2010-12-22 17:35:55 -02:00
ftdm_status_t status = FTDM_SUCCESS ;
ftdm_channel_t * fchan = event - > channel ;
ftdm_span_t * span = fchan - > span ;
2010-03-10 21:47:28 +00:00
memset ( & sigmsg , 0 , sizeof ( sigmsg ) ) ;
sigmsg . span_id = span - > span_id ;
2010-12-22 17:35:55 -02:00
sigmsg . chan_id = fchan - > chan_id ;
sigmsg . channel = fchan ;
switch ( event - > enum_id ) {
2010-11-24 21:25:24 -02:00
case FTDM_OOB_ALARM_CLEAR :
{
sigmsg . event_id = FTDM_SIGEVENT_ALARM_CLEAR ;
2010-12-22 17:35:55 -02:00
ftdm_clear_flag_locked ( fchan , FTDM_CHANNEL_IN_ALARM ) ;
status = ftdm_span_send_signal ( span , & sigmsg ) ;
2010-11-24 21:25:24 -02:00
}
break ;
case FTDM_OOB_ALARM_TRAP :
{
sigmsg . event_id = FTDM_SIGEVENT_ALARM_TRAP ;
2010-12-22 17:35:55 -02:00
ftdm_set_flag_locked ( fchan , FTDM_CHANNEL_IN_ALARM ) ;
status = ftdm_span_send_signal ( span , & sigmsg ) ;
2010-11-24 21:25:24 -02:00
}
break ;
default :
/* NOOP */
break ;
}
2010-12-22 17:35:55 -02:00
return status ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_span_next_event ( ftdm_span_t * span , ftdm_event_t * * event )
{
ftdm_status_t status = FTDM_FAIL ;
ftdm_assert_return ( span - > fio ! = NULL , FTDM_FAIL , " No I/O module attached to this span! \n " ) ;
if ( ! span - > fio - > next_event ) {
ftdm_log ( FTDM_LOG_ERROR , " next_event method not implemented in module %s! " , span - > fio - > name ) ;
return FTDM_NOTIMPL ;
}
2010-11-24 21:25:24 -02:00
2010-12-22 17:35:55 -02:00
status = span - > fio - > next_event ( span , event ) ;
if ( status ! = FTDM_SUCCESS ) {
return status ;
}
status = ftdm_event_handle_oob ( * event ) ;
if ( status ! = FTDM_SUCCESS ) {
2012-02-10 13:29:49 +01:00
ftdm_log ( FTDM_LOG_ERROR , " failed to handle event %d \n " , ( * event ) - > e_type ) ;
2010-12-22 17:35:55 -02:00
}
2010-11-24 21:25:24 -02:00
return status ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_read_event ( ftdm_channel_t * ftdmchan , ftdm_event_t * * event )
{
ftdm_status_t status = FTDM_FAIL ;
ftdm_span_t * span = ftdmchan - > span ;
ftdm_assert_return ( span - > fio ! = NULL , FTDM_FAIL , " No I/O module attached to this span! \n " ) ;
2010-12-21 16:32:02 -02:00
ftdm_channel_lock ( ftdmchan ) ;
2010-11-24 21:25:24 -02:00
if ( ! span - > fio - > channel_next_event ) {
2012-01-19 16:18:30 -02:00
ftdm_log ( FTDM_LOG_ERROR , " channel_next_event method not implemented in module %s! \n " , span - > fio - > name ) ;
2010-12-21 16:32:02 -02:00
status = FTDM_NOTIMPL ;
goto done ;
2010-11-24 21:25:24 -02:00
}
2011-05-26 11:38:24 -04:00
if ( ftdm_test_io_flag ( ftdmchan , FTDM_CHANNEL_IO_EVENT ) ) {
ftdm_clear_io_flag ( ftdmchan , FTDM_CHANNEL_IO_EVENT ) ;
}
2010-11-24 21:25:24 -02:00
status = span - > fio - > channel_next_event ( ftdmchan , event ) ;
if ( status ! = FTDM_SUCCESS ) {
2010-12-21 16:32:02 -02:00
goto done ;
2010-11-24 21:25:24 -02:00
}
2010-12-22 17:35:55 -02:00
status = ftdm_event_handle_oob ( * event ) ;
if ( status ! = FTDM_SUCCESS ) {
2012-02-10 13:29:49 +01:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_ERROR , " failed to handle event %d \n " , ( * event ) - > e_type ) ;
2010-03-10 21:47:28 +00:00
}
2010-12-21 16:32:02 -02:00
done :
ftdm_channel_unlock ( ftdmchan ) ;
2010-03-10 21:47:28 +00:00
return status ;
2010-01-15 19:22:49 +00:00
}
static ftdm_status_t ftdmchan_fsk_write_sample ( int16_t * buf , ftdm_size_t buflen , void * user_data )
{
ftdm_channel_t * ftdmchan = ( ftdm_channel_t * ) user_data ;
ftdm_buffer_write ( ftdmchan - > fsk_buffer , buf , buflen * 2 ) ;
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_send_fsk_data ( ftdm_channel_t * ftdmchan , ftdm_fsk_data_state_t * fsk_data , float db_level )
{
struct ftdm_fsk_modulator fsk_trans ;
if ( ! ftdmchan - > fsk_buffer ) {
ftdm_buffer_create ( & ftdmchan - > fsk_buffer , 128 , 128 , 0 ) ;
} else {
ftdm_buffer_zero ( ftdmchan - > fsk_buffer ) ;
}
if ( ftdmchan - > token_count > 1 ) {
ftdm_fsk_modulator_init ( & fsk_trans , FSK_BELL202 , ftdmchan - > rate , fsk_data , db_level , 80 , 5 , 0 , ftdmchan_fsk_write_sample , ftdmchan ) ;
ftdm_fsk_modulator_send_all ( ( & fsk_trans ) ) ;
} else {
ftdm_fsk_modulator_init ( & fsk_trans , FSK_BELL202 , ftdmchan - > rate , fsk_data , db_level , 180 , 5 , 300 , ftdmchan_fsk_write_sample , ftdmchan ) ;
ftdm_fsk_modulator_send_all ( ( & fsk_trans ) ) ;
ftdmchan - > buffer_delay = 3500 / ftdmchan - > effective_interval ;
}
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_clear_token ( ftdm_channel_t * ftdmchan , const char * token )
{
ftdm_status_t status = FTDM_FAIL ;
ftdm_mutex_lock ( ftdmchan - > mutex ) ;
if ( token = = NULL ) {
memset ( ftdmchan - > tokens , 0 , sizeof ( ftdmchan - > tokens ) ) ;
ftdmchan - > token_count = 0 ;
} else if ( * token ! = ' \0 ' ) {
char tokens [ FTDM_MAX_TOKENS ] [ FTDM_TOKEN_STRLEN ] ;
int32_t i , count = ftdmchan - > token_count ;
memcpy ( tokens , ftdmchan - > tokens , sizeof ( tokens ) ) ;
memset ( ftdmchan - > tokens , 0 , sizeof ( ftdmchan - > tokens ) ) ;
ftdmchan - > token_count = 0 ;
for ( i = 0 ; i < count ; i + + ) {
if ( strcmp ( tokens [ i ] , token ) ) {
ftdm_copy_string ( ftdmchan - > tokens [ ftdmchan - > token_count ] , tokens [ i ] , sizeof ( ftdmchan - > tokens [ ftdmchan - > token_count ] ) ) ;
ftdmchan - > token_count + + ;
}
}
status = FTDM_SUCCESS ;
}
ftdm_mutex_unlock ( ftdmchan - > mutex ) ;
return status ;
}
FT_DECLARE ( void ) ftdm_channel_rotate_tokens ( ftdm_channel_t * ftdmchan )
{
if ( ftdmchan - > token_count ) {
memmove ( ftdmchan - > tokens [ 1 ] , ftdmchan - > tokens [ 0 ] , ftdmchan - > token_count * FTDM_TOKEN_STRLEN ) ;
ftdm_copy_string ( ftdmchan - > tokens [ 0 ] , ftdmchan - > tokens [ ftdmchan - > token_count ] , FTDM_TOKEN_STRLEN ) ;
* ftdmchan - > tokens [ ftdmchan - > token_count ] = ' \0 ' ;
}
}
FT_DECLARE ( void ) ftdm_channel_replace_token ( ftdm_channel_t * ftdmchan , const char * old_token , const char * new_token )
{
unsigned int i ;
if ( ftdmchan - > token_count ) {
for ( i = 0 ; i < ftdmchan - > token_count ; i + + ) {
if ( ! strcmp ( ftdmchan - > tokens [ i ] , old_token ) ) {
ftdm_copy_string ( ftdmchan - > tokens [ i ] , new_token , FTDM_TOKEN_STRLEN ) ;
break ;
}
}
}
}
2010-05-20 11:43:40 -04:00
FT_DECLARE ( void ) ftdm_channel_set_private ( ftdm_channel_t * ftdmchan , void * pvt )
{
ftdmchan - > user_private = pvt ;
}
FT_DECLARE ( void * ) ftdm_channel_get_private ( const ftdm_channel_t * ftdmchan )
{
return ftdmchan - > user_private ;
}
2010-04-21 11:20:05 -04:00
FT_DECLARE ( uint32_t ) ftdm_channel_get_token_count ( const ftdm_channel_t * ftdmchan )
{
uint32_t count ;
ftdm_mutex_lock ( ftdmchan - > mutex ) ;
count = ftdmchan - > token_count ;
ftdm_mutex_unlock ( ftdmchan - > mutex ) ;
return count ;
}
FT_DECLARE ( uint32_t ) ftdm_channel_get_io_interval ( const ftdm_channel_t * ftdmchan )
{
uint32_t count ;
ftdm_mutex_lock ( ftdmchan - > mutex ) ;
count = ftdmchan - > effective_interval ;
ftdm_mutex_unlock ( ftdmchan - > mutex ) ;
return count ;
}
FT_DECLARE ( uint32_t ) ftdm_channel_get_io_packet_len ( const ftdm_channel_t * ftdmchan )
{
uint32_t count ;
ftdm_mutex_lock ( ftdmchan - > mutex ) ;
count = ftdmchan - > packet_len ;
ftdm_mutex_unlock ( ftdmchan - > mutex ) ;
return count ;
}
FT_DECLARE ( uint32_t ) ftdm_channel_get_type ( const ftdm_channel_t * ftdmchan )
{
return ftdmchan - > type ;
}
FT_DECLARE ( ftdm_codec_t ) ftdm_channel_get_codec ( const ftdm_channel_t * ftdmchan )
{
return ftdmchan - > effective_codec ;
}
FT_DECLARE ( const char * ) ftdm_channel_get_token ( const ftdm_channel_t * ftdmchan , uint32_t tokenid )
{
const char * token = NULL ;
ftdm_mutex_lock ( ftdmchan - > mutex ) ;
if ( ftdmchan - > token_count < = tokenid ) {
ftdm_mutex_unlock ( ftdmchan - > mutex ) ;
return NULL ;
}
token = ftdmchan - > tokens [ tokenid ] ;
ftdm_mutex_unlock ( ftdmchan - > mutex ) ;
return token ;
}
2010-01-15 19:22:49 +00:00
FT_DECLARE ( ftdm_status_t ) ftdm_channel_add_token ( ftdm_channel_t * ftdmchan , char * token , int end )
{
ftdm_status_t status = FTDM_FAIL ;
ftdm_mutex_lock ( ftdmchan - > mutex ) ;
if ( ftdmchan - > token_count < FTDM_MAX_TOKENS ) {
if ( end ) {
ftdm_copy_string ( ftdmchan - > tokens [ ftdmchan - > token_count + + ] , token , FTDM_TOKEN_STRLEN ) ;
} else {
memmove ( ftdmchan - > tokens [ 1 ] , ftdmchan - > tokens [ 0 ] , ftdmchan - > token_count * FTDM_TOKEN_STRLEN ) ;
ftdm_copy_string ( ftdmchan - > tokens [ 0 ] , token , FTDM_TOKEN_STRLEN ) ;
ftdmchan - > token_count + + ;
}
status = FTDM_SUCCESS ;
}
ftdm_mutex_unlock ( ftdmchan - > mutex ) ;
return status ;
}
2010-04-21 11:20:05 -04:00
FT_DECLARE ( uint32_t ) ftdm_group_get_id ( const ftdm_group_t * group )
{
return group - > group_id ;
}
2010-01-15 19:22:49 +00:00
FT_DECLARE ( ftdm_status_t ) ftdm_group_channel_use_count ( ftdm_group_t * group , uint32_t * count )
{
uint32_t j ;
* count = 0 ;
if ( ! group ) {
return FTDM_FAIL ;
}
for ( j = 0 ; j < group - > chan_count & & group - > channels [ j ] ; j + + ) {
if ( group - > channels [ j ] ) {
if ( ftdm_test_flag ( group - > channels [ j ] , FTDM_CHANNEL_INUSE ) ) {
( * count ) + + ;
}
}
}
return FTDM_SUCCESS ;
}
2010-06-07 21:45:24 -04:00
static __inline__ int chan_is_avail ( ftdm_channel_t * check )
{
2012-08-17 19:05:12 -04:00
if ( ( check - > span - > signal_type = = FTDM_SIGTYPE_M2UA ) | |
( check - > span - > signal_type = = FTDM_SIGTYPE_NONE ) ) {
2012-07-25 20:41:01 -04:00
if ( ! ftdm_test_flag ( check , FTDM_CHANNEL_READY ) | |
ftdm_test_flag ( check , FTDM_CHANNEL_INUSE ) | |
ftdm_test_flag ( check , FTDM_CHANNEL_SUSPENDED ) | |
ftdm_test_flag ( check , FTDM_CHANNEL_IN_ALARM ) | |
check - > state ! = FTDM_CHANNEL_STATE_DOWN ) {
return 0 ;
}
} else {
if ( ! ftdm_test_flag ( check , FTDM_CHANNEL_READY ) | |
! ftdm_test_flag ( check , FTDM_CHANNEL_SIG_UP ) | |
ftdm_test_flag ( check , FTDM_CHANNEL_INUSE ) | |
ftdm_test_flag ( check , FTDM_CHANNEL_SUSPENDED ) | |
ftdm_test_flag ( check , FTDM_CHANNEL_IN_ALARM ) | |
check - > state ! = FTDM_CHANNEL_STATE_DOWN ) {
return 0 ;
}
2010-06-07 21:45:24 -04:00
}
2014-07-23 00:40:27 -04:00
/* release guard time check */
if ( check - > span - > sig_release_guard_time_ms & & check - > last_release_time ) {
2014-11-09 00:41:59 -08:00
ftdm_time_t time_diff = ( ftdm_current_time_in_ms ( ) - check - > last_release_time ) ;
2014-07-23 00:40:27 -04:00
if ( time_diff < check - > span - > sig_release_guard_time_ms ) {
return 0 ;
}
/* circuit now available for outbound dialing */
check - > last_release_time = 0 ;
2014-11-25 15:38:45 +01:00
ftdm_log_chan ( check , FTDM_LOG_DEBUG , " Channel is now available, release guard timer expired % " FTDM_UINT64_FMT " ms ago \n " , ( time_diff - check - > span - > sig_release_guard_time_ms ) ) ;
2014-07-23 00:40:27 -04:00
}
2010-06-07 21:45:24 -04:00
return 1 ;
}
2010-07-30 19:46:05 -04:00
static __inline__ int chan_voice_is_avail ( ftdm_channel_t * check )
{
if ( ! FTDM_IS_VOICE_CHANNEL ( check ) ) {
return 0 ;
}
return chan_is_avail ( check ) ;
}
static __inline__ int request_voice_channel ( ftdm_channel_t * check , ftdm_channel_t * * ftdmchan ,
2014-01-10 21:14:55 -05:00
ftdm_caller_data_t * caller_data , ftdm_hunt_direction_t direction )
2010-06-07 21:45:24 -04:00
{
ftdm_status_t status ;
2010-07-30 19:46:05 -04:00
if ( chan_voice_is_avail ( check ) ) {
2010-06-07 21:45:24 -04:00
/* unlocked testing passed, try again with the channel locked */
ftdm_mutex_lock ( check - > mutex ) ;
2010-07-30 19:46:05 -04:00
if ( chan_voice_is_avail ( check ) ) {
2010-06-07 21:45:24 -04:00
if ( check - > span & & check - > span - > channel_request ) {
/* I am only unlocking here cuz this function is called
* sometimes with the group or span lock held and were
* blocking anyone hunting for channels available and
* I believe teh channel_request ( ) function may take
2011-01-10 16:49:58 -05:00
* a bit of time . However channel_request is a callback
* used by boost and may be only a few other old sig mods
* and it should be deprecated */
2010-06-07 21:45:24 -04:00
ftdm_mutex_unlock ( check - > mutex ) ;
ftdm_set_caller_data ( check - > span , caller_data ) ;
status = check - > span - > channel_request ( check - > span , check - > chan_id ,
direction , caller_data , ftdmchan ) ;
if ( status = = FTDM_SUCCESS ) {
return 1 ;
}
} else {
status = ftdm_channel_open_chan ( check ) ;
if ( status = = FTDM_SUCCESS ) {
* ftdmchan = check ;
ftdm_set_flag ( check , FTDM_CHANNEL_OUTBOUND ) ;
2011-01-10 16:49:58 -05:00
#if 0
2010-06-07 21:45:24 -04:00
ftdm_mutex_unlock ( check - > mutex ) ;
2011-01-10 16:49:58 -05:00
# endif
2010-06-07 21:45:24 -04:00
return 1 ;
}
}
}
ftdm_mutex_unlock ( check - > mutex ) ;
}
return 0 ;
}
2010-07-02 18:19:59 -04:00
static void __inline__ calculate_best_rate ( ftdm_channel_t * check , ftdm_channel_t * * best_rated , int * best_rate )
{
if ( ftdm_test_flag ( check - > span , FTDM_SPAN_USE_AV_RATE ) ) {
ftdm_mutex_lock ( check - > mutex ) ;
2010-07-09 10:19:09 -04:00
if ( ftdm_test_flag ( check , FTDM_CHANNEL_INUSE ) ) {
/* twiddle */
} else if ( ftdm_test_flag ( check , FTDM_CHANNEL_SIG_UP ) ) {
/* twiddle */
} else if ( check - > availability_rate > * best_rate ) {
/* the channel is not in use and the signaling status is down,
* it is a potential candidate to place a call */
2010-07-02 18:19:59 -04:00
* best_rated = check ;
* best_rate = check - > availability_rate ;
}
ftdm_mutex_unlock ( check - > mutex ) ;
}
}
2010-07-09 10:19:09 -04:00
static ftdm_status_t __inline__ get_best_rated ( ftdm_channel_t * * fchan , ftdm_channel_t * best_rated )
{
ftdm_status_t status ;
if ( ! best_rated ) {
return FTDM_FAIL ;
}
ftdm_mutex_lock ( best_rated - > mutex ) ;
if ( ftdm_test_flag ( best_rated , FTDM_CHANNEL_INUSE ) ) {
ftdm_mutex_unlock ( best_rated - > mutex ) ;
return FTDM_FAIL ;
}
ftdm_log_chan_msg ( best_rated , FTDM_LOG_DEBUG , " I may not be available but I had the best availability rate, trying to open I/O now \n " ) ;
status = ftdm_channel_open_chan ( best_rated ) ;
if ( status ! = FTDM_SUCCESS ) {
ftdm_mutex_unlock ( best_rated - > mutex ) ;
return FTDM_FAIL ;
}
* fchan = best_rated ;
ftdm_set_flag ( best_rated , FTDM_CHANNEL_OUTBOUND ) ;
2011-01-10 16:49:58 -05:00
#if 0
2010-07-09 10:19:09 -04:00
ftdm_mutex_unlock ( best_rated - > mutex ) ;
2011-01-10 16:49:58 -05:00
# endif
2010-07-09 10:19:09 -04:00
return FTDM_SUCCESS ;
}
2010-12-15 16:42:47 -05:00
2014-01-10 21:14:55 -05:00
static uint32_t __inline__ rr_next ( uint32_t last , uint32_t min , uint32_t max , ftdm_hunt_direction_t direction )
2010-12-17 20:04:30 -05:00
{
uint32_t next = min ;
ftdm_log ( FTDM_LOG_DEBUG , " last = %d, min = %d, max = %d \n " , last , min , max ) ;
2014-01-10 21:14:55 -05:00
if ( direction = = FTDM_HUNT_RR_UP ) {
2010-12-17 20:04:30 -05:00
next = ( last > = max ) ? min : + + last ;
} else {
next = ( last < = min ) ? max : - - last ;
}
return next ;
}
2010-12-15 16:42:47 -05:00
FT_DECLARE ( int ) ftdm_channel_get_availability ( ftdm_channel_t * ftdmchan )
{
int availability = - 1 ;
ftdm_channel_lock ( ftdmchan ) ;
if ( ftdm_test_flag ( ftdmchan - > span , FTDM_SPAN_USE_AV_RATE ) ) {
availability = ftdmchan - > availability_rate ;
}
ftdm_channel_unlock ( ftdmchan ) ;
return availability ;
}
2014-01-10 21:14:55 -05:00
static ftdm_status_t _ftdm_channel_open_by_group ( uint32_t group_id , ftdm_hunt_direction_t direction , ftdm_caller_data_t * caller_data , ftdm_channel_t * * ftdmchan )
2010-01-15 19:22:49 +00:00
{
ftdm_status_t status = FTDM_FAIL ;
2010-07-02 18:19:59 -04:00
ftdm_channel_t * check = NULL ;
ftdm_channel_t * best_rated = NULL ;
2010-01-15 19:22:49 +00:00
ftdm_group_t * group = NULL ;
2010-07-02 18:19:59 -04:00
int best_rate = 0 ;
uint32_t i = 0 ;
uint32_t count = 0 ;
2011-06-15 16:04:35 -04:00
uint32_t first_channel = 0 ;
2010-01-15 19:22:49 +00:00
if ( group_id ) {
ftdm_group_find ( group_id , & group ) ;
}
2010-01-29 19:06:21 +00:00
if ( ! group ) {
ftdm_log ( FTDM_LOG_ERROR , " Group %d not defined! \n " , group_id ) ;
2010-01-15 19:22:49 +00:00
* ftdmchan = NULL ;
return FTDM_FAIL ;
}
ftdm_group_channel_use_count ( group , & count ) ;
if ( count > = group - > chan_count ) {
2010-08-31 14:18:21 -04:00
ftdm_log ( FTDM_LOG_WARNING , " All circuits are busy (%d channels used out of %d available). \n " , count , group - > chan_count ) ;
2010-01-15 19:22:49 +00:00
* ftdmchan = NULL ;
return FTDM_FAIL ;
}
2014-01-10 21:14:55 -05:00
if ( direction = = FTDM_HUNT_BOTTOM_UP ) {
2010-01-15 19:22:49 +00:00
i = 0 ;
2014-01-10 21:14:55 -05:00
} else if ( direction = = FTDM_HUNT_RR_DOWN | | direction = = FTDM_HUNT_RR_UP ) {
2010-12-17 20:04:30 -05:00
i = rr_next ( group - > last_used_index , 0 , group - > chan_count - 1 , direction ) ;
2011-06-15 16:04:35 -04:00
first_channel = i ;
2010-01-15 19:22:49 +00:00
} else {
i = group - > chan_count - 1 ;
}
ftdm_mutex_lock ( group - > mutex ) ;
for ( ; ; ) {
if ( ! ( check = group - > channels [ i ] ) ) {
status = FTDM_FAIL ;
break ;
2010-06-07 21:45:24 -04:00
}
2010-01-15 19:22:49 +00:00
2010-07-30 19:46:05 -04:00
if ( request_voice_channel ( check , ftdmchan , caller_data , direction ) ) {
2010-06-07 21:45:24 -04:00
status = FTDM_SUCCESS ;
2014-01-10 21:14:55 -05:00
if ( direction = = FTDM_HUNT_RR_UP | | direction = = FTDM_HUNT_RR_DOWN ) {
2010-12-17 20:04:30 -05:00
group - > last_used_index = i ;
}
2010-06-07 21:45:24 -04:00
break ;
2010-01-15 19:22:49 +00:00
}
2010-06-07 21:45:24 -04:00
2010-07-02 18:19:59 -04:00
calculate_best_rate ( check , & best_rated , & best_rate ) ;
2014-01-10 21:14:55 -05:00
if ( direction = = FTDM_HUNT_BOTTOM_UP ) {
2010-12-17 20:04:30 -05:00
if ( i > = ( group - > chan_count - 1 ) ) {
2010-06-05 16:38:12 -04:00
break ;
}
2010-01-15 19:22:49 +00:00
i + + ;
2014-01-10 21:14:55 -05:00
} else if ( direction = = FTDM_HUNT_RR_DOWN | | direction = = FTDM_HUNT_RR_UP ) {
2010-12-17 20:04:30 -05:00
if ( check = = best_rated ) {
group - > last_used_index = i ;
}
i = rr_next ( i , 0 , group - > chan_count - 1 , direction ) ;
2011-06-15 16:04:35 -04:00
if ( first_channel = = i ) {
break ;
}
2010-01-15 19:22:49 +00:00
} else {
2010-06-05 16:38:12 -04:00
if ( i = = 0 ) {
break ;
}
2010-01-15 19:22:49 +00:00
i - - ;
2010-06-05 16:38:12 -04:00
}
2010-01-15 19:22:49 +00:00
}
2010-07-02 18:19:59 -04:00
2010-07-09 10:19:09 -04:00
if ( status = = FTDM_FAIL ) {
status = get_best_rated ( ftdmchan , best_rated ) ;
2010-07-02 18:19:59 -04:00
}
2010-01-15 19:22:49 +00:00
ftdm_mutex_unlock ( group - > mutex ) ;
return status ;
}
2014-01-10 21:14:55 -05:00
FT_DECLARE ( ftdm_status_t ) ftdm_channel_open_by_group ( uint32_t group_id , ftdm_hunt_direction_t direction , ftdm_caller_data_t * caller_data , ftdm_channel_t * * ftdmchan )
2011-01-10 16:49:58 -05:00
{
ftdm_status_t status ;
status = _ftdm_channel_open_by_group ( group_id , direction , caller_data , ftdmchan ) ;
if ( status = = FTDM_SUCCESS ) {
ftdm_channel_t * fchan = * ftdmchan ;
ftdm_channel_unlock ( fchan ) ;
}
return status ;
}
2010-01-15 19:22:49 +00:00
FT_DECLARE ( ftdm_status_t ) ftdm_span_channel_use_count ( ftdm_span_t * span , uint32_t * count )
{
uint32_t j ;
* count = 0 ;
if ( ! span | | ! ftdm_test_flag ( span , FTDM_SPAN_CONFIGURED ) ) {
return FTDM_FAIL ;
}
for ( j = 1 ; j < = span - > chan_count & & span - > channels [ j ] ; j + + ) {
if ( span - > channels [ j ] ) {
if ( ftdm_test_flag ( span - > channels [ j ] , FTDM_CHANNEL_INUSE ) ) {
( * count ) + + ;
}
}
}
return FTDM_SUCCESS ;
}
2011-01-10 16:49:58 -05:00
/* Hunt a channel by span, if successful the channel is returned locked */
2014-01-10 21:14:55 -05:00
static ftdm_status_t _ftdm_channel_open_by_span ( uint32_t span_id , ftdm_hunt_direction_t direction , ftdm_caller_data_t * caller_data , ftdm_channel_t * * ftdmchan )
2010-01-15 19:22:49 +00:00
{
ftdm_status_t status = FTDM_FAIL ;
2010-07-02 18:19:59 -04:00
ftdm_channel_t * check = NULL ;
ftdm_channel_t * best_rated = NULL ;
2010-01-15 19:22:49 +00:00
ftdm_span_t * span = NULL ;
2010-07-02 18:19:59 -04:00
int best_rate = 0 ;
uint32_t i = 0 ;
uint32_t count = 0 ;
2011-06-15 16:04:35 -04:00
uint32_t first_channel = 0 ;
2010-01-15 19:22:49 +00:00
2010-07-02 18:19:59 -04:00
* ftdmchan = NULL ;
2010-01-15 19:22:49 +00:00
2010-07-02 18:19:59 -04:00
if ( ! span_id ) {
ftdm_log ( FTDM_LOG_CRIT , " No span supplied \n " ) ;
return FTDM_FAIL ;
}
2010-01-15 19:22:49 +00:00
2010-07-02 18:19:59 -04:00
ftdm_span_find ( span_id , & span ) ;
2010-01-15 19:22:49 +00:00
2010-07-02 18:19:59 -04:00
if ( ! span | | ! ftdm_test_flag ( span , FTDM_SPAN_CONFIGURED ) ) {
ftdm_log ( FTDM_LOG_CRIT , " span %d not defined or configured! \n " , span_id ) ;
return FTDM_FAIL ;
}
2010-03-10 20:06:31 +00:00
2010-07-02 18:19:59 -04:00
ftdm_span_channel_use_count ( span , & count ) ;
if ( count > = span - > chan_count ) {
2010-08-31 14:18:21 -04:00
ftdm_log ( FTDM_LOG_WARNING , " All circuits are busy: active=%i max=%i. \n " , count , span - > chan_count ) ;
2010-01-15 19:22:49 +00:00
return FTDM_FAIL ;
}
2010-07-02 18:19:59 -04:00
if ( span - > channel_request & & ! ftdm_test_flag ( span , FTDM_SPAN_SUGGEST_CHAN_ID ) ) {
ftdm_set_caller_data ( span , caller_data ) ;
return span - > channel_request ( span , 0 , direction , caller_data , ftdmchan ) ;
}
2010-01-15 19:22:49 +00:00
ftdm_mutex_lock ( span - > mutex ) ;
2014-01-10 21:14:55 -05:00
if ( direction = = FTDM_HUNT_BOTTOM_UP ) {
2010-01-15 19:22:49 +00:00
i = 1 ;
2014-01-10 21:14:55 -05:00
} else if ( direction = = FTDM_HUNT_RR_DOWN | | direction = = FTDM_HUNT_RR_UP ) {
2010-12-17 20:04:30 -05:00
i = rr_next ( span - > last_used_index , 1 , span - > chan_count , direction ) ;
2011-06-15 16:04:35 -04:00
first_channel = i ;
2010-01-15 19:22:49 +00:00
} else {
i = span - > chan_count ;
}
for ( ; ; ) {
2014-01-10 21:14:55 -05:00
if ( direction = = FTDM_HUNT_BOTTOM_UP ) {
2010-01-15 19:22:49 +00:00
if ( i > span - > chan_count ) {
break ;
}
} else {
if ( i = = 0 ) {
break ;
}
}
if ( ! ( check = span - > channels [ i ] ) ) {
status = FTDM_FAIL ;
break ;
}
2010-07-30 19:46:05 -04:00
if ( request_voice_channel ( check , ftdmchan , caller_data , direction ) ) {
2010-06-07 21:45:24 -04:00
status = FTDM_SUCCESS ;
2014-01-10 21:14:55 -05:00
if ( direction = = FTDM_HUNT_RR_UP | | direction = = FTDM_HUNT_RR_DOWN ) {
2010-12-17 20:04:30 -05:00
span - > last_used_index = i ;
}
2010-06-07 21:45:24 -04:00
break ;
2010-01-15 19:22:49 +00:00
}
2010-06-07 21:45:24 -04:00
2010-07-02 18:19:59 -04:00
calculate_best_rate ( check , & best_rated , & best_rate ) ;
2014-01-10 21:14:55 -05:00
if ( direction = = FTDM_HUNT_BOTTOM_UP ) {
2010-01-15 19:22:49 +00:00
i + + ;
2014-01-10 21:14:55 -05:00
} else if ( direction = = FTDM_HUNT_RR_DOWN | | direction = = FTDM_HUNT_RR_UP ) {
2010-12-17 20:04:30 -05:00
if ( check = = best_rated ) {
span - > last_used_index = i ;
}
i = rr_next ( i , 1 , span - > chan_count , direction ) ;
2011-06-15 16:04:35 -04:00
if ( first_channel = = i ) {
break ;
}
2010-01-15 19:22:49 +00:00
} else {
i - - ;
}
}
2010-07-09 10:19:09 -04:00
if ( status = = FTDM_FAIL ) {
status = get_best_rated ( ftdmchan , best_rated ) ;
2010-07-02 18:19:59 -04:00
}
2010-01-15 19:22:49 +00:00
ftdm_mutex_unlock ( span - > mutex ) ;
return status ;
}
2014-01-10 21:14:55 -05:00
FT_DECLARE ( ftdm_status_t ) ftdm_channel_open_by_span ( uint32_t span_id , ftdm_hunt_direction_t direction , ftdm_caller_data_t * caller_data , ftdm_channel_t * * ftdmchan )
2011-01-10 16:49:58 -05:00
{
ftdm_status_t status ;
status = _ftdm_channel_open_by_span ( span_id , direction , caller_data , ftdmchan ) ;
if ( status = = FTDM_SUCCESS ) {
ftdm_channel_t * fchan = * ftdmchan ;
ftdm_channel_unlock ( fchan ) ;
}
return status ;
}
2010-01-15 19:22:49 +00:00
FT_DECLARE ( ftdm_status_t ) ftdm_channel_open_chan ( ftdm_channel_t * ftdmchan )
{
ftdm_status_t status = FTDM_FAIL ;
2010-06-07 21:45:24 -04:00
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_FAIL , " invalid ftdmchan pointer \n " ) ;
ftdm_mutex_lock ( ftdmchan - > mutex ) ;
2010-01-15 19:22:49 +00:00
2010-12-01 17:02:58 -05:00
if ( FTDM_IS_VOICE_CHANNEL ( ftdmchan ) ) {
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_SUSPENDED ) ) {
snprintf ( ftdmchan - > last_error , sizeof ( ftdmchan - > last_error ) , " %s " , " Channel is suspended \n " ) ;
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " Cannot open channel when is suspended \n " ) ;
goto done ;
}
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_IN_ALARM ) & & ! ftdm_test_flag ( ftdmchan - > span , FTDM_SPAN_PWR_SAVING ) ) {
snprintf ( ftdmchan - > last_error , sizeof ( ftdmchan - > last_error ) , " %s " , " Channel is alarmed \n " ) ;
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " Cannot open channel when is alarmed \n " ) ;
goto done ;
}
if ( globals . cpu_monitor . alarm & &
globals . cpu_monitor . alarm_action_flags & FTDM_CPU_ALARM_ACTION_REJECT ) {
snprintf ( ftdmchan - > last_error , sizeof ( ftdmchan - > last_error ) , " %s " , " CPU usage alarm is on - refusing to open channel \n " ) ;
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " CPU usage alarm is on - refusing to open channel \n " ) ;
ftdmchan - > caller_data . hangup_cause = FTDM_CAUSE_SWITCH_CONGESTION ;
goto done ;
}
2010-06-07 21:45:24 -04:00
}
if ( ! ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_READY ) ) {
snprintf ( ftdmchan - > last_error , sizeof ( ftdmchan - > last_error ) , " Channel is not ready " ) ;
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " Cannot open channel when is not ready \n " ) ;
goto done ;
2010-01-15 19:22:49 +00:00
}
2010-04-05 17:49:43 -04:00
2010-06-07 21:45:24 -04:00
status = ftdmchan - > fio - > open ( ftdmchan ) ;
if ( status = = FTDM_SUCCESS ) {
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_OPEN | FTDM_CHANNEL_INUSE ) ;
2010-01-15 19:22:49 +00:00
} else {
2010-06-07 21:45:24 -04:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_WARNING , " IO open failed: %d \n " , status ) ;
2010-01-15 19:22:49 +00:00
}
2010-06-07 21:45:24 -04:00
done :
2010-01-15 19:22:49 +00:00
ftdm_mutex_unlock ( ftdmchan - > mutex ) ;
2010-06-07 21:45:24 -04:00
2010-01-15 19:22:49 +00:00
return status ;
}
2012-09-11 14:45:57 -04:00
static ftdm_status_t _ftdm_channel_open ( uint32_t span_id , uint32_t chan_id , ftdm_channel_t * * ftdmchan , uint8_t physical )
2010-01-15 19:22:49 +00:00
{
2010-07-02 18:19:59 -04:00
ftdm_channel_t * check = NULL ;
2010-01-15 19:22:49 +00:00
ftdm_span_t * span = NULL ;
2010-07-02 18:19:59 -04:00
ftdm_channel_t * best_rated = NULL ;
ftdm_status_t status = FTDM_FAIL ;
int best_rate = 0 ;
2010-04-30 16:00:33 -04:00
* ftdmchan = NULL ;
ftdm_mutex_lock ( globals . mutex ) ;
2010-01-15 19:22:49 +00:00
ftdm_span_find ( span_id , & span ) ;
2010-06-07 21:45:24 -04:00
if ( ! span ) {
2010-04-30 16:00:33 -04:00
ftdm_log ( FTDM_LOG_CRIT , " Could not find span! \n " ) ;
2010-01-15 19:22:49 +00:00
goto done ;
}
2010-06-07 21:45:24 -04:00
if ( ! ftdm_test_flag ( span , FTDM_SPAN_CONFIGURED ) ) {
ftdm_log ( FTDM_LOG_CRIT , " Span %d is not configured \n " , span_id ) ;
goto done ;
}
2010-01-15 19:22:49 +00:00
if ( span - > channel_request ) {
ftdm_log ( FTDM_LOG_ERROR , " Individual channel selection not implemented on this span. \n " ) ;
goto done ;
}
2010-06-07 21:45:24 -04:00
2012-09-11 14:45:57 -04:00
if ( physical ) { /* Open by physical */
ftdm_channel_t * fchan = NULL ;
ftdm_iterator_t * citer = NULL ;
ftdm_iterator_t * curr = NULL ;
2010-01-15 19:22:49 +00:00
2012-09-11 14:45:57 -04:00
if ( chan_id < 1 ) {
ftdm_log ( FTDM_LOG_ERROR , " Invalid physical channel %d to open in span %d \n " , chan_id , span_id ) ;
status = FTDM_FAIL ;
goto done ;
}
citer = ftdm_span_get_chan_iterator ( span , NULL ) ;
if ( ! citer ) {
status = ENOMEM ;
goto done ;
}
for ( curr = citer ; curr ; curr = ftdm_iterator_next ( curr ) ) {
fchan = ftdm_iterator_current ( curr ) ;
if ( fchan - > physical_chan_id = = chan_id ) {
check = fchan ;
break ;
}
}
ftdm_iterator_free ( citer ) ;
if ( ! check ) {
ftdm_log ( FTDM_LOG_CRIT , " Wow, no physical channel %d in span %d \n " , chan_id , span_id ) ;
goto done ;
}
} else { /* Open by logical */
if ( chan_id < 1 | | chan_id > span - > chan_count ) {
ftdm_log ( FTDM_LOG_ERROR , " Invalid channel %d to open in span %d \n " , chan_id , span_id ) ;
goto done ;
}
if ( ! ( check = span - > channels [ chan_id ] ) ) {
ftdm_log ( FTDM_LOG_CRIT , " Wow, no channel %d in span %d \n " , chan_id , span_id ) ;
goto done ;
}
2010-01-15 19:22:49 +00:00
}
2010-06-07 21:45:24 -04:00
2011-09-12 15:21:23 -04:00
ftdm_channel_lock ( check ) ;
if ( ftdm_test_flag ( check , FTDM_CHANNEL_OPEN ) ) {
/* let them know is already open, but return the channel anyway */
status = FTDM_EBUSY ;
* ftdmchan = check ;
goto unlockchan ;
}
2010-01-15 19:22:49 +00:00
2010-09-30 11:02:53 -04:00
/* The following if's and gotos replace a big if (this || this || this || this) else { nothing; } */
/* if it is not a voice channel, nothing else to check to open it */
if ( ! FTDM_IS_VOICE_CHANNEL ( check ) ) {
goto openchan ;
}
/* if it's an FXS device with a call active and has callwaiting enabled, we allow to open it twice */
if ( check - > type = = FTDM_CHAN_TYPE_FXS
& & check - > token_count = = 1
& & ftdm_channel_test_feature ( check , FTDM_CHANNEL_FEATURE_CALLWAITING ) ) {
goto openchan ;
}
/* if channel is available, time to open it */
if ( chan_is_avail ( check ) ) {
goto openchan ;
}
/* not available, but still might be available ... */
2010-07-02 18:19:59 -04:00
calculate_best_rate ( check , & best_rated , & best_rate ) ;
if ( best_rated ) {
2010-09-30 11:02:53 -04:00
goto openchan ;
2010-07-02 18:19:59 -04:00
}
2010-09-30 11:02:53 -04:00
/* channel is unavailable, do not open the channel */
goto unlockchan ;
openchan :
if ( ! ftdm_test_flag ( check , FTDM_CHANNEL_OPEN ) ) {
status = check - > fio - > open ( check ) ;
if ( status = = FTDM_SUCCESS ) {
ftdm_set_flag ( check , FTDM_CHANNEL_OPEN ) ;
2010-01-15 19:22:49 +00:00
}
2010-09-30 11:02:53 -04:00
} else {
status = FTDM_SUCCESS ;
2010-01-15 19:22:49 +00:00
}
2010-09-30 11:02:53 -04:00
ftdm_set_flag ( check , FTDM_CHANNEL_INUSE ) ;
ftdm_set_flag ( check , FTDM_CHANNEL_OUTBOUND ) ;
* ftdmchan = check ;
2011-02-25 09:58:15 -05:00
2011-01-10 16:49:58 -05:00
/* we've got the channel, do not unlock it */
goto done ;
2010-06-07 21:45:24 -04:00
2010-09-30 11:02:53 -04:00
unlockchan :
2011-09-12 15:21:23 -04:00
ftdm_channel_unlock ( check ) ;
2010-01-15 19:22:49 +00:00
2010-05-25 12:48:10 -04:00
done :
2010-01-15 19:22:49 +00:00
ftdm_mutex_unlock ( globals . mutex ) ;
2010-09-30 11:02:53 -04:00
if ( status ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_ERROR , " Failed to open channel %d:%d \n " , span_id , chan_id ) ;
}
2010-01-15 19:22:49 +00:00
return status ;
}
2011-01-10 16:49:58 -05:00
FT_DECLARE ( ftdm_status_t ) ftdm_channel_open ( uint32_t span_id , uint32_t chan_id , ftdm_channel_t * * ftdmchan )
{
ftdm_status_t status ;
2012-09-11 14:45:57 -04:00
status = _ftdm_channel_open ( span_id , chan_id , ftdmchan , 0 ) ;
if ( status = = FTDM_SUCCESS ) {
ftdm_channel_t * fchan = * ftdmchan ;
ftdm_channel_unlock ( fchan ) ;
}
return status ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_open_ph ( uint32_t span_id , uint32_t chan_id , ftdm_channel_t * * ftdmchan )
{
ftdm_status_t status ;
status = _ftdm_channel_open ( span_id , chan_id , ftdmchan , 1 ) ;
2011-01-10 16:49:58 -05:00
if ( status = = FTDM_SUCCESS ) {
ftdm_channel_t * fchan = * ftdmchan ;
ftdm_channel_unlock ( fchan ) ;
}
return status ;
}
2010-04-19 11:39:03 -04:00
FT_DECLARE ( uint32_t ) ftdm_channel_get_id ( const ftdm_channel_t * ftdmchan )
{
return ftdmchan - > chan_id ;
}
FT_DECLARE ( uint32_t ) ftdm_channel_get_ph_id ( const ftdm_channel_t * ftdmchan )
{
return ftdmchan - > physical_chan_id ;
}
FT_DECLARE ( uint32_t ) ftdm_channel_get_span_id ( const ftdm_channel_t * ftdmchan )
{
return ftdmchan - > span_id ;
}
2010-04-21 11:20:05 -04:00
FT_DECLARE ( ftdm_span_t * ) ftdm_channel_get_span ( const ftdm_channel_t * ftdmchan )
{
return ftdmchan - > span ;
}
FT_DECLARE ( const char * ) ftdm_channel_get_span_name ( const ftdm_channel_t * ftdmchan )
{
return ftdmchan - > span - > name ;
}
2010-05-11 15:09:22 -04:00
FT_DECLARE ( void ) ftdm_span_set_trunk_type ( ftdm_span_t * span , ftdm_trunk_type_t type )
{
span - > trunk_type = type ;
}
2010-12-23 15:39:20 -05:00
FT_DECLARE ( ftdm_status_t ) ftdm_span_set_blocking_mode ( const ftdm_span_t * span , ftdm_bool_t enabled )
{
ftdm_channel_t * fchan = NULL ;
ftdm_iterator_t * citer = NULL ;
ftdm_iterator_t * curr = NULL ;
citer = ftdm_span_get_chan_iterator ( span , NULL ) ;
if ( ! citer ) {
return FTDM_ENOMEM ;
}
2011-05-26 11:38:24 -04:00
2010-12-23 15:39:20 -05:00
for ( curr = citer ; curr ; curr = ftdm_iterator_next ( curr ) ) {
fchan = ftdm_iterator_current ( curr ) ;
if ( enabled ) {
ftdm_clear_flag_locked ( fchan , FTDM_CHANNEL_NONBLOCK ) ;
} else {
ftdm_set_flag_locked ( fchan , FTDM_CHANNEL_NONBLOCK ) ;
}
}
2010-12-29 14:08:18 -05:00
ftdm_iterator_free ( citer ) ;
2010-12-23 15:39:20 -05:00
return FTDM_SUCCESS ;
}
2010-05-11 15:09:22 -04:00
FT_DECLARE ( ftdm_trunk_type_t ) ftdm_span_get_trunk_type ( const ftdm_span_t * span )
{
return span - > trunk_type ;
}
2010-11-14 17:43:38 +01:00
FT_DECLARE ( const char * ) ftdm_span_get_trunk_type_str ( const ftdm_span_t * span )
{
return ftdm_trunk_type2str ( span - > trunk_type ) ;
}
2012-07-11 19:15:35 +02:00
FT_DECLARE ( void ) ftdm_span_set_trunk_mode ( ftdm_span_t * span , ftdm_trunk_mode_t mode )
{
span - > trunk_mode = mode ;
}
FT_DECLARE ( ftdm_trunk_mode_t ) ftdm_span_get_trunk_mode ( const ftdm_span_t * span )
{
return span - > trunk_mode ;
}
FT_DECLARE ( const char * ) ftdm_span_get_trunk_mode_str ( const ftdm_span_t * span )
{
return ftdm_trunk_mode2str ( span - > trunk_mode ) ;
}
2010-04-19 11:39:03 -04:00
FT_DECLARE ( uint32_t ) ftdm_span_get_id ( const ftdm_span_t * span )
{
return span - > span_id ;
}
FT_DECLARE ( const char * ) ftdm_span_get_name ( const ftdm_span_t * span )
{
return span - > name ;
}
2010-04-21 11:20:05 -04:00
FT_DECLARE ( const char * ) ftdm_channel_get_name ( const ftdm_channel_t * ftdmchan )
{
return ftdmchan - > chan_name ;
}
FT_DECLARE ( const char * ) ftdm_channel_get_number ( const ftdm_channel_t * ftdmchan )
{
return ftdmchan - > chan_number ;
}
FT_DECLARE ( ftdm_bool_t ) ftdm_channel_call_check_hold ( const ftdm_channel_t * ftdmchan )
{
ftdm_bool_t condition ;
ftdm_channel_lock ( ftdmchan ) ;
2010-05-20 11:43:40 -04:00
condition = ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_HOLD ) ? FTDM_TRUE : FTDM_FALSE ;
2010-04-21 11:20:05 -04:00
ftdm_channel_unlock ( ftdmchan ) ;
return condition ;
}
FT_DECLARE ( ftdm_bool_t ) ftdm_channel_call_check_answered ( const ftdm_channel_t * ftdmchan )
{
ftdm_bool_t condition = FTDM_FALSE ;
ftdm_channel_lock ( ftdmchan ) ;
condition = ( ftdmchan - > state = = FTDM_CHANNEL_STATE_UP ) ? FTDM_TRUE : FTDM_FALSE ;
ftdm_channel_unlock ( ftdmchan ) ;
return condition ;
}
FT_DECLARE ( ftdm_bool_t ) ftdm_channel_call_check_busy ( const ftdm_channel_t * ftdmchan )
{
ftdm_bool_t condition = FTDM_FALSE ;
ftdm_channel_lock ( ftdmchan ) ;
condition = ( ftdmchan - > state = = FTDM_CHANNEL_STATE_BUSY ) ? FTDM_TRUE : FTDM_FALSE ;
ftdm_channel_unlock ( ftdmchan ) ;
return condition ;
}
FT_DECLARE ( ftdm_bool_t ) ftdm_channel_call_check_hangup ( const ftdm_channel_t * ftdmchan )
{
ftdm_bool_t condition = FTDM_FALSE ;
ftdm_channel_lock ( ftdmchan ) ;
condition = ( ftdmchan - > state = = FTDM_CHANNEL_STATE_HANGUP | | ftdmchan - > state = = FTDM_CHANNEL_STATE_TERMINATING )
? FTDM_TRUE : FTDM_FALSE ;
ftdm_channel_unlock ( ftdmchan ) ;
return condition ;
}
FT_DECLARE ( ftdm_bool_t ) ftdm_channel_call_check_done ( const ftdm_channel_t * ftdmchan )
{
ftdm_bool_t condition = FTDM_FALSE ;
ftdm_channel_lock ( ftdmchan ) ;
condition = ( ftdmchan - > state = = FTDM_CHANNEL_STATE_DOWN ) ? FTDM_TRUE : FTDM_FALSE ;
ftdm_channel_unlock ( ftdmchan ) ;
return condition ;
}
2011-02-25 09:58:15 -05:00
FT_DECLARE ( ftdm_status_t ) _ftdm_channel_call_hold ( const char * file , const char * func , int line , ftdm_channel_t * ftdmchan , ftdm_usrmsg_t * usrmsg )
2010-04-19 11:39:03 -04:00
{
2010-12-23 15:39:20 -05:00
ftdm_status_t status ;
2010-04-21 11:20:05 -04:00
ftdm_channel_lock ( ftdmchan ) ;
2010-12-23 15:39:20 -05:00
2010-04-21 11:20:05 -04:00
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_HOLD ) ;
2011-02-25 09:58:15 -05:00
status = ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_DIALTONE , 0 , usrmsg ) ;
2010-04-21 11:20:05 -04:00
ftdm_channel_unlock ( ftdmchan ) ;
2010-12-23 15:39:20 -05:00
return status ;
2010-04-21 11:20:05 -04:00
}
2011-02-25 09:58:15 -05:00
FT_DECLARE ( ftdm_status_t ) _ftdm_channel_call_unhold ( const char * file , const char * func , int line , ftdm_channel_t * ftdmchan , ftdm_usrmsg_t * usrmsg )
2010-04-21 11:20:05 -04:00
{
2010-12-23 15:39:20 -05:00
ftdm_status_t status ;
2010-04-21 11:20:05 -04:00
ftdm_channel_lock ( ftdmchan ) ;
2010-12-23 15:39:20 -05:00
2011-02-25 09:58:15 -05:00
status = ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_UP , 0 , usrmsg ) ;
2010-12-23 15:39:20 -05:00
2010-04-21 11:20:05 -04:00
ftdm_channel_unlock ( ftdmchan ) ;
2010-12-23 15:39:20 -05:00
return status ;
2010-04-19 11:39:03 -04:00
}
2010-12-29 13:38:43 -05:00
FT_DECLARE ( void ) ftdm_ack_indication ( ftdm_channel_t * fchan , ftdm_channel_indication_t indication , ftdm_status_t status )
2010-04-19 11:39:03 -04:00
{
2010-12-23 15:39:20 -05:00
ftdm_sigmsg_t msg ;
2011-05-26 11:38:24 -04:00
2011-01-07 14:15:24 -05:00
if ( ! ftdm_test_flag ( fchan , FTDM_CHANNEL_IND_ACK_PENDING ) ) {
return ;
}
2011-05-26 11:38:24 -04:00
ftdm_log_chan ( fchan , FTDM_LOG_DEBUG , " Acknowledging indication %s in state %s (rc = %d) \n " ,
2010-12-29 13:38:43 -05:00
ftdm_channel_indication2str ( indication ) , ftdm_channel_state2str ( fchan - > state ) , status ) ;
ftdm_clear_flag ( fchan , FTDM_CHANNEL_IND_ACK_PENDING ) ;
2010-12-23 15:39:20 -05:00
memset ( & msg , 0 , sizeof ( msg ) ) ;
2010-12-29 13:38:43 -05:00
msg . channel = fchan ;
2010-12-23 15:39:20 -05:00
msg . event_id = FTDM_SIGEVENT_INDICATION_COMPLETED ;
msg . ev_data . indication_completed . indication = indication ;
msg . ev_data . indication_completed . status = status ;
ftdm_span_send_signal ( fchan - > span , & msg ) ;
2010-04-19 11:39:03 -04:00
}
2010-07-29 13:15:29 -04:00
2011-01-10 16:49:58 -05:00
/*! Answer call without locking the channel. The caller must have locked first */
2011-02-25 09:58:15 -05:00
static ftdm_status_t _ftdm_channel_call_answer_nl ( const char * file , const char * func , int line , ftdm_channel_t * ftdmchan , ftdm_usrmsg_t * usrmsg )
2010-04-19 11:39:03 -04:00
{
2010-07-29 13:15:29 -04:00
ftdm_status_t status = FTDM_SUCCESS ;
2010-04-21 11:20:05 -04:00
2010-12-09 18:01:31 -05:00
if ( ! ftdm_test_flag ( ftdmchan - > span , FTDM_SPAN_USE_SKIP_STATES ) ) {
/* We will fail RFC's if we not skip states, but some modules apart from ftmod_sangoma_isdn
* expect the call to always to go PROGRESS and PROGRESS MEDIA state before going to UP , so
2010-12-23 15:39:20 -05:00
* use FTDM_SPAN_USE_SKIP_STATES for now while we update the sig modules */
2010-11-25 16:16:36 -05:00
2010-12-09 18:01:31 -05:00
if ( ftdmchan - > state < FTDM_CHANNEL_STATE_PROGRESS ) {
2011-02-25 09:58:15 -05:00
status = ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_PROGRESS , 1 , usrmsg ) ;
2010-12-23 15:39:20 -05:00
if ( status ! = FTDM_SUCCESS ) {
2011-01-04 09:30:49 -05:00
status = FTDM_ECANCELED ;
2010-12-23 15:39:20 -05:00
goto done ;
}
2010-12-09 18:01:31 -05:00
}
2010-04-21 11:20:05 -04:00
2010-12-09 18:01:31 -05:00
/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
if ( ftdmchan - > state = = FTDM_CHANNEL_STATE_TERMINATING ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS \n " ) ;
2010-12-23 15:39:20 -05:00
status = FTDM_ECANCELED ;
2010-12-09 18:01:31 -05:00
goto done ;
}
2010-09-03 11:21:40 -04:00
2010-12-09 18:01:31 -05:00
if ( ftdmchan - > state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA ) {
2011-02-25 09:58:15 -05:00
status = ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , 1 , usrmsg ) ;
2010-12-23 15:39:20 -05:00
if ( status ! = FTDM_SUCCESS ) {
2011-01-04 09:30:49 -05:00
status = FTDM_ECANCELED ;
2010-12-23 15:39:20 -05:00
goto done ;
}
2010-12-09 18:01:31 -05:00
}
2010-04-21 11:20:05 -04:00
2010-12-09 18:01:31 -05:00
/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
if ( ftdmchan - > state = = FTDM_CHANNEL_STATE_TERMINATING ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Ignoring answer because the call has moved to TERMINATING while we're moving to UP \n " ) ;
2010-12-23 15:39:20 -05:00
status = FTDM_ECANCELED ;
2010-12-09 18:01:31 -05:00
goto done ;
}
2010-09-03 11:21:40 -04:00
}
2010-04-21 11:20:05 -04:00
2011-02-25 09:58:15 -05:00
status = ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_UP , 1 , usrmsg ) ;
2010-12-23 15:39:20 -05:00
if ( status ! = FTDM_SUCCESS ) {
2011-01-04 09:30:49 -05:00
status = FTDM_ECANCELED ;
goto done ;
2010-12-23 15:39:20 -05:00
}
2010-04-21 11:20:05 -04:00
2010-07-29 13:15:29 -04:00
done :
2011-01-04 09:30:49 -05:00
return status ;
}
2011-02-25 09:58:15 -05:00
FT_DECLARE ( ftdm_status_t ) _ftdm_channel_call_answer ( const char * file , const char * func , int line , ftdm_channel_t * ftdmchan , ftdm_usrmsg_t * usrmsg )
2011-01-04 09:30:49 -05:00
{
2011-01-10 16:49:58 -05:00
ftdm_status_t status ;
2011-01-04 09:30:49 -05:00
2011-01-10 16:49:58 -05:00
/* we leave the locking up to ftdm_channel_call_indicate, DO NOT lock here since ftdm_channel_call_indicate expects
* the lock recursivity to be 1 */
2011-02-25 09:58:15 -05:00
status = _ftdm_channel_call_indicate ( file , func , line , ftdmchan , FTDM_CHANNEL_INDICATE_ANSWER , usrmsg ) ;
2011-01-04 09:30:49 -05:00
2010-07-29 13:15:29 -04:00
return status ;
2010-04-21 11:20:05 -04:00
}
2011-05-26 11:38:24 -04:00
FT_DECLARE ( ftdm_status_t ) _ftdm_channel_call_transfer ( const char * file , const char * func , int line , ftdm_channel_t * ftdmchan , const char * arg , ftdm_usrmsg_t * usrmsg )
{
ftdm_status_t status ;
ftdm_usrmsg_t * msg = NULL ;
ftdm_bool_t free_msg = FTDM_FALSE ;
if ( ! usrmsg ) {
msg = ftdm_calloc ( 1 , sizeof ( * msg ) ) ;
ftdm_assert_return ( msg , FTDM_FAIL , " Failed to allocate usr msg " ) ;
memset ( msg , 0 , sizeof ( * msg ) ) ;
free_msg = FTDM_TRUE ;
} else {
msg = usrmsg ;
}
ftdm_usrmsg_add_var ( msg , " transfer_arg " , arg ) ;
/* we leave the locking up to ftdm_channel_call_indicate, DO NOT lock here since ftdm_channel_call_indicate expects
* the lock recursivity to be 1 */
status = _ftdm_channel_call_indicate ( file , func , line , ftdmchan , FTDM_CHANNEL_INDICATE_TRANSFER , msg ) ;
if ( free_msg = = FTDM_TRUE ) {
ftdm_safe_free ( msg ) ;
}
return status ;
}
2010-05-17 14:36:10 -04:00
/* lock must be acquired by the caller! */
2011-02-25 09:58:15 -05:00
static ftdm_status_t _ftdm_channel_call_hangup_nl ( const char * file , const char * func , int line , ftdm_channel_t * chan , ftdm_usrmsg_t * usrmsg )
2010-04-23 16:28:01 -04:00
{
2010-12-23 15:39:20 -05:00
ftdm_status_t status = FTDM_SUCCESS ;
2011-05-26 11:38:24 -04:00
2012-04-16 13:48:35 -04:00
/* In native sigbridge mode we ignore hangup requests from the user and hangup only when the signaling module decides it */
if ( ftdm_test_flag ( chan , FTDM_CHANNEL_NATIVE_SIGBRIDGE ) & & chan - > state ! = FTDM_CHANNEL_STATE_TERMINATING ) {
2012-01-26 22:44:19 -05:00
ftdm_log_chan_ex ( chan , file , func , line , FTDM_LOG_LEVEL_DEBUG ,
" Ignoring hangup in channel in state %s (native bridge enabled) \n " , ftdm_channel_state2str ( chan - > state ) ) ;
2012-04-16 13:48:35 -04:00
ftdm_set_flag ( chan , FTDM_CHANNEL_USER_HANGUP ) ;
2012-01-26 22:44:19 -05:00
goto done ;
}
2010-04-23 16:28:01 -04:00
if ( chan - > state ! = FTDM_CHANNEL_STATE_DOWN ) {
2010-07-29 13:15:29 -04:00
if ( chan - > state = = FTDM_CHANNEL_STATE_HANGUP ) {
/* make user's life easier, and just ignore double hangup requests */
return FTDM_SUCCESS ;
}
2010-09-21 07:19:56 -04:00
if ( chan - > hangup_timer ) {
ftdm_sched_cancel_timer ( globals . timingsched , chan - > hangup_timer ) ;
}
2011-01-05 15:27:20 -02:00
ftdm_set_flag ( chan , FTDM_CHANNEL_USER_HANGUP ) ;
2011-01-07 16:00:06 -05:00
/* if a state change requested by the user was pending, a hangup certainly cancels that request */
if ( ftdm_test_flag ( chan , FTDM_CHANNEL_STATE_CHANGE ) ) {
ftdm_channel_cancel_state ( file , func , line , chan ) ;
}
2011-02-25 09:58:15 -05:00
status = ftdm_channel_set_state ( file , func , line , chan , FTDM_CHANNEL_STATE_HANGUP , 1 , usrmsg ) ;
2010-04-23 16:28:01 -04:00
} else {
/* the signaling stack did not touch the state,
2010-12-21 15:11:22 -05:00
* core is responsible from clearing flags and stuff , however , because ftmod_analog
* is a bitch in a serious need of refactoring , we also check whether the channel is open
* to avoid an spurious warning about the channel not being open . This is because ftmod_analog
* does not follow our convention of sending SIGEVENT_STOP and waiting for the user to move
* to HANGUP ( implicitly through ftdm_channel_call_hangup ( ) , as soon as ftmod_analog is fixed
* this check can be removed */
if ( ftdm_test_flag ( chan , FTDM_CHANNEL_OPEN ) ) {
ftdm_channel_close ( & chan ) ;
}
2010-04-23 16:28:01 -04:00
}
2012-01-26 22:44:19 -05:00
done :
2010-12-23 15:39:20 -05:00
return status ;
2010-04-23 16:28:01 -04:00
}
2011-02-25 09:58:15 -05:00
FT_DECLARE ( ftdm_status_t ) _ftdm_channel_call_hangup_with_cause ( const char * file , const char * func , int line , ftdm_channel_t * ftdmchan , ftdm_call_cause_t cause , ftdm_usrmsg_t * usrmsg )
2010-04-21 11:20:05 -04:00
{
2010-12-23 15:39:20 -05:00
ftdm_status_t status = FTDM_SUCCESS ;
2010-04-23 16:28:01 -04:00
ftdm_channel_lock ( ftdmchan ) ;
2010-04-21 11:20:05 -04:00
ftdmchan - > caller_data . hangup_cause = cause ;
2010-04-23 16:28:01 -04:00
2011-02-25 09:58:15 -05:00
status = _ftdm_channel_call_hangup_nl ( file , func , line , ftdmchan , usrmsg ) ;
2010-04-23 16:28:01 -04:00
ftdm_channel_unlock ( ftdmchan ) ;
2010-12-23 15:39:20 -05:00
return status ;
2010-04-19 11:39:03 -04:00
}
2011-02-25 09:58:15 -05:00
FT_DECLARE ( ftdm_status_t ) _ftdm_channel_call_hangup ( const char * file , const char * func , int line , ftdm_channel_t * ftdmchan , ftdm_usrmsg_t * usrmsg )
2010-04-19 11:39:03 -04:00
{
2010-12-23 15:39:20 -05:00
ftdm_status_t status = FTDM_SUCCESS ;
2010-04-23 16:28:01 -04:00
ftdm_channel_lock ( ftdmchan ) ;
2010-12-23 15:39:20 -05:00
2010-09-03 13:30:51 -04:00
ftdmchan - > caller_data . hangup_cause = FTDM_CAUSE_NORMAL_CLEARING ;
2010-12-23 15:39:20 -05:00
2011-02-25 09:58:15 -05:00
status = _ftdm_channel_call_hangup_nl ( file , func , line , ftdmchan , usrmsg ) ;
2010-12-23 15:39:20 -05:00
2010-04-23 16:28:01 -04:00
ftdm_channel_unlock ( ftdmchan ) ;
2010-12-23 15:39:20 -05:00
return status ;
2010-04-19 11:39:03 -04:00
}
FT_DECLARE ( const char * ) ftdm_channel_get_last_error ( const ftdm_channel_t * ftdmchan )
{
return ftdmchan - > last_error ;
}
2010-04-21 11:20:05 -04:00
FT_DECLARE ( const char * ) ftdm_span_get_last_error ( const ftdm_span_t * span )
{
return span - > last_error ;
}
FT_DECLARE ( ftdm_caller_data_t * ) ftdm_channel_get_caller_data ( ftdm_channel_t * ftdmchan )
{
return & ftdmchan - > caller_data ;
}
FT_DECLARE ( ftdm_channel_t * ) ftdm_span_get_channel ( const ftdm_span_t * span , uint32_t chanid )
{
ftdm_channel_t * chan ;
ftdm_mutex_lock ( span - > mutex ) ;
if ( chanid = = 0 | | chanid > span - > chan_count ) {
ftdm_mutex_unlock ( span - > mutex ) ;
return NULL ;
}
chan = span - > channels [ chanid ] ;
ftdm_mutex_unlock ( span - > mutex ) ;
return chan ;
}
2012-09-11 14:45:57 -04:00
FT_DECLARE ( ftdm_channel_t * ) ftdm_span_get_channel_ph ( const ftdm_span_t * span , uint32_t chanid )
{
ftdm_channel_t * chan = NULL ;
ftdm_channel_t * fchan = NULL ;
ftdm_iterator_t * citer = NULL ;
ftdm_iterator_t * curr = NULL ;
ftdm_mutex_lock ( span - > mutex ) ;
if ( chanid = = 0 ) {
ftdm_mutex_unlock ( span - > mutex ) ;
return NULL ;
}
citer = ftdm_span_get_chan_iterator ( span , NULL ) ;
if ( ! citer ) {
ftdm_mutex_unlock ( span - > mutex ) ;
return NULL ;
}
for ( curr = citer ; curr ; curr = ftdm_iterator_next ( curr ) ) {
fchan = ftdm_iterator_current ( curr ) ;
if ( fchan - > physical_chan_id = = chanid ) {
chan = fchan ;
break ;
}
}
ftdm_iterator_free ( citer ) ;
ftdm_mutex_unlock ( span - > mutex ) ;
return chan ;
}
2010-04-21 11:20:05 -04:00
FT_DECLARE ( uint32_t ) ftdm_span_get_chan_count ( const ftdm_span_t * span )
{
uint32_t count ;
ftdm_mutex_lock ( span - > mutex ) ;
count = span - > chan_count ;
ftdm_mutex_unlock ( span - > mutex ) ;
return count ;
}
FT_DECLARE ( uint32_t ) ftdm_channel_get_ph_span_id ( const ftdm_channel_t * ftdmchan )
{
uint32_t id ;
ftdm_channel_lock ( ftdmchan ) ;
id = ftdmchan - > physical_span_id ;
ftdm_channel_unlock ( ftdmchan ) ;
return id ;
}
2010-12-23 15:39:20 -05:00
/*
* Every user requested indication * MUST * be acknowledged with the proper status ( ftdm_status_t )
2010-12-29 13:38:43 -05:00
* However , if the indication fails before we notify the signaling stack , we don ' t need to ack
2010-12-23 15:39:20 -05:00
* but if we already notified the signaling stack about the indication , the signaling stack is
2010-12-29 13:38:43 -05:00
* responsible for the acknowledge . Bottom line is , whenever this function returns FTDM_SUCCESS
* someone * MUST * acknowledge the indication , either the signaling stack , this function or the core
* at some later point
2010-12-23 15:39:20 -05:00
* */
2011-02-25 09:58:15 -05:00
FT_DECLARE ( ftdm_status_t ) _ftdm_channel_call_indicate ( const char * file , const char * func , int line , ftdm_channel_t * ftdmchan , ftdm_channel_indication_t indication , ftdm_usrmsg_t * usrmsg )
2010-04-19 11:39:03 -04:00
{
2010-05-17 14:36:10 -04:00
ftdm_status_t status = FTDM_SUCCESS ;
2010-12-23 15:39:20 -05:00
2010-12-29 13:38:43 -05:00
ftdm_assert_return ( ftdmchan , FTDM_FAIL , " Null channel \n " ) ;
2011-01-14 16:10:13 -05:00
ftdm_log_chan_ex ( ftdmchan , file , func , line , FTDM_LOG_LEVEL_DEBUG , " Indicating %s in state %s \n " ,
2010-12-29 13:38:43 -05:00
ftdm_channel_indication2str ( indication ) , ftdm_channel_state2str ( ftdmchan - > state ) ) ;
2010-05-17 14:36:10 -04:00
ftdm_channel_lock ( ftdmchan ) ;
2010-04-21 11:20:05 -04:00
2012-01-26 22:44:19 -05:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_NATIVE_SIGBRIDGE ) ) {
ftdm_log_chan_ex ( ftdmchan , file , func , line , FTDM_LOG_LEVEL_DEBUG ,
" Ignoring indication %s in channel in state %s (native bridge enabled) \n " ,
ftdm_channel_indication2str ( indication ) ,
ftdm_channel_state2str ( ftdmchan - > state ) ) ;
status = FTDM_SUCCESS ;
goto done ;
}
2010-12-29 13:38:43 -05:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_IND_ACK_PENDING ) ) {
2011-01-14 16:10:13 -05:00
ftdm_log_chan_ex ( ftdmchan , file , func , line , FTDM_LOG_LEVEL_WARNING , " Cannot indicate %s in channel with indication %s still pending in state %s \n " ,
2010-12-29 13:38:43 -05:00
ftdm_channel_indication2str ( indication ) ,
ftdm_channel_indication2str ( ftdmchan - > indication ) ,
ftdm_channel_state2str ( ftdmchan - > state ) ) ;
status = FTDM_EBUSY ;
goto done ;
}
ftdmchan - > indication = indication ;
2011-01-07 14:15:24 -05:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_NONBLOCK ) ) {
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_IND_ACK_PENDING ) ;
}
2010-12-29 13:38:43 -05:00
2011-03-03 09:48:48 -05:00
if ( indication ! = FTDM_CHANNEL_INDICATE_FACILITY & &
ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OUTBOUND ) ) {
2011-01-14 16:10:13 -05:00
ftdm_log_chan_ex ( ftdmchan , file , func , line , FTDM_LOG_LEVEL_WARNING , " Cannot indicate %s in outgoing channel in state %s \n " ,
2010-12-23 15:39:20 -05:00
ftdm_channel_indication2str ( indication ) , ftdm_channel_state2str ( ftdmchan - > state ) ) ;
status = FTDM_EINVAL ;
goto done ;
}
2010-09-03 11:21:40 -04:00
if ( ftdmchan - > state = = FTDM_CHANNEL_STATE_TERMINATING ) {
2011-01-14 16:10:13 -05:00
ftdm_log_chan_ex ( ftdmchan , file , func , line , FTDM_LOG_LEVEL_DEBUG , " Ignoring indication %s because the call is in %s state \n " ,
2010-12-23 15:39:20 -05:00
ftdm_channel_indication2str ( indication ) , ftdm_channel_state2str ( ftdmchan - > state ) ) ;
status = FTDM_ECANCELED ;
2010-09-03 11:21:40 -04:00
goto done ;
}
switch ( indication ) {
2010-04-21 11:20:05 -04:00
/* FIXME: ring and busy cannot be used with all signaling stacks
* ( particularly isdn stacks I think , we should emulate or just move to hangup with busy cause ) */
2010-11-24 20:04:43 -05:00
case FTDM_CHANNEL_INDICATE_RINGING :
2011-02-25 09:58:15 -05:00
status = ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_RINGING , 1 , usrmsg ) ;
2010-04-21 11:20:05 -04:00
break ;
case FTDM_CHANNEL_INDICATE_BUSY :
2011-02-25 09:58:15 -05:00
status = ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_BUSY , 1 , usrmsg ) ;
2010-04-21 11:20:05 -04:00
break ;
2010-11-24 20:04:43 -05:00
case FTDM_CHANNEL_INDICATE_PROCEED :
2011-01-10 11:29:55 -05:00
if ( ! ftdm_test_flag ( ftdmchan - > span , FTDM_SPAN_USE_PROCEED_STATE ) | |
2011-03-03 10:57:03 -05:00
ftdmchan - > state > = FTDM_CHANNEL_STATE_PROCEED ) {
2010-12-23 15:39:20 -05:00
ftdm_ack_indication ( ftdmchan , indication , status ) ;
goto done ;
2010-11-24 20:04:43 -05:00
}
2011-02-25 09:58:15 -05:00
status = ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_PROCEED , 1 , usrmsg ) ;
2010-11-24 20:04:43 -05:00
break ;
2010-04-19 11:39:03 -04:00
case FTDM_CHANNEL_INDICATE_PROGRESS :
2011-02-25 09:58:15 -05:00
status = ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_PROGRESS , 1 , usrmsg ) ;
2010-04-21 11:20:05 -04:00
break ;
case FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA :
2010-12-23 15:39:20 -05:00
if ( ! ftdm_test_flag ( ftdmchan - > span , FTDM_SPAN_USE_SKIP_STATES ) ) {
if ( ftdmchan - > state < FTDM_CHANNEL_STATE_PROGRESS ) {
2011-02-25 09:58:15 -05:00
status = ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_PROGRESS , 1 , usrmsg ) ;
2010-12-23 15:39:20 -05:00
if ( status ! = FTDM_SUCCESS ) {
2010-12-14 16:04:25 -05:00
goto done ;
}
2010-09-03 11:21:40 -04:00
}
2010-12-23 15:39:20 -05:00
/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
if ( ftdmchan - > state = = FTDM_CHANNEL_STATE_TERMINATING ) {
2011-01-14 16:10:13 -05:00
ftdm_log_chan_ex_msg ( ftdmchan , file , func , line , FTDM_LOG_LEVEL_DEBUG , " Ignoring progress media because the call is terminating \n " ) ;
2010-12-23 15:39:20 -05:00
goto done ;
}
2010-04-21 11:20:05 -04:00
}
2011-02-25 09:58:15 -05:00
status = ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , 1 , usrmsg ) ;
2010-12-23 15:39:20 -05:00
break ;
case FTDM_CHANNEL_INDICATE_ANSWER :
2011-02-25 09:58:15 -05:00
status = _ftdm_channel_call_answer_nl ( file , func , line , ftdmchan , usrmsg ) ;
2010-04-21 11:20:05 -04:00
break ;
2011-05-26 11:38:24 -04:00
case FTDM_CHANNEL_INDICATE_TRANSFER :
if ( ! ftdm_test_flag ( ftdmchan - > span , FTDM_SPAN_USE_TRANSFER ) ) {
ftdm_log_chan_ex_msg ( ftdmchan , file , func , line , FTDM_LOG_LEVEL_WARNING , " Transfer not supported \n " ) ;
status = FTDM_EINVAL ;
goto done ;
}
status = ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_TRANSFER , 1 , usrmsg ) ;
break ;
2010-04-19 11:39:03 -04:00
default :
2011-02-25 09:58:15 -05:00
/* See if signalling module can provide this indication */
status = ftdm_channel_sig_indicate ( ftdmchan , indication , usrmsg ) ;
2010-05-17 14:36:10 -04:00
break ;
2010-04-19 11:39:03 -04:00
}
2010-05-17 14:36:10 -04:00
2010-09-03 11:21:40 -04:00
done :
2010-05-17 14:36:10 -04:00
ftdm_channel_unlock ( ftdmchan ) ;
2010-12-23 15:39:20 -05:00
return status ;
2010-04-19 11:39:03 -04:00
}
2011-02-25 09:58:15 -05:00
FT_DECLARE ( ftdm_status_t ) _ftdm_channel_reset ( const char * file , const char * func , int line , ftdm_channel_t * ftdmchan , ftdm_usrmsg_t * usrmsg )
2010-12-09 13:20:05 -05:00
{
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_FAIL , " null channel " ) ;
ftdm_channel_lock ( ftdmchan ) ;
2011-02-25 09:58:15 -05:00
ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_RESET , 1 , usrmsg ) ;
2010-12-14 11:23:47 -05:00
ftdm_channel_unlock ( ftdmchan ) ;
return FTDM_SUCCESS ;
}
2012-01-26 22:44:19 -05:00
FT_DECLARE ( ftdm_status_t ) ftdm_get_channel_from_string ( const char * string_id , ftdm_span_t * * out_span , ftdm_channel_t * * out_channel )
{
ftdm_status_t status = FTDM_SUCCESS ;
int rc = 0 ;
ftdm_span_t * span = NULL ;
ftdm_channel_t * ftdmchan = NULL ;
unsigned span_id = 0 ;
unsigned chan_id = 0 ;
* out_span = NULL ;
* out_channel = NULL ;
2012-03-16 12:24:10 -04:00
if ( ! string_id ) {
ftdm_log ( FTDM_LOG_ERROR , " Cannot parse NULL channel id string \n " ) ;
status = FTDM_EINVAL ;
goto done ;
}
2012-01-26 22:44:19 -05:00
rc = sscanf ( string_id , " %u:%u " , & span_id , & chan_id ) ;
if ( rc ! = 2 ) {
ftdm_log ( FTDM_LOG_ERROR , " Failed to parse channel id string '%s' \n " , string_id ) ;
status = FTDM_EINVAL ;
goto done ;
}
status = ftdm_span_find ( span_id , & span ) ;
if ( status ! = FTDM_SUCCESS | | ! span ) {
ftdm_log ( FTDM_LOG_ERROR , " Failed to find span for channel id string '%s' \n " , string_id ) ;
status = FTDM_EINVAL ;
goto done ;
}
if ( chan_id > ( FTDM_MAX_CHANNELS_SPAN + 1 ) | | ! ( ftdmchan = span - > channels [ chan_id ] ) ) {
ftdm_log ( FTDM_LOG_ERROR , " Invalid channel id string '%s' \n " , string_id ) ;
status = FTDM_EINVAL ;
goto done ;
}
status = FTDM_SUCCESS ;
* out_span = span ;
* out_channel = ftdmchan ;
done :
return status ;
}
2011-02-24 18:45:54 -05:00
/* this function MUST be called with the channel lock held with lock recursivity of 1 exactly,
* and the caller must be aware we might unlock the channel for a brief period of time and then lock it again */
2011-02-25 09:58:15 -05:00
static ftdm_status_t _ftdm_channel_call_place_nl ( const char * file , const char * func , int line , ftdm_channel_t * ftdmchan , ftdm_usrmsg_t * usrmsg )
2010-01-15 19:22:49 +00:00
{
2012-01-26 22:44:19 -05:00
const char * var = NULL ;
2010-08-23 16:08:06 -04:00
ftdm_status_t status = FTDM_FAIL ;
2010-09-28 13:55:46 -04:00
2010-08-31 14:42:41 -04:00
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_FAIL , " null channel " ) ;
ftdm_assert_return ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OUTBOUND ) , FTDM_FAIL , " Call place, but outbound flag not set \n " ) ;
2010-08-23 16:08:06 -04:00
2011-01-07 16:00:06 -05:00
if ( ! ftdmchan - > span - > outgoing_call ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " outgoing_call method not implemented in this span! \n " ) ;
status = FTDM_ENOSYS ;
goto done ;
2010-01-15 19:22:49 +00:00
}
2010-08-23 16:08:06 -04:00
2011-01-07 16:00:06 -05:00
if ( ! ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OPEN ) ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " Cannot place call in channel that is not open! \n " ) ;
goto done ;
}
if ( ! ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OUTBOUND ) ) {
ftdm_log_chan ( ftdmchan , FTDM_LOG_ERROR , " Cannot place call in non outbound channel in state %s! \n " , ftdm_channel_state2str ( ftdmchan - > state ) ) ;
goto done ;
}
status = ftdmchan - > span - > outgoing_call ( ftdmchan ) ;
if ( status = = FTDM_BREAK ) {
/* the signaling module detected glare on time */
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " Glare detected, you should hunt in another channel! \n " ) ;
goto done ;
}
if ( status ! = FTDM_SUCCESS ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " Failed to place call! \n " ) ;
goto done ;
}
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_CALL_STARTED ) ;
ftdm_call_set_call_id ( ftdmchan , & ftdmchan - > caller_data ) ;
2012-01-26 22:44:19 -05:00
var = ftdm_usrmsg_get_var ( usrmsg , " sigbridge_peer " ) ;
if ( var ) {
ftdm_span_t * peer_span = NULL ;
ftdm_channel_t * peer_chan = NULL ;
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_NATIVE_SIGBRIDGE ) ;
ftdm_get_channel_from_string ( var , & peer_span , & peer_chan ) ;
if ( peer_chan ) {
ftdm_set_flag ( peer_chan , FTDM_CHANNEL_NATIVE_SIGBRIDGE ) ;
}
}
2011-02-24 18:45:54 -05:00
/* if the signaling stack left the channel in state down on success, is expecting us to move to DIALING */
if ( ftdmchan - > state = = FTDM_CHANNEL_STATE_DOWN ) {
if ( ! ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_NONBLOCK ) ) {
2011-02-25 10:06:20 -05:00
ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_DIALING , 1 , usrmsg ) ;
2011-02-24 18:45:54 -05:00
} else {
2011-02-25 10:06:20 -05:00
ftdm_channel_set_state ( file , func , line , ftdmchan , FTDM_CHANNEL_STATE_DIALING , 0 , usrmsg ) ;
2011-02-24 18:45:54 -05:00
}
} else if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_STATE_CHANGE ) & &
! ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_NONBLOCK ) ) {
ftdm_channel_unlock ( ftdmchan ) ;
ftdm_interrupt_wait ( ftdmchan - > state_completed_interrupt , 500 ) ;
ftdm_channel_lock ( ftdmchan ) ;
2010-12-20 14:06:54 -05:00
}
2011-01-07 16:00:06 -05:00
done :
2013-05-10 14:05:07 +02:00
ftdm_unused_arg ( file ) ;
ftdm_unused_arg ( func ) ;
ftdm_unused_arg ( line ) ;
2010-08-23 16:08:06 -04:00
return status ;
2010-01-15 19:22:49 +00:00
}
2011-02-25 09:58:15 -05:00
FT_DECLARE ( ftdm_status_t ) _ftdm_channel_call_place ( const char * file , const char * func , int line , ftdm_channel_t * ftdmchan , ftdm_usrmsg_t * usrmsg )
2011-01-10 16:49:58 -05:00
{
ftdm_status_t status ;
ftdm_channel_lock ( ftdmchan ) ;
2011-02-24 18:45:54 -05:00
/* be aware that _ftdm_channl_call_place_nl can unlock/lock the channel quickly if working in blocking mode */
2011-02-25 09:58:15 -05:00
status = _ftdm_channel_call_place_nl ( file , func , line , ftdmchan , usrmsg ) ;
2011-01-10 16:49:58 -05:00
ftdm_channel_unlock ( ftdmchan ) ;
return status ;
}
FT_DECLARE ( ftdm_status_t ) _ftdm_call_place ( const char * file , const char * func , int line ,
2011-02-25 09:58:15 -05:00
ftdm_caller_data_t * caller_data , ftdm_hunting_scheme_t * hunting , ftdm_usrmsg_t * usrmsg )
2011-01-10 16:49:58 -05:00
{
ftdm_status_t status = FTDM_SUCCESS ;
ftdm_channel_t * fchan = NULL ;
2011-01-11 14:39:58 -05:00
ftdm_assert_return ( caller_data , FTDM_EINVAL , " Invalid caller data \n " ) ;
ftdm_assert_return ( hunting , FTDM_EINVAL , " Invalid hunting scheme \n " ) ;
2011-01-10 16:49:58 -05:00
if ( hunting - > mode = = FTDM_HUNT_SPAN ) {
status = _ftdm_channel_open_by_span ( hunting - > mode_data . span . span_id ,
hunting - > mode_data . span . direction , caller_data , & fchan ) ;
} else if ( hunting - > mode = = FTDM_HUNT_GROUP ) {
status = _ftdm_channel_open_by_group ( hunting - > mode_data . group . group_id ,
hunting - > mode_data . group . direction , caller_data , & fchan ) ;
} else if ( hunting - > mode = = FTDM_HUNT_CHAN ) {
2012-09-11 14:45:57 -04:00
status = _ftdm_channel_open ( hunting - > mode_data . chan . span_id , hunting - > mode_data . chan . chan_id , & fchan , 0 ) ;
2011-01-10 16:49:58 -05:00
} else {
ftdm_log ( FTDM_LOG_ERROR , " Cannot make outbound call with invalid hunting mode %d \n " , hunting - > mode ) ;
return FTDM_EINVAL ;
}
if ( status ! = FTDM_SUCCESS ) {
return FTDM_EBUSY ;
}
/* we have a locked channel and are not afraid of using it! */
2011-02-07 16:06:45 -06:00
if ( hunting - > result_cb ) {
status = hunting - > result_cb ( fchan , caller_data ) ;
if ( status ! = FTDM_SUCCESS ) {
status = FTDM_ECANCELED ;
goto done ;
}
2011-01-10 16:49:58 -05:00
}
ftdm_channel_set_caller_data ( fchan , caller_data ) ;
2011-02-24 18:45:54 -05:00
/* be aware that _ftdm_channl_call_place_nl can unlock/lock the channel quickly if working in blocking mode */
2011-02-25 09:58:15 -05:00
status = _ftdm_channel_call_place_nl ( file , func , line , fchan , usrmsg ) ;
2011-01-10 16:49:58 -05:00
if ( status ! = FTDM_SUCCESS ) {
2011-02-25 09:58:15 -05:00
_ftdm_channel_call_hangup_nl ( file , func , line , fchan , usrmsg ) ;
2011-01-10 16:49:58 -05:00
goto done ;
}
2012-01-30 16:15:08 -05:00
/* let the user know which channel was picked and which call id was generated */
2011-01-10 16:49:58 -05:00
caller_data - > fchan = fchan ;
2012-01-30 16:15:08 -05:00
caller_data - > call_id = fchan - > caller_data . call_id ;
2011-01-10 16:49:58 -05:00
done :
ftdm_channel_unlock ( fchan ) ;
return status ;
}
2011-01-17 15:42:36 -05:00
FT_DECLARE ( ftdm_status_t ) ftdm_channel_set_sig_status ( ftdm_channel_t * fchan , ftdm_signaling_status_t sigstatus )
2010-01-15 19:22:49 +00:00
{
2011-01-17 15:42:36 -05:00
ftdm_status_t res ;
2010-12-17 18:28:57 -02:00
2011-01-17 15:42:36 -05:00
ftdm_assert_return ( fchan ! = NULL , FTDM_FAIL , " Null channel \n " ) ;
ftdm_assert_return ( fchan - > span ! = NULL , FTDM_FAIL , " Null span \n " ) ;
ftdm_assert_return ( fchan - > span - > set_channel_sig_status ! = NULL , FTDM_ENOSYS , " Not implemented \n " ) ;
ftdm_channel_lock ( fchan ) ;
res = fchan - > span - > set_channel_sig_status ( fchan , sigstatus ) ;
ftdm_channel_unlock ( fchan ) ;
return res ;
2010-01-15 19:22:49 +00:00
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_get_sig_status ( ftdm_channel_t * ftdmchan , ftdm_signaling_status_t * sigstatus )
{
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_FAIL , " Null channel \n " ) ;
ftdm_assert_return ( ftdmchan - > span ! = NULL , FTDM_FAIL , " Null span \n " ) ;
ftdm_assert_return ( sigstatus ! = NULL , FTDM_FAIL , " Null sig status parameter \n " ) ;
if ( ftdmchan - > span - > get_channel_sig_status ) {
2010-12-17 18:28:57 -02:00
ftdm_status_t res ;
ftdm_channel_lock ( ftdmchan ) ;
res = ftdmchan - > span - > get_channel_sig_status ( ftdmchan , sigstatus ) ;
ftdm_channel_unlock ( ftdmchan ) ;
return res ;
2010-01-15 19:22:49 +00:00
} else {
2010-04-14 18:36:22 -04:00
/* don't log error here, it can be called just to test if its supported */
return FTDM_NOTIMPL ;
2010-01-15 19:22:49 +00:00
}
}
FT_DECLARE ( ftdm_status_t ) ftdm_span_set_sig_status ( ftdm_span_t * span , ftdm_signaling_status_t sigstatus )
{
ftdm_assert_return ( span ! = NULL , FTDM_FAIL , " Null span \n " ) ;
2010-12-17 18:28:57 -02:00
if ( sigstatus = = FTDM_SIG_STATE_DOWN ) {
ftdm_log ( FTDM_LOG_WARNING , " The user is not allowed to set the signaling status to DOWN, valid states are UP or SUSPENDED \n " ) ;
return FTDM_FAIL ;
}
2010-01-15 19:22:49 +00:00
if ( span - > set_span_sig_status ) {
return span - > set_span_sig_status ( span , sigstatus ) ;
} else {
ftdm_log ( FTDM_LOG_ERROR , " set_span_sig_status method not implemented! \n " ) ;
return FTDM_FAIL ;
}
}
FT_DECLARE ( ftdm_status_t ) ftdm_span_get_sig_status ( ftdm_span_t * span , ftdm_signaling_status_t * sigstatus )
{
ftdm_assert_return ( span ! = NULL , FTDM_FAIL , " Null span \n " ) ;
ftdm_assert_return ( sigstatus ! = NULL , FTDM_FAIL , " Null sig status parameter \n " ) ;
if ( span - > get_span_sig_status ) {
return span - > get_span_sig_status ( span , sigstatus ) ;
} else {
return FTDM_FAIL ;
}
}
2011-02-25 09:58:15 -05:00
static ftdm_status_t ftdm_channel_sig_indicate ( ftdm_channel_t * ftdmchan , ftdm_channel_indication_t indication , ftdm_usrmsg_t * usrmsg )
{
ftdm_status_t status = FTDM_FAIL ;
if ( ftdmchan - > span - > indicate ) {
ftdm_channel_save_usrmsg ( ftdmchan , usrmsg ) ;
status = ftdmchan - > span - > indicate ( ftdmchan , indication ) ;
if ( status = = FTDM_NOTIMPL ) {
ftdm_log ( FTDM_LOG_WARNING , " Do not know how to indicate %s \n " , ftdm_channel_indication2str ( indication ) ) ;
} else if ( status ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_WARNING , " Failed to indicate %s \n " , ftdm_channel_indication2str ( indication ) ) ;
} else { /* SUCCESS */
ftdm_ack_indication ( ftdmchan , indication , FTDM_SUCCESS ) ;
}
ftdm_usrmsg_free ( & ftdmchan - > usrmsg ) ;
} else {
return FTDM_NOTIMPL ;
}
return status ;
}
2010-12-21 19:04:41 -05:00
/* this function must be called with the channel lock */
2010-12-14 11:23:47 -05:00
static ftdm_status_t ftdm_channel_done ( ftdm_channel_t * ftdmchan )
2010-01-15 19:22:49 +00:00
{
2010-09-01 14:42:34 -04:00
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_FAIL , " Null channel can't be done! \n " ) ;
2010-12-21 19:04:41 -05:00
2010-12-14 11:23:47 -05:00
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_OPEN ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_DTMF_DETECT ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_SUPRESS_DTMF ) ;
2010-01-15 19:22:49 +00:00
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_INUSE ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_OUTBOUND ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_WINK ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_FLASH ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_STATE_CHANGE ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_HOLD ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_OFFHOOK ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_RINGING ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_PROGRESS_DETECT ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_CALLERID_DETECT ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_3WAY ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_PROGRESS ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_MEDIA ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_ANSWERED ) ;
2010-07-29 13:15:29 -04:00
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_USER_HANGUP ) ;
2011-05-10 23:35:20 -04:00
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_DIGITAL_MEDIA ) ;
2012-01-26 22:44:19 -05:00
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_NATIVE_SIGBRIDGE ) ;
2010-01-15 19:22:49 +00:00
ftdm_mutex_lock ( ftdmchan - > pre_buffer_mutex ) ;
ftdm_buffer_destroy ( & ftdmchan - > pre_buffer ) ;
ftdmchan - > pre_buffer_size = 0 ;
ftdm_mutex_unlock ( ftdmchan - > pre_buffer_mutex ) ;
2011-02-28 12:47:27 -05:00
2010-09-21 07:19:56 -04:00
if ( ftdmchan - > hangup_timer ) {
ftdm_sched_cancel_timer ( globals . timingsched , ftdmchan - > hangup_timer ) ;
}
2010-01-15 19:22:49 +00:00
ftdmchan - > init_state = FTDM_CHANNEL_STATE_DOWN ;
ftdmchan - > state = FTDM_CHANNEL_STATE_DOWN ;
2010-12-29 13:38:43 -05:00
ftdmchan - > state_status = FTDM_STATE_STATUS_COMPLETED ;
2010-01-15 19:22:49 +00:00
2010-12-03 17:52:10 -05:00
ftdm_channel_command ( ftdmchan , FTDM_COMMAND_DISABLE_DEBUG_DTMF , NULL ) ;
2010-12-03 16:50:03 -05:00
ftdm_channel_command ( ftdmchan , FTDM_COMMAND_DISABLE_INPUT_DUMP , NULL ) ;
ftdm_channel_command ( ftdmchan , FTDM_COMMAND_DISABLE_OUTPUT_DUMP , NULL ) ;
2010-01-15 19:22:49 +00:00
2010-12-20 14:06:54 -05:00
if ( FTDM_IS_VOICE_CHANNEL ( ftdmchan ) & & ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_CALL_STARTED ) ) {
2010-11-23 16:27:40 -05:00
ftdm_sigmsg_t sigmsg ;
memset ( & sigmsg , 0 , sizeof ( sigmsg ) ) ;
sigmsg . span_id = ftdmchan - > span_id ;
sigmsg . chan_id = ftdmchan - > chan_id ;
sigmsg . channel = ftdmchan ;
sigmsg . event_id = FTDM_SIGEVENT_RELEASED ;
ftdm_span_send_signal ( ftdmchan - > span , & sigmsg ) ;
2010-12-10 19:14:08 -05:00
ftdm_call_clear_call_id ( & ftdmchan - > caller_data ) ;
2010-12-20 14:06:54 -05:00
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_CALL_STARTED ) ;
2010-12-14 11:23:47 -05:00
}
2010-11-23 11:43:52 -05:00
2010-12-08 09:09:14 -05:00
if ( ftdmchan - > txdrops | | ftdmchan - > rxdrops ) {
2010-12-14 11:23:47 -05:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_WARNING , " channel dropped data: txdrops = %d, rxdrops = %d \n " ,
2010-12-08 09:09:14 -05:00
ftdmchan - > txdrops , ftdmchan - > rxdrops ) ;
}
2010-12-15 12:56:49 -05:00
2010-12-10 19:14:08 -05:00
memset ( & ftdmchan - > caller_data , 0 , sizeof ( ftdmchan - > caller_data ) ) ;
2010-01-15 19:22:49 +00:00
2010-12-14 11:23:47 -05:00
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_HOLD ) ;
memset ( ftdmchan - > tokens , 0 , sizeof ( ftdmchan - > tokens ) ) ;
ftdmchan - > token_count = 0 ;
ftdm_channel_flush_dtmf ( ftdmchan ) ;
2010-12-08 09:09:14 -05:00
2010-12-14 11:23:47 -05:00
if ( ftdmchan - > gen_dtmf_buffer ) {
ftdm_buffer_zero ( ftdmchan - > gen_dtmf_buffer ) ;
}
2013-03-21 10:41:16 -04:00
if ( ftdmchan - > dtmf_buffer ) {
ftdm_buffer_zero ( ftdmchan - > dtmf_buffer ) ;
}
2010-12-14 11:23:47 -05:00
if ( ftdmchan - > digit_buffer ) {
ftdm_buffer_zero ( ftdmchan - > digit_buffer ) ;
}
if ( ! ftdmchan - > dtmf_on ) {
ftdmchan - > dtmf_on = FTDM_DEFAULT_DTMF_ON ;
}
if ( ! ftdmchan - > dtmf_off ) {
ftdmchan - > dtmf_off = FTDM_DEFAULT_DTMF_OFF ;
}
memset ( ftdmchan - > dtmf_hangup_buf , ' \0 ' , ftdmchan - > span - > dtmf_hangup_len ) ;
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_TRANSCODE ) ) {
ftdmchan - > effective_codec = ftdmchan - > native_codec ;
ftdmchan - > packet_len = ftdmchan - > native_interval * ( ftdmchan - > effective_codec = = FTDM_CODEC_SLIN ? 16 : 8 ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_TRANSCODE ) ;
}
2014-07-23 00:40:27 -04:00
if ( ftdmchan - > span - > sig_release_guard_time_ms ) {
ftdmchan - > last_release_time = ftdm_current_time_in_ms ( ) ;
}
2010-12-02 18:35:48 -05:00
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " channel done \n " ) ;
2010-01-15 19:22:49 +00:00
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_use ( ftdm_channel_t * ftdmchan )
{
2010-12-02 18:35:48 -05:00
ftdm_assert ( ftdmchan ! = NULL , " Null channel \n " ) ;
2010-01-15 19:22:49 +00:00
ftdm_set_flag_locked ( ftdmchan , FTDM_CHANNEL_INUSE ) ;
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_close ( ftdm_channel_t * * ftdmchan )
{
ftdm_channel_t * check ;
ftdm_status_t status = FTDM_FAIL ;
2010-08-31 14:42:41 -04:00
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_FAIL , " null channel double pointer provided! \n " ) ;
ftdm_assert_return ( * ftdmchan ! = NULL , FTDM_FAIL , " null channel pointer provided! \n " ) ;
2010-01-15 19:22:49 +00:00
check = * ftdmchan ;
* ftdmchan = NULL ;
if ( ftdm_test_flag ( check , FTDM_CHANNEL_CONFIGURED ) ) {
ftdm_mutex_lock ( check - > mutex ) ;
2010-12-23 18:15:37 -02:00
if ( ! ftdm_test_flag ( check , FTDM_CHANNEL_OPEN ) ) {
ftdm_log_chan_msg ( check , FTDM_LOG_WARNING , " Channel not opened, proceeding anyway \n " ) ;
}
status = check - > fio - > close ( check ) ;
2011-01-10 17:19:51 -05:00
ftdm_assert ( status = = FTDM_SUCCESS , " Failed to close channel! \n " ) ;
ftdm_channel_done ( check ) ;
* ftdmchan = NULL ;
2010-01-15 19:22:49 +00:00
check - > ring_count = 0 ;
ftdm_mutex_unlock ( check - > mutex ) ;
}
return status ;
}
static ftdm_status_t ftdmchan_activate_dtmf_buffer ( ftdm_channel_t * ftdmchan )
{
if ( ! ftdmchan - > dtmf_buffer ) {
if ( ftdm_buffer_create ( & ftdmchan - > dtmf_buffer , 1024 , 3192 , 0 ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_ERROR , " Failed to allocate DTMF Buffer! \n " ) ;
return FTDM_FAIL ;
} else {
2011-02-09 13:26:23 -05:00
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Created DTMF buffer \n " ) ;
2010-01-15 19:22:49 +00:00
}
}
if ( ! ftdmchan - > tone_session . buffer ) {
memset ( & ftdmchan - > tone_session , 0 , sizeof ( ftdmchan - > tone_session ) ) ;
teletone_init_session ( & ftdmchan - > tone_session , 0 , NULL , NULL ) ;
}
ftdmchan - > tone_session . rate = ftdmchan - > rate ;
ftdmchan - > tone_session . duration = ftdmchan - > dtmf_on * ( ftdmchan - > tone_session . rate / 1000 ) ;
ftdmchan - > tone_session . wait = ftdmchan - > dtmf_off * ( ftdmchan - > tone_session . rate / 1000 ) ;
ftdmchan - > tone_session . volume = - 7 ;
/*
ftdmchan - > tone_session . debug = 1 ;
ftdmchan - > tone_session . debug_stream = stdout ;
*/
return FTDM_SUCCESS ;
}
2011-05-26 11:38:24 -04:00
/*
* ftdmchan_activate_dtmf_buffer to initialize ftdmchan - > dtmf_buffer should be called prior to
* calling ftdm_insert_dtmf_pause
*/
static ftdm_status_t ftdm_insert_dtmf_pause ( ftdm_channel_t * ftdmchan , ftdm_size_t pausems )
{
void * data = NULL ;
2011-06-20 09:36:22 -05:00
ftdm_size_t datalen = pausems * sizeof ( uint16_t ) ;
2011-05-26 11:38:24 -04:00
data = ftdm_malloc ( datalen ) ;
ftdm_assert ( data , " Failed to allocate memory \n " ) ;
memset ( data , FTDM_SILENCE_VALUE ( ftdmchan ) , datalen ) ;
ftdm_buffer_write ( ftdmchan - > dtmf_buffer , data , datalen ) ;
ftdm_safe_free ( data ) ;
return FTDM_SUCCESS ;
}
2010-01-15 19:22:49 +00:00
FT_DECLARE ( ftdm_status_t ) ftdm_channel_command ( ftdm_channel_t * ftdmchan , ftdm_command_t command , void * obj )
{
ftdm_status_t status = FTDM_FAIL ;
2011-05-26 11:38:24 -04:00
2010-12-02 18:35:48 -05:00
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_FAIL , " No channel \n " ) ;
ftdm_assert_return ( ftdmchan - > fio ! = NULL , FTDM_FAIL , " No IO attached to channel \n " ) ;
2010-01-15 19:22:49 +00:00
2011-07-30 17:39:29 -04:00
ftdm_channel_lock ( ftdmchan ) ;
2010-01-15 19:22:49 +00:00
2011-07-30 17:39:29 -04:00
switch ( command ) {
2010-01-15 19:22:49 +00:00
case FTDM_COMMAND_ENABLE_CALLERID_DETECT :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_CALLERID ) ) {
if ( ftdm_fsk_demod_init ( & ftdmchan - > fsk , ftdmchan - > rate , ftdmchan - > fsk_buf , sizeof ( ftdmchan - > fsk_buf ) ) ! = FTDM_SUCCESS ) {
snprintf ( ftdmchan - > last_error , sizeof ( ftdmchan - > last_error ) , " %s " , strerror ( errno ) ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-12-20 16:57:01 -05:00
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_CALLERID_DETECT ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
2010-01-15 19:22:49 +00:00
}
}
break ;
case FTDM_COMMAND_DISABLE_CALLERID_DETECT :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_CALLERID ) ) {
ftdm_fsk_demod_destroy ( & ftdmchan - > fsk ) ;
2010-12-20 16:57:01 -05:00
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_CALLERID_DETECT ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
2010-01-15 19:22:49 +00:00
}
}
break ;
case FTDM_COMMAND_TRACE_INPUT :
{
2010-12-02 18:35:48 -05:00
char * path = FTDM_COMMAND_OBJ_CHAR_P ;
2010-05-28 15:06:51 -04:00
if ( ftdmchan - > fds [ FTDM_READ_TRACE_INDEX ] > 0 ) {
close ( ftdmchan - > fds [ FTDM_READ_TRACE_INDEX ] ) ;
ftdmchan - > fds [ FTDM_READ_TRACE_INDEX ] = - 1 ;
2010-01-15 19:22:49 +00:00
}
2010-12-14 16:55:40 -05:00
if ( ( ftdmchan - > fds [ FTDM_READ_TRACE_INDEX ] = open ( path , O_WRONLY | O_CREAT | O_TRUNC
| FTDM_O_BINARY , S_IRUSR | S_IWUSR ) ) > - 1 ) {
2010-05-28 15:06:51 -04:00
ftdm_log ( FTDM_LOG_DEBUG , " Tracing channel %u:%u input to [%s] \n " , ftdmchan - > span_id , ftdmchan - > chan_id , path ) ;
2010-01-15 19:22:49 +00:00
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
snprintf ( ftdmchan - > last_error , sizeof ( ftdmchan - > last_error ) , " %s " , strerror ( errno ) ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
break ;
case FTDM_COMMAND_TRACE_OUTPUT :
{
char * path = ( char * ) obj ;
2010-05-28 15:06:51 -04:00
if ( ftdmchan - > fds [ FTDM_WRITE_TRACE_INDEX ] > 0 ) {
close ( ftdmchan - > fds [ FTDM_WRITE_TRACE_INDEX ] ) ;
ftdmchan - > fds [ FTDM_WRITE_TRACE_INDEX ] = - 1 ;
2010-01-15 19:22:49 +00:00
}
2010-12-14 16:55:40 -05:00
if ( ( ftdmchan - > fds [ FTDM_WRITE_TRACE_INDEX ] = open ( path , O_WRONLY | O_CREAT | O_TRUNC
| FTDM_O_BINARY , S_IRUSR | S_IWUSR ) ) > - 1 ) {
2010-05-28 15:06:51 -04:00
ftdm_log ( FTDM_LOG_DEBUG , " Tracing channel %u:%u output to [%s] \n " , ftdmchan - > span_id , ftdmchan - > chan_id , path ) ;
2010-01-15 19:22:49 +00:00
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
snprintf ( ftdmchan - > last_error , sizeof ( ftdmchan - > last_error ) , " %s " , strerror ( errno ) ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
break ;
2010-05-28 12:44:37 -04:00
case FTDM_COMMAND_TRACE_END_ALL :
{
2010-05-28 15:06:51 -04:00
if ( ftdmchan - > fds [ FTDM_READ_TRACE_INDEX ] > 0 ) {
close ( ftdmchan - > fds [ FTDM_READ_TRACE_INDEX ] ) ;
ftdmchan - > fds [ FTDM_READ_TRACE_INDEX ] = - 1 ;
2010-05-28 12:44:37 -04:00
}
2010-06-24 15:25:58 -04:00
if ( ftdmchan - > fds [ FTDM_WRITE_TRACE_INDEX ] > 0 ) {
close ( ftdmchan - > fds [ FTDM_WRITE_TRACE_INDEX ] ) ;
ftdmchan - > fds [ FTDM_WRITE_TRACE_INDEX ] = - 1 ;
2010-05-28 12:44:37 -04:00
}
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
break ;
2010-12-02 18:35:48 -05:00
/*!< Enable DTMF debugging */
case FTDM_COMMAND_ENABLE_DEBUG_DTMF :
{
if ( ftdmchan - > dtmfdbg . enabled ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " Cannot enable debug DTMF again \n " ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
if ( ftdmchan - > rxdump . buffer ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " Cannot debug DTMF if Rx dumping is already enabled \n " ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-12-06 07:26:04 -05:00
if ( start_chan_io_dump ( ftdmchan , & ftdmchan - > rxdump , FTDM_IO_DUMP_DEFAULT_BUFF_SIZE ) ! = FTDM_SUCCESS ) {
2010-12-02 18:35:48 -05:00
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " Failed to enable rx dump for DTMF debugging \n " ) ;
2010-12-06 07:26:04 -05:00
GOTO_STATUS ( done , FTDM_FAIL ) ;
2010-12-02 18:35:48 -05:00
}
ftdmchan - > dtmfdbg . enabled = 1 ;
2010-12-03 17:52:10 -05:00
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Enabled DTMF debugging \n " ) ;
2010-12-02 18:35:48 -05:00
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
break ;
/*!< Disable DTMF debugging (if not disabled explicitly, it is disabled automatically when calls hangup) */
case FTDM_COMMAND_DISABLE_DEBUG_DTMF :
{
if ( ! ftdmchan - > dtmfdbg . enabled ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " DTMF debug is already disabled \n " ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
2010-12-06 07:26:04 -05:00
if ( disable_dtmf_debug ( ftdmchan ) ! = FTDM_SUCCESS ) {
2010-12-02 18:35:48 -05:00
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " Failed to disable DTMF debug \n " ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
break ;
/*!< Start dumping all input to a circular buffer. The size of the circular buffer can be specified, default used otherwise */
case FTDM_COMMAND_ENABLE_INPUT_DUMP :
{
ftdm_size_t size = obj ? FTDM_COMMAND_OBJ_SIZE : FTDM_IO_DUMP_DEFAULT_BUFF_SIZE ;
2010-12-03 16:50:03 -05:00
if ( ftdmchan - > rxdump . buffer ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " Input dump is already enabled \n " ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-12-06 07:26:04 -05:00
if ( start_chan_io_dump ( ftdmchan , & ftdmchan - > rxdump , size ) ! = FTDM_SUCCESS ) {
2010-12-15 09:56:27 -05:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_ERROR , " Failed to enable input dump of size % " FTDM_SIZE_FMT " \n " , size ) ;
2010-12-02 18:35:48 -05:00
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-12-15 09:56:27 -05:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_DEBUG , " Enabled input dump with size % " FTDM_SIZE_FMT " \n " , size ) ;
2010-12-02 18:35:48 -05:00
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
break ;
/*!< Stop dumping all input to a circular buffer. */
case FTDM_COMMAND_DISABLE_INPUT_DUMP :
{
2010-12-03 16:50:03 -05:00
if ( ! ftdmchan - > rxdump . buffer ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " No need to disable input dump \n " ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
2010-12-15 09:56:27 -05:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_DEBUG , " Disabled input dump of size % " FTDM_SIZE_FMT " \n " ,
ftdmchan - > rxdump . size ) ;
2010-12-02 18:35:48 -05:00
stop_chan_io_dump ( & ftdmchan - > rxdump ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
break ;
/*!< Start dumping all output to a circular buffer. The size of the circular buffer can be specified, default used otherwise */
case FTDM_COMMAND_ENABLE_OUTPUT_DUMP :
{
ftdm_size_t size = obj ? FTDM_COMMAND_OBJ_SIZE : FTDM_IO_DUMP_DEFAULT_BUFF_SIZE ;
2010-12-03 16:50:03 -05:00
if ( ftdmchan - > txdump . buffer ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " Output dump is already enabled \n " ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-12-06 07:26:04 -05:00
if ( start_chan_io_dump ( ftdmchan , & ftdmchan - > txdump , size ) ! = FTDM_SUCCESS ) {
2012-02-10 13:29:49 +01:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_ERROR , " Failed to enable output dump of size % " FTDM_SIZE_FMT " \n " , size ) ;
2010-12-02 18:35:48 -05:00
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-12-15 09:56:27 -05:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_DEBUG , " Enabled output dump with size % " FTDM_SIZE_FMT " \n " , size ) ;
2010-12-02 18:35:48 -05:00
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
break ;
/*!< Stop dumping all output to a circular buffer. */
case FTDM_COMMAND_DISABLE_OUTPUT_DUMP :
{
2010-12-03 16:50:03 -05:00
if ( ! ftdmchan - > txdump . buffer ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " No need to disable output dump \n " ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
2010-12-15 09:56:27 -05:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_DEBUG , " Disabled output dump of size % " FTDM_SIZE_FMT " \n " , ftdmchan - > rxdump . size ) ;
2010-12-02 18:35:48 -05:00
stop_chan_io_dump ( & ftdmchan - > txdump ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
break ;
/*!< Dump the current input circular buffer to the specified FILE* structure */
case FTDM_COMMAND_DUMP_INPUT :
{
if ( ! obj ) {
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-12-09 07:19:31 -05:00
if ( ! ftdmchan - > rxdump . buffer ) {
ftdm_log_chan ( ftdmchan , FTDM_LOG_WARNING , " Not dumped input to file %p, input dump is not enabled \n " , obj ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-12-02 18:35:48 -05:00
dump_chan_io_to_file ( ftdmchan , & ftdmchan - > rxdump , obj ) ;
2012-02-10 13:29:49 +01:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_DEBUG , " Dumped input of size % " FTDM_SIZE_FMT " to file %p \n " , ftdmchan - > rxdump . size , obj ) ;
2010-12-02 18:35:48 -05:00
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
break ;
/*!< Dump the current output circular buffer to the specified FILE* structure */
case FTDM_COMMAND_DUMP_OUTPUT :
{
if ( ! obj ) {
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-12-09 07:19:31 -05:00
if ( ! ftdmchan - > txdump . buffer ) {
ftdm_log_chan ( ftdmchan , FTDM_LOG_WARNING , " Not dumped output to file %p, output dump is not enabled \n " , obj ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-12-02 18:35:48 -05:00
dump_chan_io_to_file ( ftdmchan , & ftdmchan - > txdump , obj ) ;
2010-12-15 09:56:27 -05:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_DEBUG , " Dumped input of size % " FTDM_SIZE_FMT " to file %p \n " , ftdmchan - > txdump . size , obj ) ;
2010-12-02 18:35:48 -05:00
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
break ;
2010-01-15 19:22:49 +00:00
case FTDM_COMMAND_SET_INTERVAL :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_INTERVAL ) ) {
ftdmchan - > effective_interval = FTDM_COMMAND_OBJ_INT ;
if ( ftdmchan - > effective_interval = = ftdmchan - > native_interval ) {
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_BUFFER ) ;
} else {
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_BUFFER ) ;
}
ftdmchan - > packet_len = ftdmchan - > native_interval * ( ftdmchan - > effective_codec = = FTDM_CODEC_SLIN ? 16 : 8 ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
}
break ;
case FTDM_COMMAND_GET_INTERVAL :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_INTERVAL ) ) {
FTDM_COMMAND_OBJ_INT = ftdmchan - > effective_interval ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
}
break ;
case FTDM_COMMAND_SET_CODEC :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_CODECS ) ) {
ftdmchan - > effective_codec = FTDM_COMMAND_OBJ_INT ;
if ( ftdmchan - > effective_codec = = ftdmchan - > native_codec ) {
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_TRANSCODE ) ;
} else {
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_TRANSCODE ) ;
}
ftdmchan - > packet_len = ftdmchan - > native_interval * ( ftdmchan - > effective_codec = = FTDM_CODEC_SLIN ? 16 : 8 ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
}
break ;
case FTDM_COMMAND_SET_NATIVE_CODEC :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_CODECS ) ) {
ftdmchan - > effective_codec = ftdmchan - > native_codec ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_TRANSCODE ) ;
ftdmchan - > packet_len = ftdmchan - > native_interval * ( ftdmchan - > effective_codec = = FTDM_CODEC_SLIN ? 16 : 8 ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
}
break ;
case FTDM_COMMAND_GET_CODEC :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_CODECS ) ) {
FTDM_COMMAND_OBJ_INT = ftdmchan - > effective_codec ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
}
break ;
case FTDM_COMMAND_GET_NATIVE_CODEC :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_CODECS ) ) {
FTDM_COMMAND_OBJ_INT = ftdmchan - > native_codec ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
}
break ;
case FTDM_COMMAND_ENABLE_PROGRESS_DETECT :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_PROGRESS ) ) {
/* if they don't have thier own, use ours */
ftdm_channel_clear_detected_tones ( ftdmchan ) ;
ftdm_channel_clear_needed_tones ( ftdmchan ) ;
teletone_multi_tone_init ( & ftdmchan - > span - > tone_finder [ FTDM_TONEMAP_DIAL ] , & ftdmchan - > span - > tone_detect_map [ FTDM_TONEMAP_DIAL ] ) ;
teletone_multi_tone_init ( & ftdmchan - > span - > tone_finder [ FTDM_TONEMAP_RING ] , & ftdmchan - > span - > tone_detect_map [ FTDM_TONEMAP_RING ] ) ;
teletone_multi_tone_init ( & ftdmchan - > span - > tone_finder [ FTDM_TONEMAP_BUSY ] , & ftdmchan - > span - > tone_detect_map [ FTDM_TONEMAP_BUSY ] ) ;
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_PROGRESS_DETECT ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
}
break ;
case FTDM_COMMAND_DISABLE_PROGRESS_DETECT :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_PROGRESS ) ) {
2010-12-20 16:57:01 -05:00
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_PROGRESS_DETECT ) ;
2010-01-15 19:22:49 +00:00
ftdm_channel_clear_detected_tones ( ftdmchan ) ;
ftdm_channel_clear_needed_tones ( ftdmchan ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
}
break ;
case FTDM_COMMAND_ENABLE_DTMF_DETECT :
{
/* if they don't have thier own, use ours */
2011-01-10 16:42:47 -05:00
if ( FTDM_IS_VOICE_CHANNEL ( ftdmchan ) ) {
2014-07-13 02:15:38 -04:00
if ( FTDM_CHANNEL_SW_DTMF_ALLOWED ( ftdmchan ) ) {
2011-01-10 16:42:47 -05:00
teletone_dtmf_detect_init ( & ftdmchan - > dtmf_detect , ftdmchan - > rate ) ;
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_DTMF_DETECT ) ;
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_SUPRESS_DTMF ) ;
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Enabled software DTMF detector \n " ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
2010-01-15 19:22:49 +00:00
}
}
break ;
case FTDM_COMMAND_DISABLE_DTMF_DETECT :
{
2011-01-10 16:42:47 -05:00
if ( FTDM_IS_VOICE_CHANNEL ( ftdmchan ) ) {
2014-07-13 02:15:38 -04:00
if ( FTDM_CHANNEL_SW_DTMF_ALLOWED ( ftdmchan ) ) {
teletone_dtmf_detect_init ( & ftdmchan - > dtmf_detect , ftdmchan - > rate ) ;
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_DTMF_DETECT ) ;
2011-01-10 16:42:47 -05:00
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_SUPRESS_DTMF ) ;
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Disabled software DTMF detector \n " ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
2010-01-15 19:22:49 +00:00
}
}
2010-05-25 18:21:34 -04:00
break ;
2010-01-15 19:22:49 +00:00
case FTDM_COMMAND_SET_PRE_BUFFER_SIZE :
{
int val = FTDM_COMMAND_OBJ_INT ;
if ( val < 0 ) {
val = 0 ;
}
ftdmchan - > pre_buffer_size = val * 8 ;
ftdm_mutex_lock ( ftdmchan - > pre_buffer_mutex ) ;
if ( ! ftdmchan - > pre_buffer_size ) {
ftdm_buffer_destroy ( & ftdmchan - > pre_buffer ) ;
} else if ( ! ftdmchan - > pre_buffer ) {
ftdm_buffer_create ( & ftdmchan - > pre_buffer , 1024 , ftdmchan - > pre_buffer_size , 0 ) ;
}
ftdm_mutex_unlock ( ftdmchan - > pre_buffer_mutex ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
break ;
case FTDM_COMMAND_GET_DTMF_ON_PERIOD :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_DTMF_GENERATE ) ) {
FTDM_COMMAND_OBJ_INT = ftdmchan - > dtmf_on ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
}
break ;
case FTDM_COMMAND_GET_DTMF_OFF_PERIOD :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_DTMF_GENERATE ) ) {
FTDM_COMMAND_OBJ_INT = ftdmchan - > dtmf_on ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
}
break ;
case FTDM_COMMAND_SET_DTMF_ON_PERIOD :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_DTMF_GENERATE ) ) {
int val = FTDM_COMMAND_OBJ_INT ;
if ( val > 10 & & val < 1000 ) {
ftdmchan - > dtmf_on = val ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
} else {
2014-07-27 13:29:58 -04:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_ERROR , " invalid value %d range 10-1000 " , val ) ;
2010-01-15 19:22:49 +00:00
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
}
}
break ;
case FTDM_COMMAND_SET_DTMF_OFF_PERIOD :
{
if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_DTMF_GENERATE ) ) {
int val = FTDM_COMMAND_OBJ_INT ;
if ( val > 10 & & val < 1000 ) {
ftdmchan - > dtmf_off = val ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
} else {
2014-07-27 13:29:58 -04:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_ERROR , " invalid value %d range 10-1000 " , val ) ;
2010-01-15 19:22:49 +00:00
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
}
}
break ;
case FTDM_COMMAND_SEND_DTMF :
{
2014-07-13 02:15:38 -04:00
char * digits = FTDM_COMMAND_OBJ_CHAR_P ;
if ( ftdmchan - > span - > sig_send_dtmf ) {
status = ftdmchan - > span - > sig_send_dtmf ( ftdmchan , digits ) ;
GOTO_STATUS ( done , status ) ;
} else if ( ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_DTMF_GENERATE ) ) {
2010-01-15 19:22:49 +00:00
if ( ( status = ftdmchan_activate_dtmf_buffer ( ftdmchan ) ) ! = FTDM_SUCCESS ) {
GOTO_STATUS ( done , status ) ;
}
ftdm_buffer_write ( ftdmchan - > gen_dtmf_buffer , digits , strlen ( digits ) ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
}
break ;
case FTDM_COMMAND_DISABLE_ECHOCANCEL :
{
ftdm_mutex_lock ( ftdmchan - > pre_buffer_mutex ) ;
ftdm_buffer_destroy ( & ftdmchan - > pre_buffer ) ;
ftdmchan - > pre_buffer_size = 0 ;
ftdm_mutex_unlock ( ftdmchan - > pre_buffer_mutex ) ;
}
break ;
case FTDM_COMMAND_SET_RX_GAIN :
{
2010-04-21 14:52:25 -04:00
if ( ! FTDM_IS_VOICE_CHANNEL ( ftdmchan ) ) {
ftdm_log ( FTDM_LOG_ERROR , " Cannot set rx gain in non-voice channel of type: %s \n " , ftdm_chan_type2str ( ftdmchan - > type ) ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-01-15 19:22:49 +00:00
ftdmchan - > rxgain = FTDM_COMMAND_OBJ_FLOAT ;
reset_gain_table ( ftdmchan - > rxgain_table , ftdmchan - > rxgain , ftdmchan - > native_codec ) ;
if ( ftdmchan - > rxgain = = 0.0 ) {
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_USE_RX_GAIN ) ;
} else {
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_USE_RX_GAIN ) ;
}
2010-04-06 14:41:30 -04:00
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
2010-01-15 19:22:49 +00:00
}
break ;
case FTDM_COMMAND_GET_RX_GAIN :
{
FTDM_COMMAND_OBJ_FLOAT = ftdmchan - > rxgain ;
2010-04-06 14:41:30 -04:00
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
2010-01-15 19:22:49 +00:00
}
break ;
case FTDM_COMMAND_SET_TX_GAIN :
{
2010-04-21 14:52:25 -04:00
if ( ! FTDM_IS_VOICE_CHANNEL ( ftdmchan ) ) {
ftdm_log ( FTDM_LOG_ERROR , " Cannot set tx gain in non-voice channel of type: %s \n " , ftdm_chan_type2str ( ftdmchan - > type ) ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-01-15 19:22:49 +00:00
ftdmchan - > txgain = FTDM_COMMAND_OBJ_FLOAT ;
reset_gain_table ( ftdmchan - > txgain_table , ftdmchan - > txgain , ftdmchan - > native_codec ) ;
if ( ftdmchan - > txgain = = 0.0 ) {
ftdm_clear_flag ( ftdmchan , FTDM_CHANNEL_USE_TX_GAIN ) ;
} else {
ftdm_set_flag ( ftdmchan , FTDM_CHANNEL_USE_TX_GAIN ) ;
}
2010-04-06 14:41:30 -04:00
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
2010-01-15 19:22:49 +00:00
}
break ;
case FTDM_COMMAND_GET_TX_GAIN :
{
FTDM_COMMAND_OBJ_FLOAT = ftdmchan - > txgain ;
2010-04-06 14:41:30 -04:00
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
2010-01-15 19:22:49 +00:00
}
break ;
2011-07-30 17:39:29 -04:00
case FTDM_COMMAND_GET_IOSTATS :
{
if ( ! obj ) {
GOTO_STATUS ( done , FTDM_EINVAL ) ;
}
memcpy ( obj , & ftdmchan - > iostats , sizeof ( ftdmchan - > iostats ) ) ;
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
break ;
case FTDM_COMMAND_SWITCH_IOSTATS :
{
ftdm_bool_t enable = * ( ftdm_bool_t * ) obj ;
if ( enable ) {
ftdm_channel_set_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_IO_STATS ) ;
} else {
ftdm_channel_clear_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_IO_STATS ) ;
}
GOTO_STATUS ( done , FTDM_SUCCESS ) ;
}
break ;
2010-01-15 19:22:49 +00:00
default :
break ;
}
2010-01-15 20:35:11 +00:00
if ( ! ftdmchan - > fio - > command ) {
2010-01-15 19:22:49 +00:00
ftdm_log ( FTDM_LOG_ERROR , " no command function defined by the I/O freetdm module! \n " ) ;
GOTO_STATUS ( done , FTDM_FAIL ) ;
}
2010-04-06 14:41:30 -04:00
status = ftdmchan - > fio - > command ( ftdmchan , command , obj ) ;
2010-01-15 19:22:49 +00:00
if ( status = = FTDM_NOTIMPL ) {
ftdm_log ( FTDM_LOG_ERROR , " I/O backend does not support command %d! \n " , command ) ;
}
2011-07-30 17:39:29 -04:00
2010-01-15 19:22:49 +00:00
done :
2011-07-30 17:39:29 -04:00
ftdm_channel_unlock ( ftdmchan ) ;
2010-01-15 19:22:49 +00:00
return status ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_wait ( ftdm_channel_t * ftdmchan , ftdm_wait_flag_t * flags , int32_t to )
{
2010-11-30 11:38:38 -05:00
ftdm_status_t status = FTDM_FAIL ;
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_FAIL , " Null channel \n " ) ;
ftdm_assert_return ( ftdmchan - > fio ! = NULL , FTDM_FAIL , " Null io interface \n " ) ;
ftdm_assert_return ( ftdmchan - > fio - > wait ! = NULL , FTDM_NOTIMPL , " wait method not implemented \n " ) ;
2010-01-15 19:22:49 +00:00
2010-11-30 11:38:38 -05:00
status = ftdmchan - > fio - > wait ( ftdmchan , flags , to ) ;
if ( status = = FTDM_TIMEOUT ) {
/* make sure the flags are cleared on timeout */
* flags = 0 ;
2010-01-15 19:22:49 +00:00
}
2010-11-30 11:38:38 -05:00
return status ;
2010-01-15 19:22:49 +00:00
}
/*******************************/
2010-01-15 20:35:11 +00:00
FIO_CODEC_FUNCTION ( fio_slin2ulaw )
2010-01-15 19:22:49 +00:00
{
int16_t sln_buf [ 512 ] = { 0 } , * sln = sln_buf ;
uint8_t * lp = data ;
uint32_t i ;
ftdm_size_t len = * datalen ;
if ( max > len ) {
max = len ;
}
memcpy ( sln , data , max ) ;
for ( i = 0 ; i < max ; i + + ) {
* lp + + = linear_to_ulaw ( * sln + + ) ;
}
* datalen = max / 2 ;
return FTDM_SUCCESS ;
}
2010-01-15 20:35:11 +00:00
FIO_CODEC_FUNCTION ( fio_ulaw2slin )
2010-01-15 19:22:49 +00:00
{
int16_t * sln = data ;
uint8_t law [ 1024 ] = { 0 } , * lp = law ;
uint32_t i ;
ftdm_size_t len = * datalen ;
if ( max > len ) {
max = len ;
}
memcpy ( law , data , max ) ;
for ( i = 0 ; i < max ; i + + ) {
* sln + + = ulaw_to_linear ( * lp + + ) ;
}
* datalen = max * 2 ;
return FTDM_SUCCESS ;
}
2010-01-15 20:35:11 +00:00
FIO_CODEC_FUNCTION ( fio_slin2alaw )
2010-01-15 19:22:49 +00:00
{
int16_t sln_buf [ 512 ] = { 0 } , * sln = sln_buf ;
uint8_t * lp = data ;
uint32_t i ;
ftdm_size_t len = * datalen ;
if ( max > len ) {
max = len ;
}
memcpy ( sln , data , max ) ;
for ( i = 0 ; i < max ; i + + ) {
* lp + + = linear_to_alaw ( * sln + + ) ;
}
* datalen = max / 2 ;
return FTDM_SUCCESS ;
}
2010-01-15 20:35:11 +00:00
FIO_CODEC_FUNCTION ( fio_alaw2slin )
2010-01-15 19:22:49 +00:00
{
int16_t * sln = data ;
uint8_t law [ 1024 ] = { 0 } , * lp = law ;
uint32_t i ;
ftdm_size_t len = * datalen ;
if ( max > len ) {
max = len ;
}
memcpy ( law , data , max ) ;
for ( i = 0 ; i < max ; i + + ) {
* sln + + = alaw_to_linear ( * lp + + ) ;
}
* datalen = max * 2 ;
return FTDM_SUCCESS ;
}
2010-01-15 20:35:11 +00:00
FIO_CODEC_FUNCTION ( fio_ulaw2alaw )
2010-01-15 19:22:49 +00:00
{
ftdm_size_t len = * datalen ;
uint32_t i ;
uint8_t * lp = data ;
if ( max > len ) {
max = len ;
}
for ( i = 0 ; i < max ; i + + ) {
* lp = ulaw_to_alaw ( * lp ) ;
lp + + ;
}
return FTDM_SUCCESS ;
}
2010-01-15 20:35:11 +00:00
FIO_CODEC_FUNCTION ( fio_alaw2ulaw )
2010-01-15 19:22:49 +00:00
{
ftdm_size_t len = * datalen ;
uint32_t i ;
uint8_t * lp = data ;
if ( max > len ) {
max = len ;
}
for ( i = 0 ; i < max ; i + + ) {
* lp = alaw_to_ulaw ( * lp ) ;
lp + + ;
}
return FTDM_SUCCESS ;
}
/******************************/
FT_DECLARE ( void ) ftdm_channel_clear_detected_tones ( ftdm_channel_t * ftdmchan )
{
uint32_t i ;
memset ( ftdmchan - > detected_tones , 0 , sizeof ( ftdmchan - > detected_tones [ 0 ] ) * FTDM_TONEMAP_INVALID ) ;
for ( i = 1 ; i < FTDM_TONEMAP_INVALID ; i + + ) {
ftdmchan - > span - > tone_finder [ i ] . tone_count = 0 ;
}
}
FT_DECLARE ( void ) ftdm_channel_clear_needed_tones ( ftdm_channel_t * ftdmchan )
{
memset ( ftdmchan - > needed_tones , 0 , sizeof ( ftdmchan - > needed_tones [ 0 ] ) * FTDM_TONEMAP_INVALID ) ;
}
FT_DECLARE ( ftdm_size_t ) ftdm_channel_dequeue_dtmf ( ftdm_channel_t * ftdmchan , char * dtmf , ftdm_size_t len )
{
ftdm_size_t bytes = 0 ;
assert ( ftdmchan ! = NULL ) ;
if ( ! ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_READY ) ) {
2010-06-08 00:07:39 -04:00
return 0 ;
2010-01-15 19:22:49 +00:00
}
if ( ftdmchan - > digit_buffer & & ftdm_buffer_inuse ( ftdmchan - > digit_buffer ) ) {
ftdm_mutex_lock ( ftdmchan - > mutex ) ;
if ( ( bytes = ftdm_buffer_read ( ftdmchan - > digit_buffer , dtmf , len ) ) > 0 ) {
* ( dtmf + bytes ) = ' \0 ' ;
}
ftdm_mutex_unlock ( ftdmchan - > mutex ) ;
}
return bytes ;
}
FT_DECLARE ( void ) ftdm_channel_flush_dtmf ( ftdm_channel_t * ftdmchan )
{
if ( ftdmchan - > digit_buffer & & ftdm_buffer_inuse ( ftdmchan - > digit_buffer ) ) {
ftdm_mutex_lock ( ftdmchan - > mutex ) ;
ftdm_buffer_zero ( ftdmchan - > digit_buffer ) ;
ftdm_mutex_unlock ( ftdmchan - > mutex ) ;
}
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_queue_dtmf ( ftdm_channel_t * ftdmchan , const char * dtmf )
{
ftdm_status_t status ;
register ftdm_size_t len , inuse ;
ftdm_size_t wr = 0 ;
const char * p ;
2010-12-02 18:35:48 -05:00
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_FAIL , " No channel \n " ) ;
2010-01-15 19:22:49 +00:00
2010-12-03 17:52:10 -05:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_DEBUG , " Queuing DTMF %s (debug = %d) \n " , dtmf , ftdmchan - > dtmfdbg . enabled ) ;
2010-01-15 19:22:49 +00:00
2014-07-13 02:15:38 -04:00
if ( ftdmchan - > span - > sig_queue_dtmf & & ( ftdmchan - > span - > sig_queue_dtmf ( ftdmchan , dtmf ) = = FTDM_BREAK ) ) {
2012-09-13 12:34:49 -04:00
/* Signalling module wants to absorb this DTMF event */
return FTDM_SUCCESS ;
}
2010-12-02 18:35:48 -05:00
if ( ! ftdmchan - > dtmfdbg . enabled ) {
goto skipdebug ;
}
2010-07-29 17:26:03 -04:00
if ( ! ftdmchan - > dtmfdbg . file ) {
struct tm currtime ;
time_t currsec ;
2017-06-28 06:10:46 -06:00
char dfile [ 1138 ] ;
2010-07-29 17:26:03 -04:00
currsec = time ( NULL ) ;
2010-12-06 17:11:56 -02:00
# ifdef WIN32
_tzset ( ) ;
_localtime64_s ( & currtime , & currsec ) ;
# else
2010-07-29 17:26:03 -04:00
localtime_r ( & currsec , & currtime ) ;
2010-12-06 17:11:56 -02:00
# endif
2010-07-29 17:26:03 -04:00
2011-03-18 14:47:49 -04:00
if ( ftdm_strlen_zero ( globals . dtmfdebug_directory ) ) {
2013-03-07 09:41:51 -06:00
snprintf ( dfile , sizeof ( dfile ) , " dtmf-s%dc%d-20%d-%d-%d-%d%d%d.%s " ,
2011-03-18 14:47:49 -04:00
ftdmchan - > span_id , ftdmchan - > chan_id ,
currtime . tm_year - 100 , currtime . tm_mon + 1 , currtime . tm_mday ,
currtime . tm_hour , currtime . tm_min , currtime . tm_sec , ftdmchan - > native_codec = = FTDM_CODEC_ULAW ? " ulaw " : ftdmchan - > native_codec = = FTDM_CODEC_ALAW ? " alaw " : " sln " ) ;
} else {
2013-03-07 09:41:51 -06:00
snprintf ( dfile , sizeof ( dfile ) , " %s/dtmf-s%dc%d-20%d-%d-%d-%d%d%d.%s " ,
2011-03-18 14:47:49 -04:00
globals . dtmfdebug_directory ,
ftdmchan - > span_id , ftdmchan - > chan_id ,
currtime . tm_year - 100 , currtime . tm_mon + 1 , currtime . tm_mday ,
currtime . tm_hour , currtime . tm_min , currtime . tm_sec , ftdmchan - > native_codec = = FTDM_CODEC_ULAW ? " ulaw " : ftdmchan - > native_codec = = FTDM_CODEC_ALAW ? " alaw " : " sln " ) ;
}
2010-12-14 16:55:40 -05:00
ftdmchan - > dtmfdbg . file = fopen ( dfile , " wb " ) ;
2010-07-29 17:26:03 -04:00
if ( ! ftdmchan - > dtmfdbg . file ) {
ftdm_log_chan ( ftdmchan , FTDM_LOG_ERROR , " failed to open debug dtmf file %s \n " , dfile ) ;
} else {
ftdmchan - > dtmfdbg . closetimeout = DTMF_DEBUG_TIMEOUT ;
2010-12-02 18:35:48 -05:00
ftdm_channel_command ( ftdmchan , FTDM_COMMAND_DUMP_INPUT , ftdmchan - > dtmfdbg . file ) ;
2010-12-03 17:54:24 -05:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_DEBUG , " Dumped initial DTMF output to %s \n " , dfile ) ;
2010-07-29 17:26:03 -04:00
}
} else {
2010-12-02 18:35:48 -05:00
ftdmchan - > dtmfdbg . closetimeout = DTMF_DEBUG_TIMEOUT ;
2010-07-29 17:26:03 -04:00
}
2010-12-02 18:35:48 -05:00
skipdebug :
2010-07-29 17:26:03 -04:00
2010-01-15 19:22:49 +00:00
if ( ftdmchan - > pre_buffer ) {
ftdm_buffer_zero ( ftdmchan - > pre_buffer ) ;
}
ftdm_mutex_lock ( ftdmchan - > mutex ) ;
inuse = ftdm_buffer_inuse ( ftdmchan - > digit_buffer ) ;
len = strlen ( dtmf ) ;
if ( len + inuse > ftdm_buffer_len ( ftdmchan - > digit_buffer ) ) {
ftdm_buffer_toss ( ftdmchan - > digit_buffer , strlen ( dtmf ) ) ;
}
if ( ftdmchan - > span - > dtmf_hangup_len ) {
for ( p = dtmf ; ftdm_is_dtmf ( * p ) ; p + + ) {
memmove ( ftdmchan - > dtmf_hangup_buf , ftdmchan - > dtmf_hangup_buf + 1 , ftdmchan - > span - > dtmf_hangup_len - 1 ) ;
ftdmchan - > dtmf_hangup_buf [ ftdmchan - > span - > dtmf_hangup_len - 1 ] = * p ;
if ( ! strcmp ( ftdmchan - > dtmf_hangup_buf , ftdmchan - > span - > dtmf_hangup ) ) {
ftdm_log ( FTDM_LOG_DEBUG , " DTMF hangup detected. \n " ) ;
2011-02-25 09:58:15 -05:00
2015-06-29 16:59:47 -04:00
ftdm_channel_set_state ( __FILE__ , __FTDM_FUNC__ , __LINE__ , ftdmchan , FTDM_CHANNEL_STATE_HANGUP , 0 , NULL ) ;
2010-01-15 19:22:49 +00:00
break ;
}
}
}
p = dtmf ;
while ( wr < len & & p ) {
if ( ftdm_is_dtmf ( * p ) ) {
wr + + ;
} else {
break ;
}
p + + ;
}
status = ftdm_buffer_write ( ftdmchan - > digit_buffer , dtmf , wr ) ? FTDM_SUCCESS : FTDM_FAIL ;
ftdm_mutex_unlock ( ftdmchan - > mutex ) ;
2011-05-26 11:38:24 -04:00
2010-01-15 19:22:49 +00:00
return status ;
}
2011-06-13 16:22:10 -04:00
FT_DECLARE ( ftdm_status_t ) ftdm_raw_write ( ftdm_channel_t * ftdmchan , void * data , ftdm_size_t * datalen )
2010-05-28 15:06:51 -04:00
{
2010-12-03 16:50:03 -05:00
int dlen = ( int ) * datalen ;
2011-05-26 11:38:24 -04:00
if ( ftdm_test_io_flag ( ftdmchan , FTDM_CHANNEL_IO_WRITE ) ) {
ftdm_clear_io_flag ( ftdmchan , FTDM_CHANNEL_IO_WRITE ) ;
}
2010-12-08 09:09:14 -05:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_TX_DISABLED ) ) {
ftdmchan - > txdrops + + ;
if ( ftdmchan - > txdrops < = 10 ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " cannot write in channel with tx disabled \n " ) ;
}
if ( ftdmchan - > txdrops = = 10 ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " Too many tx drops, not printing anymore \n " ) ;
}
return FTDM_FAIL ;
}
2010-05-28 15:06:51 -04:00
if ( ftdmchan - > fds [ FTDM_WRITE_TRACE_INDEX ] > - 1 ) {
if ( ( write ( ftdmchan - > fds [ FTDM_WRITE_TRACE_INDEX ] , data , dlen ) ) ! = dlen ) {
2012-02-10 13:29:49 +01:00
ftdm_log ( FTDM_LOG_WARNING , " Raw output trace failed to write all of the %d bytes \n " , dlen ) ;
2010-05-28 15:06:51 -04:00
}
}
2010-12-06 17:11:56 -02:00
write_chan_io_dump ( & ftdmchan - > txdump , data , dlen ) ;
2010-05-28 15:06:51 -04:00
return ftdmchan - > fio - > write ( ftdmchan , data , datalen ) ;
}
2011-06-13 16:22:10 -04:00
FT_DECLARE ( ftdm_status_t ) ftdm_raw_read ( ftdm_channel_t * ftdmchan , void * data , ftdm_size_t * datalen )
2010-05-28 15:06:51 -04:00
{
2011-05-26 11:38:24 -04:00
ftdm_status_t status ;
if ( ftdm_test_io_flag ( ftdmchan , FTDM_CHANNEL_IO_READ ) ) {
ftdm_clear_io_flag ( ftdmchan , FTDM_CHANNEL_IO_READ ) ;
}
status = ftdmchan - > fio - > read ( ftdmchan , data , datalen ) ;
2011-04-07 11:21:50 -04:00
2011-05-26 11:38:24 -04:00
if ( status = = FTDM_SUCCESS & & ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_USE_RX_GAIN )
2011-04-07 11:21:50 -04:00
& & ( ftdmchan - > native_codec = = FTDM_CODEC_ALAW | | ftdmchan - > native_codec = = FTDM_CODEC_ULAW ) ) {
2011-04-21 12:59:37 -05:00
ftdm_size_t i = 0 ;
2011-04-07 11:21:50 -04:00
unsigned char * rdata = data ;
for ( i = 0 ; i < * datalen ; i + + ) {
rdata [ i ] = ftdmchan - > rxgain_table [ rdata [ i ] ] ;
}
}
2010-05-28 15:06:51 -04:00
if ( status = = FTDM_SUCCESS & & ftdmchan - > fds [ FTDM_READ_TRACE_INDEX ] > - 1 ) {
2010-12-07 20:33:23 -02:00
ftdm_size_t dlen = * datalen ;
2010-12-09 08:44:55 -06:00
if ( ( ftdm_size_t ) write ( ftdmchan - > fds [ FTDM_READ_TRACE_INDEX ] , data , ( int ) dlen ) ! = dlen ) {
2010-12-15 09:56:27 -05:00
ftdm_log ( FTDM_LOG_WARNING , " Raw input trace failed to write all of the % " FTDM_SIZE_FMT " bytes \n " , dlen ) ;
2010-05-28 15:06:51 -04:00
}
}
2010-08-01 03:02:53 -04:00
if ( status = = FTDM_SUCCESS & & ftdmchan - > span - > sig_read ) {
ftdmchan - > span - > sig_read ( ftdmchan , data , * datalen ) ;
}
2010-07-29 17:26:03 -04:00
if ( status = = FTDM_SUCCESS ) {
2010-12-07 20:33:23 -02:00
ftdm_size_t dlen = * datalen ;
ftdm_size_t rc = 0 ;
2010-12-02 18:35:48 -05:00
2010-12-09 08:44:55 -06:00
write_chan_io_dump ( & ftdmchan - > rxdump , data , ( int ) dlen ) ;
2010-12-02 18:35:48 -05:00
/* if dtmf debug is enabled and initialized, write there too */
if ( ftdmchan - > dtmfdbg . file ) {
2010-07-29 17:26:03 -04:00
rc = fwrite ( data , 1 , dlen , ftdmchan - > dtmfdbg . file ) ;
if ( rc ! = dlen ) {
2012-02-10 13:29:49 +01:00
ftdm_log ( FTDM_LOG_WARNING , " DTMF debugger wrote only % " FTDM_SIZE_FMT " out of % " FTDM_SIZE_FMT " bytes: %s \n " ,
rc , * datalen , strerror ( errno ) ) ;
2010-07-29 17:26:03 -04:00
}
ftdmchan - > dtmfdbg . closetimeout - - ;
if ( ! ftdmchan - > dtmfdbg . closetimeout ) {
2010-12-02 18:35:48 -05:00
close_dtmf_debug_file ( ftdmchan ) ;
2010-07-29 17:26:03 -04:00
}
}
}
2010-05-28 15:06:51 -04:00
return status ;
}
2010-01-15 19:22:49 +00:00
2011-02-09 13:26:23 -05:00
/* This function takes care of automatically generating DTMF or FSK tones when needed */
2011-02-10 18:00:31 -05:00
static ftdm_status_t handle_tone_generation ( ftdm_channel_t * ftdmchan )
2010-01-15 19:22:49 +00:00
{
2011-02-09 13:26:23 -05:00
/*
* datalen : size in bytes of the chunk of data the user requested to read ( this function
* is called from the ftdm_channel_read function )
* dblen : size currently in use in any of the tone generation buffers ( data available in the buffer )
* gen_dtmf_buffer : buffer holding the raw ASCII digits that the user requested to generate
* dtmf_buffer : raw linear tone data generated by teletone to be written to the devices
* fsk_buffer : raw linear FSK modulated data for caller id
*/
2010-01-15 19:22:49 +00:00
ftdm_buffer_t * buffer = NULL ;
ftdm_size_t dblen = 0 ;
int wrote = 0 ;
if ( ftdmchan - > gen_dtmf_buffer & & ( dblen = ftdm_buffer_inuse ( ftdmchan - > gen_dtmf_buffer ) ) ) {
char digits [ 128 ] = " " ;
char * cur ;
int x = 0 ;
if ( dblen > sizeof ( digits ) - 1 ) {
dblen = sizeof ( digits ) - 1 ;
}
if ( ftdm_buffer_read ( ftdmchan - > gen_dtmf_buffer , digits , dblen ) & & ! ftdm_strlen_zero_buf ( digits ) ) {
2011-02-09 13:26:23 -05:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_DEBUG , " Generating DTMF [%s] \n " , digits ) ;
2010-01-15 19:22:49 +00:00
2011-05-26 11:38:24 -04:00
cur = digits ;
2010-01-15 19:22:49 +00:00
for ( ; * cur ; cur + + ) {
2011-05-26 11:38:24 -04:00
if ( * cur = = ' F ' ) {
ftdm_channel_command ( ftdmchan , FTDM_COMMAND_FLASH , NULL ) ;
} else if ( * cur = = ' w ' ) {
ftdm_insert_dtmf_pause ( ftdmchan , FTDM_HALF_DTMF_PAUSE ) ;
} else if ( * cur = = ' W ' ) {
ftdm_insert_dtmf_pause ( ftdmchan , FTDM_FULL_DTMF_PAUSE ) ;
2010-01-15 19:22:49 +00:00
} else {
2011-05-26 11:38:24 -04:00
if ( ( wrote = teletone_mux_tones ( & ftdmchan - > tone_session , & ftdmchan - > tone_session . TONES [ ( int ) * cur ] ) ) ) {
ftdm_buffer_write ( ftdmchan - > dtmf_buffer , ftdmchan - > tone_session . buffer , wrote * 2 ) ;
x + + ;
} else {
ftdm_log_chan ( ftdmchan , FTDM_LOG_ERROR , " Problem adding DTMF sequence [%s] \n " , digits ) ;
return FTDM_FAIL ;
}
}
if ( x ) {
ftdmchan - > skip_read_frames = ( wrote / ( ftdmchan - > effective_interval * 8 ) ) + 4 ;
2010-01-15 19:22:49 +00:00
}
}
}
}
if ( ! ftdmchan - > buffer_delay | | - - ftdmchan - > buffer_delay = = 0 ) {
2011-02-09 13:26:23 -05:00
/* time to pick a buffer, either the dtmf or fsk buffer */
2010-01-15 19:22:49 +00:00
if ( ftdmchan - > dtmf_buffer & & ( dblen = ftdm_buffer_inuse ( ftdmchan - > dtmf_buffer ) ) ) {
buffer = ftdmchan - > dtmf_buffer ;
} else if ( ftdmchan - > fsk_buffer & & ( dblen = ftdm_buffer_inuse ( ftdmchan - > fsk_buffer ) ) ) {
buffer = ftdmchan - > fsk_buffer ;
}
}
2011-02-09 13:26:23 -05:00
/* if we picked a buffer, time to read from it and write the linear data to the device */
2010-01-15 19:22:49 +00:00
if ( buffer ) {
uint8_t auxbuf [ 1024 ] ;
2011-02-10 18:00:31 -05:00
ftdm_size_t dlen = ftdmchan - > packet_len ;
2010-01-15 19:22:49 +00:00
ftdm_size_t len , br , max = sizeof ( auxbuf ) ;
2011-02-09 13:26:23 -05:00
/* if the codec is not linear, then data is really twice as much cuz
tone generation is done in linear ( we assume anything different than linear is G .711 ) */
2010-01-15 19:22:49 +00:00
if ( ftdmchan - > native_codec ! = FTDM_CODEC_SLIN ) {
dlen * = 2 ;
}
2011-02-09 13:26:23 -05:00
/* we do not expect the user chunks to be bigger than auxbuf */
2011-02-10 18:00:31 -05:00
ftdm_assert ( ( dlen < = sizeof ( auxbuf ) ) , " Unexpected size for user data chunk size \n " ) ;
2011-02-09 13:26:23 -05:00
/* dblen is the size in use for dtmf_buffer or fsk_buffer, and dlen is the size
2011-02-10 18:00:31 -05:00
* of the io chunks to write , we pick the smaller one */
2010-01-15 19:22:49 +00:00
len = dblen > dlen ? dlen : dblen ;
2011-02-09 13:26:23 -05:00
/* we can't read more than the size of our auxiliary buffer */
ftdm_assert ( ( len < = sizeof ( auxbuf ) ) , " Unexpected size to read into auxbuf \n " ) ;
2010-01-15 19:22:49 +00:00
br = ftdm_buffer_read ( buffer , auxbuf , len ) ;
2011-02-09 13:26:23 -05:00
/* the amount read can't possibly be bigger than what we requested */
ftdm_assert ( ( br < = len ) , " Unexpected size read from tone generation buffer \n " ) ;
/* if we read less than the chunk size, we must fill in with silence the rest */
2010-01-15 19:22:49 +00:00
if ( br < dlen ) {
memset ( auxbuf + br , 0 , dlen - br ) ;
}
2011-02-09 13:26:23 -05:00
/* finally we convert to the native format for the channel if necessary */
2010-01-15 19:22:49 +00:00
if ( ftdmchan - > native_codec ! = FTDM_CODEC_SLIN ) {
if ( ftdmchan - > native_codec = = FTDM_CODEC_ULAW ) {
2010-01-15 20:35:11 +00:00
fio_slin2ulaw ( auxbuf , max , & dlen ) ;
2010-01-15 19:22:49 +00:00
} else if ( ftdmchan - > native_codec = = FTDM_CODEC_ALAW ) {
2010-01-15 20:35:11 +00:00
fio_slin2alaw ( auxbuf , max , & dlen ) ;
2010-01-15 19:22:49 +00:00
}
}
2011-02-09 13:26:23 -05:00
/* write the tone to the channel */
2010-05-28 15:06:51 -04:00
return ftdm_raw_write ( ftdmchan , auxbuf , & dlen ) ;
2010-01-15 19:22:49 +00:00
}
return FTDM_SUCCESS ;
}
2011-05-26 11:38:24 -04:00
2010-01-15 19:22:49 +00:00
FT_DECLARE ( void ) ftdm_generate_sln_silence ( int16_t * data , uint32_t samples , uint32_t divisor )
{
int16_t x ;
uint32_t i ;
int sum_rnd = 0 ;
int16_t rnd2 = ( int16_t ) ftdm_current_time_in_ms ( ) * ( int16_t ) ( intptr_t ) data ;
assert ( divisor ) ;
for ( i = 0 ; i < samples ; i + + , sum_rnd = 0 ) {
for ( x = 0 ; x < 6 ; x + + ) {
rnd2 = rnd2 * 31821U + 13849U ;
sum_rnd + = rnd2 ;
}
//switch_normalize_to_16bit(sum_rnd);
* data = ( int16_t ) ( ( int16_t ) sum_rnd / ( int ) divisor ) ;
data + + ;
}
}
2011-05-26 11:38:24 -04:00
FT_DECLARE ( ftdm_status_t ) ftdm_channel_process_media ( ftdm_channel_t * ftdmchan , void * data , ftdm_size_t * datalen )
2010-01-15 19:22:49 +00:00
{
2010-01-15 20:35:11 +00:00
fio_codec_t codec_func = NULL ;
2010-01-15 19:22:49 +00:00
ftdm_size_t max = * datalen ;
2011-02-10 18:00:31 -05:00
handle_tone_generation ( ftdmchan ) ;
2010-01-15 19:22:49 +00:00
2011-05-10 23:35:20 -04:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_DIGITAL_MEDIA ) ) {
goto done ;
}
2010-12-20 14:06:54 -05:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_TRANSCODE ) & & ftdmchan - > effective_codec ! = ftdmchan - > native_codec ) {
2010-01-15 19:22:49 +00:00
if ( ftdmchan - > native_codec = = FTDM_CODEC_ULAW & & ftdmchan - > effective_codec = = FTDM_CODEC_SLIN ) {
2010-01-15 20:35:11 +00:00
codec_func = fio_ulaw2slin ;
2010-01-15 19:22:49 +00:00
} else if ( ftdmchan - > native_codec = = FTDM_CODEC_ULAW & & ftdmchan - > effective_codec = = FTDM_CODEC_ALAW ) {
2010-01-15 20:35:11 +00:00
codec_func = fio_ulaw2alaw ;
2010-01-15 19:22:49 +00:00
} else if ( ftdmchan - > native_codec = = FTDM_CODEC_ALAW & & ftdmchan - > effective_codec = = FTDM_CODEC_SLIN ) {
2010-01-15 20:35:11 +00:00
codec_func = fio_alaw2slin ;
2010-01-15 19:22:49 +00:00
} else if ( ftdmchan - > native_codec = = FTDM_CODEC_ALAW & & ftdmchan - > effective_codec = = FTDM_CODEC_ULAW ) {
2010-01-15 20:35:11 +00:00
codec_func = fio_alaw2ulaw ;
2010-01-15 19:22:49 +00:00
}
if ( codec_func ) {
2011-06-28 14:54:37 +02:00
codec_func ( data , max , datalen ) ;
2010-01-15 19:22:49 +00:00
} else {
snprintf ( ftdmchan - > last_error , sizeof ( ftdmchan - > last_error ) , " codec error! " ) ;
2010-06-25 12:11:23 -04:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_ERROR , " no codec function to perform transcoding from %d to %d \n " , ftdmchan - > native_codec , ftdmchan - > effective_codec ) ;
2010-01-15 19:22:49 +00:00
}
}
2011-05-26 11:38:24 -04:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_DTMF_DETECT ) | |
ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_PROGRESS_DETECT ) | |
2010-01-15 19:22:49 +00:00
ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_CALLERID_DETECT ) ) {
2011-05-26 11:38:24 -04:00
2010-01-15 19:22:49 +00:00
uint8_t sln_buf [ 1024 ] = { 0 } ;
int16_t * sln ;
ftdm_size_t slen = 0 ;
if ( ftdmchan - > effective_codec = = FTDM_CODEC_SLIN ) {
sln = data ;
slen = * datalen / 2 ;
} else {
ftdm_size_t len = * datalen ;
uint32_t i ;
uint8_t * lp = data ;
slen = sizeof ( sln_buf ) / 2 ;
if ( len > slen ) {
len = slen ;
}
sln = ( int16_t * ) sln_buf ;
for ( i = 0 ; i < len ; i + + ) {
if ( ftdmchan - > effective_codec = = FTDM_CODEC_ULAW ) {
* sln + + = ulaw_to_linear ( * lp + + ) ;
} else if ( ftdmchan - > effective_codec = = FTDM_CODEC_ALAW ) {
* sln + + = alaw_to_linear ( * lp + + ) ;
} else {
snprintf ( ftdmchan - > last_error , sizeof ( ftdmchan - > last_error ) , " codec error! " ) ;
2010-06-25 12:11:23 -04:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_ERROR , " invalid effective codec %d \n " , ftdmchan - > effective_codec ) ;
2010-08-01 03:02:53 -04:00
goto done ;
2010-01-15 19:22:49 +00:00
}
}
sln = ( int16_t * ) sln_buf ;
slen = len ;
}
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_CALLERID_DETECT ) ) {
if ( ftdm_fsk_demod_feed ( & ftdmchan - > fsk , sln , slen ) ! = FTDM_SUCCESS ) {
ftdm_size_t type , mlen ;
char str [ 128 ] , * sp ;
while ( ftdm_fsk_data_parse ( & ftdmchan - > fsk , & type , & sp , & mlen ) = = FTDM_SUCCESS ) {
* ( str + mlen ) = ' \0 ' ;
ftdm_copy_string ( str , sp , + + mlen ) ;
ftdm_clean_string ( str ) ;
2012-02-10 13:29:49 +01:00
ftdm_log ( FTDM_LOG_DEBUG , " FSK: TYPE %s LEN % " FTDM_SIZE_FMT " VAL [%s] \n " ,
ftdm_mdmf_type2str ( type ) , mlen - 1 , str ) ;
2010-01-15 19:22:49 +00:00
switch ( type ) {
case MDMF_DDN :
case MDMF_PHONE_NUM :
{
if ( mlen > sizeof ( ftdmchan - > caller_data . ani ) ) {
mlen = sizeof ( ftdmchan - > caller_data . ani ) ;
}
ftdm_set_string ( ftdmchan - > caller_data . ani . digits , str ) ;
ftdm_set_string ( ftdmchan - > caller_data . cid_num . digits , ftdmchan - > caller_data . ani . digits ) ;
}
break ;
case MDMF_NO_NUM :
{
ftdm_set_string ( ftdmchan - > caller_data . ani . digits , * str = = ' P ' ? " private " : " unknown " ) ;
ftdm_set_string ( ftdmchan - > caller_data . cid_name , ftdmchan - > caller_data . ani . digits ) ;
}
break ;
case MDMF_PHONE_NAME :
{
if ( mlen > sizeof ( ftdmchan - > caller_data . cid_name ) ) {
mlen = sizeof ( ftdmchan - > caller_data . cid_name ) ;
}
ftdm_set_string ( ftdmchan - > caller_data . cid_name , str ) ;
}
break ;
case MDMF_NO_NAME :
{
ftdm_set_string ( ftdmchan - > caller_data . cid_name , * str = = ' P ' ? " private " : " unknown " ) ;
}
case MDMF_DATETIME :
{
if ( mlen > sizeof ( ftdmchan - > caller_data . cid_date ) ) {
mlen = sizeof ( ftdmchan - > caller_data . cid_date ) ;
}
ftdm_set_string ( ftdmchan - > caller_data . cid_date , str ) ;
}
break ;
}
}
ftdm_channel_command ( ftdmchan , FTDM_COMMAND_DISABLE_CALLERID_DETECT , NULL ) ;
}
}
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_PROGRESS_DETECT ) & & ! ftdm_channel_test_feature ( ftdmchan , FTDM_CHANNEL_FEATURE_PROGRESS ) ) {
uint32_t i ;
for ( i = 1 ; i < FTDM_TONEMAP_INVALID ; i + + ) {
if ( ftdmchan - > span - > tone_finder [ i ] . tone_count ) {
if ( ftdmchan - > needed_tones [ i ] & & teletone_multi_tone_detect ( & ftdmchan - > span - > tone_finder [ i ] , sln , ( int ) slen ) ) {
if ( + + ftdmchan - > detected_tones [ i ] ) {
ftdmchan - > needed_tones [ i ] = 0 ;
ftdmchan - > detected_tones [ 0 ] + + ;
}
}
}
}
}
2011-05-26 11:38:24 -04:00
2014-07-13 02:15:38 -04:00
if ( FTDM_CHANNEL_SW_DTMF_ALLOWED ( ftdmchan ) & & ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_DTMF_DETECT ) ) {
2011-09-16 10:05:43 -05:00
teletone_hit_type_t hit ;
char digit_char ;
uint32_t dur ;
2010-01-15 19:22:49 +00:00
2011-09-16 17:23:15 -05:00
if ( ( hit = teletone_dtmf_detect ( & ftdmchan - > dtmf_detect , sln , ( int ) slen ) ) = = TT_HIT_END ) {
2011-09-16 17:07:48 -05:00
teletone_dtmf_get ( & ftdmchan - > dtmf_detect , & digit_char , & dur ) ;
2011-09-16 10:05:43 -05:00
if ( ftdmchan - > state = = FTDM_CHANNEL_STATE_CALLWAITING & & ( digit_char = = ' D ' | | digit_char = = ' A ' ) ) {
2010-01-15 19:22:49 +00:00
ftdmchan - > detected_tones [ FTDM_TONEMAP_CALLWAITING_ACK ] + + ;
} else {
2011-10-07 08:38:48 -05:00
char digit_str [ 2 ] = { 0 } ;
digit_str [ 0 ] = digit_char ;
2012-09-13 12:34:49 -04:00
ftdm_channel_queue_dtmf ( ftdmchan , digit_str ) ;
2010-01-15 19:22:49 +00:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_SUPRESS_DTMF ) ) {
ftdmchan - > skip_read_frames = 20 ;
}
}
}
}
}
if ( ftdmchan - > skip_read_frames > 0 | | ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_MUTE ) ) {
2011-05-26 11:38:24 -04:00
2010-01-15 19:22:49 +00:00
ftdm_mutex_lock ( ftdmchan - > pre_buffer_mutex ) ;
if ( ftdmchan - > pre_buffer & & ftdm_buffer_inuse ( ftdmchan - > pre_buffer ) ) {
ftdm_buffer_zero ( ftdmchan - > pre_buffer ) ;
}
ftdm_mutex_unlock ( ftdmchan - > pre_buffer_mutex ) ;
2011-05-18 19:00:42 -04:00
memset ( data , FTDM_SILENCE_VALUE ( ftdmchan ) , * datalen ) ;
2010-01-15 19:22:49 +00:00
if ( ftdmchan - > skip_read_frames > 0 ) {
ftdmchan - > skip_read_frames - - ;
}
2011-05-26 11:38:24 -04:00
} else {
2010-01-15 19:22:49 +00:00
ftdm_mutex_lock ( ftdmchan - > pre_buffer_mutex ) ;
if ( ftdmchan - > pre_buffer_size & & ftdmchan - > pre_buffer ) {
ftdm_buffer_write ( ftdmchan - > pre_buffer , data , * datalen ) ;
if ( ftdm_buffer_inuse ( ftdmchan - > pre_buffer ) > = ftdmchan - > pre_buffer_size ) {
ftdm_buffer_read ( ftdmchan - > pre_buffer , data , * datalen ) ;
} else {
2011-05-18 19:00:42 -04:00
memset ( data , FTDM_SILENCE_VALUE ( ftdmchan ) , * datalen ) ;
2010-01-15 19:22:49 +00:00
}
}
ftdm_mutex_unlock ( ftdmchan - > pre_buffer_mutex ) ;
}
2010-08-01 03:02:53 -04:00
done :
2011-05-26 11:38:24 -04:00
return FTDM_SUCCESS ;
}
2010-08-01 03:02:53 -04:00
2010-01-15 19:22:49 +00:00
2011-05-26 11:38:24 -04:00
FT_DECLARE ( ftdm_status_t ) ftdm_channel_read ( ftdm_channel_t * ftdmchan , void * data , ftdm_size_t * datalen )
{
ftdm_status_t status = FTDM_FAIL ;
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_FAIL , " ftdmchan is null \n " ) ;
ftdm_assert_return ( ftdmchan - > fio ! = NULL , FTDM_FAIL , " No I/O module attached to ftdmchan \n " ) ;
ftdm_channel_lock ( ftdmchan ) ;
if ( ! ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OPEN ) ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " cannot read from channel that is not open \n " ) ;
status = FTDM_FAIL ;
goto done ;
}
if ( ! ftdmchan - > fio - > read ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " read method not implemented \n " ) ;
status = FTDM_FAIL ;
goto done ;
}
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_RX_DISABLED ) ) {
ftdmchan - > rxdrops + + ;
if ( ftdmchan - > rxdrops < = 10 ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " cannot read from channel with rx disabled \n " ) ;
}
if ( ftdmchan - > rxdrops = = 10 ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " too many rx drops, not logging anymore \n " ) ;
}
status = FTDM_FAIL ;
goto done ;
}
status = ftdm_raw_read ( ftdmchan , data , datalen ) ;
if ( status ! = FTDM_SUCCESS ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " raw I/O read filed \n " ) ;
goto done ;
}
status = ftdm_channel_process_media ( ftdmchan , data , datalen ) ;
if ( status ! = FTDM_SUCCESS ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " Failed to process media \n " ) ;
}
done :
ftdm_channel_unlock ( ftdmchan ) ;
2010-01-15 19:22:49 +00:00
return status ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_write ( ftdm_channel_t * ftdmchan , void * data , ftdm_size_t datasize , ftdm_size_t * datalen )
{
2010-12-08 09:09:14 -05:00
ftdm_status_t status = FTDM_SUCCESS ;
2010-01-15 20:35:11 +00:00
fio_codec_t codec_func = NULL ;
2010-01-15 19:22:49 +00:00
ftdm_size_t max = datasize ;
unsigned int i = 0 ;
2010-09-01 14:42:34 -04:00
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_FAIL , " null channel on write! \n " ) ;
ftdm_assert_return ( ftdmchan - > fio ! = NULL , FTDM_FAIL , " null I/O on write! \n " ) ;
2010-01-15 19:22:49 +00:00
2010-12-08 09:09:14 -05:00
ftdm_channel_lock ( ftdmchan ) ;
2010-01-15 19:22:49 +00:00
if ( ! ftdmchan - > buffer_delay & &
( ( ftdmchan - > dtmf_buffer & & ftdm_buffer_inuse ( ftdmchan - > dtmf_buffer ) ) | |
( ftdmchan - > fsk_buffer & & ftdm_buffer_inuse ( ftdmchan - > fsk_buffer ) ) ) ) {
2011-02-09 13:26:23 -05:00
/* generating some kind of tone at the moment (see handle_tone_generation),
* we ignore user data . . . */
2010-12-08 09:09:14 -05:00
goto done ;
2010-01-15 19:22:49 +00:00
}
2010-05-03 12:14:56 -04:00
if ( ! ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OPEN ) ) {
2010-12-21 15:11:22 -05:00
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " cannot write in channel not open \n " ) ;
2010-12-08 09:09:14 -05:00
status = FTDM_FAIL ;
goto done ;
2010-05-03 12:14:56 -04:00
}
2010-01-15 19:22:49 +00:00
2010-01-15 20:35:11 +00:00
if ( ! ftdmchan - > fio - > write ) {
2010-12-08 09:09:14 -05:00
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_ERROR , " write method not implemented \n " ) ;
status = FTDM_FAIL ;
goto done ;
2010-01-15 19:22:49 +00:00
}
2011-05-10 23:35:20 -04:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_DIGITAL_MEDIA ) ) {
goto do_write ;
}
2010-01-15 19:22:49 +00:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_TRANSCODE ) & & ftdmchan - > effective_codec ! = ftdmchan - > native_codec ) {
if ( ftdmchan - > native_codec = = FTDM_CODEC_ULAW & & ftdmchan - > effective_codec = = FTDM_CODEC_SLIN ) {
2010-01-15 20:35:11 +00:00
codec_func = fio_slin2ulaw ;
2010-01-15 19:22:49 +00:00
} else if ( ftdmchan - > native_codec = = FTDM_CODEC_ULAW & & ftdmchan - > effective_codec = = FTDM_CODEC_ALAW ) {
2010-01-15 20:35:11 +00:00
codec_func = fio_alaw2ulaw ;
2010-01-15 19:22:49 +00:00
} else if ( ftdmchan - > native_codec = = FTDM_CODEC_ALAW & & ftdmchan - > effective_codec = = FTDM_CODEC_SLIN ) {
2010-01-15 20:35:11 +00:00
codec_func = fio_slin2alaw ;
2010-01-15 19:22:49 +00:00
} else if ( ftdmchan - > native_codec = = FTDM_CODEC_ALAW & & ftdmchan - > effective_codec = = FTDM_CODEC_ULAW ) {
2010-01-15 20:35:11 +00:00
codec_func = fio_ulaw2alaw ;
2010-01-15 19:22:49 +00:00
}
if ( codec_func ) {
status = codec_func ( data , max , datalen ) ;
} else {
2010-12-08 09:09:14 -05:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_ERROR , " Do not know how to handle transcoding from %d to %d \n " ,
2011-05-26 11:38:24 -04:00
ftdmchan - > effective_codec , ftdmchan - > native_codec ) ;
2010-01-15 19:22:49 +00:00
status = FTDM_FAIL ;
2010-12-08 09:09:14 -05:00
goto done ;
2010-01-15 19:22:49 +00:00
}
2010-12-08 09:09:14 -05:00
}
2010-01-15 19:22:49 +00:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_USE_TX_GAIN )
& & ( ftdmchan - > native_codec = = FTDM_CODEC_ALAW | | ftdmchan - > native_codec = = FTDM_CODEC_ULAW ) ) {
unsigned char * wdata = data ;
for ( i = 0 ; i < * datalen ; i + + ) {
wdata [ i ] = ftdmchan - > txgain_table [ wdata [ i ] ] ;
}
}
2010-05-28 15:06:51 -04:00
2011-05-10 23:35:20 -04:00
do_write :
2010-12-08 09:09:14 -05:00
if ( ftdmchan - > span - > sig_write ) {
2010-12-08 10:45:45 -05:00
status = ftdmchan - > span - > sig_write ( ftdmchan , data , * datalen ) ;
2010-12-08 09:09:14 -05:00
if ( status = = FTDM_BREAK ) {
/* signaling module decided to drop user frame */
status = FTDM_SUCCESS ;
goto done ;
}
}
2010-05-28 15:06:51 -04:00
status = ftdm_raw_write ( ftdmchan , data , datalen ) ;
2010-01-15 19:22:49 +00:00
2010-12-08 09:09:14 -05:00
done :
ftdm_channel_unlock ( ftdmchan ) ;
2010-01-15 19:22:49 +00:00
return status ;
}
2011-03-01 09:54:52 -05:00
FT_DECLARE ( ftdm_iterator_t * ) ftdm_get_iterator ( ftdm_iterator_type_t type , ftdm_iterator_t * iter )
2010-09-01 14:42:34 -04:00
{
2010-09-10 14:01:52 -04:00
int allocated = 0 ;
if ( iter ) {
if ( iter - > type ! = type ) {
ftdm_log ( FTDM_LOG_ERROR , " Cannot switch iterator types \n " ) ;
return NULL ;
}
allocated = iter - > allocated ;
memset ( iter , 0 , sizeof ( * iter ) ) ;
iter - > type = type ;
iter - > allocated = allocated ;
return iter ;
}
2010-09-01 14:42:34 -04:00
2010-09-10 14:01:52 -04:00
iter = ftdm_calloc ( 1 , sizeof ( * iter ) ) ;
if ( ! iter ) {
return NULL ;
}
iter - > type = type ;
iter - > allocated = 1 ;
return iter ;
}
2010-09-01 14:42:34 -04:00
2013-06-01 15:20:51 +02:00
FT_DECLARE ( ftdm_iterator_t * ) ftdm_get_span_iterator ( ftdm_iterator_t * iter )
{
if ( ! ( iter = ftdm_get_iterator ( FTDM_ITERATOR_SPANS , iter ) ) ) {
return NULL ;
}
iter - > pvt . hashiter = hashtable_first ( globals . span_hash ) ;
return iter ;
}
2010-09-10 14:01:52 -04:00
FT_DECLARE ( ftdm_iterator_t * ) ftdm_span_get_chan_iterator ( const ftdm_span_t * span , ftdm_iterator_t * iter )
{
2012-07-06 18:43:03 -04:00
if ( ! span - > chan_count ) {
return NULL ;
}
2011-02-25 12:20:32 -05:00
if ( ! ( iter = ftdm_get_iterator ( FTDM_ITERATOR_CHANS , iter ) ) ) {
2010-09-10 14:01:52 -04:00
return NULL ;
}
iter - > pvt . chaniter . index = 1 ;
iter - > pvt . chaniter . span = span ;
2010-09-01 14:42:34 -04:00
return iter ;
}
FT_DECLARE ( ftdm_iterator_t * ) ftdm_iterator_next ( ftdm_iterator_t * iter )
{
2010-09-10 14:01:52 -04:00
ftdm_assert_return ( iter & & iter - > type , NULL , " Invalid iterator \n " ) ;
switch ( iter - > type ) {
case FTDM_ITERATOR_VARS :
2013-06-01 15:20:51 +02:00
case FTDM_ITERATOR_SPANS :
2010-09-10 14:01:52 -04:00
if ( ! iter - > pvt . hashiter ) {
return NULL ;
}
iter - > pvt . hashiter = hashtable_next ( iter - > pvt . hashiter ) ;
if ( ! iter - > pvt . hashiter ) {
return NULL ;
}
return iter ;
case FTDM_ITERATOR_CHANS :
2010-09-10 14:46:51 -04:00
ftdm_assert_return ( iter - > pvt . chaniter . index , NULL , " channel iterator index cannot be zero! \n " ) ;
2010-09-10 17:52:08 -04:00
if ( iter - > pvt . chaniter . index = = iter - > pvt . chaniter . span - > chan_count ) {
return NULL ;
}
2010-09-10 14:01:52 -04:00
iter - > pvt . chaniter . index + + ;
return iter ;
default :
break ;
}
ftdm_assert_return ( 0 , NULL , " Unknown iterator type \n " ) ;
return NULL ;
}
FT_DECLARE ( void * ) ftdm_iterator_current ( ftdm_iterator_t * iter )
{
const void * key = NULL ;
void * val = NULL ;
ftdm_assert_return ( iter & & iter - > type , NULL , " Invalid iterator \n " ) ;
switch ( iter - > type ) {
case FTDM_ITERATOR_VARS :
hashtable_this ( iter - > pvt . hashiter , & key , NULL , & val ) ;
/* I decided to return the key instead of the value since the value can be retrieved using the key */
return ( void * ) key ;
2013-06-01 15:20:51 +02:00
case FTDM_ITERATOR_SPANS :
hashtable_this ( iter - > pvt . hashiter , & key , NULL , & val ) ;
return ( void * ) val ;
2010-09-10 14:01:52 -04:00
case FTDM_ITERATOR_CHANS :
ftdm_assert_return ( iter - > pvt . chaniter . index , NULL , " channel iterator index cannot be zero! \n " ) ;
2010-09-10 14:46:51 -04:00
ftdm_assert_return ( iter - > pvt . chaniter . index < = iter - > pvt . chaniter . span - > chan_count , NULL , " channel iterator index bigger than span chan count! \n " ) ;
2010-09-10 14:01:52 -04:00
return iter - > pvt . chaniter . span - > channels [ iter - > pvt . chaniter . index ] ;
default :
break ;
}
ftdm_assert_return ( 0 , NULL , " Unknown iterator type \n " ) ;
return NULL ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_iterator_free ( ftdm_iterator_t * iter )
{
/* it's valid to pass a NULL iterator, do not return failure */
2010-09-01 14:42:34 -04:00
if ( ! iter ) {
2010-09-10 14:01:52 -04:00
return FTDM_SUCCESS ;
2010-01-15 19:22:49 +00:00
}
2010-09-10 14:01:52 -04:00
if ( ! iter - > allocated ) {
memset ( iter , 0 , sizeof ( * iter ) ) ;
return FTDM_SUCCESS ;
}
ftdm_assert_return ( iter - > type , FTDM_FAIL , " Cannot free invalid iterator \n " ) ;
ftdm_safe_free ( iter ) ;
return FTDM_SUCCESS ;
2010-01-15 19:22:49 +00:00
}
2013-06-01 22:19:16 +02:00
static const char * print_neg_char [ ] = { " " , " ! " } ;
static const char * print_flag_state [ ] = { " OFF " , " ON " } ;
static void print_channels_by_flag ( ftdm_stream_handle_t * stream , ftdm_span_t * inspan , uint32_t inchan_id , uint64_t flagval , int not , int * count )
2010-12-08 14:50:40 -05:00
{
2013-06-01 22:19:16 +02:00
ftdm_bool_t neg = ! ! not ;
const char * negind = print_neg_char [ neg ] ;
const char * flagname ;
2013-06-03 17:27:04 -05:00
uint64_t flag = ( ( uint64_t ) 1 < < flagval ) ;
2012-06-19 22:35:37 -04:00
int mycount = 0 ;
2010-12-08 14:50:40 -05:00
2013-06-01 22:19:16 +02:00
flagname = ftdm_val2str ( flag , channel_flag_strs , ftdm_array_len ( channel_flag_strs ) , " invalid " ) ;
2010-12-08 14:50:40 -05:00
ftdm_mutex_lock ( globals . mutex ) ;
2012-06-19 22:35:37 -04:00
if ( inspan ) {
2013-06-01 22:19:16 +02:00
ftdm_iterator_t * c_iter , * c_cur ;
2012-06-19 22:35:37 -04:00
2013-06-01 22:19:16 +02:00
c_iter = ftdm_span_get_chan_iterator ( inspan , NULL ) ;
for ( c_cur = c_iter ; c_cur ; c_cur = ftdm_iterator_next ( c_cur ) ) {
ftdm_channel_t * fchan ;
ftdm_bool_t cond ;
fchan = ftdm_iterator_current ( c_cur ) ;
if ( inchan_id & & inchan_id ! = fchan - > chan_id ) {
continue ;
2010-12-08 14:50:40 -05:00
}
2013-06-01 22:19:16 +02:00
cond = ! ! ftdm_test_flag ( fchan , flag ) ;
if ( neg ^ cond ) {
mycount + + ;
}
stream - > write_function ( stream , " [s%dc%d][%d:%d] flag %s% " FTDM_UINT64_FMT " (%s%s) %s \n " ,
fchan - > span_id , fchan - > chan_id ,
fchan - > physical_span_id , fchan - > physical_chan_id ,
negind , flagval , negind , flagname ,
print_flag_state [ cond ] ) ;
2010-12-08 14:50:40 -05:00
}
2013-06-01 22:19:16 +02:00
ftdm_iterator_free ( c_iter ) ;
2010-12-08 14:50:40 -05:00
2012-06-19 22:35:37 -04:00
} else {
2013-06-01 22:19:16 +02:00
ftdm_iterator_t * s_iter , * s_cur ;
s_iter = ftdm_get_span_iterator ( NULL ) ;
for ( s_cur = s_iter ; s_cur ; s_cur = ftdm_iterator_next ( s_cur ) ) {
ftdm_iterator_t * c_iter , * c_cur ;
ftdm_span_t * span ;
span = ftdm_iterator_current ( s_cur ) ;
if ( ! span ) {
2012-06-19 22:35:37 -04:00
break ;
}
2013-06-01 22:19:16 +02:00
c_iter = ftdm_span_get_chan_iterator ( span , NULL ) ;
for ( c_cur = c_iter ; c_cur ; c_cur = ftdm_iterator_next ( c_cur ) ) {
ftdm_channel_t * fchan ;
fchan = ftdm_iterator_current ( c_cur ) ;
if ( neg ^ ! ! ftdm_test_flag ( fchan , flag ) ) {
stream - > write_function ( stream , " [s%dc%d][%d:%d] flag %s% " FTDM_UINT64_FMT " (%s%s) \n " ,
fchan - > span_id , fchan - > chan_id ,
fchan - > physical_span_id , fchan - > physical_chan_id ,
negind , flagval , negind , flagname ) ;
2012-06-19 22:35:37 -04:00
mycount + + ;
}
}
2013-06-01 22:19:16 +02:00
ftdm_iterator_free ( c_iter ) ;
2012-06-19 22:35:37 -04:00
}
2013-06-01 22:19:16 +02:00
ftdm_iterator_free ( s_iter ) ;
2010-12-08 14:50:40 -05:00
}
2013-06-01 22:19:16 +02:00
2012-06-19 22:35:37 -04:00
* count = mycount ;
2010-12-08 14:50:40 -05:00
ftdm_mutex_unlock ( globals . mutex ) ;
}
2013-06-01 22:19:16 +02:00
static void print_spans_by_flag ( ftdm_stream_handle_t * stream , ftdm_span_t * inspan , uint64_t flagval , int not , int * count )
2012-06-20 16:28:00 -04:00
{
2013-06-01 22:19:16 +02:00
ftdm_bool_t neg = ! ! not ;
const char * negind = print_neg_char [ neg ] ;
const char * flagname ;
2013-06-03 17:27:04 -05:00
uint64_t flag = ( ( uint64_t ) 1 < < flagval ) ;
2012-06-20 16:28:00 -04:00
int mycount = 0 ;
2013-06-01 22:19:16 +02:00
flagname = ftdm_val2str ( flag , span_flag_strs , ftdm_array_len ( span_flag_strs ) , " invalid " ) ;
2012-06-20 16:28:00 -04:00
ftdm_mutex_lock ( globals . mutex ) ;
if ( inspan ) {
2013-06-01 22:19:16 +02:00
ftdm_bool_t cond ;
2012-06-20 16:28:00 -04:00
2013-06-01 22:19:16 +02:00
cond = ! ! ftdm_test_flag ( inspan , flag ) ;
if ( neg ^ cond ) {
mycount + + ;
2012-06-20 16:28:00 -04:00
}
2013-06-01 22:19:16 +02:00
stream - > write_function ( stream , " [s%d] flag %s% " FTDM_UINT64_FMT " (%s%s) %s \n " ,
inspan - > span_id , negind , flagval , negind , flagname ,
print_flag_state [ cond ] ) ;
2012-06-20 16:28:00 -04:00
} else {
2013-06-01 22:19:16 +02:00
ftdm_iterator_t * s_iter , * s_cur ;
s_iter = ftdm_get_span_iterator ( NULL ) ;
for ( s_cur = s_iter ; s_cur ; s_cur = ftdm_iterator_next ( s_cur ) ) {
ftdm_span_t * span ;
span = ftdm_iterator_current ( s_cur ) ;
if ( ! span ) {
2012-06-20 16:28:00 -04:00
break ;
}
2013-06-01 22:19:16 +02:00
if ( neg ^ ! ! ftdm_test_flag ( span , flag ) ) {
stream - > write_function ( stream , " [s%d] flag %s% " FTDM_UINT64_FMT " (%s%s) \n " ,
span - > span_id , negind , flagval , negind , flagname ) ;
2012-06-20 16:28:00 -04:00
mycount + + ;
}
}
2013-06-01 22:19:16 +02:00
ftdm_iterator_free ( s_iter ) ;
2012-06-20 16:28:00 -04:00
}
2013-06-01 22:19:16 +02:00
2012-06-20 16:28:00 -04:00
* count = mycount ;
2010-12-08 14:50:40 -05:00
ftdm_mutex_unlock ( globals . mutex ) ;
}
2010-09-24 08:35:20 -04:00
static void print_channels_by_state ( ftdm_stream_handle_t * stream , ftdm_channel_state_t state , int not , int * count )
{
2013-06-01 22:19:16 +02:00
ftdm_iterator_t * s_iter , * s_cur ;
ftdm_bool_t neg = ! ! not ;
int mycount = 0 ;
2010-09-24 08:35:20 -04:00
2013-06-01 22:19:16 +02:00
s_iter = ftdm_get_span_iterator ( NULL ) ;
2010-09-24 08:35:20 -04:00
ftdm_mutex_lock ( globals . mutex ) ;
2013-06-01 22:19:16 +02:00
for ( s_cur = s_iter ; s_cur ; s_cur = ftdm_iterator_next ( s_cur ) ) {
ftdm_iterator_t * c_iter , * c_cur ;
ftdm_span_t * span ;
span = ftdm_iterator_current ( s_cur ) ;
if ( ! span ) {
2010-09-24 08:35:20 -04:00
break ;
}
2013-06-01 22:19:16 +02:00
c_iter = ftdm_span_get_chan_iterator ( span , NULL ) ;
for ( c_cur = c_iter ; c_cur ; c_cur = ftdm_iterator_next ( c_cur ) ) {
ftdm_channel_t * fchan = ftdm_iterator_current ( c_cur ) ;
if ( neg ^ ( fchan - > state = = state ) ) {
stream - > write_function ( stream , " [s%dc%d][%d:%d] in state %s \n " ,
fchan - > span_id , fchan - > chan_id ,
2010-09-24 08:35:20 -04:00
fchan - > physical_span_id , fchan - > physical_chan_id , ftdm_channel_state2str ( fchan - > state ) ) ;
2013-06-01 22:19:16 +02:00
mycount + + ;
2010-09-24 08:35:20 -04:00
}
}
2013-06-01 22:19:16 +02:00
ftdm_iterator_free ( c_iter ) ;
2010-09-24 08:35:20 -04:00
}
2013-06-01 22:19:16 +02:00
* count = mycount ;
2010-09-24 08:35:20 -04:00
ftdm_mutex_unlock ( globals . mutex ) ;
2013-06-01 22:19:16 +02:00
ftdm_iterator_free ( s_iter ) ;
2010-09-24 08:35:20 -04:00
}
2010-12-21 19:04:41 -05:00
static void print_core_usage ( ftdm_stream_handle_t * stream )
{
stream - > write_function ( stream ,
" -------------------------------------------------------------------------------- \n "
2012-06-19 22:35:37 -04:00
" ftdm core state [!]<state-name> - List all channels in or not in the given state \n "
" ftdm core flag [!]<flag-int-value|flag-name> [<span_id|span_name>] [<chan_id>] - List all channels with the given flag value set \n "
2012-06-20 16:28:00 -04:00
" ftdm core spanflag [!]<flag-int-value|flag-name> [<span_id|span_name>] - List all spans with the given span flag value set \n "
2010-12-21 19:04:41 -05:00
" ftdm core calls - List all known calls to the FreeTDM core \n "
" -------------------------------------------------------------------------------- \n " ) ;
}
2012-06-19 22:35:37 -04:00
2012-06-20 16:28:00 -04:00
static unsigned long long ftdm_str2val ( const char * str , val_str_t * val_str_table , ftdm_size_t array_size , unsigned long long default_val )
2012-06-19 22:35:37 -04:00
{
2012-09-26 08:11:08 -05:00
ftdm_size_t i ;
2012-06-20 16:28:00 -04:00
for ( i = 0 ; i < array_size ; i + + ) {
if ( ! strcasecmp ( val_str_table [ i ] . str , str ) ) {
return val_str_table [ i ] . val ;
2012-06-19 22:35:37 -04:00
}
}
2012-06-20 16:28:00 -04:00
return default_val ;
2012-06-19 22:35:37 -04:00
}
2012-06-20 16:28:00 -04:00
static const char * ftdm_val2str ( unsigned long long val , val_str_t * val_str_table , ftdm_size_t array_size , const char * default_str )
2012-06-19 22:35:37 -04:00
{
2012-09-26 08:11:08 -05:00
ftdm_size_t i ;
2012-06-20 16:28:00 -04:00
for ( i = 0 ; i < array_size ; i + + ) {
if ( val_str_table [ i ] . val = = val ) {
return val_str_table [ i ] . str ;
2012-06-19 22:35:37 -04:00
}
}
2012-06-20 16:28:00 -04:00
return default_str ;
2012-06-19 22:35:37 -04:00
}
static void print_channel_flag_values ( ftdm_stream_handle_t * stream )
{
int i ;
for ( i = 0 ; i < ftdm_array_len ( channel_flag_strs ) ; i + + ) {
2012-06-20 16:28:00 -04:00
stream - > write_function ( stream , " %s \n " , channel_flag_strs [ i ] . str ) ;
}
}
static void print_span_flag_values ( ftdm_stream_handle_t * stream )
{
int i ;
for ( i = 0 ; i < ftdm_array_len ( span_flag_strs ) ; i + + ) {
stream - > write_function ( stream , " %s \n " , span_flag_strs [ i ] . str ) ;
2012-06-19 22:35:37 -04:00
}
}
2013-06-01 22:30:45 +02:00
/**
* Compute log2 of 64 bit integer v
*
* Bit Twiddling Hacks
* http : //graphics.stanford.edu/~seander/bithacks.html#IntegerLog
*/
static int ftdm_log2_64 ( uint64_t v )
{
unsigned int shift ;
uint64_t r ;
r = ( v > 0xFFFFFFFF ) < < 5 ; v > > = r ;
shift = ( v > 0xFFFF ) < < 4 ; v > > = shift ; r | = shift ;
shift = ( v > 0xFF ) < < 3 ; v > > = shift ; r | = shift ;
shift = ( v > 0xF ) < < 2 ; v > > = shift ; r | = shift ;
shift = ( v > 0x3 ) < < 1 ; v > > = shift ; r | = shift ;
2013-06-03 17:27:04 -05:00
return ( ( int ) ( r | ( v > > 1 ) ) ) ;
2013-06-01 22:30:45 +02:00
}
2010-09-24 08:35:20 -04:00
static char * handle_core_command ( const char * cmd )
{
char * mycmd = NULL ;
int argc = 0 ;
int count = 0 ;
int not = 0 ;
char * argv [ 10 ] = { 0 } ;
2010-12-08 14:50:40 -05:00
char * flag = NULL ;
2013-06-02 03:02:14 +02:00
uint64_t flagval = 0 ;
2010-12-21 19:04:41 -05:00
ftdm_channel_t * fchan = NULL ;
2012-06-19 22:35:37 -04:00
ftdm_span_t * fspan = NULL ;
2010-09-24 08:35:20 -04:00
ftdm_stream_handle_t stream = { 0 } ;
FTDM_STANDARD_STREAM ( stream ) ;
2013-06-02 03:02:14 +02:00
if ( ! ftdm_strlen_zero ( cmd ) ) {
2010-09-24 08:35:20 -04:00
mycmd = ftdm_strdup ( cmd ) ;
2013-06-02 03:02:14 +02:00
argc = ftdm_separate_string ( mycmd , ' ' , argv , ftdm_array_len ( argv ) ) ;
2010-09-24 08:35:20 -04:00
} else {
2010-12-21 19:04:41 -05:00
print_core_usage ( & stream ) ;
goto done ;
}
if ( ! argc ) {
print_core_usage ( & stream ) ;
2010-09-24 08:35:20 -04:00
goto done ;
}
if ( ! strcasecmp ( argv [ 0 ] , " state " ) ) {
2013-06-02 03:02:14 +02:00
ftdm_channel_state_t st = FTDM_CHANNEL_STATE_INVALID ;
char * state = NULL ;
2010-09-24 08:35:20 -04:00
if ( argc < 2 ) {
stream . write_function ( & stream , " core state command requires an argument \n " ) ;
2010-12-21 19:04:41 -05:00
print_core_usage ( & stream ) ;
2010-09-24 08:35:20 -04:00
goto done ;
}
2013-06-02 03:02:14 +02:00
2010-09-24 08:35:20 -04:00
state = argv [ 1 ] ;
2013-06-02 03:02:14 +02:00
if ( state [ 0 ] = = ' ! ' ) {
2010-09-24 08:35:20 -04:00
not = 1 ;
state + + ;
}
2013-06-02 03:02:14 +02:00
for ( st = FTDM_CHANNEL_STATE_DOWN ; st < FTDM_CHANNEL_STATE_INVALID ; st + + ) {
if ( ! strcasecmp ( state , ftdm_channel_state2str ( st ) ) ) {
2010-09-24 08:35:20 -04:00
break ;
}
}
2013-06-02 03:02:14 +02:00
if ( st = = FTDM_CHANNEL_STATE_INVALID ) {
2010-09-24 08:35:20 -04:00
stream . write_function ( & stream , " invalid state %s \n " , state ) ;
goto done ;
}
2013-06-02 03:02:14 +02:00
print_channels_by_state ( & stream , st , not , & count ) ;
stream . write_function ( & stream , " \n Total channels %s state %s: %d \n " ,
not ? " not in " : " in " , ftdm_channel_state2str ( st ) , count ) ;
2010-12-08 14:50:40 -05:00
} else if ( ! strcasecmp ( argv [ 0 ] , " flag " ) ) {
2012-06-19 22:35:37 -04:00
uint32_t chan_id = 0 ;
2013-06-02 03:02:14 +02:00
2010-12-08 14:50:40 -05:00
if ( argc < 2 ) {
2010-12-21 19:04:41 -05:00
stream . write_function ( & stream , " core flag command requires an argument \n " ) ;
print_core_usage ( & stream ) ;
2010-12-08 14:50:40 -05:00
goto done ;
}
2013-06-02 03:02:14 +02:00
2010-12-08 14:50:40 -05:00
flag = argv [ 1 ] ;
2013-06-02 03:02:14 +02:00
if ( flag [ 0 ] = = ' ! ' ) {
2010-12-08 14:50:40 -05:00
not = 1 ;
flag + + ;
}
2013-06-02 03:02:14 +02:00
2012-06-19 22:35:37 -04:00
if ( isalpha ( flag [ 0 ] ) ) {
2012-06-20 16:28:00 -04:00
flagval = ftdm_str2val ( flag , channel_flag_strs , ftdm_array_len ( channel_flag_strs ) , FTDM_CHANNEL_MAX_FLAG ) ;
2012-06-19 22:35:37 -04:00
if ( flagval = = FTDM_CHANNEL_MAX_FLAG ) {
2013-06-02 03:02:14 +02:00
stream . write_function ( & stream , " \n Invalid channel flag value. Possible channel flags: \n " ) ;
2012-06-19 22:35:37 -04:00
print_channel_flag_values ( & stream ) ;
goto done ;
}
2013-06-01 22:30:45 +02:00
flagval = ftdm_log2_64 ( flagval ) ;
2012-06-19 22:35:37 -04:00
} else {
flagval = atoi ( flag ) ;
}
/* Specific span specified */
if ( argv [ 2 ] ) {
ftdm_span_find_by_name ( argv [ 2 ] , & fspan ) ;
if ( ! fspan ) {
stream . write_function ( & stream , " -ERR span:%s not found \n " , argv [ 2 ] ) ;
goto done ;
}
}
/* Specific channel specified */
if ( argv [ 3 ] ) {
chan_id = atoi ( argv [ 3 ] ) ;
2013-06-02 03:02:14 +02:00
if ( chan_id = = 0 | | chan_id > = ftdm_span_get_chan_count ( fspan ) ) {
stream . write_function ( & stream , " -ERR invalid channel %u \n " , chan_id ) ;
2012-06-19 22:35:37 -04:00
goto done ;
}
}
print_channels_by_flag ( & stream , fspan , chan_id , flagval , not , & count ) ;
2013-06-02 03:02:14 +02:00
stream . write_function ( & stream , " \n Total channels %s flag % " FTDM_UINT64_FMT " : %d \n " , not ? " without " : " with " , flagval , count ) ;
2012-06-20 16:28:00 -04:00
} else if ( ! strcasecmp ( argv [ 0 ] , " spanflag " ) ) {
if ( argc < 2 ) {
stream . write_function ( & stream , " core spanflag command requires an argument \n " ) ;
print_core_usage ( & stream ) ;
goto done ;
}
flag = argv [ 1 ] ;
2013-06-02 03:02:14 +02:00
if ( flag [ 0 ] = = ' ! ' ) {
2012-06-20 16:28:00 -04:00
not = 1 ;
flag + + ;
}
if ( isalpha ( flag [ 0 ] ) ) {
flagval = ftdm_str2val ( flag , span_flag_strs , ftdm_array_len ( span_flag_strs ) , FTDM_SPAN_MAX_FLAG ) ;
if ( flagval = = FTDM_SPAN_MAX_FLAG ) {
stream . write_function ( & stream , " \n Invalid span flag value. Possible span flags \n " ) ;
print_span_flag_values ( & stream ) ;
goto done ;
}
2013-06-01 22:30:45 +02:00
flagval = ftdm_log2_64 ( flagval ) ;
2012-06-20 16:28:00 -04:00
} else {
flagval = atoi ( flag ) ;
}
/* Specific span specified */
if ( argv [ 2 ] ) {
ftdm_span_find_by_name ( argv [ 2 ] , & fspan ) ;
if ( ! fspan ) {
stream . write_function ( & stream , " -ERR span:%s not found \n " , argv [ 2 ] ) ;
goto done ;
}
}
print_spans_by_flag ( & stream , fspan , flagval , not , & count ) ;
if ( ! fspan ) {
2013-06-02 03:02:14 +02:00
stream . write_function ( & stream , " \n Total spans %s flag % " FTDM_UINT64_FMT " : %d \n " , not ? " without " : " with " , flagval , count ) ;
2012-06-20 16:28:00 -04:00
}
2010-12-21 19:04:41 -05:00
} else if ( ! strcasecmp ( argv [ 0 ] , " calls " ) ) {
2013-06-02 03:02:14 +02:00
uint32_t current_call_id = 0 ;
2010-12-21 19:04:41 -05:00
ftdm_mutex_lock ( globals . call_id_mutex ) ;
for ( current_call_id = 0 ; current_call_id < = MAX_CALLIDS ; current_call_id + + ) {
2013-06-02 03:02:14 +02:00
ftdm_caller_data_t * calldata = NULL ;
2010-12-21 19:04:41 -05:00
if ( ! globals . call_ids [ current_call_id ] ) {
continue ;
}
2013-06-02 03:02:14 +02:00
2010-12-21 19:04:41 -05:00
calldata = globals . call_ids [ current_call_id ] ;
fchan = calldata - > fchan ;
if ( fchan ) {
2013-06-02 03:02:14 +02:00
stream . write_function ( & stream , " Call %u on channel %d:%d \n " , current_call_id ,
2010-12-21 19:04:41 -05:00
fchan - > span_id , fchan - > chan_id ) ;
} else {
2013-06-02 03:02:14 +02:00
stream . write_function ( & stream , " Call %u without a channel? \n " , current_call_id ) ;
2010-12-21 19:04:41 -05:00
}
count + + ;
}
ftdm_mutex_unlock ( globals . call_id_mutex ) ;
stream . write_function ( & stream , " \n Total calls: %d \n " , count ) ;
2010-09-24 08:35:20 -04:00
} else {
stream . write_function ( & stream , " invalid core command %s \n " , argv [ 0 ] ) ;
2010-12-21 19:04:41 -05:00
print_core_usage ( & stream ) ;
2010-09-24 08:35:20 -04:00
}
done :
ftdm_safe_free ( mycmd ) ;
return stream . data ;
}
2010-04-26 16:55:44 -04:00
FT_DECLARE ( char * ) ftdm_api_execute ( const char * cmd )
2010-01-15 19:22:49 +00:00
{
2010-01-15 20:35:11 +00:00
ftdm_io_interface_t * fio = NULL ;
2010-01-15 19:22:49 +00:00
char * dup = NULL , * p ;
char * rval = NULL ;
2010-04-26 16:55:44 -04:00
char * type = NULL ;
2010-01-15 19:22:49 +00:00
2010-04-26 16:55:44 -04:00
dup = ftdm_strdup ( cmd ) ;
if ( ( p = strchr ( dup , ' ' ) ) ) {
* p + + = ' \0 ' ;
cmd = p ;
2010-12-21 19:04:41 -05:00
} else {
cmd = " " ;
2010-01-15 19:22:49 +00:00
}
2010-04-26 16:55:44 -04:00
type = dup ;
2010-09-24 08:35:20 -04:00
if ( ! strcasecmp ( type , " core " ) ) {
return handle_core_command ( cmd ) ;
}
2010-01-15 19:22:49 +00:00
2013-06-02 02:56:44 +02:00
fio = ftdm_global_get_io_interface ( type , FTDM_TRUE ) ;
2010-01-15 20:35:11 +00:00
if ( fio & & fio - > api ) {
2010-01-15 19:22:49 +00:00
ftdm_stream_handle_t stream = { 0 } ;
ftdm_status_t status ;
FTDM_STANDARD_STREAM ( stream ) ;
2013-06-02 02:56:44 +02:00
2010-01-15 20:35:11 +00:00
status = fio - > api ( & stream , cmd ) ;
2010-01-15 19:22:49 +00:00
if ( status ! = FTDM_SUCCESS ) {
ftdm_safe_free ( stream . data ) ;
} else {
rval = ( char * ) stream . data ;
}
}
ftdm_safe_free ( dup ) ;
2013-06-02 02:56:44 +02:00
2010-01-15 19:22:49 +00:00
return rval ;
}
2010-04-27 14:32:36 -04:00
static ftdm_status_t ftdm_set_channels_gains ( ftdm_span_t * span , int currindex , float rxgain , float txgain )
2010-04-05 18:13:13 -04:00
{
unsigned chan_index = 0 ;
if ( ! span - > chan_count ) {
2010-08-30 12:09:10 -04:00
ftdm_log ( FTDM_LOG_ERROR , " Failed to set channel gains because span %s has no channels \n " , span - > name ) ;
2010-04-27 14:32:36 -04:00
return FTDM_FAIL ;
2010-04-05 18:13:13 -04:00
}
for ( chan_index = currindex + 1 ; chan_index < = span - > chan_count ; chan_index + + ) {
if ( ! FTDM_IS_VOICE_CHANNEL ( span - > channels [ chan_index ] ) ) {
continue ;
}
2010-04-27 14:32:36 -04:00
if ( ftdm_channel_command ( span - > channels [ chan_index ] , FTDM_COMMAND_SET_RX_GAIN , & rxgain ) ! = FTDM_SUCCESS ) {
return FTDM_FAIL ;
}
if ( ftdm_channel_command ( span - > channels [ chan_index ] , FTDM_COMMAND_SET_TX_GAIN , & txgain ) ! = FTDM_SUCCESS ) {
return FTDM_FAIL ;
}
2010-04-05 18:13:13 -04:00
}
2010-04-27 14:32:36 -04:00
return FTDM_SUCCESS ;
2010-04-05 18:13:13 -04:00
}
2011-07-29 14:55:35 -04:00
static ftdm_status_t ftdm_report_initial_channels_alarms ( ftdm_span_t * span )
{
ftdm_channel_t * fchan = NULL ;
ftdm_iterator_t * curr = NULL ;
ftdm_status_t status = FTDM_SUCCESS ;
ftdm_alarm_flag_t alarmbits ;
ftdm_event_t fake_event ;
ftdm_iterator_t * citer = ftdm_span_get_chan_iterator ( span , NULL ) ;
2010-04-27 14:32:36 -04:00
2011-07-29 14:55:35 -04:00
if ( ! citer ) {
status = FTDM_ENOMEM ;
goto done ;
2010-04-27 14:32:36 -04:00
}
2011-07-29 14:55:35 -04:00
memset ( & fake_event , 0 , sizeof ( fake_event ) ) ;
fake_event . e_type = FTDM_EVENT_OOB ;
2010-04-27 14:32:36 -04:00
2011-07-29 14:55:35 -04:00
for ( curr = citer ; curr ; curr = ftdm_iterator_next ( curr ) ) {
fchan = ftdm_iterator_current ( curr ) ;
status = ftdm_channel_get_alarms ( fchan , & alarmbits ) ;
if ( status ! = FTDM_SUCCESS ) {
ftdm_log_chan_msg ( fchan , FTDM_LOG_ERROR , " Failed to initialize alarms \n " ) ;
continue ;
2010-11-09 16:34:34 -05:00
}
2011-07-29 14:55:35 -04:00
fake_event . channel = fchan ;
fake_event . enum_id = fchan - > alarm_flags ? FTDM_OOB_ALARM_TRAP : FTDM_OOB_ALARM_CLEAR ;
ftdm_event_handle_oob ( & fake_event ) ;
2010-04-27 14:32:36 -04:00
}
2011-07-29 14:55:35 -04:00
done :
ftdm_iterator_free ( citer ) ;
return status ;
}
2010-04-27 14:32:36 -04:00
2010-04-27 17:21:57 -04:00
FT_DECLARE ( ftdm_status_t ) ftdm_configure_span_channels ( ftdm_span_t * span , const char * str , ftdm_channel_config_t * chan_config , unsigned * configured )
2010-04-27 14:32:36 -04:00
{
2010-05-11 15:09:22 -04:00
int currindex ;
2010-12-03 17:52:10 -05:00
unsigned chan_index = 0 ;
2010-05-11 15:09:22 -04:00
ftdm_assert_return ( span ! = NULL , FTDM_EINVAL , " span is null \n " ) ;
ftdm_assert_return ( chan_config ! = NULL , FTDM_EINVAL , " config is null \n " ) ;
ftdm_assert_return ( configured ! = NULL , FTDM_EINVAL , " configured pointer is null \n " ) ;
ftdm_assert_return ( span - > fio ! = NULL , FTDM_EINVAL , " span with no I/O configured \n " ) ;
ftdm_assert_return ( span - > fio - > configure_span ! = NULL , FTDM_NOTIMPL , " span I/O with no channel configuration implemented \n " ) ;
2012-01-04 11:16:29 -05:00
currindex = span - > chan_count ;
2010-04-27 18:20:25 -04:00
* configured = 0 ;
* configured = span - > fio - > configure_span ( span , str , chan_config - > type , chan_config - > name , chan_config - > number ) ;
if ( ! * configured ) {
2011-09-12 13:07:34 +02:00
ftdm_log ( FTDM_LOG_ERROR , " %d:Failed to configure span \n " , span - > span_id ) ;
2010-04-27 18:20:25 -04:00
return FTDM_FAIL ;
}
2010-04-27 16:12:22 -04:00
2010-05-11 15:09:22 -04:00
if ( chan_config - > group_name [ 0 ] ) {
if ( ftdm_group_add_channels ( span , currindex , chan_config - > group_name ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_ERROR , " %d:Failed to add channels to group %s \n " , span - > span_id , chan_config - > group_name ) ;
return FTDM_FAIL ;
}
}
if ( ftdm_set_channels_gains ( span , currindex , chan_config - > rxgain , chan_config - > txgain ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_ERROR , " %d:Failed to set channel gains \n " , span - > span_id ) ;
2010-04-27 14:32:36 -04:00
return FTDM_FAIL ;
}
2010-05-11 15:09:22 -04:00
2011-08-03 20:30:39 -04:00
for ( chan_index = currindex + 1 ; chan_index < = span - > chan_count ; chan_index + + ) {
if ( chan_config - > iostats ) {
ftdm_channel_set_feature ( span - > channels [ chan_index ] , FTDM_CHANNEL_FEATURE_IO_STATS ) ;
}
if ( ! FTDM_IS_VOICE_CHANNEL ( span - > channels [ chan_index ] ) ) {
continue ;
}
if ( chan_config - > debugdtmf ) {
2012-01-04 11:16:29 -05:00
span - > channels [ chan_index ] - > dtmfdbg . requested = 1 ;
2010-12-03 17:52:10 -05:00
}
2012-01-04 11:16:29 -05:00
span - > channels [ chan_index ] - > dtmfdetect . duration_ms = chan_config - > dtmfdetect_ms ;
2012-02-07 14:28:47 -05:00
if ( chan_config - > dtmf_on_start ) {
span - > channels [ chan_index ] - > dtmfdetect . trigger_on_start = 1 ;
2010-12-03 17:52:10 -05:00
}
2014-07-27 13:29:58 -04:00
if ( chan_config - > dtmf_time_on ) {
ftdm_channel_command ( span - > channels [ chan_index ] , FTDM_COMMAND_SET_DTMF_ON_PERIOD , & chan_config - > dtmf_time_on ) ;
}
if ( chan_config - > dtmf_time_off ) {
ftdm_channel_command ( span - > channels [ chan_index ] , FTDM_COMMAND_SET_DTMF_OFF_PERIOD , & chan_config - > dtmf_time_off ) ;
}
2010-12-03 17:52:10 -05:00
}
2011-08-03 20:30:39 -04:00
2010-04-27 14:32:36 -04:00
return FTDM_SUCCESS ;
}
2010-04-05 18:13:13 -04:00
2010-01-15 19:22:49 +00:00
static ftdm_status_t load_config ( void )
{
2012-07-18 08:16:35 -05:00
const char cfg_name [ ] = " freetdm.conf " ;
2010-01-15 19:22:49 +00:00
ftdm_config_t cfg ;
char * var , * val ;
int catno = - 1 ;
2010-04-08 13:25:44 -04:00
int intparam = 0 ;
2010-01-15 19:22:49 +00:00
ftdm_span_t * span = NULL ;
unsigned configured = 0 , d = 0 ;
ftdm_analog_start_type_t tmp ;
ftdm_size_t len = 0 ;
2010-04-27 14:32:36 -04:00
ftdm_channel_config_t chan_config ;
2011-07-25 19:02:30 -04:00
ftdm_status_t ret = FTDM_SUCCESS ;
2010-04-27 14:32:36 -04:00
memset ( & chan_config , 0 , sizeof ( chan_config ) ) ;
2010-12-03 17:52:10 -05:00
sprintf ( chan_config . group_name , " __default " ) ;
2010-01-15 19:22:49 +00:00
if ( ! ftdm_config_open_file ( & cfg , cfg_name ) ) {
2013-03-08 15:15:07 -05:00
ftdm_log ( FTDM_LOG_ERROR , " Failed to open configuration file %s \n " , cfg_name ) ;
2010-01-15 19:22:49 +00:00
return FTDM_FAIL ;
}
2012-07-11 20:41:55 +02:00
ftdm_log ( FTDM_LOG_DEBUG , " Reading FreeTDM configuration file \n " ) ;
2010-01-15 19:22:49 +00:00
while ( ftdm_config_next_pair ( & cfg , & var , & val ) ) {
if ( * cfg . category = = ' # ' ) {
if ( cfg . catno ! = catno ) {
ftdm_log ( FTDM_LOG_DEBUG , " Skipping %s \n " , cfg . category ) ;
catno = cfg . catno ;
}
} else if ( ! strncasecmp ( cfg . category , " span " , 4 ) ) {
if ( cfg . catno ! = catno ) {
char * type = cfg . category + 4 ;
char * name ;
2012-07-11 20:41:55 +02:00
2010-01-15 19:22:49 +00:00
if ( * type = = ' ' ) {
type + + ;
}
2012-07-11 20:41:55 +02:00
2010-01-15 19:22:49 +00:00
ftdm_log ( FTDM_LOG_DEBUG , " found config for span \n " ) ;
catno = cfg . catno ;
2012-07-11 20:41:55 +02:00
2010-01-15 19:22:49 +00:00
if ( ftdm_strlen_zero ( type ) ) {
ftdm_log ( FTDM_LOG_CRIT , " failure creating span, no type specified. \n " ) ;
span = NULL ;
continue ;
}
if ( ( name = strchr ( type , ' ' ) ) ) {
* name + + = ' \0 ' ;
}
2012-07-06 18:43:03 -04:00
/* Verify if trunk_type was specified for previous span */
2011-07-25 19:02:30 -04:00
if ( span & & span - > trunk_type = = FTDM_TRUNK_NONE ) {
ftdm_log ( FTDM_LOG_ERROR , " trunk_type not specified for span %d (%s) \n " , span - > span_id , span - > name ) ;
ret = FTDM_FAIL ;
goto done ;
}
2010-05-11 15:09:22 -04:00
if ( ftdm_span_create ( type , name , & span ) = = FTDM_SUCCESS ) {
2010-01-15 19:22:49 +00:00
ftdm_log ( FTDM_LOG_DEBUG , " created span %d (%s) of type %s \n " , span - > span_id , span - > name , type ) ;
2010-05-11 15:09:22 -04:00
d = 0 ;
2010-12-03 17:52:10 -05:00
/* it is confusing that parameters from one span affect others, so let's clear them */
memset ( & chan_config , 0 , sizeof ( chan_config ) ) ;
sprintf ( chan_config . group_name , " __default " ) ;
2011-08-03 20:30:39 -04:00
/* default to storing iostats */
chan_config . iostats = FTDM_TRUE ;
2010-01-15 19:22:49 +00:00
} else {
ftdm_log ( FTDM_LOG_CRIT , " failure creating span of type %s \n " , type ) ;
span = NULL ;
continue ;
}
}
if ( ! span ) {
continue ;
}
ftdm_log ( FTDM_LOG_DEBUG , " span %d [%s]=[%s] \n " , span - > span_id , var , val ) ;
2012-07-11 20:41:55 +02:00
2010-01-15 19:22:49 +00:00
if ( ! strcasecmp ( var , " trunk_type " ) ) {
2010-05-11 15:09:22 -04:00
ftdm_trunk_type_t trtype = ftdm_str2ftdm_trunk_type ( val ) ;
ftdm_span_set_trunk_type ( span , trtype ) ;
2012-07-11 20:41:55 +02:00
ftdm_log ( FTDM_LOG_DEBUG , " setting trunk type to '%s' \n " , ftdm_trunk_type2str ( trtype ) ) ;
2012-07-11 19:15:35 +02:00
} else if ( ! strcasecmp ( var , " trunk_mode " ) ) {
ftdm_trunk_mode_t trmode = ftdm_str2ftdm_trunk_mode ( val ) ;
ftdm_span_set_trunk_mode ( span , trmode ) ;
ftdm_log ( FTDM_LOG_DEBUG , " setting trunk mode to '%s' \n " , ftdm_trunk_mode2str ( trmode ) ) ;
2010-01-15 19:22:49 +00:00
} else if ( ! strcasecmp ( var , " name " ) ) {
if ( ! strcasecmp ( val , " undef " ) ) {
2010-04-27 16:12:22 -04:00
chan_config . name [ 0 ] = ' \0 ' ;
2010-01-15 19:22:49 +00:00
} else {
2010-04-27 16:12:22 -04:00
ftdm_copy_string ( chan_config . name , val , FTDM_MAX_NAME_STR_SZ ) ;
2010-01-15 19:22:49 +00:00
}
} else if ( ! strcasecmp ( var , " number " ) ) {
if ( ! strcasecmp ( val , " undef " ) ) {
2010-04-27 16:12:22 -04:00
chan_config . number [ 0 ] = ' \0 ' ;
2010-01-15 19:22:49 +00:00
} else {
2010-04-27 16:12:22 -04:00
ftdm_copy_string ( chan_config . number , val , FTDM_MAX_NUMBER_STR_SZ ) ;
2010-01-15 19:22:49 +00:00
}
} else if ( ! strcasecmp ( var , " analog-start-type " ) ) {
if ( span - > trunk_type = = FTDM_TRUNK_FXS | | span - > trunk_type = = FTDM_TRUNK_FXO | | span - > trunk_type = = FTDM_TRUNK_EM ) {
if ( ( tmp = ftdm_str2ftdm_analog_start_type ( val ) ) ! = FTDM_ANALOG_START_NA ) {
span - > start_type = tmp ;
2012-07-11 20:41:55 +02:00
ftdm_log ( FTDM_LOG_DEBUG , " changing start type to '%s' \n " , ftdm_analog_start_type2str ( span - > start_type ) ) ;
2010-01-15 19:22:49 +00:00
}
} else {
ftdm_log ( FTDM_LOG_ERROR , " This option is only valid on analog trunks! \n " ) ;
}
} else if ( ! strcasecmp ( var , " fxo-channel " ) ) {
if ( span - > trunk_type = = FTDM_TRUNK_NONE ) {
2012-07-11 19:15:35 +02:00
span - > trunk_type = FTDM_TRUNK_FXO ;
span - > trunk_mode = FTDM_TRUNK_MODE_CPE ;
ftdm_log ( FTDM_LOG_DEBUG , " setting trunk type to '%s' start(%s), mode(%s) \n " , ftdm_trunk_type2str ( span - > trunk_type ) ,
ftdm_analog_start_type2str ( span - > start_type ) , ftdm_trunk_mode2str ( span - > trunk_mode ) ) ;
2010-01-15 19:22:49 +00:00
}
if ( span - > trunk_type = = FTDM_TRUNK_FXO ) {
2010-05-11 15:09:22 -04:00
unsigned chans_configured = 0 ;
2010-04-27 17:21:57 -04:00
chan_config . type = FTDM_CHAN_TYPE_FXO ;
2010-04-27 18:20:25 -04:00
if ( ftdm_configure_span_channels ( span , val , & chan_config , & chans_configured ) = = FTDM_SUCCESS ) {
configured + = chans_configured ;
}
2010-01-15 19:22:49 +00:00
} else {
2012-07-11 20:24:35 +02:00
ftdm_log ( FTDM_LOG_WARNING , " Cannot add FXO channels to a %s trunk! \n " , ftdm_trunk_type2str ( span - > trunk_type ) ) ;
2010-01-15 19:22:49 +00:00
}
} else if ( ! strcasecmp ( var , " fxs-channel " ) ) {
if ( span - > trunk_type = = FTDM_TRUNK_NONE ) {
span - > trunk_type = FTDM_TRUNK_FXS ;
2012-07-11 19:15:35 +02:00
span - > trunk_mode = FTDM_TRUNK_MODE_NET ;
ftdm_log ( FTDM_LOG_DEBUG , " setting trunk type to '%s' start(%s), mode(%s) \n " , ftdm_trunk_type2str ( span - > trunk_type ) ,
ftdm_analog_start_type2str ( span - > start_type ) , ftdm_trunk_mode2str ( span - > trunk_mode ) ) ;
2010-01-15 19:22:49 +00:00
}
if ( span - > trunk_type = = FTDM_TRUNK_FXS ) {
2010-04-27 18:20:25 -04:00
unsigned chans_configured = 0 ;
2010-04-27 17:21:57 -04:00
chan_config . type = FTDM_CHAN_TYPE_FXS ;
2010-04-27 18:20:25 -04:00
if ( ftdm_configure_span_channels ( span , val , & chan_config , & chans_configured ) = = FTDM_SUCCESS ) {
configured + = chans_configured ;
}
2010-01-15 19:22:49 +00:00
} else {
2012-07-11 20:24:35 +02:00
ftdm_log ( FTDM_LOG_WARNING , " Cannot add FXS channels to a %s trunk! \n " , ftdm_trunk_type2str ( span - > trunk_type ) ) ;
2010-01-15 19:22:49 +00:00
}
} else if ( ! strcasecmp ( var , " em-channel " ) ) {
if ( span - > trunk_type = = FTDM_TRUNK_NONE ) {
span - > trunk_type = FTDM_TRUNK_EM ;
2012-07-11 19:15:35 +02:00
span - > trunk_mode = FTDM_TRUNK_MODE_CPE ;
ftdm_log ( FTDM_LOG_DEBUG , " setting trunk type to '%s' start(%s), mode(%s) \n " , ftdm_trunk_type2str ( span - > trunk_type ) ,
ftdm_analog_start_type2str ( span - > start_type ) , ftdm_trunk_mode2str ( span - > trunk_mode ) ) ;
2010-01-15 19:22:49 +00:00
}
if ( span - > trunk_type = = FTDM_TRUNK_EM ) {
2010-04-27 18:20:25 -04:00
unsigned chans_configured = 0 ;
2010-04-27 17:21:57 -04:00
chan_config . type = FTDM_CHAN_TYPE_EM ;
2010-04-27 18:20:25 -04:00
if ( ftdm_configure_span_channels ( span , val , & chan_config , & chans_configured ) = = FTDM_SUCCESS ) {
configured + = chans_configured ;
}
2010-01-15 19:22:49 +00:00
} else {
2012-07-11 20:24:35 +02:00
ftdm_log ( FTDM_LOG_WARNING , " Cannot add EM channels to a %s trunk! \n " , ftdm_trunk_type2str ( span - > trunk_type ) ) ;
2010-01-15 19:22:49 +00:00
}
} else if ( ! strcasecmp ( var , " b-channel " ) ) {
2012-07-11 20:24:35 +02:00
if ( span - > trunk_type = = FTDM_TRUNK_NONE ) {
ftdm_log ( FTDM_LOG_ERROR , " No trunk type specified in configuration file \n " ) ;
break ;
2010-04-27 18:20:25 -04:00
}
2012-07-11 20:24:35 +02:00
if ( FTDM_SPAN_IS_DIGITAL ( span ) ) {
unsigned chans_configured = 0 ;
chan_config . type = FTDM_CHAN_TYPE_B ;
if ( ftdm_configure_span_channels ( span , val , & chan_config , & chans_configured ) = = FTDM_SUCCESS ) {
configured + = chans_configured ;
}
2010-01-15 19:22:49 +00:00
} else {
2012-07-11 20:24:35 +02:00
ftdm_log ( FTDM_LOG_WARNING , " Cannot add B channels to a %s trunk! \n " , ftdm_trunk_type2str ( span - > trunk_type ) ) ;
}
} else if ( ! strcasecmp ( var , " d-channel " ) ) {
if ( span - > trunk_type = = FTDM_TRUNK_NONE ) {
ftdm_log ( FTDM_LOG_ERROR , " No trunk type specified in configuration file \n " ) ;
break ;
}
if ( FTDM_SPAN_IS_DIGITAL ( span ) ) {
2010-04-27 18:20:25 -04:00
unsigned chans_configured = 0 ;
2012-07-11 20:24:35 +02:00
if ( d ) {
ftdm_log ( FTDM_LOG_WARNING , " ignoring extra d-channel \n " ) ;
continue ;
}
2010-01-15 19:22:49 +00:00
if ( ! strncasecmp ( val , " lapd: " , 5 ) ) {
2010-04-27 17:21:57 -04:00
chan_config . type = FTDM_CHAN_TYPE_DQ931 ;
2010-01-15 19:22:49 +00:00
val + = 5 ;
} else {
2010-04-27 17:21:57 -04:00
chan_config . type = FTDM_CHAN_TYPE_DQ921 ;
2010-01-15 19:22:49 +00:00
}
2010-04-27 18:20:25 -04:00
if ( ftdm_configure_span_channels ( span , val , & chan_config , & chans_configured ) = = FTDM_SUCCESS ) {
configured + = chans_configured ;
}
2010-01-15 19:22:49 +00:00
d + + ;
2012-07-11 20:24:35 +02:00
} else {
ftdm_log ( FTDM_LOG_WARNING , " Cannot add D channels to a %s trunk! \n " , ftdm_trunk_type2str ( span - > trunk_type ) ) ;
2010-01-15 19:22:49 +00:00
}
} else if ( ! strcasecmp ( var , " cas-channel " ) ) {
2010-04-27 18:20:25 -04:00
unsigned chans_configured = 0 ;
2010-04-27 17:21:57 -04:00
chan_config . type = FTDM_CHAN_TYPE_CAS ;
2010-04-27 18:20:25 -04:00
if ( ftdm_configure_span_channels ( span , val , & chan_config , & chans_configured ) = = FTDM_SUCCESS ) {
configured + = chans_configured ;
}
2010-01-15 19:22:49 +00:00
} else if ( ! strcasecmp ( var , " dtmf_hangup " ) ) {
span - > dtmf_hangup = ftdm_strdup ( val ) ;
span - > dtmf_hangup_len = strlen ( val ) ;
2010-04-05 18:13:13 -04:00
} else if ( ! strcasecmp ( var , " txgain " ) ) {
2010-04-27 14:32:36 -04:00
if ( sscanf ( val , " %f " , & ( chan_config . txgain ) ) ! = 1 ) {
2010-04-05 18:13:13 -04:00
ftdm_log ( FTDM_LOG_ERROR , " invalid txgain: '%s' \n " , val ) ;
}
} else if ( ! strcasecmp ( var , " rxgain " ) ) {
2010-04-27 14:32:36 -04:00
if ( sscanf ( val , " %f " , & ( chan_config . rxgain ) ) ! = 1 ) {
2010-04-05 18:13:13 -04:00
ftdm_log ( FTDM_LOG_ERROR , " invalid rxgain: '%s' \n " , val ) ;
}
2010-12-03 17:52:10 -05:00
} else if ( ! strcasecmp ( var , " debugdtmf " ) ) {
chan_config . debugdtmf = ftdm_true ( val ) ;
ftdm_log ( FTDM_LOG_DEBUG , " Setting debugdtmf to '%s' \n " , chan_config . debugdtmf ? " yes " : " no " ) ;
2012-01-04 11:16:29 -05:00
} else if ( ! strncasecmp ( var , " dtmfdetect_ms " , sizeof ( " dtmfdetect_ms " ) - 1 ) ) {
2012-02-07 14:28:47 -05:00
if ( chan_config . dtmf_on_start = = FTDM_TRUE ) {
chan_config . dtmf_on_start = FTDM_FALSE ;
ftdm_log ( FTDM_LOG_WARNING , " dtmf_on_start parameter disabled because dtmfdetect_ms specified \n " ) ;
}
2012-01-04 11:16:29 -05:00
if ( sscanf ( val , " %d " , & ( chan_config . dtmfdetect_ms ) ) ! = 1 ) {
ftdm_log ( FTDM_LOG_ERROR , " invalid dtmfdetect_ms: '%s' \n " , val ) ;
}
2012-02-07 14:28:47 -05:00
} else if ( ! strncasecmp ( var , " dtmf_on_start " , sizeof ( " dtmf_on_start " ) - 1 ) ) {
if ( chan_config . dtmfdetect_ms ) {
ftdm_log ( FTDM_LOG_WARNING , " dtmf_on_start parameter ignored because dtmf_detect_ms specified \n " ) ;
} else {
if ( ftdm_true ( val ) ) {
chan_config . dtmf_on_start = FTDM_TRUE ;
} else {
chan_config . dtmf_on_start = FTDM_FALSE ;
}
}
2014-07-27 13:29:58 -04:00
} else if ( ! strcasecmp ( var , " dtmf_time_on " ) ) {
if ( sscanf ( val , " %u " , & ( chan_config . dtmf_time_on ) ) ! = 1 ) {
ftdm_log ( FTDM_LOG_ERROR , " invalid dtmf_time_on: '%s' \n " , val ) ;
}
} else if ( ! strcasecmp ( var , " dtmf_time_off " ) ) {
if ( sscanf ( val , " %u " , & ( chan_config . dtmf_time_off ) ) ! = 1 ) {
ftdm_log ( FTDM_LOG_ERROR , " invalid dtmf_time_off: '%s' \n " , val ) ;
}
2011-08-03 20:30:39 -04:00
} else if ( ! strncasecmp ( var , " iostats " , sizeof ( " iostats " ) - 1 ) ) {
if ( ftdm_true ( val ) ) {
chan_config . iostats = FTDM_TRUE ;
} else {
chan_config . iostats = FTDM_FALSE ;
}
ftdm_log ( FTDM_LOG_DEBUG , " Setting iostats to '%s' \n " , chan_config . iostats ? " yes " : " no " ) ;
2010-01-15 19:22:49 +00:00
} else if ( ! strcasecmp ( var , " group " ) ) {
len = strlen ( val ) ;
2010-04-27 14:32:36 -04:00
if ( len > = FTDM_MAX_NAME_STR_SZ ) {
len = FTDM_MAX_NAME_STR_SZ - 1 ;
2010-12-15 09:56:27 -05:00
ftdm_log ( FTDM_LOG_WARNING , " Truncating group name %s to % " FTDM_SIZE_FMT " length \n " , val , len ) ;
2010-01-15 19:22:49 +00:00
}
2010-04-27 14:32:36 -04:00
memcpy ( chan_config . group_name , val , len ) ;
chan_config . group_name [ len ] = ' \0 ' ;
2010-01-15 19:22:49 +00:00
} else {
ftdm_log ( FTDM_LOG_ERROR , " unknown span variable '%s' \n " , var ) ;
}
2010-04-05 17:49:43 -04:00
} else if ( ! strncasecmp ( cfg . category , " general " , 7 ) ) {
2010-09-23 13:58:20 -04:00
if ( ! strncasecmp ( var , " cpu_monitor " , sizeof ( " cpu_monitor " ) - 1 ) ) {
if ( ! strncasecmp ( val , " yes " , 3 ) ) {
globals . cpu_monitor . enabled = 1 ;
if ( ! globals . cpu_monitor . alarm_action_flags ) {
globals . cpu_monitor . alarm_action_flags | = FTDM_CPU_ALARM_ACTION_WARN ;
}
}
2011-03-18 14:47:49 -04:00
} else if ( ! strncasecmp ( var , " debugdtmf_directory " , sizeof ( " debugdtmf_directory " ) - 1 ) ) {
ftdm_set_string ( globals . dtmfdebug_directory , val ) ;
ftdm_log ( FTDM_LOG_DEBUG , " Debug DTMF directory set to '%s' \n " , globals . dtmfdebug_directory ) ;
2010-09-23 13:58:20 -04:00
} else if ( ! strncasecmp ( var , " cpu_monitoring_interval " , sizeof ( " cpu_monitoring_interval " ) - 1 ) ) {
2010-04-05 17:49:43 -04:00
if ( atoi ( val ) > 0 ) {
globals . cpu_monitor . interval = atoi ( val ) ;
} else {
ftdm_log ( FTDM_LOG_ERROR , " Invalid cpu monitoring interval %s \n " , val ) ;
}
} else if ( ! strncasecmp ( var , " cpu_set_alarm_threshold " , sizeof ( " cpu_set_alarm_threshold " ) - 1 ) ) {
2010-04-08 13:25:44 -04:00
intparam = atoi ( val ) ;
if ( intparam > 0 & & intparam < 100 ) {
globals . cpu_monitor . set_alarm_threshold = ( uint8_t ) intparam ;
2010-04-05 17:49:43 -04:00
} else {
ftdm_log ( FTDM_LOG_ERROR , " Invalid cpu alarm set threshold %s \n " , val ) ;
}
2011-12-01 12:13:12 -05:00
} else if ( ! strncasecmp ( var , " cpu_reset_alarm_threshold " , sizeof ( " cpu_reset_alarm_threshold " ) - 1 ) | |
! strncasecmp ( var , " cpu_clear_alarm_threshold " , sizeof ( " cpu_clear_alarm_threshold " ) - 1 ) ) {
2010-04-08 13:25:44 -04:00
intparam = atoi ( val ) ;
if ( intparam > 0 & & intparam < 100 ) {
2011-12-01 12:13:12 -05:00
globals . cpu_monitor . clear_alarm_threshold = ( uint8_t ) intparam ;
if ( globals . cpu_monitor . clear_alarm_threshold > globals . cpu_monitor . set_alarm_threshold ) {
globals . cpu_monitor . clear_alarm_threshold = globals . cpu_monitor . set_alarm_threshold - 10 ;
ftdm_log ( FTDM_LOG_ERROR , " Cpu alarm clear threshold must be lower than set threshold, "
" setting clear threshold to %d \n " , globals . cpu_monitor . clear_alarm_threshold ) ;
2010-04-05 17:49:43 -04:00
}
} else {
ftdm_log ( FTDM_LOG_ERROR , " Invalid cpu alarm reset threshold %s \n " , val ) ;
}
} else if ( ! strncasecmp ( var , " cpu_alarm_action " , sizeof ( " cpu_alarm_action " ) - 1 ) ) {
char * p = val ;
do {
if ( ! strncasecmp ( p , " reject " , sizeof ( " reject " ) - 1 ) ) {
globals . cpu_monitor . alarm_action_flags | = FTDM_CPU_ALARM_ACTION_REJECT ;
} else if ( ! strncasecmp ( p , " warn " , sizeof ( " warn " ) - 1 ) ) {
globals . cpu_monitor . alarm_action_flags | = FTDM_CPU_ALARM_ACTION_WARN ;
}
p = strchr ( p , ' , ' ) ;
if ( p ) {
while ( * p + + ) if ( * p ! = 0x20 ) break ;
}
} while ( p ) ;
}
2010-01-15 19:22:49 +00:00
} else {
ftdm_log ( FTDM_LOG_ERROR , " unknown param [%s] '%s' / '%s' \n " , cfg . category , var , val ) ;
}
}
2011-07-25 19:02:30 -04:00
/* Verify is trunk_type was specified for the last span */
if ( span & & span - > trunk_type = = FTDM_TRUNK_NONE ) {
ftdm_log ( FTDM_LOG_ERROR , " trunk_type not specified for span %d (%s) \n " , span - > span_id , span - > name ) ;
ret = FTDM_FAIL ;
}
done :
2010-01-15 19:22:49 +00:00
ftdm_config_close_file ( & cfg ) ;
ftdm_log ( FTDM_LOG_INFO , " Configured %u channel(s) \n " , configured ) ;
2011-07-25 19:02:30 -04:00
if ( ! configured ) {
ret = FTDM_FAIL ;
}
2012-07-11 20:41:55 +02:00
2011-07-25 19:02:30 -04:00
return ret ;
2010-01-15 19:22:49 +00:00
}
2010-01-15 20:35:11 +00:00
static ftdm_status_t process_module_config ( ftdm_io_interface_t * fio )
2010-01-15 19:22:49 +00:00
{
ftdm_config_t cfg ;
char * var , * val ;
char filename [ 256 ] = " " ;
2010-01-15 20:35:11 +00:00
ftdm_assert_return ( fio ! = NULL , FTDM_FAIL , " fio argument is null \n " ) ;
2010-01-15 19:22:49 +00:00
2010-01-15 20:35:11 +00:00
snprintf ( filename , sizeof ( filename ) , " %s.conf " , fio - > name ) ;
2010-01-15 19:22:49 +00:00
2010-01-15 20:35:11 +00:00
if ( ! fio - > configure ) {
ftdm_log ( FTDM_LOG_DEBUG , " Module %s does not support configuration. \n " , fio - > name ) ;
2010-01-15 19:22:49 +00:00
return FTDM_FAIL ;
}
if ( ! ftdm_config_open_file ( & cfg , filename ) ) {
2014-05-10 02:56:06 -04:00
/* This is normal if the user did not provide a configuration for this module */
ftdm_log ( FTDM_LOG_DEBUG , " File %s is not available \n " , filename ) ;
2010-01-15 19:22:49 +00:00
return FTDM_FAIL ;
}
while ( ftdm_config_next_pair ( & cfg , & var , & val ) ) {
2010-01-15 20:35:11 +00:00
fio - > configure ( cfg . category , var , val , cfg . lineno ) ;
2010-01-15 19:22:49 +00:00
}
ftdm_config_close_file ( & cfg ) ;
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_global_add_io_interface ( ftdm_io_interface_t * interface1 )
{
ftdm_status_t ret = FTDM_SUCCESS ;
ftdm_mutex_lock ( globals . mutex ) ;
if ( hashtable_search ( globals . interface_hash , ( void * ) interface1 - > name ) ) {
ftdm_log ( FTDM_LOG_ERROR , " Interface %s already loaded! \n " , interface1 - > name ) ;
} else {
hashtable_insert ( globals . interface_hash , ( void * ) interface1 - > name , interface1 , HASHTABLE_FLAG_NONE ) ;
}
ftdm_mutex_unlock ( globals . mutex ) ;
return ret ;
}
2013-06-02 02:56:44 +02:00
FT_DECLARE ( ftdm_io_interface_t * ) ftdm_global_get_io_interface ( const char * iotype , ftdm_bool_t autoload )
{
ftdm_io_interface_t * fio = NULL ;
ftdm_mutex_lock ( globals . mutex ) ;
fio = ( ftdm_io_interface_t * ) hashtable_search ( globals . interface_hash , ( void * ) iotype ) ;
if ( ! fio & & autoload ) {
ftdm_load_module_assume ( iotype ) ;
fio = ( ftdm_io_interface_t * ) hashtable_search ( globals . interface_hash , ( void * ) iotype ) ;
if ( fio ) {
ftdm_log ( FTDM_LOG_INFO , " Auto-loaded I/O module '%s' \n " , iotype ) ;
}
}
ftdm_mutex_unlock ( globals . mutex ) ;
return fio ;
}
2010-01-15 19:22:49 +00:00
FT_DECLARE ( int ) ftdm_load_module ( const char * name )
{
ftdm_dso_lib_t lib ;
2014-07-22 20:53:28 -04:00
int count = 0 ;
ftdm_bool_t load_proceed = FTDM_TRUE ;
2011-02-17 09:17:41 -05:00
char path [ 512 ] = " " ;
2010-01-15 19:22:49 +00:00
char * err ;
ftdm_module_t * mod ;
ftdm_build_dso_path ( name , path , sizeof ( path ) ) ;
if ( ! ( lib = ftdm_dso_open ( path , & err ) ) ) {
ftdm_log ( FTDM_LOG_ERROR , " Error loading %s [%s] \n " , path , err ) ;
ftdm_safe_free ( err ) ;
return 0 ;
}
if ( ! ( mod = ( ftdm_module_t * ) ftdm_dso_func_sym ( lib , " ftdm_module " , & err ) ) ) {
ftdm_log ( FTDM_LOG_ERROR , " Error loading %s [%s] \n " , path , err ) ;
ftdm_safe_free ( err ) ;
return 0 ;
}
if ( mod - > io_load ) {
ftdm_io_interface_t * interface1 = NULL ; /* name conflict w/windows here */
if ( mod - > io_load ( & interface1 ) ! = FTDM_SUCCESS | | ! interface1 | | ! interface1 - > name ) {
ftdm_log ( FTDM_LOG_ERROR , " Error loading %s \n " , path ) ;
2014-07-22 20:53:28 -04:00
load_proceed = FTDM_FALSE ;
2010-01-15 19:22:49 +00:00
} else {
ftdm_log ( FTDM_LOG_INFO , " Loading IO from %s [%s] \n " , path , interface1 - > name ) ;
if ( ftdm_global_add_io_interface ( interface1 ) = = FTDM_SUCCESS ) {
process_module_config ( interface1 ) ;
}
}
}
if ( mod - > sig_load ) {
if ( mod - > sig_load ( ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_ERROR , " Error loading %s \n " , path ) ;
2014-07-22 20:53:28 -04:00
load_proceed = FTDM_FALSE ;
2010-01-15 19:22:49 +00:00
} else {
ftdm_log ( FTDM_LOG_INFO , " Loading SIG from %s \n " , path ) ;
}
}
2014-07-22 20:53:28 -04:00
if ( load_proceed ) {
2010-01-15 19:22:49 +00:00
char * p ;
mod - > lib = lib ;
ftdm_set_string ( mod - > path , path ) ;
if ( mod - > name [ 0 ] = = ' \0 ' ) {
if ( ! ( p = strrchr ( path , * FTDM_PATH_SEPARATOR ) ) ) {
p = path ;
}
ftdm_set_string ( mod - > name , p ) ;
}
ftdm_mutex_lock ( globals . mutex ) ;
if ( hashtable_search ( globals . module_hash , ( void * ) mod - > name ) ) {
ftdm_log ( FTDM_LOG_ERROR , " Module %s already loaded! \n " , mod - > name ) ;
ftdm_dso_destroy ( & lib ) ;
} else {
hashtable_insert ( globals . module_hash , ( void * ) mod - > name , mod , HASHTABLE_FLAG_NONE ) ;
count + + ;
}
ftdm_mutex_unlock ( globals . mutex ) ;
} else {
2014-07-22 20:53:28 -04:00
ftdm_log ( FTDM_LOG_ERROR , " Errors during module load. Unloading %s \n " , path ) ;
2010-01-15 19:22:49 +00:00
ftdm_dso_destroy ( & lib ) ;
}
return count ;
}
FT_DECLARE ( int ) ftdm_load_module_assume ( const char * name )
{
char buf [ 256 ] = " " ;
snprintf ( buf , sizeof ( buf ) , " ftmod_%s " , name ) ;
return ftdm_load_module ( buf ) ;
}
FT_DECLARE ( int ) ftdm_load_modules ( void )
{
char cfg_name [ ] = " modules.conf " ;
ftdm_config_t cfg ;
char * var , * val ;
int count = 0 ;
if ( ! ftdm_config_open_file ( & cfg , cfg_name ) ) {
return FTDM_FAIL ;
}
while ( ftdm_config_next_pair ( & cfg , & var , & val ) ) {
if ( ! strcasecmp ( cfg . category , " modules " ) ) {
if ( ! strcasecmp ( var , " load " ) ) {
count + = ftdm_load_module ( val ) ;
}
}
}
return count ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_unload_modules ( void )
{
2010-03-12 18:27:24 +00:00
ftdm_hash_iterator_t * i = NULL ;
ftdm_dso_lib_t lib = NULL ;
2017-06-28 06:10:46 -06:00
char modpath [ 256 ] = { 0 } ;
2010-01-15 19:22:49 +00:00
2010-03-12 18:27:24 +00:00
/* stop signaling interfaces first as signaling depends on I/O and not the other way around */
2010-01-15 19:22:49 +00:00
for ( i = hashtable_first ( globals . module_hash ) ; i ; i = hashtable_next ( i ) ) {
2010-03-12 18:27:24 +00:00
const void * key = NULL ;
void * val = NULL ;
ftdm_module_t * mod = NULL ;
2010-01-15 19:22:49 +00:00
hashtable_this ( i , & key , NULL , & val ) ;
2010-03-12 18:27:24 +00:00
if ( ! key | | ! val ) {
continue ;
}
mod = ( ftdm_module_t * ) val ;
2010-01-15 19:22:49 +00:00
2010-03-12 18:27:24 +00:00
if ( ! mod - > sig_unload ) {
continue ;
}
2010-01-15 19:22:49 +00:00
2010-03-12 18:27:24 +00:00
ftdm_log ( FTDM_LOG_INFO , " Unloading signaling interface %s \n " , mod - > name ) ;
if ( mod - > sig_unload ( ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_ERROR , " Error unloading signaling interface %s \n " , mod - > name ) ;
continue ;
}
2010-01-15 19:22:49 +00:00
2010-03-12 18:27:24 +00:00
ftdm_log ( FTDM_LOG_INFO , " Unloaded signaling interface %s \n " , mod - > name ) ;
}
2010-01-15 19:22:49 +00:00
2010-03-12 18:27:24 +00:00
/* Now go ahead with I/O interfaces */
for ( i = hashtable_first ( globals . module_hash ) ; i ; i = hashtable_next ( i ) ) {
const void * key = NULL ;
void * val = NULL ;
ftdm_module_t * mod = NULL ;
hashtable_this ( i , & key , NULL , & val ) ;
if ( ! key | | ! val ) {
continue ;
2010-01-15 19:22:49 +00:00
}
2010-03-12 18:27:24 +00:00
mod = ( ftdm_module_t * ) val ;
if ( ! mod - > io_unload ) {
continue ;
}
ftdm_log ( FTDM_LOG_INFO , " Unloading I/O interface %s \n " , mod - > name ) ;
if ( mod - > io_unload ( ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_ERROR , " Error unloading I/O interface %s \n " , mod - > name ) ;
continue ;
}
ftdm_log ( FTDM_LOG_INFO , " Unloaded I/O interface %s \n " , mod - > name ) ;
}
/* Now unload the actual shared object/dll */
for ( i = hashtable_first ( globals . module_hash ) ; i ; i = hashtable_next ( i ) ) {
ftdm_module_t * mod = NULL ;
const void * key = NULL ;
void * val = NULL ;
hashtable_this ( i , & key , NULL , & val ) ;
if ( ! key | | ! val ) {
continue ;
}
mod = ( ftdm_module_t * ) val ;
lib = mod - > lib ;
snprintf ( modpath , sizeof ( modpath ) , " %s " , mod - > path ) ;
ftdm_log ( FTDM_LOG_INFO , " Unloading module %s \n " , modpath ) ;
ftdm_dso_destroy ( & lib ) ;
ftdm_log ( FTDM_LOG_INFO , " Unloaded module %s \n " , modpath ) ;
2010-01-15 19:22:49 +00:00
}
return FTDM_SUCCESS ;
}
2010-04-28 18:16:22 -04:00
static ftdm_status_t post_configure_span_channels ( ftdm_span_t * span )
{
unsigned i = 0 ;
2010-05-17 11:23:33 -04:00
ftdm_status_t status = FTDM_SUCCESS ;
ftdm_signaling_status_t sigstatus = FTDM_SIG_STATE_DOWN ;
2010-04-28 18:16:22 -04:00
for ( i = 1 ; i < = span - > chan_count ; i + + ) {
2011-07-29 14:55:35 -04:00
sigstatus = FTDM_SIG_STATE_DOWN ;
2010-05-17 11:23:33 -04:00
ftdm_channel_get_sig_status ( span - > channels [ i ] , & sigstatus ) ;
if ( sigstatus = = FTDM_SIG_STATE_UP ) {
2010-04-28 18:16:22 -04:00
ftdm_set_flag ( span - > channels [ i ] , FTDM_CHANNEL_SIG_UP ) ;
}
}
if ( ftdm_test_flag ( span , FTDM_SPAN_USE_CHAN_QUEUE ) ) {
status = ftdm_queue_create ( & span - > pendingchans , SPAN_PENDING_CHANS_QUEUE_SIZE ) ;
}
2010-08-31 18:13:56 -04:00
if ( status = = FTDM_SUCCESS & & ftdm_test_flag ( span , FTDM_SPAN_USE_SIGNALS_QUEUE ) ) {
status = ftdm_queue_create ( & span - > pendingsignals , SPAN_PENDING_SIGNALS_QUEUE_SIZE ) ;
}
2010-04-28 18:16:22 -04:00
return status ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_configure_span ( ftdm_span_t * span , const char * type , fio_signal_cb_t sig_cb , . . . )
2010-01-15 19:22:49 +00:00
{
ftdm_module_t * mod = ( ftdm_module_t * ) hashtable_search ( globals . module_hash , ( void * ) type ) ;
ftdm_status_t status = FTDM_FAIL ;
2010-04-12 16:10:25 -04:00
if ( ! span - > chan_count ) {
ftdm_log ( FTDM_LOG_WARNING , " Cannot configure signaling on span with no channels \n " ) ;
return FTDM_FAIL ;
}
2010-01-15 19:22:49 +00:00
if ( ! mod ) {
ftdm_load_module_assume ( type ) ;
if ( ( mod = ( ftdm_module_t * ) hashtable_search ( globals . module_hash , ( void * ) type ) ) ) {
ftdm_log ( FTDM_LOG_INFO , " auto-loaded '%s' \n " , type ) ;
2010-06-06 13:07:30 -04:00
} else {
ftdm_log ( FTDM_LOG_ERROR , " can't load '%s' \n " , type ) ;
return FTDM_FAIL ;
2010-01-15 19:22:49 +00:00
}
}
2010-06-06 13:07:30 -04:00
if ( mod - > sig_configure ) {
2010-01-15 19:22:49 +00:00
va_list ap ;
va_start ( ap , sig_cb ) ;
status = mod - > sig_configure ( span , sig_cb , ap ) ;
2010-04-12 16:10:25 -04:00
va_end ( ap ) ;
2010-04-28 18:16:22 -04:00
if ( status = = FTDM_SUCCESS ) {
status = post_configure_span_channels ( span ) ;
2010-04-05 16:01:08 -04:00
}
2010-01-15 19:22:49 +00:00
} else {
2010-06-06 13:07:30 -04:00
ftdm_log ( FTDM_LOG_CRIT , " module '%s' did not implement the sig_configure method \n " , type ) ;
2010-01-15 19:22:49 +00:00
status = FTDM_FAIL ;
}
return status ;
}
2010-04-28 18:16:22 -04:00
FT_DECLARE ( ftdm_status_t ) ftdm_configure_span_signaling ( ftdm_span_t * span , const char * type , fio_signal_cb_t sig_cb , ftdm_conf_parameter_t * parameters )
2010-01-15 19:22:49 +00:00
{
ftdm_module_t * mod = ( ftdm_module_t * ) hashtable_search ( globals . module_hash , ( void * ) type ) ;
ftdm_status_t status = FTDM_FAIL ;
ftdm_assert_return ( type ! = NULL , FTDM_FAIL , " No signaling type " ) ;
ftdm_assert_return ( span ! = NULL , FTDM_FAIL , " No span " ) ;
ftdm_assert_return ( sig_cb ! = NULL , FTDM_FAIL , " No signaling callback " ) ;
ftdm_assert_return ( parameters ! = NULL , FTDM_FAIL , " No parameters " ) ;
2010-04-12 16:10:25 -04:00
if ( ! span - > chan_count ) {
2010-12-29 13:38:43 -05:00
ftdm_log ( FTDM_LOG_WARNING , " Cannot configure signaling on span %s with no channels \n " , span - > name ) ;
2010-04-12 16:10:25 -04:00
return FTDM_FAIL ;
}
2010-01-15 19:22:49 +00:00
if ( ! mod ) {
ftdm_load_module_assume ( type ) ;
if ( ( mod = ( ftdm_module_t * ) hashtable_search ( globals . module_hash , ( void * ) type ) ) ) {
ftdm_log ( FTDM_LOG_INFO , " auto-loaded '%s' \n " , type ) ;
}
}
if ( ! mod ) {
ftdm_log ( FTDM_LOG_ERROR , " Failed to load module type: %s \n " , type ) ;
return FTDM_FAIL ;
}
if ( mod - > configure_span_signaling ) {
status = mod - > configure_span_signaling ( span , sig_cb , parameters ) ;
2010-04-28 18:16:22 -04:00
if ( status = = FTDM_SUCCESS ) {
status = post_configure_span_channels ( span ) ;
2010-04-12 16:10:25 -04:00
}
2010-01-15 19:22:49 +00:00
} else {
ftdm_log ( FTDM_LOG_ERROR , " Module %s did not implement the signaling configuration method \n " , type ) ;
}
return status ;
}
2012-07-26 16:43:18 -04:00
static void * ftdm_span_service_events ( ftdm_thread_t * me , void * obj )
{
2012-09-14 16:51:43 -05:00
uint32_t i ;
2012-07-26 16:43:18 -04:00
unsigned waitms ;
ftdm_event_t * event ;
ftdm_status_t status = FTDM_SUCCESS ;
ftdm_span_t * span = ( ftdm_span_t * ) obj ;
short * poll_events = ftdm_malloc ( sizeof ( short ) * span - > chan_count ) ;
2012-09-14 16:51:43 -05:00
if ( me = = 0 ) { } ;
2012-07-26 16:43:18 -04:00
memset ( poll_events , 0 , sizeof ( short ) * span - > chan_count ) ;
for ( i = 1 ; i < = span - > chan_count ; i + + ) {
poll_events [ i ] | = FTDM_EVENTS ;
}
while ( ftdm_running ( ) & & ! ( ftdm_test_flag ( span , FTDM_SPAN_STOP_THREAD ) ) ) {
waitms = 1000 ;
status = ftdm_span_poll_event ( span , waitms , poll_events ) ;
switch ( status ) {
case FTDM_FAIL :
ftdm_log ( FTDM_LOG_CRIT , " %s:Failed to poll span for events \n " , span - > name ) ;
break ;
case FTDM_TIMEOUT :
break ;
case FTDM_SUCCESS :
/* Check if there are any channels that have events available */
while ( ftdm_span_next_event ( span , & event ) = = FTDM_SUCCESS ) ;
break ;
default :
ftdm_log ( FTDM_LOG_CRIT , " %s:Unhandled IO event \n " , span - > name ) ;
}
}
return NULL ;
}
2012-07-27 21:31:24 -04:00
FT_DECLARE ( ftdm_status_t ) ftdm_span_register_signal_cb ( ftdm_span_t * span , fio_signal_cb_t sig_cb )
{
span - > signal_cb = sig_cb ;
return FTDM_SUCCESS ;
}
2010-01-15 19:22:49 +00:00
FT_DECLARE ( ftdm_status_t ) ftdm_span_start ( ftdm_span_t * span )
{
2011-01-04 14:23:25 -05:00
ftdm_status_t status = FTDM_FAIL ;
ftdm_mutex_lock ( span - > mutex ) ;
if ( ftdm_test_flag ( span , FTDM_SPAN_STARTED ) ) {
status = FTDM_EINVAL ;
goto done ;
2010-01-15 19:22:49 +00:00
}
2012-07-26 16:43:18 -04:00
if ( span - > signal_type = = FTDM_SIGTYPE_NONE ) {
/* If there is no signalling component, start a thread to poll events */
status = ftdm_thread_create_detached ( ftdm_span_service_events , span ) ;
if ( status ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_CRIT , " Failed to start span event monitor thread! \n " ) ;
goto done ;
}
2012-07-27 21:31:24 -04:00
//ftdm_report_initial_channels_alarms(span);
ftdm_set_flag_locked ( span , FTDM_SPAN_STARTED ) ;
2012-07-26 16:43:18 -04:00
goto done ;
}
2010-01-15 19:22:49 +00:00
2011-01-04 14:23:25 -05:00
if ( ! span - > start ) {
status = FTDM_ENOSYS ;
goto done ;
}
2012-08-15 13:19:38 +02:00
/* Start I/O */
if ( span - > fio & & span - > fio - > span_start ) {
status = span - > fio - > span_start ( span ) ;
if ( status ! = FTDM_SUCCESS )
goto done ;
}
/* Start SIG */
2011-07-29 14:55:35 -04:00
status = ftdm_report_initial_channels_alarms ( span ) ;
if ( status ! = FTDM_SUCCESS ) {
2011-01-05 13:11:37 -05:00
goto done ;
}
2011-01-04 14:23:25 -05:00
status = span - > start ( span ) ;
if ( status = = FTDM_SUCCESS ) {
ftdm_set_flag_locked ( span , FTDM_SPAN_STARTED ) ;
}
done :
ftdm_mutex_unlock ( span - > mutex ) ;
return status ;
2010-01-15 19:22:49 +00:00
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_add_to_group ( const char * name , ftdm_channel_t * ftdmchan )
{
2010-01-15 21:43:41 +00:00
unsigned int i ;
2010-01-15 19:22:49 +00:00
ftdm_group_t * group = NULL ;
ftdm_mutex_lock ( globals . group_mutex ) ;
2010-01-29 19:06:21 +00:00
ftdm_assert_return ( ftdmchan ! = NULL , FTDM_FAIL , " Cannot add a null channel to a group \n " ) ;
2010-01-15 19:22:49 +00:00
if ( ftdm_group_find_by_name ( name , & group ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_DEBUG , " Creating new group:%s \n " , name ) ;
ftdm_group_create ( & group , name ) ;
}
/*verify that group does not already include this channel first */
2010-01-15 21:43:41 +00:00
for ( i = 0 ; i < group - > chan_count ; i + + ) {
2010-01-15 19:22:49 +00:00
if ( group - > channels [ i ] - > physical_span_id = = ftdmchan - > physical_span_id & &
group - > channels [ i ] - > physical_chan_id = = ftdmchan - > physical_chan_id ) {
ftdm_mutex_unlock ( globals . group_mutex ) ;
2010-01-29 19:06:21 +00:00
ftdm_log ( FTDM_LOG_DEBUG , " Channel %d:%d is already added to group %s \n " ,
group - > channels [ i ] - > physical_span_id ,
group - > channels [ i ] - > physical_chan_id ,
name ) ;
2010-01-15 19:22:49 +00:00
return FTDM_SUCCESS ;
}
}
if ( group - > chan_count > = FTDM_MAX_CHANNELS_GROUP ) {
2010-01-29 19:06:21 +00:00
ftdm_log ( FTDM_LOG_ERROR , " Max number of channels exceeded (max:%d) \n " , FTDM_MAX_CHANNELS_GROUP ) ;
2010-01-15 19:22:49 +00:00
ftdm_mutex_unlock ( globals . group_mutex ) ;
return FTDM_FAIL ;
}
group - > channels [ group - > chan_count + + ] = ftdmchan ;
ftdm_mutex_unlock ( globals . group_mutex ) ;
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_channel_remove_from_group ( ftdm_group_t * group , ftdm_channel_t * ftdmchan )
{
2010-01-15 21:43:41 +00:00
unsigned int i , j ;
2010-01-15 19:22:49 +00:00
//Need to test this function
ftdm_mutex_lock ( globals . group_mutex ) ;
for ( i = 0 ; i < group - > chan_count ; i + + ) {
if ( group - > channels [ i ] - > physical_span_id = = ftdmchan - > physical_span_id & &
group - > channels [ i ] - > physical_chan_id = = ftdmchan - > physical_chan_id ) {
j = i ;
while ( j < group - > chan_count - 1 ) {
group - > channels [ j ] = group - > channels [ j + 1 ] ;
j + + ;
}
group - > channels [ group - > chan_count - - ] = NULL ;
if ( group - > chan_count < = 0 ) {
/* Delete group if it is empty */
hashtable_remove ( globals . group_hash , ( void * ) group - > name ) ;
}
ftdm_mutex_unlock ( globals . group_mutex ) ;
return FTDM_SUCCESS ;
}
}
ftdm_mutex_unlock ( globals . group_mutex ) ;
//Group does not contain this channel
return FTDM_FAIL ;
}
2010-04-27 14:32:36 -04:00
static ftdm_status_t ftdm_group_add_channels ( ftdm_span_t * span , int currindex , const char * name )
2010-01-15 19:22:49 +00:00
{
2010-02-02 19:11:07 +00:00
unsigned chan_index = 0 ;
2010-01-15 19:22:49 +00:00
2010-01-25 18:53:27 +00:00
ftdm_assert_return ( strlen ( name ) > 0 , FTDM_FAIL , " Invalid group name provided \n " ) ;
ftdm_assert_return ( currindex > = 0 , FTDM_FAIL , " Invalid current channel index provided \n " ) ;
2010-01-15 19:22:49 +00:00
2010-01-25 18:53:27 +00:00
if ( ! span - > chan_count ) {
return FTDM_SUCCESS ;
}
2010-01-15 19:22:49 +00:00
2010-01-29 19:06:21 +00:00
for ( chan_index = currindex + 1 ; chan_index < = span - > chan_count ; chan_index + + ) {
if ( ! FTDM_IS_VOICE_CHANNEL ( span - > channels [ chan_index ] ) ) {
continue ;
}
2010-01-25 18:53:27 +00:00
if ( ftdm_channel_add_to_group ( name , span - > channels [ chan_index ] ) ) {
2010-01-29 19:06:21 +00:00
ftdm_log ( FTDM_LOG_ERROR , " Failed to add chan:%d to group:%s \n " , chan_index , name ) ;
2010-01-15 19:22:49 +00:00
}
}
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_group_find ( uint32_t id , ftdm_group_t * * group )
{
ftdm_group_t * fgroup = NULL , * grp ;
if ( id > FTDM_MAX_GROUPS_INTERFACE ) {
return FTDM_FAIL ;
}
ftdm_mutex_lock ( globals . group_mutex ) ;
for ( grp = globals . groups ; grp ; grp = grp - > next ) {
if ( grp - > group_id = = id ) {
fgroup = grp ;
break ;
}
}
ftdm_mutex_unlock ( globals . group_mutex ) ;
if ( ! fgroup ) {
return FTDM_FAIL ;
}
* group = fgroup ;
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_group_find_by_name ( const char * name , ftdm_group_t * * group )
{
ftdm_status_t status = FTDM_FAIL ;
* group = NULL ;
ftdm_mutex_lock ( globals . group_mutex ) ;
if ( ! ftdm_strlen_zero ( name ) ) {
if ( ( * group = hashtable_search ( globals . group_hash , ( void * ) name ) ) ) {
status = FTDM_SUCCESS ;
}
}
ftdm_mutex_unlock ( globals . group_mutex ) ;
return status ;
}
static void ftdm_group_add ( ftdm_group_t * group )
{
ftdm_group_t * grp ;
ftdm_mutex_lock ( globals . group_mutex ) ;
for ( grp = globals . groups ; grp & & grp - > next ; grp = grp - > next ) ;
if ( grp ) {
grp - > next = group ;
} else {
globals . groups = group ;
}
hashtable_insert ( globals . group_hash , ( void * ) group - > name , group , HASHTABLE_FLAG_NONE ) ;
ftdm_mutex_unlock ( globals . group_mutex ) ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_group_create ( ftdm_group_t * * group , const char * name )
{
ftdm_group_t * new_group = NULL ;
ftdm_status_t status = FTDM_FAIL ;
ftdm_mutex_lock ( globals . mutex ) ;
if ( globals . group_index < FTDM_MAX_GROUPS_INTERFACE ) {
new_group = ftdm_calloc ( 1 , sizeof ( * new_group ) ) ;
ftdm_assert ( new_group ! = NULL , " Failed to create new ftdm group, expect a crash \n " ) ;
status = ftdm_mutex_create ( & new_group - > mutex ) ;
ftdm_assert ( status = = FTDM_SUCCESS , " Failed to create group mutex, expect a crash \n " ) ;
new_group - > group_id = + + globals . group_index ;
new_group - > name = ftdm_strdup ( name ) ;
ftdm_group_add ( new_group ) ;
* group = new_group ;
status = FTDM_SUCCESS ;
} else {
2010-01-29 19:06:21 +00:00
ftdm_log ( FTDM_LOG_ERROR , " Group %s was not added, we exceeded the max number of groups \n " , name ) ;
2010-01-15 19:22:49 +00:00
}
ftdm_mutex_unlock ( globals . mutex ) ;
return status ;
}
2014-07-13 00:34:04 -04:00
static void ftdm_group_destroy ( ftdm_group_t * * group )
{
ftdm_group_t * grp = NULL ;
ftdm_assert ( group ! = NULL , " Group must not be null \n " ) ;
grp = * group ;
ftdm_mutex_destroy ( & grp - > mutex ) ;
ftdm_safe_free ( grp - > name ) ;
ftdm_safe_free ( grp ) ;
* group = NULL ;
}
2010-08-31 18:13:56 -04:00
static ftdm_status_t ftdm_span_trigger_signal ( const ftdm_span_t * span , ftdm_sigmsg_t * sigmsg )
2010-02-09 22:01:15 +00:00
{
2012-07-27 21:31:24 -04:00
if ( ! span - > signal_cb ) {
return FTDM_FAIL ;
}
return span - > signal_cb ( sigmsg ) ;
2010-08-31 18:13:56 -04:00
}
static ftdm_status_t ftdm_span_queue_signal ( const ftdm_span_t * span , ftdm_sigmsg_t * sigmsg )
{
ftdm_sigmsg_t * new_sigmsg = NULL ;
new_sigmsg = ftdm_calloc ( 1 , sizeof ( * sigmsg ) ) ;
if ( ! new_sigmsg ) {
return FTDM_FAIL ;
}
memcpy ( new_sigmsg , sigmsg , sizeof ( * sigmsg ) ) ;
ftdm_queue_enqueue ( span - > pendingsignals , new_sigmsg ) ;
return FTDM_SUCCESS ;
}
2010-04-21 11:20:05 -04:00
2010-08-31 18:13:56 -04:00
FT_DECLARE ( ftdm_status_t ) ftdm_span_trigger_signals ( const ftdm_span_t * span )
{
ftdm_sigmsg_t * sigmsg = NULL ;
while ( ( sigmsg = ftdm_queue_dequeue ( span - > pendingsignals ) ) ) {
ftdm_span_trigger_signal ( span , sigmsg ) ;
2011-02-25 17:53:02 -05:00
ftdm_sigmsg_free ( & sigmsg ) ;
2010-08-31 18:13:56 -04:00
}
return FTDM_SUCCESS ;
}
2010-09-21 07:19:56 -04:00
static void execute_safety_hangup ( void * data )
{
ftdm_channel_t * fchan = data ;
ftdm_channel_lock ( fchan ) ;
fchan - > hangup_timer = 0 ;
if ( fchan - > state = = FTDM_CHANNEL_STATE_TERMINATING ) {
2011-12-18 23:02:59 -05:00
ftdm_log_chan ( fchan , FTDM_LOG_WARNING , " Forcing hangup since the user did not confirmed our hangup after %dms \n " , FORCE_HANGUP_TIMER ) ;
2015-06-29 16:59:47 -04:00
_ftdm_channel_call_hangup_nl ( __FILE__ , __FTDM_FUNC__ , __LINE__ , fchan , NULL ) ;
2010-09-21 07:19:56 -04:00
} else {
ftdm_log_chan ( fchan , FTDM_LOG_CRIT , " Not performing safety hangup, channel state is %s \n " , ftdm_channel_state2str ( fchan - > state ) ) ;
}
ftdm_channel_unlock ( fchan ) ;
}
2010-08-31 18:13:56 -04:00
FT_DECLARE ( ftdm_status_t ) ftdm_span_send_signal ( ftdm_span_t * span , ftdm_sigmsg_t * sigmsg )
{
2011-07-28 08:04:07 -04:00
ftdm_channel_t * fchan = NULL ;
2013-07-03 02:07:05 -04:00
ftdm_status_t status = FTDM_SUCCESS ;
2010-04-27 17:21:57 -04:00
if ( sigmsg - > channel ) {
2011-07-28 08:04:07 -04:00
fchan = sigmsg - > channel ;
ftdm_channel_lock ( fchan ) ;
2010-04-27 17:21:57 -04:00
}
2010-11-30 13:17:48 -05:00
2010-04-21 11:20:05 -04:00
/* some core things to do on special events */
switch ( sigmsg - > event_id ) {
case FTDM_SIGEVENT_SIGSTATUS_CHANGED :
2010-08-31 19:05:37 -04:00
{
2010-12-19 21:09:50 +01:00
if ( sigmsg - > ev_data . sigstatus . status = = FTDM_SIG_STATE_UP ) {
2011-07-28 08:04:07 -04:00
ftdm_set_flag ( fchan , FTDM_CHANNEL_SIG_UP ) ;
ftdm_clear_flag ( fchan , FTDM_CHANNEL_SUSPENDED ) ;
2010-08-31 19:05:37 -04:00
} else {
2011-07-28 08:04:07 -04:00
ftdm_clear_flag ( fchan , FTDM_CHANNEL_SIG_UP ) ;
2011-01-17 15:42:36 -05:00
if ( sigmsg - > ev_data . sigstatus . status = = FTDM_SIG_STATE_SUSPENDED ) {
2011-07-28 08:04:07 -04:00
ftdm_set_flag ( fchan , FTDM_CHANNEL_SUSPENDED ) ;
2011-01-17 15:42:36 -05:00
} else {
2011-07-28 08:04:07 -04:00
ftdm_clear_flag ( fchan , FTDM_CHANNEL_SUSPENDED ) ;
2011-01-17 15:42:36 -05:00
}
2010-08-31 19:05:37 -04:00
}
2010-02-09 22:01:15 +00:00
}
2010-04-21 11:20:05 -04:00
break ;
case FTDM_SIGEVENT_START :
2010-09-28 13:55:46 -04:00
{
2012-10-11 00:49:33 -05:00
ftdm_assert ( ! ftdm_test_flag ( fchan , FTDM_CHANNEL_CALL_STARTED ) , " Started call twice! \n " ) ;
2011-01-07 16:00:06 -05:00
2011-07-28 08:04:07 -04:00
if ( ftdm_test_flag ( fchan , FTDM_CHANNEL_OUTBOUND ) ) {
ftdm_log_chan_msg ( fchan , FTDM_LOG_WARNING , " Inbound call taking over outbound channel \n " ) ;
ftdm_clear_flag ( fchan , FTDM_CHANNEL_OUTBOUND ) ;
2011-01-07 16:00:06 -05:00
}
2011-07-28 08:04:07 -04:00
ftdm_set_flag ( fchan , FTDM_CHANNEL_CALL_STARTED ) ;
ftdm_call_set_call_id ( fchan , & fchan - > caller_data ) ;
2010-09-28 13:55:46 -04:00
/* when cleaning up the public API I added this because mod_freetdm.c on_fxs_signal was
2011-05-10 23:35:20 -04:00
* doing it during SIGEVENT_START , but now that flags are private they can ' t , wonder if
* is needed at all ? */
2010-09-28 13:55:46 -04:00
ftdm_clear_flag ( sigmsg - > channel , FTDM_CHANNEL_HOLD ) ;
2011-05-17 20:02:18 -04:00
if ( sigmsg - > channel - > caller_data . bearer_capability = = FTDM_BEARER_CAP_UNRESTRICTED ) {
2011-05-10 23:35:20 -04:00
ftdm_set_flag ( sigmsg - > channel , FTDM_CHANNEL_DIGITAL_MEDIA ) ;
}
2010-09-28 13:55:46 -04:00
}
2010-04-21 11:20:05 -04:00
break ;
2011-01-17 19:15:02 -05:00
case FTDM_SIGEVENT_PROGRESS_MEDIA :
{
2011-01-18 11:28:37 -05:00
/* test signaling module compliance */
2011-07-28 08:04:07 -04:00
if ( fchan - > state ! = FTDM_CHANNEL_STATE_PROGRESS_MEDIA ) {
ftdm_log_chan ( fchan , FTDM_LOG_WARNING , " FTDM_SIGEVENT_PROGRESS_MEDIA sent in state %s \n " , ftdm_channel_state2str ( fchan - > state ) ) ;
2011-01-18 11:28:37 -05:00
}
2011-01-17 19:15:02 -05:00
}
break ;
2011-01-18 11:28:37 -05:00
case FTDM_SIGEVENT_UP :
{
/* test signaling module compliance */
2011-07-28 08:04:07 -04:00
if ( fchan - > state ! = FTDM_CHANNEL_STATE_UP ) {
ftdm_log_chan ( fchan , FTDM_LOG_WARNING , " FTDM_SIGEVENT_UP sent in state %s \n " , ftdm_channel_state2str ( fchan - > state ) ) ;
2011-01-18 11:28:37 -05:00
}
2010-07-29 13:15:29 -04:00
}
2011-01-18 11:28:37 -05:00
break ;
case FTDM_SIGEVENT_STOP :
{
/* TODO: we could test for compliance here and check the state is FTDM_CHANNEL_STATE_TERMINATING
* but several modules need to be updated first */
/* if the call was never started, do not send SIGEVENT_STOP
this happens for FXS devices in ftmod_analog which blindly send SIGEVENT_STOP , we should fix it there . . . */
2011-07-28 08:04:07 -04:00
if ( ! ftdm_test_flag ( fchan , FTDM_CHANNEL_CALL_STARTED ) ) {
ftdm_log_chan_msg ( fchan , FTDM_LOG_DEBUG , " Ignoring SIGEVENT_STOP since user never knew about a call in this channel \n " ) ;
2011-01-18 11:28:37 -05:00
goto done ;
}
2011-07-28 08:04:07 -04:00
if ( ftdm_test_flag ( fchan , FTDM_CHANNEL_USER_HANGUP ) ) {
ftdm_log_chan_msg ( fchan , FTDM_LOG_DEBUG , " Ignoring SIGEVENT_STOP since user already requested hangup \n " ) ;
2011-01-18 11:28:37 -05:00
goto done ;
}
2011-07-28 08:04:07 -04:00
if ( fchan - > state = = FTDM_CHANNEL_STATE_TERMINATING ) {
ftdm_log_chan_msg ( fchan , FTDM_LOG_DEBUG , " Scheduling safety hangup timer \n " ) ;
2011-01-18 11:28:37 -05:00
/* if the user does not move us to hangup in 2 seconds, we will do it ourselves */
2011-07-28 08:04:07 -04:00
ftdm_sched_timer ( globals . timingsched , " safety-hangup " , FORCE_HANGUP_TIMER , execute_safety_hangup , fchan , & fchan - > hangup_timer ) ;
2011-01-18 11:28:37 -05:00
}
2010-09-21 07:19:56 -04:00
}
2010-07-29 13:15:29 -04:00
break ;
2010-04-21 11:20:05 -04:00
default :
break ;
2010-04-27 17:21:57 -04:00
}
2010-12-10 19:14:08 -05:00
2011-09-08 12:50:34 -04:00
if ( fchan ) {
/* set members of the sigmsg that must be present for all events */
sigmsg - > chan_id = fchan - > chan_id ;
sigmsg - > span_id = fchan - > span_id ;
sigmsg - > call_id = fchan - > caller_data . call_id ;
sigmsg - > call_priv = fchan - > caller_data . priv ;
}
2010-08-31 18:13:56 -04:00
/* if the signaling module uses a queue for signaling notifications, then enqueue it */
if ( ftdm_test_flag ( span , FTDM_SPAN_USE_SIGNALS_QUEUE ) ) {
ftdm_span_queue_signal ( span , sigmsg ) ;
} else {
2013-07-03 02:07:05 -04:00
status = ftdm_span_trigger_signal ( span , sigmsg ) ;
2010-02-09 22:01:15 +00:00
}
2010-07-29 13:15:29 -04:00
done :
2010-12-09 13:20:05 -05:00
2011-07-28 08:04:07 -04:00
if ( fchan ) {
ftdm_channel_unlock ( fchan ) ;
2010-04-27 17:21:57 -04:00
}
2010-04-21 11:20:05 -04:00
2013-07-03 02:07:05 -04:00
return status ;
2010-02-09 22:01:15 +00:00
}
2010-04-05 17:49:43 -04:00
static void * ftdm_cpu_monitor_run ( ftdm_thread_t * me , void * obj )
{
cpu_monitor_t * monitor = ( cpu_monitor_t * ) obj ;
struct ftdm_cpu_monitor_stats * cpu_stats = ftdm_new_cpu_monitor ( ) ;
2011-12-01 12:13:12 -05:00
ftdm_log ( FTDM_LOG_DEBUG , " CPU monitor thread is now running \n " ) ;
2010-04-05 17:49:43 -04:00
if ( ! cpu_stats ) {
2011-12-01 12:13:12 -05:00
goto done ;
2010-04-05 17:49:43 -04:00
}
monitor - > running = 1 ;
2011-12-01 12:13:12 -05:00
while ( ftdm_running ( ) ) {
double idle_time = 0.0 ;
int cpu_usage = 0 ;
if ( ftdm_cpu_get_system_idle_time ( cpu_stats , & idle_time ) ) {
2010-04-05 17:49:43 -04:00
break ;
}
2011-12-01 12:13:12 -05:00
cpu_usage = ( int ) ( 100 - idle_time ) ;
2010-04-05 17:49:43 -04:00
if ( monitor - > alarm ) {
2011-12-01 12:13:12 -05:00
if ( cpu_usage < = monitor - > clear_alarm_threshold ) {
ftdm_log ( FTDM_LOG_DEBUG , " CPU alarm is now OFF (cpu usage: %d) \n " , cpu_usage ) ;
2010-04-05 17:49:43 -04:00
monitor - > alarm = 0 ;
2011-12-01 12:13:12 -05:00
} else if ( monitor - > alarm_action_flags & FTDM_CPU_ALARM_ACTION_WARN ) {
ftdm_log ( FTDM_LOG_WARNING , " CPU alarm is still ON (cpu usage: %d) \n " , cpu_usage ) ;
2010-04-05 17:49:43 -04:00
}
} else {
2011-12-01 12:13:12 -05:00
if ( cpu_usage > = monitor - > set_alarm_threshold ) {
ftdm_log ( FTDM_LOG_WARNING , " CPU alarm is now ON (cpu usage: %d) \n " , cpu_usage ) ;
2010-04-05 17:49:43 -04:00
monitor - > alarm = 1 ;
}
}
ftdm_interrupt_wait ( monitor - > interrupt , monitor - > interval ) ;
}
ftdm_delete_cpu_monitor ( cpu_stats ) ;
monitor - > running = 0 ;
2011-12-01 12:13:12 -05:00
done :
2013-05-10 14:05:07 +02:00
ftdm_unused_arg ( me ) ;
2011-12-01 12:13:12 -05:00
ftdm_log ( FTDM_LOG_DEBUG , " CPU monitor thread is now terminating \n " ) ;
2010-04-05 17:49:43 -04:00
return NULL ;
}
2010-04-05 18:28:13 -04:00
static ftdm_status_t ftdm_cpu_monitor_start ( void )
2010-04-05 17:49:43 -04:00
{
2011-12-25 20:49:10 -05:00
if ( ftdm_interrupt_create ( & globals . cpu_monitor . interrupt , FTDM_INVALID_SOCKET , FTDM_NO_FLAGS ) ! = FTDM_SUCCESS ) {
2010-04-05 17:49:43 -04:00
ftdm_log ( FTDM_LOG_CRIT , " Failed to create CPU monitor interrupt \n " ) ;
return FTDM_FAIL ;
}
2010-04-05 18:28:13 -04:00
if ( ftdm_thread_create_detached ( ftdm_cpu_monitor_run , & globals . cpu_monitor ) ! = FTDM_SUCCESS ) {
2010-04-05 17:49:43 -04:00
ftdm_log ( FTDM_LOG_CRIT , " Failed to create cpu monitor thread!! \n " ) ;
return FTDM_FAIL ;
}
return FTDM_SUCCESS ;
}
2010-04-05 18:28:13 -04:00
static void ftdm_cpu_monitor_stop ( void )
2010-04-05 17:49:43 -04:00
{
2010-04-05 18:28:13 -04:00
if ( ! globals . cpu_monitor . interrupt ) {
return ;
}
if ( ! globals . cpu_monitor . running ) {
return ;
}
if ( ftdm_interrupt_signal ( globals . cpu_monitor . interrupt ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_CRIT , " Failed to interrupt the CPU monitor \n " ) ;
return ;
}
while ( globals . cpu_monitor . running ) {
2010-04-05 17:49:43 -04:00
ftdm_sleep ( 10 ) ;
}
2010-04-05 18:28:13 -04:00
ftdm_interrupt_destroy ( & globals . cpu_monitor . interrupt ) ;
2010-04-05 17:49:43 -04:00
}
2010-01-15 19:22:49 +00:00
FT_DECLARE ( ftdm_status_t ) ftdm_global_init ( void )
{
memset ( & globals , 0 , sizeof ( globals ) ) ;
time_init ( ) ;
ftdm_thread_override_default_stacksize ( FTDM_THREAD_STACKSIZE ) ;
globals . interface_hash = create_hashtable ( 16 , ftdm_hash_hashfromstring , ftdm_hash_equalkeys ) ;
globals . module_hash = create_hashtable ( 16 , ftdm_hash_hashfromstring , ftdm_hash_equalkeys ) ;
globals . span_hash = create_hashtable ( 16 , ftdm_hash_hashfromstring , ftdm_hash_equalkeys ) ;
globals . group_hash = create_hashtable ( 16 , ftdm_hash_hashfromstring , ftdm_hash_equalkeys ) ;
ftdm_mutex_create ( & globals . mutex ) ;
ftdm_mutex_create ( & globals . span_mutex ) ;
ftdm_mutex_create ( & globals . group_mutex ) ;
2010-12-10 19:14:08 -05:00
ftdm_mutex_create ( & globals . call_id_mutex ) ;
2010-05-27 15:16:03 -04:00
ftdm_sched_global_init ( ) ;
2011-03-03 10:57:03 -05:00
globals . running = 1 ;
2010-09-21 07:19:56 -04:00
if ( ftdm_sched_create ( & globals . timingsched , " freetdm-master " ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_CRIT , " Failed to create master timing schedule context \n " ) ;
2011-03-03 10:57:03 -05:00
goto global_init_fail ;
2010-09-21 07:19:56 -04:00
}
if ( ftdm_sched_free_run ( globals . timingsched ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_CRIT , " Failed to run master timing schedule context \n " ) ;
2011-03-03 10:57:03 -05:00
goto global_init_fail ;
2010-09-21 07:19:56 -04:00
}
2011-03-03 10:57:03 -05:00
2010-01-15 19:22:49 +00:00
return FTDM_SUCCESS ;
2011-03-03 10:57:03 -05:00
global_init_fail :
globals . running = 0 ;
ftdm_mutex_destroy ( & globals . mutex ) ;
ftdm_mutex_destroy ( & globals . span_mutex ) ;
ftdm_mutex_destroy ( & globals . group_mutex ) ;
ftdm_mutex_destroy ( & globals . call_id_mutex ) ;
hashtable_destroy ( globals . interface_hash ) ;
hashtable_destroy ( globals . module_hash ) ;
hashtable_destroy ( globals . span_hash ) ;
hashtable_destroy ( globals . group_hash ) ;
return FTDM_FAIL ;
2010-01-15 19:22:49 +00:00
}
FT_DECLARE ( ftdm_status_t ) ftdm_global_configuration ( void )
{
2010-04-05 17:49:43 -04:00
int modcount = 0 ;
if ( ! globals . running ) {
return FTDM_FAIL ;
}
modcount = ftdm_load_modules ( ) ;
2010-01-15 19:22:49 +00:00
ftdm_log ( FTDM_LOG_NOTICE , " Modules configured: %d \n " , modcount ) ;
2010-09-23 13:58:20 -04:00
globals . cpu_monitor . enabled = 0 ;
2010-04-05 17:49:43 -04:00
globals . cpu_monitor . interval = 1000 ;
2010-09-23 13:58:20 -04:00
globals . cpu_monitor . alarm_action_flags = 0 ;
2011-12-16 10:06:57 -05:00
globals . cpu_monitor . set_alarm_threshold = 92 ;
globals . cpu_monitor . clear_alarm_threshold = 82 ;
2010-04-05 17:49:43 -04:00
2010-01-15 19:22:49 +00:00
if ( load_config ( ) ! = FTDM_SUCCESS ) {
globals . running = 0 ;
2010-01-15 22:17:26 +00:00
ftdm_log ( FTDM_LOG_ERROR , " FreeTDM global configuration failed! \n " ) ;
2010-01-15 19:22:49 +00:00
return FTDM_FAIL ;
}
2010-04-05 17:49:43 -04:00
2010-09-23 13:58:20 -04:00
if ( globals . cpu_monitor . enabled ) {
2011-12-01 12:13:12 -05:00
ftdm_log ( FTDM_LOG_INFO , " CPU Monitor is running interval:%d set-thres:%d clear-thres:%d \n " ,
2010-09-23 13:58:20 -04:00
globals . cpu_monitor . interval ,
globals . cpu_monitor . set_alarm_threshold ,
2011-12-01 12:13:12 -05:00
globals . cpu_monitor . clear_alarm_threshold ) ;
2010-09-23 13:58:20 -04:00
2010-04-05 18:28:13 -04:00
if ( ftdm_cpu_monitor_start ( ) ! = FTDM_SUCCESS ) {
2010-04-05 17:49:43 -04:00
return FTDM_FAIL ;
}
}
2010-01-15 19:22:49 +00:00
return FTDM_SUCCESS ;
}
FT_DECLARE ( uint32_t ) ftdm_running ( void )
{
return globals . running ;
}
2014-07-13 00:34:04 -04:00
static void destroy_span ( ftdm_span_t * span )
{
if ( ftdm_test_flag ( span , FTDM_SPAN_CONFIGURED ) ) {
ftdm_span_destroy ( span ) ;
}
hashtable_remove ( globals . span_hash , ( void * ) span - > name ) ;
ftdm_safe_free ( span - > dtmf_hangup ) ;
ftdm_safe_free ( span - > type ) ;
ftdm_safe_free ( span - > name ) ;
ftdm_safe_free ( span ) ;
}
static void force_stop_span ( ftdm_span_t * span )
{
/* This is a forced stop */
ftdm_clear_flag ( span , FTDM_SPAN_NON_STOPPABLE ) ;
ftdm_span_stop ( span ) ;
}
static void span_for_each ( void ( * func ) ( ftdm_span_t * span ) )
{
ftdm_span_t * sp = NULL , * next = NULL ;
for ( sp = globals . spans ; sp ; sp = next ) {
next = sp - > next ;
func ( sp ) ;
}
}
2010-01-15 19:22:49 +00:00
FT_DECLARE ( ftdm_status_t ) ftdm_global_destroy ( void )
{
2014-07-13 00:34:04 -04:00
ftdm_group_t * grp = NULL , * next_grp = NULL ;
2010-01-15 19:22:49 +00:00
time_end ( ) ;
2010-09-28 11:05:54 -04:00
/* many freetdm event loops rely on this variable to decide when to stop, do this first */
2010-01-15 19:22:49 +00:00
globals . running = 0 ;
2010-03-12 18:27:24 +00:00
2010-09-28 11:05:54 -04:00
/* stop the scheduling thread */
ftdm_free_sched_stop ( ) ;
2010-09-21 07:19:56 -04:00
2010-09-28 11:05:54 -04:00
/* stop the cpu monitor thread */
2010-04-05 18:28:13 -04:00
ftdm_cpu_monitor_stop ( ) ;
2010-04-05 17:49:43 -04:00
2010-09-28 11:05:54 -04:00
/* now destroy channels and spans */
2010-03-12 18:27:24 +00:00
globals . span_index = 0 ;
2010-01-15 19:22:49 +00:00
ftdm_span_close_all ( ) ;
2010-03-12 18:27:24 +00:00
2014-07-13 00:34:04 -04:00
/* Stop and destroy alls pans */
2010-01-15 19:22:49 +00:00
ftdm_mutex_lock ( globals . span_mutex ) ;
2014-07-13 00:34:04 -04:00
span_for_each ( force_stop_span ) ;
span_for_each ( destroy_span ) ;
2010-01-15 19:22:49 +00:00
globals . spans = NULL ;
2014-07-13 00:34:04 -04:00
2010-01-15 19:22:49 +00:00
ftdm_mutex_unlock ( globals . span_mutex ) ;
2010-09-28 11:05:54 -04:00
/* destroy signaling and io modules */
2010-03-15 14:57:00 +00:00
ftdm_unload_modules ( ) ;
2014-07-13 00:34:04 -04:00
/* Destroy hunting groups */
ftdm_mutex_lock ( globals . group_mutex ) ;
grp = globals . groups ;
while ( grp ) {
next_grp = grp - > next ;
ftdm_group_destroy ( & grp ) ;
grp = next_grp ;
}
ftdm_mutex_unlock ( globals . group_mutex ) ;
2012-04-02 15:00:35 -05:00
2010-09-28 11:05:54 -04:00
/* finally destroy the globals */
2010-01-15 19:22:49 +00:00
ftdm_mutex_lock ( globals . mutex ) ;
2014-07-13 00:34:04 -04:00
2010-09-28 11:05:54 -04:00
ftdm_sched_destroy ( & globals . timingsched ) ;
2014-07-13 00:34:04 -04:00
2010-01-15 19:22:49 +00:00
hashtable_destroy ( globals . interface_hash ) ;
2010-09-08 19:41:34 -04:00
hashtable_destroy ( globals . module_hash ) ;
2010-01-15 19:22:49 +00:00
hashtable_destroy ( globals . span_hash ) ;
2010-09-08 19:41:34 -04:00
hashtable_destroy ( globals . group_hash ) ;
2014-07-13 00:34:04 -04:00
2010-01-15 19:22:49 +00:00
ftdm_mutex_destroy ( & globals . span_mutex ) ;
2010-09-08 19:41:34 -04:00
ftdm_mutex_destroy ( & globals . group_mutex ) ;
2010-12-10 19:14:08 -05:00
ftdm_mutex_destroy ( & globals . call_id_mutex ) ;
2010-01-15 19:22:49 +00:00
2014-07-13 00:34:04 -04:00
ftdm_mutex_unlock ( globals . mutex ) ;
ftdm_mutex_destroy ( & globals . mutex ) ;
ftdm_sched_global_destroy ( ) ;
ftdm_global_set_logger ( NULL ) ;
2010-01-15 19:22:49 +00:00
memset ( & globals , 0 , sizeof ( globals ) ) ;
return FTDM_SUCCESS ;
}
FT_DECLARE ( uint32_t ) ftdm_separate_string ( char * buf , char delim , char * * array , int arraylen )
{
int argc ;
char * ptr ;
int quot = 0 ;
char qc = ' \' ' ;
int x ;
if ( ! buf | | ! array | | ! arraylen ) {
return 0 ;
}
memset ( array , 0 , arraylen * sizeof ( * array ) ) ;
ptr = buf ;
2011-06-23 14:09:06 -04:00
/* we swallow separators that are contiguous */
while ( * ptr = = delim ) ptr + + ;
2010-01-15 19:22:49 +00:00
for ( argc = 0 ; * ptr & & ( argc < arraylen - 1 ) ; argc + + ) {
array [ argc ] = ptr ;
for ( ; * ptr ; ptr + + ) {
if ( * ptr = = qc ) {
if ( quot ) {
quot - - ;
} else {
quot + + ;
}
} else if ( ( * ptr = = delim ) & & ! quot ) {
* ptr + + = ' \0 ' ;
2011-06-23 14:09:06 -04:00
/* we swallow separators that are contiguous */
while ( * ptr = = delim ) ptr + + ;
2010-01-15 19:22:49 +00:00
break ;
}
}
}
if ( * ptr ) {
array [ argc + + ] = ptr ;
}
2011-06-23 14:09:06 -04:00
/* strip quotes */
2010-01-15 19:22:49 +00:00
for ( x = 0 ; x < argc ; x + + ) {
2011-06-23 14:09:06 -04:00
char * p = array [ x ] ;
2010-01-15 19:22:49 +00:00
while ( ( p = strchr ( array [ x ] , qc ) ) ) {
memmove ( p , p + 1 , strlen ( p ) ) ;
p + + ;
}
}
return argc ;
}
FT_DECLARE ( void ) ftdm_bitstream_init ( ftdm_bitstream_t * bsp , uint8_t * data , uint32_t datalen , ftdm_endian_t endian , uint8_t ss )
{
memset ( bsp , 0 , sizeof ( * bsp ) ) ;
bsp - > data = data ;
bsp - > datalen = datalen ;
bsp - > endian = endian ;
bsp - > ss = ss ;
if ( endian < 0 ) {
bsp - > top = bsp - > bit_index = 7 ;
bsp - > bot = 0 ;
} else {
bsp - > top = bsp - > bit_index = 0 ;
bsp - > bot = 7 ;
}
}
FT_DECLARE ( int8_t ) ftdm_bitstream_get_bit ( ftdm_bitstream_t * bsp )
{
int8_t bit = - 1 ;
if ( bsp - > byte_index > = bsp - > datalen ) {
goto done ;
}
if ( bsp - > ss ) {
if ( ! bsp - > ssv ) {
bsp - > ssv = 1 ;
return 0 ;
} else if ( bsp - > ssv = = 2 ) {
bsp - > byte_index + + ;
bsp - > ssv = 0 ;
return 1 ;
}
}
bit = ( bsp - > data [ bsp - > byte_index ] > > ( bsp - > bit_index ) ) & 1 ;
if ( bsp - > bit_index = = bsp - > bot ) {
bsp - > bit_index = bsp - > top ;
if ( bsp - > ss ) {
bsp - > ssv = 2 ;
goto done ;
}
if ( + + bsp - > byte_index > bsp - > datalen ) {
bit = - 1 ;
goto done ;
}
} else {
bsp - > bit_index = bsp - > bit_index + bsp - > endian ;
}
done :
return bit ;
}
FT_DECLARE ( void ) print_hex_bytes ( uint8_t * data , ftdm_size_t dlen , char * buf , ftdm_size_t blen )
{
char * bp = buf ;
uint8_t * byte = data ;
uint32_t i , j = 0 ;
if ( blen < ( dlen * 3 ) + 2 ) {
return ;
}
* bp + + = ' [ ' ;
j + + ;
for ( i = 0 ; i < dlen ; i + + ) {
snprintf ( bp , blen - j , " %02x " , * byte + + ) ;
bp + = 3 ;
j + = 3 ;
}
* - - bp = ' ] ' ;
}
FT_DECLARE ( void ) print_bits ( uint8_t * b , int bl , char * buf , int blen , ftdm_endian_t e , uint8_t ss )
{
ftdm_bitstream_t bs ;
int j = 0 , c = 0 ;
int8_t bit ;
uint32_t last ;
if ( blen < ( bl * 10 ) + 2 ) {
return ;
}
ftdm_bitstream_init ( & bs , b , bl , e , ss ) ;
last = bs . byte_index ;
while ( ( bit = ftdm_bitstream_get_bit ( & bs ) ) > - 1 ) {
buf [ j + + ] = bit ? ' 1 ' : ' 0 ' ;
if ( bs . byte_index ! = last ) {
buf [ j + + ] = ' ' ;
last = bs . byte_index ;
if ( + + c = = 8 ) {
buf [ j + + ] = ' \n ' ;
c = 0 ;
}
}
}
}
FT_DECLARE_NONSTD ( ftdm_status_t ) ftdm_console_stream_raw_write ( ftdm_stream_handle_t * handle , uint8_t * data , ftdm_size_t datalen )
{
ftdm_size_t need = handle - > data_len + datalen ;
if ( need > = handle - > data_size ) {
void * new_data ;
need + = handle - > alloc_chunk ;
if ( ! ( new_data = realloc ( handle - > data , need ) ) ) {
return FTDM_MEMERR ;
}
handle - > data = new_data ;
handle - > data_size = need ;
}
memcpy ( ( uint8_t * ) ( handle - > data ) + handle - > data_len , data , datalen ) ;
handle - > data_len + = datalen ;
handle - > end = ( uint8_t * ) ( handle - > data ) + handle - > data_len ;
* ( uint8_t * ) handle - > end = ' \0 ' ;
return FTDM_SUCCESS ;
}
FT_DECLARE ( int ) ftdm_vasprintf ( char * * ret , const char * fmt , va_list ap ) /* code from switch_apr.c */
{
# ifdef HAVE_VASPRINTF
return vasprintf ( ret , fmt , ap ) ;
# else
char * buf ;
int len ;
size_t buflen ;
va_list ap2 ;
char * tmp = NULL ;
# ifdef _MSC_VER
# if _MSC_VER >= 1500
/* hack for incorrect assumption in msvc header files for code analysis */
__analysis_assume ( tmp ) ;
# endif
ap2 = ap ;
# else
va_copy ( ap2 , ap ) ;
# endif
len = vsnprintf ( tmp , 0 , fmt , ap2 ) ;
if ( len > 0 & & ( buf = ftdm_malloc ( ( buflen = ( size_t ) ( len + 1 ) ) ) ) ! = NULL ) {
len = vsnprintf ( buf , buflen , fmt , ap ) ;
* ret = buf ;
} else {
* ret = NULL ;
len = - 1 ;
}
va_end ( ap2 ) ;
return len ;
# endif
}
FT_DECLARE_NONSTD ( ftdm_status_t ) ftdm_console_stream_write ( ftdm_stream_handle_t * handle , const char * fmt , . . . )
{
va_list ap ;
char * buf = handle - > data ;
char * end = handle - > end ;
int ret = 0 ;
char * data = NULL ;
if ( handle - > data_len > = handle - > data_size ) {
return FTDM_FAIL ;
}
va_start ( ap , fmt ) ;
ret = ftdm_vasprintf ( & data , fmt , ap ) ;
va_end ( ap ) ;
if ( data ) {
ftdm_size_t remaining = handle - > data_size - handle - > data_len ;
ftdm_size_t need = strlen ( data ) + 1 ;
if ( ( remaining < need ) & & handle - > alloc_len ) {
ftdm_size_t new_len ;
void * new_data ;
new_len = handle - > data_size + need + handle - > alloc_chunk ;
2010-04-13 15:17:32 -04:00
if ( ( new_data = ftdm_realloc ( handle - > data , new_len ) ) ) {
2010-01-15 19:22:49 +00:00
handle - > data_size = handle - > alloc_len = new_len ;
handle - > data = new_data ;
buf = handle - > data ;
remaining = handle - > data_size - handle - > data_len ;
handle - > end = ( uint8_t * ) ( handle - > data ) + handle - > data_len ;
end = handle - > end ;
} else {
ftdm_log ( FTDM_LOG_CRIT , " Memory Error! \n " ) ;
ftdm_safe_free ( data ) ;
return FTDM_FAIL ;
}
}
if ( remaining < need ) {
ret = - 1 ;
} else {
ret = 0 ;
snprintf ( end , remaining , " %s " , data ) ;
handle - > data_len = strlen ( buf ) ;
handle - > end = ( uint8_t * ) ( handle - > data ) + handle - > data_len ;
}
ftdm_safe_free ( data ) ;
}
return ret ? FTDM_FAIL : FTDM_SUCCESS ;
}
FT_DECLARE ( char * ) ftdm_strdup ( const char * str )
{
ftdm_size_t len = strlen ( str ) + 1 ;
void * new = ftdm_malloc ( len ) ;
if ( ! new ) {
return NULL ;
}
return ( char * ) memcpy ( new , str , len ) ;
}
FT_DECLARE ( char * ) ftdm_strndup ( const char * str , ftdm_size_t inlen )
{
char * new = NULL ;
ftdm_size_t len = strlen ( str ) + 1 ;
if ( len > ( inlen + 1 ) ) {
len = inlen + 1 ;
}
new = ( char * ) ftdm_malloc ( len ) ;
if ( ! new ) {
return NULL ;
}
memcpy ( new , str , len - 1 ) ;
new [ len - 1 ] = 0 ;
return new ;
}
2010-12-21 19:04:41 -05:00
static ftdm_status_t ftdm_call_set_call_id ( ftdm_channel_t * fchan , ftdm_caller_data_t * caller_data )
2010-12-10 19:14:08 -05:00
{
uint32_t current_call_id ;
2010-12-21 19:04:41 -05:00
ftdm_assert_return ( ! caller_data - > call_id , FTDM_FAIL , " Overwriting non-cleared call-id \n " ) ;
2010-12-10 19:14:08 -05:00
ftdm_mutex_lock ( globals . call_id_mutex ) ;
2010-12-21 19:04:41 -05:00
2010-12-10 19:14:08 -05:00
current_call_id = globals . last_call_id ;
2010-12-21 19:04:41 -05:00
for ( current_call_id = globals . last_call_id + 1 ;
current_call_id ! = globals . last_call_id ;
current_call_id + + ) {
if ( current_call_id > MAX_CALLIDS ) {
2010-12-10 19:14:08 -05:00
current_call_id = 1 ;
}
2010-12-21 19:04:41 -05:00
if ( globals . call_ids [ current_call_id ] = = NULL ) {
break ;
2010-12-10 19:14:08 -05:00
}
2010-12-21 19:04:41 -05:00
}
ftdm_assert_return ( globals . call_ids [ current_call_id ] = = NULL , FTDM_FAIL , " We ran out of call ids \n " ) ;
2010-12-10 19:14:08 -05:00
globals . last_call_id = current_call_id ;
caller_data - > call_id = current_call_id ;
globals . call_ids [ current_call_id ] = caller_data ;
2010-12-21 19:04:41 -05:00
caller_data - > fchan = fchan ;
2010-12-10 19:14:08 -05:00
ftdm_mutex_unlock ( globals . call_id_mutex ) ;
return FTDM_SUCCESS ;
}
static ftdm_status_t ftdm_call_clear_call_id ( ftdm_caller_data_t * caller_data )
{
2010-12-20 14:06:54 -05:00
if ( caller_data - > call_id ) {
ftdm_assert_return ( ( caller_data - > call_id < = MAX_CALLIDS ) , FTDM_FAIL , " Cannot clear call with invalid call-id \n " ) ;
} else {
/* there might not be a call at all */
return FTDM_SUCCESS ;
}
2010-12-10 19:14:08 -05:00
ftdm_mutex_lock ( globals . call_id_mutex ) ;
if ( globals . call_ids [ caller_data - > call_id ] ) {
2010-12-20 14:06:54 -05:00
ftdm_log ( FTDM_LOG_DEBUG , " Cleared call with id %u \n " , caller_data - > call_id ) ;
2010-12-10 19:14:08 -05:00
globals . call_ids [ caller_data - > call_id ] = NULL ;
2010-12-21 19:04:41 -05:00
caller_data - > call_id = 0 ;
2010-12-10 19:14:08 -05:00
} else {
ftdm_log ( FTDM_LOG_CRIT , " call-id did not exist %u \n " , caller_data - > call_id ) ;
}
ftdm_mutex_unlock ( globals . call_id_mutex ) ;
2010-12-20 14:06:54 -05:00
2010-12-10 19:14:08 -05:00
return FTDM_SUCCESS ;
}
2011-02-25 09:58:15 -05:00
FT_DECLARE ( ftdm_status_t ) ftdm_sigmsg_get_raw_data ( ftdm_sigmsg_t * sigmsg , void * * data , ftdm_size_t * datalen )
2011-02-18 13:01:57 -05:00
{
if ( ! sigmsg | | ! sigmsg - > raw . len ) {
return FTDM_FAIL ;
}
* data = sigmsg - > raw . data ;
* datalen = sigmsg - > raw . len ;
return FTDM_SUCCESS ;
}
2011-02-25 09:58:15 -05:00
FT_DECLARE ( ftdm_status_t ) ftdm_sigmsg_get_raw_data_detached ( ftdm_sigmsg_t * sigmsg , void * * data , ftdm_size_t * datalen )
{
if ( ! sigmsg | | ! sigmsg - > raw . len ) {
return FTDM_FAIL ;
}
2011-03-09 16:55:33 -05:00
2011-02-25 09:58:15 -05:00
* data = sigmsg - > raw . data ;
2011-03-09 16:55:33 -05:00
* datalen = sigmsg - > raw . len ;
sigmsg - > raw . data = NULL ;
sigmsg - > raw . len = 0 ;
2011-02-25 09:58:15 -05:00
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_sigmsg_set_raw_data ( ftdm_sigmsg_t * sigmsg , void * data , ftdm_size_t datalen )
2011-02-18 13:01:57 -05:00
{
ftdm_assert_return ( sigmsg , FTDM_FAIL , " Trying to set raw data on a NULL event \n " ) ;
2011-02-25 09:58:15 -05:00
ftdm_assert_return ( ! sigmsg - > raw . len , FTDM_FAIL , " Overwriting existing raw data \n " ) ;
ftdm_assert_return ( datalen , FTDM_FAIL , " Data length not set \n " ) ;
2011-02-18 13:01:57 -05:00
2011-02-25 09:58:15 -05:00
sigmsg - > raw . data = data ;
2011-02-18 13:01:57 -05:00
sigmsg - > raw . len = datalen ;
2011-02-25 09:58:15 -05:00
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_usrmsg_get_raw_data ( ftdm_usrmsg_t * usrmsg , void * * data , ftdm_size_t * datalen )
{
if ( ! usrmsg | | ! usrmsg - > raw . len ) {
return FTDM_FAIL ;
}
* data = usrmsg - > raw . data ;
* datalen = usrmsg - > raw . len ;
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_usrmsg_set_raw_data ( ftdm_usrmsg_t * usrmsg , void * data , ftdm_size_t datalen )
{
ftdm_assert_return ( usrmsg , FTDM_FAIL , " Trying to set raw data on a NULL event \n " ) ;
ftdm_assert_return ( ! usrmsg - > raw . len , FTDM_FAIL , " Overwriting existing raw data \n " ) ;
ftdm_assert_return ( datalen , FTDM_FAIL , " Data length not set \n " ) ;
2011-02-18 13:01:57 -05:00
2011-02-25 09:58:15 -05:00
usrmsg - > raw . data = data ;
usrmsg - > raw . len = datalen ;
2011-02-18 13:01:57 -05:00
return FTDM_SUCCESS ;
}
2011-02-25 09:58:15 -05:00
FT_DECLARE ( ftdm_status_t ) ftdm_channel_save_usrmsg ( ftdm_channel_t * ftdmchan , ftdm_usrmsg_t * usrmsg )
2011-02-18 13:01:57 -05:00
{
2011-02-25 09:58:15 -05:00
ftdm_assert_return ( ! ftdmchan - > usrmsg , FTDM_FAIL , " Info from previous event was not cleared \n " ) ;
if ( usrmsg ) {
2011-02-18 13:01:57 -05:00
/* Copy sigmsg from user to internal copy so user can set new variables without race condition */
2011-02-25 09:58:15 -05:00
ftdmchan - > usrmsg = ftdm_calloc ( 1 , sizeof ( ftdm_usrmsg_t ) ) ;
memcpy ( ftdmchan - > usrmsg , usrmsg , sizeof ( ftdm_usrmsg_t ) ) ;
2011-02-18 13:01:57 -05:00
2011-02-25 09:58:15 -05:00
if ( usrmsg - > raw . data ) {
usrmsg - > raw . data = NULL ;
usrmsg - > raw . len = 0 ;
}
if ( usrmsg - > variables ) {
usrmsg - > variables = NULL ;
2011-02-18 13:01:57 -05:00
}
}
return FTDM_SUCCESS ;
}
2011-02-25 09:58:15 -05:00
FT_DECLARE ( ftdm_status_t ) ftdm_sigmsg_free ( ftdm_sigmsg_t * * sigmsg )
2011-02-18 13:01:57 -05:00
{
2011-02-25 09:58:15 -05:00
if ( ! * sigmsg ) {
2011-02-18 13:01:57 -05:00
return FTDM_SUCCESS ;
}
2011-02-25 09:58:15 -05:00
if ( ( * sigmsg ) - > variables ) {
hashtable_destroy ( ( * sigmsg ) - > variables ) ;
( * sigmsg ) - > variables = NULL ;
}
if ( ( * sigmsg ) - > raw . data ) {
ftdm_safe_free ( ( * sigmsg ) - > raw . data ) ;
( * sigmsg ) - > raw . data = NULL ;
( * sigmsg ) - > raw . len = 0 ;
}
ftdm_safe_free ( * sigmsg ) ;
return FTDM_SUCCESS ;
}
FT_DECLARE ( ftdm_status_t ) ftdm_usrmsg_free ( ftdm_usrmsg_t * * usrmsg )
{
if ( ! * usrmsg ) {
return FTDM_SUCCESS ;
}
if ( ( * usrmsg ) - > variables ) {
hashtable_destroy ( ( * usrmsg ) - > variables ) ;
( * usrmsg ) - > variables = NULL ;
2011-02-18 13:01:57 -05:00
}
2011-02-25 09:58:15 -05:00
if ( ( * usrmsg ) - > raw . data ) {
ftdm_safe_free ( ( * usrmsg ) - > raw . data ) ;
( * usrmsg ) - > raw . data = NULL ;
( * usrmsg ) - > raw . len = 0 ;
2011-02-18 13:01:57 -05:00
}
2011-02-25 09:58:15 -05:00
ftdm_safe_free ( * usrmsg ) ;
2011-02-18 13:01:57 -05:00
return FTDM_SUCCESS ;
}
2010-12-10 19:14:08 -05:00
2010-01-15 19:22:49 +00: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-01-15 19:22:49 +00:00
*/