2007-03-29 22:34:40 +00:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
2009-02-13 23:37:37 +00:00
* Copyright ( C ) 2005 - 2009 , Anthony Minessale II < anthm @ freeswitch . org >
2007-03-29 22:34:40 +00:00
*
* 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
2009-02-04 21:20:54 +00:00
* Anthony Minessale II < anthm @ freeswitch . org >
2007-03-29 22:34:40 +00:00
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
*
2009-02-04 21:20:54 +00:00
* Anthony Minessale II < anthm @ freeswitch . org >
2007-03-29 22:34:40 +00:00
* Michael Jerris < mike @ jerris . com >
2007-06-04 22:10:42 +00:00
* Bret McDanel < bret AT 0xdecafbad dot com >
2007-03-29 22:34:40 +00:00
*
* switch_ivr_async . c - - IVR Library ( async operations )
*
*/
2008-01-27 17:36:53 +00:00
2007-03-29 22:34:40 +00:00
# include <switch.h>
2009-09-23 22:39:00 +00:00
# include <speex/speex_preprocess.h>
# include <speex/speex_echo.h>
2007-03-29 22:34:40 +00:00
2008-02-05 21:09:52 +00:00
# ifdef SWITCH_VIDEO_IN_THREADS
2007-04-19 21:40:50 +00:00
struct echo_helper {
switch_core_session_t * session ;
int up ;
} ;
static void * SWITCH_THREAD_FUNC echo_video_thread ( switch_thread_t * thread , void * obj )
{
struct echo_helper * eh = obj ;
switch_core_session_t * session = eh - > session ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
switch_status_t status ;
switch_frame_t * read_frame ;
2008-05-27 04:30:03 +00:00
eh - > up = 1 ;
while ( switch_channel_ready ( channel ) ) {
2008-05-08 19:19:47 +00:00
status = switch_core_session_read_video_frame ( session , & read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2008-05-27 04:30:03 +00:00
2007-04-19 21:40:50 +00:00
if ( ! SWITCH_READ_ACCEPTABLE ( status ) ) {
break ;
}
2008-05-27 04:30:03 +00:00
2008-02-05 21:09:52 +00:00
if ( switch_test_flag ( read_frame , SFF_CNG ) ) {
continue ;
}
2008-05-08 19:19:47 +00:00
switch_core_session_write_video_frame ( session , read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2008-05-27 04:30:03 +00:00
2007-04-19 21:40:50 +00:00
}
eh - > up = 0 ;
return NULL ;
}
2008-02-05 21:09:52 +00:00
# endif
2007-04-19 21:40:50 +00:00
2008-09-25 19:53:43 +00:00
SWITCH_DECLARE ( void ) switch_ivr_session_echo ( switch_core_session_t * session , switch_input_args_t * args )
2007-04-19 21:40:50 +00:00
{
switch_status_t status ;
switch_frame_t * read_frame ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2008-02-05 21:09:52 +00:00
# ifdef SWITCH_VIDEO_IN_THREADS
2008-05-27 04:30:03 +00:00
struct echo_helper eh = { 0 } ;
2007-04-19 21:40:50 +00:00
switch_thread_t * thread ;
switch_threadattr_t * thd_attr = NULL ;
2008-02-05 21:09:52 +00:00
# endif
2007-04-19 21:40:50 +00:00
2009-02-10 19:09:06 +00:00
if ( switch_channel_pre_answer ( channel ) ! = SWITCH_STATUS_SUCCESS ) {
return ;
}
2008-05-27 04:30:03 +00:00
2008-02-05 21:09:52 +00:00
# ifdef SWITCH_VIDEO_IN_THREADS
2007-04-19 21:40:50 +00:00
if ( switch_channel_test_flag ( channel , CF_VIDEO ) ) {
eh . session = session ;
switch_threadattr_create ( & thd_attr , switch_core_session_get_pool ( session ) ) ;
switch_threadattr_detach_set ( thd_attr , 1 ) ;
switch_threadattr_stacksize_set ( thd_attr , SWITCH_THREAD_STACKSIZE ) ;
switch_thread_create ( & thread , thd_attr , echo_video_thread , & eh , switch_core_session_get_pool ( session ) ) ;
}
2008-02-05 21:09:52 +00:00
# endif
2007-04-19 21:40:50 +00:00
2008-05-27 04:30:03 +00:00
while ( switch_channel_ready ( channel ) ) {
2008-05-08 19:19:47 +00:00
status = switch_core_session_read_frame ( session , & read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2007-04-19 21:40:50 +00:00
if ( ! SWITCH_READ_ACCEPTABLE ( status ) ) {
break ;
}
2008-09-25 19:53:43 +00:00
2009-10-12 22:23:55 +00:00
switch_ivr_parse_all_events ( session ) ;
2008-09-25 19:53:43 +00:00
if ( args & & ( args - > input_callback | | args - > buf | | args - > buflen ) ) {
switch_dtmf_t dtmf ;
/*
dtmf handler function you can hook up to be executed when a digit is dialed during playback
if you return anything but SWITCH_STATUS_SUCCESS the playback will stop .
*/
if ( switch_channel_has_dtmf ( channel ) ) {
if ( ! args - > input_callback & & ! args - > buf ) {
status = SWITCH_STATUS_BREAK ;
break ;
}
switch_channel_dequeue_dtmf ( channel , & dtmf ) ;
if ( args - > input_callback ) {
status = args - > input_callback ( session , ( void * ) & dtmf , SWITCH_INPUT_TYPE_DTMF , args - > buf , args - > buflen ) ;
} else {
switch_copy_string ( ( char * ) args - > buf , ( void * ) & dtmf , args - > buflen ) ;
status = SWITCH_STATUS_BREAK ;
}
}
if ( args - > input_callback ) {
switch_event_t * event = NULL ;
2009-02-21 23:19:58 +00:00
if ( switch_core_session_dequeue_event ( session , & event , SWITCH_FALSE ) = = SWITCH_STATUS_SUCCESS ) {
2008-09-25 19:53:43 +00:00
status = args - > input_callback ( session , event , SWITCH_INPUT_TYPE_EVENT , args - > buf , args - > buflen ) ;
switch_event_destroy ( & event ) ;
}
}
if ( status ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
}
2008-05-08 19:19:47 +00:00
switch_core_session_write_frame ( session , read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2008-02-05 21:09:52 +00:00
# ifndef SWITCH_VIDEO_IN_THREADS
2008-05-08 19:19:47 +00:00
status = switch_core_session_read_video_frame ( session , & read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2008-05-27 04:30:03 +00:00
2008-02-05 21:09:52 +00:00
if ( ! SWITCH_READ_ACCEPTABLE ( status ) ) {
break ;
}
2008-05-27 04:30:03 +00:00
2008-02-05 21:09:52 +00:00
if ( switch_test_flag ( read_frame , SFF_CNG ) ) {
continue ;
}
2008-05-08 19:19:47 +00:00
switch_core_session_write_video_frame ( session , read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2008-02-05 21:09:52 +00:00
# endif
2007-04-19 21:40:50 +00:00
}
2008-02-05 21:09:52 +00:00
# ifdef SWITCH_VIDEO_IN_THREADS
2007-04-19 21:40:50 +00:00
if ( eh . up ) {
2008-05-27 04:30:03 +00:00
while ( eh . up ) {
2008-11-14 23:31:21 +00:00
switch_cond_next ( ) ;
2007-04-19 21:40:50 +00:00
}
}
2008-02-05 21:09:52 +00:00
# endif
2007-04-19 21:40:50 +00:00
}
2007-06-15 01:47:48 +00:00
typedef struct {
switch_file_handle_t fh ;
int mux ;
2008-01-03 21:34:44 +00:00
int loop ;
2008-07-16 13:35:42 +00:00
char * file ;
2007-06-15 01:47:48 +00:00
} displace_helper_t ;
2008-01-03 21:34:44 +00:00
static switch_bool_t write_displace_callback ( switch_media_bug_t * bug , void * user_data , switch_abc_type_t type )
2007-06-15 01:47:48 +00:00
{
displace_helper_t * dh = ( displace_helper_t * ) user_data ;
switch ( type ) {
case SWITCH_ABC_TYPE_INIT :
break ;
case SWITCH_ABC_TYPE_CLOSE :
if ( dh ) {
2009-03-03 16:55:07 +00:00
switch_core_session_t * session = switch_core_media_bug_get_session ( bug ) ;
switch_channel_t * channel ;
2007-06-15 01:47:48 +00:00
switch_core_file_close ( & dh - > fh ) ;
2009-03-03 16:55:07 +00:00
if ( session & & ( channel = switch_core_session_get_channel ( session ) ) ) {
2009-03-03 17:14:58 +00:00
switch_channel_set_private ( channel , dh - > file , NULL ) ;
2009-03-03 16:55:07 +00:00
}
2007-06-15 01:47:48 +00:00
}
break ;
case SWITCH_ABC_TYPE_READ_REPLACE :
{
2007-12-17 21:08:24 +00:00
switch_frame_t * rframe = switch_core_media_bug_get_read_replace_frame ( bug ) ;
2007-06-15 01:47:48 +00:00
if ( dh & & ! dh - > mux ) {
2007-12-17 21:08:24 +00:00
memset ( rframe - > data , 255 , rframe - > datalen ) ;
2007-06-15 01:47:48 +00:00
}
2007-12-17 21:08:24 +00:00
switch_core_media_bug_set_read_replace_frame ( bug , rframe ) ;
2007-06-15 01:47:48 +00:00
}
break ;
case SWITCH_ABC_TYPE_WRITE_REPLACE :
if ( dh ) {
2007-12-17 21:08:24 +00:00
switch_frame_t * rframe = NULL ;
2007-06-15 01:47:48 +00:00
switch_size_t len ;
2007-12-10 18:13:07 +00:00
switch_status_t st ;
2007-06-15 01:47:48 +00:00
2007-12-17 21:08:24 +00:00
rframe = switch_core_media_bug_get_write_replace_frame ( bug ) ;
len = rframe - > samples ;
2007-06-15 01:47:48 +00:00
if ( dh - > mux ) {
2008-02-14 17:12:17 +00:00
int16_t buf [ SWITCH_RECOMMENDED_BUFFER_SIZE / 2 ] ;
2007-12-17 21:08:24 +00:00
int16_t * fp = rframe - > data ;
2007-06-16 02:25:40 +00:00
uint32_t x ;
2007-12-10 18:13:07 +00:00
st = switch_core_file_read ( & dh - > fh , buf , & len ) ;
2008-05-27 04:30:03 +00:00
for ( x = 0 ; x < ( uint32_t ) len ; x + + ) {
2007-06-15 01:47:48 +00:00
int32_t mixed = fp [ x ] + buf [ x ] ;
switch_normalize_to_16bit ( mixed ) ;
fp [ x ] = ( int16_t ) mixed ;
}
} else {
2007-12-17 21:08:24 +00:00
st = switch_core_file_read ( & dh - > fh , rframe - > data , & len ) ;
rframe - > samples = ( uint32_t ) len ;
rframe - > datalen = rframe - > samples * 2 ;
2007-06-15 01:47:48 +00:00
}
2007-12-10 18:13:07 +00:00
if ( st ! = SWITCH_STATUS_SUCCESS | | len = = 0 ) {
2008-01-03 21:34:44 +00:00
if ( dh - > loop ) {
uint32_t pos = 0 ;
switch_core_file_seek ( & dh - > fh , & pos , 0 , SEEK_SET ) ;
} else {
2008-07-16 13:35:42 +00:00
switch_core_session_t * session = switch_core_media_bug_get_session ( bug ) ;
switch_channel_t * channel ;
if ( session & & ( channel = switch_core_session_get_channel ( session ) ) ) {
switch_channel_set_private ( channel , dh - > file , NULL ) ;
}
2008-01-03 21:34:44 +00:00
return SWITCH_FALSE ;
}
2007-12-10 18:13:07 +00:00
}
2007-12-17 21:08:24 +00:00
switch_core_media_bug_set_write_replace_frame ( bug , rframe ) ;
2007-06-15 01:47:48 +00:00
}
break ;
case SWITCH_ABC_TYPE_WRITE :
default :
break ;
}
return SWITCH_TRUE ;
}
2008-01-03 21:34:44 +00:00
static switch_bool_t read_displace_callback ( switch_media_bug_t * bug , void * user_data , switch_abc_type_t type )
{
displace_helper_t * dh = ( displace_helper_t * ) user_data ;
switch ( type ) {
case SWITCH_ABC_TYPE_INIT :
break ;
case SWITCH_ABC_TYPE_CLOSE :
if ( dh ) {
2009-03-03 16:55:07 +00:00
switch_core_session_t * session = switch_core_media_bug_get_session ( bug ) ;
switch_channel_t * channel ;
2008-01-03 21:34:44 +00:00
switch_core_file_close ( & dh - > fh ) ;
2009-03-03 16:55:07 +00:00
if ( session & & ( channel = switch_core_session_get_channel ( session ) ) ) {
2009-03-03 17:14:58 +00:00
switch_channel_set_private ( channel , dh - > file , NULL ) ;
2009-03-03 16:55:07 +00:00
}
2008-01-03 21:34:44 +00:00
}
break ;
case SWITCH_ABC_TYPE_WRITE_REPLACE :
{
switch_frame_t * rframe = switch_core_media_bug_get_write_replace_frame ( bug ) ;
if ( dh & & ! dh - > mux ) {
memset ( rframe - > data , 255 , rframe - > datalen ) ;
}
switch_core_media_bug_set_write_replace_frame ( bug , rframe ) ;
}
break ;
case SWITCH_ABC_TYPE_READ_REPLACE :
if ( dh ) {
switch_frame_t * rframe = NULL ;
switch_size_t len ;
switch_status_t st ;
rframe = switch_core_media_bug_get_read_replace_frame ( bug ) ;
len = rframe - > samples ;
if ( dh - > mux ) {
2008-02-14 17:12:17 +00:00
int16_t buf [ SWITCH_RECOMMENDED_BUFFER_SIZE / 2 ] ;
2008-01-03 21:34:44 +00:00
int16_t * fp = rframe - > data ;
uint32_t x ;
st = switch_core_file_read ( & dh - > fh , buf , & len ) ;
2008-05-27 04:30:03 +00:00
for ( x = 0 ; x < ( uint32_t ) len ; x + + ) {
2008-01-03 21:34:44 +00:00
int32_t mixed = fp [ x ] + buf [ x ] ;
switch_normalize_to_16bit ( mixed ) ;
fp [ x ] = ( int16_t ) mixed ;
}
} else {
st = switch_core_file_read ( & dh - > fh , rframe - > data , & len ) ;
rframe - > samples = ( uint32_t ) len ;
rframe - > datalen = rframe - > samples * 2 ;
}
if ( st ! = SWITCH_STATUS_SUCCESS | | len = = 0 ) {
if ( dh - > loop ) {
uint32_t pos = 0 ;
switch_core_file_seek ( & dh - > fh , & pos , 0 , SEEK_SET ) ;
} else {
2008-07-16 13:35:42 +00:00
switch_core_session_t * session = switch_core_media_bug_get_session ( bug ) ;
switch_channel_t * channel ;
if ( session & & ( channel = switch_core_session_get_channel ( session ) ) ) {
switch_channel_set_private ( channel , dh - > file , NULL ) ;
}
2008-01-03 21:34:44 +00:00
return SWITCH_FALSE ;
}
}
switch_core_media_bug_set_read_replace_frame ( bug , rframe ) ;
}
break ;
case SWITCH_ABC_TYPE_WRITE :
default :
break ;
}
return SWITCH_TRUE ;
}
2007-11-01 11:28:26 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_stop_displace_session ( switch_core_session_t * session , const char * file )
2007-06-15 01:47:48 +00:00
{
switch_media_bug_t * bug ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
if ( ( bug = switch_channel_get_private ( channel , file ) ) ) {
switch_channel_set_private ( channel , file , NULL ) ;
switch_core_media_bug_remove ( session , & bug ) ;
return SWITCH_STATUS_SUCCESS ;
}
return SWITCH_STATUS_FALSE ;
}
2008-01-03 21:34:44 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_displace_session ( switch_core_session_t * session , const char * file , uint32_t limit , const char * flags )
2007-06-15 01:47:48 +00:00
{
2008-01-28 07:26:10 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2007-06-15 01:47:48 +00:00
switch_media_bug_t * bug ;
switch_status_t status ;
time_t to = 0 ;
displace_helper_t * dh ;
2009-02-10 19:09:06 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
switch_core_session_get_read_impl ( session , & read_impl ) ;
if ( ( status = switch_channel_pre_answer ( channel ) ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_FALSE ;
}
2008-09-27 08:52:13 +00:00
if ( ! switch_channel_media_ready ( channel ) | | ! switch_core_session_get_read_codec ( session ) ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Can not displace session. Media not enabled on channel \n " ) ;
2008-09-27 18:49:21 +00:00
return SWITCH_STATUS_FALSE ;
2008-09-27 08:52:13 +00:00
}
2007-06-15 01:47:48 +00:00
if ( ( bug = switch_channel_get_private ( channel , file ) ) ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Only 1 of the same file per channel please! \n " ) ;
2007-06-15 01:47:48 +00:00
return SWITCH_STATUS_FALSE ;
}
if ( ! ( dh = switch_core_session_alloc ( session , sizeof ( * dh ) ) ) ) {
return SWITCH_STATUS_MEMERR ;
}
2008-05-27 04:30:03 +00:00
2009-02-10 19:09:06 +00:00
dh - > fh . channels = read_impl . number_of_channels ;
dh - > fh . samplerate = read_impl . actual_samples_per_second ;
2008-07-16 13:35:42 +00:00
dh - > file = switch_core_session_strdup ( session , file ) ;
2008-05-27 04:30:03 +00:00
2007-06-15 01:47:48 +00:00
if ( switch_core_file_open ( & dh - > fh ,
file ,
2009-02-10 19:09:06 +00:00
read_impl . number_of_channels ,
read_impl . actual_samples_per_second ,
2008-05-27 04:30:03 +00:00
SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT , NULL ) ! = SWITCH_STATUS_SUCCESS ) {
2007-06-15 01:47:48 +00:00
switch_channel_hangup ( channel , SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ) ;
2009-01-09 20:34:01 +00:00
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_TRUE ) ;
2007-06-15 01:47:48 +00:00
return SWITCH_STATUS_GENERR ;
}
if ( limit ) {
2009-01-25 21:23:07 +00:00
to = switch_epoch_time_now ( NULL ) + limit ;
2007-06-15 01:47:48 +00:00
}
if ( flags & & strchr ( flags , ' m ' ) ) {
dh - > mux + + ;
}
2008-01-03 21:34:44 +00:00
if ( flags & & strchr ( flags , ' l ' ) ) {
dh - > loop + + ;
}
2008-05-27 04:30:03 +00:00
2008-01-03 21:34:44 +00:00
if ( flags & & strchr ( flags , ' r ' ) ) {
status = switch_core_media_bug_add ( session , read_displace_callback , dh , to , SMBF_WRITE_REPLACE | SMBF_READ_REPLACE , & bug ) ;
} else {
status = switch_core_media_bug_add ( session , write_displace_callback , dh , to , SMBF_WRITE_REPLACE | SMBF_READ_REPLACE , & bug ) ;
}
2008-05-27 04:30:03 +00:00
2008-01-03 21:34:44 +00:00
if ( status ! = SWITCH_STATUS_SUCCESS ) {
2007-06-15 01:47:48 +00:00
switch_core_file_close ( & dh - > fh ) ;
return status ;
}
switch_channel_set_private ( channel , file , bug ) ;
return SWITCH_STATUS_SUCCESS ;
}
2009-07-06 22:21:45 +00:00
2009-03-05 01:15:17 +00:00
struct record_helper {
char * file ;
switch_file_handle_t * fh ;
2009-07-06 22:21:45 +00:00
uint32_t packet_len ;
2009-10-29 15:29:33 +00:00
int min_sec ;
2009-03-05 01:15:17 +00:00
} ;
2007-03-29 22:34:40 +00:00
static switch_bool_t record_callback ( switch_media_bug_t * bug , void * user_data , switch_abc_type_t type )
{
2009-03-05 01:15:17 +00:00
switch_core_session_t * session = switch_core_media_bug_get_session ( bug ) ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
struct record_helper * rh = ( struct record_helper * ) user_data ;
2009-08-21 22:29:44 +00:00
switch_event_t * event ;
2007-03-29 22:34:40 +00:00
switch ( type ) {
case SWITCH_ABC_TYPE_INIT :
2009-08-21 22:29:44 +00:00
if ( switch_event_create ( & event , SWITCH_EVENT_RECORD_START ) = = SWITCH_STATUS_SUCCESS ) {
2009-08-22 01:45:03 +00:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Record-File-Path " , rh - > file ) ;
2009-08-21 22:29:44 +00:00
switch_channel_event_set_data ( channel , event ) ;
switch_event_fire ( & event ) ;
}
2007-03-29 22:34:40 +00:00
break ;
case SWITCH_ABC_TYPE_CLOSE :
2009-03-20 13:58:45 +00:00
{
switch_codec_implementation_t read_impl = { 0 } ;
switch_core_session_get_read_impl ( session , & read_impl ) ;
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Stop recording file %s \n " , rh - > file ) ;
2009-03-20 13:58:45 +00:00
switch_channel_set_private ( channel , rh - > file , NULL ) ;
2009-08-21 22:29:44 +00:00
if ( switch_event_create ( & event , SWITCH_EVENT_RECORD_STOP ) = = SWITCH_STATUS_SUCCESS ) {
switch_channel_event_set_data ( channel , event ) ;
2009-08-22 01:45:03 +00:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Record-File-Path " , rh - > file ) ;
2009-08-21 22:29:44 +00:00
switch_event_fire ( & event ) ;
}
2009-03-20 13:58:45 +00:00
if ( rh - > fh ) {
2009-10-26 21:59:25 +00:00
switch_size_t len ;
uint8_t data [ SWITCH_RECOMMENDED_BUFFER_SIZE ] ;
switch_frame_t frame = { 0 } ;
2009-07-06 22:21:45 +00:00
2009-10-26 21:59:25 +00:00
frame . data = data ;
frame . buflen = SWITCH_RECOMMENDED_BUFFER_SIZE ;
2009-06-05 19:52:02 +00:00
2009-10-26 21:59:25 +00:00
while ( switch_core_media_bug_read ( bug , & frame , SWITCH_TRUE ) = = SWITCH_STATUS_SUCCESS & & ! switch_test_flag ( ( & frame ) , SFF_CNG ) ) {
len = ( switch_size_t ) frame . datalen / 2 ;
if ( len ) switch_core_file_write ( rh - > fh , data , & len ) ;
2009-06-05 19:52:02 +00:00
}
2009-10-26 21:59:25 +00:00
2009-06-05 19:52:02 +00:00
2009-03-20 13:58:45 +00:00
switch_core_file_close ( rh - > fh ) ;
2009-11-06 23:29:36 +00:00
if ( rh - > fh - > samples_out < rh - > fh - > samplerate * rh - > min_sec ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Discarding short file %s \n " , rh - > file ) ;
2009-03-20 22:49:01 +00:00
switch_file_remove ( rh - > file , switch_core_session_get_pool ( session ) ) ;
}
2009-03-20 13:58:45 +00:00
}
2007-03-29 22:34:40 +00:00
}
2009-03-20 13:58:45 +00:00
2007-03-29 22:34:40 +00:00
break ;
2009-07-06 22:21:45 +00:00
case SWITCH_ABC_TYPE_READ :
2009-03-05 01:15:17 +00:00
if ( rh - > fh ) {
2007-03-29 22:34:40 +00:00
switch_size_t len ;
2009-03-02 19:30:41 +00:00
uint8_t data [ SWITCH_RECOMMENDED_BUFFER_SIZE ] ;
switch_frame_t frame = { 0 } ;
2009-07-06 22:21:45 +00:00
2009-03-02 19:30:41 +00:00
frame . data = data ;
frame . buflen = SWITCH_RECOMMENDED_BUFFER_SIZE ;
2009-07-06 22:21:45 +00:00
2009-10-26 21:59:25 +00:00
while ( switch_core_media_bug_read ( bug , & frame , SWITCH_TRUE ) = = SWITCH_STATUS_SUCCESS & & ! switch_test_flag ( ( & frame ) , SFF_CNG ) ) {
len = ( switch_size_t ) frame . datalen / 2 ;
if ( len ) switch_core_file_write ( rh - > fh , data , & len ) ;
2007-03-29 22:34:40 +00:00
}
2009-10-26 21:59:25 +00:00
2007-03-29 22:34:40 +00:00
}
break ;
case SWITCH_ABC_TYPE_WRITE :
default :
break ;
}
return SWITCH_TRUE ;
}
2007-11-01 11:28:26 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_stop_record_session ( switch_core_session_t * session , const char * file )
2007-03-29 22:34:40 +00:00
{
switch_media_bug_t * bug ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2009-03-05 01:15:17 +00:00
if ( ! strcasecmp ( file , " all " ) ) {
return switch_core_media_bug_remove_callback ( session , record_callback ) ;
} else if ( ( bug = switch_channel_get_private ( channel , file ) ) ) {
2007-03-29 22:34:40 +00:00
switch_core_media_bug_remove ( session , & bug ) ;
return SWITCH_STATUS_SUCCESS ;
}
return SWITCH_STATUS_FALSE ;
}
2007-11-30 22:56:01 +00:00
struct eavesdrop_pvt {
switch_buffer_t * buffer ;
switch_mutex_t * mutex ;
switch_buffer_t * r_buffer ;
switch_mutex_t * r_mutex ;
switch_buffer_t * w_buffer ;
switch_mutex_t * w_mutex ;
uint32_t flags ;
} ;
static switch_bool_t eavesdrop_callback ( switch_media_bug_t * bug , void * user_data , switch_abc_type_t type )
{
struct eavesdrop_pvt * ep = ( struct eavesdrop_pvt * ) user_data ;
uint8_t data [ SWITCH_RECOMMENDED_BUFFER_SIZE ] ;
switch_frame_t frame = { 0 } ;
2009-03-02 19:30:41 +00:00
2007-11-30 22:56:01 +00:00
frame . data = data ;
frame . buflen = SWITCH_RECOMMENDED_BUFFER_SIZE ;
switch ( type ) {
case SWITCH_ABC_TYPE_INIT :
break ;
case SWITCH_ABC_TYPE_CLOSE :
break ;
case SWITCH_ABC_TYPE_WRITE :
2007-12-06 22:54:40 +00:00
break ;
case SWITCH_ABC_TYPE_READ_PING :
2009-03-02 19:30:41 +00:00
if ( ep - > buffer ) {
2009-06-05 19:52:02 +00:00
if ( switch_core_media_bug_read ( bug , & frame , SWITCH_TRUE ) = = SWITCH_STATUS_SUCCESS ) {
2008-05-27 04:30:03 +00:00
switch_buffer_lock ( ep - > buffer ) ;
2008-01-14 19:20:59 +00:00
switch_buffer_zwrite ( ep - > buffer , frame . data , frame . datalen ) ;
2008-05-27 04:30:03 +00:00
switch_buffer_unlock ( ep - > buffer ) ;
2007-11-30 22:56:01 +00:00
}
} else {
2008-05-27 04:30:03 +00:00
return SWITCH_FALSE ;
}
2007-11-30 22:56:01 +00:00
break ;
case SWITCH_ABC_TYPE_READ :
break ;
case SWITCH_ABC_TYPE_READ_REPLACE :
{
2008-01-14 19:20:59 +00:00
2007-11-30 22:56:01 +00:00
if ( switch_test_flag ( ep , ED_MUX_READ ) ) {
2007-12-17 21:08:24 +00:00
switch_frame_t * rframe = switch_core_media_bug_get_read_replace_frame ( bug ) ;
2008-05-27 04:30:03 +00:00
2007-12-17 21:08:24 +00:00
if ( switch_buffer_inuse ( ep - > r_buffer ) > = rframe - > datalen ) {
2007-11-30 22:56:01 +00:00
uint32_t bytes ;
switch_buffer_lock ( ep - > r_buffer ) ;
2007-12-17 21:08:24 +00:00
bytes = ( uint32_t ) switch_buffer_read ( ep - > r_buffer , data , rframe - > datalen ) ;
2008-05-27 04:30:03 +00:00
rframe - > datalen = switch_merge_sln ( rframe - > data , rframe - > samples , ( int16_t * ) data , bytes / 2 ) * 2 ;
2007-12-17 21:08:24 +00:00
rframe - > samples = rframe - > datalen / 2 ;
2008-05-27 04:30:03 +00:00
2007-11-30 22:56:01 +00:00
switch_buffer_unlock ( ep - > r_buffer ) ;
2007-12-17 21:08:24 +00:00
switch_core_media_bug_set_read_replace_frame ( bug , rframe ) ;
2007-11-30 22:56:01 +00:00
}
}
}
break ;
case SWITCH_ABC_TYPE_WRITE_REPLACE :
{
if ( switch_test_flag ( ep , ED_MUX_WRITE ) ) {
2007-12-17 21:08:24 +00:00
switch_frame_t * rframe = switch_core_media_bug_get_write_replace_frame ( bug ) ;
2008-05-27 04:30:03 +00:00
2007-12-17 21:08:24 +00:00
if ( switch_buffer_inuse ( ep - > w_buffer ) > = rframe - > datalen ) {
2007-11-30 22:56:01 +00:00
uint32_t bytes ;
switch_buffer_lock ( ep - > w_buffer ) ;
2007-12-17 21:08:24 +00:00
bytes = ( uint32_t ) switch_buffer_read ( ep - > w_buffer , data , rframe - > datalen ) ;
2008-05-27 04:30:03 +00:00
rframe - > datalen = switch_merge_sln ( rframe - > data , rframe - > samples , ( int16_t * ) data , bytes / 2 ) * 2 ;
2007-12-17 21:08:24 +00:00
rframe - > samples = rframe - > datalen / 2 ;
2008-05-27 04:30:03 +00:00
2007-11-30 22:56:01 +00:00
switch_buffer_unlock ( ep - > w_buffer ) ;
2007-12-17 21:08:24 +00:00
switch_core_media_bug_set_write_replace_frame ( bug , rframe ) ;
2007-11-30 22:56:01 +00:00
}
}
}
break ;
default :
break ;
}
return SWITCH_TRUE ;
}
2008-05-27 04:30:03 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_eavesdrop_session ( switch_core_session_t * session ,
const char * uuid , const char * require_group , switch_eavesdrop_flag_t flags )
2007-11-30 22:56:01 +00:00
{
switch_core_session_t * tsession ;
switch_status_t status = SWITCH_STATUS_FALSE ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2008-07-01 17:45:35 +00:00
int codec_initialized = 0 ;
2008-01-14 19:20:59 +00:00
2007-11-30 22:56:01 +00:00
if ( ( tsession = switch_core_session_locate ( uuid ) ) ) {
2008-04-11 22:35:30 +00:00
struct eavesdrop_pvt * ep = NULL ;
2007-11-30 22:56:01 +00:00
switch_media_bug_t * bug = NULL ;
switch_channel_t * tchannel = switch_core_session_get_channel ( tsession ) ;
switch_frame_t * read_frame , write_frame = { 0 } ;
2008-05-27 04:30:03 +00:00
switch_codec_t codec = { 0 } ;
int16_t buf [ SWITCH_RECOMMENDED_BUFFER_SIZE / 2 ] ;
2008-04-11 22:35:30 +00:00
uint32_t tlen ;
2008-04-12 16:17:09 +00:00
const char * macro_name = " eavesdrop_announce " ;
const char * id_name = NULL ;
2009-02-10 00:58:54 +00:00
switch_codec_implementation_t tread_impl = { 0 } , read_impl = { 0 } ;
2009-11-23 23:07:41 +00:00
switch_core_session_message_t msg = { 0 } ;
2009-02-10 00:58:54 +00:00
2008-04-11 22:35:30 +00:00
if ( ! switch_channel_media_ready ( channel ) ) {
goto end ;
}
2008-01-21 17:14:43 +00:00
2008-04-12 16:17:09 +00:00
if ( ! switch_channel_media_ready ( tchannel ) ) {
goto end ;
}
2009-02-10 00:58:54 +00:00
switch_core_session_get_read_impl ( tsession , & tread_impl ) ;
switch_core_session_get_read_impl ( session , & read_impl ) ;
2008-04-12 16:17:09 +00:00
if ( ( id_name = switch_channel_get_variable ( tchannel , " eavesdrop_announce_id " ) ) ) {
const char * tmp = switch_channel_get_variable ( tchannel , " eavesdrop_annnounce_macro " ) ;
if ( tmp ) {
macro_name = tmp ;
}
switch_ivr_phrase_macro ( session , macro_name , id_name , NULL , NULL ) ;
}
2009-10-23 16:03:42 +00:00
if ( ! zstr ( require_group ) ) {
2008-07-01 17:49:01 +00:00
int argc , i ;
int ok = 0 ;
char * argv [ 10 ] = { 0 } ;
char * data ;
2008-05-27 04:30:03 +00:00
const char * group_name = switch_channel_get_variable ( tchannel , " eavesdrop_group " ) ;
2008-07-01 17:49:01 +00:00
/* If we don't have a group, then return */
if ( ! group_name ) {
status = SWITCH_STATUS_BREAK ;
goto end ;
}
/* Separate the group */
data = strdup ( group_name ) ;
if ( ( argc = switch_separate_string ( data , ' , ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) ) {
for ( i = 0 ; i < argc ; i + + ) {
/* If one of the group matches, then ok */
2008-07-03 23:37:19 +00:00
if ( argv [ i ] & & ! strcmp ( argv [ i ] , require_group ) ) {
2008-07-01 17:49:01 +00:00
ok = 1 ;
}
}
}
switch_safe_free ( data ) ;
/* If we didn't find any match, then end */
if ( ! ok ) {
2008-04-12 16:17:09 +00:00
status = SWITCH_STATUS_BREAK ;
goto end ;
}
}
2008-05-27 04:30:03 +00:00
2008-01-14 19:20:59 +00:00
ep = switch_core_session_alloc ( session , sizeof ( * ep ) ) ;
2009-02-10 00:58:54 +00:00
tlen = tread_impl . decoded_bytes_per_packet ;
2008-04-11 22:35:30 +00:00
2009-02-10 19:09:06 +00:00
if ( switch_channel_pre_answer ( channel ) ! = SWITCH_STATUS_SUCCESS ) {
goto end ;
}
2008-05-27 04:30:03 +00:00
2007-11-30 22:56:01 +00:00
if ( switch_core_codec_init ( & codec ,
" L16 " ,
2008-05-27 04:30:03 +00:00
NULL ,
2009-02-10 00:58:54 +00:00
tread_impl . actual_samples_per_second ,
tread_impl . microseconds_per_packet / 1000 ,
tread_impl . number_of_channels ,
2008-05-27 04:30:03 +00:00
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE ,
2007-11-30 22:56:01 +00:00
NULL , switch_core_session_get_pool ( session ) ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Cannot init codec \n " ) ;
2008-03-06 19:51:11 +00:00
switch_core_session_rwunlock ( tsession ) ;
2008-04-11 22:35:30 +00:00
goto end ;
2007-11-30 22:56:01 +00:00
}
2008-05-27 04:30:03 +00:00
2008-07-01 17:45:35 +00:00
codec_initialized = 1 ;
2007-11-30 22:56:01 +00:00
switch_core_session_set_read_codec ( session , & codec ) ;
write_frame . codec = & codec ;
write_frame . data = buf ;
write_frame . buflen = sizeof ( buf ) ;
2009-02-10 00:58:54 +00:00
write_frame . rate = codec . implementation - > actual_samples_per_second ;
2008-05-27 04:30:03 +00:00
2008-01-14 19:20:59 +00:00
ep - > flags = flags ;
switch_mutex_init ( & ep - > mutex , SWITCH_MUTEX_NESTED , switch_core_session_get_pool ( tsession ) ) ;
switch_buffer_create_dynamic ( & ep - > buffer , 2048 , 2048 , 8192 ) ;
switch_buffer_add_mutex ( ep - > buffer , ep - > mutex ) ;
2007-11-30 22:56:01 +00:00
2008-01-14 19:20:59 +00:00
switch_mutex_init ( & ep - > w_mutex , SWITCH_MUTEX_NESTED , switch_core_session_get_pool ( tsession ) ) ;
switch_buffer_create_dynamic ( & ep - > w_buffer , 2048 , 2048 , 8192 ) ;
switch_buffer_add_mutex ( ep - > w_buffer , ep - > w_mutex ) ;
2007-11-30 22:56:01 +00:00
2008-01-14 19:20:59 +00:00
switch_mutex_init ( & ep - > r_mutex , SWITCH_MUTEX_NESTED , switch_core_session_get_pool ( tsession ) ) ;
switch_buffer_create_dynamic ( & ep - > r_buffer , 2048 , 2048 , 8192 ) ;
switch_buffer_add_mutex ( ep - > r_buffer , ep - > r_mutex ) ;
2007-11-30 22:56:01 +00:00
2008-05-27 04:30:03 +00:00
if ( switch_core_media_bug_add ( tsession , eavesdrop_callback , ep , 0 ,
2008-01-21 17:14:43 +00:00
SMBF_READ_STREAM | SMBF_WRITE_STREAM | SMBF_READ_REPLACE | SMBF_WRITE_REPLACE | SMBF_READ_PING | SMBF_THREAD_LOCK ,
2007-11-30 22:56:01 +00:00
& bug ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Cannot attach bug \n " ) ;
2007-11-30 22:56:01 +00:00
goto end ;
}
2008-05-27 04:30:03 +00:00
2009-11-23 23:07:41 +00:00
msg . from = __FILE__ ;
/* Tell the channel we are going to be in a bridge */
msg . message_id = SWITCH_MESSAGE_INDICATE_BRIDGE ;
switch_core_session_receive_message ( session , & msg ) ;
2008-05-27 04:30:03 +00:00
while ( switch_channel_ready ( tchannel ) & & switch_channel_ready ( channel ) ) {
2007-11-30 22:56:01 +00:00
uint32_t len = sizeof ( buf ) ;
switch_event_t * event = NULL ;
char * fcommand = NULL ;
2008-01-14 19:20:59 +00:00
char db [ 2 ] = " " ;
2008-05-08 19:19:47 +00:00
status = switch_core_session_read_frame ( session , & read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2008-05-27 04:30:03 +00:00
2007-11-30 22:56:01 +00:00
if ( ! SWITCH_READ_ACCEPTABLE ( status ) ) {
2009-11-23 23:07:41 +00:00
goto end_loop ;
2007-11-30 22:56:01 +00:00
}
2009-02-21 23:19:58 +00:00
if ( switch_core_session_dequeue_event ( session , & event , SWITCH_FALSE ) = = SWITCH_STATUS_SUCCESS ) {
2007-11-30 22:56:01 +00:00
char * command = switch_event_get_header ( event , " eavesdrop-command " ) ;
if ( command ) {
2009-10-19 15:32:12 +00:00
fcommand = switch_core_session_strdup ( session , command ) ;
2007-11-30 22:56:01 +00:00
}
switch_event_destroy ( & event ) ;
}
if ( ( flags & ED_DTMF ) & & switch_channel_has_dtmf ( channel ) ) {
2008-05-27 04:30:03 +00:00
switch_dtmf_t dtmf = { 0 } ;
2007-12-22 00:32:20 +00:00
switch_channel_dequeue_dtmf ( channel , & dtmf ) ;
2008-01-14 19:20:59 +00:00
db [ 0 ] = dtmf . digit ;
fcommand = db ;
2007-11-30 22:56:01 +00:00
}
if ( fcommand ) {
char * d ;
2008-05-27 04:30:03 +00:00
for ( d = fcommand ; * d ; d + + ) {
2007-11-30 22:56:01 +00:00
int z = 1 ;
2008-05-27 04:30:03 +00:00
2007-11-30 22:56:01 +00:00
switch ( * d ) {
case ' 1 ' :
2008-01-14 19:20:59 +00:00
switch_set_flag ( ep , ED_MUX_READ ) ;
switch_clear_flag ( ep , ED_MUX_WRITE ) ;
2007-11-30 22:56:01 +00:00
break ;
case ' 2 ' :
2008-01-14 19:20:59 +00:00
switch_set_flag ( ep , ED_MUX_WRITE ) ;
switch_clear_flag ( ep , ED_MUX_READ ) ;
2007-11-30 22:56:01 +00:00
break ;
case ' 3 ' :
2008-01-14 19:20:59 +00:00
switch_set_flag ( ep , ED_MUX_READ ) ;
switch_set_flag ( ep , ED_MUX_WRITE ) ;
2007-11-30 22:56:01 +00:00
break ;
case ' 0 ' :
2008-01-14 19:20:59 +00:00
switch_clear_flag ( ep , ED_MUX_READ ) ;
switch_clear_flag ( ep , ED_MUX_WRITE ) ;
2007-11-30 22:56:01 +00:00
break ;
2008-04-11 22:35:30 +00:00
case ' * ' :
2009-11-23 23:07:41 +00:00
goto end_loop ;
2007-11-30 22:56:01 +00:00
default :
z = 0 ;
break ;
}
2008-05-27 04:30:03 +00:00
2007-11-30 22:56:01 +00:00
if ( z ) {
2008-01-14 19:20:59 +00:00
if ( ep - > r_buffer ) {
switch_buffer_lock ( ep - > r_buffer ) ;
switch_buffer_zero ( ep - > r_buffer ) ;
switch_buffer_unlock ( ep - > r_buffer ) ;
}
2009-02-10 00:58:54 +00:00
2008-01-14 19:20:59 +00:00
if ( ep - > w_buffer ) {
switch_buffer_lock ( ep - > w_buffer ) ;
switch_buffer_zero ( ep - > w_buffer ) ;
switch_buffer_unlock ( ep - > w_buffer ) ;
}
2007-11-30 22:56:01 +00:00
}
}
}
if ( ! switch_test_flag ( read_frame , SFF_CNG ) ) {
2008-01-14 19:20:59 +00:00
switch_buffer_lock ( ep - > r_buffer ) ;
switch_buffer_zwrite ( ep - > r_buffer , read_frame - > data , read_frame - > datalen ) ;
switch_buffer_unlock ( ep - > r_buffer ) ;
2007-11-30 22:56:01 +00:00
2008-01-14 19:20:59 +00:00
switch_buffer_lock ( ep - > w_buffer ) ;
switch_buffer_zwrite ( ep - > w_buffer , read_frame - > data , read_frame - > datalen ) ;
switch_buffer_unlock ( ep - > w_buffer ) ;
2007-11-30 22:56:01 +00:00
}
2008-01-21 17:14:43 +00:00
if ( len > tlen ) {
len = tlen ;
2007-11-30 22:56:01 +00:00
}
2008-01-21 17:14:43 +00:00
2008-05-27 04:30:03 +00:00
if ( switch_buffer_inuse ( ep - > buffer ) > = len ) {
switch_buffer_lock ( ep - > buffer ) ;
2008-01-14 19:20:59 +00:00
while ( switch_buffer_inuse ( ep - > buffer ) > = len ) {
2008-05-27 04:30:03 +00:00
write_frame . datalen = ( uint32_t ) switch_buffer_read ( ep - > buffer , buf , len ) ;
2008-01-14 19:20:59 +00:00
write_frame . samples = write_frame . datalen / 2 ;
2009-02-10 00:58:54 +00:00
2008-05-08 19:19:47 +00:00
if ( ( status = switch_core_session_write_frame ( session , & write_frame , SWITCH_IO_FLAG_NONE , 0 ) ) ! = SWITCH_STATUS_SUCCESS ) {
2008-01-14 19:20:59 +00:00
break ;
}
2007-11-30 22:56:01 +00:00
}
2008-05-27 04:30:03 +00:00
switch_buffer_unlock ( ep - > buffer ) ;
}
}
2007-11-30 22:56:01 +00:00
2009-11-23 23:07:41 +00:00
end_loop :
/* Tell the channel we are no longer going to be in a bridge */
msg . message_id = SWITCH_MESSAGE_INDICATE_UNBRIDGE ;
switch_core_session_receive_message ( session , & msg ) ;
2008-05-27 04:30:03 +00:00
end :
2009-11-23 23:07:41 +00:00
2008-07-01 17:45:35 +00:00
if ( codec_initialized )
switch_core_codec_destroy ( & codec ) ;
2007-11-30 22:56:01 +00:00
2008-05-27 04:30:03 +00:00
if ( bug ) {
switch_core_media_bug_remove ( tsession , & bug ) ;
}
2007-11-30 22:56:01 +00:00
2008-04-11 22:35:30 +00:00
if ( ep ) {
if ( ep - > buffer ) {
switch_buffer_destroy ( & ep - > buffer ) ;
}
2008-05-27 04:30:03 +00:00
2008-04-11 22:35:30 +00:00
if ( ep - > r_buffer ) {
switch_buffer_destroy ( & ep - > r_buffer ) ;
}
2008-05-27 04:30:03 +00:00
2008-04-11 22:35:30 +00:00
if ( ep - > w_buffer ) {
switch_buffer_destroy ( & ep - > w_buffer ) ;
}
}
2007-11-30 22:56:01 +00:00
2008-05-27 04:30:03 +00:00
switch_core_session_rwunlock ( tsession ) ;
2007-11-30 22:56:01 +00:00
status = SWITCH_STATUS_SUCCESS ;
2009-01-09 20:34:01 +00:00
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_TRUE ) ;
2008-05-27 04:30:03 +00:00
}
2007-11-30 22:56:01 +00:00
return status ;
}
2007-05-31 14:42:23 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_record_session ( switch_core_session_t * session , char * file , uint32_t limit , switch_file_handle_t * fh )
2007-03-29 22:34:40 +00:00
{
2008-01-28 07:26:10 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2007-11-01 11:28:26 +00:00
const char * p ;
2007-03-29 22:34:40 +00:00
const char * vval ;
switch_media_bug_t * bug ;
switch_status_t status ;
2007-05-31 14:42:23 +00:00
time_t to = 0 ;
2009-03-02 19:30:41 +00:00
switch_media_bug_flag_t flags = SMBF_READ_STREAM | SMBF_WRITE_STREAM | SMBF_READ_PING ;
2008-09-27 08:52:13 +00:00
uint8_t channels ;
2009-02-10 19:09:06 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
2009-03-05 01:15:17 +00:00
struct record_helper * rh = NULL ;
2009-11-17 21:40:09 +00:00
int file_flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT ;
2009-11-23 17:54:08 +00:00
switch_core_session_get_read_impl ( session , & read_impl ) ;
2008-09-27 08:52:13 +00:00
2009-02-10 19:09:06 +00:00
if ( ( status = switch_channel_pre_answer ( channel ) ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_FALSE ;
}
2008-09-27 08:52:13 +00:00
if ( ! switch_channel_media_ready ( channel ) | | ! switch_core_session_get_read_codec ( session ) ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Can not record session. Media not enabled on channel \n " ) ;
2008-09-27 18:49:21 +00:00
return SWITCH_STATUS_FALSE ;
2008-09-27 08:52:13 +00:00
}
2009-02-10 19:09:06 +00:00
channels = read_impl . number_of_channels ;
2009-07-06 22:21:45 +00:00
2007-06-15 01:47:48 +00:00
if ( ( bug = switch_channel_get_private ( channel , file ) ) ) {
2008-03-11 22:41:49 +00:00
return switch_ivr_stop_record_session ( session , file ) ;
2007-06-15 01:47:48 +00:00
}
2007-03-29 22:34:40 +00:00
if ( ! fh ) {
if ( ! ( fh = switch_core_session_alloc ( session , sizeof ( * fh ) ) ) ) {
return SWITCH_STATUS_MEMERR ;
}
}
2009-10-27 22:04:44 +00:00
if ( ( p = switch_channel_get_variable ( channel , " RECORD_WRITE_ONLY " ) ) & & switch_true ( p ) ) {
flags & = ~ SMBF_READ_STREAM ;
flags | = SMBF_WRITE_STREAM ;
}
if ( ( p = switch_channel_get_variable ( channel , " RECORD_READ_ONLY " ) ) & & switch_true ( p ) ) {
flags & = ~ SMBF_WRITE_STREAM ;
flags | = SMBF_READ_STREAM ;
}
2007-10-01 16:34:28 +00:00
if ( ( p = switch_channel_get_variable ( channel , " RECORD_STEREO " ) ) & & switch_true ( p ) ) {
flags | = SMBF_STEREO ;
channels = 2 ;
}
2009-07-06 22:21:45 +00:00
2007-11-23 18:35:38 +00:00
if ( ( p = switch_channel_get_variable ( channel , " RECORD_ANSWER_REQ " ) ) & & switch_true ( p ) ) {
2009-10-26 21:59:25 +00:00
flags | = SMBF_ANSWER_REQ ;
2007-11-23 18:35:38 +00:00
}
2008-05-27 04:30:03 +00:00
2009-11-17 21:40:09 +00:00
if ( ( p = switch_channel_get_variable ( channel , " RECORD_APPEND " ) ) & & switch_true ( p ) ) {
file_flags | = SWITCH_FILE_WRITE_APPEND ;
}
2009-07-17 20:42:24 +00:00
fh - > samplerate = 0 ;
if ( ( vval = switch_channel_get_variable ( channel , " record_sample_rate " ) ) ) {
int tmp = 0 ;
tmp = atoi ( vval ) ;
if ( switch_is_valid_rate ( tmp ) ) {
fh - > samplerate = tmp ;
}
}
if ( ! fh - > samplerate ) {
fh - > samplerate = read_impl . actual_samples_per_second ;
}
2007-10-01 16:34:28 +00:00
fh - > channels = channels ;
2009-01-09 20:34:01 +00:00
fh - > pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN ;
2007-03-29 22:34:40 +00:00
2009-09-16 20:46:36 +00:00
if ( ! switch_is_file_path ( file ) ) {
char * tfile = NULL ;
char * e ;
const char * prefix ;
prefix = switch_channel_get_variable ( channel , " sound_prefix " ) ;
if ( ! prefix ) {
prefix = SWITCH_GLOBAL_dirs . base_dir ;
}
if ( * file = = ' [ ' ) {
tfile = switch_core_session_strdup ( session , file ) ;
if ( ( e = switch_find_end_paren ( tfile , ' [ ' , ' ] ' ) ) ) {
* e = ' \0 ' ;
file = e + 1 ;
} else {
tfile = NULL ;
}
}
2009-11-01 18:51:02 +00:00
file = switch_core_session_sprintf ( session , " %s%s%s%s%s " , switch_str_nil ( tfile ) , tfile ? " ] " : " " , prefix , SWITCH_PATH_SEPARATOR , file ) ;
2009-09-16 20:46:36 +00:00
}
2007-03-29 22:34:40 +00:00
if ( switch_core_file_open ( fh ,
file ,
2007-10-01 16:34:28 +00:00
channels ,
2009-02-10 19:09:06 +00:00
read_impl . actual_samples_per_second ,
2009-11-17 21:40:09 +00:00
file_flags , NULL ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Error opening %s \n " , file ) ;
2007-03-29 22:34:40 +00:00
switch_channel_hangup ( channel , SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ) ;
2009-01-09 20:34:01 +00:00
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_TRUE ) ;
2007-03-29 22:34:40 +00:00
return SWITCH_STATUS_GENERR ;
}
if ( ( p = switch_channel_get_variable ( channel , " RECORD_TITLE " ) ) ) {
vval = ( const char * ) switch_core_session_strdup ( session , p ) ;
switch_core_file_set_string ( fh , SWITCH_AUDIO_COL_STR_TITLE , vval ) ;
switch_channel_set_variable ( channel , " RECORD_TITLE " , NULL ) ;
}
if ( ( p = switch_channel_get_variable ( channel , " RECORD_COPYRIGHT " ) ) ) {
vval = ( const char * ) switch_core_session_strdup ( session , p ) ;
switch_core_file_set_string ( fh , SWITCH_AUDIO_COL_STR_COPYRIGHT , vval ) ;
switch_channel_set_variable ( channel , " RECORD_COPYRIGHT " , NULL ) ;
}
if ( ( p = switch_channel_get_variable ( channel , " RECORD_SOFTWARE " ) ) ) {
vval = ( const char * ) switch_core_session_strdup ( session , p ) ;
switch_core_file_set_string ( fh , SWITCH_AUDIO_COL_STR_SOFTWARE , vval ) ;
switch_channel_set_variable ( channel , " RECORD_SOFTWARE " , NULL ) ;
}
if ( ( p = switch_channel_get_variable ( channel , " RECORD_ARTIST " ) ) ) {
vval = ( const char * ) switch_core_session_strdup ( session , p ) ;
switch_core_file_set_string ( fh , SWITCH_AUDIO_COL_STR_ARTIST , vval ) ;
switch_channel_set_variable ( channel , " RECORD_ARTIST " , NULL ) ;
}
if ( ( p = switch_channel_get_variable ( channel , " RECORD_COMMENT " ) ) ) {
vval = ( const char * ) switch_core_session_strdup ( session , p ) ;
switch_core_file_set_string ( fh , SWITCH_AUDIO_COL_STR_COMMENT , vval ) ;
switch_channel_set_variable ( channel , " RECORD_COMMENT " , NULL ) ;
}
if ( ( p = switch_channel_get_variable ( channel , " RECORD_DATE " ) ) ) {
vval = ( const char * ) switch_core_session_strdup ( session , p ) ;
switch_core_file_set_string ( fh , SWITCH_AUDIO_COL_STR_DATE , vval ) ;
switch_channel_set_variable ( channel , " RECORD_DATE " , NULL ) ;
}
2009-10-29 18:36:18 +00:00
if ( limit ) {
to = switch_epoch_time_now ( NULL ) + limit ;
}
rh = switch_core_session_alloc ( session , sizeof ( * rh ) ) ;
rh - > fh = fh ;
rh - > file = switch_core_session_strdup ( session , file ) ;
rh - > packet_len = read_impl . decoded_bytes_per_packet ;
2009-10-29 15:29:33 +00:00
rh - > min_sec = 3 ;
if ( ( p = switch_channel_get_variable ( channel , " RECORD_MIN_SEC " ) ) ) {
int tmp = atoi ( p ) ;
2009-10-29 15:30:07 +00:00
if ( tmp > = 0 ) {
2009-10-29 15:29:33 +00:00
rh - > min_sec = tmp ;
}
}
2009-07-17 20:42:24 +00:00
2009-03-05 01:15:17 +00:00
if ( ( status = switch_core_media_bug_add ( session , record_callback , rh , to , flags , & bug ) ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Error adding media bug for file %s \n " , file ) ;
2007-03-29 22:34:40 +00:00
switch_core_file_close ( fh ) ;
return status ;
}
switch_channel_set_private ( channel , file , bug ) ;
return SWITCH_STATUS_SUCCESS ;
}
2009-09-23 22:39:00 +00:00
typedef struct {
SpeexPreprocessState * read_st ;
SpeexPreprocessState * write_st ;
SpeexEchoState * read_ec ;
SpeexEchoState * write_ec ;
switch_byte_t read_data [ 2048 ] ;
switch_byte_t write_data [ 2048 ] ;
switch_byte_t read_out [ 2048 ] ;
switch_byte_t write_out [ 2048 ] ;
switch_mutex_t * read_mutex ;
switch_mutex_t * write_mutex ;
int done ;
} pp_cb_t ;
static switch_bool_t preprocess_callback ( switch_media_bug_t * bug , void * user_data , switch_abc_type_t type )
{
switch_core_session_t * session = switch_core_media_bug_get_session ( bug ) ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
pp_cb_t * cb = ( pp_cb_t * ) user_data ;
switch_codec_implementation_t read_impl = { 0 } ;
switch_frame_t * frame = NULL ;
int y ;
2009-09-24 15:09:54 +00:00
switch_core_session_get_read_impl ( session , & read_impl ) ;
2009-09-23 22:39:00 +00:00
switch ( type ) {
case SWITCH_ABC_TYPE_INIT :
{
switch_mutex_init ( & cb - > read_mutex , SWITCH_MUTEX_NESTED , switch_core_session_get_pool ( session ) ) ;
switch_mutex_init ( & cb - > write_mutex , SWITCH_MUTEX_NESTED , switch_core_session_get_pool ( session ) ) ;
}
break ;
case SWITCH_ABC_TYPE_CLOSE :
{
if ( cb - > read_st ) {
speex_preprocess_state_destroy ( cb - > read_st ) ;
}
if ( cb - > write_st ) {
speex_preprocess_state_destroy ( cb - > write_st ) ;
}
if ( cb - > read_ec ) {
speex_echo_state_destroy ( cb - > read_ec ) ;
}
if ( cb - > write_ec ) {
speex_echo_state_destroy ( cb - > write_ec ) ;
}
switch_channel_set_private ( channel , " _preprocess " , NULL ) ;
}
break ;
case SWITCH_ABC_TYPE_READ_REPLACE :
{
if ( cb - > done ) return SWITCH_FALSE ;
frame = switch_core_media_bug_get_read_replace_frame ( bug ) ;
if ( cb - > read_st ) {
if ( cb - > read_ec ) {
speex_echo_cancellation ( cb - > read_ec , ( int16_t * ) frame - > data , ( int16_t * ) cb - > write_data , ( int16_t * ) cb - > read_out ) ;
memcpy ( frame - > data , cb - > read_out , frame - > datalen ) ;
}
y = speex_preprocess_run ( cb - > read_st , frame - > data ) ;
}
if ( cb - > write_ec ) {
memcpy ( cb - > read_data , frame - > data , frame - > datalen ) ;
}
}
break ;
case SWITCH_ABC_TYPE_WRITE_REPLACE :
{
if ( cb - > done ) return SWITCH_FALSE ;
frame = switch_core_media_bug_get_write_replace_frame ( bug ) ;
if ( cb - > write_st ) {
if ( cb - > write_ec ) {
speex_echo_cancellation ( cb - > write_ec , ( int16_t * ) frame - > data , ( int16_t * ) cb - > read_data , ( int16_t * ) cb - > write_out ) ;
memcpy ( frame - > data , cb - > write_out , frame - > datalen ) ;
}
y = speex_preprocess_run ( cb - > write_st , frame - > data ) ;
}
if ( cb - > read_ec ) {
memcpy ( cb - > write_data , frame - > data , frame - > datalen ) ;
}
}
break ;
default :
break ;
}
return SWITCH_TRUE ;
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_preprocess_session ( switch_core_session_t * session , const char * cmds )
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
switch_media_bug_t * bug ;
switch_status_t status ;
time_t to = 0 ;
switch_media_bug_flag_t flags = 0 ;
switch_codec_implementation_t read_impl = { 0 } ;
pp_cb_t * cb ;
int update = 0 ;
int argc ;
char * mydata = NULL , * argv [ 5 ] ;
int i = 0 ;
switch_core_session_get_read_impl ( session , & read_impl ) ;
if ( ( cb = switch_channel_get_private ( channel , " _preprocess " ) ) ) {
update = 1 ;
} else {
cb = switch_core_session_alloc ( session , sizeof ( * cb ) ) ;
}
if ( update ) {
if ( ! strcasecmp ( cmds , " stop " ) ) {
cb - > done = 1 ;
return SWITCH_STATUS_SUCCESS ;
}
}
mydata = strdup ( cmds ) ;
argc = switch_separate_string ( mydata , ' , ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ;
for ( i = 0 ; i < argc ; i + + ) {
char * var = argv [ i ] ;
char * val = NULL ;
char rw ;
int tr ;
int err = 1 ;
SpeexPreprocessState * st = NULL ;
2009-09-28 16:25:25 +00:00
SpeexEchoState * ec = NULL ;
2009-09-23 22:39:00 +00:00
switch_mutex_t * mutex = NULL ;
int r = 0 ;
if ( var ) {
if ( ( val = strchr ( var , ' = ' ) ) ) {
* val + + = ' \0 ' ;
rw = * var + + ;
while ( * var = = ' . ' | | * var = = ' _ ' ) {
var + + ;
}
if ( rw = = ' r ' ) {
if ( ! cb - > read_st ) {
cb - > read_st = speex_preprocess_state_init ( read_impl . samples_per_packet , read_impl . samples_per_second ) ;
flags | = SMBF_READ_REPLACE ;
}
st = cb - > read_st ;
ec = cb - > read_ec ;
mutex = cb - > read_mutex ;
} else if ( rw = = ' w ' ) {
if ( ! cb - > write_st ) {
cb - > write_st = speex_preprocess_state_init ( read_impl . samples_per_packet , read_impl . samples_per_second ) ;
flags | = SMBF_WRITE_REPLACE ;
}
st = cb - > write_st ;
ec = cb - > write_ec ;
mutex = cb - > write_mutex ;
}
if ( mutex ) switch_mutex_lock ( mutex ) ;
if ( st ) {
err = 0 ;
tr = switch_true ( val ) ;
if ( ! strcasecmp ( var , " agc " ) ) {
int l = read_impl . samples_per_second ;
int tmp = atoi ( val ) ;
if ( ! tr ) {
l = tmp ;
}
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Setting AGC on %c to %d \n " , rw , tr ) ;
speex_preprocess_ctl ( st , SPEEX_PREPROCESS_SET_AGC , & tr ) ;
speex_preprocess_ctl ( st , SPEEX_PREPROCESS_SET_AGC_LEVEL , & l ) ;
} else if ( ! strcasecmp ( var , " noise_supress " ) ) {
int db = atoi ( val ) ;
if ( db < 0 ) {
r = speex_preprocess_ctl ( st , SPEEX_PREPROCESS_SET_NOISE_SUPPRESS , & db ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Setting NOISE_SUPRESS on %c to %d [%d] \n " , rw , db , r ) ;
} else {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Syntax error noise_supress should be in -db \n " ) ;
}
} else if ( ! strcasecmp ( var , " echo_cancel " ) ) {
int tail = 1024 ;
int tmp = atoi ( val ) ;
if ( ! tr & & tmp > 0 ) {
tail = tmp ;
} else if ( ! tr ) {
if ( ec ) {
if ( rw = = ' r ' ) {
speex_echo_state_destroy ( cb - > read_ec ) ;
cb - > read_ec = NULL ;
} else {
speex_echo_state_destroy ( cb - > write_ec ) ;
cb - > write_ec = NULL ;
}
}
ec = NULL ;
}
if ( ! ec ) {
if ( rw = = ' r ' ) {
ec = cb - > read_ec = speex_echo_state_init ( read_impl . samples_per_packet , tail ) ;
speex_echo_ctl ( ec , SPEEX_ECHO_SET_SAMPLING_RATE , & read_impl . samples_per_second ) ;
flags | = SMBF_WRITE_REPLACE ;
} else {
ec = cb - > write_ec = speex_echo_state_init ( read_impl . samples_per_packet , tail ) ;
speex_echo_ctl ( ec , SPEEX_ECHO_SET_SAMPLING_RATE , & read_impl . samples_per_second ) ;
flags | = SMBF_READ_REPLACE ;
}
speex_preprocess_ctl ( st , SPEEX_PREPROCESS_SET_ECHO_STATE , ec ) ;
}
} else if ( ! strcasecmp ( var , " echo_supress " ) ) {
int db = atoi ( val ) ;
if ( db < 0 ) {
speex_preprocess_ctl ( st , SPEEX_PREPROCESS_SET_ECHO_SUPPRESS , & db ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Setting ECHO_SUPRESS on %c to %d [%d] \n " , rw , db , r ) ;
} else {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Syntax error echo_supress should be in -db \n " ) ;
}
} else {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " Warning unknown parameter [%s] \n " , var ) ;
}
}
}
if ( mutex ) switch_mutex_unlock ( mutex ) ;
if ( err ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Syntax error parsing preprossor commands \n " ) ;
}
} else {
break ;
}
}
switch_safe_free ( mydata ) ;
if ( update ) {
return SWITCH_STATUS_SUCCESS ;
}
if ( ( status = switch_core_media_bug_add ( session , preprocess_callback , cb , to , flags , & bug ) ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Error adding media bug. \n " ) ;
if ( cb - > read_st ) {
speex_preprocess_state_destroy ( cb - > read_st ) ;
}
if ( cb - > write_st ) {
speex_preprocess_state_destroy ( cb - > write_st ) ;
}
if ( cb - > read_ec ) {
speex_echo_state_destroy ( cb - > read_ec ) ;
}
if ( cb - > write_ec ) {
speex_echo_state_destroy ( cb - > write_ec ) ;
}
return status ;
}
switch_channel_set_private ( channel , " _preprocess " , cb ) ;
return SWITCH_STATUS_SUCCESS ;
}
2007-03-29 22:34:40 +00:00
typedef struct {
switch_core_session_t * session ;
teletone_dtmf_detect_state_t dtmf_detect ;
} switch_inband_dtmf_t ;
static switch_bool_t inband_dtmf_callback ( switch_media_bug_t * bug , void * user_data , switch_abc_type_t type )
{
switch_inband_dtmf_t * pvt = ( switch_inband_dtmf_t * ) user_data ;
2008-11-12 11:44:13 +00:00
switch_frame_t * frame = NULL ;
2007-03-29 22:34:40 +00:00
char digit_str [ 80 ] ;
switch_channel_t * channel = switch_core_session_get_channel ( pvt - > session ) ;
switch ( type ) {
case SWITCH_ABC_TYPE_INIT :
break ;
case SWITCH_ABC_TYPE_CLOSE :
break ;
2008-11-12 11:44:13 +00:00
case SWITCH_ABC_TYPE_READ_REPLACE :
if ( ( frame = switch_core_media_bug_get_read_replace_frame ( bug ) ) ) {
teletone_dtmf_detect ( & pvt - > dtmf_detect , frame - > data , frame - > samples ) ;
2007-03-29 22:34:40 +00:00
teletone_dtmf_get ( & pvt - > dtmf_detect , digit_str , sizeof ( digit_str ) ) ;
if ( digit_str [ 0 ] ) {
2007-12-22 00:32:20 +00:00
char * p = digit_str ;
2008-05-27 04:30:03 +00:00
while ( p & & * p ) {
2007-12-22 00:32:20 +00:00
switch_dtmf_t dtmf ;
dtmf . digit = * p ;
2008-04-18 17:03:34 +00:00
dtmf . duration = switch_core_default_dtmf_duration ( 0 ) ;
2007-12-22 00:32:20 +00:00
switch_channel_queue_dtmf ( channel , & dtmf ) ;
p + + ;
}
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( switch_core_media_bug_get_session ( bug ) ) , SWITCH_LOG_DEBUG , " DTMF DETECTED: [%s] \n " , digit_str ) ;
2007-03-29 22:34:40 +00:00
}
2008-11-12 11:44:13 +00:00
switch_core_media_bug_set_read_replace_frame ( bug , frame ) ;
2007-03-29 22:34:40 +00:00
}
break ;
case SWITCH_ABC_TYPE_WRITE :
default :
break ;
}
return SWITCH_TRUE ;
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_stop_inband_dtmf_session ( switch_core_session_t * session )
{
switch_media_bug_t * bug ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
if ( ( bug = switch_channel_get_private ( channel , " dtmf " ) ) ) {
switch_channel_set_private ( channel , " dtmf " , NULL ) ;
switch_core_media_bug_remove ( session , & bug ) ;
return SWITCH_STATUS_SUCCESS ;
}
return SWITCH_STATUS_FALSE ;
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_inband_dtmf_session ( switch_core_session_t * session )
{
2008-01-28 07:26:10 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2007-03-29 22:34:40 +00:00
switch_media_bug_t * bug ;
switch_status_t status ;
switch_inband_dtmf_t * pvt ;
2009-02-10 19:09:06 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
2007-03-29 22:34:40 +00:00
2009-02-10 19:09:06 +00:00
switch_core_session_get_read_impl ( session , & read_impl ) ;
2007-03-29 22:34:40 +00:00
if ( ! ( pvt = switch_core_session_alloc ( session , sizeof ( * pvt ) ) ) ) {
return SWITCH_STATUS_MEMERR ;
}
2009-02-10 19:09:06 +00:00
teletone_dtmf_detect_init ( & pvt - > dtmf_detect , read_impl . actual_samples_per_second ) ;
2007-03-29 22:34:40 +00:00
pvt - > session = session ;
2009-02-10 19:09:06 +00:00
if ( switch_channel_pre_answer ( channel ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_FALSE ;
}
2007-03-29 22:34:40 +00:00
2008-11-12 11:44:13 +00:00
if ( ( status = switch_core_media_bug_add ( session , inband_dtmf_callback , pvt , 0 , SMBF_READ_REPLACE , & bug ) ) ! = SWITCH_STATUS_SUCCESS ) {
2007-03-29 22:34:40 +00:00
return status ;
}
switch_channel_set_private ( channel , " dtmf " , bug ) ;
return SWITCH_STATUS_SUCCESS ;
}
2007-10-31 16:44:02 +00:00
typedef struct {
switch_core_session_t * session ;
teletone_generation_session_t ts ;
2008-02-13 00:32:09 +00:00
switch_queue_t * digit_queue ;
2008-05-27 04:30:03 +00:00
switch_buffer_t * audio_buffer ;
2007-10-31 16:44:02 +00:00
switch_mutex_t * mutex ;
int read ;
2008-02-13 00:32:09 +00:00
int ready ;
2007-10-31 16:44:02 +00:00
} switch_inband_dtmf_generate_t ;
2008-05-27 04:30:03 +00:00
static int teletone_dtmf_generate_handler ( teletone_generation_session_t * ts , teletone_tone_map_t * map )
2007-10-31 16:44:02 +00:00
{
2008-05-27 04:30:03 +00:00
switch_buffer_t * audio_buffer = ts - > user_data ;
int wrote ;
2007-10-31 16:44:02 +00:00
2008-05-27 04:30:03 +00:00
if ( ! audio_buffer ) {
return - 1 ;
}
2007-10-31 16:44:02 +00:00
2008-05-27 04:30:03 +00:00
wrote = teletone_mux_tones ( ts , map ) ;
switch_buffer_write ( audio_buffer , ts - > buffer , wrote * 2 ) ;
2007-10-31 16:44:02 +00:00
2008-05-27 04:30:03 +00:00
return 0 ;
2007-10-31 16:44:02 +00:00
}
2008-05-19 21:02:26 +00:00
static switch_status_t generate_on_dtmf ( switch_core_session_t * session , const switch_dtmf_t * dtmf , switch_dtmf_direction_t direction )
2007-10-31 16:44:02 +00:00
{
2008-05-27 04:30:03 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
switch_media_bug_t * bug = switch_channel_get_private ( channel , " dtmf_generate " ) ;
2008-02-13 00:32:09 +00:00
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2008-05-27 04:30:03 +00:00
if ( bug ) {
switch_inband_dtmf_generate_t * pvt = ( switch_inband_dtmf_generate_t * ) switch_core_media_bug_get_user_data ( bug ) ;
if ( pvt ) {
2007-12-22 00:51:26 +00:00
switch_mutex_lock ( pvt - > mutex ) ;
2008-02-13 00:32:09 +00:00
if ( pvt - > ready ) {
switch_dtmf_t * dt = NULL ;
switch_zmalloc ( dt , sizeof ( * dt ) ) ;
* dt = * dtmf ;
if ( switch_queue_trypush ( pvt - > digit_queue , dt ) = = SWITCH_STATUS_SUCCESS ) {
dt = NULL ;
/*
SWITCH_STATUS_FALSE indicates pretend there never was a DTMF
since we will be generating it inband now .
2008-05-27 04:30:03 +00:00
*/
2008-02-13 00:32:09 +00:00
status = SWITCH_STATUS_FALSE ;
} else {
free ( dt ) ;
}
}
2007-10-31 16:44:02 +00:00
switch_mutex_unlock ( pvt - > mutex ) ;
}
}
2008-02-13 00:32:09 +00:00
return status ;
2007-10-31 16:44:02 +00:00
}
2008-02-13 00:32:09 +00:00
2007-10-31 16:44:02 +00:00
static switch_bool_t inband_dtmf_generate_callback ( switch_media_bug_t * bug , void * user_data , switch_abc_type_t type )
{
switch_inband_dtmf_generate_t * pvt = ( switch_inband_dtmf_generate_t * ) user_data ;
switch_frame_t * frame ;
2009-02-10 19:09:06 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
switch_core_session_get_read_impl ( pvt - > session , & read_impl ) ;
2007-10-31 16:44:02 +00:00
switch ( type ) {
case SWITCH_ABC_TYPE_INIT :
{
2008-02-13 00:32:09 +00:00
switch_queue_create ( & pvt - > digit_queue , 100 , switch_core_session_get_pool ( pvt - > session ) ) ;
2007-10-31 16:44:02 +00:00
switch_buffer_create_dynamic ( & pvt - > audio_buffer , 512 , 1024 , 0 ) ;
teletone_init_session ( & pvt - > ts , 0 , teletone_dtmf_generate_handler , pvt - > audio_buffer ) ;
2009-02-10 19:09:06 +00:00
pvt - > ts . rate = read_impl . actual_samples_per_second ;
2007-10-31 16:44:02 +00:00
pvt - > ts . channels = 1 ;
switch_mutex_init ( & pvt - > mutex , SWITCH_MUTEX_NESTED , switch_core_session_get_pool ( pvt - > session ) ) ;
switch_core_event_hook_add_recv_dtmf ( pvt - > session , generate_on_dtmf ) ;
2008-02-13 00:32:09 +00:00
switch_mutex_lock ( pvt - > mutex ) ;
pvt - > ready = 1 ;
switch_mutex_unlock ( pvt - > mutex ) ;
2007-10-31 16:44:02 +00:00
}
break ;
case SWITCH_ABC_TYPE_CLOSE :
{
2008-02-13 00:32:09 +00:00
switch_mutex_lock ( pvt - > mutex ) ;
pvt - > ready = 0 ;
switch_core_event_hook_remove_recv_dtmf ( pvt - > session , generate_on_dtmf ) ;
2007-10-31 16:44:02 +00:00
switch_buffer_destroy ( & pvt - > audio_buffer ) ;
teletone_destroy_session ( & pvt - > ts ) ;
2008-02-13 00:32:09 +00:00
switch_mutex_unlock ( pvt - > mutex ) ;
2007-10-31 16:44:02 +00:00
}
break ;
case SWITCH_ABC_TYPE_READ_REPLACE :
case SWITCH_ABC_TYPE_WRITE_REPLACE :
{
switch_size_t bytes ;
2008-02-13 00:32:09 +00:00
void * pop ;
2007-10-31 16:44:02 +00:00
switch_mutex_lock ( pvt - > mutex ) ;
2008-02-13 00:32:09 +00:00
if ( ! pvt - > ready ) {
switch_mutex_unlock ( pvt - > mutex ) ;
2008-05-27 04:30:03 +00:00
return SWITCH_FALSE ;
2008-02-13 00:32:09 +00:00
}
2007-10-31 16:44:02 +00:00
if ( pvt - > read ) {
frame = switch_core_media_bug_get_read_replace_frame ( bug ) ;
} else {
frame = switch_core_media_bug_get_write_replace_frame ( bug ) ;
}
2008-05-27 04:30:03 +00:00
2008-02-13 00:32:09 +00:00
while ( switch_queue_trypop ( pvt - > digit_queue , & pop ) = = SWITCH_STATUS_SUCCESS ) {
switch_dtmf_t * dtmf = ( switch_dtmf_t * ) pop ;
char buf [ 2 ] = " " ;
2008-02-21 21:38:49 +00:00
int duration = dtmf - > duration ;
2008-02-13 00:32:09 +00:00
buf [ 0 ] = dtmf - > digit ;
2008-02-21 21:38:49 +00:00
if ( duration > 8000 ) {
duration = 4000 ;
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( switch_core_media_bug_get_session ( bug ) ) , SWITCH_LOG_WARNING , " %s Truncating ridiculous DTMF duration %d ms to 1/2 second. \n " ,
2008-02-21 21:38:49 +00:00
switch_channel_get_name ( switch_core_session_get_channel ( pvt - > session ) ) , dtmf - > duration / 8 ) ;
}
pvt - > ts . duration = duration ;
2008-02-13 00:32:09 +00:00
teletone_run ( & pvt - > ts , buf ) ;
2009-02-27 19:24:56 +00:00
free ( pop ) ;
2008-02-13 00:32:09 +00:00
}
2008-05-27 04:30:03 +00:00
2007-10-31 16:44:02 +00:00
if ( switch_buffer_inuse ( pvt - > audio_buffer ) & & ( bytes = switch_buffer_read ( pvt - > audio_buffer , frame - > data , frame - > datalen ) ) ) {
if ( bytes < frame - > datalen ) {
switch_byte_t * dp = frame - > data ;
memset ( dp + bytes , 0 , frame - > datalen - bytes ) ;
}
}
2008-02-13 00:32:09 +00:00
2007-10-31 16:44:02 +00:00
if ( pvt - > read ) {
switch_core_media_bug_set_read_replace_frame ( bug , frame ) ;
} else {
switch_core_media_bug_set_write_replace_frame ( bug , frame ) ;
}
switch_mutex_unlock ( pvt - > mutex ) ;
}
break ;
default :
break ;
}
return SWITCH_TRUE ;
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_stop_inband_dtmf_generate_session ( switch_core_session_t * session )
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2008-01-28 07:26:10 +00:00
switch_media_bug_t * bug = switch_channel_get_private ( channel , " dtmf_generate " ) ;
2007-10-31 16:44:02 +00:00
2008-01-28 07:26:10 +00:00
if ( bug ) {
2007-10-31 16:44:02 +00:00
switch_channel_set_private ( channel , " dtmf_generate " , NULL ) ;
switch_core_media_bug_remove ( session , & bug ) ;
return SWITCH_STATUS_SUCCESS ;
}
return SWITCH_STATUS_FALSE ;
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_inband_dtmf_generate_session ( switch_core_session_t * session , switch_bool_t read_stream )
{
2008-01-28 07:26:10 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2007-10-31 16:44:02 +00:00
switch_media_bug_t * bug ;
switch_status_t status ;
switch_inband_dtmf_generate_t * pvt ;
2009-02-10 19:09:06 +00:00
if ( ( status = switch_channel_pre_answer ( channel ) ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_FALSE ;
}
2008-02-05 15:50:49 +00:00
2008-02-05 17:33:34 +00:00
if ( ! switch_channel_media_ready ( channel ) | | ! switch_core_session_get_read_codec ( session ) ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Can not install inband dtmf generate. Media not enabled on channel \n " ) ;
2008-02-05 17:33:34 +00:00
return status ;
2008-02-05 15:50:49 +00:00
}
2007-10-31 16:44:02 +00:00
if ( ! ( pvt = switch_core_session_alloc ( session , sizeof ( * pvt ) ) ) ) {
return SWITCH_STATUS_MEMERR ;
}
pvt - > session = session ;
pvt - > read = ! ! read_stream ;
2008-05-27 04:30:03 +00:00
if ( ( status = switch_core_media_bug_add ( session , inband_dtmf_generate_callback , pvt , 0 ,
2007-10-31 16:44:02 +00:00
pvt - > read ? SMBF_READ_REPLACE : SMBF_WRITE_REPLACE , & bug ) ) ! = SWITCH_STATUS_SUCCESS ) {
return status ;
}
switch_channel_set_private ( channel , " dtmf_generate " , bug ) ;
return SWITCH_STATUS_SUCCESS ;
}
2007-06-16 02:25:40 +00:00
# define MAX_TONES 16
2007-06-04 22:10:42 +00:00
typedef struct {
2007-06-16 02:25:40 +00:00
teletone_multi_tone_t mt ;
char * app ;
char * data ;
char * key ;
teletone_tone_map_t map ;
int up ;
2008-11-18 02:21:04 +00:00
int total_hits ;
2008-11-18 02:05:11 +00:00
int hits ;
int sleep ;
2008-11-19 02:40:59 +00:00
int expires ;
2009-01-20 15:39:32 +00:00
int default_sleep ;
int default_expires ;
2009-01-19 16:10:54 +00:00
int once ;
switch_tone_detect_callback_t callback ;
2007-06-16 02:25:40 +00:00
} switch_tone_detect_t ;
typedef struct {
2008-05-27 04:30:03 +00:00
switch_tone_detect_t list [ MAX_TONES + 1 ] ;
2007-06-16 02:25:40 +00:00
int index ;
switch_media_bug_t * bug ;
switch_core_session_t * session ;
2009-02-11 00:16:36 +00:00
int bug_running ;
2007-06-16 02:25:40 +00:00
} switch_tone_container_t ;
2007-06-04 22:10:42 +00:00
2007-06-16 02:25:40 +00:00
static switch_bool_t tone_detect_callback ( switch_media_bug_t * bug , void * user_data , switch_abc_type_t type )
2007-06-04 22:10:42 +00:00
{
2007-06-16 02:25:40 +00:00
switch_tone_container_t * cont = ( switch_tone_container_t * ) user_data ;
switch_frame_t * frame = NULL ;
int i = 0 ;
2009-01-19 16:10:54 +00:00
switch_bool_t rval = SWITCH_TRUE ;
2007-06-04 22:10:42 +00:00
2007-06-16 02:25:40 +00:00
switch ( type ) {
case SWITCH_ABC_TYPE_INIT :
2009-02-11 00:16:36 +00:00
if ( cont ) {
cont - > bug_running = 1 ;
}
2007-06-16 02:25:40 +00:00
break ;
case SWITCH_ABC_TYPE_CLOSE :
break ;
case SWITCH_ABC_TYPE_READ_REPLACE :
case SWITCH_ABC_TYPE_WRITE_REPLACE :
{
2008-11-19 02:40:59 +00:00
int skip = 0 ;
if ( type = = SWITCH_ABC_TYPE_READ_REPLACE ) {
frame = switch_core_media_bug_get_read_replace_frame ( bug ) ;
} else {
2007-06-16 02:25:40 +00:00
frame = switch_core_media_bug_get_write_replace_frame ( bug ) ;
}
2009-02-11 00:16:36 +00:00
2008-05-27 04:30:03 +00:00
for ( i = 0 ; i < cont - > index ; i + + ) {
2008-11-18 02:21:04 +00:00
2008-11-18 02:05:11 +00:00
if ( cont - > list [ i ] . sleep ) {
cont - > list [ i ] . sleep - - ;
2008-11-19 02:40:59 +00:00
if ( cont - > list [ i ] . sleep ) {
skip = 1 ;
}
2008-11-18 02:05:11 +00:00
}
2008-05-27 04:30:03 +00:00
2008-11-19 02:40:59 +00:00
if ( cont - > list [ i ] . expires ) {
cont - > list [ i ] . expires - - ;
if ( ! cont - > list [ i ] . expires ) {
cont - > list [ i ] . hits = 0 ;
cont - > list [ i ] . sleep = 0 ;
cont - > list [ i ] . expires = 0 ;
}
}
if ( ! cont - > list [ i ] . up ) skip = 1 ;
2009-02-11 00:16:36 +00:00
if ( skip ) return SWITCH_TRUE ;
2008-11-19 02:40:59 +00:00
if ( teletone_multi_tone_detect ( & cont - > list [ i ] . mt , frame - > data , frame - > samples ) ) {
switch_event_t * event ;
cont - > list [ i ] . hits + + ;
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( switch_core_media_bug_get_session ( bug ) ) , SWITCH_LOG_DEBUG , " TONE %s HIT %d/%d \n " ,
2008-11-19 02:40:59 +00:00
cont - > list [ i ] . key , cont - > list [ i ] . hits , cont - > list [ i ] . total_hits ) ;
2009-01-20 15:39:32 +00:00
cont - > list [ i ] . sleep = cont - > list [ i ] . default_sleep ;
cont - > list [ i ] . expires = cont - > list [ i ] . default_expires ;
2008-11-18 15:11:17 +00:00
if ( cont - > list [ i ] . hits > = cont - > list [ i ] . total_hits ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( switch_core_media_bug_get_session ( bug ) ) , SWITCH_LOG_DEBUG , " TONE %s DETECTED \n " , cont - > list [ i ] . key ) ;
2008-11-18 02:05:11 +00:00
cont - > list [ i ] . up = 0 ;
2009-02-11 00:16:36 +00:00
2009-01-19 16:10:54 +00:00
if ( cont - > list [ i ] . callback ) {
2009-02-11 00:16:36 +00:00
if ( ( rval = cont - > list [ i ] . callback ( cont - > session , cont - > list [ i ] . app , cont - > list [ i ] . data ) ) = = SWITCH_TRUE ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( switch_core_media_bug_get_session ( bug ) ) , SWITCH_LOG_DEBUG , " Re-enabling %s \n " , cont - > list [ i ] . key ) ;
2009-02-11 00:16:36 +00:00
cont - > list [ i ] . up = 1 ;
cont - > list [ i ] . hits = 0 ;
cont - > list [ i ] . sleep = 0 ;
cont - > list [ i ] . expires = 0 ;
}
2009-01-19 16:10:54 +00:00
} else if ( cont - > list [ i ] . app ) {
2008-11-18 15:11:17 +00:00
if ( switch_event_create ( & event , SWITCH_EVENT_COMMAND ) = = SWITCH_STATUS_SUCCESS ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " call-command " , " execute " ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " execute-app-name " , cont - > list [ i ] . app ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " execute-app-arg " , cont - > list [ i ] . data ) ;
switch_event_add_header ( event , SWITCH_STACK_BOTTOM , " lead-frames " , " %d " , 5 ) ;
switch_core_session_queue_private_event ( cont - > session , & event ) ;
}
2007-06-16 02:25:40 +00:00
}
2009-02-11 00:16:36 +00:00
if ( cont - > list [ i ] . once ) {
rval = SWITCH_FALSE ;
}
2008-11-18 15:11:17 +00:00
if ( switch_event_create ( & event , SWITCH_EVENT_DETECTED_TONE ) = = SWITCH_STATUS_SUCCESS ) {
switch_event_t * dup ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Detected-Tone " , cont - > list [ i ] . key ) ;
2009-01-19 16:10:54 +00:00
2008-11-18 15:11:17 +00:00
if ( switch_event_dup ( & dup , event ) = = SWITCH_STATUS_SUCCESS ) {
switch_event_fire ( & dup ) ;
}
2008-05-27 04:30:03 +00:00
2008-11-18 15:11:17 +00:00
if ( switch_core_session_queue_event ( cont - > session , & event ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( switch_core_media_bug_get_session ( bug ) ) , SWITCH_LOG_ERROR , " Event queue failed! \n " ) ;
2008-11-18 15:11:17 +00:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " delivery-failure " , " true " ) ;
switch_event_fire ( & event ) ;
}
2007-06-16 02:25:40 +00:00
}
}
}
}
}
break ;
case SWITCH_ABC_TYPE_WRITE :
default :
break ;
2007-06-04 22:10:42 +00:00
}
2009-02-11 00:16:36 +00:00
if ( rval = = SWITCH_FALSE ) {
cont - > bug_running = 0 ;
}
2009-01-19 16:10:54 +00:00
return rval ;
2007-06-04 22:10:42 +00:00
}
2007-06-16 02:25:40 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_stop_tone_detect_session ( switch_core_session_t * session )
2007-06-04 22:10:42 +00:00
{
2007-06-16 02:25:40 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2008-01-28 07:26:10 +00:00
switch_tone_container_t * cont = switch_channel_get_private ( channel , " _tone_detect_ " ) ;
2009-02-11 00:16:36 +00:00
int i = 0 ;
2008-05-27 04:30:03 +00:00
2008-01-28 07:26:10 +00:00
if ( cont ) {
2007-06-16 02:25:40 +00:00
switch_channel_set_private ( channel , " _tone_detect_ " , NULL ) ;
2009-02-11 00:16:36 +00:00
for ( i = 0 ; i < cont - > index ; i + + ) {
cont - > list [ i ] . up = 0 ;
}
2007-06-16 02:25:40 +00:00
switch_core_media_bug_remove ( session , & cont - > bug ) ;
return SWITCH_STATUS_SUCCESS ;
}
return SWITCH_STATUS_FALSE ;
2007-06-04 22:10:42 +00:00
}
2008-05-27 04:30:03 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_tone_detect_session ( switch_core_session_t * session ,
2007-06-16 02:25:40 +00:00
const char * key , const char * tone_spec ,
2009-01-19 16:10:54 +00:00
const char * flags , time_t timeout ,
2009-02-11 00:16:36 +00:00
int hits ,
const char * app , const char * data ,
2009-01-19 16:10:54 +00:00
switch_tone_detect_callback_t callback )
2007-06-04 22:10:42 +00:00
{
2008-05-27 04:30:03 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
switch_status_t status ;
switch_tone_container_t * cont = switch_channel_get_private ( channel , " _tone_detect_ " ) ;
char * p , * next ;
int i = 0 , ok = 0 ;
switch_media_bug_flag_t bflags = 0 ;
2009-01-20 15:39:32 +00:00
const char * var ;
2009-02-10 19:09:06 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
switch_core_session_get_read_impl ( session , & read_impl ) ;
2008-05-27 04:30:03 +00:00
2009-02-11 00:16:36 +00:00
2009-10-23 16:03:42 +00:00
if ( zstr ( key ) ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " No Key Specified! \n " ) ;
2008-05-27 04:30:03 +00:00
return SWITCH_STATUS_FALSE ;
}
if ( cont ) {
if ( cont - > index > = MAX_TONES ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Max Tones Reached! \n " ) ;
2008-05-27 04:30:03 +00:00
return SWITCH_STATUS_FALSE ;
}
for ( i = 0 ; i < cont - > index ; i + + ) {
2009-10-23 16:03:42 +00:00
if ( ! zstr ( cont - > list [ i ] . key ) & & ! strcasecmp ( key , cont - > list [ i ] . key ) ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Re-enabling %s \n " , key ) ;
2009-02-11 00:16:36 +00:00
cont - > list [ i ] . up = 1 ;
2008-11-18 15:11:17 +00:00
cont - > list [ i ] . hits = 0 ;
cont - > list [ i ] . sleep = 0 ;
cont - > list [ i ] . expires = 0 ;
2008-05-27 04:30:03 +00:00
return SWITCH_STATUS_SUCCESS ;
}
}
}
2009-10-23 16:03:42 +00:00
if ( zstr ( tone_spec ) ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " No Spec Specified! \n " ) ;
2008-05-27 04:30:03 +00:00
return SWITCH_STATUS_FALSE ;
}
if ( ! cont & & ! ( cont = switch_core_session_alloc ( session , sizeof ( * cont ) ) ) ) {
return SWITCH_STATUS_MEMERR ;
}
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Adding tone spec %s index %d hits %d \n " , tone_spec , cont - > index , hits ) ;
2008-05-27 04:30:03 +00:00
i = 0 ;
p = ( char * ) tone_spec ;
do {
teletone_process_t this ;
next = strchr ( p , ' , ' ) ;
while ( * p = = ' ' )
p + + ;
if ( ( this = ( teletone_process_t ) atof ( p ) ) ) {
ok + + ;
cont - > list [ cont - > index ] . map . freqs [ i + + ] = this ;
}
if ( next ) {
p = next + 1 ;
}
} while ( next ) ;
cont - > list [ cont - > index ] . map . freqs [ i + + ] = 0 ;
2008-11-18 02:05:11 +00:00
2008-05-27 04:30:03 +00:00
if ( ! ok ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Invalid tone spec! \n " ) ;
2008-05-27 04:30:03 +00:00
return SWITCH_STATUS_FALSE ;
}
cont - > list [ cont - > index ] . key = switch_core_session_strdup ( session , key ) ;
if ( app ) {
cont - > list [ cont - > index ] . app = switch_core_session_strdup ( session , app ) ;
}
if ( data ) {
cont - > list [ cont - > index ] . data = switch_core_session_strdup ( session , data ) ;
}
2009-01-19 16:10:54 +00:00
cont - > list [ cont - > index ] . callback = callback ;
2008-11-18 02:05:11 +00:00
if ( ! hits ) hits = 1 ;
2008-11-18 15:11:17 +00:00
cont - > list [ cont - > index ] . hits = 0 ;
2008-11-18 02:21:04 +00:00
cont - > list [ cont - > index ] . total_hits = hits ;
2008-11-18 02:05:11 +00:00
2008-05-27 04:30:03 +00:00
cont - > list [ cont - > index ] . up = 1 ;
2009-02-11 00:16:36 +00:00
memset ( & cont - > list [ cont - > index ] . mt , 0 , sizeof ( cont - > list [ cont - > index ] . mt ) ) ;
2009-02-10 19:09:06 +00:00
cont - > list [ cont - > index ] . mt . sample_rate = read_impl . actual_samples_per_second ;
2008-05-27 04:30:03 +00:00
teletone_multi_tone_init ( & cont - > list [ cont - > index ] . mt , & cont - > list [ cont - > index ] . map ) ;
cont - > session = session ;
2009-02-10 19:09:06 +00:00
if ( switch_channel_pre_answer ( channel ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_FALSE ;
}
2008-05-27 04:30:03 +00:00
2009-01-20 15:39:32 +00:00
cont - > list [ cont - > index ] . default_sleep = 25 ;
cont - > list [ cont - > index ] . default_expires = 250 ;
if ( ( var = switch_channel_get_variable ( channel , " tone_detect_sleep " ) ) ) {
int tmp = atoi ( var ) ;
if ( tmp > 0 ) {
cont - > list [ cont - > index ] . default_sleep = tmp ;
}
}
if ( ( var = switch_channel_get_variable ( channel , " tone_detect_expires " ) ) ) {
int tmp = atoi ( var ) ;
if ( tmp > 0 ) {
cont - > list [ cont - > index ] . default_expires = tmp ;
}
}
2009-10-23 16:03:42 +00:00
if ( zstr ( flags ) ) {
2008-05-27 04:30:03 +00:00
bflags = SMBF_READ_REPLACE ;
} else {
2009-01-19 16:10:54 +00:00
if ( strchr ( flags , ' o ' ) ) {
cont - > list [ cont - > index ] . once = 1 ;
}
2009-02-11 00:16:36 +00:00
2008-05-27 04:30:03 +00:00
if ( strchr ( flags , ' r ' ) ) {
bflags | = SMBF_READ_REPLACE ;
} else if ( strchr ( flags , ' w ' ) ) {
bflags | = SMBF_WRITE_REPLACE ;
}
}
2008-11-19 02:40:59 +00:00
2009-02-11 00:16:36 +00:00
if ( cont - > bug_running ) {
status = SWITCH_STATUS_SUCCESS ;
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s bug already running \n " , switch_channel_get_name ( channel ) ) ;
2009-02-11 00:16:36 +00:00
} else {
cont - > bug_running = 1 ;
if ( ( status = switch_core_media_bug_add ( session , tone_detect_callback , cont , timeout , bflags , & cont - > bug ) ) ! = SWITCH_STATUS_SUCCESS ) {
cont - > bug_running = 0 ;
return status ;
}
switch_channel_set_private ( channel , " _tone_detect_ " , cont ) ;
2008-05-27 04:30:03 +00:00
}
cont - > index + + ;
return SWITCH_STATUS_SUCCESS ;
2007-06-04 22:10:42 +00:00
}
2008-03-11 21:32:56 +00:00
typedef struct {
const char * app ;
2008-03-11 22:19:17 +00:00
uint32_t flags ;
2008-05-19 21:02:26 +00:00
switch_bind_flag_t bind_flags ;
2008-03-11 21:32:56 +00:00
} dtmf_meta_app_t ;
typedef struct {
dtmf_meta_app_t map [ 10 ] ;
time_t last_digit ;
2008-05-27 04:30:03 +00:00
switch_bool_t meta_on ;
2008-05-19 21:02:26 +00:00
int up ;
} dtmf_meta_settings_t ;
typedef struct {
2008-05-19 22:23:11 +00:00
dtmf_meta_settings_t sr [ 3 ] ;
2008-03-11 21:32:56 +00:00
} dtmf_meta_data_t ;
# define SWITCH_META_VAR_KEY "__dtmf_meta"
2009-01-06 21:07:58 +00:00
typedef struct {
switch_core_session_t * session ;
const char * app ;
int flags ;
} bch_t ;
static void * SWITCH_THREAD_FUNC bcast_thread ( switch_thread_t * thread , void * obj )
{
bch_t * bch = ( bch_t * ) obj ;
2009-09-25 19:48:28 +00:00
if ( ! bch - > session ) {
return NULL ;
}
switch_core_session_read_lock ( bch - > session ) ;
2009-01-06 21:07:58 +00:00
switch_ivr_broadcast ( switch_core_session_get_uuid ( bch - > session ) , bch - > app , bch - > flags ) ;
2009-09-25 19:48:28 +00:00
switch_core_session_rwunlock ( bch - > session ) ;
2009-01-06 21:07:58 +00:00
return NULL ;
}
static void broadcast_in_thread ( switch_core_session_t * session , const char * app , int flags )
{
switch_thread_t * thread ;
switch_threadattr_t * thd_attr = NULL ;
switch_memory_pool_t * pool ;
bch_t * bch ;
switch_assert ( session ) ;
pool = switch_core_session_get_pool ( session ) ;
bch = switch_core_session_alloc ( session , sizeof ( * bch ) ) ;
bch - > session = session ;
bch - > app = app ;
bch - > flags = flags ;
switch_threadattr_create ( & thd_attr , pool ) ;
switch_threadattr_detach_set ( thd_attr , 1 ) ;
switch_threadattr_stacksize_set ( thd_attr , SWITCH_THREAD_STACKSIZE ) ;
switch_thread_create ( & thread , thd_attr , bcast_thread , bch , pool ) ;
}
2008-05-19 21:02:26 +00:00
static switch_status_t meta_on_dtmf ( switch_core_session_t * session , const switch_dtmf_t * dtmf , switch_dtmf_direction_t direction )
2008-03-11 21:32:56 +00:00
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
dtmf_meta_data_t * md = switch_channel_get_private ( channel , SWITCH_META_VAR_KEY ) ;
2009-01-25 21:23:07 +00:00
time_t now = switch_epoch_time_now ( NULL ) ;
2008-03-11 21:32:56 +00:00
char digit [ 2 ] = " " ;
int dval ;
2008-05-27 04:30:03 +00:00
2008-03-13 01:08:42 +00:00
if ( ! md | | switch_channel_test_flag ( channel , CF_INNER_BRIDGE ) ) {
2008-03-11 21:32:56 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2008-05-27 04:30:03 +00:00
if ( direction = = SWITCH_DTMF_RECV & & ! md - > sr [ SWITCH_DTMF_RECV ] . up ) {
2008-05-19 21:02:26 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2008-05-27 04:30:03 +00:00
if ( direction = = SWITCH_DTMF_SEND & & ! md - > sr [ SWITCH_DTMF_SEND ] . up ) {
2008-05-19 21:02:26 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2008-05-27 04:30:03 +00:00
2008-05-19 21:02:26 +00:00
if ( md - > sr [ direction ] . meta_on & & now - md - > sr [ direction ] . last_digit > 5 ) {
md - > sr [ direction ] . meta_on = SWITCH_FALSE ;
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " %s Meta digit timeout parsing %c \n " , switch_channel_get_name ( channel ) , dtmf - > digit ) ;
2008-03-11 21:32:56 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2008-05-19 21:02:26 +00:00
md - > sr [ direction ] . last_digit = now ;
2008-03-11 21:32:56 +00:00
if ( dtmf - > digit = = ' * ' ) {
2008-05-19 21:02:26 +00:00
if ( md - > sr [ direction ] . meta_on ) {
md - > sr [ direction ] . meta_on = SWITCH_FALSE ;
2008-03-11 21:32:56 +00:00
return SWITCH_STATUS_SUCCESS ;
} else {
2008-05-19 21:02:26 +00:00
md - > sr [ direction ] . meta_on = SWITCH_TRUE ;
2008-03-11 21:32:56 +00:00
return SWITCH_STATUS_FALSE ;
}
}
2008-05-19 21:02:26 +00:00
if ( md - > sr [ direction ] . meta_on ) {
2008-03-11 21:32:56 +00:00
if ( dtmf - > digit > = ' 0 ' & & dtmf - > digit < = ' 9 ' ) {
2008-05-19 22:23:11 +00:00
int ok = 0 ;
2008-03-11 21:32:56 +00:00
* digit = dtmf - > digit ;
dval = atoi ( digit ) ;
2008-05-19 21:02:26 +00:00
2008-05-27 04:30:03 +00:00
if ( direction = = SWITCH_DTMF_RECV & & ( md - > sr [ direction ] . map [ dval ] . bind_flags & SBF_DIAL_ALEG ) ) {
2008-05-19 21:02:26 +00:00
ok = 1 ;
2008-05-27 04:30:03 +00:00
} else if ( direction = = SWITCH_DTMF_SEND & & ( md - > sr [ direction ] . map [ dval ] . bind_flags & SBF_DIAL_BLEG ) ) {
2008-05-19 21:02:26 +00:00
ok = 1 ;
}
if ( ok & & md - > sr [ direction ] . map [ dval ] . app ) {
uint32_t flags = md - > sr [ direction ] . map [ dval ] . flags ;
2009-01-06 21:07:58 +00:00
2008-05-19 21:02:26 +00:00
if ( ( md - > sr [ direction ] . map [ dval ] . bind_flags & SBF_EXEC_OPPOSITE ) ) {
if ( direction = = SWITCH_DTMF_SEND ) {
flags | = SMF_ECHO_ALEG ;
} else {
flags | = SMF_ECHO_BLEG ;
}
} else if ( ( md - > sr [ direction ] . map [ dval ] . bind_flags & SBF_EXEC_SAME ) ) {
if ( direction = = SWITCH_DTMF_SEND ) {
flags | = SMF_ECHO_BLEG ;
} else {
flags | = SMF_ECHO_ALEG ;
}
} else if ( ( md - > sr [ direction ] . map [ dval ] . bind_flags & SBF_EXEC_ALEG ) ) {
flags | = SMF_ECHO_ALEG ;
} else if ( ( md - > sr [ direction ] . map [ dval ] . bind_flags & SBF_EXEC_BLEG ) ) {
flags | = SMF_ECHO_BLEG ;
} else {
flags | = SMF_ECHO_ALEG ;
}
2009-09-25 19:48:28 +00:00
if ( ( md - > sr [ direction ] . map [ dval ] . bind_flags & SBF_EXEC_INLINE ) ) {
flags | = SMF_EXEC_INLINE ;
}
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s Processing meta digit '%c' [%s] \n " ,
2008-05-19 21:02:26 +00:00
switch_channel_get_name ( channel ) , dtmf - > digit , md - > sr [ direction ] . map [ dval ] . app ) ;
2009-01-06 21:07:58 +00:00
if ( switch_channel_test_flag ( channel , CF_PROXY_MODE ) ) {
broadcast_in_thread ( session , md - > sr [ direction ] . map [ dval ] . app , flags | SMF_REBRIDGE ) ;
} else {
switch_ivr_broadcast ( switch_core_session_get_uuid ( session ) , md - > sr [ direction ] . map [ dval ] . app , flags ) ;
}
2008-12-31 01:08:51 +00:00
if ( ( md - > sr [ direction ] . map [ dval ] . bind_flags & SBF_ONCE ) ) {
memset ( & md - > sr [ direction ] . map [ dval ] , 0 , sizeof ( md - > sr [ direction ] . map [ dval ] ) ) ;
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s Unbinding meta digit '%c' \n " ,
2008-12-31 01:08:51 +00:00
switch_channel_get_name ( channel ) , dtmf - > digit ) ;
}
2008-03-11 21:32:56 +00:00
} else {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " %s Ignoring meta digit '%c' not mapped \n " ,
2008-03-11 21:32:56 +00:00
switch_channel_get_name ( channel ) , dtmf - > digit ) ;
2008-05-27 04:30:03 +00:00
2008-03-11 21:32:56 +00:00
}
}
2008-05-19 21:02:26 +00:00
md - > sr [ direction ] . meta_on = SWITCH_FALSE ;
2008-03-11 21:32:56 +00:00
return SWITCH_STATUS_FALSE ;
}
2008-05-27 04:30:03 +00:00
return SWITCH_STATUS_SUCCESS ;
2008-03-11 21:32:56 +00:00
}
2008-12-31 01:08:51 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_unbind_dtmf_meta_session ( switch_core_session_t * session , uint32_t key )
2008-03-11 21:32:56 +00:00
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2008-12-31 01:08:51 +00:00
if ( key ) {
dtmf_meta_data_t * md = switch_channel_get_private ( channel , SWITCH_META_VAR_KEY ) ;
if ( ! md | | key > 9 ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Invalid key %u \n " , key ) ;
2008-12-31 01:08:51 +00:00
return SWITCH_STATUS_FALSE ;
}
memset ( & md - > sr [ SWITCH_DTMF_RECV ] . map [ key ] , 0 , sizeof ( md - > sr [ SWITCH_DTMF_RECV ] . map [ key ] ) ) ;
memset ( & md - > sr [ SWITCH_DTMF_SEND ] . map [ key ] , 0 , sizeof ( md - > sr [ SWITCH_DTMF_SEND ] . map [ key ] ) ) ;
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_INFO , " UnBound A-Leg: %d \n " , key ) ;
2008-12-31 01:08:51 +00:00
} else {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_INFO , " UnBound A-Leg: ALL \n " ) ;
2008-12-31 01:08:51 +00:00
switch_channel_set_private ( channel , SWITCH_META_VAR_KEY , NULL ) ;
}
2008-03-11 21:32:56 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2008-05-27 04:30:03 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_bind_dtmf_meta_session ( switch_core_session_t * session , uint32_t key ,
2008-05-19 21:02:26 +00:00
switch_bind_flag_t bind_flags , const char * app )
2008-03-11 21:32:56 +00:00
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
dtmf_meta_data_t * md = switch_channel_get_private ( channel , SWITCH_META_VAR_KEY ) ;
2008-05-27 04:30:03 +00:00
2008-03-11 21:32:56 +00:00
if ( key > 9 ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Invalid key %u \n " , key ) ;
2008-03-11 21:32:56 +00:00
return SWITCH_STATUS_FALSE ;
}
2008-05-27 04:30:03 +00:00
2008-03-11 21:32:56 +00:00
if ( ! md ) {
md = switch_core_session_alloc ( session , sizeof ( * md ) ) ;
switch_channel_set_private ( channel , SWITCH_META_VAR_KEY , md ) ;
2008-05-19 21:02:26 +00:00
switch_core_event_hook_add_send_dtmf ( session , meta_on_dtmf ) ;
switch_core_event_hook_add_recv_dtmf ( session , meta_on_dtmf ) ;
2008-03-11 21:32:56 +00:00
}
2009-10-23 16:03:42 +00:00
if ( ! zstr ( app ) ) {
2008-05-19 21:02:26 +00:00
if ( ( bind_flags & SBF_DIAL_ALEG ) ) {
md - > sr [ SWITCH_DTMF_RECV ] . up = 1 ;
md - > sr [ SWITCH_DTMF_RECV ] . map [ key ] . app = switch_core_session_strdup ( session , app ) ;
md - > sr [ SWITCH_DTMF_RECV ] . map [ key ] . flags | = SMF_HOLD_BLEG ;
md - > sr [ SWITCH_DTMF_RECV ] . map [ key ] . bind_flags = bind_flags ;
2009-01-06 21:07:58 +00:00
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_INFO , " Bound A-Leg: %d %s \n " , key , app ) ;
2008-05-19 21:02:26 +00:00
}
if ( ( bind_flags & SBF_DIAL_BLEG ) ) {
md - > sr [ SWITCH_DTMF_SEND ] . up = 1 ;
md - > sr [ SWITCH_DTMF_SEND ] . map [ key ] . app = switch_core_session_strdup ( session , app ) ;
md - > sr [ SWITCH_DTMF_SEND ] . map [ key ] . flags | = SMF_HOLD_BLEG ;
md - > sr [ SWITCH_DTMF_SEND ] . map [ key ] . bind_flags = bind_flags ;
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_INFO , " Bound B-Leg: %d %s \n " , key , app ) ;
2008-05-19 21:02:26 +00:00
}
2008-05-27 04:30:03 +00:00
2008-03-11 21:32:56 +00:00
} else {
2008-05-19 21:02:26 +00:00
if ( ( bind_flags & SBF_DIAL_ALEG ) ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_INFO , " UnBound A-Leg: %d \n " , key ) ;
2008-05-19 21:02:26 +00:00
md - > sr [ SWITCH_DTMF_SEND ] . map [ key ] . app = NULL ;
} else {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_INFO , " UnBound: B-Leg %d \n " , key ) ;
2008-05-19 21:02:26 +00:00
md - > sr [ SWITCH_DTMF_SEND ] . map [ key ] . app = NULL ;
}
2008-03-11 21:32:56 +00:00
}
return SWITCH_STATUS_SUCCESS ;
}
2007-03-29 22:34:40 +00:00
struct speech_thread_handle {
switch_core_session_t * session ;
switch_asr_handle_t * ah ;
switch_media_bug_t * bug ;
switch_mutex_t * mutex ;
switch_thread_cond_t * cond ;
switch_memory_pool_t * pool ;
2008-07-09 21:19:18 +00:00
int ready ;
2007-03-29 22:34:40 +00:00
} ;
2008-05-27 04:30:03 +00:00
static void * SWITCH_THREAD_FUNC speech_thread ( switch_thread_t * thread , void * obj )
2007-03-29 22:34:40 +00:00
{
struct speech_thread_handle * sth = ( struct speech_thread_handle * ) obj ;
switch_channel_t * channel = switch_core_session_get_channel ( sth - > session ) ;
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE ;
switch_status_t status ;
switch_thread_cond_create ( & sth - > cond , sth - > pool ) ;
switch_mutex_init ( & sth - > mutex , SWITCH_MUTEX_NESTED , sth - > pool ) ;
2009-01-09 20:34:01 +00:00
if ( switch_core_session_read_lock ( sth - > session ) ! = SWITCH_STATUS_SUCCESS ) {
sth - > ready = 0 ;
return NULL ;
}
2007-03-29 22:34:40 +00:00
switch_mutex_lock ( sth - > mutex ) ;
2008-07-09 21:19:18 +00:00
sth - > ready = 1 ;
2009-02-25 03:41:18 +00:00
while ( switch_channel_up ( channel ) & & ! switch_test_flag ( sth - > ah , SWITCH_ASR_FLAG_CLOSED ) ) {
2007-03-29 22:34:40 +00:00
char * xmlstr = NULL ;
switch_thread_cond_wait ( sth - > cond , sth - > mutex ) ;
2008-11-17 17:53:57 +00:00
2009-02-25 03:41:18 +00:00
if ( switch_channel_down ( channel ) | | switch_test_flag ( sth - > ah , SWITCH_ASR_FLAG_CLOSED ) ) {
2008-11-17 17:53:57 +00:00
break ;
2009-02-25 03:41:18 +00:00
}
2008-11-17 17:53:57 +00:00
2007-03-29 22:34:40 +00:00
if ( switch_core_asr_check_results ( sth - > ah , & flags ) = = SWITCH_STATUS_SUCCESS ) {
switch_event_t * event ;
status = switch_core_asr_get_results ( sth - > ah , & xmlstr , & flags ) ;
if ( status ! = SWITCH_STATUS_SUCCESS & & status ! = SWITCH_STATUS_BREAK ) {
goto done ;
}
2008-07-07 22:07:00 +00:00
if ( status = = SWITCH_STATUS_SUCCESS & & switch_true ( switch_channel_get_variable ( channel , " asr_intercept_dtmf " ) ) ) {
const char * p ;
if ( ( p = switch_stristr ( " <input> " , xmlstr ) ) ) {
p + = 7 ;
}
while ( p & & * p ) {
char c ;
if ( * p = = ' < ' ) {
break ;
}
if ( ! strncasecmp ( p , " pound " , 5 ) ) {
c = ' # ' ;
p + = 5 ;
} else if ( ! strncasecmp ( p , " hash " , 4 ) ) {
c = ' # ' ;
p + = 4 ;
} else if ( ! strncasecmp ( p , " star " , 4 ) ) {
c = ' * ' ;
p + = 4 ;
} else if ( ! strncasecmp ( p , " asterisk " , 8 ) ) {
c = ' * ' ;
p + = 8 ;
} else {
c = * p ;
p + + ;
}
if ( is_dtmf ( c ) ) {
switch_dtmf_t dtmf ;
dtmf . digit = c ;
dtmf . duration = switch_core_default_dtmf_duration ( 0 ) ;
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_CHANNEL_LOG ( channel ) , SWITCH_LOG_DEBUG , " Queue speech detected dtmf %c \n " , c ) ;
2008-07-07 22:07:00 +00:00
switch_channel_queue_dtmf ( channel , & dtmf ) ;
}
}
switch_ivr_resume_detect_speech ( sth - > session ) ;
}
2007-03-29 22:34:40 +00:00
if ( switch_event_create ( & event , SWITCH_EVENT_DETECTED_SPEECH ) = = SWITCH_STATUS_SUCCESS ) {
if ( status = = SWITCH_STATUS_SUCCESS ) {
2008-08-16 02:17:09 +00:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Speech-Type " , " detected-speech " ) ;
2007-03-29 22:34:40 +00:00
switch_event_add_body ( event , " %s " , xmlstr ) ;
} else {
2008-08-16 02:17:09 +00:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Speech-Type " , " begin-speaking " ) ;
2007-03-29 22:34:40 +00:00
}
if ( switch_test_flag ( sth - > ah , SWITCH_ASR_FLAG_FIRE_EVENTS ) ) {
switch_event_t * dup ;
if ( switch_event_dup ( & dup , event ) = = SWITCH_STATUS_SUCCESS ) {
switch_event_fire ( & dup ) ;
}
}
if ( switch_core_session_queue_event ( sth - > session , & event ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_CHANNEL_LOG ( channel ) , SWITCH_LOG_ERROR , " Event queue failed! \n " ) ;
2008-08-16 02:17:09 +00:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " delivery-failure " , " true " ) ;
2007-03-29 22:34:40 +00:00
switch_event_fire ( & event ) ;
}
}
switch_safe_free ( xmlstr ) ;
}
}
done :
switch_mutex_unlock ( sth - > mutex ) ;
switch_core_session_rwunlock ( sth - > session ) ;
return NULL ;
}
static switch_bool_t speech_callback ( switch_media_bug_t * bug , void * user_data , switch_abc_type_t type )
{
struct speech_thread_handle * sth = ( struct speech_thread_handle * ) user_data ;
uint8_t data [ SWITCH_RECOMMENDED_BUFFER_SIZE ] ;
switch_frame_t frame = { 0 } ;
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE ;
frame . data = data ;
frame . buflen = SWITCH_RECOMMENDED_BUFFER_SIZE ;
switch ( type ) {
case SWITCH_ABC_TYPE_INIT : {
switch_thread_t * thread ;
switch_threadattr_t * thd_attr = NULL ;
switch_threadattr_create ( & thd_attr , sth - > pool ) ;
switch_threadattr_detach_set ( thd_attr , 1 ) ;
switch_threadattr_stacksize_set ( thd_attr , SWITCH_THREAD_STACKSIZE ) ;
switch_thread_create ( & thread , thd_attr , speech_thread , sth , sth - > pool ) ;
}
break ;
case SWITCH_ABC_TYPE_CLOSE : {
switch_core_asr_close ( sth - > ah , & flags ) ;
2008-07-09 21:19:18 +00:00
if ( sth - > mutex & & sth - > cond & & sth - > ready ) {
switch_mutex_lock ( sth - > mutex ) ;
switch_thread_cond_signal ( sth - > cond ) ;
switch_mutex_unlock ( sth - > mutex ) ;
}
2007-03-29 22:34:40 +00:00
}
break ;
case SWITCH_ABC_TYPE_READ :
if ( sth - > ah ) {
2009-06-05 19:52:02 +00:00
if ( switch_core_media_bug_read ( bug , & frame , SWITCH_TRUE ) = = SWITCH_STATUS_SUCCESS ) {
2007-03-29 22:34:40 +00:00
if ( switch_core_asr_feed ( sth - > ah , frame . data , frame . datalen , & flags ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( switch_core_media_bug_get_session ( bug ) ) , SWITCH_LOG_DEBUG , " Error Feeding Data \n " ) ;
2007-03-29 22:34:40 +00:00
return SWITCH_FALSE ;
}
if ( switch_core_asr_check_results ( sth - > ah , & flags ) = = SWITCH_STATUS_SUCCESS ) {
2008-07-12 15:27:34 +00:00
if ( sth - > mutex & & sth - > cond & & sth - > ready ) {
switch_mutex_lock ( sth - > mutex ) ;
switch_thread_cond_signal ( sth - > cond ) ;
switch_mutex_unlock ( sth - > mutex ) ;
}
2007-03-29 22:34:40 +00:00
}
}
}
break ;
case SWITCH_ABC_TYPE_WRITE :
default :
break ;
}
return SWITCH_TRUE ;
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_stop_detect_speech ( switch_core_session_t * session )
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
struct speech_thread_handle * sth ;
2007-12-11 19:23:57 +00:00
switch_assert ( channel ! = NULL ) ;
2007-03-29 22:34:40 +00:00
if ( ( sth = switch_channel_get_private ( channel , SWITCH_SPEECH_KEY ) ) ) {
switch_channel_set_private ( channel , SWITCH_SPEECH_KEY , NULL ) ;
switch_core_media_bug_remove ( session , & sth - > bug ) ;
return SWITCH_STATUS_SUCCESS ;
}
return SWITCH_STATUS_FALSE ;
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_pause_detect_speech ( switch_core_session_t * session )
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2008-01-28 07:26:10 +00:00
struct speech_thread_handle * sth = switch_channel_get_private ( channel , SWITCH_SPEECH_KEY ) ;
2007-03-29 22:34:40 +00:00
2008-01-28 07:26:10 +00:00
if ( sth ) {
2007-03-29 22:34:40 +00:00
switch_core_asr_pause ( sth - > ah ) ;
return SWITCH_STATUS_SUCCESS ;
}
return SWITCH_STATUS_FALSE ;
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_resume_detect_speech ( switch_core_session_t * session )
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2008-01-28 07:26:10 +00:00
struct speech_thread_handle * sth = switch_channel_get_private ( channel , SWITCH_SPEECH_KEY ) ;
2007-03-29 22:34:40 +00:00
2008-01-28 07:26:10 +00:00
if ( sth ) {
2007-03-29 22:34:40 +00:00
switch_core_asr_resume ( sth - > ah ) ;
return SWITCH_STATUS_SUCCESS ;
}
return SWITCH_STATUS_FALSE ;
}
2009-06-08 21:52:50 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_detect_speech_load_grammar ( switch_core_session_t * session , char * grammar , char * name )
2007-03-29 22:34:40 +00:00
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE ;
2008-01-28 07:26:10 +00:00
struct speech_thread_handle * sth = switch_channel_get_private ( channel , SWITCH_SPEECH_KEY ) ;
2009-11-23 17:54:08 +00:00
switch_status_t status ;
2007-03-29 22:34:40 +00:00
2008-01-28 07:26:10 +00:00
if ( sth ) {
2009-11-23 17:54:08 +00:00
if ( ( status = switch_core_asr_load_grammar ( sth - > ah , grammar , name ) ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Error loading Grammar \n " ) ;
2007-03-29 22:34:40 +00:00
switch_core_asr_close ( sth - > ah , & flags ) ;
}
2009-11-23 17:54:08 +00:00
return status ;
2007-03-29 22:34:40 +00:00
}
return SWITCH_STATUS_FALSE ;
}
2009-06-08 21:52:50 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_detect_speech_unload_grammar ( switch_core_session_t * session , const char * name )
2007-03-29 22:34:40 +00:00
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE ;
2008-01-28 07:26:10 +00:00
struct speech_thread_handle * sth = switch_channel_get_private ( channel , SWITCH_SPEECH_KEY ) ;
2009-11-23 17:54:08 +00:00
switch_status_t status ;
2007-03-29 22:34:40 +00:00
2008-01-28 07:26:10 +00:00
if ( sth ) {
2009-11-23 17:54:08 +00:00
if ( ( status = switch_core_asr_unload_grammar ( sth - > ah , name ) ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Error unloading Grammar \n " ) ;
2007-03-29 22:34:40 +00:00
switch_core_asr_close ( sth - > ah , & flags ) ;
}
2009-11-23 17:54:08 +00:00
return status ;
2007-03-29 22:34:40 +00:00
}
return SWITCH_STATUS_FALSE ;
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_detect_speech ( switch_core_session_t * session ,
2007-11-01 11:55:00 +00:00
const char * mod_name ,
2009-06-08 21:52:50 +00:00
const char * grammar , const char * name , const char * dest , switch_asr_handle_t * ah )
2007-03-29 22:34:40 +00:00
{
2008-01-28 07:26:10 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2007-03-29 22:34:40 +00:00
switch_status_t status ;
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE ;
2008-01-28 07:26:10 +00:00
struct speech_thread_handle * sth = switch_channel_get_private ( channel , SWITCH_SPEECH_KEY ) ;
2009-08-01 05:29:50 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
const char * p ;
2009-08-01 17:33:25 +00:00
switch_core_session_get_read_impl ( session , & read_impl ) ;
2009-08-01 05:29:50 +00:00
2007-03-29 22:34:40 +00:00
if ( ! ah ) {
if ( ! ( ah = switch_core_session_alloc ( session , sizeof ( * ah ) ) ) ) {
return SWITCH_STATUS_MEMERR ;
}
}
2008-01-28 07:26:10 +00:00
if ( sth ) {
2009-06-08 21:52:50 +00:00
if ( switch_core_asr_load_grammar ( sth - > ah , grammar , name ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Error loading Grammar \n " ) ;
2007-03-29 22:34:40 +00:00
switch_core_asr_close ( sth - > ah , & flags ) ;
return SWITCH_STATUS_FALSE ;
}
2009-08-01 05:29:50 +00:00
if ( ( p = switch_channel_get_variable ( channel , " fire_asr_events " ) ) & & switch_true ( p ) ) {
switch_set_flag ( sth - > ah , SWITCH_ASR_FLAG_FIRE_EVENTS ) ;
}
2007-03-29 22:34:40 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2009-11-23 17:54:08 +00:00
if ( ( status = switch_core_asr_open ( ah ,
2007-03-29 22:34:40 +00:00
mod_name ,
" L16 " ,
2009-02-10 19:09:06 +00:00
read_impl . actual_samples_per_second , dest , & flags ,
2009-11-23 17:54:08 +00:00
switch_core_session_get_pool ( session ) ) ) = = SWITCH_STATUS_SUCCESS ) {
2007-03-29 22:34:40 +00:00
2009-06-08 21:52:50 +00:00
if ( switch_core_asr_load_grammar ( ah , grammar , name ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Error loading Grammar \n " ) ;
2007-03-29 22:34:40 +00:00
switch_core_asr_close ( ah , & flags ) ;
return SWITCH_STATUS_FALSE ;
}
} else {
2009-11-23 17:54:08 +00:00
return status ;
2007-03-29 22:34:40 +00:00
}
sth = switch_core_session_alloc ( session , sizeof ( * sth ) ) ;
sth - > pool = switch_core_session_get_pool ( session ) ;
sth - > session = session ;
sth - > ah = ah ;
2009-08-01 05:29:50 +00:00
if ( ( p = switch_channel_get_variable ( channel , " fire_asr_events " ) ) & & switch_true ( p ) ) {
switch_set_flag ( ah , SWITCH_ASR_FLAG_FIRE_EVENTS ) ;
}
2007-05-31 14:42:23 +00:00
if ( ( status = switch_core_media_bug_add ( session , speech_callback , sth , 0 , SMBF_READ_STREAM , & sth - > bug ) ) ! = SWITCH_STATUS_SUCCESS ) {
2007-03-29 22:34:40 +00:00
switch_core_asr_close ( ah , & flags ) ;
return status ;
}
switch_channel_set_private ( channel , SWITCH_SPEECH_KEY , sth ) ;
return SWITCH_STATUS_SUCCESS ;
}
struct hangup_helper {
char uuid_str [ SWITCH_UUID_FORMATTED_LENGTH + 1 ] ;
switch_bool_t bleg ;
switch_call_cause_t cause ;
} ;
2007-05-12 21:43:41 +00:00
SWITCH_STANDARD_SCHED_FUNC ( sch_hangup_callback )
2007-03-29 22:34:40 +00:00
{
struct hangup_helper * helper ;
switch_core_session_t * session , * other_session ;
2007-11-01 11:28:26 +00:00
const char * other_uuid ;
2007-03-29 22:34:40 +00:00
2007-12-11 19:23:57 +00:00
switch_assert ( task ) ;
2007-03-29 22:34:40 +00:00
helper = ( struct hangup_helper * ) task - > cmd_arg ;
if ( ( session = switch_core_session_locate ( helper - > uuid_str ) ) ) {
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
if ( helper - > bleg ) {
2007-03-30 00:13:31 +00:00
if ( ( other_uuid = switch_channel_get_variable ( channel , SWITCH_BRIDGE_VARIABLE ) ) & & ( other_session = switch_core_session_locate ( other_uuid ) ) ) {
2007-03-29 22:34:40 +00:00
switch_channel_t * other_channel = switch_core_session_get_channel ( other_session ) ;
switch_channel_hangup ( other_channel , helper - > cause ) ;
switch_core_session_rwunlock ( other_session ) ;
} else {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " No channel to hangup \n " ) ;
2007-03-29 22:34:40 +00:00
}
} else {
switch_channel_hangup ( channel , helper - > cause ) ;
}
switch_core_session_rwunlock ( session ) ;
}
}
2007-11-01 11:28:26 +00:00
SWITCH_DECLARE ( uint32_t ) switch_ivr_schedule_hangup ( time_t runtime , const char * uuid , switch_call_cause_t cause , switch_bool_t bleg )
2007-03-29 22:34:40 +00:00
{
struct hangup_helper * helper ;
size_t len = sizeof ( * helper ) ;
switch_zmalloc ( helper , len ) ;
switch_copy_string ( helper - > uuid_str , uuid , sizeof ( helper - > uuid_str ) ) ;
helper - > cause = cause ;
helper - > bleg = bleg ;
2007-03-30 00:13:31 +00:00
return switch_scheduler_add_task ( runtime , sch_hangup_callback , ( char * ) __SWITCH_FUNC__ , uuid , 0 , helper , SSHF_FREE_ARG ) ;
2007-03-29 22:34:40 +00:00
}
struct transfer_helper {
char uuid_str [ SWITCH_UUID_FORMATTED_LENGTH + 1 ] ;
char * extension ;
char * dialplan ;
char * context ;
} ;
2007-05-12 21:43:41 +00:00
SWITCH_STANDARD_SCHED_FUNC ( sch_transfer_callback )
2007-03-29 22:34:40 +00:00
{
struct transfer_helper * helper ;
switch_core_session_t * session ;
2007-12-11 19:23:57 +00:00
switch_assert ( task ) ;
2007-03-29 22:34:40 +00:00
helper = ( struct transfer_helper * ) task - > cmd_arg ;
if ( ( session = switch_core_session_locate ( helper - > uuid_str ) ) ) {
switch_ivr_session_transfer ( session , helper - > extension , helper - > dialplan , helper - > context ) ;
switch_core_session_rwunlock ( session ) ;
}
}
2007-11-01 11:28:26 +00:00
SWITCH_DECLARE ( uint32_t ) switch_ivr_schedule_transfer ( time_t runtime , const char * uuid , char * extension , char * dialplan , char * context )
2007-03-29 22:34:40 +00:00
{
struct transfer_helper * helper ;
size_t len = sizeof ( * helper ) ;
char * cur = NULL ;
if ( extension ) {
len + = strlen ( extension ) + 1 ;
}
if ( dialplan ) {
len + = strlen ( dialplan ) + 1 ;
}
if ( context ) {
len + = strlen ( context ) + 1 ;
}
2007-11-01 14:58:12 +00:00
switch_zmalloc ( cur , len ) ;
2008-05-27 04:30:03 +00:00
helper = ( struct transfer_helper * ) cur ;
2007-03-29 22:34:40 +00:00
switch_copy_string ( helper - > uuid_str , uuid , sizeof ( helper - > uuid_str ) ) ;
2007-11-01 14:22:58 +00:00
cur + = sizeof ( * helper ) ;
2007-03-29 22:34:40 +00:00
if ( extension ) {
2007-11-01 14:22:58 +00:00
switch_copy_string ( cur , extension , strlen ( extension ) + 1 ) ;
2007-03-29 22:34:40 +00:00
helper - > extension = cur ;
cur + = strlen ( helper - > extension ) + 1 ;
}
if ( dialplan ) {
2007-11-01 14:22:58 +00:00
switch_copy_string ( cur , dialplan , strlen ( dialplan ) + 1 ) ;
2007-03-29 22:34:40 +00:00
helper - > dialplan = cur ;
cur + = strlen ( helper - > dialplan ) + 1 ;
}
if ( context ) {
2007-11-01 14:22:58 +00:00
switch_copy_string ( cur , context , strlen ( context ) + 1 ) ;
2007-03-29 22:34:40 +00:00
helper - > context = cur ;
}
2007-03-30 00:13:31 +00:00
return switch_scheduler_add_task ( runtime , sch_transfer_callback , ( char * ) __SWITCH_FUNC__ , uuid , 0 , helper , SSHF_FREE_ARG ) ;
2007-03-29 22:34:40 +00:00
}
struct broadcast_helper {
char uuid_str [ SWITCH_UUID_FORMATTED_LENGTH + 1 ] ;
char * path ;
switch_media_flag_t flags ;
} ;
2007-05-12 21:43:41 +00:00
SWITCH_STANDARD_SCHED_FUNC ( sch_broadcast_callback )
2007-03-29 22:34:40 +00:00
{
struct broadcast_helper * helper ;
2007-12-11 19:23:57 +00:00
switch_assert ( task ) ;
2007-03-29 22:34:40 +00:00
helper = ( struct broadcast_helper * ) task - > cmd_arg ;
switch_ivr_broadcast ( helper - > uuid_str , helper - > path , helper - > flags ) ;
}
2009-01-27 21:19:40 +00:00
SWITCH_DECLARE ( uint32_t ) switch_ivr_schedule_broadcast ( time_t runtime , const char * uuid , const char * path , switch_media_flag_t flags )
2007-03-29 22:34:40 +00:00
{
struct broadcast_helper * helper ;
size_t len = sizeof ( * helper ) + strlen ( path ) + 1 ;
2007-11-01 14:22:58 +00:00
char * cur = NULL ;
2007-03-29 22:34:40 +00:00
2007-11-01 14:58:12 +00:00
switch_zmalloc ( cur , len ) ;
2008-05-27 04:30:03 +00:00
helper = ( struct broadcast_helper * ) cur ;
2007-11-01 14:22:58 +00:00
cur + = sizeof ( * helper ) ;
2007-03-29 22:34:40 +00:00
switch_copy_string ( helper - > uuid_str , uuid , sizeof ( helper - > uuid_str ) ) ;
helper - > flags = flags ;
2008-05-27 04:30:03 +00:00
2007-11-01 14:22:58 +00:00
switch_copy_string ( cur , path , len - sizeof ( helper ) ) ;
helper - > path = cur ;
2007-03-29 22:34:40 +00:00
2007-03-30 00:13:31 +00:00
return switch_scheduler_add_task ( runtime , sch_broadcast_callback , ( char * ) __SWITCH_FUNC__ , uuid , 0 , helper , SSHF_FREE_ARG ) ;
2007-03-29 22:34:40 +00:00
}
2007-11-01 11:28:26 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_broadcast ( const char * uuid , const char * path , switch_media_flag_t flags )
2007-03-29 22:34:40 +00:00
{
switch_channel_t * channel ;
int nomedia ;
switch_core_session_t * session , * master ;
switch_event_t * event ;
switch_core_session_t * other_session = NULL ;
2007-11-01 11:28:26 +00:00
const char * other_uuid = NULL ;
2007-03-29 22:34:40 +00:00
char * app = " playback " ;
2008-01-03 21:34:44 +00:00
char * cause = NULL ;
char * mypath ;
char * p ;
2009-08-26 17:42:36 +00:00
int custom = 0 ;
2007-03-29 22:34:40 +00:00
2007-12-11 19:23:57 +00:00
switch_assert ( path ) ;
2007-03-29 22:34:40 +00:00
2008-01-28 07:26:10 +00:00
if ( ! ( master = session = switch_core_session_locate ( uuid ) ) ) {
2008-01-03 21:34:44 +00:00
return SWITCH_STATUS_FALSE ;
}
2007-03-29 22:34:40 +00:00
2008-01-03 21:34:44 +00:00
channel = switch_core_session_get_channel ( session ) ;
2007-05-14 20:38:18 +00:00
2009-08-26 17:42:36 +00:00
mypath = strdup ( path ) ;
assert ( mypath ) ;
if ( ( p = strchr ( mypath , ' : ' ) ) & & * ( p + 1 ) = = ' : ' ) {
app = mypath ;
* p + + = ' \0 ' ;
* p + + = ' \0 ' ;
path = p ;
custom + + ;
}
if ( ! custom & & ( switch_channel_test_flag ( channel , CF_EVENT_PARSE ) ) ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " Channel [%s][%s] already broadcasting...broadcast aborted \n " ,
2008-04-09 18:15:15 +00:00
switch_channel_get_name ( channel ) , path ) ;
2008-01-03 21:34:44 +00:00
switch_core_session_rwunlock ( session ) ;
2009-08-26 17:42:36 +00:00
switch_safe_free ( mypath ) ;
2008-01-03 21:34:44 +00:00
return SWITCH_STATUS_FALSE ;
}
2007-05-14 23:50:38 +00:00
2008-05-19 18:53:32 +00:00
2008-02-21 17:48:41 +00:00
if ( ( nomedia = switch_channel_test_flag ( channel , CF_PROXY_MODE ) ) ) {
2008-01-03 21:34:44 +00:00
switch_ivr_media ( uuid , SMF_REBRIDGE ) ;
}
2008-05-27 04:30:03 +00:00
2008-01-03 21:34:44 +00:00
if ( ( cause = strchr ( app , ' ! ' ) ) ) {
* cause + + = ' \0 ' ;
if ( ! cause ) {
cause = " normal_clearing " ;
2007-03-29 22:34:40 +00:00
}
2008-01-03 21:34:44 +00:00
}
2007-03-29 22:34:40 +00:00
2008-01-03 21:34:44 +00:00
if ( ( flags & SMF_ECHO_BLEG ) & & ( other_uuid = switch_channel_get_variable ( channel , SWITCH_SIGNAL_BOND_VARIABLE ) )
& & ( other_session = switch_core_session_locate ( other_uuid ) ) ) {
2009-09-25 19:48:28 +00:00
if ( ( flags & SMF_EXEC_INLINE ) ) {
switch_core_session_execute_application ( other_session , app , path ) ;
nomedia = 0 ;
} else {
if ( switch_event_create ( & event , SWITCH_EVENT_COMMAND ) = = SWITCH_STATUS_SUCCESS ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " call-command " , " execute " ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " execute-app-name " , app ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " execute-app-arg " , path ) ;
switch_event_add_header ( event , SWITCH_STACK_BOTTOM , " lead-frames " , " %d " , 5 ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " event-lock " , " true " ) ;
if ( ( flags & SMF_LOOP ) ) {
switch_event_add_header ( event , SWITCH_STACK_BOTTOM , " loops " , " %d " , - 1 ) ;
}
2008-03-12 00:30:52 +00:00
2009-09-25 19:48:28 +00:00
if ( ( flags & SMF_HOLD_BLEG ) ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " hold-bleg " , " true " ) ;
}
2009-09-24 22:21:44 +00:00
switch_core_session_queue_private_event ( other_session , & event ) ;
}
2007-03-29 22:34:40 +00:00
}
2008-05-27 04:30:03 +00:00
2008-01-03 21:34:44 +00:00
switch_core_session_rwunlock ( other_session ) ;
master = other_session ;
other_session = NULL ;
}
2007-03-29 22:34:40 +00:00
2009-01-06 21:07:58 +00:00
if ( switch_stristr ( " record " , app ) ) {
nomedia = 0 ;
}
2009-09-25 19:48:28 +00:00
2008-01-03 21:34:44 +00:00
if ( ( flags & SMF_ECHO_ALEG ) ) {
2009-09-25 19:48:28 +00:00
if ( ( flags & SMF_EXEC_INLINE ) ) {
switch_core_session_execute_application ( session , app , path ) ;
nomedia = 0 ;
} else {
if ( switch_event_create ( & event , SWITCH_EVENT_COMMAND ) = = SWITCH_STATUS_SUCCESS ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " call-command " , " execute " ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " execute-app-name " , app ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " execute-app-arg " , path ) ;
switch_event_add_header ( event , SWITCH_STACK_BOTTOM , " lead-frames " , " %d " , 5 ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " event-lock " , " true " ) ;
if ( ( flags & SMF_LOOP ) ) {
switch_event_add_header ( event , SWITCH_STACK_BOTTOM , " loops " , " %d " , - 1 ) ;
}
if ( ( flags & SMF_HOLD_BLEG ) ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " hold-bleg " , " true " ) ;
}
2009-09-29 19:03:48 +00:00
switch_core_session_queue_private_event ( session , & event ) ;
2008-03-12 00:30:52 +00:00
}
2007-03-29 22:34:40 +00:00
}
2008-01-03 21:34:44 +00:00
master = session ;
}
2007-03-29 22:34:40 +00:00
2008-01-03 21:34:44 +00:00
if ( nomedia ) {
2008-10-02 17:10:05 +00:00
if ( switch_event_create ( & event , SWITCH_EVENT_COMMAND ) = = SWITCH_STATUS_SUCCESS ) {
2008-08-16 02:17:09 +00:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " call-command " , " nomedia " ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " nomedia-uuid " , uuid ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " event-lock " , " true " ) ;
2008-01-03 21:34:44 +00:00
switch_core_session_queue_private_event ( master , & event ) ;
2007-03-29 22:34:40 +00:00
}
2008-01-03 21:34:44 +00:00
}
2007-03-29 22:34:40 +00:00
2008-01-03 21:34:44 +00:00
if ( cause ) {
2008-10-02 17:10:05 +00:00
if ( switch_event_create ( & event , SWITCH_EVENT_COMMAND ) = = SWITCH_STATUS_SUCCESS ) {
2008-08-16 02:17:09 +00:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " call-command " , " execute " ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " execute-app-name " , " hangup " ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " execute-app-arg " , cause ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " event-lock " , " true " ) ;
2008-01-03 21:34:44 +00:00
switch_core_session_queue_private_event ( session , & event ) ;
2007-03-29 22:34:40 +00:00
}
}
2008-01-03 21:34:44 +00:00
switch_core_session_rwunlock ( session ) ;
switch_safe_free ( mypath ) ;
2007-03-29 22:34:40 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2008-01-27 17:36:53 +00:00
2007-11-01 14:58:12 +00:00
/* For Emacs:
* Local Variables :
* mode : c
2008-02-03 22:14:57 +00:00
* indent - tabs - mode : t
2007-11-01 14:58:12 +00:00
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
2008-07-03 19:12:26 +00:00
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 :
2007-11-01 14:58:12 +00:00
*/