2004-08-27 22:53:56 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
1999-12-04 21:35:07 +00:00
*
2005-01-21 07:06:25 +00:00
* Copyright ( C ) 1999 - 2005 , Digium , Inc .
1999-12-04 21:35:07 +00:00
*
2004-08-27 03:28:32 +00:00
* Mark Spencer < markster @ digium . com >
1999-12-04 21:35:07 +00:00
*
2005-09-14 20:46:50 +00:00
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
1999-12-04 21:35:07 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2005-10-24 20:12:06 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* \ brief Channel Management
2005-09-14 20:46:50 +00:00
*
1999-12-04 21:35:07 +00:00
*/
# include <stdio.h>
# include <stdlib.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 */
2005-04-22 13:11:34 +00:00
# ifdef ZAPTEL_OPTIMIZATIONS
# include <sys/ioctl.h>
# ifdef __linux__
# include <linux/zaptel.h>
# else
# include <zaptel.h>
# endif /* __linux__ */
# ifndef ZT_TIMERPING
# error "You need newer zaptel! Please cvs update zaptel"
# endif
# endif
2005-06-06 20:27:51 +00:00
# include "asterisk.h"
2005-06-06 22:12:19 +00:00
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2005-06-06 20:27:51 +00:00
2005-04-21 06:02:45 +00:00
# include "asterisk/pbx.h"
# include "asterisk/frame.h"
# include "asterisk/sched.h"
# include "asterisk/options.h"
# include "asterisk/channel.h"
# include "asterisk/musiconhold.h"
# include "asterisk/logger.h"
# include "asterisk/say.h"
# include "asterisk/file.h"
# include "asterisk/cli.h"
# include "asterisk/translate.h"
# include "asterisk/manager.h"
# include "asterisk/chanvars.h"
# include "asterisk/linkedlists.h"
# include "asterisk/indications.h"
# include "asterisk/monitor.h"
# include "asterisk/causes.h"
2005-07-25 22:13:32 +00:00
# include "asterisk/callerid.h"
2005-04-21 06:02:45 +00:00
# include "asterisk/utils.h"
# include "asterisk/lock.h"
# include "asterisk/app.h"
# include "asterisk/transcap.h"
2005-07-08 21:14:34 +00:00
# include "asterisk/devicestate.h"
2002-09-10 20:48:20 +00:00
2005-10-28 23:01:13 +00:00
struct channel_spy_trans {
int last_format ;
struct ast_trans_pvt * path ;
} ;
struct ast_channel_spy_list {
struct channel_spy_trans read_translator ;
struct channel_spy_trans write_translator ;
AST_LIST_HEAD_NOLOCK ( , ast_channel_spy ) list ;
} ;
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
2005-06-06 02:29:18 +00:00
/*
* Prevent new channel allocation if shutting down .
*/
2002-06-21 01:40:13 +00:00
static int shutting_down = 0 ;
2005-06-06 02:29:18 +00:00
2003-05-30 04:41:18 +00:00
static int uniqueint = 0 ;
2000-01-02 20:59:00 +00:00
2004-11-06 21:33:01 +00:00
unsigned long global_fin = 0 , global_fout = 0 ;
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 {
2005-03-04 06:47:24 +00:00
const struct ast_channel_tech * tech ;
1999-12-04 21:35:07 +00:00
struct chanlist * next ;
2005-06-06 02:29:18 +00:00
} ;
static struct chanlist * backends = NULL ;
/*
* the list of channels we have
*/
static struct ast_channel * channels = NULL ;
1999-12-18 07:01:48 +00:00
2005-06-06 02:29:18 +00:00
/* Protect the channel list, both backends and channels.
*/
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( chlock ) ;
1999-12-04 21:35:07 +00:00
2005-07-05 17:16:17 +00:00
const struct ast_cause {
int cause ;
const char * desc ;
} causes [ ] = {
{ AST_CAUSE_UNALLOCATED , " Unallocated (unassigned) number " } ,
{ AST_CAUSE_NO_ROUTE_TRANSIT_NET , " No route to specified transmit network " } ,
{ AST_CAUSE_NO_ROUTE_DESTINATION , " No route to destination " } ,
{ AST_CAUSE_CHANNEL_UNACCEPTABLE , " Channel unacceptable " } ,
{ AST_CAUSE_CALL_AWARDED_DELIVERED , " Call awarded and being delivered in an established channel " } ,
{ AST_CAUSE_NORMAL_CLEARING , " Normal Clearing " } ,
{ AST_CAUSE_USER_BUSY , " User busy " } ,
{ AST_CAUSE_NO_USER_RESPONSE , " No user responding " } ,
{ AST_CAUSE_NO_ANSWER , " User alerting, no answer " } ,
{ AST_CAUSE_CALL_REJECTED , " Call Rejected " } ,
{ AST_CAUSE_NUMBER_CHANGED , " Number changed " } ,
{ AST_CAUSE_DESTINATION_OUT_OF_ORDER , " Destination out of order " } ,
{ AST_CAUSE_INVALID_NUMBER_FORMAT , " Invalid number format " } ,
{ AST_CAUSE_FACILITY_REJECTED , " Facility rejected " } ,
{ AST_CAUSE_RESPONSE_TO_STATUS_ENQUIRY , " Response to STATus ENQuiry " } ,
{ AST_CAUSE_NORMAL_UNSPECIFIED , " Normal, unspecified " } ,
{ AST_CAUSE_NORMAL_CIRCUIT_CONGESTION , " Circuit/channel congestion " } ,
{ AST_CAUSE_NETWORK_OUT_OF_ORDER , " Network out of order " } ,
{ AST_CAUSE_NORMAL_TEMPORARY_FAILURE , " Temporary failure " } ,
{ AST_CAUSE_SWITCH_CONGESTION , " Switching equipment congestion " } ,
{ AST_CAUSE_ACCESS_INFO_DISCARDED , " Access information discarded " } ,
{ AST_CAUSE_REQUESTED_CHAN_UNAVAIL , " Requested channel not available " } ,
{ AST_CAUSE_PRE_EMPTED , " Pre-empted " } ,
{ AST_CAUSE_FACILITY_NOT_SUBSCRIBED , " Facility not subscribed " } ,
{ AST_CAUSE_OUTGOING_CALL_BARRED , " Outgoing call barred " } ,
{ AST_CAUSE_INCOMING_CALL_BARRED , " Incoming call barred " } ,
{ AST_CAUSE_BEARERCAPABILITY_NOTAUTH , " Bearer capability not authorized " } ,
{ AST_CAUSE_BEARERCAPABILITY_NOTAVAIL , " Bearer capability not available " } ,
{ AST_CAUSE_BEARERCAPABILITY_NOTIMPL , " Bearer capability not implemented " } ,
{ AST_CAUSE_CHAN_NOT_IMPLEMENTED , " Channel not implemented " } ,
{ AST_CAUSE_FACILITY_NOT_IMPLEMENTED , " Facility not implemented " } ,
{ AST_CAUSE_INVALID_CALL_REFERENCE , " Invalid call reference value " } ,
{ AST_CAUSE_INCOMPATIBLE_DESTINATION , " Incompatible destination " } ,
{ AST_CAUSE_INVALID_MSG_UNSPECIFIED , " Invalid message unspecified " } ,
{ AST_CAUSE_MANDATORY_IE_MISSING , " Mandatory information element is missing " } ,
{ AST_CAUSE_MESSAGE_TYPE_NONEXIST , " Message type nonexist. " } ,
{ AST_CAUSE_WRONG_MESSAGE , " Wrong message " } ,
{ AST_CAUSE_IE_NONEXIST , " Info. element nonexist or not implemented " } ,
{ AST_CAUSE_INVALID_IE_CONTENTS , " Invalid information element contents " } ,
{ AST_CAUSE_WRONG_CALL_STATE , " Message not compatible with call state " } ,
{ AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE , " Recover on timer expiry " } ,
{ AST_CAUSE_MANDATORY_IE_LENGTH_ERROR , " Mandatory IE length error " } ,
{ AST_CAUSE_PROTOCOL_ERROR , " Protocol error, unspecified " } ,
{ AST_CAUSE_INTERWORKING , " Interworking, unspecified " } ,
} ;
2004-12-31 00:04:41 +00:00
static int show_channeltypes ( int fd , int argc , char * argv [ ] )
{
2005-07-25 22:13:32 +00:00
# define FORMAT "%-10.10s %-30.30s %-12.12s %-12.12s %-12.12s\n"
2004-12-31 00:04:41 +00:00
struct chanlist * cl = backends ;
2005-07-25 22:13:32 +00:00
ast_cli ( fd , FORMAT , " Type " , " Description " , " Devicestate " , " Indications " , " Transfer " ) ;
ast_cli ( fd , FORMAT , " ---------- " , " ----------- " , " ----------- " , " ----------- " , " -------- " ) ;
2004-12-31 00:04:41 +00:00
if ( ast_mutex_lock ( & chlock ) ) {
ast_log ( LOG_WARNING , " Unable to lock channel list \n " ) ;
return - 1 ;
}
while ( cl ) {
2005-07-25 22:13:32 +00:00
ast_cli ( fd , FORMAT , cl - > tech - > type , cl - > tech - > description ,
( cl - > tech - > devicestate ) ? " yes " : " no " ,
( cl - > tech - > indicate ) ? " yes " : " no " ,
( cl - > tech - > transfer ) ? " yes " : " no " ) ;
2004-12-31 00:04:41 +00:00
cl = cl - > next ;
}
ast_mutex_unlock ( & chlock ) ;
return RESULT_SUCCESS ;
2005-06-02 21:37:09 +00:00
# undef FORMAT
2004-12-31 00:04:41 +00:00
}
static char show_channeltypes_usage [ ] =
" Usage: show channeltypes \n "
2005-02-10 23:46:03 +00:00
" Shows available channel types registered in your Asterisk server. \n " ;
2004-12-31 00:04:41 +00:00
static struct ast_cli_entry cli_show_channeltypes =
{ { " show " , " channeltypes " , NULL } , show_channeltypes , " Show available channel types " , show_channeltypes_usage } ;
2005-05-15 04:48:30 +00:00
/*--- ast_check_hangup: Checks to see if a channel is needing hang up */
2001-12-20 15:21:47 +00:00
int ast_check_hangup ( struct ast_channel * chan )
{
2005-05-15 04:48:30 +00:00
time_t myt ;
2001-12-20 15:21:47 +00:00
2005-05-15 04:48:30 +00:00
/* if soft hangup flag, return true */
if ( chan - > _softhangup )
return 1 ;
/* if no technology private data, return true */
if ( ! chan - > tech_pvt )
return 1 ;
/* if no hangup scheduled, just return here */
if ( ! chan - > whentohangup )
return 0 ;
2001-12-20 15:21:47 +00:00
time ( & myt ) ; /* get current time */
2005-05-15 04:48:30 +00:00
/* 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 ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_begin_shutdown: Initiate system shutdown */
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
}
}
2005-05-15 04:48:30 +00:00
/*--- ast_active_channels: returns number of active/allocated channels */
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 ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_cancel_shutdown: Cancel a shutdown in progress */
2002-06-21 01:40:13 +00:00
void ast_cancel_shutdown ( void )
{
shutting_down = 0 ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_shutting_down: Returns non-zero if Asterisk is being shut down */
2002-06-21 01:40:13 +00:00
int ast_shutting_down ( void )
{
return shutting_down ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_channel_setwhentohangup: Set when to hangup channel */
2001-12-20 15:21:47 +00:00
void ast_channel_setwhentohangup ( struct ast_channel * chan , time_t offset )
{
2004-06-22 20:11:15 +00:00
time_t myt ;
2005-10-13 18:27:54 +00:00
struct ast_frame fr = { AST_FRAME_NULL , } ;
2001-12-20 15:21:47 +00:00
time ( & myt ) ;
2004-06-22 20:11:15 +00:00
if ( offset )
chan - > whentohangup = myt + offset ;
else
chan - > whentohangup = 0 ;
2005-10-13 18:27:54 +00:00
ast_queue_frame ( chan , & fr ) ;
2001-12-20 15:21:47 +00:00
return ;
}
2005-10-04 23:28:57 +00:00
/*--- ast_channel_cmpwhentohangup: Compare a offset with when to hangup channel */
int ast_channel_cmpwhentohangup ( struct ast_channel * chan , time_t offset )
{
time_t whentohangup ;
if ( chan - > whentohangup = = 0 ) {
if ( offset = = 0 )
return ( 0 ) ;
else
return ( - 1 ) ;
} else {
if ( offset = = 0 )
return ( 1 ) ;
else {
whentohangup = offset + time ( NULL ) ;
if ( chan - > whentohangup < whentohangup )
return ( 1 ) ;
else if ( chan - > whentohangup = = whentohangup )
return ( 0 ) ;
else
return ( - 1 ) ;
}
}
}
2005-05-15 04:48:30 +00:00
/*--- ast_channel_register: Register a new telephony channel in Asterisk */
2005-03-04 06:47:24 +00:00
int ast_channel_register ( const struct ast_channel_tech * tech )
2003-03-30 22:55:42 +00:00
{
2005-03-04 06:47:24 +00:00
struct chanlist * chan ;
ast_mutex_lock ( & chlock ) ;
2003-03-30 22:55:42 +00:00
1999-12-04 21:35:07 +00:00
chan = backends ;
2004-06-22 20:11:15 +00:00
while ( chan ) {
2005-03-04 06:47:24 +00:00
if ( ! strcasecmp ( tech - > type , chan - > tech - > type ) ) {
ast_log ( LOG_WARNING , " Already have a handler for type '%s' \n " , tech - > type ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-04 21:35:07 +00:00
return - 1 ;
}
chan = chan - > next ;
}
2005-03-04 06:47:24 +00:00
chan = malloc ( sizeof ( * chan ) ) ;
1999-12-04 21:35:07 +00:00
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 ;
}
2005-03-04 06:47:24 +00:00
chan - > tech = tech ;
chan - > next = backends ;
backends = chan ;
1999-12-04 21:35:07 +00:00
if ( option_debug )
2005-03-04 06:47:24 +00:00
ast_log ( LOG_DEBUG , " Registered handler for '%s' (%s) \n " , chan - > tech - > type , chan - > tech - > description ) ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Registered channel type '%s' (%s) \n " , chan - > tech - > type ,
chan - > tech - > description ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-04 21:35:07 +00:00
return 0 ;
}
2005-07-08 21:14:34 +00:00
void ast_channel_unregister ( const struct ast_channel_tech * tech )
{
struct chanlist * chan , * last = NULL ;
if ( option_debug )
ast_log ( LOG_DEBUG , " Unregistering channel type '%s' \n " , tech - > type ) ;
ast_mutex_lock ( & chlock ) ;
chan = backends ;
while ( chan ) {
if ( chan - > tech = = tech ) {
if ( last )
last - > next = chan - > next ;
else
backends = backends - > next ;
free ( chan ) ;
ast_mutex_unlock ( & chlock ) ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Unregistered channel type '%s' \n " , tech - > type ) ;
return ;
}
last = chan ;
chan = chan - > next ;
}
ast_mutex_unlock ( & chlock ) ;
}
const struct ast_channel_tech * ast_get_channel_tech ( const char * name )
{
struct chanlist * chanls ;
if ( ast_mutex_lock ( & chlock ) ) {
ast_log ( LOG_WARNING , " Unable to lock channel tech list \n " ) ;
return NULL ;
}
for ( chanls = backends ; chanls ; chanls = chanls - > next ) {
if ( strcasecmp ( name , chanls - > tech - > type ) )
continue ;
ast_mutex_unlock ( & chlock ) ;
return chanls - > tech ;
}
ast_mutex_unlock ( & chlock ) ;
return NULL ;
}
2005-07-05 17:16:17 +00:00
/*--- ast_cause2str: Gives the string form of a given hangup cause */
const char * ast_cause2str ( int cause )
{
int x ;
for ( x = 0 ; x < sizeof ( causes ) / sizeof ( causes [ 0 ] ) ; x + + )
if ( causes [ x ] . cause = = cause )
return causes [ x ] . desc ;
return " Unknown " ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_state2str: Gives the string form of a given channel state */
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
}
}
2005-05-15 04:48:30 +00:00
/*--- ast_transfercapability2str: Gives the string form of a given transfer capability */
2005-04-01 17:00:50 +00:00
char * ast_transfercapability2str ( int transfercapability )
{
switch ( transfercapability ) {
case AST_TRANS_CAP_SPEECH :
return " SPEECH " ;
case AST_TRANS_CAP_DIGITAL :
return " DIGITAL " ;
case AST_TRANS_CAP_RESTRICTED_DIGITAL :
return " RESTRICTED_DIGITAL " ;
case AST_TRANS_CAP_3_1K_AUDIO :
return " 3K1AUDIO " ;
case AST_TRANS_CAP_DIGITAL_W_TONES :
return " DIGITAL_W_TONES " ;
case AST_TRANS_CAP_VIDEO :
return " VIDEO " ;
default :
return " UNKNOWN " ;
}
}
2001-09-19 14:40:16 +00:00
2005-05-15 04:48:30 +00:00
/*--- ast_best_codec: Pick the best codec */
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 ,
} ;
2005-05-15 04:48:30 +00:00
/* Find the first prefered codec in the format given */
for ( x = 0 ; x < ( sizeof ( prefs ) / sizeof ( prefs [ 0 ] ) ) ; x + + )
2001-09-19 14:40:16 +00:00
if ( fmts & prefs [ x ] )
return prefs [ x ] ;
ast_log ( LOG_WARNING , " Don't know any of 0x%x formats \n " , fmts ) ;
return 0 ;
}
2005-03-04 06:47:24 +00:00
static const struct ast_channel_tech null_tech = {
. type = " NULL " ,
2005-03-27 21:58:10 +00:00
. description = " Null channel (should not see this) " ,
2005-03-04 06:47:24 +00:00
} ;
2005-05-15 04:48:30 +00:00
/*--- ast_channel_alloc: Create a new channel structure */
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 ;
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 ;
2005-03-04 06:47:24 +00:00
2002-06-21 01:40:13 +00:00
/* If shutting down, don't allocate any new channels */
2005-05-15 04:48:30 +00:00
if ( shutting_down ) {
ast_log ( LOG_WARNING , " Channel allocation failed: Refusing due to active shutdown \n " ) ;
2002-06-21 01:40:13 +00:00
return NULL ;
2005-05-15 04:48:30 +00:00
}
2005-03-04 06:47:24 +00:00
1999-12-04 21:35:07 +00:00
tmp = malloc ( sizeof ( struct ast_channel ) ) ;
2005-03-04 06:47:24 +00:00
if ( ! tmp ) {
2005-05-15 04:48:30 +00:00
ast_log ( LOG_WARNING , " Channel allocation failed: Out of memory \n " ) ;
2005-03-04 06:47:24 +00:00
return NULL ;
}
memset ( tmp , 0 , sizeof ( struct ast_channel ) ) ;
tmp - > sched = sched_context_create ( ) ;
if ( ! tmp - > sched ) {
2005-05-15 04:48:30 +00:00
ast_log ( LOG_WARNING , " Channel allocation failed: Unable to create schedule context \n " ) ;
2005-03-04 06:47:24 +00:00
free ( tmp ) ;
return NULL ;
}
2005-05-15 04:48:30 +00:00
for ( x = 0 ; x < AST_MAX_FDS - 1 ; x + + )
2005-03-04 06:47:24 +00:00
tmp - > fds [ x ] = - 1 ;
2004-03-19 04:23:20 +00:00
# ifdef ZAPTEL_OPTIMIZATIONS
2005-03-04 06:47:24 +00:00
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 ;
}
2004-03-19 04:23:20 +00:00
# else
2005-03-04 06:47:24 +00:00
tmp - > timingfd = - 1 ;
2004-03-19 04:23:20 +00:00
# endif
2005-03-04 06:47:24 +00:00
if ( needqueue ) {
if ( pipe ( tmp - > alertpipe ) ) {
2005-05-15 04:48:30 +00:00
ast_log ( LOG_WARNING , " Channel allocation failed: Can't create alert pipe! \n " ) ;
1999-12-04 21:35:07 +00:00
free ( tmp ) ;
2005-03-04 06:47:24 +00:00
return NULL ;
} else {
flags = fcntl ( tmp - > alertpipe [ 0 ] , F_GETFL ) ;
fcntl ( tmp - > alertpipe [ 0 ] , F_SETFL , flags | O_NONBLOCK ) ;
flags = fcntl ( tmp - > alertpipe [ 1 ] , F_GETFL ) ;
fcntl ( tmp - > alertpipe [ 1 ] , F_SETFL , flags | O_NONBLOCK ) ;
1999-12-04 21:35:07 +00:00
}
} else
2005-03-04 06:47:24 +00:00
/* Make sure we've got it done right if they don't */
tmp - > alertpipe [ 0 ] = tmp - > alertpipe [ 1 ] = - 1 ;
/* Always watch the alertpipe */
tmp - > fds [ AST_MAX_FDS - 1 ] = tmp - > alertpipe [ 0 ] ;
/* And timing pipe */
tmp - > fds [ AST_MAX_FDS - 2 ] = tmp - > timingfd ;
2005-07-20 16:39:49 +00:00
strcpy ( tmp - > name , " **Unkown** " ) ;
2005-03-04 06:47:24 +00:00
/* Initial state */
tmp - > _state = AST_STATE_DOWN ;
tmp - > streamid = - 1 ;
tmp - > appl = NULL ;
tmp - > data = NULL ;
tmp - > fin = global_fin ;
tmp - > fout = global_fout ;
2005-07-25 22:13:32 +00:00
snprintf ( tmp - > uniqueid , sizeof ( tmp - > uniqueid ) , " %li.%d " , ( long ) time ( NULL ) , uniqueint + + ) ;
2005-03-04 06:47:24 +00:00
headp = & tmp - > varshead ;
ast_mutex_init ( & tmp - > lock ) ;
2005-10-31 15:34:11 +00:00
AST_LIST_HEAD_INIT_NOLOCK ( headp ) ;
2005-07-20 16:39:49 +00:00
strcpy ( tmp - > context , " default " ) ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( tmp - > language , defaultlanguage , sizeof ( tmp - > language ) ) ;
2005-07-20 16:39:49 +00:00
strcpy ( tmp - > exten , " s " ) ;
2005-03-04 06:47:24 +00:00
tmp - > priority = 1 ;
tmp - > amaflags = ast_default_amaflags ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( tmp - > accountcode , ast_default_accountcode , sizeof ( tmp - > accountcode ) ) ;
2005-03-04 06:47:24 +00:00
tmp - > tech = & null_tech ;
2005-04-01 21:38:17 +00:00
ast_mutex_lock ( & chlock ) ;
2005-03-04 06:47:24 +00:00
tmp - > next = channels ;
channels = tmp ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
1999-12-04 21:35:07 +00:00
return tmp ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_queue_frame: Queue an outgoing media frame */
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 ;
2005-07-25 22:13:32 +00:00
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 ;
2005-03-04 06:47:24 +00:00
cur = chan - > readq ;
2002-06-21 01:40:13 +00:00
while ( cur ) {
2004-08-31 17:30:46 +00:00
if ( ( cur - > frametype = = AST_FRAME_CONTROL ) & & ( cur - > subclass = = AST_CONTROL_HANGUP ) ) {
/* Don't bother actually queueing anything after a hangup */
ast_frfree ( f ) ;
ast_mutex_unlock ( & chan - > lock ) ;
return 0 ;
}
2002-06-21 01:40:13 +00:00
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
2005-03-04 06:47:24 +00:00
chan - > readq = f ;
if ( chan - > alertpipe [ 1 ] > - 1 ) {
if ( write ( chan - > 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
2004-12-07 20:38:43 +00:00
} else if ( ast_test_flag ( chan , AST_FLAG_BLOCKING ) ) {
2003-04-11 04:31:33 +00:00
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 ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_queue_hangup: Queue a hangup frame for channel */
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
}
2005-05-15 04:48:30 +00:00
/*--- ast_queue_control: Queue a control frame */
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
}
2005-05-15 04:48:30 +00:00
/*--- ast_channel_defer_dtmf: Set defer DTMF flag on channel */
2001-09-19 14:40:16 +00:00
int ast_channel_defer_dtmf ( struct ast_channel * chan )
{
int pre = 0 ;
2005-07-25 22:13:32 +00:00
2001-09-19 14:40:16 +00:00
if ( chan ) {
2004-12-07 20:38:43 +00:00
pre = ast_test_flag ( chan , AST_FLAG_DEFER_DTMF ) ;
ast_set_flag ( chan , AST_FLAG_DEFER_DTMF ) ;
2001-09-19 14:40:16 +00:00
}
return pre ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_channel_undefer_dtmf: Unset defer DTMF flag on channel */
2001-09-19 14:40:16 +00:00
void ast_channel_undefer_dtmf ( struct ast_channel * chan )
{
if ( chan )
2004-12-07 20:38:43 +00:00
ast_clear_flag ( chan , AST_FLAG_DEFER_DTMF ) ;
2001-09-19 14:40:16 +00:00
}
2005-06-06 02:29:18 +00:00
/*
2005-09-15 16:34:39 +00:00
* Helper function to find channels . It supports these modes :
*
* prev ! = NULL : get channel next in list after prev
* name ! = NULL : get channel with matching name
* name ! = NULL & & namelen ! = 0 : get channel whose name starts with prefix
* exten ! = NULL : get channel whose exten or macroexten matches
* context ! = NULL & & exten ! = NULL : get channel whose context or macrocontext
*
* It returns with the channel ' s lock held . If getting the individual lock fails ,
2005-06-06 02:29:18 +00:00
* unlock and retry quickly up to 10 times , then give up .
*
* XXX Note that this code has cost O ( N ) because of the need to verify
* that the object is still on the global list .
*
* XXX also note that accessing fields ( e . g . c - > name in ast_log ( ) )
* can only be done with the lock held or someone could delete the
* object while we work on it . This causes some ugliness in the code .
* Note that removing the first ast_log ( ) may be harmful , as it would
* shorten the retry period and possibly cause failures .
* We should definitely go for a better scheme that is deadlock - free .
*/
static struct ast_channel * channel_find_locked ( const struct ast_channel * prev ,
2005-09-15 16:34:39 +00:00
const char * name , const int namelen ,
const char * context , const char * exten )
1999-12-18 07:01:48 +00:00
{
2005-06-14 18:09:56 +00:00
const char * msg = prev ? " deadlock " : " initial deadlock " ;
2005-06-06 02:29:18 +00:00
int retries , done ;
struct ast_channel * c ;
for ( retries = 0 ; retries < 10 ; retries + + ) {
ast_mutex_lock ( & chlock ) ;
for ( c = channels ; c ; c = c - > next ) {
2005-09-15 16:34:39 +00:00
if ( ! prev ) {
2005-07-08 21:14:34 +00:00
/* want head of list */
2005-09-15 16:34:39 +00:00
if ( ! name & & ! exten )
2005-07-08 21:14:34 +00:00
break ;
2005-09-15 16:34:39 +00:00
if ( name ) {
/* want match by full name */
if ( ! namelen ) {
if ( ! strcasecmp ( c - > name , name ) )
break ;
else
continue ;
}
/* want match by name prefix */
if ( ! strncasecmp ( c - > name , name , namelen ) )
2005-07-12 16:00:23 +00:00
break ;
2005-09-15 16:34:39 +00:00
} else if ( exten ) {
/* want match by context and exten */
if ( context & & ( strcasecmp ( c - > context , context ) & &
strcasecmp ( c - > macrocontext , context ) ) )
continue ;
/* match by exten */
if ( strcasecmp ( c - > exten , exten ) & &
strcasecmp ( c - > macroexten , exten ) )
2005-07-12 16:00:23 +00:00
continue ;
2005-09-15 16:34:39 +00:00
else
break ;
2005-07-12 16:00:23 +00:00
}
2005-06-06 02:29:18 +00:00
} else if ( c = = prev ) { /* found, return c->next */
c = c - > next ;
break ;
2004-06-29 12:38:04 +00:00
}
}
2005-06-06 02:29:18 +00:00
/* exit if chan not found or mutex acquired successfully */
done = ( c = = NULL ) | | ( ast_mutex_trylock ( & c - > lock ) = = 0 ) ;
/* this is slightly unsafe, as we _should_ hold the lock to access c->name */
if ( ! done & & c )
ast_log ( LOG_DEBUG , " Avoiding %s for '%s' \n " , msg , c - > name ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
2005-06-06 02:29:18 +00:00
if ( done )
return c ;
usleep ( 1 ) ;
2004-06-29 10:51:00 +00:00
}
2005-06-06 02:29:18 +00:00
/*
* c is surely not null , but we don ' t have the lock so cannot
* access c - > name
*/
ast_log ( LOG_WARNING , " Avoided %s for '%p', %d retries! \n " ,
msg , c , retries ) ;
return NULL ;
}
/*--- ast_channel_walk_locked: Browse channels in use */
struct ast_channel * ast_channel_walk_locked ( const struct ast_channel * prev )
{
2005-09-15 16:34:39 +00:00
return channel_find_locked ( prev , NULL , 0 , NULL , NULL ) ;
1999-12-18 07:01:48 +00:00
}
2005-05-15 04:48:30 +00:00
/*--- ast_get_channel_by_name_locked: Get channel by name and lock it */
2005-06-06 02:29:18 +00:00
struct ast_channel * ast_get_channel_by_name_locked ( const char * name )
2004-05-22 04:11:22 +00:00
{
2005-09-15 16:34:39 +00:00
return channel_find_locked ( NULL , name , 0 , NULL , NULL ) ;
2005-07-08 21:14:34 +00:00
}
/*--- ast_get_channel_by_name_prefix_locked: Get channel by name prefix and lock it */
struct ast_channel * ast_get_channel_by_name_prefix_locked ( const char * name , const int namelen )
{
2005-09-15 16:34:39 +00:00
return channel_find_locked ( NULL , name , namelen , NULL , NULL ) ;
2005-10-16 16:11:52 +00:00
}
/*--- ast_walk_channel_by_name_prefix_locked: Get next channel by name prefix and lock it */
struct ast_channel * ast_walk_channel_by_name_prefix_locked ( struct ast_channel * chan , const char * name , const int namelen )
{
return channel_find_locked ( chan , name , namelen , NULL , NULL ) ;
2005-09-15 16:34:39 +00:00
}
/*--- ast_get_channel_by_exten_locked: Get channel by exten (and optionally context) and lock it */
struct ast_channel * ast_get_channel_by_exten_locked ( const char * exten , const char * context )
{
return channel_find_locked ( NULL , NULL , 0 , context , exten ) ;
2004-05-22 04:11:22 +00:00
}
2005-05-15 04:48:30 +00:00
/*--- ast_safe_sleep_conditional: Wait, look for hangups and condition arg */
2004-04-27 21:21:57 +00:00
int ast_safe_sleep_conditional ( struct ast_channel * chan , int ms ,
2005-05-15 04:48:30 +00:00
int ( * cond ) ( void * ) , void * data )
2003-02-05 21:18:09 +00:00
{
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 ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_safe_sleep: Wait, look for hangups */
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 ;
}
2004-10-02 00:58:31 +00:00
static void free_cid ( struct ast_callerid * cid )
{
if ( cid - > cid_dnid )
free ( cid - > cid_dnid ) ;
if ( cid - > cid_num )
free ( cid - > cid_num ) ;
if ( cid - > cid_name )
free ( cid - > cid_name ) ;
if ( cid - > cid_ani )
free ( cid - > cid_ani ) ;
if ( cid - > cid_rdnis )
free ( cid - > cid_rdnis ) ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_channel_free: Free a channel structure */
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 ) ;
}
2005-03-04 06:47:24 +00:00
if ( chan - > tech_pvt ) {
1999-12-18 07:01:48 +00:00
ast_log ( LOG_WARNING , " Channel '%s' may not have been hung up properly \n " , chan - > name ) ;
2005-03-04 06:47:24 +00:00
free ( chan - > tech_pvt ) ;
}
2003-03-30 22:55:42 +00:00
2005-06-05 16:32:16 +00:00
ast_copy_string ( name , chan - > name , sizeof ( name ) ) ;
2003-03-30 22:55:42 +00:00
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
2004-12-24 01:40:07 +00:00
/* If there is native format music-on-hold state, free it */
if ( chan - > music_state )
ast_moh_cleanup ( chan ) ;
2001-03-12 03:04:51 +00:00
/* Free translatosr */
2005-03-04 06:47:24 +00:00
if ( chan - > readtrans )
ast_translator_free_path ( chan - > readtrans ) ;
if ( chan - > writetrans )
ast_translator_free_path ( chan - > 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 ) ;
2004-10-02 00:58:31 +00:00
free_cid ( & chan - > cid ) ;
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 */
2005-03-04 06:47:24 +00:00
if ( ( fd = chan - > alertpipe [ 0 ] ) > - 1 )
2002-06-21 01:40:13 +00:00
close ( fd ) ;
2005-03-04 06:47:24 +00:00
if ( ( fd = chan - > alertpipe [ 1 ] ) > - 1 )
2002-06-21 01:40:13 +00:00
close ( fd ) ;
2003-07-04 16:49:11 +00:00
if ( ( fd = chan - > timingfd ) > - 1 )
close ( fd ) ;
2005-03-04 06:47:24 +00:00
f = chan - > readq ;
chan - > 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 */
2005-10-28 23:01:13 +00:00
while ( ( vardata = AST_LIST_REMOVE_HEAD ( headp , entries ) ) )
ast_var_delete ( vardata ) ;
2002-09-10 20:48:20 +00:00
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
2005-10-17 15:41:55 +00:00
ast_device_state_changed_literal ( name ) ;
1999-12-18 07:01:48 +00:00
}
2005-10-28 23:01:13 +00:00
int ast_channel_spy_add ( struct ast_channel * chan , struct ast_channel_spy * spy )
2005-03-23 21:52:31 +00:00
{
2005-10-28 23:01:13 +00:00
if ( ! ast_test_flag ( spy , CHANSPY_FORMAT_AUDIO ) ) {
ast_log ( LOG_WARNING , " Could not add channel spy '%s' to channel '%s', only audio format spies are supported. \n " ,
spy - > type , chan - > name ) ;
return - 1 ;
}
2005-03-23 21:52:31 +00:00
2005-10-28 23:01:13 +00:00
if ( ast_test_flag ( spy , CHANSPY_READ_VOLADJUST ) & & ( spy - > read_queue . format ! = AST_FORMAT_SLINEAR ) ) {
ast_log ( LOG_WARNING , " Cannot provide volume adjustment on '%s' format spies \n " ,
ast_getformatname ( spy - > read_queue . format ) ) ;
return - 1 ;
}
if ( ast_test_flag ( spy , CHANSPY_WRITE_VOLADJUST ) & & ( spy - > write_queue . format ! = AST_FORMAT_SLINEAR ) ) {
ast_log ( LOG_WARNING , " Cannot provide volume adjustment on '%s' format spies \n " ,
ast_getformatname ( spy - > write_queue . format ) ) ;
return - 1 ;
}
if ( ast_test_flag ( spy , CHANSPY_MIXAUDIO ) & &
( ( spy - > read_queue . format ! = AST_FORMAT_SLINEAR ) | |
( spy - > write_queue . format ! = AST_FORMAT_SLINEAR ) ) ) {
ast_log ( LOG_WARNING , " Cannot provide audio mixing on '%s'-'%s' format spies \n " ,
ast_getformatname ( spy - > read_queue . format ) , ast_getformatname ( spy - > write_queue . format ) ) ;
return - 1 ;
}
if ( ! chan - > spies ) {
if ( ! ( chan - > spies = calloc ( 1 , sizeof ( * chan - > spies ) ) ) ) {
ast_log ( LOG_WARNING , " Memory allocation failure \n " ) ;
return - 1 ;
2005-03-23 21:52:31 +00:00
}
2005-10-28 23:01:13 +00:00
AST_LIST_HEAD_INIT_NOLOCK ( & chan - > spies - > list ) ;
AST_LIST_INSERT_HEAD ( & chan - > spies - > list , spy , list ) ;
} else {
AST_LIST_INSERT_TAIL ( & chan - > spies - > list , spy , list ) ;
2005-03-23 21:52:31 +00:00
}
2005-10-28 23:01:13 +00:00
if ( ast_test_flag ( spy , CHANSPY_TRIGGER_MODE ) ! = CHANSPY_TRIGGER_NONE ) {
ast_cond_init ( & spy - > trigger , NULL ) ;
ast_set_flag ( spy , CHANSPY_TRIGGER_READ ) ;
ast_clear_flag ( spy , CHANSPY_TRIGGER_WRITE ) ;
}
ast_log ( LOG_DEBUG , " Spy %s added to channel %s \n " ,
spy - > type , chan - > name ) ;
return 0 ;
}
void ast_channel_spy_stop_by_type ( struct ast_channel * chan , const char * type )
{
struct ast_channel_spy * spy ;
if ( ! chan - > spies )
return ;
AST_LIST_TRAVERSE ( & chan - > spies - > list , spy , list ) {
if ( ( spy - > type = = type ) & & ( spy - > status = = CHANSPY_RUNNING ) )
spy - > status = CHANSPY_DONE ;
}
}
void ast_channel_spy_trigger_wait ( struct ast_channel_spy * spy )
{
ast_cond_wait ( & spy - > trigger , & spy - > lock ) ;
}
void ast_channel_spy_remove ( struct ast_channel * chan , struct ast_channel_spy * spy )
{
struct ast_frame * f ;
if ( ! chan - > spies )
return ;
AST_LIST_REMOVE ( & chan - > spies - > list , spy , list ) ;
ast_mutex_lock ( & spy - > lock ) ;
for ( f = spy - > read_queue . head ; f ; f = spy - > read_queue . head ) {
spy - > read_queue . head = f - > next ;
ast_frfree ( f ) ;
}
for ( f = spy - > write_queue . head ; f ; f = spy - > write_queue . head ) {
spy - > write_queue . head = f - > next ;
ast_frfree ( f ) ;
}
if ( ast_test_flag ( spy , CHANSPY_TRIGGER_MODE ) ! = CHANSPY_TRIGGER_NONE )
ast_cond_destroy ( & spy - > trigger ) ;
ast_mutex_unlock ( & spy - > lock ) ;
ast_log ( LOG_DEBUG , " Spy %s removed from channel %s \n " ,
spy - > type , chan - > name ) ;
if ( AST_LIST_EMPTY ( & chan - > spies - > list ) ) {
if ( chan - > spies - > read_translator . path )
ast_translator_free_path ( chan - > spies - > read_translator . path ) ;
if ( chan - > spies - > write_translator . path )
ast_translator_free_path ( chan - > spies - > write_translator . path ) ;
free ( chan - > spies ) ;
chan - > spies = NULL ;
}
}
static void detach_spies ( struct ast_channel * chan )
{
struct ast_channel_spy * spy ;
if ( ! chan - > spies )
return ;
/* Marking the spies as done is sufficient. Chanspy or spy users will get the picture. */
AST_LIST_TRAVERSE ( & chan - > spies - > list , spy , list ) {
ast_mutex_lock ( & spy - > lock ) ;
if ( spy - > status = = CHANSPY_RUNNING )
spy - > status = CHANSPY_DONE ;
if ( ast_test_flag ( spy , CHANSPY_TRIGGER_MODE ) ! = CHANSPY_TRIGGER_NONE )
ast_cond_signal ( & spy - > trigger ) ;
ast_mutex_unlock ( & spy - > lock ) ;
}
AST_LIST_TRAVERSE_SAFE_BEGIN ( & chan - > spies - > list , spy , list )
ast_channel_spy_remove ( chan , spy ) ;
AST_LIST_TRAVERSE_SAFE_END ;
2005-03-23 21:52:31 +00:00
}
2005-05-15 04:48:30 +00:00
/*--- ast_softhangup_nolock: Softly hangup a channel, don't lock */
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 */
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( chan , AST_FLAG_BLOCKING ) )
1999-12-04 21:35:07 +00:00
pthread_kill ( chan - > blocker , SIGURG ) ;
return res ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_softhangup_nolock: Softly hangup a channel, lock */
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 ;
}
2005-10-28 23:01:13 +00:00
enum spy_direction {
SPY_READ ,
SPY_WRITE ,
} ;
# define SPY_QUEUE_SAMPLE_LIMIT 4000 /* half of one second */
static void queue_frame_to_spies ( struct ast_channel * chan , struct ast_frame * f , enum spy_direction dir )
2005-03-23 21:52:31 +00:00
{
2005-10-28 23:01:13 +00:00
struct ast_frame * translated_frame = NULL ;
struct ast_channel_spy * spy ;
struct ast_channel_spy_queue * queue ;
struct ast_channel_spy_queue * other_queue ;
struct channel_spy_trans * trans ;
struct ast_frame * last ;
2005-03-23 21:52:31 +00:00
2005-10-28 23:01:13 +00:00
trans = ( dir = = SPY_READ ) ? & chan - > spies - > read_translator : & chan - > spies - > write_translator ;
AST_LIST_TRAVERSE ( & chan - > spies - > list , spy , list ) {
ast_mutex_lock ( & spy - > lock ) ;
queue = ( dir = = SPY_READ ) ? & spy - > read_queue : & spy - > write_queue ;
if ( ( queue - > format = = AST_FORMAT_SLINEAR ) & & ( f - > subclass ! = AST_FORMAT_SLINEAR ) ) {
if ( ! translated_frame ) {
if ( trans - > path & & ( trans - > last_format ! = f - > subclass ) ) {
ast_translator_free_path ( trans - > path ) ;
trans - > path = NULL ;
}
if ( ! trans - > path ) {
ast_log ( LOG_DEBUG , " Building translator from %s to SLINEAR for spies on channel %s \n " ,
ast_getformatname ( f - > subclass ) , chan - > name ) ;
if ( ( trans - > path = ast_translator_build_path ( AST_FORMAT_SLINEAR , f - > subclass ) ) = = NULL ) {
ast_log ( LOG_WARNING , " Cannot build a path from %s to %s \n " ,
ast_getformatname ( f - > subclass ) , ast_getformatname ( AST_FORMAT_SLINEAR ) ) ;
ast_mutex_unlock ( & spy - > lock ) ;
continue ;
} else {
trans - > last_format = f - > subclass ;
}
}
translated_frame = ast_translate ( trans - > path , f , 0 ) ;
}
for ( last = queue - > head ; last & & last - > next ; last = last - > next ) ;
if ( last )
last - > next = ast_frdup ( translated_frame ) ;
else
queue - > head = ast_frdup ( translated_frame ) ;
} else {
if ( f - > subclass ! = queue - > format ) {
ast_log ( LOG_WARNING , " Spy '%s' on channel '%s' wants format '%s', but frame is '%s', dropping \n " ,
spy - > type , chan - > name ,
ast_getformatname ( queue - > format ) , ast_getformatname ( f - > subclass ) ) ;
ast_mutex_unlock ( & spy - > lock ) ;
continue ;
}
for ( last = queue - > head ; last & & last - > next ; last = last - > next ) ;
if ( last )
last - > next = ast_frdup ( f ) ;
else
queue - > head = ast_frdup ( f ) ;
2005-03-23 21:52:31 +00:00
}
2005-10-28 23:01:13 +00:00
queue - > samples + = f - > samples ;
if ( queue - > samples > SPY_QUEUE_SAMPLE_LIMIT ) {
if ( ast_test_flag ( spy , CHANSPY_TRIGGER_MODE ) ! = CHANSPY_TRIGGER_NONE ) {
other_queue = ( dir = = SPY_WRITE ) ? & spy - > read_queue : & spy - > write_queue ;
if ( other_queue - > samples = = 0 ) {
switch ( ast_test_flag ( spy , CHANSPY_TRIGGER_MODE ) ) {
case CHANSPY_TRIGGER_READ :
if ( dir = = SPY_WRITE ) {
ast_set_flag ( spy , CHANSPY_TRIGGER_WRITE ) ;
ast_clear_flag ( spy , CHANSPY_TRIGGER_READ ) ;
if ( option_debug )
ast_log ( LOG_DEBUG , " Switching spy '%s' on '%s' to write-trigger mode \n " ,
spy - > type , chan - > name ) ;
}
break ;
case CHANSPY_TRIGGER_WRITE :
if ( dir = = SPY_READ ) {
ast_set_flag ( spy , CHANSPY_TRIGGER_READ ) ;
ast_clear_flag ( spy , CHANSPY_TRIGGER_WRITE ) ;
if ( option_debug )
ast_log ( LOG_DEBUG , " Switching spy '%s' on '%s' to read-trigger mode \n " ,
spy - > type , chan - > name ) ;
}
break ;
}
if ( option_debug )
ast_log ( LOG_DEBUG , " Triggering queue flush for spy '%s' on '%s' \n " ,
spy - > type , chan - > name ) ;
ast_set_flag ( spy , CHANSPY_TRIGGER_FLUSH ) ;
ast_cond_signal ( & spy - > trigger ) ;
ast_mutex_unlock ( & spy - > lock ) ;
continue ;
}
}
if ( option_debug )
ast_log ( LOG_DEBUG , " Spy '%s' on channel '%s' %s queue too long, dropping frames \n " ,
spy - > type , chan - > name , ( dir = = SPY_READ ) ? " read " : " write " ) ;
while ( queue - > samples > SPY_QUEUE_SAMPLE_LIMIT ) {
struct ast_frame * drop = queue - > head ;
queue - > samples - = drop - > samples ;
queue - > head = drop - > next ;
ast_frfree ( drop ) ;
}
} else {
switch ( ast_test_flag ( spy , CHANSPY_TRIGGER_MODE ) ) {
case CHANSPY_TRIGGER_READ :
if ( dir = = SPY_READ )
ast_cond_signal ( & spy - > trigger ) ;
break ;
case CHANSPY_TRIGGER_WRITE :
if ( dir = = SPY_WRITE )
ast_cond_signal ( & spy - > trigger ) ;
break ;
}
}
ast_mutex_unlock ( & spy - > lock ) ;
2005-03-23 21:52:31 +00:00
}
2005-10-28 23:01:13 +00:00
if ( translated_frame )
ast_frfree ( translated_frame ) ;
2005-03-23 21:52:31 +00:00
}
2001-09-19 14:40:16 +00:00
static void free_translation ( struct ast_channel * clone )
{
2005-03-04 06:47:24 +00:00
if ( clone - > writetrans )
ast_translator_free_path ( clone - > writetrans ) ;
if ( clone - > readtrans )
ast_translator_free_path ( clone - > readtrans ) ;
clone - > writetrans = NULL ;
clone - > readtrans = NULL ;
clone - > rawwriteformat = clone - > nativeformats ;
clone - > rawreadformat = clone - > nativeformats ;
2001-09-19 14:40:16 +00:00
}
2005-05-15 04:48:30 +00:00
/*--- ast_hangup: Hangup a channel */
1999-12-04 21:35:07 +00:00
int ast_hangup ( struct ast_channel * chan )
{
int res = 0 ;
2005-07-25 22:13:32 +00:00
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 ) ;
2005-03-23 21:52:31 +00:00
2005-10-28 23:01:13 +00:00
detach_spies ( chan ) ; /* get rid of spies */
2005-03-23 21:52:31 +00:00
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 ) {
2004-12-07 20:38:43 +00:00
ast_set_flag ( chan , AST_FLAG_ZOMBIE ) ;
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 ) ;
2005-05-15 04:48:30 +00:00
if ( chan - > stream ) /* Close audio stream */
2004-04-02 23:25:24 +00:00
ast_closestream ( chan - > stream ) ;
2005-05-15 04:48:30 +00:00
if ( chan - > vstream ) /* Close video stream */
2004-04-02 23:25:24 +00:00
ast_closestream ( chan - > vstream ) ;
1999-12-04 21:35:07 +00:00
if ( chan - > sched )
sched_context_destroy ( chan - > sched ) ;
2005-05-15 04:48:30 +00:00
if ( chan - > generatordata ) /* Clear any tone stuff remaining */
2002-06-21 01:40:13 +00:00
chan - > generator - > release ( chan , chan - > generatordata ) ;
chan - > generatordata = NULL ;
chan - > generator = NULL ;
2005-05-15 04:48:30 +00:00
if ( chan - > cdr ) { /* End the CDR if it hasn't already */
2001-12-20 15:21:47 +00:00
ast_cdr_end ( chan - > cdr ) ;
2005-06-03 01:42:31 +00:00
ast_cdr_detach ( chan - > cdr ) ; /* Post and Free the CDR */
2005-08-29 23:11:29 +00:00
chan - > cdr = NULL ;
2001-12-20 15:21:47 +00:00
}
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( chan , AST_FLAG_BLOCKING ) ) {
2001-03-12 03:04:51 +00:00
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 ;
}
2004-12-07 20:38:43 +00:00
if ( ! ast_test_flag ( chan , AST_FLAG_ZOMBIE ) ) {
2001-05-07 00:43:32 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Hanging up channel '%s' \n " , chan - > name ) ;
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > hangup )
res = chan - > tech - > hangup ( chan ) ;
2005-07-25 22:13:32 +00:00
} else {
2001-05-07 00:43:32 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Hanging up zombie '%s' \n " , chan - > name ) ;
2005-07-25 22:13:32 +00:00
}
2001-05-07 00:43:32 +00:00
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-06-22 20:11:15 +00:00
" Uniqueid: %s \r \n "
2005-07-25 22:13:32 +00:00
" Cause: %d \r \n "
" Cause-txt: %s \r \n " ,
2005-05-15 04:48:30 +00:00
chan - > name ,
chan - > uniqueid ,
2005-07-25 22:13:32 +00:00
chan - > hangupcause ,
ast_cause2str ( chan - > hangupcause )
) ;
1999-12-18 07:01:48 +00:00
ast_channel_free ( chan ) ;
1999-12-04 21:35:07 +00:00
return res ;
}
int ast_answer ( struct ast_channel * chan )
{
2001-09-19 14:40:16 +00:00
int res = 0 ;
2004-06-23 17:41:51 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2001-05-07 00:43:32 +00:00
/* Stop if we're a zombie or need a soft hangup */
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( chan , AST_FLAG_ZOMBIE ) | | ast_check_hangup ( chan ) ) {
2004-06-23 17:41:51 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2001-05-07 00:43:32 +00:00
return - 1 ;
2004-06-23 17:41:51 +00:00
}
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 :
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > answer )
res = chan - > tech - > answer ( chan ) ;
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 ) ;
2004-06-24 03:04:25 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
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
}
2004-06-23 17:41:51 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
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 ;
2004-12-07 20:38:43 +00:00
ast_clear_flag ( chan , AST_FLAG_WRITE_INT ) ;
2004-08-27 03:28:32 +00:00
ast_settimeout ( chan , 0 , NULL , NULL ) ;
2002-06-21 01:40:13 +00:00
}
2004-04-02 21:58:10 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
}
2004-04-07 14:43:18 +00:00
2004-08-27 03:28:32 +00:00
static int generator_force ( void * data )
{
/* Called if generator doesn't have data */
void * tmp ;
int res ;
int ( * generate ) ( struct ast_channel * chan , void * tmp , int datalen , int samples ) ;
struct ast_channel * chan = data ;
tmp = chan - > generatordata ;
chan - > generatordata = NULL ;
generate = chan - > generator - > generate ;
res = generate ( chan , tmp , 0 , 160 ) ;
chan - > generatordata = tmp ;
if ( res ) {
ast_log ( LOG_DEBUG , " Auto-deactivating generator \n " ) ;
ast_deactivate_generator ( chan ) ;
}
return 0 ;
}
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 ;
2005-10-28 23:01:13 +00:00
2004-06-02 20:18:18 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2005-10-28 23:01:13 +00:00
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 ;
}
2005-10-28 23:01:13 +00:00
2003-04-16 02:47:03 +00:00
ast_prod ( chan ) ;
2005-10-28 23:01:13 +00:00
if ( gen - > alloc ) {
if ( ! ( chan - > generatordata = gen - > alloc ( chan , params ) ) )
res = - 1 ;
}
if ( ! res ) {
2004-08-27 03:28:32 +00:00
ast_settimeout ( chan , 160 , generator_force , chan ) ;
2002-06-21 01:40:13 +00:00
chan - > generator = gen ;
}
2005-10-28 23:01:13 +00:00
2004-06-02 20:18:18 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2005-10-28 23:01:13 +00:00
2004-06-02 20:18:18 +00:00
return res ;
2002-06-21 01:40:13 +00:00
}
2005-07-25 22:13:32 +00:00
/*--- ast_waitfor_n_fd: Wait for x amount of time on a file descriptor to have input. */
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
{
2005-07-25 17:27:36 +00:00
struct timeval start = { 0 , 0 } ;
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 ) {
2005-01-17 22:53:36 +00:00
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
2004-04-25 20:42:45 +00:00
return - 1 ;
}
if ( * ms > 0 )
2005-07-15 23:00:47 +00:00
start = ast_tvnow ( ) ;
2004-04-25 20:42:45 +00:00
y = 0 ;
2005-07-25 22:13:32 +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 ;
2005-07-25 22:13:32 +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 ) {
2005-07-15 23:00:47 +00:00
* ms - = ast_tvdiff_ms ( ast_tvnow ( ) , start ) ;
if ( * ms < 0 )
2004-04-25 20:42:45 +00:00
* ms = 0 ;
}
1999-12-04 21:35:07 +00:00
return winner ;
}
2005-07-25 22:13:32 +00:00
/*--- ast_waitfor_nanfds: Wait for x amount of time on a file descriptor to have input. */
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
{
2005-07-27 22:19:49 +00:00
struct timeval start = { 0 , 0 } ;
2004-04-25 20:42:45 +00:00
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 ) {
2005-01-17 22:53:36 +00:00
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
2004-04-25 20:42:45 +00:00
* 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 */
2005-07-25 22:13:32 +00:00
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 ;
2005-07-25 22:13:32 +00:00
for ( x = 0 ; x < n ; x + + ) {
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 ;
2005-08-31 22:12:23 +00:00
pfds [ max ] . revents = 0 ;
2004-04-25 20:42:45 +00:00
max + + ;
2001-05-07 00:43:32 +00:00
}
}
1999-12-04 21:35:07 +00:00
CHECK_BLOCKING ( c [ x ] ) ;
}
2005-07-25 22:13:32 +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 ;
2005-08-31 22:12:23 +00:00
pfds [ max ] . revents = 0 ;
2004-04-25 20:42:45 +00:00
max + + ;
}
2001-09-19 14:40:16 +00:00
}
2004-04-25 20:42:45 +00:00
if ( * ms > 0 )
2005-07-15 23:00:47 +00:00
start = ast_tvnow ( ) ;
2005-10-20 22:45:47 +00:00
if ( sizeof ( int ) = = 4 ) {
do {
int kbrms = rms ;
if ( kbrms > 600000 )
kbrms = 600000 ;
res = poll ( pfds , max , kbrms ) ;
if ( ! res )
rms - = kbrms ;
} while ( ! res & & ( rms > 0 ) ) ;
} else {
res = poll ( pfds , max , rms ) ;
}
2001-05-07 00:43:32 +00:00
if ( res < 0 ) {
2005-07-25 22:13:32 +00:00
for ( x = 0 ; x < n ; x + + )
2004-12-07 20:38:43 +00:00
ast_clear_flag ( c [ x ] , AST_FLAG_BLOCKING ) ;
2001-05-07 00:43:32 +00:00
/* 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 ;
2005-04-24 22:54:50 +00:00
} else {
/* If no fds signalled, then timeout. So set ms = 0
since we may not have an exact timeout .
*/
if ( res = = 0 )
* ms = 0 ;
2001-05-07 00:43:32 +00:00
}
2004-03-05 18:31:06 +00:00
if ( havewhen )
time ( & now ) ;
2004-04-25 20:42:45 +00:00
spoint = 0 ;
2005-07-25 22:13:32 +00:00
for ( x = 0 ; x < n ; x + + ) {
2004-12-07 20:38:43 +00:00
ast_clear_flag ( c [ x ] , AST_FLAG_BLOCKING ) ;
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 ] ;
}
2005-07-25 22:13:32 +00:00
for ( y = 0 ; y < AST_MAX_FDS ; y + + ) {
2001-05-07 00:43:32 +00:00
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 )
2004-12-07 20:38:43 +00:00
ast_set_flag ( c [ x ] , AST_FLAG_EXCEPTION ) ;
2004-04-25 20:42:45 +00:00
else
2004-12-07 20:38:43 +00:00
ast_clear_flag ( c [ x ] , AST_FLAG_EXCEPTION ) ;
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
}
2005-07-25 22:13:32 +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 ) {
2005-07-15 23:00:47 +00:00
* ms - = ast_tvdiff_ms ( ast_tvnow ( ) , start ) ;
if ( * ms < 0 )
2004-04-25 20:42:45 +00:00
* 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 ;
2005-07-25 22:13:32 +00:00
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
}
2005-06-05 15:04:43 +00:00
int ast_waitfordigit ( struct ast_channel * c , int ms )
1999-12-04 21:35:07 +00:00
{
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 ;
2005-06-05 15:04:43 +00:00
int result = 0 ;
2005-07-25 22:13:32 +00:00
2001-05-07 00:43:32 +00:00
/* Stop if we're a zombie or need a soft hangup */
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( c , AST_FLAG_ZOMBIE ) | | ast_check_hangup ( c ) )
2001-05-07 00:43:32 +00:00
return - 1 ;
2005-07-25 22:13:32 +00:00
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 ;
}
2005-07-25 22:13:32 +00:00
2005-06-05 15:04:43 +00:00
int 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 ;
2005-07-25 22:13:32 +00:00
2003-02-23 06:00:11 +00:00
/* Stop if we're a zombie or need a soft hangup */
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( c , AST_FLAG_ZOMBIE ) | | ast_check_hangup ( c ) )
2003-02-23 06:00:11 +00:00
return - 1 ;
/* Wait for a digit, no more than ms milliseconds total. */
2004-04-12 16:25:34 +00:00
while ( ms ) {
2005-04-22 01:40:23 +00:00
errno = 0 ;
2004-04-12 16:25:34 +00:00
rchan = ast_waitfor_nandfds ( & c , 1 , & cmdfd , ( cmdfd > - 1 ) ? 1 : 0 , NULL , & outfd , & ms ) ;
if ( ( ! rchan ) & & ( outfd < 0 ) & & ( ms ) ) {
2005-04-22 01:40:23 +00:00
if ( errno = = 0 | | errno = = EINTR )
2005-03-22 22:44:55 +00:00
continue ;
2004-04-12 16:25:34 +00:00
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
}
}
2005-01-15 23:48:12 +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 ;
2005-03-31 19:07:27 +00:00
int prestate ;
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
2005-07-25 22:13:32 +00:00
static struct ast_frame null_frame = {
2001-03-12 03:04:51 +00:00
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 */
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( chan , AST_FLAG_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 ;
}
2005-03-31 03:00:37 +00:00
prestate = chan - > _state ;
2002-06-21 01:40:13 +00:00
2004-12-07 20:38:43 +00:00
if ( ! ast_test_flag ( chan , AST_FLAG_DEFER_DTMF ) & & ! 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 */
2005-03-04 06:47:24 +00:00
if ( chan - > alertpipe [ 0 ] > - 1 ) {
read ( chan - > alertpipe [ 0 ] , & blah , sizeof ( blah ) ) ;
2002-06-21 01:40:13 +00:00
}
2003-05-12 04:23:55 +00:00
# ifdef ZAPTEL_OPTIMIZATIONS
2004-12-07 20:38:43 +00:00
if ( ( chan - > timingfd > - 1 ) & & ( chan - > fdno = = AST_MAX_FDS - 2 ) & & ast_test_flag ( chan , AST_FLAG_EXCEPTION ) ) {
ast_clear_flag ( chan , AST_FLAG_EXCEPTION ) ;
2003-05-12 04:23:55 +00:00
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
2005-03-04 06:47:24 +00:00
if ( ! chan - > readq | | ! chan - > readq - > next ) {
2004-03-19 04:23:20 +00:00
/* 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 */
2005-03-04 06:47:24 +00:00
if ( chan - > readq ) {
f = chan - > readq ;
chan - > readq = f - > next ;
2002-06-21 01:40:13 +00:00
/* 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 ( ) ;
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( chan , AST_FLAG_EXCEPTION ) ) {
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > exception )
f = chan - > tech - > 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 */
2004-12-07 20:38:43 +00:00
ast_clear_flag ( chan , AST_FLAG_EXCEPTION ) ;
2005-07-25 22:13:32 +00:00
} else {
if ( chan - > tech - > read )
f = chan - > tech - > read ( chan ) ;
else
ast_log ( LOG_WARNING , " No read routine on channel %s \n " , chan - > name ) ;
}
2002-06-21 01:40:13 +00:00
}
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 {
2005-10-28 23:01:13 +00:00
if ( chan - > spies )
queue_frame_to_spies ( chan , f , SPY_READ ) ;
2003-05-28 19:38:02 +00:00
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 " ) ;
}
2005-03-04 06:47:24 +00:00
if ( chan - > readtrans ) {
f = ast_translate ( chan - > readtrans , f , 1 ) ;
2003-05-28 19:38:02 +00:00
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 ) ;
2004-12-07 20:38:43 +00:00
} else if ( ast_test_flag ( chan , AST_FLAG_DEFER_DTMF ) & & 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 ) ) {
2005-03-31 03:00:37 +00:00
if ( prestate = = AST_STATE_UP ) {
2004-09-02 13:48:11 +00:00
ast_log ( LOG_DEBUG , " Dropping duplicate answer! \n " ) ;
f = & null_frame ;
}
2001-12-20 15:21:47 +00:00
/* 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 */
2004-08-27 22:53:56 +00:00
if ( f & & ( f - > frametype = = AST_FRAME_VOICE ) & & chan - > generatordata ) {
2004-08-27 03:28:32 +00:00
/* Mask generator data temporarily and apply. If there is a timing function, it
will be calling the generator instead */
2002-06-21 01:40:13 +00:00
void * tmp ;
int res ;
2004-04-02 21:58:10 +00:00
int ( * generate ) ( struct ast_channel * chan , void * tmp , int datalen , int samples ) ;
2005-07-25 22:13:32 +00:00
2004-08-27 22:53:56 +00:00
if ( chan - > timingfunc ) {
ast_log ( LOG_DEBUG , " Generator got voice, switching to phase locked mode \n " ) ;
ast_settimeout ( chan , 0 , NULL , NULL ) ;
}
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
}
2004-08-27 22:53:56 +00:00
} else if ( f & & ( f - > frametype = = AST_FRAME_CNG ) ) {
if ( chan - > generator & & ! chan - > timingfunc & & ( chan - > timingfd > - 1 ) ) {
ast_log ( LOG_DEBUG , " Generator got CNG, switching to zap timed mode \n " ) ;
ast_settimeout ( chan , 160 , generator_force , chan ) ;
}
2002-06-21 01:40:13 +00:00
}
2005-05-14 23:26:37 +00:00
/* High bit prints debugging */
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 ;
2005-07-25 22:13:32 +00:00
2001-05-07 00:43:32 +00:00
/* Stop if we're a zombie or need a soft hangup */
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( chan , AST_FLAG_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 ) ;
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > indicate )
res = chan - > tech - > indicate ( chan , condition ) ;
2003-08-14 18:46:02 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2005-03-04 06:47:24 +00:00
if ( ! chan - > tech - > indicate | | res ) {
2003-02-05 21:18:09 +00:00
/*
* 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 ) {
2005-07-25 22:13:32 +00:00
case AST_CONTROL_RINGING :
2003-02-05 21:18:09 +00:00
ts = ast_get_indication_tone ( chan - > zone , " ring " ) ;
break ;
2005-07-25 22:13:32 +00:00
case AST_CONTROL_BUSY :
2003-02-05 21:18:09 +00:00
ts = ast_get_indication_tone ( chan - > zone , " busy " ) ;
break ;
2005-07-25 22:13:32 +00:00
case AST_CONTROL_CONGESTION :
2003-02-05 21:18:09 +00:00
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); */
2004-06-14 21:18:52 +00:00
} else if ( condition = = AST_CONTROL_PROCEEDING ) {
/* Do nothing, really */
2005-01-17 12:37:55 +00:00
} else if ( condition = = AST_CONTROL_HOLD ) {
/* Do nothing.... */
} else if ( condition = = AST_CONTROL_UNHOLD ) {
/* Do nothing.... */
2005-08-30 02:12:09 +00:00
} else if ( condition = = AST_CONTROL_VIDUPDATE ) {
/* Do nothing.... */
2003-05-15 22:39:01 +00:00
} 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 )
{
2005-06-23 21:28:09 +00:00
int c ;
char * buf = ast_recvtext ( chan , timeout ) ;
if ( buf = = NULL )
return - 1 ; /* error or timeout */
c = * ( unsigned char * ) buf ;
free ( buf ) ;
return c ;
2001-12-20 15:21:47 +00:00
}
2005-06-21 01:16:18 +00:00
char * ast_recvtext ( struct ast_channel * chan , int timeout )
{
2005-06-23 21:28:09 +00:00
int res , done = 0 ;
char * buf = NULL ;
2005-06-21 01:16:18 +00:00
2005-06-23 21:28:09 +00:00
while ( ! done ) {
struct ast_frame * f ;
if ( ast_check_hangup ( chan ) )
break ;
res = ast_waitfor ( chan , timeout ) ;
if ( res < = 0 ) /* timeout or error */
break ;
timeout = res ; /* update timeout */
2005-06-21 01:16:18 +00:00
f = ast_read ( chan ) ;
2005-06-23 21:28:09 +00:00
if ( f = = NULL )
break ; /* no frame */
if ( f - > frametype = = AST_FRAME_CONTROL & & f - > subclass = = AST_CONTROL_HANGUP )
done = 1 ; /* force a break */
2005-07-15 22:06:15 +00:00
else if ( f - > frametype = = AST_FRAME_TEXT ) { /* what we want */
buf = strndup ( ( char * ) f - > data , f - > datalen ) ; /* dup and break */
2005-06-23 21:28:09 +00:00
done = 1 ;
2005-06-21 01:16:18 +00:00
}
ast_frfree ( f ) ;
}
2005-06-23 21:28:09 +00:00
return buf ;
2005-06-21 01:16:18 +00:00
}
2005-10-14 00:46:13 +00:00
int ast_sendtext ( struct ast_channel * chan , const char * text )
2000-03-26 01:59:06 +00:00
{
int res = 0 ;
2001-05-07 00:43:32 +00:00
/* Stop if we're a zombie or need a soft hangup */
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( chan , AST_FLAG_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 ) ;
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > send_text )
res = chan - > tech - > send_text ( chan , text ) ;
2004-12-07 20:38:43 +00:00
ast_clear_flag ( chan , AST_FLAG_BLOCKING ) ;
2000-03-26 01:59:06 +00:00
return res ;
}
2003-02-05 21:18:09 +00:00
static int do_senddigit ( struct ast_channel * chan , char digit )
{
int res = - 1 ;
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > send_digit )
res = chan - > tech - > send_digit ( chan , digit ) ;
if ( ! chan - > tech - > send_digit | | res ) {
2003-02-05 21:18:09 +00:00
/*
* 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 ' )
2005-07-25 22:13:32 +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 ' )
2005-07-25 22:13:32 +00:00
ast_playtones_start ( chan , 0 , dtmf_tones [ digit - ' A ' + 10 ] , 0 ) ;
2003-02-05 21:18:09 +00:00
else if ( digit = = ' * ' )
2005-07-25 22:13:32 +00:00
ast_playtones_start ( chan , 0 , dtmf_tones [ 14 ] , 0 ) ;
2003-02-05 21:18:09 +00:00
else if ( digit = = ' # ' )
2005-07-25 22:13:32 +00:00
ast_playtones_start ( chan , 0 , dtmf_tones [ 15 ] , 0 ) ;
2003-02-05 21:18:09 +00:00
else {
/* not handled */
2005-07-25 22:13:32 +00:00
ast_log ( LOG_DEBUG , " Unable to generate 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 )
{
2004-06-29 04:42:19 +00:00
return do_senddigit ( chan , digit ) ;
2004-05-20 00:29:09 +00:00
}
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 ] ;
2005-07-25 22:13:32 +00:00
2003-04-16 02:47:03 +00:00
/* 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 ) ;
2005-03-04 06:47:24 +00:00
a . subclass = chan - > rawwriteformat ;
2003-04-16 02:47:03 +00:00
a . data = nothing + AST_FRIENDLY_OFFSET ;
2004-11-01 01:44:11 +00:00
a . src = " ast_prod " ;
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 ;
2005-03-04 06:47:24 +00:00
if ( ! chan - > tech - > write_video )
2003-06-28 16:40:02 +00:00
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-12-07 20:38:43 +00:00
if ( ast_test_flag ( chan , AST_FLAG_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 ) {
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( chan , AST_FLAG_WRITE_INT ) )
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
}
2005-05-14 23:26:37 +00:00
/* High bit prints debugging */
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 :
2004-12-07 20:38:43 +00:00
ast_clear_flag ( chan , AST_FLAG_BLOCKING ) ;
2003-09-24 19:43:14 +00:00
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 :
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > send_text )
res = chan - > tech - > send_text ( chan , ( char * ) fr - > data ) ;
2005-02-28 06:06:42 +00:00
else
res = 0 ;
break ;
case AST_FRAME_HTML :
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > send_html )
res = chan - > tech - > send_html ( chan , fr - > subclass , ( char * ) fr - > data , fr - > datalen ) ;
2005-02-28 06:06:42 +00:00
else
res = 0 ;
2001-12-20 15:21:47 +00:00
break ;
2003-06-28 16:40:02 +00:00
case AST_FRAME_VIDEO :
/* XXX Handle translation of video codecs one day XXX */
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > write_video )
res = chan - > tech - > write_video ( chan , fr ) ;
2003-06-28 16:40:02 +00:00
else
res = 0 ;
break ;
1999-12-04 21:35:07 +00:00
default :
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > write ) {
2005-10-28 23:01:13 +00:00
f = ( chan - > writetrans ) ? ast_translate ( chan - > writetrans , fr , 0 ) : fr ;
2003-08-28 20:02:10 +00:00
if ( f ) {
2005-10-28 23:01:13 +00:00
if ( f - > frametype = = AST_FRAME_VOICE & & chan - > spies )
queue_frame_to_spies ( chan , f , SPY_WRITE ) ;
2005-03-24 03:04:45 +00:00
2005-07-25 22:13:32 +00:00
if ( chan - > monitor & & chan - > monitor - > write_stream & &
2003-03-25 19:30:06 +00:00
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
2005-07-25 22:13:32 +00:00
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 " ) ;
}
2005-07-05 22:21:54 +00:00
res = chan - > tech - > write ( chan , f ) ;
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
}
2005-08-22 21:19:59 +00:00
/* It's possible this is a translated frame */
if ( f & & f - > frametype = = AST_FRAME_DTMF ) {
ast_log ( LOG_DTMF , " %s : %c \n " , chan - > name , f - > subclass ) ;
} else if ( fr - > frametype = = AST_FRAME_DTMF ) {
ast_log ( LOG_DTMF , " %s : %c \n " , chan - > name , fr - > subclass ) ;
}
2003-02-12 13:59:15 +00:00
if ( f & & ( f ! = fr ) )
ast_frfree ( f ) ;
2004-12-07 20:38:43 +00:00
ast_clear_flag ( chan , AST_FLAG_BLOCKING ) ;
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-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
1999-12-04 21:35:07 +00:00
return res ;
}
2005-04-04 03:28:38 +00:00
static int set_format ( struct ast_channel * chan , int fmt , int * rawformat , int * format ,
struct ast_trans_pvt * * trans , const int direction )
2001-03-12 03:04:51 +00:00
{
int native ;
int res ;
native = chan - > nativeformats ;
2005-04-04 03:28:38 +00:00
/* Find a translation path from the native format to one of the desired formats */
if ( ! direction )
/* reading */
res = ast_translator_best_choice ( & fmt , & native ) ;
else
/* writing */
res = ast_translator_best_choice ( & native , & fmt ) ;
2001-03-12 03:04:51 +00:00
if ( res < 0 ) {
2005-07-25 22:13:32 +00:00
ast_log ( LOG_WARNING , " Unable to find a codec translation path from %s to %s \n " ,
2005-04-04 03:28:38 +00:00
ast_getformatname ( native ) , ast_getformatname ( fmt ) ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
2005-04-04 03:28:38 +00:00
/* Now we have a good choice for both. */
ast_mutex_lock ( & chan - > lock ) ;
* rawformat = native ;
2001-03-12 03:04:51 +00:00
/* User perspective is fmt */
2005-04-04 03:28:38 +00:00
* format = fmt ;
/* Free any read translation we have right now */
if ( * trans )
ast_translator_free_path ( * trans ) ;
/* Build a translation path from the raw format to the desired format */
if ( ! direction )
/* reading */
* trans = ast_translator_build_path ( * format , * rawformat ) ;
else
/* writing */
* trans = ast_translator_build_path ( * rawformat , * format ) ;
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2005-04-04 03:28:38 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Set channel %s to %s format %s \n " , chan - > name ,
direction ? " write " : " read " , ast_getformatname ( fmt ) ) ;
2001-03-12 03:04:51 +00:00
return 0 ;
}
2005-04-04 03:28:38 +00:00
int ast_set_read_format ( struct ast_channel * chan , int fmt )
2001-03-12 03:04:51 +00:00
{
2005-04-04 03:28:38 +00:00
return set_format ( chan , fmt , & chan - > rawreadformat , & chan - > readformat ,
& chan - > readtrans , 0 ) ;
}
int ast_set_write_format ( struct ast_channel * chan , int fmt )
{
return set_format ( chan , fmt , & chan - > rawwriteformat , & chan - > writeformat ,
& chan - > writetrans , 1 ) ;
2001-03-12 03:04:51 +00:00
}
2004-10-03 04:19:59 +00:00
struct ast_channel * __ast_request_and_dial ( const char * type , int format , void * data , int timeout , int * outstate , const char * cid_num , const char * cid_name , struct outgoing_helper * oh )
2002-09-10 20:48:20 +00:00
{
int state = 0 ;
2004-10-26 22:25:43 +00:00
int cause = 0 ;
2002-09-10 20:48:20 +00:00
struct ast_channel * chan ;
struct ast_frame * f ;
2003-09-12 16:51:35 +00:00
int res = 0 ;
2005-07-18 05:00:23 +00:00
2004-10-26 22:25:43 +00:00
chan = ast_request ( type , format , data , & cause ) ;
2002-09-10 20:48:20 +00:00
if ( chan ) {
2003-09-22 15:27:09 +00:00
if ( oh ) {
2005-11-01 21:11:57 +00:00
if ( oh - > vars )
ast_set_variables ( chan , oh - > vars ) ;
if ( oh - > cid_num & & * oh - > cid_num & & oh - > cid_name & & * oh - > cid_name )
ast_set_callerid ( chan , oh - > cid_num , oh - > cid_name , oh - > cid_num ) ;
if ( oh - > parent_channel )
ast_channel_inherit_variables ( oh - > parent_channel , chan ) ;
2003-09-22 15:27:09 +00:00
}
2004-10-02 00:58:31 +00:00
ast_set_callerid ( chan , cid_num , cid_name , cid_num ) ;
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
2004-10-26 22:25:43 +00:00
ast_log ( LOG_NOTICE , " Unable to call channel %s/%s \n " , type , ( char * ) data ) ;
} else {
2002-09-10 20:48:20 +00:00
ast_log ( LOG_NOTICE , " Unable to request channel %s/%s \n " , type , ( char * ) data ) ;
2004-10-26 22:25:43 +00:00
switch ( cause ) {
case AST_CAUSE_BUSY :
state = AST_CONTROL_BUSY ;
break ;
case AST_CAUSE_CONGESTION :
state = AST_CONTROL_CONGESTION ;
break ;
}
}
2003-10-09 14:12:26 +00:00
if ( chan ) {
/* Final fixups */
if ( oh ) {
if ( oh - > context & & * oh - > context )
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > context , oh - > context , sizeof ( chan - > context ) ) ;
2003-10-09 14:12:26 +00:00
if ( oh - > exten & & * oh - > exten )
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > exten , oh - > exten , sizeof ( chan - > exten ) ) ;
2005-07-15 23:24:51 +00:00
if ( oh - > priority )
chan - > priority = oh - > priority ;
2003-10-09 14:12:26 +00:00
}
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 ] ;
2004-06-29 19:29:03 +00:00
snprintf ( tmp , 256 , " %s/%s " , type , ( char * ) data ) ;
2003-09-12 16:51:35 +00:00
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 ;
}
2004-10-03 04:19:59 +00:00
struct ast_channel * ast_request_and_dial ( const char * type , int format , void * data , int timeout , int * outstate , const char * cidnum , const char * cidname )
2003-09-22 15:27:09 +00:00
{
2004-10-02 00:58:31 +00:00
return __ast_request_and_dial ( type , format , data , timeout , outstate , cidnum , cidname , NULL ) ;
2003-09-22 15:27:09 +00:00
}
2004-10-26 22:25:43 +00:00
struct ast_channel * ast_request ( const char * type , int format , void * data , int * cause )
1999-12-04 21:35:07 +00:00
{
struct chanlist * chan ;
2005-09-29 17:40:24 +00:00
struct ast_channel * c ;
2001-03-12 03:04:51 +00:00
int capabilities ;
int fmt ;
int res ;
2004-10-26 22:25:43 +00:00
int foo ;
2005-07-25 22:13:32 +00:00
2004-10-26 22:25:43 +00:00
if ( ! cause )
cause = & foo ;
* cause = AST_CAUSE_NOTDEFINED ;
2005-09-29 17:40:24 +00:00
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 ;
}
2005-09-29 17:40:24 +00:00
for ( chan = backends ; chan ; chan = chan - > next ) {
if ( strcasecmp ( type , chan - > tech - > type ) )
continue ;
capabilities = chan - > tech - > 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 - > tech - > capabilities , format ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
2005-09-29 17:40:24 +00:00
return NULL ;
1999-12-04 21:35:07 +00:00
}
2005-09-29 17:40:24 +00:00
ast_mutex_unlock ( & chlock ) ;
if ( ! chan - > tech - > requester )
return NULL ;
if ( ! ( c = chan - > tech - > requester ( type , capabilities , data , cause ) ) )
return NULL ;
if ( c - > _state = = AST_STATE_DOWN ) {
manager_event ( EVENT_FLAG_CALL , " Newchannel " ,
" Channel: %s \r \n "
" State: %s \r \n "
" CallerID: %s \r \n "
" CallerIDName: %s \r \n "
" Uniqueid: %s \r \n " ,
c - > name , ast_state2str ( c - > _state ) ,
c - > cid . cid_num ? c - > cid . cid_num : " <unknown> " ,
c - > cid . cid_name ? c - > cid . cid_name : " <unknown> " ,
c - > uniqueid ) ;
}
return c ;
2004-10-26 22:25:43 +00:00
}
2005-09-29 17:40:24 +00:00
ast_log ( LOG_WARNING , " No channel type registered for '%s' \n " , type ) ;
* cause = AST_CAUSE_NOSUCHDRIVER ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & chlock ) ;
2005-09-29 17:40:24 +00:00
return NULL ;
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 ) ;
2004-12-07 20:38:43 +00:00
if ( ! ast_test_flag ( chan , AST_FLAG_ZOMBIE ) & & ! ast_check_hangup ( chan ) )
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > call )
res = chan - > tech - > 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 ;
}
2005-07-25 22:13:32 +00:00
/*--- ast_transfer: Transfer a call to dest, if the channel supports transfer */
/* called by app_transfer or the manager interface */
2003-05-14 05:33:06 +00:00
int ast_transfer ( struct ast_channel * chan , char * dest )
{
int res = - 1 ;
2005-07-25 22:13:32 +00:00
2003-05-14 05:33:06 +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-12-07 20:38:43 +00:00
if ( ! ast_test_flag ( chan , AST_FLAG_ZOMBIE ) & & ! ast_check_hangup ( chan ) ) {
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > transfer ) {
res = chan - > tech - > transfer ( chan , dest ) ;
2003-05-14 05:33:06 +00:00
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 ;
2005-06-05 15:04:43 +00:00
int d ;
2005-07-25 22:13:32 +00:00
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 */
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( c , AST_FLAG_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 ;
2005-06-05 15:04:43 +00:00
int d ;
2005-07-25 22:13:32 +00:00
2003-02-23 06:00:11 +00:00
/* Stop if we're a zombie or need a soft hangup */
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( c , AST_FLAG_ZOMBIE ) | | ast_check_hangup ( c ) )
2003-02-23 06:00:11 +00:00
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 )
{
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > send_html )
2001-09-19 14:40:16 +00:00
return 1 ;
return 0 ;
}
2005-03-28 20:48:24 +00:00
int ast_channel_sendhtml ( struct ast_channel * chan , int subclass , const char * data , int datalen )
2001-09-19 14:40:16 +00:00
{
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > send_html )
return chan - > tech - > send_html ( chan , subclass , data , datalen ) ;
2001-09-19 14:40:16 +00:00
return - 1 ;
}
2005-03-28 20:48:24 +00:00
int ast_channel_sendurl ( struct ast_channel * chan , const char * url )
2001-09-19 14:40:16 +00:00
{
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > send_html )
return chan - > tech - > send_html ( chan , AST_HTML_URL , url , strlen ( url ) + 1 ) ;
2001-09-19 14:40:16 +00:00
return - 1 ;
}
2001-03-12 03:04:51 +00:00
int ast_channel_make_compatible ( struct ast_channel * chan , struct ast_channel * peer )
{
2005-04-18 16:26:41 +00:00
int src ;
int dst ;
2005-04-04 03:28:38 +00:00
/* Set up translation from the chan to the peer */
2005-04-18 16:26:41 +00:00
src = chan - > nativeformats ;
dst = peer - > nativeformats ;
if ( ast_translator_best_choice ( & dst , & src ) < 0 ) {
ast_log ( LOG_WARNING , " No path to translate from %s(%d) to %s(%d) \n " , chan - > name , src , peer - > name , dst ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
2005-07-25 22:13:32 +00:00
2005-04-18 16:26:41 +00:00
/* if the best path is not 'pass through', then
transcoding is needed ; if desired , force transcode path
to use SLINEAR between channels */
if ( ( src ! = dst ) & & option_transcode_slin )
dst = AST_FORMAT_SLINEAR ;
if ( ast_set_read_format ( chan , dst ) < 0 ) {
ast_log ( LOG_WARNING , " Unable to set read format on channel %s to %d \n " , chan - > name , dst ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
2005-04-18 16:26:41 +00:00
if ( ast_set_write_format ( peer , dst ) < 0 ) {
ast_log ( LOG_WARNING , " Unable to set write format on channel %s to %d \n " , peer - > name , dst ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
2005-04-18 16:26:41 +00:00
/* Set up translation from the peer to the chan */
src = peer - > nativeformats ;
dst = chan - > nativeformats ;
if ( ast_translator_best_choice ( & dst , & src ) < 0 ) {
ast_log ( LOG_WARNING , " No path to translate from %s(%d) to %s(%d) \n " , peer - > name , src , chan - > name , dst ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
2005-04-18 16:26:41 +00:00
/* if the best path is not 'pass through', then
transcoding is needed ; if desired , force transcode path
to use SLINEAR between channels */
if ( ( src ! = dst ) & & option_transcode_slin )
dst = AST_FORMAT_SLINEAR ;
if ( ast_set_read_format ( peer , dst ) < 0 ) {
ast_log ( LOG_WARNING , " Unable to set read format on channel %s to %d \n " , peer - > name , dst ) ;
2001-03-12 03:04:51 +00:00
return - 1 ;
}
2005-04-18 16:26:41 +00:00
if ( ast_set_write_format ( chan , dst ) < 0 ) {
ast_log ( LOG_WARNING , " Unable to set write format on channel %s to %d \n " , chan - > name , dst ) ;
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 ;
2005-07-25 22:13:32 +00:00
2005-01-09 09:42:54 +00:00
if ( original = = clone ) {
ast_log ( LOG_WARNING , " Can't masquerade channel '%s' into itself! \n " , original - > name ) ;
return - 1 ;
}
2004-04-20 03:16:01 +00:00
ast_mutex_lock ( & original - > lock ) ;
while ( ast_mutex_trylock ( & clone - > lock ) ) {
ast_mutex_unlock ( & original - > lock ) ;
usleep ( 1 ) ;
ast_mutex_lock ( & original - > lock ) ;
}
2005-08-31 21:28:12 +00:00
ast_log ( LOG_DEBUG , " Planning to masquerade channel %s into the structure of %s \n " ,
2001-05-07 00:43:32 +00:00
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 ) ;
2005-08-31 21:28:12 +00:00
ast_log ( LOG_DEBUG , " Done planning to masquerade channel %s into the structure of %s \n " , clone - > name , original - > name ) ;
2004-04-20 03:16:01 +00:00
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 ] ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( tmp , chan - > name , sizeof ( tmp ) ) ;
ast_copy_string ( chan - > name , newname , sizeof ( chan - > name ) ) ;
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
}
2005-01-08 17:23:29 +00:00
void ast_channel_inherit_variables ( const struct ast_channel * parent , struct ast_channel * child )
{
struct ast_var_t * current , * newvar ;
char * varname ;
AST_LIST_TRAVERSE ( & parent - > varshead , current , entries ) {
int vartype = 0 ;
varname = ast_var_full_name ( current ) ;
if ( ! varname )
continue ;
if ( varname [ 0 ] = = ' _ ' ) {
vartype = 1 ;
if ( varname [ 1 ] = = ' _ ' )
vartype = 2 ;
}
switch ( vartype ) {
case 1 :
newvar = ast_var_assign ( & varname [ 1 ] , ast_var_value ( current ) ) ;
if ( newvar ) {
2005-09-01 21:50:49 +00:00
AST_LIST_INSERT_TAIL ( & child - > varshead , newvar , entries ) ;
2005-01-08 17:23:29 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Copying soft-transferable variable %s. \n " , ast_var_name ( newvar ) ) ;
}
break ;
case 2 :
newvar = ast_var_assign ( ast_var_full_name ( current ) , ast_var_value ( current ) ) ;
if ( newvar ) {
2005-09-01 21:50:49 +00:00
AST_LIST_INSERT_TAIL ( & child - > varshead , newvar , entries ) ;
2005-01-08 17:23:29 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Copying hard-transferable variable %s. \n " , ast_var_name ( newvar ) ) ;
}
break ;
default :
if ( option_debug )
ast_log ( LOG_DEBUG , " Not copying variable %s. \n " , ast_var_name ( current ) ) ;
break ;
}
}
}
2005-01-02 02:07:24 +00:00
/* Clone channel variables from 'clone' channel into 'original' channel
All variables except those related to app_groupcount are cloned
Variables are actually _removed_ from ' clone ' channel , presumably
because it will subsequently be destroyed .
Assumes locks will be in place on both channels when called .
*/
static void clone_variables ( struct ast_channel * original , struct ast_channel * clone )
{
struct ast_var_t * varptr ;
/* we need to remove all app_groupcount related variables from the original
channel before merging in the clone ' s variables ; any groups assigned to the
original channel should be released , only those assigned to the clone
should remain
*/
AST_LIST_TRAVERSE_SAFE_BEGIN ( & original - > varshead , varptr , entries ) {
if ( ! strncmp ( ast_var_name ( varptr ) , GROUP_CATEGORY_PREFIX , strlen ( GROUP_CATEGORY_PREFIX ) ) ) {
AST_LIST_REMOVE ( & original - > varshead , varptr , entries ) ;
ast_var_delete ( varptr ) ;
}
}
AST_LIST_TRAVERSE_SAFE_END ;
/* Append variables from clone channel into original channel */
/* XXX Is this always correct? We have to in order to keep MACROS working XXX */
2005-01-15 06:37:51 +00:00
if ( AST_LIST_FIRST ( & clone - > varshead ) )
AST_LIST_INSERT_TAIL ( & original - > varshead , AST_LIST_FIRST ( & clone - > varshead ) , entries ) ;
2005-01-02 02:07:24 +00:00
}
2005-07-25 22:13:32 +00:00
/*--- ast_do_masquerade: Masquerade a channel */
2005-01-02 02:07:24 +00:00
/* Assumes channel will be locked when called */
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 ;
2004-07-09 10:57:43 +00:00
int origstate ;
2003-08-14 19:18:18 +00:00
struct ast_frame * cur , * prev ;
2005-03-04 06:47:24 +00:00
const struct ast_channel_tech * t ;
void * t_pvt ;
2004-10-02 00:58:31 +00:00
struct ast_callerid tmpcid ;
2001-05-07 00:43:32 +00:00
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 ] ;
2005-01-10 04:23:39 +00:00
2005-07-25 22:13:32 +00:00
if ( option_debug > 3 )
ast_log ( LOG_DEBUG , " Actually Masquerading %s(%d) into the structure of %s(%d) \n " ,
clone - > name , clone - > _state , original - > name , original - > _state ) ;
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
2005-07-25 22:13:32 +00:00
ast_log ( LOG_DEBUG , " Got clone lock for masquerade 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 */
2005-06-05 16:32:16 +00:00
ast_copy_string ( orig , original - > name , sizeof ( orig ) ) ;
2002-09-10 20:48:20 +00:00
/* Save the new name */
2005-06-05 16:32:16 +00:00
ast_copy_string ( newn , clone - > name , sizeof ( newn ) ) ;
2002-09-10 20:48:20 +00:00
/* 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 */
2005-06-05 16:32:16 +00:00
ast_copy_string ( original - > name , newn , sizeof ( original - > name ) ) ;
2001-05-07 00:43:32 +00:00
/* Mangle the name of the clone channel */
2005-06-05 16:32:16 +00:00
ast_copy_string ( clone - > name , masqn , sizeof ( clone - > name ) ) ;
2002-09-10 20:48:20 +00:00
/* Notify any managers of the change, first the masq then the other */
2004-08-26 22:45:26 +00:00
manager_event ( EVENT_FLAG_CALL , " Rename " , " Oldname: %s \r \n Newname: %s \r \n Uniqueid: %s \r \n " , newn , masqn , clone - > uniqueid ) ;
manager_event ( EVENT_FLAG_CALL , " Rename " , " Oldname: %s \r \n Newname: %s \r \n Uniqueid: %s \r \n " , orig , newn , original - > uniqueid ) ;
2001-05-07 00:43:32 +00:00
2005-03-04 06:47:24 +00:00
/* Swap the technlogies */
t = original - > tech ;
original - > tech = clone - > tech ;
clone - > tech = t ;
t_pvt = original - > tech_pvt ;
original - > tech_pvt = clone - > tech_pvt ;
clone - > tech_pvt = t_pvt ;
/* Swap the readq's */
cur = original - > readq ;
original - > readq = clone - > readq ;
clone - > readq = cur ;
/* Swap the alertpipes */
for ( i = 0 ; i < 2 ; i + + ) {
x = original - > alertpipe [ i ] ;
original - > alertpipe [ i ] = clone - > alertpipe [ i ] ;
clone - > alertpipe [ i ] = x ;
}
/* Swap the raw formats */
x = original - > rawreadformat ;
original - > rawreadformat = clone - > rawreadformat ;
clone - > rawreadformat = x ;
x = original - > rawwriteformat ;
original - > rawwriteformat = clone - > rawwriteformat ;
clone - > rawwriteformat = x ;
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 ;
2005-03-04 06:47:24 +00:00
cur = clone - > readq ;
2003-08-14 19:18:18 +00:00
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 ) {
2005-03-04 06:47:24 +00:00
prev - > next = original - > readq ;
original - > readq = clone - > readq ;
clone - > readq = NULL ;
if ( original - > alertpipe [ 1 ] > - 1 ) {
2005-07-25 22:13:32 +00:00
for ( i = 0 ; i < x ; i + + )
2005-03-04 06:47:24 +00:00
write ( original - > alertpipe [ 1 ] , & x , sizeof ( x ) ) ;
2003-08-14 19:18:18 +00:00
}
}
2002-09-10 20:48:20 +00:00
clone - > _softhangup = AST_SOFTHANGUP_DEV ;
2001-09-19 14:40:16 +00:00
2004-07-09 10:57:43 +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 . We do this early so that the clone has the proper
state of the original channel . */
origstate = original - > _state ;
original - > _state = clone - > _state ;
clone - > _state = origstate ;
2005-03-04 06:47:24 +00:00
if ( clone - > tech - > fixup ) {
res = clone - > tech - > 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 */
2005-03-04 06:47:24 +00:00
if ( clone - > tech - > hangup )
res = clone - > tech - > hangup ( clone ) ;
2001-05-07 00:43:32 +00:00
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 */
2005-06-05 16:32:16 +00:00
ast_copy_string ( clone - > name , zombn , sizeof ( clone - > name ) ) ;
2004-08-26 22:45:26 +00:00
manager_event ( EVENT_FLAG_CALL , " Rename " , " Oldname: %s \r \n Newname: %s \r \n Uniqueid: %s \r \n " , masqn , zombn , clone - > uniqueid ) ;
2001-05-07 00:43:32 +00:00
/* Update the type. */
original - > type = clone - > type ;
2005-07-31 21:27:21 +00:00
t_pvt = original - > monitor ;
original - > monitor = clone - > monitor ;
clone - > monitor = t_pvt ;
2005-01-21 22:30:16 +00:00
/* Keep the same language. */
2005-06-05 16:32:16 +00:00
ast_copy_string ( original - > language , clone - > language , sizeof ( original - > language ) ) ;
2001-05-07 00:43:32 +00:00
/* Copy the FD's */
2005-07-25 22:13:32 +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
}
2005-01-02 02:07:24 +00:00
clone_variables ( original , clone ) ;
2005-10-31 15:34:11 +00:00
AST_LIST_HEAD_INIT_NOLOCK ( & clone - > varshead ) ;
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 */
2004-12-07 20:38:43 +00:00
ast_copy_flags ( original , clone , AST_FLAG_EXCEPTION ) ;
2001-05-07 00:43:32 +00:00
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
2004-10-02 00:58:31 +00:00
/* Just swap the whole structures, nevermind the allocations, they'll work themselves
out . */
tmpcid = original - > cid ;
original - > cid = clone - > cid ;
clone - > cid = tmpcid ;
2001-05-07 00:43:32 +00:00
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 ;
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
2005-01-10 04:23:39 +00:00
/* Copy the music class */
2005-06-05 16:32:16 +00:00
ast_copy_string ( original - > musicclass , clone - > musicclass , sizeof ( original - > musicclass ) ) ;
2005-01-10 04:23:39 +00:00
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 */
2005-03-04 06:47:24 +00:00
if ( original - > tech - > fixup ) {
res = original - > tech - > fixup ( clone , original ) ;
2001-05-07 00:43:32 +00:00
if ( res ) {
2005-07-25 22:13:32 +00:00
ast_log ( LOG_WARNING , " Channel for type '%s' could not fixup channel %s \n " ,
2001-05-07 00:43:32 +00:00
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
2005-07-25 22:13:32 +00:00
ast_log ( LOG_WARNING , " Channel type '%s' does not have a fixup routine (for %s)! Bad things may happen. \n " ,
2001-05-07 00:43:32 +00:00
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 ) . */
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( clone , AST_FLAG_ZOMBIE ) ) {
2005-07-25 22:13:32 +00:00
ast_log ( LOG_DEBUG , " Destroying channel 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 ) ;
2005-07-25 22:13:32 +00:00
manager_event ( EVENT_FLAG_CALL , " Hangup " ,
" Channel: %s \r \n "
" Uniqueid: %s \r \n "
" Cause: %d \r \n "
" Cause-txt: %s \r \n " ,
clone - > name ,
clone - > uniqueid ,
clone - > hangupcause ,
ast_cause2str ( clone - > hangupcause )
) ;
2004-02-19 20:07:01 +00:00
} else {
2005-01-01 20:17:11 +00:00
struct ast_frame null_frame = { AST_FRAME_NULL , } ;
2004-02-19 20:07:01 +00:00
ast_log ( LOG_DEBUG , " Released clone lock on '%s' \n " , clone - > name ) ;
2004-12-07 20:38:43 +00:00
ast_set_flag ( clone , AST_FLAG_ZOMBIE ) ;
2005-01-01 20:17:11 +00:00
ast_queue_frame ( clone , & null_frame ) ;
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 */
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( original , AST_FLAG_BLOCKING ) )
2001-05-07 00:43:32 +00:00
pthread_kill ( original - > blocker , SIGURG ) ;
2005-07-25 22:13:32 +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 ;
}
2004-10-03 04:19:59 +00:00
void ast_set_callerid ( struct ast_channel * chan , const char * callerid , const char * calleridname , const char * ani )
2002-09-10 20:48:20 +00:00
{
2003-02-05 21:18:09 +00:00
if ( callerid ) {
2004-10-02 00:58:31 +00:00
if ( chan - > cid . cid_num )
free ( chan - > cid . cid_num ) ;
if ( ast_strlen_zero ( callerid ) )
chan - > cid . cid_num = NULL ;
else
chan - > cid . cid_num = strdup ( callerid ) ;
}
if ( calleridname ) {
if ( chan - > cid . cid_name )
free ( chan - > cid . cid_name ) ;
if ( ast_strlen_zero ( calleridname ) )
chan - > cid . cid_name = NULL ;
else
chan - > cid . cid_name = strdup ( calleridname ) ;
}
if ( ani ) {
if ( chan - > cid . cid_ani )
free ( chan - > cid . cid_ani ) ;
if ( ast_strlen_zero ( ani ) )
chan - > cid . cid_ani = NULL ;
else
chan - > cid . cid_ani = strdup ( ani ) ;
2003-02-05 21:18:09 +00:00
}
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 "
2004-12-21 21:46:58 +00:00
" CallerID: %s \r \n "
" CallerIDName: %s \r \n "
2005-07-25 22:13:32 +00:00
" Uniqueid: %s \r \n "
" CID-CallingPres: %d (%s) \r \n " ,
2004-10-02 00:58:31 +00:00
chan - > name , chan - > cid . cid_num ?
chan - > cid . cid_num : " <Unknown> " ,
chan - > cid . cid_name ?
chan - > cid . cid_name : " <Unknown> " ,
2005-07-25 22:13:32 +00:00
chan - > uniqueid ,
chan - > cid . cid_pres ,
ast_describe_caller_presentation ( chan - > cid . cid_pres )
) ;
2002-09-10 20:48:20 +00:00
}
int ast_setstate ( struct ast_channel * chan , int state )
{
2005-09-01 22:28:33 +00:00
int oldstate = chan - > _state ;
if ( oldstate = = state )
return 0 ;
chan - > _state = state ;
2005-10-17 15:41:55 +00:00
ast_device_state_changed_literal ( chan - > name ) ;
2005-09-01 22:28:33 +00:00
manager_event ( EVENT_FLAG_CALL ,
( oldstate = = AST_STATE_DOWN ) ? " Newchannel " : " Newstate " ,
" Channel: %s \r \n "
" State: %s \r \n "
" CallerID: %s \r \n "
" CallerIDName: %s \r \n "
" Uniqueid: %s \r \n " ,
chan - > name , ast_state2str ( chan - > _state ) ,
chan - > cid . cid_num ? chan - > cid . cid_num : " <unknown> " ,
chan - > cid . cid_name ? chan - > cid . cid_name : " <unknown> " ,
chan - > uniqueid ) ;
2001-05-07 00:43:32 +00:00
return 0 ;
}
2001-03-12 03:04:51 +00:00
2005-05-15 04:48:30 +00:00
/*--- Find bridged channel */
2004-10-23 12:19:47 +00:00
struct ast_channel * ast_bridged_channel ( struct ast_channel * chan )
{
struct ast_channel * bridged ;
bridged = chan - > _bridge ;
2005-03-04 06:47:24 +00:00
if ( bridged & & bridged - > tech - > bridged_channel )
bridged = bridged - > tech - > bridged_channel ( chan , bridged ) ;
2004-10-23 12:19:47 +00:00
return bridged ;
}
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 ;
}
}
2005-05-15 04:48:30 +00:00
if ( ! strcmp ( sound , " timeleft " ) ) { /* Queue support */
2004-05-03 02:02:27 +00:00
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 ) ;
2004-09-15 14:12:45 +00:00
res = ast_streamfile ( chan , " queue-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 ) ;
2004-09-15 14:12:45 +00:00
res = ast_streamfile ( chan , " queue-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
}
2005-10-13 18:27:54 +00:00
static enum ast_bridge_result ast_generic_bridge ( struct ast_channel * c0 , struct ast_channel * c1 ,
struct ast_bridge_config * config , struct ast_frame * * fo , struct ast_channel * * rc , int toms )
2004-05-03 02:02:27 +00:00
{
2005-08-09 01:59:59 +00:00
/* Copy voice back and forth between the two channels. */
2001-03-12 03:04:51 +00:00
struct ast_channel * cs [ 3 ] ;
struct ast_frame * f ;
2001-09-19 14:40:16 +00:00
struct ast_channel * who = NULL ;
2005-08-09 01:59:59 +00:00
enum ast_bridge_result res = AST_BRIDGE_COMPLETE ;
2005-03-31 03:00:37 +00:00
int o0nativeformats ;
int o1nativeformats ;
2005-08-09 01:59:59 +00:00
int watch_c0_dtmf ;
int watch_c1_dtmf ;
2005-09-01 00:10:49 +00:00
void * pvt0 , * pvt1 ;
2005-03-31 03:00:37 +00:00
cs [ 0 ] = c0 ;
cs [ 1 ] = c1 ;
2005-09-01 00:10:49 +00:00
pvt0 = c0 - > tech_pvt ;
pvt1 = c1 - > tech_pvt ;
2005-03-31 03:00:37 +00:00
o0nativeformats = c0 - > nativeformats ;
o1nativeformats = c1 - > nativeformats ;
2005-08-09 01:59:59 +00:00
watch_c0_dtmf = config - > flags & AST_BRIDGE_DTMF_CHANNEL_0 ;
watch_c1_dtmf = config - > flags & AST_BRIDGE_DTMF_CHANNEL_1 ;
2005-03-31 03:00:37 +00:00
for ( ; ; ) {
2005-09-01 00:10:49 +00:00
if ( ( c0 - > tech_pvt ! = pvt0 ) | | ( c1 - > tech_pvt ! = pvt1 ) | |
2005-08-09 01:59:59 +00:00
( o0nativeformats ! = c0 - > nativeformats ) | |
( o1nativeformats ! = c1 - > nativeformats ) ) {
2005-03-31 03:00:37 +00:00
/* Check for Masquerade, codec changes, etc */
2005-08-09 01:59:59 +00:00
res = AST_BRIDGE_RETRY ;
2005-03-31 03:00:37 +00:00
break ;
}
2005-10-13 18:27:54 +00:00
who = ast_waitfor_n ( cs , 2 , & toms ) ;
2005-03-31 03:00:37 +00:00
if ( ! who ) {
2005-10-14 17:02:20 +00:00
if ( ! toms ) {
res = AST_BRIDGE_RETRY ;
break ;
}
2005-03-31 03:00:37 +00:00
ast_log ( LOG_DEBUG , " Nobody there, continuing... \n " ) ;
2005-05-15 04:48:30 +00:00
if ( c0 - > _softhangup = = AST_SOFTHANGUP_UNBRIDGE | | c1 - > _softhangup = = AST_SOFTHANGUP_UNBRIDGE ) {
if ( c0 - > _softhangup = = AST_SOFTHANGUP_UNBRIDGE )
2005-10-14 17:02:20 +00:00
c0 - > _softhangup = 0 ;
if ( c1 - > _softhangup = = AST_SOFTHANGUP_UNBRIDGE )
c1 - > _softhangup = 0 ;
2005-05-15 04:48:30 +00:00
c0 - > _bridge = c1 ;
c1 - > _bridge = c0 ;
}
2005-03-31 03:00:37 +00:00
continue ;
}
f = ast_read ( who ) ;
if ( ! f ) {
* fo = NULL ;
* rc = who ;
2005-08-09 01:59:59 +00:00
res = AST_BRIDGE_COMPLETE ;
2005-03-31 03:00:37 +00:00
ast_log ( LOG_DEBUG , " Didn't get a frame from channel: %s \n " , who - > name ) ;
break ;
}
if ( ( f - > frametype = = AST_FRAME_CONTROL ) & & ! ( config - > flags & AST_BRIDGE_IGNORE_SIGS ) ) {
2005-08-30 02:12:09 +00:00
if ( ( f - > subclass = = AST_CONTROL_HOLD ) | | ( f - > subclass = = AST_CONTROL_UNHOLD ) | |
( f - > subclass = = AST_CONTROL_VIDUPDATE ) ) {
2005-03-31 03:00:37 +00:00
ast_indicate ( who = = c0 ? c1 : c0 , f - > subclass ) ;
} else {
* fo = f ;
* rc = who ;
2005-08-09 01:59:59 +00:00
res = AST_BRIDGE_COMPLETE ;
2005-03-31 03:00:37 +00:00
ast_log ( LOG_DEBUG , " Got a FRAME_CONTROL (%d) frame on channel %s \n " , f - > subclass , who - > name ) ;
break ;
}
}
if ( ( f - > frametype = = AST_FRAME_VOICE ) | |
2005-08-09 01:59:59 +00:00
( f - > frametype = = AST_FRAME_DTMF ) | |
( f - > frametype = = AST_FRAME_VIDEO ) | |
( f - > frametype = = AST_FRAME_IMAGE ) | |
( f - > frametype = = AST_FRAME_HTML ) | |
( f - > frametype = = AST_FRAME_TEXT ) ) {
if ( f - > frametype = = AST_FRAME_DTMF ) {
if ( ( ( who = = c0 ) & & watch_c0_dtmf ) | |
( ( who = = c1 ) & & watch_c1_dtmf ) ) {
* rc = who ;
* fo = f ;
res = AST_BRIDGE_COMPLETE ;
ast_log ( LOG_DEBUG , " Got DTMF on channel (%s) \n " , who - > name ) ;
break ;
} else {
goto tackygoto ;
2005-03-31 03:00:37 +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
tackygoto :
2005-08-09 01:59:59 +00:00
ast_write ( ( who = = c0 ) ? c1 : c0 , f ) ;
2005-03-31 03:00:37 +00:00
}
}
ast_frfree ( f ) ;
/* Swap who gets priority */
cs [ 2 ] = cs [ 0 ] ;
cs [ 0 ] = cs [ 1 ] ;
cs [ 1 ] = cs [ 2 ] ;
}
return res ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_channel_bridge: Bridge two channels together */
2005-08-09 01:59:59 +00:00
enum ast_bridge_result ast_channel_bridge ( struct ast_channel * c0 , struct ast_channel * c1 ,
struct ast_bridge_config * config , struct ast_frame * * fo , struct ast_channel * * rc )
2005-03-31 03:00:37 +00:00
{
struct ast_channel * who = NULL ;
2005-08-09 01:59:59 +00:00
enum ast_bridge_result res = AST_BRIDGE_COMPLETE ;
2001-09-19 14:40:16 +00:00
int nativefailed = 0 ;
2004-08-06 14:43:25 +00:00
int firstpass ;
2004-09-04 01:06:42 +00:00
int o0nativeformats ;
int o1nativeformats ;
2005-10-13 18:27:54 +00:00
long time_left_ms = 0 ;
struct timeval nexteventts = { 0 , } ;
2005-08-09 01:59:59 +00:00
char caller_warning = 0 ;
char callee_warning = 0 ;
2005-10-13 18:27:54 +00:00
int to ;
2004-04-26 23:22:34 +00:00
2004-10-23 12:19:47 +00:00
if ( c0 - > _bridge ) {
2001-05-07 00:43:32 +00:00
ast_log ( LOG_WARNING , " %s is already in a bridge with %s \n " ,
2004-10-23 12:19:47 +00:00
c0 - > name , c0 - > _bridge - > name ) ;
2001-05-07 00:43:32 +00:00
return - 1 ;
}
2004-10-23 12:19:47 +00:00
if ( c1 - > _bridge ) {
2001-05-07 00:43:32 +00:00
ast_log ( LOG_WARNING , " %s is already in a bridge with %s \n " ,
2004-10-23 12:19:47 +00:00
c1 - > name , c1 - > _bridge - > name ) ;
2001-05-07 00:43:32 +00:00
return - 1 ;
}
2005-08-09 01:59:59 +00:00
/* Stop if we're a zombie or need a soft hangup */
if ( ast_test_flag ( c0 , AST_FLAG_ZOMBIE ) | | ast_check_hangup_locked ( c0 ) | |
ast_test_flag ( c1 , AST_FLAG_ZOMBIE ) | | ast_check_hangup_locked ( c1 ) )
return - 1 ;
* fo = NULL ;
firstpass = config - > firstpass ;
config - > firstpass = 0 ;
if ( ast_tvzero ( config - > start_time ) )
config - > start_time = ast_tvnow ( ) ;
time_left_ms = config - > timelimit ;
caller_warning = ast_test_flag ( & config - > features_caller , AST_FEATURE_PLAY_WARNING ) ;
callee_warning = ast_test_flag ( & config - > features_callee , AST_FEATURE_PLAY_WARNING ) ;
if ( config - > start_sound & & firstpass ) {
if ( caller_warning )
bridge_playfile ( c0 , c1 , config - > start_sound , time_left_ms / 1000 ) ;
if ( callee_warning )
bridge_playfile ( c1 , c0 , config - > start_sound , time_left_ms / 1000 ) ;
}
2001-05-07 00:43:32 +00:00
/* Keep track of bridge */
2004-10-23 12:19:47 +00:00
c0 - > _bridge = c1 ;
c1 - > _bridge = c0 ;
2002-09-10 20:48:20 +00:00
manager_event ( EVENT_FLAG_CALL , " Link " ,
2005-08-09 01:59:59 +00:00
" Channel1: %s \r \n "
" Channel2: %s \r \n "
" Uniqueid1: %s \r \n "
" Uniqueid2: %s \r \n "
" CallerID1: %s \r \n "
" CallerID2: %s \r \n " ,
c0 - > name , c1 - > name , c0 - > uniqueid , c1 - > uniqueid , c0 - > cid . cid_num , c1 - > cid . cid_num ) ;
2005-06-21 23:10:29 +00:00
2004-09-04 01:06:42 +00:00
o0nativeformats = c0 - > nativeformats ;
2005-08-09 01:59:59 +00:00
o1nativeformats = c1 - > nativeformats ;
2005-10-13 18:27:54 +00:00
if ( config - > timelimit ) {
nexteventts = ast_tvadd ( config - > start_time , ast_samp2tv ( config - > timelimit , 1000 ) ) ;
if ( caller_warning | | callee_warning )
nexteventts = ast_tvsub ( nexteventts , ast_samp2tv ( config - > play_warning , 1000 ) ) ;
}
2001-03-12 03:04:51 +00:00
for ( /* ever */ ; ; ) {
2005-10-13 18:27:54 +00:00
to = - 1 ;
2004-05-03 02:02:27 +00:00
if ( config - > timelimit ) {
2005-10-13 18:27:54 +00:00
struct timeval now ;
now = ast_tvnow ( ) ;
to = ast_tvdiff_ms ( nexteventts , now ) ;
if ( to < 0 )
to = 0 ;
time_left_ms = config - > timelimit - ast_tvdiff_ms ( now , config - > start_time ) ;
if ( time_left_ms < to )
to = time_left_ms ;
2004-05-03 02:02:27 +00:00
if ( time_left_ms < = 0 ) {
2005-08-09 01:59:59 +00:00
if ( caller_warning & & config - > end_sound )
bridge_playfile ( c0 , c1 , config - > end_sound , 0 ) ;
if ( callee_warning & & config - > end_sound )
bridge_playfile ( c1 , c0 , config - > end_sound , 0 ) ;
2004-04-27 16:42:43 +00:00
* fo = NULL ;
2005-05-15 04:48:30 +00:00
if ( who )
* rc = who ;
2004-04-27 16:42:43 +00:00
res = 0 ;
2004-04-26 23:22:34 +00:00
break ;
}
2005-10-13 18:27:54 +00:00
if ( ! to ) {
if ( time_left_ms > = 5000 ) {
if ( caller_warning & & config - > warning_sound & & config - > play_warning )
bridge_playfile ( c0 , c1 , config - > warning_sound , time_left_ms / 1000 ) ;
if ( callee_warning & & config - > warning_sound & & config - > play_warning )
bridge_playfile ( c1 , c0 , config - > warning_sound , time_left_ms / 1000 ) ;
}
if ( config - > warning_freq ) {
nexteventts = ast_tvadd ( nexteventts , ast_samp2tv ( config - > warning_freq , 1000 ) ) ;
} else
nexteventts = ast_tvadd ( config - > start_time , ast_samp2tv ( config - > timelimit , 1000 ) ) ;
2004-04-26 23:22:34 +00:00
}
}
2005-03-23 21:52:31 +00:00
if ( c0 - > _softhangup = = AST_SOFTHANGUP_UNBRIDGE | | c1 - > _softhangup = = AST_SOFTHANGUP_UNBRIDGE ) {
if ( c0 - > _softhangup = = AST_SOFTHANGUP_UNBRIDGE )
c0 - > _softhangup = 0 ;
if ( c1 - > _softhangup = = AST_SOFTHANGUP_UNBRIDGE )
c1 - > _softhangup = 0 ;
c0 - > _bridge = c1 ;
c1 - > _bridge = c0 ;
2005-03-31 03:00:37 +00:00
ast_log ( LOG_DEBUG , " Unbridge signal received. Ending native bridge. \n " ) ;
2005-03-23 21:52:31 +00:00
continue ;
}
2001-09-19 14:40:16 +00:00
/* Stop if we're a zombie or need a soft hangup */
2005-08-09 01:59:59 +00:00
if ( ast_test_flag ( c0 , AST_FLAG_ZOMBIE ) | | ast_check_hangup_locked ( c0 ) | |
ast_test_flag ( c1 , AST_FLAG_ZOMBIE ) | | ast_check_hangup_locked ( c1 ) ) {
2001-09-19 14:40:16 +00:00
* fo = NULL ;
2005-05-15 04:48:30 +00:00
if ( who )
* rc = who ;
2001-09-19 14:40:16 +00:00
res = 0 ;
2005-08-09 01:59:59 +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 ,
ast_test_flag ( c0 , AST_FLAG_ZOMBIE ) ? " Yes " : " No " ,
ast_check_hangup ( c0 ) ? " Yes " : " No " ,
ast_test_flag ( c1 , AST_FLAG_ZOMBIE ) ? " Yes " : " No " ,
ast_check_hangup ( c1 ) ? " Yes " : " No " ) ;
2001-09-19 14:40:16 +00:00
break ;
}
2005-08-09 01:59:59 +00:00
if ( c0 - > tech - > bridge & &
( config - > timelimit = = 0 ) & &
( c0 - > tech - > bridge = = c1 - > tech - > bridge ) & &
2005-10-28 23:01:13 +00:00
! nativefailed & & ! c0 - > monitor & & ! c1 - > monitor & &
! c0 - > spies & & ! c1 - > spies ) {
/* Looks like they share a bridge method and nothing else is in the way */
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 ) ;
2005-03-23 21:52:31 +00:00
ast_set_flag ( c0 , AST_FLAG_NBRIDGE ) ;
ast_set_flag ( c1 , AST_FLAG_NBRIDGE ) ;
2005-10-13 18:27:54 +00:00
if ( ( res = c0 - > tech - > bridge ( c0 , c1 , config - > flags , fo , rc , to ) ) = = AST_BRIDGE_COMPLETE ) {
2002-09-10 20:48:20 +00:00
manager_event ( EVENT_FLAG_CALL , " Unlink " ,
2005-08-09 01:59:59 +00:00
" Channel1: %s \r \n "
" Channel2: %s \r \n "
" Uniqueid1: %s \r \n "
" Uniqueid2: %s \r \n "
" CallerID1: %s \r \n "
" CallerID2: %s \r \n " ,
c0 - > name , c1 - > name , c0 - > uniqueid , c1 - > uniqueid , c0 - > cid . cid_num , c1 - > cid . cid_num ) ;
ast_log ( LOG_DEBUG , " Returning from native bridge, channels: %s, %s \n " , c0 - > name , c1 - > name ) ;
2005-03-23 21:52:31 +00:00
ast_clear_flag ( c0 , AST_FLAG_NBRIDGE ) ;
ast_clear_flag ( c1 , AST_FLAG_NBRIDGE ) ;
2005-08-09 01:59:59 +00:00
if ( c0 - > _softhangup = = AST_SOFTHANGUP_UNBRIDGE | | c1 - > _softhangup = = AST_SOFTHANGUP_UNBRIDGE )
2005-03-23 21:52:31 +00:00
continue ;
2005-08-09 01:59:59 +00:00
c0 - > _bridge = NULL ;
c1 - > _bridge = NULL ;
return res ;
2005-03-23 21:52:31 +00:00
} else {
ast_clear_flag ( c0 , AST_FLAG_NBRIDGE ) ;
ast_clear_flag ( c1 , AST_FLAG_NBRIDGE ) ;
2005-10-28 23:01:13 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Native bridge of %s and %s was unsuccessful \n " , c0 - > name , c1 - > name ) ;
2001-09-19 14:40:16 +00:00
}
2005-10-14 17:02:20 +00:00
if ( res = = AST_BRIDGE_RETRY )
continue ;
2005-08-09 01:59:59 +00:00
switch ( res ) {
case AST_BRIDGE_RETRY :
2005-08-16 20:37:27 +00:00
/* continue; */
break ;
2005-08-09 01:59:59 +00:00
default :
2001-09-19 14:40:16 +00:00
ast_log ( LOG_WARNING , " Private bridge between %s and %s failed \n " , c0 - > name , c1 - > name ) ;
2005-08-09 01:59:59 +00:00
/* fallthrough */
case AST_BRIDGE_FAILED_NOWARN :
2005-07-25 22:13:32 +00:00
nativefailed + + ;
2005-08-09 01:59:59 +00:00
break ;
}
2001-09-19 14:40:16 +00:00
}
2005-08-09 01:59:59 +00:00
if ( ( ( c0 - > writeformat ! = c1 - > readformat ) | | ( c0 - > readformat ! = c1 - > writeformat ) | |
( c0 - > nativeformats ! = o0nativeformats ) | | ( c1 - > nativeformats ! = o1nativeformats ) ) & &
! ( 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 ) ;
2005-06-21 23:10:29 +00:00
manager_event ( EVENT_FLAG_CALL , " Unlink " ,
2005-08-09 01:59:59 +00:00
" Channel1: %s \r \n "
" Channel2: %s \r \n "
" Uniqueid1: %s \r \n "
" Uniqueid2: %s \r \n "
" CallerID1: %s \r \n "
" CallerID2: %s \r \n " ,
c0 - > name , c1 - > name , c0 - > uniqueid , c1 - > uniqueid , c0 - > cid . cid_num , c1 - > cid . cid_num ) ;
return AST_BRIDGE_FAILED ;
2001-09-19 14:40:16 +00:00
}
2004-09-04 01:06:42 +00:00
o0nativeformats = c0 - > nativeformats ;
o1nativeformats = c1 - > nativeformats ;
2001-09-19 14:40:16 +00:00
}
2005-10-13 18:27:54 +00:00
res = ast_generic_bridge ( c0 , c1 , config , fo , rc , to ) ;
2005-08-09 01:59:59 +00:00
if ( res ! = AST_BRIDGE_RETRY )
2001-05-07 00:43:32 +00:00
break ;
2001-03-12 03:04:51 +00:00
}
2005-08-09 01:59:59 +00:00
2004-10-23 12:19:47 +00:00
c0 - > _bridge = NULL ;
c1 - > _bridge = NULL ;
2005-08-09 01:59:59 +00:00
2005-06-21 23:10:29 +00:00
manager_event ( EVENT_FLAG_CALL , " Unlink " ,
2005-08-09 01:59:59 +00:00
" Channel1: %s \r \n "
" Channel2: %s \r \n "
" Uniqueid1: %s \r \n "
" Uniqueid2: %s \r \n "
" CallerID1: %s \r \n "
" CallerID2: %s \r \n " ,
c0 - > name , c1 - > name , c0 - > uniqueid , c1 - > uniqueid , c0 - > cid . cid_num , c1 - > cid . cid_num ) ;
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 ;
}
2005-05-15 04:48:30 +00:00
/*--- ast_channel_setoption: Sets an option on a channel */
2001-05-07 00:43:32 +00:00
int ast_channel_setoption ( struct ast_channel * chan , int option , void * data , int datalen , int block )
{
int res ;
2005-07-25 22:13:32 +00:00
2005-03-04 06:47:24 +00:00
if ( chan - > tech - > setoption ) {
res = chan - > tech - > setoption ( chan , option , data , datalen ) ;
2001-05-07 00:43:32 +00:00
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 ;
2005-07-25 22:13:32 +00:00
2002-06-21 01:40:13 +00:00
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 ) ;
}
2005-07-25 22:13:32 +00:00
static void * tonepair_alloc ( struct ast_channel * chan , void * params )
2002-06-21 01:40:13 +00:00
{
struct tonepair_state * ts ;
struct tonepair_def * td = params ;
2005-07-25 22:13:32 +00:00
2002-06-21 01:40:13 +00:00
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 :) */
2004-12-07 20:38:43 +00:00
ast_set_flag ( chan , AST_FLAG_WRITE_INT ) ;
2002-06-21 01:40:13 +00:00
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 ) ) ;
2005-07-25 22:13:32 +00:00
for ( x = 0 ; x < ( len / 2 ) ; x + + ) {
2002-06-21 01:40:13 +00:00
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 , } ;
2005-07-25 22:13:32 +00:00
2002-06-21 01:40:13 +00:00
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 ;
2005-07-25 22:13:32 +00:00
2002-06-21 01:40:13 +00:00
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
2005-01-15 21:51:38 +00:00
ast_group_t ast_get_group ( char * s )
2004-02-27 06:15:49 +00:00
{
char * copy ;
char * piece ;
char * c = NULL ;
2005-07-25 22:13:32 +00:00
int start = 0 , finish = 0 , x ;
2005-01-15 21:51:38 +00:00
ast_group_t group = 0 ;
2005-07-25 22:13:32 +00:00
2004-02-27 06:15:49 +00:00
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 {
2005-07-25 22:13:32 +00:00
ast_log ( LOG_ERROR , " Syntax error parsing group configuration '%s' at '%s'. Ignoring. \n " , s , piece ) ;
2005-01-13 03:31:58 +00:00
continue ;
2004-02-27 06:15:49 +00:00
}
2005-07-25 22:13:32 +00:00
for ( x = start ; x < = finish ; x + + ) {
2005-01-15 21:51:38 +00:00
if ( ( x > 63 ) | | ( x < 0 ) ) {
ast_log ( LOG_WARNING , " Ignoring invalid group %d (maximum group is 63) \n " , x ) ;
2004-02-27 06:15:49 +00:00
} else
2005-07-12 15:13:39 +00:00
group | = ( ( ast_group_t ) 1 < < x ) ;
2004-02-27 06:15:49 +00:00
}
}
return group ;
}
2004-12-09 19:55:01 +00:00
static int ( * ast_moh_start_ptr ) ( struct ast_channel * , char * ) = NULL ;
static void ( * ast_moh_stop_ptr ) ( struct ast_channel * ) = NULL ;
2004-12-24 01:40:07 +00:00
static void ( * ast_moh_cleanup_ptr ) ( struct ast_channel * ) = NULL ;
2004-12-09 19:55:01 +00:00
void ast_install_music_functions ( int ( * start_ptr ) ( struct ast_channel * , char * ) ,
2004-12-24 01:40:07 +00:00
void ( * stop_ptr ) ( struct ast_channel * ) ,
void ( * cleanup_ptr ) ( struct ast_channel * )
)
2004-12-09 19:55:01 +00:00
{
ast_moh_start_ptr = start_ptr ;
ast_moh_stop_ptr = stop_ptr ;
2004-12-24 01:40:07 +00:00
ast_moh_cleanup_ptr = cleanup_ptr ;
2004-12-09 19:55:01 +00:00
}
void ast_uninstall_music_functions ( void )
{
ast_moh_start_ptr = NULL ;
ast_moh_stop_ptr = NULL ;
2004-12-24 01:40:07 +00:00
ast_moh_cleanup_ptr = NULL ;
2004-12-09 19:55:01 +00:00
}
2005-07-25 22:13:32 +00:00
/*! Turn on music on hold on a given channel */
2004-12-09 19:55:01 +00:00
int ast_moh_start ( struct ast_channel * chan , char * mclass )
{
2005-07-25 22:13:32 +00:00
if ( ast_moh_start_ptr )
2004-12-09 19:55:01 +00:00
return ast_moh_start_ptr ( chan , mclass ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Music class %s requested but no musiconhold loaded. \n " , mclass ? mclass : " default " ) ;
return 0 ;
}
2005-07-25 22:13:32 +00:00
/*! Turn off music on hold on a given channel */
2004-12-09 19:55:01 +00:00
void ast_moh_stop ( struct ast_channel * chan )
{
if ( ast_moh_stop_ptr )
ast_moh_stop_ptr ( chan ) ;
}
2004-12-24 01:40:07 +00:00
void ast_moh_cleanup ( struct ast_channel * chan )
{
if ( ast_moh_cleanup_ptr )
ast_moh_cleanup_ptr ( chan ) ;
}
2004-12-31 00:04:41 +00:00
void ast_channels_init ( void )
{
ast_cli_register ( & cli_show_channeltypes ) ;
}
2005-01-15 21:51:38 +00:00
/*--- ast_print_group: Print call group and pickup group ---*/
char * ast_print_group ( char * buf , int buflen , ast_group_t group )
{
unsigned int i ;
int first = 1 ;
char num [ 3 ] ;
buf [ 0 ] = ' \0 ' ;
if ( ! group ) /* Return empty string if no group */
return ( buf ) ;
for ( i = 0 ; i < = 63 ; i + + ) { /* Max group is 63 */
2005-07-12 15:13:39 +00:00
if ( group & ( ( ast_group_t ) 1 < < i ) ) {
2005-01-15 21:51:38 +00:00
if ( ! first ) {
strncat ( buf , " , " , buflen ) ;
} else {
first = 0 ;
}
snprintf ( num , sizeof ( num ) , " %u " , i ) ;
strncat ( buf , num , buflen ) ;
}
}
return ( buf ) ;
}
2005-07-15 23:24:51 +00:00
void ast_set_variables ( struct ast_channel * chan , struct ast_variable * vars )
{
struct ast_variable * cur ;
for ( cur = vars ; cur ; cur = cur - > next )
pbx_builtin_setvar_helper ( chan , cur - > name , cur - > value ) ;
}
2005-10-28 23:01:13 +00:00
static void copy_data_from_queue ( struct ast_channel_spy_queue * queue , short * buf , unsigned int samples )
{
struct ast_frame * f ;
int tocopy ;
int bytestocopy ;
while ( samples ) {
f = queue - > head ;
if ( ! f ) {
ast_log ( LOG_ERROR , " Ran out of frames before buffer filled! \n " ) ;
break ;
}
tocopy = ( f - > samples > samples ) ? samples : f - > samples ;
bytestocopy = ast_codec_get_len ( queue - > format , samples ) ;
memcpy ( buf , f - > data , bytestocopy ) ;
samples - = tocopy ;
buf + = tocopy ;
f - > samples - = tocopy ;
f - > data + = bytestocopy ;
f - > datalen - = bytestocopy ;
f - > offset + = bytestocopy ;
queue - > samples - = tocopy ;
if ( ! f - > samples ) {
queue - > head = f - > next ;
ast_frfree ( f ) ;
}
}
}
struct ast_frame * ast_channel_spy_read_frame ( struct ast_channel_spy * spy , unsigned int samples )
{
struct ast_frame * result ;
/* buffers are allocated to hold SLINEAR, which is the largest format */
short read_buf [ samples ] ;
short write_buf [ samples ] ;
struct ast_frame * read_frame ;
struct ast_frame * write_frame ;
int need_dup ;
struct ast_frame stack_read_frame = { . frametype = AST_FRAME_VOICE ,
. subclass = spy - > read_queue . format ,
. data = read_buf ,
. samples = samples ,
. datalen = ast_codec_get_len ( spy - > read_queue . format , samples ) ,
} ;
struct ast_frame stack_write_frame = { . frametype = AST_FRAME_VOICE ,
. subclass = spy - > write_queue . format ,
. data = write_buf ,
. samples = samples ,
. datalen = ast_codec_get_len ( spy - > write_queue . format , samples ) ,
} ;
/* if a flush has been requested, dump everything in whichever queue is larger */
if ( ast_test_flag ( spy , CHANSPY_TRIGGER_FLUSH ) ) {
if ( spy - > read_queue . samples > spy - > write_queue . samples ) {
if ( ast_test_flag ( spy , CHANSPY_READ_VOLADJUST ) ) {
for ( result = spy - > read_queue . head ; result ; result = result - > next )
ast_frame_adjust_volume ( result , spy - > read_vol_adjustment ) ;
}
result = spy - > read_queue . head ;
spy - > read_queue . head = NULL ;
spy - > read_queue . samples = 0 ;
ast_clear_flag ( spy , CHANSPY_TRIGGER_FLUSH ) ;
return result ;
} else {
if ( ast_test_flag ( spy , CHANSPY_WRITE_VOLADJUST ) ) {
for ( result = spy - > write_queue . head ; result ; result = result - > next )
ast_frame_adjust_volume ( result , spy - > write_vol_adjustment ) ;
}
result = spy - > write_queue . head ;
spy - > write_queue . head = NULL ;
spy - > write_queue . samples = 0 ;
ast_clear_flag ( spy , CHANSPY_TRIGGER_FLUSH ) ;
return result ;
}
}
if ( ( spy - > read_queue . samples < samples ) | | ( spy - > write_queue . samples < samples ) )
return NULL ;
/* short-circuit if both head frames have exactly what we want */
if ( ( spy - > read_queue . head - > samples = = samples ) & &
( spy - > write_queue . head - > samples = = samples ) ) {
read_frame = spy - > read_queue . head ;
spy - > read_queue . head = read_frame - > next ;
read_frame - > next = NULL ;
write_frame = spy - > write_queue . head ;
spy - > write_queue . head = write_frame - > next ;
write_frame - > next = NULL ;
spy - > read_queue . samples - = samples ;
spy - > write_queue . samples - = samples ;
need_dup = 0 ;
} else {
copy_data_from_queue ( & spy - > read_queue , read_buf , samples ) ;
copy_data_from_queue ( & spy - > write_queue , write_buf , samples ) ;
read_frame = & stack_read_frame ;
write_frame = & stack_write_frame ;
need_dup = 1 ;
}
if ( ast_test_flag ( spy , CHANSPY_READ_VOLADJUST ) )
ast_frame_adjust_volume ( read_frame , spy - > read_vol_adjustment ) ;
if ( ast_test_flag ( spy , CHANSPY_WRITE_VOLADJUST ) )
ast_frame_adjust_volume ( write_frame , spy - > write_vol_adjustment ) ;
if ( ast_test_flag ( spy , CHANSPY_MIXAUDIO ) ) {
ast_frame_slinear_sum ( read_frame , write_frame ) ;
if ( need_dup )
result = ast_frdup ( read_frame ) ;
else
result = read_frame ;
} else {
if ( need_dup ) {
result = ast_frdup ( read_frame ) ;
result - > next = ast_frdup ( write_frame ) ;
} else {
result = read_frame ;
result - > next = write_frame ;
}
}
return result ;
}
2005-11-01 17:22:25 +00:00
static void * silence_generator_alloc ( struct ast_channel * chan , void * data )
{
/* just store the data pointer in the channel structure */
return data ;
}
static void silence_generator_release ( struct ast_channel * chan , void * data )
{
/* nothing to do */
}
static int silence_generator_generate ( struct ast_channel * chan , void * data , int len , int samples )
{
if ( samples = = 160 ) {
2005-11-01 18:48:05 +00:00
short buf [ 160 ] = { 0 , } ;
struct ast_frame frame = {
. frametype = AST_FRAME_VOICE ,
. subclass = AST_FORMAT_SLINEAR ,
. data = buf ,
. samples = 160 ,
. datalen = sizeof ( buf ) ,
} ;
if ( ast_write ( chan , & frame ) )
2005-11-01 17:22:25 +00:00
return - 1 ;
} else {
short buf [ samples ] ;
int x ;
struct ast_frame frame = {
. frametype = AST_FRAME_VOICE ,
. subclass = AST_FORMAT_SLINEAR ,
2005-11-01 18:48:05 +00:00
. data = buf ,
2005-11-01 17:22:25 +00:00
. samples = samples ,
. datalen = sizeof ( buf ) ,
} ;
for ( x = 0 ; x < samples ; x + + )
buf [ x ] = 0 ;
if ( ast_write ( chan , & frame ) )
return - 1 ;
}
return 0 ;
}
static struct ast_generator silence_generator = {
. alloc = silence_generator_alloc ,
. release = silence_generator_release ,
. generate = silence_generator_generate ,
} ;
struct ast_silence_generator {
int old_write_format ;
} ;
struct ast_silence_generator * ast_channel_start_silence_generator ( struct ast_channel * chan )
{
struct ast_silence_generator * state ;
if ( ! ( state = calloc ( 1 , sizeof ( * state ) ) ) ) {
ast_log ( LOG_WARNING , " Could not allocate state structure \n " ) ;
return NULL ;
}
state - > old_write_format = chan - > writeformat ;
if ( ast_set_write_format ( chan , AST_FORMAT_SLINEAR ) < 0 ) {
ast_log ( LOG_ERROR , " Could not set write format to SLINEAR \n " ) ;
free ( state ) ;
return NULL ;
}
ast_activate_generator ( chan , & silence_generator , state ) ;
if ( option_debug )
ast_log ( LOG_DEBUG , " Started silence generator on '%s' \n " , chan - > name ) ;
return state ;
}
void ast_channel_stop_silence_generator ( struct ast_channel * chan , struct ast_silence_generator * state )
{
if ( ! state )
return ;
ast_deactivate_generator ( chan ) ;
if ( option_debug )
ast_log ( LOG_DEBUG , " Stopped silence generator on '%s' \n " , chan - > name ) ;
if ( ast_set_write_format ( chan , state - > old_write_format ) < 0 )
ast_log ( LOG_ERROR , " Could not return write format to its original state \n " ) ;
free ( state ) ;
}