2012-06-20 12:30:08 -04:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
* Copyright ( C ) 2005 - 2011 , Anthony Minessale II < anthm @ freeswitch . org >
*
* Version : MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II < anthm @ freeswitch . org >
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
*
* Mathieu Rene < mrene @ avgs . ca >
*
* tdm . c - - FreeTDM Controllable Channel Module
*
*/
# include <switch.h>
# include "freetdm.h"
void ctdm_init ( switch_loadable_module_interface_t * module_interface ) ;
/* Parameters */
# define kSPAN_ID "span"
# define kCHAN_ID "chan"
2012-07-25 17:18:18 -04:00
# define kSPAN_NAME "span_name"
2012-08-14 16:22:31 -04:00
# define kPREBUFFER_LEN "prebuffer_len"
2012-08-16 01:28:32 -04:00
# define kECHOCANCEL "echo_cancel"
2012-06-20 12:30:08 -04:00
static struct {
switch_memory_pool_t * pool ;
switch_endpoint_interface_t * endpoint_interface ;
} ctdm ;
typedef struct {
int span_id ;
int chan_id ;
ftdm_channel_t * ftdm_channel ;
switch_core_session_t * session ;
switch_codec_t read_codec , write_codec ;
switch_frame_t read_frame ;
2012-08-14 16:22:31 -04:00
int prebuffer_len ;
2012-07-25 21:26:53 -04:00
unsigned char databuf [ SWITCH_RECOMMENDED_BUFFER_SIZE ] ;
2012-06-20 12:30:08 -04:00
} ctdm_private_t ;
static switch_status_t channel_on_init ( switch_core_session_t * session ) ;
static switch_status_t channel_on_destroy ( switch_core_session_t * session ) ;
static switch_call_cause_t channel_outgoing_channel ( switch_core_session_t * session , switch_event_t * var_event ,
switch_caller_profile_t * outbound_profile ,
switch_core_session_t * * new_session ,
switch_memory_pool_t * * pool ,
switch_originate_flag_t flags , switch_call_cause_t * cancel_cause ) ;
static switch_status_t channel_read_frame ( switch_core_session_t * session , switch_frame_t * * frame , switch_io_flag_t flags , int stream_id ) ;
static switch_status_t channel_write_frame ( switch_core_session_t * session , switch_frame_t * frame , switch_io_flag_t flags , int stream_id ) ;
static switch_status_t channel_receive_message ( switch_core_session_t * session , switch_core_session_message_t * msg ) ;
2012-08-14 16:22:31 -04:00
static switch_status_t channel_receive_event ( switch_core_session_t * session , switch_event_t * event ) ;
2012-06-20 12:30:08 -04:00
static switch_status_t channel_send_dtmf ( switch_core_session_t * session , const switch_dtmf_t * dtmf ) ;
2012-07-27 21:31:24 -04:00
static ftdm_status_t ctdm_span_prepare ( ftdm_span_t * span ) ;
2012-06-20 12:30:08 -04:00
switch_state_handler_table_t ctdm_state_handlers = {
. on_init = channel_on_init ,
. on_destroy = channel_on_destroy
} ;
switch_io_routines_t ctdm_io_routines = {
. send_dtmf = channel_send_dtmf ,
. outgoing_channel = channel_outgoing_channel ,
. read_frame = channel_read_frame ,
. write_frame = channel_write_frame ,
2012-08-14 16:22:31 -04:00
. receive_message = channel_receive_message ,
. receive_event = channel_receive_event
2012-06-20 12:30:08 -04:00
} ;
2012-07-30 12:32:46 -04:00
static void ctdm_report_alarms ( ftdm_channel_t * channel )
2012-07-27 21:31:24 -04:00
{
switch_event_t * event = NULL ;
ftdm_alarm_flag_t alarmflag = 0 ;
if ( switch_event_create ( & event , SWITCH_EVENT_TRAP ) ! = SWITCH_STATUS_SUCCESS ) {
ftdm_log ( FTDM_LOG_ERROR , " failed to create alarms events \n " ) ;
return ;
}
if ( ftdm_channel_get_alarms ( channel , & alarmflag ) ! = FTDM_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Failed to retrieve alarms %s:%d \n " , ftdm_channel_get_span_name ( channel ) , ftdm_channel_get_id ( channel ) ) ;
return ;
}
switch_event_add_header ( event , SWITCH_STACK_BOTTOM , " span-name " , " %s " , ftdm_channel_get_span_name ( channel ) ) ;
switch_event_add_header ( event , SWITCH_STACK_BOTTOM , " span-number " , " %d " , ftdm_channel_get_span_id ( channel ) ) ;
switch_event_add_header ( event , SWITCH_STACK_BOTTOM , " chan-number " , " %d " , ftdm_channel_get_id ( channel ) ) ;
if ( alarmflag ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " condition " , " ftdm-alarm-trap " ) ;
2012-08-01 13:18:37 -04:00
} else {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " condition " , " ftdm-alarm-clear " ) ;
2012-07-27 21:31:24 -04:00
}
if ( alarmflag & FTDM_ALARM_RED ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " alarm " , " red " ) ;
}
if ( alarmflag & FTDM_ALARM_YELLOW ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " alarm " , " yellow " ) ;
}
if ( alarmflag & FTDM_ALARM_RAI ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " alarm " , " rai " ) ;
}
if ( alarmflag & FTDM_ALARM_BLUE ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " alarm " , " blue " ) ;
}
if ( alarmflag & FTDM_ALARM_AIS ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " alarm " , " ais " ) ;
}
if ( alarmflag & FTDM_ALARM_GENERAL ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " alarm " , " general " ) ;
}
2012-07-30 13:17:39 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Reporting [%s] alarms for %s:%d \n " ,
2012-08-01 13:21:47 -04:00
( alarmflag ? " ftdm-alarm-trap " : " ftdm-alarm-clear " ) , ftdm_channel_get_span_name ( channel ) , ftdm_channel_get_id ( channel ) ) ;
2012-07-29 10:17:13 -04:00
2012-07-27 21:31:24 -04:00
switch_event_fire ( & event ) ;
return ;
}
2012-09-06 16:53:58 -04:00
static ftdm_channel_t * ctdm_get_channel_from_event ( switch_event_t * event , ftdm_span_t * span )
{
uint32_t chan_id = 0 ;
const char * chan_number = NULL ;
chan_number = switch_event_get_header ( event , " chan-number " ) ;
if ( zstr ( chan_number ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " No channel number specified \n " ) ;
return NULL ;
}
chan_id = atoi ( chan_number ) ;
if ( ! chan_id ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Invalid channel number:%s \n " , chan_number ) ;
return NULL ;
}
2012-09-11 14:45:57 -04:00
return ftdm_span_get_channel_ph ( span , chan_id ) ;
2012-09-06 16:53:58 -04:00
}
2012-07-27 21:31:24 -04:00
static void ctdm_event_handler ( switch_event_t * event )
{
ftdm_status_t status = FTDM_FAIL ;
switch ( event - > event_id ) {
case SWITCH_EVENT_TRAP :
{
ftdm_span_t * span = NULL ;
ftdm_channel_t * channel = NULL ;
const char * span_name = NULL ;
2012-09-06 16:53:58 -04:00
2012-07-27 21:31:24 -04:00
const char * cond = switch_event_get_header ( event , " condition " ) ;
2012-09-06 16:53:58 -04:00
const char * command = switch_event_get_header ( event , " command " ) ;
2012-07-27 21:31:24 -04:00
if ( zstr ( cond ) ) {
return ;
}
span_name = switch_event_get_header ( event , " span-name " ) ;
2012-09-06 16:53:58 -04:00
2012-07-27 21:31:24 -04:00
if ( ftdm_span_find_by_name ( span_name , & span ) ! = FTDM_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Cannot find span [%s] \n " , span_name ) ;
return ;
}
if ( ! strcmp ( cond , " mg-tdm-prepare " ) ) {
status = ctdm_span_prepare ( span ) ;
if ( status = = FTDM_SUCCESS ) {
2012-09-06 16:53:58 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " %s:prepared successfully \n " , span_name ) ;
2012-07-27 21:31:24 -04:00
} else if ( status ! = FTDM_EINVAL ) {
2012-09-06 16:53:58 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " %s:Failed to prepare span \n " , span_name ) ;
2012-07-27 21:31:24 -04:00
}
} else if ( ! strcmp ( cond , " mg-tdm-check " ) ) {
2012-09-06 16:53:58 -04:00
channel = ctdm_get_channel_from_event ( event , span ) ;
2012-07-27 21:31:24 -04:00
if ( ! channel ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Could not find channel \n " ) ;
return ;
}
2012-07-30 13:17:39 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Requesting alarm status for %s:%d \n " ,
ftdm_channel_get_span_name ( channel ) , ftdm_channel_get_id ( channel ) ) ;
2012-07-30 12:32:46 -04:00
ctdm_report_alarms ( channel ) ;
2012-09-06 16:53:58 -04:00
} else if ( ! strcmp ( cond , " mg-tdm-dtmfremoval " ) ) {
uint8_t enable = 0 ;
channel = ctdm_get_channel_from_event ( event , span ) ;
if ( ! channel ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Could not find channel \n " ) ;
return ;
}
if ( zstr ( command ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " %s:No command specified for mg-tdm-dtmfremoval \n " , span_name ) ;
return ;
}
if ( ! strcmp ( command , " enable " ) ) {
enable = 1 ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s DTMF-removal for %s:%d \n " ,
enable ? " Enabling " : " Disabling " , ftdm_channel_get_span_name ( channel ) , ftdm_channel_get_id ( channel ) ) ;
ftdm_channel_command ( channel , enable ? FTDM_COMMAND_ENABLE_DTMF_REMOVAL : FTDM_COMMAND_DISABLE_DTMF_REMOVAL , 0 ) ;
2012-07-27 21:31:24 -04:00
}
}
break ;
default :
break ;
}
return ;
}
2012-06-20 12:30:08 -04:00
void ctdm_init ( switch_loadable_module_interface_t * module_interface )
{
switch_endpoint_interface_t * endpoint_interface ;
ctdm . pool = module_interface - > pool ;
endpoint_interface = switch_loadable_module_create_interface ( module_interface , SWITCH_ENDPOINT_INTERFACE ) ;
endpoint_interface - > interface_name = " tdm " ;
endpoint_interface - > io_routines = & ctdm_io_routines ;
endpoint_interface - > state_handler = & ctdm_state_handlers ;
ctdm . endpoint_interface = endpoint_interface ;
2012-07-27 21:31:24 -04:00
switch_event_bind ( " mod_freetdm " , SWITCH_EVENT_TRAP , SWITCH_EVENT_SUBCLASS_ANY , ctdm_event_handler , NULL ) ;
}
static FIO_SIGNAL_CB_FUNCTION ( on_signal_cb )
{
uint32_t chanid , spanid ;
switch_event_t * event = NULL ;
ftdm_alarm_flag_t alarmbits = FTDM_ALARM_NONE ;
chanid = ftdm_channel_get_id ( sigmsg - > channel ) ;
spanid = ftdm_channel_get_span_id ( sigmsg - > channel ) ;
switch ( sigmsg - > event_id ) {
case FTDM_SIGEVENT_ALARM_CLEAR :
case FTDM_SIGEVENT_ALARM_TRAP :
{
if ( ftdm_channel_get_alarms ( sigmsg - > channel , & alarmbits ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_ERROR , " failed to retrieve alarms \n " ) ;
return FTDM_FAIL ;
}
if ( switch_event_create ( & event , SWITCH_EVENT_TRAP ) ! = SWITCH_STATUS_SUCCESS ) {
ftdm_log ( FTDM_LOG_ERROR , " failed to create alarms events \n " ) ;
return FTDM_FAIL ;
}
if ( sigmsg - > event_id = = FTDM_SIGEVENT_ALARM_CLEAR ) {
ftdm_log ( FTDM_LOG_NOTICE , " Alarm cleared on channel %d:%d \n " , spanid , chanid ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " condition " , " ftdm-alarm-clear " ) ;
} else {
ftdm_log ( FTDM_LOG_NOTICE , " Alarm raised on channel %d:%d \n " , spanid , chanid ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " condition " , " ftdm-alarm-trap " ) ;
}
}
break ;
default :
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Unhandled event %d \n " , sigmsg - > event_id ) ;
break ;
}
if ( event ) {
switch_event_add_header ( event , SWITCH_STACK_BOTTOM , " span-name " , " %s " , ftdm_channel_get_span_name ( sigmsg - > channel ) ) ;
switch_event_add_header ( event , SWITCH_STACK_BOTTOM , " span-number " , " %d " , ftdm_channel_get_span_id ( sigmsg - > channel ) ) ;
switch_event_add_header ( event , SWITCH_STACK_BOTTOM , " chan-number " , " %d " , ftdm_channel_get_id ( sigmsg - > channel ) ) ;
if ( alarmbits & FTDM_ALARM_RED ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " alarm " , " red " ) ;
}
if ( alarmbits & FTDM_ALARM_YELLOW ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " alarm " , " yellow " ) ;
}
if ( alarmbits & FTDM_ALARM_RAI ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " alarm " , " rai " ) ;
}
if ( alarmbits & FTDM_ALARM_BLUE ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " alarm " , " blue " ) ;
}
if ( alarmbits & FTDM_ALARM_AIS ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " alarm " , " ais " ) ;
}
if ( alarmbits & FTDM_ALARM_GENERAL ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " alarm " , " general " ) ;
}
switch_event_fire ( & event ) ;
}
return FTDM_SUCCESS ;
}
static ftdm_status_t ctdm_span_prepare ( ftdm_span_t * span )
{
if ( ftdm_span_register_signal_cb ( span , on_signal_cb ) ! = FTDM_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't register signal CB \n " ) ;
return FTDM_FAIL ;
}
return ftdm_span_start ( span ) ;
2012-06-20 12:30:08 -04:00
}
static switch_call_cause_t channel_outgoing_channel ( switch_core_session_t * session , switch_event_t * var_event ,
switch_caller_profile_t * outbound_profile ,
switch_core_session_t * * new_session ,
switch_memory_pool_t * * pool ,
switch_originate_flag_t flags , switch_call_cause_t * cancel_cause )
{
2012-07-25 19:37:16 -04:00
const char * szchanid = switch_event_get_header ( var_event , kCHAN_ID ) ,
2012-08-14 16:22:31 -04:00
* span_name = switch_event_get_header ( var_event , kSPAN_NAME ) ,
* szprebuffer_len = switch_event_get_header ( var_event , kPREBUFFER_LEN ) ;
2012-06-20 12:30:08 -04:00
int chan_id ;
int span_id ;
2012-07-25 21:06:47 -04:00
switch_caller_profile_t * caller_profile ;
2012-06-20 12:30:08 -04:00
ftdm_span_t * span ;
ftdm_channel_t * chan ;
switch_channel_t * channel ;
char name [ 128 ] ;
const char * dname ;
ftdm_codec_t codec ;
uint32_t interval ;
2012-06-20 21:34:04 -04:00
ctdm_private_t * tech_pvt = NULL ;
2012-07-27 21:31:24 -04:00
2012-07-25 19:37:16 -04:00
if ( zstr ( szchanid ) | | zstr ( span_name ) ) {
2012-07-19 17:51:25 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Both [ " kSPAN_ID " ] and [ " kCHAN_ID " ] have to be set. \n " ) ;
2012-06-20 12:30:08 -04:00
goto fail ;
}
chan_id = atoi ( szchanid ) ;
2012-07-25 19:37:16 -04:00
if ( ftdm_span_find_by_name ( span_name , & span ) = = FTDM_SUCCESS ) {
span_id = ftdm_span_get_id ( span ) ;
} else {
2012-07-25 19:37:47 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Cannot find span [%s] \n " , span_name ) ;
2012-07-25 19:56:25 -04:00
goto fail ;
2012-07-25 17:18:18 -04:00
}
2012-07-25 19:37:16 -04:00
2012-06-20 12:30:08 -04:00
if ( ! ( * new_session = switch_core_session_request ( ctdm . endpoint_interface , SWITCH_CALL_DIRECTION_OUTBOUND , 0 , pool ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't request session. \n " ) ;
goto fail ;
}
channel = switch_core_session_get_channel ( * new_session ) ;
2012-09-11 14:45:57 -04:00
if ( ftdm_channel_open_ph ( span_id , chan_id , & chan ) ! = FTDM_SUCCESS ) {
2012-06-20 12:30:08 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't open span or channel. \n " ) ;
goto fail ;
}
span = ftdm_channel_get_span ( chan ) ;
tech_pvt = switch_core_session_alloc ( * new_session , sizeof * tech_pvt ) ;
tech_pvt - > chan_id = chan_id ;
tech_pvt - > span_id = span_id ;
tech_pvt - > ftdm_channel = chan ;
tech_pvt - > session = * new_session ;
2012-07-25 21:26:53 -04:00
tech_pvt - > read_frame . buflen = sizeof ( tech_pvt - > databuf ) ;
tech_pvt - > read_frame . data = tech_pvt - > databuf ;
2012-08-14 16:22:31 -04:00
tech_pvt - > prebuffer_len = zstr ( szprebuffer_len ) ? 0 : atoi ( szprebuffer_len ) ;
2012-06-20 12:30:08 -04:00
switch_core_session_set_private ( * new_session , tech_pvt ) ;
2012-07-25 21:06:47 -04:00
caller_profile = switch_caller_profile_clone ( * new_session , outbound_profile ) ;
switch_channel_set_caller_profile ( channel , caller_profile ) ;
2012-06-20 12:30:08 -04:00
snprintf ( name , sizeof ( name ) , " tdm/%d:%d " , span_id , chan_id ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Connect outbound channel %s \n " , name ) ;
switch_channel_set_name ( channel , name ) ;
switch_channel_set_state ( channel , CS_INIT ) ;
if ( FTDM_SUCCESS ! = ftdm_channel_command ( chan , FTDM_COMMAND_GET_CODEC , & codec ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Failed to retrieve channel codec. \n " ) ;
2014-05-02 17:04:03 -04:00
return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER ;
2012-06-20 12:30:08 -04:00
}
if ( FTDM_SUCCESS ! = ftdm_channel_command ( chan , FTDM_COMMAND_GET_INTERVAL , & interval ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Failed to retrieve channel interval. \n " ) ;
2014-05-02 17:04:03 -04:00
return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER ;
2012-06-20 12:30:08 -04:00
}
2012-08-14 16:22:31 -04:00
if ( FTDM_SUCCESS ! = ftdm_channel_command ( chan , FTDM_COMMAND_SET_PRE_BUFFER_SIZE , & tech_pvt - > prebuffer_len ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Failed to set channel pre buffer size. \n " ) ;
2014-05-02 17:04:03 -04:00
return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER ;
2012-08-14 16:22:31 -04:00
}
2012-08-16 01:28:32 -04:00
if ( FTDM_SUCCESS ! = ftdm_channel_command ( tech_pvt - > ftdm_channel , FTDM_COMMAND_ENABLE_ECHOCANCEL , NULL ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Failed to set enable echo cancellation. \n " ) ;
}
2012-08-14 16:22:31 -04:00
2012-06-20 12:30:08 -04:00
switch ( codec ) {
case FTDM_CODEC_ULAW :
{
dname = " PCMU " ;
}
break ;
case FTDM_CODEC_ALAW :
{
dname = " PCMA " ;
}
break ;
case FTDM_CODEC_SLIN :
{
dname = " L16 " ;
}
break ;
default :
{
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Invalid codec value retrieved from channel, codec value: %d \n " , codec ) ;
goto fail ;
}
}
if ( switch_core_codec_init ( & tech_pvt - > read_codec ,
dname ,
NULL ,
2015-03-19 15:26:47 -04:00
NULL ,
2012-06-20 12:30:08 -04:00
8000 ,
interval ,
1 ,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE ,
NULL , switch_core_session_get_pool ( tech_pvt - > session ) ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Can't load codec? \n " ) ;
goto fail ;
} else {
if ( switch_core_codec_init ( & tech_pvt - > write_codec ,
dname ,
NULL ,
2015-03-19 15:26:47 -04:00
NULL ,
2012-06-20 12:30:08 -04:00
8000 ,
interval ,
1 ,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE ,
NULL , switch_core_session_get_pool ( tech_pvt - > session ) ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Can't load codec? \n " ) ;
switch_core_codec_destroy ( & tech_pvt - > read_codec ) ;
goto fail ;
}
}
if ( switch_core_session_set_read_codec ( * new_session , & tech_pvt - > read_codec ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Can't set read codec? \n " ) ;
goto fail ;
}
if ( switch_core_session_set_write_codec ( * new_session , & tech_pvt - > write_codec ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Can't set write codec? \n " ) ;
}
if ( switch_core_session_thread_launch ( * new_session ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't start session thread. \n " ) ;
goto fail ;
}
2012-07-25 20:49:33 -04:00
switch_channel_mark_answered ( channel ) ;
2012-06-20 12:30:08 -04:00
return SWITCH_CAUSE_SUCCESS ;
fail :
if ( tech_pvt ) {
if ( tech_pvt - > ftdm_channel ) {
ftdm_channel_close ( & tech_pvt - > ftdm_channel ) ;
}
if ( tech_pvt - > read_codec . implementation ) {
switch_core_codec_destroy ( & tech_pvt - > read_codec ) ;
}
if ( tech_pvt - > write_codec . implementation ) {
switch_core_codec_destroy ( & tech_pvt - > write_codec ) ;
}
}
if ( * new_session ) {
switch_core_session_destroy ( new_session ) ;
}
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ;
}
static switch_status_t channel_on_init ( switch_core_session_t * session )
{
2012-07-25 20:50:18 -04:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
switch_channel_set_state ( channel , CS_CONSUME_MEDIA ) ;
2012-06-20 12:30:08 -04:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t channel_on_destroy ( switch_core_session_t * session )
{
ctdm_private_t * tech_pvt = switch_core_session_get_private ( session ) ;
if ( ( tech_pvt = switch_core_session_get_private ( session ) ) ) {
2012-08-16 01:28:32 -04:00
if ( FTDM_SUCCESS ! = ftdm_channel_command ( tech_pvt - > ftdm_channel , FTDM_COMMAND_ENABLE_ECHOCANCEL , NULL ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Failed to enable echo cancellation. \n " ) ;
}
2012-06-20 12:30:08 -04:00
if ( tech_pvt - > read_codec . implementation ) {
switch_core_codec_destroy ( & tech_pvt - > read_codec ) ;
}
if ( tech_pvt - > write_codec . implementation ) {
switch_core_codec_destroy ( & tech_pvt - > write_codec ) ;
}
2013-01-17 10:03:40 -05:00
switch_core_session_unset_read_codec ( session ) ;
switch_core_session_unset_write_codec ( session ) ;
2012-07-25 20:04:35 -04:00
ftdm_channel_close ( & tech_pvt - > ftdm_channel ) ;
2012-06-20 12:30:08 -04:00
}
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t channel_read_frame ( switch_core_session_t * session , switch_frame_t * * frame , switch_io_flag_t flags , int stream_id )
{
ftdm_wait_flag_t wflags = FTDM_READ ;
ftdm_status_t status ;
ctdm_private_t * tech_pvt ;
const char * name ;
switch_channel_t * channel ;
int chunk ;
uint32_t span_id , chan_id ;
ftdm_size_t len ;
char dtmf [ 128 ] = " " ;
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
name = switch_channel_get_name ( channel ) ;
top :
wflags = FTDM_READ ;
chunk = ftdm_channel_get_io_interval ( tech_pvt - > ftdm_channel ) * 2 ;
status = ftdm_channel_wait ( tech_pvt - > ftdm_channel , & wflags , chunk ) ;
span_id = ftdm_channel_get_span_id ( tech_pvt - > ftdm_channel ) ;
chan_id = ftdm_channel_get_id ( tech_pvt - > ftdm_channel ) ;
if ( status = = FTDM_FAIL ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Failed to read from channel %s device %d:%d! \n " , name , span_id , chan_id ) ;
goto fail ;
}
if ( status = = FTDM_TIMEOUT ) {
goto top ;
}
if ( ! ( wflags & FTDM_READ ) ) {
goto top ;
}
len = tech_pvt - > read_frame . buflen ;
if ( ftdm_channel_read ( tech_pvt - > ftdm_channel , tech_pvt - > read_frame . data , & len ) ! = FTDM_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Failed to read from channel %s device %d:%d! \n " , name , span_id , chan_id ) ;
}
* frame = & tech_pvt - > read_frame ;
tech_pvt - > read_frame . datalen = ( uint32_t ) len ;
tech_pvt - > read_frame . samples = tech_pvt - > read_frame . datalen ;
2012-07-25 21:16:46 -04:00
tech_pvt - > read_frame . codec = & tech_pvt - > read_codec ;
2012-06-20 12:30:08 -04:00
if ( ftdm_channel_get_codec ( tech_pvt - > ftdm_channel ) = = FTDM_CODEC_SLIN ) {
tech_pvt - > read_frame . samples / = 2 ;
}
while ( ftdm_channel_dequeue_dtmf ( tech_pvt - > ftdm_channel , dtmf , sizeof ( dtmf ) ) ) {
switch_dtmf_t _dtmf = { 0 , switch_core_default_dtmf_duration ( 0 ) } ;
char * p ;
for ( p = dtmf ; p & & * p ; p + + ) {
if ( is_dtmf ( * p ) ) {
_dtmf . digit = * p ;
ftdm_log ( FTDM_LOG_DEBUG , " Queuing DTMF [%c] in channel %s device %d:%d \n " , * p , name , span_id , chan_id ) ;
switch_channel_queue_dtmf ( channel , & _dtmf ) ;
}
}
}
return SWITCH_STATUS_SUCCESS ;
fail :
return SWITCH_STATUS_GENERR ;
}
static switch_status_t channel_write_frame ( switch_core_session_t * session , switch_frame_t * frame , switch_io_flag_t flags , int stream_id )
{
ftdm_wait_flag_t wflags = FTDM_WRITE ;
ctdm_private_t * tech_pvt ;
const char * name ;
switch_channel_t * channel ;
uint32_t span_id , chan_id ;
ftdm_size_t len ;
unsigned char data [ SWITCH_RECOMMENDED_BUFFER_SIZE ] = { 0 } ;
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
span_id = ftdm_channel_get_span_id ( tech_pvt - > ftdm_channel ) ;
chan_id = ftdm_channel_get_id ( tech_pvt - > ftdm_channel ) ;
name = switch_channel_get_name ( channel ) ;
if ( switch_test_flag ( frame , SFF_CNG ) ) {
frame - > data = data ;
frame - > buflen = sizeof ( data ) ;
if ( ( frame - > datalen = tech_pvt - > write_codec . implementation - > encoded_bytes_per_packet ) > frame - > buflen ) {
goto fail ;
}
memset ( data , 255 , frame - > datalen ) ;
}
wflags = FTDM_WRITE ;
ftdm_channel_wait ( tech_pvt - > ftdm_channel , & wflags , ftdm_channel_get_io_interval ( tech_pvt - > ftdm_channel ) * 10 ) ;
if ( ! ( wflags & FTDM_WRITE ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Dropping frame! (write not ready) in channel %s device %d:%d! \n " , name , span_id , chan_id ) ;
return SWITCH_STATUS_SUCCESS ;
}
len = frame - > datalen ;
if ( ftdm_channel_write ( tech_pvt - > ftdm_channel , frame - > data , frame - > buflen , & len ) ! = FTDM_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Failed to write to channel %s device %d:%d! \n " , name , span_id , chan_id ) ;
}
return SWITCH_STATUS_SUCCESS ;
fail :
return SWITCH_STATUS_GENERR ;
}
static switch_status_t channel_send_dtmf ( switch_core_session_t * session , const switch_dtmf_t * dtmf )
{
ctdm_private_t * tech_pvt = NULL ;
char tmp [ 2 ] = " " ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
tmp [ 0 ] = dtmf - > digit ;
ftdm_channel_command ( tech_pvt - > ftdm_channel , FTDM_COMMAND_SEND_DTMF , tmp ) ;
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t channel_receive_message ( switch_core_session_t * session , switch_core_session_message_t * msg )
{
return SWITCH_STATUS_SUCCESS ;
}
2012-08-14 16:22:31 -04:00
static switch_status_t channel_receive_event ( switch_core_session_t * session , switch_event_t * event )
{
const char * command = switch_event_get_header ( event , " command " ) ;
ctdm_private_t * tech_pvt = switch_core_session_get_private ( session ) ;
2012-08-16 01:28:32 -04:00
if ( ! zstr ( command ) ) {
2012-08-16 16:42:17 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " FreeTDM received %s command \n " , command ) ;
2012-08-16 01:28:32 -04:00
if ( ! strcasecmp ( command , kPREBUFFER_LEN ) ) {
const char * szval = switch_event_get_header ( event , kPREBUFFER_LEN ) ;
int val = ! zstr ( szval ) ? atoi ( szval ) : 0 ;
2012-08-14 16:22:31 -04:00
2012-08-16 01:28:32 -04:00
if ( tech_pvt - > prebuffer_len = = val ) {
tech_pvt - > prebuffer_len = val ;
if ( FTDM_SUCCESS ! = ftdm_channel_command ( tech_pvt - > ftdm_channel , FTDM_COMMAND_SET_PRE_BUFFER_SIZE , & tech_pvt - > prebuffer_len ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Failed to set channel pre buffer size. \n " ) ;
return SWITCH_STATUS_GENERR ;
}
}
} else if ( ! strcasecmp ( command , kECHOCANCEL ) ) {
const char * szval = switch_event_get_header ( event , kECHOCANCEL ) ;
int enabled = ! ! switch_true ( szval ) ;
2012-08-16 16:42:17 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " FreeTDM sending echo cancel [%s] command \n " , enabled ? " enable " : " disable " ) ;
2012-08-16 01:28:32 -04:00
if ( FTDM_SUCCESS ! = ftdm_channel_command ( tech_pvt - > ftdm_channel , enabled ? FTDM_COMMAND_ENABLE_ECHOCANCEL : FTDM_COMMAND_DISABLE_ECHOCANCEL , NULL ) ) {
2012-08-16 02:06:10 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Failed to %s echo cancellation. \n " , enabled ? " enable " : " disable " ) ;
2012-08-16 01:28:32 -04:00
}
2012-08-16 16:42:17 -04:00
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " FreeTDM received unknown command [%s] \n " , command ) ;
2012-08-16 01:28:32 -04:00
}
2012-08-14 16:22:31 -04:00
}
return SWITCH_STATUS_SUCCESS ;
}