2007-04-15 19:39:49 +00:00
/*
* An implementation of Common ISDN API 2.0 for Asterisk
*
2009-01-17 17:35:55 +00:00
* Copyright ( C ) 2006 - 2009 Cytronics & Melware
2007-04-15 19:39:49 +00:00
*
* Armin Schindler < armin @ melware . de >
*
2007-04-19 20:24:15 +00:00
* capi_sendf ( ) by Eicon Networks / Dialogic
*
2007-04-15 19:39:49 +00:00
* This program is free software and may be modified and
* distributed under the terms of the GNU Public License .
*/
2005-08-30 11:21:58 +00:00
# include <stdio.h>
2007-04-17 21:04:42 +00:00
# include <stdlib.h>
2007-04-29 22:28:30 +00:00
# include <errno.h>
# include <unistd.h>
# include <fcntl.h>
2009-07-20 11:03:49 +00:00
# include <string.h>
2011-02-04 17:18:05 +00:00
# include <ctype.h>
2007-04-29 22:28:30 +00:00
# include <sys/types.h>
2009-03-12 15:56:20 +00:00
# include "chan_capi_platform.h"
2007-04-29 22:28:30 +00:00
# include "xlaw.h"
2007-04-15 19:39:49 +00:00
# include "chan_capi20.h"
# include "chan_capi.h"
2007-04-29 22:28:30 +00:00
# include "chan_capi_rtp.h"
2007-04-15 19:39:49 +00:00
# include "chan_capi_utils.h"
2007-04-15 20:29:12 +00:00
# include "chan_capi_supplementary.h"
2010-06-30 08:33:41 +00:00
2010-04-08 22:10:54 +00:00
# ifdef DIVA_STREAMING
# include "platform.h"
# include "diva_streaming_result.h"
# include "diva_streaming_messages.h"
# include "diva_streaming_vector.h"
# include "diva_streaming_manager.h"
2010-06-30 08:33:41 +00:00
# include "chan_capi_divastreaming_utils.h"
2010-04-08 22:10:54 +00:00
# endif
2010-10-25 21:21:31 +00:00
# ifdef DIVA_STATUS
# include "divastatus_ifc.h"
# define CC_HW_STATE_OK(__x__) ((pbx_capi_get_controller((__x__)) == NULL) || \
( pbx_capi_get_controller ( ( __x__ ) ) - > hwState ! = ( int ) DivaStatusHardwareStateERROR ) )
# else
# define CC_HW_STATE_OK(__x__) (1)
# endif
2007-04-15 20:29:12 +00:00
int capidebug = 0 ;
char * emptyid = " \0 " ;
AST_MUTEX_DEFINE_STATIC ( verbose_lock ) ;
AST_MUTEX_DEFINE_STATIC ( messagenumber_lock ) ;
AST_MUTEX_DEFINE_STATIC ( capi_put_lock ) ;
2007-04-22 10:03:52 +00:00
AST_MUTEX_DEFINE_STATIC ( peerlink_lock ) ;
2007-04-28 16:48:00 +00:00
AST_MUTEX_DEFINE_STATIC ( nullif_lock ) ;
2007-04-15 20:29:12 +00:00
static _cword capi_MessageNumber ;
2007-04-28 16:48:00 +00:00
static struct capi_pvt * nulliflist = NULL ;
2007-05-12 18:21:13 +00:00
static int controller_nullplcis [ CAPI_MAX_CONTROLLERS ] ;
2007-04-28 16:48:00 +00:00
2007-04-17 21:04:42 +00:00
# define CAPI_MAX_PEERLINKCHANNELS 32
2007-04-22 10:03:52 +00:00
static struct peerlink_s {
struct ast_channel * channel ;
time_t age ;
} peerlinkchannel [ CAPI_MAX_PEERLINKCHANNELS ] ;
2007-04-17 21:04:42 +00:00
2007-04-15 20:29:12 +00:00
/*
2009-03-10 22:39:04 +00:00
* helper for < pbx > _verbose
2007-04-15 20:29:12 +00:00
*/
2009-03-10 22:39:04 +00:00
void cc_verbose_internal ( char * text , . . . )
2007-04-15 20:29:12 +00:00
{
char line [ 4096 ] ;
va_list ap ;
va_start ( ap , text ) ;
vsnprintf ( line , sizeof ( line ) , text , ap ) ;
va_end ( ap ) ;
2009-03-10 22:39:04 +00:00
line [ sizeof ( line ) - 1 ] = 0 ;
2007-04-15 20:29:12 +00:00
2007-04-29 22:28:30 +00:00
#if 0
{
FILE * fp ;
if ( ( fp = fopen ( " /tmp/cclog " , " a " ) ) ! = NULL ) {
fprintf ( fp , " %s " , line ) ;
fclose ( fp ) ;
}
}
# endif
2009-03-10 22:39:04 +00:00
cc_mutex_lock ( & verbose_lock ) ;
2010-02-17 19:01:31 +00:00
cc_pbx_verbose ( " %s " , line ) ;
2009-03-10 22:39:04 +00:00
cc_mutex_unlock ( & verbose_lock ) ;
2007-04-15 20:29:12 +00:00
}
2007-04-28 16:48:00 +00:00
/*
* hangup and remove null - interface
*/
2007-05-08 16:30:03 +00:00
void capi_remove_nullif ( struct capi_pvt * i )
2007-04-28 16:48:00 +00:00
{
struct capi_pvt * ii ;
struct capi_pvt * tmp = NULL ;
2007-05-08 16:30:03 +00:00
int state ;
2007-04-28 16:48:00 +00:00
if ( i - > channeltype ! = CAPI_CHANNELTYPE_NULL ) {
2007-05-08 16:30:03 +00:00
return ;
2007-04-28 16:48:00 +00:00
}
2009-04-14 21:58:03 +00:00
cc_mutex_lock ( & i - > lock ) ;
if ( i - > line_plci ! = 0 ) {
ii = i - > line_plci ;
i - > line_plci = 0 ;
capi_remove_nullif ( ii ) ;
}
cc_mutex_unlock ( & i - > lock ) ;
2007-05-08 16:30:03 +00:00
if ( i - > PLCI ! = 0 ) {
/* if the interface is in use, hangup first */
cc_mutex_lock ( & i - > lock ) ;
state = i - > state ;
i - > state = CAPI_STATE_DISCONNECTING ;
capi_activehangup ( i , state ) ;
cc_mutex_unlock ( & i - > lock ) ;
return ;
}
2007-05-01 14:26:39 +00:00
2007-04-28 16:48:00 +00:00
cc_mutex_lock ( & nullif_lock ) ;
ii = nulliflist ;
while ( ii ) {
if ( ii = = i ) {
if ( ! tmp ) {
nulliflist = ii - > next ;
} else {
tmp - > next = ii - > next ;
}
2007-05-13 11:30:34 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: removed null-interface from controller %d. \n " ,
i - > vname , i - > controller ) ;
2011-11-16 21:43:04 +00:00
if ( i - > smoother ) {
2007-04-29 22:28:30 +00:00
ast_smoother_free ( i - > smoother ) ;
2011-11-16 21:43:04 +00:00
i - > smoother = 0 ;
}
2007-05-08 16:30:03 +00:00
cc_mutex_destroy ( & i - > lock ) ;
ast_cond_destroy ( & i - > event_trigger ) ;
2007-05-12 18:21:13 +00:00
controller_nullplcis [ i - > controller - 1 ] - - ;
2010-08-19 08:44:21 +00:00
ast_free ( i ) ;
2007-04-28 16:48:00 +00:00
break ;
}
tmp = ii ;
ii = ii - > next ;
}
cc_mutex_unlock ( & nullif_lock ) ;
}
2009-04-15 12:28:40 +00:00
int capi_verify_resource_plci ( const struct capi_pvt * i ) {
const struct capi_pvt * ii ;
cc_mutex_lock ( & nullif_lock ) ;
for ( ii = nulliflist ; ii ! = 0 & & ii ! = i ; ii = ii - > next ) ;
cc_mutex_unlock ( & nullif_lock ) ;
return ( ( ii = = i ) ? 0 : - 1 ) ;
}
2007-04-28 16:48:00 +00:00
/*
* create new null - interface
*/
2008-03-23 13:04:30 +00:00
struct capi_pvt * capi_mknullif ( struct ast_channel * c , unsigned long long controllermask )
2007-04-28 16:48:00 +00:00
{
struct capi_pvt * tmp ;
2007-05-12 18:21:13 +00:00
unsigned int controller = 1 ;
int contrcount ;
int channelcount = 0xffff ;
2009-03-26 21:07:28 +00:00
int maxcontr = ( CAPI_MAX_CONTROLLERS > ( sizeof ( controllermask ) * 8 ) ) ?
( sizeof ( controllermask ) * 8 ) : CAPI_MAX_CONTROLLERS ;
2007-05-12 18:21:13 +00:00
2008-03-22 20:08:45 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " capi_mknullif: find controller for mask 0x%lx \n " ,
controllermask ) ;
2007-05-12 18:21:13 +00:00
/* find the next controller of mask with least plcis used */
2008-03-23 13:04:30 +00:00
for ( contrcount = 0 ; contrcount < maxcontr ; contrcount + + ) {
2010-10-25 21:21:31 +00:00
if ( ( ( controllermask & ( 1ULL < < contrcount ) ) ! = 0 ) & & CC_HW_STATE_OK ( contrcount + 1 ) ) {
2007-05-12 18:21:13 +00:00
if ( controller_nullplcis [ contrcount ] < channelcount ) {
channelcount = controller_nullplcis [ contrcount ] ;
controller = contrcount + 1 ;
}
}
}
2007-04-28 16:48:00 +00:00
2010-08-19 08:44:21 +00:00
tmp = ast_malloc ( sizeof ( struct capi_pvt ) ) ;
2007-04-28 16:48:00 +00:00
if ( ! tmp ) {
return NULL ;
}
memset ( tmp , 0 , sizeof ( struct capi_pvt ) ) ;
cc_mutex_init ( & tmp - > lock ) ;
ast_cond_init ( & tmp - > event_trigger , NULL ) ;
2010-11-24 17:08:11 +00:00
snprintf ( tmp - > name , sizeof ( tmp - > name ) - 1 , " %s-NULLPLCI " , ( c ! = 0 ) ? c - > name : " BRIDGE " ) ;
2007-04-28 16:48:00 +00:00
snprintf ( tmp - > vname , sizeof ( tmp - > vname ) - 1 , " %s " , tmp - > name ) ;
tmp - > channeltype = CAPI_CHANNELTYPE_NULL ;
2007-04-30 15:19:28 +00:00
tmp - > used = c ;
tmp - > peer = c ;
2010-12-14 16:28:18 +00:00
if ( c = = NULL )
tmp - > virtualBridgePeer = 1 ;
2007-04-29 14:00:32 +00:00
2007-05-01 14:26:39 +00:00
tmp - > cip = CAPI_CIPI_SPEECH ;
tmp - > transfercapability = PRI_TRANS_CAP_SPEECH ;
2007-04-28 16:48:00 +00:00
tmp - > controller = controller ;
tmp - > doEC = 1 ;
tmp - > doEC_global = 1 ;
tmp - > ecOption = EC_OPTION_DISABLE_NEVER ;
tmp - > ecTail = EC_DEFAULT_TAIL ;
tmp - > isdnmode = CAPI_ISDNMODE_MSN ;
tmp - > ecSelector = FACILITYSELECTOR_ECHO_CANCEL ;
2007-04-30 15:19:28 +00:00
tmp - > capability = capi_capability ;
2007-05-12 12:31:58 +00:00
tmp - > rxgain = 1.0 ;
tmp - > txgain = 1.0 ;
2007-04-30 15:19:28 +00:00
capi_gains ( & tmp - > g , 1.0 , 1.0 ) ;
2007-04-29 22:28:30 +00:00
2010-11-24 17:08:11 +00:00
if ( c ! = 0 ) {
if ( ! ( capi_create_reader_writer_pipe ( tmp ) ) ) {
ast_free ( tmp ) ;
return NULL ;
}
2007-04-29 22:28:30 +00:00
}
2007-04-30 15:19:28 +00:00
tmp - > bproto = CC_BPROTO_TRANSPARENT ;
tmp - > doB3 = CAPI_B3_DONT ;
2007-04-29 22:28:30 +00:00
tmp - > smoother = ast_smoother_new ( CAPI_MAX_B3_BLOCK_SIZE ) ;
2007-04-30 15:19:28 +00:00
tmp - > isdnstate | = CAPI_ISDN_STATE_PBX ;
2007-04-28 16:48:00 +00:00
cc_mutex_lock ( & nullif_lock ) ;
tmp - > next = nulliflist ; /* prepend */
nulliflist = tmp ;
2007-05-12 18:21:13 +00:00
controller_nullplcis [ tmp - > controller - 1 ] + + ;
2007-04-28 16:48:00 +00:00
cc_mutex_unlock ( & nullif_lock ) ;
2007-04-30 15:19:28 +00:00
/* connect to driver */
2007-04-28 16:48:00 +00:00
tmp - > outgoing = 1 ;
tmp - > state = CAPI_STATE_CONNECTPENDING ;
tmp - > MessageNumber = get_capi_MessageNumber ( ) ;
2007-05-01 14:26:39 +00:00
2010-08-23 12:14:03 +00:00
# ifdef DIVA_STREAMING
tmp - > diva_stream_entry = 0 ;
if ( pbx_capi_streaming_supported ( tmp ) ! = 0 ) {
capi_DivaStreamingOn ( tmp , 1 , tmp - > MessageNumber ) ;
}
# endif
2010-11-26 16:57:43 +00:00
if ( c = = NULL ) {
cc_mutex_lock ( & tmp - > lock ) ;
}
capi_sendf ( ( c ! = NULL ) ? NULL : tmp , c = = NULL , CAPI_CONNECT_REQ , controller , tmp - > MessageNumber ,
2007-04-28 16:48:00 +00:00
" w()()()()(www()()()())()()()((wwbbb)()()()) " ,
0 , 1 , 1 , 0 , 3 , 0 , 0 , 0 , 0 ) ;
2010-11-26 16:57:43 +00:00
if ( c = = NULL ) {
cc_mutex_unlock ( & tmp - > lock ) ;
if ( tmp - > PLCI = = 0 ) {
cc_log ( LOG_WARNING , " %s: failed to create \n " , tmp - > vname ) ;
capi_remove_nullif ( tmp ) ;
tmp = NULL ;
}
}
if ( tmp ! = NULL ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: created null-interface on controller %d. \n " ,
tmp - > vname , tmp - > controller ) ;
}
2007-04-30 15:19:28 +00:00
2007-04-28 16:48:00 +00:00
return tmp ;
}
2010-10-09 08:29:39 +00:00
struct capi_pvt * capi_mkresourceif (
struct ast_channel * c ,
unsigned long long controllermask ,
struct capi_pvt * data_plci_ifc ,
cc_format_t codecs ,
int all )
{
2009-04-10 07:23:20 +00:00
struct capi_pvt * data_ifc /*, *line_ifc */ ;
2009-04-09 21:14:44 +00:00
unsigned int controller = 1 ;
2010-09-18 23:07:38 +00:00
int fmt = 0 ;
2009-04-09 21:14:44 +00:00
2009-04-14 21:58:03 +00:00
if ( data_plci_ifc = = 0 ) {
int contrcount ;
int channelcount = 0xffff ;
int maxcontr = ( CAPI_MAX_CONTROLLERS > ( sizeof ( controllermask ) * 8 ) ) ?
( sizeof ( controllermask ) * 8 ) : CAPI_MAX_CONTROLLERS ;
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " capi_mkresourceif: find controller for mask 0x%lx \n " ,
controllermask ) ;
/* find the next controller of mask with least plcis used */
for ( contrcount = 0 ; contrcount < maxcontr ; contrcount + + ) {
2010-10-25 21:21:31 +00:00
if ( ( ( controllermask & ( 1ULL < < contrcount ) ) ! = 0 ) & & CC_HW_STATE_OK ( contrcount + 1 ) ) {
2009-04-14 21:58:03 +00:00
if ( controller_nullplcis [ contrcount ] < channelcount ) {
channelcount = controller_nullplcis [ contrcount ] ;
controller = contrcount + 1 ;
}
2009-04-09 21:14:44 +00:00
}
}
2009-04-14 21:58:03 +00:00
} else {
controller = data_plci_ifc - > controller ;
2010-09-20 11:05:58 +00:00
codecs = ( all ! = 0 ) ? pbx_capi_get_controller_codecs ( controller ) : codecs ;
2011-10-04 08:41:28 +00:00
fmt = pbx_capi_get_controller_codecs ( controller ) & codecs & cc_get_formats_as_bits ( c - > nativeformats ) ;
2010-09-18 23:07:38 +00:00
if ( fmt ! = 0 )
2011-10-04 08:41:28 +00:00
fmt = cc_get_best_codec_as_bits ( fmt ) ;
2009-04-09 21:14:44 +00:00
}
2010-08-19 08:44:21 +00:00
data_ifc = ast_malloc ( sizeof ( struct capi_pvt ) ) ;
2009-04-09 21:14:44 +00:00
if ( data_ifc = = 0 ) {
return NULL ;
}
memset ( data_ifc , 0 , sizeof ( struct capi_pvt ) ) ;
cc_mutex_init ( & data_ifc - > lock ) ;
ast_cond_init ( & data_ifc - > event_trigger , NULL ) ;
2009-04-14 21:58:03 +00:00
snprintf ( data_ifc - > name , sizeof ( data_ifc - > name ) - 1 , " %s-%sPLCI " , c - > name , ( data_plci_ifc = = 0 ) ? " DATA " : " LINE " ) ;
2009-04-09 21:14:44 +00:00
snprintf ( data_ifc - > vname , sizeof ( data_ifc - > vname ) - 1 , " %s " , data_ifc - > name ) ;
data_ifc - > channeltype = CAPI_CHANNELTYPE_NULL ;
2009-04-14 21:58:03 +00:00
data_ifc - > resource_plci_type = ( data_plci_ifc = = 0 ) ? CAPI_RESOURCE_PLCI_DATA : CAPI_RESOURCE_PLCI_LINE ;
2009-04-09 21:14:44 +00:00
data_ifc - > used = c ;
data_ifc - > peer = c ;
data_ifc - > cip = CAPI_CIPI_SPEECH ;
data_ifc - > transfercapability = PRI_TRANS_CAP_SPEECH ;
data_ifc - > controller = controller ;
data_ifc - > doEC = 1 ;
data_ifc - > doEC_global = 1 ;
data_ifc - > ecOption = EC_OPTION_DISABLE_NEVER ;
data_ifc - > ecTail = EC_DEFAULT_TAIL ;
data_ifc - > isdnmode = CAPI_ISDNMODE_MSN ;
data_ifc - > ecSelector = FACILITYSELECTOR_ECHO_CANCEL ;
2010-09-18 23:07:38 +00:00
data_ifc - > capability = ( fmt ! = 0 & & data_plci_ifc ! = 0 ) ? fmt : capi_capability ;
data_ifc - > codec = ( fmt ! = 0 & & data_plci_ifc ! = 0 ) ? fmt : data_ifc - > codec ;
2009-04-09 21:14:44 +00:00
data_ifc - > rxgain = 1.0 ;
data_ifc - > txgain = 1.0 ;
capi_gains ( & data_ifc - > g , 1.0 , 1.0 ) ;
2009-04-14 21:58:03 +00:00
if ( data_plci_ifc = = 0 ) {
if ( ! ( capi_create_reader_writer_pipe ( data_ifc ) ) ) {
2010-08-19 08:44:21 +00:00
ast_free ( data_ifc ) ;
2009-04-14 21:58:03 +00:00
return NULL ;
}
} else {
data_ifc - > readerfd = - 1 ;
data_ifc - > writerfd = - 1 ;
2009-04-09 21:14:44 +00:00
}
2010-09-18 23:07:38 +00:00
data_ifc - > bproto = ( fmt ! = 0 & & data_plci_ifc ! = 0 ) ? CC_BPROTO_VOCODER : CC_BPROTO_TRANSPARENT ;
2009-04-09 21:14:44 +00:00
data_ifc - > doB3 = CAPI_B3_DONT ;
data_ifc - > smoother = ast_smoother_new ( CAPI_MAX_B3_BLOCK_SIZE ) ;
data_ifc - > isdnstate | = CAPI_ISDN_STATE_PBX ;
cc_mutex_lock ( & nullif_lock ) ;
data_ifc - > next = nulliflist ; /* prepend */
nulliflist = data_ifc ;
controller_nullplcis [ data_ifc - > controller - 1 ] + + ;
cc_mutex_unlock ( & nullif_lock ) ;
/* connect to driver */
data_ifc - > outgoing = 1 ;
data_ifc - > state = CAPI_STATE_CONNECTPENDING ;
data_ifc - > MessageNumber = get_capi_MessageNumber ( ) ;
2009-04-10 18:59:18 +00:00
cc_mutex_lock ( & data_ifc - > lock ) ;
2010-08-23 15:21:52 +00:00
# ifdef DIVA_STREAMING
data_ifc - > diva_stream_entry = 0 ;
if ( data_plci_ifc = = 0 ) {
capi_DivaStreamingStreamNotUsed ( data_ifc , 1 , data_ifc - > MessageNumber ) ;
} else {
if ( pbx_capi_streaming_supported ( data_ifc ) ! = 0 ) {
capi_DivaStreamingOn ( data_ifc , 1 , data_ifc - > MessageNumber ) ;
}
}
# endif
2009-04-10 18:59:18 +00:00
capi_sendf ( data_ifc ,
1 ,
2009-04-10 07:23:20 +00:00
CAPI_MANUFACTURER_REQ ,
controller ,
data_ifc - > MessageNumber ,
2010-09-18 23:07:38 +00:00
" dw(wbb(wwws()()())) " ,
2009-04-10 07:23:20 +00:00
_DI_MANU_ID ,
_DI_ASSIGN_PLCI ,
2009-04-14 21:58:03 +00:00
( data_plci_ifc = = 0 ) ? 4 : 5 , /* data */
( data_plci_ifc = = 0 ) ? 0 : ( unsigned char ) ( data_plci_ifc - > PLCI > > 8 ) , /* bchannel */
2009-04-10 07:23:20 +00:00
1 , /* connect */
2010-09-18 23:07:38 +00:00
( data_ifc - > bproto = = CC_BPROTO_VOCODER ) ? 0x1f : 1 , 1 , 0 ,
diva_get_b1_conf ( data_ifc ) ) ;
2009-04-10 18:59:18 +00:00
cc_mutex_unlock ( & data_ifc - > lock ) ;
2009-04-09 21:14:44 +00:00
2009-04-14 21:58:03 +00:00
if ( data_plci_ifc ! = 0 ) {
if ( data_ifc - > PLCI = = 0 ) {
cc_log ( LOG_WARNING , " %s: failed to create \n " , data_ifc - > vname ) ;
capi_remove_nullif ( data_ifc ) ;
data_ifc = 0 ;
} else {
cc_mutex_lock ( & data_plci_ifc - > lock ) ;
data_plci_ifc - > line_plci = data_ifc ;
capi_sendf ( data_plci_ifc , 1 , CAPI_FACILITY_REQ , data_plci_ifc - > PLCI , get_capi_MessageNumber ( ) ,
" w(w(d())) " ,
FACILITYSELECTOR_LINE_INTERCONNECT ,
0x0001 , /* CONNECT */
0x00000000 /* mask */
) ;
cc_mutex_unlock ( & data_plci_ifc - > lock ) ;
data_ifc - > data_plci = data_plci_ifc ;
data_ifc - > writerfd = data_plci_ifc - > writerfd ;
data_plci_ifc - > writerfd = - 1 ;
}
}
if ( data_ifc ! = 0 ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: created %s-resource-interface on controller %d. \n " ,
data_ifc - > vname , ( data_plci_ifc = = 0 ) ? " data " : " line " , data_ifc - > controller ) ;
}
2009-04-09 21:14:44 +00:00
2009-04-10 07:23:20 +00:00
return data_ifc ;
2009-04-09 21:14:44 +00:00
}
2007-04-15 20:29:12 +00:00
/*
2007-04-30 15:19:28 +00:00
* get a new capi message number atomically
2007-04-15 20:29:12 +00:00
*/
_cword get_capi_MessageNumber ( void )
{
_cword mn ;
cc_mutex_lock ( & messagenumber_lock ) ;
capi_MessageNumber + + ;
if ( capi_MessageNumber = = 0 ) {
/* avoid zero */
capi_MessageNumber = 1 ;
}
mn = capi_MessageNumber ;
cc_mutex_unlock ( & messagenumber_lock ) ;
2009-04-10 07:23:20 +00:00
return mn ;
2007-04-15 20:29:12 +00:00
}
2007-04-19 20:24:15 +00:00
/*
2007-04-19 20:31:42 +00:00
* find the interface ( pvt ) the PLCI belongs to
*/
2007-04-29 22:28:30 +00:00
struct capi_pvt * capi_find_interface_by_plci ( unsigned int plci )
2007-04-19 20:31:42 +00:00
{
struct capi_pvt * i ;
2009-03-12 15:56:20 +00:00
if ( unlikely ( plci = = 0 ) )
2007-04-19 20:31:42 +00:00
return NULL ;
2007-04-29 22:28:30 +00:00
for ( i = capi_iflist ; i ; i = i - > next ) {
2007-04-28 16:48:00 +00:00
if ( i - > PLCI = = plci )
return i ;
}
cc_mutex_lock ( & nullif_lock ) ;
for ( i = nulliflist ; i ; i = i - > next ) {
2007-04-19 20:31:42 +00:00
if ( i - > PLCI = = plci )
break ;
}
2007-04-28 16:48:00 +00:00
cc_mutex_unlock ( & nullif_lock ) ;
2007-04-19 20:31:42 +00:00
return i ;
}
/*
* find the interface ( pvt ) the messagenumber belongs to
*/
2007-04-29 22:28:30 +00:00
struct capi_pvt * capi_find_interface_by_msgnum ( unsigned short msgnum )
2007-04-19 20:31:42 +00:00
{
struct capi_pvt * i ;
if ( msgnum = = 0x0000 )
return NULL ;
2007-04-29 22:28:30 +00:00
for ( i = capi_iflist ; i ; i = i - > next ) {
2007-04-28 16:48:00 +00:00
if ( ( i - > PLCI = = 0 ) & & ( i - > MessageNumber = = msgnum ) )
return i ;
}
cc_mutex_lock ( & nullif_lock ) ;
for ( i = nulliflist ; i ; i = i - > next ) {
if ( ( i - > PLCI = = 0 ) & & ( i - > MessageNumber = = msgnum ) )
2007-04-19 20:31:42 +00:00
break ;
}
2007-04-28 16:48:00 +00:00
cc_mutex_unlock ( & nullif_lock ) ;
2007-04-19 20:31:42 +00:00
return i ;
}
2007-04-20 08:17:29 +00:00
/*
* wait for a specific message
*/
MESSAGE_EXCHANGE_ERROR capi_wait_conf ( struct capi_pvt * i , unsigned short wCmd )
{
MESSAGE_EXCHANGE_ERROR error = 0 ;
struct timespec abstime ;
unsigned char command , subcommand ;
subcommand = wCmd & 0xff ;
command = ( wCmd & 0xff00 ) > > 8 ;
i - > waitevent = ( unsigned int ) wCmd ;
abstime . tv_sec = time ( NULL ) + 2 ;
abstime . tv_nsec = 0 ;
cc_verbose ( 4 , 1 , " %s: wait for %s (0x%x) \n " ,
i - > vname , capi_cmd2str ( command , subcommand ) , i - > waitevent ) ;
if ( ast_cond_timedwait ( & i - > event_trigger , & i - > lock , & abstime ) ! = 0 ) {
error = - 1 ;
cc_log ( LOG_WARNING , " %s: timed out waiting for %s \n " ,
i - > vname , capi_cmd2str ( command , subcommand ) ) ;
} else {
cc_verbose ( 4 , 1 , " %s: cond signal received for %s \n " ,
i - > vname , capi_cmd2str ( command , subcommand ) ) ;
}
return error ;
}
2007-04-19 20:31:42 +00:00
/*
2007-04-28 16:48:00 +00:00
* log an error in sending capi message
2007-04-19 20:24:15 +00:00
*/
2009-03-26 22:08:33 +00:00
static void log_capi_error_message ( MESSAGE_EXCHANGE_ERROR err , unsigned char * msg )
2007-04-19 20:24:15 +00:00
{
if ( err ) {
2009-03-26 22:08:33 +00:00
_cmsg _CMSG , * CMSG = & _CMSG ;
capi_message2cmsg ( CMSG , msg ) ;
2007-04-19 20:24:15 +00:00
cc_log ( LOG_ERROR , " CAPI error sending %s (NCCI=%#x) (error=%#x %s) \n " ,
capi_cmsg2str ( CMSG ) , ( unsigned int ) HEADER_CID ( CMSG ) ,
err , capi_info_string ( ( unsigned int ) err ) ) ;
2007-04-28 16:48:00 +00:00
}
}
/*
* log verbose a capi message
*/
static void log_capi_message ( _cmsg * CMSG )
{
unsigned short wCmd ;
wCmd = HEADER_CMD ( CMSG ) ;
if ( ( wCmd = = CAPI_P_REQ ( DATA_B3 ) ) | |
( wCmd = = CAPI_P_RESP ( DATA_B3 ) ) ) {
cc_verbose ( 7 , 1 , " %s \n " , capi_cmsg2str ( CMSG ) ) ;
2007-04-19 20:24:15 +00:00
} else {
2007-04-28 16:48:00 +00:00
cc_verbose ( 4 , 1 , " %s \n " , capi_cmsg2str ( CMSG ) ) ;
2007-04-19 20:24:15 +00:00
}
}
2007-04-15 20:29:12 +00:00
/*
* write a capi message to capi device
*/
2007-04-28 20:59:44 +00:00
static MESSAGE_EXCHANGE_ERROR _capi_put_msg ( unsigned char * msg )
2007-04-19 20:24:15 +00:00
{
MESSAGE_EXCHANGE_ERROR error ;
_cmsg CMSG ;
if ( cc_mutex_lock ( & capi_put_lock ) ) {
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , " Unable to lock chan_capi put! \n " ) ;
2007-04-19 20:24:15 +00:00
return - 1 ;
}
2009-03-11 09:13:03 +00:00
if ( cc_verbose_check ( 4 , 1 ) ! = 0 ) {
capi_message2cmsg ( & CMSG , msg ) ;
log_capi_message ( & CMSG ) ;
}
2007-04-19 20:24:15 +00:00
2007-04-23 22:18:36 +00:00
error = capi20_put_message ( capi_ApplID , msg ) ;
2007-04-19 20:24:15 +00:00
if ( cc_mutex_unlock ( & capi_put_lock ) ) {
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , " Unable to unlock chan_capi put! \n " ) ;
2007-04-19 20:24:15 +00:00
return - 1 ;
2007-04-15 20:29:12 +00:00
}
2009-03-26 22:08:33 +00:00
log_capi_error_message ( error , msg ) ;
2007-04-19 20:24:15 +00:00
2007-04-15 20:29:12 +00:00
return error ;
}
/*
* wait some time for a new capi message
*/
MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg ( _cmsg * CMSG )
{
MESSAGE_EXCHANGE_ERROR Info ;
struct timeval tv ;
2007-04-23 18:47:49 +00:00
tv . tv_sec = 0 ;
2010-04-08 22:10:54 +00:00
# ifdef DIVA_STREAMING
tv . tv_usec = 5000 ;
# else
2007-04-23 18:47:49 +00:00
tv . tv_usec = 500000 ;
2010-04-08 22:10:54 +00:00
# endif
2007-04-15 20:29:12 +00:00
2007-04-23 18:47:49 +00:00
Info = capi20_waitformessage ( capi_ApplID , & tv ) ;
2007-04-15 20:29:12 +00:00
2007-04-23 18:47:49 +00:00
if ( Info = = 0x0000 ) {
2007-04-15 20:29:12 +00:00
2007-04-23 18:47:49 +00:00
Info = capi_get_cmsg ( CMSG , capi_ApplID ) ;
2007-04-15 20:29:12 +00:00
2007-04-23 18:47:49 +00:00
# if (CAPI_OS_HINT == 1) || (CAPI_OS_HINT == 2)
2007-05-12 10:23:08 +00:00
if ( Info = = 0x0000 ) {
2007-04-23 18:47:49 +00:00
/*
* For BSD allow controller 0 :
*/
if ( ( HEADER_CID ( CMSG ) & 0xFF ) = = 0 ) {
HEADER_CID ( CMSG ) + = capi_num_controllers ;
}
}
2007-05-12 10:23:08 +00:00
# endif
2007-04-15 20:29:12 +00:00
}
2007-04-23 18:47:49 +00:00
2007-04-15 20:29:12 +00:00
if ( ( Info ! = 0x0000 ) & & ( Info ! = 0x1104 ) ) {
if ( capidebug ) {
cc_log ( LOG_DEBUG , " Error waiting for cmsg... INFO = %#x \n " , Info ) ;
}
}
return Info ;
}
2005-08-30 11:21:58 +00:00
2007-04-19 20:24:15 +00:00
/*
* Eicon ' s capi_sendf ( ) function to create capi messages easily
* and send this message .
* Copyright by Eicon Networks / Dialogic
*/
MESSAGE_EXCHANGE_ERROR capi_sendf (
2007-04-20 08:17:29 +00:00
struct capi_pvt * capii , int waitconf ,
2007-04-19 20:24:15 +00:00
_cword command , _cdword Id , _cword Number , char * format , . . . )
{
MESSAGE_EXCHANGE_ERROR ret ;
int i , j ;
unsigned int d ;
unsigned char * p , * p_length ;
unsigned char * string ;
2007-08-23 13:30:05 +00:00
unsigned short header_length ;
2007-04-19 20:24:15 +00:00
va_list ap ;
capi_prestruct_t * s ;
unsigned char msg [ 2048 ] ;
write_capi_word ( & msg [ 2 ] , capi_ApplID ) ;
2008-02-20 10:15:59 +00:00
msg [ 4 ] = ( unsigned char ) ( ( command > > 8 ) & 0xff ) ;
msg [ 5 ] = ( unsigned char ) ( command & 0xff ) ;
2007-04-19 20:24:15 +00:00
write_capi_word ( & msg [ 6 ] , Number ) ;
write_capi_dword ( & msg [ 8 ] , Id ) ;
p = & msg [ 12 ] ;
p_length = 0 ;
va_start ( ap , format ) ;
for ( i = 0 ; format [ i ] ; i + + ) {
2009-03-12 15:56:20 +00:00
if ( unlikely ( ( ( p - ( & msg [ 0 ] ) ) + 12 ) > = sizeof ( msg ) ) ) {
2007-04-19 20:24:15 +00:00
cc_log ( LOG_ERROR , " capi_sendf: message too big (%d) \n " ,
2009-02-09 18:28:16 +00:00
( int ) ( p - ( & msg [ 0 ] ) ) ) ;
2007-04-19 20:24:15 +00:00
return 0x1004 ;
}
switch ( format [ i ] ) {
case ' b ' : /* byte */
d = ( unsigned char ) va_arg ( ap , unsigned int ) ;
* ( p + + ) = ( unsigned char ) d ;
break ;
case ' w ' : /* word (2 bytes) */
d = ( unsigned short ) va_arg ( ap , unsigned int ) ;
* ( p + + ) = ( unsigned char ) d ;
* ( p + + ) = ( unsigned char ) ( d > > 8 ) ;
break ;
case ' d ' : /* double word (4 bytes) */
d = va_arg ( ap , unsigned int ) ;
* ( p + + ) = ( unsigned char ) d ;
* ( p + + ) = ( unsigned char ) ( d > > 8 ) ;
* ( p + + ) = ( unsigned char ) ( d > > 16 ) ;
* ( p + + ) = ( unsigned char ) ( d > > 24 ) ;
break ;
case ' s ' : /* struct, length is the first byte */
string = va_arg ( ap , unsigned char * ) ;
2007-04-24 20:21:04 +00:00
if ( string = = NULL ) {
* ( p + + ) = 0 ;
} else {
for ( j = 0 ; j < = string [ 0 ] ; j + + )
* ( p + + ) = string [ j ] ;
}
2007-04-19 20:24:15 +00:00
break ;
case ' a ' : /* ascii string, NULL terminated string */
string = va_arg ( ap , unsigned char * ) ;
for ( j = 0 ; string [ j ] ! = ' \0 ' ; j + + )
* ( + + p ) = string [ j ] ;
* ( ( p + + ) - j ) = ( unsigned char ) j ;
break ;
case ' c ' : /* predefined capi_prestruct_t */
s = va_arg ( ap , capi_prestruct_t * ) ;
if ( s - > wLen < 0xff ) {
* ( p + + ) = ( unsigned char ) ( s - > wLen ) ;
} else {
* ( p + + ) = 0xff ;
* ( p + + ) = ( unsigned char ) ( s - > wLen ) ;
* ( p + + ) = ( unsigned char ) ( s - > wLen > > 8 ) ;
}
for ( j = 0 ; j < s - > wLen ; j + + )
* ( p + + ) = s - > info [ j ] ;
break ;
case ' ( ' : /* begin of a structure */
* p = ( p_length ) ? p - p_length : 0 ;
p_length = p + + ;
break ;
case ' ) ' : /* end of structure */
if ( p_length ) {
j = * p_length ;
* p_length = ( unsigned char ) ( ( p - p_length ) - 1 ) ;
p_length = ( j ! = 0 ) ? p_length - j : 0 ;
} else {
cc_log ( LOG_ERROR , " capi_sendf: inconsistent format \" %s \" \n " ,
format ) ;
}
break ;
default :
cc_log ( LOG_ERROR , " capi_sendf: unknown format \" %s \" \n " ,
format ) ;
}
}
va_end ( ap ) ;
if ( p_length ) {
cc_log ( LOG_ERROR , " capi_sendf: inconsistent format \" %s \" \n " , format ) ;
}
2007-08-23 13:30:05 +00:00
header_length = ( unsigned short ) ( p - ( & msg [ 0 ] ) ) ;
if ( ( sizeof ( void * ) > 4 ) & & ( command = = CAPI_DATA_B3_REQ ) ) {
void * req_data ;
va_start ( ap , format ) ;
req_data = va_arg ( ap , void * ) ;
va_end ( ap ) ;
header_length + = 8 ;
write_capi_dword ( & msg [ 12 ] , 0 ) ;
memcpy ( & msg [ 22 ] , & req_data , sizeof ( void * ) ) ;
}
write_capi_word ( & msg [ 0 ] , header_length ) ;
2007-04-19 20:24:15 +00:00
ret = _capi_put_msg ( & msg [ 0 ] ) ;
2007-04-20 08:17:29 +00:00
if ( ( ! ( ret ) ) & & ( waitconf ) ) {
ret = capi_wait_conf ( capii , ( command & 0xff00 ) | CAPI_CONF ) ;
}
2007-04-19 20:24:15 +00:00
2009-04-10 07:23:20 +00:00
return ret ;
2007-04-19 20:24:15 +00:00
}
2005-08-30 11:21:58 +00:00
/*
* decode capi 2.0 info word
*/
char * capi_info_string ( unsigned int info )
{
switch ( info ) {
/* informative values (corresponding message was processed) */
case 0x0001 :
return " NCPI not supported by current protocol, NCPI ignored " ;
case 0x0002 :
return " Flags not supported by current protocol, flags ignored " ;
case 0x0003 :
return " Alert already sent by another application " ;
/* error information concerning CAPI_REGISTER */
case 0x1001 :
return " Too many applications " ;
case 0x1002 :
return " Logical block size to small, must be at least 128 Bytes " ;
case 0x1003 :
return " Buffer exceeds 64 kByte " ;
case 0x1004 :
return " Message buffer size too small, must be at least 1024 Bytes " ;
case 0x1005 :
return " Max. number of logical connections not supported " ;
case 0x1006 :
return " Reserved " ;
case 0x1007 :
return " The message could not be accepted because of an internal busy condition " ;
case 0x1008 :
return " OS resource error (no memory ?) " ;
case 0x1009 :
return " CAPI not installed " ;
case 0x100A :
return " Controller does not support external equipment " ;
case 0x100B :
return " Controller does only support external equipment " ;
/* error information concerning message exchange functions */
case 0x1101 :
return " Illegal application number " ;
case 0x1102 :
return " Illegal command or subcommand or message length less than 12 bytes " ;
case 0x1103 :
return " The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI " ;
case 0x1104 :
return " Queue is empty " ;
case 0x1105 :
return " Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE " ;
case 0x1106 :
return " Unknown notification parameter " ;
case 0x1107 :
return " The Message could not be accepted because of an internal busy condition " ;
case 0x1108 :
return " OS Resource error (no memory ?) " ;
case 0x1109 :
return " CAPI not installed " ;
case 0x110A :
return " Controller does not support external equipment " ;
case 0x110B :
return " Controller does only support external equipment " ;
/* error information concerning resource / coding problems */
case 0x2001 :
return " Message not supported in current state " ;
case 0x2002 :
return " Illegal Controller / PLCI / NCCI " ;
case 0x2003 :
return " Out of PLCIs " ;
case 0x2004 :
return " Out of NCCIs " ;
case 0x2005 :
return " Out of LISTEN requests " ;
case 0x2006 :
return " Out of FAX resources (protocol T.30) " ;
case 0x2007 :
return " Illegal message parameter coding " ;
/* error information concerning requested services */
case 0x3001 :
return " B1 protocol not supported " ;
case 0x3002 :
return " B2 protocol not supported " ;
case 0x3003 :
return " B3 protocol not supported " ;
case 0x3004 :
return " B1 protocol parameter not supported " ;
case 0x3005 :
return " B2 protocol parameter not supported " ;
case 0x3006 :
return " B3 protocol parameter not supported " ;
case 0x3007 :
return " B protocol combination not supported " ;
case 0x3008 :
return " NCPI not supported " ;
case 0x3009 :
return " CIP Value unknown " ;
case 0x300A :
return " Flags not supported (reserved bits) " ;
case 0x300B :
return " Facility not supported " ;
case 0x300C :
return " Data length not supported by current protocol " ;
case 0x300D :
return " Reset procedure not supported by current protocol " ;
case 0x300E :
return " TEI assignment failed or supplementary service not supported " ;
case 0x3010 :
return " Request not allowed in this state " ;
/* informations about the clearing of a physical connection */
case 0x3301 :
return " Protocol error layer 1 (broken line or B-channel removed by signalling protocol) " ;
case 0x3302 :
return " Protocol error layer 2 " ;
case 0x3303 :
return " Protocol error layer 3 " ;
case 0x3304 :
return " Another application got that call " ;
/* T.30 specific reasons */
case 0x3311 :
return " Connecting not successful (remote station is no FAX G3 machine) " ;
case 0x3312 :
return " Connecting not successful (training error) " ;
case 0x3313 :
return " Disconnected before transfer (remote station does not support transfer mode, e.g. resolution) " ;
case 0x3314 :
return " Disconnected during transfer (remote abort) " ;
case 0x3315 :
return " Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands) " ;
case 0x3316 :
return " Disconnected during transfer (local tx data underrun) " ;
case 0x3317 :
return " Disconnected during transfer (local rx data overflow) " ;
case 0x3318 :
return " Disconnected during transfer (local abort) " ;
case 0x3319 :
return " Illegal parameter coding (e.g. SFF coding error) " ;
/* disconnect causes from the network according to ETS 300 102-1/Q.931 */
case 0x3481 :
return " Unallocated (unassigned) number " ;
case 0x3482 :
return " No route to specified transit network " ;
case 0x3483 :
return " No route to destination " ;
case 0x3486 :
return " Channel unacceptable " ;
case 0x3487 :
return " Call awarded and being delivered in an established channel " ;
case 0x3490 :
return " Normal call clearing " ;
case 0x3491 :
return " User busy " ;
case 0x3492 :
return " No user responding " ;
case 0x3493 :
return " No answer from user (user alerted) " ;
case 0x3495 :
return " Call rejected " ;
case 0x3496 :
return " Number changed " ;
case 0x349A :
return " Non-selected user clearing " ;
case 0x349B :
return " Destination out of order " ;
case 0x349C :
return " Invalid number format " ;
case 0x349D :
return " Facility rejected " ;
case 0x349E :
return " Response to STATUS ENQUIRY " ;
case 0x349F :
return " Normal, unspecified " ;
case 0x34A2 :
return " No circuit / channel available " ;
case 0x34A6 :
return " Network out of order " ;
case 0x34A9 :
return " Temporary failure " ;
case 0x34AA :
return " Switching equipment congestion " ;
case 0x34AB :
return " Access information discarded " ;
case 0x34AC :
return " Requested circuit / channel not available " ;
case 0x34AF :
return " Resources unavailable, unspecified " ;
case 0x34B1 :
return " Quality of service unavailable " ;
case 0x34B2 :
return " Requested facility not subscribed " ;
case 0x34B9 :
return " Bearer capability not authorized " ;
case 0x34BA :
return " Bearer capability not presently available " ;
case 0x34BF :
return " Service or option not available, unspecified " ;
case 0x34C1 :
return " Bearer capability not implemented " ;
case 0x34C2 :
return " Channel type not implemented " ;
case 0x34C5 :
return " Requested facility not implemented " ;
case 0x34C6 :
return " Only restricted digital information bearer capability is available " ;
case 0x34CF :
return " Service or option not implemented, unspecified " ;
case 0x34D1 :
return " Invalid call reference value " ;
case 0x34D2 :
return " Identified channel does not exist " ;
case 0x34D3 :
return " A suspended call exists, but this call identity does not " ;
case 0x34D4 :
return " Call identity in use " ;
case 0x34D5 :
return " No call suspended " ;
case 0x34D6 :
return " Call having the requested call identity has been cleared " ;
2011-08-07 14:31:05 +00:00
case 0x34D7 :
return " User not a member of CUG " ;
2005-08-30 11:21:58 +00:00
case 0x34D8 :
return " Incompatible destination " ;
case 0x34DB :
return " Invalid transit network selection " ;
case 0x34DF :
return " Invalid message, unspecified " ;
case 0x34E0 :
return " Mandatory information element is missing " ;
case 0x34E1 :
return " Message type non-existent or not implemented " ;
case 0x34E2 :
return " Message not compatible with call state or message type non-existent or not implemented " ;
case 0x34E3 :
return " Information element non-existent or not implemented " ;
case 0x34E4 :
return " Invalid information element contents " ;
case 0x34E5 :
return " Message not compatible with call state " ;
case 0x34E6 :
return " Recovery on timer expiry " ;
case 0x34EF :
return " Protocol error, unspecified " ;
case 0x34FF :
return " Interworking, unspecified " ;
/* B3 protocol 7 (Modem) */
case 0x3500 :
return " Normal end of connection " ;
case 0x3501 :
return " Carrier lost " ;
case 0x3502 :
return " Error on negotiation, i.e. no modem with error correction at other end " ;
case 0x3503 :
return " No answer to protocol request " ;
case 0x3504 :
return " Remote modem only works in synchronous mode " ;
case 0x3505 :
return " Framing fails " ;
case 0x3506 :
return " Protocol negotiation fails " ;
case 0x3507 :
return " Other modem sends wrong protocol request " ;
case 0x3508 :
return " Sync information (data or flags) missing " ;
case 0x3509 :
return " Normal end of connection from the other modem " ;
case 0x350a :
return " No answer from other modem " ;
case 0x350b :
return " Protocol error " ;
case 0x350c :
return " Error on compression " ;
case 0x350d :
return " No connect (timeout or wrong modulation) " ;
case 0x350e :
return " No protocol fall-back allowed " ;
case 0x350f :
return " No modem or fax at requested number " ;
case 0x3510 :
return " Handshake error " ;
/* error info concerning the requested supplementary service */
case 0x3600 :
return " Supplementary service not subscribed " ;
case 0x3603 :
return " Supplementary service not available " ;
case 0x3604 :
return " Supplementary service not implemented " ;
case 0x3606 :
return " Invalid served user number " ;
case 0x3607 :
return " Invalid call state " ;
case 0x3608 :
return " Basic service not provided " ;
case 0x3609 :
return " Supplementary service not requested for an incoming call " ;
case 0x360a :
return " Supplementary service interaction not allowed " ;
case 0x360b :
return " Resource unavailable " ;
/* error info concerning the context of a supplementary service request */
case 0x3700 :
return " Duplicate invocation " ;
case 0x3701 :
return " Unrecognized operation " ;
case 0x3702 :
return " Mistyped argument " ;
case 0x3703 :
return " Resource limitation " ;
case 0x3704 :
return " Initiator releasing " ;
case 0x3705 :
return " Unrecognized linked-ID " ;
case 0x3706 :
return " Linked response unexpected " ;
case 0x3707 :
return " Unexpected child operation " ;
2005-09-15 19:11:45 +00:00
/* Line Interconnect */
case 0x3800 :
return " PLCI has no B-channel " ;
case 0x3801 :
return " Lines not compatible " ;
case 0x3802 :
return " PLCI(s) is (are) not in any or not in the same interconnection " ;
2005-08-30 11:21:58 +00:00
default :
return NULL ;
}
}
2007-04-15 19:39:49 +00:00
/*
* show the text for a CAPI message info value
*/
void show_capi_info ( struct capi_pvt * i , _cword info )
{
char * p ;
char * name = " ? " ;
if ( info = = 0x0000 ) {
/* no error, do nothing */
return ;
}
if ( ! ( p = capi_info_string ( ( unsigned int ) info ) ) ) {
/* message not available */
return ;
}
if ( i )
name = i - > vname ;
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_4 " %s: CAPI INFO 0x%04x: %s \n " ,
name , info , p ) ;
}
2007-04-15 20:29:12 +00:00
/*
* send Listen to specified controller
*/
2007-04-29 22:28:30 +00:00
unsigned capi_ListenOnController ( unsigned int CIPmask , unsigned controller )
2007-04-15 20:29:12 +00:00
{
MESSAGE_EXCHANGE_ERROR error ;
int waitcount = 50 ;
2007-04-28 16:48:00 +00:00
_cmsg CMSG ;
2007-04-15 20:29:12 +00:00
2007-05-01 14:26:39 +00:00
error = capi_sendf ( NULL , 0 , CAPI_LISTEN_REQ , controller , get_capi_MessageNumber ( ) ,
2007-04-28 16:48:00 +00:00
" ddd()() " ,
0x0000ffff ,
CIPmask ,
0
) ;
2007-04-15 20:29:12 +00:00
if ( error )
goto done ;
while ( waitcount ) {
error = capidev_check_wait_get_cmsg ( & CMSG ) ;
if ( IS_LISTEN_CONF ( & CMSG ) ) {
error = LISTEN_CONF_INFO ( & CMSG ) ;
ListenOnSupplementary ( controller ) ;
break ;
}
usleep ( 30000 ) ;
waitcount - - ;
}
if ( ! waitcount )
error = 0x100F ;
done :
return error ;
}
2009-02-13 21:58:19 +00:00
/*
* Activate access to vendor specific extensions
*/
unsigned capi_ManufacturerAllowOnController ( unsigned controller )
{
2009-04-10 07:23:20 +00:00
MESSAGE_EXCHANGE_ERROR error ;
int waitcount = 50 ;
2009-07-20 11:03:49 +00:00
unsigned char manbuf [ CAPI_MANUFACTURER_LEN ] ;
2009-04-10 07:23:20 +00:00
_cmsg CMSG ;
2009-02-13 21:58:19 +00:00
2009-07-20 11:03:49 +00:00
if ( capi20_get_manufacturer ( controller , manbuf ) = = NULL ) {
error = CapiRegOSResourceErr ;
goto done ;
}
if ( ( strstr ( ( char * ) manbuf , " Eicon " ) = = 0 ) & &
( strstr ( ( char * ) manbuf , " Dialogic " ) = = 0 ) ) {
error = 0x100F ;
goto done ;
}
2009-04-10 07:23:20 +00:00
error = capi_sendf ( NULL , 0 , CAPI_MANUFACTURER_REQ , controller , get_capi_MessageNumber ( ) ,
" dw(d) " , _DI_MANU_ID , _DI_OPTIONS_REQUEST , 0x00000020L ) ;
2009-02-13 21:58:19 +00:00
2009-04-10 07:23:20 +00:00
if ( error )
goto done ;
2009-02-13 21:58:19 +00:00
2009-04-10 07:23:20 +00:00
while ( waitcount ) {
error = capidev_check_wait_get_cmsg ( & CMSG ) ;
2009-02-13 21:58:19 +00:00
2009-04-10 07:23:20 +00:00
if ( IS_MANUFACTURER_CONF ( & CMSG ) & & ( CMSG . ManuID = = _DI_MANU_ID ) & &
( ( CMSG . Class & 0xffff ) = = _DI_OPTIONS_REQUEST ) ) {
error = ( MESSAGE_EXCHANGE_ERROR ) ( CMSG . Class > > 16 ) ;
break ;
}
usleep ( 30000 ) ;
waitcount - - ;
}
if ( ! waitcount )
error = 0x100F ;
2009-02-13 21:58:19 +00:00
2009-04-10 07:23:20 +00:00
done :
return error ;
2009-02-13 21:58:19 +00:00
}
2007-04-15 20:29:12 +00:00
/*
* convert a number
*/
char * capi_number_func ( unsigned char * data , unsigned int strip , char * buf )
{
unsigned int len ;
2007-09-20 13:15:27 +00:00
if ( data = = NULL ) {
buf [ 0 ] = ' \0 ' ;
return buf ;
}
2007-04-15 20:29:12 +00:00
if ( data [ 0 ] = = 0xff ) {
len = read_capi_word ( & data [ 1 ] ) ;
data + = 2 ;
} else {
len = data [ 0 ] ;
data + = 1 ;
}
if ( len > ( AST_MAX_EXTENSION - 1 ) )
len = ( AST_MAX_EXTENSION - 1 ) ;
/* convert a capi struct to a \0 terminated string */
if ( ( ! len ) | | ( len < strip ) )
return NULL ;
len = len - strip ;
data + = strip ;
memcpy ( buf , data , len ) ;
buf [ len ] = ' \0 ' ;
return buf ;
}
/*
* parse the dialstring
*/
2007-04-29 22:28:30 +00:00
void capi_parse_dialstring ( char * buffer , char * * interface , char * * dest , char * * param , char * * ocid )
2007-04-15 20:29:12 +00:00
{
int cp = 0 ;
char * buffer_p = buffer ;
char * oc ;
/* interface is the first part of the string */
* interface = buffer ;
* dest = emptyid ;
* param = emptyid ;
* ocid = NULL ;
while ( * buffer_p ) {
if ( * buffer_p = = ' / ' ) {
* buffer_p = 0 ;
buffer_p + + ;
if ( cp = = 0 ) {
* dest = buffer_p ;
cp + + ;
} else if ( cp = = 1 ) {
* param = buffer_p ;
cp + + ;
} else {
cc_log ( LOG_WARNING , " Too many parts in dialstring '%s' \n " ,
buffer ) ;
}
continue ;
}
buffer_p + + ;
}
if ( ( oc = strchr ( * dest , ' : ' ) ) ! = NULL ) {
* ocid = * dest ;
* oc = ' \0 ' ;
* dest = oc + 1 ;
}
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " parsed dialstring: '%s' '%s' '%s' '%s' \n " ,
* interface , ( * ocid ) ? * ocid : " NULL " , * dest , * param ) ;
return ;
}
2007-04-17 21:04:42 +00:00
/*
* Add a new peer link id
*/
int cc_add_peer_link_id ( struct ast_channel * c )
{
int a ;
2007-04-22 10:03:52 +00:00
cc_mutex_lock ( & peerlink_lock ) ;
2007-04-17 21:04:42 +00:00
for ( a = 0 ; a < CAPI_MAX_PEERLINKCHANNELS ; a + + ) {
2007-04-22 10:03:52 +00:00
if ( peerlinkchannel [ a ] . channel = = NULL ) {
peerlinkchannel [ a ] . channel = c ;
peerlinkchannel [ a ] . age = time ( NULL ) ;
2007-04-17 21:04:42 +00:00
break ;
2007-04-22 10:03:52 +00:00
} else {
/* remove too old entries */
if ( ( peerlinkchannel [ a ] . age + 60 ) < time ( NULL ) ) {
peerlinkchannel [ a ] . channel = NULL ;
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 CC_MESSAGE_NAME
" : peerlink %d timeout-erase \n " , a ) ;
2007-04-22 10:03:52 +00:00
}
2007-04-17 21:04:42 +00:00
}
}
2007-04-22 10:03:52 +00:00
cc_mutex_unlock ( & peerlink_lock ) ;
2007-04-17 21:04:42 +00:00
if ( a = = CAPI_MAX_PEERLINKCHANNELS ) {
return - 1 ;
}
return a ;
}
/*
* Get and remove peer link id
*/
struct ast_channel * cc_get_peer_link_id ( const char * p )
{
int id = - 1 ;
struct ast_channel * chan = NULL ;
if ( p ) {
2007-04-18 11:48:07 +00:00
id = ( int ) strtol ( p , NULL , 0 ) ;
2007-04-17 21:04:42 +00:00
}
2007-04-22 10:03:52 +00:00
cc_mutex_lock ( & peerlink_lock ) ;
2007-04-17 21:04:42 +00:00
if ( ( id > = 0 ) & & ( id < CAPI_MAX_PEERLINKCHANNELS ) ) {
2007-04-22 10:03:52 +00:00
chan = peerlinkchannel [ id ] . channel ;
peerlinkchannel [ id ] . channel = NULL ;
2007-04-17 21:04:42 +00:00
}
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 CC_MESSAGE_NAME
" : peerlink %d allocated, peer is %s \n " , id , ( chan ) ? chan - > name : " unlinked " ) ;
2007-04-22 10:03:52 +00:00
cc_mutex_unlock ( & peerlink_lock ) ;
2007-04-17 21:04:42 +00:00
return chan ;
}
2007-04-29 22:28:30 +00:00
/*
* create pipe for interface connection
*/
int capi_create_reader_writer_pipe ( struct capi_pvt * i )
{
int fds [ 2 ] ;
int flags ;
if ( pipe ( fds ) ! = 0 ) {
cc_log ( LOG_ERROR , " %s: unable to create pipe. \n " ,
i - > vname ) ;
return 0 ;
}
i - > readerfd = fds [ 0 ] ;
i - > writerfd = fds [ 1 ] ;
flags = fcntl ( i - > readerfd , F_GETFL ) ;
fcntl ( i - > readerfd , F_SETFL , flags | O_NONBLOCK ) ;
flags = fcntl ( i - > writerfd , F_GETFL ) ;
fcntl ( i - > writerfd , F_SETFL , flags | O_NONBLOCK ) ;
return 1 ;
}
/*
* read a frame from the pipe
*/
struct ast_frame * capi_read_pipeframe ( struct capi_pvt * i )
{
struct ast_frame * f ;
int readsize ;
if ( i = = NULL ) {
cc_log ( LOG_ERROR , " channel has no interface \n " ) ;
return NULL ;
}
if ( i - > readerfd = = - 1 ) {
cc_log ( LOG_ERROR , " no readerfd \n " ) ;
return NULL ;
}
f = & i - > f ;
f - > frametype = AST_FRAME_NULL ;
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( f - > subclass ) = 0 ;
2007-04-29 22:28:30 +00:00
readsize = read ( i - > readerfd , f , sizeof ( struct ast_frame ) ) ;
if ( ( readsize ! = sizeof ( struct ast_frame ) ) & & ( readsize > 0 ) ) {
cc_log ( LOG_ERROR , " did not read a whole frame (len=%d, err=%d) \n " ,
readsize , errno ) ;
}
f - > mallocd = 0 ;
2009-01-06 13:40:49 +00:00
f - > FRAME_DATA_PTR = NULL ;
2007-04-29 22:28:30 +00:00
2010-03-01 17:59:31 +00:00
if ( ( f - > frametype = = AST_FRAME_CONTROL ) & &
( FRAME_SUBCLASS_INTEGER ( f - > subclass ) = = AST_CONTROL_HANGUP ) ) {
2007-04-29 22:28:30 +00:00
return NULL ;
}
if ( ( f - > frametype = = AST_FRAME_VOICE ) & & ( f - > datalen > 0 ) ) {
if ( f - > datalen > sizeof ( i - > frame_data ) ) {
cc_log ( LOG_ERROR , " f.datalen(%d) greater than space of frame_data(%d) \n " ,
2009-02-13 21:58:19 +00:00
f - > datalen , ( int ) sizeof ( i - > frame_data ) ) ;
2007-04-29 22:28:30 +00:00
f - > datalen = sizeof ( i - > frame_data ) ;
}
readsize = read ( i - > readerfd , i - > frame_data + AST_FRIENDLY_OFFSET , f - > datalen ) ;
if ( readsize ! = f - > datalen ) {
cc_log ( LOG_ERROR , " did not read whole frame data \n " ) ;
}
2009-01-06 13:40:49 +00:00
f - > FRAME_DATA_PTR = i - > frame_data + AST_FRIENDLY_OFFSET ;
2007-04-29 22:28:30 +00:00
}
return f ;
}
/*
* write for a channel
*/
int capi_write_frame ( struct capi_pvt * i , struct ast_frame * f )
{
MESSAGE_EXCHANGE_ERROR error ;
int j = 0 ;
unsigned char * buf ;
struct ast_frame * fsmooth ;
int txavg = 0 ;
int ret = 0 ;
2010-05-26 10:19:42 +00:00
int B3Blocks = 1 ;
2007-04-29 22:28:30 +00:00
2009-03-13 00:59:28 +00:00
if ( unlikely ( ! i ) ) {
2007-04-29 22:28:30 +00:00
cc_log ( LOG_ERROR , " channel has no interface \n " ) ;
return - 1 ;
}
2009-04-14 21:58:03 +00:00
{
struct capi_pvt * ii = i ;
cc_mutex_lock ( & ii - > lock ) ;
if ( i - > line_plci ! = 0 )
i = i - > line_plci ;
cc_mutex_unlock ( & ii - > lock ) ;
}
2007-04-29 22:28:30 +00:00
2009-03-13 00:59:28 +00:00
if ( unlikely ( ( ! ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) | | ( ! i - > NCCI ) | |
( ( i - > isdnstate & ( CAPI_ISDN_STATE_B3_CHANGE | CAPI_ISDN_STATE_LI ) ) ) ) ) {
2007-04-29 22:28:30 +00:00
return 0 ;
}
if ( ( ! ( i - > ntmode ) ) & & ( i - > state ! = CAPI_STATE_CONNECTED ) ) {
return 0 ;
}
2009-03-13 00:59:28 +00:00
if ( unlikely ( f - > frametype = = AST_FRAME_NULL ) ) {
2007-04-29 22:28:30 +00:00
return 0 ;
}
2010-02-13 21:23:59 +00:00
if ( unlikely ( ( ! f - > FRAME_DATA_PTR ) | | ( ! f - > datalen ) ) ) {
/* prodding from Asterisk, just returning */
return 0 ;
}
2009-03-13 00:59:28 +00:00
if ( unlikely ( f - > frametype = = AST_FRAME_DTMF ) ) {
2007-04-29 22:28:30 +00:00
cc_log ( LOG_ERROR , " dtmf frame should be written \n " ) ;
return 0 ;
}
2009-03-13 00:59:28 +00:00
if ( unlikely ( f - > frametype ! = AST_FRAME_VOICE ) ) {
2007-04-29 22:28:30 +00:00
cc_log ( LOG_ERROR , " not a voice frame \n " ) ;
return 0 ;
}
2009-03-13 00:59:28 +00:00
if ( unlikely ( i - > FaxState & CAPI_FAX_STATE_ACTIVE ) ) {
2007-04-29 22:28:30 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: write on fax activity? \n " ,
i - > vname ) ;
return 0 ;
}
if ( i - > isdnstate & CAPI_ISDN_STATE_RTP ) {
2011-10-04 08:41:28 +00:00
if ( unlikely ( ( ! ( GET_FRAME_SUBCLASS_CODEC ( f - > subclass ) & i - > codec ) ) & &
( GET_FRAME_SUBCLASS_CODEC ( f - > subclass ) ! = capi_capability ) ) ) {
2007-04-29 22:28:30 +00:00
cc_log ( LOG_ERROR , " don't know how to write subclass %s(%d) \n " ,
2011-10-04 08:41:28 +00:00
cc_getformatname ( GET_FRAME_SUBCLASS_CODEC ( f - > subclass ) ) ,
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( f - > subclass ) ) ;
2007-04-29 22:28:30 +00:00
return 0 ;
}
2007-05-01 14:26:39 +00:00
return capi_write_rtp ( i , f ) ;
2007-04-29 22:28:30 +00:00
}
2010-05-26 10:19:42 +00:00
2009-03-13 00:59:28 +00:00
if ( unlikely ( i - > B3count > = CAPI_MAX_B3_BLOCKS ) ) {
2007-04-29 22:28:30 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: B3count is full, dropping packet. \n " ,
i - > vname ) ;
return 0 ;
}
2010-10-02 00:00:57 +00:00
if ( i - > bproto = = CC_BPROTO_VOCODER | | ( i - > line_plci ! = 0 & & i - > line_plci - > bproto = = CC_BPROTO_VOCODER ) ) {
2010-05-26 10:19:42 +00:00
# ifdef DIVA_STREAMING
2010-06-30 08:33:41 +00:00
capi_DivaStreamLock ( ) ;
2010-05-26 10:19:42 +00:00
if ( i - > diva_stream_entry ! = 0 ) {
int written = 0 , ready = 0 ;
B3Blocks = 0 ;
if ( ( ready = ( i - > diva_stream_entry - > diva_stream_state = = DivaStreamActive ) ) & &
( i - > diva_stream_entry - > diva_stream - > get_tx_free ( i - > diva_stream_entry - > diva_stream ) > 2 * CAPI_MAX_B3_BLOCK_SIZE + 128 ) ) {
written = i - > diva_stream_entry - > diva_stream - > write ( i - > diva_stream_entry - > diva_stream , 8U < < 8 | DIVA_STREAM_MESSAGE_TX_IDI_REQUEST , f - > FRAME_DATA_PTR , f - > datalen ) ;
i - > diva_stream_entry - > diva_stream - > flush_stream ( i - > diva_stream_entry - > diva_stream ) ;
}
2010-06-30 08:33:41 +00:00
capi_DivaStreamUnLock ( ) ;
2010-05-26 10:19:42 +00:00
error = written ! = f - > datalen ;
if ( unlikely ( error ! = 0 ) ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: stream is %s, dropping packet. \n " , i - > vname , ( ready ! = 0 ) ? " full " : " not ready " ) ;
}
} else
# endif
{
2010-06-25 13:48:29 +00:00
# ifdef DIVA_STREAMING
2010-06-30 08:33:41 +00:00
capi_DivaStreamUnLock ( ) ;
2010-06-25 13:48:29 +00:00
# endif
2010-05-26 10:19:42 +00:00
buf = & ( i - > send_buffer [ ( i - > send_buffer_handle % CAPI_MAX_B3_BLOCKS ) *
( CAPI_MAX_B3_BLOCK_SIZE + AST_FRIENDLY_OFFSET ) ] ) ;
i - > send_buffer_handle + + ;
2009-05-08 13:03:31 +00:00
2010-05-26 10:19:42 +00:00
memcpy ( buf , f - > FRAME_DATA_PTR , f - > datalen ) ;
2009-05-08 13:03:31 +00:00
2010-05-26 10:19:42 +00:00
error = capi_sendf ( NULL , 0 , CAPI_DATA_B3_REQ , i - > NCCI , get_capi_MessageNumber ( ) ,
" dwww " , buf , f - > datalen , i - > send_buffer_handle , 0 ) ;
}
2009-05-08 13:03:31 +00:00
if ( likely ( error = = 0 ) ) {
cc_mutex_lock ( & i - > lock ) ;
2010-05-26 10:19:42 +00:00
i - > B3count + = B3Blocks ;
2009-05-08 13:03:31 +00:00
i - > B3q - = f - > datalen ;
if ( i - > B3q < 0 )
i - > B3q = 0 ;
cc_mutex_unlock ( & i - > lock ) ;
}
return 0 ;
}
2007-04-29 22:28:30 +00:00
if ( ( ! i - > smoother ) | | ( ast_smoother_feed ( i - > smoother , f ) ! = 0 ) ) {
cc_log ( LOG_ERROR , " %s: failed to fill smoother \n " , i - > vname ) ;
return 0 ;
}
for ( fsmooth = ast_smoother_read ( i - > smoother ) ;
fsmooth ! = NULL ;
fsmooth = ast_smoother_read ( i - > smoother ) ) {
buf = & ( i - > send_buffer [ ( i - > send_buffer_handle % CAPI_MAX_B3_BLOCKS ) *
( CAPI_MAX_B3_BLOCK_SIZE + AST_FRIENDLY_OFFSET ) ] ) ;
i - > send_buffer_handle + + ;
2007-05-01 14:26:39 +00:00
if ( ( i - > doES = = 1 ) & & ( ! capi_tcap_is_digital ( i - > transfercapability ) ) ) {
2007-04-29 22:28:30 +00:00
for ( j = 0 ; j < fsmooth - > datalen ; j + + ) {
2009-01-06 13:40:49 +00:00
buf [ j ] = capi_reversebits [ ( ( unsigned char * ) fsmooth - > FRAME_DATA_PTR ) [ j ] ] ;
2007-04-29 22:28:30 +00:00
if ( capi_capability = = AST_FORMAT_ULAW ) {
2009-01-06 13:40:49 +00:00
txavg + = abs ( capiULAW2INT [ capi_reversebits [ ( ( unsigned char * ) fsmooth - > FRAME_DATA_PTR ) [ j ] ] ] ) ;
2007-04-29 22:28:30 +00:00
} else {
2009-01-06 13:40:49 +00:00
txavg + = abs ( capiALAW2INT [ capi_reversebits [ ( ( unsigned char * ) fsmooth - > FRAME_DATA_PTR ) [ j ] ] ] ) ;
2007-04-29 22:28:30 +00:00
}
}
txavg = txavg / j ;
for ( j = 0 ; j < ECHO_TX_COUNT - 1 ; j + + ) {
i - > txavg [ j ] = i - > txavg [ j + 1 ] ;
}
i - > txavg [ ECHO_TX_COUNT - 1 ] = txavg ;
} else {
2007-05-01 14:26:39 +00:00
if ( ( i - > txgain = = 1.0 ) | | ( capi_tcap_is_digital ( i - > transfercapability ) ) ) {
2007-04-29 22:28:30 +00:00
for ( j = 0 ; j < fsmooth - > datalen ; j + + ) {
2009-01-06 13:40:49 +00:00
buf [ j ] = capi_reversebits [ ( ( unsigned char * ) fsmooth - > FRAME_DATA_PTR ) [ j ] ] ;
2007-04-29 22:28:30 +00:00
}
} else {
for ( j = 0 ; j < fsmooth - > datalen ; j + + ) {
2009-01-06 13:40:49 +00:00
buf [ j ] = i - > g . txgains [ capi_reversebits [ ( ( unsigned char * ) fsmooth - > FRAME_DATA_PTR ) [ j ] ] ] ;
2007-04-29 22:28:30 +00:00
}
}
}
2010-05-26 10:19:42 +00:00
error = 1 ;
2007-04-29 22:28:30 +00:00
if ( i - > B3q > 0 ) {
2010-05-26 10:19:42 +00:00
# if defined(DIVA_STREAMING)
if ( i - > diva_stream_entry ! = 0 ) {
int written = 0 , ready = 0 ;
B3Blocks = 0 ;
2010-06-30 08:33:41 +00:00
capi_DivaStreamLock ( ) ;
2010-05-26 10:19:42 +00:00
if ( ( ready = ( i - > diva_stream_entry - > diva_stream_state = = DivaStreamActive ) ) & &
( i - > diva_stream_entry - > diva_stream - > get_tx_free ( i - > diva_stream_entry - > diva_stream ) > 2 * CAPI_MAX_B3_BLOCK_SIZE + 128 ) ) {
written = i - > diva_stream_entry - > diva_stream - > write ( i - > diva_stream_entry - > diva_stream , 8U < < 8 | DIVA_STREAM_MESSAGE_TX_IDI_REQUEST , buf , fsmooth - > datalen ) ;
i - > diva_stream_entry - > diva_stream - > flush_stream ( i - > diva_stream_entry - > diva_stream ) ;
}
2010-06-30 08:33:41 +00:00
capi_DivaStreamUnLock ( ) ;
2010-05-26 10:19:42 +00:00
error = written ! = fsmooth - > datalen ;
if ( unlikely ( error ! = 0 ) ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: stream is %s, dropping packet. \n " , i - > vname , ( ready ! = 0 ) ? " full " : " not ready " ) ;
}
} else
# endif
{
error = capi_sendf ( NULL , 0 , CAPI_DATA_B3_REQ , i - > NCCI , get_capi_MessageNumber ( ) ,
" dwww " , buf , fsmooth - > datalen , i - > send_buffer_handle , 0 ) ;
}
2007-04-29 22:28:30 +00:00
} else {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: too much voice to send for NCCI=%#x \n " ,
i - > vname , i - > NCCI ) ;
}
2009-03-21 11:18:14 +00:00
if ( likely ( ! error ) ) {
2007-04-29 22:28:30 +00:00
cc_mutex_lock ( & i - > lock ) ;
2010-05-26 10:19:42 +00:00
i - > B3count + = B3Blocks ;
2007-04-29 22:28:30 +00:00
i - > B3q - = fsmooth - > datalen ;
if ( i - > B3q < 0 )
i - > B3q = 0 ;
cc_mutex_unlock ( & i - > lock ) ;
}
}
return ret ;
}
2010-08-13 21:08:20 +00:00
/*
ast_channel_lock ( chan ) to be held while
while accessing returned pointer
*/
2010-11-03 22:04:22 +00:00
const char * pbx_capi_get_cid ( const struct ast_channel * c , const char * notAvailableVisual )
2010-08-13 21:08:20 +00:00
{
const char * cid ;
# ifdef CC_AST_HAS_VERSION_1_8
2010-11-03 22:04:22 +00:00
cid = S_COR ( c - > caller . id . number . valid , c - > caller . id . number . str , notAvailableVisual ) ;
2010-08-13 21:08:20 +00:00
# else
cid = c - > cid . cid_num ;
# endif
return ( cid ) ;
}
/*
ast_channel_lock ( chan ) to be held while
while accessing returned pointer
*/
2010-11-03 22:04:22 +00:00
const char * pbx_capi_get_callername ( const struct ast_channel * c , const char * notAvailableVisual )
2010-08-13 21:08:20 +00:00
{
const char * name ;
# ifdef CC_AST_HAS_VERSION_1_8
2010-11-03 22:04:22 +00:00
name = S_COR ( c - > caller . id . name . valid , c - > caller . id . name . str , notAvailableVisual ) ;
2010-08-13 21:08:20 +00:00
# else
2010-11-03 22:04:22 +00:00
name = ( c - > cid . cid_name ) ? c - > cid . cid_name : notAvailableVisual ;
2010-08-13 21:08:20 +00:00
# endif
return ( name ) ;
}
2010-09-14 22:05:40 +00:00
/*
ast_channel_lock ( chan ) to be held while
while accessing returned pointer
*/
2010-11-03 22:04:22 +00:00
const char * pbx_capi_get_connectedname ( const struct ast_channel * c , const char * notAvailableVisual )
2010-09-14 22:05:40 +00:00
{
const char * name ;
# ifdef CC_AST_HAS_VERSION_1_8
2010-11-03 22:04:22 +00:00
name = S_COR ( c - > connected . id . name . valid , c - > connected . id . name . str , notAvailableVisual ) ;
2010-09-14 22:05:40 +00:00
# else
2010-11-03 22:04:22 +00:00
name = ( c - > cid . cid_name ) ? c - > cid . cid_name : notAvailableVisual ;
2010-09-14 22:05:40 +00:00
# endif
return ( name ) ;
}
2010-10-29 21:51:03 +00:00
const struct capi_pvt * pbx_capi_get_nulliflist ( void )
{
return nulliflist ;
}
void pbx_capi_nulliflist_lock ( void )
{
cc_mutex_lock ( & nullif_lock ) ;
}
void pbx_capi_nulliflist_unlock ( void )
{
cc_mutex_unlock ( & nullif_lock ) ;
}
2010-11-24 17:08:11 +00:00
/*!
\ brief get list of controllers . Stop parsing
after non digit detected after separator
character or end of string is reached
*/
char * pbx_capi_strsep_controller_list ( char * * param )
{
char * src , * p ;
if ( ( param = = NULL ) | | ( * param = = NULL ) | | ( * * param = = 0 ) )
return NULL ;
if ( strchr ( * param , ' | ' ) ! = NULL )
return ( strsep ( param , " | " ) ) ;
src = * param ;
p = src - 1 ;
do {
p = strchr ( p + 1 , ' , ' ) ;
} while ( ( p ! = NULL ) & & ( isdigit ( p [ 1 ] ) ! = 0 ) ) ;
if ( p ! = NULL )
* p + + = 0 ;
* param = p ;
return src ;
}