2003-06-28 16:40:02 +00:00
/*
1999-12-04 21:35:07 +00:00
* Asterisk - - A telephony toolkit for Linux .
*
* Channel Management
*
1999-12-18 07:01:48 +00:00
* Copyright ( C ) 1999 , Mark Spencer
1999-12-04 21:35:07 +00:00
*
* Mark Spencer < markster @ linux - support . net >
*
* This program is free software , distributed under the terms of
* the GNU General Public License
*/
# include <stdio.h>
# include <stdlib.h>
# include <pthread.h>
# include <string.h>
# include <sys/time.h>
# include <signal.h>
# include <errno.h>
2000-01-02 20:59:00 +00:00
# include <unistd.h>
2002-06-21 01:40:13 +00:00
# include <math.h> /* For PI */
2004-04-25 20:42:45 +00:00
# include <sys/poll.h>
2003-02-05 21:18:09 +00:00
# include <asterisk/pbx.h>
2001-12-20 15:21:47 +00:00
# include <asterisk/frame.h>
1999-12-04 21:35:07 +00:00
# include <asterisk/sched.h>
# include <asterisk/options.h>
# include <asterisk/channel.h>
# include <asterisk/channel_pvt.h>
# include <asterisk/logger.h>
2004-04-26 23:22:34 +00:00
# include <asterisk/say.h>
1999-12-04 21:35:07 +00:00
# include <asterisk/file.h>
1999-12-18 07:01:48 +00:00
# include <asterisk/translate.h>
2002-09-10 20:48:20 +00:00
# include <asterisk/manager.h>
# include <asterisk/chanvars.h>
# include <asterisk/linkedlists.h>
2003-02-05 21:18:09 +00:00
# include <asterisk/indications.h>
2003-03-25 19:30:06 +00:00
# include <asterisk/monitor.h>
2003-09-12 16:51:35 +00:00
# include <asterisk/causes.h>
2004-05-06 21:04:22 +00:00
# include <asterisk/utils.h>
2003-05-12 04:23:55 +00:00
# ifdef ZAPTEL_OPTIMIZATIONS
# include <sys/ioctl.h>
2004-06-04 15:44:14 +00:00
# ifdef __linux__
2003-05-12 04:23:55 +00:00
# include <linux/zaptel.h>
2004-06-04 15:44:14 +00:00
# else
# include <zaptel.h>
# endif /* __linux__ */
2004-03-19 04:23:20 +00:00
# ifndef ZT_TIMERPING
2004-04-27 21:21:57 +00:00
# error "You need newer zaptel! Please cvs update zaptel"
2004-03-19 04:23:20 +00:00
# endif
2003-05-12 04:23:55 +00:00
# endif
2002-09-10 20:48:20 +00:00
2003-08-28 20:02:10 +00:00
/* uncomment if you have problems with 'monitoring' synchronized files */
#if 0
# define MONITOR_CONSTANT_DELAY
# define MONITOR_DELAY 150 * 8 /* 150 ms of MONITORING DELAY */
# endif
1999-12-04 21:35:07 +00:00
2002-06-21 01:40:13 +00:00
static int shutting_down = 0 ;
2003-05-30 04:41:18 +00:00
static int uniqueint = 0 ;
2000-01-02 20:59:00 +00:00
2001-05-07 00:43:32 +00:00
/* XXX Lock appropriately in more functions XXX */
2000-01-02 20:59:00 +00:00
1999-12-04 21:35:07 +00:00
struct chanlist {
char type [ 80 ] ;
char description [ 80 ] ;
int capabilities ;
struct ast_channel * ( * requester ) ( char * type , int format , void * data ) ;
2003-03-30 22:55:42 +00:00
int ( * devicestate ) ( void * data ) ;
1999-12-04 21:35:07 +00:00
struct chanlist * next ;
} * backends = NULL ;
1999-12-18 07:01:48 +00:00
struct ast_channel * channels = NULL ;
1999-12-04 21:35:07 +00:00
/* Protect the channel list (highly unlikely that two things would change
it at the same time , but still ! */
2003-08-13 15:25:16 +00:00
static ast_mutex_t chlock = AST_MUTEX_INITIALIZER ;
1999-12-04 21:35:07 +00:00
2001-12-20 15:21:47 +00:00
int ast_check_hangup ( struct ast_channel * chan )
{
time_t myt ;
/* if soft hangup flag, return true */
2002-09-10 20:48:20 +00:00
if ( chan - > _softhangup ) return 1 ;
/* if no private structure, return true */
if ( ! chan - > pvt - > pvt ) return 1 ;
2001-12-20 15:21:47 +00:00
/* if no hangup scheduled, just return here */
if ( ! chan - > whentohangup ) return 0 ;
time ( & myt ) ; /* get current time */
/* return, if not yet */
if ( chan - > whentohangup > myt ) return 0 ;
2002-09-10 20:48:20 +00:00
chan - > _softhangup | = AST_SOFTHANGUP_TIMEOUT ;
2001-12-20 15:21:47 +00:00
return 1 ;
}
2003-08-11 21:10:52 +00:00
static int ast_check_hangup_locked ( struct ast_channel * chan )
{
int res ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2003-08-11 21:10:52 +00:00
res = ast_check_hangup ( chan ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2003-08-11 21:10:52 +00:00
return res ;
}
2002-06-21 01:40:13 +00:00
void ast_begin_shutdown ( int hangup )
{
struct ast_channel * c ;
shutting_down = 1 ;
if ( hangup ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & chlock ) ;
2002-06-21 01:40:13 +00:00
c = channels ;
while ( c ) {
2002-09-10 20:48:20 +00:00
ast_softhangup ( c , AST_SOFTHANGUP_SHUTDOWN ) ;
2002-06-21 01:40:13 +00:00
c = c - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
2002-06-21 01:40:13 +00:00
}
}
int ast_active_channels ( void )
{
struct ast_channel * c ;
int cnt = 0 ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & chlock ) ;
2002-06-21 01:40:13 +00:00
c = channels ;
while ( c ) {
cnt + + ;
c = c - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
2002-06-21 01:40:13 +00:00
return cnt ;
}
void ast_cancel_shutdown ( void )
{
shutting_down = 0 ;
}
int ast_shutting_down ( void )
{
return shutting_down ;
}
2001-12-20 15:21:47 +00:00
void ast_channel_setwhentohangup ( struct ast_channel * chan , time_t offset )
{
time_t myt ;
time ( & myt ) ;
2004-04-27 21:21:57 +00:00
if ( offset )
2003-02-05 21:18:09 +00:00
chan - > whentohangup = myt + offset ;
2004-04-27 21:21:57 +00:00
else
chan - > whentohangup = 0 ;
2001-12-20 15:21:47 +00:00
return ;
}
1999-12-04 21:35:07 +00:00
int ast_channel_register ( char * type , char * description , int capabilities ,
struct ast_channel * ( * requester ) ( char * type , int format , void * data ) )
2003-03-30 22:55:42 +00:00
{
2004-04-27 21:21:57 +00:00
return ast_channel_register_ex ( type , description , capabilities , requester , NULL ) ;
2003-03-30 22:55:42 +00:00
}
int ast_channel_register_ex ( char * type , char * description , int capabilities ,
struct ast_channel * ( * requester ) ( char * type , int format , void * data ) ,
int ( * devicestate ) ( void * data ) )
1999-12-04 21:35:07 +00:00
{
struct chanlist * chan , * last = NULL ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & chlock ) ) {
1999-12-04 21:35:07 +00:00
ast_log ( LOG_WARNING , " Unable to lock channel list \n " ) ;
return - 1 ;
}
chan = backends ;
while ( chan ) {
if ( ! strcasecmp ( type , chan - > type ) ) {
ast_log ( LOG_WARNING , " Already have a handler for type '%s' \n " , type ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-04 21:35:07 +00:00
return - 1 ;
}
last = chan ;
chan = chan - > next ;
}
chan = malloc ( sizeof ( struct chanlist ) ) ;
if ( ! chan ) {
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-04 21:35:07 +00:00
return - 1 ;
}
2001-12-20 15:21:47 +00:00
strncpy ( chan - > type , type , sizeof ( chan - > type ) - 1 ) ;
strncpy ( chan - > description , description , sizeof ( chan - > description ) - 1 ) ;
1999-12-04 21:35:07 +00:00
chan - > capabilities = capabilities ;
chan - > requester = requester ;
2003-03-30 22:55:42 +00:00
chan - > devicestate = devicestate ;
1999-12-04 21:35:07 +00:00
chan - > next = NULL ;
if ( last )
last - > next = chan ;
else
backends = chan ;
if ( option_debug )
ast_log ( LOG_DEBUG , " Registered handler for '%s' (%s) \n " , chan - > type , chan - > description ) ;
else if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Registered channel type '%s' (%s) \n " , chan - > type , chan - > description ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-04 21:35:07 +00:00
return 0 ;
}
2001-05-07 00:43:32 +00:00
char * ast_state2str ( int state )
{
2003-05-14 19:21:36 +00:00
/* XXX Not reentrant XXX */
static char localtmp [ 256 ] ;
2001-05-07 00:43:32 +00:00
switch ( state ) {
case AST_STATE_DOWN :
return " Down " ;
case AST_STATE_RESERVED :
return " Rsrvd " ;
case AST_STATE_OFFHOOK :
return " OffHook " ;
case AST_STATE_DIALING :
return " Dialing " ;
case AST_STATE_RING :
return " Ring " ;
case AST_STATE_RINGING :
return " Ringing " ;
case AST_STATE_UP :
return " Up " ;
case AST_STATE_BUSY :
return " Busy " ;
default :
2003-05-14 19:21:36 +00:00
snprintf ( localtmp , sizeof ( localtmp ) , " Unknown (%d) \n " , state ) ;
return localtmp ;
2001-05-07 00:43:32 +00:00
}
}
2001-09-19 14:40:16 +00:00
int ast_best_codec ( int fmts )
{
/* This just our opinion, expressed in code. We are asked to choose
the best codec to use , given no information */
int x ;
static int prefs [ ] =
{
/* Okay, ulaw is used by all telephony equipment, so start with it */
AST_FORMAT_ULAW ,
/* Unless of course, you're a silly European, so then prefer ALAW */
AST_FORMAT_ALAW ,
/* Okay, well, signed linear is easy to translate into other stuff */
AST_FORMAT_SLINEAR ,
2003-11-04 02:40:09 +00:00
/* G.726 is standard ADPCM */
AST_FORMAT_G726 ,
2001-09-19 14:40:16 +00:00
/* ADPCM has great sound quality and is still pretty easy to translate */
AST_FORMAT_ADPCM ,
/* Okay, we're down to vocoders now, so pick GSM because it's small and easier to
translate and sounds pretty good */
AST_FORMAT_GSM ,
2003-04-15 04:36:52 +00:00
/* iLBC is not too bad */
AST_FORMAT_ILBC ,
2002-09-10 20:48:20 +00:00
/* Speex is free, but computationally more expensive than GSM */
AST_FORMAT_SPEEX ,
2001-09-19 14:40:16 +00:00
/* Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough
to use it */
AST_FORMAT_LPC10 ,
2002-09-10 20:48:20 +00:00
/* G.729a is faster than 723 and slightly less expensive */
AST_FORMAT_G729A ,
2001-09-19 14:40:16 +00:00
/* Down to G.723.1 which is proprietary but at least designed for voice */
AST_FORMAT_G723_1 ,
} ;
for ( x = 0 ; x < sizeof ( prefs ) / sizeof ( prefs [ 0 ] ) ; x + + )
if ( fmts & prefs [ x ] )
return prefs [ x ] ;
ast_log ( LOG_WARNING , " Don't know any of 0x%x formats \n " , fmts ) ;
return 0 ;
}
2002-06-21 01:40:13 +00:00
struct ast_channel * ast_channel_alloc ( int needqueue )
1999-12-04 21:35:07 +00:00
{
struct ast_channel * tmp ;
struct ast_channel_pvt * pvt ;
2001-05-07 00:43:32 +00:00
int x ;
2002-06-21 01:40:13 +00:00
int flags ;
2004-04-27 21:21:57 +00:00
struct varshead * headp ;
2002-09-10 20:48:20 +00:00
2002-06-21 01:40:13 +00:00
/* If shutting down, don't allocate any new channels */
if ( shutting_down )
return NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & chlock ) ;
1999-12-04 21:35:07 +00:00
tmp = malloc ( sizeof ( struct ast_channel ) ) ;
if ( tmp ) {
2003-07-28 14:27:05 +00:00
memset ( tmp , 0 , sizeof ( struct ast_channel ) ) ;
1999-12-04 21:35:07 +00:00
pvt = malloc ( sizeof ( struct ast_channel_pvt ) ) ;
if ( pvt ) {
memset ( pvt , 0 , sizeof ( struct ast_channel_pvt ) ) ;
tmp - > sched = sched_context_create ( ) ;
if ( tmp - > sched ) {
2002-06-21 01:40:13 +00:00
for ( x = 0 ; x < AST_MAX_FDS - 1 ; x + + )
2001-05-07 00:43:32 +00:00
tmp - > fds [ x ] = - 1 ;
2004-03-19 04:23:20 +00:00
# ifdef ZAPTEL_OPTIMIZATIONS
tmp - > timingfd = open ( " /dev/zap/timer " , O_RDWR ) ;
if ( tmp - > timingfd > - 1 ) {
/* Check if timing interface supports new
ping / pong scheme */
flags = 1 ;
if ( ! ioctl ( tmp - > timingfd , ZT_TIMERPONG , & flags ) )
needqueue = 0 ;
}
# else
tmp - > timingfd = - 1 ;
# endif
2002-06-21 01:40:13 +00:00
if ( needqueue & &
pipe ( pvt - > alertpipe ) ) {
ast_log ( LOG_WARNING , " Alert pipe creation failed! \n " ) ;
free ( pvt ) ;
free ( tmp ) ;
tmp = NULL ;
pvt = NULL ;
} else {
if ( needqueue ) {
flags = fcntl ( pvt - > alertpipe [ 0 ] , F_GETFL ) ;
fcntl ( pvt - > alertpipe [ 0 ] , F_SETFL , flags | O_NONBLOCK ) ;
flags = fcntl ( pvt - > alertpipe [ 1 ] , F_GETFL ) ;
fcntl ( pvt - > alertpipe [ 1 ] , F_SETFL , flags | O_NONBLOCK ) ;
2004-03-19 04:23:20 +00:00
} else
/* Make sure we've got it done right if they don't */
2002-06-21 01:40:13 +00:00
pvt - > alertpipe [ 0 ] = pvt - > alertpipe [ 1 ] = - 1 ;
/* Always watch the alertpipe */
tmp - > fds [ AST_MAX_FDS - 1 ] = pvt - > alertpipe [ 0 ] ;
2003-05-12 04:23:55 +00:00
/* And timing pipe */
tmp - > fds [ AST_MAX_FDS - 2 ] = tmp - > timingfd ;
2002-06-21 01:40:13 +00:00
strncpy ( tmp - > name , " **Unknown** " , sizeof ( tmp - > name ) - 1 ) ;
tmp - > pvt = pvt ;
2002-09-10 20:48:20 +00:00
/* Initial state */
tmp - > _state = AST_STATE_DOWN ;
2002-06-21 01:40:13 +00:00
tmp - > stack = - 1 ;
tmp - > streamid = - 1 ;
tmp - > appl = NULL ;
tmp - > data = NULL ;
2003-02-05 21:18:09 +00:00
tmp - > fin = 0 ;
tmp - > fout = 0 ;
2003-09-08 16:48:07 +00:00
snprintf ( tmp - > uniqueid , sizeof ( tmp - > uniqueid ) , " %li.%d " , ( long ) time ( NULL ) , uniqueint + + ) ;
2002-09-10 20:48:20 +00:00
headp = & tmp - > varshead ;
2003-08-13 15:25:16 +00:00
ast_mutex_init ( & tmp - > lock ) ;
2004-04-27 21:21:57 +00:00
AST_LIST_HEAD_INIT ( headp ) ;
2002-09-10 20:48:20 +00:00
tmp - > vars = ast_var_assign ( " tempvar " , " tempval " ) ;
AST_LIST_INSERT_HEAD ( headp , tmp - > vars , entries ) ;
2002-06-21 01:40:13 +00:00
strncpy ( tmp - > context , " default " , sizeof ( tmp - > context ) - 1 ) ;
strncpy ( tmp - > language , defaultlanguage , sizeof ( tmp - > language ) - 1 ) ;
strncpy ( tmp - > exten , " s " , sizeof ( tmp - > exten ) - 1 ) ;
tmp - > priority = 1 ;
tmp - > amaflags = ast_default_amaflags ;
strncpy ( tmp - > accountcode , ast_default_accountcode , sizeof ( tmp - > accountcode ) - 1 ) ;
tmp - > next = channels ;
channels = tmp ;
}
1999-12-04 21:35:07 +00:00
} else {
ast_log ( LOG_WARNING , " Unable to create schedule context \n " ) ;
free ( tmp ) ;
tmp = NULL ;
}
} else {
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
free ( tmp ) ;
tmp = NULL ;
}
} else
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-04 21:35:07 +00:00
return tmp ;
}
2004-04-06 22:17:32 +00:00
int ast_queue_frame ( struct ast_channel * chan , struct ast_frame * fin )
2002-06-21 01:40:13 +00:00
{
struct ast_frame * f ;
struct ast_frame * prev , * cur ;
int blah = 1 ;
int qlen = 0 ;
2003-02-05 21:18:09 +00:00
/* Build us a copy and free the original one */
2002-06-21 01:40:13 +00:00
f = ast_frdup ( fin ) ;
if ( ! f ) {
ast_log ( LOG_WARNING , " Unable to duplicate frame \n " ) ;
return - 1 ;
}
2004-04-06 22:17:32 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2002-06-21 01:40:13 +00:00
prev = NULL ;
cur = chan - > pvt - > readq ;
while ( cur ) {
prev = cur ;
cur = cur - > next ;
qlen + + ;
}
2003-03-18 06:00:18 +00:00
/* Allow up to 96 voice frames outstanding, and up to 128 total frames */
if ( ( ( fin - > frametype = = AST_FRAME_VOICE ) & & ( qlen > 96 ) ) | | ( qlen > 128 ) ) {
2003-02-05 21:18:09 +00:00
if ( fin - > frametype ! = AST_FRAME_VOICE ) {
ast_log ( LOG_WARNING , " Exceptionally long queue length queuing to %s \n " , chan - > name ) ;
CRASH ;
} else {
ast_log ( LOG_DEBUG , " Dropping voice to exceptionally long queue on %s \n " , chan - > name ) ;
2003-05-08 04:40:35 +00:00
ast_frfree ( f ) ;
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2003-02-05 21:18:09 +00:00
return 0 ;
}
}
2002-06-21 01:40:13 +00:00
if ( prev )
prev - > next = f ;
else
chan - > pvt - > readq = f ;
if ( chan - > pvt - > alertpipe [ 1 ] > - 1 ) {
if ( write ( chan - > pvt - > alertpipe [ 1 ] , & blah , sizeof ( blah ) ) ! = sizeof ( blah ) )
2002-09-10 20:48:20 +00:00
ast_log ( LOG_WARNING , " Unable to write to alert pipe on %s, frametype/subclass %d/%d (qlen = %d): %s! \n " ,
chan - > name , f - > frametype , f - > subclass , qlen , strerror ( errno ) ) ;
2004-03-19 04:23:20 +00:00
# ifdef ZAPTEL_OPTIMIZATIONS
} else if ( chan - > timingfd > - 1 ) {
ioctl ( chan - > timingfd , ZT_TIMERPING , & blah ) ;
# endif
2003-04-11 04:31:33 +00:00
} else if ( chan - > blocking ) {
pthread_kill ( chan - > blocker , SIGURG ) ;
2002-06-21 01:40:13 +00:00
}
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2002-06-21 01:40:13 +00:00
return 0 ;
}
2004-04-06 22:17:32 +00:00
int ast_queue_hangup ( struct ast_channel * chan )
2002-06-21 01:40:13 +00:00
{
struct ast_frame f = { AST_FRAME_CONTROL , AST_CONTROL_HANGUP } ;
2003-02-12 13:59:15 +00:00
chan - > _softhangup | = AST_SOFTHANGUP_DEV ;
2004-04-06 22:17:32 +00:00
return ast_queue_frame ( chan , & f ) ;
2002-06-21 01:40:13 +00:00
}
2004-04-06 22:17:32 +00:00
int ast_queue_control ( struct ast_channel * chan , int control )
2002-06-21 01:40:13 +00:00
{
struct ast_frame f = { AST_FRAME_CONTROL , } ;
f . subclass = control ;
2004-04-06 22:17:32 +00:00
return ast_queue_frame ( chan , & f ) ;
2002-06-21 01:40:13 +00:00
}
2001-09-19 14:40:16 +00:00
int ast_channel_defer_dtmf ( struct ast_channel * chan )
{
int pre = 0 ;
if ( chan ) {
pre = chan - > deferdtmf ;
chan - > deferdtmf = 1 ;
}
return pre ;
}
void ast_channel_undefer_dtmf ( struct ast_channel * chan )
{
if ( chan )
chan - > deferdtmf = 0 ;
}
2004-05-20 16:30:10 +00:00
struct ast_channel * ast_channel_walk_locked ( struct ast_channel * prev )
1999-12-18 07:01:48 +00:00
{
2004-05-20 16:30:10 +00:00
/* Returns next channel (locked) */
1999-12-18 07:01:48 +00:00
struct ast_channel * l , * ret = NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & chlock ) ;
1999-12-18 07:01:48 +00:00
l = channels ;
if ( ! prev ) {
2004-05-20 16:30:10 +00:00
if ( l )
ast_mutex_lock ( & l - > lock ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-18 07:01:48 +00:00
return l ;
}
while ( l ) {
if ( l = = prev )
ret = l - > next ;
l = l - > next ;
}
2004-05-20 16:30:10 +00:00
if ( ret )
ast_mutex_lock ( & ret - > lock ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-18 07:01:48 +00:00
return ret ;
}
2004-05-22 04:11:22 +00:00
struct ast_channel * ast_get_channel_by_name_locked ( char * channame )
{
struct ast_channel * chan ;
chan = ast_channel_walk_locked ( NULL ) ;
while ( chan ) {
if ( ! strcasecmp ( chan - > name , channame ) )
return chan ;
ast_mutex_unlock ( & chan - > lock ) ;
2004-05-25 04:50:54 +00:00
chan = ast_channel_walk_locked ( chan ) ;
2004-05-22 04:11:22 +00:00
}
return NULL ;
}
2004-04-27 21:21:57 +00:00
int ast_safe_sleep_conditional ( struct ast_channel * chan , int ms ,
2003-02-05 21:18:09 +00:00
int ( * cond ) ( void * ) , void * data )
{
struct ast_frame * f ;
while ( ms > 0 ) {
if ( cond & & ( ( * cond ) ( data ) = = 0 ) )
return 0 ;
ms = ast_waitfor ( chan , ms ) ;
if ( ms < 0 )
return - 1 ;
if ( ms > 0 ) {
f = ast_read ( chan ) ;
if ( ! f )
return - 1 ;
ast_frfree ( f ) ;
}
}
return 0 ;
}
2002-06-21 01:40:13 +00:00
int ast_safe_sleep ( struct ast_channel * chan , int ms )
{
struct ast_frame * f ;
while ( ms > 0 ) {
ms = ast_waitfor ( chan , ms ) ;
if ( ms < 0 )
return - 1 ;
if ( ms > 0 ) {
f = ast_read ( chan ) ;
if ( ! f )
return - 1 ;
ast_frfree ( f ) ;
}
}
return 0 ;
}
1999-12-18 07:01:48 +00:00
void ast_channel_free ( struct ast_channel * chan )
{
struct ast_channel * last = NULL , * cur ;
2002-06-21 01:40:13 +00:00
int fd ;
2002-09-10 20:48:20 +00:00
struct ast_var_t * vardata ;
2002-06-21 01:40:13 +00:00
struct ast_frame * f , * fp ;
2002-09-10 20:48:20 +00:00
struct varshead * headp ;
2003-03-30 22:55:42 +00:00
char name [ AST_CHANNEL_NAME ] ;
2002-09-10 20:48:20 +00:00
headp = & chan - > varshead ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & chlock ) ;
1999-12-18 07:01:48 +00:00
cur = channels ;
while ( cur ) {
if ( cur = = chan ) {
if ( last )
last - > next = cur - > next ;
else
channels = cur - > next ;
break ;
}
last = cur ;
cur = cur - > next ;
}
if ( ! cur )
ast_log ( LOG_WARNING , " Unable to find channel in list \n " ) ;
2004-05-20 16:30:10 +00:00
else {
/* Lock and unlock the channel just to be sure nobody
has it locked still */
ast_mutex_lock ( & cur - > lock ) ;
ast_mutex_unlock ( & cur - > lock ) ;
}
1999-12-18 07:01:48 +00:00
if ( chan - > pvt - > pvt )
ast_log ( LOG_WARNING , " Channel '%s' may not have been hung up properly \n " , chan - > name ) ;
2003-03-30 22:55:42 +00:00
strncpy ( name , chan - > name , sizeof ( name ) - 1 ) ;
2003-03-25 19:30:06 +00:00
/* Stop monitoring */
if ( chan - > monitor ) {
chan - > monitor - > stop ( chan , 0 ) ;
}
2003-03-30 22:55:42 +00:00
2001-03-12 03:04:51 +00:00
/* Free translatosr */
if ( chan - > pvt - > readtrans )
ast_translator_free_path ( chan - > pvt - > readtrans ) ;
if ( chan - > pvt - > writetrans )
ast_translator_free_path ( chan - > pvt - > writetrans ) ;
1999-12-18 07:01:48 +00:00
if ( chan - > pbx )
ast_log ( LOG_WARNING , " PBX may not have been terminated properly on '%s' \n " , chan - > name ) ;
if ( chan - > dnid )
free ( chan - > dnid ) ;
if ( chan - > callerid )
free ( chan - > callerid ) ;
2002-03-10 17:14:13 +00:00
if ( chan - > ani )
free ( chan - > ani ) ;
2003-02-05 21:18:09 +00:00
if ( chan - > rdnis )
free ( chan - > rdnis ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_destroy ( & chan - > lock ) ;
2002-06-21 01:40:13 +00:00
/* Close pipes if appropriate */
if ( ( fd = chan - > pvt - > alertpipe [ 0 ] ) > - 1 )
close ( fd ) ;
if ( ( fd = chan - > pvt - > alertpipe [ 1 ] ) > - 1 )
close ( fd ) ;
2003-07-04 16:49:11 +00:00
if ( ( fd = chan - > timingfd ) > - 1 )
close ( fd ) ;
2002-06-21 01:40:13 +00:00
f = chan - > pvt - > readq ;
2002-09-10 20:48:20 +00:00
chan - > pvt - > readq = NULL ;
2002-06-21 01:40:13 +00:00
while ( f ) {
fp = f ;
f = f - > next ;
ast_frfree ( fp ) ;
}
2002-09-10 20:48:20 +00:00
/* loop over the variables list, freeing all data and deleting list items */
/* no need to lock the list, as the channel is already locked */
2004-04-27 21:21:57 +00:00
while ( ! AST_LIST_EMPTY ( headp ) ) { /* List Deletion. */
vardata = AST_LIST_FIRST ( headp ) ;
AST_LIST_REMOVE_HEAD ( headp , entries ) ;
// printf("deleting var %s=%s\n",ast_var_name(vardata),ast_var_value(vardata));
ast_var_delete ( vardata ) ;
2002-09-10 20:48:20 +00:00
}
2004-04-27 21:21:57 +00:00
2002-09-10 20:48:20 +00:00
2001-03-12 03:04:51 +00:00
free ( chan - > pvt ) ;
2003-02-05 21:18:09 +00:00
chan - > pvt = NULL ;
1999-12-18 07:01:48 +00:00
free ( chan ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
2003-03-30 22:55:42 +00:00
ast_device_state_changed ( name ) ;
1999-12-18 07:01:48 +00:00
}
2002-09-10 20:48:20 +00:00
int ast_softhangup_nolock ( struct ast_channel * chan , int cause )
1999-12-04 21:35:07 +00:00
{
int res = 0 ;
2002-09-10 20:48:20 +00:00
struct ast_frame f = { AST_FRAME_NULL } ;
1999-12-04 21:35:07 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Soft-Hanging up channel '%s' \n " , chan - > name ) ;
2001-05-07 00:43:32 +00:00
/* Inform channel driver that we need to be hung up, if it cares */
2002-09-10 20:48:20 +00:00
chan - > _softhangup | = cause ;
2004-04-06 22:17:32 +00:00
ast_queue_frame ( chan , & f ) ;
2004-04-26 03:02:49 +00:00
/* Interrupt any poll call or such */
1999-12-04 21:35:07 +00:00
if ( chan - > blocking )
pthread_kill ( chan - > blocker , SIGURG ) ;
return res ;
}
2002-09-10 20:48:20 +00:00
int ast_softhangup ( struct ast_channel * chan , int cause )
{
int res ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2002-09-10 20:48:20 +00:00
res = ast_softhangup_nolock ( chan , cause ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2002-09-10 20:48:20 +00:00
return res ;
}
2001-09-19 14:40:16 +00:00
static void free_translation ( struct ast_channel * clone )
{
if ( clone - > pvt - > writetrans )
ast_translator_free_path ( clone - > pvt - > writetrans ) ;
if ( clone - > pvt - > readtrans )
ast_translator_free_path ( clone - > pvt - > readtrans ) ;
clone - > pvt - > writetrans = NULL ;
clone - > pvt - > readtrans = NULL ;
clone - > pvt - > rawwriteformat = clone - > nativeformats ;
clone - > pvt - > rawreadformat = clone - > nativeformats ;
}
1999-12-04 21:35:07 +00:00
int ast_hangup ( struct ast_channel * chan )
{
int res = 0 ;
2001-05-07 00:43:32 +00:00
/* Don't actually hang up a channel that will masquerade as someone else, or
if someone is going to masquerade as us */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2001-09-19 14:40:16 +00:00
if ( chan - > masq ) {
2004-04-06 22:17:32 +00:00
if ( ast_do_masquerade ( chan ) )
2003-02-05 21:18:09 +00:00
ast_log ( LOG_WARNING , " Failed to perform masquerade \n " ) ;
}
if ( chan - > masq ) {
ast_log ( LOG_WARNING , " %s getting hung up, but someone is trying to masq into us?!? \n " , chan - > name ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-05-07 00:43:32 +00:00
return 0 ;
2001-09-19 14:40:16 +00:00
}
2001-05-07 00:43:32 +00:00
/* If this channel is one which will be masqueraded into something,
mark it as a zombie already , so we know to free it later */
if ( chan - > masqr ) {
chan - > zombie = 1 ;
2004-02-20 20:00:49 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-05-07 00:43:32 +00:00
return 0 ;
}
2001-09-19 14:40:16 +00:00
free_translation ( chan ) ;
2004-04-02 23:25:24 +00:00
if ( chan - > stream )
ast_closestream ( chan - > stream ) ;
if ( chan - > vstream )
ast_closestream ( chan - > vstream ) ;
1999-12-04 21:35:07 +00:00
if ( chan - > sched )
sched_context_destroy ( chan - > sched ) ;
2002-06-21 01:40:13 +00:00
/* Clear any tone stuff remaining */
if ( chan - > generatordata )
chan - > generator - > release ( chan , chan - > generatordata ) ;
chan - > generatordata = NULL ;
chan - > generator = NULL ;
2001-12-20 15:21:47 +00:00
if ( chan - > cdr ) {
/* End the CDR if it hasn't already */
ast_cdr_end ( chan - > cdr ) ;
/* Post and Free the CDR */
ast_cdr_post ( chan - > cdr ) ;
ast_cdr_free ( chan - > cdr ) ;
}
2001-03-12 03:04:51 +00:00
if ( chan - > blocking ) {
ast_log ( LOG_WARNING , " Hard hangup called by thread %ld on %s, while fd "
2004-04-27 21:21:57 +00:00
" is blocked by thread %ld in procedure %s! Expect a failure \n " ,
2003-09-08 16:48:07 +00:00
( long ) pthread_self ( ) , chan - > name , ( long ) chan - > blocker , chan - > blockproc ) ;
2001-03-12 03:04:51 +00:00
CRASH ;
}
2001-05-07 00:43:32 +00:00
if ( ! chan - > zombie ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Hanging up channel '%s' \n " , chan - > name ) ;
if ( chan - > pvt - > hangup )
res = chan - > pvt - > hangup ( chan ) ;
} else
if ( option_debug )
ast_log ( LOG_DEBUG , " Hanging up zombie '%s' \n " , chan - > name ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2002-09-10 20:48:20 +00:00
manager_event ( EVENT_FLAG_CALL , " Hangup " ,
2003-06-11 12:24:13 +00:00
" Channel: %s \r \n "
2004-04-27 21:21:57 +00:00
" Uniqueid: %s \r \n "
" Cause: %i \r \n " ,
chan - > name , chan - > uniqueid , chan - > hangupcause ) ;
1999-12-18 07:01:48 +00:00
ast_channel_free ( chan ) ;
1999-12-04 21:35:07 +00:00
return res ;
}
void ast_channel_unregister ( char * type )
{
struct chanlist * chan , * last = NULL ;
if ( option_debug )
ast_log ( LOG_DEBUG , " Unregistering channel type '%s' \n " , type ) ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & chlock ) ) {
1999-12-04 21:35:07 +00:00
ast_log ( LOG_WARNING , " Unable to lock channel list \n " ) ;
return ;
}
2004-01-14 06:04:46 +00:00
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Unregistered channel type '%s' \n " , type ) ;
1999-12-04 21:35:07 +00:00
chan = backends ;
while ( chan ) {
if ( ! strcasecmp ( chan - > type , type ) ) {
if ( last )
last - > next = chan - > next ;
else
backends = backends - > next ;
free ( chan ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-04 21:35:07 +00:00
return ;
}
last = chan ;
chan = chan - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-04 21:35:07 +00:00
}
int ast_answer ( struct ast_channel * chan )
{
2001-09-19 14:40:16 +00:00
int res = 0 ;
2001-05-07 00:43:32 +00:00
/* Stop if we're a zombie or need a soft hangup */
2001-12-20 15:21:47 +00:00
if ( chan - > zombie | | ast_check_hangup ( chan ) )
2001-05-07 00:43:32 +00:00
return - 1 ;
2002-09-10 20:48:20 +00:00
switch ( chan - > _state ) {
2001-05-07 00:43:32 +00:00
case AST_STATE_RINGING :
2001-09-19 14:40:16 +00:00
case AST_STATE_RING :
2003-08-13 17:32:44 +00:00
ast_mutex_lock ( & chan - > lock ) ;
1999-12-04 21:35:07 +00:00
if ( chan - > pvt - > answer )
2001-09-19 14:40:16 +00:00
res = chan - > pvt - > answer ( chan ) ;
2003-08-13 17:32:44 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2002-09-10 20:48:20 +00:00
ast_setstate ( chan , AST_STATE_UP ) ;
2001-12-20 15:21:47 +00:00
if ( chan - > cdr )
ast_cdr_answer ( chan - > cdr ) ;
2001-09-19 14:40:16 +00:00
return res ;
2001-05-07 00:43:32 +00:00
break ;
case AST_STATE_UP :
2003-02-05 21:18:09 +00:00
if ( chan - > cdr )
ast_cdr_answer ( chan - > cdr ) ;
2001-05-07 00:43:32 +00:00
break ;
1999-12-04 21:35:07 +00:00
}
return 0 ;
}
2004-04-02 21:58:10 +00:00
2004-04-07 14:43:18 +00:00
void ast_deactivate_generator ( struct ast_channel * chan )
2002-06-21 01:40:13 +00:00
{
2004-04-07 14:43:18 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2002-06-21 01:40:13 +00:00
if ( chan - > generatordata ) {
2004-02-04 23:18:16 +00:00
if ( chan - > generator & & chan - > generator - > release )
chan - > generator - > release ( chan , chan - > generatordata ) ;
2002-06-21 01:40:13 +00:00
chan - > generatordata = NULL ;
2002-09-10 20:48:20 +00:00
chan - > generator = NULL ;
2002-06-21 01:40:13 +00:00
chan - > writeinterrupt = 0 ;
}
2004-04-02 21:58:10 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
}
2004-04-07 14:43:18 +00:00
2002-06-21 01:40:13 +00:00
int ast_activate_generator ( struct ast_channel * chan , struct ast_generator * gen , void * params )
{
2004-06-02 20:18:18 +00:00
int res = 0 ;
ast_mutex_lock ( & chan - > lock ) ;
2002-06-21 01:40:13 +00:00
if ( chan - > generatordata ) {
2004-02-04 23:18:16 +00:00
if ( chan - > generator & & chan - > generator - > release )
chan - > generator - > release ( chan , chan - > generatordata ) ;
2002-06-21 01:40:13 +00:00
chan - > generatordata = NULL ;
}
2003-04-16 02:47:03 +00:00
ast_prod ( chan ) ;
2002-06-21 01:40:13 +00:00
if ( ( chan - > generatordata = gen - > alloc ( chan , params ) ) ) {
chan - > generator = gen ;
} else {
2004-06-02 20:18:18 +00:00
res = - 1 ;
2002-06-21 01:40:13 +00:00
}
2004-06-02 20:18:18 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
return res ;
2002-06-21 01:40:13 +00:00
}
2001-03-12 03:04:51 +00:00
int ast_waitfor_n_fd ( int * fds , int n , int * ms , int * exception )
1999-12-04 21:35:07 +00:00
{
/* Wait for x amount of time on a file descriptor to have input. */
2004-04-25 20:42:45 +00:00
struct timeval start , now ;
1999-12-04 21:35:07 +00:00
int res ;
2004-04-25 20:42:45 +00:00
int x , y ;
1999-12-04 21:35:07 +00:00
int winner = - 1 ;
2004-04-25 20:42:45 +00:00
int spoint ;
struct pollfd * pfds ;
1999-12-04 21:35:07 +00:00
2004-04-25 20:42:45 +00:00
pfds = alloca ( sizeof ( struct pollfd ) * n ) ;
if ( ! pfds ) {
ast_log ( LOG_WARNING , " alloca failed! bad things will happen. \n " ) ;
return - 1 ;
}
if ( * ms > 0 )
gettimeofday ( & start , NULL ) ;
y = 0 ;
1999-12-04 21:35:07 +00:00
for ( x = 0 ; x < n ; x + + ) {
2001-05-07 00:43:32 +00:00
if ( fds [ x ] > - 1 ) {
2004-04-25 20:42:45 +00:00
pfds [ y ] . fd = fds [ x ] ;
pfds [ y ] . events = POLLIN | POLLPRI ;
y + + ;
2001-05-07 00:43:32 +00:00
}
1999-12-04 21:35:07 +00:00
}
2004-04-25 20:42:45 +00:00
res = poll ( pfds , y , * ms ) ;
2001-05-07 00:43:32 +00:00
if ( res < 0 ) {
/* Simulate a timeout if we were interrupted */
if ( errno ! = EINTR )
* ms = - 1 ;
else
* ms = 0 ;
return - 1 ;
}
2004-04-25 20:42:45 +00:00
spoint = 0 ;
1999-12-04 21:35:07 +00:00
for ( x = 0 ; x < n ; x + + ) {
2004-04-25 20:42:45 +00:00
if ( fds [ x ] > - 1 ) {
if ( ( res = ast_fdisset ( pfds , fds [ x ] , y , & spoint ) ) ) {
winner = fds [ x ] ;
if ( exception ) {
if ( res & POLLPRI )
* exception = - 1 ;
else
* exception = 0 ;
}
}
2001-03-12 03:04:51 +00:00
}
1999-12-04 21:35:07 +00:00
}
2004-04-25 20:42:45 +00:00
if ( * ms > 0 ) {
long passed ;
gettimeofday ( & now , NULL ) ;
passed = ( now . tv_sec - start . tv_sec ) * 1000 ;
passed + = ( now . tv_usec - start . tv_usec ) / 1000 ;
if ( passed < = * ms )
* ms - = passed ;
else
* ms = 0 ;
}
1999-12-04 21:35:07 +00:00
return winner ;
}
2001-09-19 14:40:16 +00:00
struct ast_channel * ast_waitfor_nandfds ( struct ast_channel * * c , int n , int * fds , int nfds ,
int * exception , int * outfd , int * ms )
1999-12-04 21:35:07 +00:00
{
/* Wait for x amount of time on a file descriptor to have input. */
2004-04-25 20:42:45 +00:00
struct timeval start , end ;
struct pollfd * pfds ;
1999-12-04 21:35:07 +00:00
int res ;
2004-04-25 20:42:45 +00:00
long rms ;
int x , y , max ;
int spoint ;
2004-03-05 18:31:06 +00:00
time_t now = 0 ;
2004-03-05 18:22:31 +00:00
long whentohangup = 0 , havewhen = 0 , diff ;
1999-12-04 21:35:07 +00:00
struct ast_channel * winner = NULL ;
2004-04-25 20:42:45 +00:00
pfds = alloca ( sizeof ( struct pollfd ) * ( n * AST_MAX_FDS + nfds ) ) ;
if ( ! pfds ) {
ast_log ( LOG_WARNING , " alloca failed! bad things will happen. \n " ) ;
* outfd = - 1 ;
return NULL ;
}
2001-09-19 14:40:16 +00:00
if ( outfd )
2004-03-05 18:22:31 +00:00
* outfd = - 99999 ;
2001-09-19 14:40:16 +00:00
if ( exception )
* exception = 0 ;
1999-12-04 21:35:07 +00:00
2001-05-07 00:43:32 +00:00
/* Perform any pending masquerades */
for ( x = 0 ; x < n ; x + + ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & c [ x ] - > lock ) ;
2004-03-05 18:22:31 +00:00
if ( c [ x ] - > whentohangup ) {
2004-03-05 18:31:06 +00:00
if ( ! havewhen )
time ( & now ) ;
2004-03-05 18:22:31 +00:00
diff = c [ x ] - > whentohangup - now ;
if ( ! havewhen | | ( diff < whentohangup ) ) {
havewhen + + ;
whentohangup = diff ;
}
}
2001-05-07 00:43:32 +00:00
if ( c [ x ] - > masq ) {
2004-04-06 22:17:32 +00:00
if ( ast_do_masquerade ( c [ x ] ) ) {
2001-05-07 00:43:32 +00:00
ast_log ( LOG_WARNING , " Masquerade failed \n " ) ;
* ms = - 1 ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & c [ x ] - > lock ) ;
2001-05-07 00:43:32 +00:00
return NULL ;
}
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & c [ x ] - > lock ) ;
2001-05-07 00:43:32 +00:00
}
2004-04-25 20:42:45 +00:00
rms = * ms ;
2004-03-05 18:22:31 +00:00
if ( havewhen ) {
if ( ( * ms < 0 ) | | ( whentohangup * 1000 < * ms ) ) {
2004-04-25 20:42:45 +00:00
rms = whentohangup * 1000 ;
2004-03-05 18:22:31 +00:00
}
}
2004-04-25 20:42:45 +00:00
max = 0 ;
1999-12-04 21:35:07 +00:00
for ( x = 0 ; x < n ; x + + ) {
2001-05-07 00:43:32 +00:00
for ( y = 0 ; y < AST_MAX_FDS ; y + + ) {
2002-06-21 01:40:13 +00:00
if ( c [ x ] - > fds [ y ] > - 1 ) {
2004-04-25 20:42:45 +00:00
pfds [ max ] . fd = c [ x ] - > fds [ y ] ;
pfds [ max ] . events = POLLIN | POLLPRI ;
max + + ;
2001-05-07 00:43:32 +00:00
}
}
1999-12-04 21:35:07 +00:00
CHECK_BLOCKING ( c [ x ] ) ;
}
2001-09-19 14:40:16 +00:00
for ( x = 0 ; x < nfds ; x + + ) {
2004-04-25 20:42:45 +00:00
if ( fds [ x ] > - 1 ) {
pfds [ max ] . fd = fds [ x ] ;
pfds [ max ] . events = POLLIN | POLLPRI ;
max + + ;
}
2001-09-19 14:40:16 +00:00
}
2004-04-25 20:42:45 +00:00
if ( * ms > 0 )
gettimeofday ( & start , NULL ) ;
res = poll ( pfds , max , rms ) ;
2001-05-07 00:43:32 +00:00
if ( res < 0 ) {
for ( x = 0 ; x < n ; x + + )
c [ x ] - > blocking = 0 ;
/* Simulate a timeout if we were interrupted */
if ( errno ! = EINTR )
* ms = - 1 ;
2002-03-10 17:14:13 +00:00
else {
/* Just an interrupt */
#if 0
2001-05-07 00:43:32 +00:00
* ms = 0 ;
2002-03-10 17:14:13 +00:00
# endif
}
2001-05-07 00:43:32 +00:00
return NULL ;
}
2004-03-05 18:31:06 +00:00
if ( havewhen )
time ( & now ) ;
2004-04-25 20:42:45 +00:00
spoint = 0 ;
1999-12-04 21:35:07 +00:00
for ( x = 0 ; x < n ; x + + ) {
c [ x ] - > blocking = 0 ;
2004-03-05 18:32:59 +00:00
if ( havewhen & & c [ x ] - > whentohangup & & ( now > c [ x ] - > whentohangup ) ) {
2004-03-05 18:31:06 +00:00
c [ x ] - > _softhangup | = AST_SOFTHANGUP_TIMEOUT ;
2004-03-05 18:32:59 +00:00
if ( ! winner )
winner = c [ x ] ;
}
2001-05-07 00:43:32 +00:00
for ( y = 0 ; y < AST_MAX_FDS ; y + + ) {
if ( c [ x ] - > fds [ y ] > - 1 ) {
2004-04-25 20:42:45 +00:00
if ( ( res = ast_fdisset ( pfds , c [ x ] - > fds [ y ] , max , & spoint ) ) ) {
if ( res & POLLPRI )
c [ x ] - > exception = - 1 ;
else
c [ x ] - > exception = 0 ;
2004-04-24 23:11:28 +00:00
c [ x ] - > fdno = y ;
2001-05-07 00:43:32 +00:00
winner = c [ x ] ;
}
}
2001-03-12 03:04:51 +00:00
}
1999-12-04 21:35:07 +00:00
}
2001-09-19 14:40:16 +00:00
for ( x = 0 ; x < nfds ; x + + ) {
2004-04-25 20:42:45 +00:00
if ( fds [ x ] > - 1 ) {
if ( ( res = ast_fdisset ( pfds , fds [ x ] , max , & spoint ) ) ) {
if ( outfd )
* outfd = fds [ x ] ;
if ( exception ) {
if ( res & POLLPRI )
* exception = - 1 ;
else
* exception = 0 ;
}
winner = NULL ;
}
}
}
if ( * ms > 0 ) {
long diff ;
gettimeofday ( & end , NULL ) ;
diff = ( end . tv_sec - start . tv_sec ) * 1000 ;
diff + = ( end . tv_usec - start . tv_usec ) / 1000 ;
if ( diff < * ms )
* ms - = diff ;
else
* ms = 0 ;
2001-09-19 14:40:16 +00:00
}
1999-12-04 21:35:07 +00:00
return winner ;
}
2001-09-19 14:40:16 +00:00
struct ast_channel * ast_waitfor_n ( struct ast_channel * * c , int n , int * ms )
{
return ast_waitfor_nandfds ( c , n , NULL , 0 , NULL , NULL , ms ) ;
}
1999-12-04 21:35:07 +00:00
int ast_waitfor ( struct ast_channel * c , int ms )
{
2001-05-07 00:43:32 +00:00
struct ast_channel * chan ;
2001-09-19 14:40:16 +00:00
int oldms = ms ;
2001-05-07 00:43:32 +00:00
chan = ast_waitfor_n ( & c , 1 , & ms ) ;
2001-09-19 14:40:16 +00:00
if ( ms < 0 ) {
if ( oldms < 0 )
return 0 ;
else
return - 1 ;
}
2001-05-07 00:43:32 +00:00
return ms ;
1999-12-04 21:35:07 +00:00
}
char ast_waitfordigit ( struct ast_channel * c , int ms )
{
2003-02-23 06:00:11 +00:00
/* XXX Should I be merged with waitfordigit_full XXX */
1999-12-04 21:35:07 +00:00
struct ast_frame * f ;
char result = 0 ;
2001-05-07 00:43:32 +00:00
/* Stop if we're a zombie or need a soft hangup */
2001-12-20 15:21:47 +00:00
if ( c - > zombie | | ast_check_hangup ( c ) )
2001-05-07 00:43:32 +00:00
return - 1 ;
1999-12-04 21:35:07 +00:00
/* Wait for a digit, no more than ms milliseconds total. */
while ( ms & & ! result ) {
ms = ast_waitfor ( c , ms ) ;
if ( ms < 0 ) /* Error */
result = - 1 ;
else if ( ms > 0 ) {
/* Read something */
f = ast_read ( c ) ;
if ( f ) {
if ( f - > frametype = = AST_FRAME_DTMF )
result = f - > subclass ;
ast_frfree ( f ) ;
} else
result = - 1 ;
}
}
return result ;
}
2003-06-29 20:32:26 +00:00
int ast_settimeout ( struct ast_channel * c , int samples , int ( * func ) ( void * data ) , void * data )
2003-05-12 04:23:55 +00:00
{
int res = - 1 ;
# ifdef ZAPTEL_OPTIMIZATIONS
if ( c - > timingfd > - 1 ) {
2003-06-29 20:32:26 +00:00
if ( ! func ) {
samples = 0 ;
data = 0 ;
}
ast_log ( LOG_DEBUG , " Scheduling timer at %d sample intervals \n " , samples ) ;
res = ioctl ( c - > timingfd , ZT_TIMERCONFIG , & samples ) ;
c - > timingfunc = func ;
c - > timingdata = data ;
2003-05-12 04:23:55 +00:00
}
# endif
return res ;
}
2004-04-12 16:25:34 +00:00
char ast_waitfordigit_full ( struct ast_channel * c , int ms , int audiofd , int cmdfd )
2003-02-23 06:00:11 +00:00
{
struct ast_frame * f ;
struct ast_channel * rchan ;
int outfd ;
2004-04-12 16:25:34 +00:00
int res ;
2003-02-23 06:00:11 +00:00
/* Stop if we're a zombie or need a soft hangup */
if ( c - > zombie | | ast_check_hangup ( c ) )
return - 1 ;
/* Wait for a digit, no more than ms milliseconds total. */
2004-04-12 16:25:34 +00:00
while ( ms ) {
rchan = ast_waitfor_nandfds ( & c , 1 , & cmdfd , ( cmdfd > - 1 ) ? 1 : 0 , NULL , & outfd , & ms ) ;
if ( ( ! rchan ) & & ( outfd < 0 ) & & ( ms ) ) {
ast_log ( LOG_WARNING , " Wait failed (%s) \n " , strerror ( errno ) ) ;
return - 1 ;
} else if ( outfd > - 1 ) {
/* The FD we were watching has something waiting */
return 1 ;
2003-02-23 06:00:11 +00:00
} else if ( rchan ) {
f = ast_read ( c ) ;
2004-04-12 16:25:34 +00:00
if ( ! f ) {
return - 1 ;
}
switch ( f - > frametype ) {
case AST_FRAME_DTMF :
res = f - > subclass ;
2003-02-23 06:00:11 +00:00
ast_frfree ( f ) ;
2004-04-12 16:25:34 +00:00
return res ;
case AST_FRAME_CONTROL :
switch ( f - > subclass ) {
case AST_CONTROL_HANGUP :
ast_frfree ( f ) ;
return - 1 ;
case AST_CONTROL_RINGING :
case AST_CONTROL_ANSWER :
/* Unimportant */
break ;
default :
ast_log ( LOG_WARNING , " Unexpected control subclass '%d' \n " , f - > subclass ) ;
}
case AST_FRAME_VOICE :
/* Write audio if appropriate */
if ( audiofd > - 1 )
write ( audiofd , f - > data , f - > datalen ) ;
}
/* Ignore */
ast_frfree ( f ) ;
2003-02-23 06:00:11 +00:00
}
}
2004-04-12 16:25:34 +00:00
return 0 ; // Time is up
2003-02-23 06:00:11 +00:00
}
1999-12-04 21:35:07 +00:00
struct ast_frame * ast_read ( struct ast_channel * chan )
{
struct ast_frame * f = NULL ;
2002-06-21 01:40:13 +00:00
int blah ;
2003-06-29 20:32:26 +00:00
# ifdef ZAPTEL_OPTIMIZATIONS
int ( * func ) ( void * ) ;
void * data ;
2004-03-19 04:23:20 +00:00
int res ;
2003-06-29 20:32:26 +00:00
# endif
2001-03-12 03:04:51 +00:00
static struct ast_frame null_frame =
{
AST_FRAME_NULL ,
} ;
2001-05-07 00:43:32 +00:00
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2001-05-07 00:43:32 +00:00
if ( chan - > masq ) {
2004-04-06 22:17:32 +00:00
if ( ast_do_masquerade ( chan ) ) {
2001-05-07 00:43:32 +00:00
ast_log ( LOG_WARNING , " Failed to perform masquerade \n " ) ;
f = NULL ;
} else
2004-04-27 21:21:57 +00:00
f = & null_frame ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-05-07 00:43:32 +00:00
return f ;
}
/* Stop if we're a zombie or need a soft hangup */
2001-12-20 15:21:47 +00:00
if ( chan - > zombie | | ast_check_hangup ( chan ) ) {
2002-09-10 20:48:20 +00:00
if ( chan - > generator )
2004-04-07 14:43:18 +00:00
ast_deactivate_generator ( chan ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-05-07 00:43:32 +00:00
return NULL ;
}
2002-06-21 01:40:13 +00:00
2004-05-06 21:04:22 +00:00
if ( ! chan - > deferdtmf & & ! ast_strlen_zero ( chan - > dtmfq ) ) {
2004-04-27 21:21:57 +00:00
/* We have DTMF that has been deferred. Return it now */
2001-09-19 14:40:16 +00:00
chan - > dtmff . frametype = AST_FRAME_DTMF ;
chan - > dtmff . subclass = chan - > dtmfq [ 0 ] ;
/* Drop first digit */
memmove ( chan - > dtmfq , chan - > dtmfq + 1 , sizeof ( chan - > dtmfq ) - 1 ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-09-19 14:40:16 +00:00
return & chan - > dtmff ;
}
2002-06-21 01:40:13 +00:00
/* Read and ignore anything on the alertpipe, but read only
one sizeof ( blah ) per frame that we send from it */
if ( chan - > pvt - > alertpipe [ 0 ] > - 1 ) {
read ( chan - > pvt - > alertpipe [ 0 ] , & blah , sizeof ( blah ) ) ;
}
2003-05-12 04:23:55 +00:00
# ifdef ZAPTEL_OPTIMIZATIONS
if ( ( chan - > timingfd > - 1 ) & & ( chan - > fdno = = AST_MAX_FDS - 2 ) & & chan - > exception ) {
chan - > exception = 0 ;
blah = - 1 ;
2004-03-19 04:23:20 +00:00
/* IF we can't get event, assume it's an expired as-per the old interface */
res = ioctl ( chan - > timingfd , ZT_GETEVENT , & blah ) ;
if ( res )
blah = ZT_EVENT_TIMER_EXPIRED ;
if ( blah = = ZT_EVENT_TIMER_PING ) {
2003-06-29 23:23:54 +00:00
#if 0
2004-03-19 04:23:20 +00:00
ast_log ( LOG_NOTICE , " Oooh, there's a PING! \n " ) ;
2003-06-29 23:23:54 +00:00
# endif
2004-03-19 04:23:20 +00:00
if ( ! chan - > pvt - > readq | | ! chan - > pvt - > readq - > next ) {
/* Acknowledge PONG unless we need it again */
#if 0
ast_log ( LOG_NOTICE , " Sending a PONG! \n " ) ;
# endif
if ( ioctl ( chan - > timingfd , ZT_TIMERPONG , & blah ) ) {
ast_log ( LOG_WARNING , " Failed to pong timer on '%s': %s \n " , chan - > name , strerror ( errno ) ) ;
}
}
} else if ( blah = = ZT_EVENT_TIMER_EXPIRED ) {
ioctl ( chan - > timingfd , ZT_TIMERACK , & blah ) ;
func = chan - > timingfunc ;
data = chan - > timingdata ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2004-03-19 04:23:20 +00:00
if ( func ) {
#if 0
ast_log ( LOG_DEBUG , " Calling private function \n " ) ;
# endif
func ( data ) ;
} else {
blah = 0 ;
ast_mutex_lock ( & chan - > lock ) ;
ioctl ( chan - > timingfd , ZT_TIMERCONFIG , & blah ) ;
chan - > timingdata = NULL ;
ast_mutex_unlock ( & chan - > lock ) ;
}
2004-04-27 21:21:57 +00:00
f = & null_frame ;
2004-03-19 04:23:20 +00:00
return f ;
} else
ast_log ( LOG_NOTICE , " No/unknown event '%d' on timer for '%s'? \n " , blah , chan - > name ) ;
2003-05-12 04:23:55 +00:00
}
# endif
2002-06-21 01:40:13 +00:00
/* Check for pending read queue */
if ( chan - > pvt - > readq ) {
f = chan - > pvt - > readq ;
chan - > pvt - > readq = f - > next ;
/* Interpret hangup and return NULL */
2003-11-07 03:48:03 +00:00
if ( ( f - > frametype = = AST_FRAME_CONTROL ) & & ( f - > subclass = = AST_CONTROL_HANGUP ) ) {
ast_frfree ( f ) ;
2002-06-21 01:40:13 +00:00
f = NULL ;
2003-11-07 03:48:03 +00:00
}
2002-06-21 01:40:13 +00:00
} else {
chan - > blocker = pthread_self ( ) ;
if ( chan - > exception ) {
if ( chan - > pvt - > exception )
f = chan - > pvt - > exception ( chan ) ;
2003-02-05 21:18:09 +00:00
else {
ast_log ( LOG_WARNING , " Exception flag set on '%s', but no exception handler \n " , chan - > name ) ;
f = & null_frame ;
}
2002-06-21 01:40:13 +00:00
/* Clear the exception flag */
chan - > exception = 0 ;
} else
if ( chan - > pvt - > read )
f = chan - > pvt - > read ( chan ) ;
2001-03-12 03:04:51 +00:00
else
2002-06-21 01:40:13 +00:00
ast_log ( LOG_WARNING , " No read routine on channel %s \n " , chan - > name ) ;
}
2003-02-05 21:18:09 +00:00
2001-03-12 03:04:51 +00:00
if ( f & & ( f - > frametype = = AST_FRAME_VOICE ) ) {
2003-02-05 21:18:09 +00:00
if ( ! ( f - > subclass & chan - > nativeformats ) ) {
/* This frame can't be from the current native formats -- drop it on the
floor */
2003-08-16 05:10:35 +00:00
ast_log ( LOG_NOTICE , " Dropping incompatible voice frame on %s of format %s since our native format has changed to %s \n " , chan - > name , ast_getformatname ( f - > subclass ) , ast_getformatname ( chan - > nativeformats ) ) ;
2003-02-14 06:00:11 +00:00
ast_frfree ( f ) ;
2003-02-05 21:18:09 +00:00
f = & null_frame ;
2003-05-28 19:38:02 +00:00
} else {
if ( chan - > monitor & & chan - > monitor - > read_stream ) {
2003-08-28 20:02:10 +00:00
# ifndef MONITOR_CONSTANT_DELAY
int jump = chan - > outsmpl - chan - > insmpl - 2 * f - > samples ;
if ( jump > = 0 ) {
if ( ast_seekstream ( chan - > monitor - > read_stream , jump + f - > samples , SEEK_FORCECUR ) = = - 1 )
ast_log ( LOG_WARNING , " Failed to perform seek in monitoring read stream, synchronization between the files may be broken \n " ) ;
chan - > insmpl + = jump + 2 * f - > samples ;
} else
chan - > insmpl + = f - > samples ;
# else
int jump = chan - > outsmpl - chan - > insmpl ;
if ( jump - MONITOR_DELAY > = 0 ) {
if ( ast_seekstream ( chan - > monitor - > read_stream , jump - f - > samples , SEEK_FORCECUR ) = = - 1 )
ast_log ( LOG_WARNING , " Failed to perform seek in monitoring read stream, synchronization between the files may be broken \n " ) ;
chan - > insmpl + = jump ;
} else
chan - > insmpl + = f - > samples ;
# endif
if ( ast_writestream ( chan - > monitor - > read_stream , f ) < 0 )
2003-05-28 19:38:02 +00:00
ast_log ( LOG_WARNING , " Failed to write data to channel monitor read stream \n " ) ;
}
if ( chan - > pvt - > readtrans ) {
f = ast_translate ( chan - > pvt - > readtrans , f , 1 ) ;
if ( ! f )
f = & null_frame ;
}
2001-03-12 03:04:51 +00:00
}
}
2002-06-21 01:40:13 +00:00
2001-05-07 00:43:32 +00:00
/* Make sure we always return NULL in the future */
2001-12-20 15:21:47 +00:00
if ( ! f ) {
2002-09-10 20:48:20 +00:00
chan - > _softhangup | = AST_SOFTHANGUP_DEV ;
if ( chan - > generator )
2004-04-07 14:43:18 +00:00
ast_deactivate_generator ( chan ) ;
2001-12-20 15:21:47 +00:00
/* End the CDR if appropriate */
if ( chan - > cdr )
ast_cdr_end ( chan - > cdr ) ;
} else if ( chan - > deferdtmf & & f - > frametype = = AST_FRAME_DTMF ) {
2001-09-19 14:40:16 +00:00
if ( strlen ( chan - > dtmfq ) < sizeof ( chan - > dtmfq ) - 2 )
chan - > dtmfq [ strlen ( chan - > dtmfq ) ] = f - > subclass ;
else
ast_log ( LOG_WARNING , " Dropping deferred DTMF digits on %s \n " , chan - > name ) ;
f = & null_frame ;
2001-12-20 15:21:47 +00:00
} else if ( ( f - > frametype = = AST_FRAME_CONTROL ) & & ( f - > subclass = = AST_CONTROL_ANSWER ) ) {
/* Answer the CDR */
2002-09-10 20:48:20 +00:00
ast_setstate ( chan , AST_STATE_UP ) ;
2001-12-20 15:21:47 +00:00
ast_cdr_answer ( chan - > cdr ) ;
2003-05-28 19:38:02 +00:00
}
2001-05-07 00:43:32 +00:00
2002-06-21 01:40:13 +00:00
/* Run any generator sitting on the line */
if ( f & & ( f - > frametype = = AST_FRAME_VOICE ) & & chan - > generatordata ) {
/* Mask generator data temporarily */
void * tmp ;
int res ;
2004-04-02 21:58:10 +00:00
int ( * generate ) ( struct ast_channel * chan , void * tmp , int datalen , int samples ) ;
2002-06-21 01:40:13 +00:00
tmp = chan - > generatordata ;
chan - > generatordata = NULL ;
2004-04-02 21:58:10 +00:00
generate = chan - > generator - > generate ;
res = generate ( chan , tmp , f - > datalen , f - > samples ) ;
2002-06-21 01:40:13 +00:00
chan - > generatordata = tmp ;
if ( res ) {
ast_log ( LOG_DEBUG , " Auto-deactivating generator \n " ) ;
2004-04-07 14:43:18 +00:00
ast_deactivate_generator ( chan ) ;
2002-06-21 01:40:13 +00:00
}
}
2003-03-12 06:00:18 +00:00
if ( chan - > fin & 0x80000000 )
ast_frame_dump ( chan - > name , f , " << " ) ;
if ( ( chan - > fin & 0x7fffffff ) = = 0x7fffffff )
chan - > fin & = 0x80000000 ;
else
chan - > fin + + ;
2004-04-02 21:58:10 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
1999-12-04 21:35:07 +00:00
return f ;
}
2001-05-07 00:43:32 +00:00
int ast_indicate ( struct ast_channel * chan , int condition )
{
int res = - 1 ;
/* Stop if we're a zombie or need a soft hangup */
2001-12-20 15:21:47 +00:00
if ( chan - > zombie | | ast_check_hangup ( chan ) )
2001-05-07 00:43:32 +00:00
return - 1 ;
2003-08-13 18:29:58 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2003-02-05 21:18:09 +00:00
if ( chan - > pvt - > indicate )
2001-05-07 00:43:32 +00:00
res = chan - > pvt - > indicate ( chan , condition ) ;
2003-08-14 18:46:02 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2003-02-05 21:18:09 +00:00
if ( ! chan - > pvt - > indicate | | res ) {
/*
* Device does not support ( that ) indication , lets fake
* it by doing our own tone generation . ( PM2002 )
*/
if ( condition > = 0 ) {
const struct tone_zone_sound * ts = NULL ;
switch ( condition ) {
case AST_CONTROL_RINGING :
ts = ast_get_indication_tone ( chan - > zone , " ring " ) ;
break ;
case AST_CONTROL_BUSY :
ts = ast_get_indication_tone ( chan - > zone , " busy " ) ;
break ;
case AST_CONTROL_CONGESTION :
ts = ast_get_indication_tone ( chan - > zone , " congestion " ) ;
break ;
}
if ( ts & & ts - > data [ 0 ] ) {
ast_log ( LOG_DEBUG , " Driver for channel '%s' does not support indication %d, emulating it \n " , chan - > name , condition ) ;
2003-03-16 22:37:31 +00:00
ast_playtones_start ( chan , 0 , ts - > data , 1 ) ;
2003-08-13 18:29:58 +00:00
res = 0 ;
2003-05-15 22:39:01 +00:00
} else if ( condition = = AST_CONTROL_PROGRESS ) {
/* ast_playtones_stop(chan); */
} else {
2003-02-05 21:18:09 +00:00
/* not handled */
ast_log ( LOG_WARNING , " Unable to handle indication %d for '%s' \n " , condition , chan - > name ) ;
2003-08-13 18:29:58 +00:00
res = - 1 ;
2003-02-05 21:18:09 +00:00
}
}
else ast_playtones_stop ( chan ) ;
}
2003-08-13 18:29:58 +00:00
return res ;
2001-05-07 00:43:32 +00:00
}
2001-12-20 15:21:47 +00:00
int ast_recvchar ( struct ast_channel * chan , int timeout )
{
int res , ourto , c ;
struct ast_frame * f ;
ourto = timeout ;
for ( ; ; )
{
if ( ast_check_hangup ( chan ) ) return - 1 ;
res = ast_waitfor ( chan , ourto ) ;
if ( res < = 0 ) /* if timeout */
{
return 0 ;
}
ourto = res ;
f = ast_read ( chan ) ;
if ( f = = NULL ) return - 1 ; /* if hangup */
if ( ( f - > frametype = = AST_FRAME_CONTROL ) & &
2004-04-27 21:21:57 +00:00
( f - > subclass = = AST_CONTROL_HANGUP ) ) return - 1 ; /* if hangup */
if ( f - > frametype = = AST_FRAME_TEXT ) /* if a text frame */
2001-12-20 15:21:47 +00:00
{
2004-04-27 21:21:57 +00:00
c = * ( ( char * ) f - > data ) ; /* get the data */
2001-12-20 15:21:47 +00:00
ast_frfree ( f ) ;
return ( c ) ;
}
ast_frfree ( f ) ;
}
}
2000-03-26 01:59:06 +00:00
int ast_sendtext ( struct ast_channel * chan , char * text )
{
int res = 0 ;
2001-05-07 00:43:32 +00:00
/* Stop if we're a zombie or need a soft hangup */
2001-12-20 15:21:47 +00:00
if ( chan - > zombie | | ast_check_hangup ( chan ) )
2001-05-07 00:43:32 +00:00
return - 1 ;
2000-03-26 01:59:06 +00:00
CHECK_BLOCKING ( chan ) ;
if ( chan - > pvt - > send_text )
res = chan - > pvt - > send_text ( chan , text ) ;
chan - > blocking = 0 ;
return res ;
}
2003-02-05 21:18:09 +00:00
static int do_senddigit ( struct ast_channel * chan , char digit )
{
int res = - 1 ;
if ( chan - > pvt - > send_digit )
res = chan - > pvt - > send_digit ( chan , digit ) ;
if ( ! chan - > pvt - > send_digit | | res ) {
/*
* Device does not support DTMF tones , lets fake
* it by doing our own generation . ( PM2002 )
*/
static const char * dtmf_tones [ ] = {
2004-04-27 21:21:57 +00:00
" !941+1336/100,!0/100 " , /* 0 */
" !697+1209/100,!0/100 " , /* 1 */
" !697+1336/100,!0/100 " , /* 2 */
" !697+1477/100,!0/100 " , /* 3 */
" !770+1209/100,!0/100 " , /* 4 */
" !770+1336/100,!0/100 " , /* 5 */
" !770+1477/100,!0/100 " , /* 6 */
" !852+1209/100,!0/100 " , /* 7 */
" !852+1336/100,!0/100 " , /* 8 */
" !852+1477/100,!0/100 " , /* 9 */
" !697+1633/100,!0/100 " , /* A */
" !770+1633/100,!0/100 " , /* B */
" !852+1633/100,!0/100 " , /* C */
" !941+1633/100,!0/100 " , /* D */
" !941+1209/100,!0/100 " , /* * */
2004-02-25 16:01:56 +00:00
" !941+1477/100,!0/100 " } ; /* # */
2003-02-05 21:18:09 +00:00
if ( digit > = ' 0 ' & & digit < = ' 9 ' )
2003-03-16 22:37:31 +00:00
ast_playtones_start ( chan , 0 , dtmf_tones [ digit - ' 0 ' ] , 0 ) ;
2003-02-05 21:18:09 +00:00
else if ( digit > = ' A ' & & digit < = ' D ' )
2003-03-16 22:37:31 +00:00
ast_playtones_start ( chan , 0 , dtmf_tones [ digit - ' A ' + 10 ] , 0 ) ;
2003-02-05 21:18:09 +00:00
else if ( digit = = ' * ' )
2003-03-16 22:37:31 +00:00
ast_playtones_start ( chan , 0 , dtmf_tones [ 14 ] , 0 ) ;
2003-02-05 21:18:09 +00:00
else if ( digit = = ' # ' )
2003-03-16 22:37:31 +00:00
ast_playtones_start ( chan , 0 , dtmf_tones [ 15 ] , 0 ) ;
2003-02-05 21:18:09 +00:00
else {
/* not handled */
2004-05-15 22:53:55 +00:00
ast_log ( LOG_DEBUG , " Unable to handle DTMF tone '%c' for '%s' \n " , digit , chan - > name ) ;
2003-02-05 21:18:09 +00:00
}
}
return 0 ;
}
2004-05-20 00:29:09 +00:00
int ast_senddigit ( struct ast_channel * chan , char digit )
{
return do_senddigit ( chan , digit ) ;
}
2003-04-16 02:47:03 +00:00
int ast_prod ( struct ast_channel * chan )
{
struct ast_frame a = { AST_FRAME_VOICE } ;
char nothing [ 128 ] ;
/* Send an empty audio frame to get things moving */
if ( chan - > _state ! = AST_STATE_UP ) {
2003-04-17 02:52:53 +00:00
ast_log ( LOG_DEBUG , " Prodding channel '%s' \n " , chan - > name ) ;
2003-04-16 02:47:03 +00:00
a . subclass = chan - > pvt - > rawwriteformat ;
a . data = nothing + AST_FRIENDLY_OFFSET ;
2003-04-17 02:52:53 +00:00
if ( ast_write ( chan , & a ) )
ast_log ( LOG_WARNING , " Prodding channel '%s' failed \n " , chan - > name ) ;
2003-04-16 02:47:03 +00:00
}
return 0 ;
}
2003-06-28 16:40:02 +00:00
int ast_write_video ( struct ast_channel * chan , struct ast_frame * fr )
{
int res ;
if ( ! chan - > pvt - > write_video )
return 0 ;
res = ast_write ( chan , fr ) ;
if ( ! res )
res = 1 ;
return res ;
}
1999-12-04 21:35:07 +00:00
int ast_write ( struct ast_channel * chan , struct ast_frame * fr )
{
int res = - 1 ;
2003-02-12 13:59:15 +00:00
struct ast_frame * f = NULL ;
2001-05-07 00:43:32 +00:00
/* Stop if we're a zombie or need a soft hangup */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2004-04-27 21:21:57 +00:00
if ( chan - > zombie | | ast_check_hangup ( chan ) ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-05-07 00:43:32 +00:00
return - 1 ;
2003-07-29 16:09:03 +00:00
}
2001-05-07 00:43:32 +00:00
/* Handle any pending masquerades */
if ( chan - > masq ) {
2004-04-06 22:17:32 +00:00
if ( ast_do_masquerade ( chan ) ) {
2001-05-07 00:43:32 +00:00
ast_log ( LOG_WARNING , " Failed to perform masquerade \n " ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-05-07 00:43:32 +00:00
return - 1 ;
}
}
2003-07-29 16:09:03 +00:00
if ( chan - > masqr ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-05-07 00:43:32 +00:00
return 0 ;
2003-07-29 16:09:03 +00:00
}
2002-06-21 01:40:13 +00:00
if ( chan - > generatordata ) {
if ( chan - > writeinterrupt )
2004-04-07 14:43:18 +00:00
ast_deactivate_generator ( chan ) ;
2003-07-29 16:09:03 +00:00
else {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2002-06-21 01:40:13 +00:00
return 0 ;
2003-07-29 16:09:03 +00:00
}
2002-06-21 01:40:13 +00:00
}
2003-03-12 06:00:18 +00:00
if ( chan - > fout & 0x80000000 )
ast_frame_dump ( chan - > name , fr , " >> " ) ;
1999-12-04 21:35:07 +00:00
CHECK_BLOCKING ( chan ) ;
switch ( fr - > frametype ) {
case AST_FRAME_CONTROL :
/* XXX Interpret control frames XXX */
ast_log ( LOG_WARNING , " Don't know how to handle control frames yet \n " ) ;
break ;
case AST_FRAME_DTMF :
2003-09-24 19:43:14 +00:00
chan - > blocking = 0 ;
ast_mutex_unlock ( & chan - > lock ) ;
2003-02-05 21:18:09 +00:00
res = do_senddigit ( chan , fr - > subclass ) ;
2003-09-24 19:43:14 +00:00
ast_mutex_lock ( & chan - > lock ) ;
CHECK_BLOCKING ( chan ) ;
1999-12-04 21:35:07 +00:00
break ;
2001-12-20 15:21:47 +00:00
case AST_FRAME_TEXT :
if ( chan - > pvt - > send_text )
res = chan - > pvt - > send_text ( chan , ( char * ) fr - > data ) ;
break ;
2003-06-28 16:40:02 +00:00
case AST_FRAME_VIDEO :
/* XXX Handle translation of video codecs one day XXX */
if ( chan - > pvt - > write_video )
res = chan - > pvt - > write_video ( chan , fr ) ;
else
res = 0 ;
break ;
1999-12-04 21:35:07 +00:00
default :
2001-03-12 03:04:51 +00:00
if ( chan - > pvt - > write ) {
if ( chan - > pvt - > writetrans ) {
2003-02-12 13:59:15 +00:00
f = ast_translate ( chan - > pvt - > writetrans , fr , 0 ) ;
2001-03-12 03:04:51 +00:00
} else
f = fr ;
2003-08-28 20:02:10 +00:00
if ( f ) {
2001-03-12 03:04:51 +00:00
res = chan - > pvt - > write ( chan , f ) ;
2003-03-25 19:30:06 +00:00
if ( chan - > monitor & &
chan - > monitor - > write_stream & &
f & & ( f - > frametype = = AST_FRAME_VOICE ) ) {
2003-08-28 20:02:10 +00:00
# ifndef MONITOR_CONSTANT_DELAY
int jump = chan - > insmpl - chan - > outsmpl - 2 * f - > samples ;
if ( jump > = 0 ) {
if ( ast_seekstream ( chan - > monitor - > write_stream , jump + f - > samples , SEEK_FORCECUR ) = = - 1 )
ast_log ( LOG_WARNING , " Failed to perform seek in monitoring write stream, synchronization between the files may be broken \n " ) ;
chan - > outsmpl + = jump + 2 * f - > samples ;
} else
chan - > outsmpl + = f - > samples ;
# else
int jump = chan - > insmpl - chan - > outsmpl ;
if ( jump - MONITOR_DELAY > = 0 ) {
if ( ast_seekstream ( chan - > monitor - > write_stream , jump - f - > samples , SEEK_FORCECUR ) = = - 1 )
ast_log ( LOG_WARNING , " Failed to perform seek in monitoring write stream, synchronization between the files may be broken \n " ) ;
chan - > outsmpl + = jump ;
} else
chan - > outsmpl + = f - > samples ;
# endif
if ( ast_writestream ( chan - > monitor - > write_stream , f ) < 0 )
2003-03-25 19:30:06 +00:00
ast_log ( LOG_WARNING , " Failed to write data to channel monitor write stream \n " ) ;
}
2003-08-28 20:02:10 +00:00
} else
2001-05-07 00:43:32 +00:00
res = 0 ;
2001-03-12 03:04:51 +00:00
}
1999-12-04 21:35:07 +00:00
}
2003-02-12 13:59:15 +00:00
if ( f & & ( f ! = fr ) )
ast_frfree ( f ) ;
1999-12-04 21:35:07 +00:00
chan - > blocking = 0 ;
2002-06-21 01:40:13 +00:00
/* Consider a write failure to force a soft hangup */
if ( res < 0 )
2002-09-10 20:48:20 +00:00
chan - > _softhangup | = AST_SOFTHANGUP_DEV ;
2003-03-12 06:00:18 +00:00
else {
if ( ( chan - > fout & 0x7fffffff ) = = 0x7fffffff )
chan - > fout & = 0x80000000 ;
else
chan - > fout + + ;
2003-02-05 21:18:09 +00:00
chan - > fout + + ;
2003-03-12 06:00:18 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
1999-12-04 21:35:07 +00:00
return res ;
}
2004-04-06 22:17:32 +00:00
int ast_set_write_format ( struct ast_channel * chan , int fmts )
2001-03-12 03:04:51 +00:00
{
int fmt ;
int native ;
int res ;
2004-04-06 22:17:32 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2001-03-12 03:04:51 +00:00
native = chan - > nativeformats ;
fmt = fmts ;
res = ast_translator_best_choice ( & native , & fmt ) ;
if ( res < 0 ) {
2003-08-16 05:10:35 +00:00
ast_log ( LOG_NOTICE , " Unable to find a path from %s to %s \n " ,
ast_getformatname ( fmts ) , ast_getformatname ( chan - > nativeformats ) ) ;
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
2004-04-27 21:21:57 +00:00
/* Now we have a good choice for both. We'll write using our native format. */
2001-03-12 03:04:51 +00:00
chan - > pvt - > rawwriteformat = native ;
/* User perspective is fmt */
chan - > writeformat = fmt ;
/* Free any write translation we have right now */
if ( chan - > pvt - > writetrans )
ast_translator_free_path ( chan - > pvt - > writetrans ) ;
/* Build a translation path from the user write format to the raw writing format */
chan - > pvt - > writetrans = ast_translator_build_path ( chan - > pvt - > rawwriteformat , chan - > writeformat ) ;
2001-05-07 00:43:32 +00:00
if ( option_debug )
2003-08-16 05:10:35 +00:00
ast_log ( LOG_DEBUG , " Set channel %s to write format %s \n " , chan - > name , ast_getformatname ( chan - > writeformat ) ) ;
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-03-12 03:04:51 +00:00
return 0 ;
}
2004-04-06 22:17:32 +00:00
int ast_set_read_format ( struct ast_channel * chan , int fmts )
2001-03-12 03:04:51 +00:00
{
int fmt ;
int native ;
int res ;
2004-04-06 22:17:32 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2001-03-12 03:04:51 +00:00
native = chan - > nativeformats ;
fmt = fmts ;
/* Find a translation path from the native read format to one of the user's read formats */
res = ast_translator_best_choice ( & fmt , & native ) ;
if ( res < 0 ) {
2003-08-16 05:10:35 +00:00
ast_log ( LOG_NOTICE , " Unable to find a path from %s to %s \n " ,
ast_getformatname ( chan - > nativeformats ) , ast_getformatname ( fmts ) ) ;
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
2004-04-27 21:21:57 +00:00
/* Now we have a good choice for both. We'll write using our native format. */
2001-03-12 03:04:51 +00:00
chan - > pvt - > rawreadformat = native ;
/* User perspective is fmt */
chan - > readformat = fmt ;
/* Free any read translation we have right now */
if ( chan - > pvt - > readtrans )
ast_translator_free_path ( chan - > pvt - > readtrans ) ;
/* Build a translation path from the raw read format to the user reading format */
chan - > pvt - > readtrans = ast_translator_build_path ( chan - > readformat , chan - > pvt - > rawreadformat ) ;
2001-12-20 15:21:47 +00:00
if ( option_debug )
2003-08-16 05:10:35 +00:00
ast_log ( LOG_DEBUG , " Set channel %s to read format %s \n " ,
chan - > name , ast_getformatname ( chan - > readformat ) ) ;
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-03-12 03:04:51 +00:00
return 0 ;
}
2003-09-22 15:27:09 +00:00
struct ast_channel * __ast_request_and_dial ( char * type , int format , void * data , int timeout , int * outstate , char * callerid , struct outgoing_helper * oh )
2002-09-10 20:48:20 +00:00
{
int state = 0 ;
struct ast_channel * chan ;
struct ast_frame * f ;
2003-09-12 16:51:35 +00:00
int res = 0 ;
2004-05-27 16:50:07 +00:00
char * variable ;
2002-09-10 20:48:20 +00:00
chan = ast_request ( type , format , data ) ;
if ( chan ) {
2003-09-22 15:27:09 +00:00
if ( oh ) {
char * tmp , * var ;
/* JDG chanvar */
2004-05-27 16:50:07 +00:00
if ( oh - > variable )
variable = ast_strdupa ( oh - > variable ) ;
else
variable = NULL ;
tmp = variable ;
2004-04-27 21:21:57 +00:00
/* FIXME replace this call with strsep NOT*/
2003-09-22 15:27:09 +00:00
while ( ( var = strtok_r ( NULL , " | " , & tmp ) ) ) {
pbx_builtin_setvar ( chan , var ) ;
} /* /JDG */
2003-10-01 21:01:31 +00:00
if ( oh - > callerid & & * oh - > callerid )
2003-09-22 15:27:09 +00:00
ast_set_callerid ( chan , oh - > callerid , 1 ) ;
2003-10-01 21:01:31 +00:00
if ( oh - > account & & * oh - > account )
ast_cdr_setaccount ( chan , oh - > account ) ;
2003-09-22 15:27:09 +00:00
}
2004-05-06 21:04:22 +00:00
if ( callerid & & ! ast_strlen_zero ( callerid ) )
2003-10-01 14:59:40 +00:00
ast_set_callerid ( chan , callerid , 1 ) ;
2003-09-22 15:27:09 +00:00
2002-09-10 20:48:20 +00:00
if ( ! ast_call ( chan , data , 0 ) ) {
while ( timeout & & ( chan - > _state ! = AST_STATE_UP ) ) {
res = ast_waitfor ( chan , timeout ) ;
if ( res < 0 ) {
/* Something not cool, or timed out */
break ;
}
/* If done, break out */
if ( ! res )
break ;
if ( timeout > - 1 )
timeout = res ;
f = ast_read ( chan ) ;
if ( ! f ) {
state = AST_CONTROL_HANGUP ;
2003-09-12 16:51:35 +00:00
res = 0 ;
2002-09-10 20:48:20 +00:00
break ;
}
if ( f - > frametype = = AST_FRAME_CONTROL ) {
if ( f - > subclass = = AST_CONTROL_RINGING )
state = AST_CONTROL_RINGING ;
else if ( ( f - > subclass = = AST_CONTROL_BUSY ) | | ( f - > subclass = = AST_CONTROL_CONGESTION ) ) {
state = f - > subclass ;
2003-08-04 23:30:49 +00:00
ast_frfree ( f ) ;
2002-09-10 20:48:20 +00:00
break ;
} else if ( f - > subclass = = AST_CONTROL_ANSWER ) {
state = f - > subclass ;
2003-08-04 23:30:49 +00:00
ast_frfree ( f ) ;
2002-09-10 20:48:20 +00:00
break ;
2004-05-16 17:50:14 +00:00
} else if ( f - > subclass = = AST_CONTROL_PROGRESS ) {
/* Ignore */
2004-03-08 02:09:56 +00:00
} else if ( f - > subclass = = - 1 ) {
/* Ignore -- just stopping indications */
2002-09-10 20:48:20 +00:00
} else {
ast_log ( LOG_NOTICE , " Don't know what to do with control frame %d \n " , f - > subclass ) ;
}
}
ast_frfree ( f ) ;
}
2003-09-12 16:51:35 +00:00
} else
2002-09-10 20:48:20 +00:00
ast_log ( LOG_NOTICE , " Unable to request channel %s/%s \n " , type , ( char * ) data ) ;
} else
ast_log ( LOG_NOTICE , " Unable to request channel %s/%s \n " , type , ( char * ) data ) ;
2003-10-09 14:12:26 +00:00
if ( chan ) {
/* Final fixups */
if ( oh ) {
if ( oh - > context & & * oh - > context )
strncpy ( chan - > context , oh - > context , sizeof ( chan - > context ) - 1 ) ;
if ( oh - > exten & & * oh - > exten )
strncpy ( chan - > exten , oh - > exten , sizeof ( chan - > exten ) - 1 ) ;
chan - > priority = oh - > priority ;
}
if ( chan - > _state = = AST_STATE_UP )
state = AST_CONTROL_ANSWER ;
}
2002-09-10 20:48:20 +00:00
if ( outstate )
* outstate = state ;
2003-09-12 16:51:35 +00:00
if ( chan & & res < = 0 ) {
if ( ! chan - > cdr ) {
chan - > cdr = ast_cdr_alloc ( ) ;
if ( chan - > cdr )
ast_cdr_init ( chan - > cdr , chan ) ;
}
if ( chan - > cdr ) {
char tmp [ 256 ] ;
sprintf ( tmp , " %s/%s " , type , ( char * ) data ) ;
ast_cdr_setapp ( chan - > cdr , " Dial " , tmp ) ;
ast_cdr_update ( chan ) ;
ast_cdr_start ( chan - > cdr ) ;
ast_cdr_end ( chan - > cdr ) ;
/* If the cause wasn't handled properly */
if ( ast_cdr_disposition ( chan - > cdr , chan - > hangupcause ) )
ast_cdr_failed ( chan - > cdr ) ;
} else
ast_log ( LOG_WARNING , " Unable to create Call Detail Record \n " ) ;
ast_hangup ( chan ) ;
chan = NULL ;
}
2002-09-10 20:48:20 +00:00
return chan ;
}
2003-09-22 15:27:09 +00:00
struct ast_channel * ast_request_and_dial ( char * type , int format , void * data , int timeout , int * outstate , char * callerid )
{
return __ast_request_and_dial ( type , format , data , timeout , outstate , callerid , NULL ) ;
}
1999-12-04 21:35:07 +00:00
struct ast_channel * ast_request ( char * type , int format , void * data )
{
struct chanlist * chan ;
struct ast_channel * c = NULL ;
2001-03-12 03:04:51 +00:00
int capabilities ;
int fmt ;
int res ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & chlock ) ) {
1999-12-04 21:35:07 +00:00
ast_log ( LOG_WARNING , " Unable to lock channel list \n " ) ;
return NULL ;
}
chan = backends ;
while ( chan ) {
if ( ! strcasecmp ( type , chan - > type ) ) {
2001-03-12 03:04:51 +00:00
capabilities = chan - > capabilities ;
fmt = format ;
res = ast_translator_best_choice ( & fmt , & capabilities ) ;
if ( res < 0 ) {
ast_log ( LOG_WARNING , " No translator path exists for channel type %s (native %d) to %d \n " , type , chan - > capabilities , format ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
2001-03-12 03:04:51 +00:00
return NULL ;
1999-12-18 07:01:48 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-04 21:35:07 +00:00
if ( chan - > requester )
2001-03-12 03:04:51 +00:00
c = chan - > requester ( type , capabilities , data ) ;
2002-09-10 20:48:20 +00:00
if ( c ) {
2003-08-15 18:29:33 +00:00
if ( c - > _state = = AST_STATE_DOWN ) {
manager_event ( EVENT_FLAG_CALL , " Newchannel " ,
" Channel: %s \r \n "
" State: %s \r \n "
" Callerid: %s \r \n "
" Uniqueid: %s \r \n " ,
c - > name , ast_state2str ( c - > _state ) , c - > callerid ? c - > callerid : " <unknown> " , c - > uniqueid ) ;
}
2002-09-10 20:48:20 +00:00
}
2000-01-02 20:59:00 +00:00
return c ;
1999-12-04 21:35:07 +00:00
}
chan = chan - > next ;
}
if ( ! chan )
ast_log ( LOG_WARNING , " No channel type registered for '%s' \n " , type ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-04 21:35:07 +00:00
return c ;
}
2003-03-30 22:55:42 +00:00
int ast_parse_device_state ( char * device )
{
char name [ AST_CHANNEL_NAME ] = " " ;
char * cut ;
struct ast_channel * chan ;
2004-05-20 16:30:10 +00:00
chan = ast_channel_walk_locked ( NULL ) ;
2003-03-30 22:55:42 +00:00
while ( chan ) {
strncpy ( name , chan - > name , sizeof ( name ) - 1 ) ;
2004-05-20 16:30:10 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2003-03-30 22:55:42 +00:00
cut = strchr ( name , ' - ' ) ;
if ( cut )
2004-04-27 21:21:57 +00:00
* cut = 0 ;
2003-03-30 22:55:42 +00:00
if ( ! strcmp ( name , device ) )
2004-04-27 21:21:57 +00:00
return AST_DEVICE_INUSE ;
2004-05-20 16:30:10 +00:00
chan = ast_channel_walk_locked ( chan ) ;
2003-03-30 22:55:42 +00:00
}
return AST_DEVICE_UNKNOWN ;
}
int ast_device_state ( char * device )
{
char tech [ AST_MAX_EXTENSION ] = " " ;
char * number ;
struct chanlist * chanls ;
int res = 0 ;
strncpy ( tech , device , sizeof ( tech ) - 1 ) ;
number = strchr ( tech , ' / ' ) ;
if ( ! number ) {
2004-04-27 21:21:57 +00:00
return AST_DEVICE_INVALID ;
2003-03-30 22:55:42 +00:00
}
* number = 0 ;
number + + ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & chlock ) ) {
2003-03-30 22:55:42 +00:00
ast_log ( LOG_WARNING , " Unable to lock channel list \n " ) ;
return - 1 ;
}
chanls = backends ;
while ( chanls ) {
if ( ! strcasecmp ( tech , chanls - > type ) ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
2003-03-30 22:55:42 +00:00
if ( ! chanls - > devicestate )
return ast_parse_device_state ( device ) ;
else {
res = chanls - > devicestate ( number ) ;
if ( res = = AST_DEVICE_UNKNOWN )
return ast_parse_device_state ( device ) ;
else
return res ;
}
}
chanls = chanls - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
2003-03-30 22:55:42 +00:00
return AST_DEVICE_INVALID ;
}
1999-12-04 21:35:07 +00:00
int ast_call ( struct ast_channel * chan , char * addr , int timeout )
{
/* Place an outgoing call, but don't wait any longer than timeout ms before returning.
If the remote end does not answer within the timeout , then do NOT hang up , but
return anyway . */
int res = - 1 ;
2001-05-07 00:43:32 +00:00
/* Stop if we're a zombie or need a soft hangup */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2001-12-20 15:21:47 +00:00
if ( ! chan - > zombie & & ! ast_check_hangup ( chan ) )
2001-05-07 00:43:32 +00:00
if ( chan - > pvt - > call )
res = chan - > pvt - > call ( chan , addr , timeout ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
1999-12-04 21:35:07 +00:00
return res ;
}
2003-05-14 05:33:06 +00:00
int ast_transfer ( struct ast_channel * chan , char * dest )
{
/* Place an outgoing call, but don't wait any longer than timeout ms before returning.
If the remote end does not answer within the timeout , then do NOT hang up , but
return anyway . */
int res = - 1 ;
/* Stop if we're a zombie or need a soft hangup */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2003-05-14 05:33:06 +00:00
if ( ! chan - > zombie & & ! ast_check_hangup ( chan ) ) {
if ( chan - > pvt - > transfer ) {
res = chan - > pvt - > transfer ( chan , dest ) ;
if ( ! res )
res = 1 ;
} else
res = 0 ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2003-05-14 05:33:06 +00:00
return res ;
}
1999-12-04 21:35:07 +00:00
int ast_readstring ( struct ast_channel * c , char * s , int len , int timeout , int ftimeout , char * enders )
{
int pos = 0 ;
int to = ftimeout ;
char d ;
2003-02-23 06:00:11 +00:00
/* XXX Merge with full version? XXX */
2001-05-07 00:43:32 +00:00
/* Stop if we're a zombie or need a soft hangup */
2001-12-20 15:21:47 +00:00
if ( c - > zombie | | ast_check_hangup ( c ) )
2001-05-07 00:43:32 +00:00
return - 1 ;
1999-12-04 21:35:07 +00:00
if ( ! len )
return - 1 ;
do {
2003-06-29 21:54:58 +00:00
if ( c - > stream ) {
1999-12-04 21:35:07 +00:00
d = ast_waitstream ( c , AST_DIGIT_ANY ) ;
ast_stopstream ( c ) ;
2000-01-02 20:59:00 +00:00
usleep ( 1000 ) ;
1999-12-04 21:35:07 +00:00
if ( ! d )
d = ast_waitfordigit ( c , to ) ;
} else {
d = ast_waitfordigit ( c , to ) ;
}
if ( d < 0 )
return - 1 ;
2001-09-19 14:40:16 +00:00
if ( d = = 0 ) {
s [ pos ] = ' \0 ' ;
return 1 ;
}
1999-12-04 21:35:07 +00:00
if ( ! strchr ( enders , d ) )
s [ pos + + ] = d ;
2002-03-10 17:14:13 +00:00
if ( strchr ( enders , d ) | | ( pos > = len ) ) {
1999-12-04 21:35:07 +00:00
s [ pos ] = ' \0 ' ;
2003-02-23 06:00:11 +00:00
return 0 ;
}
to = timeout ;
} while ( 1 ) ;
/* Never reached */
return 0 ;
}
int ast_readstring_full ( struct ast_channel * c , char * s , int len , int timeout , int ftimeout , char * enders , int audiofd , int ctrlfd )
{
int pos = 0 ;
int to = ftimeout ;
char d ;
/* Stop if we're a zombie or need a soft hangup */
if ( c - > zombie | | ast_check_hangup ( c ) )
return - 1 ;
if ( ! len )
return - 1 ;
do {
2003-06-29 21:54:58 +00:00
if ( c - > stream ) {
2003-02-23 06:00:11 +00:00
d = ast_waitstream_full ( c , AST_DIGIT_ANY , audiofd , ctrlfd ) ;
ast_stopstream ( c ) ;
usleep ( 1000 ) ;
if ( ! d )
d = ast_waitfordigit_full ( c , to , audiofd , ctrlfd ) ;
} else {
d = ast_waitfordigit_full ( c , to , audiofd , ctrlfd ) ;
}
if ( d < 0 )
return - 1 ;
if ( d = = 0 ) {
s [ pos ] = ' \0 ' ;
return 1 ;
}
if ( d = = 1 ) {
s [ pos ] = ' \0 ' ;
return 2 ;
}
if ( ! strchr ( enders , d ) )
s [ pos + + ] = d ;
if ( strchr ( enders , d ) | | ( pos > = len ) ) {
s [ pos ] = ' \0 ' ;
1999-12-04 21:35:07 +00:00
return 0 ;
}
to = timeout ;
} while ( 1 ) ;
/* Never reached */
return 0 ;
}
2001-03-12 03:04:51 +00:00
2001-09-19 14:40:16 +00:00
int ast_channel_supports_html ( struct ast_channel * chan )
{
if ( chan - > pvt - > send_html )
return 1 ;
return 0 ;
}
int ast_channel_sendhtml ( struct ast_channel * chan , int subclass , char * data , int datalen )
{
if ( chan - > pvt - > send_html )
return chan - > pvt - > send_html ( chan , subclass , data , datalen ) ;
return - 1 ;
}
int ast_channel_sendurl ( struct ast_channel * chan , char * url )
{
if ( chan - > pvt - > send_html )
return chan - > pvt - > send_html ( chan , AST_HTML_URL , url , strlen ( url ) + 1 ) ;
return - 1 ;
}
2001-03-12 03:04:51 +00:00
int ast_channel_make_compatible ( struct ast_channel * chan , struct ast_channel * peer )
{
int peerf ;
int chanf ;
int res ;
2004-03-27 06:50:12 +00:00
ast_mutex_lock ( & peer - > lock ) ;
2001-03-12 03:04:51 +00:00
peerf = peer - > nativeformats ;
2004-03-27 06:50:12 +00:00
ast_mutex_unlock ( & peer - > lock ) ;
ast_mutex_lock ( & chan - > lock ) ;
2001-03-12 03:04:51 +00:00
chanf = chan - > nativeformats ;
2004-03-27 06:50:12 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-03-12 03:04:51 +00:00
res = ast_translator_best_choice ( & peerf , & chanf ) ;
if ( res < 0 ) {
2002-06-21 01:40:13 +00:00
ast_log ( LOG_WARNING , " No path to translate from %s(%d) to %s(%d) \n " , chan - > name , chan - > nativeformats , peer - > name , peer - > nativeformats ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
/* Set read format on channel */
2004-04-06 22:17:32 +00:00
res = ast_set_read_format ( chan , peerf ) ;
2001-03-12 03:04:51 +00:00
if ( res < 0 ) {
2002-06-21 01:40:13 +00:00
ast_log ( LOG_WARNING , " Unable to set read format on channel %s to %d \n " , chan - > name , chanf ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
/* Set write format on peer channel */
2004-04-06 22:17:32 +00:00
res = ast_set_write_format ( peer , peerf ) ;
2001-03-12 03:04:51 +00:00
if ( res < 0 ) {
2002-06-21 01:40:13 +00:00
ast_log ( LOG_WARNING , " Unable to set write format on channel %s to %d \n " , peer - > name , peerf ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
/* Now we go the other way */
peerf = peer - > nativeformats ;
chanf = chan - > nativeformats ;
res = ast_translator_best_choice ( & chanf , & peerf ) ;
if ( res < 0 ) {
2002-06-21 01:40:13 +00:00
ast_log ( LOG_WARNING , " No path to translate from %s(%d) to %s(%d) \n " , peer - > name , peer - > nativeformats , chan - > name , chan - > nativeformats ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
/* Set writeformat on channel */
2004-04-06 22:17:32 +00:00
res = ast_set_write_format ( chan , chanf ) ;
2001-03-12 03:04:51 +00:00
if ( res < 0 ) {
2002-06-21 01:40:13 +00:00
ast_log ( LOG_WARNING , " Unable to set write format on channel %s to %d \n " , chan - > name , chanf ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
/* Set read format on peer channel */
2004-04-06 22:17:32 +00:00
res = ast_set_read_format ( peer , chanf ) ;
2001-03-12 03:04:51 +00:00
if ( res < 0 ) {
2002-06-21 01:40:13 +00:00
ast_log ( LOG_WARNING , " Unable to set read format on channel %s to %d \n " , peer - > name , peerf ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
return 0 ;
}
2001-05-07 00:43:32 +00:00
int ast_channel_masquerade ( struct ast_channel * original , struct ast_channel * clone )
{
2003-02-24 06:00:18 +00:00
struct ast_frame null = { AST_FRAME_NULL , } ;
2004-04-20 03:16:01 +00:00
int res = - 1 ;
ast_mutex_lock ( & original - > lock ) ;
while ( ast_mutex_trylock ( & clone - > lock ) ) {
ast_mutex_unlock ( & original - > lock ) ;
usleep ( 1 ) ;
ast_mutex_lock ( & original - > lock ) ;
}
2001-05-07 00:43:32 +00:00
ast_log ( LOG_DEBUG , " Planning to masquerade %s into the structure of %s \n " ,
clone - > name , original - > name ) ;
if ( original - > masq ) {
ast_log ( LOG_WARNING , " %s is already going to masquerade as %s \n " ,
original - > masq - > name , original - > name ) ;
2004-04-20 03:16:01 +00:00
} else if ( clone - > masqr ) {
2001-05-07 00:43:32 +00:00
ast_log ( LOG_WARNING , " %s is already going to masquerade as %s \n " ,
clone - > name , clone - > masqr - > name ) ;
2004-04-20 03:16:01 +00:00
} else {
original - > masq = clone ;
clone - > masqr = original ;
ast_queue_frame ( original , & null ) ;
ast_queue_frame ( clone , & null ) ;
ast_log ( LOG_DEBUG , " Done planning to masquerade %s into the structure of %s \n " , original - > name , clone - > name ) ;
res = 0 ;
}
ast_mutex_unlock ( & clone - > lock ) ;
ast_mutex_unlock ( & original - > lock ) ;
return res ;
2001-05-07 00:43:32 +00:00
}
2003-02-05 21:18:09 +00:00
void ast_change_name ( struct ast_channel * chan , char * newname )
{
char tmp [ 256 ] ;
strncpy ( tmp , chan - > name , 256 ) ;
strncpy ( chan - > name , newname , sizeof ( chan - > name ) - 1 ) ;
2003-06-11 12:24:13 +00:00
manager_event ( EVENT_FLAG_CALL , " Rename " , " Oldname: %s \r \n Newname: %s \r \n Uniqueid: %s \r \n " , tmp , chan - > name , chan - > uniqueid ) ;
2003-02-05 21:18:09 +00:00
}
2004-04-06 22:17:32 +00:00
int ast_do_masquerade ( struct ast_channel * original )
2001-05-07 00:43:32 +00:00
{
2003-08-14 19:18:18 +00:00
int x , i ;
2001-05-07 00:43:32 +00:00
int res = 0 ;
char * tmp ;
2004-01-30 06:48:01 +00:00
struct ast_var_t * varptr ;
2003-08-14 19:18:18 +00:00
struct ast_frame * cur , * prev ;
2001-05-07 00:43:32 +00:00
struct ast_channel_pvt * p ;
struct ast_channel * clone = original - > masq ;
2001-09-19 14:40:16 +00:00
int rformat = original - > readformat ;
int wformat = original - > writeformat ;
2002-09-10 20:48:20 +00:00
char newn [ 100 ] ;
char orig [ 100 ] ;
char masqn [ 100 ] ;
char zombn [ 100 ] ;
2001-09-19 14:40:16 +00:00
2003-02-05 21:18:09 +00:00
# if 1
2001-05-07 00:43:32 +00:00
ast_log ( LOG_DEBUG , " Actually Masquerading %s(%d) into the structure of %s(%d) \n " ,
2003-02-05 21:18:09 +00:00
clone - > name , clone - > _state , original - > name , original - > _state ) ;
2001-09-19 14:40:16 +00:00
# endif
2001-05-07 00:43:32 +00:00
/* XXX This is a seriously wacked out operation. We're essentially putting the guts of
2004-04-27 21:21:57 +00:00
the clone channel into the original channel . Start by killing off the original
channel ' s backend . I ' m not sure we ' re going to keep this function , because
2001-05-07 00:43:32 +00:00
while the features are nice , the cost is very high in terms of pure nastiness . XXX */
2004-04-06 22:17:32 +00:00
/* We need the clone's lock, too */
ast_mutex_lock ( & clone - > lock ) ;
2003-08-11 21:31:53 +00:00
2003-08-11 22:17:46 +00:00
ast_log ( LOG_DEBUG , " Got clone lock on '%s' at %p \n " , clone - > name , & clone - > lock ) ;
2003-08-11 21:31:53 +00:00
2001-09-19 14:40:16 +00:00
/* Having remembered the original read/write formats, we turn off any translation on either
one */
free_translation ( clone ) ;
free_translation ( original ) ;
2001-05-07 00:43:32 +00:00
/* Unlink the masquerade */
original - > masq = NULL ;
clone - > masqr = NULL ;
2002-09-10 20:48:20 +00:00
/* Save the original name */
strncpy ( orig , original - > name , sizeof ( orig ) - 1 ) ;
/* Save the new name */
strncpy ( newn , clone - > name , sizeof ( newn ) - 1 ) ;
/* Create the masq name */
snprintf ( masqn , sizeof ( masqn ) , " %s<MASQ> " , newn ) ;
2001-05-07 00:43:32 +00:00
/* Copy the name from the clone channel */
2002-09-10 20:48:20 +00:00
strncpy ( original - > name , newn , sizeof ( original - > name ) - 1 ) ;
2001-05-07 00:43:32 +00:00
/* Mangle the name of the clone channel */
2002-09-10 20:48:20 +00:00
strncpy ( clone - > name , masqn , sizeof ( clone - > name ) - 1 ) ;
/* Notify any managers of the change, first the masq then the other */
manager_event ( EVENT_FLAG_CALL , " Rename " , " Oldname: %s \r \n Newname: %s \r \n " , newn , masqn ) ;
manager_event ( EVENT_FLAG_CALL , " Rename " , " Oldname: %s \r \n Newname: %s \r \n " , orig , newn ) ;
2001-05-07 00:43:32 +00:00
2004-04-27 21:21:57 +00:00
/* Swap the guts */
2001-05-07 00:43:32 +00:00
p = original - > pvt ;
original - > pvt = clone - > pvt ;
clone - > pvt = p ;
2003-08-14 19:18:18 +00:00
/* Save any pending frames on both sides. Start by counting
* how many we ' re going to need . . . */
prev = NULL ;
cur = clone - > pvt - > readq ;
x = 0 ;
while ( cur ) {
x + + ;
prev = cur ;
cur = cur - > next ;
}
/* If we had any, prepend them to the ones already in the queue, and
* load up the alertpipe */
if ( prev ) {
prev - > next = original - > pvt - > readq ;
original - > pvt - > readq = clone - > pvt - > readq ;
clone - > pvt - > readq = NULL ;
if ( original - > pvt - > alertpipe [ 1 ] > - 1 ) {
for ( i = 0 ; i < x ; i + + )
write ( original - > pvt - > alertpipe [ 1 ] , & x , sizeof ( x ) ) ;
}
}
2002-09-10 20:48:20 +00:00
clone - > _softhangup = AST_SOFTHANGUP_DEV ;
2001-09-19 14:40:16 +00:00
if ( clone - > pvt - > fixup ) {
2004-04-06 22:17:32 +00:00
res = clone - > pvt - > fixup ( original , clone ) ;
2001-09-19 14:40:16 +00:00
if ( res )
ast_log ( LOG_WARNING , " Fixup failed on channel %s, strange things may happen. \n " , clone - > name ) ;
}
2001-05-07 00:43:32 +00:00
/* Start by disconnecting the original's physical side */
if ( clone - > pvt - > hangup )
res = clone - > pvt - > hangup ( clone ) ;
if ( res ) {
ast_log ( LOG_WARNING , " Hangup failed! Strange things may happen! \n " ) ;
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & clone - > lock ) ;
2001-05-07 00:43:32 +00:00
return - 1 ;
}
2002-09-10 20:48:20 +00:00
snprintf ( zombn , sizeof ( zombn ) , " %s<ZOMBIE> " , orig ) ;
2001-05-07 00:43:32 +00:00
/* Mangle the name of the clone channel */
2002-09-10 20:48:20 +00:00
strncpy ( clone - > name , zombn , sizeof ( clone - > name ) - 1 ) ;
manager_event ( EVENT_FLAG_CALL , " Rename " , " Oldname: %s \r \n Newname: %s \r \n " , masqn , zombn ) ;
2001-05-07 00:43:32 +00:00
2004-04-27 21:21:57 +00:00
/* Keep the same language. */
2001-05-07 00:43:32 +00:00
/* Update the type. */
original - > type = clone - > type ;
/* Copy the FD's */
2003-06-29 23:23:54 +00:00
for ( x = 0 ; x < AST_MAX_FDS ; x + + ) {
2001-05-07 00:43:32 +00:00
original - > fds [ x ] = clone - > fds [ x ] ;
2003-06-29 23:23:54 +00:00
}
2004-01-30 06:48:01 +00:00
/* Append variables from clone channel into original channel */
2004-04-27 21:21:57 +00:00
/* XXX Is this always correct? We have to in order to keep MACROS working XXX */
2004-01-30 06:48:01 +00:00
varptr = original - > varshead . first ;
if ( varptr ) {
while ( varptr - > entries . next ) {
varptr = varptr - > entries . next ;
}
varptr - > entries . next = clone - > varshead . first ;
} else {
original - > varshead . first = clone - > varshead . first ;
}
clone - > varshead . first = NULL ;
2001-12-20 15:21:47 +00:00
/* Presense of ADSI capable CPE follows clone */
original - > adsicpe = clone - > adsicpe ;
2001-05-07 00:43:32 +00:00
/* Bridge remains the same */
/* CDR fields remain the same */
/* XXX What about blocking, softhangup, blocker, and lock and blockproc? XXX */
/* Application and data remain the same */
2004-04-27 21:21:57 +00:00
/* Clone exception becomes real one, as with fdno */
2001-05-07 00:43:32 +00:00
original - > exception = clone - > exception ;
original - > fdno = clone - > fdno ;
/* Schedule context remains the same */
/* Stream stuff stays the same */
2004-04-27 21:21:57 +00:00
/* Keep the original state. The fixup code will need to work with it most likely */
2001-05-07 00:43:32 +00:00
/* dnid and callerid change to become the new, HOWEVER, we also link the original's
fields back into the defunct ' clone ' so that they will be freed when
ast_frfree is eventually called */
tmp = original - > dnid ;
original - > dnid = clone - > dnid ;
clone - > dnid = tmp ;
tmp = original - > callerid ;
original - > callerid = clone - > callerid ;
clone - > callerid = tmp ;
2003-06-29 23:23:54 +00:00
/* Restore original timing file descriptor */
original - > fds [ AST_MAX_FDS - 2 ] = original - > timingfd ;
2001-09-19 14:40:16 +00:00
/* Our native formats are different now */
original - > nativeformats = clone - > nativeformats ;
2003-02-05 21:18:09 +00:00
/* And of course, so does our current state. Note we need not
call ast_setstate since the event manager doesn ' t really consider
these separate */
original - > _state = clone - > _state ;
2001-09-19 14:40:16 +00:00
2004-04-27 21:21:57 +00:00
/* Context, extension, priority, app data, jump table, remain the same */
2001-05-07 00:43:32 +00:00
/* pvt switches. pbx stays the same, as does next */
/* Set the write format */
2004-04-06 22:17:32 +00:00
ast_set_write_format ( original , wformat ) ;
2001-05-07 00:43:32 +00:00
/* Set the read format */
2004-04-06 22:17:32 +00:00
ast_set_read_format ( original , rformat ) ;
2001-09-19 14:40:16 +00:00
ast_log ( LOG_DEBUG , " Putting channel %s in %d/%d formats \n " , original - > name , wformat , rformat ) ;
2001-03-12 03:04:51 +00:00
2001-05-07 00:43:32 +00:00
/* Okay. Last thing is to let the channel driver know about all this mess, so he
can fix up everything as best as possible */
if ( original - > pvt - > fixup ) {
2004-04-06 22:17:32 +00:00
res = original - > pvt - > fixup ( clone , original ) ;
2001-05-07 00:43:32 +00:00
if ( res ) {
ast_log ( LOG_WARNING , " Driver for '%s' could not fixup channel %s \n " ,
original - > type , original - > name ) ;
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & clone - > lock ) ;
2001-05-07 00:43:32 +00:00
return - 1 ;
}
} else
ast_log ( LOG_WARNING , " Driver '%s' does not have a fixup routine (for %s)! Bad things may happen. \n " ,
original - > type , original - > name ) ;
2004-02-19 20:07:01 +00:00
/* Now, at this point, the "clone" channel is totally F'd up. We mark it as
a zombie so nothing tries to touch it . If it ' s already been marked as a
zombie , then free it now ( since it already is considered invalid ) . */
if ( clone - > zombie ) {
ast_log ( LOG_DEBUG , " Destroying clone '%s' \n " , clone - > name ) ;
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & clone - > lock ) ;
2004-02-19 20:07:01 +00:00
ast_channel_free ( clone ) ;
manager_event ( EVENT_FLAG_CALL , " Hangup " , " Channel: %s \r \n " , zombn ) ;
} else {
ast_log ( LOG_DEBUG , " Released clone lock on '%s' \n " , clone - > name ) ;
clone - > zombie = 1 ;
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & clone - > lock ) ;
2004-02-19 20:07:01 +00:00
}
2001-05-07 00:43:32 +00:00
/* Signal any blocker */
if ( original - > blocking )
pthread_kill ( original - > blocker , SIGURG ) ;
2003-08-11 21:17:33 +00:00
ast_log ( LOG_DEBUG , " Done Masquerading %s (%d) \n " ,
original - > name , original - > _state ) ;
2002-09-10 20:48:20 +00:00
return 0 ;
}
2003-02-05 21:18:09 +00:00
void ast_set_callerid ( struct ast_channel * chan , char * callerid , int anitoo )
2002-09-10 20:48:20 +00:00
{
if ( chan - > callerid )
free ( chan - > callerid ) ;
2003-02-05 21:18:09 +00:00
if ( anitoo & & chan - > ani )
free ( chan - > ani ) ;
if ( callerid ) {
2002-09-10 20:48:20 +00:00
chan - > callerid = strdup ( callerid ) ;
2003-02-05 21:18:09 +00:00
if ( anitoo )
chan - > ani = strdup ( callerid ) ;
} else {
2002-09-10 20:48:20 +00:00
chan - > callerid = NULL ;
2003-02-05 21:18:09 +00:00
if ( anitoo )
chan - > ani = NULL ;
}
if ( chan - > cdr )
ast_cdr_setcid ( chan - > cdr , chan ) ;
2002-09-10 20:48:20 +00:00
manager_event ( EVENT_FLAG_CALL , " Newcallerid " ,
" Channel: %s \r \n "
2003-06-11 12:24:13 +00:00
" Callerid: %s \r \n "
" Uniqueid: %s \r \n " ,
2002-09-10 20:48:20 +00:00
chan - > name , chan - > callerid ?
2003-06-11 12:24:13 +00:00
chan - > callerid : " <Unknown> " ,
chan - > uniqueid ) ;
2002-09-10 20:48:20 +00:00
}
int ast_setstate ( struct ast_channel * chan , int state )
{
if ( chan - > _state ! = state ) {
int oldstate = chan - > _state ;
chan - > _state = state ;
if ( oldstate = = AST_STATE_DOWN ) {
2003-03-30 22:55:42 +00:00
ast_device_state_changed ( chan - > name ) ;
2002-09-10 20:48:20 +00:00
manager_event ( EVENT_FLAG_CALL , " Newchannel " ,
" Channel: %s \r \n "
" State: %s \r \n "
2003-06-11 12:24:13 +00:00
" Callerid: %s \r \n "
" Uniqueid: %s \r \n " ,
chan - > name , ast_state2str ( chan - > _state ) , chan - > callerid ? chan - > callerid : " <unknown> " , chan - > uniqueid ) ;
2002-09-10 20:48:20 +00:00
} else {
manager_event ( EVENT_FLAG_CALL , " Newstate " ,
" Channel: %s \r \n "
" State: %s \r \n "
2003-06-11 12:24:13 +00:00
" Callerid: %s \r \n "
" Uniqueid: %s \r \n " ,
chan - > name , ast_state2str ( chan - > _state ) , chan - > callerid ? chan - > callerid : " <unknown> " , chan - > uniqueid ) ;
2002-09-10 20:48:20 +00:00
}
}
2001-05-07 00:43:32 +00:00
return 0 ;
}
2001-03-12 03:04:51 +00:00
2004-05-03 02:02:27 +00:00
static long tvdiff ( struct timeval * now , struct timeval * then )
{
2004-04-26 23:22:34 +00:00
return ( ( ( now - > tv_sec * 1000 ) + now - > tv_usec / 1000 ) - ( ( then - > tv_sec * 1000 ) + then - > tv_usec / 1000 ) ) ;
}
2004-05-06 22:29:00 +00:00
static void bridge_playfile ( struct ast_channel * chan , struct ast_channel * peer , char * sound , int remain )
2004-05-03 02:02:27 +00:00
{
2004-05-06 22:29:00 +00:00
int res = 0 , min = 0 , sec = 0 , check = 0 ;
check = ast_autoservice_start ( peer ) ;
if ( check )
return ;
2004-05-03 02:02:27 +00:00
if ( remain > 0 ) {
if ( remain / 60 > 1 ) {
2004-04-26 23:22:34 +00:00
min = remain / 60 ;
sec = remain % 60 ;
2004-05-03 02:02:27 +00:00
} else {
2004-04-26 23:22:34 +00:00
sec = remain ;
}
}
2004-05-03 02:02:27 +00:00
if ( ! strcmp ( sound , " timeleft " ) ) {
res = ast_streamfile ( chan , " vm-youhave " , chan - > language ) ;
2004-04-26 23:22:34 +00:00
res = ast_waitstream ( chan , " " ) ;
2004-05-03 02:02:27 +00:00
if ( min ) {
res = ast_say_number ( chan , min , AST_DIGIT_ANY , chan - > language , ( char * ) NULL ) ;
res = ast_streamfile ( chan , " minutes " , chan - > language ) ;
2004-04-26 23:22:34 +00:00
res = ast_waitstream ( chan , " " ) ;
}
2004-05-03 02:02:27 +00:00
if ( sec ) {
res = ast_say_number ( chan , sec , AST_DIGIT_ANY , chan - > language , ( char * ) NULL ) ;
res = ast_streamfile ( chan , " seconds " , chan - > language ) ;
2004-04-26 23:22:34 +00:00
res = ast_waitstream ( chan , " " ) ;
}
2004-05-03 02:02:27 +00:00
} else {
res = ast_streamfile ( chan , sound , chan - > language ) ;
2004-04-26 23:22:34 +00:00
res = ast_waitstream ( chan , " " ) ;
}
2004-05-06 22:29:00 +00:00
check = ast_autoservice_stop ( peer ) ;
2004-04-26 23:22:34 +00:00
}
2004-05-03 02:02:27 +00:00
int ast_channel_bridge ( struct ast_channel * c0 , struct ast_channel * c1 , struct ast_bridge_config * config , struct ast_frame * * fo , struct ast_channel * * rc )
{
2004-04-26 23:22:34 +00:00
/* Copy voice back and forth between the two channels. Give the peer
2001-03-12 03:04:51 +00:00
the ability to transfer calls with ' # < extension ' syntax . */
2004-04-26 23:22:34 +00:00
int flags ;
2001-03-12 03:04:51 +00:00
struct ast_channel * cs [ 3 ] ;
int to = - 1 ;
struct ast_frame * f ;
2001-09-19 14:40:16 +00:00
struct ast_channel * who = NULL ;
2004-04-26 23:22:34 +00:00
int res = 0 ;
2001-09-19 14:40:16 +00:00
int nativefailed = 0 ;
2004-04-26 23:22:34 +00:00
struct timeval start_time , precise_now ;
2004-05-03 02:02:27 +00:00
long elapsed_ms = 0 , time_left_ms = 0 ;
int playit = 0 , playitagain = 1 , first_time = 1 ;
2004-04-26 23:22:34 +00:00
flags = ( config - > allowdisconnect | | config - > allowredirect_out ? AST_BRIDGE_DTMF_CHANNEL_0 : 0 ) + ( config - > allowredirect_in ? AST_BRIDGE_DTMF_CHANNEL_1 : 0 ) ;
/* timestamp */
gettimeofday ( & start_time , NULL ) ;
time_left_ms = config - > timelimit ;
2004-05-03 02:02:27 +00:00
if ( config - > play_to_caller & & config - > start_sound )
2004-05-06 22:29:00 +00:00
bridge_playfile ( c0 , c1 , config - > start_sound , time_left_ms / 1000 ) ;
2004-05-03 02:02:27 +00:00
if ( config - > play_to_callee & & config - > start_sound )
2004-05-06 22:29:00 +00:00
bridge_playfile ( c1 , c0 , config - > start_sound , time_left_ms / 1000 ) ;
2003-02-05 21:18:09 +00:00
2001-05-07 00:43:32 +00:00
/* Stop if we're a zombie or need a soft hangup */
2003-08-11 21:10:52 +00:00
if ( c0 - > zombie | | ast_check_hangup_locked ( c0 ) | | c1 - > zombie | | ast_check_hangup_locked ( c1 ) )
2001-05-07 00:43:32 +00:00
return - 1 ;
if ( c0 - > bridge ) {
ast_log ( LOG_WARNING , " %s is already in a bridge with %s \n " ,
c0 - > name , c0 - > bridge - > name ) ;
return - 1 ;
}
if ( c1 - > bridge ) {
ast_log ( LOG_WARNING , " %s is already in a bridge with %s \n " ,
c1 - > name , c1 - > bridge - > name ) ;
return - 1 ;
}
/* Keep track of bridge */
c0 - > bridge = c1 ;
c1 - > bridge = c0 ;
2001-03-12 03:04:51 +00:00
cs [ 0 ] = c0 ;
cs [ 1 ] = c1 ;
2002-09-10 20:48:20 +00:00
manager_event ( EVENT_FLAG_CALL , " Link " ,
" Channel1: %s \r \n "
2004-04-21 04:52:18 +00:00
" Channel2: %s \r \n "
" Uniqueid1: %s \r \n "
" Uniqueid2: %s \r \n " ,
c0 - > name , c1 - > name , c0 - > uniqueid , c1 - > uniqueid ) ;
2002-09-10 20:48:20 +00:00
2001-03-12 03:04:51 +00:00
for ( /* ever */ ; ; ) {
2004-04-26 23:22:34 +00:00
/* timestamp */
2004-05-03 02:02:27 +00:00
if ( config - > timelimit ) {
2004-04-26 23:22:34 +00:00
gettimeofday ( & precise_now , NULL ) ;
elapsed_ms = tvdiff ( & precise_now , & start_time ) ;
time_left_ms = config - > timelimit - elapsed_ms ;
2004-05-03 02:02:27 +00:00
if ( playitagain & & ( config - > play_to_caller | | config - > play_to_callee ) & & ( config - > play_warning & & time_left_ms < = config - > play_warning ) ) {
2004-04-26 23:22:34 +00:00
/* narrowing down to the end */
2004-05-03 02:02:27 +00:00
if ( config - > warning_freq = = 0 ) {
2004-04-26 23:22:34 +00:00
playit = 1 ;
first_time = 0 ;
playitagain = 0 ;
2004-05-03 02:02:27 +00:00
} else if ( first_time ) {
2004-04-26 23:22:34 +00:00
playit = 1 ;
first_time = 0 ;
2004-05-03 02:02:27 +00:00
} else {
if ( ( time_left_ms % config - > warning_freq ) < = 50 ) {
2004-04-26 23:22:34 +00:00
playit = 1 ;
}
}
}
2004-05-03 02:02:27 +00:00
if ( time_left_ms < = 0 ) {
if ( config - > play_to_caller & & config - > end_sound )
2004-05-06 22:29:00 +00:00
bridge_playfile ( c0 , c1 , config - > end_sound , 0 ) ;
2004-05-03 02:02:27 +00:00
if ( config - > play_to_callee & & config - > end_sound )
2004-05-06 22:29:00 +00:00
bridge_playfile ( c1 , c0 , config - > end_sound , 0 ) ;
2004-04-27 16:42:43 +00:00
* fo = NULL ;
if ( who ) * rc = who ;
res = 0 ;
2004-04-26 23:22:34 +00:00
break ;
}
2004-05-03 02:02:27 +00:00
if ( time_left_ms > = 5000 & & playit ) {
if ( config - > play_to_caller & & config - > warning_sound & & config - > play_warning )
2004-05-06 22:29:00 +00:00
bridge_playfile ( c0 , c1 , config - > warning_sound , time_left_ms / 1000 ) ;
2004-05-03 02:02:27 +00:00
if ( config - > play_to_callee & & config - > warning_sound & & config - > play_warning )
2004-05-06 22:29:00 +00:00
bridge_playfile ( c1 , c0 , config - > warning_sound , time_left_ms / 1000 ) ;
2004-04-26 23:22:34 +00:00
playit = 0 ;
}
}
2001-09-19 14:40:16 +00:00
/* Stop if we're a zombie or need a soft hangup */
2003-08-11 21:17:33 +00:00
if ( c0 - > zombie | | ast_check_hangup_locked ( c0 ) | | c1 - > zombie | | ast_check_hangup_locked ( c1 ) ) {
2001-09-19 14:40:16 +00:00
* fo = NULL ;
if ( who ) * rc = who ;
res = 0 ;
2003-04-07 20:29:50 +00:00
ast_log ( LOG_DEBUG , " Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s \n " , c0 - > name , c1 - > name , c0 - > zombie ? " Yes " : " No " , ast_check_hangup ( c0 ) ? " Yes " : " No " , c1 - > zombie ? " Yes " : " No " , ast_check_hangup ( c1 ) ? " Yes " : " No " ) ;
2001-09-19 14:40:16 +00:00
break ;
}
2004-04-26 23:22:34 +00:00
if ( c0 - > pvt - > bridge & & config - > timelimit = = 0 & &
2003-03-25 19:30:06 +00:00
( c0 - > pvt - > bridge = = c1 - > pvt - > bridge ) & & ! nativefailed & & ! c0 - > monitor & & ! c1 - > monitor ) {
2001-09-19 14:40:16 +00:00
/* Looks like they share a bridge code */
2002-03-10 17:14:13 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Attempting native bridge of %s and %s \n " , c0 - > name , c1 - > name ) ;
2001-09-19 14:40:16 +00:00
if ( ! ( res = c0 - > pvt - > bridge ( c0 , c1 , flags , fo , rc ) ) ) {
c0 - > bridge = NULL ;
c1 - > bridge = NULL ;
2002-09-10 20:48:20 +00:00
manager_event ( EVENT_FLAG_CALL , " Unlink " ,
" Channel1: %s \r \n "
2004-04-21 04:52:18 +00:00
" Channel2: %s \r \n "
" Uniqueid1: %s \r \n "
" Uniqueid2: %s \r \n " ,
c0 - > name , c1 - > name , c0 - > uniqueid , c1 - > uniqueid ) ;
2003-04-07 20:29:50 +00:00
ast_log ( LOG_DEBUG , " Returning from native bridge, channels: %s, %s \n " , c0 - > name , c1 - > name ) ;
2001-09-19 14:40:16 +00:00
return 0 ;
}
/* If they return non-zero then continue on normally. Let "-2" mean don't worry about
my not wanting to bridge */
if ( ( res ! = - 2 ) & & ( res ! = - 3 ) )
ast_log ( LOG_WARNING , " Private bridge between %s and %s failed \n " , c0 - > name , c1 - > name ) ;
if ( res ! = - 3 ) nativefailed + + ;
}
2002-06-21 01:40:13 +00:00
if ( ( ( c0 - > writeformat ! = c1 - > readformat ) | | ( c0 - > readformat ! = c1 - > writeformat ) ) & &
! ( c0 - > generator | | c1 - > generator ) ) {
2001-09-19 14:40:16 +00:00
if ( ast_channel_make_compatible ( c0 , c1 ) ) {
ast_log ( LOG_WARNING , " Can't make %s and %s compatible \n " , c0 - > name , c1 - > name ) ;
2002-09-10 20:48:20 +00:00
manager_event ( EVENT_FLAG_CALL , " Unlink " ,
" Channel1: %s \r \n "
2004-04-21 04:52:18 +00:00
" Channel2: %s \r \n "
" Uniqueid1: %s \r \n "
" Uniqueid2: %s \r \n " ,
c0 - > name , c1 - > name , c0 - > uniqueid , c1 - > uniqueid ) ;
2001-09-19 14:40:16 +00:00
return - 1 ;
}
}
2001-03-12 03:04:51 +00:00
who = ast_waitfor_n ( cs , 2 , & to ) ;
if ( ! who ) {
2003-02-05 21:18:09 +00:00
ast_log ( LOG_DEBUG , " Nobody there, continuing... \n " ) ;
2001-03-12 03:04:51 +00:00
continue ;
}
f = ast_read ( who ) ;
if ( ! f ) {
* fo = NULL ;
* rc = who ;
2001-05-07 00:43:32 +00:00
res = 0 ;
2003-04-07 20:29:50 +00:00
ast_log ( LOG_DEBUG , " Didn't get a frame from channel: %s \n " , who - > name ) ;
2001-05-07 00:43:32 +00:00
break ;
2001-03-12 03:04:51 +00:00
}
2003-02-05 21:18:09 +00:00
2001-03-12 03:04:51 +00:00
if ( ( f - > frametype = = AST_FRAME_CONTROL ) & & ! ( flags & AST_BRIDGE_IGNORE_SIGS ) ) {
* fo = f ;
* rc = who ;
2001-05-07 00:43:32 +00:00
res = 0 ;
2004-03-01 16:14:41 +00:00
ast_log ( LOG_DEBUG , " Got a FRAME_CONTROL (%d) frame on channel %s \n " , f - > subclass , who - > name ) ;
2001-05-07 00:43:32 +00:00
break ;
2001-03-12 03:04:51 +00:00
}
if ( ( f - > frametype = = AST_FRAME_VOICE ) | |
( f - > frametype = = AST_FRAME_TEXT ) | |
( f - > frametype = = AST_FRAME_VIDEO ) | |
( f - > frametype = = AST_FRAME_IMAGE ) | |
( f - > frametype = = AST_FRAME_DTMF ) ) {
2001-05-07 00:43:32 +00:00
if ( ( f - > frametype = = AST_FRAME_DTMF ) & &
( flags & ( AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1 ) ) ) {
if ( ( who = = c0 ) ) {
if ( ( flags & AST_BRIDGE_DTMF_CHANNEL_0 ) ) {
* rc = c0 ;
* fo = f ;
/* Take out of conference mode */
res = 0 ;
2003-04-07 20:31:16 +00:00
ast_log ( LOG_DEBUG , " Got AST_BRIDGE_DTMF_CHANNEL_0 on c0 (%s) \n " , c0 - > name ) ;
2001-05-07 00:43:32 +00:00
break ;
} else
goto tackygoto ;
2001-03-12 03:04:51 +00:00
} else
2001-05-07 00:43:32 +00:00
if ( ( who = = c1 ) ) {
if ( flags & AST_BRIDGE_DTMF_CHANNEL_1 ) {
* rc = c1 ;
* fo = f ;
res = 0 ;
2003-04-07 20:31:16 +00:00
ast_log ( LOG_DEBUG , " Got AST_BRIDGE_DTMF_CHANNEL_1 on c1 (%s) \n " , c1 - > name ) ;
2001-05-07 00:43:32 +00:00
break ;
} else
goto tackygoto ;
2001-03-12 03:04:51 +00:00
}
} else {
#if 0
ast_log ( LOG_DEBUG , " Read from %s \n " , who - > name ) ;
if ( who = = last )
ast_log ( LOG_DEBUG , " Servicing channel %s twice in a row? \n " , last - > name ) ;
last = who ;
# endif
2001-05-07 00:43:32 +00:00
tackygoto :
2002-06-21 01:40:13 +00:00
/* Don't copy packets if there is a generator on either one, since they're
not supposed to be listening anyway */
2003-03-16 22:37:31 +00:00
if ( who = = c0 )
ast_write ( c1 , f ) ;
else
ast_write ( c0 , f ) ;
2001-03-12 03:04:51 +00:00
}
ast_frfree ( f ) ;
} else
ast_frfree ( f ) ;
/* Swap who gets priority */
cs [ 2 ] = cs [ 0 ] ;
cs [ 0 ] = cs [ 1 ] ;
cs [ 1 ] = cs [ 2 ] ;
}
2001-05-07 00:43:32 +00:00
c0 - > bridge = NULL ;
c1 - > bridge = NULL ;
2002-09-10 20:48:20 +00:00
manager_event ( EVENT_FLAG_CALL , " Unlink " ,
" Channel1: %s \r \n "
2004-04-21 04:52:18 +00:00
" Channel2: %s \r \n "
" Uniqueid1: %s \r \n "
" Uniqueid2: %s \r \n " ,
c0 - > name , c1 - > name , c0 - > uniqueid , c1 - > uniqueid ) ;
2003-04-07 20:29:50 +00:00
ast_log ( LOG_DEBUG , " Bridge stops bridging channels %s and %s \n " , c0 - > name , c1 - > name ) ;
2001-05-07 00:43:32 +00:00
return res ;
}
int ast_channel_setoption ( struct ast_channel * chan , int option , void * data , int datalen , int block )
{
int res ;
if ( chan - > pvt - > setoption ) {
res = chan - > pvt - > setoption ( chan , option , data , datalen ) ;
if ( res < 0 )
return res ;
} else {
errno = ENOSYS ;
return - 1 ;
}
if ( block ) {
/* XXX Implement blocking -- just wait for our option frame reply, discarding
intermediate packets . XXX */
ast_log ( LOG_ERROR , " XXX Blocking not implemented yet XXX \n " ) ;
return - 1 ;
}
2001-03-12 03:04:51 +00:00
return 0 ;
}
2001-12-20 15:21:47 +00:00
2002-06-21 01:40:13 +00:00
struct tonepair_def {
int freq1 ;
int freq2 ;
int duration ;
int vol ;
} ;
struct tonepair_state {
float freq1 ;
float freq2 ;
float vol ;
int duration ;
int pos ;
int origwfmt ;
struct ast_frame f ;
unsigned char offset [ AST_FRIENDLY_OFFSET ] ;
short data [ 4000 ] ;
} ;
static void tonepair_release ( struct ast_channel * chan , void * params )
{
struct tonepair_state * ts = params ;
if ( chan ) {
2004-04-06 22:17:32 +00:00
ast_set_write_format ( chan , ts - > origwfmt ) ;
2002-06-21 01:40:13 +00:00
}
free ( ts ) ;
}
static void * tonepair_alloc ( struct ast_channel * chan , void * params )
{
struct tonepair_state * ts ;
struct tonepair_def * td = params ;
ts = malloc ( sizeof ( struct tonepair_state ) ) ;
if ( ! ts )
return NULL ;
memset ( ts , 0 , sizeof ( struct tonepair_state ) ) ;
ts - > origwfmt = chan - > writeformat ;
2004-04-06 22:17:32 +00:00
if ( ast_set_write_format ( chan , AST_FORMAT_SLINEAR ) ) {
2002-06-21 01:40:13 +00:00
ast_log ( LOG_WARNING , " Unable to set '%s' to signed linear format (write) \n " , chan - > name ) ;
tonepair_release ( NULL , ts ) ;
ts = NULL ;
} else {
ts - > freq1 = td - > freq1 ;
ts - > freq2 = td - > freq2 ;
ts - > duration = td - > duration ;
ts - > vol = td - > vol ;
}
/* Let interrupts interrupt :) */
chan - > writeinterrupt = 1 ;
return ts ;
}
2003-02-05 21:18:09 +00:00
static int tonepair_generator ( struct ast_channel * chan , void * data , int len , int samples )
2002-06-21 01:40:13 +00:00
{
struct tonepair_state * ts = data ;
int x ;
2003-02-05 21:18:09 +00:00
/* we need to prepare a frame with 16 * timelen samples as we're
* generating SLIN audio
*/
len = samples * 2 ;
2002-06-21 01:40:13 +00:00
if ( len > sizeof ( ts - > data ) / 2 - 1 ) {
ast_log ( LOG_WARNING , " Can't generate that much data! \n " ) ;
return - 1 ;
}
memset ( & ts - > f , 0 , sizeof ( ts - > f ) ) ;
for ( x = 0 ; x < len / 2 ; x + + ) {
ts - > data [ x ] = ts - > vol * (
sin ( ( ts - > freq1 * 2.0 * M_PI / 8000.0 ) * ( ts - > pos + x ) ) +
sin ( ( ts - > freq2 * 2.0 * M_PI / 8000.0 ) * ( ts - > pos + x ) )
) ;
}
ts - > f . frametype = AST_FRAME_VOICE ;
ts - > f . subclass = AST_FORMAT_SLINEAR ;
ts - > f . datalen = len ;
2003-02-05 21:18:09 +00:00
ts - > f . samples = samples ;
2002-06-21 01:40:13 +00:00
ts - > f . offset = AST_FRIENDLY_OFFSET ;
ts - > f . data = ts - > data ;
ast_write ( chan , & ts - > f ) ;
ts - > pos + = x ;
if ( ts - > duration > 0 ) {
if ( ts - > pos > = ts - > duration * 8 )
return - 1 ;
}
return 0 ;
}
static struct ast_generator tonepair = {
alloc : tonepair_alloc ,
release : tonepair_release ,
generate : tonepair_generator ,
} ;
int ast_tonepair_start ( struct ast_channel * chan , int freq1 , int freq2 , int duration , int vol )
{
struct tonepair_def d = { 0 , } ;
d . freq1 = freq1 ;
d . freq2 = freq2 ;
d . duration = duration ;
if ( vol < 1 )
d . vol = 8192 ;
else
d . vol = vol ;
if ( ast_activate_generator ( chan , & tonepair , & d ) )
return - 1 ;
return 0 ;
}
void ast_tonepair_stop ( struct ast_channel * chan )
{
ast_deactivate_generator ( chan ) ;
}
int ast_tonepair ( struct ast_channel * chan , int freq1 , int freq2 , int duration , int vol )
{
struct ast_frame * f ;
int res ;
if ( ( res = ast_tonepair_start ( chan , freq1 , freq2 , duration , vol ) ) )
return res ;
/* Give us some wiggle room */
while ( chan - > generatordata & & ( ast_waitfor ( chan , 100 ) > = 0 ) ) {
f = ast_read ( chan ) ;
if ( f )
ast_frfree ( f ) ;
else
return - 1 ;
}
return 0 ;
}
2003-03-25 19:30:06 +00:00
2004-02-27 06:15:49 +00:00
unsigned int ast_get_group ( char * s )
{
char * copy ;
char * piece ;
char * c = NULL ;
int start = 0 , finish = 0 , x ;
unsigned int group = 0 ;
copy = ast_strdupa ( s ) ;
if ( ! copy ) {
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
return 0 ;
}
c = copy ;
while ( ( piece = strsep ( & c , " , " ) ) ) {
if ( sscanf ( piece , " %d-%d " , & start , & finish ) = = 2 ) {
/* Range */
} else if ( sscanf ( piece , " %d " , & start ) ) {
/* Just one */
finish = start ;
} else {
ast_log ( LOG_ERROR , " Syntax error parsing '%s' at '%s'. Using '0' \n " , s , piece ) ;
return 0 ;
}
for ( x = start ; x < = finish ; x + + ) {
if ( ( x > 31 ) | | ( x < 0 ) ) {
2004-02-27 09:04:42 +00:00
ast_log ( LOG_WARNING , " Ignoring invalid group %d (maximum group is 31) \n " , x ) ;
2004-02-27 06:15:49 +00:00
} else
group | = ( 1 < < x ) ;
}
}
return group ;
}